这个memcpy代码是如何工作的

时间:2017-04-14 11:11:48

标签: c printf memcpy

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

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

char *a = "\0hey\0\0";   /*  6 */
char *b = "word\0up yo"; /* 10 */
char *c = "\0\0\0\0";    /*  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;
}

我原本期望打印输出结果为:

\0hey\0\0\0word\0up yo\0\0\0

但是我得到了:

\0ord\0\0\0\0\0\0\0\0\0\0\0\0???Z

最后,当我打印而不是z时,我得到正确的输出。 任何人都可以向我解释为什么会这样吗?提前谢谢。

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

1 个答案:

答案 0 :(得分:1)

C中的字符串是零终止的;标准C库中的函数采用此属性。特别是,函数strlen返回字符串开头的非零字符数。在您的示例中,strlen(a)等于0,因为a的第一个字符为零。

代码具有以下效果:

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

现在zp仍然包含\0,因为strlen(a)为0,因此会复制1个字符。

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

现在zp包含word\0:复制了五个字符。

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

现在只有zp的第一个字符被覆盖,因此它包含\0ord\0

  

最后,当我打印而不是z时,我得到正确的输出。任何人都可以向我解释为什么会这样吗?提前谢谢。

这是因为abc碰巧在内存中按顺序分配 。当您从a&#34;开始打印&#34; 20字节时,您实际上正在查看超过a的最新字节的内存。此内存恰好包含b。所以你实际上开始阅读bbc也是如此。请注意,这绝不是保证。查看为char *分配的内存实际上是未定义行为的实例。

  

我如何连接这些字符串?

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

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

char a[] = "\0hey\0\0";   /*  6 */
char b[] = "word\0up yo"; /* 10 */
char c[] = "\0\0\0\0";    /*  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);