玩转字符串函数与字符函数——【C语言】

news2024/11/24 9:02:02

在C语言的学习中,我们经常会遇到字符串,对它的处理也是数不胜数,但是我们没有很好的处理办法,字符串只能放在字符数组或常量字符串中通过自定义函数去使用处理。而现在我将带领大家学习C语言函数库中专门处理字符串的函数。

这些处理字符串的函数全部放在#include<string.h>和#include<type.h>中使用!接下啦让我们具体认识一下这些函数!!!

目录

string.h中的函数介绍

strlen函数

strcpy函数​编辑

strcat函数

strcmp函数

strstr函数

 strtok函数

 更加严谨的库函数

strncpy函数

strncat函数

strncmp函数 

小结 

ctype.h中的函数介绍 


string.h中的函数介绍

strlen函数

strlen函数是获取字符串函数大小(作用)

1.返回值类型是size_t(无符号整数)

2.参数是接收一个不可修改的char*类型的指针

3.参数指向的字符串必须要以 '\0' 结束。

4.strlen函数返回值是返回字符串的长度,当指针指向'\0'时结束计数,所以字符串的长度不包括'\0'。 

下面一段程序使用strlen函数:

#include <stdio.h>
int main()
{
 const char*str1 = "abcdef";
 const char*str2 = "bbb";
 if(strlen(str2)-strlen(str1)>0)
 {
 printf("str2>str1\n");
 }
 else
 {
 printf("srt1>str2\n");
 }
 return 0;
}

代码分析很明显str1的字符串长度为6,str2的字符串长度为3,3-6=-3理应输出结果为str1>str2,但实际结果为: 这是为什么呢?因为strlen函数返回的类型为无符号整型,所以两数相减默认结果也为无符号整型,-3在二进制存储中的补码非常大,但是计算机却认为-3的补码就是它的原码,所以换算为十进制将会是一个非常大的正数,所以结果输出结果出现了错误。

如果我们将if条件判断中的条件换成(strlen(str2)>strlen(str1));结果就会正确!

下面我们来创建自定义函数,模拟实现strlen函数 。

//模拟strlen函数

size_t my_strlen(char* arr)
{
	int count = 0;
	while (*arr != '\0')
	{
		count++;
		arr++;
	}
	return count;
}

int main(void)
{
	char arr[100];
	gets(arr);
	printf("%u\n", my_strlen(arr));

	return 0;
}

 我们仿照strlen函数中的参数以及返回值以及原理模拟出my_strlen函数。具体是传入我们要求字符数组的首元素,创建一个临时变量count用来计传入数组的个数,利用while循环判断指针是否指向'\0',如果没有指向count++、arr++进行计数和指针向后移动,直到走到'\0'处跳出循环,返回count的数即可实现strlen函数的模拟。


strcpy函数

srtcpy函数是将源指向的字符串复制到指向的数组中;

1.返回值是一个char*的指针,指向复制字符串的首元素地址。

2.参数为两个char*类型的指针,后面那个是被复制的字符串,所以不能被修改,前面的是复制的字符串。

3. 源字符串必须以'\0'结束。

4.目标空间必须足够大,确保能存放源字符串。

5.目标空间必须可变。

6.此函数会将源字符串中的'\0'拷贝到目标空间中。

下面是对strcpy函数的使用:

int main(void)
{
	char arr1[100];
	char arr2[100] = "hello world";
	char* p = strcpy(arr1, arr2);
	printf("%s\n", p);

	return 0;
}

将arr2中的字符串拷贝到arr1中去。 

 下面是对strcpy函数的模拟:

模拟strcpy函数
char* my_strcpy(char* p1, const char* p2)
{
	assert(p1 && p2);
	char* ret = p1;
	while (*p1++ = *p2++)
	{
		;
	}
	return ret;
}


int main(void)
{
	char arr1[100];
	char arr2[100];
	gets(arr2);
	char* p = my_strcpy(arr1, arr2);
	printf("%s\n", p);
	return 0;
}

我们的目的还是将arr2中的内容拷贝到arr1中,创建自定义函数my_strpy函数仿照strcpy函数的函数模板,使用assert函数进行断言,防止传入的指针为空指针。创建一个字符指针来标记目标数组的首元素地址用来作为返回值。利用while循环进行条件判断如果p2不为'\0‘则进行*p1=*p2赋值,赋值成功后两个指针全部向后移动一位,直到p2为'\0'结束循环即可完成复制(操作可以简化到while语句的判断条件中),最后将目标数组的地址返回即可。

