C++:string类

C++ std::string类介绍

在C++中,std::string类是标准模板库(Standard  Template Library,STL)d 一部分,它提供了对字符串的封装,使得字符串的处理变动更加方安全和高效。与传统都C语言分隔字符串(字符串是以'\0'结尾的一些字符的合集)相比,std::string类提供了丰富的成员函数来执行各种字符串操作,如连接、查找、比较、替换等等,同时自动管理内存,减少了内存泄漏的风险。

1.标准库中的string类

1.1string类的了解

可以参考文献cplusplus.com - The C++ Resources Network

1.2 auto和范围for
auto关键字
  • 在早期的C/C++中auto的含义是:使用auto修饰的变量是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会规定:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须有编译器在编译时期推导而得。
  • 用auto声明指针类型时,用auto和auto*没有任何区别,但是auto声明引用类型时必须加&
  • 当在同一行声明多个变量时,这些变量必须是相同类型,否者编译器将会报错,因为编译器实器只对第一个类型进行推导,然后用推导出俩的类型定义其他变量
  • auto不能作为函数的参数,可以做返回值但是建议谨慎使用
  • auto不能用来直接声明数组
int func1()
{
	return 10;
}
int main()
{
	int a = 0;
	auto b = a;
	auto c = 'a';
	auto d = func1();

	cout << typeid(b).name() << endl;//int
	cout << typeid(c).name() << endl;//char
	cout << typeid(d).name() << endl;//int


	return 0;
}

int main()
{
	auto e;
	cout << e << endl;
	return 0;
}

 

 解析:使用auto来推导变量的类型时必须初始化变量,否者根本无从推导变量的类型,编译器会报错,这一点和引用类似。

int main()
{
	int x = 10;
	auto y = &x;
	auto* z = &x;
	
	cout << typeid(x).name() << endl;//int
	cout << typeid(y).name() << endl;//int * __ptr64
	cout << typeid(z).name() << endl;//int * __ptr64

	return 0;
}

 解析:变量y和z都是指向变量x的指针,用auto声明指针类型时,用auto和auto*没有任何区别,所以两者的类型相同

int main()
{
	auto aa = 1, bb = 2;
	auto cc = 3, dd = 4.0;


	return 0;
}

 解析:当在同一行声明多个变量时,这些变量必须是相同类型,否者编译器将会报错,如在上面例子中aa和bb变量在同一行定义并且是相同类型的变量,所以不会报错;而在同一行定义的cc和dd变量一个是整形,一个是浮点型变量所以编译器报错。

int main()
{
	auto arr[] = { 1,2,3,4 };
	return 0;
}

 

 解析:auto不能用来直接声明数组

int func1()
{
	return 10;
}

void func2()
{
	func1();
}

auto func3()
{
	return func2();
}

 解析:使用auto做函数的返回值时,有时候需要调用多个函数才能知道返回类型。如在上面代码中想知道func3的返回值类型需要回去看func2的返回值类型,想知道func2的返回值类型需要回去看func1的返回值类型,这样就有一些麻烦了,特别是当需要调用函数多时,会降低程序的运行效率。

范围for
  • 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基本范围的for循环。for循环后的括号由冒号 “:”分为两部分:第一部分是范围内的用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
  • 范围for可以作用到数组和容器对象上的遍历
  • 范围for的底层很简单,容器遍历实际就是替换为迭代器
int main()
{
	
	int arr[] = { 1,2,3,4,5 };

	for (auto e : arr)
	{
		e *= 2;
	}
	

	for (auto e : arr)
	{
		cout << e;
	}
	cout << endl;
	return 0;
}
int main()
{

	int arr[] = { 1,2,3,4,5 };

	//只能访问而不能修改数组的值
	/*for (auto e : arr)
	{
		e *= 2;
	}*/

	for (auto& e : arr)
	{
		e *= 2;
	}

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

	cout << endl;
	return 0;
}

解析:上面两个代码的功能是一样的,都是访问数组中各元素的值并且修改元素的值,只不过需要注意的是使用auto来修改数组中的值时需要使用auto&。

