C++ Prime 第三章 字符串、向量和数组

2022-12-25~2023-03-15

命名空间using声明

  • 头文件不应该包含using声明

3.1节练习

  • 练习3.1: using std::cout; using std::endl; using std::cin; using std::string; ...... 或者不使用using,仅在需要使用到std中的函数时在前面加上std::

3.2 标准库类型string

  • 直接初始化:直接执行初始化方法
  • 拷贝初始化:通过等号,将等号右侧的数值拷贝到等号左侧中
  • getline:从输入流中读取数据,读取到换行符时就将目前读取到的数据存入到string对象中。
string line;
while (getline(cin, line))
  cout < line << endl;
  • empty函数:检查string对象是否是一个空字符串,返回对应的布尔值
#include<iostream>
#include<string>
using namespace std;


int main()
{
	string line;
	while (getline(cin, line)) {
		if (line.empty()) {
			cout << "empty" << endl;
		}
		else {
			cout << line << endl;
		}
	}

	system("pause");
	return 0;
}
  • size函数:返回字符串对象的长度,类型不是int是string::size_type,size函数返回的是一个无符号整型数,切记不要和带符号的数据类型进行比较等操作
  • 字面值和sgring对象相加:由于历史原因,c++中的字符串字面值并不是标准库中的string对象,所以当字面值和字符串进行相加操作时会自动进行类型转化,当string和字面值相加时必须保证+号两边必须有一个string类型的数据

3.2.2节练习

  • 练习3.2:
#include<iostream>
#include<string>
using namespace std;


int main()
{
	string line;
	while (getline(cin, line)) {
		if (line.size() == 1) {
			cout << line << endl;
		}
		
	}
	system("pause");
	return 0;
}
  • 练习3.3: getline遇到换行符就将输入流中的数据保存到string对象中 string的输入运算符,在输入流中会忽略空白字符直到遇到第一个非空白字符为止,后续再遇到空白字符,就将数据保存到string中并停止
  • 练习3.4:
#include<iostream>
#include<string>
using namespace std;


int main()
{
	string line1, line2;
	if (line1 == line2) {
		cout << "line1 == line2" << endl;
	}
	else {
		if (line1 > line2) {
			cout << line1 << endl;
		}
		else
		{
			cout << line2 << endl;
		}
	}
	return 0;
}

#include<iostream>
#include<string>
using namespace std;


int main()
{
	string line1, line2;
	if (line1.size() > line2.size()) {
		cout << line1 << endl;
	}
	else {
		cout << line2 << endl;
	}
	return 0;
}

  • 练习3.5:
#include<iostream>
#include<string>
using namespace std;


int main()
{
	string line1, line2;
	while (cin >> line1) {
		line2 += line1;
	}
	cout << line2 << endl;
	return 0;
}
#include<iostream>
#include<string>
using namespace std;


int main()
{
	string line1, line2;
	while (cin >> line1) {
		line2 += (line1 + " ");
	}
	cout << line2 << endl;
	return 0;
}
               
  • 逻辑与运算符:只有当与运算符的右侧的对象为真时,编译器才会取检查左侧的对象的情况

3.2.3节练习

  • 练习3.6:
#include<iostream>
#include<string>
using namespace std;


int main()
{
	string line = "1234456asdqwe";
	for (auto& c : line) {
		c = 'X';
	}
	cout << line << endl;
	return 0;
}
  • 练习3.7: 每次都是在修改临时变量所以,运行前后的结果没有变化
#include<iostream>
#include<string>
using namespace std;


int main()
{
	string line = "1234456asdqwe";
	line = "123133";
	for (char c : line) {
		c = 'X';
		cout << c << endl;
	}
	cout << line << endl;
	system("pause");
	return 0;
}
  • 练习3.8: while:
#include<iostream>
#include<string>
using namespace std;


int main()
{
	string line = "123123123asdasd";
	decltype(line.size()) line_length = 0;
	cout << line_length << endl;
	while (line_length != line.size()) {
		line[line_length] = 'X';
		++line_length;                                        
	}
	cout << line << endl;
	system("pause");
	return 0;
}

传统for循环:

#include<iostream>
#include<string>
using namespace std;


int main()
{
	string line = "123123123asdas";
		for (decltype(line.size()) line_length = 0; 
			line_length < line.size(); 
			line_length++) {
			line[line_length] = 'X';
	}
		cout << line << endl;
	system("pause");
	return 0;
}

while结构更清晰

  • 练习3.9: 实际运行并不会报错,访问空字符的第一个下标元素是空
  • 练习3.10:
#include<iostream>
#include<string>
using namespace std;


