Lesson08---string(4)类

Lesson08—string类(4)

c++第八章string类的实现


文章目录

  • Lesson08---string类(4)
  • 前言
  • 一、计算机是怎么储存文字的
    • 1. 在此之前先思考一个问题
    • 2.编码表
      • 2.1 ascll码
      • 2.2unicode码
      • 2.3UTF码
      • 2.4gbk码
  • 二、实现一个简单的string
    • 1.构造函数和析构函数
    • 2.范围for和迭代器
    • 3.常见的成员函数
      • 3.1 size
      • 3.2 reserve
      • 3.3 push_back
      • 3.4 append
      • 3.5 insert(insert(size_t pos, char ch))
      • 3.6 void insert(size_t pos, const char* str);
      • 3.7 void erase(size_t pos = 0, size_t len = npos);
      • 3.8 size_t find(char ch, size_t pos=0);
      • 3.9 size_t find(const char* sub, size_t pos = 0);
      • 3.10 拷贝构造函数 My_String(const My_String& str);
      • 3.11赋值函数 My_String& operator=(My_String s);
      • 3.12 My_String substr(size_t pos = 0, size_t len = npos);
    • 4.运算符重载
    • 5.比较运算符 重载
    • 6.流插入和提取


前言

这篇文章写了计算机是怎么存储文字的,以及string类的底层是怎么实现的


一、计算机是怎么储存文字的

1. 在此之前先思考一个问题

#define _CRT_SECURE_NO_WARNINGS 
#include<bits/stdc++.h>
using namespace std;
int main()
{char buff1[] = "abcd";char buff2[] = "你好";cout << sizeof(buff1) << endl;cout << sizeof(buff2) << endl;return 0;
}

上面的代码输出是多少?


在这里插入图片描述
这就很奇怪为什么数量不一样需要的字节却是一样的?

为什么第一个数组明明只有4的字母要的内存却是5的?

通过调试来看看
在这里插入图片描述
这里可以看到第一个数组里面存的其实是ascll码,内存里面那个61.62其实就是97的16进制,比实际的数量多1是因为\0,中文是俩个字节

2.编码表

2.1 ascll码

在计算机里面只有010101,它也只认识0101010其他的语言它必须翻译成01010计算机它才能认识,最开始发明计算机的大佬用的是英语,大佬们就对英语进行了编码,对26个字母进行了映射,以及一些标点符号

在这里插入图片描述
在这里插入图片描述
计算机内存里面只会存ascii码,显示的时候就去找这个表然后显示出来


在这里插入图片描述
早年间计算机只有在美国那边使用,所以最开始就只弄了英文和一些标点符号,但随着计算机的普及一种语言早以满足不了人们

在这里插入图片描述
ascll码的取值范围是0-127,那么上面的负数到底是啥?


2.2unicode码

英文就26个大小一共也就26*2加上一些符号上面的加起来差不多也就100多个,所有的单词都是这些组成,那么中文呢?

汉字十几万个难道也去做一个十几万个的映射表?


unicode也就是统一码,它诞生就是为了编码全世界的文字
在这里插入图片描述
在这里插入图片描述
大部分的文字用俩个字节就足以存下,但这里又会出现一个新的问题,如果中英混合怎么办?


2.3UTF码

如果想实现混合编码那么这几套就必须要兼容,utf码提供了三种编码
在这里插入图片描述
用的最多的就是utf8

2.4gbk码

中华的文化博大精深就比如中文不仅有简体字还有繁体字utf就没有gbk处理中文处理的好,gbk就是专门处理中文的一种编码在这里插入图片描述

二、实现一个简单的string

1.构造函数和析构函数

我这里采用多文件的形式

//string.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
class My_String
{friend ostream& operator<<(ostream& out, My_String& string);
public:My_String(const char* str="");~My_String();const char* c_str()const;
private:char* _str;size_t _size;size_t _capacity;};

在这里插入图片描述


#include"string.h"
My_String::My_String(const char* str):_size(strlen(str)){_str = new char[_size + 1];_capacity = _size;strcpy(_str, str);
}My_String::~My_String()
{delete[] _str;_str = nullptr;_size = _capacity = 0;
}const char* My_String::c_str() const
{return _str;
}ostream& operator<<(ostream& out,  My_String& string)
{cout << string._str;return out;
}

在这里插入图片描述

2.范围for和迭代器

//string.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
class My_String
{friend ostream& operator<<(ostream& out, My_String& string);
public:typedef char* iterator;iterator begin(); iterator end();My_String(const char* str="");~My_String();const char* c_str()const;size_t size()const;char& operator[](size_t pos);private:char* _str;size_t _size;size_t _capacity;};

