C:内存函数

news2024/12/23 3:27:11

目录

前言:

一、memcpy 函数的使用及实现

1、memcpy函数的介绍

 1.1 memcpy函数参数解读

 2、memcpy函数的使用

3、memcpy函数的模拟实现

二、memmove函数的使用及模拟

1、memmove函数的使用

2、memmove函数的模拟实现

三、memset 函数的使用

1、memset函数的介绍(cplusplus)

2、memset函数的使用

2.1 memset函数对数组的应用

2.2 memset函数对字符串的应用

​编辑

 四、memcmp函数的使用

1、memcmp函数的介绍

2、memcmp函数的使用


前言:

上篇文章介绍了C语言字符串函数,我们学会了一些对字符串的操作,比如说将字符串从一个字符数组拷贝到另一个字符数组中,我们可以通过使用strcpy函数实现。但是,如果我们想要拷贝一个整型数组到另一个整型数组中时,strcpy函数就失效了,那我们应该怎么才能实现这个操作呢?不要着急,本篇文章将带大家搞定这个问题。

一、memcpy函数的使用及实现

1、memcpy函数的介绍

cplusplus上的介绍:

作用介绍:

参数介绍:

返回值介绍:

 1.1 memcpy函数参数解读

(1)void* destination

该参数的作用是目标空间,用来存放将要拷贝的内存,为什么返回值是 void* 呢?这是因为这个函数的作用是内存拷贝,既然是内存拷贝,内存中又可能存放的是整型数组,也有可能存放的是字符数组……,因此我们不关心存放数据的类型,因此使用void*指针来接收任意类型的数据的地址。

(2)const void* source

source是源头,也就是要拷贝的内存数据,这里也是void*指针是因为我们不知道我们未来要拷贝的数据是什么类型的,可能是整型,可能是字符,也可能是结构体,因此我们也使用void*。

用const修饰是因为我们不希望要拷贝的数据被修改,因此使用const修饰会使得整个工程更加稳定。

(3)size_t num

num的作用是限定拷贝的字节数,比如说source中有十个字节的数据,我们可以通过修改num的值来拷贝我们想要的个数,num为5,我们就拷贝五个字节的数据到destination中;num的类型是size_t的原因是我们拷贝的个数最低都是0个,不会出现负数的情况,因此使用size_t类型最为合适。

 2、memcpy函数的使用

前面学习了memcpy函数,接下来我们将使用memcpy函数来实现一些操作

比如说我们打算将整型数组arr1[ ] = {1,2,3,4,5,6,7,8,9,10}拷贝到整型数组 arr2[10] = { 0 };

#include <stdio.h>
int main()
{
    int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    int arr2[10] = { 0 };
    memcpy(arr2, arr1, 5 * sizeof(int));
    return 0;
}

调试结果:

源头从 3 开始拷贝,比如说:

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

 一些总结:

  • 函数memcpy从source的位置开始向后赋值num个字节的数据到destination指向的内容;
  • 这个函数在遇到\0的时候并不会停下来,与字符串函数不同;
  • 如果source和destination有任何的重叠,赋值的结果都是未定义的。

3、memcpy函数的模拟实现

接下来我们尝试自己写一个函数来实现memcpy的功能

void* my_memcpy(void* dest, const void* src, size_t num)
{
	
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1, 5 * sizeof(int));
	return 0;
}

注意:在my_memcpy中,源头是void*指针类型的  

现在有一个问题,我们不知道我们要拷贝的是内容是什么类型的,我们只知道要拷贝的是20个字节,我们该怎么将这20个字节拿到arr2中呢?

在前面学习qsort函数的模拟实现中,我们用到了一个方法,我们可以一个字节一个字节的拷贝,那么就可以使用强制类型转换将void*指针转换为char*指针

void* my_memcpy(void* dest, const void* src, size_t num)
{
	while (num--)//num是字节总数,因此num每减1,就拷贝一个字节
	{
		*(char*)dest = *(char*)src;
         dest = (char*)dest + 1;
         src = (char*)src + 1;
	}
}

调试结果: 

总代码:

#include <stdio.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
    // 保存目标地址,以便最后返回
    void* ret = dest;
    // 循环 num 次进行逐个字节的复制
    while (num--)
    {
        // 将源地址指向的内容复制到目标地址指向的位置,并转换为 char* 类型进行操作,确保每次只复制一个字节
        *(char*)dest = *(char*)src;
        // 目标地址向后移动一个字节
        dest = (char*)dest + 1;
        // 源地址向后移动一个字节
        src = (char*)src + 1;
    }
    // 返回复制后的目标地址
    return ret;
}
int main()
{
    int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    int arr2[10] = { 0 };
    my_memcpy(arr2, arr1, 5 * sizeof(int));
    return 0;
}

