【C++】STL常用容器总结之十二:string类

article/2025/8/15 12:44:13

13、string类

声明

string类本不是STL的容器,但是它与STL容器有着很多相似的操作,因此,把string放在这里一起进行介绍。
之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下的需要。我们尽可以把它看成是C++的基本数据类型。
首先,为了在我们的程序中使用string类型,我们必须包含头文件。如下:

#include  <string>  // 注意这里不是string.h,string.h是C字符串头文件

1、声明一个C++字符串

声明一个字符串变量很简单: string str;
这样我们就声明了一个字符串变量,但既然是一个类,就有构造函数和析构函数。上面的声明没有传入参数,所以就直接使用了string的默认的构造函数,这个函数所作的就是把str初始化为一个空字符串。string类的构造函数和析构函数如下:

1)  string s;  // 生成一个空字符串s 
2)  string s(str) ; // 拷贝构造函数生成str的复制品 
3)  string s(str, stridx);  // 将字符串str内"始于位置stridx"的部分当作字符串的初值 
4)  string s(str, stridx, strlen) ; // 将字符串str内"始于stridx且长度顶多strlen"的部分作为字符串的初值 
5)  string s(cstr) ;  // 将C字符串(以NULL结束)作为s的初值 
6)  string s(chars, chars_len) ;  // 将C字符串前chars_len个字符作为字符串s的初值。 
7)  string s(num, ‘c’) ;  // 生成一个字符串,包含num个c字符 
8)  string s(“value”);  string s=“value”;  // 将s初始化为一个字符串字面值副本
9)  string s(begin, end);  // 以区间begin/end(不包含end)内的字符作为字符串s的初值 
10) s.~string();  //销毁所有字符,释放内存 

2、string与C字符数组的比较

string串要取得其中某一个字符,和传统的C字符串一样,可以用s[i]的方式取得。比较不一样的是如果s有三个字符,传统C的字符串的s[3]是’\0’字符,但是C++的string则是只到s[2]这个字符而已。

1、C风格字符串

  • 用”“括起来的字符串常量,C++中的字符串常量由编译器在末尾添加一个空字符;
  • 末尾添加了‘\0’的字符数组,C风格字符串的末尾必须有一个’\0’。

2、C字符数组及其与string串的区别

  • char ch[ ]={‘C’, ‘+’, ‘+’}; //末尾无NULL
  • char ch[ ]={‘C’, ‘+’, ‘+’, ‘\0’}; //末尾显式添加NULL
  • char ch[ ]=”C++”; //末尾自动添加NULL字符 若[ ]内数字大于实际字符数,将实际字符存入数组,其余位置全部为’\0’。
    这里写图片描述

3、string对象的操作

string s;
1)  s.empty();  // s为空串 返回true
2)  s.size();  // 返回s中字符个数 类型应为:string::size_type
3)  s[n];  //0开始相当于下标访问
4)  s1+s2;  // 把s1和s2连接成新串 返回新串 
5)  s1=s2;  // 把s1替换为s2的副本
6)  v1==v2;  // 比较,相等返回true
7)  `!=, <, <=, >, >=`  惯有操作 任何一个大写字母都小于任意的小写字母

当进行string对象和字符串字面值混合连接操作时,+操作符的左右操作数必须至少有一个是string类型的:

string s1(“hello”);
string s3=s1+”world”;  //合法操作
string s4=”hello”+”world”;  //非法操作:两个字符串字面值相加

4、字符串操作函数

1、string类函数

1) =, s.assign() // 赋以新值
2) swap() // 交换两个字符串的内容
3) +=, s.append(), s.push_back() // 在尾部添加字符
4) s.insert() // 插入字符
5) s.erase() // 删除字符
6) s.clear() // 删除全部字符
7) s.replace() // 替换字符
8) + // 串联字符串
9) ==,!=,<,<=,>,>=,compare() // 比较字符串
10) size(),length() // 返回字符数量
11) max_size() // 返回字符的可能最大个数
12) s.empty() // 判断字符串是否为空
13) s.capacity() // 返回重新分配之前的字符容量
14) reserve() // 保留一定量内存以容纳一定数量的字符
15) [ ], at() // 存取单一字符
16) >>,getline() // 从stream读取某值
17) << // 将谋值写入stream
18) copy() // 将某值赋值为一个C_string
19) c_str() // 返回一个指向正规C字符串(C_string)的指针 内容与本string串相同 有’\0’
20) data() // 将内容以字符数组形式返回 无’\0’
21) s.substr() // 返回某个子字符串
22) begin() end() // 提供类似STL的迭代器支持
23) rbegin() rend() // 逆向迭代器
24) get_allocator() // 返回配置器

