教C++编程课,遇到学生问了个问题,虽然题目很简单,但要写出足够有趣的代码还是可能的。题目是这样说的,写个函数delchar(char *s1, char s2),从字符串s1中删去所有s2字符。给学生的答案自然要各种规范,并且得避免教学大纲要求不讲的位运算等等内容,不过就编程玩耍而言,这个函数可以极度简单,今天午饭后闲来无事,写了写。我先写的是下面的代码,总共6行有效的函数体。当然这么玩也有缺点,要求s1至少得有1个字符,空字符串貌似是不行的。
char *delchar(char *s1, char s2) { char *t = s1, *p = s1; do *p++ = (*t^s2) ? *t : *p--; while (*t++); *p = 0; return s1; }
当然,如果仍然觉得行数有点多的话,也可以进一步的混乱化,这也避免了限制s1至少一个字符的问题,如下:
char *delchar(char *s1, char s2) { char *t,*p; for (t = p = s1 ; *t++ ; *p++ = (*t ^ s2) ? *t : *p--) ; *p = 0; return s1; }
然后,稍微解释那么一下下上面这是在干啥,这解释纯粹是为了避免某些多事的学生偷窥到这个Blog文章然后纠缠不清。
解决问题的总体思路是这样的:先搞两个指针,一个叫进度指针p,一个叫测试指针t,开始的时候两者都指向原始字符串开头,然后让测试指针开始逐个向后扫描每一个字符,如果遇到字符串结尾,那么就意味着扫描结束了。如果遇到了不应该被删掉的字符,那么就把t的所指内容复制到p所指的地方,然后p和t同步后移,如果遇到了应该删掉的字符,那么t继续后移,而p不动。扫描结束之后,p所指的位置应该就是终止符号’\0’的位置,所以要写上终止符号。需要注意的是’\0’和数值0和逻辑false在C++里面可以认为是等价的。而判断t所指字符是否是s2,可以用==的逻辑判断,也可以用异或计算,至少按照我记忆中的说法,异或要比==快那么一点点。那个看起来很长的for的第三部分,只有一处是有点技巧,就是=左侧和右侧分别是++和–,这使得p在执行删除操作的时候移位效果抵消,而只让t后移。