使用结构指针数组时出现 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 调用基本上什么都不做。
你好,我已经为我的代码苦苦挣扎了一段时间,最后发现 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
循环。在 returningNULL
的情况下,您的函数有时不会设置*found
,因此调用者必须在使用记录计数之前进行空检查。 - 我不太同意另一个更改 realloc 策略的建议。保持代码简单易读并不是一个坏计划,无论是对于初学者还是专家。而且我怀疑它的效率真的很低,因为现代操作系统具有最小分配大小,因此除非您的搜索 return 超过 1000 条记录,否则 realloc 调用基本上什么都不做。