如果我们向将int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };中(1,2,3,4,5)拷贝放到(3,4,5,6,7)的位置上,这样可以实现吗?

	my_memcpy(arr1+2, arr1, 5 * sizeof(int));

调试结果:

为什么这里会是(1,2,1,2,1)呢?其实也很好理解

 因此最终结果是(1,2,1,2,1,2,1,8,9,10) 

关于重叠问题,我们一般使用后面的这个函数memmove函数

而memcpy函数一般用来处理不重叠情况。

在vs2022中,memcpy的能力是比较强的,也是可以用来处理重叠问题,但是对于memcpy函数,本来的作用是不包括处理重叠的问题的,这就像是老师说让你考到60分就行,但是你能考100分。但是不能保证在所有的编译器上memcpy都可以考到100分

也就是说无法确定其它编程环境是否可以实现,因此,如果要处理重叠问题,最好还是交给memmove函数.

二、memmove函数的使用及模拟

1、memmove函数的使用

memove函数的使用与memcpy函数是一样的,也是用来实现内存中数据的拷贝的,因此就不详细介绍了。不过前面也说了memmove函数可以实现重叠拷贝,来测试一下

#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1+2, arr1, 5 * sizeof(int));
	return 0;
}

调试结果:
 可以看到的确将(1,2,3,4,5)的内容拷贝到(3,4,5,6,7)的位置上了

那么memmove函数究竟是怎么实现这个操作的呢?我们来模拟了解一下

2、memmove函数的模拟实现

前面我们知道,如果拷贝1,会把3给覆盖,拷贝2,会把4给覆盖。

该怎么拷贝才能实现不被覆盖呢?

可以从后向前拷贝,先拷贝5,覆盖7,在拷贝4覆盖6,这时候在拷贝3覆盖5,拷贝2覆盖4,拷贝1覆盖3,由于3,4,5已经拷贝完成,不会出现还没有拷贝就被覆盖的情况。

那是不是从后向前拷贝就一定正确呢?

我们在换一种情况试试:

这时候如果还是从后向前拷贝的话会出现什么问题呢?

8拷贝到6,7拷贝到5,这时候向拷贝6的时候已经变成了8,因此从后向前失效了。

这时候我们在从前向后拷贝,3拷贝到1,4拷贝到2……恰好可以全部拷贝。

不知道大家有没有发现一个规律:

如果dest在src的后面,则从后向前拷贝;

如果dest在src的前面,则从前向后拷贝;

如果没有重叠,则随意。

如果是 后->前,该怎么拷贝呢?

比如说先拷贝5,我们只需要在起始位置跳过num个字节即可

比如说:*((char*)src + num)

代码实现:

#include <stdio.h>
#include <string.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
    void* ret = dest;
	if (dest < src)
	{
		//前->后
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		while (num--)
		{
			//后->前
			//num进来减1,变为19,src加上19后跳到最后一位上,也就是5,dest加上19跳到8的位置,然后将5赋值到8的位置
			*((char*)dest + num) = *((char*)src + num);
		}
	}
    return ret;
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr+2, arr, 5 * sizeof(int));
	return 0;
}

三、memset函数的使用

1、memset函数的介绍(cplusplus)

参数介绍:
注意:

memset是以字节为单位来设置内存的 ,而不是以一个元素为单位设置的。

 作用介绍:

返回值介绍:

2、memset函数的使用

2.1 memset函数对数组的应用

那么memset函数究竟有什么作用呢?

比如说:

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i] = i + 1;
	}
	return 0;
}

我们想将arr数组全部初始化为0,我们该怎么做呢?

你可能会说这不简单?直接使用循环不就可以了吗?

for (i = 0; i < 10; i++)
{
	arr[i] = 0;
}

这样的确可以,不过我们也可以使用库函数memset函数来实现这个操作。

我们要设置的这个空间整型数组arr[10]的地址交给ptr,而数组的地址就是数组名arr,我们需要将该数组的元素都变为0,也就是要设置的值value为0,由于是整型数组,有十个元素,所以num就等于40字节。

代码展示:

