Code:
void main() {
int *array = calloc(5, sizeof(int));
int *amount = 9;
array[0] = 1;
array[1] = 2;
array[3] = 5;
int i = 0;
while (i < 5) {
printf("%d ", array[i]);
i += 1;
}
printf("%d", amount); //Printing
array = realloc(array, amount * sizeof(int)); //Problem is here
printf("\n");
i = 0;
while (i < 9) {
printf("%d ", array[i]);
i += 1;
}
free(array);
}
It says "invalid operands to binary * (have 'int *' and 'unsigned int'), but when I tried printing "amount", it's actually 9? I'm trying to use a pointer integer so that I can pass it by reference.
A couple of things:
First,
int *amount = 9;
does not do the same thing as
*amount = 9;
In the first case, the *
is only there to indicate that amount
has pointer type, and we are initializing the pointer value (i.e, the address) to 9
, which is most likely not a valid pointer value, and attempting to dereference it may lead to a runtime error.
In the second case, we are assigning the integer value 9
to the object amount
is pointing to.
Why didn’t this break when you passed amount
to printf
? Basically, you invoked undefined behavior by passing an argument of the wrong type (%d
expects an int
, you passed an int *
). One of the possible results of undefined behavior is getting the expected result. For whatever reason, printf
was able to treat that int *
value as an int
. Most compilers should flag that type mismatch, but you may heed to crank up the warning level to see it.
There’s a constraint on the binary *
operator that both operands have arithmetic type. int *
is not an arithmetic type, hence the diagnostic.
Based on how you are actually using amount
in your code, you should not have declared it as a pointer, but as a regular int
:
int amount = 9;
Secondly, as a rule, you do not want to assign the result of realloc
to the original pointer. If realloc
fails, it will return NULL
and leave the original block of memory as-is. However, if you assign that NULL
back to your original pointer, you will lose any access to that memory. Best practice is to assign the result of realloc
to a temporary, and then verify that the temporary is valid before assigning it back to the original:
int *tmp = realloc( array, amount * sizeof *array );
if ( tmp )
{
array = tmp;
}
else
{
// handle realloc error
}
Note the use of sizeof *array
instead of sizeof (int)
. sizeof
is an operator like unary *
or unary +
, and its operand can either be a parenthesized type name or an expression. The expression *array
has type int
, so sizeof *array == sizeof (int)
. This helps make code a bit easier to read, and if you ever change the type of array
(say to double *
), you won’t have to update the realloc
call. It’s also very useful when allocating multidimensional array types - would you rather write
int (*arr)[10] = malloc( sizeof (int) * 10 * rows);
or
int (*arr)[10] = malloc( sizeof *arr * rows );
?