前言:

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



正文:

1. memcpy的使用和模拟实现

1.1 memcpy的使用

首先我们来了解一下memcpy的标准形式与参数
它的作用是将一些值拷贝在另一处

void * memcpy ( void * destination, const void * source, size_t num );

void*为返回类型

void* destination为“复制目标地点”

const void* source为“复制源”

size_t num为“复制值的字节数”

接着我们来看一下memcpy究竟是什么效果

#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;
}

运行结果:

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函数是怎么交换的吗?
以下展示:

在这里插入图片描述

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

*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;

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

#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;
}

运行结果完全一致:

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来拷贝一下:

#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;
}

运行结果:

0 1 2 3 4 5 6 7 8 9
0 1 2 0 1 2 0 1 8 9

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

while (num--)
{
	*((char*)dest + num)= *((char*)src + num);
}

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

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的 “升级版
因为他完全可以杜绝掉拷贝有交集重叠的问题
所以,他们两个几乎完全一致:

void * memmove ( void * destination, const void * source, size_t num );

void*为返回类型

void* destination为“复制目标地点”

const void* source为“复制源”

size_t num为“复制值的字节数”

3. memset的使用

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

void * memset ( void * ptr, int value, size_t num );

这里直接展示一个实例:

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

运行结果:

helloxxxxxx

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

4. memcmp的使用

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

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

在这里插入图片描述

如果前者大就返回正值,反之为负,相等为正
这里直接拿来主义一个例子:

#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;
}

运行结果:

'DWgaOtP12df0' is greater than 'DWGAOTP12DF0'.

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

  • 本节完…
Logo

更多推荐