2016-11-10 4 views
1

Я делаю массив структур для динамического выделения списка продуктов, но это работает только несколько раз (3 ~ 5 раз), а затем я получил эту ошибку.C - realloc с массивом структур

* Ошибка в `./test ': перераспределить(): недействительный следующий размер: 0x000055bc0b44f260 *

Вот мой код, это часть работы колледжа.

#include <stdio.h> 
#include <stdlib.h> 

typedef struct { 
    int cod; 
    float price; 
} Product; 

int main() { 

    FILE *fp; 

    fp = fopen("products.txt", "r+"); 

    if(fp == NULL) 
     fopen("products.txt", "w+"); 

    int control = 1; 
    int choice; 
    int tam = 0; 
    int i; 
    Product *p1; 

    p1 = malloc(sizeof(Product)); 

    while(fread(&p1[0], sizeof(Product), 1, fp) != NULL){ 
     tam++; 
    } 

    if(tam > 1){ 
     rewind(fp); 

     p1 = malloc((tam) * sizeof(*p1)); 

     for (int i = 0; i < tam; i++){ 
      fread(&p1[i], sizeof(Product), 1, fp); 
     } 
    } 

    rewind(fp); 

    do { 
     printf("1 - Add product\n2 - Show all products\n3 - Exit\n-> "); 
     scanf(" %d", &choice); 

     switch (choice) { 
      case 1: 
       if (tam == 0) { 
        //p1 = malloc(sizeof(Product)); 
        printf("Digit the product code: "); 
        scanf(" %d", &p1[tam].cod); 
        printf("Digit the product price: "); 
        scanf(" %f", &p1[tam].price); 
        tam++; 
       } else { 
        printf("***Realloqing: %d***\n", tam * sizeof(*p1)); 
        p1 = (Product*)realloc(p1, (tam) * sizeof(Product)); 
        for (i = tam; i > 0; i--) { 
         p1[i].cod = p1[i-1].cod; 
         p1[i].price = p1[i-1].price; 
        } 
        printf("Digit the product code: "); 
        scanf(" %d", &p1[0].cod); 
        printf("Digit the product price: "); 
        scanf(" %f", &p1[0].price); 
        tam++; 
       } 
      break; 
      case 2: 
       for (i = 0; i < tam; i++) { 
        printf("Product code: %d\nProduct price: %f\n", p1[i].cod, p1[i].price); 
       } 
      break; 
      case 3: 
       control = 0; 
      break; 
     } 

    } while (control); 

    for (int i = 0; i < tam; i++){ 
     fwrite(&p1[i], sizeof(Product), 1, fp); 
    } 

    fclose(fp); 

    free(p1); 

    return 0; 
} 
+1

Несколько вещей: во-первых вы не должны назначить обратно к указателю вы передаете 'realloc', если' realloc' терпит неудачу и возвращает нулевой указатель, вы потеряете исходный указатель и имеет утечку памяти. Затем вы должны прочитать [эту дискуссию о литье 'malloc' (и друзей)] (http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc/605858). –

+0

Что касается вашей проблемы, кажется, что вы пишете границы вашей памяти. Возможно, вы захотите использовать такой инструмент, как [Valgrind] (http://valgrind.org/), чтобы помочь вам найти такие проблемы. –

+0

'fopen (" products.txt "," w + ");' -> 'fp = fopen (" products.txt "," w + ");' –

ответ

1

Проблема здесь:

printf("***Realloqing: %d***\n", tam * sizeof(*p1)); 
    p1 = (Product*)realloc(p1, tam * sizeof(Product)); 

Когда tam есть, скажем, 1, то вы перераспределить tam * sizeof(Product), но вы должны перераспределить (tam + 1) * sizeof(Product), потому что теперь вам нужно пространство для продуктов.

Так что это исправляет проблему:

printf("***Realloqing: %d***\n", (tam + 1) * sizeof(*p1)); 
    p1 = (Product*)realloc(p1, (tam + 1) * sizeof(Product)); 
1

Это:

p1 = (Product*)realloc(p1, (tam) * sizeof(Product)); 

Нарушает Первое правило перераспределить, которая является то, что вы не должны присвоить результат перераспределить непосредственно к одной и той же переменной, которая передается в качестве первого аргумента. Когда вы это сделаете, если это не удастся, вы потеряли (просочились) старый указатель.

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

Если вы исправляете все, что по-прежнему оставляет вас с нарушенной программой, используйте valgrind.

+3

Вы уверены в« Первом правиле Realloc »? На странице [man page] (http://pubs.opengroup.org/onlinepubs/009695399/functions/realloc.html) говорится: _ Если для нового размера объекта памяти потребуется перемещение объекта, пространство для предыдущего экземпляра объект освобожден. –

+3

@KeineLust: Да, я уверен. Обратите внимание, что я сказал: «Если это не удастся». Вы считаете, что это удается. –

+1

Хорошо, я вижу вашу мысль. –

Смежные вопросы