字符串函数

字符串函数

个人主页:大白的编程日记
个人专栏:C语言学习之路


前言

哈喽,各位小伙伴大家好!上一期咱们已经那指针部分内容讲完了,今天小编继续带大家学习字符串函数的内容。咱们直接进入主题。向大厂冲锋!


一.字符函数

在编程的过程中,我们经常要处理字符和字符串,为了方便操作字符和字符串,C语言标准库中提供了⼀系列库函数,接下来我们就学习⼀下这些函数。

1.1字符分类函数

C语言中有⼀系列的函数是专门做字符分类的,也就是⼀个字符是属于什么类型的字符的。
这些函数的使用都需要包含⼀个头文件是 ctype.h。
在这里插入图片描述
这些函数的使用方法非常类似,我们就讲解⼀个函数的使用,其他的函数非常类似。


1.2islower函数的使用


islower是专门用来判断字符是大写小写字母的库函数,那他具体是怎么使用的呢?

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<ctype.h>
int main()
{
	int ret = islower('a');
	printf("%d", ret);
	return 0;
}

使用islower函数只需要把字符作为参数传给函数即可。然后通过函数的返回值即可判断是否是小写字母。

 int islower ( int c );

islower 是能够判断参数部分的 c 是否是小写字母的库函数。通过返回值来说明是否是小写字母,如果是小写字母就返回非0的整数,如果不是小写字母,则返回0。

验证:

  • 小写字母
    在这里插入图片描述
  • 大写字母

1.3代码练习

我们现在试着写一段代码,实现将字符串中的小写字母转化为大写字母。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<ctype.h>
int main()
{
	char a[20] = "abKSAas";
	int i = 0;
	while (a[i] != '\0')
	{
		if (a[i] >= 'a' && a[i] <= 'z')
		{
			a[i] -= 32;//小写转大写
		}
		i++;
	}
	printf("%s", a);
	return 0;
}

这里我们用while循环遍历字符数组,再用if对每个字符进行判断,如果是小写字母,因为字符在内存中存的是ascll码值,小写字母比大写字母的ascll码值大32,所以只需要对字符-32即可把小写字母转化为大写字母。

这是一种将小写字母转大写的方法。那有没有更简单快捷的方法或者库函数呢?这就涉及到字符转化函数了。


1.4字符转换函数

上面的方法完成字母大小写转化的方法太繁琐,为了简单快捷我们可以使用库函数完成大小写转化。
C语言提供了2个字符转换函数:

  1. tolower
int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写

  1. toupper
    在这里插入图片描述
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写

这两个库函数的参数是int类型,因为字符在内存存放的是ascll码值,完成转化将转化完后ascll码值返回。
这两个库函数的头文件也是 ctype.h。

上面的代码,我们将小写转大写,是-32完成的效果,有了转换函数,就可以直接使用 tolower 函数。

