strcpy、memcpy和memset的区别及memcpy在什么情况下会失败

时间:2021-12-09 20:55:45

转自:http://www.cnblogs.com/stoneJin/archive/2011/09/16/2179248.html,但是原文程序有误!

strcpy和memcpy都是标准C库函数,它们有下面的特点。
strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符。

已知strcpy函数的原型是:char* strcpy(char* dest, const char* src);
memcpy提供了一般内存的复制。即memcpy对于需要复制的内容没有限制,因此用途更广。
void *memcpy( void *dest, const void *src, size_tcount);

[cpp]  view plain copy
  1. char * strcpy(char * dest, const char * src) // 实现src到dest的复制  
  2. {  
  3.     if((src==NULL)||(dest==NULL))  
  4.     {  
  5.         return NULL;  
  6.     }  
  7.     char* strDest=dest;  
  8.     while((*dest++=*src++)!='\0');  
  9.     return strDest;  
  10. }  
  11.   
  12. void *memcpy(void *memTo, const void *memFrom, size_t size)  
  13. {  
  14.     if((memTo == NULL) || (memFrom == NULL)) //memTo和memFrom必须有效  
  15.     return NULL;  
  16.     char *tempFrom = (char *)memFrom;             //保存memFrom首地址  
  17.   char *tempTo = (char *)memTo;                  //保存memTo首地址        
  18.   while(size -- > 0)                //循环size次,复制memFrom的值到memTo中  
  19.        *tempTo++ = *tempFrom++ ;    
  20.   return memTo;  
  21. }  

strcpy和memcpy主要有以下3方面的区别。
1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度
3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy

以下摘自:http://hi.baidu.com/zengzhaonong/item/f1e1383565fa5c302e0f812d

相关函数: bcopy(),memccpy(),memmove(),strcpy(),strncpy()

