我的字符指针指向无效的值后从int *
我正在学习C编程语言,我刚开始学习数组指针 。 我在这个问题上有问题,我希望那个输出必须是5
但是是2
,谁能解释一下为什么?
int main(){ int arr[] = {1, 2, 3, 4, 5}; char *ptr = (char *) arr; printf("%d", *(ptr+4)); return 0; }
假设int是32位(4字节)的小端序结构, int arr[]
的单个字节看起来像这样(最低有效字节在下面的地址,所有的值都是hex):
|01 00 00 00|02 00 00 00|03 00 00 00|04 00 00 00|05 00 00 00
char *ptr = (char *) arr;
现在, ptr
指向第一个字节 – 因为您已经转换为char*
,所以它被视为字符数组向前:
|1|0|0|0|2|0|0|0|3|0|0|0|4|0|0|0|5|0|0|0 ^ +-- ptr
然后, *(ptr+4)
访问char数组的第五个元素并返回相应的char
值:
|1|0|0|0|2|0|0|0|3|0|0|0|4|0|0|0|5|0|0|0 ^ +-- *(ptr + 4) = 2
因此, printf()
打印2
。
在Big Endian系统中,每个int
内的字节顺序相反,导致
|0|0|0|1|0|0|0|2|0|0|0|3|0|0|0|4|0|0|0|5 ^ +-- *(ptr + 4) = 0
这是因为char
的大小是1, int
的大小是4。 这意味着将4
添加到ptr
会使结果指向int
数组中的第二个条目。
如果你在一个大的endian系统上编译,你将会打印33554432。
int main(){ int arr[] = {1,2,3,4,5}; char *ptr = (char *) arr; printf("%d",*(ptr+4)); return 0; }
每个arr
大小都有sizeof(int)
大小(在你的实现中可能是4)。
由于ptr
是一个指向char
的指针,因此指针运算会在&arr[0]
之后4个字节ptr + 4
个点,这可能是&arr[1]
。
在内存中,它看起来像这样:
Address | 0 1 2 3 | 4 5 6 7 | ... Value | arr[0] | arr[1] | ...
你所做的绝对不是在生产代码中推荐的,但是在学习过程中对于理解指针,表演等是绝对有用的,所以对于这个例子来说是很棒的。 所以,为什么你得到2.这是因为你的数组是一个整数,这取决于你的架构有不同的大小(在你的情况, sizeof(int)
是4)。 您将ptr
定义为一个char指针,char的大小为1个字节。 指针算术(这就是你写ptr+4
时所做的)与指针所引用的对象的大小一致,在你的情况下用字符。 因此, ptr+4
距离数组的开始4个字节,因此在你的int
数组的第二个位置。 这就对了。 尝试ptr+5
,你应该得到0。
在32位平台上, int
是char
四倍。 当你给ptr
加4时,你把ptr指向 ptr(它本身就是一个内存位置)的大小增加4倍。 这恰好是int
数组中第二个元素的地址。
在64位平台上, int
是char
8倍, 和你的输出将是非常不同的。
长话短说,你的代码是不可移植的(也可以参考Joachim Pileborg的回答),但有趣的是取消。
由于你是int *转换为char *,ptr [0] = 1,ptr [4] = 2,ptr [8] = 3,ptr [12] = 4,ptr [16] = 5,其他都等于0 。ptr + 4指向ptr数组中的第四个元素。 所以结果是2。
int main(){ int arr[] = {1,2,3,4,5}; char *ptr = (char *) arr; printf("%d",*(ptr+4)); return 0; }
想象一下, arr
存储在地址100
(完全哑地址)。 所以你有: arr[0]
被存储在地址100处arr[1]
被存储在地址104处(由于int
types,存在+4) arr[2]
被存储在地址108处arr[3]
被存储在地址112处。等等
现在你正在做char *ptr = (char *) arr;
,所以ptr
= 100(和arr
)。 下一条语句很有趣,特别是printf
的第二个参数: *(ptr+4)
。 请记住ptr
= 100。所以ptr + 4
= 104,与arr[1]
地址相同! 所以它会打印arr[1]
的值,即2。