I've been digging into memory allocation and pointers in C. I was under the impression that if you do not allocate enough memory for a value and then try to put that value in that memory cell, the program would either crash or behave incorrectly. But what I get is a seemingly correct output where I'd expect something else.
#include <stdio.h>
#include <stdlib.h>
int main()
{
// Here we intentionally allocate only 1 byte,
// even though an `int` takes up 4 bytes
int * address = malloc(1);
address[0] = 16777215; // this value surely takes more than 3 bytes. It cannot fit 1 byte.
address[1] = 1337; // just for demo, let's put a random other number in the next memory cell.
printf("%i\n", address[0]); // Prints 16777215. How?! Didn't we overwrite a part of the number?
return 0;
}
Why does this work? Does malloc
actually allocate more than the number of bytes that we pass to it?
EDIT
Thanks for the comments! But I wish to note that being able to write to unassigned memory is not the part that surprises me and it's not part of the question. I know that writing out of bounds is possible and it is "undefined behavior".
For me, the unexpected part is that the line address[1] = 1337;
does not in any way corrupt the int
value at address[0]
.
It seems that the explanations for this diverge, too.
@Mini suggests that the reason for this is that
malloc
actually allocates more than what's passed, because of cross-platform differences.@P__J__ in the comments says that
address[1]
for some reason points to the next sizeof(int) byte, not to the next byte. But I don't think I understand what controls this behavior then, becausemalloc
doesn't seem to know about what types we will put into the allocated blocks.
EDIT 2
So thanks to the comments, I believe I understand the program behavior now.
The answer lies in the pointer arithmetic. The program "knows" that an address
pointer is of type int
, and therefore adding 1
to it (or accessing via address[1]
) gives an address of the block that lies 4
(sizeof(int)
) bytes ahead.
And if we really wanted, we could move just one byte and really corrupt the value at address[0]
by coercing address
to char *
as described in this answer
Thanks to all and to @P__J__ and @Blastfurnace in particular!