一般在做 int arr[M] 動態記憶體配置時長這樣
int *arr1 = (int*)malloc(sizeof(int) * M); /* for C */
int *arr2 = new int[M]; /* for C++*/
為初學者小提一下,上式是在宣告時就給初值,也可拆開來寫,等價於
int *arr1 ;
/* do something */
arr1 = (int*)malloc(sizeof(int) * M); /* for C */
int *arr2;
/* do something */
arr2 = new int[M]; /* for C++*/
以下所有說明採第一種,合起來方式。釋放時
free(arr1); // for C
delete [] arr2; // for C++
一維的時候沒什麼問題,到二維以上時便有些問題出現。
----
假設欲配置 int arr[M][N] 動態配憶體時,最簡單的做法為
/* for C */
int **arr1 = (int**)malloc(sizeof(int*)*M);
for(int i=0; i<M; ++i) arr1[i] = (int*)malloc(sizeof(int)*N);
/* for C++ */
int **arr2 = new int*[M];
for(int i=0; i<M; ++i) arr2[i] = new int[N];
釋放時
/* for C */
for (int i=0; i<M; ++i) free(arr1[i]);
free(arr1);
/* for C++ */
for (int i=0; i<M; ++i) delete [] arr2;
delete [] arr2;
上面這方法可行,但有缺點
(1) 記憶體位置不連續
恕我懶得再畫記憶體空間示意圖,若要將 arr 做初始化為 0 之動作,只能這麼做
for(i=0; i<M; ++i)
for(j=0; j<N; ++j)
arr[i][j] = 0;
進階一點的方式頂多是 C 語言用 memset 改善,而 C++ 用 fill 方式改善。
/* for C */
for(i=0; i<M; ++i)
memset(arr1, 0, sizeof(int) * N);
/* for C++ */
for(i=0; i<M; ++i)
fill(arr2, arr2+N, 0);
memcpy 使用上也是有此缺點。如此操作麻煩,讀取速度慢也是一缺點。
(2) 無法以線性轉換方式操作
由於位置並非連續,故若由二維轉一維,沒辦法以線性方式做轉換。
----
改善方式其實不難,以 C 為例,配置 int arr[M][N] 時,
int **arr = (int**)malloc(sizeof(int*) * M);
int *trunk = (int*)malloc(sizeof(int) * M * N);
for(int i=0; i<M; ++i) {
arr[i] = trunk;
trunk += N;
}
要初始化時
memset( (void*)arr, 0, sizeof(int) * M * N);
要做指定時
arr[2][3] = 10;
要複制另一個 arr2 時
memcpy( (void*)arr, (void*)arr2, sizeof(int) * M * N);
要釋放時
free(arr[0]);
free(arr);
當然這配置方式,部份會引來爭議,原因在於裡面用到指標 + - 運算,
大多 compiler 在做 + - 運算時,是在做 offset 動作,
但標準規範裡並不保證這種事,只是大多 compiler 都這麼做。
最後附上一段 sample code。
#include <iostream> #include <cstdlib> using namespace std; void display(int** arr, size_t m, size_t n) { size_t i, j; cout << '\n'; for(i=0; i<m; ++i){ cout << '\n'; for(j=0; j<n; ++j) cout << arr[i][j] << ' '; } } int main() { const size_t M = 10; const size_t N = 5; size_t i, j; int cnt; int* trunk = NULL; int* trunk2= NULL; // --------------------------------- // c style // allocate int** c=NULL; c = (int**)malloc(sizeof(int*)*M); trunk = (int*)malloc(sizeof(int)*M*N); for(i=0; i<M; ++i){ c[i]=trunk; trunk+=N; } // set value cnt=0; for(i=0; i<M; ++i) for(j=0; j<N; ++j) c[i][j]=++cnt; display(c, M, N); // release free(c[0]); free(c); // --------------------------------- // cpp style // allocate int** cpp=NULL; cpp = new int*[M]; trunk2 = new int[M*N]; for(i=0; i<M; ++i){ cpp[i]=trunk2; trunk2+=N; } // set value cnt=0; for(i=0; i<M; ++i) for(j=0; j<N; ++j) cpp[i][j]=++cnt; display(cpp, M, N); // release delete [] cpp[0]; delete [] cpp; return 0; }