int main()
{
	string line1, line2;
	cin >> line1;
	for (auto& c : line1) {
		if (!ispunct(c)) {
			line2 += c;
		}
	}
	cout << line2 << endl;
	system("pause");
	return 0;
}
  • 练习3.11: 合法,c的类型是const char& alt

3.3 标准库类型vector

  • vector:表示对象的集合,其中所有对象的类型都相同,每个对象都有一个索引与之对应,索引用来访问对象
  • 列表初始化vector对象
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{
	vector<int> MyInt1;
	vector<int> MyInt2 = MyInt1; // 拷贝初始化
	vector<int> MyInt3(MyInt2); // 拷贝初始化?
	vector<int> MyInt4 = { 10, 20, 30 }; // 列表初始化
	vector<vector<int>> MyInt5 = { MyInt1, MyInt2, MyInt3 }; // 列表初始化
	vector<int> MyInt6(10, 1); // MyInt6中包含了10个1
	vector<int> MyInt7(10); // MyInt7中包含了10个元素,元素的初始值由元素类型自身决定,int即为0
	cout << MyInt7[0] << endl;
	vector<string> MyString(10);// MyInt7中包含了10个元素,元素的初始值由元素类型自身决定,string即为空字符串
	cout << MyString[0] << endl;
	system("pause");
	return 0;
}
  • 值初始化:创建vector对象时忽略初始值时,此时库会创建一个元素初值并把它赋予给容器中的所有元素,这个元素初值由vector中的元素类型决定,如果是int就为0,如果是string就按照string本身的默认初始化值来即空字符串
  • 列表初始化的初始值转化为元素数量:当列表初始化提供的值无法进行初始化操作时,考虑将初始值转化成提供元素数量
vector<int> MyInt(10); // 10个元素,每个元素都初始化为0
vector<string> MyString(10); // 10个元素,每个元素都初始化为空字符串
vector<string> MyString{10}; // 提供的值无法进行初始化操作,vector<string> MyString{10}-->vector<string> MyString(10)

3.3.1节练习

  • 练习3.12: (a)正确:ivec保存了一个vector对象的元素 (b)错误,svec和ivec保存的数据类型不同 (c)正确,svec保存了10个字符串"null"
  • 练习3.13: (a)没有包含元素 (b)10个元素,值都是0 (c)10个元素,值都是42 (d)1个元素,值是10 (e)2个元素,值是10和42 (f)10个元素,值都是空字符串 (g)10个元素,值都是"hi"

练习3.3.2节练习

  • 练习3.14:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{
	vector<int> Myint;
	int temp;
	while (cin >> temp) {
		Myint.push_back(temp);
	}
	system("pause");
	return 0;
}
  • 练习3.15:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{
	vector<string> Mystring;
	string temp;
	while (cin >> temp) {
		Mystring.push_back(temp);
	}
	system("pause");
	return 0;
}

3.3.3节练习

  • 练习3.16:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{
	vector<int> v1;
	cout << v1.size() << endl; // 0

	vector<int> v2(10);
	cout << v2.size() << endl; // 10
	for (auto temp : v2) {
		cout << temp << endl; // 10个0
	}

	vector<int> v3(10, 42);
	cout << v3.size() << endl; // 10
	for (auto temp : v3) {
		cout << temp << endl; // 10个42
	}

	vector<int> v4{ 10 };
	for (auto temp : v4) {
		cout << temp << endl; // 10
	}

	vector<int> v5{ 10, 42 };
	for (auto temp : v5) {
		cout << temp << endl; // 10、42
	}

	vector<int> v6{ 10 };
	for (auto temp : v6) {
		cout << temp << endl; // 10
	}

	vector<string> v7{ 10, "hi"};
	for (auto temp : v7) {
		cout << temp << endl; // 10hi
	}


	system("pause");
	return 0;
}
  • 练习3.17:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{
	vector<string> s;
	string temp;
	while (cin >> temp)
	{
		for (auto& c : temp) {
			c = toupper(c);
		}
		s.push_back(temp);
	}
	for (auto c : s) {
		cout << c << endl;
	}

	system("pause");
	return 0;
}
  • 练习3.18: 不合法
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{

	vector<int> ivec(1);
	ivec[0] = 42;
  
	system("pause");
	return 0;
}
  • 练习3.19:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{

	vector<int> ivec1(10, 42);
	vector<int> ivec2{ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
	vector<int> ivec3 = { 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };

	system("pause");
	return 0;
}
  • 练习3.20: 相邻:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{

	vector<int> ivec;
	int temp;
	while (cin >> temp) {
		ivec.push_back(temp);
	}
	for (decltype(ivec.size()) i = 0; i < ivec.size() - 1; i++) {
		cout << ivec[i] + ivec[i + 1] << endl;
	}
	system("pause");
	return 0;
}

首尾:

#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{

	vector<int> ivec;
	int temp;
	while (cin >> temp) {
		ivec.push_back(temp);
	}
	decltype(ivec.size()) temp_time = ivec.size() - 1;
	for (decltype(ivec.size()) i = 0; i < ivec.size() - 1; i++) {
		if (i < temp_time - i) {
			cout << ivec[i] + ivec[temp_time - i] << endl;
		}
		else if (i == (temp_time - i)) {
			cout << ivec[i] << endl;
		}
	}

	system("pause");
	return 0;
}
  • cbegin()、cend()不论容器的对象是不是常量,返回的都是const_iterator
  • 箭头运算符->把解引用和访问成员两个操作结合在一起,it->mem==(* it).mem
  • 两个对vector对象的操作会导致vectaor的迭代器失效: 1、在范围for循环中向vector添加元素 2、任何一种改变vector容量的操作,都会使vector对象的迭代器失效

