C语言 模拟实现memcpy与memmove函数详解

目录
  • 一、memcpy函数的介绍
    • 1.函数的声明
    • 2.函数功能与注意事项
    • 3.函数的使用
  • 二、模拟实现memcpy函数
    • 1.模拟分析
    • 2.模拟实现
  • 三、memmove函数的介绍
    • 1.函数的声明
    • 2.为什么会有memmove函数
    • 3.函数功能与注意事项
    • 4.函数的使用
  • 四、模拟实现memmove函数
    • 1.模拟分析
    • 2.模拟实现

一、memcpy函数的介绍

1.函数的声明

void * memcpy ( void * destination, const void * source, size_t num );

2.函数功能与注意事项

  • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  • 注意这个函数在遇到 '\0' 的时候并不会停下来。
  • 如果source和destination有任何的重叠,复制的结果都是未定义的。
  • memcpy函数可以拷贝任何的类型的数据,不像strcpy函数只能拷贝字符串。

3.函数的使用

#include <stdio.h>
#include <string.h>//使用memcpy函数时记得引用它的头文件
int main()
{
	int arr1[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int arr2[5] = { 0 };//总共大小为20字节
	memcpy(arr1, arr2, 20//拷贝20个字节的数据);//将arr2中的数据拷贝到arr1中
	int i = 0;
	printf("拷贝后arr1中的数据为:");
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

运行结果:

二、模拟实现memcpy函数

1.模拟分析

1.因为我们不知道我们要拷贝的是什么类型的数据,可能是char类型的数据,也可能是int类型的数据,还有可能是double类型的数据,这些不同类型数据的大小是不同的。为了实现一个能拷贝所有类型数据的memcpy函数,我们就只能一个字节一个字节的拷贝,因为最小类型的大小是一个字节,这样就能将所有类型的数据都进行拷贝了。

2.因为我们不知道传到memcpy函数的地址是什么类型,所以我们在接收传过来的地址时要用void*类型的指针来接收。

3.由于我们只需要将源地址存储的数据拷贝到目标地址里面,所以只需要改变目标地址处存储的内容,而不需要改变源地址处存储的地址。所以我们就需要用const void*类型的指针来接收源地址。

4.为了实现链式访问,我们要将传进来的目标起始地址(destination)返回。由于这个函数在执行的时候会改变destination存储的内容,所以我们要重新创建一个void*类型的指针来存储这个地址。

5.为了避免传进来的地址是空指针,我们需要用assert来断言传进来的地址不是空指针。

2.模拟实现

#include<stdio.h>
#include<assert.h>
//模拟实现memcpy
void* my_memcpy(void* dest, const void* scr, size_t count)
{
	assert(dest && scr);//断言传进来的地址不是空指针
	void* ret = dest;//保存目标起始地址
	while (count--)//拷贝源地址存储的数据
	{
		*(char*)dest = *(char*)scr;
		(char*)dest = (char*)dest + 1;
		(char*)scr = (char*)scr + 1;
	}
	return ret;//返回目标起始地址
}

//应用模拟实现的函数
int main()
{
	int arr1[] = { 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 };
	int arr2[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	my_memcpy(arr2, arr1, 24);//拷贝6个字节的数据
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

运行结果:

三、memmove函数的介绍

1.函数的声明

void * memmove ( void * destination, const void * source, size_t num );

2.为什么会有memmove函数

为什么会有memmove这个函数呢,这个还要从上面的memcpy函数说起。因为memcpy函数不能将一个数组的中的数据拷贝到自身(也就是目标数据是自己,源数据也是自己,只不过是一个数组里面不同的位置的数据拷贝到另外一个位置上),如果像这样拷贝就会出现重叠拷贝,会导致结果不是我们预期的结果。

就像下面这个代码:

//应用模拟实现的memcpy函数
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	my_memcpy(arr + 2, arr, 24);//预期出现结果为1 2 1 2 3 4 5 6 9 10
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);//实际出现结果
	}
	return 0;
}

运行结果:

出现预期结果和实际结果不同的原因:

出现这种结果的原因就是因为memcpy函数将自身数据拷贝到自身不同位置的时候出现了重叠拷贝。源数据的起始地址为arr,目标数据的起始地址arr + 2,当我们一进来memcpy这个函数的时候,我们就先将arr处的数据拷贝到arr + 2处,将arr + 1处的数据拷贝到arr + 3处,当我们想要将arr + 2处的数据拷贝到arr + 4处的时候,我们发现arr + 2处的数据已经被替换成了arr处的数据(1),于是我们就只能将1拷贝到arr + 4处;当我们要将arr + 3处的数据拷贝到arr + 5处的时候,我们发现arr + 3处的数据早已被替换成了arr + 1处的数据(2),所以我们只能将2拷贝到arr + 5处,就像这样反复的重叠拷贝,拷贝的数据一直都是1/2/1/2/1/2,直到拷贝完我们想要拷贝的字节数。

于是为了将自身的数据拷贝到自身不同的位置处,我们就需要用memmove函数来实现,memmove函数就是为了解决上面这种问题而被创造的。

3.函数功能与注意事项

  • memmove和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。

4.函数的使用

#include<stdio.h>
#include<string.h>//使用memmove函数时记得引用它的头文件
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	memmove(arr + 2, arr, 24);//预期出现结果为1 2 1 2 3 4 5 6 9 10
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);//实际出现结果
	}
	return 0;
}

