strcpy函数的C/C++实现
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要考虑一下几点:
- 函数src参数应为const,dst参数为非const;
- 函数要返回dst的地址,以方便嵌套使用该函数;
- 函数返回的dst的地址不要为const类型;
- 确定dst要有字符串结束符;
- 注意输入合法性检查注意输入合法性检查。
对于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++实现的更多相关文章
- strcpy函数的实现
strcpy函数的实现 大家一般认为名不见经传strcpy函数实现不是很难,流行的strcpy函数写法是: char *my_strcpy(char *dst,const char *src) { a ...
- strcpy函数实现
1,strcpy最简便实现 char * strcpy_to (char *dst, const char *src) { char *address = dst; assert((dst != NU ...
- strcpy函数和strncpy函数的区别
strcpy函数和strncpy函数的原型介绍在我的另一篇文章中介绍了,见strcpy,strncpy,strlen等函数原型 strcpy:字串复制 原型:char *strcpy(char *de ...
- memcpy、memmove、memset及strcpy函数实现和理解
memcpy.memmove.memset及strcpy函数实现和理解 关于memcpy memcpy是C和C++ 中的内存拷贝函数,在C中所需的头文件是#include<string.h> ...
- strlen() 和 strcpy()函数
strlen() 和 strcpy()函数的区别,这两个一个是返回一个C风格字符串的长度,一个是对一个C风格字符串的拷贝,两个本来功能上是不同的,此外,他们还有一些细小的区别:strlen(" ...
- strcpy函数导致release版程序崩溃
最近在写一个读取模型文件的小程序.很随意的使用了strcpy函数进行char字符数组的拷贝,这个数组是需要传递给PostMessage作为WPARAM的参数.代码部分如下: char pStrCurr ...
- strcmp函数和strcpy函数
(一)strcmp函数 strcmp函数是比較两个字符串的大小,返回比較的结果.一般形式是: i=strcmp(字符串,字符串); 当中,字符串1.字符串2均可为字符串常量或变量:i 是用于存放比 ...
- 第九十六题(编写strcpy 函数)
96.08 年中兴校园招聘笔试题 1.编写strcpy 函数 已知strcpy 函数的原型是 char *strcpy(char *strDest, const char *strSrc); 当中st ...
- strcpy函数
不调用C/C++库函数,编写strcpy()函数. char * my_strcpy(char *strDest,const char *strSrc) { char *p=strDest; whil ...
随机推荐
- L008-oldboy-mysql-dba-lesson08
L008-oldboy-mysql-dba-lesson08 xtrabackup安装 [root@web01 installer]# wget https://www.percona.com/dow ...
- Redis源码研究--字符串
之前看的内容,占个位子,以后补上. ------------8月2日------------- 好久没看了,惭愧,今天抽了点时间重新看了Redis的字符串,一边写博客,一边看. Redis的字符串主要 ...
- php判断服务器是否支持Gzip压缩功能
Gzip可以压缩网页大小从而达到加速打开网页的速度,目前主流的浏览器几乎都支持这个功能,但开启Gzip是需要服务器支持的,在这里我们简单的使用php来判断服务器是否支持Gzip功能. 新建一个php类 ...
- Spark Streaming揭秘 Day14 State状态管理
Spark Streaming揭秘 Day14 State状态管理 今天让我们进入下SparkStreaming的一个非常好用的功能,也就State相关的操作.State是SparkStreaming ...
- javac mac 终端乱码
java和javac在简体中文的Mac OSX的终端(Terminal.app)环境下,默认是以GBK编码的中文输出各种诸如语法错误,数组访问越界之类的信息.但是,Mac的终端的默认编码是UTF-8, ...
- 【NHibernate】配置- sql打印
<property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property> <pr ...
- 【BZOJ 3171】 [Tjoi2013]循环格
Description 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子.每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0).给定一个起始位置(r,c) ,你可以沿着箭头防线在格 ...
- 【BZOJ 1031】[JSOI2007]字符加密Cipher
Description 喜欢钻研问题的JS 同学,最近又迷上了对加密方法的思考.一天,他突然想出了一种他认为是终极的加密办法:把需要加密的信息排成一圈,显然,它们有很多种不同的读法.例如下图,可以读作 ...
- submit与button区别提交区别
提交表单时使用submit会自动提交form表单数据, 如果使用jquery的form表单插件时需要将提交按钮改为button时$("#表单id").ajaxSubmit({}); ...
- shell 实现word count
awk '{arr[$2]+=$1}END{for (i in arr) print i,arr[i]}' sort_all.txt | sort -k2nr -g