Memcpy 用于包含指针的嵌套结构

问题描述 投票:0回答:1

以下代码给出崩溃说明双重释放。如何解决这个问题而不留下内存泄漏。 尝试将 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);

}
c pointers crash memcpy
1个回答
0
投票

问题在于您在

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;
来简化这一过程,并摆脱许多手动分配和副本。

© www.soinside.com 2019 - 2024. All rights reserved.