字符串及字符串函数(二)

本文详细介绍了C语言标准库中的字符串处理函数,包括strcmp用于比较字符串、strncpy和strncat用于安全拷贝字符串、strstr查找子串、strtok分割字符串和strerror处理错误码。通过实例演示了这些函数的使用和模拟实现。
摘要由CSDN通过智能技术生成
在编程的过程中,我们经常要处理字符和字符串,为了⽅便操作字符和字符串,C语⾔标准库中提供了
⼀系列库函数,上部分内容已经介绍了字符分类函数,字符转换函数,以及strlen,strcpy,strcat的基本使用和简易的模拟实现,接下来我们就接着学习⼀下剩下的函数。
六.strcmp函数的使用和模拟实现
注意:包含头文件<string.h>
功能:比较两个字符串(比较两个字符串中对应位置上字符ascii值的大小)
函数结构:
根据标准规定:
第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字
第⼀个字符串等于第⼆个字符串,则返回0
第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字
那么如何判断两个字符串大小呢?
那就是一一比较两个字符串中对应位置字符的ascii值大小。
例如:
#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcqdefg";
	int ret = strcmp(arr1, arr2);
	printf("%d\n", ret);//-1
//因为第4个位置上q的ascii值大于d的,所以字符串2大于1
	return 0;
}

结果返回值是-1,但不一定,不同的编译器上对此的处理不同(编者这里使用的是vs2022),具体参考如下:

即若arr1大于arr2,则返回一个正数,相等返回0,小于返回一个负数,具体值随机。
许多初学者会误将两个字符串的长度的比较用作字符串的比较,这是初学者容易犯错的地方,字符串一般是不能直接比较的。
strcmp函数的简易模拟实现:
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	int ret = 0;
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')//此时两个字符串直至\0前都相等,说明两字符串相等,返回0
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;//满足标准返回值的要求

}

应用:由strcmp的功能不难发现,它的功能可以应用于登录过程中的数据处理,即当用户向应用中输入账号密码后,通过strcmp函数就可以将用户输入值与原先数据库中的值进行比对。

之前我们学习过了一下字符串函数
//strcpy
//strcat
//strcmp
但是它们都是长度不受限制的字符串函数,是不安全的,因为它们不会处理字符串的长度,存在越界访问的风险;
因而在vs中使用会弹出报错提示,类似scanf要使用scanf_s,所以平时我们需要在代码前加上一个宏定义能让我们自由使用这些函数。
#define _CRT_SECURE_NO_WARNINGS 1
针对上述情况,c语言库还提供了一些更安全的字符串函数:
//strncpy
//strncat
//strncmp
//它们都是长度受限制的字符串函数,并且多了一个参数size_t num,是相对安全的,但也仅限于相对安全,同样需要在代码前加一个宏定义。

七.strncpy函数 

作用功能与strcpy函数类似,但是多了一个参数num,即在原先strcpy函数功能基础上将字符串前num个字符进行处理。使用的时候同样要包含头文件<string.h>

拷⻉num个字符从源字符串到⽬标空间。 如果源字符串的⻓度⼩于num,则拷⻉完源字符串之后,在⽬标的后边追加\0,直到num个。

举个例子:

int main()//int main()
{
//	char arr1[20] = "abcdef";
//	char arr2[20] = "abqdefgh";
//	int ret = strncmp(arr1, arr2, 6);
//	//6表示最多比较6个
//	printf("%s\n", arr2);


	char arr1[20] = "abcdef";
	char arr2[20] = "xxxxxxxxxxxx";
	strncpy(arr2, arr1, 8);
	//有几个拷贝几个
	//如果多了的话用\0补足
	printf("%s\n", arr2);//abcdef
	return 0;
}

显然字符串arr1是不足8位的,但是strncpy函数会自动给arr1末位补上\0.

虽然如此,但是程序员写平时写代码的时候不会如此鲁莽,一般会事先计算好字符串大小再传参。

例如:

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

八.strncat函数的使用

与上述函数类似,话不多说,上函数结构:

意思是:将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加⼀个 \0 字符。如果source 指向的字符串的⻓度⼩于num的时候,只会将字符串中到 \0 的内容追加到destination指向的字符串末尾。

例如:

#include <stdio.h>
#include <string.h>
int main()
{
	char str1[20]={0};
	char str2[20]={0};
	strcpy(str1, "To be ");
	strcpy(str2, "or not to be");
	strncat(str1, str2, 6);
	printf("%s\n", str1);//To be or not
	return 0;
}

九.strncmp函数的使用

函数机制与上述函数类似,这里不再赘述。

十.strstr的使用和模拟实现

注意:包含头文件<string.h>

功能:在一个字符串中查找另一个字符串,并记录匹配第一次的位置

函数结构:

由此可见,函数返回字符串str2在字符串str1中第一次出现的位置。字符串的比较匹配不包含\0字符,以\0作为结束标志。

上代码:

#include <stdio.h>
#include <string.h>
int main ()
{
     char str[] ="This is a simple string";
     char * p;
     p = strstr (str,"simple");//p指向了simple的首字符
     strncpy (p,"sample",6);//通过p将simple修改为sample
     printf("%s\n", str);//This is a sample string
     return 0;
} 

strstr函数的模拟实现:

strstr函数的模拟实现有几处难点:那就是情况多样,可能出现多次匹配。

