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);

strcpy是拷贝字符串,以\0为标志结束(即一旦遇到数据值为0的内存地址拷贝过程即停止) 
strcpy的原型为 
char *strcpy(char *dest, const char *src) 
而memcpy是给定来源和目标后,拷贝指定大小n的内存数据,而不管拷贝的内容是什么(不仅限于字符) 
memcpy的原型为 
void *memcpy(void *dest, const void *src, size_t n);

memcpy源码:

/***
*memcpy.c - contains memcpy routine *Purpose:
* memcpy() copies a source memory buffer to a destination buffer.
* Overlapping buffers are not treated specially, so propogation may occur.
*
**********/ #include <cruntime.h>
#include <string.h> #pragma function(memcpy) /***
*memcpy - Copy source buffer to destination buffer
*
*Purpose:
* memcpy() copies a source memory buffer to a destination memory buffer.
* This routine does NOT recognize overlapping buffers, and thus can lead
* to propogation.
*
* For cases where propogation must be avoided, memmove() must be used.
*
*Entry:
* void *dst = pointer to destination buffer
* const void *src = pointer to source buffer
* size_t count = number of bytes to copy
*
*Exit:
* Returns a pointer to the destination buffer
*
*Exceptions:
*******************************************************************************/ void * __cdecl memcpy (
void * dst,
const void * src,
size_t count
)
{
void * ret = dst; #if defined (_M_IA64) { __declspec(dllimport) void RtlCopyMemory( void *, const void *, size_t count ); RtlCopyMemory( dst, src, count ); } #else /* defined (_M_IA64) */
/*
* copy from lower addresses to higher addresses
*/
while (count--) {
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
#endif /* defined (_M_IA64) */ return(ret);
}

实现很简单,count一直减,把src值赋给dest,唯一值得注意的是函数原型。

void * __cdecl memcpy (
void * dst,
const void * src,
size_t count
) 可以看到参数为void 类型的指针,也返回一个void *指针。
我们可以利用void *类型指针为任何类型实现copy,如结构体:
    struct A{
int x;
int y;
};
A *a=new A();
A *b=new A();
a->x=;
a->y=; memcpy(b,a,sizeof(A));
printf("%d%d\n",b->x,b->y);

输出53。

memset源码:

/***
*char *memset(dst, val, count) - sets "count" bytes at "dst" to "val"
*
*Purpose:
* Sets the first "count" bytes of the memory starting
* at "dst" to the character value "val".
*
*Entry:
* void *dst - pointer to memory to fill with val
* int val - value to put in dst bytes
* size_t count - number of bytes of dst to fill
*
*Exit:
* returns dst, with filled bytes
*
*Exceptions:
*
*******************************************************************************/ void * __cdecl memset (
void *dst,
int val,
size_t count
)
{
void *start = dst; #if defined (_M_IA64) || defined (_M_AMD64) { __declspec(dllimport) void RtlFillMemory( void *, size_t count, char ); RtlFillMemory( dst, count, (char)val ); } #else /* defined (_M_IA64) || defined (_M_AMD64) */
while (count--) {
*(char *)dst = (char)val;
dst = (char *)dst + ;
}
#endif /* defined (_M_IA64) || defined (_M_AMD64) */ return(start);
}

1.memmove

函数原型:void *memmove(void *dest, const void *source, size_t count)

返回值说明:返回指向dest的void *指针

参数说明:dest,source分别为目标串和源串的首地址。count为要移动的字符的个数

函数说明:memmove用于从source拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。

2.memcpy

函数原型:void *memcpy(void *dest, const void *source, size_t count);

返回值说明:返回指向dest的void *指针

函数说明:memcpy功能和memmove相同,但是memcpy中dest和source中的区域不能重叠,否则会出现未知结果。

3.两者区别

函数memcpy()   从source  指向的区域向dest指向的区域复制count个字符,如果两数组重叠,不定义该函数的行为。   
  而memmove(),如果两函数重叠,赋值仍正确进行。

memcpy函数假设要复制的内存区域不存在重叠,如果你能确保你进行复制操作的的内存区域没有任何重叠,可以直接用memcpy;   
  如果你不能保证是否有重叠,为了确保复制的正确性,你必须用memmove。

memcpy的效率会比memmove高一些,如果还不明白的话可以看一些两者的实现:


void *memmove(void *dest, const void *source, size_t count)
{
 assert((NULL != dest) && (NULL != source));
 char *tmp_source, *tmp_dest;
 tmp_source = (char *)source;
 tmp_dest = (char *)dest;
 if((dest + count<source) || (source + count) <dest))
 {// 如果没有重叠区域
   while(count--)
     *tmp_dest++ = *tmp_source++;
}
else
{ //如果有重叠
 tmp_source += count - 1;
 tmp_dest += count - 1;
 while(count--)
   *--tmp_dest = *--tmp;
}
return dest;
}


void *memcpy(void *dest, const void *source, size_t count)
{
 assert((NULL != dest) && (NULL != source));
 char *tmp_dest = (char *)dest;
 char *tmp_source = (char *)source;
 while(count --)//不对是否存在重叠区域进行判断
   *tmp_dest ++ = *tmp_source ++;
 return dest;
}

memmove普通实现

memmove - Copy source buffer to destination buffer
;
;Purpose:
;       memmove() copies a source memory buffer to a destination memory buffer.
;       This routine recognize overlapping buffers to avoid propogation.
;       For cases where propogation is not a problem, memcpy() can be used.
;
;   Algorithm:

    void* memmove(void* dest, void* source, size_t count)

   {

       void* ret = dest;

 

       if (dest <= source || dest >= (source + count))

       {

          //Non-Overlapping Buffers
         //copy from lower addresses to higher addresses
    

         while (count --)

               *dest++ = *source++;

     }

     else

     {

        //Overlapping Buffers
       //copy from higher addresses to lower addresses

 

       dest += count - 1;

       source += count - 1;

       while (count--)

                *dest-- = *source--;l

      }

      return ret;

   }

 

