C++初级----string类(STL)

1、标准库中的string

1.1、sring介绍

        字符串是表示字符序列的类,标准的字符串类提供了对此类对象的支,其接口类似于标准字符容器的接口,但是添加了专门用于操作的单字节字符字符串的设计特性。

        string类是使用char,即作为他的字符类型,使用他默认的char_traits和分配器类型。string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits 和allocator作为basic_string的默认参数。

        这个类独立于所使用的编码来处理字节;如果用来处理多字节或者变长字符(如utf-8)序列,这个类的所有成员,以及他的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

1.2、string类常用的接口

1.2.1、string类对象的常见构造
string类对象常见的构造
函数名称功能说明
string()构造空的string类对象,即空字符串
string(const char* s)用C-string来构造string类对象
string(size_t n,char c)string类对象包含n个字符c
string(const string& s)拷贝构造函数
#include<iostream>
#include<string>int main()
{string s1;                      // 构造空的string对象string s2("hewllo word");       // 用C格式的字符串构造string对象string s3(s2);                  //拷贝构造return 0;
}
1.2.2、string类对象的容量操作

函数名称

功能说明

size(重点)

返回字符串有效字符长度

length

返回字符串有效字符长度

capacity

返回空间总大小

empty(重点)

检测字符串释放为空串,是返回true,否则返回false

clear

清空有效字符

reserve(重点)

为字符串预留空间

resize(重点)

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

注意:

        size() 与length() 的方法底层与实现原理完全相同,引入size只是为了和其他容器的接口保持一致。

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

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

        reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小。

1.2.3、string类对象的访问以及遍历操作

函数名称

功能说明

operator[]

返回pos位置的字符,const string类对象调用

begin+ end

begin获取一个字符的迭代器,end获取最后一个字符下一个位置的迭代器

rbegin +rend

rbegin获取最后一个字符的迭代器,end获取最开始一个字符前一个位置的迭代器

范围for

C++11支持更简洁的范围for的新遍历方式

1.2.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把空间预留好,这样可以节省一些时间。

1.2.5、string类非成员函数

函数

功能说明

operator+

尽量少用,因为传值返回,导致深拷贝效率低

operator>>

输入运算符重载

operator<<

输出运算符重载

getline

获取一行字符串

Relational operators

大小比较

1.2.6、vs和g++下string结构对比

下述结构是在32位平台下进行验证,32位平台下指针占4个字节。

         vs下string的结构

                string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字 符串的存储空间:

  •                         当字符串长度小于16时,使用内部固定的字符数组来存放
  •                         当字符串长度大于等于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;

g++下string的结构

         G++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指 针将来指向一块堆空间,内部包含了如下字段:

  •                  空间总大小
  •                 字符串有效长度
  •                 引用计数
struct _Rep_base
{size_type _M_length;size_type _M_capacity;_Atomic_word _M_refcount;
};

2、string类的模拟实现

2.1、深浅拷贝

        浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共 享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为 还有效,所以当继续对资源进项操作时,就会发生发生了访问违规。

        深拷贝:每个对象都有一份独立的资源,不要和其他对象共享。

2.2、写时拷贝

写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。

        引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给 计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该 对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。

2.3、string模拟实现代码

