精通C语言(1.内存函数)


前言:

随着指针篇的完结,C语言大部分知识点其实已经全部被学完,下面我们来看一下几个C语言内置的一些内存函数,包括memcpy、memmove、memset和memcmp,如果各位观众有兴趣的话,不妨跟着我来了解一下他们的用法,快记好笔记~


文章目录

    • 前言:
    • 正文:
      • [1. memcpy的使用和模拟实现](#1. memcpy的使用和模拟实现)
        • [1.1 memcpy的使用](#1.1 memcpy的使用)
        • [1.2 memcpy的模拟实现](#1.2 memcpy的模拟实现)
      • [2. memmove的使用和模拟实现](#2. memmove的使用和模拟实现)
      • [3. memset的使用](#3. memset的使用)
      • [4. memcmp的使用](#4. memcmp的使用)

正文:

1. memcpy的使用和模拟实现

1.1 memcpy的使用

首先我们来了解一下memcpy的标准形式与参数

它的作用是将一些值拷贝在另一处

c 复制代码
void * memcpy ( void * destination, const void * source, size_t num );

void*为返回类型
void* destination为"复制目标地点"
const void* source为"复制源"
size_t num为"复制值的字节数"
接着我们来看一下memcpy究竟是什么效果

c 复制代码
#include <stdio.h>
#include <string.h>
#include <assert.h>

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

运行结果:

c 复制代码
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1.2 memcpy的模拟实现

首先参数的确定是和原函数一样的,这样的话确定了参数,然后我们来思考一下怎么去"copy "

还记得我们之前qsort函数是怎么交换的吗?

以下展示:

同理,我们这里也用这个方法,因为不管是什么类型,都能以单个字节来赋值或者说拷贝:

c 复制代码
*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;

解决了这个大问题以后,我们只需要确定返回的是"目标地址"就好了,下面是完整代码和使用:

c 复制代码
#include <stdio.h>
#include <string.h>
#include <assert.h>

void* my_memcpy(void* dest, const void* src, size_t num);

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

void* my_memcpy(void* dest, const void* src, size_t num)
{
	const void* ret = dest;
	assert(dest && src);
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

运行结果完全一致:

c 复制代码
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

2. memmove的使用和模拟实现

memmove是干什么的,和memcpy有什么区别?

在讨论这个问题之前,我们先再用memcpy来拷贝一下:

c 复制代码
#include <stdio.h>
#include <string.h>
#include <assert.h>

void* my_memcpy(void* dest, const void* src, size_t num);

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

void* my_memcpy(void* dest, const void* src, size_t num)
{
	const void* ret = dest;
	assert(dest && src);
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

运行结果:

c 复制代码
0 1 2 3 4 5 6 7 8 9
0 1 2 0 1 2 0 1 8 9

我们发现他并没有完全的拷贝到位,而是出现了重复,如果仔细分析的话就会发现是因为之前拷贝的影响到了后面的值(因为有交集)

这样的话我们不妨从后面开始赋值:

c 复制代码
while (num--)
{
	*((char*)dest + num)= *((char*)src + num);
}

这样的话好像出现了另一种情况,便出现了分类:

这样处理一下:

c 复制代码
void* my_memmove(void* dest, const void* src, size_t num)
{
	const void* ret = dest;
	assert(dest && src);
	if (dest < src)
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		while (num--)
		{
			*((char*)dest + num)= *((char*)src + num);
		}
	}
	return ret;
}

如果注意细节的话就能发现这个函数其实就是my_memmove函数

接下来讲解一下什么是memmove,这个函数其实可以理解为一个memcpy的 "升级版 "

因为他完全可以杜绝掉拷贝有交集重叠的问题

所以,他们两个几乎完全一致:

c 复制代码
void * memmove ( void * destination, const void * source, size_t num );

void*为返回类型
void* destination为"复制目标地点"
const void* source为"复制源"
size_t num为"复制值的字节数"

3. memset的使用

memset有点像是直接给内存赋值的一个函数

c 复制代码
void * memset ( void * ptr, int value, size_t num );

这里直接展示一个实例:

c 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
	char str[] = "hello world";
	memset(str+5, 'x', 6);
	printf(str);
	return 0;
}

运行结果:

c 复制代码
helloxxxxxx

通过实例我们可以发现这个函数就是把ptr这个地址以后的值赋成value,一共赋num个字节

4. memcmp的使用

c 复制代码
int memcmp ( const void * ptr1, const void * ptr2, size_t num );

ptr1ptr2两个是要比较的地址,num是比较的字节数

如果前者大就返回正值,反之为负,相等为正

这里直接拿来主义一个例子:

c 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
 char buffer1[] = "DWgaOtP12df0";
 char buffer2[] = "DWGAOTP12DF0";
 int n;
 n = memcmp(buffer1, buffer2, sizeof(buffer1));
 if (n > 0) 
 printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
 else if (n < 0) 
 printf("'%s' is less than '%s'.\n", buffer1, buffer2);
 else 
 printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
 return 0;
}

运行结果:

c 复制代码
'DWgaOtP12df0' is greater than 'DWGAOTP12DF0'.

证明了buffer1[]更大一些,原因是g的ASCII码比G的大32

  • 本节完...
相关推荐
侯小啾33 分钟前
【03】C语言 强制类型转换 与 进制转换
c语言·数据结构·算法
徐同保1 小时前
tailwindcss暗色主题切换
开发语言·前端·javascript
蓝纹绿茶1 小时前
bash:**:pip:***python: 错误的解释器: 没有那个文件或目录
开发语言·python·pip
云知谷2 小时前
【经典书籍】C++ Primer 第15章类虚函数与多态 “友元、异常和其他高级特性” 精华讲解
c语言·开发语言·c++·软件工程·团队开发
START_GAME2 小时前
深度学习Diffusers:用 DiffusionPipeline 实现图像生成
开发语言·python·深度学习
不爱编程的小九九2 小时前
小九源码-springboot088-宾馆客房管理系统
java·开发语言·spring boot
Evand J3 小时前
【MATLAB例程】到达角度定位(AOA),平面环境多锚点定位(自适应基站数量),动态轨迹使用EKF滤波优化。附代码下载链接
开发语言·matlab·平面·滤波·aoa·到达角度
细节控菜鸡3 小时前
【2025最新】ArcGIS for JS 实现随着时间变化而变化的热力图
开发语言·javascript·arcgis
Pluto_CSND4 小时前
Java实现gRPC双向流通信
java·开发语言·单元测试
原来是猿5 小时前
谈谈环境变量
java·开发语言