内存函数
1.什么是内存函数
就是一些能操作计算机内存的C语言内置函数。相比于本文介绍的memcpy,memmove,memcmp,memset
我们更熟悉strcpy,strcmp
这两个字符串函数,但是字符串函数的限制非常大,只能在使用字符串时使用(关注’\0’),而memcpy,memmove,memcmp,memset
这四个函数可以面对任意类型的数据,没有字符串结束符的限制。
2.1 memcpy与memmove
函数定义
void * memcpy ( void * destination, const void * source, size_t num );
void * memmove ( void * destination, const void * source, size_t num );
//destination目标地址
//source起始地址
//size_t(unsigned int)字节个数
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
函数memmove从source后num-1个字节位置开始向前复制num个字节的数据到destination的内存位置
这个函数在遇到 ‘\0’ 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
该函数的返回的是一个void *类型的指针,也就是destination的初值。
注意事项
对于memcpy与memmove两个函数要注意num的值,不能使它在使用指针访问空间时,发生越界访问。
函数模拟
void* memcpy(void* destination, const void* source, size_t num)
{
assert(destination && source);//断言,判断是否为空<assert.h>
for (int i = 0; i < num; i++)//复制num个字节的数据给destination
{
*((char*)destination + i) = *((char*)source + i);
//由于是void*类型的指针且为destination赋值时是一个字节一个字节的复制
//所以这里强制类型转换为char*类型
}
return destination;//返回destination的起始地址
}
void* memmove(void* destination, const void* source, size_t num)
{
assert(destination && source);//断言,判断是否为空
while (num)//num=0时为假,while结束循环
{
*((char*)destination + num - 1) = *((char*)source + num - 1);
//从num-1位至第0位总共有num个字节
//同memcpy逐字节复制,由后向前
num--;
}
return destination;
}
2.2memset
函数定义
void * memset ( void * ptr, int value, size_t num );
函数memset从ptr开始逐字节的赋值为value,复制num个字节。
返回ptr的初值。
/* memset example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "almost every programmer should know memset!";
memset (str,'-',6);
puts (str);
return 0;
}
注意事项
1.int类型数组初始化可以控制的只有****0或**-1**.
由于函数memset使用时是逐字节赋值的,所以value会发生截断,使其仅保留八位bit位。只有在对赋值为0或-1时才能控制其数值(-1截断后为11111111,0截断后为00000000,故在赋值时可以为全0或全1)
2.注意赋值时的元素类型
由于数据的元素类型不同,所以在设定value的值时要注意元素类性。
对于char类型,char中的字符储存在内存中是该字符所对应的Ascll值,所以在对char型赋值时value的值最好是字符型
char a = '0';//Ascll 48->00110000
int b = 1;
memset(&a, '1', sizeof(char));//Ascll 49->00110001
memset(&b, 0, sizeof(int));
函数模拟
void* memset(void* ptr, int value, size_t num)
{
assert(ptr);//断言,判断是否为空<assert.h>
for (int i = 0; i < num; i++)//复制num个
{
*((char*)ptr + i) = value;
//逐字节复制
}
return ptr;//返回初始地址
}
2.3memcmp
函数定义
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
比较ptr1与ptr2中的前num个字节。
与strcmp较为相似,自第一个字节开始开始比较
两个内存块完全相等,函数memcmp返回0
两个内存块中不匹配的第一个字节在ptr1 中的值大于在 ptr2 中的值返回一个大于0的数
两个内存块中不匹配的第一个字节在ptr1 中的值小于在 ptr2 中的值返回一个小于0的数
注意事项
对于memcmp()不会在’\0‘处停下来,会继续比较’\0‘后面的内存单元,所以要注意不要让num的值大于ptr1与ptr2的长度,否则结果有可能是错误的。
函数模拟
int mem(const void* ptr1, const void* ptr2, size_t num)
{
assert(ptr1 && ptr2);
for (int i = 0; i < num; i++)
{
if (*((char*)ptr1 + i) > *((char*)ptr2 + i))
return 1;
if (*((char*)ptr1 + i) < *((char*)ptr2 + i))
return -1;
}
return 0;
}
总结
1.对于函数memcpy、memmove、memcmp、memset
在使用时引用头文件<string.h>,都需要注意num的值防止造成越界访问。
2.memcpy、memmove、memset
返回值都是目标的起始地址。