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

news2024/12/24 9:14:11

目录

〇、概念

一、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对象
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默认复制到结尾
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);使用单个字符赋值
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:构造还是赋值?

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()用来返回指定下标处的字符 


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对象的访问和数组没有区别:

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

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

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

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 +=即可。


string a("abcdefg");
a += "higk";
a += 'l';
string b("mn");
a += b;
cout << a << endl;

b. append()

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


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在指定下标处插入一个字符串。
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个字符。
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风格字符串

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

2. find() 和 rfind()

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

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对象。      


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()将字面字符串转为浮点数(只能接受常量字符串)
		//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对象:

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码比较):

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对象。
  • 第三个参数是控制输入结束的字符,不传该参数就默认以回车结束。

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

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

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

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


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


练习】

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

	{
		// 法一:倒着找到后先删除后插入
		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;
	}

源代码】

#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-------------------------

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1643670.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何查看Windows 10故障日志和错误日志?这里提供详细步骤

序言 当你的计算机崩溃时,会生成一个崩溃日志,可以帮助你分析崩溃的原因。但是,你知道如何查看Windows 10崩溃日志和错误日志吗?如果你不知道,别担心。这篇文章将向你展示如何使用两种方法查看Windows10崩溃日志。 使用事件查看器查看Windows 10故障日志 要查看Windows…

【Java】基本程序设计结构(一)

前言&#xff1a;现在&#xff0c;假定已经成功安装了JDK&#xff0c;并且能够运行上篇示例程序。本篇将开始介绍Java程序中的基本设计结构&#xff0c;其中包括&#xff1a;一个简单的Java应用&#xff0c;注释&#xff0c;数据类型&#xff0c;变量与常量&#xff0c;运算符&…

对于子数组问题的动态规划

前言 先讲讲我对于这个问题的理解吧 当谈到解决子数组问题时&#xff0c;动态规划(DP)是一个强大的工具&#xff0c;它在处理各种算法挑战时发挥着重要作用。动态规划是一种思想&#xff0c;它通过将问题分解成更小的子问题并以一种递归的方式解决它们&#xff0c;然后利用这些…

Linux(openEuler、CentOS8)基于chrony企业内网NTP服务器搭建实验

一、知识点 chrony 是由 守护进程 chronyd 以及 命令行工具 chronyc 组成的 chronyd 在后台静默运行并通过 123 端口与时间服务器定时同步时间&#xff0c;默认的配置文件是 /etc/chrony.conf chronyc 通过 323 端口与 chronyd 交互&#xff0c;可监控 chronyd 的性能并在运…

EPAI手绘建模APP资源管理和模型编辑器2

g) 矩形 图 26模型编辑器-矩形 i. 修改矩形的中心位置。 ii. 修改矩形的长度和宽度。 h) 正多边形 图 27模型编辑器-内接正多边形 图 28模型编辑器-外切正多边形 i. 修改正多边形的中心位置。 ii. 修改正多边形中心距离端点的长度。 iii. 修改正多边形的阶数。阶数为3&…

LLVM Instruction Selection 笔记

Instruction Selection 所处阶段 注&#xff1a;上图来源于 Welcome to the back-end: The LLVM machine representation 可以看到 SelectionDAG 架在 LLVM IR 和 LLVM MIR 之间&#xff0c;在此之前 machine independent optimization 已经完成。之后基本上就进入了 machine …

Dynamics 365: 从0到1了解如何创建Custom API(2) - Custom API与插件关联

接上一篇文章Dynamics 365: 从0到1了解如何创建Custom API(1) - 在Power Apps中创建-CSDN博客 这次我们主要写一个插件&#xff0c;与我们之前创建的Custom API进行关联。 1. 编写插件代码 因为代码太少了&#xff0c;我就不写注释了&#xff0c;大家如果有不懂的可以在评论…

2024牛客五一集训派对day5 K.Stack

题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 const int maxn 1e6 5, inf 1e18, maxm 4e4 5; c…

知乎23届数据分析校招A卷——笔记