#include <stdio.h>
#include <string.h>
int main()
{
	int arr[10] = { 0 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i] = i + 1;
	}
	/*for (i = 0; i < 10; i++)
	{
		arr[i] = 0;
	}*/
	memset(arr, 0, 10 * sizeof(int));
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

调试过程:

结果展示:

 如果memset(arr, 1, 10 * sizeof(int));这是否是将每一个元素都改为1了呢?

调试监控窗口

为什么没有达到想要的结果呢?

我们在来看一下内存窗口:

破案了,memset函数将每一个字节都设置为1,而不是把一个元素设置为1。

前面强调了memset是以字节为单位来设置内存的 ,而不是以一个元素为单位设置的。

2.2 memset函数对字符串的应用

代码:

#include <stdio.h>
#include <string.h>
int main()
{
	char arr[] = "hello world";
	//如何将helo改为五个x
	memset(arr, 'x', 5);
	return 0;
}

调试结果:

如果我们想修改world呢?

memset(arr+6, 'x', 5);

从前向后数hello五个字符,还有一个空格,共6个字符。

注意:这个函数比较常见,因此需要熟练掌握!!! 

 四、memcmp函数的使用

memcmp函数与之前学习的strcmp函数的功能是比较相似的,不过strcmp函数只能用来做字符串的比较,而memcmp函数是用来做内存块的比较,不论是什么类型。

1、memcmp函数的介绍

参数介绍:
 

返回值介绍:

2、memcmp函数的使用

直接上例题,比较arr1与arr2中前3个元素

#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,3 };
	int ret = memcmp(arr1, arr2, 12);
	printf("%d\n", ret);
	return 0;
}

结果:

如果我们比较前4个元素呢?

int ret = memcmp(arr1, arr2, 16);、

这里返回的就是1了。


结语:本篇文章到这里就结束啦!期待下次的相遇!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mybatis 配置文件完成增删改查(五) :单条件 动态sql查询,相当于switch

文章目录 单条件 动态sql查询写测试方法 疑问总结 单条件 动态sql查询 <select id"selectByConditionBySingle" resultMap"brandResultMap">.select *from tb_brandwhere<choose>/*相当于switch*/<when test"status ! null">…

基于Vision-Board的智能应急环境监测控制小车

目录 1 项目概述 1.1 项目背景 1.2 系统功能介绍 1.2.1 下位机智能小车控制系统 1.2.2 微信小程序App 1.2.3 PC上位机App 1.3 框图介绍 1.3.1 主控板卡 1.3.2 小车控制模块 1.3.3 通信模块 1.4 系统使用的技术要点 2 系统硬件设计 2.1 Version board主控板块系统结…

matlab恢复默认窗口布局

1.点击主页&#xff0c;选择布局 2.选择默认&#xff0c;即可恢复到默认的窗口布局

ollama 部署教程(window、linux)

目录 一、官网 二、安装方式一&#xff1a;window10版本下载 三、安装方式二&#xff1a;linux版本docker 四、 模型库 五、运行模型 六、API服务 七、python调用 ollama库调用 langchain调用 requests调用 aiohttp调用 八、模型添加方式 1.线上pull 2.导入 GGU…

HCIA--实验十九:配置接口DCHP

一、实验内容 1.需求/要求&#xff1a; 通过一台5700交换机和一台PC&#xff0c;通过在交换机的接口上配置接口DHCP来实现PC自动获取ip地址。 二、实验过程 1.拓扑图&#xff1a; 2.步骤&#xff1a; 1.给vlan10配置ip地址&#xff0c;进入vlan10开启接口的DHCP&#xff1…

药用植物的空间多组学:从生物合成途径到工业应用-文献精读51

Spatial multi-omics in medicinal plants: from biosynthesis pathways to industrial applications 药用植物的空间多组学&#xff1a;从生物合成途径到工业应用 摘要 随着分子测序和成像技术的快速发展&#xff0c;药用植物的多组学研究进入了单细胞时代。我们讨论了空间多…

EMT-LTR--学习任务间关系的多目标多任务优化

EMT-LTR–学习任务间关系的多目标多任务优化 title&#xff1a; Learning Task Relationships in Evolutionary Multitasking for Multiobjective Continuous Optimization author&#xff1a; Zefeng Chen, Yuren Zhou, Xiaoyu He, and Jun Zhang. journal&#xff1a; IEE…

2024最新windows 11系统 PHP或者idea编译器-配置Git环境和使用教程

