陣列(一維、二維、多維)與指標的關係與區別總結
陣列用於同種資料型別的儲存,常規的陣列選取的是一塊連續記憶體空間來儲存同種型別的資料。
1、 靜態陣列
靜態陣列是在宣告時已經確定子陣列大小的陣列,即陣列元素的個數固定不變。在編譯期間在棧中分配好記憶體的陣列,在執行期間不能改變儲存空間,執行後由系統自動釋放。
陣列的宣告
int a[10]; float b[5]={};double c[]={1,2,3};
尤其注意下面這種陣列宣告是錯誤的,int num; char a[num]; 即使在前面是int num=5也是錯的,無法明確陣列的大小,導致編譯失敗,num必須是常量或常量表達式。
例如const int num=5;或者在前面對num進行巨集定義。
修改後:
2、 動態陣列
動態陣列是指在宣告時沒有確定陣列大小的陣列,即忽略圓括號中的下標;當要用它時,可隨時用ReDim語句重新指出陣列的大小。使用動態陣列的優點是可以根據使用者需要,有效利用儲存空間。最大的特點是在程式執行後才分配記憶體的陣列,需要人工手動去建立和釋放。
(1)一維陣列
C語言:利用malloc()函式來宣告陣列空間 利用free()函式來釋放宣告空間
C++語言:利用new()函式來宣告陣列空間 利用delete()函式來釋放宣告空間
(2)二維陣列
在c中
在c++中:
3、 陣列與指標
(1)一維陣列 int a[10]={};
我們需要知道的一點就是一維陣列名錶示的是儲存的首地址,其次a[i]=*(a+i),a+i代表的是第i個元素的地址,等於第一個元素的地址+i*sizeof(陣列型別)。
(2)二維陣列
二維陣列可以理解為是一個特殊的一維陣列,它的每一個元素也都是一維陣列。
例:
二維陣列a[3][2]可以理解為一個特殊的一維陣列,其中每一個元素都是一個一維陣列,如a[0][2]實際包含兩個元素a[0][0]和a[0][1]。
如圖可得到以下結論:
(1)a+i指向a[i][2]: a為陣列a[3][2]的首地址,特殊的一維陣列包含3個元素a[0][2],a[1][2],a[2][2]。由一維陣列的性質“首地址+i”得到的是第i個元素的地址,所以a+i指向特殊一維陣列的第i個元素。
(2)a[i]指向a[i][0]: 特殊的一維陣列的每個元素又都是一個數組,如a[0][2]實際包含兩個元素a[0][0]和a[0][1]。a[0]相當於一維陣列名,指向首元素 a[0][0],所以a[i]指向a[i][0],a[i]+j指向a[i][j]。
從圖中看似a+i和a[i]指向的都是a[i][0],其實不然。a+i指向的是a[i],因為a[i]=*(a+i),這個比較難理解的。
a[i]的確指向的是a[i][0],但a+1取值後仍然是一個地址指向a[i][0]。
可以這樣理解,a+i指向的是特殊一維陣列的第i個元素,第i個元素還是一個一維陣列。*(a+i)直面的意思是想取出第i個元素的內容,但a+i所指空間還是個陣列,難道*(a+i)直接就能將整個陣列取出來?要知道陣列都是通過下標一個個進行訪問的,不能整體獲得。所以*(a+i)只是獲得這個陣列空間首元素的地址,這樣就可以通過下標對內容進行訪問。
最後總結一下:
對於二維陣列a[3][2],若看成3行2列的形式。
(1)a+i指向第i行,此時還沒有獲得第i行元素首地址,沒有辦法訪問其中的元素
(2)*(a+i)或a[i]指向第i行首元素,獲得第i行元素的首地址。
(3)a[i]+j指向第i行第j個元素,可以通過a[i]第i行元素的首地址訪問各個元素。關鍵是要記住a[i]=*(a+i), a[i][j]=*(*(a+i)+j)。
同理針對三維陣列,我們同理可以得到a[i][j][k]=*( (*(*(a+i)+j))+k),甚至可以推廣到多維。
(3)一維陣列名arr與普通指標ptr的區別
1、 陣列名取地址得到的是陣列名所指元素的地址,而對指標取地址得到的是指標變數自身的地址。即對於陣列名arr而言,arr==&arr==arr[0],對於普通指標ptr,一般ptr!=&ptr;
2、 陣列名是常量指標,指標是變數指標。即陣列名不能為左值,普通指標則可以。
3、 Sizeof(arr)此時的大小不是4而是4*陣列元素的個數
Sizeof(ptr)的結果為4
同時我們需要注意一點就是,指標偏移問題
通過例子我們可以發現&arr+1實際上偏移了16個位元組,而&ptr+1只是偏移了4個位元組。
(4)二維陣列名a與指標
雖然在數值上表現的相同,但是二維陣列名的型別是陣列陣列,即int (* arr)[3]=a;
故用int * ptr=a則會報錯,而int *ptr=a[0]=&a[0]則正確。
參考連結: