【C++入门(7)】string

news2024/11/25 0:24:21

一、与C语言的联系

C++的string类其实是从C语言的字符串演变过来的,是STL中用于处理字符串的一个容器。

在C语言中,字符串是以 '\0' 为结尾的一串字符,为了便于操作,C语言标准库中也提供了不少str系列的库函数供人使用。但是这些库函数是与字符串相分离的,并不符合面向对象编程的思想,而且C语言字符串的底层空间还需要人自行管理,繁琐且存在越界等风险,所以C++中规定了string类,来对C语言的字符串进行“升级”。

二、string的成员函数

1、构造函数

string类中提供了7种构造函数,

第一种是无参的默认构造函数,这时字符串末尾会自动加一个'\0',

第二种是拷贝构造函数,

第三种是把str中的,pos位置之后的npos个字符拷贝到对象中,

第四种和第五种是兼容C语言的表现,前者是将C字符串初始化给对象,后者是用C字符串中的前n个字符来初始化对象,

第六种是用n个字符c来为对象初始化,

第七种是关于迭代器的使用,目前先不做介绍。

#include <iostream>
using namespace std;

int main()
{
	string a0("hello world!");
	const char* pb = "hello world!";
	string a1;
	string a2(a0);
	string a3(a0, 2, 3);
	string a4("hello world!");
	string a5(pb, 3);
	string a6(8, 'c');

	cout << a1 << endl;
	cout << a2 << endl;
	cout << a3 << endl;
	cout << a4 << endl;
	cout << a5 << endl;
	cout << a6 << endl;

	return 0;
}

第三个构造函数的最后一个参数是缺省参数,可以在传参的时候省略,缺省值为-1。而size_t是无符号整数,所以-1也就是整型最大值。相当于如果不传这个参数,这个函数会从pos之后开始拷贝后,一直拷贝到str结尾为止。

2、析构函数

string的析构函数是比较简单的,我们平时也基本用不到,往往是由编译器自动调用的。

3、赋值操作符

string中提供了赋值操作符的三种重载,分别支持了用另一个对象,用C字符串,以及用一个单个的字符,来为对象进行赋值。

#include <iostream>
using namespace std;

int main()
{
	string a("hello world!");
	string b, c, d;

	b = a;
	c = "hello world!";    //注意和c("hello world!");的区别,一个是构造,一个是赋值
	d = 'c';

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

	return 0;
}

4、大小、容量相关函数

(1)size和length

这两个函数都是返回对象中存储的字符串的大小,都不计算字符串末尾的'\0',单位都是字节,区别只是函数名不一样罢了,他们的功能完全相同。

这俩函数返回的是对象中实际存储的字符串的大小,而不是对象存储空间的大小。因为string类底层是使用动态内存管理来创建空间,存储字符串的,所以对象实际占用的存储空间往往大于对象所存储的字符串的大小。

(2)max_size与capacity

这个函数的作用是返回string类的最大容量,然而这只是一个理论最大值,实际上受限于各种客观因素,往往达不到。

capacity函数的作用是返回当前这个对象中为字符串开辟的空间大小。

(3)resize与reserve

resize函数能重新设置字符串的大小。

如果设定的n值小于当前字符串的大小,那么字符串中前n个字符会保留,第n个之后的数据会被丢弃。

如果设定的n值大于当前字符串的大小,那么多出来的空间会用指定的字符c来填充,如果没有指定字符c,则会填充 '\0' ,但这时如果调用size函数会发现,字符串的大小已经变成了设定值。

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

int main()
{
	string a("abcd");
	a.resize(7);
	cout << a << endl;
	cout << a.size() << endl;
	return 0;
}

reserve函数可以改变字符串的容量到 n ,n需要大于字符串当前的容量。

如果 n 大于字符串当前的容量,那么字符串的容量就会扩大,扩大到 n 或者比 n 更大一些,也就是说,扩大后的字符串容量并不一定就是 n 。字符串的大小不会改变。

如果 n 小于字符串当前的容量,那么这个函数可能不会有作用,这时函数的行为是没有被C++明确规定的,容量可能会缩小到 n ,也可能不变,具体看编译器。

