*C++:string

news2024/9/23 7:29:30

一.STL简介

1.STL

STL(standard template libaray- 标准模板库 ) C++ 标准库的重要组成部分 ,不仅是一个可复用的组件库,而且 是一个包罗数据结构与算法的软件框架

2.STL六大组件

二.标准库里的string类

标准string库网址:string - C++ Reference

1.string构造函数

int main()
{
    string s1;
    string s2("张三");
    string s3("hello world");
    string s4(10, '*');       //10个*
    string s5(s2);            //拷贝构造
    string s6(s3, 0, 5);      //以s3为基准,拷贝第0到第5个字符
    string s7(s3, 6);         //第三个参数没有给的时候会自动填充一个npos(-1),指向最后一个位置
    string s8(s3, 6, 100);    //超出string长度的时候,会以最后一个位置为结尾

    cout << s1 << endl;
    cout << s2 << endl;
    cout << s3 << endl;
    cout << s4 << endl;
    cout << s5 << endl;
    cout << s6 << endl;
    cout << s7 << endl;
    cout << s8 << endl;
}

2.赋值运算符重载(operator=)

int main()
{
	string s1;
	string s2("张三");

	s1 = s2;             //str
	cout << s1 << endl;
 
 	s1 = "1111";         //char*
	cout << s1 << endl; 

	s1 = '2';            //char
	cout << s1 << endl;

	return 0;
}

大于小于号运算符重载:

cout << (s1 == s2) << endl; //0
cout << (s1 > s2) << endl;  //0

3.string尾插(字符,字符串)

(1).尾插一个字符(push_back)

int main()
{
	string s1("hello");
	// 尾插一个字符
	s1.push_back('7');    //hello7
}
(2).尾插一个字符串(append,+=)

不过在一些情况下+=是更好的选择:

int main()
{
	// 增
	string s1("hello");
	// 尾插一个字符
	s1.push_back('7');
	// 尾插一个字符串
	s1.append("world");
    //    +=
	s1 += '7';                //本质上+=字符就是调用push_back
	s1 += "world";            //本质上+=字符串就是调用append
}

4.迭代器(iterator)

对于一个字符串,在C语言中我们使用下标+[ ],在C++的string里面,我们可以使用迭代器来实现字符串的遍历。

在这之前,我们先学会begin()和end()的使用方法:

所以实际上,这两个东西就是返回一个指向字符串起始/末尾字符的迭代器。

C语言遍历string的方法:

int main()
{
	string s1("hello world");
	cout << s1 << endl;

	// 遍历string
	cout << s1.size() << endl;   //不包括\0

    // 下标+[]
	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1[i] << " ";
	}
}

C++可以使用迭代器来实现遍历:

