Как вы используете realloc, когда у вас есть указатель на указатель на структуру?

У меня есть этот массив структур, и эта функция принимает указатель на указатель массива. Исходный размер равен 2, поэтому всякий раз, когда он достигает размера, мне нужно перераспределить и удвоить размер. Когда этот код запускается, я получаю ошибку недопустимого старого размера от realloc. Что я делаю неправильно?

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

person chuck    schedule 13.12.2016    source источник
comment
while(fscanf(...) != EOF) небезопасно. Подумайте, что происходит, когда некоторые, но не все преобразования завершаются успешно.   -  person EOF    schedule 14.12.2016


Ответы (3)


В вашей функции inv (предположительно) является адресом переменной-указателя. Это значение той переменной, которую вы хотите передать realloc.

*inv = realloc(*inv, (*size * 2 * sizeof(struct Inventory)));

По той же причине увеличение inv само по себе не даст ожидаемого результата.

Поскольку вам нужно использовать realloc, вы должны использовать count для ссылки на массив.

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++;
}
person dbush    schedule 13.12.2016

Проблема возникает из-за того, что вы изменяете inv (inv++;).

Вы можете только realloc данные, если переданный указатель является допустимым выделенным указателем, а не указателем внутри выделенной зоны.

Таким образом, вам нужно сохранить данные inv, чтобы вы могли использовать realloc. Указатель на текущий элемент должен быть другой переменной.

И убедитесь, что realloc не возвращает NULL перед назначением обратно inv, иначе вы потеряете исходный указатель.

Это почти заставило меня пропустить самую большую ошибку (1 ошибка, скрывающая другую, классическую): вы передаете тип struct Inventory **, чтобы вы могли изменить указатель, но вместо этого вы изменяете двойной указатель.

Вы должны выполнить свой realloc для указанного значения, а не для адреса указателя:

*inv = realloc(*inv, (*size * 2 * sizeof(struct Inventory)));
person Jean-François Fabre    schedule 13.12.2016

Когда вы обновляете inv с realloc(), ваш inv теперь указывает на начало нового массива с измененным размером. Итак, ваш код

  if (count == *size - 1) {
    inv = realloc(inv, (*size * 2 * sizeof(struct Inventory*)));
    *size *= 2;
  }
  inv++;

последний inv++ заставит inv эффективно указывать на inv[1], а не на inv[count], на который вы, вероятно, хотели бы указать.

Я добавляю ниже, потому что за неправильные ответы голосуют

Предложение

*inv = realloc(*inv, (*size * 2 * sizeof(struct Inventory)));

не является правильным.

То, что вы пытаетесь сделать, это динамическое удвоение массива указателей. Таким образом, правильный тип указателя для передачи в realloc здесь — struct Inventory **.

(Вы, вероятно, создали исходную таблицу pptr = malloc(sizeof(struct Inventory*) * INIT_SIZE), поэтому inv здесь правильный тип для realloc)

Сказав, что после того, как вы выполнили realloc в своей функции, исходный указатель inv, используемый кодом, который вызывал функцию this, больше недействителен, поэтому при возврате этой функции вы теряете свой указатель на измененный размер множество. Чтобы справиться с этим, вы должны вернуть вызывающей функции новое значение указателя inv.

дополнительное редактирование:

И не забудьте выделить память для фактического элемента struct Inventory:

inv[count] = malloc(sizeof(struct Inventory));

в начале цикла.

person Yogi Jason    schedule 13.12.2016