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的测试部分可以看到;这是因为代码中只这样写的:

 while (count && (*dest++ = *source++))    /* copy string */
count--; if (count) /* pad out with zeroes */
while (--count)
*dest++ = '\0';

这样在当source的长度大于或等于count时,就不会执行下面的if语句,而上面的while条件判断由于是先判断count的值,后复制的,因此,在count减为0时,刚好复制完最后一个有效字符,即 \0 的前一个字符,而没有复制\0.

如果要想使得source的长度大于count时,复制到dst中的字符串也有结束符,_strncpy_3函数可以做到这一点;

注意若while中的换为(*dest++ = *source++) && count,结果就会不同,即:

 while ( (*dest++ = *source++) && count )
count--;

这样写,就会在source长度大于count时,多复制一个字符,因为count为0时,*source不是\0,仍会惊醒复制曹组,之后才会判断count的值。


代码:

 #include <iostream>

 using namespace std;
#define SIZE 100 /***
*char *strcpy(dst, src) - copy one string over another
*
*Purpose:
* Copies the string src into the spot specified by
* dest; assumes enough room.
*
*Entry:
* char * dst - string over which "src" is to be copied
* const char * src - string to be copied over "dst"
*
*Exit:
* The address of "dst"
*
*Exceptions:
*******************************************************************************/ const char * _strcpy_1(char *dst,const char *src)
{
if (NULL == src || NULL == dst)
{
return NULL;
}
char *dst_ret = dst;
//const char *dst_ret = dst;
while ( (*dst++ = *src++) != '\0') ; //*的优先级高于++,结束时'\0'已经复制
return dst_ret;
} char * _strcpy_2(char *dst,const char *src)
{
if (NULL == src || NULL == dst)
{
return NULL;
}
char *dst_ret = dst;
//const char *dst_ret = dst; //返回值不需要是const类型的
while ( (*dst++ = *src++) != '\0') ; //*的优先级高于++
return dst_ret;
} //标准库函数给出的implementation,没有输入合法性检查
char * _strcpy_3(char *dst,const char *src)
{
char *cp = dst; while ( *cp++ = *src++ )
; /* Copy src over dst */ return ( dst );
} //标准库函数给出的implementation,加上输入合法性检查
//好的implementation要考虑一下几点:
//1)函数src参数应为const,dst参数为非const
//2)注意输入合法性检查
char * _strcpy_4(char *dst,const char *src)
{
if (NULL == src || NULL == dst)
{
return NULL;
} char *cp = dst; while ( *cp++ = *src++ )
; /* Copy src over dst */ return ( dst );
} /***
*char *strncpy(dest, source, count) - copy at most n characters
*
*Purpose:
* Copies count characters from the source string to the
* destination. If count is less than the length of source,
* NO NULL CHARACTER is put onto the end of the copied string.
* If count is greater than the length of sources, dest is padded
* with null characters to length count.
*
*
*Entry:
* char *dest - pointer to destination
* char *source - source string for copy
* unsigned count - max number of characters to copy
*
*Exit:
* returns dest
*
*Exceptions:
*
*******************************************************************************/ //不好的implementation
//因为参数count为int,且在src的长度小于count时,dst后面的没有处理
char * _strncpy_1(char *dst,const char *src,int count)
{
if (NULL == src || NULL == dst)
{
return NULL;
}
char *cp = dst;
int current_count = ;
//while ( (*cp++ = *src++) != '\0' && current_count != count)
// ++current_count; //*(cp - 1) = '\0'; //结束符 while ( current_count != count && (*cp++ = *src++) != '\0')
++current_count; *cp = '\0'; //结束符 return ( dst );
} //标准库函数的implementation
char * _strncpy_2 (
char * dest,
const char * source,
size_t count
)
{
char *start = dest; while (count && (*dest++ = *source++)) /* copy string */
count--; if (count) /* pad out with zeroes */
while (--count)
*dest++ = '\0'; //在sorce的长度小于count时,后面不补'\0',只是将source的前面count个字符覆盖,后面的不变 return(start);
} //标准库函数的implementation,加上输入合法性检查
//好的implementation要考虑一下几点:
//1)输入source为const,dest为非const,count为size_t类型
//2)在sorce的长度小于count时,后面补'\0'
//3)在sorce的长度大于count时,同样有结束符'\0'
char * _strncpy_3 (
char * dest,
const char * source,
size_t count
)
{
if (NULL == source || NULL == dest)
{
return NULL;
} char *start = dest; while (count && (*dest++ = *source++)) /* copy string */
count--; //若while中的换为(*dest++ = *source++) && count,结果就会不同 //*(dest - 1) = '\0'; //结束符
*dest = '\0'; //在sorce的长度小于count时,后面补'\0' if (count) /* pad out with zeroes */
while (--count)
*dest++ = '\0'; return(start);
} //测试程序
int main()
{
//_strcpy
char src_1[SIZE] = "hello world!";
char dst[SIZE] = "\0"; cout<<"test _strcpy_1..."<<endl;
cout<<"the src string is : "<<src_1<<endl;
_strcpy_1(dst,src_1);
cout<<"the dst string is : "<<dst<<endl; char src_2[SIZE] = "hello!";
cout<<"test _strcpy_2..."<<endl;
cout<<"the src string is : "<<src_2<<endl;
_strcpy_2(dst,src_2);
cout<<"the dst string is : "<<dst<<endl; char src_3[SIZE] = "happy birthday!";
cout<<"test _strcpy_3..."<<endl;
cout<<"the src string is : "<<src_3<<endl;
_strcpy_3(dst,src_3);
cout<<"the dst string is : "<<dst<<endl; char *src_null = NULL; //不能这样赋值,报错:cannot convert from 'int' to 'char [100]'
//cout<<"test _strcpy_3(src == NULL )..."<<endl;
////cout<<"the src string is : "<<src_3<<endl;
//_strcpy_3(dst,src_null);
//cout<<"the dst string is : "<<dst<<endl; char src_4[SIZE] = "happy!";
cout<<"test _strcpy_4..."<<endl;
cout<<"the src string is : "<<src_4<<endl;
_strcpy_4(dst,src_4);
cout<<"the dst string is : "<<dst<<endl; cout<<"test _strcpy_4(src == NULL )..."<<endl;
_strcpy_4(dst,src_null);
cout<<"the dst string is : "<<dst<<endl; //_strncpy
char dst_2[SIZE] = "\0";
size_t count = ;
cout<<"test _strncpy_1..."<<endl;
cout<<"the src string is : "<<src_1<<endl;
cout<<"the number to copy is : "<<count<<endl;
_strncpy_1(dst_2,src_1,count);
cout<<"the dst_2 string is : "<<dst_2<<endl; count = ;
cout<<"test _strncpy_1..."<<endl;
cout<<"the src string is : "<<src_1<<endl;
cout<<"the number to copy is : "<<count<<endl;
_strncpy_1(dst_2,src_1,count);
cout<<"the dst_2 string is : "<<dst_2<<endl; count = ;
cout<<"test _strncpy_2..."<<endl;
cout<<"the src string is : "<<src_1<<endl;
cout<<"the number to copy is : "<<count<<endl;
_strncpy_2(dst_2,src_1,count);
cout<<"the dst_2 string is : "<<dst_2<<endl; count = ;
cout<<"test _strncpy_2..."<<endl;
cout<<"the src string is : "<<src_1<<endl;
cout<<"the number to copy is : "<<count<<endl;
_strncpy_2(dst_2,src_1,count);
cout<<"the dst_2 string is : "<<dst_2<<endl; count = ;
cout<<"test _strncpy_3..."<<endl;
cout<<"the src string is : "<<src_1<<endl;
cout<<"the number to copy is : "<<count<<endl;
_strncpy_3(dst_2,src_1,count);
cout<<"the dst_2 string is : "<<dst_2<<endl; count = ;
cout<<"test _strncpy_3..."<<endl;
cout<<"the src string is : "<<src_1<<endl;
cout<<"the number to copy is : "<<count<<endl;
_strncpy_3(dst_2,src_1,count);
cout<<"the dst_2 string is : "<<dst_2<<endl; return ;
}

