头文件:#include <string.h>
strcpy() 函数用来复制字符串,其原型为:
char *strcpy(char *dest, const char *src);
【参数】dest 为目标字符串指针,src 为源字符串指针。
注意:src 和 dest 所指的内存区域不能重叠,且dest 必须有足够的空间放置 src 所包含的字符串(包含结束符NULL)
【返回值】成功执行后返回目标数组指针 dest。
strcpy() 把src所指的由NULL结束的字符串复制到dest 所指的数组中,返回指向 dest 字符串的起始地址。
注意:如果参数 dest 所指的内存空间不够大,可能会造成缓冲溢出(buffer Overflow)的错误情况,在编写程序时请特别留意,或者用strncpy()来取代。

strncpy()用来复制字符串的前n个字符,其原型为:
    char * strncpy(char *dest, const char *src, size_t n);
【参数说明】dest 为目标字符串指针,src 为源字符串指针。
strncpy()会将字符串src前n个字符拷贝到字符串dest。
不像strcpy(),strncpy()不会向dest追加结束标记'\0',这就引发了很多不合常理的问题,将在下面的示例中说明。

如果src的前n个字节不含NULL字符,则结果不会以NULL字符结束。        
如果src的长度小于n个字节,则以NULL填充dest直到复制完n个字节。        
src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。    
注意:src 和 dest 所指的内存区域不能重叠,且dest 必须有足够的空间放置n个字符
【返回值】返回指向dest的指针(该指向dest的最后一个元素)

1. strcpy

我们知道,strcpy 是依据 \0 作为结束判断的,如果 to 的空间不够,则会引起 buffer overflow。
strcpy 常规的实现代码如下(来自 OpenBSD 3.9):

char *
strcpy(char *to, const char *from)
{
       char *save = to;

for (; (*to = *from) != '\0'; ++from, ++to);
       return(save);
}

但通常,我们的 from 都来源于用户的输入,很可能是非常大的一个字符串,因此 strcpy 不够安全。

2. 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" 本身,还包含71 (79-8)个  '\0' 。

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

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

--------------------------------------------------------------------------

注意:定义一个 字符串数组的时候,一定要留一个字节给空字符'\0'。

char qq[8] = "qwer123"

char ww[8] = "qwer1234"

printf("%s\n",qq);

printf("%s\n",ww);

执行这条语句后,打印的结果都是一样的。都是  qwer123 ,因为 ww[8]的最后一个字节被'\0'填充了。

还有一些讲了strncpy注意事项的博客,写的不错。

http://blog.csdn.net/stpeace/article/details/22581763  (别再耍流氓了: 请别再用strcpy, 而用strncpy)

http://blog.haipo.me/?p=1065             (停止使用 strncpy 函数!)(这篇文章重点看)

停止使用 strncpy 函数!

也许你曾经被多次告知,要使用 strncpy 替代 strcpy 函数,因为 strncpy 函数更安全。而今天我要告诉你,strncpy 是不安全的,并且是低效的,strncpy 的存在是由于一个历史原因造成的,你不应当再使用 strncpy 函数。

下面我来解释为什么 strncpy 函数是不安全并且是低效的,以及我们应该使用那些替代函数。

我以前对 strncpy 一直存在误解,直到有一次出现了 BUG。好不容易定位到 strncpy 身上,然后仔细查看文档,才明白问题所在。

误解一:如果src 长度小于 n, 那么strncpy 和 strcpy 效果一样?

错,事实上,strncpy 还会把 dest 剩下的部分全部置为 0

一直认为 strncpy 只是比 strcpy 多了长度校验,却不知道 strncpy 会把剩下的部分全置为 0(粗体部分)。

