首页 > 系统相关 >C语言王国——内存函数

C语言王国——内存函数

时间:2024-06-02 13:01:13浏览次数:23  
标签:函数 void destination C语言 char source 内存 memcpy

目录

1 memcpy函数

1.1 函数表达式

1.2 函数模拟

2 memmove函数 

2.1 函数的表达式

2.2 函数模拟 

3 memset函数

3.1 函数的表达式

3.2 函数的运用

4 memcmp函数

4.1函数的表达式:

4.2 函数的运用

5 结论

接上回我们讲了C语言的字符和字符串函数,今天也由姜糖来给大家分享一下C语言的内存函数吧!

1 memcpy函数

1.1 函数表达式

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

此函数是将source变量中num个字节赋值给destination

注意

  • 需包含头文件string
  • 遇到'\0'不会停下
  • 如果source和destination有任何重叠,复制的结果都是未定义的。

1.2 函数模拟

原理函数memcpy从cource的位置开始向后复制num个字节的数据到destination指向的内存位置

void* memcpy(void* destination, const void* source, size_t num)
{
	assert(destination && source);//断言是否为空指针
	char* ret = destination;//记录改变前的地址,以防丢失
	while (num--)
	{
		*(char*)destination = *(char*)source;//因为是字节的改变所以强转为char*
		destination = (char*)destination + 1;
		source = (char*)source + 1;
	}
	return ret;
}

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

注意:

  1. 使用void*指针进行间接引用时,必须先将其转换为实际类型的指针。这里是改变字节,所以使用时改为char*。
  2. 重叠的就交给memmove处理。


2 memmove函数 

2.1 函数的表达式

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

*包含头文件string

用来处理memcpy处理不了的堆叠问题。

那什么是堆叠问题呢?

如果destination为source+1,num为12则,当source中的1赋值到destination上的2时,就导致了source中的2也变成了1,导致拷贝结果不对,这就是堆叠。

那堆叠该怎么解决呢?

在memcpy中我们使用的是从前往后拷贝,但是这里不行,所以我们使用从前往后拷贝,在数字被改变之前就完成拷贝的步骤。那是否从后往前拷贝就能解决所有问题呢?答案是不行的,比如:

如图,在arr数组上面将蓝色拷贝给黄色就会出错,所有我们在编写memmove中应该分类讨论。

那具体该怎么分类呢?

同样如图所示,设蓝色为source,若黄色首地址在蓝色前面则,从后往前拷贝;反之则从前往后。

2.2 函数模拟 

#include<stdio.h>
#include<assert.h>

void* memmove(void* destination, const void* source, size_t num)
{
	assert(destination && source);
	char* ret = destination;
	if (destination < source)//从前往后
	{
		while (num--)
		{
			*(char*)destination = *(char*)source;//因为是字节的改变所以强转为char*
			destination = (char*)destination + 1;
			source = (char*)source + 1;
		}
	}
	else//从后往前
	{
		*((char*)destination + num) = *((char*)source + num);
	}
}

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

有些人可能会有疑惑,好像memcpy能干的,memmove能干,memcpy不能干的事,memcove也能干,那为什么存在memcpy呢?

memcpy()函数的实现相对于memmove()函数来说更简单、更高效。因为memcpy()不考虑内存重叠的情况,所以它在处理非重叠内存区域的数据复制时更快。而memmove()函数需要先判断内存区域是否重叠,再决定如何进行数据复制,所以相对来说会慢一些。

所以,当你确定要进行的数据复制操作不会涉及到内存重叠的情况时,可以选择使用memcpy()函数。而当你不能确定内存是否重叠,或者确实需要处理内存重叠的情况时,可以使用memmove()函数来确保正确的复制结果。

总而言之,memcpy()和memmove()都有各自的应用场景,你可以根据实际需求选择合适的函数。

姜糖也只能说存在即合理,其实如果想偷懒都用memmove就行啦。


3 memset函数

3.1 函数的表达式

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

此函数是将内存中的值以字节为单位设置成想要的内容。

包含头文件string。

3.2 函数的运用

#include<stdio.h>
#include<string.h>

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	memset(arr, 0, 40);//将数组全部归0
	int i;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}

	char str[] = "Hello world";
	memset(str, 'x', 5);//将Hellw全部置为x
	puts(str);

	return 0;
}

输出结果为:


4 memcmp函数

4.1函数的表达式:

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

