c++-string

C+±string

string 是 C++ 标准库中提供的字符串类,定义在 <string> 头文件中,属于 std 命名空间。该类的接口与常规容器接口基本一致,还有一些属于 string 的额外操作。

1. 底层理解

string 底层是一个存储字符的顺序表。

cpp 复制代码
class string{
    char* _str;          // 字符串的起始地址
    size_t _size;        // 下一个字符存储的位置
    size_t capacity;     // 当前容量
};

stirng 底层实际开辟 capacity + 1 大小,为了兼容 C 保留 '\0'

2. 成员函数

2.1 构造函数

序号 函数原型 说明
1️⃣ string() 默认构造函数,构造一个空的 string 对象,但是有一个 '\0'(兼容C)
2️⃣ string(const string& str) 拷贝构造
3️⃣ string(const string& str , size_t pos , size_t len = npos) 拷贝部分 str ,从 pos 位置开始拷贝 len 个(len 超出 str 实际大小或为 npos 拷贝至结尾)
4️⃣ string(const char * s) 使用 C 风格字符串构造 string 对象
5️⃣ string(const char * s , size_t n) 使用 s 中前 n 个字符构造 string 对象
6️⃣ string(size_t n , char c) 使用 nc 字符构造 string 对象
7️⃣ template <class InputIterator> string (InputIterator first , InputIterator last) 使用一段迭代器区间构造 string 对象

string::nposstatic const size_t npos = -1;

2.2 赋值重载

序号 函数原型 说明
1️⃣ string& operator= (const string& str) 将 str 对象赋值给当前 string 对象
2️⃣ string& operator= (const char * s) 将 C 风格字符串赋值给当前 string 对象
3️⃣ string& operator= (char c) 将 c 字符赋值给当前 string 对象

2.3 迭代器

序号 函数原型 说明
1️⃣ iterator begin() 返回指向 string 对象中第一个字符的迭代器
2️⃣ const_iterator begin() const 返回指向 string 对象中第一个字符的 const 迭代器
3️⃣ iterator end() 返回指向 string 对象结尾的下一个位置的迭代器
4️⃣ const_iterator end() const 返回指向 string 对象结尾的下一个位置的 const 迭代器
5️⃣ reverse_iterator rbegin() 返回指向 string 对象结尾位置的迭代器
6️⃣ const_reverse_iterator rbegin() const 返回指向 string 对象结尾位置的 const 迭代器
7️⃣ reverse_iterator() rend() 返回指向 string 对象起始的前一个位置的迭代器
8️⃣ const_reverse_iterator() rend() const 返回指向 string 对象起始的前一个位置的 const 迭代器

范围 for

  • 范围for的本质就是迭代器。

  • 范围for可以遍历普通数组和容器对象。

cpp 复制代码
// 元素的访问
for (auto c : str) {
    cout << c << str;
}
// 元素的修改
for (auto& c : str) {
    c *= 2;
}

2.4 容量相关的接口

序号 函数原型 说明
1️⃣ size_t size() const 返回 string 的长度
2️⃣ size_t capacity() const 返回 string 的容量
3️⃣ void resize (size_t n) 1. n > size(): 将 size 设置为 n,并将 size ~ n 下标区间元素填充 '\0' 2. n < size(): 将 size 设置为 n,n后的元素被删除
4️⃣ void resize (size_t n , char c) 1. n > size(): 将 size 设置为 n,并将 size ~ n 下标区间元素填充 c 2. n < size(): 将 size 设置为 n,n后的元素被删除
5️⃣ void reserve (size_t n = 0) 修改 string 对象的 capacity() 至 n
6️⃣ void clear(); 清空 string 对象的内容
7️⃣ bool empty() const 判断当前 string 对象是否为空

resize 和 reserve的区别


2.5 元素的访问

序号 函数原型 说明
1️⃣ char& operator[] (size_t pos) 返回 string 对象中 pos 位置字符的引用
2️⃣ const char& operator[](size_t pos) const 返回 const string 对象中 pos 位置字符的引用
3️⃣ char& at (size_t pos) 返回 string 对象中 pos 位置字符的引用
4️⃣ const char& at (size_t pos) const 返回 const string 对象中 pos 位置字符的引用
5️⃣ char& back() 返回 string 对象最后一个字符的引用
6️⃣ const char& back() const 返回 const string 对象最后一个字符的引用
7️⃣ char& front() 返回 string 对象第一个字符的引用
8️⃣ const char& front() const 返回 const string 对象第一个字符的引用

\] 和 at 的区别:\[\]断言检查pos位置是否合法,at是抛异常。

2.6 修改相关的接口

