当前位置: 首页 > news >正文

C++STL详解(一):string类

C++STL详解(一):string类

  • 一、auto和范围for
    • 1、auto关键字
    • 2、范围for
  • 二、string类的常用接口说明(注意下面我只讲解最常用的接口)
    • 1. string类对象的常见构造
    • 2、string类对象的容量操作
    • 3、string类对象的访问及遍历操作
    • 4、string类对象的修改操作
    • 5、string类非成员函数
  • 三、vs和g++下string结构的说明
    • 1、vs下string的结构
    • 2、g++下string的结构

有关string类文档介绍详解

一、auto和范围for

在这里补充2个C++11的小语法,方便我们后面的学习。

1、auto关键字

  • 在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得
  • 用auto 声明指针类型时,用auto和auto*没有任何区别,但用auto 声明引用类型时 则必须加&。
  • 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
  • auto不能作为函数的参数,可以做返回值,但是建议谨慎使用。
  • auto不能直接用来声明数组。
#include<iostream>
using namespace std;
int func1()
{return 10;
}// 不能做参数
void func2(auto a)
{}// 可以做返回值,但是建议谨慎使用
auto func3()
{return 3;
} int main()
{int a = 10;auto b = a;auto c = 'a';auto d = func1();// 编译报错:rror C3531: “e”: 类型包含“auto”的符号必须具有初始值设定项auto e;cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;cout << typeid(d).name() << endl;int x = 10;auto y = &x;auto* z = &x;auto& m = x;cout << typeid(x).name() << endl;cout << typeid(y).name() << endl;cout << typeid(z).name() << endl;auto aa = 1, bb = 2;// 编译报错:error C3538: 在声明符列表中,“auto”必须始终推导为同一类型auto cc = 3, dd = 4.0;// 编译报错:error C3318: “auto []”: 数组不能具有其中包含“auto”的元素类型auto array[] = { 4, 5, 6 };return 0;
}
#include<iostream>
#include <string>
#include <map>
using namespace std;
int main()
{std::map<std::string, std::string> dict = { { "apple", "苹果" },{ "orange","橙子" }, {"pear","梨"} };// auto的用武之地//std::map<std::string, std::string>::iterator it = dict.begin();auto it = dict.begin();while (it != dict.end()){cout << it->first << ":" << it->second << endl;++it;}return 0}

这段代码通过 std::map 存储了三个水果名称及其对应的中文翻译,使用迭代器遍历并打印出每一个键值对。 auto 使得迭代器的类型自动推导,简化了代码。

2、范围for

  • 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
  • 范围for可以作用到数组和容器对象上进行遍历。
  • 范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。
#
include<iostream>
#include <string>
#include <map>
using namespace std;
int main()
{int array[] = { 1, 2, 3, 4, 5 };// C++98的遍历for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i){array[i] *= 2;} for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i){cout << array[i] << endl;}// C++11的遍历for (auto& e : array)e *= 2;for (auto e : array)cout << e << " " << endl;string str("hello world");for (auto ch : str){cout << ch << " ";} cout << endl;
return 0;
}

二、string类的常用接口说明(注意下面我只讲解最常用的接口)

1. string类对象的常见构造

  1. string()(空字符串构造)
#include <iostream>
#include <string>
using namespace std;int main()
{string s1;  // 调用默认构造函数,构造一个空字符串cout << "s1: " << s1 << endl;  // 输出空内容cout << "s1.size(): " << s1.size() << endl;  // 输出 0return 0;
}

功能说明:
构造一个空的 string 对象,不包含任何字符。

注意事项:
默认初始化后,size() 返回 0,但可以通过 push_back 或 += 动态添加字符。

  1. string(const char* s)(C字符串构造)
#include <iostream>
#include <string>
using namespace std;int main() 
{const char* cstr = "Hello, C++";string s2(cstr);  // 用C风格字符串构造string对象cout << "s2: " << s2 << endl;  // 输出 "Hello, C++"return 0;
}

功能说明:
通过C风格字符串(const char*)初始化 string 对象。

注意事项:
需确保传入的指针指向有效的以 \0 结尾的字符串,否则行为未定义。

  1. string(const string& s)(拷贝构造)
#include <iostream>
#include <string>
using namespace std;int main() {string original = "Copy this";string copy(original);  // 调用拷贝构造函数cout << "copy: " << copy << endl;  // 输出 "Copy this"return 0;
}

功能说明:
通过另一个 string 对象构造新对象,内容与原对象完全一致。

注意事项:
深拷贝实现,修改原对象不会影响新对象。

总结:
在这里插入图片描述

2、string类对象的容量操作

  1. size()(返回有效字符长度)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s = "Hello";cout << "s.size(): " << s.size() << endl;  // 输出 5return 0;
}

