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

STL模板库——string容器

一、string基本概念

  string是C++STL中的字符串容器。本质上是一个封装了char*的动态字符串类,管理堆区分配的字符串数组,提供一系列字符串操作方法。
在底层,std::string维护了几个重要成员:

  • char*指针(指向存储字符串的动态数组)
  • 长度size_t size(字符串的当前大小)
  • 容量 size_t capacity(字符串当前分配的最大空间)
  • 字符存储区(在堆区分配的存储空间)
特点
  1.  自动管理内存
  2.  动态扩展
  3. 提供丰富的成员函数
  4.  兼容C风格字符串
  5. STL兼容性

二、string构造函数

        1. 默认构造(空字符串)

                创建一个空字符串,长度为0,但仍可以动态扩展。

std::string str;  
std::cout << "空字符串:\"" << str << "\"" << std::endl;

        输出内容:

        2. C风格字符串构造

                直接使用C语言的const char*(char[])初始化std::string

std::string  str1("Hello,World!");
std::cout << "字符串:" << str1 << std::endl;

        输出内容:

        3. 拷贝构造

                用已有的std::string创建新字符串,内容完全相同。

std::string  str1("Hello,World!");
string str2(str1);
cout << "拷贝构造:" << str2 << endl;  

        输出内容:

        4.指定长度的字符串构造

                使用char* 创建字符串,但只取前n个字符。

string str3("Hello,World!", 5);
cout << "部分截取:" << str3 << endl;  

        输出内容:

        5. 重复字符构造

                使用n个相同字符初始化string

string str4(10, 'A');
cout << "重复字符:" << str4 << endl; 

        输出内容:

        6. 迭代器构造(从容器中取一部分字符串)

                使用迭代器从original中截取部分内容。

string original = "ABCDEFG";
string str5(original.begin() + 2, original.begin() + 5);
cout << "部分字符串:" << str5 << endl;  

        输出内容:

        7. 移动构造

    std::move允许std::string 进行资源转移。

string tempVar = "Hello";
string str6 = move(tempVar);
cout << "移动后的tempVar:" << tempVar << endl;
cout << "移动到str6:" << str6 << endl; 

        输出内容:

三、string赋值操作

        常见的赋值操作包括:

  • operator =赋值运算符
  • assign() 赋值函数

        1. 赋值运算符operator=

                可以将字符串赋值给string对象,有几种不同的情况:

                (1) 直接赋值C风格字符(char*)

                        将C风格字符串“Hello,World!”赋值给string

string str;
str = "Hello,World!";
cout << str << endl; 

输出内容:

                (2) 赋值给另一个string

       str2拷贝str1的内容,不会影响str1

string str1 = "Hello";
string str2;
str2 = str1;
cout << str2 << endl;  

输出内容:

                (3) 赋值单个字符

        string支持单个字符赋值(char a=’A’),它会被自动转换string(“A”)

string str3;
str3 = 'A';
cout << str3 << endl;  

输出内容:

                (4) 使用move()进行移动赋值

                        将str4的数据转移到str5,避免拷贝,提高效率。

string str4 = "Hello";
string str5;
str5 = move(str4);
cout << "str4: " << str4 << endl;  // str1 变为空
cout << "str5: " << str5 << endl;  // str2 获得 "Hello"   

输出内容:

        2. assign()赋值函数

    assign()string专门提供的赋值函数,可以灵活地从字符串字符迭代器范围等方式进行赋值。

                (1) 赋值C风格字符串

        assign()作用和operator = 一样,但更灵活。

string str;
str.assign("Hello,World!");
cout << str << endl;  

输出内容:

                (2) 赋值部分C风格字符串

                        从char* 开头取n个字符赋值。

string str1;
str.assign("Hello,World!", 5);
cout << str1 << endl;   

输出内容:

                (3) 赋值另一个string

                        等价于str4=str3

