现在的位置: 首页 > 综合 > 正文

二维数组来个了断!

2013年10月03日 ⁄ 综合 ⁄ 共 4115字 ⁄ 字号 评论关闭

持续面临二维数组的问题, 每次都怕怕的. 那些指针实在让人烦恼, 那些内存更让人烦恼.

今日总结: 以供日后参考.
只写出最常用的几个
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可以不是已知

抱歉!评论已关闭.