news 2026/1/7 6:14:20

串的代码实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
串的代码实现

前言

最近期末临近,我不得不分出我宝贵的时间去应对那该死的期末考试,我宝贵的清晨无法完整地投入到代码中去让我感觉十分沮丧,今天在休息的时候了解到智谱开源了他们家的auto GLM大模型,这是什么东西呢,它是一种智能手机Ai模型,可以直接利用语音或者文字指令命令AI帮助在手机上操作的开源程序,比如说点外卖、对比各大带货网站上对应商品的价格等等,经过豆包手机的战败以后,智谱接踵而来,我相信ai的时代已然降临。

今天上午我要完成串的代码整理,然后下午完成两道对应的题目,顺便学一下java应付考试,然后学习一下概数,具体计划细节下午再商讨。

代码

#include<iostream> #include<cstring> using namespace std; class String { private: char* str; size_t length;//size_t是专门为长度准备的变量类型 public: String();//初始化字符串为空串 String(const char* s);//初始化字符串为传入字符串的副本 ~String(); String(const String& s);//拷贝构造函数 size_t getLength() const;//获取字符串长度 char operator[] (size_t index) const;//用运算符重载实现获取字符串的索引 String &operator= (const String& s);//赋值运算符的重载 bool operator==(const String& s) const;//等于运算符重载 bool operator!=(const String& s) const;//不等于运算符重载 String copy() const;//字符串的拷贝 String operator+(const String& s) const;//拼接字符串运算符的重载 friend ostream& operator<<(ostream& out, const String& s);//友元函数用来输出字符串 }; String::String() {//字符串的创建 length = 0; str = new char[1]; str[0] = '\0';//只有结束符,那么这就是一个空的字符串 } //字符串的创建2 String::String(const char* s) {//添加const保证在这个函数内部不会改变s的值 length = strlen(s);//这里s仅是字符串,所以只能用strlen求长度 str = new char[length+1]; strcpy_s(str, length + 1, s); } //字符串的销毁 String::~String() { delete[] str; } //拷贝构造函数 String::String(const String& s) {//用已经创建的对象来初始化对象 length = s.length; str = new char[length + 1]; strcpy_s(str, length + 1,s.str); } //获取字符串的长度 size_t String::getLength() const {//const代表函数内部不能改变成员变量 return length; } //索引的符号重载 char String::operator[](size_t index) const { return str[index]; } //赋值符号的重载 String& String::operator=(const String& s) {//返回值类型是对象引用,目的是节省内存,不会在函数内部生成一个新的对象来操作 if (this != &s) {//避免自赋值:s1=s1,this代表需要被赋值的String类对象,然后s代表待传入的或者是把值赋给别人的String类对象 delete[] str; length = s.length;//这里s是String类对象,所以可以直接调用类内的成员变量 str = new char[length + 1]; strcpy_s(str, length + 1, s.str);//这里s作为String类对象,依然使用类内的成员变量 } return *this;//返回包含字符串内容和长度的String类对象 } //等于运算符的重载 bool String::operator==(const String& s) const{ return strcmp(str, s.str) == 0;//strcmp函数逐个比较两个字符串中字符的大小,然后如果等于0,则代表相等,那么得1,返回 } //不等于运算符的重载 bool String::operator!=(const String& s) const{ return strcmp(str, s.str) != 0; } //字符串的拷贝 String String::copy() const{ return *this;//这里原本是报错的,为什么加了拷贝构造函数以后,就不报错啦??? } //串的拼接 String String::operator+(const String& s) const{ String result; result.length = length + s.length; result.str = new char [result.length + 1];//这里char代表申请的是一个result.length + 1长度的char类型的连续的内存 //而如果是char*,那就是申请如此数量的指针,这些指针存放在一个数组里,每一个指针指向一个字符串。 strcpy_s(result.str, result.length + 1, str);//代表将str复制给result strcat_s(result.str, result.length + 1, s.str);//代表将s复制一份,拷贝到result后面 return result; } //输出字符串 ostream& operator<<(ostream& out, const String& s) { out << s.str; return out; } int main() { String s("520"); cout << s.copy() << endl; cout << s + "1314" << endl; cout << (s != "520") << endl; String a , b , c; a = b = c = s; cout << a << b << c << s << endl; }

