C++ 多维数组详解

发布时间:2026/5/19 2:41:12

C++ 多维数组详解 3.6 多维数组其实C中没有什么多维数组所说的多维数组其实就是数组的数组。当一个数组的元素依旧是数组时通常使用两个维度来定义它一个维度表示数组本身大小另外一个维度表示其元素数组的数组大写1intia[3][4];大小为3的数组每个元素是含有4个整数的数组。1intarr[10][20][30] {0};大小为10的数组它的每个元素都是大小为20的数组这些数组的元素又包含30个整数的数组最后将所有元素初始化为0。由内到外的顺序阅读此类定义有助于更好地理解其真实含义。在第一条语句中定义名称为ia显然ia是一个含有3个元素的数组。再往右边写着ia的元素的维度所以ia的元素本省又是含有4个元素的数组。在观察最左边就能知道真正储存的元素ia的元素的数组是整数。因此最后可以明确第一条语句的含义定义了一个大小为3名为ia的数组该数组的每个元素都是含有4个整数的数组。再用同样的方式理解第二条arr的定义首先arr是一个大小为10的数组它的每个元素都是大小为10的数组而这些数组的元素又都是含有30个整数的数组。并且定义数组时对下标运算符的数量并没有限制因此只要愿意就可以定义一个数组它的元素是数组数组的元素又是数组禁止套娃对于二维数组来说常吧第一个维度成为行第二个维度称为列。多维数组的初始化允许使用花括号括起来的一组值初始化多维数组这点和普通的数组一样。下面初始化形式中多维数组的每一行分别用花括号括了起来123456intia[3][4]//三个元素每个元素都是大小为4的数组{{0,1,2,3}//第1行的初始值{4,5,6,7}//第2行的初始值{8,9,10,11}//第3行的初始值}其中内层嵌套的花括号并非必需的例如下面的初始化语句形式上更为简洁完成的功能和上面的代码完全一致12intia[3][4] {0,1,2,3,4,5,6,7,8,9,10,11};//没有标识每行的花括号与之前的初始化语句是等价的类似一维数组在初始化多维数组时也并非所有元素的值都必须包含在初始化表之内。如果仅仅想初始化每一行的第一个元素通过如下的语句12intia[3][4] {{0},{4},{8}};//显式地初始化每行的首元素其他没有列出的元素执行默认初始化这个过程和一位数组一样。此时如果去掉内层花括号结果就不同了。12intix[3][4] {0,3,6,9};//显式地初始化第1行其他元素执行值的初始化。此时的含义是它初始化了第一行的4个元素其他元素被初始化0。多维数组的下标引用可以使用下标运算符来访问多维数组的元素此时数组的每个维度都对应一个下标运算符。如果表达式含有的下标运算符数量和数组的维度一样多该表达式的结果将是给定类型的元素举个例子arr[0][0][0]的下标运算符数量为3并且arr是3维的此时下标运算符数量和数组的维度就是一样多了。反之如果表达式含有的下标运算符数量比数组的维度小则表达式的结果将是定索引的一个内层数组1234ia[2][3] arr[0][0][0];//用arr的首元素为ia最后一行的最后一个元素赋值int(row)[4] ia[1];//把row绑定到ia的第二个4元素数组上在第一个例子中对于用到的两个数组来说表达式提供的下标运算符数量和它们各自的维度相同。在等号左侧ia[2]得到数组ia的最后一行此时返回的是表达ia最后一行的那个一维数组而并非任何实际元素对于这个一维数组再去取下标得到编号为[3]的元素也就是这行的最后一个元素。经常使用for循环来处理多维数组的元素二维数组大多数就两层嵌套的for循环去处理外层for循环处理行内层for循环处理列三维数组中最外层循环表示面中间层表示行最内层表示列。以此遍历数组123456789constexprsize_trowCnt 3 , colCnt 4;intia[rowCnt][colCnt];for(size_ti 0;i ! rowCnt;i){for(size_tj 0;j ! colCnt;j){ia[i][j] i * colCnt j;}}使用范围for语句处理多维数组由于在C11新标准中新增了范围for语句所以前一个程序可以简化为如下形式123456789size_tcnt 0;for(auto row : ia){for(auto col : row){col cnt;cnt;}}ia是一个由数组构成的数组每次遍历相当于一行一行的遍历了ia。所以每次遍历row相当于取出一行ia。相当于对于外层数组的每一个元素。而col又相当于每一行的row的引用。相当于对于内层数组的每一个元素。这个循环赋值给ia元素的值和之前的那个循环是完全相同的区别在于通过使用范围for语句把管理数组索引的任务交给了系统。因为要改变元素的值所以得把控制变量row和col声明成引用类型。 第一个for循环遍历ia的所有元素这些元素是大小为4的数组因此row的类型就应该是含有4个整数的数组的引用。 第二个for循环遍历那些4个元素数组中的某一个因此col的类型是整数的引用。每次迭代把cnt的值赋给ia的当前元素然后将cnt加1。在上面的例子中因为要改变数组元素的值所以我们选用引用类型作为循环控制变量但是其实还有一个深层次的原因促使我们这么做。123for(constauto row:ia)for(auto col:row)coutcolendl;这个循环中并没有任何写操作但是我们还是将外层循环的控制变量声明成了引用类型这是为了 避免数组ia被自动转换成指针 。12for(auto row:ia)for(auto col:row)此时ia被自动转化成指针row也变成指针了auto colrow就变成col遍历row的每一个地址。但是我们又不要遍历地址。所以外层的引用方式必须要加的。程序无法通过编译。这是因为想之前一样第一个循环遍历ia的所有元素注意这些元素实际上是大小为4的数组。因为row不是引用类型所以编译器初始化row时会自动将这些数组形式的元素和其他类型的数组一样转换成指向该数组内首元素的指针。这样会得到的row的类型就是int*显然内层的循环就不合法了编译器将试图在一个int*内遍历这显然和程序的初衷不一样。Tips要使用范围for语句处理多维数组除了最内层的循环外其他所有循环的控制变量都应该是引用类型。指针和多维数组当程序使用多维数组的名字时也会自动将其转换成指向数组首元素的指针。因为多维数组实际上是数组的数组所以由多维数组名转换而来的指针实际上是指向第一个内层数组的指针123456intia[3][4];//大小为3的数组每个元素是含有4个整数的数组int(*p)[4] ia;//p指向含有4个整数的数组p ia[2];//p指向ia的尾元素。(*p)意味着p是一个指针。接着看右侧指针p指向的是一个维度为4的数组再看左侧可知数组中的元素是整数。所以p是指向含有4个整数的数组的指针。12345//在上述声明中圆括号必不可少int*ip[4];//整形指针的数组int(*ip)[4];//指向含有4个整数的数组随着C11新标准提出通过使用auto或者decltype就能尽可能地避免在数组前面加上一个指针类型了123456789//输出ia中每个元素的值每个内层数组各占一行//p指向含有4个整数的数组for(auto p ia;p ! ia 3; p){//q指向4个整数数组的首元素也就是说q指向一个整数for(auto q *p; q ! *p 4;q)cout *q ;coutendl;}外层的for循环首先声明了一个指针并且令其指向ia的第一个内层数组然后依次迭代直到ia的全部3行都处理完为止。其中递增运算p负责将指针p移动到ia的下一行。内层的for循环负责输出内层数组所包含的值。它首先令指针q指向p当前所在行的第一个元素。*p是一个含有4个数组的数组像往常一样数组名被自动地转换成指向该数组首元素的指针。内层for循环不断迭代直到我们处理完了当前内层数组的所有元素为止。为了获取内层for循环的终止条件再一次解引用p得到指向内层数组首元素的指针给它加上4就得到了终止条件。

相关新闻