深入了解 C++ 中的 string 类型

在 C++ 中,处理字符串是一项常见的任务,而std::string 类型是这项任务的主要工具之一。它提供了丰富的功能和便利的操作,使得字符串处理变得更加简单和高效。本文将深入探讨 std::string 类型,包括其定义、特性、常见操作、注意事项以及具体的使用示例。

1. std::string 的定义和特性

std::string 是 C++ 标准库中的一个类,用于表示字符串。它具有以下特性:

  • 动态大小std::string 允许在运行时动态调整字符串的长度,不需要在编译时指定固定大小。

  • 自动管理内存std::string 类会自动管理字符串的内存分配和释放,无需手动管理内存。

  • 可变性std::string 中的字符串内容是可以被修改的,可以通过各种操作来修改字符串的内容。

2. std::string 的常见操作

std::string 类提供了丰富的成员函数和操作符,用于对字符串进行操作。下面是一些常见的操作:

  • 字符串赋值:可以使用 = 或 assign() 函数将一个字符串赋值给另一个字符串。

  • 字符串连接:可以使用 + 操作符或 append() 函数将两个字符串连接起来。

  • 字符串比较:可以使用 ==!=<<=>>= 操作符或 compare() 函数来比较两个字符串的大小关系。

  • 获取字符串长度:可以使用 size() 或 length() 函数获取字符串的长度。

  • 访问字符串中的字符:可以使用 [] 操作符或 at() 函数来访问字符串中的单个字符。

  • 查找子串:可以使用 find()rfind()find_first_of()find_last_of() 等函数来查找子串在字符串中的位置。

  • 子串提取:可以使用 substr() 函数来提取字符串中的子串。

  • 字符串替换:可以使用 replace() 函数来替换字符串中的子串。

  • 字符串插入和删除:可以使用 insert() 和 erase() 函数来在字符串中插入和删除字符或子串。

3. 注意事项和最佳实践

在使用 std::string 类时,需要注意以下事项:

  • 避免频繁的拷贝操作:由于 std::string 是动态分配内存的,频繁的拷贝操作可能会导致性能下降。可以使用引用或移动语义来避免不必要的拷贝。

  • 注意字符串的内存管理:虽然 std::string 类会自动管理内存,但在处理大量字符串时,仍需要注意内存的使用情况,避免内存泄漏或内存碎片问题。

  • 使用成员函数而不是操作符:虽然 std::string 支持很多操作符重载,但使用成员函数通常更加清晰和安全。

  • 使用范围检查:在访问字符串的字符时,应该使用 at() 函数而不是 [] 操作符,以确保访问的索引在字符串的有效范围内,避免发生越界访问的问题。

  • 避免使用 C 风格字符串函数:尽量避免使用像 strcpystrcat 等 C 风格的字符串函数来处理 std::string,以避免潜在的缓冲区溢出和安全性问题。

4. std::string 的高级应用

除了基本的字符串操作外,std::string 还支持一些高级功能,例如正则表达式匹配、格式化输出、字符串流等。通过这些功能,可以更加灵活地处理字符串,满足复杂的字符串处理需求。

5. 具体的使用示例

下面是一个具体的使用示例,演示了 std::string 的基本操作:

#include <iostream>
#include <string>

int main() {
    std::string str1 = "Hello";
    std::string str2(" world!");

    std::string combined = str1 + str2;
    std::cout << "Combined string: " << combined << std::endl;

    std::cout << "Length of combined string: " << combined.size() << std::endl;

    char ch = combined[0];
    std::cout << "First character: " << ch << std::endl;

    size_t pos = combined.find("world");
    if (pos != std::string::npos) {
        std::cout << "Substring 'world' found at position: " << pos << std::endl;
    } else {
        std::cout << "Substring not found" << std::endl;
    }

    std::string sub = combined.substr(6, 5);
    std::cout << "Substring: " << sub << std::endl;

    combined.replace(6, 5, "C++");
    std::cout << "Replaced string: " << combined << std::endl;

    combined.insert(5, " C++");
    std::cout << "Inserted string: " << combined << std::endl;

    combined.erase(0, 5);
    std::cout << "Erased string: " << combined << std::endl;

    return 0;
}

 6. string 的简易模拟实现

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
#include <assert.h>
using namespace std;
namespace imitate_string
{
    class string
    {
        // 友元函数应该在类外进行定义
        friend ostream& operator<<(ostream& _cout, const string& s);
        friend istream& operator>>(istream& _cin, string& s);