(4)clear与empty

这个函数的作用就是清空字符串中的数据,把这个字符串变成空字符串,大小也变成 0 。

 它的作用是判断这个字符串的大小是否为0,如果是返回true,如果不是返回false。

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

int main()
{
	string a;
	cout << a.empty() << endl;
	a.append(2, '\0');
	cout << a.empty() << endl;
	a.resize(5);
	cout << a.empty() << endl;
	a.resize(0);
	cout << a.empty() << endl;
	return 0;
}

5、元素访问相关函数

(1)下标访问操作符

下标访问操作符也提供了重载,第一个是对于一般的string类创建的对象使用的,第二个是对于const修饰的string类的对象使用的。

区别在于前者可用于修改值的语句,而后者不可以,符合了其常属性。

(2)at

 at 函数用于获取pos位置的下一个元素,返回值是该元素别名,因此可以对该字符直接进行修改。

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

int main()
{
	string a("1234567");
	cout << a.at(5) << endl;
	a.at(5) = 'x';
	cout << a << endl;
	return 0;
}

6、迭代器相关函数

迭代器是设计用于我们遍历访问修改字符串中的元素的,它的行为和指针很相似,但底层不一定就是指针,具体是什么要看编译器是怎么实现的。

(1)begin和end

begin函数返回一个迭代器,这个迭代器指向的是对象存储的字符串的起始位置,也就是字符串的第一个字符的位置。

end函数返回一个迭代器,指向字符串的最后一个字符的下一个位置,也就是 '\0' ,注意这个迭代器是不可被解引用的,会报越界错误。

如果对象是空字符串,那么begin函数和end函数返回的迭代器指向的位置是相同的。

(2)rbegin和rend

rbegin函数返回一个迭代器,指向字符串的最后一个字符。

rend函数返回一个迭代器,指向字符串的第一个字符的前一个位置。

这俩函数和begin与end相似,他们函数名前 'r' 的意思是reverse逆序,也就是说begin与end是正序的,从前往后的遍历,而rbegin与rend则是逆序的从后往前的遍历。

当使用这两个函数时,接收其返回值时也要使用相应类型的迭代器。

string a("hello");
string::reverse_iterator it = a.rbegin();

(3)cbegin、cend、crbegin、crend

这四个函数和上面四个函数的作用是基本相同的,唯一区别在于返回值一定是被const修饰的迭代器,所以调用这四个函数得到的迭代器,只能对字符串进行遍历操作,而不能修改字符串的值。

7、修改字符串的相关函数

对于字符串的增加减少,插入删去,使用这些函数:

(1)+= 操作符

+= 操作符有三种重载,分别支持字符串 += string字符串、C字符串、一个字符。

#include <iostream>
using namespace std;

int main()
{
	string a("ab");
	string b("cd");
	cout << a << endl;
	a += b;
	cout << a << endl;
	a += "efg";
	cout << a << endl;
	a += 'h';
	cout << a << endl;

	return 0;
}

(2)append与insert

这个函数是在字符串末尾增加上指定的字符串。

第一种重载是将字符串str拷贝到原字符串的末尾,

第二种重载是将字符串str的第subpos之后的sublen个字符拷贝到原字符串的末尾,

第三种重载是将C字符串拷贝到原字符串的末尾,

第四种重载是将C字符串的前n个字符拷贝到原字符串的末尾,

第五种重载是将n个字符c拷贝到原字符串的末尾。

#include <iostream>
using namespace std;

int main()
{
	string a("abcdef");
	string b1, b2, b3, b4, b5;
	b1.append(a);
	b2.append(a, 0, 3);
	b3.append("abcd");
	b4.append("abcdef", 4);
	b5.append(4, 'x');
	cout << b1 << endl;
	cout << b2 << endl;
	cout << b3 << endl;
	cout << b4 << endl;
	cout << b5 << endl;
	return 0;
}

 

insert函数的作用是在原字符串第pos个字符之后,插入一个字符串,原来字符串的内容依次后移。

#include <iostream>
using namespace std;

