多维数组
更多资料可查阅官方博客,官方博客地址:https://llfc.club/
严格来说,C++语言中没有多维数组,通常所说的多维数组其实是数组的数组。谨记这一点,对今后理解和使用多维数组大有益处。
当一个数组的元素仍然是数组时,通常使用两个维度来定义它:一个维度表示数组本身大小,另外一个维度表示其元素(也是数组)大小:
// 大小为3的数组,每个元素是大小为4的数组
int ia[3][4];
按照由内而外的顺序阅读此类定义有助于更好地理解其真实含义。
在第一条语句中,我们定义的名字是ia
,显然ia
是一个含有3个元素的数组。
接着观察右边发现,ia
的元素也有自己的维度,所以ia
的元素本身又都是含有4个元素的数组。
再观察左边知道,真正存储的元素是整数。因此最后可以明确第一条语句的含义:它定义了一个大小为3的数组,该数组的每个元素都是含有4个整数的数组。
上面的代码可以理解为下面的形式
也可以初始化为
// 这些数组的元素是含有30个整数的数组
int arr[10][20][30] = {0}
使用同样的方式理解arr的定义。
首先arr是一个大小为10的数组,它的每个元素都是大小为20的数组,这些数组的元素又都是含有30个整数的数组。
实际上,定义数组时对下标运算符的数量并没有限制,因此只要愿意就可以定义这样一个数组:它的元素还是数组,下一级数组的元素还是数组,再下一级数组的元素还是数组,以此类推。对于二维数组来说,常把第一个维度称作行,第二个维度称作列。
多维数组的初始化
允许使用花括号括起来的一组值初始化多维数组,这点和普通的数组一样。下面的初始化形式中,多维数组的每一行分别用花括号括了起来:
//三个元素,每个元素是大小为4的数组
int ia[3][4] ={
//第一行的初始值
{0,1,2,3},
//第二行初始值
{4,5,6,7},
//第三行初始值
{8,9,10,11}
};
其中内层嵌套着的花括号并非必需的,例如下面的初始化语句,形式上更为简洁,完成的功能和上面这段代码完全一样:
int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
类似于一维数组,在初始化多维数组时也并非所有元素的值都必须包含在初始化列表之内。如果仅仅想初始化每一行的第一个元素,通过如下的语句即可:
//初始化每一行的首元素
int ia2[3][4] = {{0},{4},{8}};
其他未列出的元素执行默认值初始化,这个过程和一维数组一样。在这种情况下如果再省略掉内层的花括号,结果就大不一样了。
//值初始化第一i行
int ix[3][4] = {0,3,5,9};
含义发生了变化,它初始化的是第一行的4个元素,其他元素被初始化为0。
多维数组的下标
引用可以使用下标运算符来访问多维数组的元素,此时数组的每个维度对应一个下标运算符。
如果表达式含有的下标运算符数量和数组的维度一样多,该表达式的结果将是给定类型的元素;
反之,如果表达式含有的下标运算符数量比数组的维度小,则表达式的结果将是给定索引处的一个内层数组:
int ia[3][4] = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12}};
int arr[1][1][1] = {{{1}}};
// 用arr的首元素为ia的最后一个元素赋值
ia[2][3] = arr[0][0][0];
//row是一个4维数组的引用,将row绑定到ia的第二个元素(4维数组)上
int (&row)[4] = ia[1];
使用for循环
我们可以使用for循环构建数组
constexpr size_t rowCnt = 3, colCnt=4;
//12 个未初始化的元素
int ia[rowCnt][colCnt];
//对于每一行
for(size_t i = 0; i != rowCnt; ++i){
//对于行内的每一列
for( size_t j = 0; j != colCnt; ++j){
ia[i][j] = i*colCnt + j;
}
}
C++11风格处理多维数组
由于C++11新标准增加了范围for语句,所以前一个程序可以简化为
constexpr size_t rowCnt = 3, colCnt=4;
//12 个未初始化的元素
int ia[rowCnt][colCnt];
size_t cnt = 0;
for(auto &row: ia){
for(auto & col : row){
col = cnt;
++cnt;
}
}
输出每一个元素
for(const auto & row: ia){
for(auto col : row){
std::cout << col << " ";
}
std::cout << std::endl;
}
输出
0 1 2 3
4 5 6 7
8 9 10 11
指针和多维数组
当程序使用多维数组的名字时,也会自动将其转换成指向数组首元素的指针。
新手雷区
定义指向多维数组的指针时,千万别忘了这个多维数组实际上是数组的数组。
因为多维数组实际上是数组的数组,所以由多维数组名转换得来的指针实际上是指向第一个内层数组的指针:
//大小为3的数组,每个元素是含有4个整数的数组
int ia[3][4];
//p指向含有4个整数的数组
int(*p)[4] = ia;
//将p修改为指向ia数组的尾部
p = &ia[2];
随着C++11新标准的提出,通过使用auto或者decltype
就能尽可能地避免在数组前面加上一个指针类型了:
// ia数组
int ia[3][4] = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12}};
//输出ia中每个元素的值,每个内存数组各占一行
//p指向含有4个整数的数组
for(auto p = ia; p != ia + 3; ++p){
//q指向4个整数的数组的首元素
for(auto q = *p; q != *p + 4; ++q){
std::cout << *q << ' ';
}
std::cout << std::endl;
}
使用C++11提供的std::begin
也能实现类似的功能
// ia数组
int ia[3][4] = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12}};
// p指向ia的第一个数组
for(auto p = std::begin(ia); p != std::end(ia); ++p){
// q指向内存数组的首元素
for( auto q = std::begin(*p); q != std::end(*p); ++q){
// 输出q所指的整数值
std::cout << *q << ' ';
}
std::cout << std::endl;
}
类型别名简化多维数组指针
可以使用using 进行类型别名的声明,或者使用typedef声明类型的别名
// ia数组
int ia[3][4] = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12}};
// 新标准下类型别名的声明
using int_array = int[4];
// 使用typedef 声明类型的别名
typedef int int_array_t[4];
for(int_array * p = ia; p != ia + 3; ++p){
for(int *q = *p ; q != *p+4; ++q){
std::cout << *q << " ";
}
std::cout << std::endl;
}
练习题1:矩阵加法
题目描述
编写一个C++程序,输入两个2x3
的矩阵,计算它们的和,并输出结果矩阵。
示例代码框架
#include <iostream>
int main() {
const int ROW = 2;
const int COL = 3;
int matrix1[ROW][COL];
int matrix2[ROW][COL];
int sum[ROW][COL];
// 输入第一个矩阵
std::cout << "请输入第一个2x3矩阵的元素(共6个整数):" << std::endl;
for(int i = 0; i < ROW; ++i) {
for(int j = 0; j < COL; ++j) {
// 在此输入元素
}
}
// 输入第二个矩阵
std::cout << "请输入第二个2x3矩阵的元素(共6个整数):" << std::endl;
for(int i = 0; i < ROW; ++i) {
for(int j = 0; j < COL; ++j) {
// 在此输入元素
}
}
// 计算两个矩阵的和
// 在此实现加法逻辑
// 输出结果矩阵
std::cout << "两个矩阵的和为:" << std::endl;
for(int i = 0; i < ROW; ++i) {
for(int j = 0; j < COL; ++j) {
// 在此输出sum[i][j]
}
std::cout << std::endl;
}
return 0;
}
预期输出(示例)
请输入第一个2x3矩阵的元素(共6个整数):
1 2 3 4 5 6
请输入第二个2x3矩阵的元素(共6个整数):
6 5 4 3 2 1
两个矩阵的和为:
7 7 7
7 7 7
答案
#include <iostream>
int main() {
const int ROW = 2;
const int COL = 3;
int matrix1[ROW][COL];
int matrix2[ROW][COL];
int sum[ROW][COL];
// 输入第一个矩阵
std::cout << "请输入第一个2x3矩阵的元素(共6个整数):" << std::endl;
for(int i = 0; i < ROW; ++i) {
for(int j = 0; j < COL; ++j) {
std::cin >> matrix1[i][j];
}
}
// 输入第二个矩阵
std::cout << "请输入第二个2x3矩阵的元素(共6个整数):" << std::endl;
for(int i = 0; i < ROW; ++i) {
for(int j = 0; j < COL; ++j) {
std::cin >> matrix2[i][j];
}
}
// 计算两个矩阵的和
for(int i = 0; i < ROW; ++i) {
for(int j = 0; j < COL; ++j) {
sum[i][j] = matrix1[i][j] + matrix2[i][j];
}
}
// 输出结果矩阵
std::cout << "两个矩阵的和为:" << std::endl;
for(int i = 0; i < ROW; ++i) {
for(int j = 0; j < COL; ++j) {
std::cout << sum[i][j] << " ";
}
std::cout << std::endl;
}
return 0;
}
练习题2:矩阵转置
题目描述
编写一个C++程序,输入一个3x3
的矩阵,计算其转置矩阵,并输出结果。
示例代码框架
#include <iostream>
int main() {
const int SIZE = 3;
int matrix[SIZE][SIZE];
int transpose[SIZE][SIZE];
// 输入原始矩阵
std::cout << "请输入一个3x3矩阵的元素(共9个整数):" << std::endl;
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
// 在此输入matrix[i][j]
}
}
// 计算转置矩阵
// 在此实现转置逻辑
// 输出转置后的矩阵
std::cout << "矩阵的转置为:" << std::endl;
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
// 在此输出transpose[i][j]
}
std::cout << std::endl;
}
return 0;
}
预期输出(示例)
请输入一个3x3矩阵的元素(共9个整数):
1 2 3 4 5 6 7 8 9
矩阵的转置为:
1 4 7
2 5 8
3 6 9
答案
#include <iostream>
int main() {
const int SIZE = 3;
int matrix[SIZE][SIZE];
int transpose[SIZE][SIZE];
// 输入原始矩阵
std::cout << "请输入一个3x3矩阵的元素(共9个整数):" << std::endl;
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
std::cin >> matrix[i][j];
}
}
// 计算转置矩阵
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
transpose[j][i] = matrix[i][j];
}
}
// 输出转置后的矩阵
std::cout << "矩阵的转置为:" << std::endl;
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
std::cout << transpose[i][j] << " ";
}
std::cout << std::endl;
}
return 0;
}
赞赏
感谢支持