前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用C++简单的实现一个string类

用C++简单的实现一个string类

原创
作者头像
晨星成焰
修改2024-04-15 15:30:45
2141
修改2024-04-15 15:30:45
举报
文章被收录于专栏:C++入门基础知识

简单模拟一个string类的实现。

头文件

myString.h

代码语言:cpp
复制
#pragma once
//#define _CRT_SECURE_NO_WARNINGS   if  use unsafe cstring function
#include<iostream>
#include <cstring>
#include<cassert>

class myString {
public:
	/*--------------basic-------------------*/
	myString(const char* str = nullptr);
	myString(const myString& str);  //深拷贝
	~myString();
	size_t length() const { return m_size; }
	size_t size() const { return m_size; }
	size_t capacity() const { return m_capacity; }
	const char* c_str()const { return m_data; }
	char* begin() { return m_data; }
	char* end() { return m_data + m_size; }
	const char* begin() const { return m_data; }
	const char* end() const { return m_data + m_size; }

    /*--------------operator--------------*/
	myString& operator=(const myString& str);//重载 = 运算符返回引用是为了支持连续赋值操作,符合C++的语义,并且可以提高性能
	myString operator+(const myString& str);//当你的函数需要返回一个新对象时,应该返回对象本身而不是引用
	myString& operator+=(const myString& str);
	char& operator[](size_t pos);//实现数组访问的运算符重载
	friend std::istream& operator >> (std::istream& cin, myString& str);   // 输入,输出运算符的重载
	friend std::ostream& operator << (std::ostream& cout, myString& str);

	friend bool operator > (const myString& str1, const myString& str2);  // 各类比较重载
	friend bool operator < (const myString& str1, const myString& str2);
	friend bool operator >= (const myString& str1, const myString& str2);
	friend bool operator <= (const myString& str1, const myString& str2);
	friend bool operator == (const myString& str1, const myString& str2);
	friend bool operator != (const myString& str1, const myString& str2);
	

	/*---------------function------------*/
	myString substr(size_t pos, size_t len) const;  ////求子串函数
	void reserve(size_t n);
	void resize(size_t n, char ch);
	void checkExpend(size_t additionalSize);
	void append(const myString& str);
	void append(const char* s);
	void push_back(const char s);
	void pop_back();
	void insert(const char ch, size_t pos);
	void insert(const char* s, size_t pos);
	size_t find(const char* s, size_t index = 0);
	size_t find(const myString& str, size_t index = 0);
	size_t find(const char ch, size_t index = 0);
	void showString();
private:
	char* m_data;
	size_t m_size;
	size_t m_capacity;
	//static const size_t npos;
};

cpp文件

myString.cpp

代码语言:cpp
复制
#include"myString.h"

myString::myString(const char* str) {
	if (str == nullptr) {
		//std::cout << "构造函数赋值为空" << std::endl;
		m_data = new char[1];//对空字符串自动申请存放结束标志'\0'的
		m_data[0] = '\0';
		m_size = 0;
		m_capacity = 1;
	}
	else {
		//std::cout << "构造函数" << std::endl;
		m_size = strlen(str);
		m_capacity = m_size+1;
		m_data = new char[m_size + 1];
		strcpy_s(m_data,m_size+1 ,str);//我们要想对字符串进行增删查改,得先另外开辟一段空间(在堆上)
		                    //再将str指向的字符串拷贝到这段空间:
	}
}

myString::~myString() {
	delete[] m_data;
}

myString::myString(const myString& str)
	:m_data(nullptr)
{
	//m_size = strlen(str.m_data);
	//m_capacity = m_size;
	//myString tmp(str.m_data);
	//std::swap(m_data, tmp.m_data); //另一种写法
	//std::cout<< "深拷贝" << std::endl;
	m_size = strlen(str.m_data);
	m_capacity = m_size+1;
	m_data = new char[m_size + 1];
	strcpy_s(m_data, m_size+1, str.m_data);
}


myString& myString::operator=(const myString& str) {
	if (this == &str) {
		return *this;
	}
	m_size = strlen(str.m_data);
	m_capacity = m_size+1;
	//std::cout << "oper=" << std::endl;
	char* tmp = new char[m_size + 1];//先开空间再释放原空间,减少开空间失败带来的损失
	delete[] m_data;
	m_data = tmp;
	strcpy_s(m_data, m_size + 1, str.m_data);
	return *this;
}

myString myString::operator+ (const myString& str2)
{
	myString tmp;
	delete tmp.m_data;
	tmp.m_size = strlen(m_data) + strlen(str2.m_data);
	tmp.m_data = new char[tmp.m_size + 1];
	tmp.m_capacity = tmp.m_size + 1;
	strcpy_s(tmp.m_data,tmp.m_size+1 ,m_data);
	strcat_s(tmp.m_data, tmp.m_size + 1, str2.m_data); 
	return tmp;
}

