【C语言进阶(6)】字符串函数的使用方法 + 模拟实现

文章目录

  • Ⅰ 字符操作函数
    • ⒈字符分类函数
    • ⒉字符转换函数
  • Ⅱ 字符串操作函数
    • ⒈strlen
    • ⒉strcpy
    • ⒊strcat
    • ⒋strcmp
    • ⒌strncpy
    • ⒍strncat
    • ⒎strncmp
    • ⒏strstr
    • ⒐strtok
    • ⒑strerror
  • Ⅲ 模拟实现字符串函数
    • ⒈模拟实现 strlen
    • ⒉模拟实现 strcpy
    • ⒊模拟实现 strcat
    • ⒋模拟实现 strcmp
    • ⒌模拟实现 strncpy
    • ⒍模拟实现 strncat
    • ⒎模拟实现 strncmp
    • ⒏模拟实现 strstr

本文重点介绍函数

  • 求字符串长度 —— strlen
  • 长度不受限制的字符串函数 —— strcpy、strcat、strcmp
  • 长度受限制的字符串函数 —— strncpy、strncat、strncmp
  • 字符串查找函数 —— strstr、strtok
  • 错误信息报告函数 —— strerror

Ⅰ 字符操作函数

引用头文件

⒈字符分类函数

函数名 函数功能
iscntrl 判断是否是控制字符
isspace 判断是否是空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
sdigit 判断是否是十进制数字: 0~9
isxdigit 判断是否是十六进制数字:包括所有十进制数字,小写字母 a ~ f,大写字母 A ~ F
islower 判断是否是小写字母:a ~ z
isupper 判断是否是大写字母 A ~ Z
isalpha 判断是否是字母:a ~ z 或 A ~ Z
isalnum 判断是否是字母或者数字:a ~ z,A ~ Z,0 ~ 9
ispunct 判断是否是标点符号:任何不属于数字或者字母的图形字符(可打印)
isgraph 判断是否是任何图形字符
isprint 判断是否是任何可打印字符,包括图形字符和空白字符

⒉字符转换函数

函数名 函数功能
toupper 将小写字母转换成大写字母
tolower 将大写字母转换成小写字母

函数用例

int main()
{
	char str[] = "i WANT TO PLAY bLACK mYTH wUKONG!";

	for (int i = 0; i < strlen(str); i++)
	{
		if (islower(str[i]))
		{
			str[i] = toupper(str[i]);
		}
		else if (isupper(str[i]))
		{
			str[i] = tolower(str[i]);
		}
	}

	printf("%s\n", str);

	return 0;
}

在这里插入图片描述

Ⅱ 字符串操作函数

字符串函数相关知识

  • 字符串末尾一定悄悄的藏着一个 ’ \0 '。
  • 字符串函数引用头文件:
  • 只能对字符串进行操作,有 ’ \0 ’ 这个限制条件

⒈strlen

求字符串长度

size_t strlen ( const char * str );
  • size_t 是个无符号整形,想打印 strlen 函数的返回值最好使用 %zd 。

函数功能

  • 求字符串长度,返回 ’ \0 ’ 之前出现的所有字符个数。

函数参数

  • 一个字符串的首字符的地址。

函数用例

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第1张图片

⒉strcpy

拷贝字符串

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

