关于 C 语言 generic pointer 的问题

2017-09-10 11:15:47 +08:00
 wheeler

在看 Understanding and Using C Pointers (这本书真是错漏百出),其中一个例子觉得有问题,但是勘误上没有,想求证下。

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

#define safeFree(p) saferFree((void**)&(p))

void saferFree(void** pp)
{
    if (pp != NULL && *pp != NULL) {
        free(*pp);
        *pp = NULL;
    }
}

int main()
{
    int* pi;
    pi = (int*)malloc(sizeof(int));
    *pi = 5;
    printf("Before: %p\n", pi);
    safeFree(pi);
    printf("After: %p\n", pi);
    safeFree(pi);
    return (EXIT_SUCCESS);
}

作者想写个 free 的封装,来避免 double free 的问题。根据这里我觉得这里的 void ** 不对,应该是 void * 才对。

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

void saferFree(void* p)
{
    int** ptr = p;
    if (ptr && *ptr) {
        free(*ptr);
        *ptr = NULL;
    }
}

int main()
{

    int* pi = malloc(sizeof(*pi));
    *pi = 5;

    printf("Before: %p\n", pi);
    saferFree(&pi);
    printf("After: %p\n", pi);
    saferFree(&pi);

    return 0;
}

2195 次点击
所在节点    问与答
8 条回复
billlee
2017-09-10 11:37:23 +08:00
原书没有错,用 void**, 把 main 的局部变量 pi 的地址传过去,判断 pi 是否为 NULL, 如果不是 NULL, 进行 free, 并把 pi 设置为 NULL. 如果 pi 是 NULL, 就不管了。

如果用 void*, 就是把栈变量 pi 复制一份传过去,free 后就没办法把 main 的局部变量 pi 改称 NULL 了。
Volftooth
2017-09-10 11:41:07 +08:00
两个都没错、指向指针的指针也是指针嘛、但作者写的那个个人觉得更好理解一些、从参数上就能看出这是一个指向任意类型指针的指针、楼主写的这个从参数上看是无类型指针、用起来不注意的话可能出错、可能直接传 pi 而不是&pi、隐藏细节在函数体内了
verrickt
2017-09-10 11:45:43 +08:00
如果改成一级指针,main 调用 safer'free,pi 值传递,在 saferfree 的 p 会复制 pi 的值。对 p 取地址,得到的是本地变量 p 的地址而不是 pi 的地址。所以 saferfree 不会改变 main 里 pi 的值。你可以在 main 里对 pi 打个断点,看看两者不一样的地方
wheeler
2017-09-10 11:53:29 +08:00
@billlee @verrickt 感谢回复,后面的代码片 `saferFree(&pi);` 传的是 `pi` 的地址。其实我想问的是前面的代码片是不是不可移植。
verrickt
2017-09-10 11:56:45 +08:00
@wheeler 借楼问下,对 Null 取地址是 ub 吗?如果是的话,原作者的写法,第二次调用 saferfree 会 ub
ryd994
2017-09-10 13:16:16 +08:00
free(NULL)按照标准,是 no-op,为什么还要判断*pp ?
XiaoxiaoPu
2017-09-10 13:17:12 +08:00
@wheeler 原书的代码没有任何问题,也不会不可移植。
XiaoxiaoPu
2017-09-10 13:18:42 +08:00
@verrickt 取指针操作当然跟变量的值无关,只跟变量的类型和存储地址有关。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/389525

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX