C语言【字符函数和字符串函数】

前言

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

字符函数

字符分类函数

C语言中有一系列的函数是专门用来做字符分类的,也是将一个字符判断是属于什么类型的字符。
这些函数的使用都需要包含一个头文件<ctype.h>
(c -> 字符,type -> 类型,ctype -> 字符类型)

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

这些函数的使用方法都大同小异,就拿一个函数来使用。

int isupper ( int c ); 

isupper是判断参数的C是否为大写字母的
如果是大写字母就返回非0;相反则返回0.

函数使用

情景:写一个代码,将字符串中的大写字母转小写,其他字符不变

//写⼀个代码,将字符串中的大写字⺟转小写,其他字符不变。
int main()
{
	char str[] = "heLLo WorLd.,\n";
	char c = 0;
	int sz = sizeof(str) / sizeof(str[0]) - 1;//因为sizeof在计算字符串时,会把\0也计算进去,但是这个\0的长度我们并不需要
	//size_t sz = strlen(str)  当然,你也可以用库函数strlen
	for (int i = 0; i < sz; i++)
	{
		c = str[i];
		if (isupper(c))
		{
			c += 32;//大写字母与小写字母的ASCII码值相差32
		}
		putchar(c);//输出一个字符
	}
	return 0;
}

字符转换函数

C语言提供了2个字符转换函数:

函数功能
tolower将大写字母转为小写字母
toupper将小写字母转为大写字母
int tolower ( int c );
int toupper ( int c );

上面的代码,我们小写转大写是通过操作ASCII码值实现的,我们现在学习了这两个库函数,就可以直接用tolower 函数

int main()
{
	char str[] = "heLLo WorLd.,\n";
	char c = 0;
	int sz = sizeof(str) / sizeof(str[0]) - 1;//因为sizeof在计算字符串时,会把\0也计算进去,但是这个\0的长度我们并不需要
	//size_t sz = strlen(str)  当然,你也可以用库函数strlen
	for (int i = 0; i < sz; i++)
	{
		c = str[i];
		if (isupper(c))
		{
			c = tolower(c);
		}
		putchar(c);//输出一个字符
	}
	return 0;
}

字符串函数

接下来讲解的字符串函数的头文件都是 <string.h>

1. strlen的使用和模拟实现

size_t strlen( const char *string );

字符串以'\0'作为结束标记,strlen计算并返回的是字符串中'\0'之前的字符个数(其中并不包含'\0')

注意事项

1.函数参数所指向的字符串必须要有'\0'(不然就会是随机值)
2.函数的返回值的类型是size_t,是无符号的
3.使用前需要包含头文件

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

int main()
{
	const str[] = "abcdefg";//7
	size_t ret = strlen(str);
	printf("%zd\n", ret);
	
	return 0;
}

在这里插入图片描述

模拟实现

方法一(计数器方式)
#include<assert.h>
//模拟实现1(创建临时变量)
int my_strlen1(const char* str)
{
	assert(str);
	int count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}
方法二(不创建临时变量)
#include<assert.h>
//2(递归)
int my_strlen2(const char* str)
{
	assert(str);
	if (*str == '\0')
	{
		return 0;
	}
	return 1 + my_strlen2(str + 1);
}
方法三(指针 - 指针)
#include<assert.h>
//3(指针-指针)
int my_strlen3(const char* str)
{
	assert(str);
	char* tmp = str;
	while (*str)
	{
		str++;
	}
	return str - tmp;
}

在这里插入图片描述

2. strcpy的使用与模拟实现

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

CopiestheCstringpointedbysourceintothearraypointedbydestination, including the terminating null character (and stopping at that point).
将指向的源头字符串复制到指向目的地的数组中,包括结束符空字符'\0’(并在该点停止)。

注意事项

1.源头字符串必须要有'\0'
2.strcpy会把源头字符串的'\0'拷贝到目标空间
3.目标空间必须足够大,确保能存放源字符串
4.目标空间不能用const修饰

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

int main()
{
	char str1[] = "Guang Dong";
	char str2[20] = { "XXXXXXXXXXXXXXXXXXX" };
	printf("使用前: %s\n", str2);
	strcpy(str2, str1);
	printf("使用后: %s\n", str2);
	return 0;
}

在这里插入图片描述

模拟实现
#include<assert.h>
#include<string.h>

//strcpy的使用与模拟
//字符串拷贝(会拷贝源头的'\0')
char* my_strcpy(char* dis, const char* src)
{
	assert(dis && src);
	char* tmp = dis;
	//第一版
	//while (*src != '\0')
	//{
	//	*dis = *src;
	//	dis++;
	//	src++;
	//}
	//*dis = *src;

	//第二版(优化)
	//while (*dis = *src)
	//{
	//	dis++;
	//	src++;
	//}

	//第三版(再优化)
	while (*dis++ = *src++)
		;
	return tmp;
}

运行结果
在这里插入图片描述

3. strcat的使用与模拟实现

Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end ofthe new string for medby the concatenation of both in destination.
将复印一个源字符串附加到目标字符串。目标字符串中的终止空字符('\0')会被源字符串的第一个字符覆盖,新字符串的末尾也会包含一个空字符,以便对目标字符串中的两个字符串的连接进行调解。

注意事项

1.源字符串必须要有'\0'
2.目标字符串也要有'\0',否则没办法知道从哪里开始追加字符串
3.目标空间要足够大,能容纳下新增的内容
4.目标空间斌不能被const修饰

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

int main()
{
	char str1[] = "GuangDong";
	char str2[30] = { "Welcome to the " };
	printf("增加前 %s\n", str2);
	strcat(str2, str1);
	printf("增加后 %s\n", str2);
	return 0;
}

在这里插入图片描述

模拟实现
//strcat的使用与模拟
//在目标字符串的'\0'处拷贝源字符串(拷贝'\0')
char* my_strcat(char* dis, const char* src)
{
	assert(dis && src);
	char* tmp = dis;
	while (*dis != '\0')
	{
		dis++;
	}

	while (*dis++ = *src++)
		;

	return tmp;

}
int main()
{
	char str1[] = "GuangDong";
	char str2[30] = { "Welcome to the " };
	printf("增加前 %s\n", str2);
	my_strcat(str2, str1);
	printf("增加后 %s\n", str2);
	return 0;
}

在这里插入图片描述

4. strcmp的使用与模拟实现

This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null-character is reached.
该函数从每个字符串的第一个字符开始比较。如果彼此相等,则继续比较下面的字符对,直到字符不同或出现终止的空字符为止。(比较的是字符之间的ASCII码值,与字符串的长度没关系)

规定

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

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

int main()
{
	char str1[] = "abcde";
	char str2[] = "abd";
	int ret = strcmp(str1, str2);
	if (ret > 0)
	{
		printf("str1 大于 str2");
	}
	else if (ret == 0)
	{
		printf("str1 等于 str2");
	}
	else
		printf("str1 小于 str2");
	return 0;
}

在这里插入图片描述

模拟实现

#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')//两个都走到了\0
		{
			return 0;
		}
		str1++;
		str2++;

	}
	return *str1 - *str2;
}

上面最后一行的代码很巧妙的比较了字符之间大小,并且也返回了值
在这里插入图片描述

5. strncpystrncatstrncmp的使用

1.strncpy

char * strncpy ( char * destination, const char * source, size_t num );

Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
将源字符串的 num 个字符复制到目标字符串。如果在复制完 num 个字符之前发现源 C 字符串的结束标志'\0' ,则将用 0 填充目标字符串,直到总共写入 num 个字符为止。

从源字符串拷贝 num 个字符到目标空间
如果源字符串的长度小于 num,则在拷贝完源字符串后,会在目标空间后面追加 0 ,直到 num个

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

int main()
{
	char str1[] = "GuangDongSheng";//长度为字符串长度+\0
	const char str2[] = "QingYuan";
	printf("使用函数前:%s\n", str1);
	strncpy(str1, str2, 10);
	printf("使用函数后:%s\n", str1);
	return 0;
}

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

2.strncat

char * strncat ( char * destination, const char * source, size_t num );

Appends the first num characters of source to destination, plus a terminating null-character.(将源字符串的前 num 个字符加一个空字符作为结束符,追加到目的地。)
If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.(如果源字符串的长度小于 num,则只会将字符串中到 '\0' 的内容追加到目标空间末尾)

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


int main()
{
	char str1[50] = "GuangDongSheng";
	const char str2[] = "QingYuanShi";
	printf("使用函数前:%s\n", str1);
	strncat(str1, str2, 15);
	printf("使用函数后:%s\n", str1);
	return 0;
}

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

3.strncmp

int strncmp ( const char * str1, const char * str2, size_t num );

其实和前两个函数是差不多的,只不过该函数比较的是 str1 与 str2 的前 num 个字符,如果相等就往后比较,那么最多能比较 num 个字符,如果提前发现不一样,就会提前结束

在这里插入图片描述

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

int main()
{
	const char str1[] = "abcde";
	const char str2[] = "abcdd";
	printf("%d",strncmp(str1, str2,4));
	return 0;
}

在这里插入图片描述

6.strstr的使用与模拟实现

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


Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.(返回str2字符串第一次出现在str1字符串的位置)
The matching process does not include the terminating null-characters, but it stops there.(字符串的比较匹配并不包含字符'\0',而是以字符'\0'作为结束标志)

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[] = "abbbbbcaa";
	char str2[] = "bbc";
	char* ret = strstr(str1, str2);
	if (ret != NULL)
		printf("%s\n", ret);
	else
		printf("找不到\n");
	return 0;
}

在这里插入图片描述

模拟实现

思路:
1.需要记录开始比配时的地址(如果匹配失败了,会返回到开始匹配时的地址)
2.匹配失败往前指针往前走一步
3.如果str1走到了'\0',返回NULL
特殊情况:
如果str2是一个空字符串const char str2 = "\0",那么返回的时str1的起始地址

#include<assert.h>

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	if (*str2 == '\0')//特殊情况
	{
		return (char*)str1;
	}
	char* tmp = str1;
	while (*tmp)
	{
		const char* s1 = tmp;//用来记录str1的地址,用于匹配
		const char* s2 = str2;//用来记录str2的地址,用于匹配
		while (*s1 == *s2)//开始匹配
		{
			s1++;
			s2++;
		}
		
		if (*s2 == '\0')
			return tmp;
		tmp++;
	}
	return NULL;
}

在这里插入图片描述

7.strtok的使用

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

1.delimiters参数指向一个字符串,将指向的字符串定义为分隔符
2.str指向一个字符串,它包含了0个或多个由delimiters字符串中的一个或多个分割字符
3.strtok函数会直到str中的分割字符,并将其换成'\0',返回被分割的字符串的首元素地址
4.strtok函数的str不为NULL,函数将找到str中第一个分割字符,并会保留它在str字符串中的位置(下次进来就是在分割字符的地址处)
5.strtok函数的str为NULL函数将在被保留的位置开始,查找下一个分割字符
6.如果strtok找不到更多的str中的分割字符,则会返回NULL指针。

#include<stdio.h>
#include<string.h>
int main()
{
	char str[] = "192.268.354.456@163.com";
	char sep[] = ".@";
	char* tmp = NULL;

	for (tmp = strtok(str, sep); tmp != NULL; tmp = strtok(NULL, sep))
	{
		printf("%s ", tmp);
	}
	return 0;
}

在这里插入图片描述

8.strerror的使用

char * strerror ( int errnum );

解释 errnum 的值,生成一个带有信息的字符串,描述错误原因。
在不同的系统和C语言标准库的实现中都规定了⼀些错误码,⼀般是放在<errno.h>头文件中,在我们启动C语言程序的时候就会使用一个全局变量errno来记录程序当前的错误码,这不过在启动时errno是0(没有错误),当我们的程序发生了某个错误,就会将对应的错误码存放在errno中,但是很难理解错误码的意思,所以每个错误码都会有一个对应的错误信息,strerror函数就可以返回对应的错误信息字符串的地址。

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	int i = 0;
	for (i = 0; i <= 10; i++)//C语言有很多个错误码,这里取11个来展示
	{
		printf("%s\n", strerror(i));
	}
	return 0;
}

在这里插入图片描述

错误信息翻译
No error没有错误
Operation not permitted不允许操作
No such file or directory找不到文件或目录
No such proces没有这样的程序
Interrupted function call函数调用中断
Input/output error输入 / 输出错误
No such device or address没有这样的设备或地址
Arg list too long列表参数过长
Exec format error执行格式错误
Bad file descriptor无效的文件
No child processes没有子过程

结语

感谢您能阅读完此片文章,如果有任何建议或纠正欢迎在评论区留言。如果您认为这篇文章对您有所收获,点一个小小的赞就是我创作的巨大动力,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值