【C语言进阶】---常见内存函数

内存函数

🎈🎈 作者 : @whispar
🎈🎈专栏 : C语言从无到有

✨放低姿态,空杯心态✨
在这里插入图片描述


内存函数可在任意类型使用,字符串函数只能比较字符串,内存函数不关注’\0’, 只关注要拷贝的字节数

一、memcpy

void * memcpy ( void * destination, const void * source, size_t num )
✔功能演示:参数类型必须是void*。因为memcpy函数是内存拷贝函数,它必须什么类型都能接收。

函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置,这个函数在遇到 ‘\0’ 的时候并不会停下来。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main() {
	int arr1[] = {1,2,3,4,5,6,7,8,9 };
	int arr2[10] = {0};
	memcpy(arr2, arr1, 20);
	for (int i = 0; i < 10; i++) {
		printf("%d", arr2[i]);
	}
	return 0;
}

image-20220713110855860

模拟实现memcpy

✔void 类型不能进行解引用操作和++运算,在解引用操作和++运算之前,要进行强制类型转换。并且因为此函数是一个字节一个字节的拷贝,所以要将ptr1和ptr2变量强制类型转化为char*类型
✔目标变量dest的地址需要存放在一个临时指针变量中,因为dest在循环体中一直是变化的
✔将dest和sour指针变量assert断言,使其不为NULL。并且因为sour是不能改变的,所以用const修饰,以保护起来。
*

image-20220714214420358

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* sour, size_t num){
	assert(dest && sour);
	void* ret = dest;
	while(num--){
		*(char*)dest = *(char*)sour;
		dest = (char*)dest + 1;
		sour  = (char*)sour + 1;
	}
	return ret;
}
int main() {
	int arr1[] = {1,2,3,4,5,6,7,8,9 };
	int arr2[10] = {0};
	my_memcpy(arr2, arr1, 20);
	for (int i = 0; i < 10; i++) {
		printf("%d", arr2[i]);
	}
	return 0;
}

memcpy不支持自身内部拷贝,可能存在覆盖,主要负责拷贝两块独立空间中的数据,重叠内存拷贝使用memmove

二、memmove

void * memmove ( void * destination, const void * source, size_t num )
✔功能实现:如果源空间和目标空间出现重叠,就得使用memmove函数处理
#include<stdio.h>
int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10};
	int arr2[10] = {0};
	memmove(arr1, arr1+3, 20);
	for (int i = 0; i < 10; i++) {
		printf("%d", arr1[i]);
	}
	return 0;
}

image-20220713164029182

模拟实现memmove

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

为避免出现空间重叠现象,根据dest 和 sour 的位置分情况处理,选择从前向后或从后向前拷贝

image-20220714194637865

image-20220714195435369

#include<assert.h>
#include<stdio.h>
void* my_memmove(void* dest, const void* sour, size_t num) {
	assert(dest && sour);
	void* ret = dest;
	if (dest < sour)
	{
	//前向后拷贝
		while (num--) 
		{
			*(char*)dest = *(char*)sour;
			dest = (char*)dest + 1;
			sour = (char*)sour + 1;
		}
	}
	else
	{
	//后向前拷贝
		while (num--)
		{
			*((char*)dest + num) = *((char*)sour + num);
		}
	}
	return ret;
}

三、memcmp


int memcmp ( const void * ptr1, const void * ptr2, size_t num )
✔功能实现:比较两个内存块,将 ptr1 所指向的内存块的前 num 个字节与 ptr2 指向的前num字节数进行比较, 返回不同意义的值
返回值表明
>0在两个内存块中不匹配的第一个字节在 ptr1 中的值大于在 ptr2 中的值
0两个内存块的内容相等
<0在两个内存块中不匹配的第一个字节在 ptr1 中的值小于在 ptr2 中的值
#include<stdio.h>
#include<string.h>
int main(){
	int arr1[] = { 1,5,4,5 };//01 00 00 00/ 05 00 00 00/ 04 00 00 00 /05 00 00 00
	int arr2[] = { 1,3,5,6 };//01 00 00 00/ 03 00 00 00 /05 00 00 00/ 06 00 00 00
	int ret = memcmp(arr1, arr2, 12);//arr1 > arr2
	printf("%d", ret);
	return 0;
}
image-20220714211211694

模拟实现 memcpy()

✔void 类型不能进行解引用操作和++运算,在解引用操作和++运算之前,要进行强制类型转换。并且因为此函数是一个字节一个字节的拷贝,所以要将ptr1和ptr2变量强制类型转化为char*类型*


#include<stdio.h>
#include<assert.h>
int my_memcmp(const void* ptr1, const void* ptr2, size_t num) {
	assert(ptr1 && ptr2);
	while (num-- && *(char*)ptr1 == *(char*)ptr2){
		      ptr1 = (char*)ptr1 +1;
		      ptr2 = (char*)ptr2 +1;
	    }
	return(*(char*)ptr1 - *(char*)ptr2);
}
int main(){
	//char arr1[] = "hello world";
	//char arr2[] = "hello bilibili";
	int arr1[] = { 1,5,7,5 };
	int arr2[] = { 1,5,7,6};
	int ret = my_memcmp(arr1, arr2, 12);
	if (ret == 0)
		printf("==\n");
	else if (ret < 0)
		printf("<\n");
	else
		printf(">\n");
	return 0;
}

四、memset()


void * memset ( void * ptr, int value, size_t num );
✔功能实现:将 ptr 所指向的内存块的前num个字节数设置为指定值
#include<stdio.h>
int main() {
	char arr[] = "hello bilibili";
	memset(arr, 'x', 5);
	printf("%s", arr);
	return 0;
}
image-20220714220003032

模拟实现memset()

void* my_memset(void* ptr, int value, size_t num) {
	assert(ptr);
	void* ret = ptr;
	while (num--){
		*(char*)ptr = value;  //赋值
		ptr = (char*)ptr + 1; //前移
	}
	return ret;
}

相信看到这里,大家已经对常见的内存函数已经有一定了解,如果你感觉这篇博客对你有帮助的话,不要忘了一键三连支持一下再离开噢!

  • 30
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 37
    评论
评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

署前街的少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值