前言

1. 字符分类、转换函数基本用法

1.1 字符分类函数基本概念与用法

1.2 字符转换函数基本概念与用法

2.strlen基本概念与模拟实现

2.1 初步认识与使用strlen函数

2.2 strlen函数的模拟实现

3.strcpy函数的基本概念与模拟实现

3.1 初步认识strcpy函数

3.2 strcpy函数的模拟实现

4.strcat的基本概念与模拟实现

4.1 初步认识strcat

4.2 strcat的模拟实现

5.strcmp的基本概念与模拟实现

5.1 初步认识strcmp

5.2 strcmp的模拟实现

6.strncpy、strncat和strncmp的基本概念

6.1 初步认识strncpy

6.2 初步认识strncat

6.3 初步认识strncmp

7.认识strstr函数与模拟实现

7.1 初步认识strstr函数

7.2 strstr函数的模拟实现

8.strtok的使用

总结:

前言

字符串处理是C语言编程中的核心技能之一。尽管C语言没有内置的字符串类型,但通过标准库提供的一系列函数,我们可以高效、灵活地处理文本数据。本文将深入探讨C语言字符串处理的方方面面,不仅涵盖基本函数使用,还会揭示常见陷阱、性能考虑和实际应用场景。

1. 字符分类、转换函数基本用法

1.1 字符分类函数基本概念与用法

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

这些函数的使用方法非常类似,我们就讲解⼀个函数的实现,其他的非常类似:
int islower ( int c );

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

那我们可以利用这个函数做一个小练习,写⼀个代码,将字符串中的小写字⺟转⼤写,其他字符不变。

#include<stdio.h>
#include<ctype.h>
int main()
{
	char s1[] = "I love C";
	char* p = s1;
	while (*p)
	{
		if (islower(*p))
		{
			*p -= 32;
		}
		p++;
	}
	printf("%s", s1);
	return 0;
}

1.2 字符转换函数基本概念与用法

C语言提供了2个字符转换函数:
int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写 
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写
上面的代码,我们将⼩写转⼤写,是-32完成的效果,有了转换函数,就可以直接使用  tolower
数。
#include<stdio.h>
#include<ctype.h>
int main()
{
	char s1[] = "I love C";
	char* p = s1;
	while (*p)
	{
		if (islower(*p))
		{
			*p=toupper(*p);
		}
		p++;
	}
	printf("%s", s1);
	return 0;
}

2.strlen基本概念与模拟实现

2.1 初步认识与使用strlen函数

size_t strlen ( const char * str );

注意事项:

字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前⾯出现的字符个数(不包含 '\0' )。

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

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

strlen的使⽤需要包含头⽂件(string.h)。

用法示例:

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

	int main()
	{
		char s[] = "hello world";
		printf("%zd", strlen(s));
		return 0;
	}

2.2 strlen函数的模拟实现

在这里给出三种方法:

方法一:指针-指针

#include<stdio.h>
int my_strlen(const char* s)
{
	char *p=(char*)s;
	while (*s != '\0')
	{
		s++;
	}
	return s-p;
}
int main()
{
	char s[] = "I love C" ;
	printf("%d",my_strlen(s));
	return 0;
}

方法二:创建计数器,遍历整个字符数组

#include<stdio.h>
int my_strlen(const char* s)
{
	int count = 0;
	while (*s != '\0')
	{
		count++;
		s++;
	}
	return count;
}
int main()
{
	char s[] = "I love C" ;
	printf("%d",my_strlen(s));
    return 0;
}

方法三:递归

#include<stdio.h>
int my_strlen(const char* s)
{
	if (*s == '\0')
	{
		return 0;
	}
	else
	{
		return 1 + my_strlen(s + 1);
	}
}
int main()
{
	char s[] = "I love C";
	printf("%d",my_strlen(s));
}

3.strcpy函数的基本概念与模拟实现

3.1 初步认识strcpy函数

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

其实就是把一个字符串复制到另一个字符串上,得到完全相同的两个字符串。

注意事项:

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

会将源字符串中的 '\0' 拷贝到目标空间。

⽬标空间必须⾜够⼤,以确保能存放源字符串。

⽬标空间必须可修改。

基本用法:

#include<stdio.h>
#include<string.h>
int main()
{
	char s[] = "*****************";
	char s2[] = "asdfghj";
	strcpy(s, s2);
	printf("%s", s);
}

我们调试时发现,s2中的'\0'也会被复制过来。

3.2 strcpy函数的模拟实现

#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dst, const char* src)
{
	char* ret=dst;
	assert(dst != NULL && src != NULL);
	/*while (*dst++ = *src++)
		;
	return ret;*/
	while (*src != '\0')
	{
		*dst++ = *src++;
	}
	*dst = '\0';
	return ret;
}
int main()
{
	char s1[] = "I love C";
	char s2[50] = { 0 };
	char* ret=my_strcpy(s2, s1);
	printf("%s", ret);
}

4.strcat的基本概念与模拟实现

4.1 初步认识strcat

其实就是在目标字符从'\0'开始,把源字符串给复制上去。

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

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

目标空间必须有⾜够的⼤,能容纳下源字符串的内容。

目标空间必须可修改。

代码实现:

#include<stdio.h>
#include<string.h>
	int main()
	{
			char s1[100] =  "I love C " ;
			char s2[] = "and I am learning C";
			printf("%s",strcat(s1, s2));
			return 0;
	}

