二維數組來個了斷!

來源:互聯網
上載者:User

持續面臨二維數組的問題, 每次都怕怕的. 那些指標實在讓人煩惱, 那些記憶體更讓人煩惱.

今日總結: 以供日後參考.
唯寫出最常用的幾個
1: 在棧上 分配 int A[m][n].
    缺點, m, n必須為已知
    函數參數調用
   fun( int A[][n], int dims_i, int dims_j )
  {
        A[i][j] = 0;
  }

2: 動態分配-使用stl
   極力推薦!!! 雖然, 這個方法會造成記憶體不連續, 但是, 比起代碼的優美, 調用的直觀, 也不用自己管理記憶體, 缺點可以忽略不計!!!
   

  1.     int m=3;
  2.     int n = 3;
  3.     vector< vector<int> > myvec( m, vector<int>(n) );
  4.     for (  int i=0; i<m; ++i)
  5.     {
  6.         for (int j=0; j<n; ++j)
  7.         {
  8.             myvec[i][j]  = i*j;
  9.         }
  10.     }

  1. vector<vector<int> > A;
  2. A.resize(m);                       //m行
  3. for(int i = 1; i < n; i++)         //
  4. {
  5.      ga[i].resize(n);              //n列
  6. }

3: 動態分配, 自己管理記憶體
由於本質上, 動態實現2維數組的話, 需要多申請點記憶體. 也就是存放一維數組指標的記憶體.
下面的方法, 把 "存放一維數組指標的記憶體" indexSize 和 存放資料的記憶體 h*rowSize 放在了一起. 實在巧妙. 這樣,
釋放記憶體時, 一句delete搞定.

  1. void** malloc2d(int w, int h, int size)
  2. {
  3.   int j;
  4.   int rowSize = w * size;
  5.   int indexSize = h * sizeof(void *);
  6.   void **a = (void **) malloc(indexSize + h * rowSize);
  7.   char *dataStart = (char *) a + indexSize;
  8.   for(j = 0; j < h; j++)
  9.     a[j] = dataStart + j * rowSize;
  10.   return a;
  11. }

參數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)
  只可以按照 一維的本質來訪問數組元素.
 

  1. void test3( int** a, int dim_i, int dim_j )
  2. {//  這裡傳進來int** a, 實際上是沒有意義的, 還得轉化為 int*
  3.     // 注意, 這裡的a只是一個純粹一個指標, 丟失了編譯器為之維護的維度長度資訊, 所以, 
  4.     // 只能當一維數組來使用了
  5.      
  6.     int* p = (int*)a;   // :老老實實的按一維數組來噁心的存取吧.
  7.     for ( int i=0; i<dim_i; ++i )
  8.     {
  9.         for (int j=0; j<dim_j; ++j)
  10.         {
  11.             *(p+i*dim_j+j) = i*j;
  12.         }
  13.     }
  14.     
  15.     return;
  16. }

2: 如果申請的記憶體中不僅包含資料占空間, 也包含了行指標占的空間. 那麼, 是可以通過[][]來存取的.

見下面函數的 test4

 

  1. void test2( int a[][2], int dim_i, int dim_j )
  2. {
  3.     a[1][1] = 1;
  4.     return;
  5. }
  6. // :適用於本質上不含行指標 的二維數組.
  7. // :eg 1 在棧上分類的二維數組, 或不含行指標的 int a[2][2]
  8. // :eg 2 int ** pa =(int**)malloc(sizeof(int)*2*2) . 兩行兩列
  9. void test3( int** a, int dim_i, int dim_j )
  10. {
  11.     // 注意, 這裡的a只是一個純粹一個指標, 丟失了編譯器為之維護的維度長度資訊, 所以, 
  12.     // 只能當一維數組來使用了
  13.     int* p = (int*)a;   // :老老實實的按一維數組來噁心的存取吧.
  14.     for ( int i=0; i<dim_i; ++i )
  15.     {
  16.         for (int j=0; j<dim_j; ++j)
  17.         {
  18.             *(p+i*dim_j+j) = i*j;
  19.         }
  20.     }
  21.     
  22.     return;
  23. }
  24. // :適用於 含有行指標資料的 二維數組
  25. // :eg malloc2d
  26. void test4( int** a, int dim_i, int dim_j )
  27. {
  28.     for ( int i=0; i<dim_i; ++i )
  29.     {
  30.         for (int j=0; j<dim_j; ++j)
  31.         {
  32.             a[i][j] = (i+1)*(j+1);
  33.         }
  34.     }
  35.     return;
  36. }
  37. void** malloc2d(int w, int h, int size)
  38. {
  39.     int j;
  40.     int rowSize = w * size;
  41.     int indexSize = h * sizeof(void *);
  42.     void **a = (void **) malloc(indexSize + h * rowSize);
  43.     char *dataStart = (char *) a + indexSize;
  44.     for(j = 0; j < h; j++)
  45.         a[j] = dataStart + j * rowSize;
  46.     return a;
  47. }
  48. int main()
  49. {
  50.     // 第一種方式
  51.     int **pa2 = (int**)malloc2d( 2,2,sizeof(int) );
  52.     test4( pa2, 2, 2 );
  53.     cout<<"pa2[1][1]"<<pa2[1][1]<<endl;
  54.     // 第二種方式
  55.     int a[2][2] = { {0, 0}, {0, 0} };
  56.     test3( (int**)a, 2, 2 );
  57.     // 第三種方式
  58.     int m=3;
  59.     int n = 3;
  60.     vector< vector<int> > myvec( m, vector<int>(n) );
  61.     for (  int i=0; i<m; ++i)
  62.     {
  63.         for (int j=0; j<n; ++j)
  64.         {
  65.             myvec[i][j]  = i*j;
  66.         }
  67.     }
  68. }

另外別的一些方法還有很多, 這裡不一一列舉:
別的方法參考下面地址:
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可以不是已知

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.