实验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

image

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
实验任务2

image

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表达式用法如下

image

 实验任务 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';
}
实验任务3

image

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;
实验任务4

image

 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;
}
实验任务5

image

 实验任务 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;
}
实验任务6

image

 实验任务 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  }
实验任务7

image

 

image

 实验总结

1.在本次实验中,深入理解了C++中字符串输入的特性。在算法功能上,明确了 reverse 、 reverse_copy 、 rotate 、 generate 、 minmax_element 、 transform 等算法的具体作用。

2.通过对比 cin >> s 和 getline 的使用场景,明确了 cin >> s 会以空格作为输入结束的分隔符,而当需要输入包含空格的字符串时, getline(cin, s) 是更合适的选择。

posted @ 2025-10-18 01:10  沉睡的余数  阅读(10)  评论(1)    收藏  举报