C/C++ 入门(7)string类(STL)

个人主页:仍有未知等待探索-CSDN博客

专题分栏:C++

                                                        请多多指教!

目录

一、标准库中的string

1、了解

2、string类常用接口说明

1、常见的构造函数

2、容量操作 ​编辑

3、访问及遍历操作

4、修改操作

5、非成员函数

 二、string类实现

1、string类的大体框架

2、构造和析构函数 

3、迭代器 

4、成员函数 

5、非成员函数

 三、问题

1、深拷贝和浅拷贝问题

2、strcpy,memcpy

四、总代码


一、标准库中的string

1、了解

1、string是表示字符串的字符串类
2、该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。

2、string类常用接口说明

下面的函数都可以去下面的网址进行查文档,来看函数的功能。(接下来我会实现这个string类)

string - C++ Reference

1、常见的构造函数

string类对象的常见构造
函数名称功能说明
string()        构造空的string类,即空字符串
string(const char*s)

用c_str()来构造string类对象

string(size_t n, char c)string类对象中包含n个字符c
string(const string& s)拷贝构造函数

2、容量操作
 

3、访问及遍历操作

4、修改操作

5、非成员函数

 二、string类实现

实现string类能让我们更好的明白模板的使用,函数重载等等。

1、string类的大体框架

#include <iostream>
#include <cstring>
#include <assert.h>
using namespace std;class string
{
public:private:char* _str; // string存的字符串size_t _size; // string中字符串的长度 size_t _capacity; // string的容量
};

2、构造和析构函数 

string():_str(nullptr),_size(0),_capacity(0)
{}
string(const char* str):_size(strlen(str)),_capacity(_size)
{_str = new char[_capacity + 1];strcpy(_str, str);
}
string(const string& str):_str(new char[str._capacity + 1]),_size(str._size),_capacity(str._capacity)
{strcpy(_str, str._str);
}
~string()
{delete[] _str;_str = nullptr;_size = 0;_capacity = 0;
}

3、迭代器 

typedef char* iterator;
iterator begin()
{return _str;
}
iterator end()
{return _str + _size;
}

4、成员函数 


string& operator=(const string& str)
{char* tmp = new char[str._capacity + 1];strcpy(tmp, str._str);delete[] _str;_str = tmp;_size = str._size;_capacity = str._capacity;return *this;
}
void reserve(int x)
{if (_capacity < x){char* tmp = new char[x + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = x;}
}
void swap(string& str)
{std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);
}
const char* c_str() const
{return _str;
}
void clear()
{_str[0] = '\0';_size = 0;
}
void insert(int index, const string& str)
{int len = str._size;assert(index >= 0 && index < _size);if (_size + len >= _capacity){reserve(_capacity + len);}for (int i = _size - 1; i >= index; i -- ){_str[i + len] = _str[i];}for (int j = 0, i = index; j < str._size; j ++ ,i ++ ){_str[i] = str._str[j];}_size += len;
}
void insert(int index, char ch)
{assert(index >= 0 && index < _size);if (_size + 1 >= _capacity){reserve(2 * _capacity);_capacity *= 2;}for (int i = _size - 1; i >= index; i -- ){_str[i + 1] = _str[i];}_str[index] = ch;_size ++ ;}
void append(const string& str)
{int len = str._size;if (len + _size > _capacity){reserve(len + _size);_capacity = len * _size;}int end = _size;for (int i = 0; i < str._size; i ++ ,end ++ ){_str[end] = str._str[i];}_size += len;
}
string& operator+=(const string& str)
{append(str);return *this;
}
void push_back(const char ch)
{if (_size + 1 >= _capacity){reserve(2 * _capacity);}_capacity *= 2;_str[_size] = ch;_size ++ ;
}
int size() const
{return _size;
}
int capacity() const
{return _capacity;
}
bool empty() const
{return _size == 0;
}
void resize(int n, char ch = '\0')
{if (n < _size){for (int i = n; i < _size; i ++ ){_str[i] = '\0';}}else if (n + 1 < _capacity){for (int i = _size; i < n; i ++ ){_str[i] = ch;}}else{reserve(n);}
}
char& operator[](size_t index)
{assert(index < _size);return _str[index];
}
const char& operator[](size_t index)const
{assert(index < _size);return _str[index];
}
bool operator==(const string& str)
{int ret = strcmp(_str, str.c_str());return ret == 0;
}
bool operator!=(const string& str)
{return !(*this == str);
}
bool operator>(const string& str)
{int ret = strcmp(_str, str.c_str());return ret > 0;
}
bool operator<(const string& str)
{int ret = strcmp(_str, str.c_str());return ret < 0;
}
bool operator<=(const string& str)
{return *this < str || *this == str;
}
bool operator>=(const string& str)
{return *this > str || *this == str;
}
int find (char c, size_t pos = 0) const
{assert(pos < _size);for (int i = pos; i < _size; i ++ ){if (_str[i] == c) return i;}return npos;
}
int find (const char* s, size_t pos = 0) const
{char* p = strstr(_str + pos, s);if (p != nullptr){return p - _str;}return npos;
}
string& erase (size_t pos = 0, size_t len = npos)
{assert(pos < _size);if (len == npos || len >= _size - pos){_str[pos] = '\0';_size = pos;}else{int i = 0;for (i = pos + len; i < _size; i ++ ){_str[i - len] = _str[i];}_str[i] = '\0';_size -= len;}return *this;
}

