文章目录
前言
c语言<string.h>库里面有很多的字符函数,比如memcpy,memmove,memcmp等,这些函数是从内存层面来进行拷贝、比较等等,其中memcpy和memmove函数十分相似,但是又不完全相同,memcpy是假定要操作的两块内存无重叠部分,而memmove则是要操作的两块内存有无重叠部分均可。
memcpy函数
void * memcpy ( void * destination, const void * source, size_t num );
这是对memcpy函数的声明,可以明确看出,其返回的是void*类型的指针,并且有三个参数,第一个参数表示目标地址,第二个参数表示源地址,第三个参数表示拷贝大小(单位是字节)。
此函数代表着,在内存空间中,从source指向的空间开始,往后一共num个字节的内存空间,将这些空间里面的内容拷贝到 从destination指向的空间开始,往后一共num个字节的内存空间。
从下方代码和运行结果不难看出其逻辑。
#include <stdio.h>
#include <string.h>
int main()
{
char name[40];
char myname[] = "Pierre de Fermat";
memcpy(name, myname, strlen(myname) + 1);//+1是因为要拷贝\0
int arr1[10] = {0};
int arr2[5] = {4,2,55,88,3};
memcpy(arr1+3, arr2, sizeof(arr2)); //arr1是 arr1[10]这个数组首元素的地址,+3就是跳过3个int类型的数据
printf("%s\n",name);
for (int i = 0;i < 10;i++)
printf("%d ", arr1[i]);
return 0;
}
其写法如下,此函数是一个字节一个字节拷贝内存的,所以如果两块空间有重叠部分,那么就会造成错误,如下图所示:
void* my_memcpy(void* dest, const void* src, const int size)
{
assert(dest);
assert(src);
char* dest1 = (char*)dest;
char* src1 = (char*)src;
for (int i = 0;i < size;i++)
{
*dest1++ = *src1++;
}
return dest;
}
如下, 从arr1开始,往后20个字节的内容,一个字节一个字节拷贝给arr+2开始,往后20个字节的空间。但是拷贝了8个字节的内存(可以理解为拷贝了两个int类型的数据)之后,函数内部dest的指针指向了原数组中“5”这个数字存储空间的第一个字节,而src的指针指向了原数组“3”这个数字存储空间的第一个字节,但是此时的“3”已经被前面的操作修改成了1,所以从这里开始一个字节一个字节复制,实际上是复制的1,所以“5”的地方被改成了1。而这样拷贝了四个字节的内存之后(step3->step4,如下面过程图的第二张),开始了原数组“4”的内容拷贝到原数组“6”的内容,但是原数组“4”,已经被改成了“2”,拷贝四次之后,一个int类型的数据被拷贝完,step4->step5,然后又重复之前的拷贝,具体步骤见下方第一张过程图片(一个格子代表一个int数据的内存,不是一个字节)。
memmove函数
memmove函数相当于是memcpy函数的升级版,考虑了两块空间重叠的问题,其写法如下:
void* my_memove(void* dest,const void* src,const int size)
{
assert(dest);
assert(src);
char* dest1 = (char*)dest;
char* src1 = (char*)src;
if (dest < src)//从前向后拷贝
{
for (int i = 0;i < size;i++)
{
*dest1++ = *src1++;
}
}
else //从后向前拷贝
{
for (int i = size - 1;i >= 0;i--)
{
*(dest1 + i) = *(src1 + i);
}
}
return dest;
}
重叠的情况分为两种,一种是目标空间起始位置在源空间起始位置的前面,另一种情况是目标空间起始位置在源空间起始位置的后面。对于前者,只需要从源空间起始位置开始,往后拷贝设定的大小即可,但是对于后者,就应该从源空间末尾处开始,从后往前拷贝设定大小的内容,如下图,很容易看出来。
如果说memmove是一个有着100分功能的函数,那么memcpy就是有60分的函数,其只适用于两块空间未重叠的情况,而memmove任何情况都使用。
memcmp函数
void* memove(void* dest,const void* src,const int size);
memcmp函数和strcmp函数类似,也是从两个指针指向的地址,一个字节一个字节比过去,比较size个字节的内容,不过memcmp函数可以比较其他的数据类型,不仅限于字符型数据,如下。
#include <stdio.h>
#include <string.h>
int main()
{
int a = 5;
int b = 4;
int* dest = &a;
int* src = &b;
int ret = memcmp(dest, src, 4);
if (ret < 0)
printf("<");
else if (ret > 0)
printf(">");
else printf("=");
return 0;
}