1
    char test[]={"abcde"};
    char* test1={"xyz"};
    memcpy(test+5,test1,3);
    printf("%s",test);

我试图了解 memcpy 的工作原理,这是我迄今为止编写的示例。这给出了输出abcdexyz&vjunkcharacters

和以下消息。

*** stack smashing detected ***: ./testcode terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb7656dd5]
/lib/i386-linux-gnu/libc.so.6(+0xffd8a)[0xb7656d8a]
./testcode[0x8048797]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75704d3]
./testcode[0x80483a1]

这种情况背后的原因是什么?

4

5 回答 5

4

根本原因:

char test[]={"abcde"};

分配足够的内存空间来5仅存储字符。

memcpy(test+5,test1,3);  

将指向的数据复制到test1分配的内存空间之外。
从技术上讲,以这种方式在分配的内存范围之外写入是未定义的行为,这意味着任何事情都可能发生。

实际发生了什么?

这里实际发生的是将memcpy字符复制到分配的内存之外,从而覆盖NULL标记字符数组结尾的终止符test
此外,printf从起始地址读取内容,test直到遇到一个随机的NULL从而打印出垃圾字符。

解决方案:
在执行memcpy. 由于您打算复制3字符,因此您的目标缓冲区test至少应为:

5 + 3 + 1 byte for NULL terminator = 9 bytes

您可以简单地使用:

char test[9]="abcde";
于 2012-09-26T06:49:26.500 回答
2

您的memcpy调用确实破坏了堆栈,这就是您看到该消息的原因。您正在将数据复制到test数组末尾,这是不允许的。

于 2012-09-26T06:44:40.403 回答
2

在没有额外缓冲区的情况下执行此操作

事实上,最直接的方法是避免复制:

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

int main() {
  char a[] = "abcde";
  char b[] = "xyz";
  printf("%s%s\n", a, b);
  return 0;
}

用 memcpy 做

memcpy将n字节从复制srcdest。您需要自己正确跟踪复制字符串的空终止字节。

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

int main() {
  char a[] = "abcde";
  char b[] = "xyz";

  /* note that both strings add a '\0' termination */
  char c[sizeof(a) + sizeof(b) - 1];

  /* copy the content of a to c */
  memcpy(c, a, sizeof(a));

  /* copy the content of b to where a ends (concatenate the strings) */
  memcpy(c + sizeof(a) - 1, b, sizeof(b));

  /* note that the '\0' termination of the string is necessary to let
   * functions like printf know where the string is over 
   */
  printf(c);

  return 0;
}

用 strcpy 和 strcat 做

请注意,在使用 memcpy 时,正确处理字符串的空终止存在很多缺陷。要简化字符串的此过程,您应该执行以下操作。

如果这些确实是字符串而不是随机字节,您应该坚持使用标准库的字符串函数。这就是它的完成方式。

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

int main() {
  char a[] = "abcde";
  char b[] = "xyz";

  /* note that both strings add a '\0' termination */
  char c[sizeof(a) + sizeof(b) - 1];

  /* copy the content of a to c */
  strcpy(c, a);

  /* copy the content of b to where a ends (concatenate the strings) */
  strcat(c, b);

  /* note that the '\0' termination of the string is necessary to let
   * functions like printf know where the string is over 
   */
  printf(c);

  return 0;
}

关于知道字符串的大小

关于知道缓冲区的大小,请注意您通常不能简单地做sizeof(a_string). 如果将字符数组传递给函数,它会衰减为指针,并且此操作不再返回数组的预期大小,而是指针的大小。

对于字符串,您需要发出strlen(a_string)which 扫描空终止的出现并返回字符串的长度(不包括终止)。

至于包含随机数据的字符缓冲区(或需要写入的空缓冲区),这种方法也不起作用。您总是需要将缓冲区的大小作为附加参数传递。

于 2012-09-26T07:03:02.123 回答
1

该行memcpy(test+5,test1,3);用简单的话执行以下操作:

“从数组“test”的最后一个元素开始,将数组“test1”中的 3 个字符复制到那里”,这基本上写入了数组“test”长度之外的 2 个字符。

所以如果你只是想玩'memcpy'定义第三个数组:

char test[]="abcde";
char test1[]="xyz";
char output[sizeof(test) + sizeof(test1)];
memset(output, 0, sizeof(output));
memcpy(&output[0],test,5);
memcpy(&output[5],test1,3);
printf("%s",output);
于 2012-09-26T06:51:06.593 回答
1

变量 test1 在内存中 4 个字符,3 个字符加上结束字符串终止符。试试这个:

char test[9]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,4);
于 2012-09-26T06:52:51.580 回答