内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

2024-05-15 14:36

本文主要是介绍内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

内存函数

  • 一.memcpy(内存拷贝1)
    • 1.函数使用
    • 2.模拟实现
  • 二.memmove(内存拷贝2)
    • 1.函数使用
    • 2.模拟实现
  • 三.memcmp(内存比较)
    • 1.函数使用
    • 2.模拟实现
  • 四.memset(内存设置)
    • 1.函数使用
    • 2.模拟实现

前言:

  • 之前我们学习了一些字符串库函数,并且模拟实现了它们。但是它们只能作用于字符串,那有没有适用于各种数据类型的函数呢?答案是有的,现在我将为你介绍——内存函数(memory function)
  • 内存函数头文件——string.h

一.memcpy(内存拷贝1)

1.函数使用

void* memory(void* destination, const void* source, size_t num);
  • memcpy函数用于拷贝两块独立空间中的数据(不可重叠),将源内存块按照每一个字节拷贝到目标内存块,num表示要拷贝字节的数目。destination 与 source 都是拷贝与被拷贝的起始地址。
#include<stdio.h>
#include<string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7 };int arr2[10] = { 0 };int arr3[] = { 1,2,3,4,5,6,7,8,9,10 };memcpy(arr2, arr1, 24);memcpy(arr3 + 2, arr3, 20);return 0;
}

在这里插入图片描述

  • 观察到arr1将前6个整形拷贝到了arr2中,也就是24个字节,是没有问题的。
  • 而第二个操作本来打算:将 arr3 中的 1,2,3,4,5 拷贝到 arr3 中的 3,4,5,6,7 上,但是得到的是1,2,1,2,1这是因为将1,2拷贝到3,4上,原来的内容就被修改了,达不到要求的效果。

总结:

  1. 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。
  2. 这个函数在遇到 ‘\0’ 的时候并不会停下来。
  3. 用于拷贝两块独立空间中的数据,如果source和destination有任何的重叠,复制的结果都是未定义的。
  4. 由于不知道拷贝什么样的数据,所以参数的指针类型为void*(可接收任意类型指针),在函数内部强制类型转换为 char*,可以用于每个字节拷贝。

2.模拟实现

  • 首先是必不可少的断言操作,其次就是要保留目标空间的起始地址便于之后的返回。然后拷贝每一个字节中的内容,所以要循环 num 次。每拷贝一个字节,两个指针向后移动,直到循环结束为止。拷贝结束后返回起始地址即可。
void* my_memcpy(void* destination, const void* source, size_t num)
{assert(destination && source);//断言,当二者之一指针为NULL则报错void* ret = destination;//存起始地址便于返回while (num--)//循环拷贝,每次拷贝一个字节{*(char*)destination = *(char*)source;destination = (char*)destination + 1;source = (char*)source + 1;}return ret;
}

注意:在对 destination 和 source 指针进行操作时,要先将它们强制类型转换为 char* 类型的指针。(char* 类型的指针解引用操作时向后访问一个字节的内容)。而 void* (泛型指针)是不能进行解引用操作的。

二.memmove(内存拷贝2)

1.函数使用

  • 上面学习了memcpy函数,得知其不能用于处理重叠的内存之间的数据拷贝,那么这样实现重叠部分的数据拷贝呢?memmove会带你实现。
void* memmove(void* destination, const void* source, size_t num);
  • memmove函数用于拷贝两块空间中的数据(可以重叠),将源内存块按照每一个字节拷贝到目标内存块,num表示要拷贝字节的数目。destination 与 source 都是拷贝与被拷贝的起始地址。
#include<stdio.h>
#include<string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };memmove(arr1 + 2, arr1, 20);return 0;
}

在这里插入图片描述

总结:

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

2.模拟实现

分析:
1.当要将紫色区间拷贝到蓝色区间,若采用从前往后(1,2,3,4,5)拷贝,会改变紫色区间中要进行拷贝的数据。换个思路:采用从后往前拷贝,能避免这个问题。
在这里插入图片描述

2.当要将紫色区间拷贝到蓝色区间,若采用从后往前(7,6,5,4,3)拷贝,会改变紫色区间中要进行拷贝的数据。换个思路:采用从前往后拷贝,能避免这个问题。

在这里插入图片描述
总结:

  1. 在同一块内存中:重叠时,当dest指针 > src指针,采用从前向后拷贝。
  2. 在同一块内存中:重叠时,当dest指针 < src指针,采用从后向前拷贝。
  3. 在同一块内存中:若没有重叠,二者都可以采用。
  4. 在不同块内存中:二者都可以采用。
void* my_memmove(void* destination, const void* source, size_t num)
{assert(destination && source);//断言void* ret = destination;//保存起始地址if (destination < source)//从前向后拷贝{while (num--){*(char*)destination = *(char*)source;destination = (char*)destination + 1;source = (char*)source + 1;}}else//从后向前拷贝{while (num--){*((char*)destination+num) = *((char*)source+num);}}return ret;//返回起始地址
}

