编写strcpy函数和类String的构造函数、析构函数、赋值函数和重载运算符函数
已知strcpy函数的原型是
 char *strcpy(char *strDest, const char *strSrc);
 其中strDest是目的字符串,strSrc是源字符串。
(1)不调用C++/C的字符串库函数,请编写函数 strcpy
char *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”) );
二、网上广泛流传的,也是摘自林锐的
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 ); //断言字符串地址非0
    int len;
    while( (*str++) != '\0' )
    { 
        len++;
    }
    return len;
}
include <cstring>
#include <iostream>
using namespace std;


//已知类String的原型为:
class String
{
字符串拷贝函数strcpy作用public:
String(const char *str = NULL);                    // 普通构造函数
String(const String &other);                      // 拷贝构造函数
~ String(void);                                    // 析构函数
String& operator =(const String &other);          // 赋值函数
String& operator +(const String &other);          //重载运算符+
String& operator -(const String &other);    //重载运算符-
bool operator==(const String &other);            //重载"==",判断两个字符串相等 
    bool operator<(const String &other);
    bool operator>(const String &other);
friend ostream& operator << (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 &other)                          // 得分点:输入参数为const型
{     
int length = strlen(other.m_data);
m_data = new char[length+1];                            //加分点:对m_data加NULL 判断
if(m_data!=NULL)
        strcpy(m_data, other.m_data);    
}

//赋值函数

String& String::operator=(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, other.m_data );   
return *this;                                            //得分点:返回本对象的引用 
}

String& String::operator+(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,other.m_data);
return *this;
}
String& String::operator-(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 &other)
{
    if(strcmp(m_data,other.m_data)<0)
        return true;
    return false;
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。