chuck
chuck

Reputation: 53

How do you use realloc when you have a pointer to a pointer of a struct?

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

Answers (3)

Yogi Jason
Yogi Jason

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

dbush
dbush

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

Jean-François Fabre
Jean-François Fabre

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

Related Questions