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

简介:

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

 

1
2
3
4
5
6
7
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的长度了 这时会有什么效果呢
就比如:

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

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

举个简单的例子:

1
2
3
4
5
6
7
8
9
10
# 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

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

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

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

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

  

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

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

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

 

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

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

 

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

 

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

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


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

2分

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

  

4分

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

  

7分

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

  

10分

1
2
3
4
5
6
7
8
9
//为了实现链式操作,将目的地址返回,加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函数了,
完美的版本为:

1
2
3
4
5
6
7
8
9
10
11
int  strlen(  const  char  *str )  //输入参数const
 
{
  assert ( strt != NULL );  //断言字符串地址非0
  int  len;
  while ( (*str++) !=  '\0'  )
 {
  len++;
 }
  return  len;
}

  

 本文转自二郎三郎博客园博客,原文链接:http://www.cnblogs.com/haore147/p/3646311.html,如需转载请自行联系原作者

相关文章
|
8天前
|
程序员 C语言
C语言库函数 — 内存函数(含模拟实现内存函数)
C语言库函数 — 内存函数(含模拟实现内存函数)
16 0
|
8天前
|
程序员 C语言 开发者
C语言库函数 — 字符串函数(含模拟实现字符串函数)
C语言库函数 — 字符串函数(含模拟实现字符串函数)
34 0
|
15天前
|
存储 C语言
【我爱C语言】详解字符函数isdigit和字符串转换函数(atoi和snprintf实现互相转换字符串)&&三种strlen模拟实现1
【我爱C语言】详解字符函数isdigit和字符串转换函数(atoi和snprintf实现互相转换字符串)&&三种strlen模拟实现
|
15天前
|
机器学习/深度学习 C语言
【C语言】函数的系统化精讲(三)1
【C语言】函数的系统化精讲(三)
|
15天前
|
编译器 C语言
【C语言】函数的系统化精讲(一)2
【C语言】函数的系统化精讲(一)2
|
15天前
|
编译器 Serverless C语言
【C语言】函数的系统化精讲(一)1
【C语言】函数的系统化精讲(一)
|
15天前
|
存储 程序员 编译器
【C语言第二回】main、printf和库函数
【C语言第二回】main、printf和库函数
|
1月前
|
存储 编译器 C语言
在C语言中的数组和字符串
在C语言中的数组和字符串
|
8月前
|
存储 机器学习/深度学习 Linux
【C语言】语言篇——数组和字符串
【C语言】语言篇——数组和字符串
37 0
|
8月前
|
存储 C语言
C语言之指针(指针数组以及指针的指针和字符串)
C语言之指针(指针数组以及指针的指针和字符串)
70 0