strcpy,memcpy,memmove和内存重叠分析
一:strcpy函数用法和实现:
/*
GNU-C中的实现(节选):
*/
char* strcpy(char *d, const char *s)
{
char *r=d;
while((*d++=*s++));
return r;
}
有没有发现这个实现并不是很好。。至少没有判断是不是为NULL。一个更好的版本:
char *strcpy(char *strDest, const char *strSrc)
{
assert((strDest!=NULL) && (strSrc !=NULL));
char *address = strDest;
while( (*strDest++ = * strSrc++) != '\0') return address ;
}
好好研究这段代码其实写的挺妙的。。(当然不是我写的)。。
二:memcpy函数用法和实现:
从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
微软实现:
void * __cdecl memcpy (void * dst,const void * src, size_t count )
{
void * ret = dst;
#if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
{
extern void RtlMoveMemory( void *, const void *, size_t count );
RtlMoveMemory( dst, src, count );
}
#else /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
/* * copy from lower addresses to higher addresses */
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
#endif /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
return(ret);
}
写的是不是也很好。。仿佛天衣无缝啊!。。但是你有没有注意到一个问题:那就是内存重叠。。
什么叫内存重叠呢?就是两块内存区域有一个共同的部分。。是不是很SB的解释。。当存在这个问题的时候,那还和我们预期的那样拷贝吗?注意:理解了这个才是关键。。
例子:(引用网上一个例子)
int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
memcpy(a+4, a, sizeof(int)*6)
如果照微软实现的话,那么输出应该是0123012301(理解这个再忘下看吧。。)
而我们想要达到的目的是输出:0123012345。。如果你实验一下,确实也是输出0123012345。。(对于这个问题,我也解释不了)。为了避免这样的情况发生,我们找到了一个更好的函数:memmove。。
三:memmove函数用法和实现
用法和memcpy函数一样。。
实现:
void *memmove(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp_source, *tmp_dest;
tmp_source = (char *)source;
tmp_dest = (char *)dest;
if((dest + count<source) || (source + count) <dest))
{// 如果没有重叠区域
while(count--)
*tmp_dest++ = *tmp_source++;
}
else
{ //如果有重叠(反向拷贝)
tmp_source += count - 1;
tmp_dest += count - 1;
while(count--)
*--tmp_dest = *--tmp;
}
return dest;
}
一开始看到这段代码的时候,觉得好神奇啊。后来发现,其实有个很大的漏洞(先不说那些小问题),那就是内存重叠有两种情况。其实我觉得该作者也想到了,而且给出了解决办法。,估计是粗心大意吧。
:src<dest&&src+count>dest; dest<src&&dest+count>src。。但是网上那位作者没有写清楚,下面我就重写一下上面的else部分:
else
{
//重叠1:(反向拷贝)
if(tmp_source<=tmp_dest&&tmp_source+count>=tmp_dest)
{
tmp_source += count - 1;
tmp_dest += count - 1;
while(count--)
*tmp_dest-- = *tmp_source--;
}
//重叠2:(正向拷贝)
else
{
while (count--)
{
*tmp_dest++=*tmp_source++;
}
}
}
但写完之后发现傻逼了。。后面的那个else不可以和前面的那个if写在一起么?所以优化后的完整代码:
void *memmove(void *dest, const void *source, size_t count)
{
assert((NULL != dest) && (NULL != source));
char *tmp_source, *tmp_dest;
tmp_source = (char *)source;
tmp_dest = (char *)dest; if(tmp_source<=tmp_dest&&tmp_source+count>=tmp_dest)
{
tmp_source += count - 1;
tmp_dest += count - 1;
while(count--)
*tmp_dest-- = *tmp_source--;
}
else
{
while (count--)
{
*tmp_dest++=*tmp_source++;
}
} return tmp_dest;
}
此时就加上了内存重叠的判断。如果你理解了上面的那个(输出应该是0123012301),一切都明白了。。还有:别忘了那个问题哟,运行的时候还是输出:0123012345。。和我们的理论值有冲突。。希望大神发现问题能告知,一起学习,交流。。
此时才发现,平时写的那些代码,我们能懂他们多少呢?
strcpy,memcpy,memmove和内存重叠分析的更多相关文章
- strcpy&memcpy&memmove
strcpy extern char *strcpy(char *dest,char *source); { assert((dest!=NULL)&&(source!=NULL)); ...
- memcpy不能复制内存重叠区域,memmove可以拷贝重叠内存
http://blog.csdn.net/li_ning_/article/details/51418400 下面s和s2指向的内存区域有重叠,memcpy不能正确复制,src赋值给dst时,可能会修 ...
- C++ 浅析调试,内存重叠查看
这里举个例子查看内存, 环境为:vs 2017 测试为strcpy[因为测试老api,需要在 预处理中 添加 _CRT_SECURE_NO_WARNINGS ] 测试问题:内存溢出 源码: #incl ...
- memmove 和 memcpy的区别以及处理内存重叠问题
区别: memcpy和memmove()都是C语言中的库函数,在头文件string.h中,作用是拷贝一定长度的内存的内容,原型分别如下: void *memcpy(void *dst, const v ...
- [整理]内存重叠之memcpy、memmove
函数原型: void *memcpy( void *dest, const void *src, size_t count ); void *memmove( void* dest, const vo ...
- C语言标准库函数memcpy和memmove的区别以及内存重叠问题处理
①memcpy()和memmove()都是C语言中的标准库函数,定义在头文件string.h中,作用是拷贝一定长度的内存的内容,原型分别如下: void *memcpy(void *dst, cons ...
- strcpy和memcpy,memmove函数的区别
strcpy和memcpy的区别 strcpy和memcpy都是标准C库函数,它们有下面的特点. strcpy提供了字符串的复制.即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制 ...
- 字符串函数(strcpy字符串拷,strcmp字符串比较,strstr字符串查找,strDelChar字符串删除字符,strrev字符串反序,memmove拷贝内存块,strlen字符串长度)
1.strcpy字符串拷贝拷贝pStrSource到pStrDest,并返回pStrDest地址(源和目标位置重叠情况除外) char *strcpy(char *pStrDest, const ch ...
- 【C语言】模拟实现memmove函数(考虑内存重叠)
//模拟实现memmove函数(考虑内存重叠) #include <stdio.h> #include <assert.h> #include <string.h> ...
随机推荐
- 【hdoj_2152】Fruit(母函数)
题目:http://acm.hdu.edu.cn/showproblem.php?pid=2152 本题采用母函数模板求解,母函数模板如下: http://blog.csdn.net/ten_sory ...
- LoadRunner Agent Runtime Settings Configuration启动报错
解决方法: 关闭负载机器上的防火墙功能即可解决
- bzoj 1491
思路:先求出每两点之间的最短路,建出n个最短路径图,然后枚举起点终点和中间点,计算条数用到拓扑图dp... 看别人的方法很巧妙地用floyd在计算最短路的时候就可以直接计算条数啦... #includ ...
- OpenStack 认证服务 KeyStone连接和用户管理(五)
一) 创建环境变量链接keyston vim adminrc export OS_USERNAME=admin export OS_PASSWORD=redhat export OS_PROJECT_ ...
- summernote富文本编辑器配合validate表单验证无法进行表单提交的问题
1.使用summernote富文本编辑器提交图片到服务器 在使用bootstrap中,我们用到了summernote富文本编辑器,使用summernote将图片上传到服务器中,参考我的上篇文章http ...
- Bzoj3942 Censoring(KMP)
\(KMP\)问题的核心在于数组\(next\)(或者\(pre\)/\(fail\),各种叫法),几乎所有的此类型题都是需要计算\(next\)的. 这里解释一波\(next\):即满足字符子串\( ...
- phongap开发中安卓平台上如何调用第三方播放器来播放HLS视频
前文曾经讲了关于在安卓平台上利用phonegap开发播放HLS的解决方案,其实最好的方案就是自己针对HLS视频开发自己的播放器,但是开发播放器是一个浩大的工程,必须对原生安卓开发非常熟悉,并且对视频播 ...
- JZYZOJ1383 [usaco2003feb]impster 位运算 最短路
http://172.20.6.3/Problem_Show.asp?id=1383 找能到达某个状态的最小操作数,然后把所有状态扫一遍即可,要额外判定一下起始就有的状态(如果起始里没有0那么这些状 ...
- BZOJ 3391 [Usaco2004 Dec]Tree Cutting网络破坏(树形DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3391 [题目大意] 给定一棵树,求分支size均不大于一半点数的点 [题解] 递归的同 ...
- 【数论】nefu119 组合素数
算组合数中的素因子p的个数,基本同这题 http://www.cnblogs.com/autsky-jadek/p/6592194.html #include<cstdio> using ...