(附:memmove、memcpy和memccpy简介http://blog.sina.com.cn/s/blog_79a0eceb0100z5qh.html
表头文件: #include <string.h>
定义函数: void *memcpy(void *dest, const void *src, size_t n)
函数说明: memcpy()用来拷贝src所指的内存内容前n个字节到dest所指的内存地址上。与strcpy()不同的是,memcpy()会完整的复制n个字节,不会因为遇到字符串结束'\0'而结束
返回值: 返回指向dest的指针
附加说明指针src和dest所指的内存区域不可重叠

strcpy、memcpy和memset的区别及memcpy在什么情况下会失败

memcpy在什么情况下会失败 http://zhidao.baidu.com/question/487139972.html

一个memcpy,会不会用?肯定会啦,好,我问题,C语言在实现的时候,是“从前拷贝”,还是“从后拷贝”?估计是不知道。那么,有一天你使用memcpy(p+5,p,10);这个语句的时候,就可能会获得错误的结果。
1. 失败情况:copy的区域重叠。
例如如下例子
memcpy(a, b, 10);
如果指针b在a之前且距离小于10,则实际copy结果没有达到预计目标,
        这个和memcpy的实现有关。这种情况需要使用memmove。
2. 异常情况          当copy越界时,可能会出现程序异常。          如果是在栈上,那可能更麻烦,因为它出现异常的位置往往不是真的有问题的位置。
<pre id="recommend-content-1222778693" class="recommend-text mb-10" name="code" style="white-space: pre-wrap; word-wrap: break-word; margin-top: 0px; margin-bottom: 10px; padding: 0px; background-color: rgb(255, 255, 255);"><pre id="recommend-content-1222778693" class="recommend-text mb-10" name="code" style="white-space: pre-wrap; word-wrap: break-word; margin-top: 0px; margin-bottom: 10px; padding: 0px; font-family: arial, 'courier new', courier, 宋体, monospace; color: rgb(51, 51, 51); line-height: 24px; background-color: rgb(255, 255, 255);">memcpy进行内存拷贝时有可能发生内存读写错误,比如length大于要拷贝的空间或大于目的空间,可能发生:
 
 
 
 
<pre id="recommend-content-1222778693" class="recommend-text mb-10" name="code" style="white-space: pre-wrap; word-wrap: break-word; margin-top: 0px; margin-bottom: 10px; padding: 0px; background-color: rgb(255, 255, 255);"><pre id="recommend-content-1222778693" class="recommend-text mb-10" name="code" style="white-space: pre-wrap; word-wrap: break-word; margin-top: 0px; margin-bottom: 10px; padding: 0px; font-family: arial, 'courier new', courier, 宋体, monospace; color: rgb(51, 51, 51); line-height: 24px; background-color: rgb(255, 255, 255);">int *p = new[10];
 
 
 
 
<pre id="recommend-content-1222778693" class="recommend-text mb-10" name="code" style="white-space: pre-wrap; word-wrap: break-word; margin-top: 0px; margin-bottom: 10px; padding: 0px; background-color: rgb(255, 255, 255);"><pre id="recommend-content-1222778693" class="recommend-text mb-10" name="code" style="white-space: pre-wrap; word-wrap: break-word; margin-top: 0px; margin-bottom: 10px; padding: 0px; font-family: arial, 'courier new', courier, 宋体, monospace; color: rgb(51, 51, 51); line-height: 24px; background-color: rgb(255, 255, 255);">memcpy(dst, p, 20);//20超过10了,由于p是堆内分配的,所以超过的部分不属于进程空间,发生内存读写错误。
 
 
 
 
<pre id="recommend-content-1222778693" class="recommend-text mb-10" name="code" style="white-space: pre-wrap; word-wrap: break-word; margin-top: 0px; margin-bottom: 10px; padding: 0px; background-color: rgb(255, 255, 255);"><pre id="recommend-content-1222778693" class="recommend-text mb-10" name="code" style="white-space: pre-wrap; word-wrap: break-word; margin-top: 0px; margin-bottom: 10px; padding: 0px; font-family: arial, 'courier new', courier, 宋体, monospace; color: rgb(51, 51, 51); line-height: 24px; background-color: rgb(255, 255, 255);">int p[10];
memcpy(dst, p, 20);//不发生错误,因为定义的变量在栈里,p超过10位仍属于进程空间。
 
 
 
<pre id="best-content-1224516957" class="best-text mb-10" name="code" style="white-space: pre-wrap; word-wrap: break-word; margin-top: 0px; margin-bottom: 10px; padding: 0px; background-color: rgb(255, 252, 246);"><pre id="recommend-content-1222778693" class="recommend-text mb-10" name="code" style="white-space: pre-wrap; word-wrap: break-word; margin-top: 0px; margin-bottom: 10px; padding: 0px; background-color: rgb(255, 255, 255);">
 
 
 

Memset、Memcpy、Strcpy 的作用和区别(转)

(1) Memset
原型: extern void *memset(void *buffer, int c, int count); 
用法: #include <string.h> 

功能: 把buffer所指内存区域的前count个字节设置成字符 c。 
说明: 返回指向buffer的指针。用来对一段内存空间全部设置为某个字符
例如: 
char a[10]; 
memset(a, '\0', sizeof(a)); 
memset可以方便的清空一个结构类型的变量或数组。 
如:struct _test{ char s[10]; 
int x; 
int y;
}; 
变量 struct _test st; 
(1)一般清空st的方法如下: 
st.s[0] = '\0'; st.x =0; st.y =0; 
(2) 用memset方法如下: 
memset(&st,0,sizeof(struct _test)); 
数组: struct _test st[10]; 
memset(st,0,sizeof(struct _test)*10); //清空方法 
//memset 源码的实现 C语言
#include <mem.h> 
void* memset(void* s, int c, size_t n)
{
unsigned char* p = (unsigned char*) s;
while (n > 0) 
{
*p++ = (unsigned char) c;
--n;
}
return s;
}


(2)memcpy
原型:extern void *memcpy(void*dest,void*src,unsignedintcount); 用法: #include <string.h>
功能: 由src所指内存区域复制count个字节到dest所指内存区域。 
说明: src和dest所指内存区域不能重叠,函数返回指向dest的指针.可以拿它拷贝任何数据类型的对象。 
例如: char a[10],b[5]; 
memcpy(b, a, sizeof(b)); /*注意如果用sizeof(a),会造成b的内存地址溢出*/
(3) Strcpy 
原型: extern char *strcpy(char *dest,char *src); 
用法: #include <string.h> 
功能: 把src所指由NULL结束的字符串复制到dest所指的数组中。 
说明: src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳 src的字符串.返回指向dest的指针。 
例如: char a[100],b[50];
strcpy(a,b);
如用 strcpy(b,a); 
要注意a中的字符串长度(第一个‘\0’之前)是否超过50位,如超过,则会造成b的内存地址溢出。
假如有如下代码,请问输出为多少?
#include "stdio.h"
main()
{ char dest[3];
char str[6]="Hello";
strcpy(dest,str); 
printf("%s\n",dest);
}
编译输出如下结果:
Hello //没有输出乱码,有点怪怪的为什么?
分析:
1>str中字符串的长度大于dest 的内存长度3.为什么str字符串还能完拷贝到dest 中呢?
来看看 strcpy的 源代码实现:
char *strcpy(char *strDest,const char *strSrc) 

assert((strDest!=NULL)&&(strSrc !=NULL)) //判断指针是否合法,即分配内存,指向某块确定区域
char *address = strDest; //记住目标地址的起始值
while((*strDest++ = *strSrc++)!='\0') //先拷贝,后判断,这样就不用在拷贝完了后,再加一句
NULL; // *strDest = '\0'; -->即加一个结束符.因为字符串结束已拷贝了.
return address; //返回目标首地址的值。 
}
//从上面的代码可以看出,strcpy函数,假定strDest的内存空间是足够可以放下strSrc的内容的.
//也就是说使用者,在使用strcpy函数时,应使 (strDest内存空间)>= (strSrc内存空间) 
// 在调用 strcpy(dest,str); 时,while((*strDest++ = *strSrc++)!='\0') 没有判断strDest的内存是否够,而是将srtSrc的内容直接拷贝到strDest,当拷到'\0'就结束.
//因此在使用printf("%s\n",dest); 时 输出遇到'\0'时停此输出.所以会输出: Hello

