8

I was trying to grasp the malloc function in C, and I wrote the following code:

int i;

int *arr = (int*)malloc(5*sizeof(int)); 

if(arr==NULL){

  printf("Failed to allocate memory for arr...\n");
  exit(1);

}

I thought this meant that only 5 elements could be added to the array. To test out if that was true, I added the following code:

arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
arr[4] = 5;
arr[5] = 6;
arr[6] = 7;
arr[7] = 8;
arr[8] = 9;

for(i=0;i<9;i++){

    printf("%d\n",arr[i]);

}

Surprisingly, that code compiled and ran perfectly. How was that possible?

jww
  • 97,681
  • 90
  • 411
  • 885
Nirav Bhatia
  • 1,003
  • 3
  • 13
  • 25
  • Once you've figured this out for yourself(based on the answers folks have given or otherwise), have a look at [buffer overruns](http://en.wikipedia.org/wiki/Buffer_overrun). Kind of relevant and interesting. – decimus phostle Jul 18 '12 at 23:06

4 Answers4

10

C doesn't enforce any array bounds checking, so while you requested space for 5 integers, you used more.

In fact you overwrote 4 memory locations that really weren't set aside for your specific purpose. Your program went past the area in memory that was set aside for your array, and started to store values in memory outside the allocated region.

The fact that this "worked" is just pure luck and not something to be dependent on. It may work the next 100 times, or it may fail the next time you try it, with most likely a "segmentation fault" message.

Defensive programming, like you did by sensibly checking the return value of malloc, being mindful that you are responsible for bounds checking, compiling code with high warning levels enabled, etc are some of your best defenses to guard against these sort of errors. Other tools, such as valgrind, lint type checkers can also help, but at the end it's up to you.

One of C's greatest strengths, its freedom to do all sorts of things, low and high-level, is also one of its greatest weaknesses IMO. If Java is a Volvo, C is perhaps more like a Ferrari with spotty breaks at times :)

Levon
  • 138,105
  • 33
  • 200
  • 191
  • 1
    Malloc allocates a chunk of memory which will be at least the size requested. It could be larger, depending on the malloc implementation. It does not clear the memory to zeros. You can access memory off the end of your array, and you can access memory off the end of the allocated chunk. You will get random "garbage". – webjprgm Jul 18 '12 at 22:51
  • 1
    @webjprgm Never actually thought about `malloc/calloc` allocating more memory than requested .. for "zeroing" out memory `calloc` would be appropriate. – Levon Jul 18 '12 at 22:54
  • Also note that if you continue the for loop indefinitely, it will likely cause a segfault when you reach the end of the allocated pages for your program. – webjprgm Jul 18 '12 at 22:57
  • 1
    Also, "that really weren't for you to use" isn't exactly true. Every memory address is for you to use as every process has its own virtual memory. You can't overwrite data from another program by accident as you don't have access to it. However, once you actually try to access the address at runtime and if there is no physical memory mapped to it, it'll result in a seg fault. – Femaref Jul 18 '12 at 22:58
  • @Femaref I see your point .. perhaps instead of "for you to use", "allocated for the particular purpose" would be a better phrase here, though I think conceptually the wording is clear. – Levon Jul 18 '12 at 23:00
  • Yes, it should be okay to word it like this in these circumstances. I just wanted to point out that there is a bit more going on behind the scenes. – Femaref Jul 18 '12 at 23:02
  • @Femaref No, you are right, it was informative (to me as well) and I also adjusted the language to reflect what you brought up. Thanks for the constructive/informative feedback. – Levon Jul 18 '12 at 23:03
0

C does not do bounds checking.

bisarch
  • 1,388
  • 15
  • 31
0

How was that possible?

You're writing past the end of the array. This doesn't cause the program to crash (immediately) as there is no bounds checking in C, though, if you write far enough, it will eventually cause a fault. At times you may be able to write hundreds of int values, and other times you may not be able to write any extra.

Community
  • 1
  • 1
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
0

Memory in your computer is basically laid out sequentially. You asked malloc to give you a small piece of that memory -- enough for 5 ints. There's definitely more memory available in your computer than it takes to allocate an array of length 5. so if you write to or read from arr[8], you're writing somewhere else in memory.

Usually, modern computers have so much memory that you're probably writing somewhere that isn't in use. But occasionally, you'll accidentally overwrite some other malloc'd data.

Note that sometimes your program will crash (as you expected). This is because you might try to write so far outside your allocated memory, that the address isn't valid any more. Your OS usually catches that and crashes your program for you.

Jack Edmonds
  • 31,931
  • 18
  • 65
  • 77