2013-07-05 14:07:49
本函数给出了几种strcpy与strncpy的实现,有ugly implementation,也有good implementation。并参考标准库中的implementation,最后给出了比较好的implementation。
字符串复制,一个一个字符进行判断,直到最后一个结束符。
问题:
*与++的优先级问题:
根据《C缺陷与C陷阱》上的说法,两者是同一个优先级,结合性是从右向左。但*p++的含义却是先得到*p的值,之后再对指针p加1,具体实例见文章:
因此,
while ( (*dst = *src) != '\0')
dst++;
*src++;
可简写为:
while ( (*dst = *src) != '\0') ;
又因为'\0'的ASCII值就是0,因此while ( (*dst++ = *src++) != '\0') ; 可简写为while ( *dst++ = *src++ ) ;
并注意到结束时字符串结束符'\0'已经复制,因为是先复制再判断的。
小结:
标准库函数并没有输入合法性检查,这将输入合法性检查的任务推给了函数的调用者。
对于strcpy函数,好的implementation要考虑一下几点:-
- 函数src参数应为const,dst参数为非const;
- 函数要返回dst的地址,以方便嵌套使用该函数;
- 函数返回的dst的地址不要为const类型;
- 确定dst要有字符串结束符;
- 注意输入合法性检查注意输入合法性检查。
对于strncpy函数,除了以上几点外,好的implementation还要考虑一下几点:
当source的长度小于count时,应该怎么办?标准库函数的做法是,对dst大于source长度、小于count的部分赋值为\0;但在当source的长度大于count时。赋值到dst中的字符串是没有结束符的,在下面的运行结果中_strncpy_2的测试部分可以看到;这是因为代码中只这样写的:
1 while (count && (*dest++ = *source++)) /* copy string */2 count--;3 4 if (count) /* pad out with zeroes */5 while (--count)6 *dest++ = '\0';
这样在当source的长度大于或等于count时,就不会执行下面的if语句,而上面的while条件判断由于是先判断count的值,后复制的,因此,在count减为0时,刚好复制完最后一个有效字符,即 \0 的前一个字符,而没有复制\0.
如果要想使得source的长度大于count时,复制到dst中的字符串也有结束符,_strncpy_3函数可以做到这一点;
注意若while中的换为(*dest++ = *source++) && count,结果就会不同,即:
1 while ( (*dest++ = *source++) && count )2 count--;
这样写,就会在source长度大于count时,多复制一个字符,因为count为0时,*source不是\0,仍会惊醒复制曹组,之后才会判断count的值。
代码:
1 #include2 3 using namespace std; 4 #define SIZE 100 5 6 7 /*** 8 *char *strcpy(dst, src) - copy one string over another 9 * 10 *Purpose: 11 * Copies the string src into the spot specified by 12 * dest; assumes enough room. 13 * 14 *Entry: 15 * char * dst - string over which "src" is to be copied 16 * const char * src - string to be copied over "dst" 17 * 18 *Exit: 19 * The address of "dst" 20 * 21 *Exceptions: 22 *******************************************************************************/ 23 24 const char * _strcpy_1(char *dst,const char *src) 25 { 26 if (NULL == src || NULL == dst) 27 { 28 return NULL; 29 } 30 char *dst_ret = dst; 31 //const char *dst_ret = dst; 32 while ( (*dst++ = *src++) != '\0') ; //*的优先级高于++,结束时'\0'已经复制 33 return dst_ret; 34 } 35 36 char * _strcpy_2(char *dst,const char *src) 37 { 38 if (NULL == src || NULL == dst) 39 { 40 return NULL; 41 } 42 char *dst_ret = dst; 43 //const char *dst_ret = dst; //返回值不需要是const类型的 44 while ( (*dst++ = *src++) != '\0') ; //*的优先级高于++ 45 return dst_ret; 46 } 47 48 //标准库函数给出的implementation,没有输入合法性检查 49 char * _strcpy_3(char *dst,const char *src) 50 { 51 char *cp = dst; 52 53 while ( *cp++ = *src++ ) 54 ; /* Copy src over dst */ 55 56 return ( dst ); 57 } 58 59 //标准库函数给出的implementation,加上输入合法性检查 60 //好的implementation要考虑一下几点: 61 //1)函数src参数应为const,dst参数为非const 62 //2)注意输入合法性检查 63 char * _strcpy_4(char *dst,const char *src) 64 { 65 if (NULL == src || NULL == dst) 66 { 67 return NULL; 68 } 69 70 char *cp = dst; 71 72 while ( *cp++ = *src++ ) 73 ; /* Copy src over dst */ 74 75 return ( dst ); 76 } 77 78 /*** 79 *char *strncpy(dest, source, count) - copy at most n characters 80 * 81 *Purpose: 82 * Copies count characters from the source string to the 83 * destination. If count is less than the length of source, 84 * NO NULL CHARACTER is put onto the end of the copied string. 85 * If count is greater than the length of sources, dest is padded 86 * with null characters to length count. 87 * 88 * 89 *Entry: 90 * char *dest - pointer to destination 91 * char *source - source string for copy 92 * unsigned count - max number of characters to copy 93 * 94 *Exit: 95 * returns dest 96 * 97 *Exceptions: 98 * 99 *******************************************************************************/100 101 //不好的implementation102 //因为参数count为int,且在src的长度小于count时,dst后面的没有处理103 char * _strncpy_1(char *dst,const char *src,int count)104 {105 if (NULL == src || NULL == dst)106 {107 return NULL;108 }109 char *cp = dst;110 int current_count = 0;111 //while ( (*cp++ = *src++) != '\0' && current_count != count) 112 // ++current_count;113 114 //*(cp - 1) = '\0'; //结束符115 116 while ( current_count != count && (*cp++ = *src++) != '\0') 117 ++current_count;118 119 *cp = '\0'; //结束符120 121 return ( dst );122 }123 124 //标准库函数的implementation125 char * _strncpy_2 (126 char * dest,127 const char * source,128 size_t count129 )130 {131 char *start = dest;132 133 while (count && (*dest++ = *source++)) /* copy string */134 count--;135 136 if (count) /* pad out with zeroes */137 while (--count)138 *dest++ = '\0'; //在sorce的长度小于count时,后面不补'\0',只是将source的前面count个字符覆盖,后面的不变139 140 return(start);141 }142 143 //标准库函数的implementation,加上输入合法性检查144 //好的implementation要考虑一下几点:145 //1)输入source为const,dest为非const,count为size_t类型146 //2)在sorce的长度小于count时,后面补'\0'147 //3)在sorce的长度大于count时,同样有结束符'\0'148 char * _strncpy_3 (149 char * dest,150 const char * source,151 size_t count152 )153 {154 if (NULL == source || NULL == dest)155 {156 return NULL;157 }158 159 char *start = dest;160 161 while (count && (*dest++ = *source++)) /* copy string */162 count--; //若while中的换为(*dest++ = *source++) && count,结果就会不同163 164 //*(dest - 1) = '\0'; //结束符165 *dest = '\0'; //在sorce的长度小于count时,后面补'\0'166 167 if (count) /* pad out with zeroes */168 while (--count)169 *dest++ = '\0';170 171 return(start);172 }173 174 175 //测试程序176 int main()177 {178 //_strcpy179 char src_1[SIZE] = "hello world!";180 char dst[SIZE] = "\0";181 182 cout<<"test _strcpy_1..."<
运行结果(分别测试count大于、以及小于source长度的情形):
1 test _strcpy_1... 2 the src string is : hello world! 3 the dst string is : hello world! 4 test _strcpy_2... 5 the src string is : hello! 6 the dst string is : hello! 7 test _strcpy_3... 8 the src string is : happy birthday! 9 the dst string is : happy birthday!10 test _strcpy_4...11 the src string is : happy!12 the dst string is : happy!13 test _strcpy_4(src == NULL )...14 the dst string is : happy!15 test _strncpy_1...16 the src string is : hello world!17 the number to copy is : 418 the dst_2 string is : hell19 test _strncpy_1...20 the src string is : hello world!21 the number to copy is : 2022 the dst_2 string is : hello world!23 test _strncpy_2...24 the src string is : hello world!25 the number to copy is : 426 the dst_2 string is : hello world!27 test _strncpy_2...28 the src string is : hello world!29 the number to copy is : 2030 the dst_2 string is : hello world!31 test _strncpy_3...32 the src string is : hello world!33 the number to copy is : 434 the dst_2 string is : hell35 test _strncpy_3...36 the src string is : hello world!37 the number to copy is : 2038 the dst_2 string is : hello world!39 请按任意键继续. . .
从运行结果可以看出,