3.4.1节练习

  • 练习3.21: 基本类似:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{

	vector<int> v(5, 42);
	for (vector<int>::const_iterator i = v.cbegin(); i != v.cend(); ++i) {
		cout << *i << endl;
	}

	system("pause");
	return 0;
}
  • 练习3.22:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{

	vector<string> text{ "hiiiiiiiiiii", "", "123123"};
	for (vector<string>::iterator i = text.begin(); i != text.end() && !i->empty(); ++i) {
		for (auto& c : *i) {
			c = toupper(c);
		}
		cout << *i << endl;
		
	}
	system("pause");
	return 0;
}
  • 练习3.23:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{

	vector<string> text{ "hiiiiiiiiiii", "", "123123"};
	for (vector<string>::iterator i = text.begin(); i != text.end() && !i->empty(); ++i) {
		for (auto& c : *i) {
			c = toupper(c);
		}
		cout << *i << endl;
		
	}
	system("pause");
	return 0;
}
  • 练习3.23:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{

	vector<int> my_list(10, 1);
	for (vector<int>::iterator i = my_list.begin(); i != my_list.end(); ++i) {
		*i = *i * 2;
	}
	for (vector<int>::iterator i = my_list.begin(); i != my_list.end(); ++i) {
		cout << *i << endl;
	}

	system("pause");
	return 0;
}

3.4.2迭代器运算

  • 所有标准容器都支持递增运算、和!=、==进行比较
  • 迭代器不支持两个迭代器相加运算、支持两个迭代器相减运算

3.4.2节练习

  • 练习3.24: 相邻:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{

	vector<int> vec{ 1, 2, 3, 4, 5 };
	auto beg = vec.begin(), end = vec.end() - 1;
	while (beg != end) {
		cout << *beg + *(beg + 1) << endl;
		++beg;
	}

	system("pause");
	return 0;
}

首尾:

#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{

	vector<int> vec{ 1, 2, 3, 1, 3, 4, 5 };
	auto beg = vec.begin(), end = vec.end() - 1;
	while (true) {
		if (end > beg) {
			cout << *beg + *end << endl;
			--end;
			++beg;
		}
		else if (end == beg) {
			cout << *beg << endl;
			break;
		}
		else {
			break;
		}
	}

	system("pause");
	return 0;
}
  • 练习3.25:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main()
{

	vector<int> vec(11, 0);
	auto beg = vec.begin();
	unsigned grade;
	while (cin >> grade) {
		if (grade <= 100) {
			*(beg + (grade / 10)) = *(beg + (grade / 10)) + 1;
			cout << *(beg + (grade / 10)) << endl;
		}
	}
	for (auto i : vec) {
		cout << i << endl;
	}
	system("pause");
	return 0;
}
  • 练习3.26:两个迭代器不支持相加运算

3.5 数组

  • 存放相同类型数据的容器,数组大小确定不变
  • 数组的声明:a[d],a为数字名字,d是一个常量表达式代表数组中元素的个数
  • 数组定义时必须指定数组的类型,不允许使用auto关键字
  • 字符数组的特殊性:使用字符串字面值进行字符数组初始化时,需要注意字面值结尾处还有一个空字符 const char a4[6] = "Daniel"; // 错误,Daniel隐形的包含了一个空字符串
  • 数组不允许拷贝和赋值

3.5.1节练习

  • 练习3.27: (a):非法,buf_size不是常量 (c):非法,tet_size函数的返回值不是一个常量 (d):非法,fundamental隐形的包含了一个空字符,没有空间来存放空字符
  • 练习3.28:
#include<iostream>
#include<string>
#include<vector>
using namespace std;

int sa[10]; // 0
string ia[10]; // 空字符

int main()
{
	int sa2[10]; // 未定义
	string ia2[10]; // 空字符
	system("pause");
	return 0;
}
  • 练习3.29: 缺点: 1、数组的维度大小在创建时必须已确定,并且数组无法进行扩容 2、定义数组时必须显式指定数组的类型,无法使用auto等关键字 3、数组无法进行拷贝、赋值操作

3.5.2 节练习

  • 练习3.30:数组的大小是10,for循环中从0开始遍历,所以for循环结束的边界值应该array_size-1,而不是array_size
  • 练习3.31:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main(){
	int int_array[10] = {};
	int temp = 0;
	for (auto& a : int_array) {
		a = temp;
		temp++;
	}
	return 0;
}
  • 练习3.32: 拷贝:
#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main(){
	int int_array[10] = {};
	int temp = 0;
	for (auto& a : int_array) {
		a = temp;
		temp++;
	}
	int int_array1[10] = {};
	int temp1 = 0;
	for (auto& a : int_array1) {
		a = int_array[temp1];
		temp++;
	}
	return 0;
}

vector:

#include<iostream>
#include<string>
#include<vector>
using namespace std;


int main(){
	vector<int> vet_int(10);
	int temp = 0;
	for (auto &a : vet_int) {
		a = temp;
		temp++;
	}
	vector<int> vec_int1 = vet_int;
	return 0;
}
  • 练习3.33:如果scores在函数体外,编译器会将scores的数值都默认初始化为0,如果在函数体内,socres内的数值未定义,运行程序结果未知

3.5.3 指针和数组

  • 很多用到数组名的地方,编译器都会自动的将数组名替换成一个指向数组首元素的指针
	int ia[] = { 0, 1, 2 };
	cout << ia[0] << endl; // 0
	auto ia2(ia);
	*ia = 10;
	cout << ia[0] << endl; // 10
  • 当使用decltype关键字对数组进行数据类型推导时,数组名不会被替换成指向数组首元素的指针
	int ia[] = { 0, 1, 2 };
	decltype(ia) ia3 = { 1, 2, 3 }; // decltype返回的类型是由0,1,2构成的数组类型
  • 标准库函数begin、end
int ia[] = {0, 1, 2};
int *beg = begin(ia); //beg指针指向ia的首元素
int *last = end(ia); //last指针指向ia的尾元素的下一位置,尾后指针无法执行解引用和递增操作
  • 两个指针相减的结果是他们之间的距离,返返回的结果类型是名为ptrdiff_t的带符号类型数据
  • 对数组执行下标运算其实是对指向数组元素的指针进行下标运算
int ia[] = {1, 2, 3}

int i = ia[2]; // 对数组进行下标运算
int *p = ia;
i = *(p + 2); // 等价于int i = ia[2]

3.5.3练习

  • 练习3.34: 程序功能:让p1指针前进或后退p2到p1之间个元素,当p1为常量指针时程序非法
  • 练习3.35:
using namespace std;
#include<iostream>

int my_array[5] = {10, 20, 30, 40, 50};
int main()
{
	int *p = my_array;
	int* last = end(my_array);
	while (p != last)
	{
		*p = 0;
		p++;
	}
	for (auto temp : my_array)
	{
		cout << temp << endl;
	}
	system("pause");
	return 0;
}

  • 练习3.36 判断数组:
using namespace std;
#include<iostream>

int main()
{
	int my_array1[6] = { NULL, 20, 30, 40, 50 };
	int my_array2[6] = { NULL, 20, 30, 40, 50 };

	if (sizeof(my_array1) == sizeof(my_array2))
	{
		bool same_flag = true;
		int max_num = sizeof(my_array1) / sizeof(my_array1[0]);
		for (int i = 0; i < max_num; i++)
		{
			if (my_array1[i] != my_array2[i])
			{
				same_flag = false;
				break;
			}
		}
		if (same_flag == true)
		{
			cout << "相等" << endl;
		}
		else
		{
			cout << "不相等" << endl;
		}
	}
	else
	{
		cout << "不相等" << endl;
	}

	system("pause");
	return 0;
}

判断vector

using namespace std;
#include<iostream>
#include<vector>