文章目录 目录 文章目录 安装流程 小结 概要安装流程技术细节小结 概要 确保电脑上已安装到git,如下图所示&#xff1a;-是已安装好&#xff1a; 安装git教程&#xff1a; Git安装使用教程_git安装教程-CSDN博客 安装流程 点击左上角如图所示&#xff1a; 需要验证git本地 …

认识URL

目录 url定义 定义 实例 url组成 组成 大家看到这时是否会有疑问&#xff1a;我们常用的端口号8080和http默认端口号有什么关系&#xff1f; url定义 定义 url就是统一资源定位符&#xff0c;简称网址。目的是使用url用于访问网络上的资源 实例 url组成 组成 实例&a…

Python 连接mysql数据库,并且执行查询

之前一直在写Java&#xff0c;但是随着python的崛起&#xff0c;自己也被慢慢的带入到了这样的一个阵营&#xff0c;学习python&#xff0c;了解机器学习 曾经有一个.... 不谈曾经&#xff0c;现在的我是一个小菜鸟&#xff0c;用学习Java实现业务的需求来学习python 项目的目…

Python文件读取

文件操作的步骤 打开文件读写文件关闭文件 open()打开函数 使用open()可以打开一个已经存在的文件&#xff0c;或者创建一个新文件 open(name,mode,encoding)name:打开文件的文件名&#xff0c;也可以包含具体路径 mode:设置打开文件的模式&#xff1a;只读、写入、追加等…

【高并发内存池】基本框架 + 固定长度内存池实现 1

高并发内存池 1. 基本框架2. 定长内存池的实现2.1 介绍定长内存池2.2 T* New()2.3 void Delete(T* obj) 3. 源码&#xff08;附赠测试&#xff09;4. 总结 1. 基本框架 高并发内存池主要由三个部分构成&#xff1a; 1.thread cache:用于小于256KB的内存的分配。线程缓存是每个…

解决element plus报错ResizeObserver loop completed with undelivered notifications.

1、问题描述 在使用动态数据切换渲染el-table表格过程中&#xff0c;报错如下&#xff1a; ResizeObserver loop completed with undelivered notifications. 2、解决方案 在网上找了很多办法&#xff0c;包括&#xff1a; 为每一列指定宽度&#xff0c;试了&#xff0c;问题…

【AcWing】基础算法

目录 1、快速排序 1.1 快速排序 1.2 第k个数 2、归并排序 2.1 归并排序 2.2 逆序对的数量 3、二分 3.1 数的范围 3.2 数的三次方根 4、高精度 4.1 高精度加法 4.2 高精度减法 4.3 高精度乘法 4.4 高精度除法 5、前缀和与差分 5.1 前缀和 5.2 子矩阵的和 5.3 …

0.设计模式总览——设计模式入门系列

在现代软件开发中&#xff0c;设计模式为我们提供了优秀的解决方案&#xff0c;帮助我们更好地组织代码和架构。本系列专栏将对设计模式的基本思想、原则&#xff0c;以及常用的分类、实现方式&#xff0c;案例对比、以及使用建议&#xff0c;旨在提高开发者对设计模式的理解和…

数据库的学习

第一章 绪论 基本概念 数据---描述事物的符号 数据库DB---长期存在在计算机内、有组织的、可共享的 大量数据的集合 数据库管理系统DBMS---位于用户和操作系统之间的一层数据管理软件 数据库系统DBS---由数据库、数据库管理系统&#xff08;及其应用开发工具&#xff09;、…

VBA技术资料MF201:添加简单的右键菜单

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

Linux bash特性:

命令别名&#xff1a; 命令行定义命令别名&#xff1a; alias cdt‘cd’ alias 别名‘完整命令’ unlias----删除别名 但是断开连接后&#xff0c;再次链接&#xff0c;命令别名会失效&#xff0c;不同窗口别名也不生效 配置文件内更改命令别名&#xff1a; 在对应用户的…

导入时,Excel模板不被下载

问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 这是个SSM项目&#xff0c;以前经常遇到这个问题&#xff0c;今天有幸记录下来 [ERROR][o.a.s.r.StreamResult] Can not find a java.io.InputStream with the name [downLoadFile] in the invocation stack…

【计算机网络篇】计算机网络概述

本文主要介绍计算机网络第一章节的内容&#xff0c;文中的内容是我认为的重点内容&#xff0c;并非所有。参考的教材是谢希仁老师编著的《计算机网络》第8版。跟学视频课为河南科技大学郑瑞娟老师所讲计网。 文章目录 &#x1f3af;一.计算机网络的组成 ✨主要内容 1.边缘部…