6

我试图了解 strcpy 和 strncpy 的区别/缺点。有人可以帮忙吗:

void main()
{
char src[] = "this is a long string";
char dest[5];

strcpy(dest,src) ;
printf("%s \n", dest);
printf("%s \n", src);

}

输出是:

this is a long string 
a long string 

问题:我不明白,源代码是如何被修改的。根据解释,strcpy 应该继续复制,直到遇到'\ 0',所以它确实如此,但是“src”字符串是如何被修改的。

请解释。

4

7 回答 7

11

简单的答案是您(通过 strcpy() 调用)在系统规范之外做了一些事情,因此当之无愧地遭受未定义的行为。

更困难的答案涉及检查系统上的具体内存布局,以及 strcpy() 在内部如何工作。它可能是这样的:

     N+28 "g0PP"
     N+24 "trin"
     N+20 "ng s"
     N+16 "a lo"
     N+12 " is "
src  N+08 "this"
     N+04 "DPPP"
dest N+00 "DDDD"

字母D代表 dest 中的字节,字母P是填充字节,0字符是用作字符串终止符的 ASCII NUL 字符。

现在 strcpy(dest,src) 将稍微改变内存内容(假设它正确处理重叠的内存区域):

     N+28 "g0PP"
     N+24 "trin"
     N+20 "g0 s"
     N+16 "trin"
     N+12 "ng s"
src  N+08 "a lo"
     N+04 " is "
dest N+00 "this"

即,虽然 dest 现在“包含”完整字符串“这是一个长字符串”(如果计算溢出的内存),但 src 现在包含一个完全不同的以 NUL 结尾的字符串“一个长字符串”。

于 2009-10-21T16:00:42.230 回答
7

这是缓冲区溢出和未定义的行为。

在您的情况下,编译器似乎已按顺序放置在内存中destsrc当您从 复制src到 时dest,它会继续复制到末尾dest并覆盖部分src

于 2009-10-21T15:57:29.813 回答
1

字符串很可能是精确的邻居。所以在你的情况下,你可能有这张照片

dst | | | | |源代码 | | | | | |

所以你开始写作,碰巧 src 的字段被覆盖了。

但是,您肯定不能依赖它。一切都可能发生你所拥有的是未定义的行为。因此,其他时间和/或其他选项可能会在另一台计算机上发生其他事情。

问候弗里德里希

于 2009-10-21T15:58:22.203 回答
1

您的代码导致缓冲区溢出 - 复制到 dest 的字符数超过了它可以容纳的字符数。在您的情况下,附加字符写在堆栈的另一个位置,即 src 指向的位置。

你需要使用strncpy()函数。

于 2009-10-21T16:01:36.830 回答
1

作为附加说明,请记住,strncpy当您需要执行带有缓冲区溢出保护的复制时,该函数不是正确的函数。此功能不用于该目的,也从未用于该目的。strncpy是很久以前创建的函数,用于在某些旧版本的 UNIX 中的某些非常特定的文件系统中执行一些非常特定于应用程序的字符串复制。不幸的是,该库的作者设法“劫持”了听起来很一般的名称strncpy,以用于非常狭窄和特定的目的。然后为了向后兼容的目的而保留它。而现在,我们有一两代程序员strncpy仅仅根据它的名字就对它的用途做出假设,从而不恰当地使用它。事实上,strncpy几乎没有或根本没有有意义的用途。

C 标准库(至少它的 C89/90 版本)不提供带有缓冲区溢出保护的字符串复制功能。为了执行这种受保护的复制,您必须使用一些特定于平台的函数,如strlcpystrcpy_s或自己编写一个。

PS StackOverflow 上的这个线程包含一个很好的讨论,讨论了开发的真正目的strncpy。有关其在 UNIX 文件系统中的作用的详细说明,请参阅此帖子。另外,请参阅此处strncpy以获取有关如何出现的好文章。

Once again, strncpy is a function for copying a completely different kind of string - fixed length string. It is not even intended to be used with traditional C-style null-terminated strings.

于 2009-10-21T17:34:08.750 回答
0

我建议快速阅读:

http://en.wikipedia.org/wiki/Strncpy#strncpy

这向您展示了差异。本质上 strncpy 允许您指定要复制的字节数,这意味着结果字符串不一定以空值结尾。

现在,当您使用 strcpy 将一个字符串复制到另一个字符串时,它不会检查生成的内存区域以查看它是否足够大 - 在这方面它不会握住您的手。它最多检查 src 字符串中的空字符。

当然,这个例子中的 dst 只有 5 个字节。那么会发生什么?它一直在写,直到 dest 的末尾,然后在内存中过去。在这种情况下,堆栈上的下一部分内存是您的 src 字符串。因此,虽然您的代码不是故意复制它,但内存中字节的布局加上 dst 结束后的写入导致了这种情况。

希望有帮助!

于 2009-10-21T15:58:44.420 回答
0

要么我误解了你的问题,要么你误解了 strcpy:

问题:我不明白,源代码是如何被修改的。根据解释,strcpy 应该继续复制,直到遇到'\ 0',所以它确实如此,但是“src”字符串是如何被修改的。

在我看来,您希望 strcpy 在到达 dest 末尾时停止复制到 dest,基于看到一个\0字符。这不是它的作用。strcpy 复制到目标,直到它到达源字符串的末尾,由一个\0字符分隔。它假定您为副本分配了足够的内存。在复制之前,dest 缓冲区可以包含任何内容,包括所有空值。

strncpy 通过让您实际告诉它您要复制到的缓冲区有多大来解决这个问题,这样您就可以避免它复制的内容超出容量的情况。

于 2009-10-21T16:08:26.733 回答