考虑我有一个结构
typedef struct point_t
{
int x;
int y;
}POINT;
我为 POINT 创建一个指向指针的指针并将其初始化为NULL
。
POINT **ppPoint = NULL;
*ppPoint
也应该返回NULL
吗?
这里有 2 层指针这一事实实际上是无关紧要的。事实上,您的外部指针在NULL
意味着取消引用它是非法的。因此,询问通过取消引用它会获得什么价值是没有意义的。
考虑一下:
int *p = NULL; // modern practice would be to use nullptr anyway
if (0 == *p) // this is Undefined Behaviour!
{
// do something, maybe?
}
你只是在上面添加另一层,而不是int
,你有point_t*
,但这真的没有区别。
未定义行为的问题是任何事情都可能发生!您的程序可能会崩溃,或者它可能看起来可以正常工作,或者它有时可能会给您垃圾值,或者它可能......
空指针不指向任何内容。这适用于普通指针、函数指针和成员指针。它也适用于指向指针的指针。
因此,谈论"它所指向的东西"的价值是没有意义的。
不能取消引用值为NULL
的指针。因此,您将无法访问*ppPoint
.
您可以使用要检查的printf()
中的%p
格式化器检查变量的地址。
printf("Address of ppPoint: %p", *ppPoint);
printf("Address of *ppPoint: %p", *ppPoint);
首先,对神秘的空值存在常见的误解。在这种情况下,有 3 个相关术语:
- 空指针
- 空指针常量
NULL
宏
空指针常量是整数0
或转换为指针的整数,(void*)0
。NULL
宏保证是可移植的空指针常量。
每当将空指针常量(如NULL
(分配给任何指针时,该指针都会变为空指针。这允许编译器在内部表示一个空指针作为0
以外的其他东西,因为地址0x00...00
在许多系统上通常是一个有效的物理地址。
具体来说,C17 6.3.2.3/3 对此进行了定义:
值为
0
的整数常量表达式,或转换为类型的此类表达式void *
,称为空指针常量。如果将 null 指针常量转换为指针类型,则生成的指针(称为null指针(保证与指向任何对象或函数的指针不相等进行比较。
通过取消引用来访问空指针时,不会得到任何可预测的结果。这是根据 C17 6.5.3.2/4 定义的未定义行为:
如果为指针分配了无效值,则未定义一元 * 运算符的行为。
这意味着任何事情都可能发生。如果幸运的话,您只会崩溃。
但是,您可以将空指针与另一个空指针或空指针常量进行比较,并且保证它们相等 (C17 6.5.9(。
至于指针到指针是一种特例,事实并非如此。指向类型与上述任何规则无关。总的来说,在 C 语言中,指针到指针并没有什么特别之处 - 它从来都不是特例,而是始终被视为指针到类型。