零基础教学必会篇(详解字符函数和字符串函数)(完结版)

本文详细介绍了C语言中几个重要的字符串和内存操作函数,包括strstr、strtok的功能及模拟实现,以及strerror、perror、memcpy、memmove、memcmp和memset的用途。通过代码示例和功能解析,帮助读者理解这些函数的工作原理和使用场景。
摘要由CSDN通过智能技术生成

各位csdn的友友们好,上次阿博给大家讲了一些简单的字符串函数的功能和模拟实现,今天就和阿博一起再上一个台阶继续拿捏它们😊😊😊

在这里插入图片描述

1.strstr的功能介绍

2.strstr函数的模拟实现

3.strtok的功能介绍

4.strerror和perror的功能介绍

5.memcpy的功能介绍

6.memcpy函数的模拟实现

7.内存重叠

8.memmove的功能介绍

9.memmove函数的模拟实现

10.memcmp的功能介绍

11.memcmp函数的模拟实现

12.memset的功能介绍

1.strstr的功能介绍
在这里插入图片描述

它的功能就是在str1中找str2,而且是第一次出现的位置,如果没有找到,则返回的是空指针,如果找到了str2,并且找到多次,它只返回第一次出现的地址

代码测试

#include<stdio.h>
#include<string.h>
int  main()
{
	char arr1[] = "abcdebcdf";
	char arr2[] = "bcd";
	//char arr2[]="bcq";
	char*p= strstr(arr1, arr2);
	if (p == NULL)
	{
		printf("找不到\n");
	}
	else
		printf("%s\n", p);
	return  0;
}

在这里插入图片描述
在这里插入图片描述

这就是strstr相关的功能了,如果找到了,友友们一定要切记返回的是第一次出现的地址.

这里阿博再给友友们拓展一些相类似的函数
1.strchr
在这里插入图片描述

这个函数的功能是在一个字符串中找字符第一次出现的位置.

2.strrchr
在这里插入图片描述

这个函数的功能是找一个字符在字符串中最后一次出现的位置.

2.strstr函数的模拟实现

逻辑分析
在这里插入图片描述
代码实现

 #include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	char* s1 = NULL;
	char* s2 = NULL;
	char* cp = (char*)str1;
	while (*cp)
	{
		s1 = cp;
		s2 = (char*)str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return  cp;
		}
		cp++;
	}
	return  NULL;
}
int  main()
{
	char arr1[] = "abcdebcdf";
	//char arr2[] = "bcd";
	char arr2[]="bcd";
	char*p= my_strstr(arr1, arr2);
	if (p == NULL)
	{
		printf("找不到\n");
	}
	else
		printf("%s\n", p);
	return  0;
}

3.strtok的功能介绍
在这里插入图片描述
这里阿博给友友们传输一些内功🥷🥷🥷

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

代码测试1

//strtok的功能介绍
int main()
{
	char arr[] = "i@love.you";
	char buf[30] = { 0 };
	strcpy(buf, arr);        //这里是在buf文件里面操作,防止原文件被改变
	const char* p = "@.";
	char*str=strtok(buf, p);
	printf("%s\n", str);

	str = strtok(NULL, p);
	printf("%s\n", str);

	str = strtok(NULL, p);
	printf("%s\n", str);
	return  0;
}

在这里插入图片描述

这种写法没有错,但是如果分隔符比较多的话,我们需要写很多行代码,所以我们换一种方法.

在这里插入图片描述
代码测试2

int main()
{
	char arr[] = "i@love.you";
	char buf[30] = { 0 };
	strcpy(buf, arr);        //这里是在buf文件里面操作,防止原文件被改变
	const char* p = "@.";
	char* str = NULL;
	for (str = strtok(buf, p); str != NULL; str = strtok(NULL, p))  //第一次我们传buf的地址,然后第二次,第三次,第四次......我们都传空指针的地址,到最后没有分割符了,str为空,跳出循环.
	{
		printf("%s\n", str);
	}
	return  0;
}

在这里插入图片描述
4.strerror和perror的功能介绍
strerror
在这里插入图片描述
代码测试

int  main()
{
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		printf("打开文件失败,原因是:%s\n", strerror(errno));
		return 1;
	}
	fclose(pf);
	pf = NULL;
	return  0;
}

在这里插入图片描述

