C++ STL与string类

news2024/9/24 20:29:08

一 什么是STL?

STL,全称是标准模板库(Standard Template Library),是C++标准库的一部分。STL提供了一些常用的数据结构和算法,帮助开发者更方便、高效地编写代码。通过使用STL,开发者不需要重复造轮子,可以直接使用已经优化好的组件,提高了代码的可读性和可维护性。

二 STL的六大组件

1. 容器(Containers)

容器是用来存储和管理一组数据的集合。STL提供了几种不同类型的容器,适用于不同的场景:

  • 序列式容器:存储数据的顺序很重要。

    • vector:动态数组,可以自动调整大小。
    • list:双向链表,适用于频繁插入和删除操作。
    • deque:双端队列,支持在两端高效地插入和删除。
  • 关联式容器:根据键值对数据进行管理。

    • set:集合,存储不重复的元素,并自动排序。
    • map:映射,存储键值对,键不重复,自动排序。
    • unordered_setunordered_map:基于哈希表实现,不自动排序,但操作更快。
2. 迭代器(Iterators)

迭代器是一种对象,允许我们遍历容器中的元素,而无需了解容器的内部实现。可以将迭代器看作是指向容器中元素的指针。常见的迭代器类型有:

  • 输入迭代器
  • 输出迭代器
  • 前向迭代器
  • 双向迭代器
  • 随机访问迭代器
3. 算法(Algorithms)

STL提供了许多常用的算法,可以直接作用于容器的数据上。这些算法大大简化了代码的编写和维护。例如:

  • sort:排序
  • find:查找
  • replace:替换
  • count:计数
  • for_each:遍历每个元素
4. 函数对象(Function Objects 或仿函数 Functors)

函数对象是重载了operator()的类。它们可以像函数一样调用,并且可以保存状态。例如,用于自定义排序规则的函数对象。

5. 适配器(Adapters)

适配器是一种修改容器或函数对象接口的工具,使其适应不同的需求。例如:

  • 容器适配器:stack(栈)、queue(队列)、priority_queue(优先队列)。
  • 函数适配器:可以将普通函数或函数对象转换为不同的形式,以适应特定的需求。
6. 分配器(Allocators)

分配器负责管理内存的分配和释放。STL容器默认使用标准的动态内存分配器,但可以根据需要自定义分配器。

三 STL的重要性

STL的设计哲学是通用性和高效性,它极大地提升了C++编程的效率和灵活性。通过使用STL,开发者可以避免重复造轮子,直接使用已经高度优化的组件,编写出更高效、更易维护的代码。

四 string

定义:

C++ 标准库提供了一个名为 std::string 的类,用于处理字符串。string 类是 std 命名空间的一部分。

string 类对象的常见构造

#include <string>
using namespace std;

int main()
{
	// 1 string();

	string s1;//默认构造函数
	cout << s1 << endl;

	// 2 string(const char* s);

	string s2("hello world");//C-string 构造
	cout << s2 << endl;

	// 3 string(const string& s);

	string s3(s2);//拷贝构造
	cout << s3 << endl;

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

	string s4(s3, 0, 30);//部分字符串构造
	cout << s4 << endl;

	// 5 string(const char* s, size_t n);

	string s5("hello", 3);//前 N 个字符构造
	cout << s5 << endl;
	
	// 6 string(size_t n, char c);

	string s6(10, 'x');  //重复字符构造
	cout << s6 << endl;

	return 0;
}

输出:

在上面我们已经知道怎么构造了,现在我想和C语言一样遍历字符数组那C++中的string类该怎么实现呢?

string对象遍历和修改:

string s6("World");// C-string 构造

for (int i = 0; i < s6.size(); i++)
{
	cout << s6[i] << " ";
}
cout << endl;

在上面代码中我们靠size()成员函数来获取字符串个数(和C语言一样不包含‘\0’),然后在for循环中,使用了s1[i]来访问字符串s1中位置为i的字符。这里用到了string类的operator[]操作符。这个操作符允许我们像访问数组元素一样访问字符串中的字符。

遍历方式:

1 重载操作符operator[]

string类中,operator[]被重载用来访问字符串中的字符

char& operator[] (size_t pos);

这个重载操作符的声明表示它返回一个对char类型的引用,参数pos是一个size_t类型的值,表示字符在字符串中的位置。

