C释放一个实例,该实例由其他指针指向

C释放一个实例,该实例由其他指针指向,c,pointers,free,C,Pointers,Free,我有下面的C代码。我有两个指针指向同一个物体。 它说双重自由错误。有人能帮忙看看问题出在哪里吗?谢谢 #include <stdlib.h> #include <stdio.h> typedef struct edge { int head; } edge_t; typedef struct edge_list_t { edge_t *edge; } edge_list_t; int main() { edge_list_t *p1;

我有下面的C代码。我有两个指针指向同一个物体。 它说双重自由错误。有人能帮忙看看问题出在哪里吗?谢谢

#include <stdlib.h>
#include <stdio.h>

typedef struct edge {
    int head;
} edge_t;

typedef struct edge_list_t {
    edge_t *edge;
} edge_list_t;
int main() {
    edge_list_t *p1;
    edge_list_t *p2;
    edge_t *c;

    p1 = malloc(sizeof(edge_list_t));
    p2 = malloc(sizeof(edge_list_t));

    c = malloc(sizeof(edge_t));

    p1->edge = c;
    p2->edge = c;

    free(c);

    if (p2->edge) {
        printf("not freed\n");
        free(p2->edge);
    } else {c
        printf("freed\n");
    }
    return 1;
}
#包括
#包括
typedef结构边缘{
int头;
}边缘;
类型定义结构边缘列表{
边缘_t*边缘;
}边缘列表;
int main(){
边缘列表*p1;
边缘列表*p2;
边缘t*c;
p1=malloc(sizeof(edge_list_t));
p2=malloc(sizeof(edge_list_t));
c=malloc(sizeof(edge_t));
p1->边缘=c;
p2->edge=c;
免费(c);
如果(p2->边缘){
printf(“未释放\n”);
自由(p2->边缘);
}else{c
printf(“释放的\n”);
}
返回1;
}
^最后一个
免费
是双
免费
。请记住,在第一次调用
free
后,
c
的值无效。

此处:

p2->edge = c;

free(c);
当您释放
c
时,
c
的值不会改变,即使这样,
p2->edge
的值也会保持不变。它当然会保持c的原始值。 因此,您总是释放
c
p2->edge
这两个值都相同的值

为了避免这种情况,如果调用
free()
,然后选中
if(c)
,则将
c
设置为NULL,这将再次返回false和not free
c


注意:free()不会以任何方式更改指针。它相信指针指向的是以前从未释放过的正确内存()d。

一旦将
c
的控制权转移到
p1
,就不应该释放
p1
p2
共享一个边缘指针,您应该通过一个同时释放边缘指针的函数来释放
p1
p2
。这些观察结果导致:

#include <stdio.h>
#include <stdlib.h>

typedef struct edge
{
    int head;
} edge_t;

typedef struct edge_list_t
{
    edge_t *edge;
} edge_list_t;

// Will acquire a loop when you have an actual list of edges
static void free_edge_list(edge_list_t *e)
{
    free(e->edge);
    free(e);
}

int main(void)
{
    edge_list_t *p1;
    edge_list_t *p2;
    edge_t *c;

    p1 = malloc(sizeof(edge_list_t));
    p2 = malloc(sizeof(edge_list_t));

    c = malloc(sizeof(edge_t));

    p1->edge = c;

    c = malloc(sizeof(edge_t));
    p2->edge = c;

    free_edge_list(p1);
    free_edge_list(p2);

    return 0;
}
#包括
#包括
typedef结构边缘
{
int头;
}边缘;
类型定义结构边缘列表
{
边缘_t*边缘;
}边缘列表;
//当您有一个实际的边列表时,将获取一个循环
静态无空洞边缘列表(边缘列表)
{
自由(e->边缘);
免费(e);
}
内部主(空)
{
边缘列表*p1;
边缘列表*p2;
边缘t*c;
p1=malloc(sizeof(edge_list_t));
p2=malloc(sizeof(edge_list_t));
c=malloc(sizeof(edge_t));
p1->边缘=c;
c=malloc(sizeof(edge_t));
p2->edge=c;
自由边列表(p1);
自由边列表(p2);
返回0;
}

通常,您应该检查内存分配是否成功;这段代码(仍然)不会这样做。

释放
释放内存块不会将指向该块的指针设置为NULL。分配三个块,释放其中一个块两次。那不好。欢迎来到堆栈溢出。请尽快阅读这篇文章。
}else{c
中的
c
是不需要的入侵者。请注意,
main()
程序通常在成功时返回0和1(或任何非零值)表示某种失败。但除此之外,您已经创建了一个简洁的问题-做得好。@OP:也许您想看看的概念是,这是您所追求的吗?您能告诉我如何设置if条件以避免第二次空闲吗?谢谢。
if(p2->edge!=c)free(p2->edge)
@user2529913
p2->edge=NULL;
free(c)之后;
@DavidSchwartz在
free(c)
之后,
c
值是一个无效的地址,因此表达式
p2->edge!=c
在技术上是未定义的行为。我认为问题有三个方面(或者,从一个角度看问题就有三个问题):(1)一旦将
c
的控制权转移到其中一个结构,代码就不应执行
free(c);
;以及(2)代码不应让
p1
p2
共享
c
,以及(3)代码应该通过释放
p->edge
元素和主结构的函数来释放
p1
p2
。我添加了free(p2->edge),if条件仍然进入第二个自由路径。free(c);free(p2->edge);if(p2->->edge){printf(“not freed\n”);free(p2->->edge);}else{printf(“freed\n”);}C不能保护你不被射中自己的脚;它假设你知道你瞄准的是危险的武器,并且你有充分的理由在身体的末端打洞。这意味着它不会溺爱初学者,初学者可以在你学习语言时尝试。当你这样做时,
free(p2->edge)
,释放由
p2->edge
指向的内存。现在
p2->edge
指向您已释放的内存,那么为什么要再次释放它呢?
如果(p2->edge)
相同,如果(p2->edge!=NULL)
p2->->->->edge
不为NULL,则指向您已释放的内存。
#include <stdio.h>
#include <stdlib.h>

typedef struct edge
{
    int head;
} edge_t;

typedef struct edge_list_t
{
    edge_t *edge;
} edge_list_t;

// Will acquire a loop when you have an actual list of edges
static void free_edge_list(edge_list_t *e)
{
    free(e->edge);
    free(e);
}

int main(void)
{
    edge_list_t *p1;
    edge_list_t *p2;
    edge_t *c;

    p1 = malloc(sizeof(edge_list_t));
    p2 = malloc(sizeof(edge_list_t));

    c = malloc(sizeof(edge_t));

    p1->edge = c;

    c = malloc(sizeof(edge_t));
    p2->edge = c;

    free_edge_list(p1);
    free_edge_list(p2);

    return 0;
}