问题描述
#include <stdio.h>
int main() {
int *numPtrA = NULL; // pointer to an integer pointer to null.. ascii value of zero
printf("%p\n",numPtrA + 2); // prints 0x8 which i expect
printf("%p\n",numPtrA + 5); // prints 0x14 and i dont kNow why
}
我试图通过向空指针的ASCII码添加一些东西来打印地址0x14,我认为这是0地址。但是,当我将5加到NULL时,我不明白为什么我得到0x14而不是0x20。我以为ptrNumA是一个指向整数的指针,因此应该添加5个整数块(每个4字节),新地址应为0x20
感谢您的帮助。非常感谢。
解决方法
从技术上讲,numPtrA
既不指向数组也不指向单个对象,因此,向其添加除0以外的任何值都会导致C ++中出现未定义的行为,因为指针算术仅针对数组范围内的指针定义和物体。
这是最新的C ++标准草案的引文:
[expr.add]
将具有整数类型的表达式J添加到指针类型的表达式P或从其中减去时,结果的类型为P。
- 如果P的值为空指针值,J的值为0,则结果为空指针值。 [不适用]
- 否则,如果P指向具有n个元素的数组对象x的数组元素i ... [不适用] (注意:指向对象的指针可以视为数组此规则中1个元素的数量)
- 否则,行为是不确定的。
除技术性外,前缀0x表示十六进制基数。 5 * 4 = 20 = 0x14
和0x20 = 32 != 20
。
也就是说,空指针的值不一定是0(即使文字0始终是空指针文字),因此期望值不能移植到某些不是这种情况的系统中。这在嵌入式系统中很常见,在该系统中实际存储需要使用地址0。
此外,当您传递printf
作为参数时,%p
说明符void*
要求参数的类型为int*
。违反此约束的结果是程序的行为未定义。
答案在评论中。
在您的情况下,sizeof(int) == 4
并因此numPtr + 2
指向地址8 = 2*4
,而numPtr + 5
指向地址20 = 5*4
,它实际上是十六进制表示的0x14
。
不允许您对未指向有效对象的指针进行指针算术-这是未定义的行为(根据6.5.6,详细信息和引号here)。这样您就可以得到任何结果。
此外,不保证在C中空指针的二进制表示形式为零。我建议学习What's the difference between null pointers and NULL?。
然后最后,%p
以十六进制给出输出。指针算术的基础是typeptr + 5
等于以字节表示的加sizeof(*typeptr) * 5
。由于sizeof(int)
可能为0x4,因此您得到0x4 * 0x5 = 0x14
。