第三章:字符串、向量和数组
之前介绍的都是C++的内置类型,由C++语言直接定义,直接实现到计算机硬件中。而标准库还定义了一些具有更高级性质的类型,本章介绍两种最重要的,即string和vector。
一.命名空间的using声明
使用using声明的格式为:using namespace::name;即使用某个命名空间中的某个名字。
一般来说头文件不应包含using声明。
二.标准库类型string
使用string必须包含string头文件。
如果使用等号初始化一个变量,则为拷贝初始化,即把等号右侧的初始值拷贝到左侧的对象,不使用等号为直接初始化。
string的操作中is>>s是把is中的字符赋给s,以空格作为分隔。
在执行读取操作时,string对象会自动忽略开头的空白并从第一个真正的字符读起,直到遇到下一处空白为止。
对于is>>s遇到空白即结束,我们可以用getline函数来代替,其参数为一个输入流和一个string对象,输入流遇到换行符停止,并将不包含换行符的字符串赋给string对象。注意,getline返回的是一个输入流对象,因此也可用于在while中判断输入是否结束以及是否输入非法字符。
string的size函数返回的是一个string::size_type类型的值,并不是int或者unsigned,这个类型与机器无关。事实上,大多数标准库类型都定义了这种以机器无关的配套类型。例如在我的编译器中大多数标准库类型的size返回的都是size_t类型。
注意,size返回的一般是无符号类型,所以如果与有符号数混用会产生意想不到的后果,例如int n; s.size() < n;如果n为负数,则判断的结果很可能相反。所以如果一条表达式中已经有了size函数就不要使用int了。
标准库允许把字符字面值和字符串字面值转换成string对象,所以这两者可以和string对象相加。(切记,字符串字面值和string是不同的类型)
string对象的相加必须保证加好两边至少有一个string对象。
在cctype(或者说ctype.h)中定义了一些函数能对某个字符进行判断处理。
C++中兼容了C语言的标准库,所以一些C语言的头文件为xxx.h,而在C++中也实现了这些文件,不过命名为cxxx,最好使用后面这种头文件,因为在名为cname的头文件中定义的名字从属于命名空间std,而定义在.h中的文件则不然。
不管什么时候对string对象(以及其他序列)使用了下标,都要确认在那个位置上确实有值。
三.标准库类型vector
vector是模板而非类型,由vector生成的类型必须包含vector中元素的类型,编译器根据模板创造类或函数的过程称为实例化。
在早期版本的C++中,如果vector的元素还是vector,那么在右边留一个空格,如vector<vector<int> >,但是现在一般不用了。
列表初始化只能使用花括号不能使用圆括号。
如果只对vector进行数量的初始化,vector会对里面的元素进行默认初始化。
列表初始化时,如果里面的值不能用作vector的元素值,则vector会考虑用另外的角度看待列表的值。
如果循环体内部包含有向vector对象添加元素的语句,则不能使用范围for循环,因为范围for语句体内不应改变所遍历序列的大小。
注意,vector是有比较运算符的,即>、<等,是以字典顺序进行比较(当然内部的元素要支持比较操作)。
要使用size_type(以及其他模板类的元素),需首先指定它是由哪种类型定义的,如vector<int>::size_type。
四.迭代器介绍
一般来说,我们不清楚或者不在意迭代器准确的类型是什么,所以直接可以用auto声明变量。
迭代器之间可以进行== 和 !=,如果两个迭代器指向的是同一个元素或者是同一个容器的尾后迭代器则相等,否则不相等。
使用迭代器也要注意空与非空的问题。
迭代器的循环通常用!=来判断结束,因为所有迭代器都定义了== 和!=,而大多数迭代器都没有定义<。
迭代器都有递增的操作,end返回的迭代器不指向任何元素不能递增和解引用。
一般使用iterator和const_iterator来表示迭代器类型。
如果vector本身是个常量(即const加在外面的),那么begin返回的是const_iterator,否则返回的是iterator。
C++11提供了cbegin和cend,这两个无论怎样返回的都是const_iterator。
通过解引用可以访问原来元素的成员,例如(*it).empty(),注意,第一个括号不能少。
箭头运算符->把解引用和成员访问两个操作结合在一起。
前面说过在范围for循环中不要改变序列的大小,其实在任何使用了迭代器的循环体中都不要去改变容器的大小,因为这可能造成迭代器失效,尤其是push_back。
vector和string的迭代器除了递增还有加减以及比较大小等操作。
迭代器相减得到的是difference_type的带符号整数。
五.数组
数组初始化表示维度的应该是一个常量表达式,当然大多数编译器不是常量表达式也能运行,例如g++,但是我们要知道这只是编译器的拓展,不是标准的C++。
使用列表初始化可以不提供维度,如果列表中的元素不够维度,剩下的元素默认初始化。
字符数组可以使用字符串字面值来初始化,例如
char a1[] = "C++";
const char a2[] = "C++";
但是要注意字符串字面值最后还有一个未显示的/0,所以a1,a2长度都是4。(如果你用strlen统计长度的话还是3,因为strlen不计算/0的长度)
不能将数组的内容拷贝给其他数组作为初始值,也不能用数据为其他数组赋值。(可以的话那也只是编译器拓展)
复杂的数组定义:数组的定义可以很多重,导致比较复杂,前面说过读变量的定义可以从右往左读,而读数组的定义从数组的名字开始从内往外读会好一些。
在使用数组下标时,通常将其定义为size_t类型,size_t是一种机器相关类型,它被设计的足够大以便能够表示内存中任意对象的大小。
使用数组的时候也要确保下标在合理范围内。
在很多用到数组名字的地方,编译器都会自动将其替换为一个指向数组首元素的指针。即在大多数表达式中,数组名都代表数组首元素的指针。使用数组作为auto变量的初始值,auto会推出指针类型。但是在decltype中数组还是数组。
数组的指针也能像迭代器一样使用,可以利用数组的长度来获取尾后指针。
虽然可以通过长度来获得尾后指针,但是终究不方便,C++11引入两个函数begin和end来获取数组的头指针和尾后指针,不过不是作为成员,而是单独的函数,例如begin(a),这两个函数在头文件iterator中。
两个指针相减的结果是名为ptrdiff_t的类型,其为与机器相关的有符号类型。
标准库类型也能执行下标运算,但是它们的下标必须都是无符号类型,而内置类型的下标运算是有符号的,即可以为负数。
所谓C风格字符串不是一种类,而是指存放在字符数组中的并以空字符结束的字符串。C中有一些函数可以处理这种字符串,例如strlen,strcmp,strcat,strcpy,但是传入这些函数的字符串参数必须以空字符结尾。
对大多数应用来说,使用标准库string要比使用C风格字符串更安全,更高效。
为了与之前的旧代码衔接,C++标准库做了如下安排
- 允许使用以空字符结束的字符数组初始化或赋值string对象。
- string中的加法对象允许使用空字符结束的字符数组作为其中一个运算对象。
string提供了一个c_str函数来返回一个C风格的字符串,但是我们不能保证c_str返回的数组一直有效,如果后续操作改变了string对象,数组可能失效,所以如果要一直保持效用,就复制一个数组。例如
string str = "hello, world!";
const char *ch = str.c_str();
str[0] = 'A';
cout << ch << endl; // 会输出Aello, world!
可以使用数组初始化vector,提供地址的范围即可。
现代C++程序应尽可能使用vector和迭代器以及string。
六.多维数组
其实严格来说C++语言中并没有多维数组,我们说的多维数组只是数组的元素又是数组而已,可以由内往外读获取多维数组的定义。
多维数组的下标引用中若下标个数比维度少,则代表的是数组而不是具体的元素。
要使用范围for语句处理多维数组,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型。否则编译器可能自动将数组转为指针类型导致后面的循环不合法。
多维数组的名字可以代表一个指向数组的指针,所以要用指向数组的指针来得到它,例如int (*P)[4] = a;也可以此时*p代表第一个数组的首元素地址。也可以使用auto来得到类型。
可以使用类型别名(typedef 和 using)来处理多维数组,即把后面的数组重新定义为一种类型。
练习
3.1 没啥好说的,在原来的练习加上using声明,在具体代码中去掉std::即可。
3.2
一次读入一整行:
#include <iostream>
#include <string>
using std::cin; using std::cout; using std::endl;
using std::string;
int main() {
string test;
getline(cin, test);
cout << test << endl;
}
一次读入一个词:
#include <iostream>
#include <string>
using std::cin; using std::cout; using std::endl;
using std::string;
int main() {
string test;
cin >> test;
cout << test << endl;
}
3.3
标准库 string 的输入运算符自动忽略字符串开头的空白(包括空格符、换行符、制表符等),从第一个真正的字符开始读起,直到遇见下一处空白为止。
如果希望在最终的字符串中保留输入时的空白符,应该使用 getline 函数代替原来的 >> 运算符,getline 从给定的输入流中读取数据,直到遇到换行符为止,此时换行符也被读取进来,但是并不存储在最后的字符串中。
3.4
输出较大:
#include <iostream>
#include <string>
using std::cin; using std::cout; using std::endl;
using std::string;
int main() {
string s1, s2;
cin >> s1 >> s2;
if (s1 == s2)
cout << "两个字符串相等" << endl;
else if (s1 > s2)
cout << s1 << endl;
else
cout << s2 << endl;
return 0;
}
输出长度较大:
#include <iostream>
#include <string>
using std::cin; using std::cout; using std::endl;
using std::string;
int main() {
string s1, s2;
cin >> s1 >> s2;
if (s1.size() == s2.size())
cout << "两个字符串长度相等" << endl;
else if (s1.size() > s2.size())
cout << s1 << endl;
else
cout << s2 << endl;
return 0;
}
3.5
#include <iostream>
#include <string>
using std::cin; using std::cout; using std::endl;
using std::string;
int main() {
string s, result;
while (getline(cin, s)) {
result += s;
}
cout << result << endl;
return 0;
}
#include <iostream>
#include <string>
using std::cin; using std::cout; using std::endl;
using std::string;
int main() {
string s, result;
while (getline(cin, s)) {
if (result.empty())
result += s;
else
result = result + ' ' + s;
}
cout << result << endl;
return 0;
}
3.6
#include <iostream>
#include <string>
using std::cin; using std::cout; using std::endl;
using std::string;
int main() {
string test;
getline(cin, test);
cout << test << endl;
for (auto &ch : test) {
ch = 'X';
}
cout << test << endl;
}
3.7
并不会造成不同的影响(当然如果题目意思是去掉引用的话那肯定更改不了了)。
#include <iostream>
#include <string>
using std::cin; using std::cout; using std::endl;
using std::string;
int main() {
string test;
getline(cin, test);
cout << test << endl;
for (char &ch : test) {
ch = 'X';
}
cout << test << endl;
}
3.8
#include <iostream>
#include <string>
using std::cin; using std::cout; using std::endl;
using std::string;
int main() {
string test;
getline(cin, test);
cout << test << endl;
int i = 0;
while (i < test.size()) {
test[i] = 'X';
++i;
}
cout << test << endl;
}
#include <iostream>
#include <string>
using std::cin; using std::cout; using std::endl;
using std::string;
int main() {
string test;
getline(cin, test);
cout << test << endl;
for (unsigned int i = 0; i < test.size(); ++i) {
test[i] = 'X';
}
cout << test << endl;
}
感觉for循环会更简洁易读一点。
3.9
不合法,s没有初始值,下标访问前要确保对应下标有值。这种错误某些编译器在编译的时候不会报错(例如我的g++)。
3.10
#include <iostream>
#include <string>
using std::cin; using std::cout; using std::endl;
using std::string;
int main() {
string test;
getline(cin, test);
cout << test << endl;
string result;
for (auto ch : test) {
if (!ispunct(ch)) {
result += ch;
}
}
cout << result << endl;
}
3.11
auto一般会忽略顶层const,保留底层const,不过设置引用的时候会保留顶层const。所以c的类型为const char&,语句是合法的。
3.12
(a) 正确
(b) 错误,类型不匹配
(c) 正确,初始化10个值为"null"的string
3.13
(a) 0 (b) 10 {0} (c) 10 {42...} (d) 1 {10}
(e) 2 {10 42} (f) 10 {""...} (g) 10 {"hi"...}
3.14
#include <iostream>
#include <string>
#include <vector>
using std::cin; using std::cout; using std::endl;
using std::string;
using std::vector;
int main() {
vector<int> nums;
int temp;
while (cin >> temp) {
nums.push_back(temp);
}
for (auto i : nums) {
cout << i << ' ';
}
cout << endl;
return 0;
}
3.15
#include <iostream>
#include <string>
#include <vector>
using std::cin; using std::cout; using std::endl;
using std::string;
using std::vector;
int main() {
vector<string> nums;
string temp;
while (getline(cin, temp)) {
nums.push_back(temp);
}
for (auto i : nums) {
cout << i << endl;
}
return 0;
}
3.16
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
vector<int> v1;
vector<int> v2(10);
vector<int> v3(10, 42);
vector<int> v4{10};
vector<int> v5{10, 42};
vector<string> v6{10};
vector<string> v7{10, "hi"};
cout << "v1 的元素个数是:" << v1.size() << endl;
if (v1.size() > 0) { // 当 vector 含有元素时逐个输出
cout << "v1 的元素分别是:" << endl;
for (auto e : v1) // 使用范围 for 语句遍历每一个元素
cout << e << " ";
cout << endl;
}
cout << "v2 的元素个数是:" << v2.size() << endl;
if (v2.size() > 0) {
cout << "v2 的元素分别是:" << endl;
for (auto e : v2)
cout << e << " ";
cout << endl;
}
cout << "v3 的元素个数是:" << v3.size() << endl;
if (v3.size() > 0) {
cout << "v3 的元素分别是:" << endl;
for (auto e : v3)
cout << e << " ";
cout << endl;
}
cout << "v4 的元素个数是:" << v4.size() << endl;
if (v4.size() > 0) {
cout << "v4 的元素分别是:" << endl;
for (auto e : v4)
cout << e << " ";
cout << endl;
}
cout << "v5 的元素个数是:" << v5.size() << endl;
if (v5.size() > 0) {
cout << "v5 的元素分别是:" << endl;
for (auto e : v5)
cout << e << " ";
cout << endl;
}
cout << "v6 的元素个数是:" << v6.size() << endl;
if (v6.size() > 0) {
cout << "v6 的元素分别是:" << endl;
for (auto e : v6)
cout << e << " ";
cout << endl;
}
cout << "v7 的元素个数是:" << v7.size() << endl;
if (v7.size() > 0) {
cout << "v7 的元素分别是:" << endl;
for (auto e : v7)
cout << e << " ";
cout << endl;
}
return 0;
}
3.17
#include <iostream>
#include <string>
#include <vector>
using std::cin; using std::cout; using std::endl;
using std::string;
using std::vector;
int main() {
vector<string> vs;
string temp;
while (cin >> temp) {
if (!temp.empty())
vs.push_back(temp);
}
for (auto &str : vs) {
for (auto &ch : str) {
ch = toupper(ch);
}
}
for (auto str : vs) {
cout << str << endl;
}
return 0;
}
3.18
不合法,ivec.push_back(42);
3.19
vector<int> ivec(10, 42);
vector<int> ivec = {42...};
vector<int> ivec{42...};
vector<int> ivec;
for (int i = 0; i < 10; ++i)
ivec.push_back(42);
3.20
#include <iostream>
#include <string>
#include <vector>
using std::cin; using std::cout; using std::endl;
using std::string;
using std::vector;
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] << ' ';
}
cout << endl;
int n = ivec.size();
for (int i = 0; i < n / 2; ++i) {
cout << ivec[i] + ivec[n - i - 1] << ' ';
}
cout <<endl;
return 0;
}
3.21
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main() {
vector<int> v1;
vector<int> v2(10);
vector<int> v3(10, 42);
vector<int> v4{10};
vector<int> v5{10, 42};
vector<string> v6{10};
vector<string> v7{10, "hi"};
cout << "v1 的元素个数是:" << v1.size() << endl;
if (v1.cbegin() != v1.cend()) { // 当 vector 含有元素时逐个输出
cout << "v1 的元素分别是:" << endl;
for (auto it = v1.cbegin(); it != v1.cend(); it++)
cout << *it << " ";
cout << endl;
}
cout << "v2 的元素个数是:" << v2.size() << endl;
if (v2.cbegin() != v2.cend()) {
cout << "v2 的元素分别是:" << endl;
for (auto it = v2.cbegin(); it != v2.cend(); it++)
cout << *it << " ";
cout << endl;
}
cout << "v3 的元素个数是:" << v3.size() << endl;
if (v3.cbegin() != v3.cend()) {
cout << "v3 的元素分别是:" << endl;
for (auto it = v3.cbegin(); it != v3.cend(); it++)
cout << *it << " ";
cout << endl;
}
cout << "v4 的元素个数是:" << v4.size() << endl;
if (v4.cbegin() != v4.cend()) {
cout << "v4 的元素分别是:" << endl;
for (auto it = v4.cbegin(); it != v4.cend(); it++)
cout << *it << " ";
cout << endl;
}
cout << "v5 的元素个数是:" << v5.size() << endl;
if (v5.cbegin() != v5.cend()) {
cout << "v5 的元素分别是:" << endl;
for (auto it = v5.cbegin(); it != v5.cend(); it++)
cout << *it << " ";
cout << endl;
}
cout << "v6 的元素个数是:" << v6.size() << endl;
if (v6.cbegin() != v6.cend()) {
cout << "v6 的元素分别是:" << endl;
for (auto it = v6.cbegin(); it != v6.cend(); it++)
cout << *it << " ";
cout << endl;
}
cout << "v7 的元素个数是:" << v7.size() << endl;
if (v7.cbegin() != v7.cend()) {
cout << "v7 的元素分别是:" << endl;
for (auto it = v7.cbegin(); it != v7.cend(); it++)
cout << *it << " ";
cout << endl;
}
return 0;
}
3.22
#include <iostream>
#include <string>
#include <vector>
using std::cin; using std::cout; using std::endl;
using std::string;
using std::vector;
int main() {
vector<string> text;
string temp;
while (getline(cin, temp))
text.push_back(temp);
for (auto it = text.begin(); it != text.end() && !it->empty(); ++it) {
for (auto ch = it->begin(); ch != it->end(); ++ch)
if (isalpha(*ch))
*ch = toupper(*ch);
}
for (auto it = text.cbegin(); it != text.end(); ++it)
cout << *it << endl;
return 0;
}
3.23
#include <iostream>
#include <string>
#include <vector>
using std::cin; using std::cout; using std::endl;
using std::string;
using std::vector;
int main() {
vector<int> ivec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto it = ivec.begin(); it != ivec.end(); ++it) {
*it *= 2;
}
for (auto it = ivec.cbegin(); it != ivec.cend(); ++it) {
cout << *it << ' ';
}
cout << endl;
return 0;
}
3.24
#include <iostream>
#include <string>
#include <vector>
using std::cin; using std::cout; using std::endl;
using std::string;
using std::vector;
int main() {
vector<int> ivec;
int temp;
while (cin >> temp)
ivec.push_back(temp);
for (auto it = ivec.cbegin(); it != (ivec.cend() - 1); ++it) {
cout << *it + *(it + 1) << ' ';
}
cout << endl;
for (auto it1 = ivec.cbegin(), it2 = ivec.cend() - 1; it1 < it2; ++it1, --it2) {
cout << *it1 + *it2 << ' ';
}
cout << endl;
return 0;
}
3.25
#include <iostream>
#include <string>
#include <vector>
using std::cin; using std::cout; using std::endl;
using std::string;
using std::vector;
int main() {
vector<unsigned> scores(11, 0);
unsigned grades;
while (cin >> grades) {
if (grades <= 100) {
++*(scores.begin() + grades / 10); // 注意这里++不能写在后面,优先级++会高一些
}
}
for (auto it = scores.cbegin(); it != scores.cend(); ++it)
cout << *it << ' ';
cout << endl;
return 0;
}
3.26
因为C++没有定义迭代器的加法。
3.27
(a) 非法,数组的维度要是常量表达式
(b) 合法
(c) 非法,数组的维度要是常量表达式,函数的返回值要是constexpr(const都不行)
(d) 非法,字符串字面值末尾还有一个/0,维度不够
3.28
sa:""
ia:0
sa2:"" // string是一种类,使用类的默认初始化
ia2:不确定
3.29
数组与 vector 的相似之处是都能存放类型相同的对象,且这些对象本身没有名字,需要通过其所在位置访问。
数组与 vector 的最大不同是,数组的大小固定不变,不能随意向数组中增加额外的元素,虽然在某些情境下运行时性能较好,但是与 vector 相比损失了灵活性。
具体来说,数组的维度在定义时已经确定,如果我们想更改数组的长度,只能创建一个更大的新数组,然后把原数组的所有元素复制到新数组中去。数组也无法像 vector 那样使用 size 函数直接获取数组的维度。如果是字符数组,可以调用 strlen 函数得到字符串的长度;如果是其他数组,只能使用 sizeof(array) / sizeof(array[0]) 的方式计算数组的维度。
3.30
for循环中应该是ix < array_size。
3.31
#include <iostream>
#include <string>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
int main() {
int a[10];
for (size_t i = 0; i < 10; ++i) {
a[i] = i;
}
return 0;
}
3.32
#include <iostream>
#include <string>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
int main() {
const int sz = 10;
int a[sz];
for (size_t i = 0; i < sz; ++i) {
a[i] = i;
}
int b[sz];
for (size_t i = 0; i < sz; ++i) {
b[i] = a[i];
}
return 0;
}
#include <iostream>
#include <string>
#include <vector>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main() {
vector<int> a(10);
for (int i = 0; i < 10; ++i)
a[i] = i;
vector<int> b = a;
}
3.33
如果不初始化 scores,则该数组会含有未定义的数值,这是因为 scores 是定义在函数内部的整型数组,不会执行默认初始化。
3.34
使p1指向p2指向的元素,其实按照题目条件应该不会非法,但是既然问了,那么p1p2类型不同的时候非法。
3.35
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main() {
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int *pbeg = std::begin(a); pbeg != std::end(a); pbeg++) {
*pbeg = 0;
}
for (auto i : a)
cout << i << ' ';
cout <<endl;
return 0;
}
3.36
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main() {
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int b[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *abeg = std::begin(a);
int *aend = std::end(a);
int *bbeg = std::begin(b);
int *bend = std::end(b);
if ((aend - abeg) != (bend - bbeg)) {
cout << "数组不等" << endl;
return 0;
}
for (int i = 0; i < (aend - abeg); ++i) {
if (a[i] != b[i]) {
cout << "数组不等" << endl;
return 0;
}
}
cout << "数组相等" << endl;
return 0;
}
vector直接比较就行。
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main() {
vector<int> a = {1, 2, 3};
vector<int> b = {2, 3, 4};
if (a == b)
cout << "vector相等" << endl;
else
cout << "vector不等" << endl;
return 0;
}
3.37
该程序的原意是输出 ca 中存储的 5 个字符,每个字符占一行,但实际的执行效果无法符合预期。因为以列表初始化方式赋值的 C 风格字符串与以字符串字面值赋值的有所区别,后者会在字符串最后额外增加一个空字符以示字符串的结束,而前者不会这样做。
因此在该程序中,ca 的 5 个字符全都输出后,并没有遇到预期的空字符,也就是说,while 循环的条件仍将满足,无法跳出。程序继续在内存中 ca 的存储位置之后挨个寻找空字符,直到找到为止。在这个过程中,额外经历的内容也将被输出出来,从而产生错误。
(虽然在我的编译器上能够正常输出,但是这是编译器拓展)
3.38
指针的值是它所指对象的内存地址,如果我们把两个指针加在一起,就是试图把内存中两个对象的存储地址加在一起,这显然是没有任何意义的。
3.39
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main() {
string str1 = "hello";
string str2 = "hello, world";
cout << (str1 < str2) << endl;
const char* ch1 = "hello";
const char* ch2 = "hello, world";
cout << (strcmp(ch1, ch2) < 0) << endl;
return 0;
}
3.40
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main() {
char ch1[] = "hello, ";
char ch2[] = "world!";
char ch3[20];
strcpy(ch3, ch1);
strcat(ch3, ch2);
cout << ch3 << endl;
return 0;
}
3.41
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main() {
int a[10] = {1, 2, 3, 4};
vector<int> ivec(a + 1, a + 4);
for (auto i : ivec)
cout << i << ' ';
cout <<endl;
return 0;
}
3.42
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main() {
vector<int> ivec = {1, 2, 3, 4};
int a[4];
int *beg = std::begin(a);
for (auto i = ivec.cbegin(); i != ivec.cend(); ++i) {
*beg = *i;
beg++;
}
for (auto i : a)
cout << i << ' ';
cout << endl;
return 0;
}
3.43
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main() {
int a[3][4] = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}};
// 版本1
cout << "版本1:" << endl;
for (int (&p)[4] : a) {
for (int q : p) {
cout << q << ' ';
}
cout << endl;
}
// 版本2
cout << "版本2:" << endl;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
cout << a[i][j] << ' ';
}
cout << endl;
}
// 版本3
cout << "版本3:" << endl;
for (int (*p)[4] = a; p < a + 3; ++p) {
for (int *q = *p; q < *p + 4; ++q) {
cout << *q << ' ';
}
cout << endl;
}
return 0;
}
3.44
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
using int_array = int[4];
int main() {
int a[3][4] = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}};
// 版本1
cout << "版本1:" << endl;
for (int_array &p : a) {
for (int q : p) {
cout << q << ' ';
}
cout << endl;
}
// 版本2
cout << "版本2:" << endl;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
cout << a[i][j] << ' ';
}
cout << endl;
}
// 版本3
cout << "版本3:" << endl;
for (int_array *p = a; p < a + 3; ++p) {
for (int *q = *p; q < *p + 4; ++q) {
cout << *q << ' ';
}
cout << endl;
}
return 0;
}
3.45
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main() {
int a[3][4] = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}};
// 版本1
cout << "版本1:" << endl;
for (auto &p : a) {
for (auto q : p) {
cout << q << ' ';
}
cout << endl;
}
// 版本2
cout << "版本2:" << endl;
for (auto i = 0; i < 3; ++i) {
for (auto j = 0; j < 4; ++j) {
cout << a[i][j] << ' ';
}
cout << endl;
}
// 版本3
cout << "版本3:" << endl;
for (auto p = a; p < a + 3; ++p) {
for (auto q = *p; q < *p + 4; ++q) {
cout << *q << ' ';
}
cout << endl;
}
return 0;
}