2、函数说明

1、s.assign();

s.assign(str); // 不说 
s.assign(str,1,3); // 如果str是"iamangel" 就是把"ama"赋给字符串 
s.assign(str,2,string::npos); // 把字符串str从索引值2开始到结尾赋给s 
s.assign("gaint"); // 不说 
s.assign("nico",5); // 把’n’ ‘I’ ‘c’ ‘o’ ‘\0’赋给字符串 
s.assign(5,'x'); // 把五个x赋给字符串

2、大小和容量函数

一个C++字符串存在三种大小:
1) 现有的字符数,函数是s.size()和s.length(),他们等效。s.empty()用来检查字符串是否为空。
2) max_size(); 这个大小是指当前C++字符串最多能包含的字符数,很可能和机器本身的限制或者字符串所在位置连续内存的大小有关系。
3) capacity()重新分配内存之前string所能包含的最大字符数。
这里另一个需要指出的是reserve()函数,这个函数为string重新分配内存。重新分配的大小由其参数决定,默认参数为0,这时候会对string进行非强制性缩减。

3、元素存取

我们可以使用下标操作符[]和函数at()对元素包含的字符进行访问。但是应该注意的是操作符[]并不检查索引是否有效(有效索引0~str.length()),如果索引失效,会引起未定义的行为。而at()会检查,如果使用at()的时候索引无效,会抛出out_of_range异常。
有一个例外不得不说,const string a;的操作符[]对索引值是a.length()仍然有效,其返回值是’\0’。其他的各种情况,a.length()索引都是无效的。

4、比较函数

C ++字符串支持常见的比较操作符(>,>=,<,<=,==,!=),甚至支持string与C-string的比较(如 str<”hello”)。在使用>,>=,<,<=这些操作符的时候是根据”当前字符特性”将字符按字典顺序进行逐一的比较。字典排序靠前的字符小,比较的顺序是从前向后比较,遇到不相等的字符就按这个位置上的两个字符的比较结果确定两个字符串的大小。
另一个功能强大的比较函数是成员函数compare()。他支持多参数处理,支持用索引值和长度定位子串来进行比较。他返回一个整数来表示比较结果,返回值意义如下:0-相等 、>0-大于、<0-小于。

5、插入字符

也许你需要在string中间的某个位置插入字符串,这时候你可以用insert()函数,这个函数需要你指定一个安插位置的索引,被插入的字符串将放在这个索引的后面。
s.insert(0,”my name”);
s.insert(1,str);
这种形式的insert()函数不支持传入单个字符,这时的单个字符必须写成字符串形式。为了插入单个字符,insert()函数提供了两个对插入单个字符操作的重载函数:
insert(size_type index, size_type num, chart c)和insert(iterator pos, size_type num, chart c)。
其中size_type是无符号整数,iterator是char*,所以,你这么调用insert函数是不行的:
insert(0, 1, ‘j’);这时候第一个参数将转换成哪一个呢?
所以你必须这么写:insert((string::size_type)0, 1, ‘j’)!
第二种形式指出了使用迭代器安插字符的形式。

6、提取子串s.substr()

s.substr(); // 返回s的全部内容 
s.substr(11); // 从索引11往后的子串 
s.substr(5,6); // 从索引5开始6个字符

5、字符串流stringstream操作

Iostream标准库支持内存中的输入输出,只要将流与存储在程序内存中的string对象捆绑起来即可。此时,可使用iostream输入和输出操作符读写这个stream对象。使用stringstream,我们必须包含头文件#include。

1、string s

1)  >>操作符 // 用于从istream对象中读入输入
2)  is >> s;  // 从输入流is中读取一个以空白字符分割的字符串,写入s
3)  <<操作符 // 用于把输出写到ostream对象中
4)  os << s; // 将s写到输出流os中
5)  getline(is, s);  // 从输入流is中读取一行字符,写入s,直到遇到分行符或到了文件尾
6)  istream // 输入流 提供输入操作
7)  ostream // 输出流 提供输出操作