这里阿博给友友们解答一下疑惑,其实c语言的库函数在调用失败的时候,会将一个错误码存放在一个叫:errno的变量中,当我们想知道调用库函数的时候产生了什么错误信息,就可以将errno中的错误码翻译成错误信息.

在这里插入图片描述

友友们注意,我们一定要把这个文件扩展名给打开,这样我们就可以完整的看到文件名了.

perror
在这里插入图片描述
代码测试

int  main()
{
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("打开文件失败");   //其实就可以把perror抽象的理解成printf+serror
		return 1;
	}
	fclose(pf);
	pf = NULL;
	return  0;
}

在这里插入图片描述
5.memcpy的功能介绍
在这里插入图片描述
代码测试

void test1()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 20);       //注意这里是字节个数,不是元素个数
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
}
void test2()
{
	float arr1[] = { 1.0f,2.0f,3.0f,4.0f,5.0f };
	float arr2[10] = { 0 };
	memcpy(arr2, arr1, 12);
	int i = 0;
	for (i = 0; i < 10; i++)      //注意这里是字节个数
	{
		printf("%f ", arr2[i]);
	}
}
int  main()
{
	//test1();
	test2();
	return  0;
}

在这里插入图片描述

在这里插入图片描述
6.memcpy函数的模拟实现

代码实现

#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	while (num--)
	{
		//*dest = *src;
		//dest++;
		//src++;           //err
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
void test1()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1, 20);       //注意这里是字节个数,不是元素个数
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
}

🕹️🕹️🕹️友友们注意虽然void*的指针可以接收任意类型的数据,但是这种指针不能直接解引用和加减运算.🕹️🕹️🕹️

7.内存重叠

代码测试


#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	while (num--)
	{
		//*dest = *src;
		//dest++;
		//src++;           //err
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
void test1()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	            // 1,2,1,2,3,4,5,8,9,10   我们期待的结果
	my_memcpy(arr1+2, arr1, 20);       //注意这里是字节个数,不是元素个数
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
}

在这里插入图片描述

8.memmove的功能介绍
在这里插入图片描述
代码测试

void test1()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	            // 1,2,1,2,3,4,5,8,9,10   我们期待的结果
	memmove(arr1+2, arr1, 20);       //注意这里是字节个数,不是元素个数
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
}

在这里插入图片描述
9.memmove函数的模拟实现

逻辑分析
在这里插入图片描述

代码实现

#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	if (dest < src)
	{
		while (num--)
		{
			//*dest = *src;
			//dest++;
			//src++;           //err
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);   //这里的num已经是19了
		}
	}
	return ret;
}

在这里插入图片描述
10.memcmp的功能介绍
在这里插入图片描述
代码测试

void test3()
{
	int arr1[] = { 1,2,3,4,7 };
	int arr2[] = { 1,2,3,4,6 };
	int ret = memcmp(arr1, arr2, 17);
	printf("%d\n", ret);
}

11.memcmp函数的模拟实现

代码实现

#include<assert.h>
int my_memcmp(const void* str1, const void* str2,size_t num)
{
	assert(str1 && str2);
	while (num--)
	{
		if(*(char*)str1!=*(char*)str2)
			return  *(char*)str1 - *(char*)str2;
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
	}
	return 0;
}
void test3()
{
	int arr1[] = { 1,2,3,4,7 };
	int arr2[] = { 1,2,3,4,6 };
	int ret = my_memcmp(arr1, arr2, 16);
	printf("%d\n", ret);
}
int  main()
{
	//test1();
	//test2();
	test3();
	return  0;
}

12.memset的功能介绍
在这里插入图片描述
代码实现

void  test4()
{
	char arr[] = "hello world";
	memset(arr, 'x', 5);
	printf("%s\n", arr);
}

在这里插入图片描述

友友们注意memset是以字节为单位设置的

错误示范

void test5()
{
	int arr[10] = { 0 };
	memset(arr, 1, sizeof(arr));      // 01  01  01  01,这种写法无法将每个元素设置为1
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
}

在这里插入图片描述
在这里插入图片描述

好了友友们,本期创作到这里就告一段落了,如果感觉有帮助的话,可以给阿博点个关注哦,后续会继续给友友们带来一些新的干货😊😊😊

评论 35
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿博历练记

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

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

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

打赏作者

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

抵扣说明:

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

余额充值