[英]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.