int main()
{
	string s1("hello world");
	for (auto ch : s1)
	{
		cout << ch;
	}
	cout << endl;//hello world
	return 0;
}
1.3string类的常见接口
1.3.1string类对象的常见构造
函数名称(constructor)功能说明
string()  (重点)构造空的string类对象,即空字符串
string(const char*s)  (重点)用C-string来构造string类对象
string(size_t n,char c)  string类对象中包含n个字符c
string(const string& s)  (重点)拷贝构造函数
int main()
{
	string s1();//构造空的string类对象s1
	string s2("hello world");//用C格式字符串构造string类对象s2
	string s3(s2);//拷贝构造s3

	
	cout << s2 << endl;//hello world
	cout << s3 << endl;//hello world

	return 0;
}
1.3.2string类对象的容量操作

函数名称功能说明
size   (重点)返回字符串有效字符长度
length返回字符串有效字符长度
capacity返回空间总大小
empty (重点)检测字符串是否为空
clear  (重点)清空有效字符
reserve  (重点)为字符串预留空间
resize  (重点)将有效字符的个数改成n个,多出的空间用字符c填充

微提醒:

1.size()和length() 方法底层的实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下都是用size()

2.clear()只是将string中有效字符清空,不改变底层空间大小

3.resize(size_t n)和resize(size_t n,char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时,resize( n)用0来填充多出的空间,resize(size_t n,char c)用字符c来填充多出的空间。特别需要注意的是:resize在改变元素个数时,如果是将元素个数增加,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变

4.reserve(size_t res_arg = 0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间大小时,reserve不会改变容量大小

int main()
{
	string s1("hello world");
	//大小
	cout << s1.size() << endl;//11
	cout << s1.length() << endl;//11

	//空间
	cout << s1.capacity() << endl;//15

	return 0;
}

微提醒:如在上面例子中:size和length计算出的结果一样

int main()
{
	string s1("good lucky");
	cout << s1.size() << endl;
	cout << s1.capacity() << endl<<endl;

	//比size和capacity都小
	s1.reserve(5);
	cout << s1.size() << endl;
	cout << s1.capacity() << endl << endl;

	//在size和capacity之间
	s1.reserve(13);
	cout << s1.size() << endl;
	cout << s1.capacity() << endl << endl;

	//比size和capacity都小
	s1.reserve(20);
	cout << s1.size() << endl;
	cout << s1.capacity() << endl << endl;


	return 0;
}

微提醒:

在上面例子中为s1保留5个字节大小时(比size和capacity都小),s1的size和capacity都没有改变;为s1保留20个字节大小时(比size和capacity都大),s1的size没有改变,但是capacity扩容了;在这个过程中s1的size一直都没有改变,这表明在vs编译器上,reserve只会改变capacity的大小而不会改变size的大小

int main()
{
	string s1("good day");
	cout << s1.size() << endl;
	cout << s1.capacity() << endl<<endl;

	//比size和capacity都小
	s1.resize(4);
	cout << s1.size() << endl;
	cout << s1.capacity() << endl << endl;
	
	//在size和capacity之间
	s1.resize(10);
	cout << s1.size() << endl;
	cout << s1.capacity() << endl << endl;

	//比size和capacity都大
	s1.resize(20);
	cout << s1.size() << endl;
	cout << s1.capacity() << endl << endl;
	return 0;
}

微提醒:由上面例子可以知道当为s1的大小改变为5个字节大小时(比size和capacity都小),s1的size改变而capacity没有改变;使s1大小改变为20个字节大小时(比size和capacity都大),s1的size和capacity都扩容了;在这个过程中s1的size一直在改变,这表明在vs编译器上,reserve会改变capacity的大小和size的大小

1.3.3string类对象的访问及遍历操作
函数名称功能说明
operator[](重点)返回pos位置的字符,const string类对象调用
begin + endbegin获取一个字符的迭代器 +end获取最后一个字符下一个位置的迭代器
rbegin + rendbegin获取一个字符的迭代器 +end获取最后一个字符下一个位置的迭代器
范围forC++11支持更简明的范围for的新遍历方式
int main()
{
	string s1("happy day");
	//operartor[]
	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1[i];
	}
	cout << endl;//happy day

	//begin+end
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it;
		it++;
	}
	cout << endl;//happy day

	//rbegin + rend
	string::reverse_iterator rit = s1.rbegin();
	while (rit != s1.rend())
	{
		cout << *rit;
		rit++;
	}
	cout << endl; //yad yppah

	//范围for
	for (auto e : s1)
	{
		cout << e;
	}
	cout << endl;//happy day

	return 0;
}

