本文主要介绍memcpy(),memmove(),memset三个函数的使用方法,内部实现细节,注意事项。
1.memcpy()
函数功能:从存储区 src 复制 count 个字节到存储区 dest。
函数声明:
void *memcpy( void *dest, const void *src, size_t count );
参数分析:
dest ---> 指向用于存储复制内容的目标数组(存储区地址),类型强制转换为 void* 指针。
src---->指向要复制的数据源(数据源地址),类型强制转换为 void* 指针。
count----->代表要拷贝的字节个数
size_t
这是无符号整数类型,它是 sizeof 关键字的结果。
返回值:
该函数返回一个指向目标存储区 dest 的指针。
实例演示:
int main() {
int arr1[] = { 1,2,3,4,5 };
int arr2[5] = { 0 };
memcpy(arr2, arr1, sizeof(arr1));
int i = 0;
for (i = 0; i < 5; i++) {
printf("%d ", arr2[i]);
}
return 0;
}
运行结果:
可以看到,其中内容拷贝成功。
memcp()函数源码:
void *memcpy(void *dst, const void *src, size_t count)
{
if(NULL == dst || NULL == src){
return NULL;
}
void *ret = dst;
if(dst <= src || (char *)dst >= (char *)src + count){
//没有内存重叠,从低地址开始复制
while(count--){
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
}else{
//有内存重叠,从高地址开始复制
src = (char *)src + count - 1;
dst = (char *)dst + count - 1;
while(count--){
*(char *)dst = *(char *)src;
dst = (char *)dst - 1;
src = (char *)src - 1;
}
}
return ret;
}
这里面值得注意的是,memcpy函数按照C语言标准其实是不用考虑内存重叠的情况的,但是在上面的源码中我们包含了有内存重叠的情况。
2.memmove()
C 库函数 void *memmove(void *str1, const void *str2, size_t n) 从 str2 复制 n 个字符到 str1,但是在重叠内存块这方面,memmove() 是比 memcpy() 更安全的方法。如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同。
函数声明:
void *memmove( void *dest, const void *src, size_t count );
参数含义:
- dest -- 指向用于存储复制内容的目标数组(目的地址),类型强制转换为 void* 指针。
- src -- 指向要复制的数据源(源头地址),类型强制转换为 void* 指针。
- count -- 要被复制的字节数。
演示:
int main() {
int arr1[] = { 1,2,3,4,5,6 };
int arr2[] = { 2,3,4,5,6,7 };
memmove(arr1, arr1 + 2, sizeof(arr1[1])*2);
for (int i = 0; i < 6; i++) {
printf("%d ,",arr1[i]);
}
return 0;
}
可以看到,对于重叠的内存区域也会进行正确的拷贝。
源码:
void* memmove(void* dst,const void* src,size_t count)
{
void* ret = dst;
//dst <= src表示,如果dst在src的前面,从前往后复制不会覆盖src中还没有复制的内容
if (dst <= src || (char*)dst >= ((char*)src + count))
{
//从前往后复制,则不会出现覆盖src中没有复制的内容
while(count--)
{
*(char*)dst = *(char*)src; //char类型指针,表示一个字节一个字节的复制
dst = (char*)dst + 1; //移动一个字节
src = (char*)src + 1;
}
}
else
{
//从后往前复制,则不会出现覆盖src中没有复制的内容
dst = (char*)dst + count - 1;//移动到末尾
src = (char*)src + count - 1;
while(count--)
{
*(char*)dst = *(char*)src;
dst = (char*)dst - 1; //移动一个字节
src = (char*)src - 1;
}
}
//返回dst的头指针,还方便左值操作。
//如:ptstr = memmove(ptstr,src,count); cout << memmove(ptstr,src,count);
return ret;
}
3.memset()
C 库函数 void *memset(void *str, int c, size_t n) 复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符
函数声明:
void *memset( void *dest, int c, size_t count );
- dest -- 指向要填充的内存块(目的地址)。
- c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
- count -- 要被设置为该值的字符数。
演示:
int main() {
char arr[10] = { '0' };
memset(arr, '#', sizeof(arr));
for (int i = 0; i < 10; i++) {
printf("%c ", arr[i]);
}
return 0;
}
源码:
void *(memset) (void *s,int c,size_t n)
{
const unsigned char uc = c;
unsigned char *su;
for(su = s;0 < n;++su,--n)
*su = uc;
return s;
}
以上便是三个C语言库函数中的内存操作函数了,希望对你有所帮助。