C++中string类用法


String类

在C语言中,我们对于对于字符数组的认识,仅仅局限于字符串,我们对于该数组进行一些操作的时候,往往要配合str系列的库函数来使用,但是这些库函数比较繁琐,底层空间需要用户来维护,有可能会在操作中越界访问。

C++中提供了string类,来完善对于字符串的使用和处理

总结:

  • string类型是表示字符串的字符串类
  • 该类的接口与常规的容器的接口基本相同,再向其中添加了一些专门用来操作string的常规操作。
  • string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>string;
  • 不能操作多字节或者变长字符的序列。

String的用法

我们对于String的使用从string的构造开始

string类对象的构造方法

四种构造方法:

1. string( ) 空参构造,得到一个空的字符串类型

2.string(const char* s) 使用C-string来构造string类对象,即传参一个字符串"xxx"

3.string(size_t n ,char c) 表示得到一个n个c字符的字符串

4.string(const string& s) 表示通过拷贝构造函数来得到新的string对象

下面是代码演示:

int main()
{
    
    
    string s1;   //得到空字符串
    string s2("hello world!!!");  //字符串内容为hello world!!!\0
    string s3(s2);  //拷贝构造函数,数值一样,地址不同
    string s4(10,'c');//十个字符为c的连起来的字符串
    return 0;
}

string类的容量操作

函数名称 功能说明
size 返回字符串有效字符长度
length 返回字符串有效字符长度
capacity 返回空间总大小
empty 检测字符串是否为空串,如果为空,返回true,反之返回false
clear 清空字符串
reserve 扩容,为字符串预留足够的空间
resize 设置有效字符的个数,多出来的空间用‘\0’来代替

代码演示

size和length的区别

size()和length()方法底层实现的原理是一样的,只是为了与其他STL容器接口保持一致,才又加入了size(),以后一般情况下,直接使用size()即可

#include<iostream>
#include<string>
using namespace std;  //需要导入这些头文件以及展开std命名空间,下文不再一一写入代码段
void test11()
{
    
    
	string s("hello world");
	cout << s.size() << endl; //11
	cout << s.length() << endl;//11
}
int main()
{
    
    
	test11();

	return 0;
}

在这里插入图片描述

capacity的使用

capacity在不同的环境下的初始化的数值是不同的,在VS下我们根据下面代码可知,初始值为15,后序大概为1.5倍扩容,在Linux下初始值从0开始,。后序大概为2倍扩容。

void test12()
{
    
    
	//测试capacity
	String::string s;
	int num = s.capacity();
	cout << num << endl;
	for (int i = 0; i < 100; i++)
	{
    
    
		s += i;
		if (num != s.capacity())
		{
    
    
			cout << "capacity改为:" << s.capacity() << endl;
		}
		num = s.capacity();
	}
}
int main()
{
    
    
	test12();

	return 0;
}

在这里插入图片描述

empty和clear的使用

empty是用来判断当前字符串是否为空值(空串),真返回1,假返回0

clear用来清理字符串内容的,实际上是通过'\0'来实现的,会改变size的数值为0,capacity不会改变

void test13()
{
    
    
	string s("hello world");
	//检验empty的使用
	cout << s.empty() << endl;
	s.clear(); //当清空clear字符串s之后,再通过empty判空
	cout << s.empty() << endl;
	
	//empty返回为0表示假,返回为1表示真

	//判断clear之后是否size以及capacity发生改变
	string s1("hello world");
	cout << "当前capacity为:"<<s1.capacity() << endl;
	cout << "当前size为:" <<s1.size() << endl;
	//清理clear
	s1.clear();
	cout << "当前capacity为:" << s1.capacity() << endl;
	cout << "当前size为:" << s1.size() << endl;
}
int main()
{
    
    
	test13();

	return 0;
}

在这里插入图片描述

reserve和resize的使用

reserve是用来扩容更改capacity的,reserve在VS中只能向上扩容,不能缩容(减小),且不会改变size的大小

resize是用来改变字符串长度大小的,不管如何要满足size<=capacity,所以resize底层会在更改size大小前调用reserve来判断此时是否需要扩容,所以可能会影响capacity的大小