功能说明:
返回字符串中当前存储的有效字符数量(不包含结尾的 \0)。

注意事项:
与 length() 功能完全相同,但 size() 是STL容器的通用接口,推荐优先使用。

  1. empty()(检查字符串是否为空)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s1 = "abc";string s2;cout << "s1.empty(): " << s1.empty() << endl;  // 输出 0(false)cout << "s2.empty(): " << s2.empty() << endl;  // 输出 1(true)return 0;
}

功能说明:
若字符串长度为0(即 size() == 0),返回 true,否则返回 false。

注意事项:
比手动检查 size() == 0 更直观,推荐使用。

  1. clear()(清空字符串)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s = "Hello";s.clear();cout << "After clear, s: " << s << endl;       // 输出空cout << "s.size(): " << s.size() << endl;      // 输出 0cout << "s.capacity(): " << s.capacity() << endl; // 容量可能不变return 0;
}

功能说明:
清空字符串内容,但不释放内存(capacity() 可能保持不变)

注意事项:
若需彻底释放内存,可结合 shrink_to_fit()(C++11)使用。

  1. reserve()(预留空间)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s;s.reserve(100);  // 预分配至少100字节的空间cout << "s.capacity(): " << s.capacity() << endl; // 可能 >=100cout << "s.size(): " << s.size() << endl;         // 输出 0(内容仍为空)return 0;
}

功能说明:
提前分配内存以减少后续动态扩容的开销。

注意事项:
实际容量可能大于请求值(由实现决定)。
仅影响容量,不改变内容或长度。

  1. resize()(调整有效字符数量)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s = "Hello";s.resize(8, 'x');  // 扩展至8字符,不足部分用'x'填充cout << "s: " << s << endl;           // 输出 "Helloxxx"s.resize(3);       // 截断至3字符cout << "s: " << s << endl;           // 输出 "Hel"return 0;
}

功能说明:
调整字符串长度:
若 n > size(),填充指定字符(默认 \0)。
若 n < size(),截断多余字符。

注意事项:

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
  2. clear()只是将string中有效字符清空,不改变底层空间大小。
  3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空resize(size_t n, charc)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
  4. eserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。

总结:
在这里插入图片描述

3、string类对象的访问及遍历操作

  1. operator[](下标访问字符)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s = "Hello";// 非const对象:可读可写s[0] = 'h';                  // 修改第一个字符cout << s[0] << endl;        // 输出 'h'(读取第一个字符)// const对象:只读const string cs = "World";cout << cs[2] << endl;       // 输出 'r'(只能读取)// cs[0] = 'w';             // 错误!const对象不可修改return 0;
}

功能说明:
通过下标直接访问指定位置的字符(从 0 开始)。

注意事项:
不检查越界(若 pos >= size(),行为未定义)。
对 const string 返回 const char&,禁止修改。

  1. begin() 和 end()(正向迭代器)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s = "C++";// 使用迭代器遍历for (auto it = s.begin(); it != s.end(); ++it) {cout << *it << " ";      // 输出:C + + }cout << endl;// 修改内容*s.begin() = 'c';           // 将首字符改为 'c'cout << s << endl;           // 输出 "c++"return 0;
}

功能说明:
begin() 返回指向首字符的迭代器,end() 返回末尾的“哨兵”迭代器(指向最后一个字符的下一个位置)。

注意事项:
若字符串为空,begin() == end()。
支持通过迭代器修改字符(除非是 const 迭代器)。

  1. rbegin() 和 rend()(反向迭代器)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s = "12345";// 反向遍历for (auto rit = s.rbegin(); rit != s.rend(); ++rit) {cout << *rit << " ";     // 输出:5 4 3 2 1}cout << endl;return 0;
}

