您好,登錄后才能下訂單哦!
小編給大家分享一下C語言中數組和指針,內存之間的關系是什么,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
首先論證一維數組和一級指針之前的關系,我們常常使用一級指針指針的方式訪問一維數組,只有對內存的理解到位才能理解它們直接的關系。
1.數組名是數組的首地址
2.對數組名取地址得到的還是數組的首地址
3.數組的訪問方式其實就是首地址+偏移的尋址訪問
我們在程序中會定義很多變量,有基本類型和自定義類型
在進行開發的時候我對內存的訪問訪問就是通過變量名賦值的方式讀寫內存
但是如果你看到的直接變量的符號名你將不可能理解內存。
每一種類型都有字節寬度,char 1
字節 short 2字節 int 字節float 4 double 8
,其他的自定義類型也有一個對應的大小,對于通過變量名讀寫操作內存,我們需要自動在腦子里面形成一個映射關系。
int a=10;// 往某段內存地址位x的內存 寫入4個字節的數據10 intp =(int)20; //往某段內存地址位x1的內存 寫入4個字節的數據20 int** p =(int**)30;// 往某段內存地址位x2的內存 寫入4個字節的數據30 int b = a; //讀取某段內存地址為x的內存 讀取4給字節數據值 寫入首地址為b的某段內存 寬度為4,
對于賦值讀寫需要腦子里面自動分割成一塊塊內存然后將變量符號名字與對于的首地址(還有寬度)對于起來,忽略數據類型的概念,對于一個變量只關注首地址+數據寬度。
對于使用指針訪問數組如圖下所示
基本上有點基礎的都可以看出來使用直接使用數組arr和使用指針p相比少了
arr是首地址+偏移 然后直接往這個地址里面讀或者寫
指針的操作方式首先需要得到p對象 所占的空間里面存放的值(這里是數組首地址)然后再通過存放的值+偏移的方式 讀寫內存
int* p =arr; 把p這個對象 賦值數組首地址 任何指針類型32位下4個字節 64位下8個字節,p這個對象需要4個字節的空間存儲arr值,因為p是一個變量,占4個字節 int* p=arr;就是 往p所占的4個字節里面存儲arr值首地址
而通過p[_i]下標訪問的時候 首先就需要 取出來p里面存的四個字節值y
然后y+偏移的方式 訪問讀或者寫該指針指向數組中的內容
從上面的結果我們可以得到,別看到一級指針操作一維數組 和數組直接訪問問之前只多了一層指針變量的尋址,但是含義就完全的變了。
如有些書上說數組作為實參會退化為指針
lea eax,[arr] 是數組首地址保存到eax寄存器中
push eax 參數入棧 此時esp寄存器的值減4,push eax相當與啥?相當于創建了一個零時對象 占4個字節的指針,傳遞過去,首地址值訪問一塊4個字節的內存后這段4個字節的內存后編譯器認為這是一個指針,所以funtion里面使用sizeof可以看到占4個字節(可以私下去測試),所以把編譯器給的類型去掉后 。
int a = (int)arr; 往a占的4個字節內存中寫入數組首地址,從匯編的角度來看,是不是找到一絲熟悉的感覺了,沒錯下面這兩個除了編譯器附加的一些類型的限制之外沒有區別,甚至可以說是完全一樣的,我們完全可以使用一個int a;操作任何基本類型和抽象類型對象
int a= (int)arr; int* p =arr;
函數傳遞一級指針和二級指針
下圖可以看到傳遞一級是將p的地址ebp-0x3c里面存儲的內容 push到棧中傳參
而傳遞二級指針的時候是lea 得到ebp-0x3c
這個值 p的地址傳遞進去
所以對于二級指針而言 我們很容易在funtion2函數里面改變被調用函數里面p指向的內容
(這種方式多與一些庫的設計 如ffmpeg 的一些函數設計傳遞一個一級指針的地址進去(指向NULL)函數里面可以創建某些對象然后然后改變被調函數的指針,釋放的時候同理,這樣可以減少開發者所作的工作
可以用一級指針指針引用一位數組,以前剛學習的時候我自認而然的使用二級指針引用二維數組,發現是不可以。
進程的內存就是線性的32位可以尋址00000000-0xffffffff 4gb,從內存的角度看沒有二維數組的概念,也沒有多維數組的概念,對于任何一個變量,關注的應該都是首地址,寬度
int arr[4][3] ; 在內存布局上可以 int arr[12];是完全一樣的沒有任何區別
二維數組或者多維數組的設計知識為了理解的方便,比如使用二維數組可以更加直觀的表示一個nm地圖的狀態,使用一維度的話沒有那么的直觀。三維數組可以讓我們更直觀的表示一個空間的概念,其實它們內存也就是一個一線性的一維數組int arr[4][3]
我們通過 arr[_i][_j]的訪問方式mov eax,[_i];
首先得到_i的值保存到eax寄存器中lea ecx,arrtow[eax4];
lea指令是得到[]里面的地址 arrtow首地址 + _i41(char占1個字節如果是其他類型需要對應大小)mov edx ,[_j] ;edx
寄存器保存_j的值movsx eax.byte ptr[ecx+edx]
就是arrtow+_i41+_j1 取出這個內存編號中的值取一個字節放入eax寄存器中 char到int有一個轉換
mov [a],eax 放入a變量所在的地址中 四個字節
可以看到二維數組其實也是一個一維數組 首地址+_im寬度+j*寬度的尋址方式
三維數組同理
二級指針不能引用二維數組是因為是因為二級指針操作內存的方式和二維數組的完全不同,一級指針可以引用一維數組是因為它們操作內存的方式是相同的
lea eax,[arrtow] mov dword ptr [pp],eax //這兩行把char** pp = (char**)arrtow arrtow值給 pp變量 mov eax,dword ptr [_i]; //_i的值保存在eax寄存器中 mov ecx.dword ptd[pp]; //得到pp中存儲的值 就是arrtow值(數組首地址) mov edx,dword ptr [ecx+eax4] // 數組首地址+_i4的值 指針寬度占4個字節, 將arrtow+_i 4位首地址讀取四個字節 到edx寄存器 (這里就尋址了一次) mov eax.dword ptr [_j]; //讀取_j的值存放在eax寄存器中 movsx ecx,byte ptr [edx+eax]//把在arrtow+_i4地址處取的四個字節數據當做首地址 +_j再次當作首地址取一個字節 當如ecx寄存器 mov dword ptr [a],ecx, 放入a變量中
通過二級指針和二維數組訪問內存的方式不同,可以明白為啥不能使用二級指針直接訪問二維數組,同理三級指針尋址3次,四級指針4次,不管多少維數組都是和一維數組一樣一次,所以如果我把斷點繼續指行就會應為訪問未知地址掛掉。
再次將論點移到內存,我們所作的一切都只是對內存的訪問,而C/C++一不小心就會出現對內存的非法的訪問,所以了解內存是一件非常重要的事情,而指針只是訪問操作內存的一種靈活的方式。和前面說的一樣,任何指針占,所以任何一個4個字節的內存單元 一個int的大小 可以以任何的指針的方式訪問內存,極度的靈活(如果對內存沒有足夠的理解同時就會導致極度的不安全),
以上是“C語言中數組和指針,內存之間的關系是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。