首页 > 系统相关 >C语言进阶【3】---C语言内存函数

C语言进阶【3】---C语言内存函数

时间:2024-09-12 14:52:56浏览次数:12  
标签:进阶 int C语言 --- arr3 sizeof include memcpy 函数

本章概述

本章函数概述

我们在本章的博客中讲的内容是有关内存的操作,我们 直接通过内存块对数据进行操作。 因为我们是直接对内存块操作,所以可以对任意类型数据进行操作(我们没必要管它是什么类型的数据,我们只对这个内存块操作)。接下来所讲的这些内存函数的头文件为:<string.h>这些内存函数是对每个字节进行操作

memcpy使用和模拟

  • memcpy的功能:和strcpy函数的功能类似strcpy函数是对元素进行拷贝,而memcpy函数是对内存块进行拷贝所以内存块里面的数据类型没意义。比如,前面咱们讲过了strcpy和strncpy函数,它们只能对字符串进行拷贝。但是,当我们想进行两个整形数据的拷贝时候,就不能用strcpy和strncpy函数了,就只能用memcpy函数了。memcpy函数能拷贝的数据类型比strcpy和strncpy函数拷贝的数据库类型要广泛些
  • memcpy函数的结构:
//	void * memcpy ( void * destination, const void * source, size_t num );
//	因为我们进行内存块的拷贝,所以里面是什么类型的数据咱们是不知道的,所以当你传给我地址的时候我只能用void*指针来接收。
//	因为咱们是进行内存块的拷贝,所以要知道具体拷贝多少个字节的空间,size_t num 就是要拷贝的字节数。
//	返回的是传给des的首元素地址,因为是什么类型咱不知道,所以返回void*指针数据类型。
//	des和source的地址是可以被我们指定的。

由于size_t num是表示要拷贝的字节数,咱们是第一次见到它的这种意义,所以我给大家放个它的截图,给大家看一下。如图:在这里插入图片描述

  • memcpy函数的使用:----->对字符串的拷贝
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcdefghu"; 	
	char arr2[30] = {0};
	void* p = memcpy(arr2, arr1, 4 * sizeof(char));
	printf("%s\n", (char*)p);
	return 0;
}

