实验四 现代c++ 标准库与类的模板

发布时间 2023-11-30 22:53:39作者: 小程夏天

1.普通数组、array、vector的相关性,以及,区别

相关性

存储多个元素:
1. 普通数组: 使用 C 风格数组声明和定义,大小固定。
2. array: 是 C++11 引入的标准库容器,提供了数组的替代,大小固定。
3. vector: 是 C++ 标准库中的动态数组,大小可以动态调整。

元素访问:
1. 普通数组和array: 使用索引进行元素访问,支持随机访问。
2. vector: 也支持随机访问,但由于其动态性,访问元素时可能涉及到额外的性能开销。

内存管理:
1. 普通数组: 需要手动管理内存。
2. array: 不需要手动管理内存,大小固定。
3. vector: 不需要手动管理内存,大小可变。

 

实验中也可以发现,vector通常根据你存的大小分配2^n的内存空间确保足够存储切留有空余

区别

大小是否固定:
1. 普通数组: 大小固定。
2. array: 大小固定,提供了更多的成员函数和类型安全。
3. vector: 大小可变。

成员函数和类型安全:
1. 普通数组: 基本数组,仅支持数组的基本操作。
2. array: 提供了成员函数,如 `at()` 和 `front()`,并在编译时进行类型安全检查。
3. vector: 提供了丰富的成员函数,但在运行时执行类型安全检查。

内存分配方式:
1. 普通数组: 在栈上分配内存。
2. array: 在栈上分配内存,大小固定。
3. vector: 在堆上分配内存,大小可变。

这里两种方式的区别是

  • 在栈上分配内存:

  • 适用于相对较小的、生命周期短暂的局部变量。
  • 自动管理生命周期,不需要显式释放。
  • 在堆上分配内存:

  • 适用于较大的数据结构、需要长时间存活的对象、动态数据结构等。
  • 需要程序员显式管理内存的生命周期,避免内存泄漏。

灵活性和性能:
1. 普通数组和array: 大小在编译时确定,具有较高的性能。
2. vector: 大小在运行时确定,具有更大的灵活性,但可能涉及性能开销。

 

迭代器与指针相关性,以及,区别

 

  1. 抽象级别:

    • 指针: 是一种直接操作内存地址的低级别工具,常用于 C 语言等。
    • 迭代器: 是 C++ 中的一种高级抽象,提供了更丰富的接口,适用于各种数据结构。
  2. 语法:

    • 指针: 使用 运算符来解引用,可以直接对指针进行算术运算。
    • 迭代器: 通常通过 来解引用,提供了更高层次的抽象,不一定支持指针的所有算术运算。
  3. 泛型性:

    • 指针: 不具备泛型性,通常与具体的数据类型关联。
    • 迭代器: 是泛型的,可以适用于不同类型的容器,提供了一致的接口。
  4. 容器访问:

    • 指针: 不天然支持容器的直接访问。
    • 迭代器: 是容器的一部分,可以通过容器提供的 和 等函数获取迭代器。begin()end()

这里给出ai写的一些代码方便理解复习

 

相互转换:

指针和迭代器之间可以进行相互转换:
cpp

Copy code
int arr[] = {1, 2, 3, 4};
int* ptr = arr;
std::vector<int> vec(arr, arr + 4);
std::vector<int>::iterator it = vec.begin();
int* ptr_from_iterator = &(*it);
函数参数:

函数参数中可以接受指针或迭代器:
cpp
Copy code
void processArray(int* begin, int* end) {
    // Process elements in the range [begin, end)
}

void processVector(std::vector<int>::iterator begin, std::vector<int>::iterator end) {
    // Process elements in the range [begin, end)
}
遍历:

在循环中使用指针或迭代器进行遍历:
cpp
Copy code
int arr[] = {1, 2, 3, 4};
for (int* ptr = arr; ptr < arr + 4; ++ptr) {
    // Process each element using the pointer
}

std::vector<int> vec = {1, 2, 3, 4};
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
    // Process each element using the iterator
}
View Code

 

 

C风格字符串和string类型区别

 

C 风格字符串:

  1. 存储方式:

    • C 风格字符串: 使用字符数组( 数组)来存储字符串。字符串的结束由 null 字符()标志。
    • C++ 中的 std::string: 使用动态分配的内存来存储字符串,而不需要显式地处理字符串的结束标志。
  2. 内存管理:

    • C 风格字符串: 需要手动分配和释放内存,开发者负责确保字符数组足够大,防止溢出。
    • C++ 中的 string: 内存管理由 类自动处理,无需手动分配或释放内存。 会动态调整大小,更加方便和安全。
  3. 长度信息:

    • C 风格字符串: 长度信息通常由字符串结束的 null 字符来表示,需要使用 等函数来获取长度。strlen
    • C++ 中的 std::string: 类型内部包含了字符串的长度信息,可以使用 或 成员函数获取长度。std::stringsize()length()
  4. 字符串拼接:

    • C 风格字符串: 需要使用 等函数进行字符串拼接。strcat
    • C++ 中的 std::string: 可以直接使用 运算符或 成员函数来进行字符串拼接。+append
  5. 字符串操作:

    • C 风格字符串: 需要使用一系列函数如 、、 等进行字符串操作。strcmpstrcpystrncpy
    • C++ 中的 std::string: 提供了丰富的成员函数,如 、、、 等,方便进行各种字符串操作。findsubstrerasereplace
  6. 编译时类型:

    • C 风格字符串: 字符数组是原始的 C 数据类型,不具备面向对象的特性。
    • C++ 中的 std::string: 是一个类,具有面向对象的封装和功能。

