在反匯編觀察后,你會發(fā)現(xiàn):指針變量就是塊內(nèi)存區(qū)域,里面存放的是地址,你可以通過這個地址訪問其它內(nèi)存。

                                               數(shù)組就是塊連續(xù)的內(nèi)存區(qū)域,里面連續(xù)排列著同樣size的內(nèi)存,多維數(shù)組也是一樣的。

上述很簡單,就不貼代碼贅述了。

 

但人們一般糾結(jié)這樣一個問題:數(shù)組名 是不是 一種指針?

也就是說arr[]的這個arr是不是一種指針?

 

這個問題之前csdn論壇上討論的熱火朝天:

http://bbs.csdn.net/topics/380226723

http://blog.csdn.net/yby4769250/article/details/7294718#reply

 

一種看法就是把這個數(shù)組名當(dāng)作一種特殊的指針來看待,特殊之處在于是常量,不能改變其指向的位置。

一種是透過C語言,從C語言編譯之后的匯編,視角來看,認(rèn)為數(shù)組名和指針在內(nèi)存中完全不是一回事。

 

太認(rèn)真考慮其定義和概念就接近于一種“玄學(xué)”,我這里就單純講反匯編角度來分析 數(shù)組名 和 指針在內(nèi)存中的差別吧。

隨便寫的代碼:

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

#include <stdio.h>

void func(int *p) {
    *(p+1) = 2;}

void main() {        int v = 1;        int *p = &v;        int v2 = *p + v;        int arr[100];        int v3 = arr[0] + v;        int v4 = *(arr+2) + v2;        func(arr);}

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

 

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

void main() {008114D0  push        ebp  
008114D1  mov         ebp,esp  
008114D3  sub         esp,298h  
008114D9  push        ebx  
008114DA  push        esi  
008114DB  push        edi  
008114DC  lea         edi,[ebp-298h]  
008114E2  mov         ecx,0A6h  
008114E7  mov         eax,0CCCCCCCCh  
008114EC  rep stos    dword ptr es:[edi]  
008114EE  mov         eax,dword ptr ds:[00818000h]  
008114F3  xor         eax,ebp  
008114F5  mov         dword ptr [ebp-4],eax  
        int v = 1;008114F8  mov         dword ptr [v],1  
        int *p = &v;008114FF  lea         eax,[v]  
00811502  mov         dword ptr [p],eax  
        int v2 = *p + v;00811505  mov         eax,dword ptr [p]  
00811508  mov         ecx,dword ptr [eax]  
0081150A  add         ecx,dword ptr [v]  
0081150D  mov         dword ptr [v2],ecx  
        int arr[100];        int v3 = arr[0] + v;00811510  mov         eax,4  00811515  imul        eax,eax,0  00811518  mov         ecx,dword ptr arr[eax]  
0081151F  add         ecx,dword ptr [v]  
00811522  mov         dword ptr [v3],ecx  
        int v4 = *(arr+2) + v2;00811528  mov         eax,dword ptr [ebp-1B4h]  
0081152E  add         eax,dword ptr [v2]  
00811531  mov         dword ptr [v4],eax  
        func(arr);00811537  lea         eax,[arr]  
0081153D  push        eax  
0081153E  call        func (0811226h)  
00811543  add         esp,4  }

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

 可以看到arr[100]這個數(shù)組名arr在匯編代碼中變成了一個單純的標(biāo)號,代表一個地址,這個地址是     數(shù)組這一列連續(xù)內(nèi)存空間的首地址。

假設(shè)數(shù)組地址是N,那么數(shù)組名在匯編代碼中就是N本身。

 

但對比來看,指針在這里是棧空間上申請的內(nèi)存。這塊內(nèi)存里存著別的內(nèi)存的地址。

假設(shè)指針的地址是M,指針指向的內(nèi)存的地址是N,那就是地址為M的內(nèi)存里存著N。

 

二者對比 數(shù)組名和指針的差別就清楚了吧。一個就只是標(biāo)號(地址),一個是一塊內(nèi)存,內(nèi)存里面存著地址。

 

上述是講數(shù)組名 和 指針的差別。

下面要講,

而當(dāng)數(shù)組作為函數(shù)參數(shù)時,其實就是轉(zhuǎn)化為指針來玩的。

 

