前段时间准备面试,看了一些库函数的实现,在看到memcpy时,发现有处理source和destination所指内存有重叠的情况,而strcpy没有,特别模仿库函数写了这个函数,并进行了测试.以下是具体的source code 和测试结果.
 
char *strcpy2(char *strDest, const char *strSrc)
{
assert( (strDest!=NULL) && ( strSrc!=NULL));
 if ( strDest == strSrc)
  return strDest ;
 char *tempptr = strDest ;
while( (*strDest++ = *strSrc++) != '\0')
;
return tempptr ;
}
这是修改网络上source code得到的一个版本,简洁,完全可以工作.初看觉得在程序内部改变了strDest和strSrc的地址(确实如此),不是太好,而实际上当别的函数调用后strDest和strSrc的地址恢复到调用前,因为调用只是改变参数的副本,程序改变地址指向的内容,而没有改变地址本身.不过更加明了的写法是用两个零时变量来替代,修改后如下:
char *strcpy3(char *strDest, const char *strSrc)
{
assert( (strDest!=NULL) && ( strSrc!=NULL));
 if ( strDest == strSrc)
   return strDest ;
 char *pDest = strDest ;
 char *pSrc=\'#\'" /> while( (*pDest ++ = *pSrc ++) != '\0');
 return strDest;
}
和strcpy2相比,增加了一个变量,不过程式更清晰,看个人爱好了.我偏向strcpy3.呵呵.
 
void memcpy2(void *pDst,const void *pSrc, size_t size)
{
 assert(pDst != NULL);
 assert(pSrc != NULL);
 //src and dst has a  shared area.
 if((pSrc<pDst) && ((char*)pSrc+size > pDst))
 {
  char *pstrSrc= (char *)pSrc + size -1;
  char *pstrDst = (char *)pDst + size -1;
while(size--)
   *pstrDst -- = *pstrSrc--;
 }
 else
 {
  char *pstrSrc= (char *)pSrc ;
  char *pstrDst = (char *)pDst ;
while(size--)
   *pstrDst++ = *pstrSrc++;
 }
}
 
 
int main()
{
 char *pSrc = (char *)malloc(1024);
 char *pDst = pSrc+4;
 strcpy2(pSrc,"12345678910");
 strcpy2(pDst,pSrc);    //(1)
 printf("Before memcpy: pSrc =%s pDst =%s\n",pSrc,pDst);
 memcpy2(pDst,pSrc,strlen(pSrc)*sizeof(char));
 printf("After memcpy: pSrc =%s \n pDst =%s\n",pSrc,pDst);
 return 0;
}
 
测试结果:
1.如果没有注释掉语句(1),执行到词语时,因为pDst覆盖了pSrc的结束符'\0'而陷入死循环,最后访问到不该访问的地址空间而出现debug错误.
2.注释掉语句(1),执行 memcpy2后,pSrc变成"123412345678910########",pDst变成"12345678910####","#"表示乱码,原因也是原有的结束符被覆盖.程序可以结束.
 
 
总结:
 1.const在特定的情况下并不能保证它所修饰函数参数为只读.
 2.在内存块有重叠的情况下,strcpy会崩溃,memcpy不会.