功能说明:
rbegin() 返回指向最后一个字符的反向迭代器,rend() 返回首字符前一个位置的迭代器。

注意事项:
反向迭代器的 ++ 操作会向字符串开头移动。

  1. 范围 for 循环(C++11)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s = "Range";// 简洁遍历(只读)for (char ch : s) {cout << ch << " ";       // 输出:R a n g e}cout << endl;// 修改内容需用引用for (char& ch : s) {ch = toupper(ch);       // 转为大写}cout << s << endl;           // 输出 "RANGE"return 0;
}

功能说明:
语法上,底层通过 begin() 和 end() 实现。

注意事项:
若需修改元素,需使用 char& 引用类型。

总结:在这里插入图片描述

4、string类对象的修改操作

  1. operator+=(追加字符串/字符)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s = "Hello";s += " World";      // 追加字符串s += '!';           // 追加字符cout << s << endl;  // 输出 "Hello World!"return 0;
}

功能说明:
支持追加另一个 string、C风格字符串或单个字符。

注意事项:
直接修改原字符串,是最常用的拼接方式(高效且简洁)。

  1. c_str()(返回C风格字符串)
#include <iostream>
#include <string>
#include <cstring>
using namespace std;int main() 
{string s = "C++";const char* p = s.c_str();  // 获取C风格字符串指针cout << "C-string: " << p << endl;          // 输出 "C++"cout << "Length via strlen: " << strlen(p) << endl;  // 输出 3// 注意:若s被修改,p可能失效s += "11";// cout << p;  // 危险!p可能指向无效内存return 0;
}

功能说明:
返回 const char* 指针,指向以 \0 结尾的字符数组。

注意事项:
不要存储返回的指针,若原 string 被修改,指针可能失效(如扩容后)。
常用于需要C风格字符串的接口(如文件操作、C库函数)。

  1. find() 和 npos(查找字符/子串)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s = "Hello, C++!";size_t pos;// 查找字符pos = s.find('C');if (pos != string::npos) {cout << "'C' found at: " << pos << endl;  // 输出 7}// 查找子串pos = s.find("C++");if (pos != string::npos){cout << "\"C++\" found at: " << pos << endl;  // 输出 7}// 查找不存在的字符pos = s.find('x');if (pos == string::npos) {cout << "'x' not found!" << endl;  // 输出此提示}return 0;
}

功能说明:
find() 返回首次匹配的位置(从 0 开始),失败时返回 string::npos。
可查找字符或子串,支持指定起始位置(如 s.find(‘o’, 5))。

注意事项:
检查返回值时必须使用 npos,不可直接与 -1 比较(npos 是无符号类型)。
rfind() 为反向查找(从后往前)。

  1. substr()(提取子串)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s = "Programming";string sub = s.substr(3, 4);  // 从位置3开始,截取4个字符cout << sub << endl;          // 输出 "gram"// 省略长度参数:截取到末尾sub = s.substr(7);cout << sub << endl;          // 输出 "ming"return 0;
}

功能说明:
返回从 pos 开始、长度为 n 的子串(默认 n 到末尾)。

注意事项:
1. 在string尾部追加字符时,s.push_back© / s.append(1, c) / s += 'c’三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好

总结:
在这里插入图片描述

5、string类非成员函数

  1. operator>> 和 operator<<(输入/输出运算符重载)
#include <iostream>
#include <string>
using namespace std;int main() 
{string s;// 输入示例(遇到空格/换行停止)cout << "Enter a word: ";cin >> s;                   // 输入 "Hello World"cout << "You entered: " << s << endl;  // 输出 "Hello"(空格截断)// 输出示例string name = "Alice";cout << "Name: " << name << endl;    // 输出 "Name: Alice"return 0;
}

功能说明:
从流中读取数据到 string,默认以空格/换行分隔。
将 string 输出到流。

注意事项:
会忽略前导空白符,读取到下一个空白符为止。
需配合 getline() 读取整行(见下文)。

  1. getline()(获取整行输入)