对于它的模拟实现一般有两种方法:1.简单的写法-暴力查找。2.KMP算法-更加高效,实现和理解也更复杂。这里编者将着重讲解法1,对法2感兴趣的同学可以自行了解实现。


char* my_strstr(const char* str1, const char* str2)//在arr1中查找arr2
{
	const char* s1 = NULL;
	const char* s2 = NULL;
	const char* cur = str1;//current中存放的是最终的返回值,即要从此处向后打印

	//特殊场景处理,若str2是一个空字符串,则直接返回str1
	if (*str2=='\0')
		return (char*)str1;

	while (*cur)
	{
		s1 = cur;
		s2 = str2;
		//while (*s1 == *s2)//有可能中途遇见\0了
		while (*s1 !='\0' && *s2!='\0' && *s1 == *s2)
		{

			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return (char*)cur;
		}
		cur++;
	}
	//最终cur遍历完的时候都找不到的时候,返回空指针
	return NULL;
}
int main()
{
	char arr1[] = "this is an apple";
	//const char* p = "is"; 只要是字符串地址就行
	char arr2[] = "is";
	char* ret = my_strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("找不到!\n");
	}
	else
	{
		printf("%s\n", ret);//is is an apple
	}
	return 0;

一般的情况是好理解的,这里不多解释,主要解释一下特殊情况:就是提前匹配到目标字符串的前几个字符,但是不完全匹配。这里画图给读者们简要解释一下,目标字符串bbc在源字符串中可能会先匹配到前两个bb但是到了第三个b与与bbc就不匹配了,这里就需要重置指针,所以在模拟实现中我们要设置两个新指针s1,s2,而尽量不适用str1,str2,这是为了字符串的起始位置不被破坏,方便查找,而cur的作用是为了更新str1的查找位置,一点一点向后挪动。

十一.strtok函数的使用

很多同学第一次见到这个函数的时候可能不是很好理解这个函数,别担心。

char * strtok ( char * str, const char * sep);
1. sep参数指向⼀个字符串,定义了⽤作分隔符的字符集合
2.  第⼀个参数指定⼀个字符串,它包含了0个或者多个由sep字符串中⼀个或者多个分隔符分割的标
记。
3. strtok函数找到str中的下⼀个标记,并将其⽤ \0 结尾,返回⼀个指向这个标记的指针。(注:
strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷⻉的内容
并且可修改。)
4. strtok函数的第⼀个参数不为 NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串
中的位置。
5. strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标
记。
6. 如果字符串中不存在更多的标记,则返回 NULL 指针。
简言之:strtok函数会找到字符串中的特殊字符,并记录下一个特殊符号前面字符串的地址,以此类推。当strtok函数的第一个参数为NULL的时候,它会从第一次查找到的特殊符号处再向后查找。
上代码:
int main()
{
	char arr1[] = "zsanfeng@yeah.net@hehe";
	char arr2[30] = { 0 };
	strcpy(arr2, arr1);
	const char* sep = "@.";
	char* ret = NULL;
	for (ret = strtok(arr2, sep);ret != NULL;ret = strtok(NULL, sep))
	{
		printf("%s\n", ret);
        //    zsanfeng
        //    yeah
        //    net
        //    hehe
	}

	/*ret = strtok(arr2, sep);
	printf("%s\n", ret);

	ret = strtok(NULL, sep);
	printf("%s\n", ret);

	ret = strtok(NULL, sep);
	printf("%s\n", ret);*/

	return 0;
}

这里的循环结构非常巧妙,望读者细细体会。

十二.strerror函数

注意:要包含头文件<errno.h>

strerror 函数可以把参数部分错误码对应的错误信息的字符串地址找到。
错误码是什么意思呢?
在不同的系统和C语⾔标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头⽂件中说明的,C语⾔程序启动的时候就会使⽤⼀个全局的变量errno来记录程序的当前错误码,只不过程序启动 的时候errno是0,表⽰没有错误,当我们在使⽤标准库中的函数的时候发⽣了某种错误,就会将对应 的错误码,存放在errno中,⽽⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是 有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。
用vs打开名为erron.h的文件:
这里有一系列库中的错误码,每种错误码都对应一种错误,而strerror的作用就是将错误码翻译成错误信息,供程序员调试.
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>

//打印⼀下0~10错误码对应的信息
int main()
{
    int i = 0;
       for (i = 0; i <= 10; i++) 
     {
       printf("%s\n", strerror(i));
     }
    return 0;
}

有什么用呢,这里为大家举一个示例:

int main()
{
	//fopen以读的形式打开文件的时候,如果文件不存在,就打开失败了
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));//将错误码翻译为错误信息
		return 1;
	}
	//读文件
	//关闭文件

	fclose(pf);
	return 0;
}

上文说过,strerror只能翻译错误信息后记录下来,不能直接打印,需要借助Printf函数。

这里再为大家介绍一个将二者功能合二为一的函数perror(printf+strerror),

上代码:

int main()
{
	//fopen以读的形式打开文件的时候,如果文件不存在,就打开失败了
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("zhangsan");
		//有能力直接打印错误信息,打印的时候,先打印传给perror的字符穿,然后打印冒号,再打印空格,最后打印错误码对应的错误信息
		return 1;
	}
	//读文件
	
	//关闭文件
	fclose(pf);
	return 0;
}

。perror函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。
以上,字符串函数介绍完毕。感谢观看。望屏幕前的您能有所收获。
  • 41
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值