为什么在执行memcpy时检测到堆栈崩溃?

为什么在执行memcpy时检测到堆栈崩溃?,c,memory-management,C,Memory Management,我正在努力掌握memcpy到底是如何工作的,这就是我到目前为止所写的例子。 这将输出为abcdexyz&vjunkcharacters 还有下面的消息 char test[]={"abcde"}; char* test1={"xyz"}; memcpy(test+5,test1,3); printf("%s",test); 这种情况背后的原因是什么?您的memcpy调用会破坏堆栈,这就是您看到该消息的原因。您正在将数据复制到测试数组的末尾,这是不允许的。您的me

我正在努力掌握memcpy到底是如何工作的,这就是我到目前为止所写的例子。 这将输出为
abcdexyz&vjunkcharacters

还有下面的消息

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

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

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

您的
memcpy
调用会破坏堆栈,这就是您看到该消息的原因。您复制的数据超过了
测试的末尾,这是不允许的。

根本原因:

*** 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]
分配足够的内存空间,仅存储
5个
字符

char test[]={"abcde"};
test1
指向的数据复制到分配的内存空间之外。
从技术上讲,以这种方式超出分配内存的界限进行写入是未定义的行为,这意味着任何事情都可能发生

实际发生了什么?

这里实际发生的是
memcpy
将字符复制到分配的内存之外,从而覆盖标记字符数组结束的
NULL
终止符
test

此外,
printf
test
的起始地址读取内容,直到遇到一个随机的
NULL
,从而打印出垃圾字符

解决方案:
在执行
memcpy
之前,应确保目标缓冲区已分配足够的内存。由于您打算复制
3个
字符,您的目标缓冲区
test
应至少为:

memcpy(test+5,test1,3);  
您可以简单地使用:

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

根本原因:

*** 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]
分配足够的内存空间,仅存储
5个
字符

char test[]={"abcde"};
test1
指向的数据复制到分配的内存空间之外。
从技术上讲,以这种方式超出分配内存的界限进行写入是未定义的行为,这意味着任何事情都可能发生

实际发生了什么?

这里实际发生的是
memcpy
将字符复制到分配的内存之外,从而覆盖标记字符数组结束的
NULL
终止符
test

此外,
printf
test
的起始地址读取内容,直到遇到一个随机的
NULL
,从而打印出垃圾字符

解决方案:
在执行
memcpy
之前,应确保目标缓冲区已分配足够的内存。由于您打算复制
3个
字符,您的目标缓冲区
test
应至少为:

memcpy(test+5,test1,3);  
您可以简单地使用:

5 + 3 + 1 byte for NULL terminator = 9 bytes
memcpy(test+5,test1,3)以简单的文字执行以下操作:

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

因此,如果您只想使用“memcpy”,请定义第三个数组:

char test[9]="abcde";
memcpy(test+5,test1,3)以简单的文字执行以下操作:

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

因此,如果您只想使用“memcpy”,请定义第三个数组:

char test[9]="abcde";

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

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);

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

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);

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

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

char test[9]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,4);

使用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 */
  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;
}
#包括
#包括
int main(){
字符a[]=“abcde”;
字符b[]=“xyz”;
/*请注意,这两个字符串都添加了'\0'终止符*/
字符c[sizeof(a)+sizeof(b)-1];
/*将a的内容复制到c*/
strcpy(c,a);
/*将b的内容复制到a结束的位置(连接字符串)*/
strcat(c,b);
/*请注意,字符串的“\0”终止符是让
*printf等函数知道字符串的结束位置
*/
printf(c);
返回0;
}

了解字符串的大小

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

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


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

在没有附加缓冲区的情况下执行此操作

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

char test[9]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,4);

使用strcpy和strcat执行此操作

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

如果这些确实是字符串而不是随机字节,那么您应该坚持使用st