C语言——J/字符函数 和 字符串函数

2024-03-11 19:45:14 浏览数 (2)

前言:在编程的过程中,我们经常要处理字符和字符串,为了⽅便操作字符和字符串,C语⾔标准库中提供了⼀系列库函数。

一、字符分类函数

C语言中有⼀系列的函数是专⻔做字符分类的,也就是⼀个字符是属于什么类型的字符的。这些函数的使⽤都需要包含⼀个头文件是 ctype.h

代码语言:javascript复制
//函数        //如果他的参数符合下列条件就返回真
1、iscntrl    任何控制字符
2、isspace    空白字符:空格 ,换页f,换行n,回车r,水平制表符t,垂直制表符v
3、isdigit    十进制数字0 ~ 9数字字符
4、isxdigit   十六进制数字字符,包括所有十进制数字字符,小写字母a ~ f,大写字母A ~ F
5、islower    小写字母a ~ z
6、isupper    大写字母A ~ Z
7、isalpha    字母a ~ z或A ~ Z
8、isalnum    字母或数字,A ~ Z/a ~ z/0 ~ 9
9、ispunct    标点符号,任何不属于数字或者字母的图形字符(可打印)
10、isgraph   任何图形字符
11、isprint   任何可打印字符,包括图形字符和空白字符

这些函数的使⽤⽅法⾮常类似,我们就讲解⼀个函数的事情,其他的⾮常类似:

代码语言:javascript复制
int islower ( int c );

用途:islower 是能够判断参数部分的 c 是否是⼩写字⺟的; 说明:通过返回值来说明是否是⼩写字⺟,如果是⼩写字⺟就返回非0的整数,如果不是⼩写字⺟,则返回0。

代码语言:javascript复制
//判断大小写
#include<stdio.h>
int main()
{
	int ch = getchar();
	if (ch >= 'A' && ch <= 'Z')
	{
		printf("大写n");
	}
	else if (ch >= 'a' && ch <= 'z')
	{
		printf("小写n");
	}
	return 0;
}

练习:

写⼀个代码,将字符串中的⼩写字⺟转大写,其他字符不变。

代码语言:javascript复制
#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 (islower(c))
			c -= 32;
		putchar(c);
		i  ;
	}
	return 0;
}

二、字符转换函数

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

代码语言:javascript复制
int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写

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

练习:

代码语言:javascript复制
#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 (islower(c))
            c = toupper(c);

        // 输出字符
        putchar(c);

        // 移动到下一个字符
        i  ;
    }
    return 0;
}

三、strlen(字符个数)

代码语言:javascript复制
#include<string.h>
size_t strlen ( const char * str );

• 字符串以 '' 作为结束标志,strlen函数返回的是在字符串中 '' 前⾯出现的字符个数(不包 含 '' ); • 参数指向的字符串必须要以 '' 结束; • 注意函数的返回值为 size_t,是无符号的( 易错 );(因为长度的返回值不可能是负数所以是无符号整型) • strlen 的使用需要包含头文件;

注:返回值惹的祸(因为其返回值为无符号整型所以会输出 if 语句)

练习:

代码语言:javascript复制
#include <stdio.h>
#include <string.h>
int main()
{
	const char* str1 = "abcdef";
	const char* str2 = "bbb";
	if (strlen(str2) - strlen(str1) > 0)
    //if ((int)strlen(str2) - (int)strlen(str1) > 0)
    //类型转换就可以实现实际的输出
	{
		printf("str2>str1n");
	}
	else
	{
		printf("srt1>str2n");
	}
	return 0;
}

模拟实现:

代码语言:javascript复制
#include <stdio.h>
#include <assert.h>

//从前到后
size_t my_strlen1(const char* str)
{
	size_t count = 0;
	assert(str != NULL);//判断是否为空指针
	while (*str != '')//可以对其不用进行判断
	{
		count  ;
		str  ;
	}
	return count;
}

//相减
size_t my_strlen2(const char* str)
{
	assert(str);
	const char* start = str;
	while (*str != '')//可以对其不用进行判断因为  的A值也是0
	{
		str  ;
	}
	return str - start;
}

//写一个函数,不能使用临时变量,求字符串长度 - 递归
size_t my_strlen3(const char* str)
{
	if (*str == '')
		return 0;
	else
		return 1   my_strlen3(str   1);
}

int main()
{
	char arr[] = "abc";
	size_t len1 = my_strlen1(arr);
	size_t len2 = my_strlen2(arr);
	size_t len3 = my_strlen3(arr);

	printf("%zdn", len1);
	printf("%zdn", len2);
	printf("%zdn", len3);

	return 0;
}

四、strcpy(复制)

代码语言:javascript复制
#include<string.h>
char* strcpy(char * destination, const char * source );

