实验1 现代C++编程初体验
实验任务 1 验证性实验
在C++编码环境中,输入、运行并观察以下代码,结合运行结果和注释,体验使用C++标准库进行编程的便捷性。从面 向对象编程范式的角度,体会封装与基于接口编程的意义。

1 #include <iostream> 2 #include <string> 3 #include <vector> 4 #include <algorithm> 5 template<typename T> 6 void output(const T &c); 7 void test1(); 8 void test2(); 9 void test3(); 10 int main() { 11 std::cout << "测试1: \n"; 12 test1(); 13 14 std::cout << "\n测试2: \n"; 15 test2(); 16 17 std::cout << "\n测试3: \n"; 18 test3(); 19 } 20 21 template <typename T> 22 void output(const T &c) { 23 for(auto &i : c) 24 std::cout << 25 i << ' '; 26 std::cout << '\n'; 27 } 28 void test1() { 29 using namespace std; 30 31 string s0{"0123456789"}; 32 cout << "s0 = " << s0 << endl; 33 34 string s1(s0); 35 reverse(s1.begin(), s1.end()); 36 cout << "s1 = " << s1 << endl; 37 38 string s2(s0.size(), ' '); 39 reverse_copy(s0.begin(), s0.end(), s2.begin()); 40 cout << "s2 = " << s2 << endl; 41 } 42 43 void test2() { 44 using namespace std; 45 46 vector<int> v0{2, 0, 4, 9}; 47 cout << "v0: "; output(v0); 48 49 vector<int> v1(v0); 50 reverse(v1.begin(), v1.end()); 51 cout << "v1: "; output(v1); 52 53 vector<int> v2(v0); 54 reverse_copy(v0.begin(), v0.end(), v2.begin()); 55 cout << "v2: "; output(v2); 56 } 57 58 void test3() { 59 using namespace std; 60 61 vector<int> v0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 62 cout << "v0: "; output(v0); 63 64 vector<int> v1(v0); 65 rotate(v1.begin(), v1.begin()+1, v1.end()); 66 cout << "v1: "; output(v1); 67 68 vector<int> v2(v0); 69 rotate(v2.begin(), v2.begin()+2, v2.end()); 70 cout << "v2: "; output(v2); 71 72 vector<int> v3(v0); 73 rotate(v3.begin(), v3.end()-1, v3.end()); 74 cout << "v3: "; output(v3); 75 76 vector<int> v4(v0); 77 rotate(v4.begin(), v4.end()-2, v4.end()); 78 cout << "v4: "; output(v4); 79 }
1. reverse 和 reverse_copy 有什么区别?
reverse 是直接反转原容器的元素顺序,会修改原容器。
2.rotate 算法是如何改变元素顺序的?它的三个参数分别代表什么?
reverse_copy 是将原容器反转后的结果拷贝到另一个容器,原容器保持不变。
实验任务 2 验证性实验
在C++编码环境中,输入、运行并观察以下代码,体验使用C++标准库高效完成数据赋值、排序和基本统计。

