使用 memcpy 时出现意外结果

Unexpected results when using memcpy

您好,我遇到了这个简单的 C 程序,但我无法理解这段代码的工作原理:

#include <string.h>
#include <stdio.h>

char *a = "[=10=]hey[=10=][=10=]";   /*  6 */
char *b = "word[=10=]up yo"; /* 10 */
char *c = "[=10=][=10=][=10=][=10=]";    /*  4 */

int main(void)
{
    char z[20];
    char *zp = z;
    memcpy(zp, a, strlen(a)+1);
    memcpy(zp, b, strlen(b)+1);
    memcpy(zp, c, strlen(c)+1);
    /* now z contains all 20 bytes, including 8 NULLs */
    int i;

for(i = 0; i < 20; i++){
    if (z[i] == 0){
      printf("\0");
    }

    printf("%c", z[i]);}
    return 0;
}

我原以为打印 z 的输出是:

[=11=]hey[=11=][=11=][=11=]word[=11=]up yo[=11=][=11=][=11=]

但我得到的是:

[=12=]ord[=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=]???Z

最后,当我打印 a 而不是 z 时,我得到了正确的输出。 谁能向我解释为什么会这样?提前致谢。

编辑: 我如何连接这些字符串?

C 中的字符串以零结尾;标准 C 库中的函数假定此 属性。特别是,函数 strlen returns 从字符串开头算起的非零字符数。在您的示例中,strlen(a) 等于 0,因为 a 的第一个字符已为零。

代码将产生以下效果:

 memcpy(zp, a, strlen(a)+1);

现在zp仍然包含[=18=],因为strlen(a)是0,所以复制了1个字符。

 memcpy(zp, b, strlen(b)+1);

现在 zp 包含 word[=21=]: 复制了五个字符。

 memcpy(zp, c, strlen(c)+1);

现在只是 zp 的第一个字符被覆盖,所以它包含 [=23=]ord[=23=].

Finally , when i print a instead of z i get the right output. Can anyone explain to me why this happens ? Thanks in advance.

那是因为abc恰好在内存中顺序分配。当您打印“从 a 开始的 20 个字节”时,您实际上是在查看 a 的最新字节之后的内存。该内存恰好包含b。所以你实际上开始阅读 bbc 也是如此。请注意,这绝不是 保证 。查看为 char * 分配的内存实际上是未定义行为的一个实例。

How i could concatenate such strings?

一般来说,没有办法在运行时找到这样的"strings"的长度。我不会这样称呼它们字符串,因为 "string" 在 C 语言中有特定的含义 - 它指的是零终止字符串,而你的只是内存区域。

但是,由于您在编译时知道大小,因此可以使用它。为避免代码中出现幻数,最好使用 char 数组而不是 char 指针,因为这样您就可以使用 sizeof 运算符。但是,请注意 C 中的所有字符串文字都是隐式零终止的!要将结果放入 20 字节缓冲区,您需要使用 sizeof(x) - 1:

char a[] = "[=13=]hey[=13=][=13=]";   /*  6 */
char b[] = "word[=13=]up yo"; /* 10 */
char c[] = "[=13=][=13=][=13=][=13=]";    /*  4 */

memcpy(zp, a, sizeof(a) - 1);
zp += sizeof(a) - 1;
memcpy(zp, b, sizeof(b) - 1);
zp += sizeof(b) - 1;
memcpy(zp, c, sizeof(c) - 1);