【C++】《C++ Primer》第三章:字符串、向量和数组(知识点总结和习题答案)

目录

3.1 命名空间的using声明

头文件内不应有using声明

3.2 标准库类型string

cin和getline

string对象相加

range for处理每个字符

编程习惯!

3.3 标准库类型vector

初始化方式:()和{}

C++中vector添加元素和C语言的区别

缓冲区溢出 与 下标不合法

3.4 迭代器

迭代器的概念

迭代器的运算符

编程习惯!

迭代器的const、非const、cbegin()

迭代器失效

3.5 数组

初始化

遍历

指针和数组的隐式关系

指针也是迭代器

标准库函数begin和end

附:部分习题答案


3.1 命名空间的using声明

头文件内不应有using声明

3.2 标准库类型string

cingetline

void test()
{
    string s;
	while (cin >> s)
	{
		cout << s << endl;
	}
}

输入: 
abc de
输出: 
abc
de
void test()
{
    string s;
	while (getline(cin, s))
	{
		cout << s << endl;
	}
}

输入: 
abc de
输出: 
abc de

string对象相加

规则:必须保证=两边至少有一个是string

range for处理每个字符

void test()
{

	string s("abcd");
	for (auto c : s)
	{
		cout << c << " ";
	}
}
输出: a b c d
注,如果for (int c : s),那么输出 97 98 99 100,因为是这样的:
char c = 'a';
int temp = c;
cout << temp;

注:向vector添加元素,不能使用 range for!因为:

但是可以用range for来遍历!

编程习惯!

遍历vector的时候,依然必须要保证下标的合法的!!

3.3 标准库类型vector

初始化方式:(){}

一般来说,圆括号()表示"构造",花括号{}表示初始化值的列表

对于后者,也有例外:

注意,对于用 range for初始化的理解:

// 第一种情况
vector<int> v(10);
for (auto i : v)
{
    cout << i << " ";
    v[i] = 42;
}
for (auto num : v)
{
    cout << num << " ";
}
cout << endl;
最后输出:
0 0 0 0 0 0 0 0 0 0
42 0 0 0 0 0 0 0 0 0

// 另一种情况
vector<int> v2(10);
for (auto &i : v2)
{
    i = 42;
}
for (auto num : v2)
{
    cout << num << " ";
}
cout << endl;

最后输出:
42 42 42 42 42 42 42 42 42 42

range for的原理是,每次迭代i都会被初始化为v中下一个元素的值;

3-7行,因为v每个元素都是0,因此i每次都是0,因此v[i] = 42永远只有第0个元素被赋值为42,其余不变;

19-22行,因为i是个引用,遍历整个v2,因此每次i = 42都会把每个元素赋值为42;

C++中vector添加元素和C语言的区别

C在创建vector的时候,顺便指定其容量是最好的;

C++却相反,事先设定大小反而性能可能更差。

缓冲区溢出 与 下标不合法

void test()
{
	vector<int >v;
	v[10] = 10; // 直接崩溃!因为v是空的,无法用下标访问

    vector<int >v1(11, 0); // 初始化v1为11个0
	v[10] = 10; // 正确, 因为现在v1有11个元素,因此可以访问

}

3.4 迭代器

迭代器的概念

技巧:平时其实无须注意迭代器的类型,用auto即可,因此:

vector<int>::iterator iter = v1.begin(); // 完全不用写前面的那一长串!
直接用:
auto iter = v1.begin(); 

迭代器的运算符

  • *iter 解引用,获得迭代器所指元素的引用
  • (*iter).age 解引用,获得迭代器所指对象的age成员
  • iter->age 和上面的等价
  • ++/-- iter 移动迭代器

因此,->会方便点,就不需要每次都加*了(->把解引用和成员访问两个操作结合在一起)

注1:C++迭代器可以往回退,但Python里的迭代器是不行的,例如:

