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. javascript 事件的学习

    1.事件绑定: addEventListener , removeEventListener.是dom2级别的事件绑定 attachEvent , detachEvent 是IE的事件绑定. 2. 事 ...

  2. [Linux] Linux学习笔记(5)-文件与目录管理

    1.Linux目录结构为树状结构,最顶层的目录为跟目录"/",其它目录通过挂载可以将它添加到目录树中,通过解除挂载移除它们. 2.绝对路径与相对路径 绝对路径写法:由根目录&quo ...

  3. TImage 的一些操作

    //给 image上写数字. Image1.Picture.Bitmap.Height:= Image1.Height; Image1.Picture.Bitmap.Width:= Image1.Wi ...

  4. Pandas简易入门(四)

    本节主要介绍一下Pandas的另一个数据结构:DataFrame,本文的内容来源:https://www.dataquest.io/mission/147/pandas-internals-dataf ...

  5. 获取股票历史数据和当前数据的API

    关键字:股票,stock,API,接口 1.获取股票当前数据 新浪数据接口:http://hq.sinajs.cn/list={code}.{code}替换为股票代码,沪市股票代码加前缀sh,深市股票 ...

  6. CR0,CR3寄存器

    驱动在hook系统函数的时候通常要将只读属性暂时的屏蔽掉,主要有三种方法 1.修改CR0寄存器的WP位,使只读属性失效(这是网上用的最多的方法),切忌使用完之后立马修改回来 2.只读的虚拟地址,通过C ...

  7. Microsoft Office Excel 不能访问文件

    问题描述: Microsoft Office Excel 不能访问文件“XX.xls”.可能的原因有: 1 文件名称或路径不存在.2 文件正被其他程序使用.3 您正要保存的工作簿与当前打开的工作簿同名 ...

  8. 在一个工程管理多个应用-b

    Demo:http://download.csdn.net/detail/u012881779/9166527 本文的产生是因产品经理提出的特殊需求: 一个针对多所学校的应用,对不同学校需要分别使用一 ...

  9. iOS 本地存储四种方法

    在iOS开发过程中,不管是做什么应用,都会碰到数据保存的问题.将数据保存到本地,能够让程序的运行更加流畅,不会出现让人厌恶的菊花形状,使得用户体验更好.下面介绍⼀一下数据保存的方式: 1.NSKeye ...

  10. HighCharts 根据spline-plot-bands图,定制自己的图(区间里显示多个数据)

    公司项目里有这样一个需求,根据数据绘图,但是数据很多,不可能每个点每个点的去画,这样显示的数据太密集非常的难看(更显得技术不专业),如图: 所以我和项目经理商量如何显示这个图形,按照他的意思是,按照范 ...