strcpy函数的C/C++实现

时间:2022-09-05 22:51:10

2013-07-05 14:07:49

本函数给出了几种strcpy与strncpy的实现,有ugly implementation,也有good implementation。并参考标准库中的implementation,最后给出了比较好的implementation。

字符串复制,一个一个字符进行判断,直到最后一个结束符。

问题:

*与++的优先级问题:

根据《C缺陷与C陷阱》上的说法,两者是同一个优先级,结合性是从右向左。但*p++的含义却是先得到*p的值,之后再对指针p加1,具体实例见文章:http://www.cnblogs.com/youngforever/p/3171283.html

因此,

while ( (*dst = *src) != '\0')

dst++;  

*src++;

可简写为:

while ( (*dst = *src) != '\0') ;

又因为'\0'的ASCII值就是0,因此while ( (*dst++ = *src++) != '\0') ;  可简写为while ( *dst++ = *src++ ) ;

 并注意到结束时字符串结束符'\0'已经复制,因为是先复制再判断的。

小结:

标准库函数并没有输入合法性检查,这将输入合法性检查的任务推给了函数的调用者。
对于strcpy函数,好的implementation要考虑一下几点:

    1. 函数src参数应为const,dst参数为非const;
    2. 函数要返回dst的地址,以方便嵌套使用该函数;
    3. 函数返回的dst的地址不要为const类型;
    4. 确定dst要有字符串结束符;
    5. 注意输入合法性检查注意输入合法性检查。

对于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 #include <iostream>
  2 
  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 //不好的implementation
102 //因为参数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 //标准库函数的implementation
125 char *  _strncpy_2 (
126     char * dest,
127     const char * source,
128     size_t count
129     )
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 count
152     )
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     //_strcpy
179     char src_1[SIZE] = "hello world!";
180     char dst[SIZE] = "\0";
181 
182     cout<<"test _strcpy_1..."<<endl;
183     cout<<"the src string is : "<<src_1<<endl;
184     _strcpy_1(dst,src_1);
185     cout<<"the dst string is : "<<dst<<endl;
186 
187     char src_2[SIZE] = "hello!";
188     cout<<"test _strcpy_2..."<<endl;
189     cout<<"the src string is : "<<src_2<<endl;
190     _strcpy_2(dst,src_2);
191     cout<<"the dst string is : "<<dst<<endl;
192 
193     char src_3[SIZE] = "happy birthday!";
194     cout<<"test _strcpy_3..."<<endl;
195     cout<<"the src string is : "<<src_3<<endl;
196     _strcpy_3(dst,src_3);
197     cout<<"the dst string is : "<<dst<<endl;
198 
199     char *src_null = NULL;  //不能这样赋值,报错:cannot convert from 'int' to 'char [100]'
200     //cout<<"test _strcpy_3(src == NULL )..."<<endl;
201     ////cout<<"the src string is : "<<src_3<<endl;
202     //_strcpy_3(dst,src_null);
203     //cout<<"the dst string is : "<<dst<<endl;
204 
205     char src_4[SIZE] = "happy!";
206     cout<<"test _strcpy_4..."<<endl;
207     cout<<"the src string is : "<<src_4<<endl;
208     _strcpy_4(dst,src_4);
209     cout<<"the dst string is : "<<dst<<endl;
210 
211     cout<<"test _strcpy_4(src == NULL )..."<<endl;
212     _strcpy_4(dst,src_null);
213     cout<<"the dst string is : "<<dst<<endl;
214 
215     //_strncpy
216     char dst_2[SIZE] = "\0";
217     size_t count = 4;
218     cout<<"test _strncpy_1..."<<endl;
219     cout<<"the src string is : "<<src_1<<endl;
220     cout<<"the number to copy is : "<<count<<endl;
221     _strncpy_1(dst_2,src_1,count);
222     cout<<"the dst_2 string is : "<<dst_2<<endl;
223 
224     count = 20;
225     cout<<"test _strncpy_1..."<<endl;
226     cout<<"the src string is : "<<src_1<<endl;
227     cout<<"the number to copy is : "<<count<<endl;
228     _strncpy_1(dst_2,src_1,count);
229     cout<<"the dst_2 string is : "<<dst_2<<endl;
230 
231     count = 4;
232     cout<<"test _strncpy_2..."<<endl;
233     cout<<"the src string is : "<<src_1<<endl;
234     cout<<"the number to copy is : "<<count<<endl;
235     _strncpy_2(dst_2,src_1,count);
236     cout<<"the dst_2 string is : "<<dst_2<<endl;
237 
238     count = 20;
239     cout<<"test _strncpy_2..."<<endl;
240     cout<<"the src string is : "<<src_1<<endl;
241     cout<<"the number to copy is : "<<count<<endl;
242     _strncpy_2(dst_2,src_1,count);
243     cout<<"the dst_2 string is : "<<dst_2<<endl;
244 
245     count = 4;
246     cout<<"test _strncpy_3..."<<endl;
247     cout<<"the src string is : "<<src_1<<endl;
248     cout<<"the number to copy is : "<<count<<endl;
249     _strncpy_3(dst_2,src_1,count);
250     cout<<"the dst_2 string is : "<<dst_2<<endl;
251 
252     count = 20;
253     cout<<"test _strncpy_3..."<<endl;
254     cout<<"the src string is : "<<src_1<<endl;
255     cout<<"the number to copy is : "<<count<<endl;
256     _strncpy_3(dst_2,src_1,count);
257     cout<<"the dst_2 string is : "<<dst_2<<endl;
258 
259     return 0;
260 }

运行结果(分别测试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 : 4
18 the dst_2 string is : hell
19 test _strncpy_1...
20 the src string is : hello world!
21 the number to copy is : 20
22 the dst_2 string is : hello world!
23 test _strncpy_2...
24 the src string is : hello world!
25 the number to copy is : 4
26 the dst_2 string is : hello world!
27 test _strncpy_2...
28 the src string is : hello world!
29 the number to copy is : 20
30 the dst_2 string is : hello world!
31 test _strncpy_3...
32 the src string is : hello world!
33 the number to copy is : 4
34 the dst_2 string is : hell
35 test _strncpy_3...
36 the src string is : hello world!
37 the number to copy is : 20
38 the dst_2 string is : hello world!
39 请按任意键继续. . .

从运行结果可以看出,