精通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

  • 本节完...
相关推荐
草莓熊Lotso2 小时前
《吃透 C++ vector:从基础使用到核心接口实战指南》
开发语言·c++·算法
-雷阵雨-3 小时前
数据结构——LinkedList和链表
java·开发语言·数据结构·链表·intellij-idea
大飞pkz6 小时前
【设计模式】责任链模式
开发语言·设计模式·c#·责任链模式
gplitems1237 小时前
Gunslinger – Gun Store & Hunting WordPress Theme: A Responsible
开发语言·前端·javascript
大飞pkz8 小时前
【设计模式】六大基本原则
开发语言·设计模式·c#·六大原则
iCxhust8 小时前
Intel8259汇编串口接收转C语言
c语言·开发语言·汇编
掘根9 小时前
【Qt】布局管理器
开发语言·qt
半夏知半秋9 小时前
skynet-socket.lua源码分析
服务器·开发语言·学习·架构·lua
西猫雷婶10 小时前
random.shuffle()函数随机打乱数据
开发语言·pytorch·python·学习·算法·线性回归·numpy