Ошибка времени выполнения free () при работе с массивами указателей структуры - PullRequest
1 голос
/ 07 марта 2020

Здравствуйте, я некоторое время боролся со своим кодом и, наконец, обнаружил, что причиной является функция free (). Я думаю, что мне не хватает деталей о том, как работает free ().

Мой вывод:

test test test test test 
ID: 200
RELEASE YEAR: 2006


ID: 201
RELEASE YEAR: 2006


ID: 202
RELEASE YEAR: 2006


ID: 203
RELEASE YEAR: 2006


ID: 204
RELEASE YEAR: 2006


AB

Редактировать: Добавлен полный код

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

#define MAX 1000                                        //Do not edit this macro.

typedef struct{
    int film_id;
    char title[255];
    char description[1023];
    unsigned int release_year;
    char rental_duration;
    float rental_rate;
    unsigned char length;
    float replacement_cost;
    char rating[10];
    char last_update[30];
} RECORD_t, *RECORD;                                    //Do not edit this struct.


RECORD *find_by_year(int release_year, RECORD film_array, int start, int end,int *found);


int main(){
    RECORD rec = (RECORD)malloc(sizeof(RECORD_t)*MAX);  //Do not edit this line.
    FILE *file = fopen("data.txt", "rb");               //Do not edit this line.
    if (file == NULL) {                                 //Do not edit this line.
        printf("Cannot open the file.\n");              //Do not edit this line.
        exit(0);                                        //Do not edit this line.
    }                                                   //Do not edit this line.
    fread(rec, sizeof(RECORD_t)*MAX, 1, file);          //Do not edit this line.
    fclose(file);                                       //Do not edit this line.


    int i,test;
    RECORD *rec_arr;

    rec_arr=find_by_year(2006,rec,200,203,&test);
    for(i=0;i<test;i++){
            printf("ID: %d\n", rec_arr[i]->film_id);
            printf("RELEASE YEAR: %d\n", rec_arr[i]->release_year);
            printf("\n\n");
            fflush(stdout);
    }
    printf("A");
                fflush(stdout);

//  file = fopen("data.txt", "wb");                     //Do not edit this line.
//  fwrite(rec, sizeof(RECORD_t)*MAX, 1, file);         //Do not edit this line.
//  fclose(file);                                       //Do not edit this line.
    free(rec);                                          //Do not edit this line.


    printf("B");
    fflush(stdout);

    free(rec_arr);

printf("C");
    fflush(stdout);

    return 1;                                           //Do not edit this line.
}

RECORD *find_by_year(int release_year, RECORD film_array, int start, int end,int *found) {

    RECORD *rec_arr=malloc(sizeof(RECORD)*1);
    RECORD *narray;//for realloc check
    int size=1,i,j;
    start--;
    if(rec_arr==NULL){//if malloc fails
        printf("MALLOC FAILED find_by_year returning NULL\n");
        fflush(stdout);
        return NULL;
    }

    for(i=start;i<=end;i++){
        if(film_array[i].release_year==release_year){
            rec_arr[size-1]=&film_array[i];
            size++;
            narray=realloc(rec_arr,size);//increment the size by 1


            //ERROR HANDLING
            if(narray==NULL){//if realloc fails
                printf("INNER REALLOC FAILED find_by_year");
                fflush(stdout);
                narray =malloc(sizeof(RECORD) * size);

                if(narray==NULL){ //if malloc fails
                    printf("INNER MALLOC ALSO FAILED find_by_year returning NULL\n");
                    fflush(stdout);
                    return NULL;
                }

                for(j=1;j<size;j++){//copy
                    narray[size-1]=rec_arr[size-1];
                    free(rec_arr);
                }
            }
            printf("test ");
            fflush(stdout);

            rec_arr=narray;
        }
    }
    printf("\n");
    fflush(stdout);

    *found=size-1;


    if(size==1)//if not found anything
        return NULL;

    return rec_arr;
}



Из результатов отладки free (rec_arr) терпит неудачу каждый раз, в чем может быть проблема здесь. Я обрезал код, и я почти уверен, что обрезанные части работают после отладки.

Ответы [ 2 ]

2 голосов
/ 07 марта 2020

Главное, что не так с вашим кодом - это подход. Постоянное увеличение размера массива на единицу с помощью realloc() ужасно неэффективно. Вместо этого просто сделайте один проход по данным, чтобы проверить, сколько записей соответствует, затем выделите все хранилище за раз и сделайте второй проход, чтобы заполнить его. Или выделите массив размером со все записи, заполните только ту часть, которая вам нужна, и не беспокойтесь об «потраченной впустую» памяти, потому что это, вероятно, не имеет значения.

Любой из вышеуказанных подходов в результате получается намного более простой код с меньшим количеством ошибок.

1 голос
/ 07 марта 2020

Эта строка неверна:

narray=realloc(rec_arr,size);//increment the size by 1

Второй аргумент realloc должен быть числом байтов, а не количеством записей. Вы должны умножить size на sizeof(RECORD).


Вот некоторые общие рекомендации по остальной части кода:

  • Я предлагаю просто прервать в случае if(narray=NULL) , Этот код почти никогда не произойдет, и, вероятно, все равно потерпит неудачу, даже если он действительно войдет. Восстановление из нехватки памяти является продвинутой версией c (особенно с учетом того, что современные операционные системы перегружены).
  • Вы упомянули об использовании Eclipse + CDT - вы должны иметь возможность шагать по коду в отладчике вместо того, чтобы использовать операторы отладки printf.
  • Было бы хорошо проверить на rec будучи NULL в первой строке main, а также проверьте возвращаемое значение find_by_year - если он возвращает NULL, то вы не хотите go для выполнения i l oop. Ваша функция не устанавливает *found в случае возврата NULL, иногда, поэтому вызывающий должен выполнить нулевую проверку перед использованием счетчика записей.
  • Я действительно не согласен с другим предложением изменить стратегию reallo c. Простота чтения кода - неплохой план как для начинающих, так и для экспертов. И я сомневаюсь, что это действительно неэффективно, поскольку современные операционные системы имеют минимальный размер выделения, поэтому вызовы reallo c в основном ничего не сделают, если ваш поиск не даст более 1000 записей.
...