在看 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;
}
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 了。 |
2
Volftooth 2017-09-10 11:41:07 +08:00 via iPhone 1
两个都没错、指向指针的指针也是指针嘛、但作者写的那个个人觉得更好理解一些、从参数上就能看出这是一个指向任意类型指针的指针、楼主写的这个从参数上看是无类型指针、用起来不注意的话可能出错、可能直接传 pi 而不是&pi、隐藏细节在函数体内了
|
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 打个断点,看看两者不一样的地方
|
4
wheeler OP |
5
verrickt 2017-09-10 11:56:45 +08:00 via Android
@wheeler 借楼问下,对 Null 取地址是 ub 吗?如果是的话,原作者的写法,第二次调用 saferfree 会 ub
|
6
ryd994 2017-09-10 13:16:16 +08:00 1
free(NULL)按照标准,是 no-op,为什么还要判断*pp ?
|
7
XiaoxiaoPu 2017-09-10 13:17:12 +08:00 1
@wheeler 原书的代码没有任何问题,也不会不可移植。
|
8
XiaoxiaoPu 2017-09-10 13:18:42 +08:00
@verrickt 取指针操作当然跟变量的值无关,只跟变量的类型和存储地址有关。
|