C++入门7——string类详解

目录

1.什么是string类?

2.string类对象的常见构造

2.1 string();

2.2 string (const char* s);

2.3 string (const string& str);

2.4 string (const string& str, size_t pos, size_t len = npos);

2.5 string (const char* s, size_t n);

2.7 验证:

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

3.1 下标+ [] 访问

3.2 iterator迭代器访问

3.3 at访问 

4. string类对象的容量操作

4.1 size与length

4.2 capacity

4.3 reserve

4.4 resize

4.5 clear

4.6 empty

5.string类对象的修改操作

5.1 增

1. append

2. +=

3.insert 

5.2 删

1. pop_back

2. erase

5.3 查 

1.substr

2.find

5.4 改

1. replace

2. swap 

5.5 查改结合完成替换操作


1.什么是string类?

在官网中,string类有这样的介绍:

Strings are objects that represent sequences of characters.

即:string类表示的对象是字符串类。

1. string是表示字符串的字符串类

2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。

3. string在底层实际是:basic_string模板类的别名,typedef basic_string string;

4. 不能操作多字节或者变长字符的序列。

(在使用string类时,必须包含#include头文件以及using namespace std;)

2.string类对象的常见构造

2.1 string();

在官网中,对string();的解释为:

Constructs an empty string, with a length of zero characters.

即:构造一个空字符串,长度为零字符。

int main()
{//string();定义一个空的string类string s1;return 0;
}

2.2 string (const char* s);

在官网中,对于string (const char* s);的解释为:

Copies the null-terminated character sequence (C-string) pointed by s.

即:复制s指向的以空字符结尾的字符串。

int main()
{//string (const char* s);复制s指向的以空字符结尾的字符串string s2("hello world!");return 0;
}

2.3 string (const string& str);

在官网中,对string (const string& str);的解释为:

Constructs a copy of str.

即可以理解为拷贝构造。

int main()
{//拷贝构造s2string s3(s2);string s4 = s2;return 0;
}

2.4 string (const string& str, size_t pos, size_t len = npos);

在官网中,对string (const string& str, size_t pos, size_t len = npos);的解释为:

Copies the portion of str that begins at the character position pos and spans len characters.

即:拷贝str从pos位置到len个字符的一部分。

int main()
{//string (const string& str, size_t pos, size_t len = npos);//拷贝str从pos位置到len个字符的一部分。string s5(s2, 1, 7);return 0;
}

可在官网里括号里还有一句话:  (or until the end of str, if either str is too short or if len is string::npos).

这句话可以理解为:如果str太短或者len太长,那就只拷贝到str的结尾。

2.5 string (const char* s, size_t n);

在官网中,对string (const char* s, size_t n);的解释为:

Copies the first n characters from the array of characters pointed by s.

即:拷贝s指向的字符数组的前n个字符。

int main()
{//string (const char* s, size_t n);//拷贝s指向的字符数组的前n个字符string s6("hello world!", 5);return 0;
}

2.6 string (size_t n, char c);

在官网中,对string (size_t n, char c);的解释为:

Fills the string with n consecutive copies of character c.

即:用n个C语言字符填充。

int main()
{//string (size_t n, char c);//用n个C语言字符填充string s7(10, 'l');
}

2.7 验证:

<<与>>已实现重载,所以可以直接用。

故验证代码如下:

#include<iostream>
#include<string>
using namespace std;
int main()
{//string();定义一个空的string类string s1;//string (const char* s);复制s指向的以空字符结尾的字符串string s2("hello world!");//string (const string& str);拷贝构造s2string s3(s2);string s3_1 = s2;//string (const string& str, size_t pos, size_t len = npos);//拷贝str从pos位置到len个字符的一部分。string s4(s2, 1, 7);//拷贝s2从下标1位置开始到7个字符的一部分//string (const char* s, size_t n);//拷贝s指向的字符数组的前n个字符string s5("hello world!", 5);//拷贝"hello world!"的前5个字符//string (size_t n, char c);//用n个C语言字符填充string s6(10, 'l');//拷贝10个‘l’cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cout << s3_1 << endl;cout << s4 << endl;cout << s5 << endl;cout << s6 << endl;return 0;
}

结果如图:

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

3.1 下标+ [] 访问

①计算string类的长度或大小

 (size与length意义相同,建议用size)用法如下:

int main()
{string s1("hello world!");cout << s1.size() << endl;cout << s1.length() << endl;return 0;
}

(由结果得知,size与length不包含'\0') 

② 知道了string的长度,我们就可以这样遍历string:

int main()
{string s1("hello world!");for (size_t i = 0; i < s1.size(); i++){cout << s1[i] << endl;//重载了s1.operator[](i)}return 0;
}

 ③实现逆置string

方法一:手搓交换

int main()
{string s1("hello world!");cout << "逆置前s1="<< s1 << endl;size_t begin = 0;//左边界size_t end = s1.size() - 1;//右边界while (begin < end){char tmp = s1[begin];s1[begin] = s1[end];s1[end] = tmp;++begin;--end;}cout << "逆置后s1=" << s1 << endl;return 0;
}

方法二:使用swap

int main()
{string s1("hello world!");cout << "逆置前s1="<< s1 << endl;while (begin < end){swap(s1[begin], s1[end]);++begin;--end;}cout << "逆置后s1=" << s1 << endl;return 0;
}

3.2 iterator迭代器访问

int main()
{string s1("hello world!");string::iterator it = s1.begin();while (it != s1.end()){cout << *it << endl;++it;}return 0;
}

iterator的用法与指针类似:

二者的区别:

 下标+[]只适用于部分容器,底层物理有一定连续,如链式结构、树形、哈希结构,就只能用迭代器。迭代器才是容器访问的主流形式。

3.3 at访问 

at访问与下标+[]访问的功能相同,区别主要体现在越界访问时的报错形式:

如①下标+[]的越界访问:

int main()
{string s1("hello world!");cout << s1[20] << endl;return 0;
}

 ②at的越界访问:

int main()
{string s1("hello world!");cout << s1.at(20) << endl;return 0;
}

(即下标+[]是暴力地终止,at是温柔地终止) 

4. string类对象的容量操作

4.1 size与length

size与length返回字符串有效字符长度

前面已经说过,size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。

代码演示:

int main()
{string s1("hello world!");cout << s1.size() << endl;return 0;
}

4.2 capacity

capacity返回空间总大小

代码如下:

int main()
{string s1("hello world!");cout << s1.capacity() << endl;return 0;
}

设计程序检测string的扩容机制:

int main()
{string s1("hello world!");//检测string的扩容机制size_t old = s1.capacity();    //令old=原本的容量大小cout << old << endl;        for (size_t i = 0; i < 500; i++){s1.push_back('l');         //尾插l的过程中string的容量大小一定会发生变化if (old != s1.capacity())  //当发生扩容时,打印新的string容量大小{cout << s1.capacity() << endl;old = s1.capacity();}}return 0;
}

4.3 reserve

reserve为字符串预留空间(即可以理解为需要多少空间提前开好,不用边用边开)

reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小。(在vs2019下reserve只扩容不缩容,在g++下reserve会缩容,但只会缩到现有数据的大小)

用法如下:

int main()
{string s1("hello world!");cout << s1.capacity() << endl;s1.reserve(500);cout << s1.capacity() << endl;return 0;
}

4.4 resize

resize将有效字符的个数改变成n个,多出的空间用字符c填充

resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字 符个数增多时:resize(n)用'\0'来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大 小,如果是将元素个数减少,底层空间总大小不变。

①如果要扩容的空间>capacity,则扩容+尾插。验证如下:

int main()
{string s1("hello world!");cout << s1.size() << endl;cout << s1.capacity() << endl;//如果要扩容的空间>capacitys1.resize(100);cout << s1.size() << endl;cout << s1.capacity() << endl;cout << s1 << endl;return 0;
}

int main()
{string s1("hello world!");cout << s1.size() << endl;cout << s1.capacity() << endl;//如果要扩容的空间>capacitys1.resize(100, 'x');cout << s1.size() << endl;cout << s1.capacity() << endl;cout << s1 << endl;return 0;
}

 ②如果size<n<capacity,则只尾插不扩容,验证如下:

int main()
{string s1("hello world!");cout << s1.size() << endl;cout << s1.capacity() << endl;//如果size<n<capacitys1.resize(13,'x');cout << s1.size() << endl;cout << s1.capacity() << endl;cout << s1 << endl;return 0;
}

③如果n<size,只删除、保留前n个,不缩容,验证如下:

int main()
{string s1("hello world!");cout << s1.size() << endl;cout << s1.capacity() << endl;//如果n<capacitys1.resize(6);cout << s1.size() << endl;cout << s1.capacity() << endl;cout << s1 << endl;return 0;
}

(reserve与resize的区别可以概括为一句话:reserve只影响容量,不影响数据,resize既影响容量又影响数据)

4.5 clear

清空有效字符

clear()只是将string中有效字符清空,不改变底层空间大小。

验证如下:

int main()
{string s1("hello world!");cout << s1.size() << endl;cout << s1.capacity() << endl;s1.clear();cout << s1.size() << endl;cout << s1.capacity() << endl;cout << s1 << endl;return 0;
}

4.6 empty

检测字符串释放为空串,是返回true,否则返回false(注意:空为真,不空为假)

验证如下:

int main()
{string s1("hello world!");cout << s1.empty() << endl;string s2;cout << s2.empty() << endl;return 0;
}

5.string类对象的修改操作

修改操作无非就是增删查改,这里只介绍比较常用的操作

5.1 增

1. append

增操作其实已经有了一个我们熟悉的push_back,可是push_back每次只能尾插一个字符,为了方便就有了append:

比如我们二者兼用:

int main()
{string s1("hello");s1.push_back(' ');s1.append("world!");cout << s1 << endl;return 0;
}

append的其他常用用法如下:

①string& append (const char* s);插入常量字符串(上面的用法)

②string& append (const string& str);插入string:

int main()
{string s1("hello");string s2(s1);return 0;
}

③string& append (const string& str, size_t subpos, size_t sublen);插入string从subpos位置起到sublen个字符止的那部分:

int main()
{string s1("hello world!");string s2(s1,1,3);return 0;
}

④string& append (const char* s, size_t n);插入常量字符串的前n个:

int main()
{string s1("hello world!", 3);return 0;
}

⑥string& append (size_t n, char c);插入n个字符c:

int main()
{string s1(4,'x');return 0;
}

⑦string& append (InputIterator first, InputIterator last);插入string的一部分:

插入s1:

int main()
{string s1("hello world!");string s2;s2.append(s1.begin(), s1.end());return 0;
}

 插入去头去尾的s1:

int main()
{string s1("hello world!");string s2;s2.append(++s1.begin(), --s1.end());return 0;
}

2. +=

①string& operator+= (const string& str);插入string:

int main()
{string s1("hello world!");string s2;s2 += s1;return 0;
}

②string& operator+= (const char* s);插入字符串:

int main()
{string s1;s1 += "hello world!";return 0;
}

 ③string& operator+= (char c);插入字符:

int main()
{string s1;s1 += '!';return 0;
}

3.insert 

观察push_back与append,二者都是尾插,那有没有不是尾插的方法呢?当然有!

①string& insert (size_t pos, const string& str);在pos位置插入string:

int main()
{string s1("hello ");string s2("world!");s2.insert(0, s1);return 0;
}

②string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);在pos位置插入string的一部分:

int main()
{string s1("hello ");string s2("world!");s2.insert(0, s1, 1, 3);//ellworld!return 0;
}

③string& insert (size_t pos, const char* s);在pos位置插入字符串:

int main()
{string s1("world!");s1.insert(0, "hello ");//hello world!return 0;
}

④string& insert (size_t pos, const char* s, size_t n);在pos位置插入字符串的前n个:

int main()
{string s1("world!");s1.insert(0, "hello ",3);//helworld!return 0;
}

5.2 删

1. pop_back

尾删:

int main()
{string s1("hello world!");s1.pop_back();//hello worldreturn 0;
}

2. erase

①string& erase (size_t pos = 0, size_t len = npos);从第pos个位置删除len个字符:

int main()
{string s1("hello world!");s1.erase(5, 1);//helloworld!return 0;
}

②iterator erase (iterator p);删除string的第p个位置:

int main()
{string s1("hello world!");s1.erase(s1.begin()+1);//hllo world!return 0;
}

5.3 查 

1.substr

string substr (size_t pos = 0, size_t len = npos) const;从pos位置开始,取len个字符:

int main()
{string s1("hello world!");string s2 = s1.substr(6, 5);//worldreturn 0;
}

2.find

关于find的返回值:

The position of the first character of the first match.
If no matches were found, the function returns string::npos.
即:如果找到了就返回找到的第一个的下标,如果没有找到就返回整型的最大值。

①size_t find (char c, size_t pos = 0) const;从pos位置开始找c,没有给pos默认从头开始找:

int main()
{string s1("hello world!");size_t pos1 = s1.find('l');//2size_t pos2 = s1.find('l', 5);//9size_t pos3 = s1.find('x');//nposreturn 0;
}

 例:取string指定的一部分:

int main()
{//取文件名后缀string s1("test.cpp");size_t pos1 = s1.find('.');if (pos1 != string::npos){/*string s2 = s1.substr(pos1, s1.size() - pos1);*/string s2 = s1.substr(pos1);cout << s2 << endl;}return 0;
}

5.4 改

1. replace

①string& replace (size_t pos, size_t len, const string& str);在pos位置的len个字符替换成str:

int main()
{string s1("hello world!");s1.replace(5, 1, "?");//hello?world!return 0;
}

2. swap 

与另一个string交换:

int main()
{string s1("hello world!");string s2;s2.swap(s1);//hello world!return 0;
}

5.5 查改结合完成替换操作

例:将s1的空格全部替换为?

方法一:

int main()
{string s1("have a good time!");cout << "替换前s1=" << s1 << endl;//have a good time!size_t pos = s1.find(' ', 0);while (pos != string::npos){s1.replace(pos, 1, "?");pos = s1.find(' ', pos + 1);}cout << "替换后s1=" << s1 << endl;//have?a?good?time!return 0;
}

实际中replace效率太低,因此尽量少用replace

方法二:

int main()
{string s1("have a good time!");cout << "替换前" << s1 << endl;//have a good time!string s2;for (auto ch : s1){if (ch == ' '){s2 += "?";}else{s2 += ch;}}s1.swap(s2);cout << "替换后" << s1 << endl;//have?a?good?time!return 0;
}

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

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

相关文章

绝区肆--2024 年AI安全状况

前言 随着人工智能系统变得越来越强大和普及&#xff0c;与之相关的安全问题也越来越多。让我们来看看 2024 年人工智能安全的现状——评估威胁、分析漏洞、审查有前景的防御策略&#xff0c;并推测这一关键领域的未来可能如何。 主要的人工智能安全威胁 人工智能系统和应用程…

Java里的Arrary详解

DK 中提供了一个专门用于操作数组的工具类&#xff0c;即Arrays 类&#xff0c;位于java.util 包中。该类提供了一些列方法来操作数组&#xff0c;如排序、复制、比较、填充等&#xff0c;用户直接调用这些方法即可不需要自己编码实现&#xff0c;降低了开发难度。 java.util.…

Python爬虫系列-让爬虫自己写爬虫(半自动化,代替人工写爬虫)

现在的PC、手机客户端等终端设备大量使用了网页前后端技术&#xff0c;另外主流的网站也会经常会更新&#xff0c;导致以前一个月更新一次爬虫代码&#xff0c;变成了天天需要更新代码&#xff0c;所以自动化爬虫技术在当前就显得特别重要&#xff0c;最近我也是在多次更新某个…

赋值运算符重载和const成员函数和 const函数

文章目录 1.运算符重载(1)(2)运算符重载的语法&#xff1a;(3)运算符重载的注意事项&#xff1a;(4)前置和后置重载区别 2.const成员函数3.取地址及const取地址操作符重载4.总结 1.运算符重载 (1) 我们知道内置类型(整形&#xff0c;字符型&#xff0c;浮点型…)可以进行一系…

TB作品】51单片机 Proteus仿真 51单片机SPI显示OLED字符驱动

// GND 电源地 // VCC 接5V或3.3v电源 // D0 P1^4&#xff08;SCL&#xff09; // D1 P1^3&#xff08;SDA&#xff09; // RES 接P12 // DC 接P11 // CS 接P10 OLED显示接口与控制实验报告 背景 OLED&#xff08;有机发光二极管&#xff09;显示器由于其高对比度、低功耗和…

最新版Python安装教程

一、安装Python 1.下载Python 访问Python官网&#xff1a; https:/www.oython.orgl 点击downloads按钮&#xff0c;在下拉框中选择系统类型(windows/Mac OS./Linux等) 选择下载最新稳定版本的Python 以下内容以演示安装Windows操作系统64位的python 左边是稳定发布版本Stabl…

Linux权限概述

一、权限概述 1.权限的基本概念 2.为什么要设置权限 3.linux用户的身份类别 4.user文件的拥有者 5.group文件所属组内用户 6.other其他用户 7.特殊用户root 二、普通权限管理 1.ls -l查看文件权限 2.文件类型以及权限解析 3.文件或文件夹的权限设置 4.通过数字给文件…

CSRF verification failed. Request aborted.

最近在学习django&#xff0c;遇到这个问题。CSRF verification failed. Request aborted. 解决方案&#xff1a; 1、在Html template中加入csrf_token 2、在view.py中对应的view函数上加上装饰器 再启动运行&#xff0c;报错就解决了。

网页生成二维码、在线演示

https://andi.cn/page/621504.html

Zabbix监控软件

目录 一、什么是Zabbix 二、zabbix监控原理 三、zabbix 安装步骤 一、什么是Zabbix ●zabbix 是一个基于 Web 界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。 ●zabbix 能监视各种网络参数&#xff0c;保证服务器系统的安全运营&#xff1b;并提供灵活的…

通信协议_Modbus协议简介

概念介绍 Modbus协议&#xff1a;一种串行通信协议&#xff0c;是Modicon公司&#xff08;现在的施耐德电气Schneider Electric&#xff09;于1979年为使用可编程逻辑控制器&#xff08;PLC&#xff09;通信而发表。Modbus已经成为工业领域通信协议的业界标准&#xff08;De f…

ARM架构和Intel x86架构

文章目录 1. 处理器架构 2. ARM架构 3. Intel x86架构 4. 架构对比 5. 编译过程对比 1. 处理器架构 处理器架构是指计算机处理器的设计和组织方式&#xff0c;它决定了处理器的性能、功耗和功能特性。处理器架构影响着从计算机系统的硬件设计到软件开发的各个方面。在现代…

@[TOC](六、数据可视化—Echars(爬虫及数据可视化))

六、数据可视化—Echars&#xff08;爬虫及数据可视化&#xff09; Echarts应用 Echarts Echarts官网&#xff0c;很多图表等都是我们可以 https://echarts.apache.org/zh/index.html 是百度自己做的图表&#xff0c;后来用的人越来越多&#xff0c;捐给了orange组织&#xf…

【ROS2】初级:客户端-创建自定义 msg 和 srv 文件

目标&#xff1a;定义自定义接口文件&#xff08; .msg 和 .srv &#xff09;并将它们与 Python 和 C节点一起使用。 教程级别&#xff1a;初学者 时间&#xff1a;20 分钟 目录 背景 先决条件 任务 1. 创建一个新包2. 创建自定义定义3 CMakeLists.txt4 package.xml5. 构建 tut…

Vue3中生成本地pdf并下载

1. 前言 前端中经常会遇到在系统中根据数据导出一个pdf文件出来,一般都是后端来实现的,既然后端可以实现,前端为什么就不行呢,正好有一次也写了这个需求,就写了个小demo 示例图: 2. 实现步骤 首先下载html2pdf.js这个库yarn add html2pdf.js // 或 npm i html2pdf.js在项…

下载,连接mysql数据库驱动(最详细)

前言 本篇博客&#xff0c;我讲讲如何连接数据库&#xff1f;我使用mysql数据库举例。 目录 下载对应的数据库jar 包 百度网盘 存有8.4.0版本压缩包&#xff1a;链接&#xff1a;https://pan.baidu.com/s/13uZtXRmuewHRbXaaCU0Xsw?pwduipy 提取码&#xff1a;uipy 复制这…

数据结构--二叉树和堆

目录 1.基本概念 2.树的遍历方法 3.满二叉树&&完全二叉树 4.逻辑结构&&物理结构 5.推理公式 6.二叉树应用--堆 7.简单实现堆 1.基本概念 &#xff08;1&#xff09;这个里面的概念还是比较多的&#xff0c;但是大部分我们只需要了解即可&#xff0c;因为…

论文略读:Large Language Models Relearn Removed Concepts

通过神经元修剪在模型编辑方面取得的进展为从大型语言模型中去除不良概念提供了希望。 然而&#xff0c;目前尚不清楚在编辑后模型是否具有重新学习修剪概念的能力——>论文通过在重新训练期间跟踪修剪神经元中的概念显著性和相似性来评估模型中的概念重新学习 研究结果表明…

嵌入式C语言面试相关知识——内存管理(不定期更新)

嵌入式C语言面试相关知识——内存管理&#xff08;不定期更新&#xff09; 一、博客声明二、自问题目1、嵌入式系统的内存布局是怎么样的&#xff1f;2、动态内存分配在嵌入式系统中的使用有什么注意事项&#xff1f;3、什么是内存碎片&#xff0c;如何减少内存碎片&#xff1f…

论文复现-基于决策树算法构建银行贷款审批预测模型(金融风控场景)

作者Toby&#xff0c;来源公众号&#xff1a;Python风控模型&#xff0c;基于决策树算法构建银行贷款审批预测模型 目录 1.金融风控论文复现 2.项目背景介绍 3.决策树介绍 4.数据集介绍 5.合规风险提醒 6.技术工具 7.实验过程 7.1导入数据 7.2数据预处理 7.3数据可…