常见有关内存操作函数的实现(不借助库函数)

问题描述:在C语言标准所提供的库函数中,有关于三个常见的关于内存操作的函数:memcpy(内存拷贝),memmove(内存移动,亦可实现内存拷贝)和memset(内存块数据的初始化)。memcpy函数存在局限性,因为其移动拷贝的方式为从前向后逐一拷贝,若原串与目标串处于同一存储空间,且两串存在重叠部分,那么移动时会出现数据覆盖问题,而memmove函数则解决了这一问题,分为从前向后与从后向前两种方式移动的情况。当然,我们可以不借助库函数,自主编写函数以实现此功能,通过自主摸索学习,进而比照库函数的实现方式,能够更好地提高编写程序的能力,完善个人对于实际问题的思维方式的思索。


★memcpy(内存拷贝)

#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;
}



int main()
{
int i = 0;
int arr[] = {1,2,3,4,5,6,7,8,9,10};   //调用my_memcpy函数中参数的含义是从第三个元素开始将其后的四个元素复制到第七个元素开始往后的位置处,也就是将3,4,5,6拷贝到7,8,9,10处
int len = sizeof(arr) / sizeof(arr[0]);
my_memcpy(arr+6,arr+2,16);    //传参时注意原数组的大小,以免越界。因为调用函数强制转换为char类型的,而原数组为整型,所以该处由4个int大小的偏移变为16个char大小偏移量才会移动与期望值相同的结果
for (i = 0; i < len; i++)
{
printf("%d ",arr[i]);
}
printf("\n");
system("pause");
return 0;
}

wKiom1ZQiKvxMU6UAAAX0ObEenw822.png




★memmove函数(内存移动)
#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;
}



int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int i = 0;
int len = sizeof(arr) / sizeof(arr[0]);
my_memmove(arr+4,arr+2,16);  //注意参数调用的目标是从第三个元素开始拷贝其后的4个元素大小,拷贝至第五个元素处向后的4个元素的位置处。也就是说将3,4,5,6拷贝至5,6,7,8位置处,该处存在内存重叠的现象若采用从前向后的拷贝方式,会发现3,4拷贝到5,6处,指针再移动到原5,6处时会发现5,6已被拷贝的3,4元素覆盖,所以改用从后向前的拷贝方式
for (i = 0; i < len;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
system("pause"); 
return 0;
}

//注:若采用从前向后的移动方式,其结果为1,2,3,4,3,4,3,4,9,10,会发现与原期望的结果不相符。

wKioL1ZQjgqRbImaAAAanmJggnA927.png



★memset(内存块数据的重置)
#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;
}




int main()
{
int i = 0;
int arr[] = {1,2,3,4,5,6,7,8,9,10};
int len = sizeof(arr) / sizeof(arr[0]);
my_memset(arr,0,20);     //arr为数组的首地址,0为要重置的值,20是因为重置五个元素,因为其为整型,而调用函数时强制转化为字符型,所以5个int的偏移量等同于20个char的大小偏移量
for (i = 0; i < len; i++)
{
printf("%d ",arr[i]);
}
printf("\n");
system("pause");
return 0;
}

wKiom1ZQkYPRutmFAAAcEewoQcQ133.png

你可能感兴趣的:(常见有关内存操作函数的实现(不借助库函数))