//capacity的大小只能是在15 31 ...这样的取值,保证大概1.5倍扩容,向上扩容
void test14()
{
    
    
	string s("hello world");
	cout << "原始数值" << endl;
	cout << "当前capacity为:" << s.capacity() << endl;
	cout << "当前size为:" << s.size() << endl;
	//验证reserve和resize
	s.reserve(20);
	cout << "使用reserve扩容后:" << endl;
	cout << "当前capacity为:" << s.capacity() << endl;
	cout << "当前size为:" << s.size() << endl;
	s.resize(20);
	cout << "使用resize更改size后:" << endl;
	cout << "当前capacity为:" << s.capacity() << endl;
	cout << "当前size为:" << s.size() << endl;
	cout << endl;
	//如果此时我们通过reserve缩容(减小当前容量)
	s.reserve(10000);
	cout << "缩容为10:结果如下" << endl;
	cout << "当前capacity为:" << s.capacity() << endl;
	cout << "当前size为:" << s.size() << endl;

	//那么我们继续缩小size
	s.resize(100);
	cout << "缩小size为5:结果如下" << endl;
	cout << "当前capacity为:" << s.capacity() << endl;
	cout << "当前size为:" << s.size() << endl;
}
int main()
{
    
    
	test14();
	return 0;
}

在这里插入图片描述

shrink_to_fit()

一般capacity扩容之后,不会再缩容,但是通过shrink_to_fit将容器的内部存储空间缩小到恰好容纳当前元素数量,以节省不必要的内存空间

shrink_to_fit使得capacity==size

总结

  1. size()与length()底层实现是一样的,是因为为了与STL其他容器兼容,所以增加了size()的使用,以后一般使用size()
  2. clear()只是将string中有效字符清空,不会改变底层空间的大小
  3. resize(size_t n) 和resize(size_t n , char c) 都是可以改变size,只是对于多余的空间,前者默认用‘\0’来填充,后者用指定字符c来填充,其他是一致的。
  4. resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。也就是size<=capacity
  5. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。

string类对象的访问

我们有四种方法来对于string对象进行访问

函数名称 功能说明
operator[ ] 返回指定位置的字符,const string类对象调用
begin + end begin( )获取string对象的首元素的迭代器+end( )获得最后一个字符的下一个位置的迭代器
rbegin+rend rbegin得到最后一个字符的迭代器+rend得到string对象第一个字符的上一个位置的迭代器
范围for(增强for) 是C++11支持的for循环遍历方式,本质是调用迭代器
void test15()
{
    
    	
	string s("hello world");
	//1.operator[] 访问,可以赋值  和数组一样
	cout << s[0] << endl;
	
	//2.begin 和 end 的使用   迭代器类似于指针的使用
	string::iterator it = s.begin();
	//auto it =s.begin();   可以用auto智能指针接收
	while(it!=s.end())
	{
    
    
		cout << *it << "";
		++it;
	}
	cout << endl;
	
	//3.rbegin和end的使用,就是反向遍历
	string::reverse_iterator rit = s.rbegin();
	while (rit != s.rend())
	{
    
    
		cout << *rit << "";
		++rit;   //反向遍历也是要++rit迭代器
	}
	cout << endl;

	//4.范围for
	for (auto ch : s)
	{
    
    
		cout << ch << "";  //范围for只能正向遍历
	}
	cout << endl;
}
int main()
{
    
    
	test15();
	return 0;
}

在这里插入图片描述

注意:反向迭代器和正向迭代器的rit/it都是++

string类对象的修改操作

函数名称 功能说明
push_back 在字符串后尾插字符c
append 在字符串后追加一个字符串str
operator+= 在字符串后追加字符串str
c_str 返回C格式的字符串,也就是const char* (char指针)
find+npos 从字符串pos位置开始向后找字符c,返回该字符在字符串中的位置
rfind 从字符串pos位置开始向前找字符c,返回该字符在字符串中的位置
substr 在str中从pos位置开始,截取n个字符,然后将其返回
insert 在pos指定位置插入字符串str,很多insert用法,常用的如下。
earse 在pos位置开始,删除n个字符

函数的使用

push_back和append以及operator+=

都是在string类对象尾部,添加字符或者字符串,push_back添加字符C,append以及operator+=添加字符串

