• c++在string类源


    一:回想

    (1)c++中的string类是在面试中和笔试中常常考的题目; project代码免费下载 string类的自行实现

    (2)c++中的string类和fstream类合起来是处理外部数据的利器

    (3)string类经经常使用到find find_first_of find_first_not_of find_last_of find_last_not_of substr replace等,以及联合使用来达到java中的split和trim

      (4) 使用friend 不过在类中进行声明的非内部 却能够訪问内部成员的外部函数,并且在外部不再须要friendkeyword;它与成员函数的差别是,friend和外部函数不含有this对象指针;本文用到了const 定义的全局最大值最小值变量(取代#define)

     (5) 有些函数返回的是MyString& 、Char& 等(引用),MyString、Char 等(传值)这得看你返回的对象是函数的局部变量还是全局变量(或者类当前对象成员变量);前者仅仅能返回一个MyString、Char 等;后者强烈建议返回MyString& 、Char& 等(引用);

    (6)有些函数的參数是const MyString& ,有些是MyString& (引用);这是为什么?前者是把外部值传提到子函数内部,且不同意改变;后者是作为函数的返回值传递进去的,返回的结果为函数的处理结果(而不用函数自身返回值了)。

    二:以下是简单的实现了一下string类,參照的是STL源代码,可是自己理解的还是不够深,难免有一些错误,请各位不吝赐教

    (1)MyString.h文件

    #ifndef MYSTRING_H
    #define MYSTRING_H
    #include "MyExcept.h"
    #include <cstring>
    #include <iostream>
    const int INI_MAX = 0x7fffffff;//2^32npos
    const int INI_MIN = 0x80000000;// -2^32
    const int npos = 0xffffffff;// npos
    using namespace std;
    
    class MyString
    {
        public:
        // constructor
        MyString();//
        MyString(const MyString &);//
        MyString(const char *);
        MyString(const size_t,const char);
        // destructor
        ~MyString();
        // attributes
    
        size_t length();// 字符串长度
        bool isEmpty();// 返回字符串是否为空
        const char* c_str();// 返回c风格的trr的指针
        // friend funs
        // read writer operations
        friend ostream& operator<< (ostream&, const MyString&);
        friend istream& operator>> (istream&, MyString&);
        //add operation
        friend MyString operator+(const MyString&,const MyString&);
        // compare operations
        friend bool operator==(const MyString&,const MyString&);
        friend bool operator!=(const MyString&,const MyString&);
        friend bool operator<(const MyString&,const MyString&);
        friend bool operator<=(const MyString&,const MyString&);
        friend bool operator>(const MyString&,const MyString&);
        friend bool operator>=(const MyString&,const MyString&);
        // 成员函数实现运算符重载,事实上一般须要返回自身对象的,成员函数运算符重载会好一些
        // index operation
        char& operator[](const size_t);
        const char& operator[](const size_t)const;
        // =
        MyString& operator=(const MyString&);
        // +=
        MyString& operator+=(const MyString&);
        // +=
        //MyString operator+=(const MyString&); cannot be overloaded
        // 成员操作函数
        // substr
        MyString substr(size_t pos,const size_t n);
        // append
        MyString& append(const MyString&);
        //insert
        MyString& insert(size_t,const MyString&);
        //assign 替换
        MyString& assign(MyString&,size_t,size_t);
        // erase 删除
        MyString& erase(size_t,size_t);
        //find_first_of 查找某一个字符 size_t 是非符号数的,重载
        // 查找在字符串中第一个与str中的某个字符匹配的字符,返回它的位置。
        //搜索从index開始,假设没找到就返回string::npos
        int find_first_of(const char* str,size_t index=0);
        int find_first_of(const char ch,size_t index=0);
        int find_first_of(const MyString &,size_t index=0);
        // 在字符串中查找第一个与str中的字符都不匹配的字符,返回它的位置。搜索从index開始。假设没找到就返回string::nops
        int find_first_not_of(const char* str,size_t index=0);
        int find_first_not_of(const char ch,size_t index=0);
        int find_first_not_of(const MyString&,size_t index=0);
        // swap
        void swap(MyString& lhs,MyString& rhs);
        // replace_all
        MyString& replace_all(const char oldc,const char newc=NULL);
        MyString& replace(size_t index,size_t num1,size_t num2,const char ch);
        //find
        int find(const char* str,size_t index=0);
        int find(const MyString& str,size_t index=0);
        int find(const char ch,size_t index=0);
    
    
        //private
        private:
        char *p_str;
        size_t strLength;
    };
    
    
    #endif // MYSTRING_H

    (2)MyString.cpp文件

    #include "MyString.h"
    #include <cassert>
    
    // constructor
        MyString::MyString():p_str(NULL),strLength(0){}
    
        MyString::MyString(const MyString &str)//
        {
            if(NULL == str.p_str)
            {
                return;
            }
            strLength = str.strLength;
            p_str = new char[strLength+1];
            strcpy(p_str,str.p_str);
        }
        MyString::MyString(const char *str)
        {
            if(NULL == str)
            {
                return;
            }
            strLength = strlen(str);
            p_str = new char[strLength+1];
            strcpy(p_str,str);
        }
        MyString::MyString(const size_t len,const char ch)
        {
            if(NULL == ch)
            {
                return;
            }
            strLength = len;
            p_str = new char[strLength+1];
            for(size_t i=0;i<strLength;i++)
            {
                p_str[i] = ch;
            }
            p_str[strLength] = '';// 由于strset以''结束的
            cout << p_str << " &&" << endl;
            //strset(p_str,ch);
            //cout << p_str[0] << ",,,"<<strlen(p_str) << "," << strLength << endl;
        }
        // destructor
        MyString::~MyString()
        {
            delete[] p_str;
        }
    
        // attributes
        size_t MyString::length()// 字符串长度
        {
            return strLength;
        }
        bool MyString::isEmpty()// 返回字符串是否为空
        {
            return strLength==0?true:false;
        }
        const char* MyString::c_str()
        {
            return p_str;
        }
        // 为什么不是引用呢??? friend 使用在类里面进行声明的,外面就不须要了,并且友元函数不属于类的成员函数,所以不用MyString::
        // ostream
        ostream& operator<< (ostream& out,const MyString &str)
        {
            if(str.p_str != NULL)
            {
                out << str.p_str;
            }
            return out;
        }
        // istream,一个是const还有一个不是,依据变还是不变
        istream& operator>> (istream& in, MyString& str)
        {
            char tmp[100];// 暂时字符串
            if(in>>tmp)
            {
                delete[] str.p_str;
                str.strLength = strlen(tmp);
                str.p_str = new char[str.strLength+1];
                strcpy(str.p_str,tmp);
            }
            return in;
        }
        // + 加
        MyString operator+(const MyString& lhs,const MyString& rhs)
        {
            MyString ret;
            ret.strLength = lhs.strLength + rhs.strLength;
            ret.p_str = new char[ret.strLength+1];
            strcpy(ret.p_str,lhs.p_str);
            strcat(ret.p_str,rhs.p_str);
            return ret;
        }
        // compare operations
        bool operator==(const MyString& lhs,const MyString& rhs)
        {
            return strcmp(lhs.p_str,rhs.p_str)==0?true:false;
        }
        bool operator!=(const MyString& lhs,const MyString& rhs)
        {
            return strcmp(lhs.p_str,rhs.p_str)!=0?true:false;
        }
        bool operator<(const MyString& lhs,const MyString& rhs)
        {
            return strcmp(lhs.p_str,rhs.p_str)<0?true:false;
        }
        bool operator<=(const MyString& lhs,const MyString& rhs)
        {
            return strcmp(lhs.p_str,rhs.p_str)<=0?true:false;
        }
        bool operator>(const MyString& lhs,const MyString& rhs)
        {
            return strcmp(lhs.p_str,rhs.p_str)>0?true:false;
        }
        bool operator>=(const MyString& lhs,const MyString& rhs)
        {
            return strcmp(lhs.p_str,rhs.p_str)>=0?true:false;
        }
        // 成员函数实现运算符重载
        // index operation
        char& MyString::operator[](const size_t index)
        {
            if(index<0 || index>=strLength)
            {
                throw Outofbond() ;
            }
            return p_str[index];
        }
        const char& MyString::operator[](const size_t index)const
        {
            if(index<0 || index>=strLength)
            {
                throw Outofbond();
            }
            return p_str[index];
        }
         // = 赋值构造函数(推断是否是自身) 为什么要这样删除呢?
        MyString& MyString::operator=(const MyString& other)
        {
            if(this != &other)
            {
                if(strLength<other.strLength)
                {
                    delete[] p_str;
                    p_str = new char[other.strLength+1];
                }
                strLength = other.strLength;
                strcpy(p_str,other.p_str);
            }// 这样可能会产生多余的未释放的空间
            return *this;
        }
        // += 相当于返回的是备份的,内部对象的销毁,不影响的 和 以下的全然不一样的
    //    MyString MyString::operator+=(const MyString& other)
    //    {
    //        if(NULL == other.p_str)
    //        {
    //            return *this;
    //        }
    //        MyString ret;
    //        ret.strLength = strLength + other.strLength;
    //        ret.p_str = new char[ret.strLength+1];
    //        strcpy(ret.p_str,p_str);
    //        strcat(ret.p_str,other.p_str);
    //        return ret;
    //    }
        // 返回的是当前对象的引用,当前对象就在调用函数里,所以不会销毁的
        // 推断一下是否是自身相加
        MyString& MyString::operator+=(const MyString& other)
        {
            if(NULL == other.p_str)
            {
                return *this;
            }
            if(this == &other)
            {
                MyString copy(*this);
                return *this += copy;
            }// 必须推断是否相等的,并且要+=的,这样相当于调用了自身,可是这次直接以下去了,不进入if的
            strLength += other.strLength;
            //strLength *= 2;
            char *p_old = p_str;
            p_str = new char[strLength+1];
            strcpy(p_str,p_old);
            strcat(p_str,other.p_str);
            delete[] p_old;// 删除旧的空间
            return *this;
        }
        // 成员操作函数
        // substr  返回应用是不行的,错误的;取从pos開始的n个字符组成的子串
        //MyString& MyString::substr(size_t pos,const size_t n)
        MyString MyString::substr(size_t pos,const size_t n)
        {
            if((pos+n)>=strLength)
            {
                throw Outofbond();
            }
            MyString ret;
            ret.strLength = n;
            //ret.p_str = new char[n+1];
            ret.p_str = new char[ret.strLength+1]; //也能够
            for(size_t i=0;i<n;i++)
            {
                ret.p_str[i] = p_str[pos+i];
            }
            ret.p_str[n] = '';
    //        for(size_t i=0;i<ret.strLength;i++)
    //        {
    //            ret[i] = (*this)[pos+i];
    //            cout << ret[i] << ",,";
    //        }// 也行的,利用刚刚重载的【】,这样更好,不用再次推断越界了,不知道为什么,报错误的
    //        ret[ret.strLength] = '';
            return ret;
        }
        // append 同 += 追加到末尾
        MyString& MyString::append(const MyString& other)
        {
            *this += other;// 利用刚刚那重载的+=
            return *this;
        }
        //insert 从pos開始的插入other
        MyString& MyString::insert(size_t pos,const MyString& other)
        {
            if(pos<0 || pos>=strLength)
            {
                throw Outofbond();
            }
            char *p_old = p_str;
            strLength += other.strLength;
            p_str = new char[strLength+1];
            for(size_t i=0;i<pos;i++)
            {
                *(p_str+i) = *(p_old+i);
            }
            for(size_t i=pos;i<other.strLength+pos;i++)
            {
                *(p_str+i) = other.p_str[i-pos];
            }
            for(size_t i=other.strLength+pos;i<strLength;i++)
            {
                *(p_str+i) = p_old[i-other.strLength];
            }
            *(p_str+strLength) = '';
            return *this;
        }
        //assign 替换  用other的POS開始的n相应替换this的pos開始的
        MyString& MyString::assign(MyString&other,size_t pos,size_t n)
        {
    //        if(pos<0 || pos>=strLength)
    //        {
    //            throw Outofbond();
    //        }
            assert(pos>0 && pos<strLength);// assert 的优点
            assert(pos+n<other.strLength);
            if(strLength < pos + n)
            {
                char *p_old = p_str;
                strLength = pos + n;
                p_str = new char[strLength+1];
                for(size_t i=0;i<pos;i++)
                {
                    *(p_str+i) = *(p_old+i);
                }
                delete[] p_old;
            }
            for(size_t i=pos;i<pos+n;i++)
            {
                *(p_str+i) = other.p_str[i];
            }
            *(p_str+pos+n) = '';
            return *this;
        }
        // erase 删除 这种方法并非非常好的,并没有释放所erase的空间,请看以下的
    //    MyString& MyString::erase(size_t pos,size_t n)
    //    {
    //        if((pos+n)>strLength)
    //        {
    //            throw Outofbond();
    //        }
    //        size_t index = pos + n;
    //        while(*(p_str+index)!='')
    //        {
    //            *(p_str+index-n) = *(p_str+index);
    //            ++index;
    //        }
    //        *(p_str+index-n) = '';
    //        return *this;
    //    }
        // erase 删除 从pos開始的n个字符
        MyString& MyString::erase(size_t pos,size_t n)
        {
            if((pos+n)>strLength)
            {
                throw Outofbond();
            }
            char *p_old = p_str;
            strLength -= n;
            p_str = new char[strLength+1];
            for(size_t i=0;i<pos;i++)
            {
                p_str[i] = p_old[i];
            }
            for(size_t i=pos;i<strLength;i++)
            {
                p_str[i] = p_old[i+n];
            }
            *(p_str+strLength) = '';
            return *this;
        }
        //find_first_of 查找某一个字符 size_t 是非符号数的
        // 查找在字符串中第一个与str中的某个字符匹配的字符,返回它的位置。
        //搜索从index開始,假设没找到就返回string::npos
        int MyString::find_first_of(const char* str,size_t index)
        {
            if(NULL == str || index >=strLength)
                return npos;
            int tmp_len = strlen(str),j;
            size_t flag,min_index = INI_MAX;
            for(j=0;j<tmp_len;j++)
            {
                flag = npos;
                for(size_t i=index;i<strLength;i++)
                {
                    if(str[j] == p_str[i])
                    {
                        flag = i;
                        break;
                    }
                }
    //            indexs[j] = flag;
                if(flag != npos)
                {
                    min_index = min_index<flag?min_index:flag;
                }
            }
    //        for(j=0;j<tmp_len;j++)
    //        {
    //            if(indexs[j]!=npos)
    //                min = min<indexs[j]?min:indexs[j];
    //        }
            if(min_index == INI_MAX)
            {
                return npos;
    //            min_index = npos;
    //           cout << "---npos----" << min_index << ",,,,";
            }
            return min_index;
        }
        int MyString::find_first_of(const char ch,size_t index)
        {
            if(NULL == ch || index >=strLength)
                return npos;
            int j;
            size_t flag = npos;
            for(size_t i=index;i<strLength;i++)
            {
                if(ch == p_str[i])
                {
                    flag = i;
                    break;
                }
            }
            return flag;
        }
        int MyString::find_first_of(const MyString& str,size_t index)
        {
            if(NULL == str || index >=strLength)
                return npos;
            int j;
            size_t flag,min_index = INI_MAX;
            for(j=0;j<str.strLength;j++)
            {
                flag = npos;
                for(size_t i=index;i<strLength;i++)
                {
                    if(str[j] == p_str[i])
                    {
                        flag = i;
                        break;
                    }
                }
                if(flag != npos)
                {
                    min_index = min_index<flag?min_index:flag;
                }
            }
            if(min_index == INI_MAX)
            {
                return npos;
            }
            return min_index;
        }
        // 在字符串中查找第一个与str中的字符都不匹配的字符,返回它的位置。
        //搜索从index開始。假设没找到就返回string::nops O(N^2)
        int MyString::find_first_not_of(const char *str,size_t index)
        {
            if(NULL == str || index >=strLength)
                return npos;
            size_t i=0,j=0;
            size_t tmp_len = strlen(str);
            for(i=index;i<strLength;i++)
            {
                for(;j<tmp_len;j++)
                {
                    if(p_str[i]==str[j])
                        break;
                }
                if(j==tmp_len)
                    break;// 依据跳出的内层for的条件推断,找到即结束循环
            }
            if(i==strLength)
                return npos;// 未找到,// 依据跳出的内层for的条件推断,找到即结束循环
            return i;
        }
        int MyString::find_first_not_of(const MyString& str,size_t index)
        {
            if(NULL == str || index >=strLength)
                return npos;
            size_t i=0,j=0;
            for(i=index;i<strLength;i++)
            {
                for(;j<str.strLength;j++)
                {
                    if(p_str[i]==str[j])
                        break;// 假设相等 本轮i就无效了,进行下一轮
                }
                if(j==str.strLength)
                    break;// 依据跳出的内层for的条件推断,找到即结束循环
            }
            if(i==strLength)
                return npos;// 未找到,// 依据跳出的内层for的条件推断,找到即结束循环
            return i;
        }
        int MyString::find_first_not_of(const char ch,size_t index)
        {
            if(NULL == ch || index >=strLength)
                return npos;
            size_t i=0;
            for(i=index;i<strLength;i++)
            {
                if(p_str[i]!=ch)// 跟上面的稍微不同,找一个不等就能够了
                    break;
            }
            if(i==strLength)
                return npos;// 未找到,// 依据跳出的内层for的条件推断,找到即结束循环
            return i;
        }
        // swap  都得变得,所以非const
        void MyString::swap(MyString& lhs,MyString& rhs)
        {
            lhs.strLength ^= rhs.strLength;
            rhs.strLength ^= lhs.strLength;
            lhs.strLength ^= rhs.strLength;
            char *p_tmp = rhs.p_str;
            rhs.p_str = lhs.p_str;
            lhs.p_str = p_tmp;
        }
        // replace_all  这个东西还是不太好弄的啊,不是非常理想
        MyString& MyString::replace_all(const char oldc,const char newc)
        {
            if(NULL == oldc)
            {
                return *(this);
            }
            for(size_t i=0;i<strLength;i++)
            {
                if(p_str[i] == oldc)
                {
                    p_str[i] = newc;
                }
            }
            return *(this);
        }
        MyString& MyString::replace(size_t index,size_t num1,size_t num2,const char ch)
        {
    
        }
        // find 函数
        int MyString::find(const char* str,size_t index)
        {
            assert(str!=NULL&&index<strLength);
            // kmp 中的getnext函数
            size_t len = strlen(str);
            size_t next[len+1];
            size_t j,k;
            next[0] = npos;
            j = 0;
            k = npos;
            while(j<len)
            {
                if(k==npos || str[j]==str[k])
                {
                    j++;
                    k++;
                    next[j] = k;
                }
                else
                    k = next[k];
            }
            // kmp 算法
            k = index;
            j = 0;
            while(p_str[k]!='')
            {
                if(j==0 || p_str[k]==str[j])
                {
                    k++;
                    j++;
                }
                else
                {
                    j = next[j];// 消除指针回溯
                }
                if(str[j] == '')//匹配成功
                    return k-j;
            }
            return npos;
        }
        int MyString::find(const MyString& str,size_t index)
        {
    //        if(this == &str)
    //        {
    //            MyString other(*this);
    //            find(other,index);
    //        }
            assert(NULL!=str && index<strLength);
            // kmp 中的getnext函数
    
            size_t next[str.strLength+2];
            size_t j,k;
            next[0] = npos;
            j = 0;
            k = npos;
            while(j<str.strLength)
            {
                if(k==npos || str.p_str[j]==str.p_str[k])
                {
                    j++;
                    k++;
                    next[j] = k;
                }
                else
                    k = next[k];
            }
            int i;
            for(i=1;i<=j;i++)
                cout << next[i] << ",";
            // kmp 算法
            k = index;
            j = 0;
            while(p_str[k]!='')
            {
                if(j==0 || p_str[k]==str.p_str[j])
                {
                    k++;
                    j++;
                }
                else
                {
                    j = next[j];// 消除指针回溯
                }
                if(str.p_str[j] == '')//匹配成功,不知道为什么调用自身的str[]重载总是报错的
                    return k-j;
            }
            if(str.p_str[j] == '')// 同一个字符串
                return k-j;
            return npos;
        }
        int MyString::find(const char ch,size_t index)
        {
            assert(NULL!=ch && index<strLength);
            for(size_t i=index;i<strLength;i++)
            {
                if(p_str[i] == ch)
                    return i;
            }
            return npos;
        }
    


    (3)測试函数main.cpp

    #include "MyString.h"
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int n;
        int choose = 1;
        int p,l;
        char cs[100];
        MyString s1;
        MyString s2("hello");
        MyString s3 = "HELLO";
        cout << "***** welcome *****
    ";
        cout << "******* MADE BY zyp **********
    ";
        cout << "s1= " << s1 << "s2= " << s2 << "s3= " << s3 << endl;
        cout << "请输入一个长度小于100的字符串:比如world
    ";
        cin >> s1;
        s1 = s1;
        //s1 = s1+s1;
        s1 += s1;
        MyString s4(s1);
        s4.append(s1);
        s2.insert(2,s3);
        s1.erase(4,4);
        s1.assign(s2,1,7);
        cout << "s1= " << s1 << "s2= " << s2 << "s3= " << s3 << "s4= " << s4 << endl;
        s2 = s4.substr(2,7);
        cout << "s4[3]= " << s4[3] << s4.length() << (s1>=s2) << "s4.substr() " << s2 << endl;
        cout << "s1.find_first_of(beLE,2):" << s1.find_first_of("beLE",2) << ",s1.find_first_of(a,3):" << s1.find_first_of('a',3) << ",s1.find_first_of(s3,2):" << s1.find_first_of(s3,2) << endl;
        MyString s5(5,'b');
        s5 += s5;
        //s5.append(s5);// 不知道为什就是不能append
        cout << "s5 = " << s5 << "s5.find_first_not_of(aeHLEOl,2):" << s5.find_first_not_of("aeHLEOl",2) << "s5.find_first_not_of(aeHLEOl,0):" << s5.find_first_not_of("aeHLEOl") << endl;
        cout << "s5.find_first_not_of(s1,2):" << s5.find_first_not_of(s1,2) << "s5.find_first_not_of(b,2):" << s5.find_first_not_of('b',2) << endl;
        swap(s1,s5);
        s5.replace_all('a','J');
        MyString s6("LLO");
        cout << s1 << "," << s5 << "s5.find(LLO,0) " << s5.find("LLO",0) << "s5.find(s6,0) " << s5.find(s5) << endl;
        cout << npos << endl;
        return 0;
    }
    


    三:感悟

    (1)耗时将近2天的实现了它,自己与其从中学到了非常多,倒不如说是又一次认识了string类;

    (2)自己知道这个简单的string类,距离string源码还差的非常远非常远;可是它帮助我更好的理解了string类,至少会简单的应用了。

    (3)简单的实现了一下string类,參照的是STL源代码,可是自己理解的还是不够深,难免有一些错误,请各位不吝赐教,万分感谢!

    (4)下一步进军list

  • 相关阅读:
    Get distinct count of rows in the DataSet
    单引号双引号的html转义符
    PETS Public English Test System
    Code 39 basics (39条形码原理)
    Index was outside the bounds of the array ,LocalReport.Render
    Thread was being aborted Errors
    Reportviewer Error: ASP.NET session has expired
    ReportDataSource 值不在预期的范围内
    .NET/FCL 2.0在Serialization方面的增强
    Perl像C一样强大,像awk、sed等脚本描述语言一样方便。
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4558533.html
Copyright © 2020-2023  润新知