走进C的世界-那些年我们常犯的错---strcpy及memcpy函数
2014-10-19 16:26
295 查看
strcpy和memcpy函数是项目中经常用到的函数。可能由于使用不当造成数据错误或引发程序段错误等等。下面我们就来细细分析这两个非常重要的函数。
/*File : strcpy_memcpy.c *Auth : sjin *Date : 20141019 *Mail : 413977143@qq.com */ /* 主要针对strcpy及与memcpy函数的区别 * strcpy 函数在使用过程中的注意事项等等,在面试时及平时 * 代码编写中经常遇到的问题。 */ #include <stdio.h> /*strcpy函数提供了字符串的复制,即只用于字符串的复制,并且它不仅复制 * 字符串内容之外,还会复制字符串的结束符。遇到结束符则停止复制 *函数原型char *strcpy(char *dest,const char *src) */ char * mystrcpy(char *dest,const char *src) { if((dest == NULL) || (src == NULL)){ return NULL; } char *strdest = dest; //保存目标字符串的首地址 while((*strdest ++ = *src++) != '\0'); return dest; } /*memcpy函数提供了一般内存的复制,即对需要复制的内容没有限制 * 函数原型 void *memcpy(void * dest,const void * src,size_t count); * * 对于地址重叠情况 ,该函数的是未定义的 */ void * mymemcpy1(void *dest,const void *src,size_t count) { /*未考虑内存重叠情况*/ if((dest == NULL) || (src == NULL)){ return NULL; } char *strdest = (char *)dest; char *strsrc = (char *)src; while(count-- > 0){ *strdest++ = *strsrc++; } return dest; } void * mymemcpy2(void *dest,const void *src,size_t count) { char *strdest = NULL; char *strsrc = NULL; /*内存重叠情况*/ if((dest == NULL) || (src == NULL)){ return NULL; } if((src < dest) && (((char *)src + count) > (char *)dest)){ strdest = (char *)dest + count - 1; strsrc = (char *)src + count - 1; while(count--){ *strdest-- = *strsrc--; } }else{ strdest = (char *)dest; strsrc = (char *)src; while(count-- > 0){ *strdest++ = *strsrc++; } } return dest; } /*strcpy 与memcpy区别: *1 复制的内容不同,strcpy 只能复制字符串,而memcpy复制任意内容。 *2 复制的方法不同,strcpy不需要指定长度,它遇到字符串结尾符结束。 * 所以容易溢出。memcpy则是根据第三参数聚丁复制的长度 *3 用途不同。通常在复制字符串时用strcpy,而需要复制其他数据类型数据时则一般用memcpy *4 内存重叠时,strcpy会出现段错误,而memcpy不会 */ int main() { char buf[16] = "abcdefghijk"; char buf1[16] = "abcdefghijk"; char buf2[16] = "abcdefghijk"; char buf3[16] = "abcdefghijk"; //strcpy(buf+2,buf); ###程序崩溃,段错误 memcpy(buf + 2,buf,5); memmove(buf1+2,buf1,5); mymemcpy1(buf2 + 2,buf2,5); mymemcpy2(buf3 + 2,buf3,5); printf(" end of memcpy(buf +2,buf,5), buf is :%s\n",buf); printf(" end of memmove(buf1 +2,buf1,5), buf1 is :%s\n",buf1); printf(" end of mymemcpy1(buf2 +2,buf2,5), buf2 is :%s\n",buf2); printf(" end of mymemcpy2(buf3 +2,buf3,5), buf3 is :%s\n",buf3); return 0; }
输出结果:
end of memcpy(buf +2,buf,5), buf is :ababcdehijk end of memmove(buf1 +2,buf1,5), buf1 is :ababcdehijk end of mymemcpy1(buf2 +2,buf2,5), buf2 is :abababahijk end of mymemcpy2(buf3 +2,buf3,5), buf3 is :ababcdehijk关于内存重叠,对我来说是个新名词。所谓的内存重叠个人理解就是拷贝的目的地址在源地址的范围内。通过上面的打印结果我们可以看到。memcpy函数,本身是支持内存重叠的(有些资料或博客中说不支持的,有待考证),mymemcpy1函数是不支持的,而mymemcpy2函数是支持的,所以说,mymemcpy2才是memcpy的具体实现。关于strcpy并不支持内存重叠,编译过程中会出现段错误的。因此我总结了strcpy和memcpy函数的区别,有以下4条:1 复制的内容不同,strcpy 只能复制字符串,而memcpy复制任意内容。
2 复制的方法不同,strcpy不需要指定长度,它遇到字符串结尾符结束。
所以容易溢出。memcpy则是根据第三参数聚丁复制的长度。
3 用途不同。通常在复制字符串时用strcpy,而需要复制其他数据类型数据时则一般用memcpy。
4 内存重叠时,strcpy会出现段错误,而memcpy不会。关于内存重叠,可查看这个链接。
关于strcpy函数,再看下面的代码
/*File : strcpy.c *Auth : sjin *Date : 20141019 *Mail : 413977143@qq.com */ /*关于strcpy的一些重要的面试题 * */ #include <stdio.h> #include <string.h> int main() { char str[10] = {'\0'}; char str1[10] = {'\0'}; int i = 0; //for(i = 0; i < 10; i++){ //上面的将会出现段错误。未考虑字符串的结束符 for(i = 0; i < 9; i++){ str1[i] = 'a'; } strcpy(str,str1); printf("str is :%s\n",str); return 0; }
为了能使用编译后的程序可以正常运行,所以修改了代码,看注释。这里考察了字符串的基本常识,关于更多的介绍,可以看我以前的另外一篇博客LinuxC面试题(内存管理) 。
有更深入的理解,或者我这里有错误的地方,请指正 ,共同进步。
注:转载请注明出处http://blog.csdn.net/sjin_1314
GITHUB地址:https://github.com/jinshaohui/C_Error_problem ,欢迎各位查看,有问题及时说明。有其他好的建议欢迎给我留言或私信。
相关文章推荐
- 走进C的世界-那些年我们常犯的错---keyword相关
- 走进C的世界-那些年我们常犯的错---关键字相关
- 带领我们一起走进PHP的世界
- Ext.Net控件,简单案例1,让我们从Hello World开始,走进Ext.Net控件的世界!。
- 【有奖征文】走进VR开发世界(1)——我们离开发一款VR大作还有多远?
- 【有奖征文】走进VR开发世界——我们离开发一款VR大作还有多远?
- MongoDB学习之旅一:走进MongoDB世界
- 那些年我们一起清除过的浮动
- 带你走进多线程的世界(多线程实现方式)
- 那些年我们一起清除过的浮动(BFC特性)
- 带你走进spring的世界
- 带你走进rsync的世界
- 走进windows编程的世界-----字符编码
- 张艾迪(创始人):我们接管世界
- 那些年,我们北漂的日子--(工作第3,4,5天)
- 那些年震撼我们心灵的音乐
- 那些年,我们一起无聊过 - 博创OJ 1104 水题
- 那些年我们疯狂的日子,文字控吧
- 【SpringMVC学习02】走进SpringMVC的世界
- 走进windows编程的世界-----绘图相关