C/C++中的mem函数和strcopy函数的区别和应用

 更新时间:2016年08月15日 11:17:16   投稿:mrr  
strcpy和memcpy都是标准C库函数,strcpy提供了字符串的复制而memcpy提供了一般内存的复制。下面通过本文重点给大家介绍C/C++中的mem函数和strcopy函数的区别和应用,非常不错,感兴趣的朋友一起看下吧

strcpy和memcpy都是标准C库函数,它们有下面的特点。

strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符。

memcpy提供了一般内存的复制。即memcpy对于需要复制的内容没有限制,因此用途更广。

mem系列函数是面试的时候常考的知识点,我们需要熟练掌握这三个函数的原理和代码实现,要能准确无误的写出代码。

memcpy、memset和memset三个函数在使用过程中,均需包含以下头文件:

//在C中
#include<string.h>
//在C++中
#include<cstring>

memcpy

memcpy函数是C/C++中的内存拷贝函数,它的功能是从源src所指的内存地址的起始位置开始,拷贝n个字节到目标dst所指的内存地址的起始位置中。

研究函数功能最好的办法就是研究其源代码,这里在网上找了一份,如下:

void*__cdeclmemcpy(void* dst,constvoid* src,size_tcount)
{
void* ret = dst;
while(count--)
{ 
// 注意, memcpy函数没有处理dst和src区域是否重叠的问题
*(char*)dst = *(char*)src;
dst = (char*)dst +1;
src = (char*)src +1;
}
return(ret);
}

源代码比较简单,定义一个计数,然后从头到尾一次将src指向的值拷贝给dst,库函数中的memcpy不能处理dst和src中存在重叠部分这种情况。

那么处理重叠部分的话,我们可以采用从后往前依次拷贝的方法,下面给出我修改过的函数代码:

void*__cdeclmemcpy(void* dst,constvoid* src,size_tcount)
{
char*pDst =static_cast<char*> dst;
constchar*pSrc =static_cast<constchar*> src;
//检查参数
if(pDst==NULL|| pSrc==NULL|| count <=0){
returnNULL;
}
//判断有是否存在重叠部分
if(pDst > pSrc && pDst < pSrc + count){
for(size_ti=count-1; i>=0; i--)
{
pDest[i] = pSrc[i];
}
}
else{
for(size_ti=0; i<count; i++)
{
pDest[i] = pSrc[i];
}
}
returnpDst;
}

memset

memset一般用于对内存初始化,在这里需要注意的是,memset函数是对内存的每个字节(按字节)设置成c的值。其函数原型如下:

voidmemset(void*s,intc,size_tn)
{
constunsignedcharuc = c;//将int转换成char,截去c的高24位,留下低8位
unsignedchar*su;
for(su = s;0< n; ++su, --n)
*su = uc;
returns;
}

注意,这里有一个坑,memset一般用于将内存清零,你要是想将这段内存初始化为1而写下下面的代码:

intnum[10];
memset(num,1,sizeof(int)*10);

这里并不会如你所愿,num的每一个数都被初始化为16843009,原因就是上述提到的会截去c的高24位。

使用memset初始化比用for循环初始化要快很多,所以在初始化基本类型数据,结构体等的时候尽量选择memset,memset可以方便的清空一个结构类型的变量或数组。

memmove

它与memcpy的功能相似,都是将src所指的n个字节复制到dst所指的内存地址的起始位置,不同的是它处理了src和dst有重叠的情况。但是当目标区域与源区域没有重叠则和memcpy函数功能相同。(与上述修改过得memcpy基本一致)

所以基本原则就是,如果你能确保两段内存没有重叠的部分,就使用memcpy来进行拷贝;如果你不能确定,为了保证复制的正确性,必须用memmove。

其实现代码如下:

void*memmove(void* dest,void* src,size_tcount)
{
void* ret = dest;
if(dest <= src || dest >= (src + count))
{
//Non-Overlapping Buffers
//copy from lower addresses to higher addresses
while(count --)
*dest++ = *src++;
}
else
{
//Overlapping Buffers
//copy from higher addresses to lower addresses
dest += count - 1;
src += count - 1;
while(count--)
*dest-- = *src--;
}
returnret;
}

