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

news2024/11/23 3:58:13

目录

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()
{
    //拷贝构造s2
	string 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);拷贝构造s2
	string 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;

	//如果要扩容的空间>capacity
	s1.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;

	//如果要扩容的空间>capacity
	s1.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<capacity
	s1.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<capacity
	s1.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 world
	return 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);//world
	return 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');//2
	size_t pos2 = s1.find('l', 5);//9
	size_t pos3 = s1.find('x');//npos
	return 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.coloradmin.cn/o/1904812.html

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

相关文章

Educational Codeforces Round 167 (Rated for Div. 2)(A~C)题解

A. Catch the Coin 解题思路: 最终&#x1d465;一定会相等&#xff0c;我们考虑直接到下面接住他。 #include<bits/stdc.h> using namespace std; typedef long long ll; #define N 1000005 ll dp[N], w[N], v[N], h[N]; ll dis[1005][1005]; ll a, b, c, n, m, t; ll…

PCIe驱动开发(2)— 第一个简单驱动编写和测试

PCIe驱动开发&#xff08;2&#xff09;— 第一个简单驱动编写和测试 一、前言 教程参考&#xff1a;02_实战部分_PCIE设备测试 教程参考&#xff1a;03_PCIe设备驱动源码解析 二、驱动编写 新建hello_pcie.c文件 touch hello_pcie.c然后编写内容如下所示&#xff1a; #i…

芯片封装简介

1、背景 所谓“封装技术”是一种将集成电路用绝缘的塑料或陶瓷材料打包的技术。以CPU为例&#xff0c;实际看到的体积和外观并不是真正的CPU内核的大小和面貌&#xff0c;而是CPU内核等元件经过封装后的产品。封装技术对于芯片来说是必须的&#xff0c;也是至关重要的。因为芯片…

Java AI+若依框架项目开发 RuoYi-Vue(SpringBoot + Vue)

1.诺依的版本 本次选择RuoYI-Vue框架进行讲解 官网地址&#xff1a;RuoYi-Vue: &#x1f389; 基于SpringBoot&#xff0c;Spring Security&#xff0c;JWT&#xff0c;Vue & Element 的前后端分离权限管理系统&#xff0c;同时提供了 Vue3 的版本 (gitee.com) 2.搭建后端…

centos7|操作系统|低版本的OpenSSH升级到最新版本OpenSSH-9.8.p1

前言&#xff1a; 1、 OpenSSH是什么 OpenSSH 是 SSH &#xff08;Secure SHell&#xff09; 协议的免费开源实现。SSH协议族可以用来进行远程控制&#xff0c; 或在计算机之间传送文件。而实现此功能的传统方式&#xff0c;如telnet(终端仿真协议)、 rcp ftp、 rlogin、rsh都…

集合复习(java)

文章目录 Collection 接口Collection结构图Collection接口中的方法Iterator 与 Iterable 接口Collection集合遍历方式迭代器遍历增强 for 遍历 List&#xff08;线性表&#xff09;List特有方法ArrayList&#xff08;可变数组&#xff09;ArrayList 底层原理ArrayList 底层原理…

土豆炒肉做法

菜单&#xff1a;土豆、葱、铁辣子、纯瘦肉、淀粉、生抽、酱油、刀、案板、十三香、盐巴、擦板 流程&#xff1a; 洗土豆&#xff0c;削皮&#xff0c;擦成条&#xff0c;用凉水过滤两遍淀粉&#xff0c;顺便放个燥里洗肉&#xff0c;切成条&#xff0c;按照生抽、酱油、淀粉、…

【Etabs】【Rhino】Swallow(ESD)软件的ETABS功能介绍

Swallow(ESD)软件的ETABS功能介绍 来源&#xff1a;https://www.food4rhino.com/app/swallowesd 文章目录 Swallow(ESD)软件的ETABS功能介绍1. Load模块1.1 Support节点支座1.2 LoadPattern荷载模式1.3 LoadPattByName引用模型荷载模式1.4 AutoWindChinese自动风荷载参数1.5 R…

【数据结构与算法】插入排序

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​

