当前位置: 首页 > news >正文

C++学习之路,从0到精通的征途:string类

目录

一.string类的概念

二.string的常见接口

1.string类对象的常见构造

​​2.string类对象的容量操作

(1)size,length,capacity

​​(2)reserve

(3)resize

​​(4)clear,shrink_to_fit 

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

(1)auto与范围for

auto关键字:

范围for:

(2)遍历1:operator[]/at 

​(3)遍历2:迭代器

​(4)遍历3: 范围for

​4.string类对象的修改操作

(1)+=,append,push_back,insert

​(2)erase,replace,pop_back

​(3)c_str,substr ​

​(4)find,rfind,find_first_of,find_last_of

​实际运用:如何从一个网站名中获取协议,域名,资源名? 

​5.string类的非成员函数

​(1)operator+

(2)relational operators 

(3)getline 


一.string类的概念

源文档:String class

        由于string在std命名空间中,所以在使用string类时需要用展开命名空间,并且包含#include头文件。

二.string的常见接口

1.string类对象的常见构造

源文档源文档:        这里只对一些常用的进行演示:

#include<iostream>
#include<string>
using namespace std;

int main()
{
	string s1; // 创建一个没有初始化的空字符串
	string s2("******"); // 创建一个初始值为"******"的字符串
	string s3(6, '*'); // 创建一个以6个'*'为初始值的字符串
	string s4 = "Hello World"; // (构造+拷贝构造)创建一个以"Hello World"为初始值的字符串
	string s5(s4); // 用s2拷贝构造s5

	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	cout << s5 << endl;

	return 0;
}

        运行结果:

​2.string类对象的容量操作

(1)size,length,capacity

void Test_string2()
{
	string s1 = "Hello World";
	cout << s1.size() << endl;		// 返回字符串有效字符长度
	cout << s1.length() << endl;	// 返回字符串有效字符长度
	cout << s1.capacity() << endl;  // 返回字符串所申请的空间总大小
}

        运行结果:

​(2)reserve

void Test_string3()
{
	string s1 = "Hello World";
	string s2(s1);
	cout << s1.capacity() << endl;

	// 当n大于字符串对象的容量大小,会进行扩容
	s1.reserve(100);
	cout << s1.capacity() << endl;

	// 当n小于字符串对象的容量大小,取决于编译平台,不推荐使用
	s2.reserve(5);
	cout << s2.capacity() << endl;

}

        运行结果:

​        可以看到在当前的vs编译环境下,字符串s2的大小没有进行缩容。

(3)resize

void Test_string4()
{
	string s1 = "Hello world";
	string s2(s1);
	string s3(s1);
	string s4(s1);
	cout << s1.size() << endl;     // 11
	cout << s1.capacity() << endl; // 15

	// n大于size且小于capacity,进行插入数据
	s1.resize(13);	   // 默认用'\0’填充
	cout << s1 << endl;
	cout << s1.size() << endl;     
	cout << s1.capacity() << endl; 

	s2.resize(13,'x'); // 用'x’填充
	cout << s2 << endl;
	cout << s2.size() << endl;
	cout << s2.capacity() << endl;

	// n大于capacity,进行扩容操作
	s3.resize(30, 'x');
	cout << s3 << endl;
	cout << s3.size() << endl;
	cout << s3.capacity() << endl;

	// n小于size,删除数据
	s4.resize(5);
	cout << s4 << endl;
	cout << s4.size() << endl;
	cout << s4.capacity() << endl;
}

        运行结果:

​        调制过程中可以看到s1用'\0'填充:

​(4)clear,shrink_to_fit 

void Test_string5()
{
	string s1 = "Hello world";
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.clear();
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
}

        运行结果:

void Test_string6()
{
	string s1 = "Hello world";
	s1.reserve(100); // 扩容
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.shrink_to_fit(); // 缩容
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
}

        运行结果:

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

(1)auto与范围for

        在学习string类对象的访问前,我们在这里补充2C++11的小语法,方便我们后面的学习。

auto关键字:

        在早期C/C++auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期 推导而得

	int a = 10;
	auto b = a; // b自动推导为int类型

        auto声明指针类型时,用autoauto*没有任何区别,但用auto声明引用类型时则必须加&。

        当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量

        auto不能作为函数的参数,可以做返回值,但是建议谨慎使用。

auto func()
{
    return 10;
}

        auto不能直接用来声明数组。 

范围for:

        对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。

        范围for可以作用到数组和容器对象上进行遍历

        范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到

(2)遍历1:operator[]/at 

// 遍历1
void Test_string8()
{
	string s1 = "Hello World";
	string s2(s1);
	cout << s1 << endl;
	for (int i = 0; i < s1.size(); ++i)
	{
		s1[i] = 'x';
		cout << s1[i] << " ";
	}
	cout << endl;
	for (int i = 0; i < s2.size(); ++i)
	{
		s2.at(i) = 'm';
		cout << s2.at(i) << " ";
	}
}

        运行结果:

(3)遍历2:迭代器

        迭代器在现阶段可以理解为像指针一样的东西,它是一种容器通用的访问方式。

void Test_string9()
{
	string s1 = "Hello World";
	cout << s1 << endl;
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		*it = 'x';
		cout << *it << " ";
		it++;
	}
}

        运行结果:

(4)遍历3: 范围for

        原理:编译时替换为迭代器。

void Test_string10()
{
	string s1 = "Hello World";
	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;
	for (auto e : s1)
	{
		e--;
		cout << e << " ";
	}
}

        运行结果:

4.string类对象的修改操作

(1)+=,append,push_back,insert

 

