ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

造轮子:新建一个属于自己的String类

2019-12-27 17:57:42  阅读:261  来源: 互联网

标签:tmp const String 新建 strlength char str 轮子 MyString


练习造轮子,新建一个属于自己的MyString类

首先来开启检测内存泄漏的函数

在main里添加

_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);

开启内存泄漏检测

int main()
{
    _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF); 

    int *p = new int;
    
    return 0;
}

如上,写一个一定会泄漏的语句,new了一个int指针,运行程序,在output窗口看到输出如下:

发现了4bytes的泄漏(对应int),那么泄漏检测成功

 

新建MyString类,为了完成一个字符串的功能,需要有一个char*的数组保存数据,再为了方便使用定义一个int类型的成员变量来表示当前MyString的长度

接下来定义MyString的构造函数,需要有默认构造函数,带参数的构造函数和拷贝构造函数,

代码如下:

class MyString
{
private:
    char* p;
    int strlength;
public:
    MyString();
    MyString(const char* a);
    MyString(const MyString& a);
    MyString(std::string s);
    ~MyString();
}

接下来完成构造函数和析构函数的实现

MyString::MyString()
{
    strlength = 0;
    p = new char[strlength + 1];
    p[0] = '\0';
}

MyString::~MyString()
{
    delete p;
}

MyString::MyString(const char* a)
{
    strlength = strlen(a);
    p = new char[strlength + 1];
    memcpy(p, a, strlength);
    p[strlength] = '\0';
}

MyString::MyString(const MyString& a)
{
    strlength = a.strlength;
    p = new char[strlength + 1];
    memcpy(p, a.p, strlength);
    p[strlength] = '\0';
}

MyString::MyString(std::string s)
{
    strlength = (int)s.length();
    p = new char[strlength + 1];
    memcpy(p, s.c_str(), strlength);
    p[strlength] = '\0';
}

 

类比std::string,可以定义获得长度、是否为空和获得内容的函数(在类内)

    int length() const { return strlength; };
    bool empty() const { return strlength == 0; };
    const char* c_str() { return p; };    

 

为了查看是否正确,对<<流运算符进行重载,实现输出到屏幕,定义如下:

    friend istream& operator>> (istream& in, MyString& str);
    friend ostream& operator<<(ostream& o, const MyString& a);

实现:

istream& operator>> (istream& in, MyString& str)
{
    in >> str.p;
    str.strlength = strlen(str.p);
    return in;
}

ostream& operator<<(ostream& o, const MyString& str)
{
    o << str.p;
    return o;
}

尝试输入输出一下,在main中添加代码:

    MyString s1;
    MyString s2("qwer");
    MyString s3(s2);
    MyString s4(std::string("1234"));

    cout << "s1:\t" << s1 << "\ts1.length():\t" << s1.length() << "\ts1.empty():\t" << s1.empty() << endl;
    cout << "s2:\t" << s2 << "\ts2.length():\t" << s2.length() << "\ts2.empty():\t" << s2.empty() << endl;
    cout << "s3:\t" << s3 << "\ts3.length():\t" << s3.length() << "\ts3.empty():\t" << s3.empty() << endl;
    cout << "s4:\t" << s4 << "\ts4.length():\t" << s4.length() << "\ts4.empty():\t" << s4.empty() << endl;

    MyString s5;
    cin >> s5;
    cout << s5;

发现程序在cin的时候崩溃了。回头查看代码,发现在>>重载的时候没有为p开辟新的内存空间

加上开辟新的内存空间的代码,修改重载>>如下

istream& operator>> (istream& in, MyString& str)
{
    char* tmp = new char[1024];
    
    in >> tmp;
    str.strlength = strlen(tmp);

    str.p = new char[str.strlength + 1];
    memcpy(str.p, tmp, str.strlength);
    str.p[str.strlength] = '\0';
    delete tmp;
    
    return in;
}

重新运行,程序不崩溃了但是报了内存泄漏

1byte的内存泄漏,对应的是一个char类型的对象。

回看代码,原来是在cin>>s5的时候没有delete s5本来的内存空间,就直接new了一块内存给它,而s5是空值,刚好对应了1byte的内存,泄漏发生在这里,修改重载>>的代码

istream& operator>> (istream& in, MyString& str)
{
    char* tmp = new char[1024];
    
    in >> tmp;
    str.strlength = strlen(tmp);
    if (str.p)
        delete str.p;
    str.p = new char[str.strlength + 1];
    memcpy(str.p, tmp, str.strlength);
    str.p[str.strlength] = '\0';
    delete tmp;
    
    return in;
}

重新运行

