编写strcpy函数和类String的构造函数、析构函数、赋值函数和重载运算符函数已知strcpy函数的原型是char *strcpy(char *strDest, const char *strSrc);其中strDest是目的字符串,strSrc是源字符串。
(1)不调用C++/C的字符串库函数,请编写函数strcpychar *strcpy(char *strDest, const char *strSrc); //将源字符串加const,表明其为输入参数{assert((strDest!=NULL) && (strSrc !=NULL)); // 2分 //对源地址和目的地址加非0断言char *address = strDest; // 2分//为了实现链式操作,将目的地址返回while( (*strDest++ = * strSrc++) != …\0‟ ) // 2分NULL ;return address ; // 2分}(2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?答:为了实现链式表达式。
// 2分例如int length = strlen( strcpy( strDest, “hello world”) );二、网上广泛流传的,也是摘自林锐的http://www.blog.sh/user3/skyflowing/archives/2006/60452.html题目:已知strcpy函数的原型是:char * strcpy(char * strDest,const char * strSrc);1.不调用库函数,实现strcpy函数。
2.解释为什么要返回char *。
解说:1.strcpy的实现代码char * strcpy(char * strDest,const char * strSrc){if ((strDest==NULL)||(strsrc="/=NULL"))//[1](我感觉应为&&)throw "Invalid argument(s)";//[2]char * strDestCopy=strDest;//[3]while ((*strDest++=*strSrc++)!='\0');//[4]return strDestCopy;}错误的做法:[1](A)不检查指针的有效性,说明答题者不注重代码的健壮性。
(B)检查指针的有效性时使用((!strDest)||(!strSrc))或(!(strDest&&strSrc)),说明答题者对C语言中类型的隐式转换没有深刻认识。
在本例中char *转换为bool即是类型隐式转换,这种功能虽然灵活,但更多的是导致出错概率增大和维护成本升高。
所以C++专门增加了bool、true、false三个关键字以提供更安全的条件表达式。
(C)检查指针的有效性时使用((strDest==0)||(strsrc="/=0")),说明答题者不知道使用常量的好处。
直接使用字面常量(如本例中的0)会减少程序的可维护性。
0虽然简单,但程序中可能出现很多处对指针的检查,万一出现笔误,编译器不能发现,生成的程序内含逻辑错误,很难排除。
而使用NULL代替0,如果出现拼写错误,编译器就会检查出来。
[2](A)return new string("Invalid argument(s)");,说明答题者根本不知道返回值的用途,并且他对内存泄漏也没有警惕心。
从函数中返回函数体内分配的内存是十分危险的做法,他把释放内存的义务抛给不知情的调用者,绝大多数情况下,调用者不会释放内存,这导致内存泄漏。
(B)return 0;,说明答题者没有掌握异常机制。
调用者有可能忘记检查返回值,调用者还可能无法检查返回值(见后面的链式表达式)。
妄想让返回值肩负返回正确值和异常值的双重功能,其结果往往是两种功能都失效。
应该以抛出异常来代替返回值,这样可以减轻调用者的负担、使错误不会被忽略、增强程序的可维护性。
[3](A)忘记保存原始的strDest值,说明答题者逻辑思维不严密。
[4](A)循环写成while (*strDest++=*strSrc++);,同[1](B)。
(B)循环写成while (*strSrc!='\0') *strDest++=*strSrc++;,说明答题者对边界条件的检查不力。
循环体结束后,strDest字符串的末尾没有正确地加上'\0'。
2.返回strDest的原始值使函数能够支持链式表达式,增加了函数的“附加值”。
同样功能的函数,如果能合理地提高的可用性,自然就更加理想。
链式表达式的形式如:int iLength=strlen(strcpy(strA,strB));又如:char * strA=strcpy(new char[10],strB);返回strSrc的原始值是错误的。
其一,源字符串肯定是已知的,返回它没有意义。
其二,不能支持形如第二例的表达式。
其三,为了保护源字符串,形参用const限定strSrc所指的内容,把const char *作为char *返回,类型不符,编译报错。
类似的我们可以写出一个10分的strlen函数int strlen( const char *str ) //输入参数const{assert( strt != NULL ); //断言字符串地址非0int len;while( (*str++) != '\0' ){len++;}return len;}include <cstring>#include <iostream>using namespace std;//已知类String的原型为:class String{public:String(const char *str = NULL); // 普通构造函数String(const String &o ther); // 拷贝构造函数~ String(void); // 析构函数String& operato r =(const String &other); // 赋值函数String& operato r +(const String &other); //重载运算符+String& operato r -(const String &other); //重载运算符-bool operator==(const String &o ther); //重载"==",判断两个字符串相等bool operator<(const String &o ther);bool operator>(const String &o ther);friend ostream& operato r << (ostream &, const String &); //重载<<,这里必须使用friend,因为涉及到两个类之间私有成员的访问private:char *m_data; // 用于保存字符串};//请编写String的上述4个函数。
//普通构造函数String::String(const char *str){if(NULL==str){m_data = new char[1]; // 得分点:对空字符串自动申请存放结束标志'\0'的//加分点:对m_data加NULL 判断if(m_data!=NULL)*m_data = '\0';}else{int length = strlen(str);m_data = new char[length+1]; // 若能加NULL 判断则更好if(m_data!=NULL)strcpy(m_data, str);}}// String的析构函数String::~String(void){delete [] m_data; // 或delete m_data;}//拷贝构造函数String::String(const String &o ther) // 得分点:输入参数为const型{int length = strlen(other.m_data);m_data = new char[length+1]; //加分点:对m_data加NULL 判断if(m_data!=NULL)strcpy(m_data, o ther.m_data);}//赋值函数String& String::operato r=(const String &other) // 得分点:输入参数为const型{if(this == &other) //得分点:检查自赋值return *this;delete [] m_data; //得分点:释放原有的内存资源int length = strlen( other.m_data );m_data = new char[length+1]; //加分点:对m_data加NULL 判断if(m_data!=NULL)strcpy( m_data, o ther.m_data );return *this; //得分点:返回本对象的引用}String& String::operato r+(const String &other) //重载运算符+ {char temp[200];strcpy(temp,m_data);delete [] m_data;int length=strlen(this->m_data)+strlen(other.m_data);m_data=new char[length+1];if(m_data!=NULL)strcpy(m_data,temp);strcat(m_data,o ther.m_data);return *this;}String& String::operato r-(const String &other){char *temp,*p;if( (temp=strstr(m_data,other.m_data)) ==NULL){cout<<"没有符合的子串,不能使用'-'操作"<<endl;return *this;}else{p=temp;temp=temp+strlen(other.m_data);*p='\0';strcat(m_data,temp);}return *this;}//重载运算符"<<"ostream& operator<<(ostream &output, const String &other){output<<other.m_data;return output;}bool String::operator<(const String &o ther){if(strcmp(m_data,other.m_data)<0)return true;return false;}bool String::operator>(const String &o ther) {if(strcmp(m_data,other.m_data)>0)return true;return false;}bool String::operator==(const String &other) {if(strcmp(m_data,other.m_data)==0)return true;return false;}void main(){String s1("Hello,");String s2("World!");String s3(s2);//调用拷贝构造函数String s4(s2);String s5("Hello,World");String s6("Hello,World!");String s7("Hello,World!");String s8("o,W");String s9;//String s3;//调用构造函数中的默认构造.//s3=s2;// 调用重载后的赋值函数cout<<s1<<endl;cout<<s2<<endl;cout<<s3<<endl;s3=s1+s2;cout<<s1<<endl;cout<<s2<<endl;cout<<s3<<endl;if(s4==s2)cout<<"两个字符串相等"<<endl;elsecout<<"两个字符串不相等"<<endl;if(s5<s6)cout<<"s5小于s6"<<endl;else if(s5>s6)cout<<"s5大于s6"<<endl;elsecout<<"s5等于s6"<<endl;s9=s7-s8;cout<<s9<<endl;system("pause");}原文:/rgaofei/blog/item/f538fc081b332333b0351dd0.html。