M.M*_*M.M 21 c c++ arrays language-lawyer
这段代码是否正确?
int arr[2];
int (*ptr)[2] = (int (*)[2]) &arr[1];
ptr[0][0] = 0;
Run Code Online (Sandbox Code Playgroud)
ptr[0][1]
访问越界越明显无效arr
.
注意:毫无疑问,ptr[0][0]
指定相同的内存位置arr[1]
; 问题是我们是否被允许通过访问该内存位置ptr
.下面是一些表达式确定指定相同内存位置但不允许以这种方式访问内存位置的示例.
注2:还要考虑**ptr = 0;
.正如马克·凡·莱恩指出,ptr[0]
就相当于*(ptr + 0)
,但是ptr + 0
似乎陷入指针运算部的犯规.但通过使用*ptr
,可以避免这种情况.
尝试在这里回答为什么代码可以在常用的编译器上运行:
int arr[2];
int (*ptr)[2] = (int (*)[2]) &arr[1];
printf("%p\n", (void*)ptr);
printf("%p\n", (void*)*ptr);
printf("%p\n", (void*)ptr[0]);
Run Code Online (Sandbox Code Playgroud)
所有行在常用编译器上都打印相同的地址。因此,ptr
是一个对象,它表示与常用编译器上*ptr
相同的内存位置,因此实际上是一个指向 的指针,因此是。因此,代码将一个值赋给。ptr
ptr[0]
arr[1]
arr[0][0]
arr[1]
arr[1]
现在,让我们假设一个反常的实现,其中指向数组的指针(注意:我说的是指向数组的指针,即&arr
具有类型int(*)[]
,而不是arr
意味着与&arr[0]
具有类型相同int*
)是指向其中第二个字节的指针数组。那么取消引用与使用算术ptr
减 1 相同。对于结构和联合,可以保证指向此类类型的指针与指向此类类型的第一个元素的指针相同,但是在将指向数组的指针转换为指针时,没有为数组找到这样的保证(即指向数组的指针将是与指向数组第一个元素的指针相同),事实上 @FUZxxl 计划提交一份有关该标准的缺陷报告。对于这样一个反常的实现,ie不会与 相同。在 RISC 处理器上,事实上它会因数据对齐而导致问题。ptr
char*
*ptr
ptr[0]
&arr[1]
一些额外的乐趣:
int arr[2] = {0, 0};
int *ptr = (int*)&arr;
ptr[0] = 5;
printf("%d\n", arr[0]);
Run Code Online (Sandbox Code Playgroud)
该代码应该有效吗?它打印 5。
更有趣的是:
int arr[2] = {0, 0};
int (*ptr)[3] = (int(*)[3])&arr;
ptr[0][0] = 6;
printf("%d\n", arr[0]);
Run Code Online (Sandbox Code Playgroud)
这应该有效吗?它打印 6。
这显然应该有效:
int arr[2] = {0, 0};
int (*ptr)[2] = &arr;
ptr[0][0] = 7;
printf("%d\n", arr[0]);
Run Code Online (Sandbox Code Playgroud)