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

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中:


http://www.kler.cn/a/599763.html

相关文章:

  • 深入理解Spring框架:核心概念与组成剖析
  • C++题目
  • uv - reference [官方文档翻译]
  • 【嵌入式学习2】内存管理
  • GitLens with `Commit Graph`
  • 使用Python调用Jenkins Api之获取构建日志使用说明文档
  • 两个手机都用流量,IP地址会一样吗?深入解析
  • Excel第41套全国人口普查
  • 在Spring Boot中,可以通过实现一些特定的接口来拓展Starter
  • 安全上网沙箱:多方面解决政企私的上网问题
  • 2025-如何创建自己的电商网站
  • Linux 系统关机和重启指令
  • Spring Boot项目快速创建-开发流程(笔记)
  • JAVA_数据结构_栈和队列
  • CSS 中text - shadow和box - shadow原理、属性的使用方法及区别
  • 鸿蒙进行视频上传,使用 request.uploadFile方法
  • Android 13系统定制实战:基于系统属性的音量键动态屏蔽方案解析
  • [AI速读]用持续集成(CI)优化芯片验证环境:Jenkins与EDA工具的实战指南
  • 【Linux学习笔记】gcc编辑器和动静态库的深度剖析
  • SAP-ABAP:SAP事务码SE14深度解析:数据库表管理核心工具