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+1
th 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 tomalloc(size)
, so you should replace yourrealloc()
withmalloc()
.- You don't need to cast the return value from
malloc()
,calloc()
, andrealloc()
. In fact, casting may hide errors from failing to includestdlib.h
. - You need
argc
timessizeof(int)
bytes, notargc
. The two are going to be equal only ifsizeof(int)
is 1. - Given a pointer
T *p;
, I find it easier to writemalloc()
calls asp = malloc(n * sizeof *p);
—this is simpler to write, easier to read, and does not depend on the type ofp
.
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:
The size computation remains correct even if the type of
input
oroutput
changes (say fromint
tolong
on a 64-bit machine).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.