C语言内存函数:memcpy、memcat、memmove介绍和模拟实现(实用性高,建议三连收藏)

目录

1.memcpy函数 

1.1函数介绍

1.2函数示范使用 

1.3函数的模拟实现

 1.4补充

2.memmove函数

2.1函数介绍

2.2函数的使用示范 

2.3函数的模拟实现 

3.memcmp(内存比较函数) 

3.1函数介绍

 3.2函数的示范使用,有趣的例子

4.函数补充memset(内存设置函数) 

4.1函数介绍

4.2函数示范使用 

5.结语


 

1.memcpy函数 

引入:之前我们讲过字符串的拷贝函数,但是当我们要拷贝整型数据或者结构体数组等类型弟弟数据的时候,就需要一个包容性更好的函数了。 

1.1函数介绍

函数头文件:string.h

函数参数:

①目的地

指向要复制内容的目标数组的指针,类型转换为 void* 类型的指针。

②源

指向要复制的数据源的指针,类型转换为 const void* 类型的指针。

③数量

要复制的字节数。 size_t 是无符号整数类型。

返回值类型:void*

返回值:返回目的字符串的地址也就是考到到某个地方,这个某个地方的地址。

函数功能:

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


1.2函数示范使用 

struct {char name[40];int age;
} person, person_copy;
int main()
{char myname[] = "Pierre de Fermat";memcpy(person.name, myname, strlen(myname) + 1);person.age = 46;memcpy(&person_copy, &person, sizeof(person));printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);return 0;
}

输出: 

1.3函数的模拟实现

函数模拟实现思想:我们参照库函数1来写,我们的想法是将源src的地址起的num个自己的内容拷贝到以目的地址dest为起点的空间中。那么由于我们的函数是要实现不同类型的内容都可以兼容拷贝,那么参数肯定是要设计为我们的void*类型来实现广泛接受,当我们实现的时候我们又想一个字节一个字节的遍历,那就应该将原先的void*的地址,转换为char*d的地址,以num为循环遍历拷贝条件,最后返回我们的目的空间的其实地址就行。

加下来我们看代码实现:

#include<stdio.h>
#include<assert.h>
#include <string.h>void* my_memcpy(void* dst, const void* src, size_t count)
{void* ret = dst;//保存目的空间地址assert(dst);assert(src);//断言,因为后续有指针的解引用操作,防止指针为空指针while (count--){*(char*)dst = *(char*)src;dst = (char*)dst + 1;src = (char*)src + 1;}return ret;
}struct {char name[40];int age;
} person, person_copy;
int main()
{char myname[] = "woaini";my_memcpy(person.name, myname, strlen(myname) + 1);person.age = 46;my_memcpy(&person_copy, &person, sizeof(person));printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);return 0;
}

我们来看一下实现效果:

 

 1.4补充

①关于 dst = (char*)dst + 1;指针的移动

首先我们知道void* l类型的指针是不支持指针运算的,所以要强制转换类型,然后因为char*类型的指针一步的长度刚好是一个字节,控制力度较好控制,所以转换为了字符型指针。

那么

可以这样写吗:(char*)dest++;

这种写法是错误的,因为强制类型转换是临时的,强制类型并不会改变这个指针本身弟弟类型,只是我用的时候临时转换的,后置++是先试用再++,等加加的时候,已经不能够在使用了。

那么:++(char*)dest 呢

这种写法可以但是有些编译器会报错,所以还是比较推荐第一种写法。

②我们想一下这个问题:

如果我们拷贝的空间是重复的呢,,比如我们有一个整型数组:

int arr1 = [1,2,3,4,5,6]

