欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言數(shù)組和指針,內(nèi)存之間的關系

 更新時間:2022年02月03日 10:52:51   作者:伴你永居我憶i ?  
這篇文章主要介紹了C語言數(shù)組和指針,內(nèi)存之間的關系,首先論證一維數(shù)組和一級指針之前的關系,我們常常使用一級指針指針的方式訪問一維數(shù)組,只有對內(nèi)存的理解到位才能理解它們直接的關系。需要的小伙伴可以參考一下

首先論證一維數(shù)組和一級指針之前的關系,我們常常使用一級指針指針的方式訪問一維數(shù)組,只有對內(nèi)存的理解到位才能理解它們直接的關系。

  • 1.數(shù)組名是數(shù)組的首地址
  • 2.對數(shù)組名取地址得到的還是數(shù)組的首地址
  • 3.數(shù)組的訪問方式其實就是首地址+偏移的尋址訪問

我們在程序中會定義很多變量,有基本類型和自定義類型
在進行開發(fā)的時候我對內(nèi)存的訪問訪問就是通過變量名賦值的方式讀寫內(nèi)存
但是如果你看到的直接變量的符號名你將不可能理解內(nèi)存。
每一種類型都有字節(jié)寬度,
char 1字節(jié) short 2字節(jié) int 字節(jié)float 4 double 8,其他的自定義類型也有一個對應的大小,對于通過變量名讀寫操作內(nèi)存,我們需要自動在腦子里面形成一個映射關系。

int a=10;// 往某段內(nèi)存地址位x的內(nèi)存 寫入4個字節(jié)的數(shù)據(jù)10
intp =(int)20; //往某段內(nèi)存地址位x1的內(nèi)存 寫入4個字節(jié)的數(shù)據(jù)20
int** p =(int**)30;// 往某段內(nèi)存地址位x2的內(nèi)存 寫入4個字節(jié)的數(shù)據(jù)30
int b = a; //讀取某段內(nèi)存地址為x的內(nèi)存 讀取4給字節(jié)數(shù)據(jù)值 寫入首地址為b的某段內(nèi)存 寬度為4,

對于賦值讀寫需要腦子里面自動分割成一塊塊內(nèi)存然后將變量符號名字與對于的首地址(還有寬度)對于起來,忽略數(shù)據(jù)類型的概念,對于一個變量只關注首地址+數(shù)據(jù)寬度。

對于使用指針訪問數(shù)組如圖下所示
基本上有點基礎的都可以看出來使用直接使用數(shù)組arr和使用指針p相比少了
arr是首地址+偏移 然后直接往這個地址里面讀或者寫
指針的操作方式首先需要得到p對象 所占的空間里面存放的值(這里是數(shù)組首地址)然后再通過存放的值+偏移的方式 讀寫內(nèi)存
int* p =arr; 把p這個對象 賦值數(shù)組首地址 任何指針類型32位下4個字節(jié) 64位下8個字節(jié),p這個對象需要4個字節(jié)的空間存儲arr值,因為p是一個變量,占4個字節(jié) int* p=arr;就是 往p所占的4個字節(jié)里面存儲arr值首地址
而通過p[_i]下標訪問的時候 首先就需要 取出來p里面存的四個字節(jié)值y
然后y+偏移的方式 訪問讀或者寫該指針指向數(shù)組中的內(nèi)容

從上面的結果我們可以得到,別看到一級指針操作一維數(shù)組 和數(shù)組直接訪問問之前只多了一層指針變量的尋址,但是含義就完全的變了。
如有些書上說數(shù)組作為實參會退化為指針
lea eax,[arr] 是數(shù)組首地址保存到eax寄存器中
push eax 參數(shù)入棧 此時esp寄存器的值減4,push eax相當與啥?相當于創(chuàng)建了一個零時對象 占4個字節(jié)的指針,傳遞過去,首地址值訪問一塊4個字節(jié)的內(nèi)存后這段4個字節(jié)的內(nèi)存后編譯器認為這是一個指針,所以funtion里面使用sizeof可以看到占4個字節(jié)(可以私下去測試),所以把編譯器給的類型去掉后 。
int a = (int)arr; 往a占的4個字節(jié)內(nèi)存中寫入數(shù)組首地址,從匯編的角度來看,是不是找到一絲熟悉的感覺了,沒錯下面這兩個除了編譯器附加的一些類型的限制之外沒有區(qū)別,甚至可以說是完全一樣的,我們完全可以使用一個int a;操作任何基本類型和抽象類型對象

