-1

Actually I expected a warning / an error here but it compiles without any problems. Why is it possible to call a calloc-function with 0 objects as first argument? And why does it allocate memory for this?

int* p_integer=calloc(0, sizeof(int));

if(!p_integer){
    exit(EXIT_FAILURE); 
}

//prints 4 
printf("size *p_integer: %zu\n", sizeof(*p_integer));

OK, some additions:

void* calloc( size_t num, size_t size );


Allocates memory for an array of num objects of size and initializes all bytes in the 
allocated storage to zero.

If allocation succeeds, returns a pointer to the lowest (first) byte in the allocated 
memory block that is suitably aligned for any object type.

If size is zero, the behavior is implementation defined (null pointer may be returned, 
or some non-null pointer may be returned that may not be used to access storage) 

https://en.cppreference.com/w/c/memory/calloc

How to understand that? In my case is the size (second parameter) not zero, right? So there is no explanation for the case if the first parameter == zero. Or do I have to calculate 0*sizeof(int) == 0 (size of requested memory block). Which "size" do they mean?

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • 4
    Since `p_integer` is of type `int*`, `sizeof(*p_integer)` is the same as `sizeof(int)`. Setting `p_integer = NULL;` doesn't change the *size* of `p_integer`. – David Schwartz Mar 20 '20 at 22:32
  • 1
    `malloc(0)` or `calloc(0, ...);` may return a `NULL` pointer or a non-NULL pointer. In both cases: No memory may be used and `free()` on the returned pointer is a valid operation. – Ctx Mar 20 '20 at 22:36
  • So the program should exit after p_integer=NULL; ? But it doesn't. –  Mar 20 '20 at 22:39
  • The compiler is not required to issue a warning for this. And this may be interesting to read: https://stackoverflow.com/questions/1073157/zero-size-malloc – Jabberwocky Mar 20 '20 at 22:44
  • _So the program should exit after p_integer=NULL_: it's implementation dependent. – Jabberwocky Mar 20 '20 at 22:45
  • It may return a non-NULL pointer. Was it null? – jarmod Mar 20 '20 at 22:46
  • I thought that the size is NOT zero. But it IS zero. Because the size will be calculated as 0*sizeof(int)! ;-) –  Mar 20 '20 at 22:46
  • The **NOTES** section of the *cppreference.com* page seems to explain why we have it. – David C. Rankin Mar 21 '20 at 00:54

3 Answers3

1

Why is it possible to call a calloc-function with 0 objects as first argument? (OP)

It is possible because the C spec for the library says it is allowed. Yet memory allocations of 0 are an edge case that results in implementation-defined behavior.

C17/18 was recently updated in this area to:

If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned to indicate an error, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object. C17dr § 7.22.3 1


And why does it allocate memory for this? (OP)

There is no evidence that any memory was allocated, just that a non-NULL pointer was returned for OP. It can't be used to reference any memory.

do I have to calculate 0*sizeof(int) == 0 (size of requested memory block). Which "size" do they mean?

The "size" is the product (without size_t range limitation). The size of an object is never 0 including sizeof(int), so only the n needs testing. With calloc(n, sz), where both are variables, I would test with if (n == 0 || sz == 0) rather than perform multiplication which brings in overflow issues.


To avoid this implementation defined behavior, test arguments first. Example:

int *p = (n > 0) ? calloc(n, sizeof *p) : malloc(1);
if (p == NULL) Oops();
...
free(p);

Alternatively, to account for implementation defined behavior, perhaps not error on calloc(0, sizeof *p) returning NULL.

int *p = calloc(n, sizeof *p);
if (p == NULL && n > 0) Oops();
...
free(p);
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

[This answer addresses the reason we would want calloc and malloc to provide zero bytes of memory when requested. It does not address what the C standard says about it.]

Consider writing a program that examines some input and perhaps categorizes various things, making lists of data in category C1, C2, and so on. Later, the software will process all the data for C1, then all the data for C2, and so on.

Consider which is simpler and shorter:

  • The program allocates space for N list items and processes N list items, and this code works whether N is zero or positive.
  • The program must explicitly test N and use different code paths depending on whether N is zero or positive.

The former choice is simpler, shorter, and cleaner. Generally, it offers less opportunity for bugs. When software must have different paths based on whether N is zero or positive, there is a chance a programmer might overlook the zero case, resulting in a bug.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
0

zero sized malloc, calloc is 100% OK. free is OK

sizeof of the p_integer or *p_integer is not using dereferencing the pointer - it is 100% OK

you can assign any value to the p_integer - but if malloc or calloc returns valid not NULL pointer it will result in the potential memory leak;

0___________
  • 60,014
  • 4
  • 34
  • 74