以下代码给出崩溃说明双重释放。如何解决这个问题而不留下内存泄漏。 尝试将 tmp 的内容复制到列表。从 get_copy 中删除 free 不会导致崩溃。但这会导致内存泄漏。怎么解决这个问题
我们在这里分配了三次内存(忽略循环),所以它被释放了3次。 memcpy 将复制内存而不是内容,我明白。但是我如何释放之前分配的内存。 似乎提供的信息应该足以理解这里的问题。但 stackoverflow 不允许我在不添加更多文本的情况下发帖。所以,我写的没什么有用的。请忽略最后一段并帮助解决查询。如果存在嵌套指针,则在 memcpy 之后释放内存时会发生崩溃。
#include <stdio.h>
#include <stdlib.h>
typedef struct s1_ {
int x,y,z;
} tmp_type;
typedef struct s2_ {
tmp_type* p1;
char a;
} tmp_data;
typedef struct s3_ {
tmp_data* v1;
int num;
} tmp_list;
void get_copy(tmp_list *list) {
tmp_data tmp[10];
int i;
for(i=0;i<10;i++){
tmp[i].p1= calloc(1,sizeof(tmp_type));
tmp[i].p1->x = tmp[i].p1->y = tmp[i].p1->z = 6;
tmp[i].a = 'a'+i;
}
list->num = 5;
list->v1 = calloc(5,sizeof(tmp_data));
for(i=0;i<5;i++) {
list->v1[i].p1 = calloc(1,sizeof(tmp_type));
}
memcpy(list->v1,tmp,sizeof(list->v1));
for(i=0;i<5;i++) {
memcpy((list->v1[i].p1), (tmp[i].p1), sizeof(tmp_type));
free(tmp[i].p1);
}
}
void main()
{
tmp_list l1;
int i;
get_copy(&l1);
for (i=0;i<l1.num;i++) {
printf("list: %c %d %d %d\n",
l1.v1[i].a,
l1.v1[i].p1->x,
l1.v1[i].p1->y,
l1.v1[i].p1->z);
}
for(i=0;i<l1.num;i++){
free(l1.v1[i].p1);
}
free(l1.v1);
}
问题在于您在
get_copy
末尾复制的内容的顺序:
// Allocating v1 array
list->v1 = calloc(5,sizeof(tmp_data)); // OK
// Allocating p1 for each v1[i]
for(i=0;i<5;i++) {
list->v1[i].p1 = calloc(1,sizeof(tmp_type)); // OK
}
// Copying tmp array to v1 array
memcpy(list->v1,tmp,sizeof(list->v1)); // Oh no!
// All p1's you just allocated are now lost and replaced with tmp p1's!
// Copy tmp p1's to v1 p1's and free tmp p1's
for(i=0;i<5;i++) {
// This copy actually does nothing as both p1's are the same object!
memcpy((list->v1[i].p1), (tmp[i].p1), sizeof(tmp_type)); // Oops!
// Deallocates tmp[i].p1 which is also v1[i].p1!
free(tmp[i].p1); // Oh no!
}
我们需要重新安排复制的顺序,而且我们也不需要那么多
memcpy
。
// Allocating v1 array
list->v1 = calloc(5,sizeof(tmp_data));
// Allocate and copy array members
for(i=0;i<5;i++) {
list->v1[i] = tmp[i]; // Copy tmp_data
list->v1[i].p1 = calloc(1,sizeof(tmp_type)); // Alloc tmp_type
*list->v1[i].p1 = *tmp[i].pi; // Copy tmp_type
}
// Free tmp p1's
for(i=0;i<10;i++) {
free(tmp[i].p1);
}
请注意,您可以通过将
tmp_type* p1;
更改为 tmp_type p1;
来简化这一过程,并摆脱许多手动分配和副本。