「C++ STL篇 1-0」string类的使用

目录

〇、概念

一、string类的构造函数

二、赋值运算符重载

三、有关容量的操作

四、string对象的访问

五、遍历string对象的字符数组

六、string对象的修改

七、string对象的常用操作

八、字符串和数字间的转换

拓展】

练习】

源代码】



〇、概念

1. string类是什么?

string类的底层是一个支持动态增长的char数组,它用new来动态分配内存,因此string也被称为变长字符串。

string的底层是一个叫 basic_string 的类模板,模板中存的是char。


事实上string库中还用basic_string类模板实现了存储宽字符的wstring ,存储16位字符的 u16string(C++11后支持) ,和存储32位字符的 u32string(C++11后支持):

2. string类的官方文档

博主在文章中只是讲述了有关string类的常用函数,对于一些不常用,可以查看官方文档: string类的官方文档

3. 导入string类

要使用官方的string类:

  • 首先我们要引入头文件:#include<string>
  • 其次展开命名空间std中的string类:using std::string;

严格来说string是属于C++ std标准库的,不在STL中,但是两者有许多相似之处,就放在一起总结了。


一、string类的构造函数

0. 全部构造函数

以下为C++98中string的所有构造函数

1. 常用的四个构造函数

|--------------------------------|------------------------|
| string() (重点) | 构造空的string类对象,即空字符 |
| string(const char* s) (重点) | 用字符数组来构造string对象 |
| string(const string & s) (重点) | 拷贝构造函数 |
| string(size_t n, char c) | 用n个c字符来构造string对象 |

cpp 复制代码
string a;  //注意空字符串的创建不是string a(); 这是在声明一个返回值为string 的无参函数。
string b("abc"); //使用字面字符串来构造对象
string c(b);     //拷贝构造
string d(3, 'a');

cout << a << endl;
cout << b << endl;
cout << c << endl;
cout << d << endl;

唯一要注意的一点是创建空字符串不是string a(); 这是在声明一个返回值为string 的无参函数。是string a;

2. 可能用到的构造函数

|-------------------------------------------------------------|-----------------------------------------|
| string (const string& str, size_t pos, size_t len = npos); | 从str的下标 pos 处开始复制 len 个字符,不设置len默认复制到结尾 |

cpp 复制代码
string e("1abcdefg", 1);     //abcdefg (从下标1开始复制)
string f(e, 1);              //bcdefg  (从下标1开始复制)
string g("1abcdefg", 1, 5);  //abcde   (从下标1开始复制5个字符)
string h(e, 0, 3);           //abc     (从下标0开始复制3个字符)

唯一要注意的一点是:**第二、三个参数的意义是,从下标pos处开始复制len个字符。**不是复制它们之间的字符。不传第三个参数则默认复制到结尾。

拓1:string::npos


  • npos是std命名空间中string类下的一个静态成员变量。(std::string::npos)
  • npos用来表示一个非常非常大的数值(约为42亿9千万),因为size_t是无符号的整型,如果将-1的补码转化为无符号的整型将非常非常大,所以一般用string::npos来表示直到字符串的结尾。

二、赋值运算符重载

1. 三个赋值运算符重载函数

有三个重载,分别接受字符串,字符数组,字符作为参数。

以上三个运算符重载又互相构成函数重载。

2. 使用赋值运算符重载函数

|-------------------------------------------|----------------|
| string& operator= (const string & str); | 使用string对象赋值 |
| string& operator= (const char* s); | 使用字面字符串/字符数组赋值 |
| string& operator= (char c); | 使用单个字符赋值 |

cpp 复制代码
string a("abcd");
string b("bcde");
string c = b; // 注意这是在调用构造和拷贝构造函数
a = b;
cout << a << endl;
a = "fghi";
cout << a << endl;
a = 'j';
cout << a << endl;

唯一一点要注意的就是要区分是在调用构造函数还是在赋值,上面代码中的第三行就是在调用构造函数。


拓2:构造还是赋值?

cpp 复制代码
string a = b; // 注意这是在调用构造而不是赋值
string b("bcde");
a = b; // 这里才是赋值

要注意第一行代码可不是在赋值,而是在通过隐式类型转换调用构造函数(先构造,再拷贝,编译器可能优化为直接构造)


