内存操作函数(c语言)

目录

  • 概述
  • 1. `memcpy`函数
  • 2.`memcpy`函数的模拟实现
  • 3. `memcmp`函数
  • 4.`memcmp`函数的模拟实现
  • 5. `memset`函数
  • 6.`memset`函数的模拟实现
  • 7. `memmove`函数
  • 8.`memmove`函数的模拟实现
  • 结语

概述

C语言提供了一些非常有用的内存操作函数,其中包括memcpymemcmpmemsetmemmove。这些函数可以帮助我们在程序中对内存进行复制、比较和设置操作。本文将介绍这些函数的用法和模拟实现。

1. memcpy函数

memcpy函数用于将一个内存区域的内容复制到另一个内存区域。它的原型如下:

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

其中,destination是目标内存区域的指针,source是源内存区域的指针,number是要复制的字节数。下面是一个使用memcpy函数的示例:

#include <stdio.h>
#include <string.h>int main() 
{char src[] = "Hello, World!";char dest[20];memcpy(dest, src, 10);printf("复制后的字符串:%s", dest);return 0;
}
  • 输出结果:
    在这里插入图片描述
    上述代码将字符串src的前十个字节的内容复制到了dest数组中,但是并没有复制到'\0',所以在输出"Hello,Wor"之后是随机值。

2.memcpy函数的模拟实现