这时我就有个疑问,为什么我在for循环中传过去的是数字而返回来的确实字符呢?

因为 operator[] 用数字 0 查找字符串中第 0 个位置的字符 这个过程类似于数组的访问,但实际上是通过函数调用来实现的,而且operator[] 返回的是字符的引用,所以我们不仅可以读取这个字符,还可以对它进行修改(也就是说我返回的是W的引用 代码就是char& tmp = W,然后改变tmp就是改变w)。

总结:
  • 数组访问:访问数组元素时,是通过指针偏移和解引用来实现的。例如,arr[i]实际上是*(arr + i),即从指针arr偏移i个元素后得到的地址的值。
  • 字符串访问:在string类中,operator[]是一个函数调用。每次使用s1[pos]时,实际上是调用了这个函数来返回字符串中位置pos的字符的引用。

 2 迭代器 iterator

迭代器是一种对象,允许程序员遍历容器(如数组、链表、树等数据结构)中的元素,而无需了解容器的内部结构。它们类似于指针,可以指向容器中的元素,并提供访问和操作这些元素的方法。

#include <iostream>
#include <string> //允许你在代码中省略std::前缀来直接使用标准库中的名称

using namespace std;

int main() {
    string s1("hello world");
    string::iterator it1 = s1.begin(); //定义迭代器
    while (it1 != s1.end()) {
        cout << *it1 << " ";
        it1++;
    }
    return 0;
}

为什么在上面我定义了using namespace std;可在定义迭代器是还是要写呢?

这是因为在C++中,迭代器(iterator)是容器(如std::vectorstd::string等)的一部分。每个容器都有自己的迭代器类型定义在其类内。这意味着iteratorstd::string类的一个嵌套类型,因此必须通过string::iterator来访问它。

在主函数中string::iterator it1:声明一个it1变量,其类型是string::iterator,它是一个迭代器类型,可以用于遍历std::string对象的字符。然后begin的作用是返回第一个有效位置的迭代器,让it1指向第一个有效元素的迭代器,这就有点类似于C语言里面的指针,但是指针是一个内存地址,可以指向任何类型的变量但是迭代器是一个对象只能指向容器中的元素,通过解引用操作符*,可以访问迭代器指向的元素。下面while循环也没什么好讲的,end就和begin是相对的,begin指向第一个那end就是指向'\0'。

总结:

迭代器提供了统一的接口来遍历不同类型的容器(如数组、链表、树等),不需要知道容器的内部实现。

迭代器可以用来访问和修改容器中的元素,支持向前和向后移动(在支持的容器中),使得遍历操作更加灵活。

对于链表等数据结构,无法使用操作符 [] 进行访问,必须使用迭代器。

3 反向迭代器

反向迭代器是一种特殊的迭代器,用于从容器(如字符串、向量、列表等)的末尾向前迭代,而不是从头到尾。

#include <iostream>
#include <string> 

using namespace std;

int main() {
    string s1("hello world");
    string::reverse_iterator rit = s1.rbegin(); //定义反向迭代器
    while (rit != s1.rend()) {
        cout << *rit << " ";
        rit++;
    }
    return 0;
}
  • rbegin(): 返回一个指向容器最后一个元素的反向迭代器。
  • rend(): 返回一个指向容器第一个元素之前位置的反向迭代器。

4 范围for

在讲范围for之前我们需要了解一下auto关键字

auto关键字让编译器自动推断变量的类型。

string s1("hello world");
for (auto e : s1)
{
    cout << e << " ";
}
cout << endl;

首先e是用来存储每次迭代时从s1中获取的元素而s1就是要遍历的范围。auto e意味着e的类型将由s1的元素类型决定。

常见成员函数:

begin

虽然在上文中我们已经提到它的用法但是在这里还是要重新提起

用法:

string s1("hello world");
string::iterator it = s1.begin();
cout << *it << endl;

输出:

iterator与const_iterator和const iterator的区别:

为了帮助你更好地理解 C++ 中的 iteratorconst_iterator,我们可以借助 C 语言中的 const int* p2int* const p2 的概念。让我们首先复习一下这两个指针的区别,然后再将其应用到 C++ 迭代器的理解上。

const int* p2:指向常量整数的指针。你不能通过这个指针修改它所指向的值,但可以改变指针本身,使其指向另一个地址。

