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

2024-02-20 18:40

本文主要是介绍memset ,memcpy ,memmove,strcpy 的根本区别 与实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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

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

from:

 

http://afreez.blog.51cto.com/59057/7349

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

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  ==   0 return   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脚本的第二个参数
$@ 是传给脚本的所有参数的列表
from:http://dadekey.blog.51cto.com/107327/119938/

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

C语言的跨平台性及库的跨平台性研究
2009-07-26 22:47:24
标签: 跨平台 VC++ C Gcc -mno-cygwin
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。 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的播放器。
posted on 2013-01-22 10:13  lexus 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/lexus/archive/2013/01/22/2870885.html

这篇关于memset ,memcpy ,memmove,strcpy 的根本区别 与实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/729167

相关文章

Python如何实现读取csv文件时忽略文件的编码格式

《Python如何实现读取csv文件时忽略文件的编码格式》我们再日常读取csv文件的时候经常会发现csv文件的格式有多种,所以这篇文章为大家介绍了Python如何实现读取csv文件时忽略文件的编码格式... 目录1、背景介绍2、库的安装3、核心代码4、完整代码1、背景介绍我们再日常读取csv文件的时候经常

Golang中map缩容的实现

《Golang中map缩容的实现》本文主要介绍了Go语言中map的扩缩容机制,包括grow和hashGrow方法的处理,具有一定的参考价值,感兴趣的可以了解一下... 目录基本分析带来的隐患为什么不支持缩容基本分析在 Go 底层源码 src/runtime/map.go 中,扩缩容的处理方法是 grow

Go 1.23中Timer无buffer的实现方式详解

《Go1.23中Timer无buffer的实现方式详解》在Go1.23中,Timer的实现通常是通过time包提供的time.Timer类型来实现的,本文主要介绍了Go1.23中Timer无buff... 目录Timer 的基本实现无缓冲区的实现自定义无缓冲 Timer 实现更复杂的 Timer 实现总结在

基于Python实现多语言朗读与单词选择测验

《基于Python实现多语言朗读与单词选择测验》在数字化教育日益普及的今天,开发一款能够支持多语言朗读和单词选择测验的程序,对于语言学习者来说无疑是一个巨大的福音,下面我们就来用Python实现一个这... 目录一、项目概述二、环境准备三、实现朗读功能四、实现单词选择测验五、创建图形用户界面六、运行程序七、

在Dockerfile中copy和add的区别及说明

《在Dockerfile中copy和add的区别及说明》COPY和ADD都是Dockerfile中用于文件复制的命令,但COPY仅用于本地文件或目录的复制,不支持自动解压缩;而ADD除了复制本地文件或... 目录在dockerfile中,copy 和 add有什么区别?COPY 命令ADD 命令总结在Doc

Vue中动态权限到按钮的完整实现方案详解

《Vue中动态权限到按钮的完整实现方案详解》这篇文章主要为大家详细介绍了Vue如何在现有方案的基础上加入对路由的增、删、改、查权限控制,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、数据库设计扩展1.1 修改路由表(routes)1.2 修改角色与路由权限表(role_routes)二、后端接口设计

C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)

《C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)》本文主要介绍了C#集成DeepSeek模型实现AI私有化的方法,包括搭建基础环境,如安装Ollama和下载DeepS... 目录前言搭建基础环境1、安装 Ollama2、下载 DeepSeek R1 模型客户端 ChatBo

Qt实现发送HTTP请求的示例详解

《Qt实现发送HTTP请求的示例详解》这篇文章主要为大家详细介绍了如何通过Qt实现发送HTTP请求,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、添加network模块2、包含改头文件3、创建网络访问管理器4、创建接口5、创建网络请求对象6、创建一个回复对

C++实现回文串判断的两种高效方法

《C++实现回文串判断的两种高效方法》文章介绍了两种判断回文串的方法:解法一通过创建新字符串来处理,解法二在原字符串上直接筛选判断,两种方法都使用了双指针法,文中通过代码示例讲解的非常详细,需要的朋友... 目录一、问题描述示例二、解法一:将字母数字连接到新的 string思路代码实现代码解释复杂度分析三、

grom设置全局日志实现执行并打印sql语句

《grom设置全局日志实现执行并打印sql语句》本文主要介绍了grom设置全局日志实现执行并打印sql语句,包括设置日志级别、实现自定义Logger接口以及如何使用GORM的默认logger,通过这些... 目录gorm中的自定义日志gorm中日志的其他操作日志级别Debug自定义 Loggergorm中的