1.原版的strcpy()函数原型

char * strcpy( char *strDest, const char *strSrc )
{
 assert( (strDest != NULL) && (strSrc != NULL) );
 char *address = strDest;
 while( (*strDest++ = * strSrc++) != ‘\0’ );
 return address;
}

在库函数中,字符的赋值所采用的循环代码,只用了一行代码:while( (*strDest++ = * strSrc++) != ‘\0’ );。It is so beautiful !

2.有哪些问题

  从source 往dest里赋值时,如果dest的长度大于source 的长度,会发生什么情况呢。

  可是有时候我们会不小心把*strScr的长度大于*strDest的长度了 这时会有什么效果呢
就比如:

 char str_dest[10];
char str_scr[20];
strcpy(str_dest, str_scr);

有位大哥做了验证:程序并不会报错,它会继续输出str_scr中的内容;而我的解释是,这是系统依赖的错误。

举个简单的例子:

  # include <stdio.h>
# include <string.h>
int main()
{
char str1[3];
char str2[20]={"this is a test"};
strcpy(str1, str2);
printf("%s\n", str1);
return 0;
}

运行结果:

  this is a test
  这时我们会把目光注视到原函数上,我们发现strcpy的原函数并没有加两个字符串长度的限制条件,它只是把原字符串中的内容一个一个地赋值到目标字符串中,而且到最后还给目标字符串加上了结束符“\0”。那么如果目标字符串长度不够时会怎么样呢? 大哥认为:

  它会继续一个一个地赋值字符。拿上面的例子 str1[3], str2[20]="this is a test", str2往str1里赋值。当str2里的thi 到s 的时候,str1的长度不够了,但是数字中的地址是连续的,比如str1的首地址是1000,那么str1[0]=1000,str1[1]=1001,str1[2]=1002, 这个时候还要继续往str1里赋值,怎么办,地址还会继续增加的,那么继续增加的地址是我们没有申请的空间的,这样的话就会很危险的,如果没有申请的地址空间没有被系统占用还好,如果被系统占用的话系统可能就会崩溃的,所以在使用strcpy函数时要小心谨慎, 原字符串长度要小于目标字符串的长度。

3.ANSI C 中strcpy 的安全版本: strncpy

  在 ANSI C 中,strcpy 的安全版本是 strncpy

char *strncpy(char *s1, const char *s2, size_t n);

但 strncpy 其行为是很诡异的(不符合我们的通常习惯)。标准规定 n 并不是 sizeof(s1),而是要复制的 char 的个数。一个最常见的问题,就是 strncpy 并不帮你保证 '\0'结束。

char buf[8];
strncpy( buf, "abcdefgh", 8 );

看这个程序,buf 将会被 "abcdefgh" 填满,但却没有  '\0'结束符了。

  

  另外,如果 s2 的内容比较少,而 n 又比较大的话,strncpy 将会把之间的空间都用 '\0' 填充。这又出现了一个效率上的问题,如下:

char buf[80];
strncpy( buf, "abcdefgh", 79 );

上面的 strncpy 会填写 79 个 char,而不仅仅是 "abcdefgh" 本身。

strncpy 的标准用法为:(手工写上 '\0' )

strncpy(path, src, sizeof(path) - 1);
path[sizeof(path) - 1] = '/0';
len = strlen(path);

4.有关strcpy的面试题参考 这里 :

  很多公司的面试官在面试程序员的时候,要求应聘者写出库函数strcpy()的工作方式或者叫实现,很多人以为这个题目很简单,实则不然,别看这么一个小小的函数,他可以从三个方面来考查:

(1)编程风格
(2)出错处理
(3)算法复杂度分析(用于提高性能)

如果这个题目10分的话,我们列出2分到10分的答案:
 

2分

void strcpy( char *strDest, char *strSrc )
{
  while( (*strDest++ = * strSrc++) != ‘\0’ );
}

  

4分

void strcpy( char *strDest, const char *strSrc )
//将源字符串加const,表明其为输入参数,加2分
{
  while( (*strDest++ = * strSrc++) != ‘\0’ );
}

  

7分

void strcpy(char *strDest, const char *strSrc)
{
 //对源地址和目的地址加非0断言,加3分
 assert( (strDest != NULL) && (strSrc != NULL) );
 while( (*strDest++ = * strSrc++) != ‘\0’ );
}

  

10分

//为了实现链式操作,将目的地址返回,加3分!
char * strcpy( char *strDest, const char *strSrc )
{
 assert( (strDest != NULL) && (strSrc != NULL) );
 char *address = strDest;
 while( (*strDest++ = * strSrc++) != ‘\0’ )
NULL;
  return address;//引用返回地址,方便链式操作!!
}

  从2分到10分的几个答案我们可以清楚的看到,小小的strcpy竟然暗藏着这么多玄机,真不是盖的!需要多么扎实的基本功才能写一个完美的strcpy啊!

看了不同分值的strcpy版本,应该也可以写出一个10分的strlen函数了,
完美的版本为:

int strlen( const char *str ) //输入参数const

{
 assert( strt != NULL ); //断言字符串地址非0
 int len;
 while( (*str++) != '\0' )
 {
  len++;
 }
 return len;
}

  

 

C语言中strcpy(char *strDest, const char *strScr)字符串复制库函数的理解与分析的更多相关文章

  1. [转载] 已知strcpy的函数原型:char *strcpy(char *strDest, const char *strSrc),编写函数 strcpy(C++版)

    已知strcpy的函数原型:char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串,strSrc 是源字符串.不调用C++/C ...

  2. 字符串复制char *strcpy(char* dest, const char *src);

    ⒈strcpy的实现代码 char * strcpy(char * strDest,const char * strSrc) { if ((NULL==strDest) || (NULL==strSr ...

  3. C语言中strcpy,strcmp,strlen,strcat函数原型

    //strcat(dest,src)把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0' char *strcat(char * strDest, const char ...

  4. C 语言中char* 和const char*的区别

    const char *p = "123"; p[1] = '3'; // 会报错p = "456"; // 不会报错 const char * 只是说指针指向 ...

  5. char* strcpy( char* dest, const char* src ), int binary_search(int *arr, int key, int n), 可能的实现

    #include <stdio.h> char* stringCopy( char* dest, const char* src ) { size_t i = 0; while (dest ...

  6. C++ 字符串、string、char *、char[]、const char*的转换和区别

    1.字符串 字符串本质就是一串字符,在C++中大家想到字符串往往第一反应是std::string(后面简称string) 字符串得从C语言说起,string其实是个类,C语言是没有class的,所以C ...

  7. C++ char*,const char*,string,int 的相互转换

    C++ char*,const char*,string,int 的相互转换   1. string转const char* string s ="abc";const char* ...

  8. 【Qt开发】几个傻不拉几关于char*和const char*的不兼容问题

    1. string转const char* string s ="abc";constchar* c_s = s.c_str(); 2. const char*转string   ...

  9. char*,const char*和string 三者转换

    1. const char* 和string 转换 (1) const char*转换为 string,直接赋值即可. EX: const char* tmp = "tsinghua&quo ...

随机推荐

  1. jQuery基于ajax实现星星评论代码

    本文实例讲述了jQuery基于ajax实现星星评论代码.分享给大家供大家参考.具体如下: 这里使用jquery模仿点评网的星星评论功能,Ajax评论模块,鼠标点击星星即可评价,下边是分数,可以点击后给 ...

  2. 提高jQuery执行效率需要注意几点

    1. 使用最新版本的jQuery jQuery的版本更新很快,你应该总是使用最新的版本.因为新版本会改进性能,还有很多新功能. 下面就来看看,不同版本的jQuery性能差异有多大.这里是三条最常见的j ...

  3. Unity3D开发(五):Unity3D 4.x 使用Mecanim实现连击(转)

    原地址:http://www.unitymanual.com/blog-1801-1221.html unity3d 4.x 版本之后提供了一种新的动画机制Mecanim,虽然目前还支持之前的Anim ...

  4. Android串口通信(基于Tiny6410平台)

    友善之臂的Android系统有他们自己编写的一个串口通信程序,网上没有找到他的源代码,而且界面操作不在一个界面,不是很方便,这里我自己写了一个粗糙点的串口通信程序. 同样这里还是调用友善之臂的frie ...

  5. LightOj 1065 - Number Sequence (矩阵快速幂,简单)

    题目 和 LightOj 1096 - nth Term 差不多的题目和解法,这道相对更简单些,万幸,这道比赛时没把模版给抽风坏. #include<stdio.h> #include&l ...

  6. hdu 4038 Stone

    思路: 如果负数的个数为偶数则不必改变,为奇数就将最大负数变为正: 对于正数,尽量将1,2变为3即可. 代码如下: #include<cstring> #include<iostre ...

  7. cojs 简单的区间问题 解题报告

    新学了些弦图和区间图的新玩意,于是就想着出一道题目 其实这道题不用弦图和区间图的理论也是可以做的 首先考虑第一问,第一问是一个NOIP普及组水平的贪心 我们把区间按照右端点从小到大排序,之后从头到尾扫 ...

  8. BZOJ 3720 gty的妹子树

    块状树裸题 块状树: 首先对树进行分块,分出的每一块都是一个连通块 通常的分块的方式如下: 1.父亲所在块不满,分到父亲所在块中 2.父亲所在块满,自己单独开一个块 (貌似有更为优越的分块方式? 注意 ...

  9. 李洪强iOS开发之Foundation框架—结构体

    Foundation框架—结构体 一.基本知识 Foundation—基础框架.框架中包含了很多开发中常用的数据类型,如结构体,枚举,类等,是其他ios框架的基础. 如果要想使用foundation框 ...

  10. C#中用JavaScriptSerializer和Json.Net操作json格式的文件

    1.json文件 2.写出对应的类 //折扣 public class Discount { public string Qty { get; set; } public string percent ...