在这里插入图片描述

//string.cpp
#include"string.h"My_String::iterator My_String::begin()
{return _str;
}My_String::iterator My_String::end()
{return _str+_size;
}My_String::My_String(const char* str):_size(strlen(str)){_str = new char[_size + 1];_capacity = _size;strcpy(_str, str);
}My_String::~My_String()
{delete[] _str;_str = nullptr;_size = _capacity = 0;
}const char* My_String::c_str() const
{return _str;
}ostream& operator<<(ostream& out,  My_String& string)
{cout << string._str;return out;
}
size_t My_String::size()const
{return _size;
}
char& My_String::operator[](size_t pos)
{assert(pos < _size);return _str[pos];
}

在这里插入图片描述
这里需要注意命名最好养成习惯,要不然就会出现各种各样的问题
在这里插入图片描述
这样以后就可以用迭代器和范围for来遍历这个数组了,范围for的底层就是迭代器

3.常见的成员函数

3.1 size

这个比较简单就不过多赘述
在这里插入图片描述

3.2 reserve

这个函数有保留的意思这里我拿来扩容,细节可以参考https://blog.csdn.net/m0_67371175/article/details/141872058?spm=1001.2014.3001.5502的第七条

void My_String::reserve(size_t n)
{if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[]_str;_capacity = n;_str = tmp;}
}

在这里插入图片描述

3.3 push_back

这个函数在string容器里面比较复杂我这里就简单实现一下

void My_String::push_back(char ch)
{size_t newcapacity;if (_size == _capacity){if (_capacity == 0){newcapacity = 4;}else{newcapacity = _capacity * 2;}My_String::reserve(newcapacity);}_str[_size] = ch;_str[_size + 1] = '\0';++_size;
}

在这里插入图片描述

3.4 append

这里append和push_back的区别就是一个是字符一个是字符串这里我append是尾插字符串

void My_String::append(const char* str)
{size_t len = strlen(str);if (_size+len>_capacity){reserve(_size + len);}strcpy(_str+_size, str);_size += len;
}

在这里插入图片描述

3.5 insert(insert(size_t pos, char ch))

下面代码运行结果是死循环,你找的到问题出在哪里吗
错误1:

void My_String::insert(size_t pos, char ch)
{if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}size_t end = _size;while (end >= pos){_str[end + 1] = _str[end];end--;}_str[pos] = ch;_size++;}

在这里插入图片描述

在这里插入图片描述
因为这里的end是size_t类型没有符号所以直接就变成了最大的正数了
在这里插入图片描述
错误2:
在这里插入图片描述
把end换成int类型还是死循环你知道为什么吗?

在这里插入图片描述

int类型和size_t类型比较发生隐式类型转换,int类型转换成了size_t了
在这里插入图片描述
解决方法就是把pos强制转换成int
在这里插入图片描述
这样就可以解决这个问题
或者也可以这样
在这里插入图片描述

3.6 void insert(size_t pos, const char* str);

void My_String::insert(size_t pos, const char* str)
{size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}int end = _size;while (end >= (int)pos){_str[end + len] = _str[end];end--;}_size += len;memcpy(_str + pos, str, len);
}
size_t len = strlen(str);if (_size + len > _capacity)
{reserve(_size + len);
}

也可以这么写

size_t len = strlen(str);if (_size + len > _capacity)
{reserve(_size + len);
}
size_t end = _size + len;while (end>= pos+len)
{_str[end]=_str[end - len];end--;}
memcpy(_str + pos, str, len);
_size += len;

insert函数写好了以后尾插就可以直接调用这个函数了

3.7 void erase(size_t pos = 0, size_t len = npos);

//下面代码还有一个错误可以尝试找一下
void My_String::erase(size_t pos, size_t len)
{assert(pos < _size );if (pos+len>=_size){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}
}

在这里插入图片描述
但是这样写就没错

void My_String::erase(size_t pos, size_t len)
{assert(pos < _size );if (len>=_size - pos){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}
}

在这里插入图片描述
我这里len的缺省值是npos,npos是size_t n=-1,然后它是无符号整型纯的补码,也就是111111…也就是size_t的最大值,如果在+一个数就会溢出

3.8 size_t find(char ch, size_t pos=0);

size_t My_String::find(char ch, size_t pos)
{for (size_t i = pos	; i < _size; i++){if (_str[i] == ch){return i;}}return npos;
}

3.9 size_t find(const char* sub, size_t pos = 0);

