C语言之内存函数

C语言之内存函数

文章目录

  • C语言之内存函数
    • 1. memcpy 使⽤和模拟实现
      • 1.1 memcpy 函数的使用
      • 1.3 memcpy的模拟实现
    • 2. memmove 使⽤和模拟实现
      • 2.1 memmove 函数的使用
      • 2.2 memmove的模拟实现
    • 3. memset 函数的使用
    • 4. memcmp 函数的使⽤

1. memcpy 使⽤和模拟实现

函数声明如下:

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

memcpy函数和strncpy函数很相似,

  1. 只不过strncpy函数只能处理字符数组,而memcpy函数可以处理任意类型的数据
  2. strncpy函数会在目标字符数组结尾添加’\0’,而memcpy函数则不会
  3. 都在string.h库函数中

1.1 memcpy 函数的使用

代码一:
将arr1中的1 2 3 4 5 拷贝到arr2中

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

代码运行结果如下:
在这里插入图片描述

memcpy函数有三个参数

  1. 参数一为需要拷贝的目标地址
  2. 参数二为拷贝数据来源的地址
  3. 参数三为需要拷贝的字节大小
    在上述代码中,传给了memcpy函数20个字节的大小
    因为整型是4个字节,所以只会拷贝前5个数据

代码二:
将arr1中的4 5 6 7 8拷贝到arr2中

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

在这里插入图片描述

代码三:
将arr1中的字符串拷贝到arr2中

#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "Hello \0World!";
	char arr2[20] = { 0 };
	memcpy(arr2, arr1, 13);
	int i = 0;
	for (i = 0; i < 13; i++)
	{
		printf("%c", arr2[i]);
	}
	return 0;
}

代码运行结果如下:
在这里插入图片描述
memcpy函数在拷贝数据时,遇到\0时不会停下来

代码四:
将arr中的 1 2 3 4 5 拷贝到arr中4 5 6 7 8的位置上

#include <stdio.h>
#include <string.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	memcpy(arr + 3, arr, 5 * sizeof(int));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

在这里插入图片描述

由于空间重叠了,当改dest的第三个元素时,src的第三个元素已经被改成了1,使用dest第三个元素为1,第四个同理,为2,所以使用memcpy无法拷贝重复的空间

在VS2022中可以实现
在这里插入图片描述
但是
C语言中规定:
memcpy拷贝的就是不重复的数据
重复的数据交给memmove

在VS2022中,memcpy是可以拷贝重复部分的数据的,在C语言中规定的memcpy功能可能只有60分,但是VS2022中可能将其提升到了100分

总结:
• 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。
• 这个函数在遇到 ‘\0’ 的时候并不会停下来。
• 如果source和destination有任何的重叠,复制的结果都是未定义的

1.3 memcpy的模拟实现

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

思路:

  1. 由于memcpy要处理不同类型的数据,所以第一个参数和第二个参数得是void类型的,void类型的指针可以接收任意类型的地址
  2. 由于不确定传进来的是什么数据,只知道需要拷贝多少字节,在函数内部可以将其强制类型转换为char*类型的指针,一个字节一个字节拷贝
  3. 函数返回值为dest的地址,所以为void*

实现代码如下:

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

void* my_memcpy(void* dest, const void* src, size_t num)
{
	char* ret = dest;
	assert(dest && src); //assert断言,判断传入的地址是否为空指针
	while (num--)   //一个字节一个字节拷贝
	{
		*(char*)dest = *(char*)src; //void*类型不能解引用,并且需要一个字节一个字节的拷贝,所以强制类型转换为char*类型
		dest = (char*)dest + 1; //强制类型转换是临时的,再次强制类型转换并+1找到下一个需要交换的地址
		src = (char*)src + 1;
	}
	return ret;  //返回dest的地址
}

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

2. memmove 使⽤和模拟实现

函数声明如下:

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

• 和memcpy的差别就是memmove函数处理的源内存块和⽬标内存块是可以重叠的

• 如果源空间和⽬标空间出现重叠,就得使⽤memmove函数处理。

2.1 memmove 函数的使用

将arr中的 1 2 3 4 5 拷贝到arr中4 5 6 7 8的位置上

#include <stdio.h>
#include <string.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	memcpy(arr + 3, arr, 5 * sizeof(int));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

代码运行结果如下:
在这里插入图片描述

2.2 memmove的模拟实现

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

思路:

  1. 由于memmove也要处理不同类型的数据,所以第一个参数和第二个参数得是void类型的,void类型的指针可以接收任意类型的地址
  2. 由于不确定传进来的是什么数据,只知道需要拷贝多少字节,在函数内部可以将其强制类型转换为char*类型的指针,一个字节一个字节拷贝
  3. 函数返回值为dest的地址,所以为void*
  4. dest 和 src 会有两种关系
    1.dest 在 src 左边
    2.dest 在 src 右边