序号 函数原型 说明
1️⃣ void push_back (char c) 在当前 string 对象的末尾追加 c 字符
2️⃣ string& append (const string& str) 在 string 对象的末尾追加 str 对象
3️⃣ string& append (const string& str , size_t subpos , size_t sublen) 在 string 对象的末尾追加 str 对象的子串,从 subpos 位置开始,拷贝 sublen 个字符过去
4️⃣ string& insert (size_t pos, const string& str); 在 string 对象的 pos 位置添加 str 对象
5️⃣ string& insert (size_t pos, size_t n, char c); 在 string 对象的 pos 位置添加 n 个 c 字符
6️⃣ string& erase (size_t pos = 0, size_t len = npos); 从 string 对象的 pos 位置删除 len 个字符(若len = npos删除至结尾)
7️⃣ string& operator+= (const string& str); 在 string 对象的末尾追加 str 对象
8️⃣ *string& operator+= (const char s);** 在 string 对象的末尾追加 s 字符串
9️⃣ string& operator+= (char c); 在 string 对象的末尾追加 c 字符

2.7 其他接口

序号 函数原型 说明
1️⃣ const char c_str() const* 将 string 对象以C风格字符串返回
2️⃣ size_t find (char c , size_t pos = 0) const 从当前 string 对象的 pos 位置开始查找 c 字符,返回这个字符第一次出现的位置,否则返回 string::npos
3️⃣ size_t rfind (char c , size_t pos = npos) const 从当前 string 对象的 pos 位置从后向前开始查找 c 字符,返回这个字符最后一次出现的位置,否则返回 string::npos
4️⃣ string substr (size_t pos = 0 , size_t len = npos) const 返回 string 对象 pos 位置开始的 len 个字符的子串

3. 非成员函数

序号 函数原型 说明
1️⃣ istream& getline (istream& is , string& str , char delim) 获取一行字符遇到 delim 字符终止
2️⃣ istream& getline (istream& is , string& str) 获取一行字符遇到 \n 终止
3️⃣ relational operators 关系比较(>、<、>=、<=、!=、==)
4️⃣ istream& operator>> (istream& is, string& str); 流提取运算符重载
5️⃣ ostream& operator<< (ostream& os, const string& str); 流插入运算符重载

4. string模拟实现

cpp 复制代码
// string.hpp
#pragma once

#include <iostream>
#include <cstring>
#include <cassert>

namespace simulateSTL
{
    class string
    {
    public:
        typedef char* iterator;
        typedef const char* const_iterator;
        iterator begin() { return _str; }
        iterator end() { return _str + _size; }
        const_iterator begin() const { return _str; }
        const_iterator end() const { return _str + _size; }
        size_t size() const { return _size; }
        size_t capacity() const { return _capacity; }
        void clear() { _size = 0; _str[_size] = 0; }
        bool empty() const { return _size == 0; }
        char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; }
        const char& operator[](size_t pos) const { assert(pos < _size); return _str[pos]; }
        const char* c_str() const { return _str; } 
        bool operator==(const string& str) const { return !strcmp(_str , str._str); }
        bool operator!=(const string& str) const { return !(*this == str); }
        bool operator<(const string& str) const { return strcmp(_str , str._str) < 0; }
        bool operator<=(const string& str) const { return *this < str || *this == str; }
        bool operator>(const string& str) const { return !(*this <= str); }
        bool operator>=(const string& str) const { return !(*this < str); }
        void swap (string& str) { std::swap(_str , str._str);std::swap(_size , str._size);std::swap(_capacity , str._capacity); }
    public:
        string(const char *str = "");
        string(const string& str);
        string& operator=(string str);
        ~string();
        void reserve(size_t n);
        void resize(size_t n , char c = '\0');
        void push_back(char c);
        void pop_back();
        string& append(const char* s);
        string& operator+=(const string& str);
        string& operator+=(char c);
        string& insert(size_t pos , char c);
        string& insert(size_t pos , const char* s);
        string& erase(size_t pos);
        string substr(size_t pos = 0 , size_t len = npos) const;
        size_t find(char c , size_t pos = 0) const;
    private:
        char *_str = nullptr;
        size_t _size = 0;
        size_t _capacity = 0;

