持續面臨二維數組的問題, 每次都怕怕的. 那些指標實在讓人煩惱, 那些記憶體更讓人煩惱.
今日總結: 以供日後參考.
唯寫出最常用的幾個
1: 在棧上 分配 int A[m][n].
缺點, m, n必須為已知
函數參數調用
fun( int A[][n], int dims_i, int dims_j )
{
A[i][j] = 0;
}
2: 動態分配-使用stl
極力推薦!!! 雖然, 這個方法會造成記憶體不連續, 但是, 比起代碼的優美, 調用的直觀, 也不用自己管理記憶體, 缺點可以忽略不計!!!
- int m=3;
- int n = 3;
- vector< vector<int> > myvec( m, vector<int>(n) );
- for ( int i=0; i<m; ++i)
- {
- for (int j=0; j<n; ++j)
- {
- myvec[i][j] = i*j;
- }
- }
- vector<vector<int> > A;
- A.resize(m); //m行
- for(int i = 1; i < n; i++) //
- {
- ga[i].resize(n); //n列
- }
3: 動態分配, 自己管理記憶體
由於本質上, 動態實現2維數組的話, 需要多申請點記憶體. 也就是存放一維數組指標的記憶體.
下面的方法, 把 "存放一維數組指標的記憶體" indexSize 和 存放資料的記憶體 h*rowSize 放在了一起. 實在巧妙. 這樣,
釋放記憶體時, 一句delete搞定.
- void** malloc2d(int w, int h, int size)
- {
- int j;
- int rowSize = w * size;
- int indexSize = h * sizeof(void *);
- void **a = (void **) malloc(indexSize + h * rowSize);
- char *dataStart = (char *) a + indexSize;
- for(j = 0; j < h; j++)
- a[j] = dataStart + j * rowSize;
- return a;
- }
參數w,h是所申請二維數組的列數和行數,size是數組單元的位元組數。比如,申請一個4*5的int型的二維數組,使用:
int **m = (int **) malloc2d(5, 5, sizeof(int));
直接使用m[x][y]即可以引用x行y列的值。
退回時,直接使用free(m)即可。
參考: http://blog.csdn.net/hanbf/archive/2007/08/31/1767645.aspx
////////////////////////////////////////////////////////////
下面對編程中常見的, 通過函數指標傳遞二維數組地址後,
如何在函數內部存取數組元素. 這裡進行一下集中討論.
1)如果未經處理資料是 本質上一維的, 佔用空間僅僅包含未經處理資料大小, 不含對行指標的儲存空間.
則, eg int A[2][2]; // :在棧上分配的記憶體. sizeof(A) == 2*2*sizeof(int)
只可以按照 一維的本質來訪問數組元素.
- void test3( int** a, int dim_i, int dim_j )
- {// 這裡傳進來int** a, 實際上是沒有意義的, 還得轉化為 int*
- // 注意, 這裡的a只是一個純粹一個指標, 丟失了編譯器為之維護的維度長度資訊, 所以,
- // 只能當一維數組來使用了
-
- int* p = (int*)a; // :老老實實的按一維數組來噁心的存取吧.
- for ( int i=0; i<dim_i; ++i )
- {
- for (int j=0; j<dim_j; ++j)
- {
- *(p+i*dim_j+j) = i*j;
- }
- }
-
- return;
- }
2: 如果申請的記憶體中不僅包含資料占空間, 也包含了行指標占的空間. 那麼, 是可以通過[][]來存取的.
見下面函數的 test4
- void test2( int a[][2], int dim_i, int dim_j )
- {
- a[1][1] = 1;
- return;
- }
- // :適用於本質上不含行指標 的二維數組.
- // :eg 1 在棧上分類的二維數組, 或不含行指標的 int a[2][2]
- // :eg 2 int ** pa =(int**)malloc(sizeof(int)*2*2) . 兩行兩列
- void test3( int** a, int dim_i, int dim_j )
- {
- // 注意, 這裡的a只是一個純粹一個指標, 丟失了編譯器為之維護的維度長度資訊, 所以,
- // 只能當一維數組來使用了
- int* p = (int*)a; // :老老實實的按一維數組來噁心的存取吧.
- for ( int i=0; i<dim_i; ++i )
- {
- for (int j=0; j<dim_j; ++j)
- {
- *(p+i*dim_j+j) = i*j;
- }
- }
-
- return;
- }
- // :適用於 含有行指標資料的 二維數組
- // :eg malloc2d
- void test4( int** a, int dim_i, int dim_j )
- {
- for ( int i=0; i<dim_i; ++i )
- {
- for (int j=0; j<dim_j; ++j)
- {
- a[i][j] = (i+1)*(j+1);
- }
- }
- return;
- }
- void** malloc2d(int w, int h, int size)
- {
- int j;
- int rowSize = w * size;
- int indexSize = h * sizeof(void *);
- void **a = (void **) malloc(indexSize + h * rowSize);
- char *dataStart = (char *) a + indexSize;
- for(j = 0; j < h; j++)
- a[j] = dataStart + j * rowSize;
- return a;
- }
- int main()
- {
- // 第一種方式
- int **pa2 = (int**)malloc2d( 2,2,sizeof(int) );
- test4( pa2, 2, 2 );
- cout<<"pa2[1][1]"<<pa2[1][1]<<endl;
- // 第二種方式
- int a[2][2] = { {0, 0}, {0, 0} };
- test3( (int**)a, 2, 2 );
- // 第三種方式
- int m=3;
- int n = 3;
- vector< vector<int> > myvec( m, vector<int>(n) );
- for ( int i=0; i<m; ++i)
- {
- for (int j=0; j<n; ++j)
- {
- myvec[i][j] = i*j;
- }
- }
- }
另外別的一些方法還有很多, 這裡不一一列舉:
別的方法參考下面地址:
http://blog.csdn.net/smilelance/archive/2006/10/09/1327326.aspx
轉自水木清華
1.
A (*ga)[n] = new A[m][n];
...
delete []ga;
缺點:n必須是已知
優點:調用直觀,連續儲存,程式簡潔(經過測試,解構函式能正確調用)
2. A** ga = new A*[m];
for(int i = 0; i < m; i++)
ga[i] = new A[n];
...
for(int i = 0; i < m; i++)
delete []ga[i];
delete []ga;
缺點:非連續儲存,程式煩瑣,ga為A**類型
優點:調用直觀,n可以不是已知
3. A* ga = new A[m*n];
...
delete []ga;
缺點:調用不夠直觀
優點:連續儲存,n可以不是已知
4. vector<vector<A> > ga;
ga.resize(m); //這三行可用可不用
for(int i = 1; i < n; i++) //
ga[i].resize(n); //
...
缺點:非連續儲存,調試不夠方便,編譯速度下降,程式膨脹(實際速度差別不大)
優點:調用直觀,自動析構與釋放記憶體,可以調用stl相關函數,動態增長
5. vector<A> ga;
ga.resize(m*n);
方法3,4的結合
6. 2的改進版(Penrose提供,在此感謝)
A** ga = new A*[m];
ga[0] = new A[m*n];
for(int i = 1; i < m; i++)
ga[i] = ga[i-1]+n;
...
delete [] ga[0];
delete [] ga;
缺點:程式煩瑣,ga為A**類型
優點:連續儲存,調用直觀,n可以不是已知