strcpy,memcpy,内存块重叠的更多相关文章

  1. 字符串函数(strcpy字符串拷,strcmp字符串比较,strstr字符串查找,strDelChar字符串删除字符,strrev字符串反序,memmove拷贝内存块,strlen字符串长度)

    1.strcpy字符串拷贝拷贝pStrSource到pStrDest,并返回pStrDest地址(源和目标位置重叠情况除外) char *strcpy(char *pStrDest, const ch ...

  2. C语言memmove()函数: 复制内存内容(可以重叠的内存块)

    头文件:#include <string.h> memmove() 用来复制内存内容,其原型为: void * memmove(void *dest, const void *src, s ...

  3. strcpy, memcpy, memset函数

    一. strcpy函数 原型声明:char *strcpy(char* dest, const char *src);   头文件:#include <string.h> 和 #inclu ...

  4. C++实现简单的内存块自己主动管理

    #ifndef __MEM__H #define __MEM__H #include<iostream> using namespace std; //自己主动管理内存块 typedef ...

  5. strcpy函数内存分析

    void strcpy(char* strDest, char* strSrc) { while((*strDest++ = *strSrc++) != '\0'); } 看上面这段代码,只有一条语句 ...

  6. Python解析器源码加密系列之(二):一次使用标准c的FILE*访问内存块的尝试

    摘要:由于近期打算修改Python解释器以实现pyc文件的加密/解密,出于保密的要求,解密之后的数据只能放在内存中,不能写入到文件中.但是后续的解析pyc文件的代码又只能接受FILE*作为入参,所以就 ...

  7. memcpy内存拷贝及优化策略图解

    一般内存拷贝与优化 代码实现 #include<iostream> usingnamespace std; //不安全的内存拷贝(当源内存地址与目标内存地址重叠时会产生错误) void h ...

  8. 固定尺寸内存块的缓冲队列类及C++实现源代码

    -------------------------------------------------------------------------------- 标题: 固定尺寸内存块的缓冲队列类及实 ...

  9. access_ok | 检查用户空间内存块是否可用

    access_ok() 函数是用来代替老版本的 verify_area() 函数的.它的作用也是检查用户空间指针是否可用. 函数原型:access_ok (type, addr, size); 变量说 ...

随机推荐

  1. autoplay media studio couldn't load

    AutoPlay Media Studio 7 (English version) is installed on target machine. Following error occurred w ...

  2. SGU 239.Minesweeper

    题意: 如图,一列未知的区域长度为n(≤1000),给出第二列的数字,求区域中雷的排列有多少种. Solution: 搜索.这题看上去1000的范围很大,实际上加上合理的剪枝,状态数会变得非常非常少. ...

  3. IOS 学习日志 2015-3-16

    Objective--C 一 关键字 self 相当于java中的this,但是又有不同 它即可一代替对象,也可以代替类, 也就是说它既可以用在静态方法中又可以用在动态方法中. super 相当于父类 ...

  4. ubuntu fcitx 安装 使用

    系统内置的ibus的86五笔,感觉有些老不太好用, 所以安装试用了一下fcitx下的五笔,记录一下安装方法 ,各种搜索... 我的ubuntn版本: #48-Ubuntu SMP Fri Aug 24 ...

  5. 安装交叉编译arm-linux-gcc环境

    设置好交叉编译的执行文件路径贴加到环境变量PATH 设置如下 export PATH=$PATH:/XXX/XXX/bin /etc/profile /~/.bashrc source  /etc/p ...

  6. Java Servlet 接收上传文件

    在Java中使用 Servlet 来接收用户上传的文件,需要用到两个apache包,分别是 commons-fileupload 和 commons-io 包: 如果直接在doPost中,使用requ ...

  7. 做个无边框winform窗体,并美化界面

    今天下午程序写完,有些时间就搞下界面美化,做个无框窗体.首先把窗体的FormBorderStyle设置为None,就变成无框的啦,不过你会发现这样窗体上就没有原来的最大最小化和关闭按钮了哦,所以要自己 ...

  8. Laravel Repository 模式

    Repository 模式 为了保持代码的整洁性和可读性,使用Repository Pattern 是非常有用的.事实上,我们也不必仅仅为了使用这个特别的设计模式去使用Laravel,然而在下面的场景 ...

  9. js 数组 var arr=[] 的用法总结

    刚接触了一个js数组,用起来很头疼,总结一下 基本格式: var arr = [[name,value],[name2,value2],[name3,value3]]; 如何给 arr 动态添加元素 ...

  10. 阿里云主机建立SWAP分区脚本

    工具:add_swap.sh    所有执行的脚本都需要root身份来执行,执行方法:以root身执行命令:bash xxx.sh 功能:自动检测系统swap分区大小,交换分区大小不合理则自动新增并挂 ...