关于C库函数的一些模拟实现以及讲解思考

memcpy函数

memcpy函数分析

首先这个函数的功能是用来进行内存拷贝的,仿照与strcpy,那么关于它的定义有如下解释

在这里插入图片描述
从图中可以看出,函数拥有三个参数,destination(目的地),source(来源于哪),num(需要几个字节),而函数的功能如下:Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination.

即将源头的内容拷贝到目的地中,拷贝num字节

在这里回顾void*

void*是一个万能指针,它可以接收任意类型的指针,但相应的这是有代价的,你不能通过它直接取出里面的内容,需要将它强制转化为某种类型的指针,才能将它取出


而在这个函数中,由于我们不知道具体要拷贝什么类型的函数,于是我们就直接将这个指针类型设置为void*

那么有了上面的分析,模拟实现如下

memcpy模拟实现

//模拟实现memcpy
#include <stdio.h>
#include <string.h>

void* my_memcpy(void* arr2, void* arr1, size_t size)
{
    
    
	while (size--)
	{
    
    
		*(char*)arr2 = *(char*)arr1;
		(char*)arr2 = (char*)arr2 + 1;
		(char*)arr1 = (char*)arr1 + 1;
	}
}

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

memmove函数

memmove函数分析

其实memmove函数和memcpy函数功能基本类似,在有些编译器上它们的功能甚至会被手动优化,那么有什么区别?

我们来看下面的例子,输出结果是多少?

void* my_memcpy(void* arr2, void* arr1, size_t size)
{
    
    
	void* ret = arr2;
	while (size--)
	{
    
    
		*(char*)arr2 = *(char*)arr1;
		(char*)arr2 = (char*)arr2 + 1;
		(char*)arr1 = (char*)arr1 + 1;
	}
	return ret;
}

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

输出结果如下
在这里插入图片描述

为什么?

这段代码的目的是把arr的数据复制到arr+2的地方去,总共复制16个字节的内容,图示如下:
在这里插入图片描述
问题就在于3和4上,这两个元素是有重叠部分的,在这个部分内的元素会发生重叠,导致拷贝出错,出错原因如下:
在这里插入图片描述
如下图,当内存中开始取代时,重叠部分的区域会来回取代,这样就导致了刚才输出的异常,那么解决方法就是现在的这个memmove函数

这个函数的功能强大在于,它可以根据dest和reso的位置确定是从前往后拷贝还是从后往前拷贝,对于上面这个情况,如果我们采取的是从后向前拷贝,模式图如下:

在这里插入图片描述
在这种模式下就可以做到拷贝,那么总结一下就得到了下面的函数实现

memmove模拟实现

void* my_memmove(void* dest, void* reso, size_t size)
{
    
    
	void* ret = dest;
	if (reso > dest)
	{
    
    
		while (size--)
		{
    
    
			*(char*)dest = *(char*)reso;
			(char*)dest = (char*)dest + 1;
			(char*)reso = (char*)reso + 1;
		}
	}
	else
	{
    
    
		while (size--)
		{
    
    
			*((char*)dest + size) = *((char*)reso + size);
		}
	}
	return ret;
}

void* my_memcpy(void* arr2, void* arr1, size_t size)
{
    
    
	void* ret = arr2;
	while (size--)
	{
    
    
		*(char*)arr2 = *(char*)arr1;
		(char*)arr2 = (char*)arr2 + 1;
		(char*)arr1 = (char*)arr1 + 1;
	}
	return ret;
}

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

从这个函数体中能看出,实际上是分为两种情况,一种情况是如果源头在目标的前面,就从前向后拷贝,如果在后面就从后向前拷贝

用这种很巧妙的方式解决了这个问题

strstr函数

strstr函数分析

char *strstr(const char *haystack, const char *needle)
在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 ‘\0’。

这是一个查找字符串的函数,在一段字符串中查找指定的字符串,如果找到了就返回地址

strstr函数模拟实现

//strstr模拟实现
#include <stdio.h>

char* my_strstr(const char* str1, const char* str2)
{
    
    
	char* s1 = (char*)str1;
	char* s2 = (char*)str2;
	char* cp = (char*)str2;
	while (*cp)
	{
    
    
		s1 = cp;
		s2 = (char*)str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
    
    
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
    
    
			return cp;
		}
	}
	return NULL;
}

int main()
{
    
    
	char str1[] = {
    
     "abcde" };
	char str2[] = {
    
     "bcd" };
	printf("%s\n", my_strstr(str1, str2));
	return 0;
}