void Test_string11()
{
	string s1 = "Hello ";
	string s2(s1);
	string s3(s1);
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	s1 += "World"; // 向s1追加"World"
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	
	s2.append("World"); // 向s2追加"World"
	cout << s2 << endl;
	cout << s2.size() << endl;
	cout << s2.capacity() << endl;
	
	s1.push_back('x'); // 向s1尾插一个'x'
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	s2.insert(5, "xxx"); // 向s2的第五个位置插入字符串"xxx"
	cout << s2 << endl;
	cout << s2.size() << endl;
	cout << s2.capacity() << endl;

    // 谨慎使用insert,因为底层要挪动数据,再插入,效率不高
	s3.insert(6, "World"); // 向s3的尾部追加一个"World"
	cout << s3 << endl;
	cout << s3.size() << endl;
	cout << s3.capacity() << endl;
}

        运行结果:

(2)erase,replace,pop_back

void Test_string12()
{
	string s1 = "Hello World";
	string s2(s1);
	string s3(s1);

	// 谨慎使用erase,因为底层要挪动数据覆盖删除
	s1.erase(5, 6); //把s1第5个位置后的6个字符删除
	cout << s1 << endl;

	// 谨慎使用replace,因为底层要挪动数据
	s2.replace(5, 6, "xxxxx"); // 将s2下标为2的位置往后6个字符替换为"xxxxx"
	cout << s2 << endl;

	s3.pop_back(); // 尾删
	cout << s3 << endl;
}

        运行结果:

(3)c_str,substr 

void Test_string13()
{
	string s1 = "Hello World";
	const char* cstr = s1.c_str(); // 将string类转化为const char*类型,转变为C语言类型的接口
	cout << cstr << endl;

	string substr = s1.substr(5, 6); // 将s1中第五个位置后面6个字符拷贝到substr中
	cout << substr << endl;
}

        运行结果:

(4)find,rfind,find_first_of,find_last_of

void Test_string14()
{
	string s1 = "Hello World";

	// 从前往后查找字符'l'
	size_t pos1 = s1.find('l');
	cout << pos1 << endl;

	// 从后往前找字符'l'
	size_t pos2 = s1.rfind('l');
	cout << pos2 << endl;

	// 从前往后查找"World"中的任意一个出现的字符
	size_t pos3 = s1.find_first_of("World");
	cout << pos3 << endl;

	// 从后往前查找"Hello"中的任意一个出现的字符
	size_t pos4 = s1.find_last_of("Hello");
	cout << pos4 << endl;
}

        运行结果:

实际运用:如何从一个网站名中获取协议,域名,资源名? 

void Test_string15()
{
	string url = "https://mpbeta.csdn.net/mp_blog/creation/editor/146455672?spm=1000.2115.3001.5352";
	// 获取协议名
	size_t pos1 = url.find(':');
	string sub1;
	if (pos1 != string::npos)
	{
		sub1 = url.substr(0, pos1);
	}
	cout << sub1 << endl;

	// 获取域名
	string sub2;
	string sub3;
	size_t pos2 = url.find('/', pos1 + 3);
	if (pos2 != string::npos)
	{
		sub2 = url.substr(pos1 + 3, pos2 - (pos1 + 3));
		// 获取资源名
		sub3 = url.substr(pos2 + 1);
	}
	cout << sub2 << endl;
	cout << sub3 << endl;

}

        运行结果:

5.string类的非成员函数

(1)operator+

void Test_string16()
{
	string s1 = "Hello ";
	string s2 = "world";
	// s1与s2拼接
	cout << s1 + s2 << endl;
	// 字符串与s2拼接
	cout << "Goodbye " + s2 << endl;
}

        运行结果:

(2)relational operators 

(3)getline 

void Test_string17()
{
	string s1;
	cin >> s1; // 这种输入方式只能将'\n'作为输入终止符,并且忽略了空格
	cout << s1 << endl;
}

        运行结果:

         而getline可以输入空格,并且指定任意输入终止符:

void Test_string17()
{
	string s2;
	getline(cin, s2, '#'); // 指定'#'为输入终止符
	cout << s2 << endl;
}

        运行结果:

        调试中可以看到换行符也在s2中:

相关文章:

  • 23种设计模式中的策略模式
  • 深入解析 Spring 启动过程
  • 借助可视化,快速洞察数据背后的商机
  • 地理信息系统(GIS)在智慧城市中的40个应用场景案例
  • JUC并发编程
  • 基于PySide6与pycatia的CATIA绘图文本批量处理工具开发实践
  • Windows下安装常用软件--MySQL篇
  • 第一课:Stable Diffusion | Web UI初了解
  • 网络运维学习笔记(DeepSeek优化版) 022 HCIP-Datacom路由概念、BFD协议详解与OSPF第一课
  • FreeCAD教程-dwg格式文件的打开-ODA Connverter的使用方法
  • Vulhub-jangow-01-1.0.1通关攻略
  • 塔能科技:智慧物联节能专利成就裴然
  • Matlab2024a免费版下载教程
  • mysql传统主从模式下,主从中断接续
  • 热门面试题第13天|Leetcode 110.平衡二叉树 257. 二叉树的所有路径 404.左叶子之和 222.完全二叉树的节点个数
  • 贪心:一道简单题的细节问题
  • 批量给 PPT 文档添加或删除保护,批量设置打开密码和只读密码
  • Elasticsearch 文档
  • 向量化地图重建
  • vue java 实现大地图切片上传
  • 时隔4年多,这一次普京和泽连斯基能见面吗?
  • 国产水陆两栖大飞机AG600批产首架机完成总装下线
  • 【社论】人工智能将为教育带来什么
  • 世贸组织欢迎中美经贸高层会谈取得积极成果
  • 历史地理学者成一农重回母校北京大学,担任历史系教授
  • “春申阡陌”漆画展:将传统漆艺融入现代创作