int main()
{
	char a[20] = "abKSAas";
	int i = 0;
	while (a[i] != '\0')
	{
		if (islower(a[i]))
		{
			a[i]=toupper(a[i]);//小写转大写
		}
		i++;
	}
	printf("%s", a);
	return 0;


如果我们要把大写转小写就可以这样写。

int main()
{
	/*int ret = islower('A');
	printf("%d", ret);
	return 0;*/
	char a[20] = "abKSAas";
	int i = 0;
	while (a[i] != '\0')
	{
		if (isupper(a[i]))
		{
			a[i]=tolower(a[i]);//大写转小写
		}
		i++;
	}
	printf("%s", a);
	return 0;
}


这些库函数我们在写代码时可以多加使用,熟练掌握。


二.strlen函数

2.1strlen的使用

size_t strlen ( const char * str );

strlen是用来统计字符串长度的库函数。
他的使用只需要把字符串地址作为参数传给strlen即可。函数就会把字符长度用返回值返回。那他是怎么统计字符串长度的呢?

  • 统计方式:
    字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。

  • 参数要求
    因此 参数指向的字符串必须要以 ‘\0’ 结束。否则会产生越界访问的情况。

  • 头文件
    strlen的使用需要包含头文件 string.h。

  • 返回值
    注意函数的返回值为size_t,是无符号的( 易错 )

#include<string.h>
int main()
{
	if (strlen("abc") - strlen("abcdef"))
	{
		printf(">\n");
	}
	else
	{
		printf("<=\n");
	}
	return 0;
}

大家看一下这个的代码。
可能很多小伙伴都认为第一个长度为3,第二个长度为6.
3-6=-3。表达式结果为假输出<=。是不是呢?我们呢来验证一下。

验证:

大家发现结果是>。为什么呢?这就是因为涉及到strlen的返回值了。

size_t strlen ( const char * str );

strlen的返回值是size_t的无符号整数类型。两个无符号整数相加减,得到的只能是无符号整数。所以-3会被当成无符号整数,我们又知道整数在内存中存的是补码,负数的符号位是1,可是这里-3被当成无符号数,那符号位的1就是数值位,这时候-3就是一个很大的正数。所以表达式结果为真,结果输出>。


2.2strlen的模拟实现

那我们现在来模拟实现strlen库函数。
这里我们用递归的方式实现strlen的模拟。

#include<string.h>
int my_strlen(const char* a)
{
	if (*a != '\0')
	{
		return 1 + my_strlen(a + 1);//不是\0返回值+1
	}
	else
		return 0;//遇到\0结束
}
int main()
{
	char a[20] = "abcdef";
	int ret = my_strlen(a);
	printf("%d\n", ret);
}

这里我们写一个my_strlen函数,进入函数后对首字符指针解引用判断是否为\0。
是返回1+参数为未统计字符串函数的返回值。
不是说明遇到\0,直接返回0。
函数的执行过程大概是这样子:

大家可以发现,递归把统计字符串的长度分成了统计每个字符的个数,每次调用函数就能统计一个字符,把他累加到返回值里。


三.str函数

3.1strcpy函数

int main()
{
	char a[20] = "abcdef";
	char a1[20] = { 0 };
	return 0;
}

如果我们现在想把a数组的字符串拷贝到a1数组中,我们该怎么办?循环遍历赋值吗?
这里还有个更快的方法,就是直接使用strcpy函数。

strcpy库函数是专门用来拷贝字符串的函数。
函数有两个参数,第一个是拷贝后的数据存放的位置。
第二个是拷贝数据的起始位置。

  • 源字符串参数
    源字符串必须以 ‘\0’ 结束。否则产生越界现象。

  • 拷贝方式
    将待拷贝字符串拷贝到目的地中,同时会将源字符串中的 ‘\0’ 也拷贝到目标空间。

验证:

  • 目标空间大小
    目标空间必须足够大,以确保能存放源字符串。否则则会报错。

验证:
在这里插入图片描述

  • 目标空间修改
    目标空间必须可修改。
char a[20] = "abcdef";
char* a1 = "##########";//常量字符串不能修改
strcpy(a1, a);

这里要把a数组的字符串拷贝到a1里去,a1指向的是常量字符串。
常量字符串不能修改,所以程序会出错。

验证:


这里程序直接崩溃了,因为常量字符串不能被修改。


3.2strcpy的模拟实现

接下来我们来模拟strcpy函数

void my_strcpy( char* dest, const char* src)
{
	assert(dest && src);
	while (*src!='\0')
   {
	 *dest = *src;//拷贝
	 dest++;//移动
	 src++;
   }
	*dest = '\0';//补上\0
}
int main()
{
	char a[20] = "abcdef";
	char a1[] = "##########";
	my_strcpy(a1, a);
	printf("%s\n", a1);
	return 0;
}

在这里插入图片描述

这里我们用while循环遍历字符串,然后对源头指针解引用。
判断是否为\0。
不是就对目标空间的指针指向的位置字符改成源头字符。
直到遇到\0为止。然后再在目标空间指针指向的位置补上\0即可
其实这个代码还能优化。

void my_strcpy( char* dest, const char* src)
{
	assert(dest && src);
	while (*dest++=*src++);
	*dest = '\0';//补上\0
}
int main()
{
	char a[20] = "abcdef";
	char a1[] = "##########";
	my_strcpy(a1, a);
	printf("%s\n", a1);
	return 0;
}

我们让循环判断的时候,同时进行拷贝,使用自增,然后循环空语句,直到src遇到\0,dest的值为\0,\0的ascll码值为0,0为假。循环停止。

库里的函数返回值是char
,也就是返回目标空间的起始地址。
这里我们还能修改一下代码。

char* my_strcpy( char* dest, const char* src)
{
	assert(dest && src);
	char* ret=dest;//保存目标空间起始地址
	while (*dest++=*src++);
	*dest = '\0';//补上\0
	return ret;
}

这里我们ret保存目标空间的起始地址,然后return返回即可。


3.3strcat函数

char arr[] = "hello ";
char arr1[20] = "word!";

如果现在我想把这两个字符串拼接成一句话,我该怎么办呢?
这时候就用到我们的strcat库函数了。

strcat函数是专门用来拼接字符串的库函数。
他也有两个参数,
一个参数是追加字符串的目标空间。
一个是被追加字符串的起始地址。
那他是怎么使用和拼接的呢?

  • 源字符
    源字符串必须以 ‘\0’ 结束。

  • 目标空间
    目标字符串中也得有 \0 ,否则没办法知道追加从哪里开始。

  • 目标空间修改
    目标空间必须可修改。


3.4strcat的模拟实现

其实大家可以发现strcat和strcpy很相似,只是一个是从目标空间\0的位置开始复制,一个是从目标空间的起始地址开始复制。
所以我们只要找到目标空间\0的位置,再按照strcpy的方法复制即可

char* my_strcat(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest && src);
	while (*dest!='\0')//循环找\0
	{
		dest++;
	}
	while (*dest++=*src++)
	{
		;
	}
	*dest = '\0';//补上\0
	return ret;
}
int main()
{
	char arr[20] = "hello ";
	char arr1[] = "word!";
	my_strcat(arr, arr1);
	printf("%s\n", arr);
	return 0;
}

