string介绍

  • string也是cpp中的一个容器,从名字可以看出来它封装的是和字符串相关的操作, 它是basic_string的一个类型别名,类型是std::basic_string<char>,让我们看一下basic_string的定义,它接受三个模板参数,其余两个模板参数使用默认值
    在这里插入图片描述
  • string是序列式容器

成员类型

  • 包括指针、迭代器、值类型等
  • 还有一个值 npos,它是size_t(-1), 用于比较string的某些函数的返回值的结果是否正常
    在这里插入图片描述

构造函数

  • string的构造函数比较乱,我挑几个常用的进行介绍,包括构造函数等,这里就不介绍析构函数了
    在这里插入图片描述
  • 示例
#include <iostream>
#include <string>

int main() {
    // 1. 默认构造
    std::string s1;
    std::cout << "s1: \"" << s1 << "\"\n";

    // 2. 从 C 字符串构造
    std::string s2("hello");
    std::cout << "s2: " << s2 << "\n";

    // 3. 拷贝构造
    std::string s3(s2);
    std::cout << "s3: " << s3 << "\n";

    // 4. 子串构造(pos, len)
    std::string s4(s2, 1, 3);
    std::cout << "s4: " << s4 << "\n";

    // 5. 重复字符构造(count, char)
    std::string s5(5, 'a');
    std::cout << "s5: " << s5 << "\n";

    // 6. 从 char 数组 + 指定长度
    const char arr[] = {'h', 'e', 'l', 'l', 'o', '\0', 'x'};
    std::string s6(arr, 5);
    std::cout << "s6: " << s6 << "\n";

    // 7. 迭代器区间构造
    std::string s7(s2.begin(), s2.end());
    std::cout << "s7: " << s7 << "\n";

    // 8. 移动构造(C++11)
    std::string temp = "temporary";
    std::string s8(std::move(temp));
    std::cout << "s8: " << s8 << "\n";
    std::cout << "temp(after move): " << temp << "\n";

    // 9. initializer_list 构造
    std::string s9({'H', 'i', '!'});
    std::cout << "s9: " << s9 << "\n";

    // 10. assign(不是构造,但常一起用)
    std::string s10;
    s10.assign("world");
    std::cout << "s10: " << s10 << "\n";

    return 0;
}

成员函数

元素访问

  • at 访问指定索引的元素前会检查是否越界,越界就会抛异常,返回对应元素的引用;operator[]的行为和at一样,只不过不会检查索引是否有效;front返回首个有效的元素;back返回最后一个有效的元素;和vector一样,string底层也是使用动态数组实现的,所以data返回存储数据的原始指针;c_str返回一个以‘\0’结尾的字符数组

在这里插入图片描述

  • 代码示例
#include <iostream>
#include <string>

int main() {
    std::string s = "hello";

    // 1. at()(带边界检查)
    std::cout << "at(1): " << s.at(1) << "\n";

    // 2. operator[]
    std::cout << "operator[2]: " << s[2] << "\n";

    // 3. front()
    std::cout << "front(): " << s.front() << "\n";

    // 4. back()
    std::cout << "back(): " << s.back() << "\n";

    // 5. data()
    const char* p1 = s.data();
    std::cout << "data(): " << p1 << "\n";

    // 6. c_str()
    const char* p2 = s.c_str();
    std::cout << "c_str(): " << p2 << "\n";

    // 修改内容(验证访问)
    s[0] = 'H';
    std::cout << "after modify: " << s << "\n";

    // 使用 at 修改
    s.at(1) = 'A';
    std::cout << "after at modify: " << s << "\n";

    return 0;
}

迭代器

  • begin()获取首个有效元素的地址,end获取最后一个有效元素的下一个位置,以及反向迭代器,还有一些常量迭代器,适合于常量对象使用
    在这里插入图片描述
  • 代码示例
#include <iostream>
#include <string>