• 原字符串必须以 '' 结束; • 会将原字符串中的 '' 拷贝到目标空间; • 目标空间必须足够大,以确保能存放源字符串; • 目标空间必须可修改;

练习:

代码语言:javascript复制
int main()
{
	char arr1[20] = {0};//目标空间必须足够大
	char arr2[] = "hello world";
	strcpy(arr1, arr2);
	printf("%sn", arr1);

	return 0;
}


//目标空间的常量字符串是不可修改的
int main()
{
	char* p = "abcdefghilmkqwer";//常量字符串,不能修改
	char arr2[] = "hello world";
	strcpy(p, arr2);//目标空间必须是可修改的
	printf("%sn", p);

	return 0;
}

模拟实现:

代码语言:javascript复制
//原版
void my_strcpy(char* dest, char* src)
{
	while (*src != '')
	{
		*dest = *src;
		dest  ;
		src  ;
	}
	*dest = *src;
}

//改进后
char* my_strcpy(char* dest, char* src)
{
	assert(dest != NULL);
	assert(src != NULL);

	//assert(src && dest);另一种判断方法

	char* ret = dest;
	assert(dest && src);
	while (*dest   = *src  )
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[20] = { 0 };
	char arr2[] = "abcdef";
	printf("%sn", my_strcpy(arr1, arr2));

	return 0;
}

五、strcat (追加)

• 源字符串必须以 '' 结束; • 目标字符串中也得有 ,否则没办法知道追加从哪里开始; • 目标空间必须有足够的大,能容纳下源字符串的内容; • 目标空间必须可修改;

练习:

代码语言:javascript复制
#include <string.h>
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	strcat(arr1, arr2);
	printf("%sn", arr1);

	return 0;
}

• 字符串自己给自己追加,如何?

无论库函数,还是模拟出来的最好不要自己追加,实在是要追加就用库里的strncat.(有限制)

模拟实现:

代码语言:javascript复制
char* my_strcat(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest && src);
	//1. 找到目标空间的
	while (*dest)
	{
		dest  ;
	}
	//2. 拷贝
	while (*dest   = *src  )
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[20] = "hello ";
	my_strcat(arr1, arr1);
	printf("%sn", arr1);

	return 0;
}

六、strcmp(比较)

• 标准规定: ◦ 第⼀个字符串⼤于第⼆个字符串,则返回大于0的数字; ◦ 第⼀个字符串等于第⼆个字符串,则返回0; ◦ 第⼀个字符串⼩于第⼆个字符串,则返回小于0的数字; ◦ 那么如何判断两个字符串? 答案是比较两个字符串中对应位置上字符ASCII码值的⼤⼩。

练习:

代码语言:javascript复制
int main()
{
	int ret = strcmp("bbq", "abcdef");
	printf("%dn", ret);//1、返回值

// if (ret > 0)//2、返回输出
//		printf("大于n");
//	else if (ret == 0)
//		printf("等于n");
//	else
//		printf("小于n");
//
	return 0;
}

模拟实现:

代码语言:javascript复制
int my_strcmp(const char* s1, const char* s2)
{
	while (*s1 == *s2)
	{
		if (*s1 == '')
			return 0;
		s1  ;
		s2  ;
	}
	if (*s1 > *s2)
		return 1;
	else
		return -1;
}

改造后
//int my_strcmp(const char* s1, const char* s2)
//{
//	while (*s1 == *s2)
//	{
//		if (*s1 == '')
//			return 0;
//		s1  ;
//		s2  ;
//	}
//	return *s1 - *s2;
//}

int main()
{
	int ret = my_strcmp("abcdef", "abc");
	if (ret > 0)
		printf("大于n");
	else if (ret == 0)
		printf("等于n");
	else
		printf("小于n");
	return 0;
}

七、strncpy (有限制的复制)

代码语言:javascript复制
char * strncpy ( char * destination, const char * source, size_t num );

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

练习:

代码语言:javascript复制
#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[20] = "xxxxxxxxxx";
	char arr2[] = "hello";
	int ret = strncpy(arr1, arr2, 3);

	printf("%s", arr1);
	return 0;
}

八、strncat(有限制的追加)

代码语言:javascript复制
char * strncat ( char * destination, const char * source, size_t num );

• 将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加⼀个 字 符。 • 如果source 指向的字符串的⻓度小于num的时候,只会将字符串中到 的内容追加到destination指向的字符串末尾。

练习:

代码语言:javascript复制
#include <stdio.h>
#include <string.h>
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	strncat(arr1, arr2, 3);

	printf("%s", arr1);

	return 0;
}

九、strncmp(有限制比较)

