使用 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.
那是因为a
、b
、c
恰好在内存中顺序分配。当您打印“从 a
开始的 20 个字节”时,您实际上是在查看 a
的最新字节之后的内存。该内存恰好包含b
。所以你实际上开始阅读 b
。 b
和 c
也是如此。请注意,这绝不是 保证 。查看为 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);
您好,我遇到了这个简单的 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.
那是因为a
、b
、c
恰好在内存中顺序分配。当您打印“从 a
开始的 20 个字节”时,您实际上是在查看 a
的最新字节之后的内存。该内存恰好包含b
。所以你实际上开始阅读 b
。 b
和 c
也是如此。请注意,这绝不是 保证 。查看为 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);