一、基本概念

        泛型编程:所谓泛型程序设计,就是编写不依赖于具体数据类型的程序。C++中,模板是泛型编程的主要工具。泛型程序设计的主要思想是将算法从特定的数据结构中抽象出来,使算法成为通用的、可以作用于各种不同的数据结构。以函数模板形式实现的通用算法与各种通用容器结合,提高了软件的复用性[2]。例如,所有标准库容器的迭代器都定义了==和!=,我们只要养成使用迭代器和!=的习惯,就不用太在意用的到底是哪种容器类型。

        缓冲区溢出(buffer overflow):一种严重的程序故障,主要的原因是试图通过一个越界的索引访问容器内容,容器类型包括string、vector和数组等[1]。

        容器(container):容器是容纳、包含一组元素的对象。容器类库中包含13种基本容器:向量(vector)、双端队列(deque)、列表(list)、单向链表(forward_list),数组(array),集合(set)、多重集合(multiset)、映射(map)、多重映射(multimap),以及后面四种容器的无序(unorder)形式。顺序容器(sequence container)将一组具有相同类型的元素以严格的线性形式组织起来,向量、双端队列、列表、单向链表和数组容器就属于这一种;关联容器(associative container)具有根据一组索引来快速提取元素的能力,集合和映射容器就属于这一种。而关联容器又可分为有序和无序,有序容器中键(key)按顺序存储,无序容器则使用哈希函数组织元素[2]。

        迭代器(iterator):迭代器提供了顺序访问容器中每个元素的方法,如++、--、*、->等运算符。指针也具有相同的特性,因此指针本身就是一种迭代器,迭代器是泛化的指针[2]。所有标准库容器都可以使用迭代器,但是其中只有少数几种才同时支持下标运算符。

        常量表达式(const expression):指值不会改变并且在编译过程就能得到计算结果的表达式。常量表达式有字面值、用常量表达式初始化的const对象等。

        程序的完整流程:需求分析、程序设计、代码编写(遵循良好的编码规范,确保代码的可读性、可维护性和可扩展性)、编译和构建(使用相应的编译器将源代码转换为可执行文件或库文件)、调试和测试(通过单元测试、集成测试和系统测试,验证程序在各种情况下的正确性和稳定性)、部署和运行(将程序部署到目标环境中,并根据需要提供必要的配置和资源)、优化和维护以及使用文档交付。

        范围for语句:该语句遍历给定序列中的每个元素并对序列中的每个值执行某种操作,语法形式为:

for(declaration:expression)

        statement;

        其中,expression部分是一个对象,用于表示一个序列。declaration部分负责定义一个变量,该变量在每次迭代后会被初始化为expression部分的下一个元素值。

二、auto类型说明符和decltype类型指示符

        auto类型说明符

        使用目的:编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚地知道表达式的类型。auto类型说明符,可以让编译器替我们去分析表达式所属的类型。

        注意事项:编译器推断出来的auto类型有时候和初始值的类型并不完全一样,编译器会适当地改变结果类型使其更符合初始化规则。如,auto一般会忽略掉顶层const,同时底层const则会保留下来。

        decltype类型指示符

        使用目的希望从表达式的类型推断出要定义的变量的类型,但是不想用该表达式的值初始化变量。decltype类型指示符,可以让编译器分析表达式(如变量、函数等)并得到它的类型,却不实际计算表达式的值。

        注意事项:decltype的结果类型与表达式形式密切相关。如果decltype使用的是一个不加括号的变量,则得到的结果就是该变量的类型;如果给变量加上了一层或多层括号,编译器就会把它当成是一个表达式,从而decltype就会得到引用类型。

二、编程实践

练习3.17(P94)

# include<vector>
# include<iostream>
# include<string>

using namespace std;

int main() 
{
	string word = "";
	vector<string> WordVector;
	cout << "请输入一组英文单词(单词间利用空格符间隔,EOF结尾):" << endl;
	// 将所有原始单词存入词向量中
	while (cin >> word)
	{
		WordVector.push_back(word);
	}
	cout << "单词向量构建完成!" << endl;
	// 逐单词修改为大写形式并输出(每个单词占用一行)
	// 基于范围for循环修改单词
	for (auto b = WordVector.begin(); b != WordVector.end(); ++b)
	{
		for (auto  &w : *b)
			w = toupper(w);
		cout << *b << endl;	
	}
	return 0;
}

