问题描述:在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语言函数库中这三种函数的源码加以借鉴,本文代码没有库函数源码那样的健壮性和紧凑型,但是通俗易懂,比源码容易上手和练习,在自主实现的基础上,参考对照库函数的源码,可谓一举两得,更上一层楼。