C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第1张图片

之前我们讲过一些字符串函数(http://t.csdnimg.cn/ZcvCo),今天我们来讲一讲几个内存函数,那么可能有人要问了,都有字符串函数了,怎么又来个内存函数,这不是一样的么?

我们要知道之前的字符串函数只能对字符串进行一系列操作很是局限,这次的内存函数就不一样了,内存函数的范围就很广了,它可以对数组啊,或者是结构体进行操作了。

memcpy函数

它是一个内存拷贝函数,类似于字符串函数strcpy。

memcpy的头文件是

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第2张图片

int main() {
	int arr1[10] = { 0 };
	int arr2[] = { 1,2,3,4,5 };
	memcpy(arr1, arr2, 20 );
	return 0;
}

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第3张图片

1、上面的例子就是两个数组,传的也是整形,所以就不能用strcpy,所以就体现了memcpy的重要性和通用性。

2、这个num一定要注意是字节的大小,所以上面的例子传了5个整数int,所以字节大小就是20。

 那么我们该如何对他进行模拟实现呢?

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

int main() {
	int arr1[10] = { 0 };
	int arr2[] = { 1,2,3,4,5 };
	my_memcpy(arr1, arr2, 20 );
	return 0;
}

这里我们进行了一个模拟实现:

1、首先我们因为要考虑传的参数都可能不同,所以为了通用性,我们这里用void*来接受各种类型的指针。

2、其次当进行拷贝的时候,由于是一个字节一个字节进行的,所以我们只能转换成(char*)来进行交换。

3、交换完之后,我们还需要将dest和src进行后移,移动到下一个字节待交换,因为强制类型转换是临时性的,所以这里在进行移动的时候还需要进行一次强制类型转换。

4、sz是总字节大小,所以用做循环的变量,来控制循环。

memmove函数

 刚刚的memcpy函数是用来进行,两个之间的拷贝,那么这个memove函数是用来进行同一个内存块的拷贝。

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第4张图片

int main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr+2, arr, 12 );
	return 0;
}

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第5张图片

 思考memmove的模拟实现

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第6张图片

但是这个思路到底能否实现呢? 

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第7张图片

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第8张图片

那么只是用从后向前拷贝就可以解决所有问题么? 

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第9张图片

所以这个我们就要进行分类讨论了 

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第10张图片

可以看到上面这个图,我们可以看到,最后通过我们的分析可以知道,我们当destsrc时要进行从后向前拷贝。

那么我们来实现一下代码:

void* my_memmove(void* dest, void* src, size_t sz) {
	assert(dest && src);
	void* ret = dest;
	while (sz--) {
		if (dest < src) {
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
		else {
			*((char*)dest + sz) = *((char*)src + sz);
		}
	}
	return ret;
}
int main() {
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr+2, arr, 12 );
	return 0;
}

我们用while循环sz为循环变量,当dest

 memset函数

这个函数可以将内存块进行指定更改,例如:

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第11张图片

我们可以看到arr代表首元素地址,所以从数组第一个1开始,向后的12个字节,也就是3个int整形,所以我们看到内存里面的前三个被替换成了0。

另外也可以替换字符串

int main() {
	char arr[] = { "Hello world" };

	memset(arr+6 ,'x', 3);
	printf("%s", arr);
	return 0;
}

 我们可以替换字符串就像这样

但是当用这个函数的时候有一个点:

int main() {
	int arr[] = { 1,2,3,4,5,6 };

	memset(arr+1 ,1, 8);
	return 0;
}

 这个函数我们想要把2,3也都变成1,但是我们运行结果却不是

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第12张图片

我们发现并不是更改成了1,当我们用16进制看的时候会发现:

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第13张图片

它是将每一个字节都更改成了1,所以导致最后的值很大。 

 memcmp函数

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第14张图片

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第15张图片

可以看到,由于memcmp是按照字节比较的所以,当我们取前三个元素的字节时,arr1和arr2都是一样的,所以输出结果就是0。

但是当我改成:

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第16张图片

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)_第17张图片

07比04大所以,arr2大于arr1返回的是小于0的值。 

 感谢大家的观看!!!我们下次再见

你可能感兴趣的:(c语言,开发语言,基础能力)