结果如下:


strcat函数

strcat函数是连接字符串的函数,将已知字符串连接到目标字符串。

1.返回值是目标字符串的首元素地址

2.两个参数是char*类型的字符指针,后面的指针是已知字符串元素首地址不能修改,所以用const修饰,前面指针是目标字符串的首地址。

3.源字符串必须以 '\0' 结束。

4.目标空间必须有足够的大,能容纳下源字符串的内容。

5.目标空间必须可修改。

 下面是对strcat函数的使用:

int main(void)
{
	char arr1[20] = "hello ";
	char arr2[20] = "world";
	char* p = strcat(arr1, arr2);
	printf("%s\n", p);

	return 0;
}

strcat函数的原理:找到目标字符串'\0'处进行覆盖,加入已知字符串到目标字符串的尾部,直到已知字符串的'\0'处结束,返回目标字符串的首元素指针。

 最后是对strcat函数的模拟实现:

char* my_strcat(char* p1, const char* p2)
{
	assert(p1 && p2);
	char* ret = p1;
	while (*p1 != '\0')
		p1++;
	while (*p1++ = *p2++)
	{
		;
	}
	return ret;
}

int main(void)
{
	char* arr1[100];
	char* arr2[100];
	gets(arr1);
	gets(arr2);
	char* p = my_strcat(arr1, arr2);
	printf("%s\n", p);

	return 0;
}

 目标是把已知字符串放到目标字符串的末尾,所以我们接收到两个指针时,先标记目标函数的首元素为最后返回值做准备,然后我们利用while循环将目标字符串的指针指到末尾'\0'处,然后进行的操作就和strcpy函数的原理一样,进行复制,最后将目标函数的首元素返回即可完成。

以下是代码运行结果:


strcmp函数

strcmp函数是比较两个字符串大小的函数。

1.返回值为int类型的数

第一个字符串大于第二个字符串,则返回大于0的数字

第一个字符串等于第二个字符串,则返回0

第一个字符串小于第二个字符串,则返回小于0的数字 

2.参数为两个比较的字符串,为了使保护两个字符串无意被修改,所以都用const修饰。

3.此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续以下对,直到字符不同或达到终止空字符。

下面是对strcmp函数的使用:

int main(void)
{
	char arr1[100] = "hello";
	char arr2[100] = "hell";
	printf("%d\n", strcmp(arr1, arr2));

	return 0;
}

hello与hell这两个字符串,前面hell全部相等,只有最后一个o与'\0'进行比较大小,根据ascaii码值o比'\0'大,所以arr1字符串比arr2字符串大,返回1。 

最后对strcmd函数模拟实现:

//模拟实现strcmp函数

int my_strcmp(const char* p1, const char* p2)
{
	assert(p1 && p2);
	while (*p1 == *p2)
	{
		p1++;
		p2++;
	}
	if (*p1 - *p2 > 0)
		return 1;
	else if (*p1 - *p2 < 0)
		return -1;
	else
		return 0;
}


int main(void)
{
	char arr1[100];
	char arr2[100];
	gets(arr1);
	gets(arr2);
	printf("%d\n", my_strcmp(arr1, arr2));
	return 0;
}

将两个字符串传入函数中,使用while循环进行比较(*p1 == *p2)如果相等就让两个指针都向后挪动一位继续比较,如果相同则返回0,如果*p1>*p2则返回1,*p1<*p2则返回-1即可。

以下是运行结果:


strstr函数

strstr函数的作用就是查找子字符串。子字符串为str2,目标字符串为str1。 

1.返回值为char*类型的指针,返回指向 str2 中第一次出现的 str1 的指针,如果 str2 不是 str1 的一部分,则返回一个空指针。

2.参数类型为两个字符指针,分别指向目标字符串和子字符串,因为不能被修改所以加入const进行修饰。

3.匹配过程不包括终止空字符,但它到此为止。

下面是我们对strstr函数的使用:

int main(void)

{
	char arr1[100] = "hello world";
	char arr2[100] = "lo";
	char* p = strstr(arr1, arr2);
	printf("%s\n", p);

	return 0;
}

上面是对子字符串lo在目标字符串hello world中的查找,当查找到时,将返回从lo开始的字符串开始打印,结果应该是:lo world。那我们来看一下结果是否与我们设想的相同呢?

 运行结果与我们设想相同。