另一种实现:

void* mymemcpy( void* dest, const void* src, size_t count )
{
    char* d = (char*)dest;
    const char* s = (const char*)src;
  //  int n = (count + 7) / 8; // count > 0 assumed
    int n = count >> 3;
    switch( count & 7 )
    {
              do {  *d++ = *s++;
    case 7:        *d++ = *s++;
    case 6:        *d++ = *s++;
    case 5:        *d++ = *s++;
    case 4:        *d++ = *s++;
    case 3:        *d++ = *s++;
    case 2:        *d++ = *s++;
    case 1:        *d++ = *s++;
    case 0          } //while (--n > 0);
                 while (n-- > 0)
    }

return dest;
}

												

C的memset,memcpy,strcpy 的区别 及memset memcpy memmove源码的更多相关文章

  1. gcc和g++的区别【转自中国源码网】

    gcc和g++的区别[转自中国源码网] gcc和g++都是GNU(组织)的一个编译器. 误区一:gcc只能编译c代码,g++只能编译c++代码两者都可以,但是请注意:1.后缀为.c的,gcc把它当作是 ...

  2. python_way day10 python和其他语言的作用域 、 python2.7多继承和3.5多继承的区别 、 socket 和 socketserver源码(支持并发处理socket,多进程,多线程)

    python_way day10 1.python的作用域和其他语言的作用域 2.python2.7多继承和3.5多继承的区别 3.socket和socketserver源码(并发处理socket) ...

  3. 面试题:HashMap和ConcurrentHashMap的区别,HashMap的底层源码。

    Hashmap本质是数组加链表.根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面. ConcurrentHashMap:在hashMap的基 ...

  4. HashMap和ConcurrentHashMap的区别,HashMap的底层源码。

    Hashmap本质是数组加链表.根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面. ConcurrentHashMap:在hashMap的基 ...

  5. HashMap和ConcurrentHashMap的区别,HashMap的底层源码

    HashMap本质是数组加链表,根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面. ConcurrentHashMap在HashMap的基础 ...

  6. vue打包时,assets目录 和static目录下文件的处理区别(nodeModule中插件源码修改后,打包后的文件应放在static目录)

    为了回答这个问题,我们首先需要了解Webpack如何处理静态资产.在 *.vue 组件中,所有模板和CSS都会被 vue-html-loader 及 css-loader 解析,并查找资源URL.例如 ...

  7. memcpy、memmove、memset及strcpy函数实现和理解

    memcpy.memmove.memset及strcpy函数实现和理解 关于memcpy memcpy是C和C++ 中的内存拷贝函数,在C中所需的头文件是#include<string.h> ...

  8. c语言中几个常见的库函数strlen、strcmp、strcat、strcpy、strncpy、memset、memcpy、memmove、mmap

    1.strlen() 1)计算给定字符串的长度,不包括’\0’在内 unsigned int strlen(const char *s) { assert(NULL != s);//如果条件不满足,则 ...

  9. memmove和memcpy函数的区别及实现

    一.memmove()和memcpy()函数和strcpy()函数的区别: (1)使用的类型不同,strcpy()函数只对字符串进行操作:memmove()和memcpy()函数对所有类型都适用,为内 ...

随机推荐

  1. HUD 4473 Exam

    题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=4473 题目意思 定义f(x) = 满足(a * b)|x的有序对(a,b)的个数. 然后输入一个n, ...

  2. CF#52 C Circular RMQ (线段树区间更新)

    Description You are given circular array a0, a1, ..., an - 1. There are two types of operations with ...

  3. Docker之dockerfile

    一.什么是dockerfile Docker通过对于在dockerfile中的一系列指令的顺序解析实现自动的Image的构建: 通过使用build命令,根据dockerfile的描述来构建镜像: bu ...

  4. Nhibernate初入门基本配置(一)

    文章出处:http://www.cnblogs.com/GoodHelper/archive/2011/02/14/nhiberante_01.html 一.NHibernate简介 什么是?NHib ...

  5. JSP页面中包含文件

    在JSP中,主要有3种功能可以将外部内容包含到JSP文档中jsp:include动作. jsp:include动作允许我们在请求期间将其他页面的输出包含进来.它的主要优点是:在被包含的页面发生更改时, ...

  6. JQuery 限制文本框只能输入数字和小数点

    $(function(){ /*JQuery 限制文本框只能输入数字*/ $(".NumText").keyup(function(){ $(this).val($(this).v ...

  7. 帝国cms7.0判断字段为空,显示为不同

    在一些情况下,我们的字段会留空,但是又不希望内容模板上只显示空.比如,在后台,如添加作者为小明,则显示小明,不填作者则显示"佚名",我们可以用以下代码. <? if($nav ...

  8. Qt之界面美化输入框(使用QSS确实非同凡响)

    我们先看下酷狗音乐的输入框效果图: 这里我们需要实现在输入框里面添加一个按钮(多个也一样),并且提供一个默认时候的文字..直接上代码好了. QHBoxLayout *lay = new QHBoxLa ...

  9. openstack之keystone

    一.什么是keystone 用于为openstack家族中的其它组件成员提供统一的认证服务,包括身份认证.令牌发放和校验.服务列表.用户权限定义等: 基本概念: 用户User:用于身份认证.一个用户可 ...

  10. 没有login页面

    "/"应用程序中的服务器错误. 无法找到资源. 说明:HTTP 404.您正在查找的资源(或者它的一个依赖项)可能已被移除,或其名称已更改,或暂时不可用.请检查以下 URL 并确保 ...