运行结果(分别测试count大于、以及小于source长度的情形):

 test _strcpy_1...
the src string is : hello world!
the dst string is : hello world!
test _strcpy_2...
the src string is : hello!
the dst string is : hello!
test _strcpy_3...
the src string is : happy birthday!
the dst string is : happy birthday!
test _strcpy_4...
the src string is : happy!
the dst string is : happy!
test _strcpy_4(src == NULL )...
the dst string is : happy!
test _strncpy_1...
the src string is : hello world!
the number to copy is :
the dst_2 string is : hell
test _strncpy_1...
the src string is : hello world!
the number to copy is :
the dst_2 string is : hello world!
test _strncpy_2...
the src string is : hello world!
the number to copy is :
the dst_2 string is : hello world!
test _strncpy_2...
the src string is : hello world!
the number to copy is :
the dst_2 string is : hello world!
test _strncpy_3...
the src string is : hello world!
the number to copy is :
the dst_2 string is : hell
test _strncpy_3...
the src string is : hello world!
the number to copy is :
the dst_2 string is : hello world!
请按任意键继续. . .

从运行结果可以看出,

strcpy函数的C/C++实现的更多相关文章

  1. strcpy函数的实现

    strcpy函数的实现 大家一般认为名不见经传strcpy函数实现不是很难,流行的strcpy函数写法是: char *my_strcpy(char *dst,const char *src) { a ...

  2. strcpy函数实现

    1,strcpy最简便实现 char * strcpy_to (char *dst, const char *src) { char *address = dst; assert((dst != NU ...

  3. strcpy函数和strncpy函数的区别

    strcpy函数和strncpy函数的原型介绍在我的另一篇文章中介绍了,见strcpy,strncpy,strlen等函数原型 strcpy:字串复制 原型:char *strcpy(char *de ...

  4. memcpy、memmove、memset及strcpy函数实现和理解

    memcpy.memmove.memset及strcpy函数实现和理解 关于memcpy memcpy是C和C++ 中的内存拷贝函数,在C中所需的头文件是#include<string.h> ...

  5. strlen() 和 strcpy()函数

    strlen() 和 strcpy()函数的区别,这两个一个是返回一个C风格字符串的长度,一个是对一个C风格字符串的拷贝,两个本来功能上是不同的,此外,他们还有一些细小的区别:strlen(" ...

  6. strcpy函数导致release版程序崩溃

    最近在写一个读取模型文件的小程序.很随意的使用了strcpy函数进行char字符数组的拷贝,这个数组是需要传递给PostMessage作为WPARAM的参数.代码部分如下: char pStrCurr ...

  7. strcmp函数和strcpy函数

    (一)strcmp函数 strcmp函数是比較两个字符串的大小,返回比較的结果.一般形式是: i=strcmp(字符串,字符串); 当中,字符串1.字符串2均可为字符串常量或变量:i   是用于存放比 ...

  8. 第九十六题(编写strcpy 函数)

    96.08 年中兴校园招聘笔试题 1.编写strcpy 函数 已知strcpy 函数的原型是 char *strcpy(char *strDest, const char *strSrc); 当中st ...

  9. strcpy函数

    不调用C/C++库函数,编写strcpy()函数. char * my_strcpy(char *strDest,const char *strSrc) { char *p=strDest; whil ...

随机推荐

  1. Less和Sass编译

    使用koala编译 Koala 是一款由国人开发的开源预处理语言图形编译工具,目前已支持 Less.Sass.Compass 与CoffeeScript. 目前支持以下系统:Windows,Mac, ...

  2. jquery 点击查看,收起特效

    <div class="all"> <p><a href="javascript:;" id="onvk"&g ...

  3. js字符串长度计算(一个汉字==两个字符)和字符串截取

    js字符串长度计算(一个汉字==两个字符)和字符串截取 String.prototype.realLength = function() { return this.replace(/[^\x00-\ ...

  4. android 打开GPS的几种方式

    1.在讨论打开gps的之前先看下如何检测gps的开关情况: 方式一: boolean gpsEnabled = locationManager.isProviderEnabled(LocationMa ...

  5. Using jQuery to add a dynamic “Back To Top” floating button with smooth scroll

    Ever read a really long blog post or article and then had to scroll all the way up to the top of the ...

  6. Spark Streaming揭秘 Day11 Receiver Tracker的具体实现

    Spark Streaming揭秘 Day11 Receiver Tracker的具体实现 ReceiverTracker是运行在Driver上Receiver管理程序,今天让我们深入学习一下. 核心 ...

  7. C++ list 类学习笔记

    双向循环链表list list是双向循环链表,,每一个元素都知道前面一个元素和后面一个元素.在STL中,list和vector一样,是两个常被使用的容器.和vector不一样的是,list不支持对元素 ...

  8. [翻译]15个最常见的WCF面试问题

    WCF和ASMX WebService的区别是什么? 最基本的区别在于,ASMX或者ASP.NET WebService是用来通过基于HTTP的SOAP来实现通讯.但WCF可以使用任意协议(HTTP, ...

  9. Torry的困惑(基本型)

    #include<stdio.h> int main() { long long i,j; int n; //用于记录输入的要进行乘积的质数的个数 ; //用于记录前n个质数的乘积,并初始 ...

  10. 使用NPIO操作Excel

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using NPOI.SS. ...