如何区分是构造还是赋值?就看对象有没有创建出来,如上面第一行代码中的对象a正在创建,所以这是在调用构造函数;而第三行中使用的是已经创建好的a对象,所以是在赋值,调用了赋值运算符重载函数。

三、有关容量的操作

1. 有关容量的操作函数

2. 常用的容量操作函数

|---------------------------------------|------------------------------|
| size_t size() const noexcept; | 返回字符串有效字符长度 |
| size_t length() const noexcept; | 返回字符串有效字符长度 |
| size_t capacity() const noexcept; | 返回字符串占用空间总大小(字节) |
| bool empty() const noexcept; | 检测字符串是否为空串,是返回true,否则返回false |
| void clear() noexcept; | 清空字符串 |
| void reserve (size_t n = 0); | 为字符串预留空间 |
| void resize (size_t n); | 设置有效字符长度,用'\0'填充多出来的位置 |
| void resize (size_t n, char c); | 设置有效字符长度,用指定字符填充多出来的位置 |

a. 获取字符串有效字符长度

推荐使用size() ,少用length() 。虽然设计方面两个函数是一样的,但为了在学习后面的容器时不产生混乱(其它容器中都有size() 来计算元素个数,但不一定有length() ),使用推荐使用size()

b. 获取字符串占用空间总大小

stirng对象中的字符数组的空间大小不一定等于有效字符长度size,因为扩容是有消耗的,所以一般扩容不是一个一个一个扩,而是以1.5或2倍大小来扩容,我们可以通过capacity()来获取stirng对象中的字符数组的空间大小。

c. 判空和清空字符串

  • empty()通过检查有效字符长度来判断string对象是否为空,为空返回true。
  • clear()通过将有效字符长度置为0来清空字符串。

d. 为字符串预留空间

当string对象的有效字符长度size等于容量capacity时会触发扩容,扩容是有消耗的,如果我们提前知道有效字符长度size,就可以通过reserve()来提前开好一片空间,就不需要频繁的扩容了。

当所给值小于容器当前的 capacity时,什么也不做(不会缩小容量)。

e. 设置有效字符长度

resize() 通过设置有效字符长度size,来更新字符串的长度,如果新长度比当前字符串有效长度长,默认用'\0'填充。(string对象的打印不是遇到'\0'终止,但'\0'不会被显示)


我们也可以通过**resize()的第二个参数来指定,**当新长度比当前字符串有效长度长时的填充字符。

四、string对象的访问

1. string对象的三种访问方法

string对象主要三种访问方法:[ ]、at()、string::iterator


  • [ ]没什么好说的,重载[ ]让string类能像数组一样使用。
  • 成员函数at()用来返回指定下标处的字符,类似于Java中的charAt(),让string类符合封装的思想,但几乎不怎么用。
  • string::iterator就是迭代器,string类的迭代器可以当作指针来用,begin(),end()返回的就是数组下标0和下标size处的迭代器。

2. operator [ ] 和 at()

operator [ ] 和 at() 返回的都是string对象的字符数组的i下标处的引用,所以可以用来修改string对象的字符数组。


  • 重载[ ]让string类能像数组一样使用
  • 成员函数at()用来返回指定下标处的字符

cpp 复制代码
string a("abcdefghijklmn");

cout << "使用[]遍历string对象的字符串" << endl;
for (int i = 0; i < a.size(); i++)
{
	//operator [ ]是string对象的字符数组的i下标处的引用。
	a[i]++;
	cout << a[i];
}	
putchar(10);

cout << "使用at()遍历string对象的字符串" << endl;
for (int i = 0; i < a.size(); i++)
{
	// at() 返回的也是string对象的字符数组的i下标处的引用
	a.at(i)++;
	cout << a.at(i);
}
putchar(10);

3. string::iterator

string类的迭代器可以当作指针来用,begin(),end()相当于指向字符串开头和结尾('\0'处)的指针。通过+/- 能获取下一个或上一个地址。通过*(解引用)能取出地址中的内容。


五、遍历string对象的字符数组

上面的三种访问方式都可以用来遍历string对象。这里因为[]和at()区别不大,所以就演示使用[ ] 和 stirng::iterator 来遍历string对象。

1. 使用[ ]遍历string对象的字符数组

重载[ ]让string对象的访问和数组没有区别:

cpp 复制代码
//operator [ ] 和 at() 返回的都是string对象的字符数组的i下标处的引用,所以可以用来修改string对象的字符数组。
a = "abcdefg";
for (int i = 0; i < a.size(); ++i)
{
	a[i] += 1;
	cout << a[i];
}

2. 使用迭代器来遍历string对象的字符数组

string的迭代器可以当指针使用:

cpp 复制代码
a = "abcdefg";
string::iterator it = a.begin();
while (it != a.end())
{
	cout << *it; //string的迭代器可以当指针使用。
	++it;
}

使用迭代器来遍历string对象的最大优势在于:可以使用范围for。

上面代码中auto后面的e是临时变量,不会对原字符串造成改变


只有auto + &才能修改原字符串

六、string对象的修改

0. string类中有关修改的函数

1. 追加

|--------------------|-------------------------|
| 追加: | |
| operator +=() (常用) | 在字符串后追加字符串/string对象/字符。 |
| push_back() | 在字符串后尾插字符,只能尾插一个字符。 |
| append()(常用) | 在字符串后追加一个字符串 |

a. operator +=()

重载+=让我们可以在字符串后随意追加字符串/string对象/字符,一般情况下有operator +=即可。


cpp 复制代码
string a("abcdefg");
a += "higk";
a += 'l';
string b("mn");
a += b;
cout << a << endl;

b. append()

append()主要用于一些特殊情况:追加某个字符串的一部分、追加某个字符n次。


cpp 复制代码
string a = "abcdefghijklmno";
a.append("lmn");
string c("opq");
a.append(c);
cout << a << endl;

a.append("rstuvw", 3); // 尾插一个字符串,取其前n个字符
cout << a << endl;
a.append("rstuvwxyz123", 3, 8); // 尾插一个字符串,从下标n开始,取其前i个字符
cout << a << endl;
a.append(3, ' '); //尾插n个相同的字符
cout << a << endl;

2. 插入

一般来说insert只用于要在字符串中间插入内容时。用的比较少。

|--------|----------------|
| 插入: | |
| insert | 在指定下标处插入一个字符串。 |

cpp 复制代码
string a = "abcdefghijklmnopqrstuvwxyz  ";
a.insert(0, "123"); // 在n下标处插入一个字符串
cout << a << endl;
a.insert(3, "456789", 3); // 在n下标处插入,一个字符串的前n个字符
cout << a << endl;
a.insert(6, "7891011", 3, 5); //在n下标处插入,一个字符串从下标n开始的n个字符
cout << a << endl;

3. 删除

|-------|----------------|
| 删除: | |
| erase | 删除指定位置开始的n个字符。 |

cpp 复制代码
a = "ab123456789cdefghigklmnopqrstuvwxyz111";
a.erase(2, 9); //删除从指定下标开始的n个字符。
cout << a << endl;
a.erase(25);    //删除从指定下标后的所有字符。
cout << a << endl;
int n = 3;
a.erase(a.begin() + n);    //删除下标为n的字符
cout << a << endl;

七、string对象的常用操作

0. string对象的操作函数

其中copy()完全可以使用 operator =() 来替代,compare()也可以使用operator >()来替代。


常用的操作函数只有四个:

|----------|--------------------|
| c_str() | 返回C格式字符串(char* ) |
| find() | 从前往后查找子串,返回起始位置的下标 |
| rfind() | 从后往前查找子串,返回起始位置的下标 |
| substr() | 截取子串,并返回一个string对象 |

1. c_str()

返回一个 const char* 指针,该指针指向一个和string对象有效内容相同的char数组,且是以'\0'结尾。该函数的作用是获取一个适用于C语言库函数的C风格字符串

cpp 复制代码
string a;
a = "abcdefgdefg";
cout << a.c_str() << endl;      // 返回一个char*指向的字符数组

2. find() 和 rfind()

都是用来查找子串的不过find()是从前往后找,rfind()是从后往前找。找到了就立即返回子串起始位置的下标,没找到就返回string::npos(约为42亿9千万)。

cpp 复制代码
string a = "abcdefgdefg";
cout << a.find("defg") << endl; //查找子串,返回起始位置的下标
if(a.find("defgl") == string::npos) //找不到返回string::npos(约为42亿9千万);
	cout << "未找到该子串" << endl;