const int* p2;
int a = 10;
int b = 20;
p2 = &a;  // 可以
*p2 = 30; // 错误,不允许通过 p2 修改 a 的值
p2 = &b;  // 可以

int* const p2:常量指针,指向整数。你可以通过这个指针修改它所指向的值,但不能改变指针本身使其指向另一个地址。

int* const p2;
int a = 10;
p2 = &a; // 需要在初始化时赋值
*p2 = 30; // 可以,通过 p2 修改 a 的值
p2 = &b;  // 错误,不允许改变 p2 指向的地址

1: iterator 类似于 int* p2,即普通的指针。你可以通过它修改容器中的元素,并且可以改变迭代器本身使其指向容器中的不同位置。

std::vector<int> vec = {1, 2, 3, 4, 5};
std::vector<int>::iterator it = vec.begin();
*it = 10; // 可以,修改元素
++it;     // 可以,改变迭代器的位置

2: const_iterator 类似于 const int* p2,即指向常量的指针。你不能通过它修改容器中的元素,但可以改变迭代器本身使其指向容器中的不同位置。

std::vector<int> vec = {1, 2, 3, 4, 5};
std::vector<int>::const_iterator cit = vec.begin();
// *cit = 10; // 错误,不能修改元素
++cit;       // 可以,改变迭代器的位置

3: const iterator 类似于 int* const p2,即常量指针。迭代器本身是常量,不能改变它指向的元素位置,但可以通过它修改容器中的元素。

const iterator 类似于 int* const p2,即常量指针。迭代器本身是常量,不能改变它指向的元素位置,但可以通过它修改容器中的元素。

总结:

const 出现在 * 左边时,它修饰的是指向的值。

const 出现在 * 右边时,它修饰的是指针本身。

iterator可修指可修值 , const_iterator只修指向不修值 , const iterator只修修值不修指向

end

用法:

string s1("hello world");
string::iterator it = s1.end() - 1;
cout << *it << endl;

输出:

size

用法:

string s1("hello world");
cout << s1.size() << endl;

输出:

capacity:

用法:

string s1("hello world");
cout << s1.capacity()<< endl;

输出:

size:告诉你箱子里目前有多少东西(字符串的实际长度)

capacity:告诉你这个箱子最多可以装多少东西而不需要换一个更大的箱子(不需要重新分配内存的最大容量)。

clear

用法:

清空字符串内容,使其变成一个空字符串。

string s1("hello world");
s1.clear();

empty

用法:

检查字符串是否为空。如果字符串为空,返回 true,否则返回 false

string s1("hello world");
if (s1.empty())
{
	cout << "ture" << endl;
}
else
	cout << "flase" << endl;

输出:

reserve

用法:

预留一定的内存空间,以避免将来添加更多字符时频繁重新分配内存。

string s1("hello world");
s1.reserve(50); // 预留至少可以存储 50 个字符的空间

resize

用法:

改变字符串的大小。如果新大小比原来大,用指定字符填充新增加的部分;如果比原来小,字符串被截断。

std::string s1("hello");
s1.resize(10, 'x');
cout << s1 << endl;

s1.resize(3); 
cout << s1 << endl;

输出:

push_back

用法:

在字符串末尾添加一个字符。

string s1("hello world");
s1.push_back('!');
cout << s1 << endl;

输出:

append

用法:

在字符串末尾添加另一个字符串。

string s1("hello world");
s1.append(" abcdefj");
cout << s1 << endl;

输出:

operate+=

用法:

在字符串末尾追加另一个字符串或字符。

string s1("hello world");
s1+= "s";
cout << s1 << endl;

string s2("hello");
s2 += "  world";
cout << s2 << endl;

输出:

insert和erase

用法:

insert: 在指定位置插入字符或字符串。

string s1("hello world");
s1.insert(5, "*beautiful");
cout << s1 << endl;

输出:

erase: 删除指定位置的字符或一段字符串。

std::string s1("hello world");
s1.insert(5, ", beautiful"); // 在位置 5 插入 ", beautiful",现在 s1 是 "hello, beautiful world"
s1.erase(5, 11); // 从位置 5 开始删除 11 个字符,现在 s1 是 "hello world"
cout << s1 << endl;

输出:

replace

用法:

替换字符串中的一部分为另一个字符串。

std::string s1("hello world");
s1.replace(6, 1, "everyone");//从6开始的1个字符替换为字符串"everyone"
cout << s1 << endl;

