目录
函数介绍:
函数解析:
memcpy函数复制的数据长度
内存重叠
凑不出元素的字节数
模拟memcpy
函数介绍:
memcpy函数是一个用于内存复制的函数,声明在 string.h 中(C++是 cstring)。
其原型是:
void * memcpy ( void * destination, const void * source, size_t num );
作用是:以source指向的地址为起点,将连续的n个字节数据,复制到以destin指向的地址为起点的内存中。
函数有三个参数,第一个是目标地址,第二个是源地址,第三个是数据长度。
使用memcpy函数时,需要注意:
- 数据长度(第三个参数)的单位是字节。
- 注意该函数有一个返回值,类型是void*,是一个指向destin的指针。
- 这个函数在遇到 '\0' 的时候并不会停下来。
- 如果source和destination有任何的重叠,复制的结果都是未定义的。
函数解析:
- memcpy拷贝的是空间 ,也就是字节数(1byte = 8bit)。
- 使用的原理与strncpy类似,但还是有不同之处,列如:最后的参数不同,strncpy最后的num表示的是宽度,而memcpy表示的是字节数。
- 以及,memcpy的前两个参数的类型是void* 表示memcpy可以调整任意类型的内存,或是说任意类型可以使用它。
memcpy函数复制的数据长度
int arr1[] = { 1, 2, 3, 4, 5, 6, 7 };
int arr2[10] = { 0 };
memcpy(arr2,arr1,28);
使用memcpy函数时,特别要注意数据长度。如果复制的数据类型是char,那么数据长度就等于元素的个数。而如果数据类型是其他(如int, double, 自定义结构体等),就要特别注意数据长度的值。
不过,无论拷贝何种数据类型,都用
n * sizeof(type_name)
的写法。
char a[10] = "abcdefgh";
unsigned n = 2;
void * p = memcpy(a+3, a, n);
以上代码将从a开始的两个字节的数据(即’a’和’b’),复制到从a+3开始的内存('d’所在的地址)。这样,'d’和’e’被替换。执行结束之后,字符数组(字符串)a的内容变为"abcabfgh"。
内存重叠
int arr1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
memcpy(arr1+2,arr1,20);
以上代码将1开始的20个字节复制到arr1+2开始的内存,也就是从arr[2]开始的20个字节。这样原先的内容变为了,{1,2,1,2,3,4,5,8,9,10}
但真的是这样吗?
通过上图,我们得知,因为20个字节数,我们需要复制的元素包含了1、2、3、4、5,而又因为arr1+2所在位置表示的元素是3,因在复制的过程中元素3被覆盖了,变为了元素1,元素4也是如此被覆盖成了元素2,因而当进行后续复制时,得到的结果与我们想象中的结果发生了偏移。
凑不出元素的字节数
int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
unsigned n = 5;
void * p = memcpy(a+3, a, n);
以上代码将从a开始的5个字节的数据复制。
5个字节的数据是什么呢?前四个字节组成了一个完整的int(即第一个元素0),int类型的长度是4个字节。
第五个字节,只能取到第二个元素的第1个字节。这里又会涉及小端方式储存,那么读到的是元素1的低8位,写成十六进制即0x1。
注:这里的存储单元是指二进制形式
由于目标地址是a+3。而因为a+3 = &a[3],所以只的是下标为3的元素,也就是元素3被替换为0。元素4写成十六进制是0x0004,低8位被替换为0x1,变为0x0001。
所以执行结束之后,数组a的内容变为 { 0, 1, 2, 0, 1, 5, 6, 7, 8, 9 }
模拟memcpy
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
while (num--)//进行一个字节一个字节的拷贝复制
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr1[] = { 1, 2, 3, 4, 5, 6, 7 };
int arr2[10] = { 0 };
my_memcpy(arr2,arr1,28);
return 0;
}
注:两个参数强制转化为char*类型是为了一个字节一个字节的进行拷贝复制,因为char*的数据特点和长度是1字节的原理,所以在此处更为合适使用!