走进C的世界-那些年我们常犯的错---strcpy及memcpy函数

   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不须要指定长度,它遇到字符串结尾符结束。 * 所以easy溢出。

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不须要指定长度,它遇到字符串结尾符结束。
所以easy溢出。

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 ,欢迎各位查看,有问题及时说明。有其它好的建议欢迎给我留言或私信。



posted @ 2017-05-03 09:18  jzdwajue  阅读(310)  评论(0编辑  收藏  举报