这次我们发现用memmove函数来拷贝的预期结果和实际结果就一样了,下面我们就讲讲memmove函数的模拟实现。

四、模拟实现memmove函数

1.模拟分析

1.将地址传进函数和函数接收地址的方法和上面的memcpy函数是一样的,memcpy函数需要注意的地方memmove函数同样需要注意,这里就不重复讲了,嘿嘿。

2.memmove函数还需要注意的一点就是需要分析该怎么拷贝才不会重叠,下面为图解:

情况一:dest小于等于src的地址

像下面这样从前往后拷贝,这样就不会重叠了。

情况二:dest大于scr的地址

像下面这样从后往前拷贝,这样就不会重叠了。

2.模拟实现

#include<stdio.h>
#include<assert.h>
//模拟实现memmove
void* my_memmove(void* dest, const void* scr, size_t count)
{
	assert(dest && scr);//断言传进来的地址不是空指针
	void* ret = dest; //保存目标起始地址
	if (dest <= scr)//从前往后拷贝
	{
		while (count--)
		{
			*(char*)dest = *(char*)scr;
			(char*)dest = (char*)dest + 1;
			(char*)scr = (char*)scr + 1;
		}
	}
	else//从后往前拷贝
	{
		while (count--)
		{
			*((char*)dest + count) = *((char*)scr + count);
		}
	}
	return ret;
}

//应用模拟实现的函数
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	my_memmove(arr + 2, arr, 24);//预期出现结果为1 2 1 2 3 4 5 6 9 10
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);//实际出现结果
	}
	return 0;
}

运行结果

