字符串库函数的使用与模拟

我的博客主页:转送门


文章目录


前言

本章主要对字符串涉及到部分常用库函数进行使用和模拟实现,对涉及到的常用字符函数进行实现,并参考常规实现和库函数实现的代码差异。

一、库函数的学习和使用方式

    库函数学习与使用标签页:传送门

      这是一个面向 C++ 编程语言的在线资源和社区网站。它的主要作用包括:

  1. 教育和学习资源:提供了大量关于 C++ 编程语言的教程、文档和示例代码。这对于初学者和有经验的程序员来说都是非常有用的,可以帮助他们学习和理解 C++ 的各种概念和语法。

  2. 参考文档:网站上有详细的 C++ 标准库文档,包括各种类、函数和头文件的描述。这对于开发人员在编写 C++ 程序时查找参考信息非常方便。

  3. 论坛和社区:cplusplus.com 提供了一个论坛和社区,允许开发人员和学习者在其中讨论C++ 相关的话题、提出问题和寻求帮助。这是一个互动的平台,使人们能够与其他 C++ 程序员建立联系和分享经验。

  4. 工具和资源:网站还提供了一些与 C++ 开发相关的工具和资源,如在线编译器、代码示例、书籍推荐等。

常规使用方式——库函数查询:先返回老版本

二、strlen函数的使用及模拟

有人说英文看着头疼怎么办,简单的方式就是用谷歌或者edge自带的页面翻译功能,但是可能导致显示部分的问题,但是能让你看清楚大概的函数解释。

右键翻译

strlen函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	if (strlen("abc")> strlen("abcdef") > 0)
	{
		printf("大于\n");
	}
	else
	{
		printf("小于等于\n");
	}
	return 0;
}

strlen函数的模拟

strlen的实现逻辑

strlen是对字符串的一个遍历查找,找到 ‘\0’ 后返回遍历次数即是字符串的长度。

首先观察库函数部分的声明

size_t strlen ( const char * str );
可以看见函数是以无符号整形为返回值类型量的。这一点不难理解,字符串的长度不能为负数,因此返回值为一个无符号整形,所以在后面的函数使用过程中
不能出现(strlen(str1)-strlen(str2)<0)这种类型的比较两个数组的关系的方式,因为其为无符号的运算方式,会导致其值无法小于0,判断也会出错。

两种解决办法:
一种是使用的时候对函数返回值后面进行强制类型转换。
另一种是使用其他的比较方式,不使用值比较的方式。

其次,对库函数逻辑部分进行分析

移动字符串首元素的地址,移动一次计数器增加一次,最后遇到‘\0’,返回count。

代码实现

#include<stdio.h>
//模拟实现strlen
size_t my_strlen(const char* s)
{
	int count = 0;
	while (*s++ != '\0')
	{
		count++;
	}
	return count;
}
int main()
{
	char str1[] = "abde";
	char str2[] = "sadndd";

	printf("str1 %d str2 %d", my_strlen(str1),my_strlen(str2));

	return 0;
}

三、strcmp函数的使用及模拟

老样子,读文档中函数的使用方法和解释部分,不会的一键翻译。

strcmp函数的使用

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

int main()
{
    char str1[] = "abbcd";
    char str2[] = "abbdd";
    if (strcmp(str1, str2) < 0)
    {
        printf("%s 比 %s 小", str1, str2);
    }
    else if(strcmp(str1, str2) == 0)
    {
        printf("%s 和 %s 相等", str1, str2);

    }
    else
    {
        printf("%s 比 %s 大", str1, str2);
    }

    return 0;
}

strcmp函数的模拟

strcmp的实现逻辑

strcmp是对两个字符串的大小比较,通过依次从字符串首元素依次向下比较。

字符比较(character comparison)是指按照字典次序对单个字符或字符串进行比较大小的操作,一般都是以ASCII码值的大小作为字符比较的标准。

当两者字符比较到 \0",其他部位全部相同时字符串大小相等。

如果前字符串大于后者字符串返回大于零的数值。

如果前字符串小于后者字符串返回小于零的数值。

首先观察库函数部分的声明

int strcmp ( const char * str1, const char * str2 );
函数的返回部分一个整形,参数部分为指针,通过const进行了指针修饰。

其次,对库函数逻辑部分进行分析

通过对两个字符串的指针的移动,截止条件为一个字符串找到了'\0',依次比较各位大小,当发现两者不相同时候,返回值。