void test16()
{
    
    
	string s;//空串
	//push_back的使用
	s.push_back('1');
	s.push_back('2');
	s.push_back('3');
	s.push_back('4');
	s.push_back('5');
	for (auto ch : s)
	{
    
    
		cout << ch << " ";
	}
	cout << endl;
	//append
	s.append("hello world");
	for (auto ch : s)
	{
    
    
		cout << ch << " ";
	}
	cout << endl;

	//3.operator+=
	s += "abcdefg";
	for (auto ch : s)
	{
    
    
		cout << ch << " ";
	}
}
int main()
{
    
    
	test16();
	return 0;
}

在这里插入图片描述

c_str的使用

c_str实际上就是将c++的string类型与C语言中的char* 兼容,因为在C语言中char* 字符数组表示的就是字符串。所以c_str返回的就是C语言中的const char* 类型

void test17()
{
    
    
    //const char* c_str() const;
	string s("hello world");
	cout << s.c_str() << endl;//c_str主要就是兼容C语言 返回的是const char*字符指针类型
}
int main()
{
    
    
	test17();
	return 0;
}

find和rfind的使用

find正向查找,rfind逆向查找,都可以指定pos位置作为起点,向后,向前查找指定字符C或者字符串,找到便返回下标位置,找不到返回的是npos也就是-1

void test18()
{
    
    
	string s("hello world");
	int pos = s.find('h');  //如果找不到返回的是npos 也就是-1
	cout << pos << endl;
	pos = s.find('l', 0);
	cout << pos << endl;
	pos = s.find('l', 6);
	cout << pos << endl;
	pos = s.find("hello");
	cout << pos << endl;

	//rfind的使用,就是从后向前开始查找
	string s1("123456 123456");
	pos = s1.rfind("123456");  //7
	cout << pos << endl;

	pos = s1.rfind('1');  //7
	cout << pos << endl;

	pos = s1.rfind('1',5);  //0
	cout << pos << endl;

}
int main()
{
    
    
	test18();
	return 0;
}

在这里插入图片描述

substr的使用

两个参数,表示起始位置和截止位置,前闭后开 [) 截止位置为缺省参数赋值npos

1. s.substr(5) 表示从下标为5的位置开始截取到字符串s的末尾

2. s.substr(0,5) 表示截取[0,5)的s字符串

void test19()
{
    
    
	//string substr (size_t pos = 0, size_t len = npos) const;
	string s("hello world");
	cout << s << endl;
	s.substr(5);  //在1str中从pos位置开始,截取n个字符,然后将其返回
	cout << s.substr(5) << endl;
	cout << s.substr(0, 5) << endl;
}
int main()
{
    
    
	test19();
	return 0;
}

在这里插入图片描述

insert的用法

insert有很多种方法,但是常用的就那些,比如在pos位置上插入字符串str,在pos位置上插入字符串str并指定该插入该字符串的元素个数,在pos位置上插入字符串str并指定从该字符串的subpos位置开始插入sublen字符,或者是

常用四种用法

  • string& insert (size_t pos, const char* s); 在pos位置上插入字符串str

  • string& insert (size_t pos, const char* s, size_t n); 在pos位置上插入字符串str并指定该插入该字符串的字符个数

  • string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);

    ​ 在pos位置上插入字符串str并指定从该字符串的subpos位置开始插入sublen字符

  • string& insert (size_t pos, size_t n, char c); 在pos位置上插入n个字符c

void test21()
{
    
    
	string s("hello world");
	//string& insert (size_t pos, const char* s);  
	//表示在pos位置上插入字符数组s
	s.insert(1, "123");
	cout << s << endl;
	//string& insert (size_t pos, const char* s, size_t n);
	//表示在pos位置上插入s字符数组的前n个字符
	s.insert(1, "123456",10);   //如果n超过原有数组的长度,将多出来的字符位置填充'\0',相当于将这个"123456"字符串扩容为"123456\0\0\0\0" 然后插入到s对象pos位置
	cout << s.size() << endl;
	// string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);
	s.clear();
	cout << s << endl;
	s.insert(0, "123456");  //如果插入数值pos的位置越界,那么就会报错
	cout << s.size() << endl;
	cout << s << endl;
	//string& insert (size_t pos, size_t n, char c);
	//表示在pos位置上,插入n个字符c
	s.insert(0, 10, 'c');
	cout << s << endl;
}
int main()
{
    
    
	test21();
	return 0;
}

