1、关于定义二维数组
先说在前面,一般的我们说的C/C++中的二维数组是定义在栈中的二维数组。比如定义了一个array[3][4],那就指的是定义了一个三行四列的矩阵形状的二维数组,如下图所示。这样的矩阵在内存中是以箭头右边的方式存放的,也就是说实际上我们定义的二维数组在内存中仍然像是一维数组那样连续存储的。可以想象为把一个矩阵一层层伸展铺平。
因此可以使用如下方法定义二维数组:
方法一: 直接确定二维数组的行和列数
/* 可以使用下面的方法来初始化二维数组
* 也就是直接将二维数组铺平,写成一维数组的形式
*/
int array[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
/* 可以使用标准的二维数组的初始化方式
*/
int array[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
方法二: 不用指明二维数组的行数,但要指明列数
下面的一种写法本质上是定义了一个数组指针。
/* 经典的写法
*/
int array[][4];
/* 一种更帅的写法,本质上是定义了一个数组指针
*/
int (*array)[4];
方法三: 动态分配的方式,这种写法比较灵活,在定义的时候不需要指明二维矩阵的行数和列数
/* 使用动态分配内存的形式,用malloc
*/
int **array // array[M][N]
array = (int **)malloc(M * sizeof(int *));
for(int i = 0; i < M; i++) {
array[i] = (int *)malloc(N * sizeof(int));
}
// 释放
for(int i = 0; i < M; i++)
free(array[i]);
free(array);
/* 使用动态分配内存的形式,用new
*/
int **array // array[M][N]
array = new int*[M];
for(int i = 0; i < M; i++) {
array[i] = new int[N];
}
// 释放
for(int i = 0; i < M; i++)
delete [] array[i];
delete [] array;
不过按照这种形式实现的二维数组本质上已经不是我们之前说的传统的二维数组 了,采用此种方法定义的二维数组的结构如下图所示,这样的二维数组在堆上分配内存。也就是说这样实现的二维数组本质上已经是指针数组了。使用这样的方式分配二维数组空间之后,可以使用array[i][j]进行数组的读写操作没有问题,但是应该知道不同行的内存空间不一定连续。这是因为每一行的数组的内存都是使用malloc分配的,多次使用malloc分配的内存空间并不一定是连续的,这与在栈上分配的二维矩阵有着根本的不同,比如同样的对于顶底的二维数组array[3][4],不能再使用array[0][4]来访问array[1][0]了,这样会导致地址越界,就是因为地址不一定连续了。
2 、二维数组的传参写法
使用二维数组作为参数,可以有以下几种写法。
1 使用动态分配内存的方式申请空间,可以使用**传递参数
希望在使用二维数组的时候保持良好的编程习惯,使用哪种方法定义的就使用哪种方式传参,这样对于保持良好的编码习惯有好处,对于别人阅读你的代码也有好处。
#include <iostream>
using namespace std;
int func1(int **arr) {
cout << arr[0][0];
arr[0][2] = 20;
return 0;
}
int main()
{
int **array
int row = 3;
int col = 4;
array = (int **)malloc(row * sizeof(int *));
for (int i = 0; i < row; i++) {
array[i] = (int *)malloc(col * sizeof(int));
}
memset(*array, 0, sizeof(int)*row*col);
array[0][1] = 100;
func1(array);
cout << array[0][2];
return 0;
}
2 使用二维数组的传统定义方法传递参数
如果把数组名作为函数的参数的话,在编译的时候这个数组参数会自动退化为指针,因此以下两种写法虽然不同,但在编译之后是一样的,数组会退化成数组指针。
#include <iostream>
using namespace std;
/*
* 以下两种写法本质上是一样的
*/
int func1(int (*arr)[4]) {
cout << arr[0][0] << endl;
arr[0][2] = 20;
return 0;
}
int func2(int arr[][4]) {
cout << arr[0][0] << endl;
arr[0][2] = 20;
return 0;
}
int main()
{
int array[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
array[0][1] = 100;
func1(array);
cout << array[0][2] << endl;
return 0;
}
正是因为这个问题,在定义如下类似求数组大小的函数的时候必须将数组引用传递!否则数组会退化为一个指针,无法正确的使用sizeof运算符求出数组a所占内存空间大小。
template<class T>
int GetArrayLen(T& a)
{
return sizeof(a)/sizeof(a[0]);
}