C++遍历“高维”数组的9种方法

C++遍历“高维”数组的九种方法

一般认为C++中数组只有一维,高维数组如int ia[3][4]其实是由三个包含四个int型元素的一维数组元素组成的,即int ia[3][4]含有三个元素,每个元素都是一个int[4]类型的数组。
在阅读《C++ Primer》的过程中发现了以下几种遍历“高维”数组的方法,在这里记录下来。
所遍历的二维数组初始化如下:

int ia[3][4] = {
		{0,1,2,3},
		{4,5,6,7},
		{8,9,10,11}
	};//列表初始化,还有许多等价的写法

文末附有所有九种访问方式的测试代码。

1、使用范围for语句遍历数组元素

范围for语句不同于一般的for循环,代码如下:

for (int(&row)[4] : ia)		//此处必须加&,因为ia存储的是一个地址
		for (int col : row)	cout << col << " ";
	cout << endl;

2、普通for语句,下标运算符访问

for (size_t i = 0; i < 3; i++) {
		for (size_t j = 0; j < 4; j++) {
			cout << ia[i][j] << " ";
		}
		cout << endl;
	}

一种常规遍历数组的方法,这里size_t可直接视为unsigned int,取值非负。

3、普通for语句,指针访问

for (int(*row)[4] = ia; row != ia + 3; row++)
		for (int* col = *row; col != *row + 4; col++)
			cout << *col << " ";
	cout << endl;

这里用到的rowcol都是指针,所以最后访问具体元素时需要用到解引用符*,通过*col遍历数组中的元素。
此外,迭代器的用法和这里的指针非常相似,《C++ Primer》中比较推荐C++程序员采用迭代器的方式去访问元素,因为指针若处理不好可能会有意想不到的效果。这里用row != ia + 3作为条件而不用row <= ia + 3作为终止条件也是一个比较有趣的地方,《C++ Primer》推荐C++程序员这样处理。

4、类型别名+范围for循环访问

using int_array = int[4];
typedef int int_array[4];			//这一句和上面一句是等价的

for (int_array& row : ia) {				//若不加&会报错:
		for (int col : row) {//这句不用加//int *" 类型的值不能用于初始化 "int_array" 类型的实体
			cout << col << " ";
		}
		cout << endl;
	}

别名的两种定义方式是一个效果(这里using的定义方式似乎是C++ 11标准的特性),这样其实我们也可以通过两者等价知道int_array的类型是int[4],这里的row本质上还是一个指针。

5、类型别名+指针访问

using int_array = int[4];
typedef int int_array[4];			//这一句和上面一句是等价的

for (int_array* p = ia; p != ia + 3; p++) {
		for (int* q = *p; q != *p + 4; q++) {		//注意p要加*才能解引用成指针类型
			cout << *q << " ";
		}
		cout << endl;
	}

在这里我们可以看到*p实际上才是一个数组的首地址,而int* q表明q是一个int *型的指针,通过q的自增操作,内存中q移动sizeof(int)个单位从而达到遍历int[4]数组中的每一个元素的目的。

6、auto+范围for循环访问

for (auto& row : ia) {
		for (auto col : row) {
			cout << col << " ";
		}
		cout << endl;
	}

此处的&仍然是必须的,否则row类型会被视为int *导致出错。此处的colint型,因此可以直接输出不用解引用。

7、auto+下标访问

for (auto i = 0; i != 3; i++) {
		for (auto j = 0; j != 4; j++) {
			cout << ia[i][j] << " ";
		}
		cout << endl;
	}

很基础的访问方式,ij都属int型。

8、auto+指针访问

for (auto row = ia; row != ia + 3; row++) {
		for (auto col = *row; col != *row + 4; col++) {
			cout << *col << " ";
		}
		cout << endl;
	}

这实际上就是第三种情况的傻瓜版,auto,yyds。

9、标准库函数begin和end访问

#include 					//使用begin和end函数需要加上这个头文件和相应的using声明

//p指向ia的第一个数组
	for (auto p = begin(ia); p != end(ia); ++p) {
		//q指向内层数组的首元素
		for (auto q = begin(*p); q != end(*p); ++q) {
			cout << *q << " ";		//输出q所指的整数值
		}
		cout << endl;
	}

begin(ia)会指向ia的首地址,end(ia)指向ia尾地址的下一个地址,这两个函数定义在iterator头文件中。

测试代码

#include 
#include 
#include 					//使用begin和end函数需要加上这个头文件和相应的using声明
#include 					//使用setw函数
using std::cin; using std::cout; using std::endl;
using std::string;
using std::begin; using std::end;
using std::setw; //使用命名空间中设置宽度方式的名字
using int_array = int[4];
typedef int int_array[4];			//这一句和上面一句是等价的
typedef int VVINT[2][3];