strlen函数

函数分析

字符串函数中应用最广的函数之一,主要作用是寻找字符串中的\0,并记录在这之前有多少个字符,用来计算字符串的长度

strlen函数模拟实现

下面展示了三种strlen函数的模拟实现方式,指针,递归,和计数器

//strlen函数模拟
#include <stdio.h>
#include <string.h>

//计数器
size_t my_strlen1(const char* arrr)
{
    
    
	int ret = 0;
	while (*arrr != '\0')
	{
    
    
		ret++;
		arrr++;
	}
	return ret;
}

//指针-指针
size_t my_strlen2(const char* arr)
{
    
    
	int ret = 0;
	const char* p = arr;
	while (*arr != '\0')
	{
    
    
		arr++;
	}
	ret =(int)(arr - p);
	return ret;
}

//递归
size_t my_strlen3(const char* str)
{
    
    
	if (*str == '\0')
	{
    
    
		return 0;
	}
	else
	{
    
    
		return 1 + my_strlen3(str + 1);
	}
}

int main()
{
    
    
	char arr[] = "abcd";
	int len1 = (int) my_strlen1(arr);
	int len2 = (int)my_strlen2(arr);
	int len3 = (int)my_strlen3(arr);
	printf("%d\n", len1);
	printf("%d\n", len2);
	printf("%d\n", len3);
	return 0;
}

strcpy函数

strcpy函数分析

strcpy函数又叫做字符串拷贝函数,运用场景通常是需要把一个字符串赋予给另外一个字符串时,由于语法限定不可以使用arr1=arr2这种语句用来赋值,于是诞生了字符串复制函数。


字符串函数通常都和\0有关,这个函数也不例外,这个函数的原理就是找到字符串中的\0并把它前面的内容复制到另外一个字符串中

strcpy函数模拟实现

//strcpy函数模拟
#include <stdio.h>

void my_strcpy1(char* arr2, const char* arr1)
{
    
    
	do
	{
    
    
		*arr2 = *arr1;
		arr2++;
		arr1++;
	} while (*arr1 != '\0');
}

char* my_strcpy2(char* str2, const char* str1)
{
    
    
	char* ret = str1;
	while (*str2++ = *str1++);
	return ret;
}

int main()
{
    
    
	char arr1[] = {
    
     "abcdef" };
	char arr2[10] = {
    
     0 };
	char arr3[10] = {
    
     0 };
	my_strcpy1(arr2, arr1);
	my_strcpy2(arr3, arr1);
	printf("%s\n", arr1);
	printf("%s\n", arr2);
	printf("%s\n", arr3);
	printf("%s\n", my_strcpy2(arr3, arr1));
	return 0;
}

strcat函数

strcat函数分析

strcat函数也叫做字符串追加函数,在指定的字符串后追加要追加的部分

strcat函数模拟实现

//strcat函数模拟
#include <stdio.h>
#include <string.h>

char* my_strcat(char* arr1, char* arr2)
{
    
    
	char* ret = arr1;
	while (*arr1 != '\0')
	{
    
    
		arr1++;
	}
	while (*arr2 != '\0')
	{
    
    
		*arr1 = *arr2;
		arr2++;
		arr1++;
	}
	return ret;
}

int main()
{
    
    
	char arr1[20] = "abcdef";
	char arr2[] = "ghi";
	printf("%s\n", my_strcat(arr1, arr2));
	return 0;
}

strcmp函数

strcmp函数分析

这个函数也叫做字符串比较函数,给定两个字符串进行比较,比较的是字符串的ASCII码值,如果相等进行下一个,直到必出大小或遇到\0


如果A字符串大于B字符串,返回一个大于0的数,小于返回一个小于0的数,如果相等则返回0

strcmp函数模拟实现

//strcmp函数模拟
#include <stdio.h>
#include <string.h>

int my_strcmp(char* arr1, char* arr2)
{
    
    
	int ret = 0;
	while (*arr1 != '\0' && *arr2 != '\0')
	{
    
    
		if (*arr1 > *arr2)
		{
    
    
			ret = 1;
			break;
		}
		else if (*arr1 < *arr2)
		{
    
    
			ret = -1;
			break;
		}
		else
		{
    
    
			arr1++;
			arr2++;
		}
	}
	return ret;
}

int main()
{
    
    
	char arr1[] = {
    
     "abcde" };
	char arr2[] = {
    
     "abcde\0fg" };
	int len = my_strcmp(arr1, arr2);
	printf("%d", len);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_73899585/article/details/131094645