給定一段c++程式碼
分別用三種方式配置3個大小相同的二維陣列
img1
, img2
以及img3
int img1[10][20];
int** img2;
img2 = new int* [10];
for (int i = 0; i < 10; ++i) {
img2[i] = new int[20];
}
int** img3;
img3 = new int* [10];
int* data = new int[10 * 20];
for (int i = 0; i < 10; ++i) {
img3[i] = data + i * 20;
}
雖然我們學C/C++都是先學陣列後學指標
但事實上指標的概念在 C 語言發展中比陣列更早出現,並且更加原始
陣列的語法實際上是指標操作的簡化
給定一個陣列arr1
int arr1[5] = { 0 , 1 , 2 , 3 , 4 };
編譯器會將arr1
視為指向該陣列第一個元素的指標
所以在語法上 arr1[i]
等價於* (arr1 + i)
img1
直接透過int img1[10][20];
宣告
記憶體位址是連續的
而img2
首先被分配了長度為10,用來存放指標的陣列
而每個陣列中的指標又都被配置了長度為20的int陣列
因此記憶體位置是不連續的
img3
同樣被分配了長度為10,用來存放指標的陣列
後面則是透過分配一個連續的一維陣列data
以指針來模擬二維陣列
將img3
存放的指標,指向data
的特定位置
因此記憶體位置是連續的
方法一樣,都是用&
符號來取址:&img1[5][6]
, &img2[5][6]
, &img3[5][6]
但底層邏輯有所差異
其中img1
以及img3
的尋址都是在連續的記憶體配置上,透過計算指針的偏移量得到
但img2
需要兩次的間接尋址:取得第5個指針後找的它的第3個元素
理解原理後,開發中可以根據要求了使用分配方式
img1
的方式屬於靜態分配
編譯時配置,記憶體管理全由編譯器負責,無須手動釋放
十分的簡單易用,位址也連續,大小也是確定的
但缺點也很明顯:靈活性低
img2
則是動態分配
最明顯的缺點是性能不佳,訪問元素時需經兩次尋址
但它允許img2
指向的每個陣列長短不一
使用的情況大概只剩不規則且動態的陣列
例如在處理矩形以外的不規則網格時(如稀疏矩陣)
另外記憶體釋放時要逐行釋放
img3
為動態分配
兼具動態分配優點,且記憶體位址連續
算是在性能與靈活性之間的平衡點
記憶體釋放時需要先對實際數據data
釋放
再對存放指針的陣列img3
釋放