int main() {
    std::string s = "hello";

    // 1. begin() / end()
    std::cout << "forward (begin -> end): ";
    for (auto it = s.begin(); it != s.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << "\n";

    // 2. cbegin() / cend()(只读迭代器)
    std::cout << "const forward (cbegin -> cend): ";
    for (auto it = s.cbegin(); it != s.cend(); ++it) {
        std::cout << *it << " ";
        // *it = 'x'; // ❌ 编译错误(只读)
    }
    std::cout << "\n";

    // 3. rbegin() / rend()(反向迭代器)
    std::cout << "reverse (rbegin -> rend): ";
    for (auto it = s.rbegin(); it != s.rend(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << "\n";

    // 4. crbegin() / crend()(只读反向)
    std::cout << "const reverse (crbegin -> crend): ";
    for (auto it = s.crbegin(); it != s.crend(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << "\n";

    // 5. 通过迭代器修改内容
    for (auto it = s.begin(); it != s.end(); ++it) {
        *it = std::toupper(*it);
    }
    std::cout << "after modify: " << s << "\n";

    return 0;
}

容量相关

  • empty 判断容器是否有有效的元素;size和length计算容器内的有效元素个数;max_size得到可以容纳的最大元素数量;reserve预分配空间;capacity获取元素的容量;shrink_to_fit可以把容器的capacity减少到和size一样,但是具体取决于编译器实现,不一定会缩容,使用时需要注意
    在这里插入图片描述
#include <iostream>
#include <string>

int main() {
    std::string s;

    // 1. empty()
    std::cout << "empty: " << std::boolalpha << s.empty() << "\n";

    // 2. size() / length()
    s = "hello";
    std::cout << "size: " << s.size() << "\n";
    std::cout << "length: " << s.length() << "\n";

    // 3. capacity()
    std::cout << "capacity(before): " << s.capacity() << "\n";

    // 4. reserve()
    s.reserve(100);
    std::cout << "capacity(after reserve 100): " << s.capacity() << "\n";

    // 5. max_size()
    std::cout << "max_size: " << s.max_size() << "\n";

    // 6. 扩展字符串,观察 capacity 变化
    for (int i = 0; i < 50; ++i) {
        s.push_back('x');
    }
    std::cout << "size(after push): " << s.size() << "\n";
    std::cout << "capacity(after push): " << s.capacity() << "\n";

    // 7. shrink_to_fit()
    s.shrink_to_fit();
    std::cout << "capacity(after shrink): " << s.capacity() << "\n";

    return 0;
}

修改操作

  • clear函数只会清空元素,不会改变数量;insert 可以在指定位置插入一个或一段区间的元素,返回插入的第一个元素的迭代器;push_back在容器末尾插入一个元素;pop_back移除末尾的元素;resize可以重新指定容器的大小,多余的元素以对应类型的默认值填充或者指定值填充;swap可以用来交换两个容器的内容;append可以直接在容器末尾追加元素;operatpr+=可以让容器和字符串做加法或者直接和相同类型的对象相加;replace用给定的字符串替换指定区间的元素;copy用来拷贝一个指定区间的字符串传递给一个变量,返回拷贝的字符数量,其余函数需要的cpp标准比较高,这里就不介绍了
    在这里插入图片描述
  • 代码示例
#include <iostream>
#include <string>
#include <algorithm>
#include <cstring>

int main() {
    std::string s = "hello";

    // 1. clear()
    {
        std::string t = s;
        t.clear();
        std::cout << "clear: \"" << t << "\"\n";
    }

    // 2. insert()
    {
        std::string t = s;
        t.insert(2, "XYZ");
        std::cout << "insert: " << t << "\n";
    }

    // 3. erase()
    {
        std::string t = s;
        t.erase(1, 2);
        std::cout << "erase: " << t << "\n";
    }

    // 4. push_back()
    {
        std::string t = s;
        t.push_back('!');
        std::cout << "push_back: " << t << "\n";
    }

    // 5. pop_back()
    {
        std::string t = s;
        t.pop_back();
        std::cout << "pop_back: " << t << "\n";
    }

    // 6. append()
    {
        std::string t = s;
        t.append(" world");
        std::cout << "append: " << t << "\n";
    }

    // 7. operator+=
    {
        std::string t = s;
        t += "!!!";
        std::cout << "operator+=: " << t << "\n";
    }

    // 8. replace()
    {
        std::string t = s;
        t.replace(1, 3, "ABC");
        std::cout << "replace: " << t << "\n";
    }

    // 9. copy()
    {
        std::string t = "hello world";
        char buf[20] = {0};
        std::size_t n = t.copy(buf, 5, 6); // 从下标 6 开始复制 5 个字符
        buf[n] = '\0';                     // copy 不会自动补 '\0'
        std::cout << "copy: " << buf << "\n";
    }

    // 10. resize()
    {
        std::string t = s;
        t.resize(8, 'x');
        std::cout << "resize bigger: " << t << "\n";

        t.resize(3);
        std::cout << "resize smaller: " << t << "\n";
    }

    // 11. swap()
    {
        std::string a = "aaa";
        std::string b = "bbb";
        a.swap(b);
        std::cout << "swap: a = " << a << ", b = " << b << "\n";
    }
    return 0;
}

查找

  • find从前往后查找给定子串是否出现,出现返回对应第一个元素的位置;rfind从后向前查找指定字符是否出现;find_first_of找到第一个是对应字符的的首字符位置,find_last_of找第一个不是的。选择合适的函数使用能事半功倍
    在这里插入图片描述
  • 代码示例
#include <iostream>
#include <string>

int main() {
    std::string s = "hello world";

    // 1. find(从前往后找子串)
    std::size_t pos1 = s.find("world");
    if (pos1 != std::string::npos)
        std::cout << "find: " << pos1 << "\n";

    // 2. rfind(从后往前找子串)
    std::size_t pos2 = s.rfind("l");
    if (pos2 != std::string::npos)
        std::cout << "rfind: " << pos2 << "\n";

    // 3. find_first_of(找第一个属于某集合的字符)
    std::size_t pos3 = s.find_first_of("aeiou");
    if (pos3 != std::string::npos)
        std::cout << "find_first_of (vowel): " << pos3 << " -> " << s[pos3] << "\n";

    // 4. find_first_not_of(找第一个不属于某集合的字符)
    std::string t = "   abc";
    std::size_t pos4 = t.find_first_not_of(' ');
    if (pos4 != std::string::npos)
        std::cout << "find_first_not_of (skip space): " << pos4 << " -> " << t[pos4] << "\n";

    // 5. find_last_of(找最后一个属于某集合的字符)
    std::size_t pos5 = s.find_last_of("aeiou");
    if (pos5 != std::string::npos)
        std::cout << "find_last_of (vowel): " << pos5 << " -> " << s[pos5] << "\n";

    // 6. find_last_not_of(找最后一个不属于某集合的字符)
    std::string u = "abc   ";
    std::size_t pos6 = u.find_last_not_of(' ');
    if (pos6 != std::string::npos)
        std::cout << "find_last_not_of (trim right): " << pos6 << " -> " << u[pos6] << "\n";

    return 0;
}

对字符串的操作

在这里插入图片描述

  • 代码示例
#include <iostream>
#include <string>

int main() {
    std::string s1 = "hello";
    std::string s2 = "hello";
    std::string s3 = "world";

    // 1. compare()
    std::cout << "compare(s1, s2): " << s1.compare(s2) << "\n"; // 0
    std::cout << "compare(s1, s3): " << s1.compare(s3) << "\n"; // <0 或 >0

    // 2. starts_with()  (C++20)
#if __cplusplus >= 202002L
    std::cout << "starts_with(\"he\"): " << std::boolalpha
              << s1.starts_with("he") << "\n";
#endif

    // 3. ends_with() (C++20)
#if __cplusplus >= 202002L
    std::cout << "ends_with(\"lo\"): " << std::boolalpha
              << s1.ends_with("lo") << "\n";
#endif

    // 4. contains() (C++23)
#if __cplusplus >= 202302L
    std::cout << "contains(\"ell\"): " << std::boolalpha
              << s1.contains("ell") << "\n";
#endif

    // 5. substr()
    std::string sub = s1.substr(1, 3); // 从 index=1 开始取 3 个字符
    std::cout << "substr: " << sub << "\n";

    return 0;
}

对string的介绍就到这里了,接下来我会写一篇关于string的模拟实现的文章,欢迎点赞关注,如果有写的不对的地方,还请批评指针。

更多推荐