2

malloc and calloc have these signatures:

void* malloc( size_t size );
void* calloc( size_t num, size_t size );

They do basically the same thing. Both allocate a chunk of memory of the specified size and return a pointer to that chunk. The difference is that calloc initializes the whole memory to zeros. Actually, calloc could be implemented kind of like this:

void* calloc( size_t num, size_t size ) {
    void * ptr = malloc(num*size);
    if(!ptr) return NULL;
    return memset(ptr,0,num*size);
}

(I know that there are reasons to not implement it like this, but that's not the topic.)

Since they are so similar, what is the reason for their different signatures? When you call malloc you specify the number of bytes you want and when you're calling calloc you specify a block size and the number of blocks. I don't prefer one over the other, but it bothers me that they are different.

Imagine that you have written a piece of code with some mallocs, and then you realize that all of these allocations need to be zeroed. If they had the same signature it would mean that you only have to change the "m" to a "c".

Was there ever a reason for this design choice, or was it just a coincidence?

2 Answers 2

4

The C that was standardized had experienced one and a half decades of organic growth. Not everything has to make perfect sense. Indeed, many standardized functions do not make much sense, such as the inherently unsafe gets() function.

The allocations of calloc(n, sizeof(T)) and malloc(n * sizeof(T)) may allocate different amounts of memory depending on alignment restrictions of the system. This is not an issue on the x86 architecture, but may apply on other architectures.

2
  • What does alignment have to do with it? Only wrap-around seems potentially relevant. Oct 7, 2019 at 23:05
  • @Deduplicator I was operating under the mistaken assumption that the array allocated by calloc() would not be an object, and this difference would be relevant on platforms where objects must be aligned by their size, e.g. a 300-byte object to a 512-byte boundary. Alignment padding would change memory consumption. I am now convinced that the allocated memory is an object, so there cannot be a difference. (For example, glibc's malloc does not take alignment into account except when requested via valloc(), but glibc is not very portable. These differences don't matter on AMD64 architectures.)
    – amon
    Oct 8, 2019 at 20:55
2

If size_t is 32 bits, and pointers are 64 but, then they are not equivalent at all if size * nitems doesn’t fit in 32 bits.

6
  • 3
    I'm not sure whether this is genius language-lawyering or false. The largest size of an object is size_t. Your observation applies iff the memory allocated by malloc() is not an object (but just a memory region that may hold objects). The size of pointers is not immediately relevant as pointers may be much larger than total addressable memory (e.g. some architectures use weird function pointers, so normal pointers are made larger so that all pointers have the same size in C).
    – amon
    Nov 22, 2018 at 20:45
  • I always thought that anything the memory allocation functions could return counted as an "object", but this does ever so slightly shake me with the interesting doubt that maybe the memory region pointed to by calloc is not required to be considered a single "object" - if malloc and realloc always had to return an "object" but calloc was free of that requirement, then "legally" calloc would be allowed to allocate memory larger than size_t bytes (chars). But as far as I know the meaning of "object" in the C standard is meant to include the memory regions allocated by calloc too.
    – mtraceur
    Oct 7, 2019 at 20:53
  • 1
    Just checked, and I think this is it! From the last C89 standard draft, emphasis added: 4.10.3.1 The calloc function says "The calloc function allocates space for an array of nmemb objects, each of whose size is size.", while [40.10.3.3 The malloc function] says "The malloc function allocates space for an object whose size is specified by size and whose value is indeterminate. " ! And the realloc definition also talks about a singular object !!! So this was deliberate.
    – mtraceur
    Oct 7, 2019 at 21:00
  • @mtraceur Thank you for hunting down the correct place in the standard. This disproves my theories. Arrays are objects, so calloc() is not special.
    – amon
    Oct 8, 2019 at 20:45
  • @amon I'm not so sure - that's how I wanted to interpret it initially (because I want calloc to be limited to allocation sizes that fit in size_t), but unless I missed it, the C89 final draft never explicitly says that size_t can hold the size of any "object", and the way we get that idea is because it says that size_t must hold all values that sizeof can give, and sizeof must be able to give the size of any type that it can actually operate on. But while sizeof can get the size of array types, it cannot ever get the size of dynamically allocated regions of memory.
    – mtraceur
    Oct 9, 2019 at 19:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.