微提醒:operator[]的访问方式相当于数组用下标访问一样,没有特别大的难度;begin和end的使用需要使用到迭代器iterator,在这个代码中的it变量我们可以看做是指针,他的使用方式和指针相似但却不是指针;而rbegin和rend的使用需要使用的reserve_iterator迭代器,和iterator迭代器相似,只不过是开始结束位置相反

1.3.4string类对象的修改操作

函数名称功能说明
push_back在字符串后面尾插字符c
append在字符串后追加字符串
operator+= (重点)在字符串后追加字符串str
c_str   (重点)返回C格式字符串
find + npos   (重点)从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind   (重点)从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr在str中从pos位置开始,截取n个字符,然后将其返回
int main()
{
	string s1("lucky day");
	s1.push_back('f');
	cout << s1 << endl;//lucky dayf

	s1 += 'o';
	cout << s1 << endl;//lucky dayfo

	s1 += ' ';
	s1.append("for me");
	cout << s1 << endl;//lucky dayfo for me
	return 0;
}

 

int main()
{
	string s1("happy day");
	size_t pos = s1.find('d');
	cout << pos << endl;//6

	size_t p = s1.rfind('h');
	cout << p << endl;//8
	return 0;
}

微提醒:find是从左向右开始查找字符,rfind是从右向左查找字符,两者都是返回该字符在字符串中的位置下标

int main()
{
	string s("hello world lucky day good");
	string s1 = s.substr(6, 5);
	cout << s1 << endl;//world

	string s2 = s.substr(6);
	cout << s2 << endl;//world lucky day good

	string s3("hello world");
	string s4 = s3.substr(6, 10);
	cout << s4 << endl; //world
	return 0;
}

微提醒:substr的第一个参数是从这个下标开始截取字符串,第二个参数表示截取的字符个数,如果第二个参数没有给,那么编译器会默认截取到该字符串的最后一个字符为止;如果第二个参数的大小大于剩余字符串的大小,也是默认取到最后一个字符为止。如在上面例子中,s1是从第六个位置开始截取5个字符,则为world;s2是从第六个字符开始截取,由于第二个参数没写则是默认取到最后一个字符为止,则为world lucky day good;s3是从第六个字符开始截取,由于第二个参数10大于剩余字符串(world)的大小,所以也是取到最后一个字符为止,则为world

微提醒:

1.在string尾部追加字符时,push_back,append,operator+=三种的实现方式差不多。一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串

2.对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抱歉,我无法提供思维导图。但是,我可以为您提供有关C++ std::string的一些信息。 C++的std::string是一个非常有用的字符串处理,它提供了许多功能和方法来操作字符串。下面是一些std::string的常用方法和功能: 1. 创建std::string对象:可以使用以下方式创建std::string对象: ```cpp std::string str1; // 创建一个空字符串 std::string str2 = "Hello"; // 创建一个包含字符串"Hello"的字符串 std::string str3(str2); // 使用另一个字符串初始化一个字符串 ``` 2. 访问字符串的字符:可以使用下标运算符[]或at()方法来访问字符串中的字符。例如: ```cpp std::string str = "Hello"; char ch = str[0]; // 获取第一个字符'H' char ch = str.at(1); // 获取第二个字符'e' ``` 3. 连接字符串:可以使用+运算符或append()方法来连接两个字符串。例如: ```cpp std::string str1 = "Hello"; std::string str2 = "World"; std::string result = str1 + " " + str2; // 连接两个字符串 str1.append(" "); // 在字符串末尾添加空格 str1.append(str2); // 连接两个字符串 ``` 4. 获取字符串长度:可以使用length()或size()方法来获取字符串的长度。例如: ```cpp std::string str = "Hello"; int length = str.length(); // 获取字符串的长度 int size = str.size(); // 获取字符串的长度 ``` 5. 查找子字符串:可以使用find()方法来查找子字符串在字符串中的位置。例如: ```cpp std::string str = "Hello World"; int pos = str.find("World"); // 查找子字符串的位置 ``` 6. 字符串转换:可以使用std::to_string()函数将其他型的数据转换为字符串,也可以使用std::stoi()、std::stof()等函数将字符串转换为其他型的数据。例如: ```cpp int num = 123; std::string str = std::to_string(num); // 将整数转换为字符串 std::string str = "456"; int num = std::stoi(str); // 将字符串转换为整数 float f = std::stof(str); // 将字符串转换为浮点数 ``` 这些只是std::string的一些常用功能和方法,还有很多其他功能和方法可以用于字符串处理。希望这些信息对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值