size_t My_String::find(const char* sub, size_t pos)
{char* p = strstr(_str + pos, sub);return p - _str;
}

3.10 拷贝构造函数 My_String(const My_String& str);

My_String::My_String(const My_String& str)
{_str = new char[str._capacity + 1];_size = str._size;_capacity = str._capacity;strcpy(_str, str._str);
}

3.11赋值函数 My_String& operator=(My_String s);

My_String& My_String::operator=(My_String s)
{if (this != &s) {char* temp = new char[s._capacity + 1];strcpy(temp, s._str);delete[] _str;_str = temp;_size = s._size;_capacity = s._capacity;}return *this;
}

3.12 My_String substr(size_t pos = 0, size_t len = npos);

My_String My_String::substr(size_t pos, size_t len)
{if (len > _size - pos){My_String sub(_str + pos);return sub;}else{My_String sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += pos + i;}return sub;}
}

4.运算符重载

这 里只重载+=比较有意义就先重载这一个

My_String& My_String::operator+=(char ch)
{push_back(ch);return *this;}My_String& My_String::operator+=(const char* str)
{append(str);return *this;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
加上const以后就不再报错


5.比较运算符 重载

bool My_String::operator<(const My_String& s) const
{return strcmp(_str,s._str) < 0;
}bool My_String::operator>(const My_String& s) const
{return !(*this <= s._str);
}bool My_String::operator<=(const My_String& s) const
{return *this < s || *this == s;
}bool My_String::operator>=(const My_String& s) const
{return !(*this < s._str);
}bool My_String::operator==(const My_String& s) const
{return strcmp(_str,s._str)==0;
}bool My_String::operator!=(const My_String& s) const
{return !(*this == s._str);
}

6.流插入和提取

void My_String::clear()
{_str[0] = '\0';_size = 0;
}
ostream& operator<<(ostream& out,  My_String& string)
{out << string._str;return out;
}
istream& operator>>(istream& in, My_String& string)
{string.clear();char ch = in.get();while (ch != ' ' && ch != '\n'){string += ch;ch = in.get();}return in;
}

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

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

相关文章

解锁免费数据恢复工具的潜力,找回珍贵数据记忆

数据的分享与存储普遍倾向于电子化形式&#xff0c;这一转变无疑极大地提升了便捷性。然而&#xff0c;电子化存储也伴随着风险&#xff0c;诸如系统崩溃、误删除或外部因素干扰等意外情况&#xff0c;都可能导致宝贵数据的突然丢失。为了预防这一潜在问题&#xff0c;今天我们…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-09-29

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-09-29 在这一期中&#xff0c;我们对大语言模型在软件开发中的跨学科应用的几个工作做简要的介绍。相关内容涵盖软件测试时的问题报告&#xff0c;问题分类&#xff0c;测试生成&#xff0c;和软件测试中的AI应用: …

97、配置 VXLAN 不同子网互访 (分布式网关)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、基础配置SW1SW2IGP IS-IS 二、VXLAN1.引入库 总结 前言 一、基础配置 SW1 vlan 10 vlan 20interface GigabitEthernet0/0/1port link-type accessport de…

【一篇文章理解Java中多级缓存的设计与实现】

文章目录 一.什么是多级缓存&#xff1f;1.本地缓存2.远程缓存3.缓存层级4.加载策略 二.适合/不适合的业务场景1.适合的业务场景2.不适合的业务场景 三.Redis与Caffine的对比1. 序列化2. 进程关系 四.各本地缓存性能测试对比报告(官方)五.本地缓存Caffine如何使用1. 引入maven依…

【Python】PyJWT:轻松实现 JSON Web Token (JWT) 网络令牌的生成与验证

PyJWT 是一个用 Python 实现的轻量级库&#xff0c;用于处理 JSON Web Token (JWT)。JWT 是一种安全的方式&#xff0c;用来表示双方之间经过签名的令牌&#xff0c;通常用于认证和授权场景。PyJWT 简化了 JWT 的生成和验证过程&#xff0c;使得开发者能够轻松地在 Python 项目…

Python | Leetcode Python题解之第443题压缩字符串

题目&#xff1a; 题解&#xff1a; class Solution:def compress(self, chars: List[str]) -> int:def reverse(left: int, right: int) -> None:while left < right:chars[left], chars[right] chars[right], chars[left]left 1right - 1n len(chars)write lef…

基于php摄影门户网站

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

Verilog:实例数组(重复实例化的快捷方法)

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 前言 谈到重复实例化&#xff0c;一般都会想到for generate结构&#xff0c;但其实有一种更加简单的语法&#xff0c;只是使用的人不多&#xff0c;它就是实例数…

JavaScript 使用 Graham 扫描的凸包(Convex Hull using Graham Scan)

先决条件&#xff1a; 如何检查两个给定的线段是否相交&#xff1f; c https://blog.csdn.net/hefeng_aspnet/article/details/141713655 java https://blog.csdn.net/hefeng_aspnet/article/details/141713762 python https://blog.csdn.net/hefeng_aspnet/article/details/…

智能监控,守护绿色能源:EasyCVR在电站视频监控中心的一站式解决方案

随着科技的飞速发展&#xff0c;视频监控技术在社会安全、企业管理及智慧城市建设等领域中扮演着越来越重要的角色。特别是在电力行业中&#xff0c;电站作为能源供应的关键设施&#xff0c;其安全性和稳定性至关重要。传统的人工监控方式已难以满足现代电站复杂多变的运行需求…

基于SpringBoot+Vue+MySQL的甜品店管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 在数字化浪潮的推动下&#xff0c;甜品店行业也面临着转型与升级的需求。传统的线下经营模式已难以满足现代消费者对于便捷、高效购物体验的追求。为了提升运营效率、优化顾客体验&#xff0c;我们设计了一款基于SpringBoot后端…

Ubuntu 16.04安装填坑记录

一. 问题描述&#xff1a; &#xff08;1&#xff09;Ubuntu 16.04使用USB启动盘安装时&#xff0c;出现"try ubuntu without installation"或“install ubuntu”选择&#xff0c;Enter选择安装后&#xff0c;显示器黑屏无任何显示。 原因分析&#xff1a; 显示黑…

遥感图像变换检测实践上手(TensorRT+UNet)

目录 简介 分析PyTorch示例 onnx模型转engine 编写TensorRT推理代码 main.cpp测试代码 小结 简介 这里通过TensorRTUNet&#xff0c;在Linux下实现对遥感图像的变化检测&#xff0c;示例如下&#xff1a; 可以先拉去代码&#xff1a;RemoteChangeDetection 分析PyTorch示…

网络攻击DDOoS的原理、攻击手段及防范措施详解

一、DDoS的原理 1. 原理 DDoS&#xff08;分布式拒绝服务攻击&#xff09;是利用大量的僵尸主机对受害者发起攻击&#xff0c;从而造成受害者的资源被耗尽无法为合法用户提供服务。DDoS一般采用三级结构&#xff0c;包括&#xff1a; 攻击者&#xff1a;攻击指令的发起方僵尸…

【鸿蒙HarmonyOS NEXT】数据存储之分布式键值数据库

【鸿蒙HarmonyOS NEXT】数据存储之分布式键值数据库 一、环境说明二、分布式键值数据库介绍三、示例代码加以说明四、小结 一、环境说明 DevEco Studio 版本&#xff1a; API版本&#xff1a;以12为主 二、分布式键值数据库介绍 KVStore简介&#xff1a; 分布式键值数据库…

OpenHarmony(鸿蒙南向)——平台驱动指南【DAC】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 概述 功能简介 DAC&#xff08;Digital to Analog Converter&…

Python办公自动化之Word

在现代办公环境中&#xff0c;自动化无疑是提升工作效率的关键。特别是处理文档的工作&#xff0c;很多人可能花费大量时间在重复性任务上。那么&#xff0c;有没有一种方法可以让我们用 Python 来自动化 Word 文档的操作呢&#xff1f;今天&#xff0c;我们来聊聊如何用 Pytho…

AI Agent应用出路到底在哪?

1 Agent/Function Call 的定义 Overview of a LLM-powered autonomous agent system&#xff1a; Agent学会调用外部应用程序接口&#xff0c;以获取模型权重中缺失的额外信息&#xff08;预训练后通常难以更改&#xff09;&#xff0c;包括当前信息、代码执行能力、专有信息源…

Docker安装与应用

前言 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言开发。Docker 可以让开发者打包他们的应用以及依赖包到一个轻 量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互 之间…

大语言模型之LlaMA系列- LlaMA 2及LLaMA2_chat(上)

LlaMA 2是一个经过预训练与微调的基于自回归的transformer的LLMs&#xff0c;参数从7B至70B。同期推出的Llama 2-Chat是Llama 2专门为对话领域微调的模型。 在许多开放的基准测试中Llama 2-Chat优于其他开源的聊天模型&#xff0c;此外Llama 2-Chat还做了可用性与安全性评估。 …