我正在学习 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[]
看起来像这样(低地址的最低有效字节。所有值都是十六进制):
|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*
,所以它被视为 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
是一,而 的大小int
是四。这意味着添加4
到ptr
使结果指向int
数组中的第二个条目。
如果你在大端系统上编译它,你会打印 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
,因此指针算术在ptr + 4
4 个字节之后生成点&arr[0]
,这可能是&arr[1]
。
在内存中,它看起来像:
Address | 0 1 2 3 | 4 5 6 7 | ...
Value | arr[0] | arr[1] | ...
在 32 位平台上,int
是char
. 当您将 4 添加到 时,您添加了 ptr 指向 ptrptr
的大小的 4 倍(它本身就是一个内存位置)。这恰好是数组中第二个元素的地址。int
在 64 位平台上,大小int
是 的8倍char
;你的输出会非常不同。
长话短说,您的代码不可移植,(另请参阅 Joachim Pileborg 的回答 re endianness)但有趣的是取消选择。
在生产代码中绝对不建议您这样做,但对于在学习过程中理解指针、强制转换等绝对是非常有用的,因此您的示例非常棒。所以,为什么你得到 2。这是因为你的数组是一个整数数组,取决于你的架构,它有不同的大小(在你的情况下sizeof(int)
是 4)。您定义ptr
为 char 指针,char 的大小为 1 字节。指针算术(这就是您在编写时所做的ptr+4
)适用于指针引用的对象的大小,在您的情况下适用于字符。因此ptr+4
距离数组的开头有 4 个字节,因此位于数组的第二个位置int
。这就对了。试试ptr+5
,你应该得到 0。
由于您将 int* 转换为 char*,因此 ptr[0] = 1, ptr[4] = 2, ptr[8] = 3, ptr[12] = 4 , ptr[16] = 5 和所有其他等于 0 . ptr+4 指向 ptr 数组中的第 4 个元素。所以结果是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。(由于类型,有 +4 int
)
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。