memcpy
C/C++ 库函数 void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1。
#include <stdio.h>
#include<string.h>
int main(){
int d[10]={1,2,3,4,5,6,7,8,9,10};
memcpy(d+3, d, 7*sizeof(int));// 注意第三函数为字节数
for(int i=0;i<10;i++){
printf("%d ", d[i]);
}
return 0;
}
/*输出
1 2 3 1 2 3 4 5 6 7
*/
从上面代码运行结果看不出什么问题来,其实隐含的问题(内存重叠)已经在现在的版本中被解决了。
接下来看看这个可能被HR问到的问题。
memcpy内存重叠
举个例子:数组a[10]={0,1,2,3,4,5,6,7,8,9},将a中的从下标0开始的7个数据,储存到从下标3开始的该数组中,我们想要的结果则为:a[10]={0 1 2 0 1 2 3 4 5 6}。但memcpy之前采用的算法为从下标0开始依次复制到从下标3的地址,结果为a[10]={0 1 2 0 1 2 0 1 2 0},如示例1代码运行结果。这是因为复制的内存存在着重叠现象。
示例1
#include <stdio.h>
#include<string.h>
#include <stddef.h>
void *memcpy(void *dst, const void *src, size_t len)
{
if(NULL == dst || NULL == src){
return NULL;
}
void *ret = dst;
while(len--){
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
return ret;
}
int main(){
int d[10]={0,1,2,3,4,5,6,7,8,9};
memcpy(d+3, d, 7*sizeof(int));
for(int i=0;i<10;i++){
printf("%d ", d[i]);
}
return 0;
}
/*输出
1 2 3 1 2 3 1 2 3 1
*/
内存重叠问题通过示例2进行解决,先判断是否发生内存重叠,再通过先复制重叠地址的内容再复制其他内容进行解决。
示例2
#include <stdio.h>
#include<string.h>
#include <stddef.h>
void *memcpy(void *dst, const void *src, size_t len)
{
if(NULL == dst || NULL == src){
return NULL;
}
void *ret = dst;
if(dst <= src || (char *)dst >= (char *)src + len){
//没有内存重叠,从低地址开始复制
while(len--){
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
}else{
//有内存重叠,从高地址开始复制
src = (char *)src + len - 1;
dst = (char *)dst + len - 1;
while(len--){
*(char *)dst = *(char *)src;
dst = (char *)dst - 1;
src = (char *)src - 1;
}
}
return ret;
}
int main(){
int d[10]={0,1,2,3,4,5,6,7,8,9};
memcpy(d+3, d, 7*sizeof(int));
for(int i=0;i<10;i++){
printf("%d ", d[i]);
}
return 0;
}
/*输出
0 1 2 0 1 2 3 4 5 6
*/
示例2的实现其实就是memmove()的实现。memmove() 是比 memcpy() 更安全的方法。如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同。
https://www.runoob.com/cprogramming/c-function-memcpy.html
https://blog.youkuaiyun.com/lz20120808/article/details/52135046
https://blog.youkuaiyun.com/lxgwm2008/article/details/11952285