建议在看书的时候就直接将这部分的课后习题过一遍,当时过挺简单的,没必要忘得差不多了再回去复习重做,这块的知识点就从其他地方做题遇到不懂的再翻就行。
16章 STL string类
第一题
#include <iostream> // 包含头文件。 #include<algorithm> #include<string> using namespace std; // 指定缺省的命名空间。 int main() { string instr; cout << "请输入一串字符:" << endl; cin >> instr; string copystr = instr; reverse(instr.begin(), instr.end()); if (copystr == instr) { cout << "字符串为回文"; } else { cout << "bushi"; } }
第二题
#include <iostream> // 包含头文件。 #include<algorithm> #include<string> using namespace std; // 指定缺省的命名空间。 int main() { string instr; cout << "请输入一串字符:" << endl; cin >> instr; int count = 0; for (int i = 0; i < instr.length(); i++) { if ((instr[i] == 'a') || (instr[i] == 'e') || (instr[i] == 'i') || (instr[i] == 'o') || (instr[i] == 'u')) { count++; } } cout << "元音数:" << count; }
第三题
#include <iostream> // 包含头文件。 #include<algorithm> #include<string> using namespace std; // 指定缺省的命名空间。 int main() { string instr; cout << "请输入一串字符:" << endl; cin >> instr; int count = 0; for (int i = 1; i < instr.length(); i += 2) { transform(instr.begin() + i, instr.begin() + i + 1, instr.begin() + i, ::toupper); } cout << "zhuan:" << instr; }
第四题
#include <iostream> // 包含头文件。 #include<algorithm> #include<string> using namespace std; // 指定缺省的命名空间。 int main() { string str1 = "i"; string str2 = "love"; string str3 = "STL"; string str4 = "string"; str1.append(" "); str2.append(" "); str3.append(" "); str4.append(" "); str3.append(str4); str2.append(str3); str1.append(str2); cout << str1; }
第五题
#include <iostream> // 包含头文件。 #include<algorithm> #include<string> using namespace std; // 指定缺省的命名空间。 int main() { string str1 = "good day string! today is beautiful"; auto findpos = str1.find('a', 0); while(findpos != string::npos) //find函数在找不到结果时返回npos { cout <<findpos<<endl; //返回第一个找到的位置 auto newfindpos = findpos + 1; //第一次找到的位置往后加1 findpos = str1.find('a', newfindpos); //下次查找从新位置开始,find返回新位置 } }
17章 STL动态数组类vector
第一题
自己的代码不严谨,应该像示例提前将情况都列出。使用一个函数将所有的选项都展示,在函数中输入内容,选择要实现的功能
第一题、第二题
#include <iostream> // 包含头文件。 #include<algorithm> #include<string> #include<vector> using namespace std; // 指定缺省的命名空间。 template<typename T> void show(const T& invector) { for (auto count = invector.cbegin(); count != invector.cend(); count++) { cout <<"容器中元素为:"<< * count << endl; } } int main() { int num; int stop = 10; vector<int>vec1; while(stop!=0) { cout << endl<<"请输入一些整数(逐个输入):" << endl; cin >> num; vec1.push_back(num); cout <<"输入的整数为:"<< num << endl; cout << "continue?(输入0停止)" << endl; cin >> stop; //show(vec1); } int cha; cout << "请输入查询的索引值:" << endl; cin >> cha; if (cha < vec1.size()) { cout << vec1[cha]<<endl; } cout << "请输入想要查询的元素值:" << endl; int find_num = 0; cin >> find_num; for (auto count1 = vec1.begin(); count1 != vec1.end(); count1++) { if (*count1 == find_num) //不严谨,对每个元素进行判断,如果有两个相同的将输出两遍 { cout << "找到查询的元素"; } } }
第三题
重载<<运算符需要注意
char option() //提供一个函数,实现菜单选项以及输入信息 { cout << "请输入想要的选项:" << endl; cout << "选项1:输入货物的尺寸:" << endl; cout << "选项2:输出货物的信息:" << endl; cout << "选项3:退出:" << endl; char opt; cin >> opt; return opt; } class goods { public: int length; int high; string name; goods() {}; goods(int inlen, int inhigh, string inname) { length = inlen; high = inhigh; name = inname; cout << "初始化完成"<<endl; }; ~goods() {}; }; ostream& operator<< (ostream& output, goods& ingoods) //重载<<运算符 { output << "货物高:" << ingoods.high << endl << "货物长:" << ingoods.length << endl << "货物名称:" << ingoods.name << endl; return output; } int main() { vector<goods> vecdate; char opt_choose; /*cout << "请输入选择的选项:"; cin >> opt_choose;*/ while ((opt_choose = option()) != '3') //将上面定义好的参数传递给opt_choose,且这个值不是选项3的时候 { if (opt_choose == '1') //输入货物的尺寸 { goods goods1; string name1 = ""; cout << "请输入货物名称:"; cin >> name1; int len1 = 0; cout << "请输入货物长:"; cin >> len1; int high1 = 0; cout << "请输入货物高:"; cin >> high1; vecdate.push_back(goods(len1, high1,name1)); //实例化一个对象,并将其放到vector的末尾 } else if(opt_choose == '2') //输出货物的信息 { cout << "请输入想要查询的索引:介于0和"<<vecdate.size()-1 <<"之间" << endl; int num = 0; cout << "想要查询的索引值为:"; cin >> num; if (num < vecdate.size()) { cout << vecdate[num] << endl; //没有将class传入cout的运算符,需要重载<<运算符 } } } return 0; }
第四题
#include <iostream> // 包含头文件。 #include<algorithm> #include<deque> #include<vector> using namespace std; // 指定缺省的命名空间。 template<typename T> void show(const T& invector) { for (auto count = invector.cbegin(); count != invector.cend(); count++) { cout <<"容器中元素为:"<< * count << endl; } } int main() { deque<string>exdeque{"hello", "cool", "C++"}; show(exdeque); }
18章 STL list 和forward_list
第一题
实现的想法与17章的第一题类似,注意局部变量的使用,如果循环中用到的变量其他地方还要使用,就将其放到循环外。
#include <iostream> // 包含头文件。 #include<algorithm> #include<list> using namespace std; // 指定缺省的命名空间。 template<typename T> void show(const T& invector) { for (auto count = invector.cbegin(); count != invector.cend(); count++) { cout <<"容器中元素为:"<< * count << endl; } } char option() //提供一个函数,实现菜单选项以及输入信息 { cout << "请输入想要的选项:" << endl; cout << "选项1:输入存储的值:" << endl; cout << "选项2:输出存储的值:" << endl; cout << "选项3:退出:" << endl; char opt; cin >> opt; return opt; } int main() { char opt; list<int>list1; while ((opt = option()) != '3') { int num = 0; if (opt == '1') { cout << "请输入想要存储的数:"; cin >> num; list1.push_front(num); } else if(opt == '2') { show(list1); cout << "输出"; } } return 0; }
第二题
在插入元素后,迭代器仍然指向原本元素,因为其解引用的值未变
#include <iostream> // 包含头文件。 #include<algorithm> #include<list> using namespace std; // 指定缺省的命名空间。 int main() { list<int>list1; list1.push_front(1); list1.push_front(2); list1.push_front(3); //现在list1内部的元素为3,2,1 auto find_1 = find(list1.begin(), list1.end(), 1); //迭代器指向1所在位置 auto find_3 = find(list1.begin(), list1.end(), 3); //迭代器指向3所在位置 //cout << *(find_1) << endl; //cout << *(find_3) << endl; list1.insert(list1.begin() , 1000); list1.push_front(500); //现在元素值为500,1000,3,2,1 cout << *(find_1) << endl; cout << *(find_3) << endl; return 0; }
第三题
insert(插入的位置,插入的容器起始,插入的容器终止)
#include <iostream> // 包含头文件。 #include<algorithm> #include<list> #include<vector> using namespace std; // 指定缺省的命名空间。 template<typename T> void show(const T& invector) { for (auto count = invector.cbegin(); count != invector.cend(); count++) { cout <<"容器中元素为:"<< * count << endl; } } int main() { list<int>list1; vector<int>vec1{11, 12, 13}; list1.push_front(1); list1.push_front(2); list1.push_front(3); //现在list1内部的元素为3,2,1 list1.insert(list1.begin(), vec1.begin(), vec1.end()); show(list1); return 0; }
第四题
#include <iostream> // 包含头文件。 #include<algorithm> #include<list> #include<vector> using namespace std; // 指定缺省的命名空间。 template<typename T> void show(const T& invector) { for (auto count = invector.cbegin(); count != invector.cend(); count++) { cout <<"容器中元素为:"<< * count << endl; } } bool down (const int& left, const int& right) { return left > right; } int main() { list<int>list1; vector<int>vec1{11, 12, 13}; list1.push_front(1); list1.push_front(2); list1.push_front(3); //现在list1内部的元素为3,2,1 list1.insert(list1.begin(), vec1.begin(), vec1.end()); list1.sort(down); //自定义下降 show(list1); list1.reverse(); //直接将默认升序反转 show(list1); return 0; }
第19章 STL集合类set
第一题
在代码中用到了类型转换函数,将string转化为c风格字符串,在C++中,构造函数、析构函数、类型转换函数没有返回类型,在类型转换函数中,不写返回类型,但是必须出现return。类型转接中返回类型在operator后面的括号前面,函数运算符是在类型在operator前面
#include <iostream> // 包含头文件。 #include<algorithm> #include<set> #include<string> using namespace std; template<typename T> void show(const T& invector) { for (auto count = invector.cbegin(); count != invector.cend(); count++) { cout <<"容器中元素为:"<< *count<< endl; } } class books { public: string names; string num; string coutdata; books(const string inkeys, const string inmeaning) :names(inkeys), num(inmeaning),coutdata(inkeys+inmeaning) {}; //使用sort排序 bool operator < (const books& inword) const { return (this->names < inword.names); //对于string没有<运算符 } //使用find函数 bool operator ==(const string& inkey) //判断输入的词与当前词的索引相同 { return(inkey == this->names); } operator const char* () const //将string类转换为c风格,函数后面的const不可少 { return coutdata.c_str(); } }; int main() { set<books>set_ex; set_ex.insert(books{ "xiaoming","1111111111" }); set_ex.insert(books{ "xiaoli","222222222" }); set_ex.insert(books{ "xiaowang","3333333" }); set_ex.insert(books{ "xiaozhang","444444444" }); show(set_ex); cout << "请输入想要查询的名字:"; string input; getline(cin, input); //有getline就不需要在前面cin了,只需要在内部传入cin auto element = set_ex.find(books(input, " ")); if (element != set_ex.end()) { cout << "查找的电话号码为:" << (*element).num << endl; } else { cout << "没有查到该人" << endl; } return 0; }
第二题
set会在插入元素时自动排序,所以对于不是基本数据类型的元素需要重载<运算符,如果想要使用find函数还需要重载==运算符。
#include <iostream> // 包含头文件。 #include<algorithm> #include<set> #include<string> using namespace std; class word { public: string keys; string meaning; word(const string inkeys, const string inmeaning) :keys(inkeys), meaning(inmeaning) {}; //template<typename T1> bool operator < (const word& inword) const { return (this->keys < inword.keys); //对于string没有<运算符 } bool operator==(const string& inkey) //判断输入的词与当前词的索引相同 { return(inkey == this->keys); } }; int main() { set<word>set_ex; word word1("book", "to learn"); //set在插入时对元素进行排序,需要重载<运算符 word word2("water", "to drink"); set_ex.insert(word1); set_ex.insert(word2); cout << "请输入想要查询的词:"; string input; getline(cin,input); //有getline就不需要在前面cin了,只需要在内部传入cin auto element = set_ex.find(word(input, " ")); if (element != set_ex.end()) { cout << "单词的含义是" << (*element).meaning << endl; } else { cout << "没有查到该单词" << endl; } return 0; }
第三题
#include <iostream> // 包含头文件。 #include<algorithm> #include<set> #include<string> using namespace std; template<typename T> void show(const T& invector) { for (auto count = invector.cbegin(); count != invector.cend(); count++) { cout <<"容器中元素为:"<< (*count)<< endl; } } int main() { set<int>set_ex; multiset<int>mulset_ex; set_ex.insert(5); set_ex.insert(5); mulset_ex.insert(5); mulset_ex.insert(5); mulset_ex.insert(5); show(set_ex); cout << "下面是multiset的输出。"<<endl; show(mulset_ex); return 0; }
第20章 STL映射类map
第一题
可包含重复元素的关联容器,可以使用STL::multimap实现
multimap<string, string> numbercount;
第二题
在结构体里创建一个二元谓词(跟二元函数类似,但是返回值类型是bool),根据string元素进行排序
struct fpredicate { bool operator <(const wordpropetry& lsh, const wordpropetry& rah)const { return (lsh.word < rah.word); } };
第三题
在map中需要使用迭代器(指针)的first和second来表达键和值,在往map中插入元素时,map名.insert(make_pair(键,值))实现
#include <iostream> // 包含头文件。 #include<algorithm> #include<string> #include<map> using namespace std; template<typename T> void show(const T& invector) { for (auto count = invector.cbegin(); count != invector.cend(); count++) { cout <<"容器中元素为:"<< count->first<< endl; cout << "容器中元素为:" << count->second << endl << endl; } } int main() { multimap<int, int>num_set; num_set.insert(make_pair(1, 1)); num_set.insert(make_pair(2, 2)); num_set.insert(make_pair(1, 2)); show(num_set); return 0; }
第21章 理解函数对象
第一题
函数对象是用作函数的对象,实现了operator()的类的对象
#include <iostream> // 包含头文件。 #include<algorithm> #include<string> #include<vector> using namespace std; template<typename T=int> //提供默认参数类型,否则下方需要传入参数类型 struct Double { void operator()(const T input) const { cout << input * 2 << endl; } }; int main() { vector<int>vec1; for (int i = 0; i < 10; i++) { vec1.push_back(i); } for_each(vec1.begin(), vec1.end(), Double<double>()); //因为在构建函数模版时提供了默认参数,所以这块可以不传入double类型 return 0; }
第二题
#include <iostream> // 包含头文件。 #include<algorithm> #include<string> #include<vector> using namespace std; template<typename T=int> //提供默认参数类型,否则下方需要传入参数类型 struct Double { int count; Double() { count = 0; }; void operator()(const T input) { count++; cout << input * 2 << endl; } }; int main() { vector<int>vec1; for (int i = 0; i < 10; i++) { vec1.push_back(i); } //Double<int>result; result的实际类型 // for_each返回所传入函数对象的最终状态 auto result=for_each(vec1.begin(), vec1.end(), Double<>()); cout << "计数器:" << result.count << endl; return 0; }
第三题
在实际使用中作为sort函数的第三个参数传入
#include <iostream> // 包含头文件。 #include<algorithm> #include<vector> using namespace std; template<typename T> class SortAscending { public: bool operator()(const T& num1, const T& num2)const { return(num1 < num2); } }; template<typename T> void show(const T& invector) { for (auto count = invector.cbegin(); count != invector.cend(); count++) { cout <<"容器中元素为:"<< *count<< endl; } } int main() { vector<int>vec1; for (int i = 10; i>0; i--) { vec1.push_back(i*10); } cout << "排序前:"<<endl; show(vec1); sort(vec1.begin(), vec1.end(), SortAscending<int>()); cout << "排序后:" << endl; show(vec1); return 0; }
第22章 lamdba表达式
第一题
sort(容器.begin(), 容器.end(),
[](auto in1, auto in2) {return in1 > in2; });
第二题
cout << "想要添加的元素值:";
int numinput = 0;
cin >> numinput;
for_each(vec.begin(), vec.end(),
[=](int& element) {element += numinput; });
代码的使用示例
#include <iostream> // 包含头文件。
#include<algorithm>
#include<vector>
using namespace std;
template<typename T>
void show(const T& invector)
{
for (auto count = invector.cbegin(); count != invector.cend(); count++)
{
cout <<"容器中元素为:"<< *count<< endl;
}
}
int main()
{
vector<int>vec{1, 4, 5, 2, 6};
show(vec);
cout << "降序排列" << endl;
sort(vec.begin(),vec.end());
show(vec);
cout << "升序排列" << endl;
sort(vec.begin(), vec.end(),
[](auto in1, auto in2) {return in1 > in2; });
show(vec);
cout << "输入在容器元素值增加的值:";
int numinput = 0;
cin >> numinput;
for_each(vec.begin(), vec.end(),
[=](int& element) {element += numinput; });
show(vec);
return 0;
}
第23章 STL算法
第一题
struct compare { bool operator() (const string str1, const string str2)const { //因为不改变输入的字符串内容,所以使用现有的两个字符串构建新的字符串 string copy1(str1),copy2(str2); //因为不区分大小写所以将两个字符串都转换为小写 transform(copy1.begin(),copy1.end(),tolower); transform(copy2.begin(),copy2.end(),tolower); return(copy1<copy2); } };
第二题
#include <iostream> // 包含头文件。 #include<algorithm> #include<string> #include<list> #include<vector> using namespace std; // 指定缺省的命名空间。 template<typename T> void show(const T& invector) { for (auto count = invector.cbegin(); count != invector.cend(); count++) { cout <<"容器中元素为:"<< *count<< endl; } } int main() { list<string>listname; listname.push_back("xiaoming"); listname.push_back("xiaoli"); listname.push_back("xiaowang"); show(listname); vector<string>vec1(3); copy(listname.begin(),listname.end(),vec1.begin()); show(vec1); return 0; }
第三题
std::sort( )与 stdstable sot( )之间的区别在于,后者在排序时保持对象的相对位置不变。由于该应用程序需要按生成顺序存储数据,因此应使用 stable sort(),以保持天体事件的相对顺序不变
第24章 自适应容器:栈和队列
第一题
class Person { public: int age; bool isFemale; //重载<运算符,用于判断传入对象的年龄和性别 bool operator< (const Person& anotherperson) const { bool bret = false; if(age > anotherperson.age) bret = true; else if(isFemale && anotherperson.isFemale) bret = ture; return bret; } };
第二题
string str; cout << "输入字符串"<<endl; cin >> str; stack<int>st1; for (int i = 0; i < str.length(); i++) { st1.push(name[i]); } while (st1.size() != 0) { cout <<char( st1.top())<<endl; st1.pop(); }
第25章 使用STL位标志
第一题
#include<bitset> #include <iostream> int main() { bitset<4>fourbits(1); //初始化四位bitset;初始值0001 cout << fourbits << endl; bitset<4>onefourbits(2); //初始化四位bitset;初始值0010 cout << onefourbits << endl; bitset<4>addres(fourbits.to_ullong() + onefourbits.to_ullong()); cout << addres; return 0; }
第二题
#include<bitset> #include <iostream> int main() { bitset<4>fourbits(1); //初始化四位bitset;初始值0001 cout << fourbits << endl; fourbits.flip(); //按位取反 cout << fourbits << endl; return 0; }
第26章 理解智能指针
第一题
语句 object ->DoSomething 0有问题,因为指针在复制时失去了对对象的拥有权。这将导致程序崩溃。
第二题
代码类似下述
#include <memory> #include <iostream> using namespace std; class Fish { public: Fish() {cout << "Fish: Constructed!" << endl;} ~Fish() {cout << "Fish: Destructed!" << endl;} void Swim() const (cout << "pish swims in water" << endl;) }; class Carp: public Fish { }; void MakeFishSwim(const unique ptr<Fish>& inFish) { inpish->Swim(); } int main () { unique ptr<Fish> myCarp (new Carp); // note thisMakeFishSwim(myCarp); return 0; }
鉴于 MakeFishSwim()接受的参数为引用,不会导致复制,因此不会出现切除问题。另外,请注意变量myCarp的实例化语法。
切除问题
当把一个派生类对象赋给一个基类对象时(用对象创建对象),会发生对象切割。(另外用基类对象强制转换派生类对象也会)。父类引用或指针调用子类重写方法,实际调用结果为父类中方法
多态的实现是通过指针和引用,对象的转换只能完成对象切割,无法完成多态
#include <iostream> using namespace std; //基类 class Base{ public: virtual void printError(){ //对象切片无法使用virtual关键字声明虚函数解决 cout << "基类方法!" << endl; }; }; //派生类 class Derived : public Base{ public: void printError(){ cout << "派生类方法!" << endl; } }; void test() { Base e = Derived(); //对象切片导致子类对象调用基类方法,而不是子类方法 ex.printError(); //输出基类方法! } int main() { test(); return 0; }
第三题
unique_ptr 的复制构造函数和复制赋值运算符都是私有的,因此不允许复制和赋值。
第27章 使用流进行输入和输出
第一题
在使用流并关闭它之前,需要使用 is_open()检查 open()是否成功。
第二题
不能插入到 ifstream。Ifstream 旨在用于输入,而不是输出,因此不支持流插入运算符<<。
第28章 异常处理
第一题
绝不要在析构函数中引发异常。
第二题
没有处理代码可能引发的异常,即缺少 ty...catch 块。
第三题
绝不要在 catch 块中分配内存。如果 try 块内的代码分配内存失败,将导致恶性循环。