我们只需用while遍历目标空间,直到找到\0,然后再拷贝即可
注意要保存目标空间的起始地址。

  • 自己拼接自己
    如果字符串自己拼接自己会怎么样呢?

    可以发现自己拼接自己时会出现死循环和越界的现象。
    所以自己拼接自己时尽量不要使用srtcat函数。

3.5strcmp函数

strcmp是用来比较字符串的大小的库函数。

strcmp的参数是两个比较字符串地址。
返回值是int类型。

  • 第⼀个字符串大于第⼆个字符串,则返回大于0的数字
  • 第⼀个字符串等于第⼆个字符串,则返回0
  • 第⼀个字符串小于第⼆个字符串,则返回小于0的数字

那他是怎么比较字符串大小的呢?

char arr[20] = "abcdef";
char arr1[] = "abcdefh";


strcmp是逐个比较,直到两个字符大小不同,哪个字符的ascll码值大,哪个字符串就大。
大于返回大于0的返回值,小于返回雄安与0的返回值。
如果两个字符串都遇到\0,说明这两字符串相等。
返回0。
注意\0也会比较!


3.6strcmp的模拟实现

接下来我们来模拟实现strcmp函数。

int my_strcmp(const char* str1, const char* str2)
{
	int ret = 0;
	assert(str1 && str2);
	while (*str1 == *str2)//相等循环多次比较
	{
		if (*str1 == '\0')//遇到\0全部比较完毕
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;//作差返回
}

我们先用while循环判断是否第一对字符相等,

  • 如果不相等,直接返回两个字符ascll码值的差。

  • 如果相等,判断是否遇到\0,遇到说明两个字符串比较完毕
    且相等,直接返回0.

  • 如果不是\0,继续移动,比较下一对字符。

  • 等于

  • 大于
    =

  • 小于


四.strn函数和str函数对比

  • strncpy函数

  • 字符足够

    字符足够时,根据num的长度拷贝。不会自动补上\0。

  • 字符不够

    字符不够时,补上\0保证拷贝num个字符。

  • strncat函数

  • 字符足够

    字符足够时,根据num的长度拼接。会自动补上\0。

  • 字符不够

    字符不够时,不会自动填充\0。


)

  • strncmp函数