总体而言,C++ 中的 提供了更加安全和方便的字符串处理方式,免去了手动内存管理和数组越界等问题。

 
 
实验任务五
#include <iostream>
#include <string>
#pragma once 
using namespace std;

class TextCoder {
private:
    string text;

    void encoder();

    void decoder();

public:
    TextCoder(const string &Text);

    string get_ciphertext();

    string get_deciphertext();
};

TextCoder::TextCoder(const string &Text) : text{Text} {}

void TextCoder::encoder() {
    for (char &ch : text) {
        if (isalpha(ch))//判断是否是字符 
         {
            char base = islower(ch) ? 'a' : 'A';
            ch = (ch - base + 7) % 26 + base;
        }
    }
}

void TextCoder::decoder() {
        for (char &ch : text) {
            if (isalpha(ch)) {
                char base = isupper(ch)?'A':'a';
                ch = (ch - base + 26 - 7) % 26 + base;
            }
        }
    }

string TextCoder::get_ciphertext() {
    encoder();
    return text;
}

string TextCoder::get_deciphertext() {
    decoder();
    return text;
}
View Code
#include "textcoder.hpp"
#include <iostream>
#include <string>

void test() {
    using namespace std;

    string text, encoded_text, decoded_text;

    cout << "输入英文文本: ";
    while (getline(cin, text)) {
        encoded_text = TextCoder(text).get_ciphertext();  // 这里使用的是临时无名对象
        cout << "加密后英文文本:\t" << encoded_text << endl;

        decoded_text = TextCoder(encoded_text).get_deciphertext(); // 这里使用的是临时无名对象
        cout << "解密后英文文本:\t" << decoded_text << endl;
        cout << "\n输入英文文本: ";
    }
}

int main() {  
    test(); 
}
View Code

 实验任务六

 

#include <iostream>
#include <vector>
#include <string>

using namespace std;

class Info {
private:
    string nickname;
    string contact;
    string city;
    int n;

public:
    Info(const string &nickname, const string &contact, const string &city, int n)
        : nickname(nickname), contact(contact), city(city), n(n) {} 

    void output() const {
        cout << "昵称:        " << nickname << endl;
        cout << "联系方式:    " << contact << endl;
        cout << "所在城市:    " << city << endl;
        cout << "预定人数:    " << n << endl<<endl;

    }
};

int main() {
    const int limitsum = 100;//const常量安全性  
    vector<Info> audience_info_list;

    cout << "录入信息:" << endl << endl;
    cout << "昵称         联系方式(邮箱/手机号)      所在城市    预约参加人数" << endl;

    int totalNumber = 0; 

    while (1) {
        string nickname, contact, city;
        int n;
        if (!(cin >> nickname >> contact >> city >> n)) 
        {
            break; //ctrl+z退出循环 
        }

        if (n <= 0) {
            cout << "预定参加人数必须大于0,请重新输入。\n";
            continue;
        }

        if (n > limitsum) {
            char choice;
            cout << "对不起,只剩" << limitsum - totalNumber << "个名额。" << endl;
            cout << "1.输入 u,更新(update)预定信息" << endl;
            cout << "2.输入 q,退出预定" << endl;
            cout << "你的选择:";
            cin >> choice;
            cout<<endl; 

            if (choice == 'q') {
                break; 
            } else if (choice == 'u') {
                cout << "请重新输入信息:\n";
                continue;
            }
        }

        totalNumber += n;
        audience_info_list.emplace_back(nickname, contact, city, n);
        //.emplace_back()从尾部直接构造对象,而不需要用push_back把一个个对象构造出来再插入,
        //避免拷贝更加高效 
    }

    cout << "截止目前,一共有" << totalNumber << "位预约人数预定参加。预定听众信息如下:" << endl;

    for (const auto &info : audience_info_list) {
        info.output();
    }
    //迭代器遍历输出 
}
View Code

 

 

 

 

前四个验证性实验体会

1.了解到了getline函数的使用方法和场景

2.了解到了清楚缓冲区的操作,优点和用处实验例子中给的是为了在cin之后回车键(换行符)会留在输入缓冲区中。接着,使用 getline(cin, s1); 读取一行字符串,如果输入缓冲区中有残留的换行符,getline 可能会立即读取到这个换行符,导致用户无法输入。也就是说,getline 可能在没有输入的情况下直接结束,因为它会读取到留在输入缓冲区中的换行符。

3.了解到了string类里面的许多个成员函数以及cctype内的函数如(isupper(),islower(),isalpha(),isdigit(),tolower(),toupper())

其中有一些注意事项比如,string和vector .end()返回位置是end后一位的迭代器,很多函数跟随着遵循相同的左闭右开的格式,比如.substr(),和遍历数组的时候迭代器循环同样也是。

4.了解了标准库中string和int和double相互转化的函数。