    public:
        static const size_t npos = -1;
    };

    string::string(const char *str)
        : _size(strlen(str))
    {
        _str = new char[_size + 1]; // 兼容C保留'\0'位置
        strcpy(_str, str);
        _capacity = _size;
    }

    // 现代写法
    string::string(const string& str) {
        string temp(str._str);
        swap(temp);
    }

    // 现代写法
    string& string::operator=(string str) {
        swap(str);
        return *this;
    }

    string::~string()
    {
        // C++中可以delete nullptr
        delete[] _str;
        _size = _capacity = 0;
    }

    void string::reserve(size_t n) {
        if (n > _capacity) {
            char* temp = new char[n + 1];   // 兼容C保留'\0'
            strcpy(temp , _str);
            delete[] _str;
            _str = temp;
            _capacity = n;
        }
    }

    void string::resize(size_t n , char c) {
        if (n <= _size) {
            _size = n;
            _str[_size] = 0;
        } else {
            if (n > _capacity) {
                reserve(n);
            }

            while (_size < n) {
                _str[_size++] = c;
            }

            _str[_size] = 0;
        }
    }

    void string::push_back(char c) {
        if (_size == _capacity) {
            reserve(_capacity == 0 ? 4 : _capacity * 2);
        }

        _str[_size++] = c;
        _str[_size] = 0;

    }

    void string::pop_back() {
        assert(!empty());
        _str[--_size] = 0;
    }

    string& string::append(const char* s) {
        size_t len = strlen(s);
        if (_size + len > _capacity) {
            reserve(_size + len > _capacity * 2 ? _size + len : _capacity * 2);
        }
        for (size_t i = 0; i < len; i++) {
            _str[_size++] = s[i];
        }
        _str[_size] = 0;

        return *this;
    }

    string& string::operator+=(const string& str) {
        return append(str._str);
    }

    string& string::operator+=(char c) {
        push_back(c);
        return *this;
    }

    string& string::insert(size_t pos , char c) {
        assert(pos <= _size);
        if (_size == _capacity) {
            reserve(_capacity == 0 ? 4 : _capacity * 2);
        }

        size_t end = _size + 1;
        while (end > pos) {
            _str[end] = _str[end - 1];
            end--;
        }

        _str[pos] = c;
        _size++;

        return *this;
    }

    string& string::insert(size_t pos , const char* s) {
        assert(pos <= _size);
        size_t len = strlen(s);
        if (_size + len > _capacity) {
            reserve(_size + len > _capacity * 2 ? _size + len : _capacity * 2);
        }

        size_t end = _size + len;
        while (end > pos + len - 1) {
            _str[end] = _str[end - len];
            end--;
        }
        strncpy(_str + pos , s , len);
        _size += len;

        return *this;
    }

    string& string::erase(size_t pos) {
        assert(pos < _size);
        size_t end = pos;
        while (end < _size) {
            _str[end] = _str[end + 1];
            end++;
        }
        _size--;

        return *this;
    }

    string string::substr(size_t pos , size_t len) const {
        assert(pos < _size);
        // 修正len
        if (len + pos > _size || len == npos) {
            len = _size - pos;
        }
        string sub;
        sub.reserve(len);
        for (size_t i = 0; i < len; i++) {
            sub += _str[pos + i];
        }
        return sub;
    }

    size_t string::find(char c , size_t pos) const {
        assert(pos < _size);
        while (pos < _size) {    
            if (_str[pos] == c) return pos;
            pos++;
        }
        return npos;
    }

    // 全局运算符重载函数
    std::ostream& operator<<(std::ostream& out, const string& s) {
            for (auto ch : s) {
                  out << ch;
            }

            return out;
      }

    std::istream& operator>>(std::istream& in, string& s) {
            s.clear();

        // 定义缓冲区
            const int N = 256;
            char buff[N]; 
            int i = 0;  // 0 ~ 255

            char ch;
            ch = in.get();  // 获取单个字符
            while (ch != ' ' && ch != '\n') {
                  buff[i++] = ch;
                  if (i == N-1) {
                        buff[i] = '\0';
                        s += buff;
                        i = 0;
                  }

                  ch = in.get();
            }

            if (i > 0) {
                  buff[i] = '\0';
                  s += buff;
            }

            return in;
      }
}  // namespace end
相关推荐
吃饭只吃七分饱27 分钟前
C++第8章:IO库
开发语言·c++
Gappsong8743 小时前
Rufus:Ubuntu U盘启动盘制作工具详解
linux·c++·web安全·网络安全
Kira Skyler4 小时前
c++,从汇编角度看lambda
汇编·c++
Algebraaaaa5 小时前
C++ 多线程中成员函数如何传参?拷贝、引用还是指针?
开发语言·c++
程序员编程指南5 小时前
Qt开发环境搭建全攻略(Windows+Linux+macOS)
linux·c语言·c++·windows·qt
Aurora_wmroy7 小时前
算法竞赛备赛——【图论】求最短路径——Bellman-Ford & SPFA
数据结构·c++·算法·蓝桥杯·图论
刚入坑的新人编程8 小时前
暑假算法训练.6
数据结构·c++·算法·哈希算法
云边有个稻草人10 小时前
【C++】第十八节—一文万字详解 | map和set的使用
c++·set·map·multimap·multiset·序列式容器和关联式容器
wwww.wwww11 小时前
使用qt编写上位机程序,出现串口死掉无法接受数据的bug
c++·qt·bug