C++面试题4:memcpy的用法
memcpy函数用于把资源内存(src所指向的内存区域)拷贝到目标内存(desk所指向的内存区域);拷贝多少个?有一个size变量控制
用法:可以拷贝任何类型的对象,因为函数的参数类型是void*
,也就是说传进去的实参可以是int
,
*short*
,char*
等等。
原型:void *memcpy(void *desc, void *src, unsigned int
count)
实现memcpy
void *memcpy(void *desc,const void *src,size_t size)
{
//非法输入
if(desc == NULL || src == NULL)
{
return 0;
}
//由于函数拷贝是一个字节一个字节拷贝的,所以要进行类型转换
unsigned char *desc1 = (unsigned char *)desc;
unsigned char *src1 = (unsigned char *)src;
while(size--)
{
*desc1=*src1;
desc1++;
src1++;
}
return desc;
}
这个程序不足的地方在于没有考虑覆盖重叠的情况。如果desc>src但是src+count>desc,我们这个时候复制就一定要注意了。
准确代码.cppvoid *memcpy(void *desc,const void *src, size_t size)
{
//非法输入
if(desc == NULL || src == NULL)
{
return 0;
}
unsigned char *desc1 = (unsigned char *)desc;
unsigned char *src1 = (unsigned char *)src;
if(desc1 > src1 && src1 + size > desc)
{
for(size_t i = size-1; i >= 0; i--)
{
desc1[i]=src1[i];
}
}
else
{
for(size_t i = 0; i < n; i++)
{
desc1[i]=src1[i];
}
}
return desc;
}
《编写高质量代码:改善C++程序的150个建议》建议20:使用memcpy()系列函数一定要足够小心
memcpy()、memset()、memcmp()等这些内存操作函数经常会帮我们完成一些数据复制、赋值等操作。因为在C语言中,无论是内置类型,还是自定义的结构类型(struct),其内存模型对于我们来说都是可知的、透明的。所以,我们可以对该对象的底层字节序列一一进行操作,简单而有效。
在传统C风格中的数据类型叫做POD对象,即一种古老的纯数据,其二进制内容可以随意复制的,所以我们可以大胆的使用memset()、memcpy()、memcmp()等函数对对象的内存进行操作。
但是在C++中,要注意了,C++对象可能不是一个POD,这是为什么呢?
这就从C++动多态说起,动多态的一个基本支撑技术就是虚函数,在使用虚函数时候,类的每一次继承都会产生一个虚函数表(vtable),其中存放的是指向虚函数的指针,这些虚函数表必须存放在对象体中,也就是和对象的数据内存放在一起,所以对象数据的内存并不是以连续的方式存放的,而是被切割成了不同的部分,既然对象的数据不再集中在一起,如果这个时候使用memcpy,会带来不可以预计的后果。
总结:要区分哪些数据对象是POD,哪些是非POD。由于非POD对象存在,在C++中使用memcpy()系列的函数一定要保持足够小心