简体   繁体   English

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

[英]Understanding allocated memory addresses in array elements in C (gcc in Windows 10)

I'm trying to get a grip on pointers and arrays in C. Now, I'm stuck on trying to figure out how my C compiler allocates memory for the elements in a two dimensional array. 我试图掌握C中的指针和数组。现在,我坚持试图弄清楚C编译器如何为二维数组中的元素分配内存。 Here's my example code: 这是我的示例代码:

#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;
}

The output I get on my system is: 我在系统上得到的输出是:

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
-----

I understand why ar is 16 bytes in size; 我明白为什么ar大小为16个字节; it should be able to hold 4 int s, which on my system is 4x4 = 16 bytes. 它应该能够容纳4个int ,在我的系统上为4x4 = 16个字节。 This, I guess, is also why the difference in bytes between &ar + 1 and &ar is (hex) 30 - 20 = 16. 我猜这也是为什么&ar + 1&ar之间的字节差为(hex) &ar = 16的原因。

What I don't understand is why the difference between ar + 1 and ar is only 8 bytes. 我不明白的是为什么ar + 1ar之间的区别只有8个字节。 This would mean that the array can only hold 2 int s á 4 bytes. 这将意味着,在阵列只能容纳2 int S A的4个字节。

I have the same problem understanding ar[0] and ar[1] as you can see in my code. 正如您在我的代码中看到的那样,我在理解ar[0]ar[1]遇到了同样的问题。

Shouldn't ar + 1 and &ar + 1 produce the same result? ar + 1&ar + 1是否应该产生相同的结果?

In your case, ar is an array. 就您而言, ar是一个数组。 Hence, first of all, remember 因此,首先请记住

  • ar is type of int [2][2] , which is an array of array of int s arint [2][2] ,它是int s的数组
  • &ar is of type int (*)[2][2] , ie, pointer to an array of array of 2 int s. &arint (*)[2][2] ,即指向2个int s数组的指针。

That said, array type, in cases, decay to the pointer to the first element of the array. 也就是说,在某些情况下,数组类型会衰减到指向数组第一个元素的指针。 Note 注意

So, in case of an expression like 所以,如果像

ar + 1

is just the same as 与...相同

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

which basically points to ar[1] . 它基本上指向ar[1]

What I don't understand is why the difference between ar + 1 and ar is only 8 bytes 我不明白的是为什么ar + 1ar之间的区别只有8个字节

So, the "difference" here, is by the size occupied by the elements of ar[0] , which is , 2 ints , which is, in your platform, 8 bytes. 因此,这里的“差异”是由ar[0]元素占用的大小确定的,即2 ints ,在您的平台中为8个字节。 Result checks out. 结果签出。

On the other hand, for an expression like 另一方面,对于像

&ar + 1;

it operates on the pointer type (as mentioned earlier), and points to the location one past the last element in the array. 它对指针类型进行操作(如前所述),并指向数组中最后一个元素之后的位置。 So, the difference is, for 2 arrays of 2 int s each, hence (2*2*4) = 16 bytes. 因此, 不同之处在于,对于每个2个int的2个数组,因此(2 * 2 * 4)= 16个字节。


Note: 注意:

Quoting C11 , chapter §6.3.2.1 引用C11 ,第§6.3.2.1章

Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue. 除非它是sizeof运算符, _Alignof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则将类型为“ array of type”的表达式转换为带有键入“指向类型的指针” ,它指向数组对象的初始元素,而不是左值。 [....] [....]

ar , when used in an expression, "decays" to a pointer to the first element. ar在表达式中使用时,“衰减”到第一个元素的指针。 In this case, arr + 1 gives arithmetic on a pointer of type int (*)[2] . 在这种情况下, arr + 1int (*)[2]类型的指针进行算术运算。 Which points to an int [2] with size 8 bytes. 指向大小为8个字节的int [2]

This rule of "array decay" is specified in C17 6.3.2.1 §3: C17 6.3.2.1§3中规定了“阵列衰减”的规则:

Except when it is the operand of the sizeof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue 除非它是sizeof运算符的操作数或一元&运算符,或者是用于初始化数组的字符串文字,否则将类型为“ array of type”的表达式转换为类型为“ pointer”的表达式输入'',指向数组对象的初始元素,不是左值

