Struggling to use calloc and realloc to initialize arrays in C Struggling to use calloc and realloc to initialize arrays in C unix unix

Struggling to use calloc and realloc to initialize arrays in C


realloc takes allocations sizes in bytes, not array elements, so you need to multiply by sizeof(int) like this

input = (int*)realloc(NULL,(argc) * sizeof(int)); output = (int*)calloc(calc, sizeof(int));

also this doesnt work

input = (int*)realloc(NULL,(argc) * sizeof(int)); ...input[argc] = 0;

If input is allocated to hold argc ints, then the largest permitted index into input is input[argc-1]. It isn't clear to me whether you are allocating too few items, or that input[argc] is in error.


Edit:Might I suggest this as an alternate formulation. if we set the last slot in the input array to 0 before we parse the inputs, then we don't care whether the number of inputs is even or odd.

int   calc = argc/2; // actually (argc-1+1)/2int * input = (int *)realloc(NULL, (calc*2) * sizeof(int));int * ouput = (int *)calloc(calc, sizeof(int));input[calc*2 - 1] = 0; // in case we run out of inputsfor (int j = 1; j < argc; ++j){   input[j-1] = atoi(argv[j]);}


Since this is homework, I will make some general comments, and I hope that will not only help you in solving your problem, but also improve your programming style.

Your code contains:

 if(size == 1 && size % 2 != 0)     size++;

If size is 1, size % 2 is going to be 1 too, and therefore your second check is always true. The effect of the two lines is as if you had written:

if (size == 1)    size = 2;

I doubt if that is what you want.

Given the problem statement, your input variable will store n or n+1 elements, where n is the number of numbers you want to add, and is equal to argc-1.

In C, integer division truncates, so 1/2 is 0, 5/2 is 2, etc. Mathematically, 5/2 is 2.5 of course. In the statements below, I distinguish between "C" and true mathematical dvision by writing // for the latter.

Now, for your output array, you want n//2 elements if n is even, and (n+1)//2 elements if n is odd. Because of integer division property mentioned above, you can verify that your output array will always contain (n+1)/2 elements.

If you don't care about wasting one element worth of space, for your input, you can always allocate n+1 elements, and then set the n+1th element to zero before you start reading numbers from the command-line arguments. This has the following advantages:

  • No need to worry about even or odd number of numbers in the rest of your program,
  • You don't need to calloc(): you just set the last element to zero. The rest of the elements are going to be written to, and the last element that you set to zero will be overwritten if you have even number of elements.

Now, about your realloc() call:

input = (int*)realloc(NULL,(argc));

This has the following "problems":

  • realloc(NULL, size) is equivalent to malloc(size), so you should replace your realloc() with malloc().
  • You don't need to cast the return value from malloc(), calloc(), and realloc(). In fact, casting may hide errors from failing to include stdlib.h.
  • You need argc times sizeof(int) bytes, not argc. The two are going to be equal only if sizeof(int) is 1.
  • Given a pointer T *p;, I find it easier to write malloc() calls as p = malloc(n * sizeof *p);—this is simpler to write, easier to read, and does not depend on the type of p.

So, making the above changes, you get:

size_t n = argc - 1; /* number of inputs */input = malloc((n+1) * sizeof *input);

atoi() does no error checking: if you have learned about strtol(), you should use that.

When you are adding the numbers together, you can do:

count := 0while count < n:    output[count/2] := input[count] + input[count+1]    count := count + 2


Beware of sizes in malloc, calloc, and realloc. You need to multiply by the size of the thing pointed to, so

  input  = realloc(NULL, argc * sizeof(*input));   output = calloc(calc, sizeof(*output));

This code is superior to alternatives in two ways:

  1. The size computation remains correct even if the type of input or output changes (say from int to long on a 64-bit machine).

  2. There are no casts. The casts are not necessary, and you want to avoid casting wherever possible, because when you write a cast, the compiler trusts you implicitly. If you make a mistake when casting, it is very hard for the compiler to cast it.

    Memory-allocation functions are designed to return void * for a reason: you can assign the result to any pointer type without a cast.

I'd also recommend you follow up with

assert(input != NULL && output != NULL);

just in case your machine runs out of memory. This would avoid a segfault in that case.