0

I am expecting the following snippet to allocate memory for five members using calloc.

$ cat calloc.c
// C program to demonstrate the use of calloc() 
// and malloc() 
#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
  int *arr; 
  arr = (int *)calloc(5, sizeof(int)); 
  printf("%x\n", *arr);
  printf("%x\n", *(arr+1));
  printf("%x\n", *(arr+2));
  printf("%x\n", *(arr+3));
  printf("%x\n", *(arr+4));
  printf("%x\n", *(arr+5));
  printf("%x\n", *(arr+6));
  // Deallocates memory previously allocated by calloc() function 
  free(arr); 

  return(0); 
} 

But it seems to be allocating more than five; it is allocating six members, why?

./a.out 
0
0
0
0
0
0
411
Steve Summit
  • 45,437
  • 7
  • 70
  • 103
Milan
  • 1,447
  • 5
  • 19
  • 27
  • 4
    accessing data outside the bounds of your object is undefined behavior. Do not rely on it. – Christian Gibbons Sep 13 '19 at 22:36
  • There might be a minimum size it allocates. But you are allowed to access **5** elements - what you allocated. If you are thinking the sixth element is yours, your code demonstrates *no proof* of that. Possible [duplicate question](https://stackoverflow.com/questions/13064850/malloc-vs-custom-allocator-malloc-has-a-lot-of-overhead-why). – Weather Vane Sep 13 '19 at 22:38
  • 1
    Side note: if you get tired of typing things like `*(arr+3)`, you can just use `arr[3]`. It's 100% completely and totally equivalent. – Steve Summit Sep 13 '19 at 22:41
  • 4
    Possible duplicate of [What happens if I set a value outside of the memory allocated with calloc?](https://stackoverflow.com/q/55692816/608639), [No out of bounds error](https://stackoverflow.com/q/9137157/608639), [How dangerous is it to access an array out of bounds?](https://stackoverflow.com/q/15646973/608639), [Malloc and array index confusion in C](https://stackoverflow.com/q/11551472/608639), etc. – jww Sep 13 '19 at 23:51

4 Answers4

5

Allocating memory isn't like buying lollipops. Allocating memory is more like buying land.

If you buy five lollipops and you try to eat the sixth one, this obviously doesn't work — it's pretty nonsensical to even talk about "trying to eat the sixth one".

But if you buy a ten foot by fifty foot plot of land, and you start putting up 10x10 foot buildings, and after building five of them (completely occupying your land), you build a sixth one encroaching over onto your neighbor's land, your neighbor might not notice right away, so you might get away with it. (For a little while, anyway. There's bound to be trouble in the end.)

Similarly, if you allocate an array of size 5 and then try to access a nonexistent 6th element, there's no law of nature that prevents it the way there was when you tried to eat the nonexistent 6th lollipop. In C you don't generally get an error message about out-of-bound array access, so you might get code that seems to work, even though it's doing something totally unacceptable, like encroaching on a neighbor's land.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • I really like your land analogy. This can even be expanded to saying that, when you build out-of-bounds, it may be that you are wrecking your neighbors garage that happens to be standing there and he won't find out until he tries to use his car (silent data corruption), or your own work goes horribly wrong because your land is located at a shore, and the "land" that you are trying to build on is actually open ocean (no memory present, segfault). I absolutely have to remember that analogy! – cmaster - reinstate monica Sep 13 '19 at 23:03
2

First of all, let's get something clear: for all purposes, *(a+x) is the same as a[x].

C has free memory access. If you do arr[1000], you will still get a value printed, or the program will crash with a segmentation fault. This is the classic case of undefined behaviour. The compiler cannot know whether the code you wrote is wrong or not, so it cannot throw an error. Instead, the C standard says this is undefined behaviour. What this means is that you are accessing memory you shouldn't.

You, as the programmer, are responsible to check that you don't go out of bounds of the array and not the compiler. Also, calloc initializes all elements with 0. Why do you think you got 411? Try running it again, you will probably get a different value. That memory you are accessing at a[5] is not allocated for the array. Instead, you are going out of the bounds of the array. That memory could have very well been allocated to something else. If it was allocated to another program, you would get a segmentation fault when you run the program.

selbie
  • 100,020
  • 15
  • 103
  • 173
DarkAtom
  • 2,589
  • 1
  • 11
  • 27
  • whole point of confusion for me is when a[5] gives me 0, I would have been satisfied if its give me something garbase(as in case of a[6]) and this remains the same every time I run it. – Milan Sep 13 '19 at 22:48
  • Restart your computer and try again, maybe memory addresses change this time. `a[5]` just happens to be 0, it is just a coincidence and was not set like that by `calloc` – DarkAtom Sep 13 '19 at 22:50
  • @Milan This is one of the more confusing aspects of undefined behavior. We say it will do something random, we say it can do *anything*, but frequently, as here, it does something completely predictable and almost reasonable-looking. This makes you search for the reason, it may make you wonder if you were misinformed about the original code being illegal or not working. Sometimes, though, there's no decent explanation for the seemingly-predictable behavior, other than "undefined behavior means *anything* can happen, and that includes doing something reasonable-looking." – Steve Summit Sep 13 '19 at 22:57
  • @Milan Undefined behavior means that it is not guaranteed to work. But this does not mean that is guaranteed not to work. – Steve Summit Sep 13 '19 at 22:59
  • @Steve Summit if you want to comply with any kind of standard you must not have undefined behavior in your code. This is mainly because other people might try to compile your code with a different compiler or even a different version of the same compiler and get a different result. While sometimes you can get away with it, it is best to not do it unless you are specifically looking for that kind of fun. – DarkAtom Sep 13 '19 at 23:02
  • Well , I am not really sure about this, but tried it running from two different setups and still the a[5] prints 0. is there still any logical reason to it ? – Milan Sep 13 '19 at 23:11
  • @Milan as long as the standard doesn't say it you cannot count on it. Look up in the compiler documentation, maybe it's an extension or something. – DarkAtom Sep 13 '19 at 23:14
  • @Milan There is probably a logical reason for it, but (a) it can only be found by inspecting the source code for your machine's version of `calloc`, and (b) it isn't likely to be very interesting in the end. Also (c) it won't be anything you can make use of, because it' won't be anything you can depend on. So while I understand that your curiosity is aroused here (and, most of the time, curiosity is a good thing), in this case, I'm afraid you're likely to be disappointed. – Steve Summit Sep 13 '19 at 23:18
1

It hasn't allocated memory more than 5. It has allocated 5 members and initialized them with 0. When you access to outside of the allocated memory, it may be written anything into it, and not certainly a non zero value.

mrazimi
  • 337
  • 1
  • 3
  • 12
0

Every time a malloc, calloc or realloc is called, the memory allocation is done from heap area.

Run Time/ Dynamic allocation -> Heap

Static/Compile Time-> Stack

// C program to demonstrate the use of calloc() 
// and malloc() 
#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
 int *arr; 
 arr = (int *)calloc(5, sizeof(int)); // dynamically allocate memory for 5 element each of size of integer variables and intializes all with 0.
  printf("%x\n", *arr);//array name is a constant pointer(points to base address of the array
 printf("%x\n", *(arr+1));
 printf("%x\n", *(arr+2));
 printf("%x\n", *(arr+3));
 printf("%x\n", *(arr+4));
 printf("%x\n", *(arr+5));
 printf("%x\n", *(arr+6));// you are accessing memory which is not the part of your pointer variable. There are chances that this is the part of the some other program or variable.
 // Deallocates memory previously allocated by calloc() function 
 free(arr); 
 arr=NULL;//always assign pointer to null to avoid any dangling pointer situation

 return(0); 
}