我们这样写:memecpy(arr1+2,arr1,60

我们原本是想得到:
1,2,1,2,3,4,5,6

但是如果我们使用memcpy就会出现这样的情况

但是,当我们去编译器里实现这段代码我们来看一下结果:

 

我们发怎么和我们预计的不一样,这个函数好像对于重叠的内存空间也能正常拷贝呀

这就是最后要补充的点:

memcpy确实是不负责重叠拷贝的。这是因为最初设计memcpy函数的时候我们是要求只用实现不重叠拷贝就好(相当于60分),在Vs上函数实现了重叠拷贝(相当于100分),哪也可以,但是我们接下来要介绍的这个函数才是正宗的负责重叠拷贝的。我们接着next.

2.memmove函数

2.1函数介绍

 

函数头文件:<string.h>

函数参数:

void * destination:指向要复制内容的目标数组的指针,类型转换为 void* 类型的指针。
const void * source:指向要复制的数据源的指针,类型转换为 const void* 类型的指针。size_t num :要复制的字节数。 size_t 是无符号整数类型。

 返回值:返回目标数组的地址

函数功能:将 num 字节的值从指向的位置复制到目标指向的内存块。复制就像使用中间缓冲区一样进行,从而允许目标重叠。

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。

2.2函数的使用示范 

刚刚上面举例的数组就是一个示范,下面用一个字符数组来示范:

#include <stdio.h>
#include <string.h>
int main ()
{char str[] = "memmove can be very useful......";memmove (str+20,str+15,11);puts (str);return 0;
}

2.3函数的模拟实现 

对于函数的返回值由于不知道传递进入的目标首地址会是什么类型,我们就用Void*作为返回类型,对于函数参数的设计,目的数组和源数组的地址都不确定是什么类型所以设计为void*类型,由于源字符串我们不会去操作改变,所以我们用const修饰。

由于函数实现的同一片空间的内容拷贝所以请看图解实现思想:

由上图得出结论一:当我们的dst<= src,也就是说目标地址要小于源地址的时候应该先将源字符串首地址的内容拷贝到目的数组的地址中,循环拷贝num个字节。 

结论②:当src<=dest<=src+num时, 目标地址要大于等于源地址并且小于等于源地址+num字节的的时候应该先将源字符串尾部地址的内容拷贝到目的数组的尾部地址中,循环拷贝num个字节。

当dest大于src+num时,随便怎么拷贝循序都行1,为了方便书写条件,我们就可以将其归结到上述两种情况其中之一,最好是第二种情况。 

 第一种实现:

void* my_memmove(void* dest, const void* src, size_t num)
{void* ret = dest;//保存目的空间地址assert(dest && src);//断言判断if (dest < src)//虽然void*不可以解引用或者算术运算,但是可以比较大小,因为保存的是地址编号{while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else{while (num--){*((char*)dest + num) = *((char*)src + num);}}return ret;
}
int main()
{char str[] = "memmove can be very useful......";my_memmove(str + 20, str + 15, 11);puts(str);return 0;
}

第二种实现大家可以试一下:

void * memmove ( void * dst, const void * src, size_t count)
{void * ret = dst;if (dst <= src || (char *)dst >= ((char *)src + count)){
while (count--) {*(char *)dst = *(char *)src;dst = (char *)dst + 1;src = (char *)src + 1;}}else {dst = (char *)dst + count - 1;src = (char *)src + count - 1;while (count--) {*(char *)dst = *(char *)src;dst = (char *)dst - 1;src = (char *)src - 1;}}return(ret);
}

3.memcmp(内存比较函数) 

3.1函数介绍

头文件包含:string.h

函数参数: 

PTR1型

指向内存块的指针。

PTR2型

指向内存块的指针。

数量

要比较的字节数。

返回值:

返回值表明
<0在两个内存块中不匹配的第一个字节在 ptr1 中的值低于 ptr2 中的值(如果计算为 unsigned char 值)
0两个内存块的内容相等
>0在两个内存块中不匹配的第一个字节在 ptr1 中的值大于 ptr2 中的值(如果计算为 unsigned char 值)
函数:是根据指针指向的内容一个字节一个字节的往后面进行比较,直到比出大小或者达到要求比较的字节数num.

 3.2函数的示范使用,有趣的例子

int main()
{int arr1[] = { 1,2,1,4,5,6 };int  arr2[] = { 1,2,257 };int ret1 = memcmp(arr1, arr2, 9);int ret2 = memcmp(arr1, arr2, 10);printf("%d\n%d\n", ret1, ret2);return 0;
}

两个数组前九个字节是一模一样的,这样说明我们的这个memcmp是一个字节一个字节的比较的

4.函数补充memset(内存设置函数) 

4.1函数介绍

 函数功能:将指定空间的num个字节设置为指定的value值,返回的是指定空间的地址。

4.2函数示范使用 

int main()
{char arr[] = { "hello word" };memset(arr + 1, 'x', 4);printf("%s\n", arr);return 0;
}

 

5.结语

以上就是本期的所有内容,知识含量蛮多,大家可以配合解释和原码运行理解。创作不易,大家如果觉得还可以的话,欢迎大家三连,有问题的地方欢迎大家指正,一起交流学习,一起成长,我是Nicn,正在c++方向前行的奋斗者,感谢大家的关注与喜欢。

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

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

相关文章

【靶场实战】Pikachu靶场RCE漏洞关卡详解

Nx01 系统介绍 Pikachu是一个带有漏洞的Web应用系统&#xff0c;在这里包含了常见的web安全漏洞。 如果你是一个Web渗透测试学习人员且正发愁没有合适的靶场进行练习&#xff0c;那么Pikachu可能正合你意。 Nx02 RCE漏洞概述 RCE漏洞&#xff0c;可以让攻击者直接向后台…

【Jenkins】配置及使用|参数化|邮件|源码|报表|乱码

目录 一、Jenkins 二、Jenkins环境搭建 1、下载所需的软件包 2、部署步骤 3、其他 三、Jenkins全局设置 &#xff08;一&#xff09;Manage Jenkins——Tools系统管理->全局工具配置分别配置JDK、Maven、Allure、Git&#xff0c;可以配置路径或者直接选择版本安装 1…

解决zabbix图像中文乱码

使用zabbix查看监控图像信息&#xff0c;发现会有中文乱码现象。 解决方法如下&#xff1a; 1.拷贝windows文字文件到服务器上 C:\Windows\Fonts目录下拷贝自己需要的中文语言文件 2.修改配置文件 vim /usr/share/zabbix/include/defines.inc.php 81行 define(ZBX_GRAPH_F…

zookeeper搭建(单机模式和集群模式)

目录 单机模式&#xff1a; 集群搭建&#xff1a; 单机模式&#xff1a; 1.新建data和logs目录(data目录用来存放数据库快照&#xff0c;logs目录用来存放日志文件) [rootmaster dev]# mkdir -p /home/apps/zookeeper/data [rootmaster dev]# mkdir -p /home/apps/zookeeper/…

新数据不影响原来的数据

问题描述 新数据修改时&#xff0c;原来的数据也会受影响 const obj1 ref({ name: slx, age: 20 })const obj2 obj1obj2.value.name hhhhconsole.log(obj1, obj1.value)console.log(obj2, obj2.value)解决方法 (仅适用于对象 在这段代码中&#xff0c;obj1 和 obj2 指向同…

【Python基础】文件详解(文件基础、csv文件、时间处理、目录处理、excel文件、jsonpicke、ini配置文件)

文章目录 &#xff08;一&#xff09;文件详解1 快速入门文件操作1.1 快速实现文件读取1.2 快速实现文件写入 2 文件打开方式详解2.1 open方法2.2 打开方式2.3 文件读写操作2.3.1 基本读写2.3.2 读写方式打开2.3.3 实现重复读取 3 文件编码问题4 文件读写方法4.1 文件读取方式4…

【PTA编程题】7-1 保持链表有序

对于输入的若干学生的信息&#xff0c;按学号顺序从小到大建立有序链表&#xff0c;最后遍历链表&#xff0c;并按顺序输出学生信息。 输入格式: 首先输入一个正整数T&#xff0c;表示测试数据的组数&#xff0c;然后是T组测试数据。每组测试数据首先输入一个正整数n&#xf…

IT行业证书的获取与价值:提升职业竞争力的关键

目录 IT行业证书的价值和作用 1. Cisco&#xff08;思科&#xff09;认证&#xff08;如CCNA、CCNP、CCIE&#xff09;&#xff1a; 2. 微软认证&#xff08;如MCSA、MCSE、MCSD&#xff09;&#xff1a; 3. 计算机网络技术&#xff08;CompTIA Network、CompTIA Security&a…

《汇编语言》- 读书笔记 - 各章检测点归档

《汇编语言》- 读书笔记 - 各章检测点归档 检测点 1.1检测点 2.1检测点 2.2检测点 2.3检测点 3.1检测点 3.2检测点 6.1检测点 9.1 检测点 1.1 1个CPU 的寻址能力为8KB&#xff0c;那么它的地址总线的宽度为 13 。 解&#xff1a;8KB 8192B 213 1KB的存储器有 10…

构建高效直播美颜系统:美颜SDK集成与性能优化指南

如今&#xff0c;美颜技术的广泛应用成为各类直播平台的标配之一。今天&#xff0c;小编将与大家进一步讨论如何构建高效的直播美颜系统&#xff0c;重点关注美颜SDK的集成和性能优化方面。 一、美颜SDK的选择与集成 选择合适的美颜SDK是构建高效直播美颜系统的第一步。不同的…

MATLAB频域分析(附完整代码)

1. MATLAB进行频域分析举例 以下是一个使用MATLAB进行频域分析的例子。在这个例子中&#xff0c;我们将生成一个含有两个不同频率分量的信号&#xff0c;然后使用快速傅里叶变换&#xff08;FFT&#xff09;来分析其频域特性。 main.m文件 clc;close all;clear all;warning of…

12. onnx转为rknn测试时有很多重叠框的修改(python)

我们下载rknn-toolkit2-master后并进行前面的处理后&#xff0c;进入到rknn-toolkit2-master\examples\onnx\yolov5文件夹&#xff0c;里面有个test.py文件&#xff0c;打开该文件&#xff0c;其代码如下&#xff1a; # -*- coding: utf-8 -*- # coding:utf-8import os import…

msvcp120.dll丢失如何解决/找不到msvcp120.dll的5种有效的解决方法

在计算机系统运行过程中&#xff0c;如果遇到“找不到msvcp120.dll”的提示信息&#xff0c;这代表了何种具体状况呢&#xff1f;首先&#xff0c;我们需要明确msvcp120.dll文件的重要性。msvcp120.dll是Microsoft Visual C Redistributable Package的一部分&#xff0c;这是一…

工作与生活平衡:在生活中寻找和谐

工作和生活是我们生活中不断交织的两个重要方面。对许多人来说&#xff0c;找到两者之间的完美平衡已经成为一个持久的挑战。然而&#xff0c;与其专注于平衡&#xff0c;更重要的是要认识到工作和生活并不是可以相互平衡的两个分离实体&#xff0c;而是一个相互影响的循环。正…

[word] word小数点对齐怎么设置 #微信#其他#其他

word小数点对齐怎么设置 使用Word编辑文档的时候&#xff0c;如果有小技巧的话&#xff0c;可以解决很多遇到的问题&#xff0c;也让工作更高效的完成&#xff0c;下面给大家分享word小数点对齐怎么设置的小技巧。 1、设置格式 选中内容&#xff0c;点击段落一一制表符&#…

扩展鸿蒙textinput组件

扩展鸿蒙textinput组件&#xff0c;支持快速扩展展性&#xff0c;标题文本等&#xff0c;文本内容双向绑定、文本组件快速复用。 组件代码 /*** 单选文本*/ Component export default struct DiygwInput{//绑定的值Link value:string;//未选中图标State labelImg: Resource …

探索虚拟与增强现实的无限可能:塑造未来的生活体验

美国当地时间2月2日&#xff0c;苹果首款头显Vision Pro正式上市&#xff0c;当天&#xff0c;在员工高喊“AVP&#xff08;Apple Vision Pro&#xff09;”呼声中&#xff0c;苹果首席执行官蒂姆‧库克&#xff08;Tim Cook&#xff09;在位于纽约曼哈顿第五大道的苹果旗舰店开…

ShardingSphere 5.x 系列【3】分库分表中间件技术选型

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址&#xff1a;https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 前言2. My Cat3. ShardingSphe…

Docker 一小时从入门到实战 —— Docker commands | Create your own image | vs VM ... 基本概念扫盲

Docker crash course 文章目录 Docker crash course1. What and Why of Docker?2.1 What2.2 What problem does it solve?2.2.1 before containers2.1.2 with containers 2. Docker vs Virtual Machines2.1 Difference2.2 Benefits 3. Install docker locally4. Images vs Co…

【CSS】外边距折叠(margin 塌陷)

外边距折叠(collapsing margins) 毗邻的两个或多个margin会合并成一个margin&#xff0c;叫做外边距折叠。 规则如下: 两个或多个毗邻的普通流中的块元素垂直方向上的 margin会折叠浮动元素 / inline-block元素 / 绝对定位元素 / 行内元素的margin不会和垂直方向上的其他元素…