持续面临二维数组的问题, 每次都怕怕的. 那些指针实在让人烦恼, 那些内存更让人烦恼.
今日总结: 以供日后参考.
只写出最常用的几个
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可以不是已知