输出:

find

用法:

查找字符串中第一次出现的子字符串或字符的位置。如果没有找到,返回 std::string::npos

std::string s1("hello world");
size_t pos = s1.find("n");
if (pos != std::string::npos) 
{
	std::cout << "找到了"<< pos << std::endl;
}
else 
{
	std::cout << "没找到" << std::endl;
}



std::string s1("hello world");
size_t pos = s1.find("world");
if (pos != std::string::npos) 
{
	std::cout << "找到了"<< pos << std::endl;
}
else 
{
	std::cout << "没找到"<< std::endl;
}

输出:

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

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

相关文章

吴恩达机器学习笔记 三十九 协同过滤的TensorFlow实现

TensorFlow的一个优点&#xff1a;可以自动算出成本函数的导数 如上图&#xff0c;设 f( x ) wx&#xff0c;成本 J 为(wx - 1)^2&#xff0c;用GradientTape()这个函数&#xff0c;TensorFlow会记录计算成本J所需的操作序列&#xff0c;保存在 tape 中。 dJdw为自动计算出的导…

图片转文字怎么操作?教你几招图片转文字小妙招

在日常的工作学习中&#xff0c;我们每天可能会接触到大量的图片资料&#xff0c;无论是会议纪要、书籍扫描页、还是网络上的有用信息截图&#xff0c;如果能快速将这些图片中的文字提取出来&#xff0c;无疑将极大提升我们的工作效率。下面给大家分享几种能够将图片转换成文字…

AI学习记录 - 自注意力机制的计算流程图

过段时间解释一下&#xff0c;为啥这样子计算&#xff0c;研究这个自注意力花了不少时间&#xff0c;网上很多讲概念&#xff0c;但是没有具体的流程图和计算方式总结…

多线程 01:Java 多线程学习导航,线程简介,线程相关概念的整理

一、概述 记录时间 [20240807] 立秋 & 128 创作纪念日 本文是关于 Java 多线程学习的导航篇&#xff0c;总览了有关多线程学习的几个模块。简单介绍了一些与线程相关的基本概念&#xff0c;便于后续展开多线程的学习。 前置知识&#xff1a;Java 基础篇&#xff1b;Java 面…

腾讯云AI代码助手的实用性能以及带给开发者的便捷开发陪伴

腾讯云AI代码助手的实用性能以及带给开发者的便捷开发陪伴 前言一、开发环境介绍二、腾讯云AI代码助手使用实例1 一键代码补全2 与腾讯云ai代码助手对话3 直接对源码进行注释&#xff0c;查错 三 获得的帮助与提升四 对腾讯云AI代码助手的建议总结 前言 在日常的编程工作的生活…

SQL报错注入之updatexml

目录 1.updatexml报错原理 2.判断是否有注入点 我们在地址栏中输入?id1 我们在地址栏中输入?id1-- 3.updatexml报错注入 3.1爆库名 3.2爆表名 3.3爆字段名 3.4爆数据 1.updatexml报错原理 updatexml(xml_doument,XPath_string,new_value) 第一个参数&#xff1a;XML…

07-软件参数的基本配置

1.设置交叉 2.Design insight 关闭 3.数据保存设置 4.原理图设置 5.PCB-General设置 PCB-Board Insight Modes设置 PCB-Board Insight Color Overrides PCB-DRC Violations Display PCB-Interactive Routing PCB-Defaults

【C++】C++11的新特性 — 线程库 ,原子操作 , 条件变量

勇敢就是接受发生在你身上的事&#xff0c;并把它尽力做到最好。 -- 约翰・欧文 -- C11的新特性 1 线程1.1 线程概念1.2 C中的线程1.3 线程并行1.4 锁 2 原子操作3 条件变量Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;&#xff01;&#xff01;下…

最短路问题中的bellman-ford算法

最短路问题中的bellman-ford算法 题目 如果要处理单源最短路问题当中存在负权边的&#xff0c;那么就需要用到 bellman-ford算法和SPFA算法&#xff0c;一般情况下都是用 SPFA算法&#xff0c;除了有边数限制的情况只能用bellman-ford算法&#xff0c;比如下面这种 题目 给定…

SVG入门指南