int main()
{
	string a("123456789");
	a.insert(3, "abc");
	cout << a << endl;
	return 0;
}

(3)push_back与pop_back

这两个函数用于在字符串末尾添加或删除一个字符,并把字符串大小增大或减小 1 。

注意他们不可以增删一个字符串,只能增删一个字符,所以并不常用。

(4)assign

assign的作用是用新字符串覆盖原字符串。

#include <iostream>
using namespace std;

int main()
{
	string a("abcdefg");
	a.assign("hello");
	cout << a << endl;
	return 0;
}

(5)erase

erase函数会删除字符串中的字符。

第一种重载是一个全缺省参数的函数,它可以删除原字符串中从第pos个字符开始的,长为len个字符的数据,当len不传参时,会一直删到字符串结尾,当pos、len都不传参时,会把字符串中的字符全部删掉。

#include <iostream>
using namespace std;

int main()
{
	string a("123456789");
	cout << a.erase(3, 4) << endl;
	return 0;
}

(6)replace

这个函数将原字符串中,第pos个字符之后的len个字符,替换为指定的字符串,原字符串中再之后的字符不动或依次前移后移。

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

int main()
{
	string a("123456789");
	a.replace(1, 3, "abc");
	cout << a << endl;
	a.replace(1, 3, "x");
	cout << a << endl;
	a.replace(1, 3, "hello");
	cout << a << endl;
	return 0;
}

(7)swap

swap函数用于交换原字符串和指定字符串中的数据,所以只支持和string字符串进行调用。

8、字符串操作的相关函数

(1)c_str和data

c_str 函数返回一个指向C字符串的指针,C字符串的内容就是string字符串中的有效内容(用size函数看到的大小,这些string字符串的数据,不包括底层包含的 '\0' ),再在结尾额外增加一个 '\0' 。

data 函数返回一个指向C字符串的指针,C字符串的内容就是string字符串中的有效内容,结尾没有 '\0' 。

这两个函数返回的都是被const修饰的指针,不允许通过解引用修改值。

(2)copy

copy 函数向C字符串 s 中拷贝一个字符串,这个字符串是从原字符串的第pos个字符的下一个开始,长为len的子串。

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

int main()
{
	char a[] = "xxxxxx";
	char* pa = a;
	string b("12345");
	b.copy(pa, 3, 0);
	cout << pa << endl;
	return 0;
}

(3)find与rfind

这两个函数都是从原字符串中查找 string字符串str 或 C字符串s 或 字符c 的,前者是查找最先出现的,后者是查找最后出现的。

这两个函数需要符合查找的字符串中的所有字符。

(4)find_first_of与find_last_of

这两个函数都是从原字符串中查找 string字符串str 或 C字符串s 或 字符c 的,前者是查找最先出现的,后者是查找最后出现的。

这两个函数不需要符合查找的字符串中的所有字符,只查找到其中任何一个字符就会停止并返回位置。

(5)substr

substr 函数用来获得一个子串,从原字符串的第pos个字符的下一个开始,长为len的子串。

如果len未被指定,则子串一直延续到原字符串结束。

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

int main()
{
	string a("123456");
	string b;
	b = a.substr(1, 2);
	cout << b << endl;
	return 0;
}

(6)compare

compare 函数用于比较两个字符串的大小,按照字典序进行比较,如果相等返回0,原字符串大返回一个大于 0 的值,原字符串小返回一个小于 0 的值。

三、string的遍历与修改

1、下标 [ ]

 用下标方式来遍历和修改字符串中的元素:

#include <iostream>
using namespace std;

int main()
{
	string a("hello world!");
	for (size_t i = 0; i < a.size(); i++) {
		cout << ++a[i] << ' ';
	}
	cout << endl;
	return 0;
}

2、迭代器 iterator 

用迭代器方式来遍历和修改字符串中的元素:

#include <iostream>
using namespace std;

int main()
{
	string a("hello world!");

	string::iterator it = a.begin();
	while (it != a.end()) {
		cout << ++(*it) << ' ';
		++it;
	}
	cout << endl;
	return 0;
}