比较ptr1和ptr2指针指向的位置开始,向后num个字节

包含头文件string。

此函数和strncmp原理大致相同。

4.2 函数的运用

#include<stdio.h>
#include<string.h>

int mian()
{
	char str1[] = "hello world";
	char str[] = "helloworld";
	int ret = memcmp(str1, str, 6);
	if (ret)
	{
		printf("前6个一样");
	}
	else
		printf("前6个不一样");

	return 0;
}

输出结果:


5 结论

最后两个函数的模拟姜糖改为了函数的运用,意在让大家自己开动脑筋结合本文和前文的字符串函数的模拟自己去完成,因为他们都有异曲同工之妙。

接下来有什么问题可以私信姜糖哦。也希望大家能一键三连,谢谢大家了。最后就让我们一起进步吧!

标签:函数,void,destination,C语言,char,source,内存,memcpy
From: https://blog.csdn.net/2301_78955228/article/details/139388111

相关文章

  • C语言-for循环之穷举法练习
    //需求:求出一个偶数纸币需要多少张50元,20元,10元来配合include<stdio.h>intmain(void){intn=0;//存储你输入的数值inti=0;//for循环使用intj=0;intk=0;intw=50;定义50元的数值inte=20;定义20元的数值ints=10;定义10元的数值printf("pleaseente......
  • 【C语言】文件操作(中卷)
    前言在文件操作(上卷)中,讲到的主要都是正式文件操作开始之前的前置知识,而这一卷中,我们将开始正式地操作文件。在上卷中我们已经说到,stdinstdoutstderr是三个C语言程序启动时默认打开的流。这三个流的类型是:FILE*,通常称为文件指针。而C语言,就是通过FILE*的文件指针来维护流的......
  • C语言----递归函数,计算一个非负整数的数字之和
    intDigitSum(intn){if(n==0)//如果n为0,则停止递归,因为没有更多的数字可以添加。{return0;}else{returnn%10+DigitSum(n/10);}/*假设输入123,第一次递归,return3和DigitSum(12)DigitSum(12)......
  • C语言练习题之——从简单到烧脑(13)(每日两道)
    打印爱心1.1:普通输出爱心#include<stdio.h>intmain(){ printf("******************\n");//7(代表边上的空格) printf("******************************\n");//4 printf("************************************\n&quo......
  • 第四篇:openEuler网络配置与C语言开发环境验证
    在阅读文章前,请读者朋友认真阅读免责声明:免责声明:本人所发表的所有文章、资源、知识等内容(包括免费、付费等)旨在向广大读者介绍我的职业生涯中积累的一些经验、知识等内容,受个人水平所限这些知识、经验、代码等不一定是最佳实践,也可能存在遗漏、错误,请广大读者自行甄别(甄别......
  • 【C语言小游戏——“猜数字”】
    编写一个简单的C语言小游戏——“猜数字”。这个游戏的规则是:计算机随机生成一个1到100之间的整数,玩家尝试猜测这个数字。如果玩家猜的数字太大或太小,程序会给出提示,直到玩家猜中为止。#include<stdio.h>#include<stdlib.h>#include<time.h>intmain(){//初始化......
  • 【C语言】typedef 和define对比
    【前言】     typedef和define都是给定义别名的关键字。通过他们我们可以对一些比较长的类型或语句进行缩短。【概念】        typedef关键字的作用范围主要限定在特定的数据类型上。通过typedef,我们可以为基本类型(如int、float)或自定义的结构体(typedefst......
  • 【Python内功心法】:深挖内置函数,释放语言潜能
    文章目录......
  • ref和reaction的区别(以及TS中ref,computed函数会自动推断定义其泛型(一般不用自己动手))
    其次就是了解ref,reactive的区别。ref通过对象名.value来访问对象里的值,若对象里还有属性则访问其需要:对象名.value.属性名reactive则通过:对象名.属性名,来直接访问属性值其次,两者都是响应式对象。但如果对直接对reactive对象进行赋值,那么其会丢失响应性。代码示例如下:<scri......
  • c++内存分配
    想象一下你有一个房子,房子里有很多房间,每个房间都可以用来存放东西。在C++中,内存管理就像是你在设计和建造这个房子。你可以自己决定房间的数量和大小,也可以随时动态地改变它们。但是,你需要小心地管理这些房间,确保你不会浪费空间或者让房间里的东西互相干扰。所以,C++中的内存管......