前言 SVG 是一种使用 XML 描述 2D 图形的语言&#xff0c;与传统前端 DOM 开发比较类似&#xff0c;本文尝试总结一下 SVG 的基本用法。 基本图形绘制 与 canvas 不同&#xff0c;svg 使用声明式的方式来绘制图形&#xff0c;比如绘制一个矩形&#xff1a; <svg width&q…

Elastic 利用由 Search AI 提供支持的自动导入功能加速 SIEM 数据导入

作者&#xff1a;来自 Elastic Jamie Hynds, Mark Settle Elastic 正在通过自动导入功能自动完成 SIEM 数据导入&#xff0c;从而加速采用 AI 驱动的安全分析。这项新功能&#xff08;安全分析或 SIEM 解决方案中独一无二的功能&#xff09;可自动开发自定义数据集成。Elastic …

轻松上手MYSQL:掌握MYSQL聚合函数,数据分析不再难

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索MYSQL聚合函数之旅✨ &#x1f44b; 大家好&#xff01;文本学习和探…

240807-Gradio客户端GUI与服务端API分离代码示例

A. 客户端服务端分离的最终效果 B. 前后端核心代码 Gradio支持将前端界面&#xff08;客户端&#xff09;与后端逻辑&#xff08;服务端&#xff09;分离。通过这种方式&#xff0c;客户端负责用户交互和显示&#xff0c;而服务端负责实际的数据处理和功能实现。 以下是如何实…

买Zoho企业邮箱赠公司后缀的域名吗?

随着市场上企业邮箱服务提供商的增多&#xff0c;选择适合自身需求的服务变得尤为重要。其中一个常见的问题是&#xff1a;购买Zoho企业邮箱服务时是否会赠送公司后缀的域名&#xff1f;赠送域名有哪些套路&#xff1f;本文将详细探讨这些问题。 一、买Zoho企业邮箱赠送公司后…

让三岁小孩都能理解动态规划_来自B站罐装-蜜糖

系列文章目录 文章目录 系列文章目录一、认识算法动态规划难在哪?学习目标 二、记忆化搜索 非常直觉的处理方式注意&#xff1a; 三、70.爬楼梯 入门 模板通过记忆化搜索 发现动态规划四要素 四、118.杨辉三角 使用答案空间处理&#xff08;题目给了返回值的样式&#xff09;五…

The Ether: EvilScience (v1.0.1)打靶渗透【附代码】(权限提升)

靶机下载地址: https://www.vulnhub.com/entry/the-ether-evilscience-v101,212/ 1. 主机发现端口扫描目录扫描敏感信息获取 1.1. 主机发现 nmap -sn 192.168.7.0/24|grep -B 2 00:0C:29:7F:50:FB 1.2. 端口扫描 nmap -p- 192.168.7.172 1.3. 目录扫描 dirb http://192.16…

vm虚拟机下安装CentOS7系统

VMware16安装CentOS7 1.启动之前安装的VM 具体VMware安装过程 2.配置Linux&#xff08;centos7&#xff09;的镜像文件 选择安装镜像文件 4.开启虚拟机 开始读秒安装 选择安装过程中使用的语言&#xff0c;这里选择英文、键盘选择美式键盘。点击Continue 首先设置时间…

MySQL——数据类型、索引的建立、数据的约束

文章目录 数据类型索引的建立普通索引唯一索引使用ALTER 命令添加和删除索引使用ALTER 命令添加和删除主键显示索引信息 数据的约束非空约束&#xff1a;not null&#xff0c;值不能为null唯一约束&#xff1a;unique&#xff0c;值不能重复主键约束&#xff1a;primary key外键…

【实现100个unity特效之15】最简单的方法使用shader graphs实现2d非像素和像素树叶草的随风摇摆效果

文章目录 前言非像素树叶草飘动效果新建材质效果像素树叶草飘动效果参考完结 前言 本文只是实现一个简单版本的2d树叶草随风摇摆的效果&#xff0c;如果你想要实现更加复杂的效果&#xff0c;包括2d互动草&#xff0c;你可以参考我之前的文章&#xff1a; 【推荐100个unity插件…

基元检测-霍夫直线变换原理

在之前已经使用过正规方程法、梯度下降法拟合直线 1、回顾过去 梯度下降法拟合一元函数 最小二乘法的线性代数推导 现在使用一种新的直线检测方法&#xff0c;霍夫变换&#xff0c;它也可以拟合直线&#xff0c;接下里将说明他的原理。 2、霍夫变换 霍夫变换&#xff08;…