【C++--string模拟实现】

news2024/12/23 1:08:48

一、基本思路

新建一个项目,在项目中创建头文件string.h 源文件string.cpp

在头文件中,先定义一个新的命名空间(为了防止与库中的string发生冲突),命名空间的名字可以按照自己意愿来命名。

接下来就可以在命名空间中来模拟实现string类辣

在实现的过程中可以多查查string::operator+= - C++ Reference (cplusplus.com)

了解函数功能,然后再去实现 

【1】确定成员变量: size_t _size; size_t _capacity; char* _str;

【2】成员函数模拟实现

(1)构造和析构函数

		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_size + 1];
		    my_strcpy(_str, str);//完成初始化工作
		}
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
			std::cout << "~string()" << std::endl;
		}

(2)size()和capacity()

		size_t size()const
		{
			return _size;
		}
		size_t capacity()const
		{
			return _capacity;
		}

(3)operator[ ]重载

		char& operator[](size_t pos)
		{
			assert(pos <= _size);
			return _str[pos];
		}

(4)reserve()

		void reserve(size_t n = 0)
		{
			char* tmp = new char[n];//在堆区开辟空间,出函数不会销毁
			my_strcpy(tmp, _str);//由于有的vs使用strcpy会报错,所以可以用自己实现的strcpy
			delete[] _str;
			_str = tmp;
			_capacity = n;
		}

(5)push_back()

		void push_back(char c)
		{
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 6 : _capacity * 2);
			}
			_str[_size] = c;
			_size++;
			_str[_size] = '\0';
		}

(6)operator+=的实现

		string& operator+= (char c)
		{
			push_back(c);
			return *this;
		}
		string& operator+= (const char* s)
		{
			size_t len = strlen(s);
			if (_size + len > _capacity)
			{
				reserve(_size + len+10);
			}
			append(s);
			return *this;
		}

(7)append()

		string& append(const char* s)
		{
			size_t len = strlen(s);
			if (_size + len > _capacity)
			{
				reserve(_size + len + 10);
			}
			my_strcpy(_str + _size, s);
			return *this;
		}

(8)c_str()

		const char* c_str()const
		{
			return _str;
		}

(9)operator<<

这个函数得在类外实现,因为在类内实现的话,默认第一个参数是this,那么在实际使用的时候对象名就得写在ostream的左边,与我们常规写法不一样。

由于库中的_str是私有成员,因此可以通过调用函数c_str来获取_str

std::ostream& operator<<(std::ostream& os, const abl::string& str)
{
	os << str.c_str() ;
	return os;
}

(10)拷贝构造

		//现代写法
	string(const string& s)
		:_str(nullptr)
		,_size(0)
		,_capacity(0)
	{
		string tmp(s._str);//调用默认构造函数string(const char* str = "")
		swap(tmp);//this可能没有初始化,析构的时候就会报错,因此要写参数初始化列表
	}
		//string(const string& s)
		//{
		//	_str = new char[s._capacity + 1];
		//	memcpy(_str, s._str, s._size);
		//	_size = s._size;
		//	_capacity = s._capacity;
		//}

(11)insert

		string& insert(size_t pos, size_t n, char c)
		{
			assert(pos <= _size);
			if (_size + n > _capacity)
			{
				reserve(_size + n);
			}
			size_t end = _size+n;
			for (; end>=pos+n; end--)
			{
				//abcd  size==4   pp  n==2  end==6  end-n==4
				_str[end] = _str[end-n];
			}
			for (size_t i = 0; i < n; i++)
			{
				_str[pos + i] = c;
			}
			_size += n;
			return *this;

		}
		string& insert(size_t pos, const char* s, size_t n)
		{
			assert(pos <= _size);
			size_t len = strlen(s);
			if (_size + n > _capacity)
			{
				reserve(_size + n);
			}
			size_t end = _size + n;
			for (; end >= pos + n; end--)//当pos==0时,end>=pos恒成立,因为end为size_t类型,不可能是负数
			{
				//abcd  size==4   pp  n==2  end==6  end-n==4
				_str[end] = _str[end - n];
			}
			for (size_t i = 0; i < n; i++)
			{
				_str[pos + i] = s[i];
			}
			_size += n;
			return *this;
		}

二、完整代码