这回没有内存泄漏了,继续往下编辑MyString

考虑MyString没有赋值函数,对它的=操作符进行重载

MyString& MyString::operator=(const MyString& a)
{
    if(p)
        delete p;
    strlength = a.strlength;
    p = new char[strlength + 1];
    memcpy(p, a.p, strlength);
    p[strlength] = '\0';

    return *this;
}

在main中进行测试:

    MyString s6 = s2;
    cout << "s6:\t" << s6 << "\ts6.length():\t" << s6.length() << "\ts6.empty():\t" << s6.empty() << endl;

std::string的+=运算符很好用,这里也对它进行重载。=有了,但是好像+还没有写,重载如下

MyString operator+ (const MyString& str1, const MyString& str2) //friend function
{
    MyString ret;
    ret.strlength = str1.strlength + str2.strlength;
    if (ret.p)
        delete ret.p;
    ret.p = new char[ret.strlength + 1];
    memcpy(ret.p, str1.p, str1.strlength);
    memcpy(ret.p + str1.strlength, str2.p, str2.strlength);
    ret.p[ret.strlength] = '\0';

    return ret;
}

测试一下+运算符

MyString hello("hello");
MyString world(std::string(", world!"));
cout << "test operator+\t" << (hello + world) << endl;

 

然后就可以用+和=完成+=操作符 

MyString& MyString::operator+= (const MyString& str)
{
    *this = *this + str;
    return *this;
}

 测试一下

    MyString helloworld = hello;
    helloworld += world;
    cout << "test operator+=\t" << helloworld << endl;

 

下标运算符

char& MyString::operator[] (const int i)
{
    assert(i >= 0 && i <= strlength);
    return p[i];
}

const char& MyString::operator[] (const int i)const
{
    assert(i >= 0 && i <= strlength);
    return p[i];
}

 

字典序排序(用到strcmp函数)

bool operator== (const MyString& str1, const MyString& str2)
{
    return strcmp(str1.p, str2.p) == 0;
}

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

bool operator< (const MyString& str1, const MyString& str2)
{
    return strcmp(str1.p, str2.p) < 0;
}

bool operator<= (const MyString& str1, const MyString& str2)
{
    return strcmp(str1.p, str2.p) <= 0;
}

bool operator> (const MyString& str1, const MyString& str2)
{
    return strcmp(str1.p, str2.p) > 0;
}

bool operator>= (const MyString& str1, const MyString& str2)
{
    return strcmp(str1.p, str2.p) >= 0;
}

测试

 

获得子串(start开始,长度为n的子串)

MyString MyString::substr(int start, int n)
{
    assert(start + n <= strlength);
    MyString ret;
    ret.strlength = n;
if(ret.p)
delete ret.p; ret.p = new char[n + 1]; memcpy(ret.p, p + start, n); ret.p[n] = '\0'; return ret; }

往后添加字符串(跟+=一样)

MyString& MyString::append(const MyString& str)
{
    *this += str;
    return *this;
}

在中间添加

MyString& MyString::insert(int pos, const MyString& str)
{
    assert(pos >= 0 && pos <= strlength);

    strlength += str.length();
    char* tmp = new char[strlength + 1];
    memcpy(tmp, p, pos);
    memcpy(tmp + pos, str.p, str.length());
    memcpy(tmp + pos + str.length(), p + pos, length() - pos);
    
    tmp[strlength] = '\0';
    if (p)
        delete p;
    p = new char[strlength + 1];
    memcpy(p, tmp, strlength + 1);
    delete tmp;

    return *this;
}

替换字符串(在pos位置,将str的len长度替换原字符串)

MyString& MyString::assign(int pos, const MyString& str, int len)
{
    assert(pos >= 0 && pos <= strlength);

    if (len > str.length() || len < 0)
        len = str.length();

    strlength = pos + len;
    char* tmp = new char[strlength + 1];
    memcpy(tmp, p, pos);
    memcpy(tmp + pos, str.p, len);
    tmp[strlength] = '\0';

    if (p)
        delete p;

    p = new char[strlength + 1];
    memcpy(p, tmp, strlength + 1);
    delete tmp;

    return *this;
}

擦除中间长度为len的字符串

MyString& MyString::erase(int pos, int len)
{
    assert(pos >= 0 && pos <= strlength);
    if (pos + len > strlength || len < 0)
        len = strlength - pos;

    strlength -= len;
    char* tmp = new char[strlength + 1];
    memcpy(tmp, p, pos);
    memcpy(tmp + pos, p + pos + len, strlength - pos);
    tmp[strlength] = '\0';

    if (p)
        delete p;

    p = new char[strlength + 1];
    memcpy(p, tmp, strlength + 1);
    delete tmp;

    return *this;
}