int main()
{
	vector<int> my_vector1 = { 10, 20, 30, 40, 50 ,60 };
	vector<int> my_vector2 = { 10, 20, 30, 40, 50 };

	if (my_vector1.size() == my_vector2.size())
	{
		bool same_flag = true;
		for (int i = 0; i < my_vector1.size(); i++)
		{
			if (my_vector1[i] != my_vector2[i])
			{
				same_flag = false;
				break;
			}
		}
		if (same_flag == true)
		{
			cout << "相等" << endl;
		}
		else {
			cout << "不相等" << endl;
		}
	}
	else
	{
		cout << "不相等" << endl;
	}

	
	system("pause");
	return 0;
}

3.5.4 练习

  • 练习 3.37:将ca数组中的元素逐行打印
  • 练习 3.38:指针相减代表距离、指针加减数字代表前进后退
  • 练习 3.39:
using namespace std;
#include<iostream>
#include<string>


int main()
{
	string s1 = "12345";
	string s2 = "22345";
	if (s1 == s2)
	{
		cout << "相等" << endl;
	}

	char ca1[] = { 'c', '#', '1233', '1233', '\0' };
	char ca2[] = { 'c', '#', '1233', '1233', '\0' };
	int ret = strcmp(ca1, ca2);
	ret = 0;
	switch (ret)
	{
	case 0: {
		cout << "相等" << endl;
		break;
		}
	case 1: {
		cout << "大于" << endl;
		break;
		}
	case -1: {
		cout << "小于" << endl;
		break;
		}
	default:
		break;
	}
	
	system("pause");
	return 0;
}

  • 练习 3.40
using namespace std;
#include<iostream>


int main()
{
	const char ca1[] = "c++";
	const char ca2[] = "c#";
	char ca3[20];
	strcpy_s(ca3, ca1);
	strcat_s(ca3, " ");
	strcat_s(ca3, ca2);

	cout << ca3 << endl;

	system("pause");
	return 0;
}

3.5.5 节练习

  • 练习 3.41:
using namespace std;
#include<iostream>
#include<vector>


int main()
{
	int arr[] = { 1, 2, 3, 4 };
	vector<int> my_arr(begin(arr), end(arr));
	for (auto& temp : my_arr)
	{
		cout << temp << endl;
	}
	system("pause");
	return 0;
}
  • 练习 3.42:
using namespace std;
#include<iostream>
#include<vector>


int main()
{
	vector<int> my_arr = {1, 2, 3 ,4};
	int arr[4];
	for (int i = 0; i < my_arr.size(); i++)
	{
		arr[i] = my_arr[i];
	}

	for (auto temp : arr)
	{
		cout << temp << endl;
	}

	system("pause");
	return 0;
}

3.6节练习

  • 练习3.43:
using namespace std;
#include<iostream>
#include<vector>


int main()
{
	// 版本1范围for
	int ia[3][4] = {
		{1, 2, 3 ,4},
		{5, 6, 7, 8},
		{9, 10, 11, 12}
	};
	for (int(&p)[4] : ia)
	{
		for (int& q : p)
		{
			cout << q;
		}
		cout << endl;
	}
	// 版本2普通for下标
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			cout << ia[i][j];
		}
		cout << endl;
	}

	// 版本3普通for指针
	for (int (*p)[4] = ia; p < ia+3; p++)
	{
		for (int* q = *p; q < *p + 4; q++)
		{
			cout << *q;
		}
		cout << endl;

	}
	system("pause");
	return 0;
}
  • 练习3.44
using namespace std;
#include<iostream>
#include<vector>


int main()
{
	// 版本1范围for
	int ia[3][4] = {
		{1, 2, 3 ,4},
		{5, 6, 7, 8},
		{9, 10, 11, 12}
	};

	using int_array = int[4];

	for (int_array* i = ia; i < ia + 3; i++)
	{
		for (int* p = *i; p < *i + 4; p++)
		{
			cout << *p;
		}
		cout << endl;
	}
	system("pause");
	return 0;
}

  • 练习3.44
using namespace std;
#include<iostream>
#include<vector>


int main()
{
	// 版本1范围for
	int ia[3][4] = {
		{1, 2, 3 ,4},
		{5, 6, 7, 8},
		{9, 10, 11, 12}
	};
	for (auto i = ia; i < ia + 3; i++)
	{
		for (auto p = *i; p < *i + 4; p++)
		{
			cout << *p;
		}
		cout << endl;
	}
	system("pause");
	return 0;
}
C++Prime学习笔记 文章被收录于专栏

勇敢和愚蠢只有一剑之差

全部评论

相关推荐

11-14 16:13
已编辑
重庆科技大学 测试工程师
Amazarashi66:不进帖子我都知道🐮❤️网什么含金量
点赞 评论 收藏
分享
点赞 评论 收藏
分享
点赞 1 评论
分享
牛客网
牛客企业服务