栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > C/C++/C#

C语言之内存函数

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C语言之内存函数

在此之间,我们学过许多的字符函数,例如strcpy,strstr,strcmp等等,这里我们以strcpy函数进行举例:

//实现将arr1拷贝到arr2中
int main()
{
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[5] = { 0 };
	strcpy(arr2, arr1);
	return 0;
}

程序并没有正确运行,编译器报错:

错误分析如下:
上述代码是无法实现将arr1拷贝到arr2中,由此可见,像strcmp,strcpy,strstr这种字符串函数,它虽然能够实现字符串拷贝,比较等功能,但是由于它们的操作对象是字符串,因此对于整形数组,浮点型数组等并不适用。

那么对于整形数组,浮点型数组等其他的数据,我们该如何进行操作呢?

c语言给出了另一类函数-------内存函数(memcpy/memmove/memcmp)

memcpy:
//void*-----通用类型指针:可以接受各种类型的参数
void*memcpy(void*destination,const void*source,size_num)//size_num的单位是字节

还是选用上述实例:

#include
#include
//实现将arr1拷贝到arr2中
int main()
{
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[5] = { 0 };
	memcpy(arr2, arr1,sizeof(arr1));
	return 0;
}

此时打开监视窗口,我们不难发现,数组之间完美的实现了拷贝。

结构体类型实现拷贝:

举例:

struct person 
{
	int age;
	char name[20];
	char phone[13];
};
int main()
{
	struct person arr3[] = { {20,"张三","20031319"},{19,"lisa","193684"} };
	struct person arr4[3] = {0};
	memcpy(arr4, arr3, sizeof(arr3));
}

此时打开监视窗口,我们不难发现,结构体之间完美的实现了拷贝。

模拟实现memcpy:

以整形进行举例:

#include
#include
void* my_memcpy(void* dest, const void* scr,size_t num)
{
	void* ret = dest;
	//断言:为避免是空指针
	assert(dest != NULL);
	assert(scr != NULL);
	while (num--)//num为要拷贝的长度
	{
	//不能直接解引用操作的原因:void*类型不能直接进行++/--操作
		*(char*)dest = *(char*)scr;//先强制类型转换在解引用
		dest=(char*)dest+1;
		scr=(char*)scr+1;
	}
	return ret;//不能直接返回dest,因为此时的dest并不是首地址
}
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[5] = { 0 };
	my_memcpy(arr2, arr1,sizeof(arr1));
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}
1 2 3 4 5

上述实例,我们是实现的功能是将一个数组中的元素拷贝到另一个数组中,如果现在我们实现将数组中的前几个元素拷贝到后面的几个呢?

举例:

//实现将1 2 3 4 5拷贝到3 4 5 6 7的位置上
#include
#include
void* my_memcpy(void* dest, const void* scr,size_t num)
{
	void* ret = dest;
	assert(dest != NULL);
	assert(scr != NULL);
	while (num--)
	{
		*(char*)dest = *(char*)scr;
		dest=(char*)dest+1;
		scr=(char*)scr+1;
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memcpy(arr1+2, arr1,20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

预期输出结果为:

1 2 1 2 3 4 5 8 9 10

实际输出结果:

1 2 1 2 1 2 1 8 9 10

预期和实际不相符分析如下:

由此可得出:我们所编写的my_memcpy函数并不能实现在同一个数组中的拷贝,会出现数的覆盖现象。

那库函数memcpy能否实现呢?

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

输出结果如下:

1 2 1 2 3 4 5 8 9 10

看到这里,相信很多人都会产生疑惑,为什么库函数memcpy可以实现,而我们编写的my_memcpy不能实现呢?难道是我们写错了?

事实并非如此,memcpy虽然也实现了这样的功能,但C语言标准规定:memcpy:用来处理不重叠的内存拷贝。memmove:处理重叠的内存拷贝

我们所编写的my_memcpy是因为严格按照C语言的标准所编写,而在VS编译器上memcpy超额完成了任务,相当于抢了memmove的饭碗。

下面我们就来学习memmove函数!

memmove:

依然是上述实例:

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

输出结果如下:

1 2 1 2 3 4 5 8 9 10

现在得出的结果正是我们预期的效果!

模拟实现memmove:

目的地的地址低于源头地址:

正序进行拷贝:

#include
#include
my_memmove(void* dest, const void* scr, size_t count)
{
	assert(dest != NULL);
	assert(scr != NULL);
	void* ret = dest;
	while (count--)
	//直接按照源头一个个进行打印,不存在数的覆盖
	{
		*(char*) dest= *(char*) scr;
		dest = (char*)dest + 1;
		scr = (char*)scr + 1;
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1, arr1+2,20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

这种比较简单,这里就不赘述分析过程了
输出结果为:

3 4 5 6 7 6 7 8 9 10

目的地址高于源头地址:

倒序进行拷贝:

#include
#include
my_memmove(void* dest, const void* scr, size_t count)
{
	assert(dest != NULL);
	assert(scr != NULL);
	void* ret = dest;
	while (count--)
	{
		*((char*)dest + count) = *((char*)scr + count);
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1+2, arr1,20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

输出结果为:

1 2 1 2 3 4 5  8 9 10

对于该行代码的实现过程,我们分析如下:

*((char*)dest + count) = *((char*)scr + count);


对于上述两种情况,我们可用一个程序进行表示:

#include
#include
my_memmove(void* dest, const void* scr, size_t count)
{
	assert(dest != NULL);
	assert(scr != NULL);
	void* ret = dest;
	if(dest
		*(char*)dest = *(char*)scr;
		dest = (char*)dest + 1;
		scr = (char*)scr + 1;
	}
	else//倒序进行拷贝
	{
	while(count--)
	{
		*((char*)dest + count) = *((char*)scr + count);
	}
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1+2, arr1,20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

输出结果如下:

1 2 1 2 3 4 5 8 9 10 
memcmp:

将两个存储区的前n个字节进行比较。

举例:

#include
int main()
{
	int arr[] = { 1,2,3,4,5 };
	int arr2[] = { 1,2,5,4,3 };
	int ret=memcmp(arr, arr2, 9);//arr>arr2,返回大于零的数字,arr
	//注:VS编译器返回-1/0/1,虽然不严谨,但是并不违背C语言的标准规定
	printf("%dn", ret);
	return 0;
}

输出结果如下:

-1

分析如下:

memset:内存设置函数

举例:

字符型:

#include
int main()
{
	char arr[10] = "";
	memset(arr, '#', 10);//10代表更改10个字节
	return 0;
}

整形:

#include
int main()
{
	int  arr[10] = {0};
	memset(arr, 1, 10);
	return 0;
}

输出如下:
让不少人产生疑惑的是:为什么此时并没有实现将数组中的10个元素都修改为1呢?

原因是:该函数的操作单位是字节,而数组是一个整形数组,其中的元素都为整形,每个元素为4个字节。

具体分析如下:
因此,在使用该函数的时候,一定要注意类型。

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1037048.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号