细谈C语言中的strcpy,strncpy,memcpy,memmove,memset函数

本文深入解析了memcpy、memset、memmove等内存操作函数的功能及使用场景,并对比了memcpy与memmove在处理重叠内存区域时的不同表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.函数介绍:

1、memcpy

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

用法:#include<string.h>

功能:由src所指内存区域复制count个字节到dest所指内存区域。

说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针。

注意:和strcpy相比,memcpy不是遇到’/0’就结束,而是一定会拷贝完n个字节。

 

函数实现代码:

 

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

{

 

     assert(dest!=NULL&&src!=NULL);

     char *tmp = dest;

     const char *s = src;

 

     while (count--)

     *tmp++ = *s++;

     return dest;

}

 

2、memset

函数原型:extern void *memset(void *s, int c, size_t n)

功能:将已开辟内存空间s的首n个字节的值设为值c。将s中的前n个字符替换为c,并返回s。

memset常用于内存空间的初始化。

memset的深刻内涵:用来对一段内科空间全部设置为某个字符,一般用在对定义的字符串进行初始化为:memset(a, ‘/0’, sizeof(a));

 

函数实现代码:

 

void * memset(void* buffer, int c, int count) 

     char * buffer_p=(char*)buffer; 

     assert(buffer != NULL); 

     while(count-->0) 

         *buffer_p++=(char)c; 

     return buffer; 

}

 

3、memmove

 

void *memmove(void *s, const void *ct, size_t n)

与memcpy类似,所不同的是,当对象重叠时,该函数仍能正确执行,具体的实现代码在下面有详细解释。

 

4、strncpy

函数原型:extern char *strncpy(char *dest, char *src, int n); 

用法:#include <string.h>

 

功能:把src所指由NULL结束的字符串的前n个字节复制到dest所指的数组中。

说明:

        如果src的前n个字节不含NULL字符,则结果不会以NULL字符结束。

        如果src的长度小于n个字节,则以NULL填充dest直到复制完n个字节。

        src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。

        返回指向dest的指针(该指向dest的最后一个元素)

实现代码:

 

char * strncpy(char * dest,const char *src,size_t count)

{    

    char *tmp = dest;

    while (count-- && (*dest++ = *src++) != '/0')

    /* nothing */;

    return tmp;

}

 

5、strcpy:

 

函数原型:extern char *strcpy(char *dest,char *src); 

 

头文件:string.h

 

功能:把src所指由NULL结束的字符串复制到dest所指的数组中。 

 

说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。 返回指向dest的指针。如果src的结尾不是'/0'的话,那么系统会在src的结尾处自动加一个'/0'。例如:

 

#include <stdio.h>

#include <string.h>

 

void main()

{

 char array1[5]={'1','2','3','4','5'};

 char array2[5]={'a','b','c'};

 strcpy(array1,array2);

 printf("%s/n",array1);

}

 

输出结果:abc

 

函数实现代码:

 

char *strcpy(char *strDest, const char *strSrc) 

     assert((strDest!=NULL) && (strSrc !=NULL)); 

     char *address = strDest;     

     while( (*strDest++ = * strSrc++) != '/0') 

        NULL ; 

     return address ;       

}

 

二.下面重点来讲解memcpy和memmove的区别:

这两个函数的函数原型(除了名字)是一样的:

void *memcpy(void *dst, const void *src, size_t count):

void *memmove(void *dst, const void *src, size_t count);

它们都是从src所指向的内存中复制count个字节到dst所指内存中,并返回dst的值。当源内存区域和目标内存区域无交叉时,两者的结果都是一样的。但有交叉时不一样。源内存和目标内存交叉的情况有以下两种:(左边为低地址)

 

 

 

即:dst<=src 且 dst+count>src

 

 

即:src<dst且src+count>dst

下面将针对这两种情况来讨论。针对第一种交叉情况情况,dst<src且dst+count>src,memcpy和memmove的结果是一样的。请看下面的例子讲解:

int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

memcpy(a, a+4, sizeof(int)*6);和memmove(a, a+4, sizeof(int)*6);结果是:

4567896789

 

 

针对第二种情况,src<dst且src+count>dst,memcpy和memmove的结果是不一样的。请看下面的例子:

int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

memcpy(a+4, a, sizeof(int)*6)

 

 

 

memmove(a+4, a, sizeof(int)*6)

 

 

 

 

 

下面是这两个函数的具体实现:

 

 

void *memcpyMy(void *dst, const void *src, size_t count)

 

{

       void *address = dst;

 

       while (count)

      {

           *(char *)address = *(char *)src;

           address = (char *)address + 1;

           src = (char *)src + 1;

           count --;

       }

 

       return dst;

}

 

void *memmoveMy(void *dst, const void *src, size_t count)

 

{

       void *address = dst;

 

       if (dst <= src || (char*)dst >= (char *)src + count)

      {

            while (count --)

           {

                *(char *)address = *(char *)src;

                address = (char *)address + 1;

                src = (char *)src + 1;

            }

       }

 

       else

 

      {

           address = (char *)address + count - 1;

           src = (char *)src + count - 1;

           while (count --)

           {

                *(char *)address = *(char *)src;

                address = (char *)address - 1;

                src = (char *)src - 1;

            }

       }

 

       return dst;

}

以上两段代码是在vc6.0下通过测试的。

 

 

 

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/piaojun_pj/archive/2010/10/16/5945926.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值