C++| STL之string

发布于:2024-07-02 ⋅ 阅读:(13) ⋅ 点赞:(0)

前言:最近在做LeetCode算法题,C++字符串通常都是string作为输入,所以补充一下STL里面string。在介绍的具体使用的时候,会补充char字符串相关的进行对比。

创建

string s1;
string s2 (3,'a');// aaa
string s3 ("value");// value
string s4 (s3);// value
string s5 = "hello!";// hello!

大小和容量

string特有的函数

  • size()和length():返回string对象的字符个数,他们执行效果相同。
  • max_size():返回string对象最多包含的字符数,超出会抛出length_error异常。
  • capacity():重新分配内存之前,string对象能包含的最大字符数。

注意:max_size()是当前分配可容纳字符数,size()是已经使用的,例如下面代码。

string s = "abc"; 
s.reserve(20); 
cout << s.size() << endl;  // 3
cout << s.max_size() << endl;  // 31因为string内存分配按照(n*16-1)分配,能满足20大小的n=2

通用的函数

  • sizeof():返回占用内存的多少。返回的是数组在内存中占用的字节数,字符串数组会包含结束符。
  • strlen():只能用char* 做参数,而且必须以’\0’结尾的,但不计算后面的’\0’。对比,sizeof是运算符,strlen是函数。

效果对比

string s = "abcd";
cout << sizeof(s) << endl;  //16,string每个字符占内存大小和char不同
cout << sizeof("abcd") << endl;  //5 
cout << s.length() << endl; //4
cout << s.size() << endl; //4,s.length()和s.size()功能一样
cout << strlen("abcd") << endl; //4,不计算后面的’\0’

常用:size()、length()、sizeof()。

遍历

string和vector比较相似,都是不定长,vector的操作基本都可以用于string,所以也能像vector那样遍历string里面的字符。

string s = "hello!";// hello!
for(int i=0;i<s.size();i++)
	cout<<s[i]<<endl

字符串比较

  1. 关系运算符
string s1("abcd");
string s2("abcd");
if(str1 == str2)
	cout<<"str1 = str2"<<endl;
  1. compare函数
// 比较的字典序,每个字符逐个对比,越小越靠前,例如abc比abd小,hello比hellow小,因为hello比完了hellow还有个w
string s1="hello";
string s2="hellow";

int a=s1.compare(s2);// s1等于s2返回0,s1小于s2返回-1,s1大于s2返回1
cout<<a<<endl;// -1

int b=s1.compare(2,3,s2);// s1下标为2的字符开始的3个字符llo和s2进行比较
cout<<b<<endl;// 1

int c=s1.compare(2,3,s2,1,3);// s1下标为2的字符开始的3个字符llo和s2下标为1的字符开始的3个字符ell比较
cout<<c<<endl;// 1
  1. 遍历:全部遍历按照自己的规则一一对比,前面提过遍历了。

插入字符

函数:

  • push_back(char):尾插一个字符char。
  • insert(pos,char):在制定的位置pos前插入字符char。

测试代码:

string s;
// 尾插一个字符
s.push_back('a');
s.push_back('b');
s.push_back('c');
cout<<"s:"<<s<<endl; // s:abc

// 指定位置插入
s.insert(s.begin(),'a');
cout<<"s insert:"<<s1<<endl; // s insert:aabc

拼接字符串

方法:

  • 运算符:str+=str1。
  • append(str)

测试代码:

string s="hello";
string s1=" world";
s.append(s1);// hello world
// s+=s1;// 可替换

分配内存

函数:

  • reserve():为容器预留足够的空间,避免不必要的重复分配,减少系统开销,影响capacity。
  • resize():调整容器中有效数据区域的尺寸,如果尺寸变小,多余的截掉;若尺寸变大,第二个参数填充,影响size。

疑问:看到这两个概念的时候,会想resize有点用,可以截断string,但是reserve似乎没必要。因为string不是不定长吗,看可以不断push_back,不需要预先分配足够的空间啊。
解答:这个和string的运行机制有关,实际上每个string声明和使用的时候都会预先分配好一个容量capacity,如果不定长添加给string后总容量超过了capacity,系统会重新malloc一块连续长度足够的内存,然后把数据都复制到新的位置,再把原先的内存还给系统。如果能预先知道需要多少空间,可以提前reserve,这样能够避免系统开销,提高运行效率。

查找

查找函数find:

  • str.find(str1,pos):在str字符串中找到str1子串的首位置pos,找不到内容则字符串搜索函数返回npos.

截取

截取函数substr:

  • str.substr(pos,count):截取str字符串pos位置开始,count长度的子串。

分割

stirng:并没有通用的函数,得自己根据其它功能的函数实现。

  • string流:用string流中的getline函数,关于stream流相关的内容,我在博客C++| excel存取开头有介绍。
  • find和substr函数组合:每次find到分隔符位置,就截取一部分。

string流代码实现string分割:

string str= "hello world";
istringstream iss(str);	// 输入流
string token;			// 接收缓冲区
char split=' ';
while (getline(iss, token, split))	// 以split为分隔符
{
	cout << token << endl; // 输出
}
// 结果:
// hello
// world

find和substr函数实现string分割:

string str= "hello world";
char split=' ';
str+=split;// 末尾也加入分隔符
size_t pos=str.find(split);// size_t表示C中任何对象所能达到的最大长度,无符号整数
while(pos!=str.npos)// 找不到内容则字符串搜索函数返回npos
{
	string temp = str.substr(0, pos);
	cout << temp << endl; // 输出
	str=str.substr(pos + 1, str.size());
	pos = str.find(split);
}
// 结果:
// hello
// world

char:

  • strtok(sign):sign指定分割符,根据sign来分割字符串。
char str[] = "hello world!";
const char *split = " !";// 空格和感叹号
char *p = strtok(str,split);
while( p2 != NULL )
{
	cout<<p<<endl;
	p = strtok(NULL,split);
}
// 结果
// hello
// world

对比起来,似乎char的方法方便多了,可以string转char,下一部分会详细介绍。

注意:分割符如果是转义字符得转移符号“\”。

string互转char*

string转char*:

  • c_str():返回一个以’\0’结尾的字符数组。
  • data():仅返回字符串内容,而不含有结束符’\0’。
  • 遍历一个个位置赋值。
char ch1[20],ch2[20];
string s="123456";
strcpy(ch1,s.c_str());
strcpy(ch2,s.data());

char*转string:直接赋值。

string s;
char* p ="hello";
s = p;