繁体   English   中英

了解C中数组元素中的已分配内存地址(Windows 10中为gcc)

[英]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 + 1ar之间的区别只有8个字节。 这将意味着,在阵列只能容纳2 int S A的4个字节。

正如您在我的代码中看到的那样,我在理解ar[0]ar[1]遇到了同样的问题。

ar + 1&ar + 1是否应该产生相同的结果?

就您而言, ar是一个数组。 因此,首先请记住

  • arint [2][2] ,它是int s的数组
  • &arint (*)[2][2] ,即指向2个int s数组的指针。

也就是说,在某些情况下,数组类型会衰减到指向数组第一个元素的指针。 注意

所以,如果像

ar + 1

与...相同

(&(ar[0])) + 1;

它基本上指向ar[1]

我不明白的是为什么ar + 1ar之间的区别只有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 + 1int (*)[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

由于arint[2][2] ,因此*arint[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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM