--- sort: 3 --- # 字符串、向量和数组 ## 练习3.1 使用恰当的using 声明重做 1.4.1节和2.6.2节的练习。 解: 1.4.1 ```cpp #include using std::cout; using std::endl; int main() { int i = 50, sum = 0; while (i <= 100) { sum += i; i += 1; } cout << "sum is " << sum << endl; } ``` 2.6.2 类似 ## 练习3.2 编写一段程序从标准输入中一次读入一行,然后修改该程序使其一次读入一个词。 解: 一次读入一行: ```cpp #include #include using std::string; using std::cin; using std::cout; using std::endl; using std::getline; int main() { string s; while (getline(cin,s)) { cout << s << endl; } return 0; } ``` 一次读入一个词 ```cpp #include #include using std::string; using std::cin; using std::cout; using std::endl; using std::getline; int main() { string s; while (cin >> s) { cout << s << endl; } return 0; } ``` ## 练习3.3 请说明string类的输入运算符和getline函数分别是如何处理空白字符的。 解: - 类似`is >> s`的读取:string对象会忽略开头的空白(空格符、换行符、制表符等)并从第一个真正的字符开始,直到遇见下一**空白**为止。 - 类似`getline(is, s)`的读取:string对象会从输入流中读取字符,直到遇见**换行符**为止。 ## 练习3.4 编写一段程序读取两个字符串,比较其是否相等并输出结果。如果不相等,输出比较大的那个字符串。改写上述程序,比较输入的两个字符串是否等长,如果不等长,输出长度较大的那个字符串。 解: ```cpp #include #include using namespace std; int main() { string str1, str2; cout << "请输入两个字符串" << endl; cin >> str1; cin >> str2; if (str1 == str2) { cout << "两个字符相等" << endl; }else if (str1 > str2) { cout << str1 << endl; }else { cout << str2 < len2) cout << str1 << "比" << str2 << "的长度多" << len1 - len2 << endl; else cout << str1 << "比" << str2 << "的长度少" << len2 - len1 << endl; return 0; } ``` ## 练习3.5 编写一段程序从标准输入中读入多个字符串并将他们连接起来,输出连接成的大字符串。然后修改上述程序,用空格把输入的多个字符串分割开来。 解: 未隔开的: ```cpp #include #include using namespace std; int main() { char cont = 'y'; string s, result; cout << "请输入字符串" << endl; while(cin >> s) { result += s; cout << "是否继续(y or n)" << endl; cin >> cont; if (cont == 'y' || cont == 'Y'){ cout << "请输入下一个字符串" << endl; }else { break; } } cout << "拼接后的字符为" < #include using std::string; using std::cin; using std::cout; using std::endl; int main() { string result, s; while (cin >> s) { result += s + " "; } cout << result << endl; return 0; } ``` ## 练习3.6 编写一段程序,使用范围for语句将字符串内所有字符用X代替。 解: ```cpp #include #include using namespace std; int main() { string s; cout << "请输入一个字符串" < #include using namespace std; // while int main() { string s; cout << "请输入一个字符串" < #include using namespace std; int main() { string s; cout << "请输入一个字符串" < #include using namespace std; int main() { string s; cout << "请输入一个字符串" <> ivec; // 在C++11当中合法 vector svec = ivec; // 不合法,类型不一样 vector svec(10, "null"); // 合法 ``` ## 练习3.13 下列的vector对象各包含多少个元素?这些元素的值分别是多少? ```cpp vector v1; // size:0, no values. vector v2(10); // size:10, value:0 vector v3(10, 42); // size:10, value:42 vector v4{ 10 }; // size:1, value:10 vector v5{ 10, 42 }; // size:2, value:10, 42 vector v6{ 10 }; // size:10, value:"" vector v7{ 10, "hi" }; // size:10, value:"hi" ``` ## 练习3.14 编写一段程序,用cin读入一组整数并把它们存入一个vector对象。 解: ```cpp ##include #include #include using namespace std; using std::vector; int main() { vector v; int i; char cont = 'y'; cout << "请输入数字" << endl; while(cin >> i) { v.push_back(i); cout << "是否继续(y or n)" << endl; cin >> cont; if (cont == 'y' || cont == 'Y'){ cout << "请输入下一个整数" << endl; }else { break; } } for (auto &m : v) cout << "输入的整数为" < #include #include using namespace std; using std::vector; int main() { vector v; string i; char cont = 'y'; cout << "请输入字符串" << endl; while(cin >> i) { v.push_back(i); cout << "是否继续(y or n)" << endl; cin >> cont; if (cont == 'y' || cont == 'Y'){ cout << "请输入下一个字符串" << endl; }else { break; } } for (auto &m : v) cout << m << " "; cout << endl; return 0; } ``` ## 练习3.16 编写一段程序,把练习3.13中vector对象的容量和具体内容输出出来 解: ```cpp #include #include #include using namespace std; int main() { vector v1; // size:0, no values. vector v2(10); // size:10, value:0 vector v3(10, 42); // size:10, value:42 vector v4{ 10 }; // size:1, value:10 vector v5{ 10, 42 }; // size:2, value:10, 42 vector v6{ 10 }; // size:10, value:"" vector v7{ 10, "hi" }; // size:10, value:"hi" cout << "v1 size :" << v1.size() << endl; cout << "v2 size :" << v2.size() << endl; cout << "v3 size :" << v3.size() << endl; cout << "v4 size :" << v4.size() << endl; cout << "v5 size :" << v5.size() << endl; cout << "v6 size :" << v6.size() << endl; cout << "v7 size :" << v7.size() << endl; cout << "v1 content: "; for (auto i : v1) { cout << i << " , "; } cout << endl; cout << "v2 content: "; for (auto i : v2) { cout << i << " , "; } cout << endl; cout << "v3 content: "; for (auto i : v3) { cout << i << " , "; } cout << endl; cout << "v4 content: "; for (auto i : v4) { cout << i << " , "; } cout << endl; cout << "v5 content: "; for (auto i : v5) { cout << i << " , "; } cout << endl; cout << "v6 content: "; for (auto i : v6) { cout << i << " , "; } cout << endl; cout << "v7 content: "; for (auto i : v7) { cout << i << " , "; } cout << endl; return 0; } ``` ## 练习3.17 从cin读入一组词并把它们存入一个vector对象,然后设法把所有词都改为大写形式。输出改变后的结果,每个词占一行。 解: ```cpp #include #include #include #include using std::cin; using std::cout; using std::endl; using std::vector; using std::string; int main() { vector v; string s; while (cin >> s) { v.push_back(s); } for (auto &str : v) { for (auto &c : str) { c = toupper(c); } } for (auto i : v) { cout << i << endl; } return 0; } ``` ## 练习3.18 下面的程序合法吗?如果不合法,你准备如何修改? ```cpp vector ivec; ivec[0] = 42; ``` 解: 不合法。应改为: ```cpp ivec.push_back(42); ``` ## 练习3.19 如果想定义一个含有10个元素的vector对象,所有元素的值都是42,请例举三种不同的实现方法,哪种方式更好呢? 如下三种: ```cpp vector ivec1(10, 42); vector ivec2{ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 }; vector ivec3 = { 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 }; vector ivec4; for (int i = 0; i < 10; ++i) ivec4.push_back(42); ``` vector ivec5(10); for (auto &i : ivec5) { i = 42; } 第一种方式简介直观,当对象数量多且取值重复时适合使用;思路4不限制元素的个数,比较灵活。 ## 练习3.20 读入一组整数并把他们存入一个vector对象,将每对相邻整数的和输出出来。改写你的程序,这次要求先输出第一个和最后一个元素的和,接着输出第二个和倒数第二个元素的和,以此类推。 解: ```cpp #include #include #include using namespace std; using std::vector; int main() { vector v; int w; cout << "请输入数字" << endl; while (cin >> w) { v.push_back(w); } if (v.size() == 0) { cout << "没有任何元素" < #include #include using namespace std; int main() { vector v1; // size:0, no values. vector v2(10); // size:10, value:0 vector v3(10, 42); // size:10, value:42 vector v4{ 10 }; // size:1, value:10 vector v5{ 10, 42 }; // size:2, value:10, 42 vector v6{ 10 }; // size:10, value:"" vector v7{ 10, "hi" }; // size:10, value:"hi" cout << "v1 size :" << v1.size() << endl; cout << "v2 size :" << v2.size() << endl; cout << "v3 size :" << v3.size() << endl; cout << "v4 size :" << v4.size() << endl; cout << "v5 size :" << v5.size() << endl; cout << "v6 size :" << v6.size() << endl; cout << "v7 size :" << v7.size() << endl; cout << "v1 content: "; if (v1.cbegin() != v1.cend()) { for (auto it = v1.cbegin(); it != v1.cend(); it++) { cout << *it << " , "; } cout << endl; } cout << "v2 content: "; if (v2.cbegin() != v2.cend()) { for (auto it = v2.cbegin(); it != v2.cend(); it++) { cout << *it << " , "; } cout << endl; } cout << "v3 content: "; if (v3.cbegin()!= v3.cend()) { for (auto it = v3.cbegin(); it != v3.cend(); it++){ cout << *it << " , "; } cout << endl; } cout << "v4 content: "; if (v4.cbegin() != v4.cend()) { for(auto it = v4.cbegin(); it != v4.cend(); it++) { cout << *it << ","; } cout << endl; } cout << "v5 content: "; if (v5.cbegin() != v5.cend()) { for(auto it = v5.cbegin(); it != v5.cend(); it++) { cout << *it << ","; } cout << endl; } cout << "v6 content: "; if (v6.cbegin() != v6.cend()) { for(auto it = v6.cbegin(); it != v6.cend(); it++) { cout << *it << ","; } cout << endl; } cout << "v7 content: "; if (v7.cbegin() != v7.cend()) { for(auto it = v7.cbegin(); it != v7.cend(); it++) { cout << *it << ","; } cout << endl; } return 0; } ``` ## 练习3.22 修改之前那个输出text第一段的程序,首先把text的第一段全部改成大写形式,然后输出它。 解: ```cpp #include #include #include using namespace std; using std::vector; int main() { vector v; string w; cout << "请输入一段话" << endl; while (getline(cin, w)) { //利用getline读取一句话,直接回车产生一个空串,表示段落结束 v.push_back(w); } for(auto it = v.begin(); it != v.end() && !it -> empty();it++) { for (auto it2 = it->begin(); it2 != it->end(); it2++){ *it2 = toupper(*it2); } cout << *it << endl; } return 0; } ``` ## 练习3.23 编写一段程序,创建一个含有10个整数的vector对象,然后使用迭代器将所有元素的值都变成原来的两倍。输出vector对象的内容,检验程序是否正确。 解: ```cpp #include #include #include using namespace std; using std::vector; int main() { vector words; for (int i = 0; i < 10; i++) { words.push_back(rand() % 1000); } cout << "随机生成的数字是:" < #include #include #include using std::cin; using std::cout; using std::endl; using std::vector; using std::string; int main() { #include #include #include using namespace std; using std::vector; int main() { vector v; int w; cout << "请输入数字" << endl; while (cin >> w) { v.push_back(w); } if (v.cbegin() == v.cend()) { cout << "没有任何元素" < #include #include using namespace std; using std::vector; int main() { vector v(11); auto it = v.begin(); int i; cout << "请输入一组成绩"<> i) { if (i < 101) { ++*(it + i / 10); } } cout << "各分数段的人数分布式" << endl; for (it = v.begin(); it!= v.end();it++) { cout << *it << " "; } cout << endl; return 0; } ``` ## 练习3.26 在100页的二分搜索程序中,为什么用的是 `mid = beg + (end - beg) / 2`, 而非 `mid = (beg + end) / 2 ;` ? 解: 因为两个迭代器相互之间支持的运算只有 `-` ,而没有 `+` ,两个迭代器之间相减的结果代表他们之间的距离; 但是迭代器和迭代器差值(整数值)之间支持 `+`。 ## 练习3.27 假设`txt_size`是一个无参函数,它的返回值是`int`。请回答下列哪个定义是非法的,为什么? ```cpp unsigned buf_size = 1024; (a) int ia[buf_size]; (b) int ia[4 * 7 - 14]; (c) int ia[txt_size()]; (d) char st[11] = "fundamental"; ``` 解: - (a) 非法。 维度必须是一个常量表达式, `buf_size`是一个普通的无符号数,不是常量 - (b) 合法。 - (c) 非法。txt_size() 的值必须要到运行时才能得到,没有被定义为`constexpr`,不能作为数组的维度。 - (d) 非法。数组的大小应该是12。 ## 练习3.28 下列数组中元素的值是什么? ```cpp string sa[10]; int ia[10]; int main() { string sa2[10]; int ia2[10]; } ``` 解: 对于内置类型`int`来说,数组`ia`定义在所有函数体之外,所有元素默认初始化为0,而`ia2`定义在main函数的内部,将不被初始化,如果程序试图拷贝或输出未初始化的变量,将遇到未定义的奇异值。 string类本身接收无参数的初始化方式,所以不论数组定义在函数内还是函数外,都被默认初始化为空串。 ## 练习3.29 相比于vector 来说,数组有哪些缺点,请例举一些。 解: - 数组与vector的相似之处是都能存放类型相同的对象,且这些对象本身没有名字,需要通过其所在位置访问。 - 数组与vector的最大不同是,数组的大小固定不变,不能随意向数组中增加额外的元素,虽然在某些情境下运行时性能能较好,但是与vector相比损失了灵活性。 - 具体来说,数组的维度在定义时已经确定,如果我们想更改数组的长度,只能创建一个更大的新数组,然后把原数组的所有有元素复制到新数组中去。我们也无法像vector那样使用 size函数直接获取数组的维度。如果是字符数组,可以调用strlen函数得到字符串的长度; 如果是其他数组,只能使用 sizeof(array)/sizeof(array[0])的方式计算数组的维度。 ## 练习3.30 指出下面代码中的索引错误。 ```cpp constexpr size_t array_size = 10; int ia[array_size]; for (size_t ix = 1; ix <= array_size; ++ix) ia[ix] = ix; ``` 解: 当`ix`增长到 10 的时候,`ia[ix]`的下标越界。 ## 练习3.31 编写一段程序,定义一个含有10个int的数组,令每个元素的值就是其下标值。 ```cpp #include #include #include using namespace std; using std::vector; int main() { const int sz = 10; int num[sz]; for (int i = 0; i < sz; i++) { num[i] = i; } for (auto val : num) { cout << val << " "; } cout << endl; return 0; } ``` ## 练习3.32 将上一题刚刚创建的数组拷贝给另一数组。利用vector重写程序,实现类似的功能。 ```cpp #include #include #include using namespace std; using std::vector; int main() { const int sz = 10; vector num3; vector num4; int num1[sz], num2[sz]; for (int i = 0; i < sz; i++) { num1[i] = i; } for (int i = 0; i < sz; i++) { num2[i] = num1[i]; } cout << "num2中的值为" << endl; for (auto val : num2) { cout << val << " "; } cout << endl; for (int i = 0; i < sz; i++) { num3.push_back(i); } for (int i = 0; i < sz; i++) { num4.push_back(num3[i]); } cout << "num4中的值为" << endl; for (auto val : num4) { cout << val << " "; } cout << endl; return 0; } ``` ## 练习3.33 对于104页的程序来说,如果不初始化scores将会发生什么? 解: 该数组会含有未定义的数值,因为scores是定义在函数内部的整型数组,不会执行默认初始化。 ## 练习3.34 假定`p1` 和 `p2` 都指向同一个数组中的元素,则下面程序的功能是什么?什么情况下该程序是非法的? ```cpp p1 += p2 - p1; ``` 解: 将 `p1` 移动到 `p2` 的位置。 如果`p1` 和 `p2`的类型不同,则编译时报错。 ## 练习3.35 编写一段程序,利用指针将数组中的元素置为0。 解: ```cpp #include #include #include using namespace std; using std::vector; int main() { const int sz = 10; int nums[sz]; for (int i = 0; i < sz; i++) { nums[i] = i; } for (auto ptr = nums; ptr != nums + sz; ++ptr) *ptr = 0; // int *p = begin(nums); // while (p != end(nums)) { // *p = 0; // p++; // } for (auto num : nums) { cout << num << " "; } cout << endl; return 0; } ``` ## 练习3.36 编写一段程序,比较两个数组是否相等。再写一段程序,比较两个vector对象是否相等。 解: ```cpp #include #include #include using std::begin; using std::end; using std::cout; using std::endl; using std::vector; // pb point to begin of the array, pe point to end of the array. bool compare(int* const pb1, int* const pe1, int* const pb2, int* const pe2) { if ((pe1 - pb1) != (pe2 - pb2)) // have different size. return false; else { for (int* i = pb1, *j = pb2; (i != pe1) && (j != pe2); ++i, ++j) if (*i != *j) return false; } return true; } int main() { int arr1[3] = { 0, 1, 2 }; int arr2[3] = { 0, 2, 4 }; if (compare(begin(arr1), end(arr1), begin(arr2), end(arr2))) cout << "The two arrays are equal." << endl; else cout << "The two arrays are not equal." << endl; cout << "==========" << endl; vector vec1 = { 0, 1, 2 }; vector vec2 = { 0, 1, 2 }; if (vec1 == vec2) cout << "The two vectors are equal." << endl; else cout << "The two vectors are not equal." << endl; return 0; } ``` ## 练习3.37 下面的程序是何含义,程序的输出结果是什么? ```cpp const char ca[] = { 'h', 'e', 'l', 'l', 'o' }; const char *cp = ca; while (*cp) { cout << *cp << endl; ++cp; } ``` 解: 会将ca 字符数组中的元素打印出来。但是因为没有空字符的存在,程序不会退出循环。 ## 练习3.38 在本节中我们提到,将两个指针相加不但是非法的,而且也没有什么意义。请问为什么两个指针相加没有意义? 解: 指针的值是它所指对象的内存地址,将两个指针相减可以表示两个指针(在同一数组中)相距的距离,将指针加上一个整数也可以表示移动这个指针到某一位置。但是两个指针相加并没有逻辑上的意义,因此两个指针不能相加。 ## 练习3.39 编写一段程序,比较两个 `string` 对象。再编写一段程序,比较两个C风格字符串的内容。 解: ```cpp #include #include #include using std::cout; using std::endl; using std::string; int main() { // use string. string s1("Mooophy"), s2("Pezy"); if (s1 == s2) cout << "same string." << endl; else if (s1 > s2) cout << "Mooophy > Pezy" << endl; else cout << "Mooophy < Pezy" << endl; cout << "=========" << endl; // use C-Style character strings. const char* cs1 = "Wangyue"; const char* cs2 = "Pezy"; auto result = strcmp(cs1, cs2); if (result == 0) cout << "same string." << endl; else if (result < 0) cout << "Wangyue < Pezy" << endl; else cout << "Wangyue > Pezy" << endl; return 0; } ``` ## 练习3.40 编写一段程序,定义两个字符数组并用字符串字面值初始化它们;接着再定义一个字符数组存放前面两个数组连接后的结果。使用`strcpy`和`strcat`把前两个数组的内容拷贝到第三个数组当中。 解: ```cpp #include #include const char cstr1[]="Hello"; const char cstr2[]="world!"; int main() { constexpr size_t new_size = strlen(cstr1) + strlen(" ") + strlen(cstr2) +1; char cstr3[new_size]; strcpy(cstr3, cstr1); strcat(cstr3, " "); strcat(cstr3, cstr2); std::cout << cstr3 << std::endl; } ``` ## 练习3.41 编写一段程序,用整型数组初始化一个vector对象。 ```cpp #include #include using std::vector; using std::cout; using std::endl; using std::begin; using std::end; int main() { int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; vector v(begin(arr), end(arr)); for (auto i : v) cout << i << " "; cout << endl; return 0; } ``` ## 练习3.42 编写一段程序,将含有整数元素的 `vector` 对象拷贝给一个整型数组。 解: ```cpp #include #include using namespace std; int main() { const int sz = 10; vector words; int nums[10]; for (int i = 0; i < sz; i++) { words.push_back(i); } auto it = words.cbegin(); for (auto & val : nums) { val = *it; cout << val << " "; it++; } cout << endl; return 0; } ``` ## 练习3.43 编写3个不同版本的程序,令其均能输出`ia`的元素。 版本1使用范围`for`语句管理迭代过程;版本2和版本3都使用普通`for`语句,其中版本2要求使用下标运算符,版本3要求使用指针。 此外,在所有3个版本的程序中都要直接写出数据类型,而不能使用类型别名、`auto`关键字和`decltype`关键字。 解: ```cpp #include #include using namespace std; int main() { // 范围for语句 int ia[2][2] = {1, 2, 3, 4}; for (int (&row)[2] : ia){ for(int &val : row) { cout << val << " "; } cout << endl; } // 普通for语句,下标形式 for (int i = 0; i != 2; i++){ for(int j = 0; j != 2; j++) { cout << ia[i][j] << " "; } cout << endl; } // 普通for语句,指针形式 for (int (*p)[2] = ia; p != ia + 2; p++){ for(int *q = *p; q != *p + 2; q++) { cout << *q << " "; } cout << endl; } return 0; } ``` ## 练习3.44 改写上一个练习中的程序,使用类型别名来代替循环控制变量的类型。 解: ```cpp #include #include using namespace std; using int_array = int[2]; int main() { // 范围for语句 int ia[2][2] = {1, 2, 3, 4}; for (int_array &row : ia){ for(int &val : row) { cout << val << " "; } cout << endl; } // 普通for语句,下标形式 for (int i = 0; i != 2; i++){ for(int j = 0; j != 2; j++) { cout << ia[i][j] << " "; } cout << endl; } // 普通for语句,指针形式 for (int_array *p = ia; p != ia + 2; p++){ for(int *q = *p; q != *p + 2; q++) { cout << *q << " "; } cout << endl; } return 0; } ``` ## 练习3.45 再一次改写程序,这次使用 `auto` 关键字。 解: ```cpp #include #include using namespace std; using int_array = int[2]; int main() { // 范围for语句 int ia[2][2] = {1, 2, 3, 4}; for (auto &row : ia){ for(auto &val : row) { cout << val << " "; } cout << endl; } // 普通for语句,下标形式 for (auto i = 0; i != 2; i++){ for(auto j = 0; j != 2; j++) { cout << ia[i][j] << " "; } cout << endl; } // 普通for语句,指针形式 for (auto *p = ia; p != ia + 2; p++){ for(auto *q = *p; q != *p + 2; q++) { cout << *q << " "; } cout << endl; } return 0; } ```