zoukankan      html  css  js  c++  java
  • memset ,memcpy ,memmove,strcpy 的根本区别 与实现

    memset ,memcpy ,memmove,strcpy 的根本区别 与实现 - 邓维 - 博客园

    memset ,memcpy ,memmove,strcpy 的根本区别 与实现

    from:

    它们用处不同,但大部分情况下可以完成相同的要求。

    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的内存地址溢出。

    memcpy
    原型:extern void *memcpy(void *dest, void *src, unsigned int count);
    用法:#include <string.h>
    功能:由src所指内存区域复制count个字节到dest所指内存区域。
    说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针。可以拿它拷贝任何数据类型的对象。

    举例:char a[100],b[50]; memcpy(b, a, sizeof(b));注意如用sizeof(a),会造成b的内存地址溢出。

    memset
    原型:extern void *memset(void *buffer, int c, int count);
    用法:#include <string.h>
    功能:把buffer所指内存区域的前count个字节设置成字符c。
    说明:返回指向buffer的指针。用来对一段内存空间全部设置为某个字符。

    举例:char a[100];memset(a, '\0', sizeof(a));

    memset可以方便的清空一个结构类型的变量或数组。

    如:
    struct sample_struct
    {
    char   csName[16];
    int   iSeq;
    int   iType;
    };

    对于变量
    struct sample_strcut stTest;

    一般情况下,清空stTest的方法:
    stTest.csName[0]='\0';
    stTest.iSeq
    =0;
    stTest.iType
    =0;

    用memset就非常方便:
    memset(&stTest,0,sizeof(struct sample_struct));

    如果是数组:
    struct sample_struct   TEST[10];

    memset(TEST,0,sizeof(struct sample_struct)*10);

    对这个问题有疑问,不是对函数的疑问,而是因为没有弄懂mem和str的区别。
    mem是一段内存,他的长度,必须你自己记住
    str也是一段内存,不过它的长度,你不用记,随时都可以计算出来

    所以memcpy需要第三个参数,而strcpy不需要

    memmove

    原型:extern void *memmove(void *dest, const void *src, unsigned int count);

    用法:#include <string.h>   功能:由src所指内存区域复制count个字节到dest所指内存区域。

    说明:src和dest所指内存区域可以重叠,但复制后dest内容会被更改。函数返回指向dest的指针。

     实现:

    http://www.cnitblog.com/guopingleee/archive/2009/02/15/54581.aspx 

    strcpy()、memcpy()、memmove()、memset()的实现
     
    代码


    strcpy(), 字符串拷贝.
    char *strcpy(char *strDest, const char *strSrc)
    {
        assert((strDest
    !=NULL) && (strSrc !=NULL));
        
    char *address = strDest;    
        
    while( (*strDest++ = * strSrc++!= '\0')
           NULL ;
        
    return address ;      
    }

    代码
    memcpy, 拷贝不重叠的内存块
    void *memcpy(void* pvTo, void* pvFrom, size_t size) //byte是java里的变量类型
    {
    assert(pvTo 
    != NULL && pvFrom != NULL);
    void* pbTo = (byte*)pvTo;
    void* pbFrom = (byte*)pvFrom;
    /* 内存块重叠吗?如果重叠,就使用memmove */
    assert(pbTo
    >=pbFrom+size || pbFrom>=pbTo+size);
    while(size-->0)
        
    *pbTo++ == *pbFrom++;
    return pvTo;
    }

    代码
    void *MemCopy(void *dest,const void *src,size_t count)
    {
        
    char *pDest=static_cast<char *>(dest);
        
    const char *pSrc=static_cast<const char *>(src);
        
    if( pDest>pSrc && pDest<pSrc+count )
        {
            
    for(size_t i=count-1; i<=0++i)
            {
                pDest[i]
    =pSrc[i];
            }
        }
        
    else
        {
            
    for(size_t i=0; i<count; ++i)
            {
                 pDest[i]
    =pSrc[i];
            }
        }
        
    return pDest;
    }
    代码

    void *Memmove(void *Dst, const void*Src,size_t count)
    {
    assert(Dst 
    && Src);
    void* pDst = Dst;
    if (Dst<Src && (char*)Dst > (char*)Src + count)
    {
    while(count--)
    {
       
    *(char*)Dst = *(char*)Src;
       Dst 
    = (char*)Dst + 1;
       Src 
    = (char*)Src + 1;
    }
    }
    else
    {
       Dst 
    = (char*)Dst + count - 1;
       Src 
    = (char*)Src + count - 1;
       
    while(count--)
       {
          
    *(char*)Dst = *(char*)Src;
          Dst 
    = (char*)Dst -1 ;
          Src 
    = (char*)Src -1 ;
       }
    }
    return pDst;
    }

    代码

    void* memmove(void *dest, const void *src,size_t n)
    {
        
    if (n == 0return 0;
        
    if (dest == NULL) return 0;
        
    if (src == NULL)    return 0;
        
    char *psrc = (char*)src;
        
    char *pdest = (char*)dest;
        
    if((dest <= psrc) || (pdest >= psrc + n)) /*检查是否有重叠问题 */
            {
             
    for(int i=0; i < n; i++/*正向拷贝*/
              {
               
    *pdest = *psrc;
               psrc
    ++;
               pdest
    ++;
              }
            }
            
    else /*反向拷贝*/
            {
              psrc 
    += n;
              pdest 
    += n;
              
    for(int i=0;i<n;i++)
               {
                psrc
    --;
                pdest
    --;
                
    *pdest = *psrc;
               }
            }
       
    return dest;
    }
    复制代码

    memset:把buffer所指内存区域的前count个字节设置成字符c

    void * Memset(void* buffer, int c, int count)
    {
    char* pvTo=(char*)buffer;
    assert(buffer 
    != NULL);
    while(count-->0)
    *pvTo++=(char)c;
    return buffer;
    }
    复制代码

    Linux中变量$#,$@,$0,$1,$2的含义 - 邓维 - 博客园

    Linux中变量$#,$@,$0,$1,$2的含义

    我们先写一个简单的脚本,执行以后再解释各个变量的意义
      
    # touch variable
    # vi variable
      
    脚本内容如下:
      
    #!/bin/sh
    echo "number:$#"
    echo "scname:$0"
    echo "first :$1"
    echo "second:$2"
    echo "argume:$@"
    保存退出
      
    赋予脚本执行权限
      
    # chmod +x variable
      
    执行脚本
      
    # ./variable aa bb
    number:2
    scname:./variable
    first: aa
    second:bb
    argume:aa bb
      
    通过显示结果可以看到:
      
    $# 是传给脚本的参数个数
    $0 是脚本本身的名字
    $1是传递给该shell脚本的第一个参数
    $2是传递给该shell脚本的第二个参数
    $@ 是传给脚本的所有参数的列表

    C语言的跨平台性及库的跨平台性研究 - 海狗哥的流媒体空间 - 51CTO技术博客

    C语言的跨平台性及库的跨平台性研究
    2009-07-26 22:47:24
    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://jeremiah.blog.51cto.com/539865/183560
        啥?C语言是跨平台的?大家刚学C语言的时候,都知道C是不跨平台的。C的跨平台性从何说起?
      
        呵呵,看官莫急,听Jeremiah徐徐道来。
      
        本篇博客所讨论的跨平台性,是比较狭义的,主要是讨论跨Windows和Linux这两个最流行的操作系统,确切的说,是跨VC和gcc这两大编译器。在这也只是浅谈一下,不做太深入的研究。
      
        主要内容如下:
        1. C语言的跨平台性
        2. MinGW及Cygwin
        3. GCC制作动态库及静态库及调用方法
        4. VC++制作的静/动态库与GCC制作的动静态库相互替换
     

        1. C语言的跨平台性
        大家也都知道Java是跨平台的语言,主要是因为在不同的系统上面安装不同的JRE,也就是Java运行时环境,这样,相同的代码在不同的操作系统上面,运行的效果是一样的。
      
        其实Jeremiah所谓的跨平台性,跟Java的这种机制是类似的。主要是编译器GCC的跨平台性。
      
        看过Jeremiah以前博客的人都应该知道Jeremiah主要研究的是开源项目VLC,顺便研究了点FFmpeg及Live555,这些项目其实都是基于Linux开发的,但是能在Windows上运行主要是借助了两个环境,MinGW及Cygwin。以此类推,如果我们基
    于Linux做开发,想要在Windows下运行,那就用MinGW或Cygwin就okay了。Jeremiah以后也将主要从事Linux里的C编程开发。

        2. MinGW及Cygwin
        Google "MinGW Cygwin/Gcc"会出现很多关于MinGW和Cygwin的文章。主要介绍了MinGW和Cygwin这两个Jeremiah所谓的仿真Linux环境的异同。推荐看一下http://blog.classky.com/2008/11/27/difference-of-gcc-compiler-between-MinGW-and-cygwin/http://bbs.lupa.gov.cn/273398/viewspace-122539.html。英文的看这个http://www.delorie.com/howto/cygwin/mno-cygwin-howto.html里面讲的非常的好。
      
        在这Jeremiah写个简单的测试程序说明两者的异同。
    #include <stdio.h>

    int main()
    {
            printf("hello world\n");
            return 0;
    }
       
        在MinGW和Cygwin下分别执行
    gcc -o hello hello.c
    ./hello
        在各自的环境中,都能运行出hello world来。
        但是如果在cmd下运行Cygwin/GCC编译出来的hello.exe,却说找不到Cygwn1.dll。

       
        在cygwin下编译hello.c的时候加入参数-mno-cygwin,则cmd下运行的时候,就可以正确的执行。
    gcc -mno-cygwin -o hello hello.c
    ./hello
        也就是gcc -mno-cygwin编译出来的程序可以不需要Cygwin1.dll。这也就是为什么我们运行编译完的VLC的时候,没有提示需要这个Cygwin1.dll。因为我们在configure-vlc.sh中加入了CC="gcc -mno-cygwin" CXX="g++ -mno-cygwin"。那是不是说Cygwin的gcc -mno-cygwin与MinGW的gcc是一样的呢?经过Jeremiah的使用,发现,还是有些许区别的。比如我在Cygwin下用gcc -mno-cygwin编译Live555的就会报错,而在MinGW下编译,就没问题。具体原因,还没有搞明白。但是一般的程序,还是可以看成等同的。

        3. GCC制作动态库及静态库及调用方法
        如果是Linux的开发人员,这个东西简直太简单了。我这个标题主要是写给VC++的开发人员的。因为Jeremiah接触了一些VC++的开发人员,发现这些朋友对Linux相关的东西不是太熟悉。所以在这写一个简单的程序来说明Linux的库的制作及调用。主要的编译器还是MinGW的Gcc或者是Cygwin的gcc -mno-cygwin。
      
        在当前目录建立文件夹test,下面分别建立两个文件夹lib,及testlib。
    mkdir test && cd test && mkdir lib testlib
        在lib下建立add.h及add.c。
    //add.h
    int add(int, int);
      
    //add.c    
    #include "add.h"    
        
    int add(int x, int y)    
    {    
            return x + y;    
    }    
        编译生成静态库
    gcc -c add.c
    ar crs libadd.a add.o
        编译生成动态库
    gcc -shared -o libadd.dll add.c
        这样,包含一个add函数的静态库和动态库就建立好了。
      
        在testlib下建立test.c来调用库。
    //test.c    
    include <stdio.h>    
    #include "add.h"    

    int main()    
    {    
        printf("result=%d\n", add(3,5));    
        return 0;    
    }
        执行
    gcc -o test test.c -I../lib -L../lib -ladd
    ./test
        就能得到结果
    result=8
        但这只是连接的静态库。
        如果连接动态库呢? VC++的开发人员都知道调用dll的方法,需要LoadLibrary及GetProcAddress这些函数一个个的把dll中的函数导入进来调用。(参考:http://tech.ddvip.com/2007-03/117395352621216.html
        但是在Linux下面就不用,调用动态库与静态库是一样一样的。(Jeremiah很喜欢这样的方式,吼吼)
    执行
    rm ../lib/libadd.a
    gcc -o test test.c -I../lib -L../lib -ladd
    ./test
    会出现问题

        主要是因为动态库的位置我们没有告诉系统。所以系统调用libadd.dll的时候,找不到它在何处。

        Linux下通常的方法是配置LD_LIBRARY_PATH。
    export LD_LIBRARY_PATH=~/test/lib
        但是配置这个环境变量在MinGW和Cygwin是不好用的,还是会提示找不到libadd.dll。应该配置的环境变量是PATH。
    export PATH=~/test/lib:${PATH}
    echo $PATH
    ./test
        这样就能得到结果了。

        4. VC++制作的静/动态库与GCC制作的动静态库相互替换
        这样可以吗?真的可以吗?答案是:可以。

        Jeremiah某日脑子发神经,突然想研究VC++编译其与MinGW/Gcc的相互调用问题,因为这两个环境编出来的都是Windows下的程序,肯定应该存在一定的共性。而且主要是VC++静态库.lib和MinGW/Gcc的静态库.a的关系。
     

        经过研究,结论是:
        1) MinGW编译生成的动态库libadd.dll,可以被VC++的任何一个环境调用。
        2) Mingw编译生成的静态库libadd.a也可以被被VC++的任何一个环境调用,只不过要自己手动改名字,将libadd.a改为libadd.lib就可以使用了。

        3) 将上面的add.h及add.c用VC制作成一个静态库和一个动态库对VC++开发人员是小菜一碟的事情,但是经过测试发现,只有VC6生成的libadd.lib及libadd.dll才能被MinGW/Gcc调用。其他的VS版本没有调试成功,主要是因为MinGW/Gcc和VC6都使用COFF格式,而其他的VS版本,我不知道是啥格式。是否可以调整到这样的格式,还请各位VC++达人告诉我一声。谢谢。
      
        啰啰嗦嗦了这么些,最后的结果就是VLC的那些dll在VC++下是完全可以被调用到的。下一篇Jeremiah将会介绍用VC++调用libvlc.dll制作MFC的播放器。
  • 相关阅读:
    java10-3 equals方法
    java10-2 toString()方法
    java10-1 Object类
    转载 实现类的封装性
    cocosstdio之字体之文本和FNT字体
    cocos之观察者模式应用实例
    c++双字符常量
    spring之ioc
    cocos2d-x之 利用富文本控件解析xhml标签(文字标签,图片标签,换行标签,标签属性)
    cocos2d-x之利用富文本控件遍历xml
  • 原文地址:https://www.cnblogs.com/lexus/p/2870885.html
Copyright © 2011-2022 走看看