使用结构指针数组时出现 free() 运行时错误

free() runtime error while working with structure pointer arrays

你好,我已经为我的代码苦苦挣扎了一段时间,最后发现 free() 函数是原因。我想我遗漏了一些有关 free() 工作原理的细节。

My output is :

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

Edit : Added the full code

#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) 每次都失败,可能是这里的问题所在。我裁剪了代码,我几乎可以确定裁剪的部分在调试中正常工作。

您的代码的主要错误在于方法。使用 realloc() 重复将数组的大小递增 1 效率极低。相反,只需传递一次数据以检查有多少记录匹配,然后立即分配整个存储并进行第二次传递以填充它。或者,分配一个与所有记录一样大的数组,只填充您需要的部分,不要担心 "wasted" 内存,因为它可能无关紧要。

以上任何一种方法都会导致代码更简单,错误更少。

此行不正确:

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

realloc的第二个参数应该是字节数,而不是记录数。您应该将 size 乘以 sizeof(RECORD) .


以下是关于其余代码的一些一般性建议:

  • 我建议在 if(narray=NULL) 情况下中止。无论如何,该代码几乎永远不会发生,即使它确实进入了,也可能无论如何都会失败。从内存不足中恢复是一个高级主题(特别是考虑到现代操作系统过度使用)。
  • 您提到使用 Eclipse+CDT——您应该能够在调试器中逐步执行代码,而不必使用 printf 调试语句。
  • 最好在 main 的第一行检查 rec 是否为 NULL,并检查 find_by_year 的 return 值——如果它returns NULL 那么你不想继续执行 i 循环。在 returning NULL 的情况下,您的函数有时不会设置 *found,因此调用者必须在使用记录计数之前进行空检查。
  • 我不太同意另一个更改 realloc 策略的建议。保持代码简单易读并不是一个坏计划,无论是对于初学者还是专家。而且我怀疑它的效率真​​的很低,因为现代操作系统具有最小分配大小,因此除非您的搜索 return 超过 1000 条记录,否则 realloc 调用基本上什么都不做。