模拟实现memcpy memmove,字符类库函数的介绍,strerror,strtok的使用讲解。

strtok

在这里插入图片描述
上图是关于strtok库函数的介绍,很多小伙伴一看就头疼了,下面让我来给大家讲解一下这个库函数的作用。这个库函数的作用是分割字符串,首先我们来看函数的声明

char * strtok ( char * str, const char * delimiters );

1.delimiters参数是个字符串,定义了用作分割符的字符集合
2.第一个参数指定一个字符串,它包含了0个或者多个由delimiters字符串中一个或者多个分隔符分割的标记
3.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串
中的位置。
5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标

6.如果字符串中不存在更多的标记,则返回 NULL 指针

我们在代码中使用一下这个库函数

int main()
{
	char arr[] = "abcd.efg@abcd";
	const char delimiters[] = ".@";
	char* str = NULL;
	char arr2[30] = { 0 };
	strcpy(arr2, arr);

	for (str = strtok(arr2, delimiters); str != NULL; str = strtok(NULL, delimiters))
	{
		printf("%s\n", str);
	}

	return 0;
}

在这里插入图片描述
我们用一张图来让大家明白strtok是如何实现的
在这里插入图片描述
通过上述过程我们就实现了分割字符串的效果,这就是strtok库函数的作用。

strerror

我们在写代码时经常会报错,错误会有一个错误码,编译器会将错误码保存在错误码遍历中,C语言提供的错误码变量为errno,而库函数strerror的作用就是将错误码翻译成错误信息

在这里插入图片描述
我们可以在代码中演示一下,strerror的使用场景

#include <errno.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");

	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	return 0;
}

在这里插入图片描述
我们还可以使用perror,同样可以打印错误信息

在这里插入图片描述

一些字符类库函数

函数 如果符合下面条件就返回真
iscntrl 任何控制字符
isspace 空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
isdigit 十进制数字 0~9
isxdigit 十六进制数字,包括所有十进制数字,小写字母af,大写字母AF
islower 小写字母a~z
isupper 大写字母A~Z
isalpha 字母a~ z或A~Z
isalnum 字母或者数字,a~ z,A~ Z,0~9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空白字符
tolower 将大写字符转换成小写字符
toupper 将小写字符转换成大写字符

我们可以在编译器中简单使用几个这样的库函数

int main()
{
	char ch[] = "Test String";
	int i = 0;
	char c = 0;
	while (ch[i])
	{
		c = ch[i];
		if (isupper(c))
		{
			c = tolower(c);
		}
		putchar(c);
		i++;
	}
	return 0;
}

在这里插入图片描述

memcpy

在之前的分享中我与大家分享了strcpy库函数,实现了字符串的拷贝,那么如果我想拷贝的是一个整形数组,是否有一个库函数可以实现我的需求呢?我们今天就来介绍一下memcpy库函数,并跟大家一起模拟实现一下。
在这里插入图片描述
其实strcpymemcpy的实现思路大致相同,只不过memcpy的参数类型变成了void*这样就可以实现不同类型数据的拷贝,并且memcpy的参数中增加了一个size_t numnum的含义是:从source开始复制num个字节的数据到destination中。好了了解了以上这些后,我们在vs中使用一下这个库函数。

#include<stdio.h>
#include<string.h>

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr, 20);

	return 0;
}

在这里插入图片描述
我们通过调试可以看到,通过调用mempy库函数我们将arr数组中的5个元素拷贝到了arr2数组当中,为什么是五个元素呢?因为数组为整形数组一个元素占4个字节,我们调用memcpy时传递给num的值为20,所以需要拷贝20个字节的数据,所以拷贝了5个元素。

模拟实现

经过了上面的学习,我们可以尝试这自己模拟实现一下memcpy这个库函数。

#include<stdio.h>
#include<string.h>
#include<assert.h>

void* my_memcpy(void* dest, void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;

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

	return ret;
}

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr, 20);

	return 0;
}

在这里插入图片描述
因为memcpy函数的参数是void*类型,我们在使用参数时,需要将参数强制类型转换成char*类型,这样我们在拷贝数据时就可以一个字节一个字节的拷贝,当num为0时循环结束,我们就拷贝了num个字节的数据。

memmove

memmove库函数与memcpy库函数的主要区别就是,memmove库函数需要实现重叠内存的拷贝,而memcpy只需要实现不重叠内存的拷贝就可以了。
在这里插入图片描述
我们可以见memmove库函数的函数声明与memcpy库函数的声明其实是一样的,那么什么是重叠内存的拷贝呢?我们在代码中给大家举例说明。

模拟实现

在这里插入图片描述
如上图这个代码,我们想将红色区域的内容拷贝到绿色区域,最后的结果将数组变成1,2,1,2,3,4,5,8,9,10
在这里插入图片描述
类似于这样的拷贝就是重叠内存的拷贝,如果继续使用memcpy我们会发现数组并没有变成我们想要的数组,是因为当我们在拷贝时,将数组的第三个元素变成了1,当再次使用时元素3已经被替换成了1,所以没有达到我们期望的效果。那么如何解决这样的问题呢?当我们从前向后拷贝数组元素时,前面的数组元素会在拷贝前被改变,那么我们如果从后向前拷贝这样的问题是不是就是解决了呢。所以经过分析,当dest > src时我们从后向前拷贝,其他情况我们从前向后拷贝。 我们将模拟实现的代码进行优化

void* my_memmove(void* dest, void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;

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

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr + 2, arr, 20);

	return 0;
}

在这里插入图片描述
如图这样我们就模拟实现了库函数memmove

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悲伤猪小猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值