Reputation: 53
I have this array of structs and this function takes a pointer to the pointer of the array. The original size is 2, so whenever it reaches the size, I need to realloc and double the size. When this code runs, I get an invalid old size error from the realloc. What am I doing wrong?
int PopulateArray(struct Inventory **inv, int *size, FILE *inputFile) {
int count = 0;
printf("address: %u\n", inv);
printf("address: %u\n", **inv);
int itemNumber;
int quantity;
float price;
int month;
int year;
while (fscanf(inputFile, "%i %i %f %i/%i", &itemNumber,
&quantity, &price, &month, &year) != EOF) {
(*inv)->itemNumber = itemNumber;
(*inv)->quantity = quantity;
(*inv)->price = price;
(*inv)->expDate.month = month;
(*inv)->expDate.year = year;
printf("count: %i size: %i\n", count, *size);
if (count == *size - 1) {
inv = realloc(inv, (*size * 2 * sizeof(struct Inventory)));
*size *= 2;
}
inv++;
count++;
}
return count;
}
Upvotes: 5
Views: 745
Reputation: 121
When you update inv
from realloc()
, your inv
now points to the start of the newly resized array. So, your code
if (count == *size - 1) {
inv = realloc(inv, (*size * 2 * sizeof(struct Inventory*)));
*size *= 2;
}
inv++;
the last inv++
will make inv
point effectively to inv[1]
, not the inv[count]
which you would probably wanted to point to.
I am adding below because incorrect answers are being upvoted
The suggestion of
*inv = realloc(*inv, (*size * 2 * sizeof(struct Inventory)));
is not correct.
What you are attempting to do is doubling the array of pointers dynamically. So the correct pointer type to pass to realloc
here is struct Inventory **
.
(You probably created initial table by pptr = malloc(sizeof(struct Inventory*) * INIT_SIZE)
, so inv
is correct type for realloc
here)
Having said that, after you performing the realloc
in your function, the original inv
pointer used by the code that called this function is no longer valid, so upon returning this function, you lose your pointer to the resized array. To deal with this, you have to return the new inv
pointer value to the calling function.
additional edit:
And don't forget to allocate memory for the actual struct Inventory
item:
inv[count] = malloc(sizeof(struct Inventory));
at the start of the loop.
Upvotes: 0
Reputation: 223937
In your function, inv
is (presumably) the address of a pointer variable. Its the value of that variable you want to pass to realloc
.
*inv = realloc(*inv, (*size * 2 * sizeof(struct Inventory)));
For the same reason, incrementing inv
itself won't do what you expect.
Because you need to use realloc
, you should use count
to reference the array.
while (fscanf(inputFile, "%i %i %f %i/%i", &itemNumber,
&quantity, &price, &month, &year) != EOF) {
(*inv)[count].itemNumber = itemNumber;
(*inv)[count].quantity = quantity;
(*inv)[count].price = price;
(*inv)[count].expDate.month = month;
(*inv)[count].expDate.year = year;
printf("count: %i size: %i\n", count, *size);
if (count == *size - 1) {
*inv = realloc(*inv, (*size * 2 * sizeof(struct Inventory)));
if (*inv == NULL) {
perror("realloc failed");
exit(1);
}
*size *= 2;
}
count++;
}
Upvotes: 4
Reputation: 140188
The problem occurs because you're modifying inv
(inv++;
).
You can only realloc
data if the passed pointer is a valid allocated pointer, not a pointer within the allocated zone.
So you have to store your inv
data so you can use realloc
. Pointer on the current element must be a different variable.
And check that realloc
doesn't return NULL
before assigning back to inv
or you'll lose your original pointer.
That almost made me miss the biggest mistake (1 mistake hiding the other, classical): you're passing a struct Inventory **
type so you can modify the pointer, but you're modifying the double pointer instead.
You should perform your realloc on the pointed value, not on the address of the pointer:
*inv = realloc(*inv, (*size * 2 * sizeof(struct Inventory)));
Upvotes: 2