int main()
{
	string s1("hello world");
	cout << s1 << endl;

    //迭代器
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		// 写
		(*it)--;
		++it;
	}
	cout << endl;

	it = s1.begin();
	while (it != s1.end())
	{
		// 读
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

上面是正向迭代器,还有一个反向迭代器reverse_iterator,如果需要的是只读的对象,还可以有const_iterator和const_reverse_iterator。

范围for

相比于迭代器,范围for的迭代方式往往更加简洁:

int main()
{
	string s1("hello world");

	// 范围for   应用范围更广   //缺点:只能正向遍历,不能反向遍历
	// 底层替换为迭代器
	//for (char& ch : s1)
	for (auto& ch : s1)
	{
		// 写 
		ch--;
	}
	cout << endl;

	for (char ch : s1)
	{
		// 读
		cout << ch << " ";
	}
	cout << endl;
    return 0;
}

5.内存相关函数和扩容机制

(1).内存相关函数
int main()
{
	string s1("hello world");
	cout << s1.size() << endl;
	cout << s1.length() << endl;     //size 和 length本质上是一样的,推荐使用size
	cout << s1.max_size() << endl;   //最大长度(没啥用)
	cout << s1.capacity() << endl;     //已开辟的空间大小(不同类型的编译器结果是不一样的)
}

clear()函数可以用来清空string,但是只能清空size,清空不了capacity,因为可能后续还会使用所以不会清理。

int main()
{
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.clear();     //clear只清理size,不清理capacity
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
}

reserve

reserve会开一块空间,vs会比给定的空间多扩容一点,XSell按实际开辟。

改变开辟空间的大小需要先清理数据,直接reserve不会起作用。

void TestPushBackReserve()
{
	string s;
	s.reserve(100);   //这里就是提前开好了空间,后续不再进行改变 
	//vs实际开出来的大小会比100(给出来的数)大   XShell就是按照实际的开辟   原则就是必须比给的数大
	size_t sc = s.size();
	size_t sz = s.capacity();
	cout << "capacity changed: " << sc << '\n';
	cout << "capacity changed: " << sz << '\n';

	cout << "making s grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}

	//想要改变空间大小需要先clear(),然后再设置新的空间大小
	s.clear(); 
	cout << "capacity changed: " << sz << '\n';

	s.reserve(10);   //不清数据是不改变的
	sz = s.capacity();
	cout << "capacity changed: " << sz << '\n';
}

// reserve // 保留
// reverse // 反转
int main()
{
	TestPushBackReserve();

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

	// 开空间
	s1.reserve(100);
	cout << s1.size() << endl;//11
	cout << s1.capacity() << endl;//111
	  
	// 开空间+填值初始化
	s1.resize(200);   //resize是对开辟出来的空间的200个对象初始化占用size大小,reserve比要求的的多一点
	s1.resize(200, 'x'); //hello worldxxxxxxxxxxxxxxxxxxxxxxxx...  如果空间大于原本,先进行扩容然后再填值初始化
	cout << s1.size() << endl;//200
	cout << s1.capacity() << endl;//207

	s1.resize(5);   //如果小于size的长度,则缩小显示个数,但是不会缩容  //hello
	cout << s1.size() << endl;//5
	cout << s1.capacity() << endl;//207

	s1.clear();   //可以把s1里面的内容给清除(size归0),但是空间不会在clear()函数上清除(capacity不归0)
	s1.resize(0);
	cout << s1.size() << endl;//0
	cout << s1.capacity() << endl;//207

	//没啥用,可以不记
	s1.shrink_to_fit();    //这个函数名义上是把s1空间调整至合适的大小,但实际上空间大小还是会比实际稍微大一点点
	cout << s1.size() << endl;//0
	cout << s1.capacity() << endl;//15


	//目前缩容的唯一办法:调用clear()函数后重新reserve
	return 0;
}
(2).扩容机制(vs)
int main()
{
    string s1("hello world");

    size_t old = s1.capacity();
    for (size_t i = 0; i < 100; i++)
    {
	    s1 += 'x';
	    //vs扩容机制:除第一次是原本的两倍,剩下的都是上一次容量的1.5倍
	    //XShell是二倍扩容
    	if (old != s1.capacity()) 
	    {
	    	cout << "扩容:" << s1.capacity() << endl;
	      	old = s1.capacity();	
	    }
    }
}

6.at和错误分析

(1).at

有个引用符号,说明是可以修改的(下面会输出xello world)

int main()
{
	try {
		string s1("hello world");
		s1.at(0) = 'x';
		cout << s1 << endl;
		//s1[15];  // 暴力处理
		s1.at(15); // 温和的错误处理
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}

	return 0;
}
(2).错误分析

如上图,类似于try-catch这样的就是一个错误检查,比如我们用s1.at(15);这是一个温柔检查,会抛出一个异常(即进入catch),如果直接用s1[15]会直接中断,因为[]是有强制性的,它是决不允许越界访问的。

s1.at(15);

s1[15];

7.插入删除

(1).insert

int main()
{
	string s1;

	s1.insert(0, "hello");  //在第几个位置插入
	cout << s1 << endl;

	s1.insert(5, "world");
	cout << s1 << endl;

	s1.insert(0, 10, 'x');  //第0开始插入10个x
	cout << s1 << endl;

	s1.insert(s1.begin()+10, 10, 'y');
	cout << s1 << endl;

	return 0;
}

(2).erase

int main()
{
	string s1("hello world");
	s1.erase(5, 1);   //如果类似于(5,7)超出了界限,则直接把后面的删掉,不会报错
	cout << s1 << endl;

	s1.erase(5);    //从第5个位置开始后面的全删掉
	cout << s1 << endl;

	try{
		s1.erase(11);   //如果位置超了,会抛出一个异常
		cout << s1 << endl;
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
		
	string s2("hello world");
	s2.erase(0, 1);
	cout << s2 << endl;

	s2.erase(s2.begin());
	cout << s2 << endl;

	return 0;
}

其中要注意,s.erase()对应的作用,s1.erase(5);是传入了一个范围,s2.erase(s2.begin());是传入了一个指向具体位置的迭代器。所以前者为删除一串数据,后者是删除一个确定的元素。

(3).replace

int main()
{
	// world替换成 xxxxxxxxxxxxxxxxxxxxxx
	string s1("hello world hello bit");
	s1.replace(6, 5, "xxxxxxxxxxxxxxxxxxxxxx");   //第6个位置起的5个字符,替换成xxxxxxxxxxxxxxxxxxxxxx
	cout << s1 << endl;
    
    //replace没有缺省值
	s1.replace(6, 23, "yyyyy");
	cout << s1 << endl;

	// 所有空格替换成20%
	string s2("hello world hello bit");
	string s3;
	for (auto ch : s2)
	{
		if (ch != ' ')
		{
			s3 += ch;
		}
		else
		{
			s3 += "20%";
		}
	}

	s2 = s3;
	cout << s2 << endl;           //string的流插入重载
	cout << s2.c_str() << endl;   //本质上是调用的底层的private里的char* str

	return 0;
}

8.查找

(1).find


int main()
{
	string url = "ftp://www.baidu.com/?tn=65081411_1_oem_dg";

	// 协议:ftp
	// 域名:www.baidu.com
	// 资源名:?tn=65081411_1_oem_dg
	size_t pos1 = url.find("://");
	//会返回第一个匹配项的第一个字符的位置。且不给第二个参数的情况下,默认从第一个字符开始找
	//如果没有相匹配的字符,返回string::npos  (-1)
    //请注意,与成员find_first_of不同,每当搜索多个字符时,仅匹配其中一个字符是不够的,整个序列都必须匹配。
	cout << pos1 << endl;
	string protocol;
	if (pos1 != string::npos)
	{
		protocol = url.substr(0, pos1);    //子串,把第一个参数的位置到第二个参数的位置提取出来
	}
	cout << protocol << endl;

	string domain;
	string uri;

	size_t pos2 = url.find('/', pos1 + 3);
	if (pos2 != string::npos)
	{
		domain = url.substr(pos1 + 3, pos2 - (pos1 + 3));
		uri = url.substr(pos2 + 1);
	}
	cout << domain << endl;
	cout << uri << endl;

	//rfind 从后往前找的

	return 0;
}

*  substr

str 中从 pos 位置开始,截取 n 个字符,然后将其返回
(2).find_first_of

int main()
{
	string url = "ftp://www.baidu.com/?tn=65081411_1_oem_dg";

	size_t pos1 = url.find_first_of(":&/");
	cout << pos1 << endl;

	return 0;
}

(size_t pos1 = url.find_first_of(":&/");)

如果是用的find,会返回-1,这就是find和find_first_of的区别。find与成员find_first_of不同,每当搜索多个字符时,仅匹配其中一个字符是不够的,整个序列都必须匹配。

(size_t pos1 = url.find(":&/");)

9.例题

. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。icon-default.png?t=O83Ahttps://leetcode.cn/problems/add-strings/description/

class Solution {
public:
    string addStrings(string num1, string num2) {
        int end1 = num1.size()-1;
        int end2 = num2.size()-1;

        string strRet;
        int carry = 0;
        //只要还有数,就得接着算,所以用或
        while(end1 >= 0 || end2 >= 0) 
        {
            //没有数的进来只能置0,有数的进来置其距离'0'字符的距离(即实际数字)
            int val1 = end1 >= 0 ? num1[end1] - '0' : 0;
            int val2 = end2 >= 0 ? num2[end2] - '0' : 0;

            int ret = val1 + val2 + carry;
            carry = ret / 10;
            ret = ret % 10;
            strRet.insert(strRet.begin(), ret + '0');

            --end1;
            --end2;
        }

        if(carry == 1)
        {
            strRet.insert(strRet.begin(), '1');
        }

        return strRet;
    }
};

三.vs下string结构说明

首先看下面一个例子:

int main()
{
	std::string s1("hello world");
	std::string s3("hello worldxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");

	cout << sizeof(s1) << endl;  
	cout << sizeof(s3) << endl;

	return 0;
}

我们可以看到对应的sizeof结果都是40,他具体是怎么存储的呢?进入调试:

可以看到,string有一个buf数组,字符串的内容保存在这个buf数组里。

但是对于s3,他的数据不在buf数组里:

可以看到string存在于_ptr指向的堆空间中。

由此可见:size<16,存在数组中;size>=16,存在_ptr指向的堆空间中。
作用:提供buf数组能提高效率,不过当size较大时会导致buf这块空间没有被使用浪费,不过这样的浪费是可以原谅的,相当于用空间换时间。

四.string类模拟实现

五.深浅拷贝及写时拷贝

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

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

相关文章

【AI算法岗面试八股面经【超全整理】——NLP】

AI算法岗面试八股面经【超全整理】 概率论【AI算法岗面试八股面经【超全整理】——概率论】信息论【AI算法岗面试八股面经【超全整理】——信息论】机器学习【AI算法岗面试八股面经【超全整理】——机器学习】深度学习【AI算法岗面试八股面经【超全整理】——深度学习】NLP【A…

Crack道路裂缝检测数据集——目标检测数据集

【Crack道路裂缝检测数据集】共3684张。 目标检测数据集&#xff0c;标注文件为YOLO适用的txt格式。已划分为训练、验证集。 图片分辨率&#xff1a;224*224 类别&#xff1a;crack Crack道路裂缝检测数据集 数据集描述 该数据集是一个专门用于训练和评估基于YOLO&#xff0…

[笔记]某变频器,功能列表及参数表

产品代号&#xff1a;INVT GOODDRIVE&#xff0c;这家公司我的产品我似乎在特检院看到过&#xff1f;或者在某个地铁建设工地看到过。是深圳的。 1.产品功能点&#xff1a; 变频锥形电机控制、抱闸转矩验证&#xff1f;抱闸反馈零位检测行程限位超载防护轻载升速&#xff08;…

机器学习课程学习周报十三

机器学习课程学习周报十三 文章目录 机器学习课程学习周报十三摘要Abstract一、机器学习部分1. 文生图模型概述2. Stable Diffusion概述3. ControlNet概述4. 概率论复习&#xff08;二&#xff09; 总结 摘要 本周的学习内容涵盖了文生图模型、Stable Diffusion、ControlNet以…

从零开始讲DDR(5)——读懂Datasheet

对于开发人员来说&#xff0c;需要根据实际场景和使用的需要&#xff0c;使用不同厂家&#xff0c;不同型号的DDR&#xff0c;虽然原理上大同小异&#xff0c;但是还是有一些细节上的需要注意的地方&#xff0c;接触一个新的DDR芯片&#xff0c;首先就是需要找到对应的datashee…

Mybatis 返回 Map 对象

一、场景介绍 假设有如下一张学生表&#xff1a; CREATE TABLE student (id int NOT NULL AUTO_INCREMENT COMMENT 主键,name varchar(100) NOT NULL COMMENT 姓名,gender varchar(10) NOT NULL COMMENT 性别,grade int NOT NULL COMMENT 年级,PRIMARY KEY (id) ) ENGINEInnoD…

LeetCode讲解篇之238. 除自身以外数组的乘积

文章目录 题目描述题解思路题解代码 题目描述 题解思路 对于该题&#xff0c;我们可以先使用一个循环记录所有非零元素的乘积结果和非零元素的个数 如果非零元素个数为0&#xff0c;则非零元素的乘积除以数组对应位置的数字就是除自身以外的数组的乘积如果非零元素个数为1&am…

新质农业——水肥一体化技术

橙蜂智能公司致力于提供先进的人工智能和物联网解决方案&#xff0c;帮助企业优化运营并实现技术潜能。公司主要服务包括AI数字人、AI翻译、埃域知识库、大模型服务等。其核心价值观为创新、客户至上、质量、合作和可持续发展。 橙蜂智农的智慧农业产品涵盖了多方面的功能&…

【人工智能学习】8_人工智能其他通用技术

知识图谱 在看影视剧或小说时&#xff0c;若其中的人物很多、人物关系复杂&#xff0c;我们一般会用画人物关系图谱来辅助理解人物关系。那什么是知识图谱呢&#xff1f; 知识是人类对信息进行处理之后的认识和理解&#xff1b;对数据和信息的凝练、总结后的成果。 将信息转…

MySQL-排名函数ROW_NUMBER(),RANK(),DENSE_RANK()函数的异同

MySQL-排名函数ROW_NUMBER()&#xff0c;RANK()&#xff0c;DENSE_RANK()函数的异同 前言 假设有如下表结构与数据&#xff0c;class_id表示班级&#xff0c;需求&#xff1a;现在要按照班级分组&#xff0c;每个班级的学生进行年龄从小到大排序 一、ROW_NUMBER()函数 ROW_NUM…

YOLO航拍车辆和行人识别

YOLO航拍车辆和行人识别 图片数量9695&#xff0c;标注为xml和txt格式&#xff1b; class&#xff1a;car&#xff0c;pedestrian&#xff0c;truck&#xff0c;bus 用于yolo&#xff0c;Python&#xff0c;目标检测&#xff0c;机器学习&#xff0c;人工智能&#xff0c;深度学…

软件测试分类篇(下)

目录 一、按照测试阶段分类 1. 单元测试 2. 集成测试 3. 系统测试 3.1 冒烟测试 3.2 回归测试 4. 验收测试 二、按照是否手工测试分类 1. 手工测试 2. 自动化测试 3. 手工测试和自动化测试的优缺点 三、按照实施组织分类 1. α测试(Alpha Testing) 2. β测试(Beta…

图像放大效果示例【JavaScript】

实现效果&#xff1a; 当鼠标悬停在小图&#xff08;缩略图&#xff09;上时&#xff0c;大图&#xff08;预览图&#xff09;会随之更新为相应的小图&#xff0c;并高亮当前悬浮的小图的父元素。 代码&#xff1a; 1. HTML部分 <!DOCTYPE html> <html lang"z…

Nginx简介;Nginx安装

一&#xff0c;Nginx简介 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;在BSD-like 协议下发行。是一个高性能的HTTP和反向代理web服务器 &#xff0c;同时也提供了IMAP/POP3/SMTP服务。 其特点是占有内存少…

OpenCV特征检测(8)检测图像中圆形的函数HoughCircles()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在灰度图像中使用霍夫变换查找圆形。 该函数使用霍夫变换的一种修改版本在灰度图像中查找圆形。 例子&#xff1a; #include <opencv2/imgp…

【解密 Kotlin 扩展函数】扩展函数的创建(十六)

导读大纲 1.1 为第三方的类添加方法: 扩展函数 1.1 为第三方的类添加方法: 扩展函数 Kotlin 的主题之一是与现有代码的平滑集成 即使是纯 Kotlin 项目,也是构建在 Java 库之上的 如 JDK、Android 框架和其他第三方框架 而当你将 Kotlin 集成到 Java 项目中时 你还要处理尚未或不…

Ubuntu清理内存导致的一系列错误及解决方法

文章目录 火狐浏览器和pycharm消失打不开 安不上 卸不掉后记 火狐浏览器和pycharm消失 打不开 安不上 卸不掉 清理内存后&#xff0c;火狐和pycharm的图标都消失了&#xff0c;在终端输入Firefox显示无法打开 应当先snap install firefox&#xff0c;然而snap install firefo…

【排序算法】插入排序_直接插入排序、希尔排序

文章目录 直接插入排序直接插入排序的基本思想直接插入排序的过程插入排序算法的C代码举例分析插入排序的复杂度分析插入排序的优点 希尔排序希尔排序&#xff08;Shell Sort&#xff09;详解希尔排序的步骤&#xff1a;希尔排序的过程示例&#xff1a;希尔排序的C语言实现举例…

啥?Bing搜索古早BUG至今未改?

首先&#xff0c;大家先看下面的一个数学公式。 Γ ( z ) ∫ 0 ∞ t z − 1 e − t d t . \Gamma(z) \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)∫0∞​tz−1e−tdt. 看不懂&#xff1f;没关系&#xff0c;因为我也看不懂 这不是谈论的重点。 当你把鼠标光标移到公式的最开头&…

netflix是什么样的企业文化

netflix是什么样的企业文化 Netflix的企业文化以其“自由与责任”而闻名&#xff0c;这种文化理念在业界被广泛誉为管理的“黄金法则”。《奈飞文化手册》自2009年面世以来&#xff0c;便迅速成为全球企业管理的典范&#xff0c;吸引了超过1500万次的在线阅读与下载。Netflix的…