简单模拟一个string类的实现。
myString.h
#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;
};
myString.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
#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 删除。