2

I've spent quite a moment today trying to figure out why a super-simple C function, which reads a text file, doesn't work. I was able to make it work by swapping parameters in calloc function:

Instead of:

calloc(1, size_of_the_memory_to_allocate)

I did:

calloc(size_of_the_memory_to_allocate, 1)

So instead of 1 element of size 20, I did 20 of size 1.

calloc(size, 1)

Is there any difference in the allocation?

EDIT2: I guess I was not clear enough with the question, or it was misunderstood. The question was: "Why allocating pointer to pointer using calloc requires swapping arguments?". It wasn't about debugging the code, nor have I asked anyone to run it, it was about how calloc works. The answer made by @chqrlie is exactly what I was looking for. I guess I have made a mistake of adding any code to the question, and readers concentrated on it, rather than on what I have asked for. So, here's an edit, and now chqrlie's answer fit perfectly. If this still is something that won't help other users, let's just delete the question and be done with it.

Krystian
  • 3,193
  • 2
  • 33
  • 71
  • 1
    "buffer was not properly allocated". This is a bit too vague. What exactly have you observed? – n. m. could be an AI Jan 30 '16 at 19:01
  • 3
    There must be another problem which you have not identified, changing the program made the effect of some other UB benign. – Weather Vane Jan 30 '16 at 19:03
  • 4
    Provide a [mcve]. For instance(!): what is `size`? And what do you mean with "regular pointer"? `calloc` does not even take a pointer argument. – too honest for this site Jan 30 '16 at 19:11
  • *"`buffer` was not properly allocated and `fread` didn't write any data to it"*. How do you know? Your code has not checked the result of either `calloc` or `fread`. Did you even check the return value from `fopen`? – Weather Vane Jan 30 '16 at 19:14
  • @Olaf I thought the size was obvious, I've concentrated on others parts - now question was edited with the full function body, sorry for not pasting it right away. – Krystian Jan 30 '16 at 19:26
  • @WeatherVane I was debugging the code. – Krystian Jan 30 '16 at 19:26
  • 1
    A lot of close reasons stem from "I thought ..." – too honest for this site Jan 30 '16 at 19:40
  • I don't see any fault, but why use `calloc` since you know all the memory will be written to from file? – Weather Vane Jan 30 '16 at 19:49
  • @WeatherVane can `calloc` be omitted? I'm not sure I understand. – Krystian Jan 30 '16 at 20:04
  • 3
    I meant just use `malloc`. There is usually no need to waste resources zeoing a buffer that will be written to anyway. – Weather Vane Jan 30 '16 at 20:04
  • @WeatherVane right! point taken. – Krystian Jan 30 '16 at 20:09
  • With regard to @Olaf's comment, "complete" means not just the complete *function*, but a complete *program* that somebody can compile and run. The bug may well be in a different part of the code. – Nate Eldredge Jan 30 '16 at 22:01
  • I'm voting to reopen because the OP question is a real question. If his C library behaves differently for `calloc(1, size)` and `calloc(size, 1)`, There is a bug that is worth investigating. What environment are you compiling in, which OS, compiler, C library? – chqrlie Jan 31 '16 at 09:50
  • @chqrlie This code is part of an iOS app, compiled using xcode 7.2. Weather Vane and Nate Eldredge are right, it's got to be something else, because simply taking the same code into a "fresh" environment works just fine, and the project is far to complex for me to extract the part that will result in an error. Thus the rewording of the question, and my satisfaction with your answer. – Krystian Jan 31 '16 at 13:02
  • @Krystian: I looked at the source code for Apple's libmalloc available here: http://opensource.apple.com/release/os-x-1011/ and the implementation does handle overflow correctly using 128 bit arithmetic. `size` and `nmemb` are not handled completely symmetrically, but this would not explain your observation. Looking back, only early OS/X 10.4 (Tiger) C libraries ignored the potential overflow in `calloc`. Unless you can reproduce the bug, I am unable to investigate any further. – chqrlie Jan 31 '16 at 14:33
  • @chqrlie thank you very much for your support. Currently I just had to leave it the way I made it work, I was just wondering how was that possible. I will probably get back to it on monday and try again. – Krystian Jan 31 '16 at 17:47
  • Related: [Is `calloc(4, 6)` the same as `calloc(6, 4)`?](https://stackoverflow.com/questions/501839/is-calloc4-6-the-same-as-calloc6-4) – ggorlen May 11 '23 at 01:15

1 Answers1

5

The prototypes for calloc and fread are:

void *calloc(size_t nmemb, size_t size);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

The order of arguments is indeed inconsistent between these standard C library functions. It is unfortunate but it has been like this for close to 40 years and cannot be changed now.

Note that if you swap the arguments in calloc, you should get exactly the same behavior, but it is not the case for fread that returns the number of elements completely read.

The behavior you describe in your updated question is highly surprising. Either there is something you are not telling us, or your C library implements a non standard constraint in calloc() that ends up backfiring into a bug.

Note that calloc(nmemb, size) cannot just call malloc(nmemb * size) because of potential arithmetic overflow, which in the case of size_t arguments is defined in the standard. For example calloc(-1, -1) must fail, but instead would return malloc(1) if naively calling malloc(nmemb * size). The test for this overflow might be buggy in such a way as to fail for calloc(1, size) and not for calloc(size, 1) with a large size.

chqrlie
  • 131,814
  • 10
  • 121
  • 189