realloc 调用后内存泄漏
Memory leak after realloc call
我有一个 **void,其中每个位置都指向 *void,它指向我的具有 3 个字段(*char、int、float)的结构记录。我想从我的结构中的 csv 加载数据,但是当需要重新分配内存时,因为大小等于数组的容量,我得到了 realloc(): invalid next size。我没有得到我的 printf("realloc fails") 所以我认为 tmp 不为空,但无论如何我丢失了我的内存指针。
struct record{
int id;
char* field1;
int field2;
float field3;
};
long array_size = 0;
long array_capacity = INITIAL_CAPACITY;
void** array;
void** array_create(){
void **array = (void**)malloc(INITIAL_CAPACITY*sizeof(void*));
if(array == NULL){
fprintf(stderr, "array_create: unable to allocate memory for the array");
exit(EXIT_FAILURE);
}
return array;
}
void add_on_array(void** array, void* elem){
if(array == NULL){
fprintf(stderr,"add_on_array: array parameter cannot be NULL");
exit(EXIT_FAILURE);
}
if(elem == NULL){
fprintf(stderr,"add_on_array: elem parameter cannot be NULL");
exit(EXIT_FAILURE);
}
if(array_size >= array_capacity){
void** tmp = realloc(array, 2*(sizeof(void*)*array_capacity));
if(tmp == NULL){
printf("Realloc fails\n");
exit(EXIT_FAILURE);
}
array = tmp;
array_capacity = 2*array_capacity;
}
array[array_size] = elem;
array_size++;
}
while(fgets(buffer,buf_size,fp) != NULL){
read_line_p = strdup(buffer);
if(read_line_p == NULL){
fprintf(stderr,"main: unable to allocate memory for the read line");
exit(EXIT_FAILURE);
}
// strcpy(read_line_p,buffer);
char *id_field_in_read_line_p = strtok(read_line_p, ",");
char *field1_in_read_line_p = strtok(NULL,",");
char *field2_in_read_line_p = strtok(NULL,",");
char *field3_in_read_line_p = strtok(NULL, ",");
char *field1 = malloc((strlen(field1_in_read_line_p)+1)*sizeof(char));
if(field1 == NULL){
fprintf(stderr,"main: unable to allocate memory for the string field of the read record");
exit(EXIT_FAILURE);
}
int id = atoi(id_field_in_read_line_p);
strcpy(field1,field1_in_read_line_p);
int field2 = atoi(field2_in_read_line_p);
float field3 = atof(field3_in_read_line_p);
struct record *record_p = malloc(sizeof(struct record));
if(field1 == NULL){
fprintf(stderr,"main: unable to allocate memory for the read record");
exit(EXIT_FAILURE);
}
record_p->id = id;
record_p->field1 = field1;
record_p->field2 = field2;
record_p->field3 = field3;
add_on_array(array, (void*)record_p);
free(read_line_p);
}
fclose(fp);
stampa_array(array, array->size);
printf("\nData loaded\n");
}
好吧,你在这里做了一些“非常糟糕”的事情。
首先你在这里有一个名为 array
的全局变量:
void** array;
一般来说,全局变量是你应该避免的。 (在极少数情况下,您确实需要一个全局变量,我建议您给它起一个不用于任何其他用途的“丑陋”名称 - 例如:globalVariableArray
)
但更糟糕的是 - 您还有一个函数,这里有一个名为 array
的参数:
void add_on_array(void** array, void* elem){
...
}
这是什么意思?同时具有全局 array
和参数 array
?函数中会访问到哪些?
答案是函数参数array
作为一个函数局部变量,它会隐藏全局变量。
所以当你这样做时:
array = tmp;
您 更改本地 array
变量 - 而不是全局。
当函数 return 局部变量不再存在时,即对其所做的任何更改都将丢失。
换句话说 - realloc
分配的内存丢失了,你有泄漏。
解决此问题的第一步是:
将全局变量移入main
调用需要改变array
的函数时,需要传递array
的地址,即&array
。必须相应地更改函数原型。
其他全局变量也一样...
但为什么不将所有数组内容放入一个结构中呢?
喜欢:
struct ArrayContainer
{
long array_size;
long array_capacity;
void** array;
}
并在 main
中执行:
struct ArrayContainer container = {0, INITIAL_CAPACITY, NULL};
container.array = ...; // Allocate INITIAL_CAPACITY
我认为这会大大简化您的代码,因为您只需要将指向此结构的指针传递给函数。然后您可以通过该指针更改所有三个成员。
我有一个 **void,其中每个位置都指向 *void,它指向我的具有 3 个字段(*char、int、float)的结构记录。我想从我的结构中的 csv 加载数据,但是当需要重新分配内存时,因为大小等于数组的容量,我得到了 realloc(): invalid next size。我没有得到我的 printf("realloc fails") 所以我认为 tmp 不为空,但无论如何我丢失了我的内存指针。
struct record{
int id;
char* field1;
int field2;
float field3;
};
long array_size = 0;
long array_capacity = INITIAL_CAPACITY;
void** array;
void** array_create(){
void **array = (void**)malloc(INITIAL_CAPACITY*sizeof(void*));
if(array == NULL){
fprintf(stderr, "array_create: unable to allocate memory for the array");
exit(EXIT_FAILURE);
}
return array;
}
void add_on_array(void** array, void* elem){
if(array == NULL){
fprintf(stderr,"add_on_array: array parameter cannot be NULL");
exit(EXIT_FAILURE);
}
if(elem == NULL){
fprintf(stderr,"add_on_array: elem parameter cannot be NULL");
exit(EXIT_FAILURE);
}
if(array_size >= array_capacity){
void** tmp = realloc(array, 2*(sizeof(void*)*array_capacity));
if(tmp == NULL){
printf("Realloc fails\n");
exit(EXIT_FAILURE);
}
array = tmp;
array_capacity = 2*array_capacity;
}
array[array_size] = elem;
array_size++;
}
while(fgets(buffer,buf_size,fp) != NULL){
read_line_p = strdup(buffer);
if(read_line_p == NULL){
fprintf(stderr,"main: unable to allocate memory for the read line");
exit(EXIT_FAILURE);
}
// strcpy(read_line_p,buffer);
char *id_field_in_read_line_p = strtok(read_line_p, ",");
char *field1_in_read_line_p = strtok(NULL,",");
char *field2_in_read_line_p = strtok(NULL,",");
char *field3_in_read_line_p = strtok(NULL, ",");
char *field1 = malloc((strlen(field1_in_read_line_p)+1)*sizeof(char));
if(field1 == NULL){
fprintf(stderr,"main: unable to allocate memory for the string field of the read record");
exit(EXIT_FAILURE);
}
int id = atoi(id_field_in_read_line_p);
strcpy(field1,field1_in_read_line_p);
int field2 = atoi(field2_in_read_line_p);
float field3 = atof(field3_in_read_line_p);
struct record *record_p = malloc(sizeof(struct record));
if(field1 == NULL){
fprintf(stderr,"main: unable to allocate memory for the read record");
exit(EXIT_FAILURE);
}
record_p->id = id;
record_p->field1 = field1;
record_p->field2 = field2;
record_p->field3 = field3;
add_on_array(array, (void*)record_p);
free(read_line_p);
}
fclose(fp);
stampa_array(array, array->size);
printf("\nData loaded\n");
}
好吧,你在这里做了一些“非常糟糕”的事情。
首先你在这里有一个名为 array
的全局变量:
void** array;
一般来说,全局变量是你应该避免的。 (在极少数情况下,您确实需要一个全局变量,我建议您给它起一个不用于任何其他用途的“丑陋”名称 - 例如:globalVariableArray
)
但更糟糕的是 - 您还有一个函数,这里有一个名为 array
的参数:
void add_on_array(void** array, void* elem){
...
}
这是什么意思?同时具有全局 array
和参数 array
?函数中会访问到哪些?
答案是函数参数array
作为一个函数局部变量,它会隐藏全局变量。
所以当你这样做时:
array = tmp;
您 更改本地 array
变量 - 而不是全局。
当函数 return 局部变量不再存在时,即对其所做的任何更改都将丢失。
换句话说 - realloc
分配的内存丢失了,你有泄漏。
解决此问题的第一步是:
将全局变量移入
main
调用需要改变
array
的函数时,需要传递array
的地址,即&array
。必须相应地更改函数原型。
其他全局变量也一样...
但为什么不将所有数组内容放入一个结构中呢?
喜欢:
struct ArrayContainer
{
long array_size;
long array_capacity;
void** array;
}
并在 main
中执行:
struct ArrayContainer container = {0, INITIAL_CAPACITY, NULL};
container.array = ...; // Allocate INITIAL_CAPACITY
我认为这会大大简化您的代码,因为您只需要将指向此结构的指针传递给函数。然后您可以通过该指针更改所有三个成员。