    public:
        typedef char* iterator;
        typedef const char* const_iterator;

        // 构造函数
        string(const char* str = "")
            :_size(strlen(str)) // 初始化字符串长度为输入字符串的长度
        {
            // 分配内存,复制输入字符串,并添加空字符 '\0'
            char* temp = new char[_size + 1];
            strncpy(temp, str, _size);
            temp[_size] = '\0';
            _str = temp;
            _capacity = _size;
        }

        // 拷贝构造函数
        string(const string& s)
        {
            _capacity = _size = s._size;
            char* temp = new char[_size + 1];
            strncpy(temp, s._str, _size);
            temp[_size] = '\0';
            _str = temp;
        }

        // 赋值运算符
        string& operator=(const string& s)
        {
            if (this != &s) // 检查自赋值情况
            {
                delete[] _str; // 释放原有内存
                _size = s._size;
                _capacity = s._capacity;
                char* temp = new char[_size + 1];
                strncpy(temp, s._str, _size);
                temp[_size] = '\0';
                _str = temp;
            }
            return *this;
        }

        // 析构函数
        ~string()
        {
            delete[] _str;
            _str = nullptr;
            _size = _capacity = 0;
        }

        // 返回字符串起始迭代器
        iterator begin()
        {
            return _str;
        }

        // 返回字符串结束迭代器
        iterator end()
        {
            return _str + _size;
        }

        // 返回字符串起始迭代器(const 重载)
        const_iterator begin() const
        {
            return _str;
        }

        // 返回字符串结束迭代器(const 重载)
        const_iterator end() const
        {
            return _str + _size;
        }

        // 向字符串末尾添加字符
        void push_back(char c)
        {
            if (_size == _capacity)
            {
                reserve(_capacity == 0 ? 4 : 2 * _capacity);
            }
            _str[_size++] = c;
            _str[_size] = '\0';
        }

        // 运算符重载,向字符串末尾添加字符
        string& operator+=(char c)
        {
            push_back(c);
            return *this;
        }

        // 向字符串末尾添加字符串
        string& append(const char* str)
        {
            size_t len = strlen(str);
            reserve(_size + len);
            // 使用标准库函数复制字符串
            std::copy(str, str + len, _str + _size);
            _size += len;
            _str[_size] = '\0';
            return *this;
        }

        // 运算符重载,向字符串末尾添加字符串
        string& operator+=(const char* str)
        {
            append(str);
            return *this;
        }

        // 清空字符串
        void clear()
        {
            _size = 0;
            _str[0] = '\0';
        }

        // 交换字符串内容
        void swap(string& s)
        {
            std::swap(_str, s._str);
            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);
        }

        // 返回 C 风格字符串
        const char* c_str() const
        {
            return _str;
        }

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

        // 返回字符串容量
        size_t capacity() const
        {
            return _capacity;
        }

        // 判断字符串是否为空
        bool empty() const
        {
            return _size == 0;
        }

        // 调整字符串大小
        void resize(size_t n, char c = '\0')
        {
            if (_size < n)
            {
                reserve(n);
                // 使用标准库函数填充字符
                std::fill(_str + _size, _str + n, c);
            }
            _size = n;
            _str[n] = '\0';
        }

        // 保留足够的容量以存储给定的字符数
        void reserve(size_t n)
        {
            if (n > _capacity)
            {
                // 重新分配内存
                char* temp = new char[n + 1];
                strncpy(temp, _str, _size);
                temp[_size] = '\0';
                delete[] _str;
                _str = temp;
                _capacity = n;
            }
        }



        // 访问指定索引处的元素(非 const 版本)
        char& operator[](size_t index) {
            return _str[index];
        }

