本篇博客我们来学习两个个内存函数,这两个函数都是用来拷贝的,但是它们的使用范围有些许不同,所以有必要好好区分。
目录
1.memcpy:在缓存区中复制字符(可以复制任何整型、字符串等字符)
1.memcpy:在缓存区中复制字符(可以复制任何整型、字符串等字符)
1.头文件:
#include<memory.h> 或者#include<string.h> 2.使用格式:void *memcpy( void *dest, const void *src, size_t count );
3.函数memcpy从src的位置开始向后复制count个字节的数据到dest的内存位置
4.函数在拷贝时遇到‘\0’并不会停下来
5.如果src和dest有任何的重叠,复制的结果都是未定义的
6.void* 参数类型不可定义,可以拷贝任意传过来的指针内容
7.size_t count :需要拷贝的字节数
1.1函数示例
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
memcpy
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
memcpy(arr2, arr1, 20);//只拷贝前5个数组
int sz = sizeof(arr2) / sizeof(arr2[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
我们把count的值设置为了5,我们就只拷贝arr1中的前五个数据,其余部分保持初始化的0,
当我们不想从1开始拷贝数据时,比如想从3开始拷贝,只需要将源头字符串也就是arr1+2,就可以从3开始拷贝。
1.2模拟实现
void my_memcpy(void* dest, const void* src, size_t k)
{
assert(dest && src);
scanf("%d", &k);
while (k)
{
*(int*)dest = *(int*)src;
dest = (int*)dest+1;
src = (int*)src + 1;
k--;
}
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
int k = 0;
my_memcpy(arr2, arr1, k);
int sz = sizeof(arr2) / sizeof(arr2[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
2.memmove:实现空间重叠拷贝
1.头文件:#include<string.h>
2.使用格式:void *memcpy( void *dest, const void *src, size_t count );
3.memmove函数会确保重叠区域中的原始源字节在被覆盖之前被复制,即src和dest发生重叠时,会确保src已经被复制
2.1代码示例
我们就用重叠区域的拷贝来举例论证到底会不会在src和dest发生重叠时,src已经被复制
//memmove
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
int k = 0;
int i = 0;
int sz = sizeof(arr1) / sizeof(arr1[0]);
scanf("%d", &k);
memmove(arr1, arr1+2, k);
for (i = 0; i < sz; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
我们发现结果是3 4 5 6 7 6 7 8 9 10,这说明在src和dest发生重叠时,src已经被复制
2.2模拟实现
void my_memmove(void* dest, const void* src, size_t k)
{
assert(dest && src);
if (dest < src)
{
//从前往后打印
while (k--)
{
*(int*)dest = *(int*)src;
dest = (int*)dest + 1;
src = (int*)src + 1;
}
}
//从后往前打印
else
{
while (k--)
{
*( (char*)dest + k) = *((char*)src + k);
}
}
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
int i = 0;
int sz = sizeof(arr1) / sizeof(arr1[0]);
my_memmove(arr1, arr1+2, 5);
for (i = 0; i < sz; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
接下来为大家详细解释一下为什么要这样实现(就以拷贝5个数据为例):
1.第一种情况(从前向后)
dest的起始位置为3之前的任意地址(即可以是从1开始往后5个空间,也可以是从2开始往后5个空间),要拷贝的src是34567,比如此时dest是12345,我们可以直接把3放到1的位置上,4放到2的位置上,5放到3的位置上,6放到4的位置上,7放到5的位置上,这时我们可以直接从前向后打印就可以实现函数拷贝;
2.第二种情况(从后往前)
dest的起始位置时3之后(不包括3,因为为3完全重叠,拷贝与否都是看不出来的)7之前(包括7)的任意位置,要拷贝的src是34567,比如此时目标空间dest是56789,这时,我们把7放到9的位置上,6放到8的位置上,往前推,直到把3放到5的位置上,如果我们依旧从前往后放数据,就会出现,3放到了5的位置,4放到6的位置,此时本该5的位置变成了3,继续拷贝只能再次把3放到了7的位置上,4放到了8的位置上,3放到9的位置上,src覆盖了原来要存放dest数据的空间,所以只能从后往前;
3.第三种情况(从前往后或者从后往前)
dest的起始位置在8之后(包括8)的任意位置,要拷贝的src是34567,此时,我们稍加思考就会发现从前往后拷贝或者从后往前拷贝都是可以的。
*( (char*)dest + k) = *((char*)src + k)这是从后往前拷贝函数的实现代码,dest+k我们找到的是目标空间的最后一个位置,src+k是需要拷贝的最后一个数据的位置,然后执行完一次后k--
就实现了从后向前的拷贝。
好了,这就是这两个函数了,通过对比讲解,大家肯定已经掌握了它们的本质,希望大家能戒骄戒躁,好好学习。