字符串反转
找工作前写了篇blog说要做些常见的笔试面试题,像单链表反转啊字符串反转啊之类的题目,但是只写了一篇单链表反转就没再继续写下去,因为觉得实 在没什么好写的,不过都是一些简单的指针操作罢了,但是还是有很多新手问这个问题,而且我在腾讯二面的时候也被要求实现这个函数,那我也写一篇blog介 绍一下字符串反转吧。
C语言中所谓的字符串不过是字符数组,后跟一个0x00字符标识结尾,所以反转起来很容易,只要一个循环依次将第一个字符和最后一个字符交换, 第二个字符和倒数第二个字符交换……如果最中间有两个字符(即需要反转的字符串长度为偶数),那就交换,如果最中间有一个字符(即需要反转的字符串长度为 奇数),那就不需要碰它。还有就是最后一个用来标识字符串结尾的0x00字符不用动它。
这道题目通常是考察三个方面,一是对指针和字符串的理解,二是是否进行合法性检查,例如输入参数为空指针时是否进行检查,三是返回值是否是恰当,即使你通过参数返回了反转后的字符串指针,也建议在返回值里再返回一下,就像strcpy函数实 现的那样。其实还有第四点往往是大家都忽略了的,那就是Unicode问题,如果传入的字符串指针指向的是Unicode字符串,那么反转的时候就不能一 个字符一个字符的处理了,不过似乎大多数面试官都没对这一点有过要求,如果你在笔试或面试中遇到这个问题,我建议你想监考或面试官询问一下是否需要考虑 Unicode。我面试的时候因为被面试官弄的很紧张,也忘记了这点,写完后检查代码准备交过去时才想起来,索性就当不知道这回事……呵呵。
有了上面这几点,我们就可以很容易地用C语言写出这个函数了。
char *revstr(char *str, size_t len)
{
char *start = str;
char *end = str + len - 1;
char ch;
if (str != NULL)
{
while (start < end)
{
ch = *start;
*start++ = *end;
*end-- = ch;
}
}
return str;
}
代码很简单,就不多介绍了,只是为什么我给这个函数叫revstr而不是strrev呢?我开始时也是给它叫strrev,只是链接时却出错 了,这时我才发现VS2005的C++编译器已经在string.h中中提供了一个strrev函数(这看起来并不是C标准库函数,我不知道还有哪些编译 器提供了这个函数),如果你安装了crt代码包的话可以找到这个函数的实现。我们来看一下它是如何实现的吧。
char * __cdecl _strrev (
char * string
)
{
char *start = string;
char *left = string;
char ch;
while (*string++) /* find end of string */
;
string -= 2;
while (left < string)
{
ch = *left;
*left++ = *string;
*string-- = ch;
}
return(start);
}
这与我上面给出的函数并没有什么本质的不同,只是只传入了一个参数,并没有传入字符串长度,但是我觉得还是传入这个长度比较好,因为有可能我们 并不想反转整个字符串,如果采用我给出的那种实现,一个长度为10的字符串,我们只想反转前7个字符也是可以的。还有就是微软给出的这个实现并没有判断是 否传入空指针,不过我觉得这并不是个大问题,这要取决于你的具体期望,就像我在启明星辰的笔试中遇到了一道题目,要求我实现一个函数将传入的字符串中的小 写字母转换成大写字母,那么如果传入的字符串是小写字母和数字混合的呢?函数应该出错还是应该跳过数字继续处理?两种方式都没错,怎么选择要取决于你或者 阅卷人对这个函数的期望,在笔试或面试中你可以询问监考活面试官,如果没有得到准确的描述,你怎么实现都是正确的。