解释

首先是串的类的实现,这一部分的代码出现了一些我陌生又熟悉的东西,虽然运算符重载,友元函数这些都学过,但不扎实,稍后伴随学习我将同时对这部分知识进行巩固。

在字符串的类的实现中,首先是两个私有类型的成员变量,为存储字符串内容的str,类型是指向char类型的指针,然后是字符串的长度,类型为size_t,这里我着重解释一下,

size_t是用于表示“无符号整数”的类型,专门用来存储对象大小

然后是公共的成员函数,首先是构造函数,一个是默认构造函数,它的作用是初始化字符串为空串,然后是有参构造函数,它的作用是将字符串初始化为传入的字符串,然后是析构函数,然后是拷贝构造函数,这里也解释一下,

拷贝构造函数,作用是利用已经创建的对象来初始化新的对象,格式是:类名(const 类名& 对象名){},主要的应用场景就是函数的传参和函数的返回值,以函数的传参为例,当类的实例化对象作为参数传入函数时,函数内部会生成一个形参,来存储这个对象的值,这个时候就在函数内部拷贝出来一个副本,就相当于已经调用了一次拷贝构造函数。

然后是获取字符串长度的函数,紧接着是一系列运算符的重载,这个部分在类里面有所涉及,但是比较生疏所以咱们也解释一下,char operator[] (size_t index) const;是下标运算符的重载,比赛中用到的比较多,然后如果是想要改变字符串中的字符的话,只需要将这行语句变成

char& operator[] (size_t index) ;就行,然后后面的赋值运算符的重载,比赛中用不到,后面的相等和不等运算符的重载,比赛中常常用到,另外后面的拼接运算符,比赛中用它来把两个字符串拼起来,最后的输出重载:friend ostream& operator<<(ostream& out, const String& s);也是常用的,写了它,比赛中printf(s.str)这样的语句就可以写成cout<<s;,非常节省时间。

