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]
这种情况背后的原因是什么?
答案 0 :(得分: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";
答案 1 :(得分:2)
您的memcpy
电话确实粉碎了堆叠,这就是您看到该消息的原因。您正在复制数据超过test
数组的末尾,这是不允许的。
答案 2 :(得分: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
字节从src
复制到dest
。您需要自己跟踪正确复制字符串的空终止字节。
#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)
来扫描空终止的发生并返回字符串的长度(不包括终止)。
对于包含随机数据(或需要写入的空缓冲区)的字符缓冲区,这种方法也不起作用。您总是需要将缓冲区的大小作为附加参数传递。
答案 3 :(得分: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);
答案 4 :(得分:1)
变量test1在内存中4个字符,3个加上结束字符串终止符。试试这个:
char test[9]={"abcde"};
char* test1={"xyz"};
memcpy(test+5,test1,4);