下面我们进行对strstr函数的模拟实现:

//模拟strstr函数

char* my_strstr(const char* p1, const char* p2)
{
	char* ret = p1;
	char* w = p2;
	char* flag = NULL;
	while (*ret != '\0')
	{
		if (*ret == *w)
		{
			flag = ret;
			while (*w != '\0')
			{
				if (*ret != *w)
				{
					w = p2;
					ret = flag;
					flag = NULL;
					break;
				}
				w++;
				ret++;
			}
		}
		ret++;
	}

	return flag;
}

int main(void)
{
	char* arr1[100];
	char* arr2[100];
	gets(arr1);
	gets(arr2);
	char* p = my_strstr(arr1, arr2);
	printf("%s\n", p);

	return 0;
}

此函式仿照strstr函数的参数以及返回值进行模拟,因为要找到子函数对应在目标函数的位置,所以我们得创建一个char*类型的临时指针用来标记,然后先利用while循环找出目标函数与子函数的首个内容相同,用指针刚才创建的指针进行首元素标记,然后再嵌套一个循环进行全部内容比较,如果全部相同则返回刚才指针标记的地址,如果不相同则子函数指针返回到最初,目标函数继续进行往下一个位置进行比较,直到找到完成目标即可,若是没找到子函数内容则返回空指针。

运行结果如下:


 strtok函数

strtok函数是将字符串拆分函数,是将一整个字符串按照所给的分割符号拆开。

1.delimiters参数是个字符串,定义了用作分隔符的字符集合。

2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。

3.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改。)

4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。

5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。

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

strtok函数在第一次调用时,会将找到的字符作为标记,如果我们第二次调用此函数时给第一个参数传入空指针时,strtok函数会在上一次传入的字符串中继续寻找目标字符,并且将其分割。所以一般使用此函数时会和for循环进行结合使用。

具体使用方法:

int main(void)
{
	char arr[] = "zhangsan@year.com.cn";
	char sep[] = "@.";
	char copy[50];
	strcpy(copy, arr);
	char* ret = NULL;
	for (ret = strtok(copy, sep); ret != NULL; ret = strtok(NULL, sep))
	{
		printf("%s\n", ret);
	}

	return 0;
}

 运行结果如下:


 更加严谨的库函数

上面我们学习了strcpy、strcat、strcmp函数,他们都比较关注'\0‘,但是不会关注追加的字符,我们把这些函数叫做长度不受限制的字符串函数。接下来我们接收一些长度受限制的字符串函数。

分别是strncpy、strncat、strnmp函数,比之前学习的函数多了个n,那函数原型与之前有什么区别呢?

 

他们都是比之前的函数原型多一个参数size_t num,这个num就限制了需要的字符。功能和之前的函数完全相同。

那为什么说它们更加严谨呢?

strncpy函数

int main(void)
{
	char arr1[20] = "abcdef";
	char arr2[] = "xxxxxxxxxxxxxxxx";
	strncpy(arr1, arr2, 3);

	return 0;
}

 虽然arr2中的字符串很长,但我们只拷贝三个字符进入arr1中去。

如果我们的arr2中的字符串中只有三个字符,但是在strncpy中我们第三个参数写入5,会是怎么样呢?

 剩下没有的会用'\0'来替换,直到满足拷贝5个为止。

但是strncat函数就不一样了!!!

strncat函数

int main(void)
{
	char arr1[20] = "abcdef'\0'yyyyy";
	char arr2[] = "xxx";
	strncat(arr1, arr2, 5);

	return 0;
}

因为strncat函数与strcat函数原理基本相同,在遇到'\0'时会停下然后追加字符串,如果我们给予一个正常字符串时,后面全是'\0'看不到追加字符不够时的变化,所以我们用这种特殊的字符串进行调试!

 

 由此调试,我们可以看出strncat与strncpy的不同,strncat函数不管字符够不够,只要把已知的字符添加完成最后在加入’\0'即可。

strncmp函数 

strncmp函数与strcmp函数功能相同,就是由size_t num限制比较个数,用法也是非常简单,我就举一个程序:

int main(void)
{
	char arr1[100] = "abdefghigk";
	char arr2[100] = "abdfgiigk";
	printf("%d\n", strncmp(arr1, arr2, 2));
	printf("%d\n", strncmp(arr1, arr2, 4));

	return 0;
}


