Reputation:
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?
Upvotes: 0
Views: 2989
Reputation: 154169
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);
Upvotes: 2
Reputation: 223795
[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 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.
Upvotes: 2
Reputation: 67835
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;
Upvotes: 0