string str3 = "Hello";
string str4;
str4.assign(str3);
cout << str4 << endl;  
输出内容:  ![image.png](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/7e9756c9abad4191890e30d39c7f6d1d~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgRXRob25f546L:q75.awebp?rk3s=f64ab15b&x-expires=1756042197&x-signature=Dw33jW9lZKnfSKU%2FSbIkV0TELAM%3D)  
#### (4) 赋值重复字符
创建5个’A’组成的字符串。  
```cpp
string str5;
str5.assign(5, 'A');
cout << str5 << endl;

输出内容:

                (5) 赋值迭代器范围

                        使用迭代器范围截取部分字符串赋值。

string str6 = "ABCDEFG";
string str7;
str7.assign(str6.begin() + 2, str6.begin() + 5);
cout << str7 << endl;

输出内容:

                assign()函数原型

string& assign(const string & str);           // 赋值另一个 string
string& assign(const string & str, size_t pos, size_t len = npos); // 截取部分赋值
string& assign(const char* s);               // 赋值 C 风格字符串
string& assign(const char* s, size_t n);     // 取 C 字符串的前 n 个字符
string& assign(size_t n, char c);            // 赋值 n 个字符 c
template <class InputIterator>
string& assign(InputIterator first, InputIterator last); // 迭代器范围赋值  

四、 string字符串拼接

        在C++string容器中,字符串拼接有多种方式,主要包括:

  1. 使用+运算符
  2. 使用+=运算符
  3. 使用append()函数

        1.使用+运算符

    +用于拼接两个字符串,可以拼接stringchar*,但不能charstring直接相加。
示例:

string str1 = "I";
string str2 = " love";
string result1 = str1 + str2; //拼接两个字符串
cout << result1 << endl;string result2 = result1 + " you!";//拼接string和C字符串
cout << result2 << endl;   

输出结果:


注意:string不能直接拼接单个字符。
错误示例:

string result3 = "Hello" + 'A';
cout << result3 << endl;  

输出结果:


为什么?这是因为代码中存在类型不匹配和指针运算(指针偏移)问题。
问题分析:

  1.  ”Hello”的类型:”Hello”是一个C风格字符串(const char*类型)。
  2.  ‘A’的类型:’A’是一个字符(char类型),其ASCll值为65。
  3.  “Hello”+’A’实际上等价于:const char* ptr =”Hello”+65;

                也就是说,它让”Hello”的指针向后移动了65个字节,但”Hello”实际上只有6个字节(包括\0),因此访问到了随机的内存地址,导致了未定义行为(可能输出Fancyptr或者是其他的值,也可能崩溃)
正确做法:
        string result3 =string(“Hello”)+’A’; //显示转换为string再拼接
或者
        string result3 = “Hello”+string(1,’A’);//先把’A’变成string再拼接

        2.使用+=运算符

                +=直接在原字符串上追加内容,可以拼接stringchar*char
示例:

string str = "Closed off";
str += " from love"; //拼接C风格字符串
cout << str << endl;
str += '!';//追加单个字符
cout << str << endl;   

输出内容:


注意事项:不能拼接数字类型。
错误示范:str += 123;
那么会输出什么?


为什么会输出一个‘{’?
关键问题:
123是整数(int),但stringoperator+=没有定义直接接收int作为参数。因此,C++试图找到一个兼容的重载,但没有匹配的string::operator+=(int)。隐式转换发生了,int被转换成char,而char(123)的ASCll码对应的字符是’{‘。
正确做法:
   str += to_string(123); //先转换为字符串
输出内容:


不要忘记头文件#include<string>

        3.使用append()函数

     append()适用于更复杂的拼接需求,支持拼接部分字符串、指定数量字符等。

  1. 追加整个字符串

string str = "I didn't";
str.append(" need the pain");
cout << str << endl;

输出内容:


2. 追加部分字符串

string str1 = "Once or twice";
str1.append(" was enough and", 11);//只追加前11个字符
cout << str1 << endl;  

输出内容:


3. 追加重复字符

string str2 = "and it was all vain";
str2.append(3, '!');//追加3个'!'
cout << str2 << endl;    

输出内容:


4. 追加另一个string的部分内容

string str3 = "Time starts to";
string str4 = " pass before";
str3.append(str4, 0, 5);//追加str4的前5个字符
cout << str3 << endl;

输出内容:

                string::append()函数原型

string& append(const string & str); // 追加整个字符串
string& append(const string & str, size_t subpos, size_t sublen); // 追加 str 的一部分
string& append(const char* s); // 追加 C 风格字符串
string& append(const char* s, size_t n); // 追加 C 字符串前 n 个字符
string& append(size_t n, char c); // 追加 n 个字符 c
template <class InputIterator>
string& append(InputIterator first, InputIterator last); // 追加迭代器范围内容 

五、 string查找和替换

        在C++string容器中,我们可以使用一系列成员函数来查找子字符串的位置,并进行替换。

        1.find()--查找子字符串

      find()用于查找子字符串在当前string对象中的起始位置。

                 函数原型

size_t find(const string & str, size_t pos = 0) const;
size_t find(const char* s, size_t pos = 0) const;
size_t find(char ch, size_t pos = 0) const;    

    str/s:要查找的字符串或字符
     pos:从字符串的pos位置开始查找(默认为0)
返回值:

  • 找到:返回子串第一个匹配字符的索引
  • 未找到:返回string::npos
    示例
string str = "Before you know it you're frozen";
//查找子字符串"know"
size_t pos = str.find("know");
if (pos != string::npos)cout << "找到\"know\",位置:" << pos << endl;
elsecout << "未找到\"know\"" << endl;
//查找字符‘o',从索引5开始查找
pos = str.find('o', 5);
cout << "找到’o',位置:" << pos << endl;  

输出结果


在上述例子有看到使用的类型是size_t,那么这个是否可以替换为int?那就要先说一说它们之间的区别:

  1. size_t是无符号整数类型,通常表示内存大小、数值索引等非负值。
  2. int是有符合整数,可以存储负数、范围更小。

                那么可以替换吗?
也不建议。虽然在小型程序中,如果没有太大的字符串(最大索引不超过int范围),那么可能不会导致错误。如果找到了,那没什么问题,但若没找到,find()函数返回的是std::string::npos,是一个特殊的常量,它的类型是size_t,通常是一个非常大的无符号整数,在32为系统通常是(2^32-1),其二进制表示与-1的二进制补码相同。那么如果用int回被表示成-1。在64位系统,如果赋值给int,会导致溢出,结果是未定义的。

        2. rfind()--逆向查找

                与find()相同,但从字符串的末尾向前查找,返回最后一次出现的位置。
示例

string str1 = "But something";
size_t pos1 = str1.rfind('n');
cout << "最后一次'n'出现的位置:" << pos1 << endl;

输出

        3.find_first_of()--查找多个字符中的第一个匹配项

                查找字符串中任意一个字符首次出现的位置

                示例

string str2 = "happened for";
size_t pos2 = str2.find_first_of("pe");
cout << "字符 'p' 或 'e' 第一次出现的位置:" << pos2 << endl; 

输出

        4.find_last_of()--逆向查找多个字符

                查找字符串中任意一个字符最后一次出现的位置。

                示例

string str3 = "the very firt time with you";
size_t pos3 = str.find_first_of("ry");
cout<<"字符 'r' 或 'y' 最后一次出现的位置: " << pos3 << endl;  

输出

        5. replace()--替换子字符串

                可以用新字符串替换已有字符串的某部分。
                函数原型

string& replace(size_t pos, size_t len, const string & str);
string& replace(size_t pos, size_t len, const char* s); 
  • pos:要替换的起始位置
  • len:要替换的长度
  • str/s:用于替换的新字符串

示例

string str4 = "My liver melted to the ground";
//替换"liver"为"heart"
str4.replace(str4.find("liver"), 5, "heart");
cout << str4 << endl; 

输出

        6. erase()--删除子字符串

        可以删除string中的某部分内容
        函数原型

string& erase(size_t pos = 0, size_t len = npos);
  • pos:删除的起始位置
  • len:删除的字符数(默认为npos,即删除到末尾)

示例

string str5 = "Founddd something true";
str5.erase(5, 2);
cout << str5 << endl;   

输出

六、string字符串比较

        在C++中,string提供了多种比较方式。主要比较方式包括:

  1. 使用==、!=、<、>等运算符
  2. 使用compare()函数进行字符串比较

        1.运算符比较

                C++string类重载了”==、!=、<、>、<=、>=”这些运算符,比较方式如下:

  • 按ASCll码顺序逐字符比较
  • 若某个字符不同,则比较ASCll码的大小
  • 若前缀相同,则短字符串小于长字符串。

示例

//运算符比较
string str1 = "apple";
string str2 = "banana";
string str3 = "apple";
//比较相等
cout << (str1 == str2) << endl; //0(false)
cout << (str1 == str3) << endl; //1(true)
//比较不相等
cout << (str1 != str2) << endl; //1(true)
//大小比较(按ASCll码表顺序)
cout << (str1 < str2) << endl; //1(true)
cout << (str1 > str2) << endl; //0(false)    

输出

        2. compare()方法

     string::compare()方法提供了更灵活的字符串比较,它返回一个整数值:

  • 0:两个字符串相等
  • <0:当前字符串小于目标字符串
  • >0:当前字符串大于目标字符串

                compare()语法:

int compare(const string & str) const;
int compare(size_t pos, size_t len, const string & str) const;
int compare(size_t pos, size_t len, const string & str, size_t subpos, size_t sublen) const;

                1. 直接比较两个字符串:

string str4 = "stand";
string str5 = "apart";
string str6 = "stand";
cout << str4.compare(str5) << endl;//正数
cout << str4.compare(str6) << endl;//0
cout << str5.compare(str4) << endl;//负数  

输出

                2.只比较字符串的一部分

string str7 = "abcdef";
string str8 = "cde";
// 比较 str7[2] 开始的3个字符 ("cde") 和 str8 ("cde")
cout << str7.compare(2, 3, str8) << endl;  // 0,相等
// 比较 str7[2] 开始的3个字符 ("cde") 和 "cdf"
cout << str7.compare(2, 3, "cdf") << endl; // 负数,因为 'e' < 'f' 

输出

七、string字符串访问和修改

        1.访问字符串中的字符

                1.使用[ ]下标访问

        string允许像数组一样使用[ ]访问字符:

string str = "parse";
cout << str[0] << endl; //p
cout << str[4] << endl; //e                                              

输出


        []不会进行范围检查,如果访问超出范围,可能会导致未定义行为。

                2.使用at()方法

        at()方法与[]类似,但它会检查索引是否超出范围,如果超出,则抛出out_of_range异常。

string str = "parse";
cout << str.at(1) << endl;//a
cout << str.at(10) << endl;//抛出异常

输出


异常:_Xout_of_range("invalid string position");

                3.访问首尾字符

string str = "parse";
cout << "首字符:" << str.front() << endl;
cout << "尾字符:" << str.back() << endl;  

输出

           

        2.修改字符串

                使用[]at()修改字符。

string str = "parse";
str[0] = 'H';//修改第一个字符
str.at(4) = 'h';//使用at()修改
cout << str << endl;

输出

八、 string插入和删除

        1.插入字符

     insert(pos,string)
     insert(pos,string)方法用于在pos位置插入字符串:

string str = "thoug";
str.insert(5, "ht");//在索引5处插入"ht"
cout << str << endl;

输出


      insert(pos,n,char)
pos位置插入n个相同字符:

string str = "thought";
str.insert(7, 3, '!');
cout << str << endl; 

输出

        2.删除字符

      erase(pos,len)
pos开始删除len个字符:

string str1 = "Just do it";
str1.erase(4, 6);//从索引4开始删除6个字符
cout << str1 << endl;

输出


       pop_back()
删除字符串的最后一个字符:

string str2 = "Just do it!";
str.pop_back();//删除最后一个字符
cout << str << endl;  

输出

九、获取string子串

        1.substr()方法

                函数原型:

string substr(size_t pos = 0, size_t len = npos) const;
  • pos:子串的起始位置
  • len:要截取的字符数量(默认npos表示截取到末尾)
  • 返回值:返回指定范围的新字符串,不会修改原字符串

        2.substr()基本用法

                示例1:获取指定范围的子串

string str = "Hello, World!";
string sub1 = str.substr(7, 5); //从索引7开始,截取5个字符
cout << sub1 << endl; //World

输出


示例2:截取从某个位置到结尾的子串

                         如果不提供len,则默认从pos开始一直截取到字符串末尾。

string str = "C++ STL is powerful";
string sub2 = str.substr(6); //从索引6开始,一直到末尾
cout << sub2 << endl; //STL is powerful 

输出


示例3:获取整个字符串(等于拷贝)

                            如果pos =0,且len = npos,等价于复制整个字符串:

string str = "Hello,C++!";
string copy_str = str.substr(); //复制整个字符串
cout << copy_str << endl;

输出

        3.substr()find()结合使用

                可以先使用find()定位子串的位置,再用substr()提取。

string str = "Welcome to C++ programming";
//找到C++在字符串中的位置
size_t pos = str.find("C++");
//提取"C++"及后面的内容
string sub = str.substr(pos);
cout << sub << endl;

输出


十、原型

// <string> Forward declarations -*- C++ -*-// Copyright (C) 2001-2023 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>./** @file bits/stringfwd.h*  This is an internal header file, included by other library headers.*  Do not attempt to use it directly. @headername{string}*///
// ISO C++ 14882: 21 Strings library
//#ifndef _STRINGFWD_H
#define _STRINGFWD_H 1#pragma GCC system_header#include <bits/c++config.h>
#include <bits/memoryfwd.h>namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION/***  @defgroup strings Strings**  @{*/template<class _CharT>struct char_traits;template<> struct char_traits<char>;template<> struct char_traits<wchar_t>;#ifdef _GLIBCXX_USE_CHAR8_Ttemplate<> struct char_traits<char8_t>;
#endif#if __cplusplus >= 201103Ltemplate<> struct char_traits<char16_t>;template<> struct char_traits<char32_t>;
#endif_GLIBCXX_BEGIN_NAMESPACE_CXX11template<typename _CharT, typename _Traits = char_traits<_CharT>,typename _Alloc = allocator<_CharT> >class basic_string;_GLIBCXX_END_NAMESPACE_CXX11/// A string of @c chartypedef basic_string<char>    string;   /// A string of @c wchar_ttypedef basic_string<wchar_t> wstring;   #ifdef _GLIBCXX_USE_CHAR8_T/// A string of @c char8_ttypedef basic_string<char8_t> u8string;
#endif#if __cplusplus >= 201103L/// A string of @c char16_ttypedef basic_string<char16_t> u16string; /// A string of @c char32_ttypedef basic_string<char32_t> u32string; 
#endif/** @}  */_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std#endif	// _STRINGFWD_H

http://www.dtcms.com/a/340436.html

相关文章:

  • DPO,PPO,GRPO
  • 【Linux基础知识系列:第一百零四篇】使用apt-cache管理软件包信息
  • 【数据结构】直接选择排序
  • 跨域问题解决方法
  • 链表-24.两两交换链表中的结点-力扣(LeetCode)
  • Spring Boot 3整合Nacos,配置namespace
  • 云计算学习100天-第26天
  • linux的sysctl系统以及systemd系统。
  • Linux + arm 内存属性
  • 静/动态库 IIC(arm) day58
  • 机器学习——网格搜索(GridSearchCV)超参数优化
  • Linux + arm 内存屏障
  • 商用厨房物联网智能化解决方案——打造环保、高效、安全的智慧餐饮新生态
  • C语言基础:(二十)自定义类型:结构体
  • 领码方案:通用物联网数据采集低代码集成平台——万物智联时代的黄金钥匙
  • 【Grafana】grafana-image-renderer配合python脚本实现仪表盘导出pdf
  • 车载软件架构 --- 赢得汽车软件开发竞赛
  • MySQL事务及原理详解
  • YAML格式笔记
  • SQL面试题及详细答案150道(41-60) --- 条件查询与分组篇
  • 【自记】Power BI 中 ALL、ALLSELECTED、ALLEXCEPT、ALLNOBLANKROW 的区别说明
  • 自学嵌入式第二十三天:数据结构(3)-双链表
  • SQL四大类命令(DQL、DML、DDL、DCL)
  • 第1课_Rust基础入门
  • Rust系统编程:从入门到实战的蜕变之旅
  • MySQL 数据与表结构导出 Excel 技术文档
  • 基础笔记8.20
  • Spring Cloud Gateway 负载均衡全面指南
  • 甘特图-项目可视化引擎|Highcharts.js 模块特征
  • Linux I/O 多路复用实战:Select/Poll 编程指南