我正试图掌握C中的指针和数组,现在,我正试图弄清楚我的C编译器是如何为二维数组中的元素分配内存的。下面是我的示例代码:
#include <stdio.h>
int main(void)
{
int ar[2][2] = { {1, 2}, {3, 4} };
printf("sizeof(int) = %u\n-----\n", sizeof(int));
printf("ar = %p\n", ar);
printf("ar + 1 = %p\n", ar + 1);
printf("&ar = %p\n", &ar);
printf("&ar + 1 = %p\n\n", &ar + 1);
printf("sizeof(ar) = %u\n-----\n", sizeof(ar));
printf("ar[0] = %p\n", ar[0]);
printf("ar[0] + 1 = %p\n", ar[0] + 1);
printf("&ar[0] = %p\n", &ar[0]);
printf("&ar[0] + 1 = %p\n\n", &ar[0] + 1);
printf("sizeof(ar[0]) = %u\n-----\n", sizeof(ar[0]));
printf("ar[1] = %p\n", ar[1]);
printf("ar[1] + 1 = %p\n", ar[1] + 1);
printf("&ar[1] = %p\n", &ar[1]);
printf("&ar[1] + 1 = %p\n\n", &ar[1] + 1);
printf("sizeof(ar[1]) = %u\n-----\n", sizeof(ar[1]));
printf("&ar[0][0] = %p\n", &ar[0][0]);
printf("&ar[0][0] + 1 = %p\n", &ar[0][0] + 1);
printf("&ar[1][0] = %p\n", &ar[1][0]);
printf("&ar[1][0] + 1 = %p\n\n", &ar[1][0] + 1);
printf("sizeof(ar[0][0]) = %u\n-----\n", sizeof(ar[0][0]));
return 0;
}
我在我的系统上得到的输出是:
sizeof(int) = 4
-----
ar = 0061FF20
ar + 1 = 0061FF28
&ar = 0061FF20
&ar + 1 = 0061FF30
sizeof(ar) = 16
-----
ar[0] = 0061FF20
ar[0] + 1 = 0061FF24
&ar[0] = 0061FF20
&ar[0] + 1 = 0061FF28
sizeof(ar[0]) = 8
-----
ar[1] = 0061FF28
ar[1] + 1 = 0061FF2C
&ar[1] = 0061FF28
&ar[1] + 1 = 0061FF30
sizeof(ar[1]) = 8
-----
&ar[0][0] = 0061FF20
&ar[0][0] + 1 = 0061FF24
&ar[1][0] = 0061FF28
&ar[1][0] + 1 = 0061FF2C
sizeof(ar[0][0]) = 4
-----
我理解为什么ar
大小为16字节;它应该能够容纳4 int
s,在我的系统中这是4x4 = 16字节。我猜,这也是为什么&ar + 1
和&ar
之间字节的差异是(十六进制)30-20= 16。
我不明白为什么ar + 1
和ar
之间的区别只有8个字节。这意味着数组只能容纳2个int
sá4字节。
我在理解ar[0]
和ar[1]
时遇到了与您在代码中看到的相同的问题。
ar + 1
和&ar + 1
不应该产生同样的结果吗?
发布于 2018-11-26 10:40:52
ar
在表达式中使用时,“衰变”到指向第一个元素的指针。在这种情况下,arr + 1
给出了int (*)[2]
类型指针的算术。它指向大小为8字节的int [2]
。
“阵列衰减”规则在C17 6.3.2.1§3中指定:
除非它是sizeof of操作符的操作数,或者是一元&运算符,或者是用于初始化数组的字符串文字,否则,具有“类型数组”类型的“数组”类型的表达式被转换为带有类型‘指针到类型’的表达式,该表达式指向数组对象的初始元素,而不是lvalue。
因此,当您键入&ar
时,您将从数组衰减规则中得到一个特殊的异常,不会发生衰减,但是您实际上得到了一个预期的int (*)[2][2]
。因此,&ar + 1
给出了16个字节。
发布于 2018-11-26 10:51:26
所以:
sizeof(int) == 4
以下内容如下:
int ar[2][2];
是一个二维数组。
我们知道,a[b]
等于*(a + b)
。而&*
被转换为一无所有。
所以:
&ar[1]
等于
(ar + 1)
在这里,ar
“衰变”或“将被调整”(读为:神奇地转换)为指针。指向两个int元素数组的指针,即。int (*)[2]
。所以它不是int *
或int[2][2]
指针,而是int (*)[2]
。我们知道
sizeof(ar) == sizeof(int[2][2]) == sizeof(int[2]) * 2 == sizeof(int) * 2 * 2
sizeof(*ar) == sizeof(*(int(*)[2]) == sizeof(int[2]) == sizeof(int) * 2
sizeof(**ar) == sizeof(**(*(int(*)[2])) == sizeof(*(int[2])) == sizeof(*(int*)) == sizeof(int)
所以
(ar + 1)
等于(值):
(uintptr_t)ar + sizeof(*ar) * 1 ==
(uintptr_t)ar + sizeof(*(int(*)[2])) * 1) ==
(uintptr_t)ar + sizeof(int[2]) * 1) ==
(uintptr_t)ar + sizeof(int) * 2 * 1)
即。它将ar
指针值递增为2 * sizeof(int)
。
我不明白的是,为什么ar +1和ar之间的区别只有8个字节。
ar + 1
等于
(uintptr_t)ar + sizeof(*ar) + 1
ar
是int[2][2]
,*ar
是int[2]
,sizeof(*ar) = sizeof(int) * 2
也是。
所以ar + 1
等于
(uintptr_t)ar + sizeof(int) * 2 * 1
所以(ar + 1) - ar
等于
((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
sizeof(int[2]) ==
sizeof(int) * 2
ar +1和&ar +1不应该产生相同的结果吗?
对于像int array[2];
这样的数组,array
指针值等于&array
指针值。将address-of运算符应用于数组会导致指向同一内存的数组指针,这是C的一种怪癖。通过array
有一种类型的int[2][2]
,但是&array
有类型的int(*)[2][2]
,即。它是指向2d数组的指针。
由于类型改变,指针算法也会发生变化。typeof(ar)
衰变为typeof(int(*)[2])
,因此ar + 1
等于
`(uintptr_t)ar + sizeof(int[2]) * 1`.
但是因为typeof(&ar) == typeof(int(*)[2][2])
&ar + 1
等于
`(uintrpt_t)ar + sizeof(int[2][2]) * 1`.
因此,当增加指针时,指针值的差异,因为sizeof(int[2][2])
等于sizeof(int) * 2 * 2
。
我认为,如果是2d数组,“第一级”是由两个元素组成的一维数组,而不是整数。因此,typeof(ar[0])
是一个由两个int元素组成的数组。
您的代码有UB,因为%p
修饰符应该只与void*
指针一起使用。最好记住(或者至少知道你应该知道)到printf("%p", (void*)&ar[1][0] + 1);
抛出你的指针。
https://stackoverflow.com/questions/53479169
复制相似问题