模拟实现一些库函数(2)

函数介绍

本章内容给大家展示一些内存操作函数
memcpy
memmove
memset
memcmp
给大家讲解该函数,并实现模拟

memcpy

函数讲解

memcpy函数是C语言中的一个标准库函数,用于在内存之间进行数据复制。它的函数原型如下:

void *memcpy(void *destination, const void *source, size_t num);

memcpy函数的作用是将源内存块中的数据复制到目标内存块中,复制的字节数由num指定。

destination是目标内存块的指针,指向要将数据复制到的位置。
source是源内存块的指针,指向要复制数据的起始位置。
num指定要复制的字节数。
注意,memcpy函数的参数类型为void*,这意味着它可以复制任意类型的数据。

memcpy函数的工作原理是按字节复制。它从源内存块中以字节为单位逐一复制数据,并将其存储到目标内存块中。这就是为什么需要指定要复制的字节数,以确保复制的范围正确。

值得注意的是,memcpy函数不能处理内存重叠的情况。如果源内存块和目标内存块有重叠部分,使用memmove函数会更安全,它可以正确处理这种情况。

接下来我们代码示例,来看一下该函数效果:

int main() {
    int arr1[10] = { 0 };
    int arr2[] = { 32,23,14,22,5 };

    memcpy(arr1, arr2, 20);  

    for (int i = 0; i < +5; i++)
    {
        printf("%d  ", arr1[i]);
    }

    return 0;
}

在这里插入图片描述
这个函数和strcpy的区别在于strcpy只可以拷贝字符串类型,而memcpy函数可以拷贝任何类型的数据

模拟实现

接下来我们来模拟实现一下

void* my_memcpy(void* arr1, const void* arr2, size_t size)
{
    void* ret = arr1;
    assert(arr1 && arr2);
    size_t i = 0;
    while (i < size)
    {
        *(char*)arr1 = *(char*)arr2;
        arr1 = (char*)arr1 + 1;
        arr2 = (char*)arr2 + 1;
        i++;
    }
    return ret;
}

int main() {
    int arr1[10] = { 0 };
    int arr2[] = { 32,23,14,22,5 };

    my_memcpy(arr1, arr2, sizeof(arr2));

    for (int i = 0; i < 5; i++)
    {
        printf("%d  ", arr1[i]);
    }

    return 0;
}

在这里插入图片描述
接下来,来具体分析一下模拟的memcpy函数,首先他的返回值是指向目标内存的地址,所以我们设置ret来记录其实位置的地址,同时用assert函数来保证传入的arr1指针和arr2指针非空,之后进入我们的复制循环中,由于该函数是一个字节一个字节的访问,所以才循环内部,我们把arr2强转为char类型后解引用,赋值给arr1强转为char 后解引用,在这里我们不能使用

(char)arr1++ = (char)arr2++;

的原因是++的优先级高,所以如果使用的话,arr1就会跳过以传入数据的字节,也就是4个字节,之后才强转为char* 进行操作,并不会一个一个字节的操作,所以我们不使用这个代码,我们直接把arr1强转为char*后进行+1操作在赋值给arr1,同理arr2进行同样的操作。这样就可以一个字节一个字节的进行操作了。

memmove

函数讲解

刚刚在介绍memcpy时我们提到了,memcpy不能处理内存重叠的情况,而memmove可以,那么我们就来介绍一下memmove。
memmove 是 C/C++ 标准库中的一个函数,用于在内存中移动一定数量的字节数据。

memmove 函数的函数原型如下:

void* memmove(void* dest, const void* src, size_t n);

参数解释如下:

dest:目标内存块的指针,表示要移动数据的目标位置。
src:源内存块的指针,表示要从其中复制数据的起始位置。
n:要移动的字节数,即要复制的数据大小。
memmove 函数的功能是将 src 所指向的内存块中的数据复制到 dest 所指向的内存块中,同时保证当 src 和 dest 内存块重叠时也能正常执行。

相比于另一个相关的函数 memcpy,memmove 函数在处理内存块重叠的情况下更为安全,因为它会根据内存块的重叠情况自动选择正确的数据复制方式。这意味着 memmove 函数即使在源和目标内存块重叠的情况下,也可以正确地进行数据复制,而不会导致数据损坏。

介绍完成后我们来看一下该函数的效果。

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8 };
	memmove(arr1, arr1 + 2, 8);
	for (int i = 0; i < 8; i++)
	{
		printf("%d  ", arr1[i]);
	}
	return 0;
}

在这里插入图片描述

模拟实现

那么接下来我们来模拟实现一下该函数

void* my_memmove(void* dest,const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	size_t i = 0;
	if (dest < src)
		{
		while (i < num)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
			i++;
		}
		}
	else
		{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
		}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8 };
	my_memmove(arr1+2, arr1, 8);
	for (int i = 0; i < 8; i++)
	{
		printf("%d  ", arr1[i]);
	}
	return 0;
}