这个时候我们可以思考一下,返回值怎么去确定。

这里有几种确定方式:

一种是通过分支判断语句对不同情况进行分别返回值,而判断语句又可以分为元素大小判断和差值值判断。

另一种是直接返回两者差值。

后者直接省去了大部分的代码语句。

此外,函数需要确定传入字符串地址的有效性。(通过assert进行参数断言,判断有效性)

代码实现

#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* s1, const char* s2)
{
	assert(s1);
	assert(s2);
	while (*s1 == *s2)
	{
		if (*s1 == '\0')
		{
			return 0;
		}
		s1++;
		s2++;
	}
		return  (*s1 - *s2);
}

  四、strcpy函数的使用及模拟

老样子,读文档中函数的使用方法和解释部分,不会的一键翻译。(尽管有些显示错误,但结果是好的)

strcpy函数的使用

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "ILOVEYOU";
	char cpy[20] = { 0 };
	strcpy(cpy, arr);
	printf("原字符数组%s  —》 拷贝字符数组%s", arr, cpy);
	return 0;
}

运行结果:

strcpy函数的模拟

strcpy的实现逻辑

函数的实现逻辑比较简单,就是将一个字符串拷贝到一份字符数组即可。因为考虑到需要拷贝到字符串过于长,所以需要准备一个比较长的数组去存储这个字符串,并把字符串的的'\0'也需要放到数组。

首先观察库函数部分的声明

char * strcpy ( char * destination, const char * source );

函数的返回部分为一个指针变量,参数部分传递的是两个地址,前者为需要传递拷贝到字符串。后者为一个目的地数组。

其次,对库函数逻辑部分进行分析

逻辑部分需要注意的是,拷贝完后的数组需要使用,因此需要保存首元素位置,不能去更改它,并且需要拷贝到字符串也要保证不被改变,const修饰。

代码实现

char* my_strcpy(char* copy,const char* source)
{
	//用下标访问,不改变首元素地址
	int i = 0;
	while (source[i++] != '\0')//遍历查找
	{
		copy[i-1] = source[i - 1];//拷贝
	}
	copy[i] = source[i];//最后一位\0也拷贝过来,否则字符数组没有终止符号
	return copy;
}
int main()
{
	char arr[] = "ILOVEYOU";
	char cpy[20] = { 0 };
	my_strcpy(cpy, arr);
	printf("原字符数组%s —》拷贝字符数组%s", arr, cpy);
	return 0;
}

代码运行结果:

 五、strcat函数的使用及模拟

老样子,读文档中函数的使用方法和解释部分,不会的一键翻译。(尽管有些显示错误,但结果是好的)

stract函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
	char str[80];
	strcpy(str, "I ");
	strcat(str, "LOVE ");
	strcat(str, "YOU ");
	strcat(str, "FOREVER!");
	puts(str);
	return 0;
}

来个小表白,运行结果:

strcat函数的模拟

strcat的实现逻辑

将源头字符串的副本追加到目的地字符串。目标中的终止空字符被源的第一个字符覆盖,并且在目标中由两者串联形成的新字符串的末尾包含一个‘\0’空字符。

函数执行以后,下一次进行添加函数的起始位置就应该为上一次函数执行完的末指向位置,因此需要返回函数执行后的地址作为下一次函数执行所需要的参数。

首先观察库函数部分的声明

char * strcat ( char * destination, const char * source );

函数的返回部分一个指针,记录的是最后'\0'的位置,作为下一次函数执行的参数,方便下一个字符串在'\0'的位置进行覆盖和添加后续字符串。

其次,对库函数逻辑部分进行分析

以上述的四个字符串作为需要输入添加到后面的字符串,以str为目标位置。

由此可见我们需要一一个指针指向目标数组的起始位置,由于后面需要遍历使用上面的地址,因此首元素地址不能发生改变。需要一个额外的指针指向首元素地址,然后改变这个额外的指针从而不影响目标的地址本身

然后我们要实现目标位置的变化和来源字符串的遍历移动同步,且终止条件为字符串终止符号'\0',且这个'\0'仍要复制给目标位置。

函数的重复使用需要在上一次终止位置开始,返回上次终止位置空间即可作为下一次调用函数起始空间。

代码实现

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

