陣列名取位址的含義

2021-09-07 15:49:33 字數 3083 閱讀 5452

1、變數名在編譯階段被編譯器替換成儲存該變數值的記憶體空間的首位址,簡單說:變數名代表儲存該變數的記憶體空間首位址。

例如:定義乙個int型變數

int a=10;   //int型變數的用4個連續的位元組儲存,變數名a代表第乙個位元組的位址。

double b=12.1;    //double型變數用8個連續的位元組儲存,變數名b代表第乙個位元組的位址。

2、陣列名也不例外,也是代表儲存該陣列的記憶體空間的首位址。

例如:定義乙個int型陣列

int arr[3]=;   //int型陣列有3個元素,所以用12個連續的位元組儲存,陣列名a代表第乙個位元組的首位址。

double d[3]=;    //double型陣列有3個元素,所以用24個連續的位元組儲存,陣列名d代表第乙個位元組的首位址。

3、但是,陣列有一點特殊的是,陣列是一系列同型別元素的集合,c語言需要有乙個指向單個元素的指標,方便操作各個元素。所以,編譯器會根據上下文環境,自動的把陣列名轉換為陣列首元素的位址,這樣,就可以通過加減指標來指向陣列中的各個元素了。

例如:

int arr[3]=;

printf(

"arr[0]=%d\n

",*arr);

printf(

"arr[1]=%d\n

",*(arr+1

)); //注意arr會被編譯器直接替換為陣列首元素位址,所以是直接量,所以不能被改變,這裡返回的是表示式*(arr+1)的值

printf(

"arr[2]=%d\n

",*(arr+2));

4、但是,有的時候我們又需要引用整個陣列,比如用sizeof求陣列的大小,或者求整個陣列結構的首位址,不要擔心,聰明的編譯器會看出我們的需要。

例如:

int arr[3]=;

printf(

"arr size=%zu

",sizeof(arr)); //

這裡我們需要整個陣列的大小,而不是乙個指標的大小,聰明的編譯器根據sizeof操作符知道我們要的是整個陣列的大小。

int (*pa)[3

];//

因為pa指標是指向乙個陣列型別,該型別有3個int型元素。編譯器根據有沒有&符號,判斷你要的是陣列首元素位址,還是陣列的首位址。

pa=&arr; //

雖然陣列首元素位址和陣列首位址的值是一樣的,但型別是不同的,通俗的說大小是不同的,首元素位址指代的是乙個元素的大小,首位址指代整個陣列的大小。

5、用程式驗證一下:

#include int a[3]=;

intmain()

輸出結果為:

fly@noi:~$ ./t

a=0x601038

a+1=0x60103c //a+1偏移了4個位元組,說明a指向陣列首元素的位址

&a=0x601038

&a+1=0x601044 //&a+1偏移了12個位元組,說明a指向陣列首位址

檢視一下彙編版本是如果做的:

//gcc預設是at&t格式的彙編,還可以通過:gcc -s -masm=intel t.c > t.s,轉換為intel格式。

gcc -s t.c > t.s

vim t.s

輸出:

.file    "t.c"

.globl    a

.data

.align 8

.type    a, @object

.size    a, 12

a:.long    1

.long    2

.long    3

.section    .rodata

.lc0:

.string    "a=%p\n"

.lc1:

.string    "a+1=%p\n"

.lc2:

.string    "&a=%p\n"

.lc3:

.string    "&a+1=%p\n"

.text

.globl    main

.type    main, @function

main:

.lfb0:

.cfi_startproc

pushq    %rbp

.cfi_def_cfa_offset 16

.cfi_offset 6, -16

movq    %rsp, %rbp

.cfi_def_cfa_register 6

movl    $a, %esi

movl    $.lc0, %edi

movl    $0, %eax

call    printf

movl    $a+4, %eax //看到沒,雖然**裡面沒有給a加取位址的&符,但是在彙編裡面仍然取了a的位址,只不過被編譯器當作是首元素的位址

movq    %rax, %rsi

movl    $.lc1, %edi

movl    $0, %eax

call    printf

movl    $a, %esi

movl    $.lc2, %edi

movl    $0, %eax

call    printf

movl    $a+12, %eax //哈哈,找到了,果然是加了12,表明編譯器把&a當作陣列的首位址,&a+1就是跨越了整個陣列。

movq    %rax, %rsi

movl    $.lc3, %edi

movl    $0, %eax

call    printf

movl    $0, %eax

popq    %rbp

.cfi_def_cfa 7, 8

ret.cfi_endproc

.lfe0:

.size    main, .-main

.ident    "gcc: (ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"

.section    .note.gnu-stack,"",@progbits

陣列名和陣列名取位址

在c中,在幾乎所有使用陣列的表示式中,陣列名的值是個指標常量 也就是陣列第乙個元素的位址。它的型別取決於陣列元素的型別 如果它們是int型別,那麼陣列名的型別就是 指向int的常量指標 在以下兩種場合下,陣列名並不是用指標常量來表示,就是當陣列名作為sizeof操作符和單目操作符 的運算元時。siz...

陣列名和陣列名取位址

1 int a 10 2 int p a 3 int q 10 a 第二個為指向陣列的指標.a只是a 0 的位址,a 1就是a 1 的位址了,a是整個a 10 的首位址,是以整個陣列為角度來看,雖然它與a 0 的值相同,但是 a 1就已經增加了10個int型別的位元組的長度了.1 include 2...

陣列名和陣列名取位址的區別

以下 會列印出什麼樣的日誌呢?cpp view plain copy include int a 2 int main 本機 linux 結果輸出 a 0x804a014 a 0x804a014 a 1 0x804a018 a 1 0x804a01c 沒錯,上面i 和 ii列印出來的位址是一樣的,i...