三.memcmp(内存比较)

1.函数使用

int memcmp(const void* ptr1, const void* ptr2, size_t num);
  • memcmp函数用于比较两个内存块大小的函数。它会比较从 ptr1 和 ptr2 指针开始的第一个字节。当 *ptr1 大于 *ptr2 的时候返回一个大于0的数;当 *ptr1 等于 *ptr2 的时候返回0;当 *ptr1 小于 *ptr2 的时候返回一个小于0的数。比较完一次,ptr1 与 ptr2 指向下一个字节,循环 num 次,直到结束为止 。
#include<stdio.h>
#include<string.h>
int main()
{int arr1[] = { 1,257 };//01 00 00 00 01 01 00 00int arr2[] = { 1,2 };  //01 00 00 00 02 00 00 00int ret = memcmp(arr1, arr2, 8);printf("%d\n", ret);return 0;
}

在这里插入图片描述
在这里插入图片描述

  1. 在VS中内存采用的是小端存储方式。
  2. 数字在内存中是以2进制补码的形式存储的,但是为了更好的观察,以16进制展现出来。
  3. arr1与arr2中的前4个字节的内容都相同;但第5个字节,1<2,所以arr1 < arr2。

2.模拟实现

  • 首先就是断言,比较字节中的内容,若相同比较下一个字节中的内容,num–。直到字节内容不同或num==0,停止循环,返回二者字节内容的差值。
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{assert(ptr1 && ptr2);while (*(char*)ptr1 == *(char*)ptr2 && num--)//1.*(char*)ptr1 != *(char*)ptr2  2.num==0                {ptr1 = (char*)ptr1 + 1;ptr2 = (char*)ptr2 + 1;}if(num==0)//二者相同return 0;else//二者不同return  *(char*)ptr1 - *(char*)ptr2;
}

四.memset(内存设置)

1.函数使用

void* memset(void* destination, int value, size_t num);
  • memset函数可以将内存块的某一部分设置为特定的字符。三个参数中,第一个参数是开始设置内存的起始位置,第二个参数是要将内存设置成的字符,第三个参数是从起始位置开始需要设置的内存的字节数。memset函数设置内存的时候是一个字节一个字节地设置的。
#include<stdio.h>
#include<string.h>
int main()
{char arr[] = "hello world";memset(arr + 6, 'x', 5);printf("%s\n", arr);return 0;
}

在这里插入图片描述
再比如:将arr初识化为全1(每个字节都初始化为1)

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

在这里插入图片描述
因为改变一次改变一个字节,而不是所以不适合初始化整形数组。适合修改字符串内容。

2.模拟实现

void* my_memset(void* destination, int value, size_t size)
{assert(destination);void* ret = (char*)destination;//保留目标空间的起始地址便于之后的返回while (size--){*(char*)destination = value;destination = (char*)destination + 1;}return ret;
}

创作不易,如果能帮到你的话能赏个三连吗?感谢啦!!!
在这里插入图片描述

这篇关于内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/992087

相关文章

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

mtu设置多少网速最快? 路由器MTU设置最佳网速的技巧

《mtu设置多少网速最快?路由器MTU设置最佳网速的技巧》mtu设置多少网速最快?想要通过设置路由器mtu获得最佳网速,该怎么设置呢?下面我们就来看看路由器MTU设置最佳网速的技巧... 答:1500 MTU值指的是在网络传输中数据包的最大值,合理的设置MTU 值可以让网络更快!mtu设置可以优化不同的网

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

MySQL 设置AUTO_INCREMENT 无效的问题解决

《MySQL设置AUTO_INCREMENT无效的问题解决》本文主要介绍了MySQL设置AUTO_INCREMENT无效的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录快速设置mysql的auto_increment参数一、修改 AUTO_INCREMENT 的值。

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

详解Linux中常见环境变量的特点与设置

《详解Linux中常见环境变量的特点与设置》环境变量是操作系统和用户设置的一些动态键值对,为运行的程序提供配置信息,理解环境变量对于系统管理、软件开发都很重要,下面小编就为大家详细介绍一下吧... 目录前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变

安装centos8设置基础软件仓库时出错的解决方案

《安装centos8设置基础软件仓库时出错的解决方案》:本文主要介绍安装centos8设置基础软件仓库时出错的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录安装Centos8设置基础软件仓库时出错版本 8版本 8.2.200android4版本 javas

Ubuntu设置程序开机自启动的操作步骤

《Ubuntu设置程序开机自启动的操作步骤》在部署程序到边缘端时,我们总希望可以通电即启动我们写好的程序,本篇博客用以记录如何在ubuntu开机执行某条命令或者某个可执行程序,需要的朋友可以参考下... 目录1、概述2、图形界面设置3、设置为Systemd服务1、概述测试环境:Ubuntu22.04 带图