myString& myString::operator+=(const myString& s) {
	// 计算新字符串的长度
	size_t newSize = strlen(this->m_data) + strlen(s.m_data) + 1;

	// 分配新的内存来存储新的字符串
	char* newStr = new char[newSize];

	// 将当前对象的字符串复制到新的内存中
	strcpy_s(newStr, newSize,this->m_data);

	// 将参数对象的字符串追加到新的字符串中
	strcat_s(newStr,newSize ,s.m_data);

	// 释放旧的内存
	delete[] this->m_data;

	// 更新当前对象的字符串和大小
	this->m_data = newStr;
	this->m_size = newSize;
	this->m_capacity = newSize + 1;

	return *this;
}


char& myString::operator[](size_t pos)
{
	assert(pos < this->m_size);
	return m_data[pos]; //等价于 *(_str+pos)
}

std::istream& operator >> (std::istream& cin, myString& str){
	const int buffSz = 10000; // 输入缓冲区大小
	char buff[buffSz];
	cin.get(buff, buffSz); // 读到换行或者缓冲区满了

	//分配内存给新string
	char* newData = new char[strlen(buff) + 1];
	strcpy_s(newData, strlen(buff) + 1,buff);

	// 清除旧内存
	if (str.m_data) {
		delete[] str.m_data;
	}

	// 更新string
	str.m_data = newData;
	str.m_size = strlen(buff);
	str.m_capacity = str.m_size + 1;

	return cin;
}

std::ostream& operator << (std::ostream& cout, myString& str) {
	cout << str.m_data ;
	return cout;
}

bool operator > (const myString& str1, const myString& str2)
{
	return strcmp(str1.m_data, str2.m_data) > 0;
}
bool operator < (const myString& str1, const myString& str2)
{
	return strcmp(str1.m_data, str2.m_data) < 0;
}
bool operator >= (const myString& str1, const myString& str2)
{
	return strcmp(str1.m_data, str2.m_data) >= 0;
}
bool operator <= (const myString& str1, const myString& str2)
{
	return strcmp(str1.m_data, str2.m_data) <= 0;
}

bool operator == (const myString& str1, const myString& str2)
{
	return strcmp(str1.m_data, str2.m_data) == 0;
}
bool operator != (const myString& str1, const myString& str2)
{
	return strcmp(str1.m_data, str2.m_data) != 0;
}


myString myString::substr(size_t pos, size_t len) const {
	// 检查 pos 是否在字符串范围内
	if (pos > m_size) {
		throw std::out_of_range("Position out of range");
	}

	// 计算实际的长度,以防 len 超出字符串的长度
	size_t actualLen = std::min(len, m_size - pos);

	// 创建一个新的 myString 对象,用于存储子串
	myString result;
	result.m_data = new char[actualLen + 1]; // 分配内存,+1 是为了存储空字符
	result.m_size = actualLen;
	result.m_capacity = m_size + 1;

	// 复制子串到新对象中
	strncpy_s(result.m_data, actualLen + 1, m_data + pos, actualLen);
	result.m_data[actualLen] = '\0'; // 确保字符串以空字符结尾

	return result;
}

void myString::reserve(size_t n) {
	if (n > this->m_capacity)
	{
		char* tmp = new char[n + 1];
		strcpy_s(tmp,n+1,this->m_data);
		delete[] this->m_data;
		this->m_capacity = n;
	//this->m_size = n ;//扩容扩的是容量
		this->m_data = tmp;
	}
}

void myString::resize(size_t n, char ch) {
	if (n < this->m_capacity) {
		this->m_data[n] = '\0';
		this->m_capacity = n;
		//this->m_size = n - 1;
	}
	else {
		if (n > this->m_capacity) {
			reserve(n);
		}
		memset(this->m_data, ch, n - this->m_size);//从_str 的 _size 处开始初始化,把n-_size个位置初始化为 ch
	}
}

void myString::checkExpend(size_t additionalSize) {
	if (this->m_size + additionalSize >= this->m_capacity) {
		this->m_capacity = this->m_capacity == 0 ? 1 : this->m_capacity;
		// 计算新的容量,确保有足够的空间来存储当前字符串和要添加的字符串
		//reserve(this->m_capacity +1); // 分配次数多但是稳定,额外的1是为了存储字符串结束符'\0'
		reserve(this->m_capacity * 2);// 增加当前容量的两倍,分配次数变少,但是可能浪费空间或者爆空间
	}
}

void myString::append(const myString& st)
{
	size_t additionalSize = strlen(st.m_data);
	checkExpend(additionalSize);
	strcat_s(this->m_data, this->m_capacity, st.m_data);
	this->m_size += additionalSize; // 更新字符串的大小
}

void myString::append(const char* s)
{
	size_t additionalSize = strlen(s);
	checkExpend(additionalSize);
	strcat_s(this->m_data, this->m_capacity, s);
	this->m_size += additionalSize; // 更新字符串的大小
}

void myString::push_back(const char ch)
{
	checkExpend(1);
	this->m_data[this->m_size] = ch;
	this->m_size++;
	this->m_data[this->m_size + 1] = '\0'; // 确保字符串以'\0'结尾
}