实验结果

基于C++11标准的Vector容器与多维数组编程规范学习-LMLPHP

实验笔记[3][4]

练习3.20(P94

# include<vector>
# include<iostream>

using namespace std;

int main() 
{
	int num = 0;
	vector<int> numVector;
	vector<int> biSum;
	cout << "请输入一系列整型数字串(数字与数字之间利用空格间隔,输入末尾以EOF结尾)" << endl;
	while (cin >> num)
		numVector.push_back(num);
	auto amount = numVector.size();
	auto code = amount % 2;
	auto b = numVector.begin(), e = numVector.end()-1;
	// 双指针移动
	if (amount == 0)
		cout << "整数向量未存储元素!" << endl;
	else
	{
		if (code == 1)
		{
			while (b != e)
			{
				biSum.push_back(*b + *e);
				++b;
				--e;
			}
			// 添加中间单值
			biSum.push_back(*b);
		}
		else
		{
			while (b != e - 1)
			{
				biSum.push_back(*b + *e);
				++b;
				--e;
			}
			biSum.push_back(*b + *e);
		}
	}
	// 打印计算结果
	for (auto val : biSum)
		cout << val << endl;
	return 0;
}

实验结果

基于C++11标准的Vector容器与多维数组编程规范学习-LMLPHP

基于C++11标准的Vector容器与多维数组编程规范学习-LMLPHP

实验笔记

练习3.43(P116)

# include<iostream>

using namespace std;

// 所有版本直接写出数据类型
// 版本一:范围for语句管理迭代过程
void Version1(int(&array)[3][4],int row)
{
	for (int (&arr)[4] : array)
	{
		for (int a : arr)
			cout << a << " ";
		cout << endl;
	}
}

// 版本二:下标运算符
void Version2(int array[][4],int row)
{
	for (unsigned i = 0; i != row; ++i)
	{
		for (unsigned j = 0; j != 4; ++j)
			cout << array[i][j] << " ";
		cout << endl;
	}
}

// 版本三:指针
void Version3(int (*array)[4], unsigned row)
{
	for (decltype(array) arr = array; arr != array + row; ++arr)
	{
		for (int *a = *arr; a != *arr + 4; ++a)
			cout << *a << " ";
		cout << endl;
	}
}

// 版本四:auto引入
// 将二维数组的引用作为参数传递
void Version4(int (&array)[3][4],int row)
{
	for (auto &arr : array)
	{
		for (auto a : arr)
			cout << a << " ";
		cout << endl;
	}
}


int main() 
{
	int ia[3][4] = { {0,1,2,3},{4,5,6,7},{8,9,10,11} };
	cout << "Version1输出结果如下所示:" << endl;
	Version1(ia,3);
	cout << "Version2输出结果如下所示:" << endl;
	Version2(ia,3);
	cout << "Version3输出结果如下所示:" << endl;
	Version3(ia,3);
	cout << "Version4输出结果如下所示:" << endl;
	Version4(ia,3);
	return 0;
}

实验结果

基于C++11标准的Vector容器与多维数组编程规范学习-LMLPHP

实验笔记[5][6]

参考资料:

[1] C++ Primer中文版:第5版 /(美)李普曼(Lippman,S.B.),(美)拉乔伊(Lajoie,J.),(美)默(Moo,B.E.)著;王刚,杨巨峰译. —北京:电子工业出版社,2013.9.(第二章-变量和基本类型 /第三章-字符串、向量和数组)

[2] C++语言程序设计 / 郑莉,董渊编著.—5版.—北京:清华大学出版社,2020.11.(第十章-泛型程序设计与C++语言标准模板库)

Debug参考资料:

[3] C++ cin的使用,看这一篇就够了-CSDN博客

[4] 输入一串未知个数的数据直到EOF(-1)停止和键盘输入文件结尾符EOF_c++输入-1结束输入要怎么输-CSDN博客

[5] C++笔记 二维数组作为函数的参数详解 三种传参的方法总结 注意要点总结_二维数组作为参数传入函数-CSDN博客

[6] C++中如何将数组作为函数参数_c++ 数组作为函数参数-CSDN博客

12-11 22:42