Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Struggling to use calloc and realloc to initialize arrays in C

Tags:

arrays

c

unix

I'm struggling to use calloc and realloc for my array initializations. I'm trying to write a program which calculates a final sum from the command line arguments using fork() with a companion program.

If I receive a odd set of integers from the command line such as: ./program 1 2 3 4 5.

It should see that amount is odd and initialize my input array to 6 spots and put a zero in the very last spot. Such as this: [0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 0. So that my companion program is able to do the computation.

If I receive a even of amount of integers from the command line such as: ./program 1 2 3 4. It would do the same as above, except without the zero because the set of integers is even.

The output array should be initialized to whatever the amount of integers is divided by 2. So if I had 6 arguments, it would be initialized to 3. If I receive an odd amount of integers such as 7, it would reallocate input array and put the zero at the end, thus making the amount of integers 8. So it would divide that by 2 and make the output initialize to 4.

My output array would eventually hold the sums of each pair of numbers. So the above would be.

1+2=3, 3+4=7, 5+0=5.

Then it the output array would hold [3],[7],[5]. Then the loop would continue from that and calculate the final sum from the remaining arguments.

I can't get that point though because my arrays aren't initializing correctly and adding the zero to the input array if the # of arguments is odd.

Refer to the code below:

#include <stdio.h>   /* printf, stderr, fprintf */
#include <unistd.h>  /* _exit, fork */
#include <stdlib.h>  /* exit */
#include <errno.h>   /* errno */
#include <sys/wait.h>
int main(int argc, char** argv)
{
 int size = argc - 1;
 int* input;
 int* output;
 int calc; 

 if(size == 1 && size % 2 != 0)
  size++;
 if(size % 2 != 0)
 {
   calc = (size+1)/2;  
   input = (int*)realloc(NULL,(argc)); 
   output = (int*)calloc(calc, sizeof(int));
   int j;
   for(j = 1; j < argc; j++)
   {
   input[j-1] = atoi(argv[j]);
   }
   input[argc] = 0;
  }
 else 
 {  
  calc = (size)/2;
  input = (int*)realloc(NULL,(size));
  output = (int*)calloc(calc, sizeof(int));
  int j;
  for(j = 1; j < argc; j++)
  {
   input[j-1] = atoi(argv[j]);
  }

 }

 int i;
 for(i = 0; i < argc; i++)
 printf("input[%d]: %d\n",i,input[i]);

 free(input);
 free(output);
        exit(0)
    }
like image 708
user266840 Avatar asked Feb 28 '23 15:02

user266840


2 Answers

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)/2

int * 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 inputs
for (int j = 1; j < argc; ++j)
{
   input[j-1] = atoi(argv[j]);
}
like image 136
John Knoeller Avatar answered Mar 02 '23 04:03

John Knoeller


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 := 0
while count < n:
    output[count/2] := input[count] + input[count+1]
    count := count + 2
like image 21
Alok Singhal Avatar answered Mar 02 '23 05:03

Alok Singhal