使用NULL的指针算法

有人可以解释,为什么

int main(void) { char *a = NULL; int *b = NULL; double *c = NULL; printf("\n%d %d %d\n%d %d %d\n\n", (int) (a+1), (int)(b+1), (int)(c+1), (int) (a+5), (int)(b+7), (int)(c+17)); return 0; } 

输出

 1, 4, 8 5, 28, 136 

我认为它与这些变量的字节大小有关。 但我不明白第二行输出。

如果p是指向类型T的指针,并且它保存存储器地址X ,则p + N是存储器地址X + N * sizeof(T)

 (int) (a + 1) == 0 + 1 * sizeof(char) == 1 * 1 == 1 (int) (b + 1) == 0 + 1 * sizeof(int) == 1 * 4 == 4 (int) (c + 1) == 0 + 1 * sizeof(double) == 1 * 8 == 8 (int) (a + 5) == 0 + 5 * sizeof(char) == 5 * 1 == 5 (int) (b + 7) == 0 + 7 * sizeof(int) == 7 * 4 == 28 (int) (c + 17) == 0 + 17 * sizeof(double) == 17 * 8 == 136 

小调:正如Barmar在他的回答中指出的那样,对NULL指针的算术在技术上是未定义的行为。 因此,符合标准的编译器可能会对该算法做出不同的处理; 代码可能打印了1,31415,或者是玩扑克的狗的照片。 但是,您观察到的行为与您从有效指针开始时所观察到的行为相同,因此您可能不需要担心这一点。

在C中,指针算法取决于底层类型的大小。

当你在某个指针p上执行p + n ,你并没有真正添加n 。 而是添加n * (sizeof(*p)) 。 那是你用n项目推进指针。

 a + 5 = 0 + sizeof(char)* 5 = 5
 b + 7 = 0 + sizeof(int)* 7 = 28
 c + 7 = 0 + sizeof(double)* 17 = 136

对空指针的算术会导致未定义的行为,因此任何结果都是可能的。

NULL -pointers上的算术运算是未定义的行为。

从C标准:

6.3.2.3指针

[…] 3如果将空指针常量转换为指针类型,则保证将结果指针(称为空指针)与指向任何对象或函数的指针进行比较。

[…]

6.5.6加法运算符

[…] 2另外,两个操作数都应具有算术类型,或者一个操作数应是指向对象类型的指针,另一个操作数应具有整数类型。

[…]

Apx J.2未定义的行为

[…]

将指针加到或减去数组对象和整数类型会产生一个不指向或超出同一数组对象的结果(6.5.6)。