char *strncpy(char *dest, const char *src, size_t n);
DESCRIPTION
The strcpy() function copies the string pointed to by src (including the terminating `\0′ character) to the array pointed to by dest. The strings may
not overlap, and the destination string dest must be large enough to receive the copy.
The strncpy() function is similar, except that not more than n bytes of src are copied. Thus, if there is no null byte among the first n bytes of src,
the result will not be null-terminated.

In the case where the length of src is less than that of n, the remainder of dest will be padded with null bytes.

这会导致什么后果呢?

首先,如果 strncpy 的长度填错了,比如比实际的长,那么就可能会把其他数据清 0 了。我就遇到过这个问题,在后来检查代码看到这个问题时,也并不以为然,因为拷贝的字符串不可能超过缓冲区的长度。

另外,假设 dest 的长度为 1024, 而待拷贝的字符串长度只有 24,strncpy 会把余下的 1000 各字节全部置为 0. 这就可能会导致性能问题,这也是我为什么说 strncpy 是低效的。

误解二:如果src 长度大于等于 n, 那么 strncpy 会拷贝 n – 1 各字符到 dest, 然后补 0?

错,大错特错,罚抄上面的 DESCRIPTION ,直到看到:

if there is no null byte among the first n bytes of src, the result will not be null-terminated.

这就可能导致了不安全的因素。

如果待拷贝字符串长度大于了 n, 那么 dest 是不会有结尾字符 0 的。假设这样一种情况:

char s[] = "hello world";
strncpy(s, "shit!", 5);
puts(s);

输出的结果是 “shit” 还是 “shit! world” ?

这种情况只是导致了输出结果错误,严重的,如果 dest n 字节后面一直没有 0,那么就会导致程序段错误。

strncpy 最开始引入标准库是用来处理结构体中固定长度的字符串,比如路径名,而这些字符串的用法不同于 C 中带结尾字 0 的字符串。所以 strncpy 的初衷并不是一个安全的 strcpy.

那么用那些函数来替代 strncpy?

1、使用 snprintf

snprintf(dest, n, src);

的效果和我们对一个安全的字符串拷贝函数的期望完全一致。

但是这个函数效率有点问题,并且特殊字符比如 %d 会转义。

2、自己实现一个高效并且安全的字符串拷贝函数 sstrncpy,开头的 s 代表 safe

/* safe strncpy */char *sstrncpy(char *dest, const char *src, size_t n)
{if (n == 0)return dest;dest[0] = 0;return strncat(dest, src, n - 1);
}

使用 strncat 是因为很难实现一个性能能够达到库函数的字符串拷贝函数。

3、但是,上面两个函数都有一个问题:如果不能预知 src 的最大长度,那么 src 会被静默的截断。

如果是为了复制一个字符串,那么更好的做法是使用 strdup 函数

char* strdup (const char *s);

strdup 函数会调用 malloc 分配足够长度的内存并返回。

当然,你需要在你不使用的时候 free 它。

如果只是函数内部调用,也可以使用 strdupa 函数。

char* strdupa (const char *s);

strdupa 函数调用 alloca函数而非 malloc 函数分配内存,alloca 分配的内存是桟内存而非堆内存。所以当函数返回后,内存就自动释放了,不需要 free。

4、如果是从文本文件中读数据,相对与 fgets 函数,更好的做法是使用 getline

ssize_t getline (char **lineptr,size_t *n,FILE *stream);

一个简单的例子:

char *line = NULL;
size_t len = 0;while (getline(&line, &len, stdin) != -1)
{fputs(line, stdout);
}free(line);

当 line 为 NULL 或者 len 为 0 时,getline 调用 malloc 分配足够大的内存。所以你需要在用完后 free 它们。

和 fgets 相同,getline 得到的行是带换行字符的。

所以,忘了 strncpy 吧,血的教训,说出来都是泪…

strcpy()与strncpy()的区别相关推荐

  1. strcpy和memcpy的区别 | strcpy和strncpy的区别

    strcpy和memcpy都是标准C库函数,它们有下面的特点. strcpy提供了字符串的复制.即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符. 已知strcpy ...

  2. snprintf和strcpy和strncpy的区别

    概述 snprintf,strcpy,strncpy这几个函数的功能都是将原字符串拷贝到目的字符串中.但是在细节部分还是存在着一些细微的差别.主要参考man说明. snprintf 格式 int sn ...

  3. strcpy与strncpy的区别

    2019独角兽企业重金招聘Python工程师标准>>> 我们先来看看strcpy, 下面的程序没有问题: #include <iostream> using namesp ...

  4. strcpy和strncpy的区别

    1. strcpy函数:顾名思义字符串复制函数 原型:extern char *strcpy(char *dest,char *src); 功能:把从src地址开始且含有NULL结束符的字符串赋值到以 ...

  5. c语言strcpy与strncpy区别,strcpy与strncpy的区别

    我们先来看看strcpy, 下面的程序没有问题: #include using namespace std; int main() { char str[4] = {0}; char *p = &qu ...

  6. strcpy和strncpy区别 memcpy strcpy strncpy lstrcpy lstrncpy wstrcpy, memmove

    strcpy和strncpy区别(2009-04-27 15:48:52) 转载标签:杂谈 分类:C++/C 第一种情况: char* p="how are you ?"; cha ...

  7. strcpy和strncpy用法和区别

    1. strcpy函数: 顾名思义字符串复制函数:原型:extern char *strcpy(char *dest,char *src); 功能:把从src地址开始且含有NULL结束符的字符串赋值到 ...

  8. strcpy()、strncpy()函数

    本片博客简单写下关于strcpy().strncpy()两函数的用法.区别及使用时需要注意的地方. 一.使用介绍 1. strcpy()函数用法 char * strcpy ( char * dest ...

  9. stpcpy和stpncpy用法 strcpy和strncpy用法

    文章目录 strncpy, strncpy_s参考文档用法 strcpy, strncpy实例 strcpy, strncpy用法举例 运行结果 stpcpy()和stpncpy()用法上的区别(C语 ...

最新文章

  1. 王爽实验9.自己解读,代码注释很多!
  2. oracle查询保留2位小数
  3. day19 生成器函数
  4. API网关Kong系列(一)初识
  5. 【pmcaff】Pad用户使用行为分析
  6. Java开发中使用模拟接口moco响应中文时乱码
  7. JavaScript解析Json字符串
  8. linux网路编程之TCP状态转换及端口复用
  9. Java简单输入输出
  10. Visualforce简介
  11. 计算机考研专业综合考试二,2015计算机考研大纲:专业基础综合考试大纲原文(2)...
  12. Android内核开发:为什么刷机后系统第一次启动会很慢?
  13. Oracle redo解析之-1、oracle redo log结构计算
  14. SQL 循环语句 while 介绍 实例
  15. dell服务器显示器fre,戴尔全新 Freesync 显示器,专门针对游戏玩家
  16. 姓舒男孩名字简单大气,帮你解决起名的烦恼!
  17. swiper滑动时每页都有动画
  18. 跟任何人都聊得来---最受世界500强企业欢迎的沟通课(一)
  19. C++获取、设置鼠标坐标并移动鼠标
  20. jQuery实现AJAX定时刷新局部页面实例

热门文章

  1. ICPR 2020 U∧2-Net之AI生成肖像画,精细到毛发!
  2. 提高期英语学习——第二次罗塞塔
  3. 架构师进阶之路,JAVA架构师面试题
  4. QTextLine、QGlyphRun、QTextLayout
  5. linux下syscall函数
  6. Android ListView优化之局部刷新(更新)(非notifyDataSetChanged)
  7. GICv3软件overview手册之虚拟化
  8. TO DO ... ...
  9. 使用密码字典 和 Python自带的pywifi模块穷举WIFI密码
  10. 微信小程序开发09 开放数据:微信生态帮助业务快速落地