1、string.h
#pragma once
#include <assert.h>
#include <cstring>
#include <iostream>
#include <stdio.h>
//#include<string.h>
void my_strcpy(char* dest, const char* src) {
	while (*src != '\0') {
		*dest++ = *src++;
	}
	*dest = *src;   //拷贝\0
}

namespace abl
{

	class string
	{
		//这里暂时还用不到友元,因为在operator>>中并没有访问string的私有成员
	//friend std::istream& operator>>(std::istream& in, string& s);
	private:
		size_t _size;
		size_t _capacity;
		char* _str;
		static size_t npos;
	public:
		
		typedef char* iterator;
		typedef const char* const_iterator;
		iterator begin()
		{
			return _str;//指向首元素
		}
		iterator end()
		{
			return _str + _size;//指向'\0'
		}
		const_iterator begin()const
		{
			return _str;
		}
		const_iterator end()const
		{
			return _str + _size;
		}
		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_size + 1];
		    memcpy(_str, str,_size+1);//完成初始化工作
		}
		~string()
		{
			//std::cout <<"::"<< _str << std::endl;
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
			std::cout << "~string()" << std::endl;
		}
		//现代写法
	string(const string& s)
		:_str(nullptr)
		,_size(0)
		,_capacity(0)
	{
		string tmp(s._str);//调用默认构造函数string(const char* str = "")
		swap(tmp);//this可能没有初始化,析构的时候就会报错,因此要写参数初始化列表
	}
		//string(const string& s)
		//{
		//	_str = new char[s._capacity + 1];
		//	memcpy(_str, s._str, s._size);
		//	_size = s._size;
		//	_capacity = s._capacity;
		//}

		void swap(string& tmp)
		{
			std::swap(_str, tmp._str);
			std::swap(_size, tmp._size);
			std::swap(_capacity, tmp._capacity);
		}
		//现代写法
		string& operator= (string& s)
		{
			if (this != &s)
			{
				string tmp(s);//调用拷贝构造(深拷贝)
				swap(tmp);
			}
			return *this;
		}
		size_t size()const
		{
			return _size;
		}
		size_t capacity()const
		{
			return _capacity;
		}
		char& operator[](size_t pos)
		{
			assert(pos <= _size);
			return _str[pos];
		}
		void reserve(size_t n = 0)
		{
			//多留出一个空位给\0
			char* tmp = new char[n+1];//在堆区开辟空间,出函数不会销毁
			my_strcpy(tmp, _str);
			delete[] _str;
			_str = tmp;
			_capacity = n;
			//只改变了capacity,没有改变size,size不变
		}
		void push_back(char c)
		{
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 6 : _capacity * 2);
			}
			_str[_size] = c;
			_size++;
			_str[_size] = '\0';
		}
		string& operator+= (char c)
		{
			push_back(c);
			return *this;
		}
		string& operator+= (const char* s)
		{
			size_t len = strlen(s);
			if (_size + len > _capacity)
			{
				reserve(_size + len+10);
			}
			append(s);
			return *this;
		}
		string& append(const char* s)
		{
			size_t len = strlen(s);
			if (_size + len > _capacity)
			{
				reserve(_size + len + 1);
			}
			memcpy(_str + _size, s,len+1);
			_size += len;
			return *this;
		}
		string& insert(size_t pos, size_t n, char c)
		{
			assert(pos <= _size);
			if (_size + n > _capacity)
			{
				reserve(_size + n);
			}
			size_t end = _size+n;
			for (; end>=pos+n; end--)
			{
				//abcd  size==4   pp  n==2  end==6  end-n==4
				_str[end] = _str[end-n];
			}
			for (size_t i = 0; i < n; i++)
			{
				_str[pos + i] = c;
			}
			_size += n;
			return *this;

		}
		string& insert(size_t pos, const char* s, size_t n)
		{
			assert(pos <= _size);
			size_t len = strlen(s);
			if (_size + n > _capacity)
			{
				reserve(_size + n);
			}
			size_t end = _size + n;
			for (; end >= pos + n; end--)//当pos==0时,end>=pos恒成立,因为end为size_t类型,不可能是负数
			{
				//abcd  size==4   pp  n==2  end==6  end-n==4
				_str[end] = _str[end - n];
			}
			for (size_t i = 0; i < n; i++)
			{
				_str[pos + i] = s[i];
			}
			_size += n;
			return *this;
		}
		//string& erase(size_t pos = 0, size_t len = npos)
		//{

		//}
		bool operator<(string& s)const
		{
			size_t i1 = 0, i2 = 0;//遍历两个字符串4
			while (i1 < _size && i2 < s._size)
			{
				if (_str[i1] < s._str[i2])
				{
					return true;
				}
				else if (_str[i1] > s._str[i2])
				{
					return false;
				}
				else
				{
					i1++;
					i2++;
				}
			}
			//若循环正常进行结束,可能出现的情况:
			//hello hello     return false
			//hellowwww hello return false
			//hello hellowww  return true
			if (_size < s._size)
			{
				return true;
			}
			return false;
		}
		bool operator==(string& s)const
		{
			//std::cout << s._size << std::endl;
			if (_size != s._size)
			{
				return false;
			}
			return memcmp(_str, s._str, _size) == 0;
		}
		bool operator>(string& s)const
		{
			return !((*this < s) || (*this == s));
		}
		bool operator<=(string& s)const
		{
			return !(*this > s);
		}
		bool operator>=(string& s)const
		{
			return !(*this < s);
		}
		//string& operator= (const string& s)
		//{
		//	//开辟新空间,进行拷贝
		//	if (this != &s)//如果两个对象不相同
		//	{
		//		char* tmp = new char[s._capacity + 1];
		//		memcpy(tmp, s._str, s._size);
		//		delete[] _str;
		//		_str = tmp;
		//		_size = s._size;
		//		_capacity = s._capacity;
		//	}
		//	return *this;
		//}
		//void swap(string& str)
		//{
		//	
		//}
		//template<class T>
		//void swap(T m)
		//{
		//	T tmp = m;
		//	m = *this;
		//	*this = tmp;
		//}

		const char* c_str()const
		{
			return _str;
		}
		void clear()
		{
			_str[0] = '\0';
			_size = 0;
		}
	};
}
//std::ostream& operator<<(std::ostream& os, const abl::string& str)
//{
//	os << str._str << std::endl;
//	return os;
//}
size_t abl::string::npos = -1;//静态成员变量必须初始化,并且只能在类体外进行初始化
std::ostream& operator<<(std::ostream& out,const abl::string& str)
{
	for (auto ch : str)
	{
		out << ch;
	}
	//out << str.c_str();
	return out;
}
std::istream& operator>>(std::istream& in, abl::string& s)
{
	s.clear();
	char bucket[128];//相当于一个桶,装满了再往s里边加,减少了开辟空间的次数,充分利用空间
	char c=in.get();
	int i = 0;
	while (c != ' ' && c != '\n')
	{
		bucket[i] = c;
		i++;
		
		if (i == 127)
		{
			bucket[i] = '\0';//operator+=中要计算bucket的长度,以'\0'为终止条件,因此要在最后加上
			s += bucket;
			i = 0;//重新往buckt里边放入数据
		}
		c = in.get();
	}
	if (i != 0)
	{
		bucket[i] = '\0';//...
		s += bucket;
	}

	return in;
}
2、string.cpp
#include <iostream>
#include <cstring>
#include "String.h"
using namespace std;

