1.memcpy
void * memcpy ( void * destination, const void * source, size_t num );
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
接下来我们使用一下这个函数:
#include<string.h>
int main()
{
int arr1[10] = { 0 };
int arr2[] = { 1,2,3,4,5 };
memcpy(arr1, arr2, 20);
return 0;
}
经过调试之后可以发现arr1里面存放了1,2,3,4,5,这个就是memcpy的基本用法。
2.模拟实现memcpy
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<string.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);
while (num)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
num--;
}
}
int main()
{
int arr1[10] = { 0 };
int arr2[] = { 1,2,3,4,5 };
my_memcpy(arr1, arr2, 20);
return 0;
}
src里面的内容是不会被改变的,所以使用const限制一下。num是拷贝的字节数,我们每次拷贝一个字节。先使用while循环,循环num次,每次num--,dest和src是void*的指针,我们强制类型转换为char*的指针,然后解引用,将src赋给dest,dest和src这时就应该往后走一个字节,因为强制类型转换是临时的,所以还是需要强制类型转换为char*,然后+1。
当我们想把1,2,3,4,5放到3,4,5,6,7的位置上时就会出现问题,当空间不重叠内存的时候使用memcpy是可以的,像这种不重叠内存的拷贝需要使用memmove。
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr + 2, arr, 20);
return 0;
}
3.memmove
void * memmove ( void * destination, const void * source, size_t num );
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr + 2, arr, 20);
return 0;
}
使用memmove的话就能很好的解决上面的问题。
4.模拟实现memmove
我们先来想一下,如果有一个数组:
int arr[]={1,2,3,4,5,6,7,8,9,10};
假如我们要把1,2,3,4,5拷贝到3,4,5,6,7这个位置上去,使得数组变成:
int arr[]={1,2,1,2,3,4,5,8,9,10};
那我们就需要先将5放在7的位置上,4放在6的位置上,以此类推,才能达到效果,也就是从后向前拷贝。
如果我们要把3,4,5,6,7拷贝到1,2,3,4,5这个位置上,就要先将3放到1的位置上,以此类推,也就是从前往后拷贝。
所以说拷贝的方式会根据需求而改变。
那么什么时候从前往后拷贝,什么时候从后往前拷贝呢?
还是用一个数组举例:
int arr[]={1,2,3,4,5,6,7,8,9,10};
如果dest这块空间在src这块空间的左边且重叠,也就是要把高地址的数据拷贝到低地址处,就需要从前往后拷贝。
如果dest这块空间在src这块空间的右边且重叠,也就是要把低地址的数据拷贝到高地址处,就需要从后往前拷贝。
如果dest这块空间和src这块空间不重叠,不管从前往后还是从后往前都是可以的,当然是在空间充足的情况下,不能越界。
一开始我们还是需要保存起始位置的地址,用作返回值。使用if判断dest是否小于src,如果小于则进入for循环,循环sz次,这里的方法是跟上面的memcpy一样的。当dest>src时,我们使用while循环比较方便,因为我们从后向前拷贝是先将后面的数据开始,所以当我们将条件设置成sz--时,由于是后置--,也是循环sz次,但是*((char*)src + sz)就刚好能够拿出最后一个数据拷贝到*((char*)dest + sz),当然使用for循环也是可以的。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memmove(void* dest,const void* src,size_t sz)
{
assert(dest && src);
void* ret = dest;
if (dest < src)//从前向后
{
for (int i = 0; i < sz; i++)
{
*(char*)dest = *(char*)src;
dest = (char*)dest+1;
src = (char*)src + 1;
}
}
else//从后向前
{
while (sz--)
{
*((char*)dest + sz) = *((char*)src + sz);
}
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr, arr + 2, 20);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
5.memset
void * memset ( void * ptr, int value, size_t num );
这个函数就是将ptr指向的前num个字节的数据设置成指定的值(value),再把起始位置返回。
下面是memset的使用:
int main()
{
char arr[] = "hello world";
memset(arr + 6, 'x', 3);
printf("%s\n", arr);
return 0;
}
但是要注意的是num的单位是字节。如果我们想要把这个数组的内容设置成10个1,像下面这样就已经出错了,这样是把每个字节都设置成1,而不是整型。
int main()
{
int arr[10] = { 0 };
memset(arr, 1, 40);
return 0;
}
6.memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
memcmp这个函数就是比较两块空间的前num个字节的内容,如果一样则返回0,小于则返回<0,大于则返回>0。需要注意的是在比较时也是一对字节进行比较,和strcmp的区别就是strcmp是进行字符的比较,而memcmp是进行内存块的比较。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[] = { 1,2,3,4 };
int ret=memcmp(arr1, arr2, 16);
printf("%d ", ret);
return 0;
}
今天的分享到这里就结束啦!谢谢老铁们的阅读,让我们下期再见。