函数功能

  • 将 source 指向的字符串(包含 ’ \0 ')复制到 destination 指向的数组中,然后返回 destination 空间的起始地址。
  • 为了避免溢出,destination 指向的数组的大小应该 足够容纳 source 指向的串中得所有内容。

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第2张图片

函数参数

  • source:指向被复制的字符串。
  • destination:指向要在其中复制内容的目标数组。

返回值

  • destination 数组的起始地址。

函数用例

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第3张图片

⒊strcat

连接字符串

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

函数功能

  • 将一个字符串(包含 ’ \0 ')连接到另一个字符串的后面。
  • 要求目标数组里已经包含一个字符串(可以是空串),找到目标字符串的末尾并将源字符串 cv 过去。

函数参数

  • source:要追加的字符串,与目的地的内存不能重叠。
  • destination:指向目标数组的指针,该数组应包含一个字符串,并且足够大以包含连接的结果字符串。

返回值

  • destination 数组的起始地址。

函数用例

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第4张图片

⒋strcmp

比较字符串

int strcmp ( const char * str1, const char * str2 );

函数功能

  • 比较两个字符串的是否相同
  • 从第一个字符开始,依次对比两个字符串中每个对应字符的 ASCII 码值的大小。如果第一个字符串的字符的 ASCII 码小于第二个字符串对应字符的 ASCII 码,则返回一个小于 0 的值;如果大于,则返回一个大于 0 的值。

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第5张图片

函数参数

  • str1:指向第一个字符串的起始地址。
  • str2:指向第二个字符串的起始地址。

函数用例

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第6张图片

⒌strncpy

指定拷贝字符数

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

函数功能

  • 在实现程序复制的时候,应该限制源字符串的长度,确保目标数组在执行完复制后不会发生溢出。
  • 于是就有了 strncpy。在 strcpy 的基础上添加了一个参数,用来指定拷贝的字符个数

函数参数

  • source:指向被复制的字符串。
  • destination:指向要在其中复制内容的目标数组。
  • num:指定从 source 指向的字符串中拷贝 num 个字符到 destination 指向的目标数组中。

函数用例

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第7张图片

⒍strncat

指定连接字符数

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

函数功能

  • 指定从 source 指向的串中连接 num 个字符到 destination 指向的字符串的末尾
  • 与 strncpy 不同的是,strncat 总是在连接后自动追加一个结束符(’ \0 ')

函数用例

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第8张图片

⒎strncmp

指定比较字符数

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

函数功能

  • 指定比较两个字符串的前 num 个字符

函数用例

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第9张图片

⒏strstr

找字符串子串

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

函数功能

  • 在 str1 指向的字符串中查找是否存在字符串 str2
  • 看看 str1 里面是否包含 str2,如果包含则返回首次出现 str2 字符的起始地址,反之则扔一个空指针回来。

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第10张图片

函数参数

  • str1:指向待查找的字符串。
  • str2:指向被查找的字符串。

函数用例

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第11张图片

⒐strtok

分割字符串

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

函数功能

  • 按照 delimiters 中提供的分割符,将 str 中出现提供的分割符的位置改成 \0,并将 str 这个串在此处结尾。
char str[] = "wwwoBlack_myth_wukong0com";
char* deli = "o_0";

- 按照 deli 提供的字符对 str 进行分割;
- 将 str 中 o_0 这几个字符的位置换成 \0,www\0Black_myth_wukong0com
- 然后返回分隔的位置之前的串的首地址

函数参数

  • str:指向待被分割的字符串。
  • delimiters:用作分割符的字符(可以是一个字符,也可以是一个集合)。

返回值

  • 返回被分解的第一个子字符串的首字符地址。
  • 若无可检索的字符串,则返回 NULL1。

注意事项

  • strtok 函数会改变被操作的字符串,所以在使用 strtok 函数切分的字符串一般都是临时拷贝的内容并且可修改。
  • strtok 的第一个参数不为 NULL 时,函数将找到 str 中第一个分割符,strtok 函数将保存它在字符串中的位置。

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第12张图片

  • strtok 的第一个参数是为 NULL 时,函数将在同一个字符串中被保存的位置开始,查找下一个分割符。

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第13张图片

  • 如果 strtok 函数找不到分割符,则返回 NULL。

函数用例

  • strtok 函数会记录 str 串中出现分割符的位置,不用担心传 NULL 会找不到 str。

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第14张图片

⒑strerror

错误报告函数

char * strerror ( int errnum );

函数功能

  • 返回错误码所对应的错误信息
  • 错误码对应的错误信息不需要去记,C 语言的库函数在执行失败的时候,都会设置错误码。

函数用例

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第15张图片

实际使用

  • 如果在可能发生错误的情况下需要先判断错误信息,这个时候时没有提供错误码的。

  • 此时就需要将错误码先记录在 errno 变量里,直接将 errno 交给 strerror 即可,就不用每次手动输入错误码那么挫了。

  • errno:C 语言设置的一个存放错误码的全局变量。引用头文件:。当出现新的错误码时,会将旧的覆盖掉,始终记录最新的。

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第16张图片

Ⅲ 模拟实现字符串函数

  • 模拟实现字符串函数,就得保证自定义函数的(参数、返回值)同库函数一致

⒈模拟实现 strlen

1. 计数器法

size_t my_strlen(const char* str)
{
	assert(str);
	size_t len = 0;
	
	while (*str++)
	{
		len++;
	}

	return len;
}

2. 递归法

size_t my_strlen(const char* str)
{
	assert(str);

	if (*str != '\0')
	{
		return 1 + my_strlen(str + 1);
	}
	else
	{
		return 0;
	}
}

3. 指针 - 指针法

size_t my_strlen(const char* str)
{
	assert(str);
	char* start = str;
	char* end = start;

	while (*++end != '\0');

	return end - start;
}

⒉模拟实现 strcpy

char* my_strcpy(char* dest, const char* sour)
{
	assert(dest && sour);
	char* start = dest;;		//源头的地址放到目标空间中会导致目标空间的地址被改变,先用 start 保留目标空间的地址

	while (*dest++ = *sour++);	//将 sour 指向的包含 '\0' 的字符串赋给 dest 指向的空间

	return start;				//返回目标空间的起始地址
}

⒊模拟实现 strcat

char* my_strcat(char* dest, const char* sour)
{
	assert(dest && sour);
	char* start = dest;			//记录目标空间的起始地址

	while (*++dest);			//找到目标空间的 '\0' 就停止
	while (*dest++ = *sour++);	//将 sour 指向的串连接过去

	return start;				//返回目标空间的起始地址
}

⒋模拟实现 strcmp

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);

	while (*str1 == *str2)	//对应字符 ASCII 相等才会往后找不同
	{
		if ('\0' == *str1)	//在对应字符相等的情况下,*st1 = '\0',说明 *str1 和 *str2 都等于 '\0'
		{
			return 0;		//此时两个字符串完全相等
		}

		str1++;
		str2++;
	}

	return *str1 - *str2;	//返回对应字符 ASCII 码的差值
}

代码优化

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);

	while (*str1++ == *str2++);			//循环结束后 str1 和 str2 分别指向两个不想等字符的后一位

	return *(str1 - 1) - *(str2 - 1);	//重新指向两个不相等的字符然后解引用,用 ASCII 码值做差
}