        // 访问指定索引处的元素(const 版本)
        const char& operator[](size_t index) const {
            return _str[index];
        }

        // 比较运算符

        bool operator<(const string& s) {
            return strcmp(this->_str, s._str) < 0;
        }

        bool operator<=(const string& s) {
            return *this < s || strcmp(this->_str, s._str) == 0;
        }

        bool operator>(const string& s) {
            return !(*this <= s);
        }

        bool operator>=(const string& s) {
            return !(*this < s);
        }

        bool operator==(const string& s) {
            return strcmp(this->_str, s._str) == 0;
        }

        bool operator!=(const string& s) {
            return !(*this == s);
        }

        // 查找字符串中第一次出现的字符

        size_t find(char c, size_t pos = 0) const {
            if (_size == 0 || pos >= _size) {
                return std::string::npos;
            }
            for (size_t i = pos; i < _size; i++) {
                if (_str[i] == c) {
                    return i;
                }
            }
            return std::string::npos;
        }

        // 查找字符串中第一次出现的子字符串

        size_t find(const char* s, size_t pos = 0) const {
            if (_size == 0 || pos >= _size) {
                return std::string::npos;
            }
            char* temp = strstr(this->_str, s);
            return temp == NULL ? std::string::npos : temp - _str;
        }

        // 在指定位置插入字符/子字符串

        string& insert(size_t pos, char c) {
            assert(pos >= 0 && pos <= _size);
            reserve(_size + 1);
            size_t end = _size;
            while (end > pos) {
                _str[end] = _str[end - 1];
                end--;
            }
            _str[end] = c;
            return *this;
        }

        string& insert(size_t pos, const char* str) {
            assert(pos >= 0 && pos <= _size);
            int len = strlen(str);
            reserve(_size + len);
            size_t end = _size + len;
            while (end >= pos + len) {
                _str[end] = _str[end - len];
                end--;
            }
            strncpy(_str + pos, str, len);
            return *this;
        }

        // 从指定位置擦除字符

        string& erase(size_t pos = 0, size_t count = std::string::npos) {
            assert(pos >= 0 && count >= 0);
            if (pos + count >= _size) {
                _str[pos] = '\0';
                _size -= count;
            }
            else {
                while (pos + count <= _size + 1) {
                    _str[pos] = _str[pos + count];
                    ++pos;
                }
            }
            return *this;
        }

        // 获取子字符串

        string substr(size_t pos = 0, size_t len = std::string::npos) const {
            assert(pos >= 0);
            string s;
            if (len >= _size) {
                s += _str;
                return s;
            }
            for (size_t i = 0; i < len; i++) {
                s += _str[pos + i];
            }
            return s;
        }

    private:
        char* _str; // 指向动态分配的字符数组的指针
        size_t _capacity; // 字符串容量
        size_t _size; // 字符串大小
    };

    // 重载输出运算符
    ostream& operator<<(ostream& out, const string& s) {
        for (auto ch : s) {
            if (ch == '\0') {
                break;
            }
            out << ch;
        }
        return out;
    }

    // 重载输入运算符
    istream& operator>>(istream& in, string& s) {
        s.clear();
        char ch = in.get();
        char buf[128] = { 0 };
        int index = 0;
        while (ch != ' ' && ch != '\n') {
            buf[index++] = ch;
            if (index == 127) {
                buf[index] = '\0';
                s += buf;
                index = 0;
            }
            ch = in.get();
        }
        if (index > 0) {
            buf[index] = '\0';
            s += buf;
        }
        return in;
    }

    // 自定义的 getline 函数重载
    istream& getline(istream& in, string& s) {
        {
            s.clear();

            char ch = in.get();

            char buf[128] = { 0 };
            int index = 0;

            while (ch != '\n')
            {
                buf[index++] = ch;
                if (index == 127)
                {
                    buf[index] = '\0';
                    s += buf;
                    index = 0;
                }
                ch = in.get();
            }
            if (index > 0)
            {
                buf[index] = '\0';
                s.append(buf);
            }
            return in;
        }
        
    };
    
}

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这题怎么做?!?

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值