#include <iostream>
#include <string>
using namespace std;int main()
{string line;cout << "Enter a line: ";getline(cin, line);          // 读取整行(包括空格)cout << "Line: " << line << endl;  // 输出完整输入// 指定分隔符(默认'\n')getline(cin, line, ';');    // 读取直到遇到分号cout << "Until ';': " << line << endl;return 0;
}

功能说明:
从输入流中读取一行(默认以 \n 结尾),可指定分隔符。

注意事项:
与 cin >> 混用时,需先清除缓冲区残留的换行符:
cin.ignore(); // 忽略前一个输入的换行

  1. relational operators(比较运算符)
#include <iostream>
#include <string>
using namespace std;int main() 
{string a = "apple";string b = "banana";// 比较示例(按字典序)cout << boolalpha;cout << "a < b: " << (a < b) << endl;   // 输出 true('a' < 'b')cout << "a == \"apple\": " << (a == "apple") << endl;  // 输出 true// 支持所有比较运算符:>, >=, <=, !=return 0;
}

功能说明:
按字符的字典序(ASCII值)逐位比较。

注意事项:
比较时区分大小写(“A” < “a” 为真)。
可直接与C风格字符串比较(如 s == “text”)。

  1. operator+(不推荐使用)
string s1 = "Hello", s2 = "World";
string s3 = s1 + " " + s2;  // 拼接,但每次+生成临时对象

为什么不推荐?
每次 + 操作会生成临时对象,频繁拼接时效率低(尤其是循环中)。
替代方案:
使用 += 或 append() 直接修改原字符串:

string s;
s += s1;
s += " ";
s += s2;  // 无额外拷贝

总结:
在这里插入图片描述

三、vs和g++下string结构的说明

注意:下述结构是在32位平台下进行验证,32位平台下指针占4个字节。

1、vs下string的结构

string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义。

string中字符串的存储空间:

  • 当字符串长度小于16时,使用内部固定的字符数组来存放
  • 当字符串长度大于等于16时,从堆上开辟空间

这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。
其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量。
最后:还有一个指针做一些其他事情。故总共占16+4+4+4=28个字节。
在这里插入图片描述

2、g++下string的结构

G++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指针将来指向一块堆空间,内部包含了如下字段:

  • 空间总大小
  • 字符串有效长度
  • 引用计数
  • 指向堆空间的指针,用来存储字符串
http://www.dtcms.com/a/269627.html

相关文章:

  • 分布式理论:CAP、Base理论
  • 【机器学习深度学习】为什么分类任务中类别比例应接近 1:1?
  • gloo 多卡训练
  • MiniMind:3小时训练26MB微型语言模型,开源项目助力AI初学者快速入门
  • CANDENCE 17.4 进行元器件缓存更新
  • Python爬虫实战:研究phonenumbers工具相关技术
  • Git 提交规范-备忘
  • 【STM32】ADC模数转换基本原理
  • EtherCAT与Profinet协议转换在工业自动化中的应用:以汇川伺服驱动器为例
  • 【FR801xH】富芮坤FR801xH之全功能按键案例
  • JVM系列六:JVM性能调优实战指南
  • Java基础回顾(1)
  • 7 种简单方法将三星文件传输到电脑
  • 瞄准Win10难民,苹果正推出塑料外壳、手机CPU的MacBook
  • 用户生命周期与改进型RFM模型
  • C#读取modbus值,C#读写modbus,支持读写uint32值,Modbus TCP工具类
  • HTTPS工作原理
  • java获取文件的消息摘要APP进行文件完整性校验
  • JavaScript基础篇——第二章 类型转换与常见错误解析
  • 二分查找篇——搜索二维矩阵【LeetCode】遍历法
  • qt-C++笔记之setCentralWidget的使用
  • Visual Studio Code 中统一配置文件在团队协作中的应用
  • 论文略读:Prefix-Tuning: Optimizing Continuous Prompts for Generation
  • Git 安装避坑指南:从环境检查到高级配置的全流程解析
  • EXCEL转html,含图片
  • Linux下SPHinXsys源码编译安装及使用
  • Flutter基础(前端教程③-跳转)
  • Wend看源码-RAGFlow(上)
  • nvm npm nrm 使用教程
  • 台式电脑如何连wifi 快速连接方法