4.2 strcat的模拟实现

#include<stdio.h>
#include<assert.h>
char* my_strcat( char* s1, const char* s2)
{
	assert(s1 && s2 != NULL);
	char* ret = s1;
	while (*s1!='\0')
		s1++;
	while ((*s1++ = *s2++))
		;
	return ret;
}
int main()
{
	char s1[100] =  "I love C " ;
	char s2[] = "and I am learning C";
	printf("%s",my_strcat(s1, s2));
	return 0;
}

5.strcmp的基本概念与模拟实现

5.1 初步认识strcmp

就是对两个字符串进行大小的比较,比较规则:

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

第⼀个字符串等于第⼆个字符串,则返回0

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

那么如何判断两个字符串? 比较两个字符串中对应位置上字符ASCII码值的大小。

代码示例:

#include<stdio.h>
#include<string.h>
	int main()
	{
			char s1[100] =  "I love C " ;
			char s2[] = "and I am learning C";
			int ret = strcmp(s1, s2);
			if (ret < 0)
			{
					printf("%s is less than %s\n", s1, s2);
			}
			else if (ret > 0)
			{
					printf("%s is greater than %s\n", s1, s2);
			}
			else
			{
				printf("%s is equal to %s\n", s1, s2);
			}
			return 0;
	}

5.2 strcmp的模拟实现

#include<stdio.h>
int my_strcmp(char* s1, char* s2)
{
	while (*s1 && *s2)
	{
		if (*s1 != *s2)
		{
			return *s1 - *s2;
		}
	}
}
	int main()
	{
			char s1[100] =  "I love C " ;
			char s2[] = "and I am learning C";
			int ret = my_strcmp(s1, s2);
			if (ret < 0)
			{
					printf("%s is less than %s\n", s1, s2);
			}
			else if (ret > 0)
			{
					printf("%s is greater than %s\n", s1, s2);
			}
			else
			{
				printf("%s is equal to %s\n", s1, s2);
			}
			return 0;
	}

6.strncpy、strncat和strncmp的基本概念

6.1 初步认识strncpy

规则:

拷贝num个字符从源字符串到目标空间。

如果源字符串的长度小于num,则拷贝完源字符串之后,在⽬标的后边追加0,直到num个。

6.2 初步认识strncat

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

6.3 初步认识strncmp

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

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

总结,其实就是多加了一个参数,对字符串大小进行了限制,增强了安全性。

7.认识strstr函数与模拟实现

7.1 初步认识strstr函数

功能就是在str1中查找str2,如果不存在就返回空指针,否则返回str2在str1中首次出现的指针。

功能示例:

#include<stdio.h>
#include<string.h>
int main()
{
	char s1[] = "asdfghjkl";
	char s2[] = "fghjkl";
	char s3[] = "fkl";
	printf("%s\n", strstr(s1, s2));
	printf("%s", strstr(s1, s3));
	return 0;
}

7.2 strstr函数的模拟实现

#include<stdio.h>
char* my_strstr(const char* s1, const char* s2)
{
	if (!s1 || !s2)
	{
		return NULL;
	}
	char* p1=NULL;
	char* p2=NULL;
	char* curr = s1;
	while (*curr)
	{
		p1 = curr;
		p2 = s2;
		while (*p1 && *p2 && (*p1 == *p2))
		{
			p1++;
			p2++;
		}
		if (*p2 == '\0')
		{
			return curr;
		}
		curr++;
	}
	return NULL;

}
int main()
{
	char s1[] = "hello world";
	char s2[] = "world";
	printf("%s",my_strstr(s1, s2));
	return 0;
}

这里直接采取暴力搜索的方法,全部遍历,一个一个比对。

8.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 指针。

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

	return 0;
}

9.strerror的使用

char* strerror ( int errnum );

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

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

#include <errno.h>
#include <string.h>
#include <stdio.h>
int main()
{
 int i = 0;
 for (i = 0; i <= 10; i++) {
 printf("%s\n", strerror(i));
 }
 return 0;
}
在Windows11+VS2022环境下输出的结果如下:
举例:
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
 FILE * pFile;
 pFile = fopen ("unexist.ent","r");
 if (pFile == NULL)
 printf ("Error opening file unexist.ent: %s\n", strerror(errno));
 return 0;
}

也可以了解⼀下 perror 函数,perror 比特就业课主页:https://m.cctalk.com/inst/s9yewhfr 函数相当于⼀次将上述代码中的第9⾏完成了,直接将错误信息
打印出来。perror函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息
#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;
 }

总结:

C语言字符串处理是每个C程序员必须掌握的核心技能。从基本的strcpystrcatstrcmp到更安全的strncpystrncatstrncmp,再到高级的strstrstrtok和错误处理函数strerror,我们不仅学习了这些函数的使用方法,还深入探讨了它们的模拟实现、常见陷阱和性能优化。

记住,C语言字符串处理的关键在于安全效率。始终注意缓冲区边界,确保字符串以\0结尾,避免缓冲区溢出和未定义行为。同时,根据应用场景选择合适的函数和算法,避免不必要的性能损耗。

希望本文能帮助你更好地理解和应用C语言的字符串函数,写出更安全、高效、可靠的代码。实践出真知,多写代码,多思考,你一定会成为字符串处理的高手!

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