【C语言】内存函数

今天我来讲一下我最近学习的一些函数知识:

一.memcopy的使用及模拟实现

二.memmove的使用及模拟实现

三.memset的使用

四.memcmp的使用

1.memcopy的使用及模拟实现

同样,我们看一下这个函数的基本参数:

这个函数的各种参数,返回类型都是void*,说明这个函数应该能用所有的函数类型,这个时候我们要好好的注意1了。

这个函数能够确定返回多少个字节,看个人需求,下面我们来一起使用一下:

#include<stdio.h>
#pragma warning(disable:4996)
#include<ctype.h>
#include<string.h>
#include<assert.h>
#include<errno.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };//待被改变的数组
	int arr2[10] = { 2,4,1,3,5,9,0,6,8,7 };//进攻方
	memcpy(arr1,arr2,20);
	int i = 0;
	for (i = 0; i < sizeof(arr1) / sizeof(arr1[0]);i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

我们看到,这个数组成功的被改动了,我们也迫不及待的来模拟实现一下吧:

void* my_memcpy(void* destination, const void* source,size_t num)//以前我们碰到过,最好是一个一个字节进行交换
{
	while (num)//没有发生交换就继续发生交换
	{
		*(char*)destination = *(char*)source;//注意是内容交换而不是指针交换
		((char*)destination)++;
		((char*)source)++;//由于强制类型转换具有临时性,我们要多多用上小括号来确保它能达到我们的目的
		num--;//每次交换一个字节就要去减一个,那么我们要去强制类型转换成char*类型
	}
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };//待被改变的数组
	int arr2[10] = { 2,4,1,3,5,9,0,6,8,7 };//进攻方
	my_memcpy(arr1,arr2,20);
	int i = 0;
	for (i = 0; i < sizeof(arr1) / sizeof(arr1[0]);i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

这样就比较完美了。

(注意:中间的((char*)destination)++;
((char*)source)++;还可以写成destination=(char*)destination+1;source=(char*)source+1,效果相同;因为临时性,没有经过强制类型转换的指针不能+或-1操作,我们要留意)

2.memmove的使用及模拟实现

同样的,我们来看一下这个函数的基本情况:

这个函数和上面的memcopy最大的区别是这个memmove可以在内存重叠的地方进行数据移动,而memcopy最好不要去应用内存重叠的区域,要不然容易发生错误。

我们先来个错误示例:(单纯使用memcpy函数,来对比memmove)

#include<stdio.h>
#pragma warning(disable:4996)
#include<ctype.h>
#include<string.h>
#include<assert.h>
#include<errno.h>
void* my_memcpy(void* destination, const void* source,size_t num)//以前我们碰到过,最好是一个一个字节进行交换
{
	while (num)//没有发生交换就继续发生交换
	{
		*(char*)destination = *(char*)source;//注意是内容交换而不是指针交换
		((char*)destination)++;
		((char*)source)++;//由于强制类型转换具有临时性,我们要多多用上小括号来确保它能达到我们的目的
		num--;//每次交换一个字节就要去减一个,那么我们要去强制类型转换成char*类型
	}
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };//待被改变的数组
	//int arr2[10] = { 2,4,1,3,5,9,0,6,8,7 };//进攻方
	my_memcpy(arr1+1,arr1,20);
	int i = 0;
	for (i = 0; i < sizeof(arr1) / sizeof(arr1[0]);i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

看结果:

为什么失败了呢?主要是因为内存重叠,操作不当。

下面我们用画图的方式为大家讲解:

(注意:蓝色框代表“source”,红色框代表“destination”)

按照从左往右,从上到下的顺序,这样就可以很好的解释为什么会打印出这么多‘1’了。

当然我们还有一种方法来避免,只需要把arr1和arr1+1这两个指针交换一下位置就好了,我们看:

#include<stdio.h>
#pragma warning(disable:4996)
#include<ctype.h>
#include<string.h>
#include<assert.h>
#include<errno.h>
void* my_memcpy(void* destination, const void* source,size_t num)//以前我们碰到过,最好是一个一个字节进行交换
{
    while (num)//没有发生交换就继续发生交换
    {
        *(char*)destination = *(char*)source;//注意是内容交换而不是指针交换
        ((char*)destination)++;
        ((char*)source)++;//由于强制类型转换具有临时性,我们要多多用上小括号来确保它能达到我们的目的
        num--;//每次交换一个字节就要去减一个,那么我们要去强制类型转换成char*类型
    }
}
int main()
{
    int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };//待被改变的数组
    //int arr2[10] = { 2,4,1,3,5,9,0,6,8,7 };//进攻方
    my_memcpy(arr1,arr1+1,20);
    int i = 0;
    for (i = 0; i < sizeof(arr1) / sizeof(arr1[0]);i++)
    {
        printf("%d ", arr1[i]);
    }
    return 0;
}

这样就可以很好的避免这个问题了。

我们不妨画一下图来解释:

按照从左到右,从上到下的顺序,是不是很清晰?

这样我们就可以在my_memcpy的基础上进行改造了,我们看下面:

#include<stdio.h>
#pragma warning(disable:4996)
#include<ctype.h>
#include<string.h>
#include<assert.h>
#include<errno.h>
void* my_memmove(void* destination, const void* source,size_t num)//以前我们碰到过,最好是一个一个字节进行交换
{
	if (source > destination)
	{
		while (num)//没有发生交换就继续发生交换
		{
			*(char*)destination = *(char*)source;//注意是内容交换而不是指针交换
			((char*)destination)++;
			((char*)source)++;//由于强制类型转换具有临时性,我们要多多用上小括号来确保它能达到我们的目的
			num--;//每次交换一个字节就要去减一个,那么我们要去强制类型转换成char*类型
		}
	}
	else if (source < destination)
	{
		while (num)
		{
			char* des = (char*)destination + num-1;
			char* sou = (char*)source + num-1;//注意-1的操作啊,不然会有bug的,末尾必记住
			*(des) = *(sou);
			des--;
			sou--;
			num--;//每次交换一个字节就要去减一个,那么我们要去强制类型转换成char*类型
		}
	}
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };//待被改变的数组
	//int arr2[10] = { 2,4,1,3,5,9,0,6,8,7 };//进攻方
	my_memmove(arr1+1,arr1,20);
	int i = 0;
	for (i = 0; i < sizeof(arr1) / sizeof(arr1[0]);i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

我们只是把source和destination的顺序交换一下:

还不错,顺便就把memmove的模拟实现完成了。

对于使用memmove函数而言,把my_memmove换成memmove,结果是一样的。

3.memset的使用

还是惯例,我们先简单看一下它的基本信息:

这个函数的用法是给一个指针,指针以及其往后的内容要改变num个字节,这些内容均改变成value。

为了便于理解,我们直接上代码:

#include<stdio.h>
#pragma warning(disable:4996)
#include<ctype.h>
#include<string.h>
#include<assert.h>
#include<errno.h>
int main()
{
	char arr1[100] = "hellobiteu";
	printf("%s\n",memset(arr1, 'x', 6));
	return 0;
}

这里为什么可以认为‘x’是整型呢?因为‘x’是以ascii的码值存放在内存里面的,如果认为‘x’是字符,那么用int打印成功的原因是int类型的范围远远大于char类型。

(注意:我们最好不要用这个函数去处理char类型以外的数组,如int元素组成的数组,它是一个字节一个字节进行改变的,容易出现bug,我们可以在调试过程中打开内存布局,好好观察一下)

4.memcmp的使用

我们先看一下这个函数的基本信息:

这个函数和我们之前的strncmp很像,传参的样式几乎相同,但这个涉及到内存方面,而且是一个一个字节进行比较,理论上是可以任意类型的数据内存进行比较的,字符(串)的比较当然是没有问题的,但事实真的是如此吗?

这里我们仅展示比较字符串的,比较整型的bug我们在看到下一篇文章就自然而然就懂了。

#include<stdio.h>
#pragma warning(disable:4996)
#include<ctype.h>
#include<string.h>
#include<assert.h>
#include<errno.h>
int main()
{
	char arr1[100] = "hellobit";
	char arr2[100] = "hellobiteu";
	printf("%d", memcmp(arr1, arr2, 8));
	return 0;
}

下一篇再见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值