2、stringstream特定的操作

1)  stringstream strm; // 创建自由的stringstream对象
2)  stringstream strm(s); // 创建存储s的副本的stringstream对象,s是stringstream类型
3)  strm.str(); // 返回strm中存储的string类型对象
4)  strm.str(s); // 将string类型的s复制给strm 返回void

3、string到int的转换

stringstream通常是用来做数据转换的,如果你打算在多次转换中使用同一个stringstream对象,记住在每次转换前要使用clear()方法。在多次转换中重复使用同一个stringstream(而不是每次都创建一个新的对象)对象最大的好处在于效率。stringstream对象的构造和析构函数通常是非常耗费CPU时间的。
string到int的转换(与其他类型间的转换一样大同小异):

string result=”10000”;  
int n=0;
stream<<result;
stream>>n;  // n等于10000

6、C字符串、string串、stringstream之间的关系

首先必须了解,string可以被看成是以字符为元素的一种容器。字符构成序列(字符串)。有时候在字符序列中进行遍历,标准的string类提供了STL容器接口。具有一些成员函数比如begin()、end(),迭代器可以根据他们进行定位。注意,与char*不同的是,string不一定以NULL(‘\0’)结束。string长度可以根据length()得到,string可以根据下标访问。所以,不能将string直接赋值给char*。

1、string转换成const char *

如果要将字面值string直接转换成const char *类型。string有2个函数可以运用:一个是.c_str(),一个是data成员函数。
c_str()函数返回一个指向正规C字符串的指针,内容与本string串相同。这是为了与C语言兼容,在C语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成C中的字符串样式。注意:一定要使用strcpy()函数等来操作方法c_str()返回的指针

string str = "Hello World";
const char *ch1 = str.c_str();
const char *ch2 = str.data();

此时,ch1与ch2的内容将都是”Hello World”。但是只能转换成const char*,如果去掉const编译不能通过。

2、string转换成char *

C++提供的由C++字符串得到对应的C_string的方法是使用data()、c_str()和copy(),其中
1) data()以字符数组的形式返回字符串内容,但并不添加’\0’。
2) c_str()返回一个以’\0’结尾的字符数组,返回值是const char*。
3) copy()则把字符串的内容复制或写入既有的c_string或字符数组内。
C++字符串并不以’\0’结尾。我的建议是在程序中能使用C++字符串就使用,除非万不得已不选用c_string。
如果要转换成char*,可以用string的一个成员函数strcpy实现。

string str = "Hello World";
int len = str.length();
char *data = new char[len+1];  //这里+1还是不+1需要注意
strcpy(data, str.c_str());  // const char *data = new char[len+1];  strcpy(data, str);

此时,data中的内容为”Hello World”使用c_str()要么str赋给一个const指针,要么用strcpy()复制。

3、char *转换成string

string类型能够自动将C风格的字符串转换成string对象:

string str; 
const char *pc = "Hello World"; 
str = pc;
printf(“%s\n”, str);  //此处出现错误的输出
cout<<str<<endl;

不过这个是会出现问题的。有一种情况我要说明一下。当我们定义了一个string类型之后,用printf(“%s”,str);输出是会出问题的。这是因为“%s”要求后面的对象的首地址。但是string不是这样的一个类型。所以肯定出错。
用cout输出是没有问题的,若一定要printf输出。那么可以这样:

printf("%s",str.c_str());

4、char[ ] 转换成string

这个与char*的情况相同,也可以直接赋值,但是也会出现上面的问题,需要同样的处理。
- 字符数组转化成string类型:

char ch [] = "ABCDEFG";
string str(ch); //也可string str = ch;

或者

char ch [] = "ABCDEFG";
string str;
str = ch; //在原有基础上添加可以用str += ch;

5、string转换成char[ ]

string对象转换成C风格的字符串:

const char *str = s.c_str();

这是因为为了防止字符数组被程序直接处理c_str()返回了一个指向常量数组的指针。
由于我们知道string的长度可以根据length()函数得到,又可以根据下标直接访问,所以用一个循环就可以赋值了,这样的转换不可以直接赋值。

