当前位置:首页 » 《关于电脑》 » 正文

【C++】string 类模拟实现:深入探索字符串操作原理

8 人参与  2024年11月02日 08:02  分类 : 《关于电脑》  评论

点击全文阅读


 快来参与讨论?,点赞?、收藏⭐、分享?,共创活力社区。 

?在之前的文章中我们学会了对string类函数的使用,现在让我们对其进行模拟实现吧~?


目录

?引言

?string 类的功能需求分析

?模拟实现的关键步骤和代码解析

1.类的定义

2.构造函数实现

2.1 默认构造函数 

2.2 用 C 风格字符串初始化的构造函数

2.3 拷贝构造函数

3. 析构函数实现

4.获取字符串长度函数

5.字符串比较函数

 6.字符串连接函数

7.字符串插入函数

 8.字符串删除函数

9.字符串加法操作符重载

10.下标操作符重载

11.赋值操作符重载

?内存管理相关函数(如reserve和resize)

1.reserve函数

 2.resize函数

?示例用法

?总结


?引言

在 C++ 编程中,字符串处理很常见且重要。标准库的 string 类提供了方便的操作接口。了解其内部实现原理,对提升编程技能很有帮助。

?你是否曾经好奇过 string 类是如何实现这些强大功能的呢?

?本文将介绍如何模拟实现一个简单的 string 类?


?string 类的功能需求分析

存储字符串数据

字符数组存储字符序列,它能通过?索引访问字符,方便操作。还需动态管理存储空间,以适应不同长度字符串,避免内存问题。

字符串长度获取

要有获取字符串长度(字符个数)的方法,这对很多操作都必要。

字符串比较

要能比较两个字符串大小,用于排序、查找等操作。

字符串连接

能把两个字符串连接成一个新字符串,像组合单词成句子。

字符串修改

包括末尾添加、指定位置插入和删除部分字符串等操作,以灵活处理字符串。

内存管理

合理分配和释放内存,避免泄漏和浪费。字符串长度变化时要自动调整存储空间。


?模拟实现的关键步骤和代码解析

1.类的定义

class MyString {private:    char* data;  // 存储字符串的字符数组指针    size_t length;  // 实际字符个数    size_t capacity;  // 字符数组容量public:    MyString();  // 默认构造函数    MyString(const char* str);  // 用 C 风格字符串初始化的构造函数    MyString(const MyString& other);  // 拷贝构造函数    ~MyString();  // 析构函数    size_t size() const;    int compare(const MyString& other) const;    MyString& append(const char* str);    MyString& insert(size_t pos, const char* str);    MyString& erase(size_t pos, size_t count);    MyString operator+(const MyString& other) const;    char& operator[](size_t index);    const char& operator[](size_t index) const;    MyString& operator=(const MyString& other);};

?解释:

这里定义了 MyString 类,有存储字符串的 data 指针记录长度的 length 容量的 capacity。还有各种函数用于不同操作。

2.构造函数实现

 

2.1 默认构造函数 

MyString::MyString() : data(nullptr), length(0), capacity(0) {}