清空字符串

MyString& MyString::clear()
{
    strlength = 0;
    if (p)
        delete p;

    p = new char[strlength + 1];
    p[strlength] = '\0';

    return *this;
}

测试一堆:

 

测试完成,暂时完成了造轮子的过程~

 

完整代码如下:

MyString.h

#pragma once

#include <string>
#include <iostream>
#include <assert.h>

using namespace std;

class MyString
{
private:
    char* p;
    int strlength;
public:
    MyString();
    MyString(const char* a);
    MyString(const MyString& a);
    MyString(std::string s);
    ~MyString();

    int length() const { return strlength; };
    bool empty() const { return strlength == 0; };
    const char* c_str() { return p; };
            
    MyString& operator=(const MyString& a);
    MyString& operator+= (const MyString& str);

    MyString substr(int start, int n);
    MyString& append(const MyString& str);
    MyString& insert(int pos, const MyString& str);
    MyString& assign(int pos, const MyString& str, int len);
    MyString& erase(int pos, int len);
    MyString& clear();

    friend istream& operator>> (istream& in, MyString& str);
    friend ostream& operator<<(ostream& o, const MyString& a);
    friend MyString 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);
    friend bool operator>= (const MyString& str1, const MyString& str2);

    char& operator[] (const int i);
    const char& operator[] (const int i)const;
};

MyString.cpp

#include "pch.h"
#include <iostream>

#include "MyString.h"

using namespace std;

MyString::MyString()
{
    strlength = 0;
    p = new char[strlength + 1];
    p[0] = '\0';
}

MyString::~MyString()
{
    delete p;
}

MyString::MyString(const char* a)
{
    strlength = strlen(a);
    p = new char[strlength + 1];
    memcpy(p, a, strlength);
    p[strlength] = '\0';
}

MyString::MyString(const MyString& a)
{
    strlength = a.strlength;
    p = new char[strlength + 1];
    memcpy(p, a.p, strlength);
    p[strlength] = '\0';
}

MyString::MyString(std::string s)
{
    strlength = (int)s.length();
    p = new char[strlength + 1];
    memcpy(p, s.c_str(), strlength);
    p[strlength] = '\0';
}

MyString& MyString::operator=(const MyString& a)
{
    if(p)
        delete p;
    strlength = a.strlength;
    p = new char[strlength + 1];
    memcpy(p, a.p, strlength);
    p[strlength] = '\0';

    return *this;
}

MyString& MyString::operator+= (const MyString& str)
{
    *this = *this + str;
    return *this;
}

istream& operator>> (istream& in, MyString& str)
{
    char* tmp = new char[1024];
    
    in >> tmp;
    str.strlength = strlen(tmp);
    if (str.p)
        delete str.p;
    str.p = new char[str.strlength + 1];
    memcpy(str.p, tmp, str.strlength);
    str.p[str.strlength] = '\0';
    delete tmp;
    
    return in;
}

ostream& operator<<(ostream& o, const MyString& str)
{
    o << str.p;
    return o;
}

MyString operator+ (const MyString& str1, const MyString& str2) //friend function
{
    MyString ret;
    ret.strlength = str1.strlength + str2.strlength;
    if (ret.p)
        delete ret.p;
    ret.p = new char[ret.strlength + 1];
    memcpy(ret.p, str1.p, str1.strlength);
    memcpy(ret.p + str1.strlength, str2.p, str2.strlength);
    ret.p[ret.strlength] = '\0';

    return ret;
}

bool operator== (const MyString& str1, const MyString& str2)
{
    return strcmp(str1.p, str2.p) == 0;
}

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

bool operator< (const MyString& str1, const MyString& str2)
{
    return strcmp(str1.p, str2.p) < 0;
}

bool operator<= (const MyString& str1, const MyString& str2)
{
    return strcmp(str1.p, str2.p) <= 0;
}

bool operator> (const MyString& str1, const MyString& str2)
{
    return strcmp(str1.p, str2.p) > 0;
}

bool operator>= (const MyString& str1, const MyString& str2)
{
    return strcmp(str1.p, str2.p) >= 0;
}

char& MyString::operator[] (const int i)
{
    assert(i >= 0 && i <= strlength);
    return p[i];
}

const char& MyString::operator[] (const int i)const
{
    assert(i >= 0 && i <= strlength);
    return p[i];
}

MyString MyString::substr(int start, int n)
{
    assert(start + n <= strlength);
    MyString ret;
    ret.strlength = n;
    if (ret.p)
        delete ret.p;
    ret.p = new char[n + 1];
    memcpy(ret.p, p + start, n);
    ret.p[n] = '\0';

    return ret;
}

