您好,登錄后才能下訂單哦!
一:回顧
(1)c++中的string類是在面試中和筆試中經常考的題目; 工程代碼免費下載 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 僅僅是在類中進行聲明的非內部 卻可以訪問內部成員的外部函數,而且在外部不再需要friend關鍵字;它與成員函數的區別是,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] = '\0';// 因為strset以'\0'結束的 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] = '\0'; // for(size_t i=0;i<ret.strLength;i++) // { // ret[i] = (*this)[pos+i]; // cout << ret[i] << ",,"; // }// 也行的,利用剛剛重載的【】,這樣更好,不用再次判斷越界了,不知道為什么,報錯誤的 // ret[ret.strLength] = '\0'; 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) = '\0'; 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) = '\0'; 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)!='\0') // { // *(p_str+index-n) = *(p_str+index); // ++index; // } // *(p_str+index-n) = '\0'; // 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) = '\0'; 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]!='\0') { if(j==0 || p_str[k]==str[j]) { k++; j++; } else { j = next[j];// 消除指針回溯 } if(str[j] == '\0')//匹配成功 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]!='\0') { if(j==0 || p_str[k]==str.p_str[j]) { k++; j++; } else { j = next[j];// 消除指針回溯 } if(str.p_str[j] == '\0')//匹配成功,不知道為什么調用自身的str[]重載總是報錯的 return k-j; } if(str.p_str[j] == '\0')// 同一個字符串 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 *****\n"; cout << "******* MADE BY zyp **********\n"; cout << "s1= " << s1 << "s2= " << s2 << "s3= " << s3 << endl; cout << "請輸入一個長度小于100的字符串:例如world\n"; 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
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。