cout << a.find("def", 3) << endl;//查找子串,从主串的第n个位置开始找。
cout << a.find("def", 4) << endl;//查找子串,从主串的第n个位置开始找。
cout << a.rfind("def", 4) << endl;//从主串的第n个位置开始从后往前查找子串。

3. substr()

从下标pos开始,截取len个字符,不传len就默认截取到结尾。然后返回一个string对象


cpp 复制代码
string a = "abcdefgdefg";
cout << a.substr(1) << endl;        //从下标1的字开始截取到结尾
cout << a.substr(1).size() << endl; 

cout << a.substr(0, 3) << endl;     //从下标0的字开始截取3个字符

八、字符串和数字间的转换

以下函数都是string的非成员函数,不能通过对象来调用。

|-------------|-------------------------------|
| to_string() | 将数字转为字符串 |
| stoi() | 将string对象转为整数 (只能接受string对象) |
| stod() | 将string对象转为浮点数 (只能接受string对象) |
| atoi() | 将字面字符串转为整数 (只能接受常量字符串) |
| atof() | 将字面字符串转为浮点数(只能接受常量字符串) |

cpp 复制代码
		//to_string()函数:将数字转为字符串
		cout << "---------------------------" << endl;
		double a = 1234.5678;
		string s = std::to_string(a);
		cout << s << endl;

		//stoi():将字符串转为整数
		int b = stoi(s);
		cout << b << endl;

		//stod():将字符串转为浮点数
		double c = std::stod(s);
		printf("%lf\n", c);  //注意cout默认输出两位小数,所以在输出浮点数时最好使用printf()

		//atoi():将字面字符串转为整数
		const char* ss = "2345678";
		b = atoi(ss);
		cout << b << endl;
		//atof():将字面字符串转为浮点数
		c = atof("1234.5678");
		printf("%f\n", c);

拓展】

1:operator +

重载+ 让string对象能自由的拼接字符/字符串/其他string对象:

cpp 复制代码
string firstlevel("com");
string secondlevel("cplusplus");
string scheme("http://");
string hostname;
string url;

hostname = "www." + secondlevel + '.' + firstlevel;
url = scheme + hostname;

std::cout << "网址:" + url + '\n';

2:重载比较运算符

重载比较运算符 让string对象能和 字符串字符串/其他string对象 进行字典序比较(逐个按ASCII码比较):

cpp 复制代码
string s1 = "abcd";
string s2 = "abcde";
cout << (s1 == "a") << endl;

cout << (s1 > s2) << endl;
cout << (s1 >= "abcd") << endl;
		
cout << (s1 < s2) << endl;
cout << (s1 <= s2) << endl;

3:按行输入

cin >> 是以空格进行分隔的,当我们希望输入一句英文时,使用cin >> 却只能接收到一个单词。所以这个时候我们就需要使用按行输入了:getline()


  • 第一个参数是istream对象,传入std::cin即可。
  • 第二个参数是用来接收的string对象。
  • 第三个参数是控制输入结束的字符,不传该参数就默认以回车结束。

cpp 复制代码
string str;
getline(cin, str, '.'); //按行输入,指定以.结束。
cout << str << endl;

4:判断字符是字母还是数字

  • isalpha() :用来判断一个字符是不是字母。
  • isdigit() :用来判断一个字符是不是数字。

如果记不住,自己写一个也很快,判断是否是字母就比较字符是否大于等于'a'/'A',小于等于'z'/'Z',判断是否是字母就比较字符是否大于等于'0',小于等于'9' 。或用它们的ASCII码:48 65 97 。


练习】

1:将字符串中的空格替换为%20

cpp 复制代码
	{
		// 法一:倒着找到后先删除后插入
		string s1("hello world lin");
		for (int i = s1.size(); i >= 0; i--)
		{
			if (s1[i] == ' ')
			{
				s1.erase(i, 1);
				s1.insert(i, "%20");
			}
		}
		// 法二:开一个新字符串
		string s2;
		for (int i = 0; i < s1.size(); i++)
		{
			if (s1[i] == ' ')
				s2 += "20%";
			else
				s2 += s1[i];
		}
		cout << s1 << endl;
		cout << s2 << endl;
	}

2:获取文件后缀

