如果编写一个标准strcpy函数的总分值为10,下面给出几个不同得分的答案:
直接写逻辑2分
void strcpy( char *strDest, char *strSrc )
{
while( (*strDest++ = * strSrc++) != ‘\0’ );
}
使用const关键字限制strSrc加2分
void strcpy( char *strDest, const char *strSrc )
//将源字符串加const,表明其为输入参数,加2分
{
while( (*strDest++ = * strSrc++) != ‘\0’ );
}
对字符串指针加入非空判断
void strcpy(char *strDest, const char *strSrc)
{
//对源地址和目的地址加非0断言,加3分
assert( (strDest != NULL) && (strSrc != NULL) );
while( (*strDest++ = * strSrc++) != ‘\0’ );
}
将原地址返回
char * strcpy( char *strDest, const char *strSrc )
{
assert( (strDest != NULL) && (strSrc != NULL) );
char *address = strDest;
while( (*strDest++ = * strSrc++) != ‘\0’ );
return address;
}
执行以上strcpy函数后, strDest的指针会不会还指向字符串末尾,不会!strDest是形式参数
检查下面代码有什么问题?
void GetMemory( char *p )
{
p = (char *) malloc( 100 );
}
void Test( void )
{
char *str = NULL;
GetMemory( str );
strcpy( str, "hello world" );
printf( str );
}
以上代码str并不能申请到空间。
传入中GetMemory( char *p )函数的形参为字符串指针,在函数内部修改形参并不能真正的改变传入形参的实参值,执行完
1 2 |
|
后的str仍然为NULL;
1:传入形参并不能真正改变形参的值,执行完之后为空;
2:在函数GetMemory中和Test中没有malloc对应的free,造成内存泄露
下面代码会出现什么问题?
char *GetMemory( void )
{
char p[] = "hello world";
return p;
}
void Test( void )
{
char *str = NULL;
str = GetMemory();
printf( str );
}
p的作用域在栈空间中,p会被自动释放,这样str找不到p,必须在函数用malloc在堆空间中申请内存。
下面代码会出现什么问题?
void Test( void )
{
char *str = (char *) malloc( 100 );
strcpy( str, "hello" );
free( str );
... //省略的其它语句
}
需要加一句str=NULL, 防止野指针的出现。
看看下面的一段程序有什么错误?
swap( int* p1,int* p2 )
{
int *p;
*p = *p1;
*p1 = *p2;
*p2 = *p;
}
显然前面,需要加入void关键字, p是一个野指针,这里不需要用指针p,只需要用一个临时变量p
void swap( int* p1,int* p2 )
{
int p;
p = *p1;
*p1 = *p2;
*p2 = p;
}
void Func ( char str[100] )
{
sizeof( str ) = ?
}
void *p = malloc( 100 );
sizeof ( p ) = ?
函数中sizeof(str)=4
p就是一个指针,所以p=4
编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”如果n=2,移位后应该是“hiabcdefg” 函数头是这样的:
//pStr是指向以'\0'结尾的字符串的指针
//steps是要求移动的n
如果借助辅助空间,可以在O(N)的时间完成,先将后面n个字符拷贝到temp中,再将前面字符拷贝到后面位置,再将temp拷贝到前面位置。
void LoopMove(char *str, int steps)
{
int len = strlen(str);
char tmp[MAXSIZE];
memcpy(tmp, str + len - steps, steps); // 将str+len-steps到str+len的字符串拷贝到temp
memcpy(str + steps, str, len - steps); // 将str到str+len-steps的字符串拷贝到str
memcpy(str, tmp, steps); // 将temp到temp+steps的字符串拷贝到str
}
或者:
void LoopMove(char *str, int steps)
{
int len = strlen(str);
char tmp[MAXSIZE];
strcpy(tmp, str + len - steps); // 将str+len-steps到结尾拷贝到temp
strcpy(tmp + steps, str); // 将str到结尾拷贝到tmp+steps
*(tmp + len) = '/0'; // 将temp中的结尾阶段为temp+len
strcpy(str, tmp); // 再将temp拷贝给str
}
可以用O(N^2)的算法一位一位的将后面的字符串移动到前面去,存在一种O(N)的算法是反转三次
第一次整个字符串反转,第二次前面steps个字符串反转,第三次后面steps个字符串反转
class Solution {
public:
string LeftRotateString(string str, int n) {
reverse(str.begin(),str.end());
reverse(str.begin(),str.end()-n);
reverse(str.begin()+str.size()-n,str.end());
return str;
}
};
编写类String的构造函数、析构函数和赋值函数,已知类String的原型为:
class String
{
public:
String(const char *str = NULL); // 普通构造函数
String(const String &other); // 拷贝构造函数
~ String(void); // 析构函数
String & operator =(const String &other); // 赋值函数
private:
char *m_data; // 用于保存字符串
};
//普通构造函数
String::String(const char *str)
{
if(str==NULL)
{
m_data = new char[1]; // 得分点:对空字符串自动申请存放结束标志'\0'的空
//加分点:对m_data加NULL 判断
*m_data = '\0';
}
else
{
int length = strlen(str);
m_data = new char[length+1];
strcpy(m_data, str);
}
}
// String的析构函数
String::~String(void)
{
delete [] m_data;
}
//拷贝构造函数
String::String(const String &other) // 得分点:输入参数为const型
{
int length = strlen(other.m_data);
m_data = new char[length+1];
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];
strcpy( m_data, other.m_data );
return *this; //得分点:返回本对象的引用
}
赋值函数需要释放掉原来的空间,重新建立空间开始深拷贝,这是要防止自赋值的情况,拷贝构造不用干掉自己,因为拷贝构造也是构造,无中生有