 创建空字符串,data 设为 nullptr,长度和容量都为 0。

2.2 用 C 风格字符串初始化的构造函数

MyString::MyString(const char* str) {    if (str == nullptr) {        data = nullptr;        length = 0;        capacity = 0;        return;    }    length = strlen(str);  // 获取传入字符串的长度    capacity = length;    data = new char[capacity + 1];  // 分配足够的内存空间    strcpy(data, str);  // 复制字符串到 data 所指向的数组}

?从 C 风格字符串初始化若传入 nullptr,创建空字符串。否则,获取长度设为 length 和 capacity,分配内存并复制字符串到 data。

2.3 拷贝构造函数

MyString::MyString(const MyString& other) {    length = other.length;  // 设置新对象的长度    capacity = other.capacity;  // 设置新对象的容量    data = new char[capacity + 1];  // 分配内存    strcpy(data, other.data);  // 复制字符串}

?创建新对象,内容与传入对象相同。设置长度和容量,分配内存并复制字符串。

3. 析构函数实现

MyString::~MyString() {    if (data!= nullptr) {        delete[] data;  // 释放内存    }}

 ?释放 data 指向的内存,避免内存泄漏。

4.获取字符串长度函数

size_t MyString::size() const {    return length;  // 返回字符串长度}

?直接返回字符串长度 length。

5.字符串比较函数

int MyString::compare(const MyString& other) const {    for (size_t i = 0; i < length && i < other.length; i++) {        if (data[i]!= other.data[i]) {            return data[i] < other.data[i]? -1 : 1;        }    }    if (length < other.length) {        return -1;    } else if (length > other.length) {        return 1;    }    return 0;}

 ?逐字符比较两个字符串,先比较字符,再比较长度,返回相应结果。

 6.字符串连接函数

MyString& MyString::append(const char* str) {    if (str == nullptr) {        return *this;  // 传入为空则直接返回当前对象    }    size_t strLen = strlen(str);  // 计算要添加的字符串长度    if (length + strLen > capacity) {        reserve(length + strLen);  // 检查容量,不够则扩展    }    strcpy(data + length, str);  // 将字符串添加到当前字符串末尾    length += strLen;  // 更新长度    return *this;}

?解释:

?在末尾添加字符串。若传入 nullptr,返回当前对象。否则,检查容量,不够就扩展,然后复制字符串并更新长度。

7.字符串插入函数

MyString& MyString::insert(size_t pos, const char* str) {    if (str == nullptr) {        return *this;  // 传入为空则直接返回当前对象    }    size_t strLen = strlen(str);  // 计算要插入的字符串长度    if (length + strLen > capacity) {        reserve(length + strLen);  // 检查容量,不够则扩展    }    for (size_t i = length; i > pos; i--) {        data[i + strLen - 1] = data[i - 1];  // 移动字符腾出空间    }    for (size_t i = 0; i < strLen; i++) {        data[pos + i] = str[i];  // 复制要插入的字符串    }    length += strLen;  // 更新长度    return *this;}

 ?解释:

???​​​​​​​ 在指定位置插入字符串。若传入 nullptr,返回当前对象。检查容量,不够就扩展,移动字符腾出空间,复制字符串并更新长度。

 8.字符串删除函数

MyString& MyString::erase(size_t pos, size_t count) {    if (pos >= length) {        return *this;  // 位置不合法则返回当前对象    }    if (pos + count > length) {        count = length - pos;  // 调整要删除的长度    }    for (size_t i = pos; i < length - count; i++) {        data[i] = data[i + count];  // 移动字符填补空缺    }    length -= count;  // 更新长度    return *this;}

 ?解释:

??​​​​​​​?​​​​​​​  删除指定位置和长度的字符串。若位置不合法,返回当前对象。调整要删除的长度,移动字符填补空缺并更新长度。

9.字符串加法操作符重载

MyString MyString::operator+(const MyString& other) const {    MyString result;    result.length = length + other.length;  // 设置新对象长度    result.capacity = result.length;    result.data = new char[result.capacity + 1];  // 分配内存    strcpy(result.data, data);  // 复制第一个字符串    strcpy(result.data + length, other.data);  // 复制第二个字符串    return result;}

 ?解释:

??​​​​​​​?​​​​​​​  重载加法操作符,创建新对象,长度为两字符串长度之和,分配内存,复制两个字符串到新对象并返回。

10.下标操作符重载

char& MyString::operator[](size_t index) {    return data[index];  // 返回非 const 对象的字符引用,可以修改}const char& MyString::operator[](size_t index) const {    return data[index];  // 返回 const 对象的字符引用,只能读取}

??​​​​​​​? ​​​​​​​重载下标操作符,可通过下标访问字符串字符,非 const 对象可修改,const 对象只能读取。

11.赋值操作符重载

MyString& MyString::operator=(const MyString& other) {    if (this!= &other) {        if (data!= nullptr) {            delete[] data;  // 释放当前对象内存        }        length = other.length;  // 复制长度        capacity = other.capacity;        data = new char[capacity + 1];  // 分配新内存        strcpy(data, other.data);  // 复制字符串    }    return *this;}

  ?解释:

?重载赋值操作符,若不是自我赋值,释放当前对象内存,复制长度、容量和字符串数据并返回。


?内存管理相关函数(如reserveresize

 

1.reserve函数

void MyString::reserve(size_t new_capacity) {    if (new_capacity > capacity) {        char* new_data = new char[new_capacity + 1];  // 分配新内存        if (data!= nullptr) {            strcpy(new_data, data);  // 复制原字符串            delete[] data;  // 释放原内存        }        data = new_data;  // 更新 data 指针        capacity = new_capacity;  // 更新容量    }}

 ? 扩展字符串容量。若新容量大于当前容量,分配新内存,复制原字符串,释放原内存,更新 data 和 capacity。

 2.resize函数

void MyString::resize(size_t new_length, char fill_char = '\0') {    if (new_length > length) {        if (new_length > capacity) {            reserve(new_length);  // 检查容量,不够则扩展        }        for (size_t i = length; i < new_length; i++) {            data[i] = fill_char;  // 用填充字符填充新增部分        }    } else if (new_length < length) {        length = new_length;  // 截断字符串        data[length] = '\0';    }}

? 调整字符串长度。若新长度大于当前长度,检查容量,不够就扩展,用填充字符填充新增部分。若新长度小于当前长度,截断字符串并更新长度。


?示例用法

 以下是一个简单的main函数示例,展示如何使用模拟实现的MyString类:

int main() {    MyString str1("Hello");    MyString str2(" World");    // 使用 append 函数    str1.append(str2.data);    std::cout << "After append: " << str1.data << std::endl;    // 使用 insert 函数    str1.insert(5, "Beautiful ");    std::cout << "After insert: " << str1.data << std::endl;    // 使用 erase 函数    str1.erase(5, 10);    std::cout << "After erase: " << str1.data << std::endl;    // 使用 operator+ 重载    MyString str3 = str1 + "!";    std::cout << "After + operator: " << str3.data << std::endl;    return 0;}

?总结

?通过模拟实现 string 类,我们了解了字符串处理原理和技术。

从存储结构到操作函数,再到内存管理,每个环节都重要。这有助于理解标准库的 string 类,提高处理字符串问题的能力,✌为编写更好的代码打基础。


以后我将深入研究继承、多态、模板等特性,并将默认成员函数与这些特性结合,以解决更复杂编程问题!欢迎关注我?【A Charmer】  


点击全文阅读


本文链接:http://zhangshiyu.com/post/181256.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1