cpp 复制代码
	{
		// 用find找子串,用substr获取子串。
		string file_path = "test.cpp.zip.tar";
		size_t index = file_path.find(".");
		size_t index1 = file_path.rfind("."); // 从结尾开始找
		string suffix = file_path.substr(index);
		string suffix1 = file_path.substr(index1);
		cout << "使用find获取文件所有后缀:" << suffix << endl;
		cout << "使用rfind获取文件真后缀:" << suffix1 << endl;
	}

源代码】

cpp 复制代码
#include<iostream>
#include<string>
using std::cin;
using std::cout;
using std::endl;
using std::string;

int main()
{
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	// string类的构造函数
	{
		//string() (重点)	构造空的string类对象,即空字符
		//string(const char* s) (重点)	用字符数组来构造string类对象
		//string(const string & s) (重点)	拷贝构造函数
		//string(size_t n, char c)	用n个c字符来构造string类对
		cout << "----------string类的构造函数---------" << endl;
		string a; 
		//string a(); 不是在调用构造器创建一个空的string对象,而是在声明一个返回值为string的无参函数。
		string b("abcd");  //使用字符数组构造
		string c(b);  //拷贝构造
		string d(3, 'a');

		const char* e = "abcdefg";
		string f(e);
		char g[] = { 'a', 'b' }; //char数组结尾一定要加一个'\0'
		string h(g);

		cout << a << endl;
		cout << b << endl;
		cout << c << endl;
		cout << d << endl;
		cout << e << endl;
		cout << f << endl;
		cout << g << endl;
		cout << h << endl;
	}

	// 赋值运算符重载
	{
		//string& operator= (const string & str);
		//string & operator= (const char* s);
		//string& operator= (char c);
		cout << "----------赋值运算符重载---------" << endl;
		
		string a("abcdefg");
		string b = a;  //区分构造和赋值,这里b还没有创建所以调用的是构造函数
		
		b = a;  //这里b已经创建,所以调用的是赋值运算符重载
		cout << b << endl;
		b = "abcd";
		cout << b << endl;
		b = 'a';
		cout << b << endl;
	}

	// 有关容量的操作
	{
		//	size(重点)	返回字符串有效字符长度
		//	length	        返回字符串有效字符长度
		//	capacity	    返回空间总大小
		//	empty(重点)	检测字符串是否为空串,是返回true,否则返回false
		//	clear(重点)	清空有效字符
		//	reserve(重点)	为字符串预留空间
		//	resize(重点)	设置字符串长度,用指定字符填充多出来的位置
		cout << "-----------有关容量的操作---------" << endl;
		string a("abcdefg");
		cout << a.size() << endl;
		cout << a.length() << endl;
		cout << a.capacity() << endl;

		// 判空:根据size()判断
		cout << a.empty() << endl;
		// 不同于字符数组是以'\0'来判断结尾,stirng对象判断字符串的结尾是根据size属性。

		// 清空字符串:修改size()
		a.clear();
		cout << "a.clear();" << endl;
		cout << a.size() << endl;
		cout << a.empty() << endl;

		// 为stirng对象预留空间,修改capacity = n + 1;
		a.reserve(30);
		cout << "a.reserve(30);" << endl;
		cout << a.capacity() << endl;
		cout << a.size() << endl;

		// 设置string对象的有效长度,多出来的长度默认用'\0'填充
		cout << a << " 的长度: " << a.size() << endl;
		a.resize(10);
		cout << "a.resize(20);" << endl;
		cout << a << " 的长度: " << a.size() << endl;
		a.resize(20, '.');
		cout << "a.resize(20, '.');" << endl;
		cout << a << " 的长度: " << a.size() << endl;
		cout << "string对象是以size来判断结尾的,看不到的字符可能是'\0'";
	}

	//访问string对象的字符数组
	{
		cout << "---------访问string对象的字符数组--------" << endl;
		string a;
		a = "abcd";

		cout << a << endl; //重载<< 让我们能自己打印string对象的内容。

		cout << a[0] << endl;
		cout << a.at(1) << endl;
		cout << *a.begin() << endl;
		cout << *(a.begin() + 2) << endl;

		string::iterator it = a.end()-1;
		cout << *it << endl;
	}

	//遍历string对象的字符数组
	{
		cout << "---------遍历string对象的字符数组--------" << endl;
		string a("abcdefghijklmn");

		cout << "operator [ ]和at() 返回的是string对象的字符数组的i下标处的引用。" << endl;
		cout << "使用[]遍历string对象的字符串" << endl;
		for (int i = 0; i < a.size(); i++)
		{
			//operator [ ]返回的是string对象的字符数组的i下标处的引用。
			a[i]++;
			cout << a[i];
		}	
		putchar(10);

		cout << "使用at()遍历string对象的字符串" << endl;
		for (int i = 0; i < a.size(); i++)
		{
			// at() 返回的也是string对象的字符数组的i下标处的引用
			a.at(i)++;
			cout << a.at(i);
		}
		putchar(10);

		cout << "使用迭代器遍历string对象的字符串" << endl;
		for (string::iterator i = a.begin(); i != a.end(); i++)
		{
			(*i)++; //++的优先级大于*,所以要使用()
			cout << *i;
		}
		putchar(10);

		string::iterator it = a.begin();
		while (it != a.end())
		{
			(*it)++;
			cout << *it;
			it++;    //如果会忘记写it++,建议使用for循环
		}
		putchar(10);

		cout << "使用范围for+迭代器遍历string对象的字符串" << endl;
		//不使用&的范围for是无法修改原数组的
		cout << "a. 使用范围for访问,不用加&" << endl;
		for (auto e : a)
		{
			e++; //这里的e不过是一个临时变量。
			cout << e;
		}
		putchar(10);
		cout << a << endl;

		//使用&的范围for才能修改原数组的
		cout << "b. 使用范围for修改,要加&" << endl;
		for (auto& e : a)
		{
			e++;
			cout << e;
		}
		putchar(10);
		cout << a << endl;
	}


	//string对象的修改
	{
		cout << "-----------string对象的修改-----------" << endl;
	//追加
		//operator+=(重点)	在字符串后追加字符串/string对象/字符
		//push_back	        在字符串后尾插字符
		//append(重点)     	在字符串后追加一个字符串
		cout << "-----------追加-----------" << endl;
		string a("abc");
		a += 'd';
		a += "efg";
		string b("hij");
		a += b;
		cout << a << endl;

		a.push_back('k'); // 只能尾插一个字符。
		//a.push_back("lmn");

		a.append("lmn");
		string c("opq");
		a.append(c);
		cout << a << endl;

		a.append("rstuvw", 3); // 尾插一个字符串,取其前3个字符
		cout << a << endl;
		a.append("rstuvwxyz123", 3, 6); // 尾插一个字符串,从下标3开始,取其前6个字符
		cout << a << endl;
		a.append(3, ' '); //尾插3个' '字符
		cout << a << endl;


	//插入 insert
		cout << "-----------插入-----------" << endl;
		a = "abcdefghijklmnopqrstuvwxyz  ";
		a.insert(0, "123"); // 在0下标处插入一个字符串
		cout << a << endl;
		a.insert(3, "456789", 3); // 在3下标处插入,一个字符串的前3个字符
		cout << a << endl;
		a.insert(6, "4567891011", 3, 5); //在6下标处插入,一个字符串从下标3开始的5个字符
		cout << a << endl;

	//删除 erase
		cout << "-----------删除-----------" << endl;
		a = "12345678910abcdefghijklmnopqrstuvwxyz   .";
		a.erase(37, 3); //删除下标37开始的3个字符
		cout << a << endl;
		a.erase(10); //删除下标10后的所有字符
		cout << a << endl;
		a.erase(a.begin() + 9); //删除下标为9的字符
		cout << a << endl;

	}

	//string对象的常用操作
	{
		//c_str(重点) 返回C格式字符串
		//find(重点)	  从前往后查找子串,返回起始位置的下标
		//rfind	      从后往前查找子串,返回起始位置的下标
		//substr	  截取子串,并返回一个string对象
		cout << "---------------------------" << endl;
		string a;
		a = "abcdefgdefg";
		cout << a.c_str() << endl;

		cout << a.find("defg") << endl; //找到就返回在主串中起始位置的下标
		if (a.find("defgh") == string::npos) //找不到返回string::npos(约为42亿9千万)
			cout << "未找到" << endl;

		cout << a.rfind("defg") << endl; //从后往前找。
		cout << a.rfind("defg", 3) << endl; //从第4个字符开始,从后往前找。
		cout << a.rfind("defg", 2) << endl; //从第3个字符开始,从后往前找。


		a = "abcdefgdefg";
		cout << a.substr(1) << endl;        //从下标1的字开始截取到结尾
		cout << a.substr(1).size() << endl; 

		cout << a.substr(0, 3) << endl;     //从下标0的字开始截取3个字符
	}

	//string对象和数字间的转换
	{
		//to_string()函数:将数字转为字符串
		cout << "---------------------------" << endl;
		double a = 1234.5678;
		string s = std::to_string(a);
		cout << s << endl;

		//stoi():将字符串转为整数
		int b = stoi(s);
		cout << b << endl;

		//stod():将字符串转为浮点数
		double c = std::stod(s);
		printf("%lf\n", c);  //注意cout默认输出两位小数,所以在输出浮点数时最好使用printf()

		//atoi():将字面字符串转为整数
		const char* ss = "2345678";
		b = atoi(ss);
		cout << b << endl;
		//atof():将字面字符串转为浮点数
		c = atof("1234.5678");
		printf("%f\n", c);
	}


	// operator +
	{
		cout << "---------------------------" << endl;
		string firstlevel("com");
		string secondlevel("cplusplus");
		string scheme("http://");
		string hostname;
		string url;

		hostname = "www." + secondlevel + '.' + firstlevel;
		url = scheme + hostname;

		std::cout << "网址:" + url + '\n';
	}
	// 比较运算符:逐个按ASCII码比较
	{
		cout << "---------------------------" << endl;
		string s1 = "abcd";
		string s2 = "abcde";
		cout << (s1 == "a") << endl;

		cout << (s1 > s2) << endl;
		cout << (s1 >= "abcd") << endl;
		
		cout << (s1 < s2) << endl;
		cout << (s1 <= s2) << endl;

	}

	// 按行输入 : getline(cin, str)
	{
		cout << "---------------------------" << endl;
		string str;
		getline(cin, str, '.'); //按行输入,指定以.结束。
		cout << str << endl;
	}

	// 练习1:实现字符串替换函数:
	{
		// 法一:倒着找到后先删除后插入
		string s1("hello world lin");
		for (int i = s1.size(); i >= 0; i--)
		{
			if (s1[i] == ' ')
			{
				s1.erase(i, 1);
				s1.insert(i, "%20");
			}
		}
		// 法二:开一个新字符串
		string s2;
		for (int i = 0; i < s1.size(); i++)
		{
			if (s1[i] == ' ')
				s2 += "20%";
			else
				s2 += s1[i];
		}
		cout << s1 << endl;
		cout << s2 << endl;
	}

	// 练习2:获取文件后缀
	{
		// 用find找子串,用substr获取子串。
		string file_path = "test.cpp.zip.tar";
		size_t index = file_path.find(".");
		size_t index1 = file_path.rfind("."); // 从结尾开始找
		string suffix = file_path.substr(index);
		string suffix1 = file_path.substr(index1);
		cout << "使用find获取文件所有后缀:" << suffix << endl;
		cout << "使用rfind获取文件真后缀:" << suffix1 << endl;
	}

	// C++中涉及到char*的操作以'\0'为结尾,涉及string的操作以size的长度算结尾。
	{
		cout << "---------------------------" << endl;
		string s3 = "asdfg ";
		s3 += '\0';
		s3 += "hjkl";
		cout << s3 << endl;
		cout << s3.c_str() << endl;

		string s4 = s3;
		cout << s4 << endl;
	}
	return 0;
}

------------------------END-------------------------

才疏学浅,谬误难免,欢迎各位批评指正。

相关推荐
UestcXiye8 分钟前
《TCP/IP网络编程》学习笔记 | Chapter 3:地址族与数据序列
c++·计算机网络·ip·tcp
Chrikk9 分钟前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*11 分钟前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue12 分钟前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man14 分钟前
【go从零单排】go语言中的指针
开发语言·后端·golang
霁月风1 小时前
设计模式——适配器模式
c++·适配器模式
萧鼎2 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸2 小时前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农2 小时前
Python 继承、多态、封装、抽象
开发语言·python
^velpro^2 小时前
数据库连接池的创建
java·开发语言·数据库