C-基础:memcpy、memset、memmove、memcmp、memchr

流过昼夜 提交于 2019-12-07 09:19:27

一,原型

void * memcpy ( void * destination, const void * source, size_t num );

功能:将以source作为起始地址的数据复制num个字节到以destination为起始地址的数据中,不支持destination和source重叠的情况。函数返回destination指针。

void* memcpy (void* destination,constvoid* source,size_t num )
{
  char* pdes =(char*)destination;
  char* psrc =(char*)source;
  assert(destination !=NULL && source !=NULL && num>0);
  while(num--)
    *pdes++=*psrc++;
  return destination;
}
 
void * memmove ( void * destination, const void * source, size_t num );
功能:将以source作为起始地址的数据的num个字节移动到以destination为起始地址的数据中,支持destination和source重叠的情况。函数返回destination指针。
void* memmove (void* destination,constvoid* source,size_t num )
{
  char* pdes =(char*)destination;
  char* psrc =(char*)source;
  assert(destination !=NULL && source !=NULL && num>0);
  //判断destination和source是否存在重叠
  if(pdes+num <psrc || psrc+num < pdes)//不存在重叠,正常从前向后复制
    while(num--)
      *pdes++=*psrc++;
  else//存在重叠,防止信息丢失,从后向前复制
  {
    pdes = pdes+num-1;
    psrc = psrc+num-1;
    while(num--)
      *pdes--=*psrc--;
  }
  return destination;
}
 
void * memset ( void * ptr, int value, size_t num );
功能:将以ptr作为起始地址的数据的num个字节设置为value。函数返回destination指针。
void* memset (void* ptr,int value,size_t num )
{
  char* ptmp =(char*)ptr;
  assert(ptr !=NULL && num >0);
  while(num--)
    *ptmp++= value;
  return ptr;
}
 
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
功能:比较以ptr1为起始地址数据和以ptr2为起始地址的数据的num个字节大小情况。如果num个字节都相等,则相等,函数返回0。从起始位置开始,如果某个字节大,则prt1>ptr2,函数返回正数,否则ptr<ptr2,函数返回负数。
int memcmp (const void* ptr1,const void* ptr2,size_t num )
{
  int ret =0;
  const char* ptmp1 =(char*)ptr1;
  const char* ptmp2 =(char*)ptr2;
  assert(ptr1 != NULL && ptr2 != NULL && num>0);
  while(num--)
  {
    if(*ptmp1 >*ptmp2)
    {
      ret =1;
      break;
    }
    if(*ptmp1 <*ptmp2)
    {
      ret =-1;
      break;
    }
    ptmp1++;
    ptmp2++;
  }
  return ret;
}
 
void * memchr (void * ptr, int value, size_t num ); 
功能:在以ptr作为起始地址的数据中的num个字节中查找value,如果查到,则返回value所在的地址,否则返回NULL。
void* memchr (void* ptr,int value,size_t num )
{
  char* pret = NULL;
  char* ptmp =(char*)ptr;
  assert(ptr !=NULL && num>0);
  while(num)
  {
    if(*ptmp == value)
    {
      pret = ptmp;
      break;
    }
    ptmp++;
    num--;
  }
  return pret;
}

二,详解

memcpy函数详解

void *memcpy( void *dest, const void *src, size_t count ); 

作用:

  在dest处拷贝src处的字节,并以count来计算需要拷贝的字节数量,进行内存的拷贝。

参数:

  dest:新的存贮区的开始部位

  src需要拷贝的开始部位

  count需要拷贝的字节数

备注:

  dest,src,它们都是从各自的地址处进行写入,如果是p而不是&p,那么将会取得p的值(地址),在该值的地址处进行读出或写入。 

例:

int* intPoint = new int(3333); 

int* intPoint1; 

memcpy( &intPoint1, &intPoint, 4 );//在intPoint1的地址处写入intPoint地址处的值,也就是intPoint指针值。

cout << *intPoint1 << endl;          //使intPoint1指向了intPoint.

 或

int* intPoint = new int(3333); 

int intPoint1; 

memcpy( &intPoint1, intPoint, 4 ); 

cout << intPoint1 << endl; 

 

2)

memcpy函数的实现与应用

memcpy函数较memmove相比,存在的不足是没有考虑到目的地址与源地址相重合,本文对memcpy作了修改,弥补其不足。     

memcpy函数的特点是:      

1. 使用memcpy函数前,实参dest必须初始化,否则可能会出错,原因见2。

2. 函数原理是将void *src 强制转换为char *s,然后只负责拷贝n个字节到dest里,不负责在最后加上'\0'。

下面的代码其实是实现了memmove的功能,然后根据memcpy的参数为void*,给其分别尝试传入int*和char*,以此来掌握int*是如何转化为char*,及强制转化后是什么结果,涉及到大端和小端等等。

#include <stdio.h>    
#include <string.h>  
void * mymemcpy(void *dest,void *src, int n)  
{  
    char *d;  
    char *s;  
    int i=0;  
 
    s=(char *)src;  
    d=(char *)dest;  
    if(dest==NULL || src==NULL || n<0)  
        return 0;  
    if(d>=s && d<=s+n-1)  
    {  
        i=n-1;  
        printf("%d\n",i);  
        while(i>=0)  
        {  
            d[i]=s[i];  
            i--;  
        }  
    }  
    else 
    {  
        while(i<n)  
        {  
            //printf("%x ",s[i]);  
            d[i]=s[i];  
            //printf("i=%d %x\n",i,d[i]);             
            i++;  
        }  
        d[i]='\0';  
    }  
    dest=(void *)d;  
    return dest;  
}  
 
int main(char **argv,int argc)    
{    
    //情况1  
    char src[100]="helloworldhui";    
    //如果是特殊情况mymemcpy(src+2,src,7);,则不可写成char *src="helloworld"; 因为文字常量区内容不可被改变  
    //char dest[100]="";        //必须初始化  
    char *dest;  
    dest=(char *)mymemcpy(src+2,src,7);  
    printf("%s\n",dest);//*/  
 
    //情况2  
/*  int src=123456789 ;     //对应十六进制:75BCD15  
    int dest=0;               
    //dest必须初始化,不然,如果只拷贝3个字节时,dest的第四个字节未被赋值,这样输出会出错。  
    memcpy(&dest,&src,3);  //只能传递参数4,不然出错  
    //mymemcpy(&dest,&src,3)     //则拷贝前3个字节  
    printf("dest=%d %x\n",dest,dest);//*/  
 
    //情况3  
/*  int src[100]={1234,12345,123456,11234567,14,15};  
    int dest[100]={0};  
    int i;  
    memcpy(dest,src,13);    //只拷贝13个字节    
    //不能保证拷贝一个完整的整数,一个元素,即如果你输入13,3*4=12,只能保证前3个整数完整拷贝,  
    //到了第4个整数,只拷贝它的第一个字节,如例为7  
    //mymemcpy(dest,src,13);  
    for( i=0;i< 5;i++)  
        printf("*%d*\n",dest[i]);//*/ 
    return 0;    
}   
// 为情况3的输出结果:

#include <stdio.h>  
int main(void)  
{  
//  int src[10]={50,61,72,83,94};  
    _int64 src=123456789; //0x75BCD15,它在内存中的存放从低地址,低字节开始:15,cd,5b,7  
    char *p;  
    int count;  
 
    p=(char *)(&src);  
    for(count=0; count<sizeof(int);p++,count++)  
        printf("第%d字节处十六进制值是: %02x\n",count,*p);  
    return 0;  
}  
   

 

 

转载于:https://www.cnblogs.com/CPYER/p/3319099.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!