I was writing a code using malloc for something and then faced a issue so i wrote a test code which actually sums up the whole confusion which is below::
# include <stdio.h>
# include <stdlib.h>
# include <error.h>
int main()
{
int *p = NULL;
void *t = NULL;
unsigned short *d = NULL;
t = malloc(2);
if(t == NULL) perror("\n ERROR:");
printf("\nSHORT:%d\n",sizeof(short));
d =t;
(*d) = 65536;
p = t;
*p = 65536;
printf("\nP:%p: D:%p:\n",p,d);
printf("\nVAL_P:%d ## VAL_D:%d\n",(*p),(*d));
return 0;
}
Output:: abhi@ubuntu:~/Desktop/ad/A1/CC$ ./test
SHORT:2
P:0x9512008: D:0x9512008:
VAL_P:65536 ## VAL_D:0
I am allocating 2 bytes of memory using malloc. Malloc which returns a void * pointer is stored in a void* pointer 't'.
Then after that 2 pointers are declared p - integer type and d - of short type. then i assigned t to both of them*(p =t and d=t)* that means both d & p are pointing to same mem location on heap.
on trying to save 65536(2^16) to (*d) i get warning that large int value is truncated which is as expected. Now i again saved 65536(2^16) to (*p) which did not caused any warning.
*On printing both (*p) and (d) i got different values (though each correct for there own defined pointer type).
My question are:
Though i have allocated 2 bytes(i.e 16 bits) of heap mem using malloc how am i able to save 65536 in those two bytes(by using (p) which is a pointer of integer type).?? i have a feeling that the cause of this is automatic type converion of void to int* pointer (in p =t) so is it that assigning t to p leads to access to memory regions outside of what is allocated through malloc . ??.
Even though all this is happening how the hell derefrencing the same memory region through (*p) and (*d) prints two different answers( though this can also be explained if what i am thinking the cause in question 1).
Can somebody put some light on this, it will be really appreciated..and also if some one can explain the reasons behind this..
Many thanks
Answering your second question first:
The explanation is the fact that an int
is generally 4 bytes, and the most significant bytes may be stored in the first two positions. A short
, which is only 2 bytes, also stores its data in the first two positions. Clearly, then, storing 65536
in an int
and a short
, but pointing at the same memory location, will cause the data to be stored offset by two bytes for the int
in relation to the short
, with the two least significant bytes of the int
corresponding to the storage for the short
.
Therefore, when the compiler prints *d
, it interprets this as a short
and looks at the area corresponding to storage for a short
, which is not where the compiler previously stored the 65536
when *p
was written. Note that writing *p = 65536;
overwrote the previous *d = 65536;
, populating the two least significant bytes with 0
.
Regarding the first question: The compiler does not store the 65536
for *p
within 2 bytes. It simply goes outside the bounds of the memory you've allocated - which is likely to cause a bug at some point.
In C there is no protection at all for writing out of bounds of an allocation. Just don't do it, anything can happen. Here it seems to work for you because by some coincidence the space behind the two bytes you allocated isn't used for something else.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With