内存操作函数介绍及其模拟实现
文章目录:
- memcpy
- memmove
- memset
- memcmp
前言:
- 字符串函数对于字符串的很多的操作都提供了很多的方便之处,但其只适用于字符串,而内存操作函数便由此提出。
- 内存操作函数,通过访问地址的方式来访问相应的对象,其并不关心存储对象的
类型,可应用于所有类型的对象。- 对于字符串类型的相应函数,可参考文章:字符串函数介绍及其模拟实现
编译环境:vs2013
一、memcpy
void* memcpy ( void* destination, const void* source, size_t num );
- 作用:将num字节数的值从源指针指向的位置直接复制到目标指向的内存块。
- 返回:返回目标指针指向的字符串。
- 源指针和目标指针指向的对象的基础类型与此函数无关,结果是数据的二进制副本。
- 该函数不检查源指针中的任何终止空字符 ,它总是准确地复制字节数。
- 为避免溢出,目标和源参数指向的数组大小应至少为字节数,并且不应重叠(对于重叠的内存块,memmove 是一种更安全的方法)。
memcpy模拟实现及测试:
//1.memcpy 在src指向的空间拷贝num字节的数据到dest指向的空间中,不允许重叠
void* my_memcpy(void* dest, const void* src, size_t num)
{
void* temp = dest;
//断言:两空间都不为空,为空则报错返回
assert(dest != NULL);
assert(src != NULL);
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return temp;
}
//my_memcpy测试函数
void test_my_memcpy()
{
char* str1[10] = { 0 };
char* str2 = "mbcd---";
char* ret = my_memcpy(str1, str2, strlen(str2));
printf("%s\n", ret);
}
而当我们对自身进行元素拷贝时程序出现错误。
char* ret = my_memcpy(str2, str2 + 2, 2);
故:memcpy函数在对自身进行拷贝覆盖时并不能实现,由此提出memmove函数,功能同memcpy且可对自身进行拷贝覆盖。
二、memmove
void* memmove ( void* destination, const void* source, size_t num );
- 作用:将num字节数的值从源指向的空间位置复制到目标指向的内存块。复制就像使用了中间缓冲区一样,允许目标和源重叠。
- 返回:返回目标指针指向的字符串。
- 源指针和目标指针指向的对象的基础类型与此函数无关,结果是数据的二进制副本。
- 该函数不检查源中的任何终止空字符 ,它总是准确地复制字节数。
- 为避免溢出,目标参数和源参数指向的数组的大小应至少为字节数。
1 不考虑两空间产生覆盖,处理同memcpy。
2 考虑两空间产生覆盖时。
memmove模拟实现及测试:
//2.memmove 将src指向的空间前num个字节的数据拷贝到dest指向的空间中,允许重叠
void* my_memmove(void* dest, const void* src, size_t num)
{
assert(dest != NULL);
assert(src != NULL);
void* temp = dest;
if (dest <= src || (char*)dest >= ((char*)src+num))
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
dest = (char*)dest + num - 1;
src = (char*)src + num - 1;
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest - 1;
src = (char*)src - 1;
}
}
return temp;
}
//my_memmove测试函数
void test_my_memmove()
{
char str[]= "abcdefgh";
//char* ret1 = my_memmove(str + 1, str + 5, 3);
//printf("%s\n", ret1);
//char* ret2 = my_memmove(str + 5, str + 1, 3);
//printf("%s\n", ret2);
//char* ret3 = my_memmove(str + 1, str + 3, 4);
//printf("%s\n", ret3);
char* ret4 = my_memmove(str + 3, str + 1, 4);
printf("%s\n", ret4);
}
三、memset
void* memset ( void* ptr, int value, size_t num );
- 作用:将 ptr 指向的内存块的前num个字节数设置为指定值并返回ptr,常用于数据初始化。
- 返回:返回ptr指针。
- ptr:指向要填充内存块的指针。
- value:要设置的值,该值作为 int 传递,但该函数使用此值的无符号 char 转换填充内存块。
- num:要设置为该值的字节数。
memset模拟实现及测试:
//3.memset 将ptr中前num个字节用value填充,并返回ptr
void* my_memset(void* ptr, int value, size_t num)
{
assert(ptr != NULL);
void* temp = ptr;
while(num--)
{
*(char*)ptr = value;
ptr = (char*)ptr + 1;
}
return temp;
}
//my_memset测试函数
void test_my_memset()
{
char str[]= "abcdef";
char* ret = my_memset(str, '*', 3);
printf("%s\n", ret);
}
四、memcmp
int memcmp ( const void* ptr1, const void* ptr2, size_t num );
- 作用:比较两内存块,将两指针指向的前num个字节进行一一比较。
- 返回:
- ptr1>ptr2,返回一大于0的数;
- ptr1=ptr2,返回0;
- ptr1<ptr2,返回一个小于0的数。
注意,与 strcmp 不同地方为,memcmp在找到空字符后并不会停止比较.。
memcmp模拟实现及测试:
//4.memcmp ptr1与ptr2的前num个字节数据进行比较
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
assert(ptr1);
assert(ptr2);
char* temp1 = (char*)ptr1;
char* temp2 = (char*)ptr2;
while (num--)
{
if (*temp1 == *temp2)
{
temp1++;
temp2++;
}
else
{
if (*temp1 > *temp2)
return 1;
else
return -1;
}
}
return 0;
}
//my_memcmp测试函数
void test_my_memcmp()
{
char* str1 = "ab";
char* str2 = "abcdef";
int n1 = my_memcmp(str1, str2, 2);
if (n1 > 0)
printf("str1>str2\n");
else if (n1 < 0)
printf("str1<str2\n");
else
printf("str1=str2\n");
}