[C]基础14.字符函数和字符串函数

  • 博客主页:向不悔
  • 本篇专栏:[C]
  • 您的支持,是我的创作动力。

文章目录


0、总结

在编程的过程中,我们经常要处理字符和字符串,为了方便操作字符和字符串,我们要学习一下这些函数。

1、字符分类、转换函数

C语言中有一系列的函数是专门做字符分类的,也就是说,一个字符是属于什么类型的字符。这些函数的使用都需要包含一个头文件是ctype.h,分类函数参考:https://cplusplus.com/reference/cctype/

常用的分类函数如下:

转换函数的头文件也是ctype.h,参考如下:

示例,写一个代码,将字符串中的小写字母转大写,其他字符不变。

c 复制代码
#include <stdio.h> /* printf */
#include <ctype.h> /* islower、toupper */
#include <string.h> /* strlen */

int main()
{
	char str[] = "hello,world";
	int len = strlen(str);
	int i = 0;
	for (i = 0; i < len; i++)
	{
		if (islower(str[i])) str[i] = toupper(str[i]);
	}
	printf("%s\n", str);
	return 0;
}

2、strlen的使用和模拟实现

2.1 strlen的使用

介绍:

总结如下:

  • 字符串以'\0',作为结束标志,strlen函数返回的是在字符串中'\0'前面出现的字符个数,不包含'\0'
  • 参数指向的字符串必须要以'\0'结束。
  • 注意函数的返回值为size_t,是无符号的(易错)。

2.2 strlen的模拟实现

方式一:计数器方式

c 复制代码
#include <stdio.h> /* printf */
#include <assert.h>

int my_strlen(const char* str)
{
	int count = 0;
	// 如果str是空指针,程序会输出一条错误的信息并终止执行。
	// 因为如果直接对空指针进行解引用,会导致程序崩溃。
	assert(str);
	// 循环一直执行,直到str指向的字符是空字符\0。
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}

int main()
{
	const char* str = "abc";
	int len = my_strlen(str);
	printf("%d\n", len);
	return 0;
}

方式二:不能创建临时变量计数器

c 复制代码
int my_strlen(const char* str)
{
	assert(str);
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(str + 1);
}

方式三:指针-指针的方式

c 复制代码
int my_strlen(const char* str)
{
	assert(str);
	char* p = str;
	while (*p)
		p++;
	return p - str;
}

3、strcpy的使用和模拟实现

3.1 strcpy的使用

介绍:

总结如下:

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

3.2 strcpy的模拟实现

题目出自《高质量C/C++编程》书籍最后的试题部分

c 复制代码
#include <stdio.h> /* printf */
#include <assert.h>

char* my_strcpy(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest);
	assert(src);
	// 赋值后的结果(即*src的值作为条件)
	// 当*src为'\0'时候,条件为假,循环结束。
	// 就是说,先获取*src的值,再将这个值赋给*dest,用这个值(即*src的值)作为循环的条件。
	while (*dest++ = *src++);
	return ret;
}

int main()
{
	char a[30] = "xxxxxxxx";
	char b[4] = "abc";
	printf("复制前:%s\n", a);
	my_strcpy(a, b);
	printf("复制后:%s\n", a);
	return 0;
}

解释while (*dest++ = *src++);,如下:

4、strcat的使用和模拟实现

4.1 strcat的使用

介绍:

总结如下:

  • 源字符串必须以'\0'结束。
  • 目标字符串中也得有'\0',否则没办法知道追加从哪里开始。
  • 目标空间必须有足够的大,且必须可修改。
  • 字符串自己给自己追加,如何?

4.2 strcat的模拟实现

c 复制代码
#include <stdio.h> /* printf */
#include <assert.h>

char* my_strcat(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest);
	assert(src);
	while (*dest) dest++;
	while (*dest++ = *src++);
	return ret;
}

int main()
{
	char a[30] = "xxxxxxxx";
	char b[4] = "abc";
	printf("复制前:%s\n", a);
	my_strcat(a, b);
	printf("复制后:%s\n", a);
	return 0;
}

my_strcat函数在将字符串自己追加自己时会导致无限循环,可能引发程序崩溃。

5、strcmp的使用和模拟实现

5.1 strcmp的使用

介绍:

总结如下:

  • 第一个字符串大于第二个字符串,则返回大于0的数字。
  • 第一个字符串等于第二个字符串,则返回0。
  • 第一个字符串小于第二个字符串,则返回小于0的数字。
  • 是如何判断两个字符串呢?比较两个字符串中对应位置上字符ASCII码值的大小。

5.2 strcmp的模拟实现

