【样本】
——陈良乔 ,《C程序设计伴侣》,人民邮电出版社,2012年10月,p116
【评析】
作者认为“截取字符串”也是“常见的字符串处理任务”是武断的。C语言函数库中并不需要这样的函数,因为这种操作并非是对字符串的一个基本操作。
【样本】
——陈良乔 ,《C程序设计伴侣》,人民邮电出版社,2012年10月,p116
【评析】
这里对函数参数的分析虽然不能说有错,但却因为不够彻底而臃余。因为描述源字符串中的一段,应该只需要2个参数就足够了。例如,如果要说明"ABCDE"中的第2个字符开始3个字符,并不需要"ABCDE",2和3这三个实参,"ABCDE"+(2-1) 和 3就足够了。
【样本】
——陈良乔 ,《C程序设计伴侣》,人民邮电出版社,2012年10月,p116
【评析】
这个函数的参数很怪异。首先pos、n都是对source的进一步明确,但却被dest这个参数割裂开来;其次,习惯上C语言函数约定俗成的习惯是把dest放在前面,把描述source的参数放在后面。但这个函数却违背了业界共同遵守的公序良俗。
函数内部的
for( int i=0 ; i < n ; ++i ) { dest[i] = source[pos+i]; }
的问题是,根本就没有考虑到在source的第pos~第pos+n-1个字符中存在\0的情形。既然是拷贝字符串,遇到\0则应该终止。但这个函数却不是这样,遇到\0它会固执地继续copy下去,直到copy完n个字符为止,哪怕有些是没用的不需要copy的。这不但降低了程序性能,在有些情况下还是一种UB错误。例如如下调用就存在这种错误:
strsub("ABC",dest,0,5);
错误在于会访问到"ABC"范围之外,在C语言中这是一种Undefined behavior。
这个函数的正确写法应该是:
void strsub( char *dest , char *source , int n ) { while( n -- > 0) if( ( *dest ++ = *source ++ ) == '\0' ) return ; *dest = '\0'; }
【样本】
——陈良乔 ,《C程序设计伴侣》,人民邮电出版社,2012年10月,p116~117
【评析】
很遗憾,作者想到了使用memcpy(),却没注意到memcpy()只用了三个参数,这已经足以说明strsub()参数设计上的画蛇添足了。
此外,使用memcpy()依然存在copy多余字符的低效行为以及越界访问的错误。
【样本】
——陈良乔 ,《C程序设计伴侣》,人民邮电出版社,2012年10月,p117
【评析】
正如前面分析所指出的那样,两个strsub()都是错误的。即使抛开这点不谈,说第二个写法效率高于第一个写法也是毫无根据的。此外C语言程序也并非永远把性能作为追求的目标。
作者的这两个strsub()其实都不“简单”,因为压根用不着写这种strsub()函数。strsub()的功能通过简单的一次函数调用就能实现:
strncpy(dest,source+pos,n);
【样本】
——陈良乔 ,《C程序设计伴侣》,人民邮电出版社,2012年10月,p117
【评析】
这个测试及后面长篇大论的说明非常搞笑,而且非常令人费解。
首先,作者没有考虑strstr(suorce,begin)返回值为NULL的可能性。此时程序会发生一个严重的错误(strlen(ppos)调用没有意义)。
其次,如果strstr(suorce,begin)返回值不为NULL,那么main()所做的事情无非是
#include <stdio.h> #include <string.h> int main( void ) { char *begin = "live"; char substr[256]; strcpy(substr,begin); puts(substr); return 0; }
而已。其余神马的全是浮云。