memory
n.记忆力,记性;记忆,回忆;(计算机存储器的)存储量;(计算机的)存储器;对死者的记忆;记忆所及的时间(或范围)。
什么是C语言内存函数呢?
C语言内存函数是指对内存空间块的数据进行操作的函数,都在string.h这个头文件里,下面我们为大家介绍以下4个内存函数:
|---------|---------------------------------|
| 函数 | 作用 |
| memcpy | 拷贝源内存块的n个字节的数据到目标内存块,空间不可重叠 |
| memmove | 拷贝源内存块的n个字节的数据到目标内存块,空间可重叠 |
| memset | 对目标内存块的n个字节进行设置 |
| memcmp | 比较两个内存块对应的数据 |
1.memcpy函数
(1).函数定义
cpp
void * memcpy ( void * destination, const void * source, size_t num );
- void* destination 目标空间的地址,目标空间数据类型位置,使得指针类型未知,故而都使用void*类型适用任何类型数据。
- const void * source 源空间的地址,只对源空间的数据做拷贝不做修改,故const
- void* 返回void*类型的地址是由于目标空间的指针类型未知。
- size_t num 无符号类型的num,拷贝字节的大小/数量
(2).函数作用
- 从source所指向的位置开始拷贝num个字节的数据到destination所指向的空间里。
- 使用memcpy函数时,source所指向的空间与destination所指向的空间不可重叠。
- 为了避免溢出,目的参数和源参数所指向的数组的大小至少为num字节。
(3).函数使用
(4).模拟实现
cpp
void* my_memcpy(void* p1, const void* p2, size_t num)
{
//memcpy不拷贝重叠空间的数据,就当作两个独立空间处理
void* ret = p1;
while (num)//拷贝num次
{
//(char*)p1++;
//((char*)p1)++;//为啥加个括号p1就从void*转为char*
*(char*)p1 = *(char*)p2;//void*不能操作,转char*一个字节地拷贝
//强制类型转换只是对数据的类型转换,不会对变量本身转换,p1本身还是void*
((char*)p1)++;
((char*)p2)++;
num--;
}
return ret;//返回目标空间的地址
}
测试
发现问题:(char*)p1++和((char*)p)++的区别
|------|--------|-----|
| 操作符 | 含义 | 优先级 |
| () | 括号 | 1 |
| ++ | 自加加 | 2 |
| (类型) | 强制类型转换 | 3 |
"(类型)"这个操作符的优先级比++低,不加括号++会先与p结合 ,而p是void*类型,不能被操作,所以要再加括号保证强制类型转换的优先级比++高,先将void*转为char*,就可以++操作了
2.memmove函数
(1).函数定义
cpp
void * memmove ( void * destination, const void * source, size_t num );
- void* destination 目标空间的地址,目标空间数据类型位置,使得指针类型未知,故而都使用void*类型适用任何类型数据。
- const void * source 源空间的地址,只对源空间的数据做拷贝不做修改,故const
- void* 返回void*类型的地址是由于目标空间的指针类型未知。
- size_t num 无符号类型的num,拷贝字节的大小/数量
(2).函数作用
- 从source所指向的位置开始拷贝num个字节的数据到destination所指向的空间里。
- 使用memcpy函数时,source所指向的空间与destination所指向的空间可重叠。
- 为了避免溢出,目的参数和源参数所指向的数组的大小至少为num字节。
(3).函数使用
(4).模拟实现
分析:
cpp
void* my_memmove(void* p1, const void* p2, size_t num)
{
if(p1==p2)//相等的话,直接返回p1的地址
return p1;
char* ret = p1;
//重叠部分先拷贝,就能防止拷贝数据被改变
if(p1 < p2)//重叠部分在源空间的前部分,从前向后拷贝
{
while (num)
{
*(char*)p1 = *(char*)p2;
((char*)p1)++;
((char*)p2)++;
num--;
}
}
if (p1 >= p2)//重叠部分在源空间的后部分,从后向前拷贝
{
while (num)
{
*((char*)p1+num) = *((char*)p2+num);
num--;
}
}
//独立的话随便,这里已经满足了,p1在前就向上面一样用前->后,在后就向上面一样用后->前。
return ret;
}
测试
3.memset函数
(1).函数定义
cpp
void * memset ( void * ptr, int value, size_t num );
- void* ptr 需要填充数据的内存空间的地址,由于数据类型未知,使得指针类型未知,故而都使用void*类型适用任何类型数据。
- int value value为需要填充数据的值,int类型进行接受传递,在函数中int的数据会转换为unsigned char类型的数据进行填充,因为每次填充内存单元,所以都是一个字节的大小的数据。
- 其实value接收的就是字符的ASCII码值
- size_t num 无符号类型的num,填充数据的大小/数量。
- void* 函数返回的是ptr一开始指向空间的起始地址。
(2).函数作用
从ptr所指向的内存空间开始依次向后填充num个value值。
(3).函数使用
(4).模拟实现
cpp
void* my_memset(void* ptr, int value, size_t num)
{
char* ret = ptr;//返回的起始地址
while (num--)//进行num次填充
{
*((char*)ptr)++ = (unsigned char)value;//要把int类型的数据转unsigned char类型再赋值,再++
}
return ret;
}
4.memcmp函数
(1).函数定义
cpp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
- ptr1和ptr2两个指针都是用于比较的,不会被修改的,所以用const修饰,以免出现书写错误,void*是不知道内存空间的数据类型,进而不知道指针类型,所以用void*接收。
- 比较的时候是一个内存单元地比较,就是一个字节地比较。
- size_t num 比较num个字节/内存单元 。
- int 返回类型为int,满足的条件为:
(2).函数作用
- 比较两个指针所指向的内存块里的内容,是一个字节地对比。
- 和strcmp函数不同的是,memcmp不会因为检测到'\0'就结束比较。
(3).函数使用
(4).模拟实现
cpp
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
while (*((char*)ptr1)==*((char*)ptr2))//相等就继续判断
{
if (num == 0)//如果num次都判断完了,那么就返回0
return 0;
num--;
((char*)ptr1)++;
((char*)ptr2)++;
}
return (int)(*(char*)ptr1 - *(char*)ptr2);//找到不相等的就返回差值
}
本章内容结束,下章见,拜拜!!!