string str = "Hello World";
int len=str.length();
char ch[255]={};
for( int i=0;i<str.length();i++)
ch[i] = str[i];
ch[len+1] = '\0';
printf("%s\n", ch);
cout<<ch<<endl;

6、stringstream与string间的绑定

stringstream strm;
string s;
strm<<s;  // 将s写入到strm
strm>>s;  // 从strm读取串写入s
strm.str(); // 返回strm中存储的string类型对象
strm.str(s); // 将string类型的s复制给strm 返回void
char* cstr;  // 将C字符数组转换成流
string str(cstr);
stringstream ss(str);

http://chatgpt.dhexx.cn/article/e7GZYMWI.shtml

相关文章

string的常用用法详解

一般我们在C语言中用到字符串&#xff0c;都是使用字符数组来存放&#xff0c;但是操作字符数组有时候会不便&#xff0c;所以为了方便操作&#xff0c;在C的STL中加入了字符串类型&#xff08;string&#xff09;。 想要复习以往字符数组的相关知识点请点击以下链接&#xff…

对于String的用法详解

目录 一、String的基本用法 二、对于字符串常量池的理解。 三、String类的常见操作。 四、StringBuffer和StringBuilder的使用。 一、String的基本用法 1.1String的创建方法 //第一种创建方法 String str"Hellow"; System.out.println(str);//第二种创建方法 S…

String类的常见用法

目录 1、创建字符串的四种方式&#xff1a;(方式一和方式四最常用&#xff09; 2、字符串的字面量&#xff08;也是字符串的对象&#xff09; 3、字符串比较 4、关于字符串的常量池问题 5、手工入池—String 类提供的 intern 方法 6、字符串的不可变性&#xff1a; 7、修…

非抢占式多级反馈队列优先级调度算法 C++实现

介绍 前段时间比较忙&#xff0c;没有更新&#xff0c;这次的也是操作系统的一个实践作业 C实现非抢占式多级反馈队列优先级调度算法&#xff0c;希望可以帮到你们。 问题介绍 这里我用课件里的内容 1.应设置多个就绪队列&#xff0c;并为每个队列赋予不同的优先级。第一个队…

多级反馈队列算法补充

http://pages.cs.wisc.edu/~remzi/OSTEP/cpu-sched-mlfq.pdf 本文是多级反馈队列&#xff08;multi-level feedback queue&#xff0c;MLFQ&#xff09;算法的一些小补充&#xff08;两个缺陷与修改方法&#xff09;&#xff0c;参考了上面链接。因为自己用中文没有搜到想要的…

操作系统-多级反馈队列

概述 1962年&#xff0c;Corbato首次提出多级反馈队列&#xff0c;应用于兼容时分共享系统(CTSS)。Corbato因在CTSS中的贡献和后来在Multics中的贡献&#xff0c;获得了ACM颁发的图灵奖(Turing Award)。该调度程序经过多年的一系列优化&#xff0c;出现在许多现代操作系统中。 …

操作系统学习(二):浅析多级反馈队列MLFQ

目录 0、引言 1、多级反馈队列&#xff08;MLFQ&#xff09;的基本规则 2、MLFQ的规则具体说明 3、MLFQ调优及其他问题 4、总结 0、引言 在上篇文章操作系统学习&#xff08;一&#xff09;&#xff1a;浅析操作系统进程调度算法中讲到&#xff0c;在一个通用的操作系统中…

多级反馈队列调度算法(附Python3实现代码)

一、多级反馈队列调度算法 多级反馈队列调度算法是进程调度的一种算法&#xff0c;该调度算法可以不用事先知道各种进程所需的执行时间&#xff0c;还可以较好的满足各种类型进程的需要&#xff0c;是目前共认的一种较好的进程调度算法。 那你可能马上就要问了&#xff0c;多…

调度:多级反馈队列

多级反馈队列&#xff08;Multi-level Feedback Queue, MLFQ&#xff09;是有Corbato在1962年提出的&#xff0c;用于兼容时分共享系统。现在其经过多年的优化&#xff0c;已经被应用于很多现代操作系统中。多级反馈队列是为了解决两方面问题。一&#xff1a;优化周转时间。在之…

多级队列调度和多级反馈队列调度算法的实现