char* my_strcat(char* dest, const char* source)
{
	assert(dest);
	assert(source);
	char* dest_end = dest;//额外指针指向目标字符数组首元素位置,保证移动指针不丢失原先字符串位置
	while (*dest_end != '\0')//循环遍历找到目标数组的'\0'位置
	{
		dest_end++;//目标位置指针移步
	}
	while (*source != '\0')//来源字符串循环便利,终止位置为'\0'
	{
		*dest_end = *source;//覆盖
		dest_end++;
		source++;//并行指针移步添加

	}
	*dest_end = *source;//因为最后的终止位置为'\0',所以直接赋值为source的最后一位即可
	return dest_end;//返回终止位置
}

int main()
{
	char arr[100] = { 0 };
	my_strcat(arr, "I ");
	my_strcat(arr, "love ");
	my_strcat(arr, "you ");
	my_strcat(arr, "forever");
	my_strcat(arr, "!");
	printf("%s", arr);
	return 0;
}

代码运行结果:

 六、strstr函数的使用及模拟

老样子,读文档中函数的使用方法和解释部分,不会的一键翻译。(尽管有些显示错误,但结果是好的)

strstr函数的使用

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[] = "iloveyou";
	char str2[] = "ove";
	printf("%s",strstr(str1, str2));
	return 0;
}

查找一个字符串相对与另一个字符串是否有子字符串的运行结果:

strstr函数的模拟

strstr的实现逻辑

简单来讲,函数的实现实际上是两个字符串通过查找str1字符串中的字符位置是否为str2字符串首元素。

如果有则同步移动指针对元素进行比较,如果str2字符串遍历完全后,则代表str2在str1中有子字符串,返回查找时出现的在str1字符串中str2首元素相同的地址。

如果遍历过程中有元素并不相同,即代表以str1中目前和str2首元素相同的这个位置并不能查找到子字符串,继续查找下一次相同的地址,重新比较。

返回值:

找到了返回str1中和str2首元素相同,并且能找到子字符串的这个位置。

没能找到子字符串,返回NULL。

首先观察库函数部分的声明

const char * strstr ( const char * str1, const char * str2 );
      char * strstr (       char * str1, const char * str2 );
函数有两个声明,我们实现或者需要使用哪个呢?
cplusplus依旧告诉了我们,这里我们继续以c语言为演示,所以声明为
char * strstr ( char * str1, const char * str2 );
函数的返回部分为一个指针变量,参数部分传递的是两个指针参数,传递字符串。前者为要扫描的字符串地址,后者为要查找的字符串地址。

其次,对库函数逻辑部分进行分析

逻辑部分需要注意的是,两个字符串都需要重复使用的一个需求。

str1需要使用这个字符串,因此首元素地址不能丢失,指针的移动最好是copy一份地址进行移位比较(*s1

str2需要在查找过程中可能第一次查找子字符串不成功,需要重新进行下一次查找,因此首元素地址也不能改变,copy一份进行移位比较(*s2)

当第一个字符串终止时依旧没有找到子字符串,即代表没有,返回NULL

代码实现

#include<stdio.h>
#include<assert.h>
char* my_strstr(char* str1, char* str2)
{
	assert(str1);
	assert(str2);//判断传递参照指针是否为空
	while(*str1)//终止条件为str1遍历到'\0'
	{
		char* s1 = str1;
		char* s2 = str2;//地址拷贝
		while (*s1 == *s2)//查找str1字符串中str2首元素相同的位置
		{
			s1++;
			s2++;//同步移位比较
		}
		if (*s2 == '\0')//成功标志,str2遍历完全
			return str1 ;//返回str1中查找到的子字符串起始位置
		str1++;//一次查找没有找到,继续找下一次首元素相同位置
	}
	return NULL;
}

int main()
{
	char str1[] = "iloveyou";
	char str2[] = "ove";
	printf("%s",my_strstr(str1, str2));
	return 0;
}

代码运行结果:


​​​​​​总结

       本章我们熟悉并模拟了strlen,strcmp,strcpy,strcat,strstr的库函数。以上就是库函数的部分函数使用和模拟教程。库函数的使用并非需要记住所有的函数使用,去背诵记忆,而是需要合理的利用开发者手册和API文档,帮助使用已经封装好的函数去实现各种功能。同时,我们通过模拟库函数和优化模拟库函数的代码,并且和封装的库函数的代码进行比较,也能发现代码在美观和逻辑实现的巧妙之处。帮助自己更好的理解程序的逻辑,提升自己的代码水平。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lovewold少个r

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

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

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

打赏作者

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

抵扣说明:

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

余额充值