So when you type &ar , you get the special exception from the array decay rule, no decay takes place but you actually get an int (*)[2][2] as expected. 因此,当您输入&ar ,会从数组衰减规则中获得特殊异常,不会发生衰减,但实际上会得到预期的int (*)[2][2] And therefore &ar + 1 gives 16 bytes. 因此&ar + 1给出16个字节。

So: 所以:

sizeof(int) == 4

The following: 下列:

int ar[2][2];

is a 2D array. 是2D数组。

We know that, a[b] is equal to *(a + b) . 我们知道a[b]等于*(a + b) And &* is converted to nothing. &*被转换为空。

So: 所以:

&ar[1]

is equal to 等于

(ar + 1)

here ar "decays" or "shall be adjusted" (read as: magically converts) into a pointer. 这里ar “衰变”或“应调整”(读作:神奇地转换)转换成一个指针。 A pointer to an array of two int elements, ie. 指向两个int元素的数组的指针,即。 int (*)[2] . int (*)[2] So it's not an int * nor int[2][2] pointer but int (*)[2] . 因此它不是int *int[2][2]指针,而是int (*)[2] We know that 我们知道

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)

So 所以

(ar + 1)

is equal to (to the value): 等于(等于)值:

(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)

ie. 即。 it increments the ar pointer value by 2 * sizeof(int) . 它将ar指针值增加2 * sizeof(int)

What I don't understand is why the difference between ar + 1 and ar is only 8 bytes. 我不明白的是为什么ar + 1和ar之间的区别只有8个字节。

ar + 1 is equal to ar + 1等于

(uintptr_t)ar + sizeof(*ar) + 1

As ar is int[2][2] , then *ar is int[2] , so sizeof(*ar) = sizeof(int) * 2 . 由于arint[2][2] ,因此*arint[2] ,因此sizeof(*ar) = sizeof(int) * 2
So ar + 1 is equal to 所以ar + 1等于

(uintptr_t)ar + sizeof(int) * 2 * 1

So (ar + 1) - ar is equal to 因此(ar + 1) - ar等于

((uintptr_t)ar + sizeof(int[2]) * 1) - (uintrpt_t)ar ==
    sizeof(int[2]) == 
    sizeof(int) * 2

Shouldn't ar + 1 and &ar + 1 produce the same result? ar +1和&ar +1是否应该产生相同的结果?

In case of arrays like int array[2]; 对于像int array[2];这样的int array[2]; The array pointer value is equal to &array pointer value. array指针值等于&array指针值。 It is a quirk of C, that applying the address-of operator to an array results in array pointer to the same memory. 这是C的怪癖,将address-of运算符应用于数组会导致指向同一内存的数组指针。 Through array has a type of int[2][2] , but &array has the type of int(*)[2][2] , ie. Through array的类型为int[2][2] ,而&array的类型为int(*)[2][2] ,即。 it is a pointer to 2d array. 它是指向2d数组的指针。

Because the type changes, the pointer arithmetics changes. 由于类型更改,因此指针算法也会更改。 Teh typeof(ar) decays to typeof(int(*)[2]) so the ar + 1 is equal to typeof(ar)衰减为typeof(int(*)[2])因此ar + 1等于

`(uintptr_t)ar + sizeof(int[2]) * 1`. 

But because the typeof(&ar) == typeof(int(*)[2][2]) the &ar + 1 is equal to 但是因为typeof(&ar) == typeof(int(*)[2][2])所以&ar + 1等于

`(uintrpt_t)ar + sizeof(int[2][2]) * 1`.

hence the difference in pointer value when incrementing the pointer, as sizeof(int[2][2]) is equal to sizeof(int) * 2 * 2 . 因此,当sizeof(int[2][2])等于sizeof(int) * 2 * 2时,增加指针时指针值的差。

I think you fail to grasp that in case of 2d arrays, the "first" level is 1d array of two elements, than the second is an int. 我认为您无法掌握2d数组的情况,“第一”级别是两个元素的1d数组,而第二个级别是int。 So typeof(ar[0]) is an array of two int elements. 所以typeof(ar[0])是两个int元素的数组。

Your code has UB, as the %p modifer should be used only with void* pointers. 您的代码具有UB,因为%p修饰符仅应与void*指针一起使用。 It's best to remember (or at least know that you should) to printf("%p", (void*)&ar[1][0] + 1); 最好记住(或至少知道应该printf("%p", (void*)&ar[1][0] + 1);printf("%p", (void*)&ar[1][0] + 1); cast your pointers. 投下你的指针。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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