3.1:使用恰当的using声明重做1.4.1节和2.6.2节的练习。
解答:
3.2:编写一段程序从标准输入中一次读入一整行,然后修改该程序使其一次读入一个词。
解答:
#include <iostream> #include <string> using namespace std; #define OPT 1 int main(){ string line, word; #if OPT==1 while (getline(cin, line)){} #else while (cin >> word){} #endif }
3.3:请说明string类的输入运算符和getline函数分别是如何处理空白字符的。
解答:
getline函数处理字符的方式是按换行符来截断标准输入中的字符流的。而输入运算符是按空格来截断字符流的。
3.4:编写一段程序读入两个字符串,比较其是否相等并输出结果。如果不相等,输出较大的那个字符串。改写上述程序,比较输入的两个字符串是否等长,如果不等长,输出长度较大的那个字符串。
解答:
#include <iostream> #include <string> using namespace std; int main(){ string str1, str2; cin >> str1 >> str2; if (str1.size()!= str2.size()){ str1.size() > str2.size()? (cout << str1 << endl) : (cout << str2 << endl); } }
3.5:编写一段程序从标准输入中读入多个字符串并将他们链接在一起,输出链接成的大字符串。然后修改上述程序,用空格吧输入的多个字符串分隔开来。
解答:
#include <iostream> #include <string> using namespace std; #define OPT 1 int main(){ string word, sum; while (cin >> word){ #if OPT == 1 sum += word; #else sum += word + " "; #endif } cout << sum << endl; system("pause"); }
3.6:编写一段程序,使用范围for语句将字符串内的所有字符用X代替。
解答:
void fun(string &s) { for (auto &a : s) a = ‘X‘; }
3.7:就上一题完成的程序而言,如果将循环控制变量的类型设为char将发生什么?先估计一下结果,然后实际编程进行验证。
解答:
void fun(string &s) { for (char &a : s) a = ‘X‘; }
3.8:分别用while循环和传统的for循环重写第一题的程序,你觉得那种形式更好呢?为什么?
解答:
#include <iostream> #include <string> using namespace std; int main(){ string str = "hello, world"; for (auto it = str.begin(); it != str.end(); ++it){ *it = ‘X‘; } std::cout << str << std::endl; } #include <iostream> #include <string> using namespace std; int main(){ string str = "hello, world"; auto it = str.begin(); while (it != str.end()){ *it = ‘X‘; ++it; } std::cout << str << std::endl; }
3.9:下面的程序有何作用?它合法么?如果不合法,为什么?
string s; cout<<s[0]<<endl;
解答:
合法。打印字符串第一个元素。
3.10:编写一段程序,读入一个包含标点符号的字符串,将标点符号取出后输入字符串剩余的部分。
解答:
void fun(string &s) { auto a = s.begin(); while (a != s.end()){ if (ispunct(*a)) { s.erase(a); a = s.begin(); } a++; } }
3.11:下面的范围for语句合法么?如果合法,c的类型是什么?
const string s =”Keep out!”;
for(auto &c:s){/*...*/}
解答:char &
3.12:下列vector对象的定义有不正确的吗?如果有,请指出来。对于正确的,描述其执行结果;对于不正确的,说明其错误的原因。
(a)vector<vector<int>> ivec;
(b)vector<string> svec =ivec;
(c)vector<string> svec(10,”null”);
解答:
(a)(c)是正确的。
(b)不能将一个vector<vector<int>>对象赋给vector<string>对象。
3.13:下列的vector对象各包含多少个元素?这些元素的值分别是多少?
(a)vector<int> v1;
(b)vector<int> v2(10);
(c)vector<int> v3(10,42);
(d)vector<int> v4{10};
(e)vector<int>v5{10,42};
(f)vector<string> v6{10};
(g)vector<string>v7{10,”hi”};
解答:
(a) 空
(b) 10个0;
(c) 10个,都是42
(d) 1个,10
(e) 2个,10和42
(f) 10个,空字符
(g) 10个,“hi”
3.14:编写一段程序,用cin读入一组整数并把它们存入一个vector对象。
解答:
vector<int> ivec; int num; while (cin >> num){ ivec.emplace_back(num); }
3.15:改写上体的程序,不过这次读入的是字符串。
解答:
vector<string> wvec; string word; while (cin >> word){ wvec.emplace_back(word); }
3.16:编写一段程序,把练习3.13中vector对象的容量和具体内容输出出来。检验你之前的回答是否正确,如果不对,回过头重新学习3.3.1节知道弄明白如何错为止。
解答:
3.17:从cin读入一组此并把它们存入一个vector对象,然后设法把所有词都改写成大写形式。输出改变后的结果,每个词占一行。
解答:
int main(){ string str; vector<string> svec; while (cin >> str) { for (auto &b : str) { b = toupper(b); } svec.push_back(str); } for (auto &a:svec) cout <<a<< endl; system("pause"); }
3.18:下面的程序合法吗?如果不合法,你准备如何修改
vector<int> ivec;
ivec[0] = 42;
解答:合乎语法,编译器认,但会实际编译后会出现错误。
3.19:如果想定义一个含有10个元素的vector对象,所有元素的值都是42,请举例出三种不同的实现方法。哪种方法更好呢?为什么?
解答:vector<int> ivec(10,42);
3.20:读入一组整数并把它们存入一个vector对象,将每对相邻整数的和输出出来,改写你的程序,这次要求先输出第1个和最后1个元素的和,接着输出第2个和倒数第2个元素的和。以此类推。
解答:
void fun1(const vector<int> &v) { for (auto a = v.begin(); (a + 1) != v.end(); ++a) { cout << *a + *(a + 1) << " "; } cout << endl; } void fun2(const vector<int> &v) { for (auto a = v.cbegin(),b=--v.cend(); a<b; ++a,--b) { cout << *a + *b << " "; } cout << endl; }
3.21:请使用迭代器重做3.3.3节的第一个练习。
解答:
3.22:修改之前那个输出text第一段的程序,首先把text的第一段全部改成大写形式,然后再输出它。
解答:
string text = "text hello world"; transform(text.begin(), text.end(), text.begin(), toupper); for (auto it = text.cbegin(); it != text.cend() ; ++it) cout << *it ;
3.23:编写一段程序,创建一个含有10个整数的vector对象,然后使用迭代器将所有元素的值都变成原来的两倍。输出vector对象的内存,检验程序是否正确。
解答:
#include <iostream> #include <vector> using namespace std; int main(){ int num[] = { 1, 3, 4, 43, 4, 354, 5, 3, 2, 4, }; vector<int> ivec(num, num + 10); for (auto it = ivec.begin(); it != ivec.end(); ++it){ *it *= 2; } for (auto i : ivec){ cout << i << endl; } }
3.24:请使用迭代器重做3.3.3节的最后一个练习。
解答:
3.25:3.3.3节划分分数段的程序是使用下标运算符实现的,请利用迭代器改写该程序并实现完全相同的功能。
解答:
#include <iostream> #include <vector> using namespace std; int main(){ vector<unsigned> scores(11, 0); unsigned grade; while (cin >> grade){ if (grade <= 100){ vector<unsigned>::iterator it = scores.begin(); it += grade / 10; *it += 1; } } for (auto i : scores){ cout << i << endl; } }
3.26:在100页的二分搜索程序中,为什么用的是mid=beg+(end-beg)/2,而非mid=(beg+end)/2;?
解答:
迭代器的加法没有被定义。
3.27:假设txt_size是一个无参数的函数,它的返回值是int。请回答下列哪个定义是非法的?为什么?
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) 非法,中括号内必须是常量表达式
(b) 合法
(c) 非法,中括号内必须是常量表达式
(d) 非法,char[11]不能被char[12]的对象初始化
3.28:下列数组中元素的值是什么?
string sa[10];
int ia[10];
int main(){
string sa2[10];
int ia2[10];
}
解答:
sa中是空字符。
ia中都是0
sa2中是空字符
ia2中是随机值
3.29:相比于vector来说,数组有哪些缺点,请例举一些。
解答:
无法自动扩展长度
在初始化的时候需要固定的内存分配
3.30:指出下面代码中的索引错误。
constexpr size_t array_size = 10;
int ia[array_size];
for(size_t ix=1;ix<=array_size;++ix)
ia[ix]=ix;
解答:
这里有个数组越界问题,array_size是10。
ia是有10个元素的数组,那么ia[9]就是访问到了ia的最后一个元素。
当访问ia[10]的时候,已经出现访问越界的情况了。
3.31:编写一段程序,定义一个含有10个int的数组,令每个元素的值就是其下标值。
解答:
int num[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
3.32:将上一题刚刚创建数组拷贝给另外一个数组。利用vector重写程序,实现类似的功能。
解答:
vector<int> vnum(num, num + 10);
3.33:对于104页的程序来说,如果不初始化scores将发生什么?
解答:
程序将会崩溃。
这里出现了访问错误,没有初始化的socres是没有给元素分配空间的,所以直接操作必然会出现错误。
3.34:假定p1和p2指向桶一个数组中的元素,则下面程序的功能是什么?什么情况下该程序是非法的?
p1+= p2- p1;
解答:
很多情况下,这段代码都会出错。
1. p2是last*,p1是begin*
2.p1的位置大于p2很多
3.35:编写一段程序,利用指针将数组中的元素置为0;
解答:
#include <iostream> #include <iterator> using namespace std; int main(){ int num[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; auto first = begin(num); auto last = end(num); for (; first != last; ++first){ *first = 0; } for (auto i : num){ cout << i << endl; } }
3.36:编写一段程序,比较两个数组是否相等。再写一段程序,比较两个vector对象是否相等。
解答:
#include <iostream> #include <vector> #include <iterator> using namespace std; int main(){ bool flag = true; int num1[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int num2[11] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 3 }; auto first1 = begin(num1); auto last1 = end(num1); auto first2 = begin(num2); auto last2 = end(num2); for (; first1 != last1 || first2 != last2; ++first1, ++first2){ if (*first1 != *first2){ flag = false; break; } } cout << flag << endl; } #include <iostream> #include <vector> #include <iterator> using namespace std; int main(){ bool flag = true; int num1[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int num2[11] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 3 }; auto first1 = begin(num1); auto last1 = end(num1); auto first2 = begin(num2); auto last2 = end(num2); for (; first1 != last1 || first2 != last2; ++first1, ++first2){ if (*first1 != *first2){ flag = false; break; } } cout << flag << endl; }
3.37:下面的程序是何含义,程序的输出结果是什么?
const char ca[] = {‘h‘,’e’,’l’,’l’,’o’}; const char *cp=ca; while(*cp){ cout<<*cp<<endl; ++cp; }
解答:在打印出hello后出现乱码。
3.38:在本节中我们提到,将两个指针相加不但是非法的,而且也没什么意义。请问为什么两个指针相加没什么意义?
解答:指针本身的意义是内存中的地址。两个地址相加并不会有什么意义,北京站和北京南站相加并不会得到朝阳门。
3.39:编写一段程序,比较两个string对象。再编写一段程序,比较两个C风格字符串的内容。
解答:
string str1,str2; str1<str2?cout<<”str1<str2”:cout<<”str1>str2”; using namespace std; int main(){ const char *a = "hello"; const char *b = "hello"; if (strlen(a) != strlen(b)){ cout << "not equal" << endl; return -1; } for (; *a != ‘\0‘ && *b != ‘\0‘; ++a, ++b){ if (*a != *b){ cout << "not equal" << endl; return -1; } } cout << "equal" << endl; return 0; }
3.40:编写一段程序,定义两个字符数组并用字符串字面值初始化它们;接着再定义一个字符数组存放前两个数组连接后的结果。使用strcpy和strcat把前两个数组的内容拷贝到第三个数组中。
解答:
int main(){ const char *a = "hello"; const char *b = "world"; char c[100]; char res[1000]; strcpy(c, a); strcat(c, b); strcpy(res, c); cout << c << endl; cout << res << endl; system("pause"); }
3.41:编写一段程序,用整型数组初始化一个vector对象。
解答:
int arri = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; vector<int> veci(arri);
3.42:编写一段程序,将含有整数元素的vector对象拷贝给一个整型数组。
解答:
#include <iostream> #include <vector> using namespace std; int main(){ vector<int> ivec; for (int i = 0; i < 20; ++i){ ivec.push_back(i); } int *num = new int[ivec.size()]; for(size_t i = 0; i < ivec.size(); ++i){ num[i] = ivec.at(i); cout << num[i] << endl; } delete[] num; }
3.43:编写3个不同版本的程序,令其均能输出ia的元素。版本1使用范围for语句管理迭代过程;版本2和版本3都使用普通的for语句,其中版本2要求用下标运算符,版本3要求用指针。此外,在所有3个版本的程序中都要直接写出数据类型,而不能使用类型别名、auto关键字或decltype关键字。
解答:
#include <iostream> #include <vector> int main() { int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11}; //使用范围for for (int (&k)[4] : ia ) { for (int j : k ) { std::cout << j << " "; } } std::cout << std::endl; for (size_t i = 0; i != 3; i++) { for (size_t j = 0; j != 4;j++) { std::cout << ia[i][j] << " "; } } std::cout << std::endl; for (int(*p)[4] = ia; p != ia + 3;++p) { for (int *q = *p; q != *p + 4;++q) { std::cout << *q << " "; } } system("pause"); return 0; }
3.44:改写上一个练习中的程序,使用类型别名来代替循环控制变量的类型。
解答:
#include <iostream> #include <vector> using namespace std; int main() { int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11}; using int_array = int[4]; for (int_array& p : ia) for (int q : p) cout << q << " "; cout << endl; for (size_t i = 0; i != 3; ++i) for (size_t j = 0; j != 4; ++j) cout << ia[i][j] << " "; cout << endl; for (int_array* p = ia; p != ia + 3; ++p) for (int *q = *p; q != *p + 4; ++q) cout << *q << " "; cout << endl; system("pause"); return 0; }
3.45:再一次改写程序,这次使用auto关键字。
解答:
#include <iostream> #include <vector> using namespace std; int main() { int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11}; for (auto& p : ia) for (int q : p) cout << q << " "; cout << endl; for (size_t i = 0; i != 3; ++i) for (size_t j = 0; j != 4; ++j) cout << ia[i][j] << " "; cout << endl; for (auto p = ia; p != ia + 3; ++p) for (int *q = *p; q != *p + 4; ++q) cout << *q << " "; cout << endl; system("pause"); return 0; }