C语言的内存函数
目录
一、memcpy函数
二、memmove函数
三、memset 函数
四、memcmp 函数
总结
C语言库函数中有可以直接对内存操作的函数,这类函数叫作内存函数。
内存函数即针对内存块进行数据处理的函数,内存块的意思就是“一块内存,一块空间”。
在日常编程,我们常用的内存函数有四个,分别是:memcpy、memmove、memset、memcmp。它们都有一个共同的前缀“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语言的库函数里面还有几个内存函数,只要根据本篇文章的认识逻辑:先分析参数与返回值,得到具体的作用,在结合例子分析,剩下的内存函数也可以轻松掌握。