您的位置:首页 > 其它

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  strcpy 内存管理