釋出
2008年1月14日

陣列不是指標

評分:3.3/5 (37 票)
*****
非常感謝這些有用的教程,我覺得有必要寫這篇關於指標和陣列的文章。不幸的是,糾正人們腦海中錯誤的觀念有點困難。因此,準確地理解事物非常重要,以避免進一步的誤解。

陣列不等於指標。它是在記憶體中一系列簡單的變數。

當我們寫
1
2
int array[3];
array[2]=666;


C/C++ 編譯器不將 array[0] 視為指向整數值的地址,而是直接將其視為一個值,就像寫一樣
1
2
int var;
var=66;


顯而易見,“var”不是指標,就像 array[2] 不是一樣。

但是,如果我們使用指標而不是陣列,程式碼的表象是相同的,但編譯器會生成不同的彙編程式碼。例如
1
2
int *ptr = new int[3];
ptr[2] = 66;


與第一段程式碼類似,但對編譯器而言含義不同。在第一段程式碼(第二行)中,編譯器生成的程式碼將執行以下操作

1)轉到 array[0] 下兩個位置,並將其值設定為 666。

但在使用指標的程式碼中是
1)獲取 ptr[0] 的值(地址)。
2)在其上加二。
3)將其指向的值設定為 66。

實際上,“array”、“&array”和“&array[0]”的值是相等的。但是“&array”的型別是不同的(指向陣列的記憶體地址,而不是陣列的成員)。

這裡是另一個例子,使文章更容易理解。我想寫一個程式,從使用者那裡獲取一個整數,加 4,然後列印結果。一次使用整數指標,一次使用整數變數。
使用整數變數將是
1
2
3
4
5
6
7
#include<iostream>
main(){
    int int_input;
    cin>>int_input;
    cout<<(int_input + 4)<<endl;
    return 0;
}


使用指標將是
1
2
3
4
5
6
7
8
#include<iostream>
main(){
    int *int_ptr = new int[1];
    cin>>*int_ptr;
    cout<< (*int_ptr + 4)<<endl;
    delete(int_ptr);
    return 0;
}


誰認為這些程式完全相同?
讓我們看看它們的彙編。對於第一個使用整數變數的程式碼是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2212: main(){
00401000   push        ebp
00401001   mov         ebp,esp
00401003   sub         esp,44h
00401006   push        ebx
00401007   push        esi
00401008   push        edi
2213:     int int_input;
2214:     cin>>int_input;
00401009   lea         eax,[ebp-4]
0040100C   push        eax
0040100D   mov         ecx,offset cin (00414c58)
00401012   call        istream::operator>> (0040b7c0)
2215:     cout<<(int_input+4)<<endl;
00401017   push        offset endl (00401070)
0040101C   mov         ecx,dword ptr [ebp-4]
0040101F   add         ecx,4
00401022   push        ecx
00401023   mov         ecx,offset cout (00414c18)
00401028   call        ostream::operator<< (0040b3e0)
0040102D   mov         ecx,eax
0040102F   call        ostream::operator<< (00401040)
2216:     return 0;
00401034   xor         eax,eax
2217: }


而對於使用指標的程式碼是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2212: main(){
00401000   push        ebp
00401001   mov         ebp,esp
00401003   sub         esp,4Ch
00401006   push        ebx
00401007   push        esi
00401008   push        edi
2213:     int *int_ptr = new int[1];
00401009   push        4
0040100B   call        operator new (004011b0)
00401010   add         esp,4
00401013   mov         dword ptr [ebp-8],eax
00401016   mov         eax,dword ptr [ebp-8]
00401019   mov         dword ptr [ebp-4],eax
2214:     cin>>*int_ptr;
0040101C   mov         ecx,dword ptr [ebp-4]
0040101F   push        ecx
00401020   mov         ecx,offset cin (00414c38)
00401025   call        istream::operator>> (0040b8a0)
2215:     cout<< (*int_ptr + 4)<<endl;
0040102A   push        offset endl (004010a0)
0040102F   mov         edx,dword ptr [ebp-4]
00401032   mov         eax,dword ptr [edx]
00401034   add         eax,4
00401037   push        eax
00401038   mov         ecx,offset cout (00414bf8)
0040103D   call        ostream::operator<< (0040b4c0)
00401042   mov         ecx,eax
00401044   call        ostream::operator<< (00401070)
2216:     delete(int_ptr);
00401049   mov         ecx,dword ptr [ebp-4]
0040104C   mov         dword ptr [ebp-0Ch],ecx
0040104F   mov         edx,dword ptr [ebp-0Ch]
00401052   push        edx
00401053   call        operator delete (00401120)
00401058   add         esp,4
2217:     return 0;
0040105B   xor         eax,eax
2218: }


19 行 vs 32 行。因此,您可以看到,整數與“指向整數的指標”是不同的。整數是儲存整數的記憶體位置,而整數指標(指向整數的指標)是儲存地址的記憶體位置。編譯器知道這是一個指向儲存整數的記憶體位置的地址。我不會解釋彙編程式碼,因為這篇文章是為初學者準備的,我想保持簡短。

正如我所說,陣列是記憶體中一系列變數。在上面的例子中,我得出結論,指標不是整數變數,因此它也不可能是它們的序列。

請隨時傳送您對本文的評論和想法。