实验1 现代C++编程初体验
任务一:
1.源代码task1.cpp
#include <iostream> #include <string> #include <vector> #include <algorithm> template<typename T> void output(const T &C); void test1(); void test2(); void test3(); int main(){ std::cout << "测试1:\n"; test1(); std::cout << "\n测试2:\n"; test2(); std::cout << "\n测试3:\n"; test3(); } template <typename T> void output(const T &c){ for(auto &i : c) std::cout << i << ' '; std::cout << '\n'; } void test1(){ using namespace std; string s0{"0123456789"}; cout << "s0 = " << s0 << endl; string s1(s0); reverse(s1.begin(),s1.end()); cout << "s1 = " << s1 << endl; string s2(s0.size(),' '); reverse_copy(s0.begin(),s0.end(),s2.begin()); cout << "s2 = " << s2 << endl; } void test2(){ using namespace std; vector<int> v0{2,0,4,9}; cout << "v0: " ; output(v0); vector<int> v1{v0}; reverse(v1.begin(),v1.end()); cout << "v1: ";output(v1); vector<int> v2{v0}; reverse_copy(v0.begin(),v0.end(),v2.begin()); cout << "v2: ";output(v2); } void test3(){ using namespace std; vector<int> v0{0,1,2,3,4,5,6,7,8,9}; cout << "v0: ";output(v0); vector<int> v1{v0}; rotate(v1.begin(),v1.begin()+1,v1.end()); cout << "v1: "; output(v1); vector<int> v2{v0}; rotate(v2.begin(),v2.begin()+2,v2.end()); cout << "v2: "; output(v2); vector<int> v3{v0}; rotate(v3.begin(),v3.end()-1,v3.end()); cout << "v3: "; output(v3); vector<int> v4{v0}; rotate(v4.begin(),v4.end()-2,v4.end()); cout << "v4: "; output(v4); }
2.实验测试代码运行结果如下:

3.观察与思考:
(1)reverse和reverse_copy就代码参数来看,前者为两个参数,而后者是三个,两者都有共同类型的参数;后者较前者而言多了一个“复制”值对象迭代器的开端;
(2)就功能而言,reverse是将原字符串倒置,而reverse_copy正如英文含义一样,反转后复制给另一个事先准备好的字符串变量;
(3)对于rotate算法,当第二个参数是第一个元素位置时,它是将前n个元素反转后,再整体移动至数据末尾;而当第二个参数是最后一个元素位置时,它是将后n个元素反转后,再整体移动至数据前端;
(4)rotate算法的三个参数中,第一个表示第一个元素的起始位置,第三个表示末尾元素的位置,而第二个参数则表示完成移动后,更新的字符串的第一个元素位置。
任务二:
1.源代码task2.cpp
#include <iostream> #include <vector> #include <algorithm> #include <numeric> #include <iomanip> #include <cstdlib> #include <ctime> template<typename T> void output(const T &c); //int generate_random_number(); void test1(); void test2(); int main(){ std::srand(std::time(0)); std::cout << "测试1:\n"; test1(); std::cout << "\n测试2:\n"; test2(); } template <typename T> void output(const T&c){ for(auto &i:c) std::cout << i << ' '; std::cout << '\n'; } /*int generate_random_number(){ return std::rand() % 101; } */ void test1(){ using namespace std; vector<int> v0(10); //generate(v0.begin(),v0.end(),generate_random_number); //lamda表达式: generate(v0.begin(),v0.end(),[](){return std::rand()%101;}); cout << "v0: ";output(v0); vector<int> v1{v0}; sort(v1.begin(),v1.end()); cout << "v1: ";output(v1); vector<int> v2{v0}; sort(v2.begin()+1,v2.end()-1); cout << "v2: ";output(v2); } void test2(){ using namespace std; vector<int> v0(10); //generate(v0.begin(),v0.end(),generate_random_number); //lamda表达式: generate(v0.begin(),v0.end(),[](){return std::rand()%101;}); cout << "v0: ";output(v0); auto min_iter = min_element(v0.begin(),v0.end()); auto max_iter = max_element(v0.begin(),v0.end()); cout << "最小值:" << *min_iter << endl; cout << "最大值:" << *max_iter << endl; auto ans = minmax_element(v0.begin(),v0.end()); cout << "最小值:" << *(ans.first) << endl; cout << "最大值:" << *(ans.second) << endl; double avg1 = accumulate(v0.begin(),v0.end(),0.0) / v0.size(); cout << "均值:" << fixed << setprecision(2) << avg1 << endl; sort(v0.begin(),v0.end()); double avg2 = accumulate(v0.begin()+1,v0.end()-1,0.0) / v0.size(); cout << "去掉最大值、最小值之后,均值:" << avg2 << endl; }
2.实验测试代码运行结果如下:
(1)使用原代码运行结果:

(2)使用lamda表达式运行结果:
![屏幕截图 2025-10-12 152755]()
3.观察与思考:
(1)generate算法的作用是给创建的动态数组对象填充数据;
(2)一方面,代码量减少;另一方面,不需要增加多余的变量,节省空间;
(3)使用lamda表达式后,逻辑仍然未变。
任务三:
1.源代码task3.cpp
#include <iostream> #include <string> #include <algorithm> #include <cctype> unsigned char func(unsigned char c); void test1(); void test2(); int main(){ std::cout << "测试1:字符串大小写转换\n"; test1(); std::cout << "\n测试2:字符串变换\n"; test2(); } unsigned char func(unsigned char c){ if(c == 'z') return 'a'; if(c == 'Z') return 'A'; if(std::isalpha(c)) return static_cast<unsigned char>(c+1); return c; } void test1(){ std::string s1{"Hello World 2049!"}; std::cout << "s1 = " << s1 << '\n'; std::string s2; for(auto c: s1) s2 += std::tolower(c);//大写->小写 std::cout << "s2 = " << s2 << '\n'; std::string s3; for(auto c: s1) s3 += std::toupper(c);//小写->大写 std::cout << "s3 = " << s3 << '\n'; } void test2(){ std::string s1{"I love cosmos!"}; std::cout << "s1 = " << s1 << '\n'; std::string s2(s1.size(),' '); std::transform(s1.begin(),s1.end(),s2.begin(),func); std::cout << "s2 = " << s2 << '\n'; }
2.实验测试代码运行结果如下:

3.观察与思考:
(1)func的功能为将每个字母转换为按照26字母表的下一位字母;
(2)tolower是将大写字母变为小写字母,toupper是将小写字母变为大写字母;
(3)transform的前两个参数表示原字符串,而三个则表示从新字符串的起始位置开始复制该字符串转换后的串,最后一个则是字符串转换的依据(样式);改变后,相当于不保留原串,把转换的串保存在这个原字符串中。
任务四:
1.源代码task4.cpp
#include <iostream> #include <string> #include <algorithm> bool is_palindrome(const std::string &s); bool is_palindrome_ignore_case(const std::string &s); int main(){ using namespace std; string s; while(cin >> s){//std::getline(cin,s) cout << boolalpha << "区分大小写:" << is_palindrome(s) << "\n" << "不区分大小写:" << is_palindrome_ignore_case(s) << "\n\n"; } } bool is_palindrome(const std::string &s){ for (int i = 0;i < s.size() / 2; i++){ if(s[i] != s[s.size() - i - 1]){ return false; } } return true; } bool is_palindrome_ignore_case(const std::string &s){ for (int i = 0;i < s.size() / 2; i++){ if(std::tolower(s[i])!= std::tolower(s[s.size() - i - 1])){ return false; } } return true; }
2.实验测试代码运行结果如下:

3.观察与思考:
(1)可以使用getline(cin,s)来处理这样的问题。
任务五:
1.源代码task5.cpp
#include <iostream> #include <string> #include <algorithm> std::string dec2n(int x,int n = 2); int main(){ int x; while(std::cin >> x){ std::cout << "十进制:" << x << '\n' << "二进制:" << dec2n(x) << '\n' << "八进制:" << dec2n(x,8) << '\n' << "十二进制:" << dec2n(x,12) << '\n' << "十六进制:" << dec2n(x,16) << '\n' << "三十二进制:" << dec2n(x,32) << "\n\n"; } } std::string dec2n(int x,int n){ if(x == 0) return "0"; if (n < 2 || n > 36) return ""; char stand[36] = {'0','1','2','3','4','5','6','7','8', '9','A','B','C','D','E','F','G', 'H','I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X','Z'}; std::string res = ""; while(x > 0){ res += stand[x % n]; x /= n; } std::reverse(res.begin(),res.end()); return res; }
2.实验测试代码运行结果如下:

任务六:
1.源代码task6.cpp
#include <iostream> #include <string> #include <iomanip> #include <algorithm> int main(){ std::string s{"abcdefghijklmnopqrstuvwxyz"}; std::cout<< std::right << std::setw(2) << " "; for(int i = 0;i < 26; i++){ std::cout << std::right << std::setw(2) << s[i]; s[i] = std::toupper(s[i]); } std::cout << '\n'; for(int i = 1;i <= 26; i++){ std::cout << std::right << std::setw(2) << i; std::rotate(s.begin(),s.begin() + 1,s.end()); for(int j = 0;j < 26; j++){ std::cout << std::right << std::setw(2) << s[j]; } if(i <26) std::cout << '\n'; } }
2.实验测试代码运行结果如下:

任务七:
1.源代码task7.cpp
#include <iostream> #include <iomanip> #include <algorithm> double calculate(int a,int b,char sig){ switch(sig){ case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; default: return 0; } } int main(){ std::srand(std::time(0)); char signal[4] = {'+','-','*','/'}; int cnt = 10,yes = 0; int total = cnt; while(cnt--){ double res; int sig_pos = std::rand() % 4; int fir,sec; double test; bool status = true; while(status){ fir = std::rand() % 11; sec = std::rand() % 11; if((signal[sig_pos] == '-') && (fir >= sec)){ status = false; } if((signal[sig_pos] == '/') && (fir >= sec) && (sec != 0)&& (fir % sec == 0)){ status = false; } if((signal[sig_pos] != '-' ) && (signal[sig_pos] != '/')){ status = false; } } std::cout << fir << " " << signal[sig_pos] << " " << sec << " = "; std::cin >> res; test = calculate(fir,sec,signal[sig_pos]); if(res == test) yes++; } std::cout << "正确率:" << std::fixed << std::setprecision(2) << 1.0 * yes / total * 100 << "%" << std::endl; }
2.实验测试代码运行结果如下:


总结:
通过此次实验,我了解了许多c++自带标准库组件,并且能够较为熟练的掌握,体会到了其便捷性,但是仍然有一些不懂的地方,例如对于迭代器的理解,以及随机种子对于随机数生成的影响。


浙公网安备 33010602011771号