memset
memset把一段内存全部填成某个值。
函数原型:
void* memset (void* ptr, int value, size_t num);
//使用
#include <cstring>
char str[] = "hello world";
memset(str, 'x', 6);
模拟实现:
void* my_memset(void* ptr, int value, size_t num)
{
unsigned char* p = (unsigned char*)ptr;
while (num--)
{
*p = (unsigned char)value;
++p;
}
return ptr;
}
void*不能直接操作,所以要先转换类型
标准库实现通常不做空指针检查,以保证性能,如果传入nullptr,属于未定义行为(UB)
memset对一个对象进行操作会导致什么问题?
memset是按字节直接覆盖内存的操作,会破坏对象的结构,对象不仅包含成员变量,还可能包含编译器插入的内部结构,比如虚函数表指针vptr,此外,C++对象还具有语义上的不变量,这些通常由构造函数维护,memset会直接覆盖掉虚函数表指针、构造函数设置的成员变量值,可能会导致内存泄漏(如果对象成员函数包含指针)、对象语义彻底破坏。
memcpy
memcpy从src的位置开始向后复制Num个字节的数据到dst指向的内存位置。 函数原型:
void * memcpy ( void* destination, const void* source, size_t num );
//使用:
int arr1[] = {1,2,3,4,5,6,7,8,9,10};
int arr2[10] = {0};
memcpy(arr2, arr1, 20); //遇到\0并不会停下来
模拟实现:
void* my_memcpy(void* destination, const void* source, size_t num)
{
unsigned char* d = (unsigned char*)destination;
const unsigned char* s = (const unsigned char*)source;
while (num--)
{
*d = *s;
++d, ++s;
}
return destination;
}
如果内存重叠,数据会被覆盖,memcpy不处理重叠,如果发生重叠属于未定义行为。
由memmove来解决内存重叠,它会根据地址关系选择拷贝方向
memmove
memmove和memcpy的差别就是memmove处理的源内存块和目标内存块是可以重叠的。 函数原型:
void * memmove ( void* destination, const void* source, size_t num );
//使用:
int arr1 = {1,2,3,4,5,6,7,8,9,10};
memmove(arr1+2, arr1, 20);
模拟实现:
void* my_memmove(void* destination, const void* source, size_t num)
{
if (destination == source || num == 0) return destination; //防止后面+=num - 1 错误
unsigned char* d = (unsigned char*)destination;
const unsigned char* s = (const unsigned char*)source;
//判断dst和src的相对位置来进行过特殊处理
if (d > s && d < s + count) //需要从后向前拷贝
{
d += num - 1;
s += num - 1;
while (num--)
{
*d = *s;
--d, --s;
}
}
else
{
while (num--)
{
*d = *s;
++d, ++s;
}
}
return destination;
}
memcmp
memcmp逐字节比较两块内存,相同返回0,不同返回差值(第一个不同字节的差值) 函数原型:
int memcmp ( const void* ptr1, const void* ptr2, size_t num );
//使用
char buffer1[] = "DWgaOtp12df0";
char buffer2[] = "DWGAoTP12DF0";
int n = 0;
n = memcmp(buffer1, buffer2, sizeof(buffer1));
模拟实现:
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
const unsigned char* p1 = (const unsigned char*)ptr1;
const unsigned char* p2 = (const unsigned char*)ptr2;
while (num--)
{
if (*p1 != *p2) return *p1 - *p2;
++p1, ++p2;
}
return 0;
}