#pragma once
#include<assert.h>
#include <iostream>
#include <string>
using namespace std;
namespace kzy{class string{friend ostream& operator<<(ostream& _cout, const kzy::string& s);friend istream& operator>>(istream& _cin, kzy::string& s);public:typedef char* iterator;typedef const char* const_iterator;public:string(const char* str = ""):_size(strlen(str)),_capacity(_size){_str = new char[_capacity + 1];strcpy(_str, str);}string(const string& s) :_size(strlen(s._str)),_capacity(_size){_str = new char[_capacity + 1];strcpy(_str, s._str);}string& operator=(const string& s) {if (this != &s) {char *tmp = new char[s._capacity + 1];strcpy(tmp, s._str);delete[]_str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;}~string() {if (_str != nullptr) {delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}}// iteratoriterator begin(){return _str;}iterator end() {return _str+_size;}const_iterator begin()const{return _str;}const_iterator end() const{return _str + _size;}// modifyvoid push_back(char c) {if (_size == _capacity) {reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = c;++_size;_str[_size] = '\0';}string& operator+=(char c) {push_back(c);return *this;}void append(const char* str) {size_t len = _size + strlen(str);if (len > _capacity) {reserve(len);}strcpy(_str + _size, str);_size = len;}string& operator+=(const char* str) {append(str);return *this;}void clear() {_size = 0;_str[_size] = '\0';}void swap(string& s) {std::swap(_str, s._str);std::swap(_capacity, s._capacity);std::swap(_size, s._size);}const char* c_str()const {return _str;}// capacitysize_t size()const {return _size;}size_t capacity()const {return _capacity;}bool empty()const {return _size == 0;}void resize(size_t n, char c = '\0') {if (n < _size){_size = n;_str[_size] = '\0';}else{if (n > _capacity){reserve(n);}for (size_t i = _size; i < n; ++i){_str[i] = c;}_size = n;_str[_size] = '\0';}}void reserve(size_t n) {if (n > _capacity) {char* tmp = new char[n + 1];strcpy(tmp, _str);delete[]_str;_str = tmp;_capacity = n;}}// accesschar& operator[](size_t index) {assert(index < _size);return _str[index];}const char& operator[](size_t index)const {assert(index < _size);return _str[index];}//relational operatorsbool operator<(const string& s) {return strcmp(_str, s.c_str()) < 0;}bool operator<=(const string& s) {return *this == s || *this < s;}bool operator>(const string& s) {return !(*this <= s);}bool operator>=(const string& s) {return !(*this < s);}bool operator==(const string& s) {return strcmp(_str, s.c_str()) == 0;}bool operator!=(const string& s) {return !(*this==s);}// 返回c在string中第一次出现的位置size_t find(char c, size_t pos = 0) const {assert(pos <= _size);for (size_t i=pos ; i < _size; i++) {if (_str[i] == c) {return i;}}return npos;}// 返回子串s在string中第一次出现的位置size_t find(const char* s, size_t pos = 0) const {assert(pos <= _size);char* p = strstr(_str+pos, s);if (p == nullptr) {return npos;}else {return p - _str;}}// 在pos位置上插入字符c/字符串str,并返回该字符的位置string& insert(size_t pos, char c) {assert(pos <= _size);size_t end = _size+1;if (_size == _capacity) {//reserve(_capacity + 1);reserve(_capacity == 0 ? 4 : _capacity + 1);}while (end > pos) {_str[end] = _str[end-1];--end;}_str[pos] = c;_size++;return *this;}string& insert(size_t pos, const char* str) {assert(pos <= _size);size_t len = strlen(str);size_t end = _size+len;if (_size + len > _capacity) {reserve(_capacity + len);}while (end > pos + len-1) {_str[end] = _str[end - len];--end;}strncpy(_str + pos, str, len);_size += len;return *this;}// 删除pos位置上的元素,并返回该元素的下一个位置string& erase(size_t pos, size_t len=npos) {if (len >= _size - pos||len == npos) {_str[pos] = '\0';_size = pos;}else {strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;}private:char* _str;size_t _size;size_t _capacity;const static size_t npos;};const size_t string::npos = -1;ostream& operator<<(ostream& _cout, const kzy::string& s) {for (auto ch : s){_cout << ch;}return _cout;}istream& operator>>(istream& _cin, kzy::string& s) {char ch;ch = _cin.get();char buff[128] = { '\0' };size_t i = 0;while (ch != ' ' && ch != '\n') {buff[i++] = ch;if (i == 127) {s += buff;memset(buff, '\0', 128);i = 0;}ch = _cin.get();}s += buff;return _cin;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【蓝桥杯嵌入式】12届程序题刷题记录及反思

一、题目解析 按键短按LCD显示两个界面LED指示灯PWM脉冲输出 二、led控制 控制两个led灯&#xff0c;两种状态 //led void led_set(uint8_t led_dis) {HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC,led_dis << 8,GPIO_PIN_RESET);HAL…

高度不同的流体瀑布css实现方法

商城商品列表 实现瀑布流展示&#xff0c;通过flex或grid实现会导致每行中的列高度一致&#xff0c;无法达到错落有致的感觉&#xff1b; 为此需要用到&#xff1a; CSS columns 属性 columns 属性是一个简写属性&#xff0c;用于设置列宽和列数。 CSS 语法 columns: column-wi…

一些增强生产力的 AI 工具

engshell 支持自然语言交互的 shell engshell 是一个适用于任何操作系统的英语 shell&#xff0c;由 LLM 提供自然语言交互支持 Paints Chainer 漫画线稿上色 AI Paints Chainer 是一款用于为漫画上色的工具&#xff0c;只需上传一张黑白线稿&#xff0c;点击按钮&#xff0…

JQuery(二)---【使用JQuery对HTML、CSS进行操作】

零.前言 JQuery(一)---【JQuery简介、安装、初步使用、各种事件】-CSDN博客 一.使用JQuery对HTML操作 1.1获取元素内容、属性 使用JQ可以操作元素的“内容” text()&#xff1a;设置或返回元素的文本内容html()&#xff1a;设置或返回元素的内容(包括HTML标记)val()&#…

Leetcode 102. 二叉树的层序遍历

注意的点&#xff1a; 1、队列注意用popleft 2、注意用len(queue)控制层数 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.left left # self.right righ…

Redis 的主从复制、哨兵和cluster集群

目录 一. Redis 主从复制 1. 介绍 2. 作用 3. 流程 4. 搭建 Redis 主从复制 安装redis 修改 master 的Redis配置文件 修改 slave 的Redis配置文件 验证主从效果 二. Redis 哨兵模式 1. 介绍 2. 原理 3. 哨兵模式的作用 4. 工作流程 4.1 故障转移机制 4.2 主节…

vscode-插件开发-hello world-创建初始模板

目录 前言1.环境配置全局安装 yo, generator-code 2. 新建一个插件项目模板问题1: F5 按键无法启动launch.json调试(解决)问题1 描述:问题1: 找错误问题1: 可行的解决方案 3. 开发插件(添加自定义功能) 参考vscode官方示例&#xff1a;如何创建你的第一个插件开发项目模板的步骤…

Leetcode刷题-哈希表详细总结(Java)

哈希表 当我们想使⽤哈希法来解决问题的时候&#xff0c;我们⼀般会选择如下三种数据结构。 数组set &#xff08;集合&#xff09;map&#xff08;映射&#xff09; 当我们遇到了要快速判断⼀个元素是否出现集合⾥的时候&#xff0c;就要考虑哈希法。如果在做⾯试题⽬的时候…

SpringCloud学习(11)-SpringCloudAlibaba-Nacos数据模型

一、Nacos数据模型 1.1、数据模型 对于Nacos配置管理&#xff0c;通过Namespace、Group、Date ID能够定位到一个配置集。Nacos数据模型如下所示&#xff1a; 1.2、命名空间(Namespace) 可用于进行不同环境的配置隔离。例如&#xff1a; 1)、可以隔离开发环境——测试环境和…

【Linux】进程学习① (进程的PCB(task_struct)进程的标识符详解进程的创建fork函数)

目录 ​编辑 1.进程的概念 1.1进程的描述与组织&#xff1a;进程的PCB 进程&#xff1a;进程是 内核pcb对象可执行程序/内核数据结构可执行程序进程 1.3 task_struct 2.PCB内部属性 3 查看进程 4.获取进程标识符&#xff1a;getpid函数&#xff08;4-6主要围绕进程的标识符展开…

全系统各类型工程水土保持方案编制

孙老师&#xff08;高级工程师&#xff09;&#xff1a;长期承担重点水土保持方案编写方面工作&#xff0c;开设多场线下、线上培训会议&#xff0c;拥有丰富的工程和教学经验&#xff0c;为众多单位培养了近千名水土保持骨干人员&#xff0c;建有多个技术交流群&#xff0c;长…

HCIP-Datacom(H12-821)题库补充(4月7日)

最新 HCIP-Datacom&#xff08;H12-821&#xff09;完整题库请扫描上方二维码访问&#xff0c;持续更新中。 在PIM-DM中&#xff0c;路由器会为被裁剪的下游接口启动一个剪枝定时器&#xff0c;定时器超时后接口就会恢复转发。默认情况下该定时器是多少秒&#xff1f; A&#x…