c 复制代码
#include <stdio.h> /* printf */
#include <assert.h>

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		// if (*str1 == '\0') 和 if (*str2 == '\0') 在逻辑上是等价的,
		// 因为当两个字符串相等时,它们会同时到达末尾(即遇到'\0')。
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;
}

int main()
{
	char arr1[] = "abq";
	char arr2[] = "abcdef";
	int ret = my_strcmp(arr1, arr2);
	printf("%d\n", ret);


	return 0;
}

6、strncpy函数的使用

介绍:

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

7、strncat函数的使用

介绍:

  • 头文件:string.h
  • 函数原型:char* strncat(char* destination, const char* source, size_t num);
  • 作用:将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加一个\0字符。
  • 参考:https://cplusplus.com/reference/cstring/strncat/

注意:如果source指向的字符串的长度小于num的时候,只会将字符串中到\0的内容追加到destination指向的字符串末尾。

8、strncmp函数的使用

介绍:

9、strstr的使用和模拟实现

9.1 strstr的使用

介绍:

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

9.2 strstr的模拟实现

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>


char* my_strstr(const char* str1, const char* str2)
{
	char* cp = (char*)str1;
	char* s1, * s2;

	if (!*str2)
		return (char*)str1;

	while (*cp)
	{
		s1 = cp;
		s2 = (char*)str2;

		while (*s1 && *s2 && !(*s1 - *s2))
			s1++, s2++;

		if (!*s2)
			return cp;

		cp++;
	}

	return NULL;
}

int main()
{
	char s1[] = "aaabbbcccdefbbcdefa";
	char s2[] = "ccdef";
	printf("%s\n", my_strstr(s1, s2));
	return 0;
}

10、strtok函数的使用

介绍:

总结如下:

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

示例:

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#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;
}
c 复制代码
运行:
192
168
6
111

11、strerror函数的使用

介绍:

总结如下:

函数能返回对应错误码的错误信息字符串地址。系统和 C 语言标准库规定了一些错误码,一般在头文件中说明。程序启动时用变量记录当前错误码,初始为 0 表示无错误。调用标准库函数出错时,会将对应错误码存入因错误码是整数较难理解,所以每个错误码都有对应的错误信息,函数就能返回该错误信息字符串的地址。

打印0~10这些错误码对应的信息

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main()
{
	int i = 0;
	for (i = 0; i <= 10; i++)
	{
		printf("%s\n", strerror(i));
	}
	return 0;
}
c 复制代码
在Windows11+VS2022环境下输出运行:
No error
Operation not permitted
No such file or directory
No such process
Interrupted function call
Input/output error
No such device or address
Arg list too long
Exec format error
Bad file descriptor
No child processes

举个例子:

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main()
{
	FILE* pFile;
	pFile = fopen("1.txt", "r");
	if (pFile == NULL)
		printf("Error:%s\n", strerror(errno));
	return 0;
}
c 复制代码
运行:
Error:No such file or directory

也可以了解perror函数,总结如下:

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main()
{
	FILE* pFile;
	pFile = fopen("1.txt", "r");
	if (pFile == NULL)
		perror("Error 1.txt");
	return 0;
}
c 复制代码
运行:
Error 1.txt: No such file or directory

所以,perror函数打印完参数部分的字符串后,再打印一个冒号和一个空格,再打印错误信息。


完。

相关推荐
belldeep2 小时前
Fabrice Bellard(个人网站:‌bellard.org‌)介绍
c语言·tcc·知名程序员·tinygl
CodeWithMe2 小时前
【C/C++】Linux的futex锁
linux·c语言·c++
笑口常开xpr2 小时前
C 语 言 - - - 文 件 操 作
c语言·开发语言
旺仔老馒头.16 小时前
【数据结构】线性表--顺序表
c语言·数据结构·visual studio
佛大第一深情16 小时前
ESP32 在Platform Arduino平台驱动外部PSAM,进行内存管理
c语言·单片机·嵌入式硬件
一匹电信狗16 小时前
【数据结构】堆的完整实现
c语言·数据结构·c++·算法·leetcode·排序算法·visual studio
浅安的邂逅16 小时前
Linux进程7-signal信号处理方式验证、可重入函数举例、信号集函数验证、信号集阻塞验证
linux·c语言·vim·进程通信·gcc
积极向上的向日葵20 小时前
双向链表详解
c语言·数据结构·链表·双向链表
我命由我123451 天前
C++ - 数据容器之 list(创建与初始化、元素访问、容量判断、元素遍历、添加元素、删除元素)
c语言·开发语言·c++·后端·visualstudio·c#·visual studio