char a[3], b[3];
strcpy(a,"abc");
printf("a1 = %s\n", a);
strcpy(b,a);
printf("a2 = %s\n", a);
printf("b = %s\n", b);
从我理解strcpy到工作的方式输出将是:
a1 = abc
a2 = abc
b = abc
相反,我获得了
a1 = abc
a2 =
b = abc
为什么当我第二次调用strcpy时(显然)擦除了?
的内容由于
答案 0 :(得分:3)
这是一个buffer overflow问题 - 您的a
和b
太短了 - 它们没有空终止符。发生了什么a
就在内存中b
之后,所以当strcpy(b,a)
执行时,存储在b
末尾的空终止符实际上与内存位置相同a
的第一个字符。这使得a
突然变成空字符串。
对于初学者来说,将数组的长度改为4而不是3.这在沙箱/播放/学习模式中是可以的,但在生产代码中考虑:
strncpy
)以避免缓冲区溢出。答案 1 :(得分:1)
由于数组太小并且没有空终止符,因此当您尝试将a
复制到a
时,您很可能会覆盖b
strcpy
}不知道何时停止复制。该声明将解决此特定程序的问题:
char a[4], b[4];
在一般情况下,您需要确保目标有足够的空间来容纳源和空终止符。
这个例子让你更好地了解发生了什么,这只是为了演示目的而你应该使用这样的代码除了学习之外的其他任何东西。这对ideone
中的我很有用,你可以看看是否实时here但是在其他编译器中可能无法正常工作,因为我们正在调用未定义的行为:
#include <stdio.h>
#include <string.h>
int main()
{
char a[3], b[4];
// a will have a lower address in memory than b
printf("%p %p\n", a, b);
// "abc" is a null terminated literal use a size of 4 to force a copy of null
strncpy(a,"abc",4);
// printf will not overrun buffer since we terminated it
printf("a2 = %s\n", a);
// explicitly only copy 3 bytes
strncpy(b,a,3);
// manually null terminate b
b[3] = '\0' ;
// So we can prove we are seeing b's contents
b[0] = 'z' ;
// This will overrun into b now since b[0] is no longer null
printf("a2 = %s\n", a);
printf("b = %s\n", b);
}
答案 2 :(得分:0)
第一个strcpy(a,"abc")
已经错了。不要对char数组与C-String混淆... C-String总是一个char数组,但是char数组并不总是C-String。
C-String最后必须有'\0'
个字符。所以当你做strcpy“abc” - &gt; a [3]你实际上将以下 4 字节移动到你的数组{'a','b','c','\ 0'}
由于 a 和 b 一起创建, b 就在前面 a 。当你打印 a 时,它会很好在这种情况下,因为printf()仍然可以找到'\0'
来识别字符串的结尾,尽管它是错误的。 ..因为您的'\0'
字符是 b 保留的区域。
以下问题都与同一件事有关......
解决方案是:C-String的缓冲区必须是字符串的最大大小+ 1,因此您可以保证有'\0'
字符的空间。如果您需要更多详细信息,请谷歌搜索“C-String”或“以null结尾的字符串”。
答案 3 :(得分:0)
你犯了一个很常见的初学者错误。在C中,没有字符串原语;当我们谈论字符串时,我们真的在谈论空终止字符数组(或缓冲区,我不在乎你喜欢什么命名法)。所以你的char [3]将包含一个由2个字母组成的字符串,加上空终止符。另一个微妙的问题是,在内存中,它们将被放置在堆栈中作为[0] a [1] a [2] b [0] b [1] b [2] - 这就是你没有的原因当你应得的时候崩溃。看到“abc”真的是“abc \ 0”,所以a [3] == c和b [0] == \ 0,并且因为当字符串重叠时行为是未定义的(就像这些那样),我怀疑你的实现只是复制了字符,直到复制\ 0。在这种情况下,strcpy(a,b)将导致一个空字符串。
另一方面,您的程序按照写入的方式工作。你写的不是你的意思:)。