C 有没有办法将指向释放内存的所有指针设置为NULL?

C 有没有办法将指向释放内存的所有指针设置为NULL?,c,pointers,memory-management,dynamic-memory-allocation,C,Pointers,Memory Management,Dynamic Memory Allocation,我想将指向已释放内存位置的所有指针设置为NULL,这样就不可能出现悬空指针或双重释放。这在C语言中是可能的吗 例如,我有以下结构: struct B { int *arr; unsigned int len; }; struct A { struct B *b; }; // Freeing and setting them to NULL: bool test_safe_free() { struct A *a = malloc(sizeof(struct A

我想将指向已释放内存位置的所有指针设置为NULL,这样就不可能出现悬空指针或双重释放。这在C语言中是可能的吗

例如,我有以下结构:

struct B {
    int *arr;
    unsigned int len;
};

struct A {
    struct B *b;
};

// Freeing and setting them to NULL:
bool test_safe_free() {
    struct A *a = malloc(sizeof(struct A));
    struct B *b = malloc(sizeof(struct B));
    b->arr = malloc(100 * sizeof(int));
    b->len = 100;
    a->b = b;

    safe_free_A(&a);
    return a == NULL && b == NULL;
}

void safe_free_B(struct B **b_ref) {
    if (*b_ref != NULL) free((*b_ref)->arr);
    (*b_ref)->arr = NULL;
    free(*b_ref);
    *b_ref = NULL;
}

void safe_free_A(struct A **a_ref) {
    // Before freeing A, freeing B:
    if (*a_ref != NULL) safe_free_B(&((*a_ref)->b));
    free(*a_ref);
    *a_ref = NULL;
}
test\u safe\u free
函数返回false,因为即使变量
a
在释放后被设置为NULL,
b
仍然指向释放的内存,因为当
a
传递到函数中时,指针被复制(副本被设置为NULL,而原始值保持不变)


我想不出一个方法,一个结构来解决这个问题,但我也不确定我想做的是否可能

C语言不会记录指针变量的所有副本

C++可以通过智能指针的概念实现这一点,但C不能,因为它没有类似于析构函数的功能。由程序员负责跟踪任何引用并对其进行适当管理

实现这一点的一种方法是实现引用计数,这不是一项微不足道的任务。您需要创建一个结构,作为保存当前引用计数的所有已分配内存段的头。然后,您需要为
malloc
和系列创建一个包装器,该包装器为标头和请求的空间分配空间,在内存块的开头写入标头,然后在块的后面返回指向内存的指针。然后需要一个函数,该函数可以增加创建新引用时手动调用的引用计数。然后您需要一个函数来减少引用计数,当引用计数达到0时,它将调用
free

当然,即使你这样做了,你也要记住在必要的时候增加/减少引用计数,以换取知道何时不调用
free
。未能递增表示使用已释放的内存和/或双空闲,而未能递减表示内存泄漏。

在此函数中

bool test_safe_free() {
    struct A *a = (struct A *) malloc(sizeof(struct A));
    struct B *b = (struct B *) malloc(sizeof(struct B));
    b->arr = (int *) malloc(100 * sizeof(int));
    b->len = 100;
    a->b = b;

    safe_free_A(&a);
    return a == NULL && b == NULL;
}
您声明的指针
b
未传递到
safe\u free\u b
。指针
a->b
通过引用传递给函数
safe\u free\u b

safe_free_B(&((*a_ref)->b));
因此,函数
test\u safe\u free
中声明的局部变量
b
保持不变

您可以在函数中写入

a->b = b;
b = NULL;

safe_free_A(&a);
return a == NULL;
现在分配内存的所有者是指针
a->b
,而不是指针
b

但是,功能
safe\u free\u B
safe\u free\u A
不安全:

你可以这样写

void safe_free_B(struct B **b_ref) {
    if ( *b_ref != NULL ) free((*b_ref)->arr;
    free(*b_ref);
    *b_ref = NULL;
}


仅供参考:.@JonathonReinhart谢谢你提供的信息。即使你能做到这一点,那也不是个好主意。这些指针神奇地设置为NULL,如果使用,将导致混乱。你的问题是垃圾收集的绝佳论据。@ddyer什么混乱?该标准实际上允许编译器将释放存储的任何指针设置为NULL或任何其他值。如果程序试图使用指针的值来释放存储,则该程序具有未定义的behaviour@ddyer我不是那样想的。当我释放一个包含另一个结构B的结构a,然后在其他地方释放该结构B时,我想避免双重释放。例如:如果我有一个结构a的列表和另一个结构B的列表,如果该列表中的一些B已经在a列表中的一些a中,并且我尝试释放这两个列表,我会得到双重释放。我能想到的避免跟踪释放内容的位置和避免双重释放的唯一方法是将指向已释放内存位置的每个指针设置为NULL。啊,是的,当然,通常“安全”意味着NULL安全。我想我应该编辑一下。谢谢关于将
b
设置为NULL,我不确定是否可以在我的源代码中实现它,但一定会尝试,再次感谢!
void safe_free_A(struct A **a_ref) {
    // Before freeing A, freeing B:
    if ( *a_ref != NULL ) safe_free_B(&((*a_ref)->b));
    free(*a_ref);
    *a_ref = NULL;
}