内存函数是直接操作计算机中内存的函数,它不关心内存中存放的是什么数据,它只按照一块块内存字节去拷贝、移动、设置、比较。使用内存函数需要包含头文件<string.h>
memcpy函数的使用和模拟实现
memcpy(memory copy)函数是用来对内存进行拷贝的,它包含三个参数void* dest,const void* src和size_t count,如strncpy函数一样,这三个参数分别是,指向目标的指针,指向源头的指针和要拷贝的字节数。函数返回值类型为void*型,返回的是目标的起始地址。使用的时候也是要保证目标空间足够大且可修改。
注意:memcpy函数只负责不重叠的两块内存数据的拷贝。

memcpy函数的使用
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
//想把arr1中的前五个元素拷贝到arr2中,也就是20个字节数
memcpy(arr2, arr1, 20);
return 0;
}

memcpy函数的模拟实现
要实现拷贝内存数据的任意字节数这一功能,我们设计三个参数void* dest,const void* src,size_t num,dest是指向目标的指针,src是指向源头的指针,num是内存中要进行拷贝的字节数,我们不清楚会传过来什么类型的指针,就把dest和src类型都设为void* ,我们不会修改src指向的内容,用const修饰更安全点。返回值是目标的起始地址,我们就创建一个指针变量ret用于存目标的起始地址。开头再加上assert断言,确保传过来的指针的有效性
函数主要逻辑:我们知道void* 指针不能直接解引用,我们要想每个字节地进行拷贝,可以把void* 强制转换为char* 再解引用进行拷贝,就可以实现这一功能了。
程序如下:
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
//确保指针有效性
assert(dest && src);
//存目标起始地址
void* ret = dest;
//每个字节进行拷贝
while (num--)
{
*(char*)dest = *(char*)src;
//找到下一个字节的地址
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
my_memcpy(arr2, arr1, 20);
return 0;
}

调试发现程序功能正常。
memmove函数的使用和模拟实现
memmove(memory move)函数是用来处理两个重叠的内存数据的拷贝(不重叠也能处理)。参数和返回值与memcpy一模一样,函数使用方法和实现逻辑也是。

memmove函数的使用
#include<stdio.h>
#include<string.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
//想把1~5拷贝到3~7上
memmove(arr + 2, arr, 20);
//让数组变成1,2,1,2,3,4,5,8,9,10
return 0;
}

memmove函数的模拟实现
参数和返回值与上面设计的memcpy一模一样,问题在于重叠的两个内存数据的拷贝该如何处理?
重叠的两块内存数据有两种情况:
情况1:

当目标在源头后面的时候,如果我们从前往后拷贝,就会覆盖源头中原来存放的值。

所以应该从后往前拷贝。
情况2:

这种情况下从前往后拷贝就不会覆盖了。
总结下来就是,目标在源头前面就从前往后拷贝,目标在源头后面就从后往前拷贝。
判断目标在源头的前面还是后面可以直接比较dest和src的地址,因为数组在内存中的存放是连续的,越往后地址越大。
函数主要逻辑:先判断目标在源头前面还是后面,在前则从前往后打印,和memcpy拷贝逻辑一样,在后则从后往前打印,从最末尾开始往前拷贝。
程序如下:
#include<stdio.h>
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
//目标在源头前面
if (dest < src)
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
//目标在源头后面
else
{
while (num--)
{
//从最末尾开始往前拷贝
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr + 2, arr, 20);
return 0;
}

调试发现程序功能正常。
memset函数的使用
memset(memory set)是用来内存设置的函数,包含三个参数void* dest,int ch,size_t num,其中dest是目标,ch是填充进去的内容,count是填充的字节数。返回的是目标的起始地址。memset会对每个字节都进行填充。

#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcdedgfdg";
//想把c到f的内容填充成x
memset(arr + 2, 'x', 6);
return 0;
}

需要注意的是,memset是每个字节都进行内容填充,如果想把整型数组元素都填充成1是不可能的,其他大于1字节的类型也是一样。
memcmp函数的使用
memcmp(memory compare)函数是进行内容比较的函数,按照每个字节去进行比较,包含三个参数:const void* lhs,const void* rhs,size_t count,前两个指针是分别指向要比较的内容,第三个是进行比较的字节数。
它的返回值逻辑和strcmp一样,
lhs>rhs则返回大于0的数
lhs==rhs则返回等于0的数
lhs<rhs则返回小于0的数

#include<stdio.h>
#include<string.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,2,3,4,0 };
int r = memcmp(arr1, arr2, 16);
printf("%d\n", r);
return 0;
}

如果比较的字节数变成17,则结果是:

转载自CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/l1147195799/article/details/160956658



