实验1 现代C++编程初体验
实验任务1:
源代码:
1 // 现代C++标准库、算法库体验 2 // 本例用到以下内容: 3 // 1. 字符串string, 动态数组容器类vector、迭代器 4 // 2. 算法库:反转元素次序、旋转元素 5 // 3. 函数模板、const引用作为形参 6 #include <iostream> 7 #include <string> 8 #include <vector> 9 #include <algorithm> 10 // 模板函数声明 11 template<typename T> 12 void output(const T &c); 13 void test1(); 14 void test2(); 15 void test3(); 16 int main() { 17 std::cout << "测试1: \n"; 18 test1(); 19 std::cout << "\n测试2: \n"; 20 test2(); 21 std::cout << "\n测试3: \n"; 22 test3(); 23 } 24 // 输出容器对象c中的元素 25 template <typename T> 26 void output(const T &c) { 27 for(auto &i : c) 28 std::cout << i << ' '; 29 std::cout << '\n'; 30 } 31 // 测试1:组合使用算法库、迭代器、string反转字符串 32 void test1() { 33 using namespace std; 34 string s0{"0123456789"}; 35 cout << "s0 = " << s0 << endl; 36 string s1(s0); 37 // 反转s1自身 38 reverse(s1.begin(), s1.end()); 39 cout << "s1 = " << s1 << endl; 40 string s2(s0.size(), ' '); 41 // 将s0反转后结果拷贝到s2, s0自身不变 42 reverse_copy(s0.begin(), s0.end(), s2.begin()); 43 cout << "s2 = " << s2 << endl; 44 } 45 // 测试2:组合使用算法库、迭代器、vector反转动态数组对象vector内数据 46 void test2() { 47 using namespace std; 48 vector<int> v0{2, 0, 4, 9}; 49 cout << "v0: "; output(v0); 50 vector<int> v1{v0}; 51 reverse(v1.begin(), v1.end()); 52 cout << "v1: "; output(v1); 53 vector<int> v2{v0}; 54 reverse_copy(v0.begin(), v0.end(), v2.begin()); 55 cout << "v2: "; output(v2); 56 } 57 // 测试3:组合使用算法库、迭代器、vector实现元素旋转移位 58 void test3() { 59 using namespace std; 60 vector<int> v0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 61 cout << "v0: "; output(v0); 62 vector<int> v1{v0}; 63 // 将[v1.begin(), v1.end())区间内元素循环左移1位 64 rotate(v1.begin(), v1.begin()+1, v1.end()); 65 cout << "v1: "; output(v1); 66 vector<int> v2{v0}; 67 // 将[v1.begin(), v1.end())区间内元素循环左移2位 68 rotate(v2.begin(), v2.begin()+2, v2.end()); 69 cout << "v2: "; output(v2); 70 vector<int> v3{v0}; 71 // 将[v1.begin(), v1.end())区间内元素循环右移1位 72 rotate(v3.begin(), v3.end()-1, v3.end()); 73 cout << "v3: "; output(v3); 74 vector<int> v4{v0}; 75 // 将[v1.begin(), v1.end())区间内元素循环右移2位 76 rotate(v4.begin(), v4.end()-2, v4.end()); 77 cout << "v4: "; output(v4); 78 }
运行测试截图:

观察与思考:
1.reverse 和 reverse_copy 有什么区别?
答:
reverse 会直接在原序列上进行反转操作,修改原容器内容。
reverse_copy 则会把反转后的结果复制到另一个容器中,原容器保持不变。
2.rotate 算法是如何改变元素顺序的?它的三个参数分别代表什么?
答:rotate 通过“旋转”区间内的元素实现整体左移或右移。
实验任务2:
源代码:
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 #include <numeric> 5 #include <iomanip> 6 #include <cstdlib> 7 #include <ctime> 8 // 模板函数声明 9 template<typename T> 10 void output(const T &c); 11 int generate_random_number(); 12 void test1(); 13 void test2(); 14 int main() { 15 std::srand(std::time(0)); 16 std::cout << "测试1: \n"; 17 test1(); 18 // 添加随机种子 19 std::cout << "\n测试2: \n"; 20 test2(); 21 } 22 // 输出容器对象c中的元素 23 template <typename T> 24 void output(const T &c) { 25 for(auto &i: c) 26 std::cout << i << ' '; 27 std::cout << '\n'; 28 } 29 // 返回[0, 100]区间内的一个随机整数 30 int generate_random_number() { 31 return std::rand() % 101; 32 } 33 // 测试1:对容器类对象指定迭代器区间赋值、排序 34 void test1() { 35 using namespace std; 36 vector<int> v0(10); // 创建一个动态数组对象v0, 对象大小为10 37 generate(v0.begin(), v0.end(), generate_random_number); // 生成随机数填充v0 38 cout << "v0: "; output(v0); 39 vector<int> v1{v0}; 40 sort(v1.begin(), v1.end()); // 对整个vector排序 41 cout << "v1: "; output(v1); 42 vector<int> v2{v0}; 43 sort(v2.begin()+1, v2.end()-1); // 只对中间部分排序,不包含首尾元素 44 cout << "v2: "; output(v2); 45 } 46 // 测试2:对容器类对象指定迭代器区间赋值、计算最大值/最小值/均值 47 void test2() { 48 using namespace std; 49 vector<int> v0(10); 50 generate(v0.begin(), v0.end(), generate_random_number); 51 cout << "v0: "; output(v0); 52 // 求最大值和最小值 53 auto min_iter = min_element(v0.begin(), v0.end()); 54 auto max_iter = max_element(v0.begin(), v0.end()); 55 cout << "最小值: " << *min_iter << endl; 56 cout << "最大值: " << *max_iter << endl; 57 // 同时求最大值和最小值 58 auto ans = minmax_element(v0.begin(), v0.end()); 59 cout << "最小值: " << *(ans.first) << endl; 60 cout << "最大值: " << *(ans.second) << endl; 61 62 // 求平均值 63 double avg1 = accumulate(v0.begin(), v0.end(), 0.0) / v0.size(); 64 cout << "均值: " << fixed << setprecision(2) << avg1 << endl; 65 sort(v0.begin(), v0.end()); 66 double avg2 = accumulate(v0.begin()+1, v0.end()-1, 0.0) / (v0.size()-2); 67 cout << "去掉最大值、最小值之后,均值: " << avg2 << endl; 68 }
运行测试截图:

观察与思考:
1.generate 算法的作用是什么?
答:generate 可以批量为区间中的每个元素赋值,通过调用一个生成函数(或 lambda 表达式)产生数据。
2.minmax_element 和分别调用 min_element 、 max_element 相比,有什么优势?
答:minmax_element 只需一次遍历即可同时找到最小值与最大值,效率更高,而单独调用 min_element 与 max_element 需要遍历两次。
3.把代码中函数generate_random_number 的声明(line13)和定义(line35-37)注释起来,把两处调用改成如下写法,观察效果是否等同?查阅c++中lambda表达式用法。
1 // test1()模块和test2()模块: 2 generate(v0.begin(), v0.end(), generate_random_number); 3 ---->改成 4 generate(v0.begin(), v0.end(), [](){return std::rand()%101;});
答:不等同。
实验任务3:
源代码:
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <cctype> 5 unsigned char func(unsigned char c); 6 void test1(); 7 void test2(); 8 int main() { 9 std::cout << "测试1: 字符串大小写转换\n"; 10 test1(); 11 std::cout << "\n测试2: 字符变换\n"; 12 test2(); 13 } 14 unsigned char func(unsigned char c) { 15 if(c == 'z') 16 return 'a'; 17 if(c == 'Z') 18 return 'A'; 19 if(std::isalpha(c)) 20 return static_cast<unsigned char>(c+1); 21 return c; 22 } 23 void test1() { 24 std::string s1{"Hello World 2049!"}; 25 std::cout << "s1 = " << s1 << '\n'; 26 std::string s2; 27 for(auto c: s1) 28 s2 += std::tolower(c); 29 std::cout << "s2 = " << s2 << '\n'; 30 std::string s3; 31 for(auto c: s1) 32 s3 += std::toupper(c); 33 std::cout << "s3 = " << s3 << '\n'; 34 } 35 void test2() { 36 std::string s1{"I love cosmos!"}; 37 std::cout << "s1 = " << s1 << '\n'; 38 std::string s2(s1.size(), ' '); 39 std::transform(s1.begin(), s1.end(), 40 s2.begin(), 41 func); 42 std::cout << "s2 = " << s2 << '\n'; 43 }
运行测试截图:

观察与思考:
1.自定义函数func功能是什么?
答:func 用于将输入字符循环加一。
若是 'z' → 'a','Z' → 'A';
若是字母则顺序加一(如 'b'→'c');
其他字符(空格、符号等)保持不变。
2.tolower和toupper功能分别是什么?
答:tolower 将大写字母转换为小写字母,toupper 将小写字母转换为大写字母。
3.transform的4个参数意义分别是什么?如果把第3个参数s2.begin()改成s1.begin(),有何区别?
答:
参数依次为:
① 输入区间起点;② 输入区间终点;③ 输出区间起点;④ 转换函数。
若将第 3 个参数改为 s1.begin(),则会在原字符串上原地修改,而不是将结果写入新的字符串。
实验任务4
源代码:
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <cctype> 5 using namespace std; 6 7 bool is_palindrome(const string &s) { 8 string t = s; 9 reverse(t.begin(), t.end()); 10 return s == t; 11 } 12 13 bool is_palindrome_ignore_case(const string &s) { 14 string t1 = s, t2 = s; 15 transform(t1.begin(), t1.end(), t1.begin(), 16 [](unsigned char c){ return tolower(c); }); 17 reverse(t2.begin(), t2.end()); 18 transform(t2.begin(), t2.end(), t2.begin(), 19 [](unsigned char c){ return tolower(c); }); 20 return t1 == t2; 21 } 22 23 int main() { 24 using namespace std; 25 string s; 26 // 多组输入,直到按下Ctrl+Z结束测试 27 while(cin >> s) { 28 cout << boolalpha 29 << "区分大小写: " << is_palindrome(s) << "\n" 30 << "不区分大小写: " << is_palindrome_ignore_case(s) << "\n\n"; 31 } 32 }
运行测试截图:

观察与思考:
使用cin >> s输入时,输入的字符串中不能包含空格。如果希望测试字符串包含空格(如hello oop),代码应如何调整?
答:使用getline(cin, s); 这样可以读取整行内容,包括空格。
实验任务5
源代码:
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 using namespace std; 5 6 string dec2n(int x, int n = 2) { 7 const string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 8 if (x == 0) return "0"; 9 string result; 10 while (x > 0) { 11 result += digits[x % n]; 12 x /= n; 13 } 14 reverse(result.begin(), result.end()); 15 return result; 16 } 17 18 int main() { 19 int x; 20 while (cin >> x) { 21 cout << "十进制: " << x << '\n' 22 << "二进制: " << dec2n(x) << '\n' 23 << "八进制: " << dec2n(x, 8) << '\n' 24 << "十二进制: " << dec2n(x, 12) << '\n' 25 << "十六进制: " << dec2n(x, 16) << '\n' 26 << "三十二进制: " << dec2n(x, 32) << "\n\n"; 27 } 28 }
运行测试截图:

实验任务6
源代码:
1 #include <iostream> 2 #include <iomanip> 3 using namespace std; 4 5 int main() { 6 // 打印表头(小写 a-z) 7 cout << " "; 8 for (char c = 'a'; c <= 'z'; ++c) { 9 cout << setw(2) << c; 10 } 11 cout << '\n'; 12 13 14 for (int i = 1; i <= 26; ++i) { 15 cout << setw(2) << i << " "; 16 for (int j = 0; j < 26; ++j) { 17 // 列索引 j 对应字母 'a'+j 18 // 移位为 i,所以使用 (j + i) % 26 19 char ch = 'A' + ( (j + i) % 26 ); 20 cout << setw(2) << ch; 21 } 22 cout << '\n'; 23 } 24 25 return 0; 26 }
运行测试截图:

实验任务7
源代码:
1 #include <iostream> 2 #include <cstdlib> 3 #include <ctime> 4 #include <iomanip> 5 6 // 生成[min, max]区间的随机整数 7 int getRandomInt(int min, int max) { 8 return rand() % (max - min + 1) + min; 9 } 10 11 int main() { 12 // 设置随机种子,确保每次题目不同 13 srand(static_cast<unsigned int>(time(0))); 14 const int totalQuestions = 10; 15 int correctCount = 0; 16 17 std::cout << "===== 小学生算术测试(共" << totalQuestions << "题)=====\n"; 18 for (int i = 1; i <= totalQuestions; ++i) { 19 int a, b, correctAns, userAns; 20 char op; 21 22 // 循环生成合法题目 23 while (true) { 24 a = getRandomInt(1, 10); 25 b = getRandomInt(1, 10); 26 int opType = rand() % 4; // 0:加, 1:减, 2:乘, 3:除 27 28 if (opType == 0) { 29 op = '+'; 30 correctAns = a + b; 31 break; 32 } else if (opType == 1) { 33 op = '-'; 34 if (a >= b) { 35 correctAns = a - b; 36 break; 37 } 38 } else if (opType == 2) { 39 op = '*'; 40 correctAns = a * b; 41 break; 42 } else { 43 op = '/'; 44 if (a % b == 0) { 45 correctAns = a / b; 46 break; 47 } 48 } 49 } 50 51 // 输出题目并获取用户答案 52 std::cout << a << " " << op << " " << b << " = "; 53 std::cin >> userAns; 54 55 // 判断答案并统计正确数 56 if (userAns == correctAns) { 57 correctCount++; 58 } 59 } 60 61 // 计算并输出正确率 62 double accuracy = static_cast<double>(correctCount) / totalQuestions * 100; 63 std::cout << "\n===== 测试结束 =====\n"; 64 std::cout << "正确率: " << std::fixed << std::setprecision(2) << accuracy << "%\n"; 65 66 return 0; 67 }
运行测试截图:

浙公网安备 33010602011771号