⒌模拟实现 strncpy

char* my_strncpy(char* dest, const char* sour, size_t num)
{
	assert(dest && sour);

	int i = 0;
	char* start = dest;

	for (i = 0; i < num; i++)
	{
		*dest++ = *sour++;
	}
	
	return start;
}

⒍模拟实现 strncat

char* my_strncat(char* dest, const char* sour, size_t num)
{
	assert(dest && sour);
	char* start = dest;

	while (*++dest);				//找到串 1 的 '\0' 的位置

	for (int i = 0; i < num; i++)
	{
		if (!(*dest++ = *sour++))	//两个串任何一个遇到 '\0' 都直接结束函数调用
		{
			return start;
		}
	}
	*dest = '\0';					//在末尾补上一个 '\0'

	return start;
}

⒎模拟实现 strncmp

int my_strncmp(const char* str1, const char* str2, size_t num)
{
	assert(str1 && str2);

	while (*str1++ == *str2++ && --num);	//比较到第 num 个字符循环 num - 1 次即可

	return *(str1 - 1) - *(str2 - 1);		//让两个指针重新指向不相等字符的位置
}

⒏模拟实现 strstr

解题思路

【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第17张图片
【C语言进阶(6)】字符串函数的使用方法 + 模拟实现_第18张图片

结束条件

  • s2 -> ‘\0’:当 s2 指向 \0 时,说明 str2 的全部连续的内容已经在 str1 中找到了,str2 是 str1 的子串,返回 p(str1 首次出现 str2 的地址)即可。
  • p -> ‘\0’:当 p 指向 \0 时说明直到走到 str1 的尽头,s2 都没走到 \0,str1 中没有包含 str2 的子串,返回一个空指针即可。

代码实现

const char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);

	const char* s1 = str1;					//记录str1位置
	const char* s2 = str2;					//记录str2位置
	const char*  p = str1;					//记录起始位置

	while (*p)								//*p 指向 \0 时说明主串已经走到头了
	{
		s1 = p;								//字符不相等时让 s1 指向 p 的位置
		s2 = str2;							//字符不相等时让 s2 回到 str2 的初始位置

		while (*s1 && *s2 && *s1 == *s2)	//字符相等且 s1,s2 都未指向 \0 时比较下一对字符
		{
			s1++;
			s2++;
		}

		if ('\0' == *s2)					//s2 走到 \0 时说明 str2 是 str1 的子串
		{
			return p;						//返回在 str1 中首次出现 str2 的地址
		}

		p++;								//不相等时让 s1 从 p 的下一个位置开始比较
	}

	return NULL;							//都走到这步了说明 str2 肯定不是 str1 的子串
}

你可能感兴趣的:(#,C语言进阶篇,c语言,开发语言)