(4) 三者区别 
memset 主要应用是初始化某个内存空间。 
memcpy 是用于copy源空间的数据到目的空间中。 
strcpy 用于字符串copy,遇到‘\0’,将结束。 
如果理解了这些,就能知道它们的区别: 
例如初始化某块空间的时候,用到memcpy,那么就显得笨拙 
int m[100] 
memset((void*)m,0x00,sizeof(int*100); //Ok! 
memcpy((void*)m,"\0\0\0\0....",sizeof(int)*100); //Not Ok
一.函数原型 
strcpy extern char *strcpy(char *dest,char *src); 
#include <string.h> 
功能:把src所指由NULL结束的字符串复制到dest所指的数组中 
说明: src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。 返回指向dest的指针 
memcpy extern void *memcpy(void *dest,void *src,unsigned int count); 
#include <string.h> 
功能:由src所指内存区域复制count个字符串到dest所指内存区域. 
说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针. 
memset extern void *memset(void *buffer,int c,int count); 
#include <string.h> 
功能:把buffer所指内存区域的前count个字节设置成字符c 
说明:返回指向buffer的指针.
二.区别 

memset 用来对一段内存空间全部设置为某个字符,一般用于在对定义的字符串初始化为' '或者'\0'; 
例: char a[100]; memset(a,'\0',sizeof(a)); 
memcpy 是用来做内存拷贝,可以用来拷贝任何数据类型的对象,可以指定拷贝的数据长度; 
例: char a[100],b[50]; 
memcpy(b,a,sizeof(b)); 
//注意:如果使用sizeof(a),会造成内存溢出 
mem是一段内存,他的长度,必须自己记住.memcpy是见着什么拷贝什么。 
strcpy 就只能拷贝字符串,它遇到'\0'就结束拷贝; 
例:char a[100],b[50]; strcpy(a,b); 
如用strcpy(b,a)要注意a中的字符串长度(第一个'\0'之前) 是否超过50,如果超过,则会造成b的 内存溢出.
它是不会拷贝'\0'的,所以一般还有加一个语句: *a='\0'; 
三.使用技巧 

memset 可以方便的清空一个数据结构的变量或数组. 
如: struct sample_struct { 
char csName[16]; 
int iSeq; 
int iType; 
}; 
对于变量 
struct sample_struct stTest; 
一般情况下,初始化stTest的方法: 
stTest.csName[0]='\0'; 
stTest.iSeq=0; 
stTest.iType=0; 
而用memset: 
memset(&stTest,0,sizeof(struct sample_struct)); 
如果是数组: 
struct sample_struct TEST[100]; 
memset(TEST,0,sizeof(struct sample_struct)*100);