strncmp跟num的长度,比较前num的字符大小。
在这里插入图片描述

可以发现strn函数与str函数差别就在多了个参数num,
这个参数是让使用者指定想拷贝,拼接,比较字符的长度

这样就可以避免因目标空间不足而造成越界,和死循环等问题
让函数相对安全。


五.strstr strtok strerror函数

5.1strstr函数

char * strstr ( const char * str1, const char * str2);

strstr函数有两个参数,分别时两个字符串的地址。
strstr函数就是在str1函数中找到第一次出现出现的位置,
如果找不到就返回NULL空指针。

注意,字符串的比较匹配不包含 \0 字符,以 \0 作为结束标志。


5.2strstr函数的模拟实现

char* my_strstr(const char* str1, const char* str2)
{
	const char* s1 = NULL;
	const char* s2 = NULL;
	const char* cur = str1;
	if (*str2 == '\0')
		return (char*)str1;//空字符直接返回str1
	while (*cur)//从第一个源头字符开始找
	{
		s1 = cur;
		s2 = str2;
		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)//循环多次匹配
		{
			s1++;
			s2++;//移动比对字符
		}
		if (*s2 == '\0')//s2遇到\0说明全部匹配陈成功
		{
			return cur;
		}
		cur++;//移动源头字符
	}
	return NULL;
}

我们先写一个while循环,以遍历的每个字符作为源头开始查找,
之后再用while循环进行多次匹配,如果相等继续匹配,不相等跳出循环。之后对s2判断如果*s2==‘\0’。说明找到了,直接返回源头字符位置。如果全部循环完后都没找到,直接返回NULL空指针。

5.3strtok

char * strtok ( char * str, const char * sep)

strtok是用来根据给定分隔符分隔字符串的函数。
他具体怎么使用的呢?

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

strstr一般都需要for循环使用:

#include <stdio.h>
#include <string.h>
int main()
{
 char arr[] = "192.168.6.111";
 char* sep = ".";
 char* str = NULL;
 for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
 {
 printf("%s\n", str);
 }
 return 0;
}

5.4strerror函数

 char * strerror ( int errnum );

strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。

  • 具体介绍

不同的系统和C语言标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头头件中说明
的,C语言程序启动的时候就会使⽤⼀个全面的变量errno来记录程序的当前错误码,只不过程序启动
的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会讲对应
的错误码,存放在errno中,而⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是
有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。

我们来打印一下0到9的错误码是啥。

int main()
{
 int i = 0;
 for (i = 0; i <= 10; i++) {
 printf("%s\n", strerror(i));
 }
 return 0;
}


我们还学过一个库函数perror函数。
那他们有什么区别吗?
区别就在于perror函数可以对错误码自定义一些信息
并且perror是用来打印错误码的。
而strerror函数是用来获取错误码信息的,并不会打印。


后言

这就是今天给大家带来的常见字符函数的内容,大家之后在编程是可以多加使用并且熟练掌握。好啦,今天就分享到这里。感谢各位小伙伴的耐心阅读,咱们下期见!拜拜~

评论 46
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大白的编程日记.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值