V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
wheeler
V2EX  ›  问与答

关于 C 语言 generic pointer 的问题

  •  
  •   wheeler · 2017-09-10 11:15:47 +08:00 · 2166 次点击
    这是一个创建于 2631 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在看 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;
    }
    
    
    8 条回复    2017-09-10 13:18:42 +08:00
    billlee
        1
    billlee  
       2017-09-10 11:37:23 +08:00   ❤️ 1
    原书没有错,用 void**, 把 main 的局部变量 pi 的地址传过去,判断 pi 是否为 NULL, 如果不是 NULL, 进行 free, 并把 pi 设置为 NULL. 如果 pi 是 NULL, 就不管了。

    如果用 void*, 就是把栈变量 pi 复制一份传过去,free 后就没办法把 main 的局部变量 pi 改称 NULL 了。
    Volftooth
        2
    Volftooth  
       2017-09-10 11:41:07 +08:00 via iPhone   ❤️ 1
    两个都没错、指向指针的指针也是指针嘛、但作者写的那个个人觉得更好理解一些、从参数上就能看出这是一个指向任意类型指针的指针、楼主写的这个从参数上看是无类型指针、用起来不注意的话可能出错、可能直接传 pi 而不是&pi、隐藏细节在函数体内了
    verrickt
        3
    verrickt  
       2017-09-10 11:45:43 +08:00 via Android
    如果改成一级指针,main 调用 safer'free,pi 值传递,在 saferfree 的 p 会复制 pi 的值。对 p 取地址,得到的是本地变量 p 的地址而不是 pi 的地址。所以 saferfree 不会改变 main 里 pi 的值。你可以在 main 里对 pi 打个断点,看看两者不一样的地方
    wheeler
        4
    wheeler  
    OP
       2017-09-10 11:53:29 +08:00
    @billlee @verrickt 感谢回复,后面的代码片 `saferFree(&pi);` 传的是 `pi` 的地址。其实我想问的是前面的代码片是不是不可移植。
    verrickt
        5
    verrickt  
       2017-09-10 11:56:45 +08:00 via Android
    @wheeler 借楼问下,对 Null 取地址是 ub 吗?如果是的话,原作者的写法,第二次调用 saferfree 会 ub
    ryd994
        6
    ryd994  
       2017-09-10 13:16:16 +08:00   ❤️ 1
    free(NULL)按照标准,是 no-op,为什么还要判断*pp ?
    XiaoxiaoPu
        7
    XiaoxiaoPu  
       2017-09-10 13:17:12 +08:00   ❤️ 1
    @wheeler 原书的代码没有任何问题,也不会不可移植。
    XiaoxiaoPu
        8
    XiaoxiaoPu  
       2017-09-10 13:18:42 +08:00
    @verrickt 取指针操作当然跟变量的值无关,只跟变量的类型和存储地址有关。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2655 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 03:02 · PVG 11:02 · LAX 19:02 · JFK 22:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.