Git仓库介绍

1. Github GitHub 本身是一个基于云端的代码托管平台&#xff0c;它提供的是远程服务&#xff0c;而不是一个可以安装在本地局域网的应用程序。因此&#xff0c;GitHub 不可以直接在本地局域网进行安装。 简介&#xff1a;GitHub是最流行的代码托管平台&#xff0c;提供了大量…

【开放集目标检测】Grounding DINO

一、引言 论文&#xff1a; Grounding DINO: Grounding DINO: Marrying DINO with Grounded Pre-Training for Open-Set Object Detection 作者&#xff1a; IDEA 代码&#xff1a; Grounding DINO 注意&#xff1a; 该算法是在Swin Transformer、Deformable DETR、DINO基础上…

STM32崩溃问题排查

文章目录 前言1. 问题说明2. STM32&#xff08;Cortex M4内核&#xff09;的寄存器3. 崩溃问题分析3.1 崩溃信息的来源是哪里&#xff1f;3.2 崩溃信息中的每个关键字代表的含义3.3 利用崩溃信息去查找造成崩溃的点3.4 keil5中怎么根据地址找到问题点3.5 keil5上编译时怎么输出…

数据库(表)

要求如下&#xff1a; 一&#xff1a;数据库 1&#xff0c;登录数据库 mysql -uroot -p123123 2&#xff0c;创建数据库zoo create database zoo; Query OK, 1 row affected (0.01 sec) 3&#xff0c;修改字符集 mysql> use zoo;---先进入数据库zoo Database changed …

护网在即,知攻善防助力每一位安服仔~

前言 是不是已经有师傅进场了呢~ 是不是有安服&#x1f412;在值守呢~ 您是不是被网上眼花缭乱的常用应急响应工具而烦恼呢&#xff1f; 何以解忧&#xff1f;唯有知攻善防&#xff01; 创作起源&#xff1a; 驻场、护网等&#xff0c;有的客户现场只允许用客户机器&…

【计组OS】I/O方式笔记总结

苏泽 “弃工从研”的路上很孤独&#xff0c;于是我记下了些许笔记相伴&#xff0c;希望能够帮助到大家 目录 IO方式&#xff1a;程序查询方式 工作原理 程序查询方式的详细流程&#xff1a; 1. 初始化阶段 2. 发送I/O命令 3. 循环检查状态 4. 数据传输 5. 继续查询 6…

机器人动力学模型及其线性化阻抗控制模型

机器人动力学模型 机器人动力学模型描述了机器人的运动与所受力和力矩之间的关系。这个模型考虑了机器人的质量、惯性、关节摩擦、重力等多种因素&#xff0c;用于预测和解释机器人在给定输入下的动态行为。动力学模型是设计机器人控制器的基础&#xff0c;它可以帮助我们理解…

自动化设备上位机设计 四

目录 一 设计原型 二 后台代码 一 设计原型 二 后台代码 using SimpleTCP; using SqlSugar; using System.Text;namespace 自动化上位机设计 {public partial class Form1 : Form{SqlHelper sqlHelper new SqlHelper();SqlSugarClient dbContent null;bool IsRun false;i…

【MySQL基础篇】多表查询

1、多表关系 概述&#xff1a;项目开发中&#xff0c;在进行数据库表结构操作设计时&#xff0c;会根据业务需求及业务模板之间的关系&#xff0c;分析并设计表结构&#xff0c;由于业务之间相互关联&#xff0c;所以各个表结构之间也存在着各种联系&#xff0c;基本上分为三种…

react dangerouslySetInnerHTML将html字符串以变量方式插入页面,点击后出现编辑状态

1.插入变量 出现以下编辑状态 2.解决 给展示富文本的标签添加css样式 pointerEvents: none

windows上传app store的构建版本简单方法

我们在上传app store上架&#xff0c;或上传到testflight进行ios的app测试的时候&#xff0c;需要mac下的上传工具上传ipa文件到app store的构建版本上。 然而windows电脑这些工具是无法安装的。 因此&#xff0c;假如在windows上开发hbuilderx或uniapp的应用&#xff0c;可以…