void test()
{
	vector<int> v1;
	for (int i = 0; i < 10; ++i)
	{
		v1.push_back(i);
	}

	vector<int>::iterator iter = v1.begin() + 3;
	cout << *iter << endl;  // 输出3

	--iter; // 回退
	cout << *iter;  // 输出2
}

注2:C++11没有定义迭代器的加法,因为是没有意义的。而可以用两个迭代器相减,得到迭代器之间的距离。

void test()
{
	vector<int>v;
	for (int i = 0; i < 10; ++i)
	{
		v.push_back(i);
	}
	
	auto begin = v.begin();
	auto end = v.end();
	cout << *(begin + end); // 错误
	cout << end - begin; // 输出10, 指的是end到begin之间的距离(元素个数)
}

注3:不能对end进行增减或解引用,因为end返回的迭代器不实际指示某个元素。

编程习惯!

对于C++来说,推荐使用迭代器去遍历容器!

迭代器的const、非const、cbegin()

void test()
{
	vector<int> v1;
	for (int i = 0; i < 10; ++i)
	{
		v1.push_back(i);
	}

	vector<int>::const_iterator citer = v1.begin() + 4;
	*citer = 2; // 错误,因为是const,不可以修改
	cout << *citer;

    // 或者用C++11的新函数 cbegin cend
    for (auto citer = v1.cbegin(); citer != v1.cend(); ++citer)
    {
        ...
    }
}

迭代器失效

任何一种可能改变vector容量的操作,例如push_back,都会使vector对象的迭代器失效!

3.5 数组

初始化

关于int等基本数据类型和string型的初始化区别

void test()
{
	int a[10];
	int b[10] = {};
    cout << a[2]; // 输出错乱!因为函数内不会默认初始化int型数组
	cout << b[2]; // 输出0, 因为上面{}表面已经初始化为全0了

    string s[10];
    cout << s[2]; // 输出空串, 因为string特性, 不论函数内还是外, 都会默认初始化为空串!
}

int c[10]; // 函数外定义, 那么默认初始化全0

int main()
{
	test();
	cout << c[3]; // 输出0
	return 0;
}

遍历

推荐使用range for这个遍历方法!

指针和数组的隐式关系

对于auto

对于decltype:该是什么就是什么,不会发生隐式转换

指针也是迭代器

void test()
{
	int a[10] = {};
	for (int i = 0; i < 10; ++i)
	{
		a[i] = i;
	}
	int* begin = a; // 指针也是迭代器
	int* end = &a[10]; // 尾后指针

	for (; begin != end; ++begin) // 迭代
	{
		cout << *begin << " ";
	}
}

注意,第9行,a[10]的索引只到9,但作为尾后指针,可以取到最后一个元素的下一个元素,因此索引是10;这个不存在的元素唯一的作用就是提供地址用于初始化end

但是!这样很容易出错,因为C++11引入了标准库函数begin()end()

标准库函数beginend

注:上面不能用beginend来作为变量名称,不然会报错:

int *begin = begin(ia); int *end= end(ia); --> 错误

 

附:部分习题答案

练习3-2 

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

void test()
{
	// 一次读入一行
	string s;
	//while (getline(cin, s))
	//{
	//	cout << s;
	//}

	// 一次读入一个词
	string s1;
	while (cin >> s1)
	{
		cout << s1;
	}

}


int main()
{
	test();
	return 0;
}

练习3-4

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

void test()
{
	cout << "比大小:" << endl;
	string s1, s2;
	cin >> s1 >> s2;
	if (s1 == s2)
	{
		cout << s1;
	}
	else
	{
		string s3 = (s1 > s2) ? s1 : s2;
		cout << s3 << endl;
	}

	cout << "是否等长:" << endl;
	cin >> s1 >> s2;
	if (s1.size() == s2.size())
	{
		cout << s1;
	}
	else
	{
		string s4 = (s1.size() > s2.size()) ? s1 : s2;
		cout << s4 << endl;
	}


}


int main()
{
	test();
	return 0;
}

练习3-5

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

