成都网站建设设计

将想法与焦点和您一起共享

C++string类-创新互联

在c语言中,我们想要记录字符串需要创建一个字符串的数组,而c++则提供了另一种方式;

成都创新互联是一家专业从事做网站、网站设计的网络公司。作为专业的建站公司,成都创新互联依托的技术实力、以及多年的网站运营经验,为您提供专业的成都网站建设、全网整合营销推广及网站设计开发服务!

也就是这篇博客所说的string类;

目录

string类

string类的成员函数

string的构造函数

string的容量操作函数

size() / length() / capacity() 函数

reserve(size_t n) / resize(size_t n, char c) 函数

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

operator[] (size_t pos)

begin()/end()/rbegin()/rend()

迭代器——iterator

string类对象修改操作

string的其他函数


string类

#include

作为字符串数组的升级版,string类自然也有它的独特之处——可变长数组;

c语言中的字符串数组只能在创建的时候定好初始的长度,数据长度不能超过数组长度;

而string类则没有这样的顾虑,虽然string变量都有自己的初始长度,但是它内部的成员函数会在输入数据超过初始长度的时候,会自动开辟空间,因此可以不用考虑数组长度;

此外,c++考虑到需要兼容c语言,也给string类重载了一个类似于c语言创建字符串数组的构造方式

但是这里有一点需要注意的是,虽然string类这里的创建方式和c语言的字符串数组一样;

但是它还是有很多不同的;

首先就是它并不是以 ‘\0’ 作为结束的标志;

我们可以看下它内部:

可以看到 s1 并不是以 '\0’ 作为结束标志的;

好,说了那么多 string类和 c语言数组的不同,那么来讲讲string类特有的功能吧;

string类的成员函数

string类中实现了许多成员函数,并且每种函数根据不同的情况有不同的重载;

这里我们就认识一下用的比较多的函数吧;

string的构造函数
 函数名称功能      
string()创造一个空的string对象
string(const char* s)用一个字符串创建string对象
string(size_t n,char c)用 n 个 c 字符创建string对象
string(const string& s)用string对象拷贝构造一个string对象

void test3()
{
	string s1;
	string s2("abcd");
	string s3(5, 'c');
	string s4(s3);

	cout<< "s1 = "<< s1<< endl;
	cout<< "s2 = "<< s2<< endl;
	cout<< "s3 = "<< s3<< endl;
	cout<< "s4 = "<< s4<< endl;


}

我们能够看到,使用不同方式都成功创建了对应的字符串;

string的容量操作函数
 函数名 功能
size()返回字符串有效字符长度
length()返回字符串有效字符长度
capacity()返回空间总大小
empty()检测是否为空
clear()清空有效字符
reserve(size_t n = 0)为字符串开辟空间
resize(size_t n)/(size_t n ,char c)更改有效字符为n,多出的用字符c填充

c++中对于string的容量操作的函数可不少,我们先来一个一个学习吧;

size() / length() / capacity() 函数
void test4()
{
	string s1 = "hello world!";
	cout<< s1.size()<< endl;
	cout<< s1.length()<< endl;
	cout<< s1.capacity()<< endl;
}

首先是string的检查容量大小的函数;

我们发现 size() 函数和 length() 函数的返回值其实是一样的;

这是因为c++中,其他容器中的检查容量大小的函数都是 size() ,因此又引入了 size() 函数; 

此外,我们发现 capacity() 函数的返回值和其他两个函数不一样,这是由string类的实现形成的;

string类的实现可以看做是一个char类型的指针(实际上比这更复杂一点,但是为了好理解可以视为是char类型的指针),并且内部除了 char* 指针,还有一个 size 和 capacity 变量;

而它们三者的关系类似下图: 

实际上string对象开辟的大小为 capacity 这么大,而内部存储的字符串大小为size大小;

这就是为什么两个函数返回值不同的原因;

而 clear() 函数和empty()函数只在乎size()的大小;

而 size 和 capacity 的大小也是有成员变量可以修改的;

reserve(size_t n) / resize(size_t n, char c) 函数

这两个函数都是针对 capacity 变量和 size 变量而出现的函数;

我们先看看 resize 函数;