小结 

 总的来说,带n的比不带n的更加安全,因为它们限制了大小,我们在使用的时候就会注意数组空间是否能存储下等等一系列问题。

但是在正常使用下,两种类型的函数都是一样的,一个人想写bug是拦不住的!!!


ctype.h中的函数介绍 

ctype.h中的函数是处理字符的函数,只要我们能记住这些函数套着去使用就可以了!!!

下面是ctype.h中一些重要函数:

字符判断函数:

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

字符转换函数:

int tolower ( int c );   转大写

int toupper ( int c );转小写

具体使用方法: 

#include <stdio.h>
#include <ctype.h>
int main ()
{
  int i=0;
  char str[]="Test String.\n";
  char c;
  while (str[i])
 {
    c=str[i];
    if (isupper(c))
        c=tolower(c);
    putchar (c);
    i++;
 }
  return 0;
}

分析:将字符串中的小写字符转成大写。

 

 以上是我对基本字符串函数与字符函数的描述,对博主有不足的地方可以在评论区留言,博主会耐心学习,你们的支持是我最大的动力!!!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/752558.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

超高性能MCU发布,为开发人员提供了高效的工具链

近日嵌入式开发软件和服务的全球领导者IAR与业界领先的半导体器件供应商兆易创新(GigaDevice)宣布&#xff0c;联合推出最新版本IAR Embedded Workbench for Arm 9.40已经全面支持兆易创新的GD32H737/757/759系列超高性能MCU微控制器&#xff0c;这为**ERP系统**开发人员提供了…

Java 注解使用

一、注解简介 注解是那些插入到源代码中使用其他工具可以对其进行处理的标签。这些工具可以在源码层次上进行操作&#xff0c;或者可以处理编译器在其中放置了注解的类文件。 注解不会改变程序的编译方式。Java编译器对于包含注解和不包含注解的代码会生成相同的虚拟机指令。 为…

7种优秀的电商API命名方式

本文通过展示7种优秀API命名实践&#xff0c;来协助您创建高效的API端点&#xff0c;为用户提供更好的使用体验。 如今&#xff0c;API已成为了现代化编程的基本组成部分。它们不但能够改善不同开发团队的协作、并鼓励创新&#xff0c;而且能够提高应用程序的安全性。而作为两…

用PCB加热PCB——PCB加热台

之前为了焊接一些小贴片模块&#xff0c;想过买一个加热台&#xff0c;后来一搜加热台&#xff0c;发现有很多卖PTC加热板的&#xff0c;就又想自己做一个加热台。正好这个月嘉立创又送了打样券&#xff0c;搞起来~ PCB加热台设计主要考虑以下几个方面&#xff1a; 面积功率铜…

【方法】电脑如何打开Heic文件?

存放在电脑里的Heic文件打不开&#xff1f;相信有小伙伴也遇到过这样的问题。 因为Heic是苹果升级到ios11之后&#xff0c;在拍摄照片时的默认图像存储格式&#xff0c;只能兼容苹果系列产品&#xff0c;不能在Windows电脑里打开。&#xff08;Windows10 RS4开始支持该格式&am…

概率论的学习和整理18:为什么 P(至少成功1次概率) = Σ p(几何分布概率之和)----(未完成)

我们计算几何概率时&#xff0c;会很容易发现这么一个特点 我们很容易计算 试验n次&#xff0c;连续成功概率试验n次&#xff0c;连续失败概率试验n次&#xff0c;至少成功1次概率试验n次&#xff0c;最后一次成功概率试验n次&#xff0c;成功k次概率试验n次&#xff0c;累计成…

python3的全局解释器锁是什么意思?有什么要注意的?

Python中的全局解释器锁&#xff08;Global Interpreter Lock&#xff0c;GIL&#xff09;是一种机制&#xff0c;用于确保在任何给定时间只有一个线程执行Python字节码。GIL是由Python解释器实现的&#xff0c;对于CPython解释器来说是存在的&#xff0c;其他一些Python解释器…

[chatgpt+Azure]unity AI二次元小女友之使用微软Azure服务实现RestfulApi->语音识别+语音合成

1.简述 如题所述&#xff0c;这个小项目是在unity引擎端&#xff0c;使用了chatgpt微软azure的一个AI二次元女友对话的项目&#xff0c;实现原理也比较简单&#xff0c;即在unity端实现AI二次元女友的交互界面&#xff0c;接入chatgpt-3.5-turbo的api接口&#xff0c;借助chatg…

