43

Why does calloc take two arguments instead of one like malloc?

Specifically, since there is no difference between (or is there?) between the following expressions:

calloc (a, b);
calloc (b, a);
calloc (a * b, 1);
calloc (1, a * b);

why not just accept the total number of bytes to allocate? What is the rationale behind this interface? And why does this not apply to malloc?

sanjoyd
  • 3,260
  • 2
  • 16
  • 22

5 Answers5

13

I heard two [mutually exclusive] explanations for why it has two arguments:

  1. calloc takes the responsibility for checking for overflow on multiplication. If the total size of the requested block is too large (like overflows size_t), calloc returns null pointer to indicate failure. With malloc you have to watch for overflow yourself, which many people simply forget to do. (Although the history of standard library knows examples of calloc implementations that ignored overflow, and thus worked incorrectly).

  2. calloc actually allows one to allocate bigger blocks of memory than the range of type size_t, i.e. calloc might be capable of performing the proper non-overflowing large multiplication of its arguments and allocate the block of the resultant size. For this reason, since calloc uses two arguments of type size_t, it can allocate bigger blocks than malloc will ever be able to (since malloc takes only one argument of type size_t).

I always believed that the first explanation is the right one. However, after reading some posts here on SO I have my doubts.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 2
    -1, technically you can't allocate more equal and about than max value in `size_t` because it is system border, and in other point this will not make any sense. On 32-bit machines you will trying allocate all possible address space, this is impossible, on 64-bit machines this fails too. – Svisstack Nov 03 '10 at 03:16
  • 1
    (1) certainly sounds more plausible to me as a rationale. (2) could be a (perhaps unintended) consequence of the standard, though. Does it make a lot of sense to be able to allocate an `int[SIZE_MAX]` through calloc, even though you certainly can't declare one as a member of a struct (because `sizeof` wouldn't be able to measure it)? – Steve Jessop Nov 03 '10 at 03:18
  • 3
    @Svisstack: that's exactly what I was just looking at in the standard, I think AndreyT raises an interesting point. `size_t` is defined as the type returned by `sizeof`. *Not* actually as the maximum size of an object. There are objects to which you cannot apply `sizeof`, specifically dynamically allocated arrays. I don't think the phrase "system border" appears in the standard. I think you have to do better than "it fails on my 64 bit system" if you want to demonstrate that the setup described in (2) is actually forbidden by the standard. – Steve Jessop Nov 03 '10 at 03:20
  • @Steve Jessop: you are wrong with @AndreyT: this function only check integer overflow not more (without malloc), theory about allocate more than malloc is a virtual because in this function body is `malloc(size)`. EDIT: see source code of `calloc` – Svisstack Nov 03 '10 at 03:26
  • In my opinion, if `sizeof (size_t) >= sizeof (void *)`; *then* the maximum object size is limited by `size_t` (since there would be no way to access such an object). – sanjoyd Nov 03 '10 at 03:28
  • 1
    @Svisstack: What on earth do you mean, "see source code" for calloc? There are dozens or hundreds of implementations of calloc. Which one do you think is more important than the standard in defining what is permitted for a conforming implementation of the C language? There is no requirement in the standard that `calloc` must call `malloc`. AndreyT is not talking about what one particular implementation does, or even about what *sensible* implementations do. He's talking about what the standard might permit. – Steve Jessop Nov 03 '10 at 03:32
  • @Steve Jessop: oh **** where are you living, propably in your virtual word of C where are all functions is implemented what you want, fact is `calloc` is implemented in this way and OP don't need new your calloc function. At the second way OP asking practical things of `calloc`. I think `calloc` can not use `malloc` function but only if `calloc` is writed by you but in normal world any good programmer will be not rewriting common memory allocation function to allocate some BYTES more about 3,998GB where 4GB is a address space size on 32bit machines. I think you are don't know what you talking. – Svisstack Nov 03 '10 at 03:37
  • 3
    @Svisstack: I'm talking about the C standard. I really do know what I'm talking about when it comes to the difference between a standard, and particular implementations of the standard. It's not at all about how I "want" `calloc` to be implemented - I'd prefer it if the weird thing AndreT raises was forbidden by the standard. I just don't see where it is. If all you're saying is that AndreyT's option (2) doesn't apply to your PC, then well done, you are correct. But the question is explicitly about the rationale for the C standard, not about your PC. – Steve Jessop Nov 03 '10 at 03:42
  • @Steve Jessop: i don't trying it on my machine because THIS NOT MAKE ANY SENSE when `calloc` is calling `malloc`. I don't know what you have on mind when you talking about more blocs allocation by `calloc` than `malloc`. I think you can't get fail on self because you have 50k rep and dont have right. – Svisstack Nov 03 '10 at 03:45
  • @Svisstack: Sorry, but what you said make no sense. `size_t` is a language-level type. It has no connection to the "system" whatsoever. And while it might be chosen in agreement with system's limitations, it doesn't have to be. In fact, in many historical cases it was completely independent from the system. – AnT stands with Russia Nov 03 '10 at 04:01
  • 3
    @Svisstack The C standard never said it's for use only with standard machines, someone could very well write a C compiler for their super-computer center in which very large memory allocations actually do make sense. – Graphics Noob Nov 03 '10 at 04:03
  • 1
    @Svisstack: You suggestion to "see source code of `calloc`" is ridiculous at best. `calloc` has no specific "source code" in the sense you imply. `calloc` is a standard function. It has a specification, and that where it stops. You can look at as many implementations of `calloc` as you want, but that would mean absolutely nothing. – AnT stands with Russia Nov 03 '10 at 04:03
  • @Svisstack: (After reading your last comment). Sorry, but you apparently have absolutely no idea of what C language is. What you are saying is just... well, a bunch of typical misconceptions characteristic of a person who's just making their first steps in understanding the concept of standardized language. – AnT stands with Russia Nov 03 '10 at 04:07
  • 1
    I think it was designed with 2 arguments to allow for optimized clearing of memory. There could have been code like "if size==32 bytes, then do this magic block clearing instruction". So more like an accident of history than any bigger rationale. :-) – Prof. Falken Dec 30 '12 at 09:40
