一、memcpy函数
1、C 标准库 - <string.h>
2、函数描述
void * memcpy ( void * destination, const void * source, size_t num );
函数memcpy从 source 的位置复制 num 个字节到存储区 destination。
3、代码示例
#include <stdio.h>
#include <string.h>
struct {
char name[40];
int age;
} person, person_copy;
int main ()
{
char myname[] = "zhangsan";
/* using memcpy to copy string: */
memcpy ( person.name, myname, strlen(myname)+1 );
person.age = 23;
/* using memcpy to copy structure: */
memcpy ( &person_copy, &person, sizeof(person) );
printf ("person_copy: %s, %d \n", person_copy.name, person_copy.age );
return 0;
}
4、结果
5、注意事项
- memcpy函数在遇到 '\0' 的时候不会停止
- 如果source 和 destination 有重叠位置,复制后的结果可能与预期不同
二、memmove函数
1、C 标准库 - <string.h>
2、函数描述
void * memmove ( void * destination , const void * source , size_t num );
- 函数memcpy从 source 的位置复制 num 个字节到存储区 destination。
- 但是在重叠内存块这方面,memmove() 是比 memcpy() 更安全的方法。
- 如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同。
3、代码示例
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "memmove can be very useful......";
memmove (str+20,str+15,11);
puts (str);
return 0;
}
4、结果
5、注意事项
-
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
-
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
三、 模拟实现memcpy
原memcpy的函数声明是:
void * memcpy ( void * destination, const void * source, size_t num );
指针传过去是被认作void类型, 而且复制操作是按字节存储
所以使用指针时应先转换成char* 型,然后使用while循环依次复制
注意: 复制一个字节后不可直接对指针++,因为这时的指针仍是void*型,未定义+1跨过多少字节,所以要再次转换成char* ,进行++运算
可以是 ((char*)source)++;
也可以是source = (char*)source + 1;
#include <strdio.h>
#include <assert.h>
struct Student{
char name[20];
int age;
}person,person_copy;
void* mymemcpy(void * dest, const void* source, size_t num)
{
assert(dest && source);
char* first = (char*)dest;
while (num--)
{
*(char*)dest = *(char*)source;
((char*)source)++;
((char*)dest)++;
}
return first;
}
int main()
{
char myname[] = "zhangsan";
mymemcpy(person.name, myname, strlen(myname) + 1);
person.age = 23;
mymemcpy(&person_copy, &person, sizeof(person));
printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);
return 0;
}
四、模拟实现memmove
memmove主要用于目标区域和源区域有重叠的情况,要保证目标区域不会获得源区域被覆盖后的结果。
memmove的函数声明是:
void * memmove ( void * destination, const void * source, size_t num );
如图所示当source > dest 时,
结果为:
与预期相同,源区域覆盖的区域没有被使用
如图所示当source < dest 时,
结果为:
与预期的1 2 3 4 5 3 4 5 6 7 不同,源区域的6 7 两个元素被覆盖成3 4 并使用
但是
如果从后向前依次复制,则不会出现这种情况
结果为:
这时,源区域的6 7 两个元素依旧被覆盖成3 4 ,但并未使用
所以得出结论:
当地址source > dest 时,从前往后复制,source < dest 时,需要从后往前复制
(source > dest+num 和 source + num < dest 这两种情况从后向前和从前向后都可以,因为源区域 和 目标区域 都没有被覆盖)
#include <stdio.h>
#include <assert.h>
void* my_memmove(void* dest, const void* source, size_t num)
{
assert(dest && source);
char* first = (char*)dest;
if ((unsigned int)dest < (unsigned int)source)
{
while (num--)
{
*(char*)dest = *(char*)source;
((char*)source)++;
((char*)dest)++;
}
}
else
{
while (num--)
{
*((char*)dest + num ) = *((char*)source + num);
}
}
return first;
}
int main()
{
char str[] = "memmove can be very useful......";
my_memmove(str + 20, str + 15, 11);
puts(str);
return 0;
}