C++String的学习
1、C语言中的字符串
C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想(即面向对象编程(Object-Oriented Programming)),而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
String类题目,字符串相加
2、标准库中的String类
2.1string类的了解
string类的文档介绍
在使用string类时,必须包含#include头文件以及using namespace std;
2.2 auto和范围for
auto关键字:
1.在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
2.用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
3.当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
4.auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
5.auto不能直接用来声明数组
#include<iostream>
using namespace std;
int func1()
{return 10;
}
// 不能做参数
void func2(auto a)
{}// 可以做返回值,但是建议谨慎使用
auto func3()
{return 3;
}int main()
{int a = 10;auto b = a;auto c = 'a';auto d = func1();// 编译报错:rror C3531: “e”: //类型包含“auto”的符号必须具有初始值设定项auto e;cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;cout << typeid(d).name() << endl;int x = 10;auto y = &x;auto* z = &x;auto& m = x;cout << typeid(x).name() << endl;cout << typeid(y).name() << endl;cout << typeid(z).name() << endl;auto aa = 1, bb = 2;// 编译报错:error C3538: 在声明符列表中,//“auto”必须始终推导为同一类型auto cc = 3, dd = 4.0;// 编译报错:error C3318: “auto []”: //数组不能具有其中包含“auto”的元素类型auto array[] = { 4, 5, 6 };return 0;
}
auto 是 C++ 中提高代码简洁性和灵活性的重要工具
例如:
#include<iostream>
#include <string>
#include <map>
using namespace std;
int main()
{std::map<std::string, std::string> dict = { { "apple", "苹果" },{ "orange","橙子" }, {"pear","梨"} };// auto的用武之地//std::map<std::string, std::string>::iterator it = dict.begin();//此刻的auto自动类型推导成std::map<std::string, std::string>::iteratorauto it = dict.begin();while (it != dict.end()){cout << it->first << ":" << it->second << endl;++it;}return 0;
}
范围for:
1.,对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
2.范围for可以作用到数组和容器对象上进行遍历
3.范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。
#include<iostream>
#include <string>
#include <map>
using namespace std;
int main()
{int array[] = { 1, 2, 3, 4, 5 };// C++98的遍历for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i){array[i] *= 2;}for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i){cout << array[i] << endl;}// C++11的遍历for (auto& e : array)e *= 2;for (auto e : array)cout << e << " " << endl;string str("hello world");for (auto ch : str){cout << ch << " ";}cout << endl;return 0;
}
2.3 string类的接口说明(常用)
1.string类对象的常见构造
constructor(构造)
函数名称 | 功能说明 |
---|---|
string() | 构造空的string类对象,即空字符串 |
string(const char& s ) | 用C-string来构造string类对象 |
string(size_t n,char c) | string类对象包含n个字符c |
string(const string& s) | 拷贝构造函数 |
void Teststring()
{string s1; // 构造空的string类对象s1string s2("hello bit"); // 用C格式字符串构造string类对象s2string s3(s2); // 拷贝构造s3
}
2. string类对象的容量操作
函数名称 | 功能说明 |
---|---|
size(重点) | 返回字符串有效长度 |
length | 返回字符串有效长度(和size无差别) |
capacity | 返回空间总大小 |
empty(重点) | 检测字符串是否为空串 |
clear(重点) | 清空有效字符 |
reserve(重点) | 为字符串预留空间 |
resize(重点) | 将有效字符的个数改成n个,多出的空间用字符c填充 |
注意:
- size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
- clear()只是将string中有效字符清空,不改变底层空间大小。
- resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, charc)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
- reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。
3. string类对象的访问及遍历操作
函数名称 | 功能说明 |
---|---|
operator[]重点 | 返回pos位置的字符,const string类对象调用 |
begin+end | begin获取第一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器 |
rbegin+rend | 返回一个指向容器最后一个元素的反向迭代器+返回一个指向容器第一个元素之前位置的反向迭代器 |
范围for | C++11支持更简洁的范围for的新遍历方式 |
4.string类对象的修改操作
函数名称 | 功能说明 |
---|---|
push_back | 在字符串结尾插入字符c |
append | 在字符串后面追加一个字符 |
operator+= (重点) | 在字符串后追加字符串str |
c_str(重点) | 返回c格式字符串 |
find+npos(重点) | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 |
rfind(重点) | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 |
substr(重点) | 在str中从pos位置开始,截取n个字符,然后将其返回 |
注意:
- 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c’三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
- 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。
5. string类非成员函数
函数名称 | 功能说明 |
---|---|
operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
operator>>(重点) | 输入运算符重载 |
operator<<(重点) | 输出运算符重载 |
geiline(重点) | 获取一行字符串 |
relational operators(重点) | 大小比较 |
6. vs和g++下string结构的说明
注意:下述结构是在32位平台下进行验证,32位平台下指针占4个字节
vs下string的结构
string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字符串的存储空间:
1.当字符串长度小于16时,使用内部固定的字符数组来存放
2.当字符串长度大于等于16时,从堆上开辟空间
union _Bxty
{ // storage for small buffer or pointer to larger onevalue_type _Buf[_BUF_SIZE];pointer _Ptr;char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;
这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。
其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量
最后:还有一个指针做一些其他事情。
故总共占16+4+4+4=28个字节。
g++下string的结构
g++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指针将来指向一块堆空间,内部包含了如下字段:
空间总大小
字符串有效长度
引用计数
struct _Rep_base
{size_type _M_length;size_type _M_capacity;_Atomic_word _M_refcount;
};
指向堆空间的指针,用来存储字符串。
3. string类的模拟实现
3.1string类的问题
// 为了和标准库区分,此处使用String
class String
{
public:/*String():_str(new char[1]){*_str = '\0';}*///String(const char* str = "\0") 错误示范//String(const char* str = nullptr) 错误示范
String(const char* str = "")
{// 构造String类对象时,如果传递nullptr指针,可以认为程序非if (nullptr == str){assert(false);return;}_str = new char[strlen(str) + 1];strcpy(_str, str);
}~String()
{if (_str){delete[] _str;_str = nullptr;}
}
private:char* _str;
};
// 测试
void TestString()
{String s1("hello bit!!!");String s2(s1);
}
说明:在上述代码中String类里面没有显示实现拷贝构造函数和赋值运算符重载,当s1取赋值s2的时候编译器就会走默认的拷贝构造函数,那么s1和s2就会指向同一个地址空间,当其中一个地址空间被销毁了之后,另外一个以为还存在,则会以为有效,当运行时就会出现报错,(在释放时同一块空间被释放多次而引起程序崩溃),这就是上述的浅拷贝。
3.2浅拷贝
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果在对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。
形象理解:可把对象成员看作不同 “数据盒子”,浅拷贝就像给新对象的盒子复制源对象盒子里的数据。若盒子存的是基本类型值,新盒子有独立值;若存的是指针(类似 “地址标签” ),新盒子就复制这个 “地址标签”,新、旧对象的指针会指向同一块堆内存区域 。比如有类 ClassA 包含指针成员 int* ptr,执行 ClassA obj2 = obj1;(obj1 已初始化 )的浅拷贝后,obj1.ptr 和 obj2.ptr 地址相同,都指向同一块堆内存。
#include <iostream>
class Test {
public:int* ptr;Test(int val) {ptr = new int(val); // 动态分配堆内存}~Test() {delete ptr; // 析构时释放内存}
};
int main() {Test obj1(10);Test obj2 = obj1; // 浅拷贝,obj2.ptr 和 obj1.ptr 指向同一块内存// 此时 obj1 和 obj2 的析构函数都会去释放 ptr 指向的内存,会导致重复释放问题return 0;
}
3.3深拷贝
如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。
本质特征
深拷贝会创建全新的对象副本,并递归地复制原对象包含的所有数据内容,包括指针、引用等复杂成员指向的深层数据(如堆内存里的实际内容 )。新对象与原对象在内存中完全独立,修改一方的数据不会影响另一方。
3.3.1传统版写法的String类
```cpp
class String
{
public:String(const char* str = ""){// 构造String类对象时,如果传递nullptr指针,可以认为程序非if (nullptr == str){assert(false);return;}_str = new char[strlen(str) + 1];strcpy(_str, str);}String(const String& s): _str(new char[strlen(s._str) + 1]){strcpy(_str, s._str);}String& operator=(const String& s){if (this != &s){char* pStr = new char[strlen(s._str) + 1];strcpy(pStr, s._str);delete[] _str;_str = pStr;}return *this;}~String(){if (_str){delete[] _str;_str = nullptr;}}
private:char* _str;
};
3.3.2现代版写法的String类
class String
{
public:String(const char* str = ""){if (nullptr == str){assert(false);return;}_str = new char[strlen(str) + 1];strcpy(_str, str);}String(const String& s): _str(nullptr){String strTmp(s._str);swap(_str, strTmp._str);}// 对比下和上面的赋值那个实现比较好?String& operator=(String s){swap(_str, s._str);return *this;}/*String& operator=(const String& s){if(this != &s){String strTmp(s);swap(_str, strTmp._str);}return *this;}*/~String(){if (_str){delete[] _str;_str = nullptr;}}
private:char* _str;
};
3.4.写时拷贝
写时拷贝
相关文章:

C++String的学习
1、C语言中的字符串 C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想(即面向对象编程(…...

java day15 (数据库)
进入数据库的学习 DB 因为数据太多了,方便统一管理的软件 操作就不用改代码了,直接改数据库则可; 命令就是sql语句 这些都是关系型数据库,sql可以控制全部,至于具体的环境我以前就有安装过了; 理解&am…...
SQL 中 IN 和 EXISTS 的区别
SQL 中 IN 和 EXISTS 的区别 1. 基本概念 1.1 IN 运算符 IN 是一个条件运算符,用于检查某个值是否存在于指定的值列表中或子查询返回的结果集中。 SELECT * FROM employees WHERE department_id IN (SELECT id FROM departments WHERE location = New York)...

多线程爬虫使用代理IP指南
多线程爬虫能有效提高工作效率,如果配合代理IP爬虫效率更上一层楼。作为常年使用爬虫做项目的人来说,选择优质的IP池子尤为重要,之前我讲过如果获取免费的代理ip搭建自己IP池,虽然免费但是IP可用率极低。 在多线程爬虫中使用代理I…...

前端面试真题(第一集)
目录标题 1、跨域问题及解决方法同源策略生产环境解决方案开发环境解决方案其他解决方案 2、组件间通信方式Vue2中的组件通信方式Vue3中的组件通信方式通用注意事项 3、微信小程序生命周期微信小程序原生生命周期UniApp生命周期 4、微信小程序授权登录流程登录流程手机号获取 5…...
电脑安装系统蓝屏的原因
1. 内存故障 原因:内存条接触不良、损坏或兼容性问题(如不同品牌 / 频率的内存混用)。表现:蓝屏代码可能包含 MEMORY_MANAGEMENT、PAGE_FAULT_IN_NONPAGED_AREA 等。排查方法: 重新插拔内存条,清理金手指灰…...

TDengine 高级功能——流计算
简介 在时序数据的处理中,经常要对原始数据进行清洗、预处理,再使用时序数据库进行长久的储存,而且经常还需要使用原始的时序数据通过计算生成新的时序数据。在传统的时序数据解决方案中,常常需要部署 Kafka、Flink 等流处理系统…...
expect程序交互学习
文章目录 一、初级语法学习二、例子 一、初级语法学习 1.使用expect进行ssh另一台机器 [rootlocalhost ~]# yum install -y expect #先安装expect [rootlocalhost ~]# vim expect1.sh #!/usr/bin/expect spawn ssh root192.168.68.244 expect {"yes/no" {send "…...

05.字母异位词分组
题意理解 🧠 什么是“字母异位词”? 字母异位词是指由相同的字母组成,只是排列顺序不同的单词。 比如: "eat" 和 "tea" 是异位词,它们都包含 e、a 和 t。"ate" 也是它们的异位词。但…...

Mac查看MySQL版本的命令
通过 Homebrew 查看(如果是用 Homebrew 安装的) brew info mysql 会显示你安装的版本、路径等信息。 你的终端输出显示:你并没有安装 MySQL,只是查询了 brew 中的 MySQL 安装信息。我们一起来看下重点: 🧾…...

【.net core】【watercloud】树形组件combotree导入及调用
源码下载:combotree: 基于layui及zTree的树下拉框组件 链接中提供了组件的基本使用方法 框架修改内容 1.文件导入(路径可更具自身情况自行设定) 解压后将文件夹放在图示路径下,修改文件夹名称为combotree 2.设置路径(设置layu…...
[Java 基础]面向对象-封装
封装是构建健壮、可维护和安全软件的基础。 什么是封装? 想象一下你的手机。你不需要知道手机内部复杂的电路、芯片和各种组件是如何协同工作的,你只需要知道如何使用屏幕、按键或触摸操作来打电话、发短信或玩游戏。手机的内部细节被“包裹”起来&…...

2021 RoboCom 世界机器人开发者大赛-高职组(复赛)解题报告 | 珂学家
前言 题解 2021 RoboCom 世界机器人开发者大赛-高职组(复赛)解题报告。 模拟题为主,包含进制转换等等。 最后一题,是对向量/自定义类型,重定义小于操作符。 7-1 人工智能打招呼 分值: 15分 考察点: 分支判定&…...
Python趣学篇:Pygame实现3D星空穿越动画
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《Python星球日记》🪐 目录 一、项目概览与技术栈二、核心技术原理解析1. 透视投影:让3D世界"压扁"到2D屏幕2. Z轴深度:创造…...
基于Web的安全漏洞分析与修复平台设计与实现
基于Web的安全漏洞分析与修复平台设计与实现 摘要 随着信息化进程的加快,Web系统和企业IT架构愈发复杂,安全漏洞频发已成为影响系统安全运行的主要因素。为解决传统漏洞扫描工具定位不准确、修复建议不完善、响应周期长等问题,本文设计并实…...

34.1STM32下的can总线实现知识(区分linux)_csdn
看过我之前的文章就知道,正点原子下的linux中CAN总线并没有讲的很明白,都是系统自带的! 这里我找到江科大学长的can总线的讲解视频! CAN总线入门教程-全面细致 面包板教学 多机通信_哔哩哔哩_bilibili 在这里我也会一步一步讲解CA…...
相机Camera日志分析之二十四:高通相机Camx 基于预览1帧的process_capture_request三级日志分析详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:相机Camera日志分析之二十三:高通相机Camx 基于预览1帧的process_capture_request二级日志分析详解 这一篇我们开始讲: 相机Camera日志分析之二十四:高通相机Camx 基于预览1帧的process_capture_req…...
Linux 内核中 skb_dst_drop 的深入解析:路由缓存管理与版本实现差异
引言 在 Linux 内核网络子系统中,sk_buff(简称 SKB)是数据包在内核态流转的核心数据结构。为了高效处理网络数据包的路由选择,内核通过 dst_entry 结构体缓存路由信息,而 skb_dst_drop 函数则是管理这些路由缓存引用的关键工具。本文将从作用、实现原理、内核版本差异等多…...
考研系列—操作系统:冲刺笔记(4-5章)
目录 第四章 文件管理 1.真题总结文件管理方式 (1)目录文件的FCB就是“目录名-目录地址” (2)普通文件的FCB (3)区分索引文件、顺序文件、索引分配 (4)文件的物理结构 ①连续分配方式 ②链接分配 ③索引分配-使用索引表(一个文件对应一张索引表!!!) 计算考点:超级…...
功能管理:基于 ABP 的 Feature Management 实现动态开关
🚀 功能管理:基于 ABP 的 Feature Management 实现动态开关 📚 目录 🚀 功能管理:基于 ABP 的 Feature Management 实现动态开关📚 一、背景分析🧩 二、核心功能设计2.1 定义 Feature 常量与分组…...

2025年想冲网安方向,该考华为安全HCIE还是CISSP?
打算2025年往网络安全方向转,现在考证是不是来得及?考啥证? 说实话,网络安全这几年热得发烫,但热归热,入门门槛也不低,想进这个赛道,技术、项目经验、证书,缺一不可。 …...
ES6 深克隆与浅克隆详解:原理、实现与应用场景
ES6 深克隆与浅克隆详解:原理、实现与应用场景 一、克隆的本质与必要性 在 JavaScript 中,数据分为两大类型: 基本类型:Number、String、Boolean、null、undefined、Symbol、BigInt引用类型:Object、Array、Functio…...
Go Gin框架深度解析:高性能Web开发实践
Go Gin框架深度解析:高性能Web开发实践 Gin框架核心特性概览 Gin是用Go语言编写的高性能Web框架,以其闪电般的路由性能(基于httprouter)和极简的API设计著称: package mainimport "github.com…...
mybatis 参数绑定错误示范(1)
采用xml形式的mybatis 错误示例: server伪代码为: Map<String, Object> findMapNew MapUtil.<String, Object>builder().put("applyUnit", appUnit).put("planYear", year ! null ? year : -1).put("code&quo…...
每天掌握一个Linux命令 - rpm
Linux 命令工具 rpm 使用指南 Linux 命令工具 rpm 使用指南一、工具概述二、安装方式1. 系统预装2. 源码编译安装(极少场景) 三、核心功能四、基础用法1. 安装软件包2. 升级软件包3. 查询软件包信息4. 卸载软件包5. 验证文件完整性 五、进阶操作1. 批量操…...
常见的MySQL索引类型
在MySQL中,索引是用来提高数据库查询效率的一种数据结构。根据不同的使用场景和需求,MySQL提供了多种类型的索引,每种索引都有其特定的应用场景和优化效果。下面是一些常见的MySQL索引类型: 1. B-Tree索引: 这是最常…...
01串(二进制串)与集合之间存在天然的对应关系 ← bitset
【集合的二进制表示】 ● 01 串(二进制串)与集合之间存在天然的对应关系。对应机理为每个二进制位可以表示集合中一个元素的存在(1)或不存在(0)。例如,集合 {a, b, c} 的子集 {a, c} 可以表示…...

153页PPT麦肯锡咨询流程管理及企业五年发展布局构想与路径规划
麦肯锡咨询的流程管理以其高度结构化、数据驱动和结果导向的核心特点著称,旨在为客户提供清晰、可行且价值最大化的解决方案。其典型流程可概括为以下几个关键阶段:下载资料请查看文章中图片右下角信息 问题界定与结构化: 这是流程的基石。麦…...

[特殊字符] 革命性AI提示词优化平台正式开源!
AI时代最强大的Prompt工程师已经到来! 你是否还在为写不出高质量提示词而头疼?是否羡慕那些能够驾驭AI、让ChatGPT、Claude乖乖听话的"提示词大师"?今天,我们为你带来一个颠覆性的解决方案——TokenAI Auto-Prompt&…...

我的概要设计模板(以图书管理系统为例)
一、总述 1.1 需求或目标 随着数字化阅读普及,传统图书馆管理方式效率低下、资源检索不便。为提升图书管理效率,方便读者借阅与查询,公司计划开发 “在线图书管理系统”,实现图书的电子化管理、快速检索、在线借阅等功能&#x…...