1
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 时(显然)它会擦除 a 的内容?

谢谢

4

4 回答 4

3

这是一个缓冲区溢出问题——你的ab太短了——它们没有空间容纳空终止符。发生的事情a只是b在内存中,所以在strcpy(b,a)执行时,存储在末尾的空终止符b实际上与a. 这a突然变成了一个空字符串。

对于初学者,将数组的长度设置为 4 而不是 3。这在沙盒/播放/学习模式下是可以的,但在生产代码中考虑:

  • 使用更安全的字符串函数(例如strncpy)来避免缓冲区溢出。
  • 使用支持可变大小或预先计算适合数据所需大小的字符数组/缓冲区。
于 2013-05-06T17:48:26.930 回答
1

由于您的数组太小并且没有空终止符的空间,因此您a在尝试复制时很可能会覆盖ab因为strcpy不知道何时停止复制。此声明将解决此特定程序的问题:

char a[4], b[4];

在一般情况下,您需要确保您的目标有足够的空间来容纳源以及空终止符。

这个例子让你更好地了解正在发生的事情,这只是为了演示目的,你应该将这样的代码用于除学习之外的任何其他事情。这对我有用ideone,您可以查看是否存在于此处,但可能无法在其他编译器中正常工作,因为我们正在调用未定义的行为:

#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);
}
于 2013-05-06T17:50:21.093 回答
0

第一个strcpy(a,"abc")已经错了。不要将 char 数组与 C-String 混淆……C-String 始终是 char 数组,但 char 数组并不总是 C-String。

C-String'\0'最后必须有一个 char。因此,当您执行 strcpy "abc" -> a[3] 您实际上是将以下4个字节移动到您的数组 { 'a', 'b', 'c', '\0' }

因为ab是一起创建的,所以b就在a前面。在这种情况下,当您打印出a时它会很好,因为printf () 仍然可以找到 a'\0'来标识为字符串的结尾,尽管它是错误的......因为您的'\0'char 是保留给b的区域。

以下问题都与同一件事有关...解决方案是:C-String的缓冲区必须是字符串的最大大小+ 1,因此您可以保证您将有空间容纳'\0'char。如果您需要更多详细信息,请在谷歌中搜索“C-String”或“null-terminated string”。

于 2013-05-06T17:59:00.543 回答
0

你犯了一个非常常见的初学者错误。在 C 中,没有字符串原语;当我们谈论字符串时,我们实际上是在谈论以空字符结尾的字符数组(或缓冲区,我不在乎你喜欢什么命名法)。所以你的 char[3] 将包含一个由 2 个字母组成的字符串,加上空终止符。另一个微妙的问题是,在内存中,它们将作为 a[0]a[1]a[2]b[0]b[1]b[2] 排列在堆栈上——这就是你没有的原因当你应得的时候不要崩溃。看到“abc”真的是“abc\0”,所以 a[3] == c 和 b[0] == \0,并且由于字符串重叠时的行为是未定义的(就像这些一样),我怀疑你的实现只是复制字符,直到它复制一个 \0。在这种情况下, strcpy(a, b) 将导致 a 为空字符串。

另一方面,您的程序按照写入的方式工作。你写的不是你的意思:)

于 2013-05-06T17:59:23.997 回答