看了好多面经之后,我发现有很多题目都似乎很简单,但是如果要自己写的话,总感觉能写出个大概,但好像差点什么,所以我打算把见过的面试题总结出来,方便以后复习。
memcpy
下面是我们常见的的错误写法:
这里把dest和src都强制转换成了(char*)类型,但是copy一定是一个个字节的吗?不一定。
//一般版本,这里把dest和src都强制转换成了(char*)类型,但是copy一定是一个个字节完成的吗?(打算先拿这个版本给面试官看看)
void* my_memcpy(void* dest, const void* src, size_t count)
{
assert((NULL != dest) && (NULL != source));
char* tmp = (char*)dest;
const char* cur = (char*)src;
while (count--)
*tmp++ = *cur++;
return dest;
}
一般版本的进阶,不考虑内存重叠问题
void* my_memcpy(void* dest, const void* src, size_t count)
{
assert((NULL != dest) && (NULL != source));
int num = count / sizeof(dest);//按dest类型长度拷贝
int slice = num % sizeof(dest);//剩余字节拷贝
unsigned long * s = (unsigned long*)src;
unsigned long * d = (unsigned long*)dest;
while (num--)
*d++ = *s++;
while (slice--)
*((char*)d++) = *((char*)s++);
return dest;
}
再让我们看看内存重叠的情况
内存重叠问题是指目的地址的内存空间的首地址,包含在源内存空间中,这两段k空间有了交集,因而使用memcpy进行内存赋值操作时,这段重叠的空间会被破坏。分为一下两种情况(拿memcpy的dest与src举例)
- 1.src空间覆盖了dest: dest(占8bit位) 的起始地址:1000 src(占8bit位)地址: 1001
- 2.src所指的区域本来就是dest区域的一部分
dest(占8bit位)地址:1000
src (占4bit位)地址:1004
因此还需要做一个判断:stc <= dest 如果出现内存重叠的情况,就从高地址向低地址copy
最终版本,考虑内存重叠问题(相当于实现memmove):
void* my_memcpy(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;
}
memcopy和memmove的关系:
memmove这个函数名称有它的历史原因,是因为有了memcpy函数后,发现这个函数有问题,又发明了另一个没有问题的memcpy函数,但为了爆出兼容性依然保留了memcpy函数,而将新版本的memcpy函数改名为memmove函数.
总结:
- 1.考虑指针类型,不同类型指针不能通过++赋值
- 2.内存重叠情况需要从高地址向低地址copy
- 3.要记住首地址