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

C语言的内存函数

目录

一、memcpy函数

二、memmove函数

三、memset 函数

四、memcmp 函数

总结


        C语言库函数中有可以直接对内存操作的函数,这类函数叫作内存函数

        内存函数即针对内存块进行数据处理的函数,内存块的意思就是“一块内存,一块空间”。

        在日常编程,我们常用的内存函数有四个,分别是:memcpymemmovememsetmemcmp。它们都有一个共同的前缀“mem”,英文全拼为memory,译为记忆,而记忆在计算机里面的意思就是内存

        以下为四个内存函数名称的具体含义:

        “cpy”的英文全拼为“copy”,译为“拷贝、复制”,所以memcpy是内存拷贝函数

        “move”的译为“移动”,所以memcpy是内存移动函数

        “set”译为“设置”,所以memset是内存设置函数

        “cmp”的英文全称是“compare”,译为“比较”,所以metcmp是内存比较函数

        本文将会对这个四个内存函数作详细介绍。

一、memcpy函数

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

         memcpy函数参数中 void * destination指针接收的是原内存块的地址const void * source指针接收的是目标内存块的地址size_t num接收的是拷贝的字节个数num;它的返回值是目标空间的起始地址。

        所以函数memcpy的作用是:从 source 指针指向的地址开始,向后复制 num 个字节的数据到 destination 指针指向的内存位置。

        同时,这个函数遇到了“\0”并不会停下来,因为内存拷贝就是把内存拷贝过去,具体是什么内容不重要。

        它参数的两个指针类型都是“void*”,这是因为内存拷贝,你不确定会拷贝什么类型的数据,可能是整型数据、浮点型数据、结构体数据等,所以要写成void*,不能写成具体的某种类型,void*指针接收任意空间的地址都行。

        它的返回值也是void*类型的,因为返回值是目标空间的起始地址,目标空间存放数据的的数据类型不确定,所以返回值的类型也不确定。得到返回值后,如果要使用此返回值,强制转换为需要的类型即可

        同时,如果 source 和 destination 在内存上有任何的重叠,复制的结果都是未定义的。因为在C语言标准规定,memcpy只要实现空间不重叠的拷贝就行。一些编译器中的memcpy函数是没有对重叠部分进行实现与定义的,所以得到的结果也都是未定义的。

        以下是具体的代码演示:

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };memcpy(arr2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}

        在上面的程序中,指针 arr1 指向的是数组 arr1 的第一个元素,指针 arr2 指向的数组 arr2 的第一个元素,复制的字节是 20 个。因为一个整型数据占4个字节,所以复制的数据是5个。

        所以源内存块是“12345”,目标内存块是“00000”,得到的结果为“1 2 3 4 5 0 0 0 0 0”。

二、memmove函数

void * memmove ( void * destination, const void * source, size_t num );

        它的逻辑和功能与memcpy函数是基本一致的,在此不多作介绍。

        两者唯一的区别就是 memmove 函数处理的源内存块与目标内存块是可以重叠的。如果源空间和目标空间出现重叠,就得使用memmove函数处理。 

        以下是具体的代码演示:

#define _CRT_SECURE_NO_WARNINGS#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);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}return 0;
}

        在上面的程序中,指针arr1指向的数组第一个元素,指针arr1+2指向的是数组第三个元素,复制的字节是20个。

        所以源内存块是“12345”,目标内存块是“34567”,此时将源内存块与目标内存块出现重叠,该函数复制过去,得到的就是“1 2 1 2 3 4 5 8 9 10”。

三、memset 函数

void * memset ( void * ptr, int value, size_t num );

        memset 函数参数中 void * ptr 指针接收的是内存设置的起始地址int value 接收的是要设置的内存的值size_t num 接收的是设置的字节的个数返回值是内存设置的起始地址。

        关于为什么要设置成void*类型的指针,与memcpy函数的逻辑是一样的。

        所以memset函数的作用是:从指针 ptr 指向的起始地址开始,将后面的num个字节都设置为value。

        所以它只能一个个字节地设置值,且设置的值都是一样的。所以一般只适用于字符数据的设置,比如说加密之类的操作。如果是用于设置整型数据就不太合适,因为一个整型数据占据四个字节。

        以下是具体的代码演示:

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>
#include <string.h>
int main()
{char str[] = "hello world";memset(str, 'x', 6);printf(str);return 0;
}

        在上面程序中,指针 str 指向数组的第一个元素,函数运行时将此元素开始的后六个元素都是设置为“x”,所以打印出来的值为“xxxxxxworld”

四、memcmp 函数

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

        memcmp 函数参数const void * ptr1 与 const void * ptr2 两个指针接收的是两个要比较的内存块的起始地址,size_t num 接收的是要比较的字节的个数。

        它的返回值:如果指针 ptr1 指向的内存块大于 指针ptr2 指向的内存块,那就返回大于 0 的整数;如果指针 ptr1 指向的内存块小于指针 ptr2 指向的内存块,那就返回小于 0 的整数;如果指针 ptr1 指向的内存块等于指针 ptr2 指向的内存块,那就返回等于 0 的整数

        所以memcmp函数的作用是:两个内存块从起始位置开始,将一对对字节进行比较,比较 num 对,只要其中的一对字节所存储的数据不相等,就按照上述返回值规则得到返回值。如果比较完num对后,每一对字节都向相等,那么返回值就是 0。

         以下是具体的代码演示:

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>
#include <string.h>
int main()
{char buffer1[] = "DWgaOtP12df0";char buffer2[] = "DWGAOTP12DF0";int n;n = memcmp(buffer1, buffer2, sizeof(buffer1));if (n > 0)printf("'%s' is greater than '%s'.\n", buffer1, buffer2);else if (n < 0)printf("'%s' is less than '%s'.\n", buffer1, buffer2);elseprintf("'%s' is the same as '%s'.\n", buffer1, buffer2);return 0;
}

        在上面的程序中,因为在一定的比较字节内,指针 buffer1 指向的内存块小于指针 buffer2 指向的内存块,所以返回值小于 0,所以输出的结果如上图所示。

总结

        以上便是四个常用的内存函数,C语言的库函数里面还有几个内存函数,只要根据本篇文章的认识逻辑:先分析参数与返回值,得到具体的作用,在结合例子分析,剩下的内存函数也可以轻松掌握。


http://www.mrgr.cn/news/95073.html

相关文章:

  • 动平衡仿真程序设计
  • 【链表】一文搞定链表算法:从基础到实战
  • 【PCB工艺】电流、电压与电阻的关系 以及 含有电容和电感的电路
  • JavaScript 金额运算精度丢失问题及解决方案
  • Can通信流程
  • vector容器以及deque
  • 指令系统1(数据传输指令)
  • java面试题,什么是动态代理?、动态代理和静态代理有什么区别?说一下反射机制?JDK Proxy 和 CGLib 有什么区别?动态代理的底层
  • Windows 图形显示驱动开发-WDDM 3.0功能- 硬件翻转队列(五)
  • 876.链表的中间节点
  • 图莫斯TOOMOSS上位机TCANLINPro使用CAN UDS功能时 编写、加载27服务dll解锁算法文件
  • 霍尔传感器与电流互感器的区别
  • 别让时光溜走!Kairos App 帮你抓住每一刻
  • SpringBoot3+Vue3实战(Vue3快速开发登录注册页面并对接后端接口)(4)
  • Lombok常用注解
  • 男女搭配(数学思维)
  • YOLO魔改之频率分割模块(FDM)
  • stm32第七天震动传感器
  • 【模拟】从 0 到 1:模拟算法的深度剖析与实战指南
  • python实现接口自动化