6

I believe that malloc is guaranteed to return an area of memory which is aligned according to the coarsest requirement that would be compatible with the size indicated by the second argument. For example, if the system requires alignment of 2 and 4-byte integers, and the second argument is 10, the returned pointer must be aligned on a two-byte boundary; if the second argument were 12, the pointer would be aligned on a four-byte boundary. I suspect that in practice many systems will align all returned pointers to the largest possibly-required boundary, regardless of size, but I don't think it's required except for calloc.

supercat
  • 77,689
  • 9
  • 166
  • 211
2

calloc(x,y) is a equivalent to malloc(x*y)

But calloc doing additional (setting values to 0 with) memset(block, 0, x*y)

This function is only for pretty way pass the size of element and number of elements, when in malloc you must multiply this values to get needed number of bytes, this function check integer overflow too in multiplication.

For example if you want allocate memory for 12 integers and you want do something with this integers and you must have setted her values to 0, use calloc(12, sizeof(int))

But if you want allocate some memory block (256 bytes) to copy in future to it some string then memset is a not usable for you, then better use is malloc(sizeof(char) * 256) or for example malloc(sizeof(wchar_t) * 256)


void *
calloc (size_t nmemb, size_t lsize)
{
  void *ptr;
  struct __meminfo *info;
  size_t size = lsize * nmemb;

  /* if size overflow occurs, then set errno to ENOMEM and return NULL */
  if (nmemb && lsize != (size / nmemb))
    {
      set_errno (ENOMEM);
      return NULL;
    }

  /* allocate memory */
  ptr = malloc (size);

  /* get pointer to info part of chunk */
  info = __mem2info (ptr);

  /* fill memory with zeros and set __MEM_CALLOC flag */
  memset (ptr, 0, info->size);
  info->flags |= __MEM_CALLOC;

  return ptr;                   /* happy end */
}
Svisstack
  • 16,203
  • 6
  • 66
  • 100
  • 1
    Pet peeve: sizeof(char) is 1 by definition. – Ben Jackson Nov 03 '10 at 03:14
  • Be careful with integer overflow on the multiplication. – jamesdlin Nov 03 '10 at 03:17
  • 2
    *This function is only for pretty way pass the size of element and number of elements, when in malloc you must multiply this values to get needed number of bytes.* -> So why don't we have a similar interface to `malloc`? – sanjoyd Nov 03 '10 at 03:17
  • @theDigtialEngel: this is not smillar interface, this function is a shortcut for delarating array of some vectors when you must have zeroed all values. At other point, why not? – Svisstack Nov 03 '10 at 03:21
  • @Svisstack: The question is not, "what is the difference between malloc and calloc?". The question is, "what difference, if any, between malloc and calloc accounts for their different parameters?" – Steve Jessop Nov 03 '10 at 03:24
  • 1
    The funny thing is that the interface to `calloc` (I'm talking about the array of vectors part, not the memory zeroing part) is not even a shortcut; `calloc (a, b)` and `calloc (a * b)` have the same number of characters. In fact, in the first case, allocating just one element (`calloc (a, 1)`) is unnecessarily complicated. – sanjoyd Nov 03 '10 at 03:24
1

The only notable difference is that calloc is required to initialize the allocated space to zeroes while there is no such guarantee with malloc. Otherwise, I guess there are two different functions just for historical reasons.

casablanca
  • 69,683
  • 7
  • 133
  • 150
0

Everything is just bytes is a relatively new (ie c/Unix era) invention - on a lot of other architecture things were fixed sized records.

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263