#include <stdio.h>
#include <assert.h>void* my_memcpy(void* dst, void* src, size_t num)//(拷贝目标地址,拷贝来源地址,要拷贝的字节大小)
{assert(dst && src);//assert()里面的条件必须为真,否则报错终止程序,这里是防止传过来的指针为NULLvoid* ret = dst;//memcpy函数拷贝完成后会返回目标的地址,这里先用ret将dst储存起来while (num--){*(char*)dst = *(char*)src;//强制类型转换为char*,是为了让程序一个字节一个字节的拷贝dst = (char*)dst + 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, 20);for (int i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}
  • 输出结果
    在这里插入图片描述

3. memcmp函数

memcmp函数用于比较两个内存区域的内容是否相等。它的原型如下:

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

其中,ptr1ptr2分别是待比较的两个内存区域的指针,num是要比较的字节数。下面是一个使用memcmp函数的示例:

#include <stdio.h>
#include <string.h>int main() 
{char str1[] = "Hello";char str2[] = "Hello";int result = memcmp(str1, str2, strlen(str1));if (result == 0) {printf("两个字符串相等");} else {printf("两个字符串不相等");}return 0;
}
  • 输出结果
    在这里插入图片描述
    上述代码比较了两个字符串str1str2是否相等,并根据比较结果输出相应的信息。

4.memcmp函数的模拟实现

#include <stdio.h>
#include <assert.h>int my_memcmp(void* dst, void* src, size_t num)
{assert(dst && num);while (num--){if (*(char*)dst != *(char*)src)return *(char*)dst - *(char*)src;//memcmp函数的返回值是一个整型//当dst大于src时返回一个大于0的数//当dst等于src时返回0//当dst小于src时返回一个小于0的数//所以返回 dst - src 会方便很多	dst = (char*)dst + 1;src = (char*)src + 1;}return 0;
}int main()
{int arr1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int arr2[] = { 1, 2, 3, 4, 6 };int ret = my_memcmp(arr1, arr2, 20);if (ret == 0)printf("相等");else if (ret > 0)printf("arr1大于arr2");elseprintf("arr1小于arr2");return 0;
}
  • 输出结果
    在这里插入图片描述
    上述代码比较的是arr1arr2的20个字节的内容,即比较了arr11,2,3,4,5arr21,2,3,4,6

5. memset函数

memset函数用于将一个内存区域的所有字节设置为指定的值。它的原型如下:

void *memset(void *dst, int src, size_t num);

其中,dst是要设置的内存区域的指针,src是要设置的值,num是要设置的字节数。下面是一个使用memset函数的示例:

#include <stdio.h>
#include <string.h>int main() 
{char str[20];memset(str, 'A', sizeof(str));printf("设置后的字符串:%s", str);return 0;
}
  • 输出结果
    在这里插入图片描述
    上述代码将字符串str中的所有字节都设置为字符'A',但是没有设置'\0',所以输出完20'A'之后是随机值。

6.memset函数的模拟实现

#include <stdio.h>
#include <assert.h>void* my_memset(void* dst, int src, size_t num)
{assert(dst);void* ret = dst;while (num--){*(char*)dst = (char)src;dst = (char*)dst + 1;}return ret;
}int main()
{char arr[10];my_memset(arr, '*', 10);for (int i = 0; i < 10; i++)printf("%c ", arr[i]);return 0;
}
  • 输出结果
    在这里插入图片描述

7. memmove函数

memmove函数用于将一个内存区域的内容移动到另一个内存区域即使这两个区域有重叠。它的原型如下:

void *memmove(void *dst, const void *src, size_t n);

其中,dst是目标内存区域的指针,src是源内存区域的指针,num是要移动的字节数。下面是一个使用memmove函数的示例:

#include <stdio.h>
#include <string.h>int main() 
{char str[] = "Hello, World!";memmove(str + 7, str, strlen(str) + 1);printf("移动后的字符串:%s", str);return 0;
}
  • 输出结果
    在这里插入图片描述
    上述代码将字符串str中的内容"Hello, World!"移动到了字符串str的第7个元素之后,结果如上图。

8.memmove函数的模拟实现

  • 模拟memmove函数的注意事项:
    1、当在内存中的地址dst < src时,memmove函数要将数据从前往后移动数据,否则会达不到想要的结果。
    2、当在内存中的地址dst = src时,从前往后和从后往前移动数据都可行。
    3、当在内存中的地址dst > src时,memmove函数要将数据从后往前移动数据,否则会达不到想要的结果。

  • 假设我们要将int arr[] = { 1,2,3,4,5,6,7,8,9,10 };中的前5个元素移动到第3个元素开始的位置,即将数组里的1,2,3,4,5移动到3,4,5,6,7

  • 因为第3个元素的地址小于第1个元素的地址,所以我们模拟的memmove函数要从后往前移动前5个元素,才能得到我们想要的结果

    • 下图分别是从前往后移动和从后往前移动的结果

在这里插入图片描述


模拟实现代码:

#include <stdio.h>
#include <assert.h>void* my_memmove(void* dst, void* src, size_t num)
{assert(dst && src);void* ret = dst;if (dst < src){while (num--){*(char*)dst = *(char*)src;dst = (char*)dst + 1;src = (char*)src + 1;}}else{while (num--){*((char*)dst + num ) = *((char*)src + num );//这里的num是经过--的,指向的是dst和src的最后一个元素的最后一个字节,如果不经过--,则会从dst和src的最后一个字节的后一个字节开始移动,会造成结果错误}}return ret;
}int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr + 2, arr, 20);for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}
  • 输出结果
    在这里插入图片描述

结语

在使用这些内存操作函数时,需要注意传入正确的参数,并防止发生内存溢出或访问越界的情况。此外,这些函数在处理大量数据时效率较高,可以大大提高程序的执行效率和内存使用效率。

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

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

相关文章

【Android】更改手机主题导致app数据丢失问题

情景&#xff1a;在使用app过程中更改系统主题&#xff08;比如从浅色主题改为深色主题&#xff09;&#xff0c;这时activity销毁重建了&#xff08;即走了onPause、onStop、onSaveInstanceState、onDestroy、onCreate、onRestoreInstanceState、onStart、onResume的生命周期&…

用Python实现绘画樱花树

下面这段代码使用了Python的turtle模块来绘制一个类似于樱花的图案。具体来说&#xff0c;它定义了两个函数&#xff1a;Tree和Petal&#xff0c;并使用这两个函数来绘制图案。 Tree函数&#xff1a; 这个函数递归地绘制了樱花的躯干。它接受两个参数&#xff1a;branch&#x…

MQTT简介

https://mqtt.org/ MQTT&#xff08;Message Queuing Telemetry Transport&#xff09; 一种轻量级的&#xff0c;基于发布订阅模式的通信协议&#xff0c;用于在物联网和机器与机器&#xff08;M2M&#xff09;通信中传输消息。 它具有低带宽和低功耗的特点&#xff0c;适用于…

Dockerfile制作镜像

Dockerfile制作镜像 Dockerfile介绍 dockerfile 是一个用来构建镜像的文本文件&#xff0c;文本内容包含了一条条构建镜像所需的指令和说明。 dockerfile仅仅是用来制作镜像的源码文件&#xff0c;是构建容器过程中的指令&#xff0c;docker能够读取dockerfile的指定进行自动…

vue3 开发记录

1.引入nprogress插件&#xff0c;显示未声明文件 无法找到模块“nprogress”的声明文件。 解决方法&#xff1a; vite-env.d.ts // 解决引入模块的报错提示 declare module "nprogress";2.在 .evn 文件中创建了自定义环境变量 VITE_APP_BASE_URL 但在项目中使用时出…

【学习记录】Resnet

Resnet的残差块 BasicBlock模块&#xff1a; Resnet的作用 解决梯度消失。网络越深&#xff0c;会导致梯度消失。Resnet可以解决梯度消失的问题。 Resnet的原理 参考视频&#xff1a;https://www.bilibili.com/video/BV1cM4y117ob/?spm_id_from333.337.search-card.all.cl…

请查收:2024年腾讯云服务器优惠价格表_租用配置报价

一张表看懂腾讯云服务器租用优惠价格表&#xff0c;一目了然&#xff0c;腾讯云服务器分为轻量应用服务器和云服务器CVM&#xff0c;CPU内存配置从2核2G、2核4G、4核8G、8核16G、4核16G、8核32G、16核32G、16核64等配置可选&#xff0c;公网带宽1M、3M、5M、12M、18M、22M、28M…

FreeRTOS任务切换

目录 一、PendSV异常 二、任务切换场合 1、执行系统调用 2、滴答定时器(SysTick)中断 三、PendSV中断服务函数 1、分析xPortPendSVHandler中断服务函数 四、查找下一个要运行的任务的两种方法 1、获取下一个要运行的任务 2、查找下一个要运行的任务的两种方法 2.1、通…

Android全屏黑边解决方案

在Android12以上的手机&#xff0c;设置全屏后屏幕底部有黑边或者白边&#xff0c;有的屏幕顶部有黑边。解决方案很简单&#xff0c;在使用的主题中添加对应的设置即可&#xff0c;如下&#xff1a; res/values/themes.xml <resources><style name"Base.Theme.La…

C++:封装

封装:将数据和操作数据的方法进行结合, 隐藏具体的实现细节, 只提供接口用来交互 类: 一种自定义类型, 类域和访问限定符, 让外面只能看到该类的一些接口, 而看不到其具体的成员及接口的具体实现 类 语法:class name{...}; 里面可有成员函数, 成员变量类域: 访问类域里面的代…

Windows系统安装TortoiseSVN并结合内网穿透实现远程访问本地服务器——“cpolar内网穿透”

文章目录 前言1. TortoiseSVN 客户端下载安装2. 创建检出文件夹3. 创建与提交文件4. 公网访问测试 前言 TortoiseSVN是一个开源的版本控制系统&#xff0c;它与Apache Subversion&#xff08;SVN&#xff09;集成在一起&#xff0c;提供了一个用户友好的界面&#xff0c;方便用…

ThreeDWorld(TDW)学习(待更新)

目录 前言 1.TDW 2.transport challenge 总结 前言 因为挑战赛了解到tdw仿真平台。 想了解的请点击&#xff1a; GitHub - threedworld-mit/tdw: ThreeDWorld simulation environment GitHub - chuangg/tdw-transport-challenge-starter-code 1.TDW ThreeDWorld (TDW)是一…

范德蒙行列式

范德蒙行列式&#xff08;Vandermonde determinant&#xff09;是一种特殊形式的行列式&#xff0c;常在多项式理论和插值中遇到。其命名来源于法国数学家Alexandre-Thophile Vandermonde。范德蒙行列式是以一组数为变量的行列式&#xff0c;其特殊之处在于每一行的元素是前一行…

VSCode安装与使用详细教程

一、引言 简要介绍VSCode&#xff08;Visual Studio Code&#xff09;是什么&#xff0c;它的主要特点和用途&#xff0c;以及为什么选择VSCode作为代码编辑器。 二、下载与安装 访问VSCode官方网站下载页面。选择适合操作系统的版本&#xff08;Windows、macOS、Linux&…

孩提家乐福愿

孩提家乐福愿 预知过往时&#xff0c;风雨夜晚事。 ​季暖烟火气&#xff0c;升级父母知。 ​爱孩绕膝闹&#xff0c;庭院长幼喜。 ​聚德传承系&#xff0c;言行耕读义。

数据卷dockerfile

目录 一、数据卷 1. 简介 2. 数据卷和数据卷容器 1. 数据卷&#xff1a; 2. 数据卷容器&#xff1a; 二、自定义镜像 1. 作用 2. 自定义centos 3. 自定义tomcat8 一、数据卷 1. 简介 数据卷是一个可供一个或多个容器使用的特殊目录&#xff0c;它将主机操作系统目录直…

mysql修改字段的长度锁表问题

mysql修改字段的长度锁表问题 背景 MySQL&#xff08;这里指5.6及其后续版本&#xff09;修改字段的长度锁表会锁表吗&#xff1f;答案是可能会但不一定会 具体原理 MySQL 5.6 及以后版本扩大字段长度 支持 online ddl in-place 模式&#xff0c;而这将不会锁表。varchar 表示…

string字符串进行分割

c标准库中&#xff0c;对string字符串并没有提供分割操作&#xff0c;需要自己手动实现此功能。 方式1&#xff1a; 采用 std::stringstream 输入字符串&#xff0c;通过getline()函数&#xff0c;来对字符串进行分割。 #include <sstream>void getSplit(std::string s…

Unity—MVC分层开发思想

每日一句&#xff1a;当你不努力的时候&#xff0c;天赋就会一点一点被收回 目录 MVC分层开发思想 MVC是什么 MVC的开发步骤 案例&#xff1a;点击按钮实现金币进行添加&#xff0c;并且把金币记录到JSON里 MVC模式实现 背包系统基础代码 背包项目实现步骤 MVC分层开发思…

spring-data-redis概述及用法

一、spring-data-redis spring-data-redis是spring-data模块的一部分,专门用来支持在spring管理项目对redis的操作,使用java操作redis最常用的是使用jedis,但并不是只有jedis可以使用,像jdbc-redis jredis也都属于redis的java客户端,他们之间是无法兼容的,如果你在一个项目中使…