在这里插入图片描述

earse的使用

string& erase (size_t pos = 0, size_t len = npos); 从pos位置删除len个字符,len默认npos,即删除pos位置之后所有元素

iterator erase(iterator p); 删除指定迭代器位置的字符

iterator erase (iterator first, iterator last); 删除在[first,last) 之间的字符

void test22()
{
    
    
	//1. string& erase (size_t pos = 0, size_t len = npos);
	string s("hello world");
	cout << s << endl;
	s.erase(0, 6);
	cout << s << endl;
	
	//2. iterator erase(iterator p);
	s.erase(s.begin() + 3);  //删除该迭代器位置的元素
	cout << s << endl;

	//3. iterator erase (iterator first, iterator last);
	s.erase(s.begin() + 1, s.end());
	cout << s << endl;
}
int main()
{
    
    
	test22();
	return 0;
}

在这里插入图片描述

pop_back

作用为删除字符串的最后一个字符

replace的用法

replace就是对于指定区间的字符进行替换,替换为另一个字符串的内容,参数多样,顺序一般为pos,len,str,subpos,sublen,分别表示replace的字符串的指定下标,长度,要替换为的字符串str,str开始的位置,截取str的长度

主要理解就是,replace替换,需要指定空间,然后替换为str字符串形式,至于替换str字符串的那一部分,由subpos和sublen决定,从左到右,最少三个参数 pos len str。

可以由迭代器来表示范围(pos和len)如:string& replace (iterator i1, iterator i2, const char* s, size_t n);最后参数n表示替换s字符数组的个数

void test23()
{
    
    
	string s("hello world");
	//string& replace (size_t pos,  size_t len,  const string& str);
	cout << s << endl;//hello world
	s.replace(0, 2, "123456");//将pos位置向后的len个字符,替换成str字符串 //123456llo world
	cout << s << endl;
	//string& replace (iterator i1, iterator i2, const string& str); 
	//可以使用迭代器,也能实现
	string s1("hello world"); 
	cout << s1 << endl;
	s1.replace(s1.begin(), s1.begin() + 2, "123456");  //123456llo world  
	cout << s1 << endl;

	//string& replace (size_t pos,  size_t len,  const string& str,size_t subpos, size_t sublen);
	//就是将pos位置向后的len个字符,替换成从subpos位置上长度为sublen的str字符串的字符内容
	//相当于substr之后的字符串替换pos的len个字符
	string s2("hello world");
	cout << s2 << endl;//hello world
	s2.replace(0,2,"123456",0,2);  //12llo world
	cout << s2 << endl;

	//string& replace (size_t pos,  size_t len,  const char* s, size_t n);
	//在pos位置长度为len个字符,替换为s字符数组的前n个字符
	string s3("hello world");
	cout << s3 << endl;//hello world
	s3.replace(0, 2, "123456",2);  //12llo world
	cout << s3 << endl;
}
int main()
{
    
    
	test23();
	return 0;
}

在这里插入图片描述

string类对象非成员函数

operator+、operator>>、operator<<、getline、relational operators的使用

operator+ 少用,因为传值返回,导致深拷贝效率低

operator>>、operator<< 分别表示输入运算符重载和输出运算符重载

getline 获取一行字符串,用法为:getline(cin,s) 输入的字符串放在s内

relational operators 即比较大小,字符串可以比较大小,是根据每一字符的Ascil码值

int main()
{
    
    
    string s;
    cin>>s;  //这样读取字符串,读取到' '的时候就会截止
    getline(cin,s); //这样除非遇到'\n' 反之不会停止读取,遇到' '也会继续读取,所以可以读取一行 
    cout<<s<<endl;
    return 0;
}

总结

  1. string类是对应C语言中的char* 字符数组,C++中为了操作方便,提供的字符串类
  2. string的各种函数的用法,只需要去记住常用的一些即可。比如:append、push_back、+=、find、substr、reserve、resize、empty 、clear、c_str、insert、erase等
  3. 只要是涉及到范围的函数,都是前闭后开,熟练掌握string的使用即可,其扩容机制与版本环境有关。

猜你喜欢

转载自blog.csdn.net/qq_63319459/article/details/131905988