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