#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(); } // 输出容器对象c中的元素 template <typename T> void output(const T &c) { for(auto &i: c) std::cout << i << ' '; std::cout << '\n'; } // 返回[0, 100]区间内的一个随机整数 int generate_random_number() { return std::rand() % 101; } // 测试1:对容器类对象指定迭代器区间赋值、排序 void test1() { using namespace std; vector<int> v0(10); // 创建一个动态数组对象v0, 对象大小为10 generate(v0.begin(), v0.end(), generate_random_number); // 生成随机数填充v0 cout << "v0: "; output(v0); vector<int> v1{v0}; sort(v1.begin(), v1.end()); // 对整个vector排序 cout << "v1: "; output(v1); vector<int> v2{v0}; sort(v2.begin()+1, v2.end()-1); // 只对中间部分排序,不包含首尾元素 cout << "v2: "; output(v2); } // 测试2:对容器类对象指定迭代器区间赋值、计算最大值/最小值/均值 void test2() { using namespace std; vector<int> v0(10); generate(v0.begin(), v0.end(), generate_random_number); 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
1. generate 算法的作用是什么
generate函数规定了动态数组的头尾位置,再对数组中的元素批量赋值,赋值的规则由generate函数中的第三个参数确定。
2.minmax_element 和分别调用 min_element 、 把代码中函数 max_element 相比,有什么优势?
minmax_element函数与分别调用min_element、max_element相比,前者可以一次性将最大值最小值分别计算好,空间上只要一个而非两个辅助变量即可。
3.把代码中函数 max_element 相比,有什么优势? generate_random_number 的声明(line13)和定义(line35-37)注释起来,把两处调用改成如 下写法,观察效果是否等同?查阅c++中lambda表达式用法。
// test1()模块和test2()模块: generate(v0.begin(), v0.end(), generate_random_number); ---->改成 generate(v0.begin(), v0.end(), [](){return std::rand()%101;});
两者功能相同,都是生成 [0, 100] 的随机整数。lambda表达式用法如下
实验任务 3 验证性实验
在C++编码环境中,输入、运行并观察以下代码,体验使用C++标准库高效完成字符串变换操作。

#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'; }
1. 自定义函数func功能是什么?
此处自定义函数 func 的功能是仅将字母字符进行后移一位的变换,对于特殊情况规定了'z'→'a'和'Z'→'A',非字母字符保持原样。
2.tolower和toupper功能分别是什么?
tolower的功能是将大写字母字符变为小写字母,非大写字母字符保持原样;toupper的功能是将小写字母字符变为大写字母,非小写字母字符保持原样。
3.transform的4个参数意义分别是什么?如果把第3个参数s2.begin()改成s1.begin(),有何区别?
第一个参数:原始序列的起始位置;
第二个参数:原始序列的终止位置;
第三个参数:新序列从原始序列中开始执行的位置;
第四个参数:序列变换时附加的规则。
如果把第3个参数 s2.begin() 改成 s1.begin() ,其区别在于变换会在原始容器内部执行,使原序列发生变化。
实验任务 4
编写函数,实现判断回文串。是返回true,否则,返回false。
在main函数中调用,输入字符串,调用其判断,输出结果。要求支持多组输入。
严格区分大小写:bool is_palindrome(const std::string &s)
不区分大小写:bool is_palindrome_ignore_case(const std::string &s);

#include <iostream> #include <string> #include <algorithm> #include <cctype> 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) { cout << boolalpha << "区分大小写:" << is_palindrome(s) << "\n" << "不区分大小写:" << is_palindrome_ignore_case(s) << "\n\n"; } } // 以下两个函数需要补全 bool is_palindrome(const std::string &s) { using namespace std; string t=s; reverse(t.begin(),t.end()) ; if(t.compare(s)==0){ return true; } else{ return false; } } bool is_palindrome_ignore_case(const std::string &s) { using namespace std; string t=s,s0; for(auto i : s){ s0+=tolower(i); } reverse(t.begin(),t.end()) ; string t0; for(auto i : t){ t0+=tolower(i); } if(t0.compare(s0)==0){ return true; } else{ return false;
1.使用cin >> s输入时,输入的字符串中不能包含空格。如果希望测试字符串包含空格(如hello oop),代码应如 何调整?
如果希望测试字符串包含空格(如 hello oop ),可以先用get函数确认输入是否包含空格。若无,则沿用原程序;若有,则将空格以外的元素依次存到新容器中,再沿用原程序做回文判断。
实验任务 5
编写程序实现进制转换。具体要求如下: 编写函数std::string dec2n(x, n)实现把一个十进制数x转换成n进制,结果以字符串形式返回。如果第2 个参数没有指定,默认转换成二进制。(本次实验,限定参数n取值区间为[2, 36],限定参数x >= 0)
当n = 17,即17进制时,基数是0-9, A-G
当n = 18,即18进制时,基数是0-9, A-H
依次类推:
当n = 36, 即36进制时,基数是0-9, A-Z (即:10 -> A, 11->B, 12->C, …, 35->Z)
在main函数中,输入十进制整数,调用函数dec2n得到转换成指定进制的字符串,输出。要求支持多组输入。