探讨餐饮行业油烟污染与治理措施

安科瑞 华楠 摘 要&#xff1a; 近年来我国餐饮行业油烟污染已成为城市大气污染的主要来源之一。如今环境问题日益突出严重制约到人们的身体健康&#xff0c;需要引起重视采取一系列有效的措施来治理餐饮行业的油烟污染。 关键词&#xff1a;餐饮业&#xff1b;污染&#xf…

STM32驱动ADS1256串口输出-AD转换

STM32驱动ADS1256串口输出-AD转换 ADS1256ADS1256简介芯片特点引脚说明模块相关寄存器与命令相关程序初始化 实验效果接线实验现象 ADS1256 ADS1256简介 ADS1256是TI推出的一款微功耗、高精度、8 通道、24 位高性能模数转换器。该芯片还带有4个可编程的I/O口、输入缓冲器和可编…

Spring依赖注入Bean类型的8种情况详解

1、普通对象 这没什么好说的&#xff0c;大家都这么用的&#xff0c;比如需要用到 UserService&#xff0c;直接 Autowired 就可以了。 Autowired private UserService userService;2、Collection 及其子接口 除了支持注入一个单一的对象之外&#xff0c;Autowired 还支持注…

100天精通Golang(基础入门篇)——第16天:深入解析Go语言包的使用和包管理

&#x1f337; 博主 libin9iOak带您 Go to Golang Language.✨ &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &#x1f30a; 《I…

java微信公众号新建草稿并发布

java实现公众号发起新建草稿&#xff0c;并且发布得到文章链接首先要先去微信公众号的设置与开发–基础设置 查看公众号的各个参数&#xff0c;这里我是存储到数据库&#xff0c;方便后期使用&#xff0c;实体类如下&#xff1a; Data public class WeChatOfficial {private st…

蛙色Web3D编辑器全面更新,会员能力解析

导语&#xff1a; 在数字化时代&#xff0c;创意设计和虚拟展示成为了营销领域的关键。然而&#xff0c;传统的创作方式往往需要复杂的软件和技术支持&#xff0c;给用户带来了诸多麻烦。 幸运的是&#xff0c;蛙色Web3D编辑器作为一款领先的在线编辑工具&#xff0c;通过全面…

Sentieon | 每周文献-Epidemiology-第五期

流行病学系列文章-1 标题&#xff08;英文&#xff09;&#xff1a;Rare Variants in Inborn Errors of Immunity Genes Associated With Covid-19 Severity标题&#xff08;中文)&#xff1a;与Covid-19严重程度相关的免疫基因先天性缺陷的罕见变异发表期刊&#xff1a;《Fron…

背包问题学习笔记

笔记&#xff0c;不是博客&#xff0c;所以就只是粗略的写写 背包问题状态设置 1.小于等于某值&#xff0c;一般用于求在限制背包体积内的情况求解 状态设置 F(n) 表示此时的背包体积小于等于n&#xff0c;F数组初始化为0即可 例题&#xff1a;423. 采药 - AcWing题库 2.恰…

用Python采用Modbus-Tcp的方式读取485电子水尺数据

README.TXT 2023/6/15 V1.0 实现了单个点位数据通信、数据解析、数据存储 2023/6/17 V2.0 实现了多个点位数据通信、数据解析、数据存储 2023/6/19 V2.1 完善log存储&#xff0c;仅保留近3天的log记录&#xff0c;避免不必要的存储&#xff1b;限制log大小&#xff0c;2MB。架…

C#生成类库dll以及调用实例

本文讲解如何用C#语言生成类库并用winform项目进行调用 目录 创建C#类库项目 Winform调用dll 创建C#类库项目 编写代码 using System.Threading;namespace ClassLibrary1 {public class Class1{private Timer myTimer = null;//定义定时器用于触发事件//定义公共的委托和调…

HW5300V3-ISCSI存储运维,看这一篇就够了01——流程图

一、存储使用流程图 二、块存储-配置流程图

【Hippo4j源码的方式安装部署教程】

&#x1f680; 线程池管理工具-Hippo4j &#x1f680; &#x1f332; AI工具、AI绘图、AI专栏 &#x1f340; &#x1f332; 如果你想学到最前沿、最火爆的技术&#xff0c;赶快加入吧✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;CSDN-Java领域优质创作者&#…