[英]Understanding allocated memory addresses in array elements in C (gcc in Windows 10)
我试图掌握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
,在我的系统上为4x4 = 16个字节。 我猜这也是为什么&ar + 1
和&ar
之间的字节差为(hex) &ar
= 16的原因。
我不明白的是为什么ar + 1
和ar
之间的区别只有8个字节。 这将意味着,在阵列只能容纳2 int
S A的4个字节。
正如您在我的代码中看到的那样,我在理解ar[0]
和ar[1]
遇到了同样的问题。
ar + 1
和&ar + 1
是否应该产生相同的结果?
就您而言, ar
是一个数组。 因此,首先请记住
ar
是int [2][2]
,它是int
s的数组 &ar
是int (*)[2][2]
,即指向2个int
s数组的指针。 也就是说,在某些情况下,数组类型会衰减到指向数组第一个元素的指针。 注意
所以,如果像
ar + 1
与...相同
(&(ar[0])) + 1;
它基本上指向ar[1]
。
我不明白的是为什么
ar + 1
和ar
之间的区别只有8个字节
因此,这里的“差异”是由ar[0]
元素占用的大小确定的,即2 ints
,在您的平台中为8个字节。 结果签出。
另一方面,对于像
&ar + 1;
它对指针类型进行操作(如前所述),并指向数组中最后一个元素之后的位置。 因此, 不同之处在于,对于每个2个int
的2个数组,因此(2 * 2 * 4)= 16个字节。
注意:
引用C11
,第§6.3.2.1章
除非它是
sizeof
运算符,_Alignof
运算符或一元&
运算符的操作数,或者是用于初始化数组的字符串文字,否则将类型为“ array of type”的表达式转换为带有键入“指向类型的指针” ,它指向数组对象的初始元素,而不是左值。 [....]
ar
在表达式中使用时,“衰减”到第一个元素的指针。 在这种情况下, arr + 1
对int (*)[2]
类型的指针进行算术运算。 指向大小为8个字节的int [2]
。
C17 6.3.2.1§3中规定了“阵列衰减”的规则:
除非它是sizeof运算符的操作数或一元&运算符,或者是用于初始化数组的字符串文字,否则将类型为“ array of type”的表达式转换为类型为“ pointer”的表达式输入'',指向数组对象的初始元素,不是左值
因此,当您输入&ar
,会从数组衰减规则中获得特殊异常,不会发生衰减,但实际上会得到预期的int (*)[2][2]
。 因此&ar + 1
给出16个字节。
所以:
sizeof(int) == 4
下列:
int ar[2][2];
是2D数组。
我们知道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];
这样的int array[2];
array
指针值等于&array
指针值。 这是C的怪癖,将address-of运算符应用于数组会导致指向同一内存的数组指针。 Through 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数组的情况,“第一”级别是两个元素的1d数组,而第二个级别是int。 所以typeof(ar[0])
是两个int元素的数组。
您的代码具有UB,因为%p
修饰符仅应与void*
指针一起使用。 最好记住(或至少知道应该printf("%p", (void*)&ar[1][0] + 1);
) printf("%p", (void*)&ar[1][0] + 1);
投下你的指针。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.