迭代器 iterator 是定义在类域中的,所以在使用迭代器之前一定要加上所属类名以及域作用限定符(也可以展开类域,但我们通常不这么用)。

3、范围for

#include <iostream>
using namespace std;

int main()
{
	string a("hello world!");
	for (auto& e : a) {
		cout << ++e << ' ';
	}
	cout << endl;
	return 0;
}

SQL容器的范围for,底层其实就是迭代器,我们自己自定义一个类时,如果按格式定义了一个迭代器,那么我们自定义的类也可以使用范围for。

所以从语法上讲,有三种遍历方式,但从底层上讲,只有两种遍历方式,一是下标,二是迭代器。

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

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

相关文章

Java生成图片_基于Spring AI

Spring AI 优势 过去&#xff0c;使用Java编写AI应用时面临的主要困境是没有统一且标准的封装库&#xff0c;开发者需自行对接各个AI服务提供商的接口&#xff0c;导致代码复杂度高、迁移成本大。如今&#xff0c;Spring AI Alibaba的出现极大地缓解了这一问题&#xff0c;它提…

vue3之生命周期钩子

Vue 组件实例生命周期 每个 Vue 组件实例在创建时都需要经历一系列的初始化步骤&#xff0c;比如设置好数据侦听&#xff0c;编译模板&#xff0c;挂载实例到 DOM&#xff0c;以及在数据改变时更新 DOM。在此过程中&#xff0c;它也会运行被称为生命周期钩子的函数&#xff0c…

基于Arduino的燃气泄漏检测系统与自动切断调节器

Arduino LPG燃气泄漏检测系统与自动切断调节器 引言 大家好&#xff0c;今天我要分享一个非常实用的项目——Arduino LPG燃气泄漏检测系统与自动切断调节器。这个项目的重要性不言而喻&#xff0c;因为燃气泄漏是一个严重的安全隐患。在厨房烹饪时&#xff0c;我们可能会忘记…

望繁信科技成功签约国显科技 流程挖掘助力制造业智造未来

近日&#xff0c;上海望繁信科技有限公司&#xff08;简称“望繁信科技”&#xff09;成功与深圳市国显科技有限公司&#xff08;简称“国显科技”&#xff09;达成合作。国显科技作为全球领先的TFT-LCD液晶显示及Mini/Micro LED显示产品供应商&#xff0c;致力于为笔记本、手机…

设计模式02-桥接模式(Java)

4.2 桥接模式 **1.定义&#xff1a;**将抽象与实现分离&#xff0c;使它们可以独立变化。它是用组合关系代替继承关系来实现&#xff0c;从而降低了抽象和实现这两个可变维度的耦合度。 2.结构&#xff1a; 抽象化角色 &#xff1a;定义抽象类&#xff0c;并包含一个对实现化…

Spring Security无脑使用

步骤1&#xff1a;添加Spring Security依赖 在你的Spring Boot项目的pom.xml文件中&#xff0c;添加Spring Security的依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</art…

数据库的特点

数据库是有组织的&#xff0c;规范的把数据保存起来的。 怎么个组织的&#xff0c;规范的&#xff1f; 数据库的特点&#xff1a; 1.将数据放到数据表格&#xff08;二维表&#xff09;中&#xff0c;在将表格放到库中。 2.一个数据库中可以有多张表&#xff0c;每个表都有一…

【OpenCV】(四)—— 边界填充

在OpenCV的图像处理中&#xff0c;边界填充主要用于在图像边缘添加额外的像素。这项技术在多种图像处理任务中都有重要的应用&#xff0c;包括但不限于卷积操作、图像缩放、形态学操作等。 opencv中边界填充的主要方法为copyMakeBorder&#xff0c;其函数原型如下&#xff1a;…

分享一道逻辑题

1、有一个水无限多的是水塘.只有两个水瓶.一个5升一个6升.如何从水塘里用这两个水瓶取出3升水?

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-13

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-13 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-10-13目录1. The Cognitive Capabilities of Generative AI: A Comparative Analysis with Human Benchmarks2. WALL-E: World Alig…