在这里插入图片描述
对于内存重叠的情况无非就是dest<src和dest>src两种情况,dest<src的情况呢,其实和memcpy差不多,所以在这里我们不再过多赘述,我们只了解一下dest>src的情况,首先如果dest>src的话会出现覆盖的现象,所以我们从后面往前面赋值,直接把dest和src强转为char*然后加上num个字节数,从后面往前面赋值,我们直接把循环条件设置为num–,下次进入while循环直接就是从倒数第一个字节到了倒数第二个字节,实现了一个字节一个字节操作的编程行为。

memset

函数讲解

memset 是 C/C++ 标准库中的一个函数,用于将一块内存区域设置为指定的值。

memset 函数的函数原型如下:

void* memset(void* ptr, int value, size_t num);

参数解释如下:

ptr:指向要填充的内存区域的指针。
value:要设置的值,作为 unsigned char 转换后的整数。
num:要设置的字节数,即要填充的内存区域的大小。
memset 函数的作用是将 ptr 所指向的内存区域的每个字节都设置为 value。这个函数通常用于初始化内存或清除内存区域。

这个函数还是相对起来十分简单,接下来我们使用以下看一下效果。

int main() 
{
    char str[20]="hexxo,world!";
    memset(str+2, 'l', 2);
    printf("%s\n", str);  
    return 0;
}

在这里插入图片描述

模拟实现

很明显,hexxo,world!变成了hello,world!效果也是十分明显,那么我们接下来直接进行模拟。

void* my_memset(void* str,int value,size_t num)
{
    if (str == NULL)
        return NULL;
    assert(num>0);
    void* ret = str;
    while (num--)
    {
        *(char*)str = value;
        str = (char*)str + 1;
    }
    return ret;
}
int main() 
{
    char str[20]="hexxo,world!";
    my_memset(str+2, 'l', 2);
    printf("%s\n", str);  
    return 0;
}

在这里插入图片描述
首先,我们的memset函数需要三个参数,一个参数是填充目标地址,一个是填充值,一个是填充字节数。首先保证填充目标地址不能是空指针,其次检验填充字节数不能是非正数,
接下来返回目标填充首地址,接下来就是填充循环,就结束了,这个函数模拟相对来说简单了许多。

memcmp

函数讲解

memcmp 是 C/C++ 标准库中的一个函数,用于比较两段内存区域的内容是否相同。

memcmp 函数的函数原型如下:

int memcmp(const void* ptr1, const void* ptr2, size_t num);

参数解释如下:

ptr1:指向第一个内存区域的指针。
ptr2:指向第二个内存区域的指针。
num:要比较的字节数,即要比较的内存区域的大小。
memcmp 函数的作用是将两个内存区域的内容进行逐字节比较,直到遇到不相等的字节或比较字节数达到指定的大小 num 为止。

返回值的含义如下:

如果两段内存区域相等,返回值为0。
如果两段内存区域不相等,返回值小于0表示第一个不相等字节在 ptr1 中的字节值小于在 ptr2 中的字节值,返回值大于0表示相反情况。

了解了之后我们来具体看一下她的i效果吧。

int main() {
    int arr1[] = { 1,3,3 };
    int arr2[] = { 1,2,5 };
    int k = 0;
    scanf("%d", &k);
    int ret=memcmp(arr1, arr2, k);
    if (ret == 0)
        printf("前%d个字节相同",k);
    else if(ret>0)
        printf("前%d个字节arr1大",k);
    else
        printf("前%d个字节arr2大",k);
    return 0;
}

在这里插入图片描述

模拟实现

了解过后我们直接来模拟实现该函数。

int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
    const unsigned char* p1 = (const unsigned char*)ptr1;
    const unsigned char* p2 = (const unsigned char*)ptr2;

    for (size_t i = 0; i < num; ++i) {
        if (p1[i] < p2[i]) {
            return -1;
        }
        else if (p1[i] > p2[i]) {
            return 1;
        }
    }

    return 0;
}
int main() {
    int arr1[] = { 1,3,3 };
    int arr2[] = { 1,2,5 };
    int k = 0;
    scanf("%d", &k);
    int ret=my_memcmp(arr1, arr2, k);
    if (ret == 0)
        printf("前%d个字节相同",k);
    else if(ret>0)
        printf("前%d个字节arr1大",k);
    else
        printf("前%d个字节arr2大",k);
    return 0;
}

在这里插入图片描述
我们只是比较两个指针所指向内容大小,不希望其发生改变。所以,我们用const来修饰两个参数,之后我们把ptr1和ptr2转化为无符号char型分别赋值给无符号char型p1和p2,之后进入循环通过逐步比较p达到了逐字节比较的操作,并看情况选择返回值,直到遍历完for循环如果都相同,则返回0,达到模拟函数目的。

总结

经过我们模拟实现了众多库函数,相信大家能发现许多相似相同的地方,最后各位看客老爷万福金安。

在这里插入图片描述

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值