结果运行图:在这里插入图片描述
------->对整形数据进行拷贝

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr3[] = { 1,2,3,4,5,6 };
	int arr4[10] = { 0 };
	int sz = sizeof(arr4) / sizeof(arr4[0]);
	  memcpy(arr4, arr3, 4 * sizeof(int));
	  printf("arr4: ");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr4[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述

  • memcpy函数的模拟:因为这个函数对内存进行操作,所以它能够拷贝多种数据类型模拟的核心思想我们要对单个内存进行操作,也就是把各种指针类型全部转换为char *(因为char *能够访问单个字节),进行代码展示:
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
#include <assert.h>

void* my_memcpy(void* des, const void* str, size_t num)
{
	void* p = des;
	assert(des && str);
	while (num--)
	{
		*(char*)des = *(char*)str;
		des = (char*)des + 1;
		str = (char*)str + 1;

	}
	return p;
}
int main()
{
	int arr3[] = { 1,2,3,4,5,6 };
	int arr4[10] = { 0 };
	int sz = sizeof(arr4) / sizeof(arr4[0]);
	my_memcpy(arr4, arr3, 4 * sizeof(int));
	printf("arr4: ");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr4[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述

  • 拓展使用:------->当我们用memcpy函数进行自己给自己拷贝数据(重叠数据拷贝)
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
#include <assert.h>
int main()
{
	int arr3[] = { 1,2,3,4,5,6,7,8,9 };
	int sz = sizeof(arr3) / sizeof(arr3[0]);
	  memcpy(arr3+2, arr3, 4 * sizeof(int));
	  printf("arr4: ");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr3[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述
--------->当我们用my_memcpy函数进行自己给自己拷贝数据(重叠数据拷贝)

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
#include <assert.h>

void* my_memcpy(void* des, const void* str, size_t num)
{
	void* p = des;
	assert(des && str);
	while (num--)
	{
		*(char*)des = *(char*)str;
		des = (char*)des + 1;
		str = (char*)str + 1;

	}
	return p;
}
int main()
{
	int arr3[] = { 1,2,3,4,5,6,7,8,9 };
	int sz = sizeof(arr3) / sizeof(arr3[0]);
	  my_memcpy(arr3+2, arr3, 4 * sizeof(int));
	  printf("arr4: ");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr3[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述
当自己给自己进行重复数据拷贝的时,memcpy函数能达到我们的预想值。但是,我们自己模拟的my_memcpy函数就无法达到预想值,难道是我们的模拟函数有问题?答案是否。我们来举个生活中的例子,100分的试卷。考到60分就欧克了,但是你却偏偏考到80多分,说明有能考到60分的能力,但是你还能超越自己。memcpy函数就是这个道理 ,它有拷贝数据的能力(不重叠数据),但是,它还能超越自己(拷贝重叠数据)。而我们自己模拟的my_memcpy函数完成了它的基本功能。memcpy函数不太常用于拷贝重叠数据我们常用memmove函数拷贝重叠数据。

memmove使用和模拟

  • memmove函数的功能它的功能比memcpy函数要广泛些,它既能拷贝不重叠的数据,有能拷贝重叠的数据
  • memmove函数的结构:
//	void * memmove ( void * destination, const void * source, size_t num );

memmove函数的结构与memcpy函数的结构相同,但是它的功能比memcpy函数要广泛些。

  • memmove函数的使用:进行代码展示---------->数据不重叠
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr3[] = { 1,2,3,4,5,6,7,8,9 };
	int arr4[10] = { 0 };
	int sz = sizeof(arr3) / sizeof(arr3[0]);
	memmove(arr4, arr3, 4 * sizeof(int));
	printf("arr4: ");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr4[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述
进行代码展示---------->数据重叠

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr3[] = { 1,2,3,4,5,6,7,8,9 };
	int sz = sizeof(arr3) / sizeof(arr3[0]);
	memmove(arr3+2, arr3, 4 * sizeof(int));
	printf("arr4: ");
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr3[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述

memset函数的使用

  • memset函数的功能具有设置数据的功能能把整型数组里面的元素全部设为0,也能改变字符串中的某些字符元素。
  • memset函数的结构:
//	 void * memset ( void * ptr, int value, size_t num );
// 因为被改变的数据类型我们不知道(既能改变整型,也能改变字符型……),所以用void*指针接收
//	int value为我们想要改变的数据。
// size_t num为我们要改变的内存字节数目。
//	我们还可以指定改变的起始位置。
  • memset函数的使用:进行代码展示--------->改变整型数组
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++) //	我们以前改变整形数组里面元素的方法
	{
		arr[i] = 0;
		printf("%d ", arr[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	memset(arr, 0, sz * sizeof(int)); //	使用memset函数直接全部置0
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述
进行代码展示--------->改变整形数组的起始位置

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	memset(arr+2, 0, 5 * sizeof(int)); //	改变起始位置,从3开始后面置0,
									//要注意要改变的元素个数不能超过数组的范围,否则报错
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述
进行代码展示--------->改变字符串

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	char arr[] = "hello world";
	memset(arr, 'x', 6 * sizeof(char));
	printf("%s\n", arr);
	return 0;
}

结果运行图:在这里插入图片描述
我们还可以改变字符串要改变的起始位置,大家可以自行尝试一下。

  • memset函数使用注意事项对于改变整形数组时,我们使用memset函数主要是置0,不能置其它的数字,否则得不到想要的结果。也就是说,memset函数对于改变整形数组里面的元素,只能置0。进行代码展示:
//	假如,我们给整形数组全部置1
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	memset(arr, 1, sz * sizeof(int)); 
	for (i = 0; i < sz; i++)
	{
		printf("%d \n", arr[i]);
	}
	return 0;
}

结果运行图:在这里插入图片描述
是不是与我们的预期大相径庭,按理来讲应该全是1,结果全是很大的整数,这是为什么呢? 前面,咱们讲过了这些函数都是对单个字节操作的,由于int 是四个字节,所以每个字节都会改为1。到最后对Int进行解读的时候还是按照4个字节,就会导致解读的数据与期望值不同。结果调试图:如图在这里插入图片描述
从调试图中可以看出来,每个字节都被改为1。所以,我们一般用memset函数置0.

memcmp函数的使用

  • memcmp函数的功能:它和strcmp函数的功能类似,都是用来比较大小的strcmp函数是用来比较字符元素的大小的,而且只能比较字符元素的大小。而memcmp函数是进行内存单个字节比较,它会每个每个字节进行比较,它不管里面存的什么数据。
  • memcmp函数的结构:
//	 int memcmp ( const void * ptr1, const void * ptr2, size_t num );
//	它和strcmp函数一样,参数放的位置决定比较的前后。
//	ptr1大于ptr2返回大于0的值,ptr1等于ptr2返回0的,ptr1小于ptr2返回小于0的值。
//	size_t num 为要比较的字节数。
  • memcmp函数的使用:进行代码展示--------->整形比较
#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[] = { 1,2,3,5,6 };
	int arr2[] = { 1,2,3,4 };
	printf("%d\n", memcmp(arr1, arr2, 3 * sizeof(int)));
	printf("%d\n", memcmp(arr1, arr2, 13));
	return 0;
}

结果调试图:在这里插入图片描述
这是arr1的内存数据存储的形式,arr2也是一样的。前面,咱们已经讲过了,memcmp函数是每个每个字节进行比较,比如,printf("%d\n", memcmp(arr1, arr2, 13));这行代码,我们比较了13个字节的空间,arr1和arr2前面12个字节都一样,第13个字节的内容不一样——05大于04
如图所示的逻辑图:在这里插入图片描述
在这里插入图片描述
由于arr1第13个字节的内容大于arr2的内容,所以结果就会输出大于0的值,结果运行图:在这里插入图片描述
-------->字符型比较

#define  _CRT_SECURE_NO_WARNINGS	1
#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[] = "abcde";
	char arr2[] = "abcf";
	printf("%d\n", memcmp(arr1, arr2, 4 * sizeof(char)));
	return 0;
}

姐果运行图:在这里插入图片描述

彩蛋时刻!!!

https://www.bilibili.com/video/BV1pT421r7kJ/?spm_id_from=333.1007.tianma.6-3-21.click&vd_source=7d0d6d43e38f977d947fffdf92c1dfad在这里插入图片描述
每章一句永远相信美好的事情即将发生。感谢你能看到这里,点赞+关注+收藏+转发是对我最大的鼓励,咱们下期见!!!

标签:进阶,int,C语言,---,arr3,sizeof,include,memcpy,函数
From: https://blog.csdn.net/2401_83009236/article/details/142101386

相关文章

  • vue3 h5自定义tabbar并用keep-alive保存缓存路由
            路由嵌套封装tabbar组件创建一个容器放tabbar和子路由keep-alive保存路由状态1.路由嵌套{ path:'/', name:'index', component:()=>import('@/views/index.vue'), children:[ { path:'', redirect:'/com', m......
  • LabVIEW-状态机的简述与应用
    目录前言一,状态机的基本概念二,在LabVIEW中实现状态机1.使用Case结构2.使用事件结构三,注意事项四,代码实现五,动态效果前言在LabVIEW中,状态机是一种常用的设计模式,用于管理和控制程序在不同状态之间的转换。状态机非常适合处理那些具有多个执行路径和条件分支的程序,......
  • MUR3040CT-ASEMI快恢复二极管MUR3040CT
    编辑:llMUR3040CT-ASEMI快恢复二极管MUR3040CT型号:MUR3040CT品牌:ASEMI封装:TO-220AB安装方式:插件批号:最新恢复时间:35ns最大平均正向电流(IF):30A最大循环峰值反向电压(VRRM):400V最大正向电压(VF):0.95V~1.90V工作温度:-50°C~150°C芯片个数:2芯片尺寸:mil正向浪涌电流(IFMS):300AM......
  • 单选和多选在table里的报错问题Blocked aria-hidden on a <input> element because the
    单选在main.js里//table单选报错问题Vue.directive('removeAriaHidden',{bind(el,binding){constariaEls=el.querySelectorAll('.el-radio__original')ariaEls.forEach((item)=>{item.removeAttribute('aria-hidden')......
  • 【C语言基础】数据类型、运算符和表达式
    1数据类型基本类型整型:短整型,基本整型,长整型字符型实型(浮点型):单精度型,双精度型枚举类型构造类型:是使用基本类型的数据或者使用已经构造好的数据类型,进行添加、设计构造出新的数据类型,使其设计的新构造类型满足待解决问题所需要的数据类型。数组类型结构体类型共用体类......
  • 2021 CSP-J 完善程序3
    2021CSP-J完善程序31完善程序(单选题,每小题3分,共30分)(矩形计数)平面上有n个关键点,求有多少个四条边都和x轴或者y轴平行的矩形,满足四个顶点都是关键点。给出的关键点可能有重复,但完全重合的矩形只计一次。试补全枚举算法#include<stdio.h>structpoint{ intx,y,id;}......
  • 【题解】Solution Set - NOIP2024集训Day27 树形 dp
    【题解】SolutionSet-NOIP2024集训Day27树形dphttps://www.becoder.com.cn/contest/5521「HDU4661」MessagePassing「BZOJ3935」Rbtree「ARC101E」RibbonsonTree「AGC034E」CompleteCompress「COCI2014.10」Kamp「SCOI2015」小凸玩密室「AGC008F」Black......
  • Ros2 - Moveit2 - Grasps(抓握)
    MoveItGrasps是一款用于抓取块或圆柱体等物体的抓取生成器,可用作MoveIt拾取和放置管道的替代品。MoveItGrasps提供基于可达性和接近、抬起和后退运动的笛卡尔规划来过滤抓取的功能。抓握生成算法基于简单的长方体形状,不考虑摩擦锥或其他抓握动力。MoveItGrasps可与平行......
  • 多模态大语言模型综述(中)-算法实用指南
    IV.算法实用指南多模态的算法可分为两类:基础模型和大规模多模态预训练模型。基础模态是多模态的基本框架,许多新的大规模多模态预训练模型都是基于它进行改进的。下图是论文涉及的算法清单,含模型名字、年份、技术要点、功能及参考编号,以及代码开源情况。如果您也对A......
  • v-if与v-show区别
    在Vue.js中,v-if和v-show都用于条件渲染,但它们在实现方式和性能上有显著区别。以下是它们的主要区别:1.实现方式v-if:v-if是一个指令,用于有条件地渲染元素。当条件为false时,相关的DOM元素不会被渲染到页面中。当条件改变为true时,Vue会重新创建该元素及其子元......