5

I am relatively new to C programming and having a hard time understanding the whole memory allocation issue.

Let's say, I do:

int *n = malloc(sizeof(char));
// (assuming malloc doesn't return NULL of course)

That provides a Pointer to int, but I didn't allocate enough memory for an int. Why does it work then? I could even cast it to int explicitly and it wouldn't bother gcc. I am aware of C compilers being very minimalist, but even if I assign a value to *n, which doesn't fit in a char, like:

*n = 300;

... and print it out afterwards:

printf("%d", *n);

... it works perfectly fine, although now at the latest I'd expect some error like a segmentation fault.

I mean, sizeof(char) is 1 and sizeof(int) is 4 on my machine. Hence 3 bytes are written to some place in memory which hasn't been allocated properly.

Does it work just because it doesn't leave the stack?

Could somebody please point me to a place where I might find enlightenment concerning that stuff?

  • 4
    If you get a segfault, consider yourself lucky. No segfault doesn't mean your code is fine, it just means you're screwed because you get no indication that it is wrong... until you switch compilers, compiler versions, architecture, etc. and stuff blows up or gives wrong results. Sadly, it's quite easy to get that kind. –  Oct 23 '11 at 19:12
  • 1
    Note that `sizeof (char)` is 1 by definition (though this isn't particularly relevant to your question). `sizeof` yields a result that's a number of bytes, but a byte is defined to be the size of a `char` (which is usually 8 bits, but can be more). – Keith Thompson Oct 23 '11 at 20:48

2 Answers2

7

That provides a Pointer to int, but I didn't allocate enough memory for an int. Why does it work then?

The return value from malloc is void*, the language allows this to be implicitly converted to any pointer type, in this case int*. Compilers don't typically include behavior to check that what you passed to malloc met a specific size requirement, in real-world code that can be very difficult (when non-constant sizes not known at compile time are passed to malloc). As you said, C compiler are usually rather minimalist. There are such things as "static analysis" tools which can analyze code to try to find these bugs, but that's a whole different class of tool than a compiler.

... it works perfectly fine, although now at the latest I'd expect some error like a segmentation fault. I mean, sizeof(char) is 1 and sizeof(int) is 4 on my machine. Hence 3 bytes are written to some place in memory which hasn't been allocated properly.

Writing beyond the bounds of allocated memory is what is called "undefined behavior". That means that a compliant compiler can do whatever it wants when that happens. Sometimes it will crash, sometimes it can write over some other variable in your program, sometimes nothing will happen, and sometimes nothing will seem to happen and your program will crash at a later date.

In this particular case what is happening is that most implementations of malloc allocate a minimum of 16 bytes (or more or less, like 8 or 32) even if you ask for less. So when you overwrite your single allocated byte you're writing into "extra" memory that was not used for anything. It is highly not recommended that you rely on that behavior in any real program.

Does it work just because it doesn't leave the stack?

The stack has nothing to do with this particular situation.

Could somebody please point me to a place where I might find enlightenment concerning that stuff?

Any good C book will have information of this type, take a look here: The Definitive C Book Guide and List

Community
  • 1
  • 1
SoapBox
  • 20,457
  • 3
  • 51
  • 87
2

Generally a 32bit machine will allocate new memory on a 32bit boundary - it makes memory access faster.
So it has allocated a byte, but the next 3bytes are unused

Don't rely on this!

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • Actually, it has most probably allocated 8 usable bytes (sufficient to contain two pointers to link the memory chunk into a linked list when it is freed, the allocator doesn't care about memory chunks that are not freed). – ninjalj Oct 23 '11 at 21:57