int a= (int)arr;
int* p =arr;

函數(shù)傳遞一級指針和二級指針
下圖可以看到傳遞一級是將p的地址ebp-0x3c里面存儲的內(nèi)容 push到棧中傳參
而傳遞二級指針的時候是lea 得到ebp-0x3c這個值 p的地址傳遞進去
所以對于二級指針而言 我們很容易在funtion2函數(shù)里面改變被調(diào)用函數(shù)里面p指向的內(nèi)容
(這種方式多與一些庫的設計 如ffmpeg 的一些函數(shù)設計傳遞一個一級指針的地址進去(指向NULL)函數(shù)里面可以創(chuàng)建某些對象然后然后改變被調(diào)函數(shù)的指針,釋放的時候同理,這樣可以減少開發(fā)者所作的工作

可以用一級指針指針引用一位數(shù)組,以前剛學習的時候我自認而然的使用二級指針引用二維數(shù)組,發(fā)現(xiàn)是不可以。
進程的內(nèi)存就是線性的32位可以尋址00000000-0xffffffff 4gb,從內(nèi)存的角度看沒有二維數(shù)組的概念,也沒有多維數(shù)組的概念,對于任何一個變量,關注的應該都是首地址,寬度
int arr[4][3] ; 在內(nèi)存布局上可以 int arr[12];是完全一樣的沒有任何區(qū)別
二維數(shù)組或者多維數(shù)組的設計知識為了理解的方便,比如使用二維數(shù)組可以更加直觀的表示一個nm地圖的狀態(tài),使用一維度的話沒有那么的直觀。三維數(shù)組可以讓我們更直觀的表示一個空間的概念,其實它們內(nèi)存也就是一個一線性的一維數(shù)組
int arr[4][3] 我們通過 arr[_i][_j]的訪問方式
mov eax,[_i];首先得到_i的值保存到eax寄存器中
lea ecx,arrtow[eax4]; lea指令是得到[]里面的地址 arrtow首地址 + _i41(char占1個字節(jié)如果是其他類型需要對應大小)
mov edx ,[_j] ;edx寄存器保存_j的值
movsx eax.byte ptr[ecx+edx] 就是arrtow+_i41+_j1 取出這個內(nèi)存編號中的值取一個字節(jié)放入eax寄存器中 char到int有一個轉換
mov [a],eax 放入a變量所在的地址中 四個字節(jié)
可以看到二維數(shù)組其實也是一個一維數(shù)組 首地址+_im寬度+j*寬度的尋址方式
三維數(shù)組同理

二級指針不能引用二維數(shù)組是因為是因為二級指針操作內(nèi)存的方式和二維數(shù)組的完全不同,一級指針可以引用一維數(shù)組是因為它們操作內(nèi)存的方式是相同的

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值(數(shù)組首地址)
mov edx,dword ptr [ecx+eax4] // 數(shù)組首地址+_i4的值 指針寬度占4個字節(jié), 將arrtow+_i 4位首地址讀取四個字節(jié) 到edx寄存器 (這里就尋址了一次)
mov eax.dword ptr [_j]; //讀取_j的值存放在eax寄存器中
movsx ecx,byte ptr [edx+eax]//把在arrtow+_i4地址處取的四個字節(jié)數(shù)據(jù)當做首地址 +_j再次當作首地址取一個字節(jié) 當如ecx寄存器
mov dword ptr [a],ecx, 放入a變量中

通過二級指針和二維數(shù)組訪問內(nèi)存的方式不同,可以明白為啥不能使用二級指針直接訪問二維數(shù)組,同理三級指針尋址3次,四級指針4次,不管多少維數(shù)組都是和一維數(shù)組一樣一次,所以如果我把斷點繼續(xù)指行就會應為訪問未知地址掛掉。

再次將論點移到內(nèi)存,我們所作的一切都只是對內(nèi)存的訪問,而C/C++一不小心就會出現(xiàn)對內(nèi)存的非法的訪問,所以了解內(nèi)存是一件非常重要的事情,而指針只是訪問操作內(nèi)存的一種靈活的方式。和前面說的一樣,任何指針占,所以任何一個4個字節(jié)的內(nèi)存單元 一個int的大小 可以以任何的指針的方式訪問內(nèi)存,極度的靈活(如果對內(nèi)存沒有足夠的理解同時就會導致極度的不安全),

到此這篇關于C語言數(shù)組和指針,內(nèi)存之間的關系的文章就介紹到這了,更多相關數(shù)組和指針,內(nèi)存之間的關系內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論