class String { private: char* str; size_t length;//size_t是专门为长度准备的变量类型 public: String();//初始化字符串为空串 String(const char* s);//初始化字符串为传入字符串的副本 ~String(); String(const String& s);//拷贝构造函数 size_t getLength() const;//获取字符串长度 char operator[] (size_t index) const;//用运算符重载实现获取字符串的索引 String &operator= (const String& s);//赋值运算符的重载 bool operator==(const String& s) const;//等于运算符重载 bool operator!=(const String& s) const;//不等于运算符重载 String copy() const;//字符串的拷贝 String operator+(const String& s) const;//拼接字符串运算符的重载 friend ostream& operator<<(ostream& out, const String& s);//友元函数用来输出字符串 };
重载函数比赛必要性核心目的
operator[]必吃快速取 / 改字符
operator==必吃比较字符串是否相等
operator+必吃拼接字符串
operator<<必吃方便输出
其他重载不用管浪费时间,比赛用不上

然后是成员函数的具体实现,这里面首先是字符串的创建,第一个是初始化字符串为空串的构造函数,首先将length赋值为0,然后是让str指向一个char类型长度为1的内存,将'\0'存进去,这样就形成了一个空串。然后是第二个有参构造函数,将length赋值为传入字符串的长度,然后申请一块长度+1的内存,并让str指向它,然后调用strcpy_s函数,将传入字符串的值传给这个字符串,_s相比没有,设置了目标缓存大小,防止了缓冲区溢出问题。

String::String() {//字符串的创建 length = 0; str = new char[1]; str[0] = '\0';//只有结束符,那么这就是一个空的字符串 } //字符串的创建2 String::String(const char* s) {//添加const保证在这个函数内部不会改变s的值 length = strlen(s);//这里s仅是字符串,所以只能用strlen求长度 str = new char[length+1]; strcpy_s(str, length + 1, s); }

然后是字符串的销毁,这里没什么好说的,用new来申请内存,那就用delete来释放内存。

//字符串的销毁 String::~String() { delete[] str; }

然后是拷贝构造函数,它的目的是防止后续赋值操作变成浅赋值,导致两个对象指向同一个地址而双倍析构。实现思路就是将长度传过来,然后申请一个内存,把字符串的内容复制过来。

//拷贝构造函数 String::String(const String& s) {//用已经创建的对象来初始化对象 length = s.length; str = new char[length + 1]; strcpy_s(str, length + 1,s.str); }

然后获取字符串的长度咱们一带而过就好啦。

//获取字符串的长度 size_t String::getLength() const {//const代表函数内部不能改变成员变量 return length; }

然后是一系列运算符的重载,我们需要了解每一步的代码逻辑,方便记忆。

索引运算符重载,返回值类型为char,代表返回目标索引的字符,加入作用域来调用类内私有成员,然后operator作为运算符重载的核心关键字,后面加上任意字符,都可以实现对该字符的重载,这里运算符重载,直接返回数组索引值即可。

//索引的符号重载 char String::operator[](size_t index) const { return str[index]; }

然后是赋值运算符的重载,这里简单解释一下逻辑,返回值为对象引用,代表返回的是对象本身而不是它的拷贝,代表这个函数中没有新生成一个内存来操作,而是直接改变变量本身,函数内部首先判断传入字符串与对象本身是否是同一个,避免自赋值,然后如果不是同一个值,那么首先释放str指向的内存,然后将长度赋值,然后给对象申请一个新的内存空间,并把字符串的内容赋值过来。最终返回*this,this指向整个类也就是变量本身,那*this就是这个对象。

//赋值符号的重载 String& String::operator=(const String& s) {//返回值类型是对象引用,目的是节省内存,不会在函数内部生成一个新的对象来操作 if (this != &s) {//避免自赋值:s1=s1,this代表需要被赋值的String类对象,然后s代表待传入的或者是把值赋给别人的String类对象 delete[] str; length = s.length;//这里s是String类对象,所以可以直接调用类内的成员变量 str = new char[length + 1]; strcpy_s(str, length + 1, s.str);//这里s作为String类对象,依然使用类内的成员变量 } return *this;//返回包含字符串内容和长度的String类对象 }

然后是等于运算符的重载和不等于运算符的重载,返回值都是bool类型,有相等和不相等两种结果,然后作用域,然后operator==和operator!=,后面小括号里面加上const String& s,这是默认的写法,const代表不改变传入字符串的值,String&代表对象引用,直接将字符串本身传入,而不是创建一个新的副本,节省内存,最后加上const,代表这个函数内部不会改变类本身,然后函数内部利用strcmp判断两个字符串即可。

//等于运算符的重载 bool String::operator==(const String& s) const{ return strcmp(str, s.str) == 0;//strcmp函数逐个比较两个字符串中字符的大小,然后如果等于0,则代表相等,那么得1,返回 } //不等于运算符的重载 bool String::operator!=(const String& s) const{ return strcmp(str, s.str) != 0; }

然后字符串的拷贝直接返回对象本身即可。

//字符串的拷贝 String String::copy() const{ return *this;//这里原本是报错的,为什么加了拷贝构造函数以后,就不报错啦??? }

然后是串的拼接,返回值为String类对象,代表包含字符串的内容和长度的类,包含作用域,operator+(const String& s) const,然后函数内部,首先声明类对象result,用它来暂存当前类的字符串的长度和内容,然后利用strcat_s,将传入字符串拷贝到当前字符串的后面。

//串的拼接 String String::operator+(const String& s) const{ String result; result.length = length + s.length; result.str = new char [result.length + 1];//这里char代表申请的是一个result.length + 1长度的char类型的连续的内存 //而如果是char*,那就是申请如此数量的指针,这些指针存放在一个数组里,每一个指针指向一个字符串。 strcpy_s(result.str, result.length + 1, str);//代表将str复制给result strcat_s(result.str, result.length + 1, s.str);//代表将s复制一份,拷贝到result后面 return result; }

最后是输出字符串的函数,它是用于输出String类对象的友元重载函数,函数声明部分,返回值类型是ostream&,是ostream类的引用,目的是支持连续输出,比如cout<<s1<<s2;然后operator<<代表输出运算符重载的函数名,通过cout<<s语句调用这个函数,后面小括号是函数传参,第一个参数是ostream&类型的out变量,它的作用是直接操作输出流对象,传引用避免拷贝,后面是const的 String& 类型的变量s,代表待输出的变量。函数体内部的out代表输出流的对象,我打个比方,如果我们在主函数中写这样一行语句:cout<<s,就相当于operator<<(cout,s),cout和s分别占据这个函数两个参数的位置,out就是作为形参的一个名称,存储cout这个实参,然后函数内部:out<<s.str就好解释啦,就相当于简单的输出语句格式,最后返回out是返回传入的输出流对象out的引用,目的是支持链式输出,至于为什么,咱们就不深究啦。

//输出字符串 ostream& operator<<(ostream& out, const String& s) { out << s.str; return out; }

总结

在我看来串这个数据结构真是无聊,就是把<string>头文件可以实现的功能在类里面利用<cstring>头文件里面的函数来实现,真是无聊。:(

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/25 7:22:27

Rocky Linux下离线安装PaddlePaddle与PaddleOCR

Rocky Linux下离线安装PaddlePaddle与PaddleOCR 在金融、政务或工业制造等对网络安全要求极高的场景中&#xff0c;AI模型的部署往往面临一个现实挑战&#xff1a;生产环境无法接入公网。如何在这种“空气隔离”的条件下&#xff0c;完成像 PaddleOCR 这类依赖复杂的深度学习框…

作者头像 李华
网站建设 2025/12/30 19:37:20

Kotaemon从入门到精通:核心用法与实战

Kotaemon从入门到精通&#xff1a;核心用法与实战 在企业智能化转型的浪潮中&#xff0c;越来越多的组织开始部署基于大语言模型&#xff08;LLM&#xff09;的问答系统。但现实往往不如预期——用户提问“我们合同里关于退款的条款是什么&#xff1f;”系统却凭空编造出一段看…

作者头像 李华
网站建设 2025/12/30 7:17:30

Qwen3-VL-8B与向量数据库构建图文检索系统

Qwen3-VL-8B 向量数据库&#xff1a;构建轻量级图文检索系统的最佳实践 在一家电商公司的内容运营办公室里&#xff0c;设计师小李正为下季度的夏季海报寻找视觉参考。他记得去年有过一张“阳光沙滩白色连衣裙”的主推图&#xff0c;风格极简、色调明亮——但文件名是 final_v…

作者头像 李华
网站建设 2025/12/24 10:31:59

Agent-as-a-Graph:知识图谱助力大模型多智能体系统性能提升15%!

简介 Agent-as-a-Graph是一种创新的知识图谱检索方法&#xff0c;通过将工具和代理表示为知识图谱中的节点和边&#xff0c;解决了大语言模型多智能体系统中代理选择不精准的问题。该方法采用三步检索流程&#xff08;向量搜索、加权重排序、图遍历&#xff09;&#xff0c;在L…

作者头像 李华
网站建设 2025/12/24 11:23:40

Dify本地化部署指南:Docker与镜像安装

Dify本地化部署指南&#xff1a;Docker与镜像安装 在AI应用开发日益普及的今天&#xff0c;如何快速、稳定地构建可落地的智能系统&#xff0c;成为开发者和企业面临的关键挑战。传统的LLM集成方式往往需要大量编码、调试与运维工作&#xff0c;而Dify 的出现改变了这一局面—…

作者头像 李华