C语言内存函数

目录

前言

[1. memcpy 使⽤和模拟实现](#1. memcpy 使⽤和模拟实现)

[1.1 memcpy的使用](#1.1 memcpy的使用)

[1.1 memcpy模拟实现](#1.1 memcpy模拟实现)

[2. memmove 使⽤和模拟实现](#2. memmove 使⽤和模拟实现)

[2.1 memmove的使用](#2.1 memmove的使用)

[2.2 memmove模拟实现](#2.2 memmove模拟实现)

[3. memset 函数的使⽤](#3. memset 函数的使⽤)

[4.memcmp 函数的使用](#4.memcmp 函数的使用)

结语


前言

上期我们学习了字符函数以及字符串函数,但是字符串函数仅仅只能对字符进行操作,那么这次我们来学习一下内存函数


在C语言中内存函数是一组用于内存操作的标准库函数,它们定义在 <string.h>头文件中,这些函数用于复制、设置、比较内存区域等,接下来我们来学习一下C语言中常用的内存函数。

1. memcpy 使⽤和模拟实现

memcpy与strcpy非常相似,但是strcpy只能对字符进行复制操作,而memcpy可以对任意类型的数据进行复制操作。

1.1 memcpy的使用

• 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。

• 这个函数在遇到 '\0' 的时候并不会停下来。

• 如果source和destination有任何的重叠,复制的结果都是未定义的。

memcpy的使用:

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

运行结果:

可以这里的num参数为20, 表示从 arr1 复制20个字节的数据到 arr2中,因为这里复制的内容为整数,整形的大小占4个字节,所以arr2从arr1中复制了前5个数字(也就是20个字节的数据)

1.1 memcpy模拟实现

既然知道了memcpy函数是如何使用的,那么我们接下来探索一下memcpy是如何实现的

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

运行结果:

我们可以看见模拟实现的my_memcpy函数与上面使用的memcpy函数的运行结果是一样的

从中memcpy的前两个形参使用的是void *类型来接收的,void *类型不能进行解引用和加减运算,所以在解引用和加减运算之前需要强制转换成char *类型进行操作

函数的返回值是void*类型,返回的是目标地址,所以在进行指针运算前,我们需要先创建一个指针(ret)存储目标地址,当复制操作完成后,返回目标地址

注意这里的dst和src是指针变量,所以在使用前用assert断言判断一下是否为NULL(空指针),并且因为src指针指向的数据是不能被修改的,所以这里用const进行修饰。

注意:memcpy只负责处理内存不重叠的情况,对于重叠内存拷贝使用memmove

**2.**memmove 使⽤和模拟实现

memmove函数的参数与memcpy函数是一样的

• 和memcpy的差别就是memmove函数处理的源内存块和⽬标内存块是可以重叠的。

• 如果源空间和⽬标空间出现重叠,就得使⽤memmove函数处理。

2.1 memmove的使用

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

运行结果:

那么为什么memmove函数能够处理内存重叠的情况呢?接下来我们来模拟实现一下memmove函数。

2.2 memmove模拟实现

#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memmove(void* dst, const void* src, size_t count)
{
	void* ret = dst;
	if (dst <= src || (char*)dst >= ((char*)src + count))
	{
		
		while (count--) 
		{
			*(char*)dst = *(char*)src;
			dst = (char*)dst + 1;
			src = (char*)src + 1;
		}
	}
	else 
	{
		dst = (char*)dst + count - 1;
		src = (char*)src + count - 1;
		while (count--) 
		{
			*(char*)dst = *(char*)src;
			dst = (char*)dst - 1;
			src = (char*)src - 1;
		}
	}
	return(ret);
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1 + 2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

memmove的模拟实现与memcpy是相似的,但是这里需要分为两种情况讨论:

  1. 目标地址>源内存地址

如果目标地址 > 源内存地址,那么我们就需要将数据从后向前 进行拷贝,如果从前向后进行拷贝就会发生下面的现象

当我们从后面向前拷贝就不会出现这种现象:

  1. 目标地址<源内存地址

如果目标地址 < 源内存地址,那么我们就需要将数据从前向后进行拷贝

  1. 目标地址=源内存地址

当目标地址=源内存地址时,既可以使用从前向后 的方式拷贝也可以使用从后向前的方式拷贝。

3. memset 函数的使⽤

memset是⽤来设置内存的,将内存中的值以字节为单位设置成想要的内容。

•ptr表示更改的起始地址

•value表示更改的内容

•num表示更改的字节数

memset的使用:

int main()
{
	char str[] = "hello world";
	memset(str, 'x', 6);
	printf(str);
	return 0;
}

运行结果:

memset函数将str数组中的前6个字节的数据更改成了 'x'

4.memcmp 函数的使用

memcmp是用于比较两块内存

将指针 1 所指内存块的前 num 个字节与指针 2 所指内存块的前num个字节进行比较,如果它们完全匹配,则返回零,否则返回一个不等于零的值,表示哪个更大。

返回值如下:

memcmp函数的使用:

这里我们比较的是两个整形数组前4个数据的大小, 一个整形的大小为4个字节,所以比较的是16个字节数据的大小,arr前16个字节的数据<arr2前16个字节的数据,所以返回值为-1。

结语

那么以上就是C语言中常用的内存函数,学完内存函数后,对于复制、设置、比较等操作就不仅仅只局限在字符中了,也可以对任意类型的数据进行复制、设置、比较等操作。希望大家看完后能够明白这些函数是如何使用的,在此感谢大家的观看~

相关推荐
love_and_hope4 分钟前
Pytorch学习--神经网络--搭建小实战(手撕CIFAR 10 model structure)和 Sequential 的使用
人工智能·pytorch·python·深度学习·学习
Chef_Chen7 分钟前
从0开始学习机器学习--Day14--如何优化神经网络的代价函数
神经网络·学习·机器学习
芊寻(嵌入式)17 分钟前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
一颗松鼠26 分钟前
JavaScript 闭包是什么?简单到看完就理解!
开发语言·前端·javascript·ecmascript
有梦想的咸鱼_27 分钟前
go实现并发安全hashtable 拉链法
开发语言·golang·哈希算法
海阔天空_201333 分钟前
Python pyautogui库:自动化操作的强大工具
运维·开发语言·python·青少年编程·自动化
天下皆白_唯我独黑40 分钟前
php 使用qrcode制作二维码图片
开发语言·php
QAQ小菜鸟43 分钟前
一、初识C语言(1)
c语言
夜雨翦春韭44 分钟前
Java中的动态代理
java·开发语言·aop·动态代理
小远yyds1 小时前
前端Web用户 token 持久化
开发语言·前端·javascript·vue.js