多级队列调度算法 操作系统实验导航 实验一&#xff1a;银行家算法 https://blog.csdn.net/weixin_46291251/article/details/115384510 实验二&#xff1a;多级队列调度和多级反馈队列调度算法 https://blog.csdn.net/weixin_46291251/article/details/115530582 实验三&…

多级反馈队列调度算法模拟实现

实验一 多级反馈队列调度算法 一. 主要实现方法和代码介绍 ​ 1.编写进程类,其只包含所需的运行时间和进程编号两个属性,还有一个运行方法,此方法就是将所需的运行时间属性减去.传入的运行时间. ​ 2.创建进程函数:创建maxp个进程,(应该不超过10,在此创建九个,即暂时不进行进…

计操实验 多级反馈队列C语言

计操实验 多级反馈队列C语言 需求&#xff1a; 1.队列4级&#xff0c;每一级的队列长度均为10&#xff1b;第一级的时间片为T&#xff0c;第二级的时间片为2T&#xff0c;第三级的时间片为4T&#xff0c;第四级的时间片为8T&#xff1b;&#xff08;T的大小自己定&#xff09; …

【操作系统】轮转和多级反馈队列

随着计算机的技术逐渐步入家用后&#xff0c;新的调度指标接踵而来&#xff0c;周转时间已经不能满足人们日常工作的需求&#xff0c;更多时候人们更希望计算机能有更好的交互性&#xff0c;使其能更快地去响应任务&#xff0c;由此针对优化响应时间的调度策略也遍地开花&#…

多级反馈队列调度算法(c++)

如果对你有帮助&#xff0c;可以给卑微的博主留个赞、关注、收藏 (不是) (骗一下数据&#xff0c;说不定以后面试就过了&#xff0c;拜谢) 操作系统基本调度算法&#xff0c;多级反馈队列调度算法。在划分时间片的调度算法中&#xff0c;多级反馈队列算法兼顾提高系统吞吐…

多级反馈队列调度算法

实验目的&#xff1a; 在Linux下编程实现多级反馈队列调度算法&#xff0c;采用三级调度策略&#xff0c;所有进程先按到达顺序进入一级队列&#xff0c;按照时间片为2轮转一次&#xff0c;一个时间片内未完成的进程被依次移入二队列尾部。当一级队列中没有进程时&#xff0c;开…

多级反馈队列调度

多级反馈队列 ​ 多级反馈队列&#xff08;Multi-level Feedback Queue&#xff0c; MLFQ&#xff09;&#xff0c;与上个世纪70年代提出&#xff0c;主要应用于时分共享系统。主要解决两方面问题&#xff1a;一个是优化周转时间&#xff0c;一个是要给用户很好的交互体验。ML…

多级反馈队列算法

步骤&#xff1a; 0时刻&#xff0c;P1到达就绪队列&#xff08;时间片为4的&#xff09;P1先执行2ms&#xff0c;P2到达还未到时间片&#xff0c;P1继续执行2ms后&#xff0c;时间片到达了&#xff0c;P1滑到下一个就绪队列&#xff08;时间片为6的&#xff09;此时&#xff…

linux多级反馈队列的实现,多级反馈队列调度算法详解

通常在使用多级队列调度算法时&#xff0c;进程进入系统时被永久地分配到某个队列。例如&#xff0c;如果前台和后台进程分别具有单独队列&#xff0c;那么进程并不从一个队列移到另一个队列&#xff0c;这是因为进程不会改变前台或后台的性质。这种设置的优点是调度开销低&…

对数线性模型

http://blog.csdn.net/pipisorry/article/details/52788947 特征和指示特征 对数线性模型log linear model 对数线性模型有&#xff1a;最大熵模型和逻辑斯谛回归。 [概率图模型原理与技术] [PGM&#xff1a;无向图模型&#xff1a;马尔可夫网 ] 皮皮blog 最大熵模型的一般形式…

广义线性模型(Generalized Linear Model)之三:Poisson回归

广义线性模型&#xff08;Generalized Linear Model&#xff09;之三&#xff1a;Poisson回归 一、泊松回归&#xff08;Poisson regression&#xff09;简介&#xff08;一&#xff09;泊松回归&#xff08;二&#xff09;计数数据&#xff08;三&#xff09;泊松分布1&#x…