你猜下边代码会打印多少?
#include <stdio.h>
int main()
{
void a;
printf("%d\n", sizeof(a));
return 0;
}
答:会报错!那 void 既然是无类型,我们就不应该用它来定义一个变量,如果你一定要这么做,那么程序就会给你报错(我只是换个提问方式,看看多少童鞋会上当)。
那 sizeof(void *) 呢?答:如果你回答是 4 个字节或 8 个字节,那么本题不能算你答对。因为指针的尺寸是与编译器的目标平台相关的。比如目标平台是 32 位的,那么 sizeof(void*) 就是 4,如果是 64 位的,那么 sizeof(void *) 就是 8,如果是 16 位的,那么就是 2 啦。
如何有效地避免出现悬空指针?注:悬空指针就是指向了不确定的内存区域的指针,通常对这种指针进行操作会使程序发生不可预知的错误。
答:当你的指针不知道指向哪儿的时候,那么将它指向 NULL,以后就不会有太多的麻烦。比如定义一个指针变量的时候,你可以把它初始化为 NULL,这样至少可以确保它不是一个垂悬指针
对 NULL 指针进行解引用,结果是什么?答:报错。无论什么操作系统,对空指针进行解引用都是非法的。
请问下边定义有没有问题?
……
int *p = void *0;
……
答:报错
NULL 的宏定义是:#define NULL ((void *)0)
这里是将 0 强制转换成 void 指针,所以要这么写才能通过编译:int *p = (void *)0;
请问下边代码会打印什么?
#include <stdio.h>
int main()
{
int array[5] = {1, 2, 3, 4, 5};
int *pi = &array[2];
void *pv;
pv = pi;
pv++;
pi = pv;
printf("%d\n", *pi);
return 0;
}
答:建议回答“4”的童鞋自己打一次代码……
先晒下结果:
为何如此邪乎?我们把代码修改如下,你或许就会知道答案:
#include <stdio.h>
int main()
{
int array[5] = {1, 2, 3, 4, 5};
int *pi = &array[2];
void *pv;
pv = pi;
printf("%p, %p\n", pv, pi);
pv++;
pi = pv;
printf("%p, %p\n", pv, pi);
printf("%d\n", *pi);
return 0;
}
程序实现如下:
猜到了吧?由于 pv 是 void 类型指针,所以编译器并不知道其“跨度”是多少,因此 pv++ 只是简单的将地址加 1。那么地址不正确,打印出来的值肯定就是错误的!
那打印出来的是“乱码”吗?不是!如果没有猜错,你在电脑上得到的结果应该跟小甲鱼是一样的。
下边解释需要你懂得小端和大端的原理,不懂请先戳右边学习 -> 传送门
pi 指向的是数组的第三个元素(即 array[2],其值为 3)
那么 array[2] 和 array[3] 在内存中的存放形式(小端)应该如下:
pv = pi 使得 pv 也是指向 0xbf93b10c 地址。
pv++ 刚才我们解释了,编译器只知道机械将其地址加 1,即 pv 现在指向的是 0xbf93b10d 地址。
pi = pv 使得 pi 被 pv 带上了歪路……