情况一:
在这里插入图片描述

上述情况,虽然有重叠的空间,但是还是可以拷贝,实现方式和memcpy一样

情况二:

在这里插入图片描述

在上述代码中,出现了重叠的空间,如果正序交换的话,后面的内容被覆盖了,无法交换,所以我们换种方式交换,逆序交换
在这里插入图片描述
这样交换,内容就不会被覆盖了

实现代码如下:

#include <stdio.h>
#include <assert.h>
void* my_memcpy(char* dest, const char* src, size_t num)
{
	char* ret = dest; 
	assert(dest && src);   //assert断言
	if (dest < src)   //当dest在src左边时
	{
		while(num--)      //逻辑和memcpy一致
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else             //dest在src右边
	{
		while (num--)  //一个字节一个字节拷贝
		{
			*((char*)dest + num) = *((char*)src + num); //找到最后一个字节然后拷贝 num--之后找到倒数第二个字节拷贝
		}
	}
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memcpy(arr + 3, arr, 5 * sizeof(int));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

3. memset 函数的使用

函数声明如下:

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

memset是⽤来设置内存的,将内存中的值以字节为单位设置成想要的内容
第一个参数是需要修改的地址
第二个参数是设置成什么内容
第三个参数是要设置的大小

#include <stdio.h>
#include <string.h>
int main()
{
	char arr[] = "abcdefghi";
	memset(arr, 'x', 5);
	printf("%s\n", arr);
	return 0;
}

代码运行结果:
xxxxxfghi

将前5个字节的元素改成了x

4. memcmp 函数的使⽤

函数声明如下:

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

和strncmp相似
都是⽐较从ptr1和ptr2指针指向的位置开始,向后的num个字节
返回值如下:
如果ptr1大于ptr2则返回一个大于零的值
如果ptr1小于ptr2则返回一个小于零的值
如果ptr1等于ptr2则返回一个零
在这里插入图片描述

#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[] = { 1,2,3,4,9 };
	int ret = memcmp(arr1, arr2, 16);
	if (ret > 0)
		printf("大于\n");
	else if (ret < 0)
		printf("小于");
	else
		printf("等于\n");
	return 0;
}

代码运行结果:
等于

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/190998.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【python】Python将100个PDF文件对应的json文件存储到MySql数据库(源码)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

video标签在h5中被劫持问题

将video的视频链接转为blob export const encryptionVideo (options: URL) > {return new Promise((resolve, reject) > {window.URL window.URL || window.webkitURL;var xhr new XMLHttpRequest();xhr.open(GET, options.url, true);xhr.responseType blob;xhr.onl…

Windows 7隐藏用户测试

请注意Window 7是在虚拟机上安装的&#xff0c;ip是192.168.0.108。 下边都是在虚拟机Window 7上操作&#xff0c;直到最后远程连接才在自己本机Windows 11上操作。 需要同时按下Windowsr,然后输入cmd&#xff0c;再点击确定。 在命令上里边输入net user可以显示一下用户。 …

Unity阻止射线穿透UI的方法之一

if(UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject()) return; 作者&#xff1a;StormerZ https://www.bilibili.com/read/cv27797873/ 出处&#xff1a;bilibili

Qt 样式表

QLabel&#xff0c;应用于Widget&#xff1a; .QLabel {background-color:pink; }.QLabel[warnlevel_1] {border:5px solid yellow; }.QLabel[warnlevel_2] {border:5px solid red; } QWidget{background-color:rgb(54,54,54); }QLineEdit{border: 1px solid #ABCDA0; /…

8 增强型脉宽调制模块ePWM

文章目录 8.1 PWM控制基本原理8.2 PWM结构及组成单位8.3 时基模块TB8.3.1 ePWM时基模块作用8.3.2 时基模块的关键信号和寄存器 8.5 动作模块 AC8.5.1 动作模块的作用8.5.2 动作模块关键信号与寄存器 8.11 PWM模块输出8.11.1 单边非对称波形8.11.2 单边非对称脉冲波形 8.1 PWM控…

Less 安装教程

文章目录 前言LESS的系统要求安装LESS例子输出Less编译css工具后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;Sass和Less &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板…

kafka的设计原理

文章目录 1 Kafka简介2 Kafka的架构2.1 Kafka 一些重要概念2.2 工作流程2.3 副本原理2.4 分区和主题的关系2.5 生产者2.5.1 分区可以水平扩展2.5.2 分区策略 2.6 消费者2.6.1 消费方式2.6.2 分区分配策略 2.7 数据可靠性保证2.7.1 副本数据同步策略2.7.2 ACK 应答机制2.7.3 可靠…

C++ libcxxabi中dynamic_cast 实现

摘要&#xff1a;最近在看一个崩溃的过程中详细看了一遍cxxabi的定义&#xff0c;就想着看一些llvm中cxxabi的一些实现。本文描述了cxxabi中dynamic_cast的实现以及原理。   关键字&#xff1a;cxxabi,dynamic_cast 1 简介 C中&#xff0c;dynamic_cast用于有虚函数的继承链…

监控同一局域网内其它主机上网访问信息

1.先取得网关IP 2.安装IPTABLES路由表 sudo apt-get install iptables 3.启用IP转发 sudo sysctl -p 查看配置是否生效 4.配置路由 iptables -t nat -A POSTROUTING -j MASQUERADE 配置成功后,使用sudo iptables-save查看

Android获取原始图片Bitmap的宽高大小尺寸,Kotlin

Android获取原始图片Bitmap的宽高大小尺寸&#xff0c;Kotlin val options BitmapFactory.Options()options.inJustDecodeBounds trueval decodeBmp BitmapFactory.decodeResource(resources, R.mipmap.p1, options)//此时&#xff0c;decode出来的decodeBmp宽高并不是原始图…

Linux 中的 ls 命令使用教程

目录 前言 如何运用 ls 命令 1、列出带有所有权的文件和目录 2、获取以人类可读的方式显示的信息 3、列出隐藏文件 4、递归列出文件 5、在使用 ls 时对文件和目录做区分 6、列出指定扩展名的文件 7、基于大小对输出内容排序 8、根据日期和时间排序文件 让我们来总结…

【PyQt】(自定义类)阴影遮罩-升级版

这是之前发的代码(自定义类)阴影遮罩的升级版。 升级就升级在&#xff0c;优化了对非矩形控件的遮盖效果&#xff0c;例如圆角按钮&#xff0c;以及默认方法不满足时可以传入其他的遮盖方法。 自定义阴影遮罩Mask&#xff1a; class Mask(QWidget):__excludeNone__colorNonecl…

【中间件】消息队列中间件intro

中间件middleware 内容管理 introwhy use MQMQ实现漫谈主流消息队列QMQ IntroQMQ架构QMQ 存储模型 本文还是从理论层面分析消息队列中间件 cfeng现在处于理论分析阶段&#xff0c;以中间件例子&#xff0c;之前的blog对于中间件是从使用角度分享了相关的用法&#xff0c;现在就…

带你用uniapp从零开发一个仿小米商场_9. 轮播图组件封装及使用

导航栏有了,接下来就是轮播图了,轮播图如下, 因为uniapp 官方自己有轮播图,所以这里就不自己写了,直接使用uniapp的轮播图二次开发就好 uniapp的轮播图组件叫swiper ,感兴趣的朋友可以点击链接,直接去看官方文档,也可以看我这里实操 用hbuilderX编译uniapp的代码有一个好处…

FO-like Transformation

参考文献&#xff1a; [RS91] Rackoff C, Simon D R. Non-interactive zero-knowledge proof of knowledge and chosen ciphertext attack[C]//Annual international cryptology conference. Berlin, Heidelberg: Springer Berlin Heidelberg, 1991: 433-444.[BR93] Bellare M…

枚举的第一行

2023年11月26日 问题: 好奇enum的所声明的枚举类的第一行是什么 从java技术卷1中第五章5.6中,了解是枚举类的实例 验证 错误信息: 解释: 此时只有有参构造 在这个枚举类里不能使用空,大概意思是说不能使用空参创建实例 校验 在原有的基础上创建一个无参构造 结果:不再报错,第…

常见树种(贵州省):019滇白珠、杜茎山、苍山越桔、黄背越桔、贵州毛柃、半齿柃、钝叶柃、细枝柃、细齿叶柃木、土蜜树、山矾、胡颓子、檵木

摘要&#xff1a;本专栏树种介绍图片来源于PPBC中国植物图像库&#xff08;下附网址&#xff09;&#xff0c;本文整理仅做交流学习使用&#xff0c;同时便于查找&#xff0c;如有侵权请联系删除。 图片网址&#xff1a;PPBC中国植物图像库——最大的植物分类图片库 一、滇白珠…

电路 buck-boost相关知识

BUCK-BOOST 文章目录 BUCK-BOOST前言一、DC-DC工作模式电容电感特性伏秒积平衡原理 二、BUCK电路三、BOOST电路四、BUCK-BOOST电路总结 前言 最近需要用到buck-boost相关的电路知识&#xff0c;于是便写下这篇文章复习一下。 一、DC-DC 在学习buck-boost电路之前我们先来看一…

steam/csgo搬砖项目真能月入过万吗?到底真的假的

steam/csgo搬砖第三课之如何出售 steam搬砖核心原理是什么&#xff1f;为什么会有差价产生&#xff1f;buff不是更低价吗&#xff1f;很多小白会有这些疑问&#xff01; steam搬砖指的是通过买卖csgo游戏装备赚钱的。 玩过游戏的应该就很清楚&#xff0c;像绝地求生&#xff…