0

I am still in the learning phase of C and wrote the following function. I was not expecting it to work because the void pointer is only given 2 bytes which is not enough for my 23 byte char array. Though it is stored the char array and could typecaste it to another pointer variable.

void main(){
     void *p = malloc(2 * sizeof(char));
     p = "Unites State of America";
     printf("%p length -> %ld, sizeof -> %ld\n", p, strlen(p), sizeof(p)/sizeof(p[0]));

     char *pstr = (char*) p;
     printf("%s length -> %ld\n", pstr, strlen(pstr));
}

Result:

0x55600dccd008 length -> 23, sizeof -> 8
Unites State of America length -> 23

How did my void pointer exceed the size I initially requested?

Shahin
  • 1,196
  • 1
  • 8
  • 15
  • 4
    assigning to a variable of pointer type like this does not change what is stored at the location pointed to, it changes the pointer to point somewhere else - in this case to the string literal. – Hulk Apr 24 '20 at 12:13
  • 2
    ... leaving no pointers to the originally allocated space, which constitutes a "memory leak." – John Bollinger Apr 24 '20 at 12:14
  • 1
    you do not use the result of `malloc`, if you want to use it do `*p = "...";` ... and appreciate the result – bruno Apr 24 '20 at 12:15
  • Also note that you cannot modify the string. – Hulk Apr 24 '20 at 12:15
  • 1
    `sizeof(p)/sizeof(p[0])` is equal to `sizeof(void*)/sizeof(void)` - it just so happens that `gcc` interprets `sizeof(void)` as 1 and not as an error, so this is `sizeof(void*)` which is `8` on your platform. [link](https://stackoverflow.com/questions/1666224/what-is-the-size-of-void) – KamilCuk Apr 24 '20 at 12:15
  • 1
    also `sizeof(char)` is useless because by definition it values 1 – bruno Apr 24 '20 at 12:16

3 Answers3

5

You allocated 2 chars worth of memory, so now there's a small chunk of memory in the heap waiting for data to be stored there. However, you then reassign p to point to the string "Unites State of America", which is stored elsewhere. p = "string" does not move a string into the memory pointed to by p, it makes p point to the string.

Aplet123
  • 33,825
  • 1
  • 29
  • 55
3

Your understanding is not quite correct here. When you do the below two lines, you are actually leaking memory by not using the actually allocated dynamic memory.

void *p = malloc(2 * sizeof(char));
p = "Unites State of America";

Your pointer p holds a region in heap to store 2 * sizeof(char) bytes but, you are actually overwriting that location with a statically allocated string. All your string operations strlen(), sizeof() are done in this statically allocated string "Unites State of America"

You need to use functions like strncpy() or equivalent to copy the string characters to the dynamically allocated location. But since you don't have allocated sufficient bytes to hold the large string but only 2 * sizeof(char) bytes.

Your other pointer assignment isn't quite incorrect, because you have just introduced another pointer to point to the location where the const string pointed by p is referring to.

char *pstr = (char*) p;

So to summarize even if you had use the right string copy functions, copying beyond the allocated size, i.e. copying 23 bytes to a 2 byte allocated region, is a memory access violation and could lead to undesirable results.

codeforester
  • 39,467
  • 16
  • 112
  • 140
Inian
  • 80,270
  • 14
  • 142
  • 161
3

Could a void pointer store a larger array than its dynamically allocated size?

Pointers of any pointer type store addresses. Pointers themselves have a size determined by their (pointer) type, like any other object, and it's very common for all pointers provided by a given implementation to have the same size as each other. If you allocate memory, then the size is a characteristic of the allocated object, not of any pointer to it.

I was not expecting it to work because the void pointer is only given 2 bytes which is not enough for my 23 byte char array.

Indeed the two bytes you allocated are not enough to accommodate the 24 bytes of your string literal (don't forget to count the string terminator), but

  1. That's irrelevant, because you don't attempt to use the allocated space. Assigning to a pointer changes the value of the pointer itself, not of whatever data, if any, it points to.

  2. Even if you were modifying the pointed-to data, via strcpy(), for example, C does not guarantee that it would fail. Instead, such an attempt would produce undefined behavior, which could manifest in any way at all that is within the power of the program and C implementation. Sometimes that even takes the appearance of what the programmer wanted or supposed.

How did my void pointer exceed the size I initially requested?

It did not. You allocated two bytes, and recorded a pointer to their location in p. Then, you assigned the address of the first character of your string literal to p, replacing its previous value. The contents of the string literal are not copied. The program no longer having a pointer to the allocated two bytes, it has no way to access them or free them, but deallocating them requires calling free, so they remain allocated until the program terminates. This is called a "memory leak".

I should furthermore point out that there is a special consideration here involving string literals. These represent arrays, and in most contexts where an array-valued expression appears in C source code, the array is converted automatically to a pointer to its first element. A popular term for that is that arrays decay to pointers. This is why you end up assigning p to point to the first character of the array. The same would not apply if you were assigning, say, an int or double value to p, and your compiler indeed ought at least to warn in such cases.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157