void test5()
{
	string s1 = "hello world!";
	cout<<"s1.size:"<< s1.size()<<' '<<"s1.capacity:"<

我们发现,resize() 更改了有效字符的长度,而 capacity 并未改变;

并且就算我们将 size 改回原来的长度,也无法恢复原来的数据;

而 reserve() 函数则不用多说,自然是修改 capacity 的大小了,但是它改变得比较奇怪;

void test7()
{
	string s1 = "hello world!";
	cout<< "s1.capacity : "<< s1.capacity()<< ' '<< s1<< endl;
	s1.reserve(20);
	cout<< "s1.capacity : "<< s1.capacity()<< ' '<< s1<< endl;
	s1.reserve(10);
	cout<< "s1.capacity : "<< s1.capacity()<< ' '<< s1<< endl;


}

我们发现,命名我们用 reserve 函数将 capacity 更改到20,但是实际上它的大小为31;

而更改到10则没变化;

这是为什么呢?

我们先去官网上看看reserve函数的描述:

大致意思是:

如果 n 比string 的capacity 大,那么编译器就会扩大容器的大小到 n 或者更大,而其他情况下,就根据容器的实现进行优化;

也就是说,reserve 函数并非根据你输入的数据来扩大容量,而是根据编译器内部的实现来进行扩大;

因此这就是为什么我们扩大到20的时候,会扩大到31;

而至于为什么我们想要缩小到10的时候,则没变呢?

虽然官网描述中说自由优化,实际上大部分编译器的实现当 n 小于 capacity 的时候,并不会对capacity 进行修改;

此外,官网的描述中,规定这个函数不会影响字符串的内容,因此当 n 小于 capacity 的时候就不作修改了;

string类对象的访问及遍历操作
函数名称 功能
operator[] (size_t pos)返回 pos 位置的字符
begin()+end()迭代器访问
rbegin()+end()反向迭代器访问
范围forc++支持的新型for循环访问

通过之前的实践,我们都知道 string 类对象都可以直接通过 cout 直接输出;

但是c++还提供了其他方法遍历 string 类对象;

 operator[] (size_t pos)

首先就是运算符重载的 operator[] 访问了;

void test8()
{
	string s1 = "hello world!";
	for (int i = 0; i< s1.size(); i++)
	{
		cout<< s1[i];
	}
	cout<< endl;
}

这种访问方式就和 c 语言中访问字符数组一样了;

而这样的访问方式实际上是在类内部实现的;

begin()/end()/rbegin()/rend()

c++中有各种各样的容器,由于底层结构不同,所以各种容器的访问方式也不同;

但是c++为了保证容器的统一性,而创造出了迭代器——iterator,来保证容器访问方式的一致性;

迭代器——iterator

每个容器里面都有 iterator ,它是一个类似于指针的东西,用户通过迭代器能够访问容器的内容;

而每一个容器的 begin() 和 end() 函数都是为迭代器服务的;

接下来我们看看迭代器的使用方式吧!

void test9()
{
	string s1 = "hello world!";
	string::iterator is1 = s1.begin();

	while (is1 != s1.end())
	{
		cout<< *is1;
		is1++;
	}
	cout<< endl;

}

迭代器并非通过下标访问那样,只用比较 i 和 size 之间的大小;

迭代器只能通过和容器内部的 end() 返回值来比较,看是否到达变量的尾部;

并且,迭代器也有 const 类型的迭代器,用于被 const 修饰容器变量;

void test9()
{
	const string s1 = "hello world!";
	string::const_iterator is1 = s1.begin();

	while (is1 != s1.end())
	{
		cout<< *is1;
		is1++;
	}
	cout<< endl;

}

rbegin() 和 rend()

前面说过,这两个函数属于反向迭代器,而它的用法和普通迭代器一模一样;

void test9()
{
	string s1 = "hello world!";
	string::reverse_iterator is1 = s1.rbegin();

	while (is1 != s1.rend())
	{
		cout<< *is1;
		is1++;
	}
	cout<

通过反向迭代器,我们能够反向遍历容器内容的内容,其使用方式和普通迭代器是一样的;

范围for

范围for应该算是比较通用的,就不用过多讲解了;

void test9()
{
	string s1 = "hello world!";
	string::reverse_iterator is1 = s1.rbegin();

	for (auto e : s1)
	{
		cout<< e;
	}
	cout<

string类对象修改操作
函数名功能
push_back(char c)在字符串后面添加c
append()    //有多种重载在字符串后面追加字符串
operator+=在字符串后面追加字符串str
c_str()返回c格式字符串
find()+npos在pos位置往后找字符c,并返回所在位置
rfind()在pos位置往前找字符c,并返回所在位置
erase()删除对应位置的元素,并且返回该元素的下一个位置
substr在 str 中从pos位置截取 n 个字符,并返回

push_back(char c)

这个函数一次只能在字符串尾端放一个字符;

可以直接放,也能够放char类型的变量;

void test10()
{
	string s1 = "hello world!";
	char a = 'a';
	cout<< s1<< endl;
	s1.push_back('!');
	s1.push_back('!');
	s1.push_back('!');
	s1.push_back('!');
	s1.push_back(a);

	cout<< s1<< endl;
}

这里可以看到成功的在尾端放入了字符;

append(const char * s)

append(const char* s ,size_t n)

append(const string & s)

append(const string& s,size_t subpos,size_t sublen);

append(size_t n ,char c)

template
append(InputIterator first,InputIterator last)

append这个函数有比较多的重载,接下来我们看看这些重载都是怎么用的吧:

void test10()
{
	string s1 = "hello world!";
	cout<< s1<< endl;
	//append(const char * s)
	s1.append("!!!");//添加!!!到s1尾部
	cout<< s1<< endl;

	//append(const char* s ,size_t n)
	s1.append("++++++",5);//有6个 +  ,但只加了5个上去
	s1.append("@", 5);//n为5,但是由于字符串只有一个@,因此只加一个@
	cout<< s1<< endl;


	string s2 = "how are you?";
	//append(const string & s)
	s1.append(s2);//将s2添加上去
	cout<< s1<< endl;

	//append(const string& s,size_t subpos,size_t sublen);
	s1.append(s2, 4,3);//在 s2 中从 subpos位置开始添加sublen长度的字符串到s1中
	cout<< s1<< endl;

	//append(size_t n ,char c)
	s1.append(5, '*');//添加n个c到s1中
	cout<< s1<< endl;

	//template//append(InputIterator first,InputIterator last)
	string s3 = "goodbye!";
	s1.append(s3.begin(), s3.begin() + 3);//将s3中从begin()位置开始到begin()+3位置的字符添加到s1中
	cout<< s1<< endl;

}

用法如上

operator+= 

相比于 append ,+= 的重载就比较少;

它的用法就是单纯的将 += 右边的字符串添加到左边字符串的尾端;

也是比较常用的一种接口; 

void test11()
{
	string s1 = "hello world!";
	s1 += "!!";
	cout<< s1<< endl;

	string s2 = "how are you?";
	s1 += s2;
	cout<< s1<< endl;

	s1 += '#';
	cout<< s1<< endl;
}

const char* c_str() const

c_str()是一个普通的函数,就是返回string对象中的c字符串;

void test11()
{
	string s1 = "hello world!";
	cout<< s1.c_str()<< endl;


}

find(const string& s,size_t pos = 0)

find(const char* s,size_t pos = 0)

find(const char* s,size_t pos,size_t n)

find(char c,size_t pos = 0)

该函数就是在对象找寻找对应字符的位置,并且返回,若是没找到就会返回-1;

void test11()
{
	string s1 = "hello world!";
	string s2 = " wo";

	//find(const string& s,size_t pos = 0)
	int pos = s1.find(s2);//默认从0位置开始找
	cout<< pos<< endl;

	pos = s1.find(s2, 3);//从3位置开始找
	cout<< pos<< endl;
	
	//find(const char* s,size_t pos = 0)
	pos = s1.find("llo", 0);//从0位置开始找
	cout<< pos<< endl;

	//find(const char* s,size_t pos,size_t n)
	pos = s1.find("ld!",0,5);//从0位置开始找,只找5个位置
	cout<< pos<< endl;

	//find(char c,size_t pos = 0)
	pos = s1.find('d', 0);//从0位置开始找
	cout<< pos<< endl;
}

rfind(const string& s,size_t pos = npos)

rfind(const char* s,size_t pos = npos)

rfind(const char* s,size_t pos,size_t n)

rfind(char c,size_t pos = npos)

rfind 和 find 的使用方式一样,只不过是向前寻找,就不做多解释了;

而上面的 npos 实际上就是表示 string 字符串的尾部,因为 rfind 是向前寻找,因此缺省值给的尾部值;

erase(iterator p)

该函数会删除p位置的元素,然后将后面的元素一个一个往前移,然后返回p元素的下一个元素的位置;

void test1()
{
	string s1 = "abcd";
	string::iterator is1 = s1.begin();
	is1 = s1.erase(is1);
	cout<< *is1<< endl;
}

当使用erase函数的时候,若是在erase函数前面容器扩容了,就会导致迭代器失效

因此需要更新迭代器位置;

substr(size_t pos = 0,size_t  len = npos)

void test12()
{
	string s1 = "hello world!";
	cout<

这个函数就是在字符串中从 pos 位置截取 len 长度的字符并返回;

不过原字符串不会消失;

string的其他函数
函数名功能
operator+将两个string或者字符串加起来并返回
operator>>整体输入string类
operator<<整体输出string类
getline()以行接收string类
relational_operators比较大小

operator+ 

void test13()
{
	string s1 = "hello world!";

	cout<< s1<< endl;

	s1 = s1 + "!!!";
	
	cout<< s1<< endl;

}

这是一个运算符重载,返回一个 + 左边的字符串在前,右边的字符串在后组合而成的字符串;

当然,它也可以多个字符串相加;

void test13()
{
	string s1 = "hello world!";

	cout<< s1<< endl;

	s1 = s1 + "!!!";
	
	cout<< s1<< endl;

	s1 = "!!!" + s1 + "!!!";
	cout<< s1<< endl;

}

operator>>/ operator<<

这两个其实在前面就已经用过多次了:

void test13()
{
	string s1;
	cin >>s1;
	cout<< s1;

}

其中的 operator>>和普通的输入一样,遇见空格或者换行就会中断,如上图;

getline(istream& in,string& s,char delim)

getline(istream& in,string& s)

为了能够按行输入string,c++有 getline 函数;

一种形式是遇到和 delim 相同的字符就停止

void test13()
{
	string s1;
	//getline(istream& in,string& s,char delim)
	getline(cin, s1,'o');//按行接收字符串,遇到delim就结束,这里遇到o就不接收
	cout<< s1<< endl;

}

一种解释单纯的按行接收

void test13()
{
	string s1;
	//getline(istream& in,string& s)
	getline(cin, s1);//按行接收字符串
	cout<< s1<< endl;

}

以上就是string类常用的几种函数。

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


当前文章:C++string类-创新互联
浏览地址:http://chengdu.cdxwcx.cn/article/igids.html