问题描述:在C语言标准所提供的库函数中,有关于三个常见的关于内存操作的函数:memcpy(内存拷贝),memmove(内存移动,亦可实现内存拷贝)和memset(内存块数据的初始化)。memcpy函数存在局限性,因为其移动拷贝的方式为从前向后逐一拷贝,若原串与目标串处于同一存储空间,且两串存在重叠部分,那么移动时会出现数据覆盖问题,而memmove函数则解决了这一问题,分为从前向后与从后向前两种方式移动的情况。当然,我们可以不借助库函数,自主编写函数以实现此功能,通过自主摸索学习,进而比照库函数的实现方式,能够更好地提高编写程序的能力,完善个人对于实际问题的思维方式的思索。
<span style="color:#3333ff;"><span style="font-size:24px;">//1.★memcpy(内存拷贝)</span><span style="font-size:14px;">
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
void *my_memcpy(void *dst, const void *src, int count) //形参设置为void*型,有利于扩大参数的接收面,而非仅仅局限于某一类型
{
assert(dst);
assert(src);
char *p = (char *)src; //保存原串和目标串的地址,并且强制转换为char类型
char *q = (char *)dst;
while (count--) //count用以控制循环次数,表示的是拷贝的数据个数
{
*q = *p;
q++;
p++;
}
return dst;
}</span></span>
<span style="background-color: rgb(255, 255, 255);"><span style="color:#330033;"><span style="font-size:24px;">//2.★memmove函数(内存移动</span><span style="font-size:14px;">)
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
void *my_memmove(void *dst, void *src, int count) //形参设置为void*类型,有利于扩大参数的接收面,而非仅仅局限于某一类型
{
assert((dst) && (src));
char *psrc = (char *)src; //保存目标串和原串的地址,并将其强制转换为char*型
char *pdst = (char *)dst;
if (((char *)src < (char *)dst) && ((char *)dst < ((char *)src + count))) //if语句的判断条件为上文所说的同一内存空间下存在区域重叠的情形,指针移动由从前向后变为从后向前以免发生数据覆盖问题
{
psrc = (char *)src + count - 1; //count为拷贝的数据个数,所以原地址+count-1,则指针分别移动到原串和目标串的最后一个字符处,注意要-1
pdst = (char *)dst + count - 1;
while (count--)
{
*pdst-- = *psrc--;
}
}
else //另外一种则为不重叠的情况,所以沿用了memcpy的从前向后的移动方法
{
while (count--)
{
*pdst++ = *psrc++;
}
}
return dst;
}</span></span></span>
<span style="color:#ff6666;"><span style="font-size:24px;">//3.★memset(内存块数据的重置)</span>
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
void *my_memset(void *dst, int num, int count) //参数设置为void*类型
{
assert(dst);
void *p = dst; //保存目标字符串的地址
char *pdst = dst; //定义一个同样指向目标串地址的char*指针
while (count--) //需要重置的数据元素的个数
{
*pdst = (char)num; //将要重置的值不断赋值给指针指向的内容
pdst++;
}
return p;
}</span>
※注:对于C语言基础的内存块处理函数,常用到的就是这三种,读者可自行参考C语言函数库中这三种函数的源码加以借鉴,本文代码没有库函数源码那样的健壮性和紧凑型,但是通俗易懂,比源码容易上手和练习,在自主实现的基础上,参考对照库函数的源码,可谓一举两得,更上一层楼。