1、and 和 or的并列运用[先看and] 条件1 OR 条件2 AND 条件3 执行顺序是先执行AND操作符&#xff08;先看条件2和3&#xff09;&#xff0c;再根据其结果判断是否需要执行OR操作符&#xff0c;并最终返回整个表达式的逻辑结果。 条件1 and 条件2 or 条件3 执行逻辑是先执行…

Swiper轮播图

版本&#xff1a;“swiper”: “^6.8.4”, 处理每分钟重新请求数据后&#xff0c;播放卡顿&#xff0c;快速闪&#xff0c;没按照设置时间播放等bug 以下是直接vue2 完整的组件代码 使用&#xff1a; <SwiperV :imgList“swiperList” / <template><div class"…

【论文阅读笔记】关于“二进制函数相似性检测”的调研(Security 22)

个人博客链接 注&#xff1a;部分内容参考自GPT生成的内容 [Security 22] 关于”二进制函数相似性检测“的调研&#xff08;个人阅读笔记&#xff09; 论文&#xff1a;《How Machine Learning Is Solving the Binary Function Similarity Problem》&#xff08;Usenix Securi…

docker-compose启动mysql5.7报错

描述一下问题经过&#xff1a; 使用docker compose 部署mysql5.7 文件如下: 使用命名卷的情况下&#xff0c;匿名卷不存在该问题 services:mysql:restart: alwaysimage: mysql:5.7container_name: mysql-devports:- 3306:3306environment:- MYSQL_DATABASEdev- MYSQL_ROOT_PAS…

备忘: 使用langchain结合千问大模型,用本地知识库辅助AI生成代码

本文主要是寻求解决把预先准备的文字需求转换为代码的方法 主要思路&#xff1a; 把某一类文字需求储存到本地知识库&#xff0c;使得用户输入需求目标&#xff0c;然后程序自动从知识库抽取相关需求&#xff0c;然后转发给在线的大模型形成代码。 工具&#xff1a; 本地在库用…

【UnityRPG游戏制作】Unity_RPG项目_玩法相关

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;就业…

jvm 马士兵 01 JVM简介,class文件结构

01.JVM是什么 JVM是一个跨平台的标准 JVM只识别class文件&#xff0c;符合JVM规范的class文件都可以被识别 u1 是一个字节 u2是两个字节

正则表达式_字符匹配/可选字符集

正则表达式&#xff08;Regular Expression&#xff09;也叫匹配模式(Pattern)&#xff0c;用来检验字符串是否满足特 定规则&#xff0c;或从字符串中捕获满足特定规则的子串。 字符匹配 最简单的正则表达式由“普通字符”和“通配符”组成。比如“Room\d\d\d”就这样 的正则…

1.pytorch加载收数据(B站小土堆)

数据的加载主要有两个函数&#xff1a; 1.dataset整体收集数据&#xff1a;提供一种方法去获取数据及其label&#xff0c;告诉我们一共有多少数据&#xff08;就是自开始把要的数据和标签都收进来&#xff09; 2.dataloader&#xff0c;后面传入模型时候&#xff0c;每次录入数…

C++类定义时成员变量初始化

在C11中允许在类定义时对成员变量初始化。 class A { public:A() { }void show(){cout << "m_a " << m_a << endl;cout << "m_b " << m_b << endl;} private:int m_a 10;//类定义时初始化int m_b; //没有初始化…

2024阿里云ctf-web-chain17学习

agent jdk17依赖有h2思路清晰打jdbc attack <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.aliba…

踏春正当时!VELO Prevail Ride带你探索多元骑行潮流体验~

嘿&#xff0c;朋友&#xff01;踏春正当时嘞&#xff01;在这个追求个性化与多元化的新时代&#xff0c;骑行爱好者们也开始寻找能适应各种骑行场景的理想坐垫。从悠闲自在的日常通勤&#xff0c;到热血沸腾的公路竞速&#xff0c;再到勇攀高峰的山地探险&#xff0c;维乐VELO…