[英]How come an array's address is equal to its value in C?
在以下代碼中,指針值和指針地址與預期不同。
但是數組值和地址沒有!
怎么會這樣?
輸出
my_array = 0022FF00
&my_array = 0022FF00
pointer_to_array = 0022FF00
&pointer_to_array = 0022FEFC
#include <stdio.h>
int main()
{
char my_array[100] = "some cool string";
printf("my_array = %p\n", my_array);
printf("&my_array = %p\n", &my_array);
char *pointer_to_array = my_array;
printf("pointer_to_array = %p\n", pointer_to_array);
printf("&pointer_to_array = %p\n", &pointer_to_array);
printf("Press ENTER to continue...\n");
getchar();
return 0;
}
數組的名字通常是數組第一個元素的地址,所以array
和&array
有相同的值(但是類型不同,所以如果數組大於1, array+1
和&array+1
就不相等了元素長)。
對此有兩個例外:當數組名稱是sizeof
或一元&
(address-of) 的操作數時,名稱指的是數組對象本身。 因此sizeof array
為您提供整個數組的字節大小,而不是指針的大小。
對於定義為T array[size]
,它將具有類型T *
。 當/如果你增加它,你會得到數組中的下一個元素。
&array
計算到相同的地址,但給定相同的定義,它創建一個T(*)[size]
類型的指針——即,它是一個指向數組的指針,而不是指向單個元素。 如果你增加這個指針,它會增加整個數組的大小,而不是單個元素的大小。 例如,使用這樣的代碼:
char array[16];
printf("%p\t%p", (void*)&array, (void*)(&array+1));
我們可以期望第二個指針比第一個大 16 個(因為它是一個 16 個字符的數組)。 由於 %p 通常以十六進制轉換指針,因此它可能類似於:
0x12341000 0x12341010
這是因為數組名稱( my_array
) 不同於指向數組的指針。 它是數組地址的別名,它的地址定義為數組本身的地址。
然而,指針是堆棧上的一個普通 C 變量。 因此,您可以獲取其地址並獲得與其內部保存的地址不同的值。
我在這里寫過這個話題 - 請看一看。
在 C 中,當您在表達式中使用數組的名稱時(包括將其傳遞給函數),除非它是 address-of ( &
) 運算符或sizeof
運算符的操作數,否則它會衰減為指向其第一個的指針元素。
也就是說,在大多數情況下, array
在類型和值上都等價於&array[0]
。
在您的示例中, my_array
類型為char[100]
,當您將其傳遞給 printf 時,它會衰減為char*
。
&my_array
類型為char (*)[100]
(指向 100 個char
數組的指針)。 由於它是&
的操作數,這是my_array
不會立即衰減到指向其第一個元素的指針的一種情況。
指向數組的指針與指向數組第一個元素的指針具有相同的地址值,因為數組對象只是其元素的連續序列,但指向數組的指針與指向數組元素的指針具有不同的類型那個數組。 當您對兩種類型的指針進行指針運算時,這一點很重要。
pointer_to_array
具有類型char *
-初始化為點在陣列的第一個元素,因為這是什么my_array
衰減到在初始化表達-和&pointer_to_array
具有類型char **
(指針的指針到一個char
)。
其中: my_array
(衰減到char*
)、 &my_array
和pointer_to_array
都直接指向數組或數組的第一個元素,因此具有相同的地址值。
當您查看數組的內存布局時,很容易理解my_array
和&my_array
產生相同地址的原因。
假設您有一個包含 10 個字符的數組(而不是代碼中的 100 個)。
char my_array[10];
my_array
內存類似於:
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array.
在 C/C++ 中,數組衰減到指向表達式中第一個元素的指針,例如
printf("my_array = %p\n", my_array);
如果您檢查數組的第一個元素所在的位置,您將看到它的地址與數組的地址相同:
my_array[0]
|
v
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array[0].
在 B 編程語言中,它是 C 的直接前身,指針和整數可以自由互換。 系統會表現得好像所有內存都是一個巨大的數組。 每個變量名都有一個與之關聯的全局或堆棧相關地址,對於每個變量名,編譯器唯一需要跟蹤的是它是全局變量還是局部變量,以及它相對於第一個全局或局部變量的地址多變的。
給定一個像i;
這樣的全局聲明i;
[不需要指定類型,因為一切都是整數/指針]將被編譯器處理為: address_of_i = next_global++; memory[address_of_i] = 0;
address_of_i = next_global++; memory[address_of_i] = 0;
並且像i++
這樣的語句將被處理為: memory[address_of_i] = memory[address_of_i]+1;
.
類似arr[10];
聲明arr[10];
將被處理為address_of_arr = next_global; memory[next_global] = next_global; next_global += 10;
address_of_arr = next_global; memory[next_global] = next_global; next_global += 10;
. 請注意,一旦處理了該聲明,編譯器就會立即忘記arr
是一個數組。 類似arr[i]=6;
語句arr[i]=6;
將被處理為memory[memory[address_of_a] + memory[address_of_i]] = 6;
. 編譯器不會關心arr
是否代表數組而i
是整數,反之亦然。 事實上,它不會在乎它們是數組還是整數; 它會很高興地生成所描述的代碼,而不考慮由此產生的行為是否可能有用。
C 編程語言的目標之一是在很大程度上與 B 兼容。在 B 中,數組的名稱 [在 B 的術語中稱為“向量”] 標識了一個變量,該變量包含一個指針,該指針最初被分配為指向到給定大小的分配的第一個元素,因此如果該名稱出現在函數的參數列表中,則該函數將收到一個指向該向量的指針。 盡管 C 添加了“真正的”數組類型,其名稱與分配的地址嚴格相關,而不是最初指向分配的指針變量,但將數組分解為指針使得聲明 C 類型數組的代碼行為相同到 B 代碼,它聲明了一個向量,然后從不修改保存其地址的變量。
實際上&myarray
和myarray
都是基地址。
如果您想查看差異而不是使用
printf("my_array = %p\n", my_array);
printf("my_array = %p\n", &my_array);
用
printf("my_array = %s\n", my_array);
printf("my_array = %p\n", my_array);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.