上机辅导。学生的一个程序莫名出问题。她是在做一个String类,主要是要实现字符串的连接。
程序是这样的,请读者将其拷到IDE,边看边调:
~~~
#include <iostream>
#include <cassert>
#include <cstring>
using namespace std;
class String
{
private:
char* p;
int len;
public:
String();
String(const char* s);
String(const String& s);
~String();//问题出现在这儿
void show();
friend String operator+(const String& s1,const String& s2);
friend String operator-(const String& s1,const String& s2);
};
String::String()
{
len=0;
p=NULL;
}
String::String(const char* s)
{
len=strlen(s);
p=new char[len+1];
strcpy(p,s);
}
String::String(const String& s)
{
len=s.len;
if(p!=NULL)delete []p;
p=new char[len+1];
strcpy(p,s.p);
}
String operator+(const String& s1,const String& s2)
{
String total;
total.len=s1.len+s2.len;
total.p=new char[total.len+1];
strcpy(total.p,s1.p);
strcat(total.p,s2.p);
return total;
}
String operator-(const String& s1,const String& s2)
{
char* c1=new char[s1.len+1];
strcpy(c1,s1.p);
int i=s1.len-1;
while(s1.p[i]!=' '&&i>=0)--i;
c1[i+1]='\0';
char* c2=new char[s2.len+1];
strcpy(c2,s2.p);
i=0;
while(i<s2.len&&c2[i]==' ')++i;
int j=0;
while(c2[i]!='\0'&&i<s2.len)
{
c2[j]=c2[i];
++i;
++j;
}
c2[j]='\0';
String s;
s.len=s1.len+s2.len;
s.p=new char[s.len];
strcpy(s.p,c1);
strcat(s.p,c2);
delete c1;
delete c2;
return s;
}
void String::show()
{
cout<<p<<endl;
}
String::~String()
{
delete []p;
}
int main()
{
String str1("123"),str2("456"),str3;
str3=str1+str2;
str3.show();
str3=str1-str2;
str3.show();
return 0;
}
~~~
问题的表现是,`str3.show();`的输出是几个莫名的符号!
我让她单步跟踪一下,却发现无论断点设在哪里,总是要进到析构函数~String()中去!
恰其他同学的问题不少,我让她将这个程序给我发邮件,她不要在此纠缠。我清楚,这里有指针成员。祸水应该与此相关。
学习越来越深入,学生出问题的程序,常需要仔细阅读后才能给指导意见了。
午睡后,打开邮件。将程序拷入IDE,已经注意到了执行`str3=str1+str2;`时,需要有的赋值运算符=的重载。试图找一下单步时进入~String()时的场景,却未遂。
在我的IDE下,`str3=str1+str2;`的结果正常,`str3=str1-str2;`的结果却异常。野指针的表征,真伪混杂最头疼。
重载赋值运算=,在类声明中加:
~~~
String &operator=(const String& s1);
~~~
实现为:
~~~
String &String::operator=(const String &s1)
{
if(!this->p)
delete []p;
p=new char(s1.len+1);
strcpy(p,s1.p);
len=s1.len;
return *this;
}
~~~
先向学生交作业。进入~String()的问题是否还在?暂时放下,待回音。