2014-09-04 101 views
-5
#include<iostream> 
using namespace std; 


class MyString{ 

private: 
char *str=new char[10]; 

public: 
    MyString(){*str='\0';}   //default constructor 
    MyString(char *s){    //parameterized constructor 
    str=s; 
} 

private: 
int length(char* s){ 
    int i=0; 
    while(s[i]!='\0') 
     i++; 
return i; 
} 
char* delchar(char* s,int count,int start){ 
    int i,j=0; 
    char *temp= new char[10]; 
    for(i=start;i<start+count;i++){ 
     s[i]=' '; 
    } 
    for(i=0;i<length(s);i++){ 
     if(s[i]!=' ') 
      temp[j++]=s[i]; 
    } 
    s=temp; 
    return s; 
} 

public: 
MyString operator-(MyString s){ 
    int i=0,j=0,count=0,start=-1;/* i to iterate the first string,j to iterate the  second string*/ 
    MyString temp;    /* count to count the matched characters ,start to know the starting index*/ 
    temp.str=str; 

    while(temp.str[i]!='\0'){ 
     j=0; 
     start++; 
     while(s.str[j]!='\0'){ 
      if(temp.str[i]==s.str[j]){ 
       count++; 
       i++; 
       j++; 
       if(count==length(s.str)){//checks if the count 
        temp.str=delchar(temp.str,count,start); 
        i=i-count; 
        start=i-1; 
        count=0; 
       } 
      } 
      else{ 
       i++; 
       count=0; 
       break; 
      } 
     } 

    } 
    return temp; 
} 
~MyString(){ 
    delete str; 
} 

friend ostream &operator<<(ostream &stream,MyString& s){ 
    stream<<s.str<<endl; 
    return stream; 
} 

}; 
int main(){ 
char *p= new char[20]; 
char *q= new char[10]; 

cin>>p; 
cin>>q; 

MyString s1(p); 
MyString s2(q); 
MyString s3; 

s3=s1-s2; 
cout<<s3; 
delete p; 
delete q; 
return 0; 
} 

返回null上面的代碼重載 - 操作者。它試圖從例如INPUT1主串減去子:joshmathews輸入2:約什輸出:馬修斯。我正在嘗試將輸出存儲在新的MyString對象s3中。當我使用如上所示的析構函數時,輸出s3 返回null。但是當我不使用析構函數時,我會得到預期的輸出結果。任何人都可以幫忙?<<操作符重載使用析構函數

+3

請了解構造函數初始化列表。這段代碼有一個可怕的,可怕的內存錯誤。 – 2014-09-04 06:59:08

+2

也請了解std :: string,畢竟這應該是C++ – stijn 2014-09-04 07:01:42

+0

函數'delchar'完全是「脫鉤」的人。 – 2014-09-04 07:03:13

回答

0

主要問題是Operater-返回一個由默認拷貝構造函數複製的本地對象 - 默認拷貝構造函數指向s3到完全相同的temp/MyString的內存/緩衝區,並且當該temp被銷燬時,它抹掉了s3正在使用的內存。

這被稱爲懸掛指針。你可以在這裏閱讀更多:http://en.wikipedia.org/wiki/Dangling_pointer#Cause_of_wild_pointers

下面的代碼是我爲了讓你的程序執行並返回一個有效的結果,同時完成沒有錯誤的變化。但要清楚的是,這個修改版本存在問題,運行時錯誤或沒有運行時錯誤,但這有助於說明一些重要的問題。

當你定義一個分配內存的類型時,你真的開始做一些沒有空來的東西。我的改變版本完全擺脫了析構函數,所以實際上它直到程序結束時纔會泄漏內存。雖然析構函數是無效的,所以刪除它允許程序完成。但這是一般你不應該接受的事情之一。

我加了一個拷貝構造函數和拷貝賦值運算符:

MyString(const MyString& s) { 
    strcpy_s(str, 10, s.str); 
} 

MyString& operator=(const MyString& s) { 
    strcpy_s(str, 10, s.str); 
    return *this; 
} 

注意在這兩個的strcpy_s。所做的是從參數中複製字符串,而不是僅僅指向與參數完全相同的地址處的完全相同的字符串。如果參數在你的版本中被破壞了,它會消除一些內存,所以我們可以接受默認的拷貝構造函數等,因爲默認情況下它們是指向相同內臟的淺拷貝。這是分配內存的負擔之一 - 你需要在析構函數的〜和〜你的一些構造函數中處理這個問題。這被稱爲「三規則」:

如果您需要顯式聲明析構函數,複製構造函數或複製賦值運算符,您可能需要明確聲明它們中的所有三個。

下面是關於三個規則的維基百科鏈接:http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)

您需要一個析構函數,所以這是你所需要的其他線索。原因正如我所說 - 默認情況下你會得到一個免費的拷貝構造函數,但是如果有點是資源的話,它只會讓所有的指向相同的內容,但是如果沒有影響其他人,你就不能刪除它。

此外,在delchar我加了這條線向底部:

temp[j] = '\0'; 

字符的字符串必須終止於零,而你只複製實際字母字符轉換成溫度,所以沒有空字符,一個的strcpy不知道在哪裏結束。

如果你還記得我抽出你的析構函數,那麼這些就是我所做的改變。

析構函數也有一個問題,如果使用新創建一個數組,像

char* c = new char[10]; 

,那麼你需要刪除它表示在被new'd作爲陣列的方式,像這樣:

delete [] c; 

接下來你應該看看你的MyString結構是如何發生的。如果你逐步完成,你會發現str成員變成new'd - 這意味着它將一個有效的地址保存到可以使用的緩衝區中,但是如果使用了MyString(char * s)構造函數,只需要s的這個新地址,並使str保持該地址 - 這意味着指向有效緩衝區的舊地址丟失,並且新內存的緩衝區不能被釋放。所以這是一個泄漏。您可以使用我添加的構造函數中的strcpy_s策略將MyString(char * s)中的s所指向的上下文複製到new'd緩衝區中。這將在代碼中產生巨大的積極影響。

不要擔心所有的精英分子 - 他們中的許多人都是天生的倒立者,所以他們看不出與新手給予事情一個誠實的努力。

下面是完整的改變代碼:

#include<iostream> 
using namespace std; 

class MyString{ 

private: 
    char *str = new char[10]; 

public: 
    MyString(){ *str = '\0'; }   //default constructor 
    MyString(char *s){    //parameterized constructor 
     str = s; 
    } 
    MyString(const MyString& s) { 
     strcpy_s(str, 10, s.str); 
    } 
    MyString& operator=(const MyString& s) { 
     strcpy_s(str, 10, s.str); 
     return *this; 
    } 

private: 
    int length(char* s){ 
     int i = 0; 
     while (s[i] != '\0') 
      i++; 
     return i; 
    } 
    char* delchar(char* s, int count, int start){ 
     int i, j = 0; 
     char *temp = new char[10]; 
     for (i = start; i<start + count; i++){ 
      s[i] = ' '; 
     } 
     for (i = 0; i<length(s); i++){ 
      if (s[i] != ' ') 
       temp[j++] = s[i]; 
     } 
     temp[j] = '\0'; 
     s = temp; 
     return s; 
    } 

public: 
    MyString operator-(MyString s){ 
     int i = 0, j = 0, count = 0, start = -1;/* i to iterate the first string,j to iterate the  second string*/ 
     MyString temp;    /* count to count the matched characters ,start to know the starting index*/ 
     temp.str = str; 

     while (temp.str[i] != '\0'){ 
      j = 0; 
      start++; 
      while (s.str[j] != '\0'){ 
       if (temp.str[i] == s.str[j]){ 
        count++; 
        i++; 
        j++; 
        if (count == length(s.str)){//checks if the count 
         temp.str = delchar(temp.str, count, start); 
         i = i - count; 
         start = i - 1; 
         count = 0; 
        } 
       } 
       else{ 
        i++; 
        count = 0; 
        break; 
       } 
      } 

     } 
     return temp; 
    } 
    ~MyString(){ 
     //delete str; 
    } 

    friend ostream &operator<<(ostream &stream, MyString& s){ 
     stream << s.str << endl; 
     return stream; 
    } 

}; 
int main(){ 
    char *p = new char[20]; 
    char *q = new char[10]; 

    cin >> p; 
    cin >> q; 

    MyString s1(p); 
    MyString s2(q); 
    MyString s3; 

    s3 = s1 - s2; 
    cout << s3; 
    delete p; 
    delete q; 
    return 0; 
} 
+0

Thamk you very much!它幫助了很多 – 2014-09-05 05:26:07