目录
[1. memcpy函数的使用与模拟](#1. memcpy函数的使用与模拟)
[2. memmove函数的使用与模拟](#2. memmove函数的使用与模拟)
[3. memset函数的使用](#3. memset函数的使用)
[4. memcmp函数的使用](#4. memcmp函数的使用)
[5. memchr函数的使用](#5. memchr函数的使用)
前言:C语言内存函数是一组用于直接操作计算机内存的内置函数。使用时要包含头文件**<string.h>**
1. memcpy函数的使用与模拟
函数原型:
void * memcpy ( void * destination, const void * source, size_t num );
(适用于所有数据类型)
使用规则:
- 复制source所指向的内存数据到内存块destination中。(destination和source是两个内存块的首地址)
- 复制的数据量是num个字节。
- 该函数不会检查source中是否有终止字符\0,它始终精确复制 num 个字节。
- 所以num尽量不要超过source的内存大小,避免越界访问。
- source和destination的内存块不能有重叠,复制的结果都是未定义的。
memcpy函数的模拟实现:
cpp
void* my_memcpy(void* dest, const void* src, size_t num) //内存数据复制函数
{
for (int i = 0; i < num; i++)
{
*((char*)dest + i) = *((char*)src + i);
}
return dest;
}
解析:
- 因为dest与src都是void*型的指针,在进行"指针+-整数"操作时要先进行强制类型转换。
- 因为num代表的是字节数,所以要强制转换成char*(char的大小是1个字节)
模拟函数的代码验证:
cpp
void test(void)
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10];
my_memcpy(arr2, arr1, 7 * sizeof(int));
}
my_memcpy前arr2内部的数据如下:
my_memcpy运行后:
2. memmove函数的使用与模拟
函数原型:
void * memmove ( void * destination, const void * source, size_t num );
(适用于所有数据类型)
使用规则:
- 把source内存块的数据向destination移动复制
- 向左(或向右)移动,移动的距离是(dest - src)的绝对值
- 复制的规则与memcpy一样,但在memmove函数中,源内存块和目标内存块是可以重叠的。
- 如果两个内存块是重叠的,dest内存块的数据被source的数据覆盖。
memmove函数的模拟实现:
cpp
void* my_memmove(void* dest, const void* src, size_t num) //8.内存块移动复制(移动的格数是dest-src的绝对值)
{
if (dest > src && dest < (char*)src + num) //情况1:dest位于内存块(src,src+num)中,即dest的值属于该区间
{
//从右往左复制
for (int i = num - 1; i >= 0; i--)
{
*((char*)dest + i) = *((char*)src + i);
}
}
else //情况2:dest位于内存块外,即dest < src或dest > src+num(等于的话两种方向都可以,这里我放在了从左往右)
{
//从左往右复制
for (int i = 0; i < num; i++)
{
*((char*)dest + i) = *((char*)src + i);
}
}
return dest;
}
解析:
- 当dest位于区间src与src+num之间时(情况1):如果是从左往右复制,因为是dest和src都是对同一个数组进行操作,左边被覆盖过的数据 会再次被用来 覆盖右边的数据。所以要从右往左复制。
- 当dest位于src左边,且内存块重叠时(情况2):同理,为了避免重复覆盖,要从左往右复制。
- 当dest位于src左边,但内存块无重叠时(情况3):怎样复制都可以。
- 当dest位于src右边(情况4:也没有重叠):怎样复制都可以。
- 当dest等于src时:怎样复制都可以。
模拟函数的代码验证:
cpp
void test(void)
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1+3, arr1 , 5 * sizeof(int));
}
my_memove运行前:
运行后:
3. memset函数的使用
函数原型:
void * memset ( void * ptr, int value, size_t num );
(适用于所有数据类型)
使用规则:
- memset是内存块初始化函数。
- memset可以把ptr指向的内存块中的num个字节都初始化为value。
- 因为是对每个字节进行初始化,所以value的有效范围是-128~127。
- memset常用来把数据初始化为0。
我们把两个整型数组分别用memset初始化为"0"和"1"会怎么样?
cpp
void test(void)
{
int arr1[5];
int arr2[5];
memset(arr1, 0, 5*sizeof(int));
memset(arr2, 1, 5 * sizeof(int));
}
为什么value设成1,初始化结果是16843009 ?
因为memset是把每个字节都设置成value。
(1)当value为0时,这里40个字节的二进制数据是:
00000000 00000000 00000000 00000000 00000000 ......
int型的数据读取4个字节,即00000000 00000000 00000000 00000000,也就是十进制的0。
(2)当value为1时,这里40个字节的二进制数据是:
00000001 00000001 00000001 00000001 00000001 ......
int型的数据读取4个字节,即00000001 00000001 00000001 00000001,也就是十进制的16843009
所以memset常用来把数据初始化为0.
4. memcmp函数的使用
函数原型:
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
(适用于所有数据类型)
使用规则:
- 该函数与strncmp函数的使用方法一样,但适用于所有数据类型。
- memcmp比较内存块中前num个字节的大小。
- 与strncmp和strcmp 不同的是,该函数在找到字符\0后不会停止比较。
5. memchr函数的使用
函数原型:
const void* memchr(const void* ptr, int value, size_t num);
(常用于字符串)
使用规则:
- 主要用于在给定的内存区域ptr内查找指定的字符。
- 在内存块的前num个字节寻找字符value。(可以当作strnchr函数,虽然没有这个函数)
本期分享完毕,感谢大家的支持Thanks♪(・ω・)ノ