#include<iostream> #include<vector> #include<iomanip> #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'; } } std::string dec2n(int x,int n) { std::string result; int rem; if(x==0) return "0"; while(x>0) { rem=x%n; char a; if(rem<10) a='0'+rem; else a='A'+rem-10; result.push_back(a); x=x/n; } reverse(result.begin(),result.end()); return result; }
实验任务 6
编写程序,在屏幕上打印字母密文对照表。

#include <iostream> #include <iomanip> #include <string> #include <algorithm> using namespace std; int main() { string lowercase = "a b c d e f g h i j k l m n o p q r s t u v w x y z "; string uppercase = "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z "; cout << " " << lowercase.substr(0, lowercase.length() - 1) << endl; for (int i = 1; i <= 26; i++) { cout << setw(2) << i << " "; rotate(uppercase.begin(), uppercase.begin() + 2, uppercase.end()); cout << uppercase.substr(0, uppercase.length() - 1) << endl; } return 0; }
实验任务 7
编写一个程序,实现自动生成小学生算术运算题目并自动评测。具体要求如下:
程序运行后,自动生成10道10以内的算术运算题。
运算式(包括=)在程序运行时自动生成。
运算式=右侧的答案由用户输入
算术运算包括:加、减、乘、除。生成题目时,运算随机。
两个操作数限制在[1, 10]区间内的整数。
题目是减法运算时,要求第一个操作数>=第二个操作数。
题目是除法运算时,要求第一个操作数能整除第二个操作数整除。
用户完成10道测试后,屏幕给出正确率,要求以百分号形式输出,保留小数点后两位。
多次运行程序时,每次生成的题目与上次不同。(Tips: 使用 srand(time(0)) 作为随机种子)
程序正确编写后,预期测试效果如下:(截图中给了两次运行测试效果)。

1 #include<iostream> 2 #include<cstdlib> 3 #include<ctime> 4 #include<cmath> 5 #include<iomanip> 6 using namespace std; 7 // 生成随机运算符(+、-、*、/) 8 char getRandomOp() { 9 int op = rand() % 4; 10 if (op == 0) return '+'; 11 else if (op == 1) return '-'; 12 else if (op == 2) return '*'; 13 else return '/'; 14 } 15 // 生成随机操作数(1-10) 16 int getRandomNum() { 17 return rand() % 10 + 1; 18 } 19 int main() { 20 srand(time(0)); // 设置随机种子,确保每次题目不同 21 int correct = 0; 22 for (int i = 0; i < 10; i++) { 23 int a = getRandomNum(); 24 int b = getRandomNum(); 25 char op = getRandomOp(); 26 int result; 27 28 // 处理减法:保证a >= b 29 if (op == '-') { 30 result = a - b; 31 } 32 // 处理除法:保证a能被b整除 33 else if (op == '/') { 34 while (a % b != 0) { 35 a = getRandomNum(); 36 b = getRandomNum(); 37 } 38 result = a / b; 39 } 40 // 处理加法和乘法 41 else if (op == '+') { 42 result = a + b; 43 } else { 44 result = a * b; 45 } 46 // 输出题目并获取用户答案 47 cout << a << " " << op << " " << b << " = "; 48 int userAns; 49 cin >> userAns; 50 // 判断答案是否正确 51 if (userAns == result) { 52 correct++; 53 } 54 } 55 // 计算并输出正确率 56 double accuracy = (double)correct / 10 * 100; 57 cout << "正确率:" << fixed << setprecision(2) << accuracy << "%" << endl; 58 59 return 0; 60 }
实验总结
1.在本次实验中,深入理解了C++中字符串输入的特性。在算法功能上,明确了 reverse 、 reverse_copy 、 rotate 、 generate 、 minmax_element 、 transform 等算法的具体作用。
2.通过对比 cin >> s 和 getline 的使用场景,明确了 cin >> s 会以空格作为输入结束的分隔符,而当需要输入包含空格的字符串时, getline(cin, s) 是更合适的选择。