C语言内存操作函数解析和模拟实现

请添加图片描述

内存操作函数

memset

C 库函数 void *memset(void *str, int c, size_t n) 复制字符 c(一个无符号字符)到参数 str 所指向的空间的前 n 个字节。

头文件<string.h>
声明void *memset(void *str, int c, size_t n)
参数1str – 指向要填充的内存块
参数2c – 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式
参数 3n – 要被设置为该值的字符数
返回值该值返回一个指向存储区 str 的指针

使用举例:
例如我们要初始化结构体内部的一个数组为0,我们就不用写一个循环来一步步的初始化,而是直接用memset这个函数来一步到位。
注意:memset操作内存空间是以一个字节一个字节来初始化的,比如我们想把整形数组arr前面10个元素全部初始化为3,我们这样使用msmset(arr, 3, 10*sizeof(int) ),是错误的。因为memset这样操作过后,数组前面的10个元素每一个字节都是03,但是对于int 型来说,一次要解引用4个字节 就是03 03 03 03就不是原来想要的03了。
举例使用代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>

struct S
{
	int arr[50];
	int sz;
	char c;
};

int main()
{
	struct S s;
	//想把数组前面20个元素全部初始化为0
	memset(s.arr, 0, 20 * sizeof(int));
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%d ", s.arr[i]);
	}
	printf("\n");
}

模拟实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>

void* my_memset(void* p, int c, int n)
{
	assert(p);
	void* ret = p;
	while (n--)
	{
		*(char*)p = c;
		(char*)p = (char*)p + 1;
	}
	return ret;
}


int main()
{
	char arr[50];
	//把char型数组前面20个元素初始化为 ‘&’
	my_memset(arr, '&', 20 * sizeof(char));
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%c ", arr[i]);
	}
	printf("\n");
	return 0;
}

模拟结果:
在这里插入图片描述

memcpy

C 库函数 void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1。

头文件<string.h>
声明void *memcpy(void *str1, const void *str2, size_t n)
参数1str1 – 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针
参数2str2 – 指向要复制的数据源,类型强制转换为 void* 指针
参数3n – 要被复制的字节数
返回值该函数返回一个指向目标存储区 str1 的指针

注意:

1、函数memcpy从source的位置开始向后复制n个字节的数据到destination的内存位置。
2、这个函数在遇到 ‘\0’ 的时候并不会停下来。
3、如果source和destination有任何的重叠,复制的结果都是未定义的

模拟实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>

void* my_memcpy(void* dest, const void* src, int n)
{
	assert(dest && src);
	void* ret = dest;
	while (n--)
	{
	   //每一个字节每一个字节进行拷贝
		*(char*)dest = *(char*)src;
		(char*)dest = (char*)dest + 1;
		(char*)src = (char*)src + 1;
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8 };
	int arr2[10];
	my_memcpy(arr2, arr1, 8 * sizeof(int));
	int i = 0;
	for (i = 0; i < 8; i++)
	{
		printf("%d ", arr2[i]);
	}
	printf("\n");
	return 0;
}

模拟实现结果:
在这里插入图片描述

memmove

C 库函数 void *memmove(void *str1, const void *str2, size_t n) 从 str2 复制 n 个字符到 str1,但是在重叠内存块这方面,memmove() 是比 memcpy() 更安全的方法。如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同
以上也是和memcpy函数的区别;memmove能做到memcpy的事情,但是memcpy做不到memmove的事情。
举例如下:

//比如:我想把arr1里面第一个到第四个元素拷贝到第三个到第六个位置,用的是memcpy函数
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8 };
	//把arr1里面第一个到第四个元素拷贝到第三个到第六个位置
	my_memcpy(arr1 + 2, arr1, 4 * sizeof(int));
	int i = 0;
	for (i = 0; i < 8; i++)
	{
		printf("%d ", arr1[i]);
	}
	printf("\n");
	return 0;
}

我们要达到的目标是 1 2 1 2 3 4 7 8,但是在拷贝过程中源头的第三个和第四个被改成 1和2了,所以执行后的结果为:1 2 1 2 1 2 7 8
详细过程如下:
在这里插入图片描述

所以memmove函数的作用就体现出来了。如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。
但是如何保证目标区域和源区域有重叠的话,重叠区域的字节不会被覆盖呢?
我们可以分为两种情况进行讨论:
在这里插入图片描述

memmove的模拟实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>

void* my_memmove(void* dest, const void* src, int n)
{
	assert(dest && src);
	void* ret = dest;
	//目标地址比源头地址小,从头开始拷贝
	if (dest < src)
	{
		while (n--)
		{
			//每一个字节每一个字节进行替换
			*(char*)dest = *(char*)src;
			(char*)dest = (char*)dest + 1;
			(char*)src = (char*)src + 1;
		}
	}
	else
	{
	//目标地址比源头地址大,从尾部开始拷贝
		while (n--)
		{
			*((char*)dest + n) = *((char*)src + n);
		}
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8 };
	my_memmove(arr1 + 2, arr1, 4 * sizeof(int));
	int i = 0;
	for (i = 0; i < 8; i++)
	{
		printf("%d ", arr1[i]);
	}
	printf("\n");
	return 0;
}

模拟实现结果:
在这里插入图片描述

memcmp

C 库函数 int memcmp(const void *str1, const void *str2, size_t n)) 把存储区 str1 和存储区 str2 的前 n 个字节进行比较。
当我们提取这个函数的时候,我们就会联想到strcmp这个函数,但是strcmp只能是字符串之间的比较,而memcmp可以是任何类型之间的比较。这个是memcmp函数和strcmp函数的区别之一。

头文件<string.h>
声明int memcmp(const void *str1, const void *str2, size_t n)
参数1str1 – 指向内存块的指针
参数2str2 – 指向内存块的指针
参数 3n – 要被比较的字节数
返回值1如果返回值 < 0,则表示 str1 小于 str2
返回值2如果返回值 > 0,则表示 str1 大于 str2
返回值3如果返回值 = 0,则表示 str1 等于 str2

模拟实现如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>

int my_memcmp(void* str1, void* str2, int n)
{
	assert(str1 && str2);
	//先转化为char*类型的指针,然后一个字节一个字节进行比较
	char* p1 = (char*)str1;
	char* p2 = (char*)str2;
	while (n--)
	{
		while (*p1 != *p2)
		{
			return *p1 - *p2;
		}
		p1++;
		p2++;
	}
	return 0;
}


int main()
{
	int arr1[] = { 1,2,3,4,5,6 };
	int arr2[] = { 1,2,3,4,7,8 };
	int ret = my_memcmp(arr1, arr2, 4 * sizeof(int));
	printf("%d\n",ret);
	return 0;
}

在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值