strcpy

strcpy是C语言的标准库函数,使用strcpy需要包含以下头文件:

#include<string.h>
#include<stdio.h>

其函数功能是把从src地址开始且含有NULL结束符的字符串复制到dst开始的地址空间,返回指向dst的指针。其函数代码如下:

char*strcpy(char* dst ,char* src){
if(dst==NULL||src==NULL)returnNULL;// --1
if(dst==src)returndst;//--2
char* address = dst;//--3
while((*dst++ = *src++)!='\0')//--4
returnaddress;//--5
}

图中标出来的都是考点,下面一一说明:

1、需要判断参数的正确性,这里也可以抛出一个异常

2、如果指向了同一块内存,不用复制直接返回即可

3、这里需要保存原始的dst指针,用作返回值

4、这里有一个技巧,如果写成以下两种,面试的时候会大大扣分!

//第一种
while(*dst++ = *src++)//直接越界访问,没有检查指针的有效性
//第二种
while(*src!='\0'){*dst++ = *src++;}//考虑了src的边界问题,没有在dst的后面加'\0',会导致dst的长度未知引起错误

5、函数返回dst的原始值是为了能够支持链式表达式,增加了函数的附加性。

上述第5点可以用如下测试代码来说明:

intlength =strlen(strcpy(strA,strB));//如果不支持链式表达式,这里会报错。

那么有时候也会问为什么不返回src的原始值,错误原因有以下三点:

源字符串本来就已知,返回没有什么意义

不能支持形如char * strA = strcpy(new char[10],strB) 这样的表达式
为了保护源字符串,使用const限定了src所指的内容,把const char作为char 的返回值,类型不符,编译器会报错。

strcpy和memcpy主要有以下3方面的区别。

1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。

2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。

3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy

以上所述是小编给大家介绍的C/C++中的mem函数和strcopy函数的区别和应用,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

相关文章

  • C语言详细讲解树状数组与线段树

    C语言详细讲解树状数组与线段树

    顾名思义,树状数组就是用数组来模拟树形结构呗。那么衍生出一个问题,为什么不直接建树,因为树状数组能处理的问题就没必要建树。线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点
    2022-04-04
  • QT实现用户登录注册

    QT实现用户登录注册

    这篇文章主要为大家详细介绍了QT实现用户登录注册,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • linux下C/C++学生信息管理系统

    linux下C/C++学生信息管理系统

    这篇文章主要为大家详细介绍了linux下c/c++学生信息管理系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • C++ 程序抛出异常后执行顺序说明

    C++ 程序抛出异常后执行顺序说明

    这篇文章主要介绍了C++ 程序抛出异常后执行顺序说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • C++编程小心指针被delete两次

    C++编程小心指针被delete两次

    这篇文章主要介绍了C++编程指针被delete两次的严重后果,以实例阐述了C++指针使用中的误区和注意点,需要的朋友可以参考下
    2014-07-07
  • C++中运算符重载的规则语法实例

    C++中运算符重载的规则语法实例

    今天小编就为大家分享一篇关于C++中运算符重载的规则语法实例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • C语言实现电话簿项目

    C语言实现电话簿项目

    这篇文章主要为大家详细介绍了C语言实现电话簿项目,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • C++之try catch 异常处理入门实例

    C++之try catch 异常处理入门实例

    我们通常希望自己编写的程序能够在异常的情况下也能作出相应的处理,而不至于程序莫名其妙地中断或者中止运行了。在设计程序时应充分考虑各种异常情况,并加以处理
    2018-01-01
  • 纯C语言:递归二进制转十进制源码分享

    纯C语言:递归二进制转十进制源码分享

    这篇文章主要介绍了纯C语言:递归二进制转十进制源码,有需要的朋友可以参考一下
    2014-01-01
  • C语言实现贪吃蛇游戏

    C语言实现贪吃蛇游戏

    这篇文章主要为大家详细介绍了C语言实现贪吃蛇游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03

最新评论