2014-09-04 63 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