memcpy需要注意的坑

题记:今天看到一道memcpy的题,差点栽了,赶快来记录一下

首先是函数原型:

void * memcpy ( void * destination, const void * source, size_t num );
@destination:目的地址
@source:源地址
@num:字节数
将source指向的地址处的num个字节拷贝到 destination 指向的地址处

注意是这里最后一个参数是字节数

首先来看一道题

int main() {
	int a[10] = { 0,1,2,3,4,5,6,7,8,9 };
	memcpy(a, a + 3, 2);
	for (int i = 0; i<10; i++){
		printf("%d ", a[i]);
	}
	return 0;
}

看看运行结果。
是不是以为结果是:3,4,2,3,4,5,6,7,8,9
其实答案是:3,1,2,3,4,5,6,7,8,9

因为最后一个参数2是两个字节,一个int是4个字节,所以只拷贝了3这个数字的低两个字节。
如果想要拷贝两个元素的话需要作如下修改:

memcpy(a , a+3 , 2 * sizeof(int));

这样结果就是3,4,2,3,4,5,6,7,8,9

还有一个需要注意的是内存重叠

比如下面这段程序

int main() {
	int a[10] = { 0,1,2,3,4,5,6,7,8,9 };
	memcpy( a+3 , a , 4 * sizeof(int) );
	for (int i = 0; i<10; i++){
		printf("%d ", a[i]);
	}
	return 0;
}

你以为输出会是这样的 0,1,2,0,1,2,3,7,8,9

你又错了!

结果是0,1,2,0,1,2,0,7,8,9
这是因为原地址和目的地址这两段有重叠,导致了如上的输出结果

通过memmove可以避免这一问题。memmove和memcpy实现一样的功能:内存拷贝。原型如下:

void *memmove(void *dest, const void *src, size_t count)

看一下linux的源码就知道了

/**
 * memcpy - Copy one area of memory to another
 * @dest: Where to copy to
 * @src: Where to copy from
 * @count: The size of the area.
 *
 * You should not use this function to access IO space, use memcpy_toio()
 * or memcpy_fromio() instead.
 */
void *memcpy(void *dest, const void *src, size_t count)
{
	char *tmp = dest;
	const char *s = src;

	while (count--)
		*tmp++ = *s++;
	return dest;
}

/**
 * memmove - Copy one area of memory to another
 * @dest: Where to copy to
 * @src: Where to copy from
 * @count: The size of the area.
 *
 * Unlike memcpy(), memmove() copes with overlapping areas.
 */
void *memmove(void *dest, const void *src, size_t count)
{
	char *tmp;
	const char *s;

	if (dest <= src) {
		tmp = dest;
		s = src;
		while (count--)
			*tmp++ = *s++;
	} else {
		tmp = dest;
		tmp += count;
		s = src;
		s += count;
		while (count--)
			*--tmp = *--s;
	}
	return dest;
}

但是现在的memcpy已经做了改进,及时存在内存重叠也不会出现上述情况了。

PS:上面的思路都是个人的观点,如果有哪里错误的,希望大家评论区留言指正,我每条评论都回去回复的^ - ^

你可能感兴趣的:(C++)