void test_string1()
{
    abl::string s1("hello world");
    abl::string s2("legacy.cplusplus.com");
    string s3("jdksanxkdsd");
    string s4;
    cout << s3.c_str() << endl;
    cout << s4.c_str() << endl;
    cout << s1.c_str() << endl;
    for (size_t i = 0; i < s1.size(); i++)
    {
        cout << s1[i] << " ";
    }
    cout << endl;
    cout << s2.c_str() << endl;
    abl::string::iterator it = s2.begin();
    while(it!=s2.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
    cout << s2 << endl;
}
void test_string2()
{
    //string s1("hello");
    //cout << s1 << endl;
    //cout << s1.capacity() << endl;

    //abl::string s2("world");
    cout << s2.capacity() << endl;
    //s2.push_back('c');
    //s2.push_back('c');
    //s2.push_back('c');
    //cout << s2 << endl;
    //s2 += 's';
    //cout << s2 << endl;
    //s2 += "good";
    //cout << s2 << endl;
    abl::string s3("hello");
    s3.append(" judy");
    cout << s3 << endl;
    //abl::string s4("helloooo");
    s4 += '\0';
    //cout << s4 << endl;
    //s4 += "wwwwwww";
    //s4.insert(2, 3, 'y');
    //cout << s4 << endl;
    //abl::string s5("hello");
    //s5.insert(2, 5, 'p');
    //cout << s5 << endl;
    //s5.insert(9, "world", 6);
    //cout << s5 << endl;
    //for (auto ch : s5)
    //{
    //    cout << ch;
    //}
    //cout << endl;

    //string s6;
    //cin >> s6;
    //cout << s6 << endl;
    //cin >> s6;
    //cout << s6;
   /* cout << s4.npos << endl;*/
}
void test_string3()
{
    abl::string s1("hello");
    abl::string s2("helloxxxxx");
    //cout << (s2 < s1) << endl;
    abl::string s3("hello");
    //cout << (s1 == s2) << endl;
    //cout << (s1 == s3) << endl;
    cout << (s2 >= s3) << endl;
    cout << (s1 >= s2) << endl;
    cout << (s1 >= s3) << endl;
}
void test_string4()
{
    abl::string s1("helloxxxxxxxxxxx");
    //abl::string s2;
    //s2 = s1;
    //cout << s1 << endl;
    //cout << s2 << endl;
    //s1.append(" world");
    abl::string s2("worldxxx");
    s1 = s2;
    cout << s1 << endl;
    cout << s2 << endl;
}
int main()
{
    //test_string4();
    string s("hello world");
    string::iterator it = s.begin();
    while (it != s.end())
    {
        *it = 'x';
        it++;
    }
    cout << s << endl;
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高斯过程回归 | 高斯过程回归(GPR)区间预测

对于高斯过程,高斯指的是多元高斯分布,过程指的是随机过程。 我们都知道随机过程就是指函数的分布,那么多元高斯分布实际上应该是指无限元的高斯分布。 协方差函数也称为核函数,是高斯过程回归的重点。核函数的选取方式有很多,包括径向基函数(高斯核函数)、线性核函数、…

C++相关练习及详细讲解

目录 题1&#xff1a;输出数组中第k小的数在数组内找出查找数字在该数组第一次出现的索引 题1&#xff1a;输出数组中第k小的数 题目描述&#xff1a; 给定一个数组arr 输出数组中第k小的数 如果不存在 输出-1 输入格式&#xff1a; 第一行输入一个数字n 代表数组arr大小 第二…

S32K324 UDS Bootloader开发-下位机篇-Bootload软件(1)

文章目录 前言启动过程Bootloader开发链接文件编译文件跳转函数CAN收发相关发送接收初始化及使能CAN周期函数总结前言 上一篇文章介绍了S32K324 -UDS Bootlodaer开发中的需求,本文根据需求开发Bootloader软件。 本文参考NXP官网的S32K324 UBL,其中有一些Bug,也有一些和上位机…

C++ 实现红黑树

红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或 Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路 径会比其他路径长出俩倍&#xff0c;因…

SMART PLC开放式以太网通信(UDP通信)

西门子S7-200 SMART PLC不仅支持开放式以太网通信,还支持MODBU-RTU,以及ModbusTcp通信,详细内容请参考下面文章: MODBUS-RTU主站通信 【精选】PLC MODBUS通信优化、提高通信效率避免权限冲突(程序+算法描述)-CSDN博客文章浏览阅读2.5k次,点赞5次,收藏10次。MODBUS通讯…

Ubuntu 20.04源码安装git 2.35.1

《如何在 Ubuntu 20.04 上从源代码安装 Git [快速入门]》和《如何在 Ubuntu 20.04 上安装 Git》是我参考的博客。 https://git-scm.com/是git官网。 lsb_release -r看到操作系统版本是20.04。 uname -r看到内核版本是5.4.0-156-generic。 sudo apt update更新一下源。 完…

操作系统复习(3)处理机调度与死锁

一、概述 1.1了解调度的层次 调度是指&#xff0c;在一个队列中&#xff0c;按照某种方法&#xff08;算法&#xff09;&#xff0c;选择一个合适的个体的过程。进程调度的功能就是按一定策略、动态地把CPU分配给处于就绪队列中的某一进程&#xff0c;并使之执行。 作业调度&…

设置DevC++支持c++11标准

1.点击编译选项 2. 设置语言标准 3.点击确认 4.测试代码 使用auto成功 测试&#xff01;

【LeetCode】第 370 场周赛

100115. 找到冠军 I 一场比赛中共有 n 支队伍&#xff0c;按从 0 到 n - 1 编号。 给你一个下标从 0 开始、大小为 n * n 的二维布尔矩阵 grid 。对于满足 0 < i, j < n - 1 且 i ! j 的所有 i, j &#xff1a;如果 grid[i][j] 1&#xff0c;那么 i 队比 j 队 强 &…

该酷的酷该飒的飒~质感满满的羊羔绒皮外套

皮毛一体材质柔软舒适 保暖性能极佳 冬天穿也不惧严寒的哦 宽松版型&#xff0c;对身材的包容性很强 外套的细节处理也非常出色&#xff0c;车缝线整齐 纽扣和拉链质量也是很不错的哟

鼠标加速不一定都是好事,有时是适得其反,如在游戏当中

如果你玩游戏&#xff0c;你会想在Mac上禁用鼠标加速。这是因为虽然鼠标加速可能很好&#xff0c;但它可能会导致鼠标光标速度不一致&#xff0c;这在游戏中并不理想。 简单地说&#xff0c;如果macOS检测到你正在以特定的速度或强度移动鼠标&#xff0c;鼠标指针加速会提高光…

PivotNet:Vectorized Pivot Learning for End-to-end HD Map Construction

参考代码&#xff1a;BeMapNet。PS&#xff1a;代码暂未放出&#xff0c;关注该仓库动态 动机和主要贡献 在MapTR系列的算法中将单个车道线建模为固定数量的有序点集&#xff08;对应下图Evenly-based&#xff09;&#xff0c;这样的方式对于普通道路场景具备一定适应性。但是…

深度好文|听懂这些逻辑,你会越变越好。

哈喽&#xff0c;大家好&#xff0c;我是雷工。 最近看了一篇文章&#xff0c;噱头很大&#xff0c;说是手把手的教你&#xff0c;如何从一个普通人&#xff0c;成长为身价千万的中产。 这种话我肯定是不信的&#xff0c;要么标题党&#xff0c;要么割韭菜&#xff0c;千万的中…

048基于web+springboot的校园资料分享平台

欢迎大家关注&#xff0c;一起好好学习&#xff0c;天天向上 文章目录 一项目简介技术介绍 二、功能组成三、效果图四、 文章目录 一项目简介 本校园资料分享平台有管理员和用户两个角色。管理员功能有个人中心&#xff0c;学生管理&#xff0c;资料分享管理&#xff0c;资源分…

【JVM】JDBC案例打破双亲委派机制

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 JVM 打破双亲委派机制&#xff08;JDBC案例…

使用springBoot+Redis实现分布式缓存

使用springBootRedis实现分布式缓存 1. 添加redis框架 依赖 2. 配置redis连接信息 #redis 连接的配置信息 spring.redis.database15 spring.redis.port6379 spring.redis.host82.157.236.116 # 可省略 spring.redis.lettuce.pool.min-idle5 spring.redis.lettuce.pool.max-id…

QT进度条 QProgressDialog基础、高级和样式表使用详解

一、基础使用 QProgressDialog是Qt中的一个类&#xff0c;用于显示一个进度条和一个取消按钮&#xff0c;让用户可以在长时间的操作中看到进度&#xff0c;并且可以随时取消。QProgressDialog的基本用法是创建一个对象&#xff0c;设置最小值和最大值&#xff0c;然后在循环中…

多态 多继承的虚表深度剖析 (3)

&#x1f4af; 博客内容&#xff1a;多态 &#x1f600; 作  者&#xff1a;陈大大陈 &#x1f680; 个人简介&#xff1a;一个正在努力学技术的准C后端工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎私信&#xff01; &#x1f496; 欢迎大家&#xff1a;这里是CSD…

加法运算、 || 、 赋值运算

一、加法运算 在这里插入图片描述 二、&& || 三、赋值运算 四、js类型就八种&#xff1a; 五、css权重、 六&#xff1a;布局&#xff0c;尽量使用块盒。 七、小数精度存储的问题&#xff1a;存的不精确&#xff0c;算的肯定也是有问题的。 八、找单身狗算法题…

STM32G030F6P6 芯片实验 (二)

STM32G030F6P6 芯片实验 (二) Hello World - GPIO LED 尝试了下, 从 0 开始建 MDK HAL M0plus Project, 成功点亮 LED了。 但是 ST-LINK跑着跑着, 码飞了! 不知飞哪去了。 只好拿 MX 建了个 MDK Base。 呼叫 SysTick HAL_Delay(), 切换 LED。 基本上都是一样的用法, 只是换…