MyString& MyString::append(const MyString& str)
{
    *this += str;
    return *this;
}

MyString& MyString::insert(int pos, const MyString& str)
{
    assert(pos >= 0 && pos <= strlength);

    strlength += str.length();
    char* tmp = new char[strlength + 1];
    memcpy(tmp, p, pos);
    memcpy(tmp + pos, str.p, str.length());
    memcpy(tmp + pos + str.length(), p + pos, length() - pos);
    
    tmp[strlength] = '\0';
    if (p)
        delete p;
    p = new char[strlength + 1];
    memcpy(p, tmp, strlength + 1);
    delete tmp;

    return *this;
}

MyString& MyString::assign(int pos, const MyString& str, int len)
{
    assert(pos >= 0 && pos <= strlength);

    if (len > str.length() || len < 0)
        len = str.length();

    strlength = pos + len;
    char* tmp = new char[strlength + 1];
    memcpy(tmp, p, pos);
    memcpy(tmp + pos, str.p, len);
    tmp[strlength] = '\0';

    if (p)
        delete p;

    p = new char[strlength + 1];
    memcpy(p, tmp, strlength + 1);
    delete tmp;

    return *this;
}

MyString& MyString::erase(int pos, int len)
{
    assert(pos >= 0 && pos <= strlength);
    if (pos + len > strlength || len < 0)
        len = strlength - pos;

    strlength -= len;
    char* tmp = new char[strlength + 1];
    memcpy(tmp, p, pos);
    memcpy(tmp + pos, p + pos + len, strlength - pos);
    tmp[strlength] = '\0';

    if (p)
        delete p;

    p = new char[strlength + 1];
    memcpy(p, tmp, strlength + 1);
    delete tmp;

    return *this;
}

MyString& MyString::clear()
{
    strlength = 0;
    if (p)
        delete p;

    p = new char[strlength + 1];
    p[strlength] = '\0';

    return *this;
}

test.cpp

#include "pch.h"
#include <iostream>

#include "MyString.h"

using namespace std;

int main()
{
    _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF); 

    MyString s1;
    MyString s2("qwer");
    MyString s3(s2);
    MyString s4(std::string("1234"));

    cout << "s1:\t" << s1 << "\ts1.length():\t" << s1.length() << "\ts1.empty():\t" << s1.empty() << endl;
    cout << "s2:\t" << s2 << "\ts2.length():\t" << s2.length() << "\ts2.empty():\t" << s2.empty() << endl;
    cout << "s3:\t" << s3 << "\ts3.length():\t" << s3.length() << "\ts3.empty():\t" << s3.empty() << endl;
    cout << "s4:\t" << s4 << "\ts4.length():\t" << s4.length() << "\ts4.empty():\t" << s4.empty() << endl;

    //MyString s5;
    //cin >> s5;
    //cout << s5;    

    MyString s6 = s2;
    cout << "s6:\t" << s6 << "\ts6.length():\t" << s6.length() << "\ts6.empty():\t" << s6.empty() << endl;

    MyString hello("hello");
    MyString world(std::string(", world!"));
    cout << "test operator+\t" << (hello + world) << endl;

    MyString helloworld = hello;
    helloworld += world;
    cout << "test operator+=\t" << helloworld << endl;

    cout << "test []\t" << helloworld[4] << endl;
    MyString strA("A");
    MyString strAB("AB");
    cout << "test ==\t" << (strA == strAB) << endl;
    cout << "test !=\t" << (strA != strAB) << endl;
    cout << "test <\t" << (strA < strAB) << endl;
    cout << "test <=\t" << (strA <= strAB) << endl;
    cout << "test >\t" << (strA > strAB) << endl;
    cout << "test >=\t" << (strA >= strAB) << endl;

    cout << "test substr\t" << helloworld.substr(2, 3) << endl;
    helloworld.append(MyString("append!"));
    cout << "test append\t" << helloworld << endl;
    helloworld.insert(6, MyString("insert!"));
    cout << "test insert\t" << helloworld << endl;
    helloworld.assign(6, MyString("assign"), 5);
    cout << "test assign\t" << helloworld << endl;
    helloworld.erase(6, 4);
    cout << "test erase\t" << helloworld << endl;
    helloworld.clear();
    cout << "test clear\t" << helloworld << "\thelloworld.empty()\t" << helloworld.empty() << endl;

    return 0;
}

标签:tmp,const,String,新建,strlength,char,str,轮子,MyString
来源: https://www.cnblogs.com/Sseakompp/p/12108671.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有