void test()
{
	string s1, s2;
	while (cin >> s1)
	{
		if (s1 == "EOF")
		{
			break;
		}
		s2 += s1;
		
	}
	cout << s2 << endl;

}


int main()
{
	test();
	return 0;
}

练习3-6

 

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

void test()
{
	string s;
	getline(cin, s); // 注,空格也是字符,也会被X替代
	for (auto &ch : s)
	{
		ch = 'X';
	}
	cout << s;

}


int main()
{
	test();
	return 0;
}

练习3-7

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

void test()
{
	string s;
	getline(cin, s); // 注,空格也是字符,也会被X替代
	for (char& ch : s)
	{
		ch = 'X';
	}
	cout << s;

}


int main()
{
	test();
	return 0;
}

练习3-8

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

void test()
{
	string s;
	getline(cin, s);

	decltype(s.size()) index = 0;
	while (true)
	{
		if (index == s.size())
		{
			break;
		}
		char& r = s[index];
		r = 'X';

		++index;
	}

	cout << s;

}

void test1()
{
	string s;
	getline(cin, s);

	for (decltype(s.size()) index = 0; index != s.size(); ++index)
	{
		char& r = s[index];  
		r = 'X';
	}

	cout << s;

}

/// 上面的写复杂了,忘记了还可以下标访问

void test2()
{
	string s;
	getline(cin, s);
	for (decltype(s.size()) index = 0; index != s.size(); ++index)
	{
		s[index] = 'X';
	}

	cout << s;
}


int main()
{
	test2();
	return 0;
}

练习3-10

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

void test()
{
	string s1, s2;
	getline(cin, s1);

	for (auto c : s1)
	{
		if (ispunct(c))
		{
			continue;
		}
		s2 += c;
	}

	cout << s2;

}


int main()
{
	test();
	return 0;
}

练习3-14

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

void test()
{
	vector<int> v;

	int num = 0;
	while (cin >> num)
	{
		v.push_back(num);
	}
	
	//for (vector<int>::iterator begin = v.begin(); begin != v.end(); ++begin)
	//{
	//	cout << *begin << " ";
	//}
	for (auto num : v)
	{
		cout << num << " ";
	}

}


int main()
{
	test();
	return 0;
}

练习3-15

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

void test()
{
	vector<string> v;
	string s;
	while (cin >> s)
	{
		if (s == "EOF")
		{
			break;
		}
		v.push_back(s);
	}

	for (auto c : v)
	{
		cout << c << " ";
	}

}


int main()
{
	test();
	return 0;
}

练习3-17 

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

void test()
{
	vector<string> v;
	string s1, s2;
	while (cin >> s1)
	{
		if (s1 == "EOF")
		{
			break;
		}

		for (auto& c : s1)
		{
			c = toupper(c);
		}

		v.push_back(s1);
	}

	
	for (auto str : v)
	{
		cout << str << endl;
	}


}


int main()
{
	test();
	return 0;
}

练习3-19

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

void test()
{
	// 方法一
	vector<int> v(10, 42);
	for (auto i : v)
	{
		cout << i << " ";
	}
	cout << endl;

	// 方法二
	vector<int> v1;
	for (int i = 0; i < 10; ++i)
	{
		v1.push_back(42);
	}

	for (auto i : v)
	{
		cout << i << " ";
	}
	cout << endl;

	// 方法三 --> 我没想到
	vector<int> v2(10);
	for (auto &i : v2)
	{
		i = 42;
	}

	cout << endl;
	for (auto i : v2)
	{
		cout << i << " ";
	}
	cout << endl;

}


int main()
{
	test();
	return 0;
}

练习3-23

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

void test()
{
	vector<int>v;
	for (int i = 0; i < 10; ++i)
	{
		v.push_back(i);
	}

	for (auto begin = v.begin(); begin != v.end(); ++begin)
	{
		*begin *= 2;
	}

	for (auto begin = v.begin(); begin != v.end(); ++begin)
	{
		cout << *begin << " ";
	}
}


