当前位置: 首页 > news >正文

C:内存函数

目录

前言:

一、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改为五个xmemset(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了。


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

相关文章:

C:内存函数

目录 前言&#xff1a; 一、memcpy 函数的使用及实现 1、memcpy函数的介绍 1.1 memcpy函数参数解读 2、memcpy函数的使用 3、memcpy函数的模拟实现 二、memmove函数的使用及模拟 1、memmove函数的使用 2、memmove函数的模拟实现 三、memset 函数的使用 1、memset函数的…...

【Web】御网杯信息安全大赛2024 wp(全)

目录 input_data admin flask 如此多的FLAG 一夜醒来之全国CTF水平提升1000倍&#x1f60b; input_data 访问./.svn后随便翻一翻拿到flag admin dirsearch扫出来 访问./error看出来是java框架 测出来是/admin;/路由打Spring View Manipulation(Java)的SSTI https:/…...

VC++同时处理ANSI和Unicode字符集,除了使用TCHAR和_T()宏外,还有其他方法可以实现吗?

在我的C项目中&#xff0c;如果我需要同时处理ANSI和Unicode字符集&#xff0c;除了使用TCHAR和_T()宏外&#xff0c;还有其他方法可以实现吗&#xff1f; 除了使用 TCHAR 和 _T() 宏之外&#xff0c;还有其他方法可以实现同时处理 ANSI 和 Unicode 字符集&#xff1a; 1. 使用…...

MATLAB定位程序与讲解【专栏介绍】

AOA&#xff08;到达角度&#xff09;定位原理&#xff1a; 描述了基于到达角度进行定位的方法&#xff0c;适用于一维、二维或三维空间。 由动静压之比求马赫数的MATLAB函数&#xff1a; 提供了一个计算马赫数的函数&#xff0c;用于流体力学中速度的计算。 三边法定位与三点法…...

机器学习3--numpy

Numpy 一、numpy是什么&#xff1f;二、N维数组三、数组基本操作四、数组的运算 一、numpy是什么&#xff1f; numpy是一个开源的python科学计算库&#xff0c;用于处理任意维度的数组。numpy用ndarray处理多维数组。 import numpy as np np.array创建数组 机器学习数据量很大…...

Linux之我不会

一、常用命令 1.系统管理 1.1 systemctl start | stop | restart | status 服务名 案例实操 1 查看防火墙状态 systemctl status firewalld2 停止防火墙服务 systemctl stop firewalld3 启动防火墙服务 systemctl start firewalld4 重启防火墙服务 systemctl restart f…...

音视频整体解码流程和同步流程

目录 1. 整体解码流程1. 初始化 FFmpeg2. 打开媒体文件3. 查找解码器4. 打开解码器5. 读取和解码数据6. 处理解码后的帧7. 释放资源 2. 音视频同步整体流程1. 解复用媒体流2. 解码3. 以音频为时钟源进行音视频同步的策略4. 缓冲区设计 现在先说大体流程&#xff0c;不分析代码 …...

1.2 HuggingFists安装说明-Linux安装

Linux版安装说明 下载地址 【GitHub】https://github.com/Datayoo/HuggingFists 【百度网盘】https://pan.baidu.com/s/12-qzxARjzRjYFvF8ddUJQQ?pwd2024 安装说明 环境要求 操作系统&#xff1a;CentOS7 硬件环境&#xff1a;至少4核8G&#xff0c;系统使用Containerd…...

四,MyBatis-Plus 当中的主键策略和分页插件的(详细实操使用)

四&#xff0c;MyBatis-Plus 当中的主键策略和分页插件的(详细实操使用) 文章目录 四&#xff0c;MyBatis-Plus 当中的主键策略和分页插件的(详细实操使用)1. 主键策略1.1 主键生成策略介绍 2. 准备工作&#xff1a;2.1 AUTO 策略2.2 INPUT 策略2.3 ASSIGN_ID 策略2.3.1 雪花算…...

Win32打开UWP应用

最近无意间发现Windows里一个神奇的文件夹。 shell:appsfolder 运行打开 这个文件夹后&#xff0c;你可以看到本机安装的所有应用程序。 我觉得这个挺方便的&#xff0c;所以做了一个简单的appFolderDialog包给C#用 项目地址&#xff1a;https://github.com/TianXiaTech/App…...

C# C++ 笔记

第一阶段知识总结 lunix系统操作 1、基础命令 &#xff08;1&#xff09;cd cd /[目录名] 打开指定文件目录 cd .. 返回上一级目录 cd - 返回并显示上一次目录 cd ~ 切换到当前用户的家目录 &#xff08;2&#xff09;pwd pwd 查看当前所在目录路径 pwd -L 打印当前物理…...

关于最小二乘法

最小二乘法的核心思想简单而优雅&#xff1a;我们希望找到一条最佳的曲线&#xff0c;使其尽可能贴近所有的数据点。想象一下&#xff0c;当你在画布上描绘一条线&#xff0c;目标是让这条线与点的距离最小。数学上&#xff0c;这可以表示为&#xff1a; 在这个公式中&#xff…...

国产OpenEuler与Centos全面之比较

OpenEuler 和 CentOS 都是流行的 Linux 发行版&#xff0c;但它们有一些关键的区别。以下是 OpenEuler 和 CentOS 的全面比较&#xff1a; 1. 起源和支持&#xff1a; - OpenEuler&#xff1a;由华为公司支持&#xff0c;中国开源社区主导开发的操作系统&#xff0c;旨在构建一…...

Java面试题一

一、Java语言有哪些特性&#xff1f; Java语言具有多种特性&#xff0c;这些特性使得Java成为一种广泛使用的编程语言。以下是Java语言的一些主要特性&#xff1a; 面向对象&#xff08;Object-Oriented&#xff09;&#xff1a; Java是一种纯面向对象的编程语言。它支持类&…...

LabVIEW提高开发效率技巧----自动化测试和持续集成

在大型项目中&#xff0c;自动化测试和持续集成是提高开发效率和代码质量的关键手段。通过这些技术&#xff0c;开发者能够在开发的早期阶段快速发现问题&#xff0c;减少后期调试的工作量&#xff0c;并且能够确保代码的稳定性和可维护性。以下是这两个概念如何在LabVIEW开发中…...

开源链动 2+1 模式 S2B2C 商城小程序:激活 KOC,开启商业新征程

摘要&#xff1a;本文深入探讨了 KOC 在立体连接中的重要性&#xff0c;以及如何通过开源链动 21 模式 S2B2C 商城小程序发现和找到更多的 KOC。强调了历史积累强关系和快速强化强关系的方法&#xff0c;并阐述了该商城小程序在推动商业发展中的关键作用。 一、引言 在当今竞争…...

什么是Node.js?

为什么JavaScript可以在浏览器中被执行&#xff1f; 在浏览器中我们加载了一些待执行JS代码&#xff0c;这些字符串要当中一个代码去执行&#xff0c;是因为浏览器中有JavaScript的解析引擎&#xff0c;它的存在我们的代码才能被执行。 不同的浏览器使用不同的javaScript解析引…...

即插即用篇 | DenseNet卷土重来! YOLOv8 引入全新密集连接卷积网络 | ECCV 2024

本改进已同步到YOLO-Magic框架! 本文重新审视了密集连接卷积网络(DenseNets),并揭示了其在主流的ResNet风格架构中被低估的有效性。我们认为,由于未触及的训练方法和传统设计元素没有完全展现其能力,DenseNets的潜力被忽视了。我们的初步研究表明,通过连接实现的密集连接…...

智能监控,守护绿色能源:EasyCVR在电站视频监控中心的一站式解决方案

随着科技的飞速发展&#xff0c;视频监控技术在社会安全、企业管理及智慧城市建设等领域中扮演着越来越重要的角色。特别是在电力行业中&#xff0c;电站作为能源供应的关键设施&#xff0c;其安全性和稳定性至关重要。传统的人工监控方式已难以满足现代电站复杂多变的运行需求…...

【BUG】静读天下|静读天下无法设置段间距解决方案

【BUG】静读天下&#xff5c;静读天下无法设置段间距解决方案 文章目录 【BUG】静读天下&#xff5c;静读天下无法设置段间距解决方案前言解决办法 凑质量分静读天下的特点与优势功能布局与使用技巧个人使用心得结语 前言 03-23 求助&#xff5c;关于排版的问题【静读天下吧】_…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

怎么让Comfyui导出的图像不包含工作流信息,

为了数据安全&#xff0c;让Comfyui导出的图像不包含工作流信息&#xff0c;导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo&#xff08;推荐&#xff09;​​ 在 save_images 方法中&#xff0c;​​删除或注释掉所有与 metadata …...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...

Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?

Pod IP 的本质与特性 Pod IP 的定位 纯端点地址&#xff1a;Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址&#xff08;如 10.244.1.2&#xff09;无特殊名称&#xff1a;在 Kubernetes 中&#xff0c;它通常被称为 “Pod IP” 或 “容器 IP”生命周期&#xff1a;与 Pod …...