int main() {
	VVINT a{ 0 };
	for (int(&row)[3] : a) {
		for (int col : row)	cout << col << " ";
		cout << endl;
	}
	cout << string(10, '-') << setw(70) 
		<< "1、以上输出初始化的int[2][3]类型数组"
		<< string(10, '-') << endl << endl;

	int ia[3][4] = {
		{0,1,2,3},
		{4,5,6,7},
		{8,9,10,11}
	};
	size_t cnt = 0;
	//版本1:使用范围for语句管理迭代过程
	for (int(&row)[4] : ia)
		for (int col : row)	cout << col << " ";
	cout << endl;
	cout << string(10, '-') << setw(70) 
		<< "2、以上通过范围for语句在同一行输出ia[3][4]"
		<< string(10, '-') << endl << endl;

	memset(ia, 0, sizeof(ia));
	//版本2,普通for语句,下标运算符访问
	for (size_t i = 0; i < 3; i++) {
		for (size_t j = 0; j < 4; j++) {
			cout << ia[i][j] << " ";
		}
		cout << endl;
	}
	cout << string(10, '-') << setw(70) 
		<< "3、以上通过普通for语句+下标运算符分行输出memset全0后的ia[3][4]"
		<< string(10, '-') << endl << endl;

	//以下再次初始化ia[3][4]
	for (auto& row : ia) {
		for (auto& col : row) {
			col = cnt++;
		}
	}
	//版本3,普通for语句,指针访问
	for (int(*row)[4] = ia; row != ia + 3; row++)
		for (int* col = *row; col != *row + 4; col++)
			cout << *col << " ";
	cout << endl;
	cout << string(10, '-') << setw(70) 
		<< "4、以上通过普通for语句+指针访问在同一行输出再次初始化后的ia[3][4]"
		<< string(10, '-') << endl << endl;

	//版本4:类型别名+范围for循环
	for (int_array& row : ia) {				//若不加&会报错:
		for (int col : row) {//这句不用加	//int *" 类型的值不能用于初始化 "int_array" 类型的实体
			cout << col << " ";
		}
		cout << endl;
	}
	cout << string(10, '-') << setw(70) 
		<< "5、以上通过类型别名+范围for循环分行输出ia[3][4]"
		<< string(10, '-') << endl << endl;

	//版本5:类型别名+指针访问
	for (int_array* p = ia; p != ia + 3; p++) {
		for (int* q = *p; q != *p + 4; q++) {		//注意p要加*才能解引用成指针类型
			cout << *q << " ";
		}
		cout << endl;
	}
	cout << string(10, '-') << setw(70) 
		<< "6、以上通过类型别名+指针访问分行输出ia[3][4]"
		<< string(10, '-') << endl << endl;

	//版本6:auto+范围for循环
	for (auto& row : ia) {
		for (auto col : row) {
			cout << col << " ";
		}
		cout << endl;
	}
	cout << string(10, '-') << setw(70) 
		<< "7、以上通过auto关键字+范围for循环分行输出ia[3][4]"
		<< string(10, '-') << endl << endl;

	//版本7:auto+下标访问
	for (auto i = 0; i != 3; i++) {
		for (auto j = 0; j != 4; j++) {
			cout << ia[i][j] << " ";
		}
		cout << endl;
	}
	cout << string(10, '-') << setw(70) 
		<< "8、以上通过auto关键字+下标访问分行输出ia[3][4]"
		<< string(10, '-') << endl << endl;

	//版本8:auto+指针访问
	for (auto row = ia; row != ia + 3; row++) {
		for (auto col = *row; col != *row + 4; col++) {
			cout << *col << " ";
		}
		cout << endl;
	}
	cout << string(10, '-') << setw(70) 
		<< "9、以上通过auto关键字+指针访问分行输出ia[3][4]"
		<< string(10, '-') << endl << endl;

	//版本9:标准库函数begin和end访问
	//p指向ia的第一个数组
	for (auto p = begin(ia); p != end(ia); ++p) {
		//q指向内层数组的首元素
		for (auto q = begin(*p); q != end(*p); ++q) {
			cout << *q << " ";		//输出q所指的整数值
		}
		cout << endl;
	}
	cout << string(10, '-') << setw(70) 
		<< "10、以上通过标准库函数begin和end分行输出ia[3][4]"
		<< string(10, '-') << endl << endl;
	return 0;
}

你可能感兴趣的:(《C++,Primer》,c++,指针,c++11,数据结构,数组)