代码语言:javascript复制
int strncmp ( const char * str1, const char * str2, size_t num );

⽐较str1和str2的前num个字符,如果相等就继续往后⽐较,最多⽐较num个字⺟,如果提前发现不⼀样,就提前结束,⼤的字符所在的字符串⼤于另外⼀个。如果num个字符都相等,就是相等返回0.

练习:

代码语言:javascript复制
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcq";
	int ret = strncmp(arr1, arr2, 5);

	printf("%dn", ret);
	return 0;
}

十、strstr (标志出现位置)

代码语言:javascript复制
char * strstr ( const char * str1, const char * str2);

用途:函数返回字符串str2在字符串str1中第⼀次出现的位置;

说明:字符串的⽐较匹配不包含 字符,以 作为结束标志。

练习:

代码语言:javascript复制
#include <stdio.h>
#include <string.h>
//strstr 返回字符串在另外一个字符中第一次出现的位置

int main()
{
	char arr1[] = "abcdefabcdef";
	char arr2[] = "deq";
	char* ret = strstr(arr1, arr2);
	if (ret != NULL)
		printf("%sn", ret);
	else
		printf("找不到n");

	return 0;
}

模拟实现:(KMP算法)

代码语言:javascript复制
char* my_strstr(const char* str1, const char*str2)
{
	const char* cur = str1;
	const char* s1 = NULL;
	const char* s2 = NULL;

	assert(str1 && str2);
	if (*str2 == '')
	{
		return (char*)str1;
	}

	while (*cur)
	{
		s1 = cur;
		s2 = str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1  ;
			s2  ;
		}
		if (*s2 == '')
		{
			return (char*)cur;
		}
		cur  ;
	}
	return NULL;
}

int main()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bbq";
	char* ret = my_strstr(arr1, arr2);
	if (ret != NULL)
		printf("%sn", ret);
	else
		printf("找不到n");

	return 0;
}

十 一、strtok(标记) 函数的使用

代码语言:javascript复制
char * strtok ( char * str, const char * sep);

• sep参数指向⼀个字符串,定义了⽤作分隔符的字符集合; • 第⼀个参数指定⼀个字符串,它包含了0个或者多个由sep字符串中⼀个或者多个分隔符分割的标 记; • strtok函数找到str中的下⼀个标记,并将其⽤ 结尾,返回⼀个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷⻉的内容 并且可修改。)

• strtok函数的第⼀个参数不为 NULL ,函数将找到str中第⼀个标记,strtok函数将保存它在字符串 中的位置; • strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标 记; • 如果字符串中不存在更多的标记,则返回 NULL 指针。

代码语言:javascript复制
#include<stdio.h>
#include<string.h>

int main()
{
	char arr[] = "zhangsan@163.com#hehe";
	char arr2[30] = {0}; //zhangsan163com
	strcpy(arr2, arr);
	const char* p = "@.#";
	char* s = NULL;
	//   初始化部分只执行一次
	for (s = strtok(arr2, p); s != NULL; s=strtok(NULL, p))
	{
		printf("%sn", s);
	}

	//char *s = strtok(arr2, p);
	//printf("%sn", s);
	//s = strtok(NULL, p);
	//printf("%sn", s);
	//s = strtok(NULL, p);
	//printf("%sn", s);

	return 0;
}

十二、strerror(错误报告)函数的使用

代码语言:javascript复制
char * strerror ( int errnum );

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

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

代码语言:javascript复制
#include <errno.h>
#include <string.h>
#include <stdio.h>
//我们打印⼀下0~10这些错误码对应的信息
int main()
{
	int i = 0;
	for (i = 0; i <= 10; i  ) 
    {
		printf("%d: %sn",i, strerror(i));
	}
	return 0;
}

在Windows10 VS2022环境下输出的结果如下:

举例:

代码语言:javascript复制
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	FILE* pFile;
	pFile = fopen("unexist.ent", "r");//"r"以读的形式打开
	if (pFile == NULL)
		printf("Error opening file unexist.ent: %sn", strerror(errno));
	return 0;
}

C语言是可以进行文件操作来打开文件:FILE* pFile = fopen(……);如果文件打开成功,则返回一个地址;如果文件打开失败,则返回NULL。

输出:

代码语言:javascript复制
Error opening file unexist.ent: No such file or directory

也可以了解⼀下perror函数,perror函数相当于⼀次将上述代码中的第9⾏完成了,直接将错误信息打印出来。perror函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。

代码语言:javascript复制
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	FILE* pFile;
	pFile = fopen("unexist.ent", "r");
	if (pFile == NULL)
		perror("Error opening file unexist.ent");
	return 0;
}

输出:

代码语言:javascript复制
Error opening file unexist.ent: No such file or directory

0 人点赞