Postman 如何测试入参是文件类型(File)参数接口

Postman 如何测试 File 类型参数 前提背景测试步骤1、打开 Postman 选择 POST 方法输入调用地址2、参数选择 Body 下的 form-data3、KEY 选择 File 选项&#xff0c;并填写 file 前提背景 springboot 项目&#xff0c;接口的参数是 File 类型&#xff0c;需要通过 Postman 测试…

链表题, 反转链表 , 链表的中间结点 , 删除链表的倒数第 N 个结点 , 移除链表元素

文章目录 206. 反转链表203. 移除链表元素876. 链表的中间结点LCR 021. 删除链表的倒数第 N 个结点 206. 反转链表 题目链接 思路&#xff1a; 将原链表的结点&#xff0c;从头到尾一个个地拿下来头插到一个新链表中&#xff0c;这个新链表起始时为一个空链表。 class Solutio…

同三维T80001HK4 四路4K30HDMI H.264编码器

4路同时编码&#xff0c;带4路3.5外置音频 同三维T80001HK4四路4K30HDMI H.264编码器 同三维T80001HK4用于高清视频信号&#xff08;4K30Hz&#xff09;编码及网络传输的硬件设备&#xff0c;采用最新高效H.264高清数字视频压缩技术&#xff0c;具备稳定可靠、高清晰度、低码率…

408 14——42题

题目&#xff1a; 某网络中的路由器运行OSPF路由协议&#xff0c;题42表是路由器R1维护的主要链路状态信息(LSI)&#xff0c;题42图是根据题42表及R1的接口名构造出来的网络拓扑。 请回答下列问题。 1)本题中的网络可抽象为数据结构中的哪种逻辑结构? 2)针对题42表中的内容&am…

C++ 类和对象-改

在C中&#xff0c;类&#xff08;Class&#xff09;是用户自定义的数据类型&#xff0c;用来封装数据和功能的结合。而对&#xff08;Object&#xff09;是类的实例&#xff0c;通过类的定义可以创建多个对象。C是一种面向对象编程语言&#xff0c;类和对象是其核心概念。 1. …

前端开发基础NodeJS+NPM基本使用(零基础入门)

文章目录 1、Nodejs基础1.1、NodeJs简介1.2、下载安装文件1.3、安装NodeJS1.4、验证安装2、Node.js 创建第一个应用2.1、说明2.2、创建服务脚本2.3、执行运行代码2.4、测试访问3、npm 基本使用3.1、测试安装3.2、配置淘宝npm镜像3.3.1、本地安装3.3.2、全局安装3.4、查看安装信…

项目总思路

一、模型选择 高性能服务器一般用到的是 Reactor 模型&#xff0c;即事件驱动模型。 1、模型一&#xff1a;单 Reactor 单线程模型 只有一个线程会造成性能瓶颈。 适用场景&#xff1a;客户端少&#xff0c;业务处理快速。 2、模型二&#xff1a;单 Reactor 多线程模型 即…

栈——单调栈

题目描述 给定一个长度为 N 的整数数列&#xff0c;输出每个数左边第一个比它小的数&#xff0c;如果不存在则输出 −1。 输入格式 第一行包含整数 N (1≤N≤10^5)&#xff0c;表示数列长度。 第二行包含 N 个整数&#xff0c;表示整数数列。1≤ai≤10^9。 输出格式 共一…

git规范化开发

特性分支开发 以前使用git基本都是随心所欲的用&#xff0c;commit的信息比较随便&#xff0c;所以有时git分支结构有时显得混乱&#xff0c;最近标准化开发的过程中接触了特性分支开发。 何为特性分支&#xff0c;按我的理解&#xff0c;就是每一次代码的修改提交&am…

Linux操作系统学习——常见指令集合

本篇博客是对于linux系统学习的初步认识&#xff0c;了解一些常见指令以及基础知识 ls指令 ls/ls -l :只显示文件名/显示更多文件的属性&#xff0c;此时注意最后一行开头位置字母为d就代表显示的是目录的文件属性&#xff0c;还有一点就是&#xff1a;ls -l 默认查看当前目录…