int main()
{
	test();
	return 0;
}

练习3-24

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

void test()
{
	vector<int>v;
	for (int i = 0; i < 10; ++i)
	{
		v.push_back(i);
	}

	for (auto begin = v.begin(); begin != v.end(); ++begin)
	{
		cout << *begin << " ";
	}

	cout << endl;

	// 相邻两数之和
	for (auto begin = v.begin(); begin != v.end()-1; ++begin)
	{
		cout << *begin+*(begin+1) << " ";
	}

	cout << endl;

	// 首位元素之和
	//int tag = 1;
	//for (auto begin = v.begin(); begin != v.end(); ++begin)
	//{
	//	if (tag == v.size() / 2)
	//	{
	//		break;
	//	}
	//	cout << *(begin) + *(v.size()-tag-1)

	//}

}


int main()
{
	test();
	return 0;
}

练习3-25

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

void test()
{
	vector<int> v(4);
	int score;
	auto begin = v.begin();
	while (cin >> score)
	{
		if (score <= 30)
		{
			++* (begin + score / 10);
		}
	}

	for (auto begin = v.begin(); begin != v.end(); ++begin)
	{
		cout << *begin << " ";
	}


}

int main()
{
	test();
	return 0;
}

练习3-31

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

void test()
{
	int a[10] = {};
	int tag = 0;

	for (auto& i : a)
	{
		i = tag;
		++tag;
	}

	for (auto& i : a)
	{
		cout << i << " ";
	}
}


int main()
{
	test();
	return 0;
}

练习3-32

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

void test()
{
	int a[10] = {};
	int tag = 0;

	// 拷贝给另一个数组
	for (auto& i : a)
	{
		i = tag;
		++tag;
	}

	int b[10] = {};
	tag = 0;
	for (auto i : a)
	{
		b[tag] = i;
		++tag;
	}

	// 用vector重新实现
	vector<int>v;
	for (auto& i : a)
	{
		v.push_back(i);
	}

	// 打印输出
	for (auto& i : v)
	{
		cout << i << " ";
	}
}


int main()
{
	test();
	return 0;
}

练习3-36

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

void test()
{
	// 比较数组元素是否相等
	int a[] = { 1,2,3,4,5,6 };
	int b[] = { 1,2,3,4,5,6 };

	int numA = 0;
	int numB = 0;
	for (auto i : a)
	{
		++numA;
	}
	for (auto i : b)
	{
		++numB;
	}

	if (numA != numB)
	{
		cout << "不相等";
	}
	else
	{
		for (int i = 0; i < numA; ++i)
		{
			if (a[i] != b[i])
			{
				cout << "不相等";
			}
		}
		cout << "相等";
	}

}


int main()
{
	test();
	return 0;
}

练习3-39 

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

void test()
{
	string s1("wind1");
	string s2("wind1");

	if (s1.size() != s2.size())
	{
		cout << "不相等";
	}
	else
	{
		int tag = 0;
		for (int i = 0; i < s1.size(); ++i)
		{
			if (s1[i] != s2[i])
			{
				cout << "不相等";
				tag = 0;
				break;
			}
			tag = 1;
			
		}
		if (tag)
		{
			cout << "相等";
		}
		
		
	}

	cout << endl;

	// 方法二
	if (s1 == s2)
	{
		cout << "相等";
	}
	else
	{
		cout << "不相等";
	}
}


int main()
{
	test();
	return 0;
}

练习3-40和3-41

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

void test()
{
	// 整形数组初始化vector对象
	const int size = 10;
	int a[size] = { 1,2,3,4 };
	vector<int>v(begin(a), end(a));

	for (auto i : v)
	{
		cout << i << endl;
	}
	cout << endl;

	// vector对象拷贝给整型数组
	int b[size];
	auto it = cbegin(a);
	for (auto& val : b)
	{
		val = *it;
		++it;
	}

	for (auto i : b)
	{
		cout << i << endl;
	}

}



int main()
{
	test();

	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值