到此这篇关于C语言 模拟实现memcpy与memmove函数详解的文章就介绍到这了,更多相关C语言 memcpy函数内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 对比C语言中memccpy()函数和memcpy()函数的用法

    C语言memccpy()函数:复制内存中的内容 头文件: #include <string.h> 定义函数: void * memccpy(void *dest, const void * src, int c, size_t n); 函数说明:memccpy()用来拷贝src 所指的内存内容前n 个字节到dest 所指的地址上.与memcpy()不同的是,memccpy()会在复制时检查参数c 是否出现,若是则返回dest 中值为c 的下一个字节地址. 返回值:返回指向dest 中值为c 的

  • C语言 strcpy和memcpy区别详细介绍

    C语言 strcpy和memcpy区别详细介绍 PS:初学算法,开始刷leetcode,Rotate array的预备知识(写的代码Time Limit Exceed难过)于是百度高效算法,本篇作为预备知识. 1.strcpy和strncpy函数 这个不陌生,大一学C语言讲过,其一般形式为strcpy(字符数组1,字符串2)作用是将字符串2复制到字符数组1中去. EX: char str1[10]='',str2[]={"China"}; strcpy(str1,str2); strn

  • C语言中memcpy 函数的用法详解

    C语言中memcpy 函数的用法详解 memcpy(内存拷贝函数) c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中. void* memcpy(void* destination, const void* source, size_t num); void* dest 目标内存 const void* src 源内存 size_t num 字节个数 库中实现的memcpy函数 struct { ch

  • C语言 模拟实现memcpy与memmove函数详解

    目录 一.memcpy函数的介绍 1.函数的声明 2.函数功能与注意事项 3.函数的使用 二.模拟实现memcpy函数 1.模拟分析 2.模拟实现 三.memmove函数的介绍 1.函数的声明 2.为什么会有memmove函数 3.函数功能与注意事项 4.函数的使用 四.模拟实现memmove函数 1.模拟分析 2.模拟实现 一.memcpy函数的介绍 1.函数的声明 void * memcpy ( void * destination, const void * source, size_t

  • C语言 模拟实现strcpy与strcat函数详解

    目录 一.strcpy函数的介绍 1.函数的声明 2.函数功能与注意事项 3.函数的使用 二.模拟实现strcpy函数 1.模拟分析 2.模拟实现 三.strcat函数的介绍 1.函数的声明 2.函数功能与注意事项 3.函数的使用 四.模拟实现strcat函数 1.模拟分析 2.模拟实现 总结 这里有超详细的函数模实现分享,带大家一起来模拟实现这些函数,后续还将更新更多的函数模拟实现的文章. 一.strcpy函数的介绍 1.函数的声明 char* strcpy(char * destinatio

  • C语言文件操作中 fgets与fputs 函数详解

    C语言文件操作中 fgets.fputs 函数详解 先给出api fgets 语法: #include <stdio.h> char *fgets( char *str, int num, FILE *stream ); 函数fgets()从给出的文件流中读取[num - 1]个字符并且把它们转储到str(字符串)中. fgets()在到达行末时停止,在这种情况下,str(字符串)将会被一个新行符结束. 如果fgets()达到[num - 1]个字符或者遇到EOF, str(字符串)将会以nu

  • C语言基础之malloc和free函数详解

       本文介绍malloc和free函数的内容. 在C中,对内存的管理是相当重要.下面开始介绍这两个函数: 一.malloc()和free()的基本概念以及基本用法: 1.函数原型及说明: void *malloc(long NumBytes):该函数分配了NumBytes个字节,并返回了指向这块内存的指针.如果分配失败,则返回一个空指针(NULL). 关于分配失败的原因,应该有多种,比如说空间不足就是一种. void free(void *FirstByte): 该函数是将之前用malloc分

  • Go语言中的流程控制结构和函数详解

    这小节我们要介绍Go里面的流程控制以及函数操作. 流程控制 流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑.Go中流程控制分三大类:条件判断,循环控制和无条件跳转. if if也许是各种编程语言中最常见的了,它的语法概括起来就是:如果满足条件就做某事,否则做另一件事. Go里面if条件判断语句中不需要括号,如下代码所示: 复制代码 代码如下: if x > 10 {     fmt.Println("x is greater than 10&

  • C语言中改变目录的相关操作函数详解

    C语言fchdir()函数:改变当前工作目录 头文件: #include <unistd.h> 定义函数: int fchdir(int fd); 函数说明:fchdir()用来将当前的工作目录改变成以参数fd 所指的文件描述词. 返回值:执行成功则返回 0, 失败返回-1, errno 为错误代码. 范例 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <

  • C语言 模拟实现strlen函数详解

    目录 前言 一.strlen函数的介绍 1.strlen函数的声明 2.strlen函数的简单运用 3.注意事项 二.三种实现strlen函数的方法 1.计数器的方法 2.递归方法 3.指针-指针的方法 前言 用C语言模拟实现strlen函数,我这里有三种方法,快来看看跟你用的方法是否是一样. 一.strlen函数的介绍 1.strlen函数的声明 size_t strlen ( const char * str ): 这里函数的返回值为无符号整形(size_t),传入的是一个常量char*类型

  • 关于C语言qsort函数详解

    目录 C语言qsort函数详解 一.qsort函数是什么 二.使用qsort排序-以升序为例 1.整形数组排序 2.字符数组排序 3.字符指针数组排序 4.结构体数组排序 5.浮点型数组排序 三.使用冒泡排序思想模拟实现qsort函数 1.什么是冒泡排序 2.冒泡排序代码 3. 使用冒泡排序思想模拟实现qsort函数 C语言qsort函数详解 一.qsort函数是什么 我们可以使用  搜索库函数网址或者MSDN软件进行查找. qsort()函数:快速排序的函数  -引用stdlib.h头文件 参

  • C语言头文件<string.h>函数详解

    目录 1. strlen —— 求字符串长度 1.1 strlen 的声明与用处 1.2 strlen 的用法 1.3 strlen 的模拟实现 2. strcpy —— 字符串拷贝 2.1 strcpy 的声明与用处 2.2 strcpy 的用法 2.3 strcpy 的模拟实现 3. strcmp —— 字符串比较 3.1 strcmp 的声明与用处 3.2 strcmp 的用法 3.3 strcmp 的模拟实现 4. strcat —— 字符串追加 4.1 strcat 的声明与用处 4.

  • R语言学习笔记之lm函数详解

    在使用lm函数做一元线性回归时,发现lm(y~x+1)和lm(y~x)的结果是一致的,一直没找到两者之间的区别,经过大神们的讨论和测试,才发现其中的差别,测试如下: ------------------------------------------------------------- ------------------------------------------------------------- 结果可以发现,两者的结果是一样的,并无区别,但是若改为lm(y~x-1)就能看出+1和

随机推荐