void myString::pop_back() {
	if (this->m_size > 0) {
		this->m_data[m_size - 1] = '\0'; // 移除最后一个字符
		this->m_size--;
	}
}

void myString::insert(char ch, size_t pos)
{
	if (pos > this->m_size) {
		throw std::out_of_range("Position out of range");
	}

	//判断是否需要增容
	checkExpend(1);

	int end = this->m_size;
	while (end >= pos)
	{
		this->m_data[end + 1] = this->m_data[end];
		end--;
	}
	this->m_data[pos] = ch;
	this->m_size++;
	this->m_data[this->m_size + 1] = '\0';
}

void myString::insert(const char* s, size_t pos) {
	if (pos > this->m_size) {
		throw std::out_of_range("Position out of range");
	}
		int len = strlen(s);
		//判断是否需要增容
		checkExpend(len);

		int end = this->m_size;
		while (end >= pos)
		{
			this->m_data[end + len] = this->m_data[end];       //把每个字符向后移动len位
			end--;
		}

		for (size_t i = 0; i < len; i++)
		{
			this->m_data[pos + i] = s[i];              //把 s 中的每个字符逐个放到空出来的位置
		}
		this->m_size += len;
		this->m_data[this->m_size + 1] = '\0';
}

//还可以用kmp算法实现find函数,过于复杂遂放弃
size_t myString::find(const char* s, size_t index)
{
	size_t length = strlen(s);
	for (size_t this_index = index; this_index < this->m_size; this_index++)
	{
		if (this->m_data[this_index] == s[0])
		{
			for (int s_index = 0; s_index < length; s_index++)
			{
				if (this->m_data[this_index + s_index] != s[s_index])
					break;
				if (s_index == length - 1)  //匹配字符串
					return this_index;
			}
		}
	}
	return -1;
}

size_t myString::find(const myString& st, size_t index)
{
	size_t length = strlen(st.m_data);
	for (size_t this_index = index; this_index < this->m_size; this_index++)
	{
		if (this->m_data[this_index] == st.m_data[0])
		{
			for (int s_index = 0; s_index < length; s_index++)
			{
				if (this->m_data[this_index + s_index] != st.m_data[s_index])
					break;
				if (s_index == length - 1)  //匹配字符串
					return this_index;
			}
		}
	}
	return -1;
}

size_t myString::find(const char ch, size_t index)
{
	size_t length = 1;
	for (size_t this_index = index; this_index < this->m_size; this_index++)
	{
		if (this->m_data[this_index] == ch)
		{
					return this_index;
		}
	}
	return -1;
}

void myString::showString() {
	std::cout << this->m_data << std::endl;
}

测试

main.cpp

代码语言:cpp
复制
#include<iostream>
#include"Mystring.h"
using namespace std;

int main()
{
	
	cout << "/*--------------basic-------------------*/" << endl;
	myString s1("-s1的构造-");
	myString s2;
	s2 = "-s2的构造-";
	cout << "s2:" << s2 << endl;
	cout <<"s2.size():" << s2.size() << endl;
	cout << "s2.capacity(): " << s2.capacity() << endl;
	myString s3 = s1; //走的深拷贝
	s3[2] = '3';
	cout <<"s3:" << s3 << endl;
	cout << "/*--------------operator--------------*/" << endl;
	if (s3 >= s2) {
		cout <<"if s3>=s2" << "yes" << endl;
	}
	myString s4 = s2 + s3;
	cout <<"s4:" << s4 << endl;
	myString s5 = s2 + s3;
	s5 += s4;
	cout <<"s5:" << s5 << endl;
	cout << "/*---------------function------------*/" << endl;
	s2.reserve(20);
	cout << "s2.size():" << s2.size() << endl;
	cout << "s2.capacity(): " << s2.capacity() << endl;
	s3.append("s3的尾巴");
	cout << "after append s3:" << s3 << endl;
	s5.append(s3);
	cout << "after append s5:" << s5 << endl;

	s2.push_back('!');
	cout << "after push_back s2:" << s2 << endl;  

	myString s6 = "abcd";
	s6.push_back('e');
	cout <<"s6:" << s6 << endl;
	int b=s6.find('b');
	cout <<"b的位置:" << b << endl;
	int cd = s6.find("cd");
	cout << "cd的位置:" << cd << endl;
	s6.insert('c', 2);
	cout <<"after insert c pos 2:\n" << s6 << endl;
	s6.insert('abc', 1);
	cout <<"after insert abc pos 1:\n" << s6 << endl;
	return 0;
}

测试截图:

参考文献:

C++笔试题之String类的实现 https://blog.csdn.net/caoshangpa/article/details/51530482

编写一个String类c++实现 https://blog.csdn.net/qq_40821469/article/details/108913326

C++ 自己实现一个String类 https://zhuanlan.zhihu.com/p/62290636

C++ String类的详解 https://zhuanlan.zhihu.com/p/585153125

C++ 手把手教你写出你自己的String类 https://blog.csdn.net/qq_53268869/article/details/121528154

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 头文件
  • cpp文件
  • 测试
  • 测试截图:
  • 参考文献:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档