strcpy 当目标缓冲区小于 src 缓冲区时
我试图了解 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”字符串被修改了。
请解释一下。
I am trying to understand the difference/disadvantages of strcpy and strncpy.
Can somebody please help:
void main()
{
char src[] = "this is a long string";
char dest[5];
strcpy(dest,src) ;
printf("%s \n", dest);
printf("%s \n", src);
}
The output is:
this is a long string
a long string
QUESTION: I dont understand, how the source sting got modified. As per explanation, strcpy should keep copying till it encounters a '\0', so it does, but how come "src' string got modified.
Please explain.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
简单的答案是,您(使用
strcpy()
调用)做了一些超出系统规范的事情,因此理应遭受未定义行为的困扰。更复杂的答案涉及检查系统上的具体内存布局,以及 strcpy() 内部如何工作。它可能是这样的:
字母
D
代表dest中的字节,字母P
是填充字节,0< /code> 字符是用作字符串终止符的 ASCII NUL 字符。
现在
strcpy(dest,src)
将稍微改变内存内容(假设它正确处理重叠的内存区域):即,而
dest
现在“包含”完整字符串“这是一个长字符串”
(如果算上溢出的内存),src
现在包含一个完全不同的以 NUL 结尾的字符串“一个长字符串”
。The easy answer is that you have (with that
strcpy()
call) done something outside the specifications of the system, and thus deservedly suffer from undefined behaviour.The more complex answer involves examining the concrete memory layout on your system, and how
strcpy()
works internally. It probably goes something like this:The letters
D
stand for bytes in dest, the lettersP
are padding bytes, the0
characters are ASCII NUL characters used as string terminators.Now
strcpy(dest,src)
will change the memory content somewhat (presuming it correctly handles the overlapping memory areas):I.e. while
dest
now "contains" the full string"this is a long string"
(if you count the overflowed memory),src
now contains a completely different NUL-terminated string"a long string"
.这是缓冲区溢出和未定义的行为。
在您的情况下,编译器似乎已将
dest
和src
按顺序放置在内存中。当您从src
复制到dest
时,它会继续复制到dest
的末尾并覆盖src
的部分内容。This is a buffer overflow, and undefined behavior.
In your case, it appears that the compiler has placed
dest
andsrc
sequentially in memory. When you copy fromsrc
todest
, it continues copying past the end ofdest
and overwrites part ofsrc
.作为附加说明,请记住,当您需要执行带有缓冲区溢出保护的复制时,
strncpy
函数不是正确的函数。此功能并非旨在用于该目的,也从未用于该目的。strncpy
是一个很久以前创建的函数,用于在某些旧版本 UNIX 的某些非常特定的文件系统中执行一些非常特定于应用程序的字符串复制。不幸的是,该库的作者设法“劫持”了听起来很通用的名称strncpy
以用于非常狭窄和特定的目的。然后出于向后兼容的目的而保留它。现在,我们有一两代程序员仅根据 strncpy 的名称就对其用途做出假设,并因此错误地使用了它。实际上,strncpy
几乎没有任何有意义的用途。C 标准库(至少其 C89/90 版本)不提供带有缓冲区溢出保护的字符串复制功能。为了执行此类受保护的复制,您必须使用一些特定于平台的函数,例如 strlcpy, strcpy_s 或者自己写一个。
PS StackOverflow 上的这个线程包含了很好的讨论关于
strncpy
开发的真正目的。请参阅这篇帖子专门了解其作用的准确解释UNIX 文件系统。另外,请参阅此处了解如何操作的好文章strncpy
应运而生。再说一遍,strncpy 是一个用于复制完全不同类型的字符串 - 固定长度字符串的函数。它甚至不适合与传统的 C 样式空终止字符串一起使用。
As an additional note, please keep in mind that
strncpy
function is not the right function to use when you need to perform copying with buffer overrun protection. This function is not intended for that purpose and has never been intended for that purpose.strncpy
is a function that was created long time ago to perform some very application-specific string copying within some very specific filesystem in some old version of UNIX. Unfortunately, the authors of the library managed to "highjack" the generic-sounding namestrncpy
to use for that very narrow and specific purpose. It was then preserved for backward compatibility purposes. And now, we have a generation or two of programmers who make ther assumptions aboutstrncpy
's purpose based solely on its name, and consequently use it improperly. In reality,strncpy
has very little or no meaningful uses at all.C standard library (at least its C89/90 version) offers no string copying function with buffer overrrun protection. In order to perform such protected copying, you have to use either some platform-specific function, like strlcpy, strcpy_s or write one yourself.
P.S. This thread on StackOverflow contains a good discussion about the real purpose
strncpy
was developed for. See this post specifically for the precise explanation of its role in UNIX file system. Also, see here for a good article on howstrncpy
came to be.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.该字符串很可能是精确邻居。所以在你的情况下,你可能有这张图片
dst | | | | |来源| | | | | |
所以你开始写,碰巧 src 的字段被覆盖了。
但是,您绝对不能依赖它。一切都可能发生,你所拥有的是未定义的行为。因此,其他时间和/或其他选项可能会在另一台计算机上发生其他情况。
问候
弗里德里希
with high likliness the string are exact neighbours. So in your case you may have this picture
dst | | | | |src | | | | | |
so you start writing and it happens that the fields of src are overwritten.
Howerver you can surely not rely on it. Everything could happen what you have is undefined behaviour. So something else can happen on another computer another time and/or other options.
Regards
Friedrich
您的代码导致缓冲区溢出 - 复制到目标的字符超出了它可以容纳的字符。
附加字符写在堆栈上的另一个位置,在您的情况下,即 src 指向的位置。
您需要使用
strncpy()
函数。Your code caused a buffer overflow - copying to dest more characters than it can hold.
The additional characters were written on another place on the stack, in your case, where src was pointing to.
You need to use
strncpy()
function.我建议快速阅读:
http://en.wikipedia.org/wiki/Strncpy#strncpy
这向您展示了差异。本质上,strncpy 允许您指定要复制的字节数,这意味着生成的字符串不一定以空终止。
现在,当您使用 strcpy 将一个字符串复制到另一个字符串时,它不会检查生成的内存区域以查看它是否足够大 - 在这方面它不会控制您的手。它检查 src 字符串中的空字符。
当然,这个例子中的dst只有5个字节。那么会发生什么呢?它继续书写,直到目的地的尽头,并在记忆中继续过去。在这种情况下,堆栈上的下一部分内存是您的 src 字符串。因此,虽然您的代码不是有意复制它,但内存中的字节布局以及超过 dst 末尾的写入导致了这种情况。
希望有帮助!
I suggest a quick read of:
http://en.wikipedia.org/wiki/Strncpy#strncpy
which shows you the differences. Essentially strncpy lets you specify a number of bytes to copy, which means the resultant string isn't necessarily nullterminated.
Now when you use strcpy to copy one string over another, it doesn't check the resultant area of memory to see if it's big enough - it doesn't hold your hand in that regard. It checks up to the null character in the src string.
Of course, dst in this example is only 5 bytes. So what happens? It keeps on writing, to the end of dest and onwards past it in memory. And in this case, the next part of memory on the stack is your src string. So while your code isn't intentionally copying it, the layout of bytes in memory coupled with the writing past the end of dst has caused this.
Hope that helps!
要么我误解了你的问题,要么你误解了 strcpy:
在我看来,您希望 strcpy 在到达 dest 末尾时基于看到
\0
字符而停止复制到 dest 中。这不是它的作用。 strcpy 复制到目标中,直到到达源字符串的末尾(由\0
字符分隔)。它假设您为副本分配了足够的内存。在复制之前,目标缓冲区中可以有任何内容,包括所有空值。strncpy 通过让你实际告诉它你要复制到的缓冲区有多大来解决这个问题,这样你就可以避免复制超出容量的情况。
Either I'm misunderstanding your question, or you're misunderstanding strcpy:
It sounds to me like you're expecting strcpy to stop copying into dest when it reaches the end of dest, based on seeing a
\0
character. This isn't what it does. strcpy copies into the destination until it reaches the end of the source string, delimited by a\0
character. It assumes you allocated enough memory for the copy. Before the copy the dest buffer could have anything in it, including all nulls.strncpy solves this by having you actually tell it how big the buffer you're copying into is, so you can avoid cases where it copies more than can fit.