1、strcpy()函数的实现
char *MyStrCopy(char *strDesc, const char *strSource)
{
assert((NULL != strDesc)&&(NULL != strSource));
char *pszTemp = strDesc;
while(((*pszTemp++) = (*strSource++)) != '\0');
return strDesc;
}
strcpy()函数的实现是面试出现率很高的题目,这个函数的实现看起来很简单,只有几行代码,但是这几行代码却能体现一个程序员的很多东西。
首先看传参,一般应把目的字符串作为第一个参数,而源字符串作为第二个参数,这样比较符合人们的习惯;
第二个函数第一行的断言assert(),理论上字符串函数的参数不应为空,所以判空是很有必要的;
然后第三行代码的临时变量的创建,这样逻辑思维更严密;
第四行代码中的'\0'判断,如果不加这个判断说明对数据类型的隐式转换理解的不够深刻;
最后的返回值,是为了支持链式表达式,链式表达式即为了便于拷贝完函数之后直接使用返回值。
所以一个strcpy()函数能够看出你的编码习惯,以及编码风格,及对C语言的基础数据类型的理解。
2、strcmp()函数的实现
int MyStrCmp(const char *strFirst,const char *strSecond)
{
assert((NULL != strFirst)&&(NULL != strSecond));
int iRet = 0;
while(!(iRet = (*(unsigned char*)strFirst)-(*(unsigned char*)strSecond))&&(*strFirst != '\0'))
{
strFirst++;
strSecond++;
}
if (iRet < 0)
{
iRet = -1;
}
else if (iRet > 0)
{
iRet = 1;
}
return iRet;
}
strcmp()函数是比较两个字符串的大小,相等返回0,strFirst大于strSecond时返回1,小于时返回-1,此函数应注意以下几点:
1、字符大小判断时应使用*(unsigned char*)strFirst,而不是*strFirst,因为默认传入的参数为有符号数,但是字符串的ASCII没有负值,若不转化为无符号数这回在减法实现时可能会出现错误,如*strFirst的值为1,而*strSecond的值为255,这时做减法,如果是有符号的,则作为无符号数计算时ret = -254,结果为负值,正确;作为有符号数计算时ret = 2,结果为正值,错误。
2、!(iRet = (*(unsigned char*)strFirst)-(*(unsigned char*)strSecond))&&(*strFirst!='\0')语句中的&&*strFirst的使用,如果没有添加后面的语句,那么当两个字符串相等时,最后都是‘\0’,还是相等所以两个字符串会继续‘++’,这就导致计算结果有误。
3、strcat()函数实现
char *MyStrCat(char *strDesc, const char *strSource)
{
assert((NULL != strDesc)&&(NULL != strSource));
char *pszAddr = strDesc;
while(*strDesc != '\0')
{
strDesc++;
}
while(((*strDesc++) = (*strSource++)) != '\0');
return pszAddr;
}
该函数的实现字符串连接的功能,即把strSourse字符串连接到strDesc的末尾,但是该函数的实现实际上是有问题的,因为如果strDesc容量过小,这时如果连接时就会出现越界问题,这个问题在标准库函数的定义是就存在。该函数的实现在 while(*strDesc != '\0')这句要注意一下,不能直接用 while(*strDesc++ != '\0'),因为如果用后面的语句当while结束时strDesc字符串实际上指向的不是'\0',而是它的下一个位置。
4、strlen()函数的实现
size_t MyStrLen(const char *str)
{
assert(str != NULL);
size_t len = 0;
while((*str++) != '\0')
{
len++;
}
return len;
}
该函数实现的功能是计算字符串的长度,实现相对上面3个函数比较简单,但是使用却是很频繁的。并且strlen函数在计算长度是是不包括'\0'字符的,所以这点应该注意。