5、非成员函数

    ostream& operator<<(ostream& out, const string& str){int len = str._size;for (int i = 0; i < len; i ++ ){out << str._str[i];}return out;}istream& operator>>(istream& in, string& str){str.clear();char ch = in.get();char buff[128];int i = 0;while (ch != ' ' && ch != '\n'){buff[i ++ ] = ch;if (i == 127){buff[i] = '\0';str += buff;i = 0;}ch = in.get();}if (i != 0){buff[i] = '\0';str += buff;}return in;}
}

 三、问题

1、深拷贝和浅拷贝问题

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


深拷贝:每个对象都有一份独立的资源,不要和其他对象共享。如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供。

2、strcpy,memcpy

通过下面的例子也能清晰的看出来,这两个拷贝函数都是浅拷贝。所以在用的时候需要小心谨慎。

四、总代码

#include <iostream>
#include <cstring>
#include <assert.h>
using namespace std;namespace my
{class string{public:string():_str(nullptr),_size(0),_capacity(0){}string(const char* str):_size(strlen(str)),_capacity(_size){_str = new char[_capacity + 1];strcpy(_str, str);}string(const string& str):_str(new char[str._capacity + 1]),_size(str._size),_capacity(str._capacity){strcpy(_str, str._str);}~string(){delete[] _str;_str = nullptr;_size = 0;_capacity = 0;}typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}string& operator=(const string& str){char* tmp = new char[str._capacity + 1];strcpy(tmp, str._str);delete[] _str;_str = tmp;_size = str._size;_capacity = str._capacity;return *this;}void reserve(int x){if (_capacity < x){char* tmp = new char[x + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = x;}}void swap(string& str){std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}const char* c_str() const{return _str;}void clear(){_str[0] = '\0';_size = 0;_capacity = 0;}void insert(int index, const string& str){int len = str._size;assert(index >= 0 && index < _size);if (_size + len >= _capacity){reserve(_capacity + len);}for (int i = _size - 1; i >= index; i -- ){_str[i + len] = _str[i];}for (int j = 0, i = index; j < str._size; j ++ ,i ++ ){_str[i] = str._str[j];}_size += len;}void insert(int index, char ch){assert(index >= 0 && index < _size);if (_size + 1 >= _capacity){reserve(2 * _capacity);_capacity *= 2;}for (int i = _size - 1; i >= index; i -- ){_str[i + 1] = _str[i];}_str[index] = ch;_size ++ ;}void append(const string& str){int len = str._size;if (len + _size > _capacity){reserve(len + _size);_capacity = len * _size;}int end = _size;for (int i = 0; i < str._size; i ++ ,end ++ ){_str[end] = str._str[i];}_size += len;}string& operator+=(const string& str){append(str);return *this;}void push_back(const char ch){if (_size + 1 >= _capacity){reserve(2 * _capacity);}_capacity *= 2;_str[_size] = ch;_size ++ ;}int size() const{return _size;}int capacity() const{return _capacity;}bool empty() const{return _size == 0;}void resize(int n, char ch = '\0'){if (n < _size){for (int i = n; i < _size; i ++ ){_str[i] = '\0';}}else if (n + 1 < _capacity){for (int i = _size; i < n; i ++ ){_str[i] = ch;}}else{reserve(n);}}char& operator[](size_t index){assert(index < _size);return _str[index];}const char& operator[](size_t index)const{assert(index < _size);return _str[index];}bool operator==(const string& str){int ret = strcmp(_str, str.c_str());return ret == 0;}bool operator!=(const string& str){return !(*this == str);}bool operator>(const string& str){int ret = strcmp(_str, str.c_str());return ret > 0;}bool operator<(const string& str){int ret = strcmp(_str, str.c_str());return ret < 0;}bool operator<=(const string& str){return *this < str || *this == str;}bool operator>=(const string& str){return *this > str || *this == str;}int find (char c, size_t pos = 0) const{assert(pos < _size);for (int i = pos; i < _size; i ++ ){if (_str[i] == c) return i;}return npos;}int find (const char* s, size_t pos = 0) const{char* p = strstr(_str + pos, s);if (p != nullptr){return p - _str;}return npos;}string& erase (size_t pos = 0, size_t len = npos){assert(pos < _size);if (len == npos || len >= _size - pos){_str[pos] = '\0';_size = pos;}else{int i = 0;for (i = pos + len; i < _size; i ++ ){_str[i - len] = _str[i];}_str[i] = '\0';_size -= len;}return *this;}friend ostream& operator<<(ostream& out, const string& str);friend istream& operator>>(istream& in, string& str);private:char* _str; // string存的字符串size_t _size; // string中字符串的长度 size_t _capacity; // string的容量static const size_t npos = -1;};inline ostream& operator<<(ostream& out, const string& str){int len = str._size;for (int i = 0; i < len; i ++ ){out << str._str[i];}return out;}inline istream& operator>>(istream& in, string& str){str.clear();char ch = in.get();char buff[128];int i = 0;while (ch != ' ' && ch != '\n'){buff[i ++ ] = ch;if (i == 127){buff[i] = '\0';str += buff;i = 0;}ch = in.get();}if (i != 0){buff[i] = '\0';str += buff;}return in;}
}

谢谢大家! 

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

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

相关文章

LeetCode57. 插入区间

LeetCode57.插入区间 题目思路: 代码 /* 前置知识&#xff1a; vector<vector<int>> a,b; 二维vector数组是可以将二维中的一维vector数组给push_back的&#xff0c; 不是只有单个元素才可以&#xff0c;整个一维的vector数组也可以 b[0] {1,2,3},b[1] {4,5,6}…

【AIGC调研系列】大型语言模型如何减少幻觉生成

在解读大型语言模型&#xff08;LLMs&#xff09;中的长格式事实性问题时&#xff0c;我们首先需要认识到这些模型在生成内容时可能会产生与既定事实不一致的情况&#xff0c;这种情况通常被称为“幻觉”[2][3]。这种现象不仅可能导致信息的误传&#xff0c;还可能对社会造成误…

封装 H.264 视频为 FLV 格式然后推流

封装 H.264 视频为 FLV 格式并通过 RTMP 推流 flyfish 协议 RTMP (Real-Time Messaging Protocol) RTSP (Real Time Streaming Protocol) SRT (Secure Reliable Transport) WebRTC RTMP&#xff08;Real Time Messaging Protocol&#xff09;是一种用于实时音视频流传输的协…

indexDB 大图缓存

背景 最近在项目中遇到了一个问题&#xff1a;由于大屏背景图加载速度过慢&#xff0c;导致页面黑屏时间过长&#xff0c;影响了用户的体验。从下图可以看出加载耗时将近一分钟 IndexDB 主要的想法就是利用indexDB去做缓存&#xff0c;优化加载速度&#xff1b;在这之前&am…

C语言——内存函数的实现与模拟

1. memcpy 函数 与strcpy 函数类似 1.头文件 <string.h> 2.基本格式 • 函数memcpy从source的位置开始向后复制num个 字节 的数据到destination指向的内存位置。 • 这个函数在遇到 \0 的时候并不会停下来。 • 如果source和destination有任何的重叠&#xff0…

C# WinForm —— 10 单选按钮与复选框的介绍与使用

单选按钮 RadioButton 一组单选按钮中&#xff0c;只能选择一个&#xff0c;互相排斥 常用属性、事件&#xff1a; 属性用途(Name)单选按钮的ID&#xff0c;在代码里引用的时候会用到,一般以 rb开头Text单选按钮旁边显示的 文本信息Checked单选按钮的勾选状态Appearance控制单…

SpringCloud系列(18)--将服务提供者Provider注册进Consul

前言&#xff1a;在上一章节中我们把服务消费者Consumer注册进了Zookeeper&#xff0c;并且成功通过服务消费者Consumer调用了服务提供者Provider&#xff0c;而本章节则是关于如何将服务提供者Provider注册进Consul里 准备环境&#xff1a; 先安装Consul&#xff0c;如果没有…

【OceanBase诊断调优】—— 4013 内存爆问题的排查

本文介绍 4013 内存爆问题的排查。 内存爆的类型 内存爆主要分为五类&#xff0c;可以通过关键词 OOPS 确定内存爆的类型。 内存爆的类型日志信息&#xff08;关键字为 [OOPS]&#xff09;SINGLE_ALLOC_SIZE_OVERFLOWsingle alloc size large than 4G is not allowed(alloc_…

vue项目使用百度地图

打开百度地图开放平台 百度地图开放平台 | 百度地图API SDK | 地图开发 在控制台新建应用 复制访问应用的ak 可修改地图样式 使用部分 <!-- 引入地图 --><div class"main-aside"><div id"b-map-container"></div></div> …

案例-部门管理-删除

黑马程序员JavaWeb开发教程 文章目录 一、查看页面原型二、查看接口文档三、开发1、Controller2、Service&#xff08;1&#xff09;service接口层&#xff08;3&#xff09;service实现层 3、Mapper4、Postman 一、查看页面原型 二、查看接口文档 三、开发 1、Controller 因…

SpringWebFlux RequestBody多出双引号问题——ProxyPin抓包揪出真凶

缘起 公司有个服务做埋点收集的&#xff0c;可以参考我之前的文章埋点日志最终解决方案&#xff0c;今天突然发现有些数据日志可以输出&#xff0c;但是没法入库。 多出的双引号 查看Flink日志发现了JSON解析失败&#xff0c;Flink是从Kafka拿数据&#xff0c;Kafka本身不处…

Magnet for Mac:高效窗口管理工具

Magnet for Mac是一款专为Mac用户设计的窗口管理工具&#xff0c;旨在帮助用户更高效地管理和布局多个应用程序窗口&#xff0c;提升工作效率。 Magnet for Mac v2.14.0中文免激活版下载 这款软件拥有直观易用的界面和丰富的功能&#xff0c;支持用户将屏幕分割成多个区域&…

【漏洞分析】浅析android手游lua脚本的加密与解密(一)

主要用到的工具和环境&#xff1a; 1 win7系统一枚 2 quick-cocos2d-x的开发环境&#xff08;弄一个开发环境方便学习&#xff0c;而且大部分lua手游都是用的cocos2d-x框架&#xff0c;还有一个好处&#xff0c;可以查看源码关键函数中的特征字符串&#xff0c;然后在IDA定位到…

Electron中使用Prisma(以SQLite为例)

1、安装 Prisma 打开终端&#xff0c;执行以下命令安装 Prisma CLI&#xff1a; npm install prisma -g 2、初始化 Prisma 项目 在工作目录中执行以下命令来初始化一个新的 Prisma 项目&#xff1a; prisma init 这将创建一个新的文件夹&#xff0c;包含了必要的文件和目…

vue echarts折线图 折线堆积图和折线面积图

vue echarts折线图 折线堆积图和折线面积图 1、折线堆积图和折线面积图的结合&#xff1b; 上代码 <template><section><divid"performaceLineChart"ref"performaceLineChartRef"style"width: 100%; height: 500px"></d…

文旅IP孵化打造抖音宣传推广运营策划方案

【干货资料持续更新&#xff0c;以防走丢】 文旅IP孵化打造抖音宣传推广运营策划方案 部分资料预览 资料部分是网络整理&#xff0c;仅供学习参考。 PPT可编辑&#xff08;完整资料包含以下内容&#xff09; 目录 文旅IP抖音运营方案 1. 项目背景与目标 - 背景&#xff1a…

ShardingSphere 5.x 系列【25】 数据分片原理之 SQL 解析

有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址:https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 分片执行流程1.1 Simple Push Down1.2 SQL Federation2. SQL 解析2.1 解析…

【stomp 实战】Spring websocket使用详解和基本原理

spring框架对websocket有很好的支持&#xff0c;stomp协议作为websocket的子协议&#xff0c;Spring也做了很多封装&#xff0c;让我们在开发中易于使用。 学习使用Spring的Websocket模块&#xff0c;当然最好的办法就是看官网说明了。本篇文章对官网做一些简述和个人的理解。 …

Java设计模式 _结构型模式_适配器模式

一、适配器模式 **1、适配器模式&#xff08;Adapter Pattern&#xff09;**是一种结构型设计模式。适配器类用来作为两个不兼容的接口之间的桥梁&#xff0c;使得原本不兼容而不能一起工作的那些类可以一起工作。譬如&#xff1a;读卡器就是内存卡和笔记本之间的适配器。您将…

国产麒麟v10系统下打包electron+vue程序,报错unknown output format set

报错如下&#xff1a; 报错第一时间想到可能是代码配置原因报错&#xff0c;查看代码似乎感觉没啥问题 又查看具体报错原因可能是因为icon的原因报错&#xff0c;后面查阅发现ico在各系统平台会不兼容&#xff0c;也就是ico是给win下使用的&#xff0c;此处改下图标格式就ok&am…