开发者

Struggling to use calloc and realloc to initialize arrays in C

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] = at开发者_运维百科oi(argv[j]);
  }

 }

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

 free(input);
 free(output);
        exit(0)
    }


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]);
}


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


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.


why are you only allocated half the number. You have n integers so you need an n+1 integer array (assuming you need a null sentinel on the end)

and what is output for, you never seem to use it

+1 for the point about realloc (from john k)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