先講調(diào)用函數(shù)時的反匯編代碼(這里取數(shù)組地址,然后壓入棧再call func):

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

        func(arr);
00811537  lea         eax,[arr]  
0081153D  push        eax  
0081153E  call        func (0811226h)  
00811543  add         esp,4

 

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

 

再講func函數(shù)里面對數(shù)組操作的反匯編代碼:

 

上面的代碼的函數(shù)func:

void func(int *p) {    *(p+1) = 2;
}

反匯編代碼為:

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

void func(int *p) {
00FA3DE0  push        ebp  
00FA3DE1  mov         ebp,esp  
00FA3DE3  sub         esp,0C0h  
00FA3DE9  push        ebx  
00FA3DEA  push        esi  
00FA3DEB  push        edi  
00FA3DEC  lea         edi,[ebp-0C0h]  
00FA3DF2  mov         ecx,30h  
00FA3DF7  mov         eax,0CCCCCCCCh  
00FA3DFC  rep stos    dword ptr es:[edi]  
    *(p+1) = 2;
00FA3DFE  mov         eax,dword ptr [p]  
00FA3E01  mov         dword ptr [eax+4],2  }
00FA3E08  pop         edi  
00FA3E09  pop         esi  
00FA3E0A  pop         ebx  
00FA3E0B  mov         esp,ebp  
00FA3E0D  pop         ebp  
00FA3E0E  ret

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

這里形參為指針,沒什么異議。

 

改寫一下,形參改為,arr[]的話:

void func(int arr[]) {
    arr[1] = 2;
}

 

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

void func(int arr[]) {
01173DE0  push        ebp  
01173DE1  mov         ebp,esp  
01173DE3  sub         esp,0C0h  
01173DE9  push        ebx  
01173DEA  push        esi  
01173DEB  push        edi  
01173DEC  lea         edi,[ebp-0C0h]  
01173DF2  mov         ecx,30h  
01173DF7  mov         eax,0CCCCCCCCh  
01173DFC  rep stos    dword ptr es:[edi]  
    arr[1] = 2;
01173DFE  mov         eax,4  01173E03  shl         eax,0  01173E06  mov         ecx,dword ptr [arr]  
01173E09  mov         dword ptr [ecx+eax],2  }
01173E10  pop         edi  
01173E11  pop         esi  
01173E12  pop         ebx  
01173E13  mov         esp,ebp  
01173E15  pop         ebp  
01173E16  ret

photoshop培訓(xùn),電腦培訓(xùn),電腦維修培訓(xùn),移動軟件開發(fā)培訓(xùn),網(wǎng)站設(shè)計培訓(xùn),網(wǎng)站建設(shè)培訓(xùn)

 

可以看出二者(不管形參寫成*p還是arr[])是沒差別的。

數(shù)組作為函數(shù)參數(shù),都是會被轉(zhuǎn)化為指針來操作。

為何?

 

因為調(diào)用函數(shù)前壓入棧的是數(shù)組的地址,而不是整個數(shù)組。這個地址存在??臻g里,占有一定內(nèi)存,所以成了一個指針!

函數(shù)里面從棧里獲取到這個指針,繼續(xù)操作。

 

這樣是有一定道理的,因為數(shù)組可能很長,如果整個壓入棧就是從新復(fù)制了一份空間,可能非常浪費,還不如指向前一個??臻g里數(shù)組的內(nèi)存。

 

 

 

最后我想說,我玩這個反匯編,似乎沒啥實際用處,比如就算不懂?dāng)?shù)組名 和 指針差別,也可以寫程序啊。

但我總覺得,作為一個程序員,搞明白自己寫的程序,到底是怎么被計算機(jī)運行的,會非常TMD爽。而不只是單純的會寫。

所以我最近決定系統(tǒng)的玩一把反匯編。

讓自己對自己寫的任何一行C、C++代碼都對其運行原理、內(nèi)存都一清二楚,看到C、C++代碼就能迅速想象出匯編代碼的樣子。

下一個課題:徹底搞明白,各種數(shù)據(jù)類型在內(nèi)存中的存儲,又要涉及補碼了。hhh

http://www.cnblogs.com/rixiang/p/7121838.html