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

🎉个人主页: 缘三水的博客
❄专栏传送门:C语言专栏(新手向)
🎀人生格言:行动治愈迷茫的良药


🚀个人介绍:


往篇回顾

【C语言】指针(1)

【C语言】指针(2)


文章目录


前言

前面我们学完了指针,下面我们我们来学习和字符相关的一些函数


正文开始

(一)字符分类函数

定义

C语言中提供的专门用于字符分类库函数

判断一个字符属于哪种类型

需要包含头文件

c 复制代码
#include <ctype.h>

分类

原理

如果要判断的字符

不是对应字符分类函数判断的类型,则返回0

是对应的类型,则返回非0

示例

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

c 复制代码
int main()
{
	char arr[] = "I Am a Chinese";
	int i = 0;
	while (arr[i])
	{
		if (islower(arr[i]))
			arr[i] -= 32;//小写字母ASCII码值比大写字母大32
		printf("%c", arr[i]);
		i++;
	}
	return 0;
}

结果

(二)字符转换函数

定义

C语言中提供了2种字符转换函数

分别是

c 复制代码
tolower//将大写字母转换成小写字母,如果传入的不是大写字母,则不做任何处理
toupper//将小写字母转换成大写字母,如果传入的不是小写字母,则不做任何处理

需要包含头文件

c 复制代码
#include <ctype.h>

有了这样的函数,我们就可以将上面的题目这么写
代码示例
将字符串中的小写字母转大写,其他字符不变

(三)strlen

3.1 定义

函数原型

c 复制代码
size_t strlen(const char* str);

定义

用于计算字符串长度 的库函数

从起始地址向后找到\0为止

头文件

需要包含头文件

c 复制代码
#include <string.h>

参数

是char*字符指针

由于计算的字符串是固定的,所以可以用const修饰

返回值

由于长度不会是负数

所以返回值类型是size_t类型,无符号整型

使用示例

c 复制代码
int main()
{
	char arr[] = "yuansanshui";
	size_t len =  strlen(arr);
	printf("%d\n",len);//打印结果为11
	return 0;
}

关于返回值的易错题目

c 复制代码
#include <string.h>
int main()
{
	if (strlen("abc") - strlen("abcdef") > 0)
		printf(">\n");
	else
		printf("<=\n");
	return 0;
}

打印结果

为什么会打印>呢?

-3在内存中存储是以补码形式

-3的原码

10000000 00000000 00000000 00000011

反码

11111111 11111111 11111111 11111100

补码

11111111 11111111 11111111 11111101

而strlen的返回值类型是无符号整型size_t

所以-3的补码直接1被当作原码 看待

结果就是大于

3.2 strlen的模拟实现

方法

1.计数器

2.找到\0的地址

利用|指针-指针|得到中间元素个数求得

而这两个方法都需要创建临时变量

要求:不能创建临时变量
代码实现

原理

利用递归

对于字符串"abcdef"

如果遇到的不是\0,返回1+my_strlen("bcdef")

如果遇到的是\0,返回0

(四)strcpy

4.1 定义

作用

两个字符串,一个目标字符串,一个源头字符串

用来将源头字符串的内容复制粘贴到目标字符串中

函数原型

c 复制代码
char* strcpy(char * destination, const char * source );

头文件

c 复制代码
#include <string.h>

参数

两个参数,都是char*,字符指针类型

一个是指向目标字符串的地址

一个是指向源头字符串的地址

返回值

char*类型 字符指针

指向的是目标字符串 经过复制粘贴后的地址

示例

由于返回值也是目标字符串的起始地址

所以也可以接收返回值 ,再传给%s打印目标字符串
示例

strcpy函数使用注意事项

  1. 源头字符串末尾必须有\0

  2. 拷贝字符串时,也会将源头字符串末尾的\0一起拷贝过去

  3. 目标空间得足够大,能放得下源头字符串的内容

  4. 目标字符串必须能修改,否则就无法拷贝过来

    如果目标字符串是常量字符串,则无法被修改,即无法使用strcpy函数

    例如,目标字符串为char* p = "xxxxxxxxxxxxxxx"将p与源头字符串起始地址当作strcpy参数就无法拷贝

4.2 strcpy函数的模拟实现

版本一

版本二

c 复制代码
void my_strcpy(char* dest, const char* s)
{
	//后置++
	//先使用, 即先解引用,赋值,判断
	//再++ ,  即s= s+1,dest=dest+1 
	while (*dest++ = *s++)
	{
		;//直到两者指向\0,先使用, 即解引用赋值\0到目标字符串,再判断表达式为\0跳出循环
	}
}
int main()
{
	char arr1[] = "hello world";
	char arr2[] = "xxxxxxxxxxxxxxx";
	my_strcpy(arr2, arr1);
	printf("%s", arr2);
	return 0;
}

版本三

c 复制代码
#include <assert.h>
char* my_strcpy(char* dest, const char* s)
{
	//先断言一下,是否为空指针
	char* ret = dest;
	assert(dest && s);
	while (*dest++ = *s++)
	{
		;//空语句
	}
	return ret;//返回目标空间的起始地址
}
int main()
{
	char arr1[] = "hello world";
	char arr2[] = "xxxxxxxxxxxxxxx";
	char* r = my_strcpy(arr2, arr1);
	printf("%s\n", arr2);
	printf("%s\n", r);
	return 0;
}

注意空指针是不指向任何空间

而不是指向 '\0'

(五)strcat

5.1 定义

函数原型

c 复制代码
char * strcat ( char * destination, const char * source );

定义
字符串追加 函数

用于将源头字符串的内容追加到目标字符串的末尾

头文件

c 复制代码
#include <string.h>

参数

两个参数,都是char*,字符指针类型

一个是指向目标字符串的地址

一个是指向源头字符串的地址

返回值

char*类型 字符指针

指向的是目标字符串 经过字符串追加后起始地址

代码示例

5.2 strcat函数的模拟实现

代码示例

c 复制代码
#include <assert.h>
char* my_strcat(char* dest, const char* s)
{
	char* ret = dest;
	assert(dest, s);
	//1.找到目标字符串的\0
	while (*dest != '\0')
		dest++;
	//2.在\0处开始追加源头字符串的内容
	while (*dest++ = *s++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[30] = "hello";//目标字符串
	char arr2[] = " world";//源头字符串
	char* ret = my_strcat(arr1, arr2);

	printf("%s\n", arr1);
	printf("%s\n", ret);
}

(六)strcmp

5.1 定义

strcmp其实是string compare的缩写

是一种比较两个字符串的库函数

函数原型

c 复制代码
int strcmp ( const char * str1, const char * str2 );

头文件

c 复制代码
#include <string.h>

作用
字符串的比较,比较两个字符串

注意:这里的字符串比较不是按长度比较

而是,按每一位上的字符ASCII码值大小比较

例如,"abcdef" 和"abq"两个比较

首先比较同一位上的'a'和'a',相同,比较下一个

'b'和'b'相同,比较下一个

'c'和'q'比较,字符'c'的ASCII码值小于'q',因此得出结果"abcdef"的字符串比"abq"小

参数

两个参数

分别是指向要进行比较的两个字符串的地址

返回值

返回值是int整型

判断前面的字符串大于 后面的字符串,返回大于0 的数字

判断前面的字符串小于 后面的字符串,返回小于0 的数字

前面的字符串等于 后面,则返回0

代码示例

也可以将字符串放在strcmp函数内部 ,因为字符串传递的参数就是首字符地址

5.2 strcmp函数的模拟实现

代码示例

c 复制代码
#include <assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')//字符串相等的情况
			return 0;
		str1++;
		str2++;
	}
	if (*str1 > *str2)
		return 1;
	else
		return -1;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abq";
	int ret = my_strcmp(arr1, arr2);
	if (ret > 0)
		printf("arr1 > arr2\n");
	else if (ret < 0)
		printf("arr1 < arr2\n");
	else
		printf("arr1 = arr2");
	return 0;
}

分割线

在前面我们学习的字符串函数都是不受长度限制的
是一直作用到字符串末尾的
但是如果我们想限制字符串函数作用的长度呢?
C语言也给我们提供了这样的函数


(七)strncpy

7.1 定义

限制拷贝长度的字符串函数

函数原型

c 复制代码
char * strncpy ( char * destination, const char * source, size_t num );

相较strcpy函数多了一个参数,其余部分与strcpy一致
size_t类型的,表示限制拷贝的长度

头文件

c 复制代码
#include <string.h>

代码示例

特点

  • 在拷贝过程中,如果源头字符串长度不够,则拷贝\0过去凑数
  • 如果,在源头字符串中间有\0,则停止拷贝后面的字符串,拷贝长度不够依旧用\0补全

示例

7.2 与strcpy的比较

  • strcpy函数中,对源头字符串末尾必须包含\0

    并且拷贝过程中不会考虑目标空间大小是否放得下

  • strncpy函数中,源头字符串可以不包含\0

    并且在设计参数的时候需要考虑拷贝的长度

    这样就会多一层思考防止出现越界访问

(八)strncat

8.1 定义

strncat函数是一种可以限制追加字符串长度库函数

函数原型

c 复制代码
char * strncat ( char * destination, const char * source, size_t num );

相较strcat多了一个参数,其余部分不变
这个多出来的参数是size_t类型,表示限制追加的字符串长度

头文件

c 复制代码
#include <string.h>

代码示例

特点

  • strncpy函数在追加过程中,追加的末尾会附带一个\0
  • 如果源头字符串的长度小于要追加的长度,并不会用\0凑数,只会有一个\0,其余部分不变

(九)strncmp

9.1定义

一种可以限制比较字符串长度的库函数

函数原型

c 复制代码
int strncmp ( const char * str1, const char * str2, size_t num );

除了多了一个参数,其余与strcmp函数一致
多了的这个参数,表示限制的比较长度

代码示例

如图,只限制比较两个字符 ,由于arr1和arr2前两个字符相等,因此比较的结果为相等

(十)strstr

10.1定义

一种库函数

用于查找一个字符串中,第一次出现另一个字符串的位置

函数原型

c 复制代码
char * strstr ( const char * str1, const char * str2);

头文件

c 复制代码
#include <string.h>

参数
str1 : 字符指针,指向被查找 的字符串
str2 : 字符指针,指向要查找的字符串

返回值

返回一个字符指针

如果存在另一个字符串,则返回第一次 出现的地址

如果不存在,则返回空指针NULL

代码示例

10.2 strstr的模拟实现

代码示例

c 复制代码
#include <assert.h>
char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* p = str1;//p是可能找到要查找字符串的起始地址
	const char* s1 = NULL;
	const char* s2 = NULL;
	if (*str2 == '\0')//特殊场景处理,如果要查找的是空字符串\0
		return (char*)str1;
	while (*p)//判断是否到了被查找字符串的末尾
	{
		s1 = p;//查找一次字符串不一致后,回退
		s2 = str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;

		}
		if (*s2 == '\0')//说明查找到正确
			return (char*)p;
		p++;
	}
	return NULL;
}

int main()
{
	char arr1[] = "heheabcdefabcdef";//被查找字符串
	char arr2[] = "def";//要查找的字符串
	char* ret = my_strstr(arr1, arr2);
	if (ret != NULL)
		printf("找到了,后面是%s\n", ret);
	else
		printf("没找到\n");
	return 0;
}

(十一)strtok

10.1定义

函数原型

c 复制代码
char * strtok(char * str, const char *delim);

头文件

c 复制代码
#include <string.h>

功能

  • 分割字符串: 将字符串按照分隔符分割,分割成多个字符串
  • 修改原始字符串: 按照分割符分割的位置修改成\0

举例

假如有一个待分割的字符串"yuansanshui@qq.com"

经过一次函数调用后变成"yuansanshui\0qq.com"

再次调用后变成"yuansanshui\0qq\0com"

参数

  1. str :第一次调用传入待分割的字符串的指针 ,后续再分割相同 的字符串,则传入空指针NULL
  2. delim: 指向所有可能包含的分隔符

返回值

  1. 成功分割,返回分割好的子字符串的指针
  2. 没有更多可以分割的子字符串,返回空指针NULL

使用步骤

  1. 首次调用,传入待分割字符串指针和分隔符的指针
  2. 再次调用,传入NULL和相同分隔符的指针
  3. 结束条件,当返回空指针NULL时,分割完成

注意事项

  1. 破坏性: strtok函数会修改原始字符串内容,因此如果想保留原始字符串,可以拷贝一份
  2. 连续的分隔符: 多个连续分隔符会被当做单独的分割符
  3. 空指针 : 如果传入空指针作为待分割字符串的指针,则行为未定义,程序报错

代码示例

(十二)strerror

前言

在不同的系统和C语言标准库的实现中都规定了一些错误码 ,一般是放在 errno.h 这个头文件中说明的

C语言程序启动的时候就会使用一个全局的变量 errno 来记录程序的当前错误码

只不过程序启动的时候 errno 是 0,表示没有错误

当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码,存放在 errno 中

12.1定义

函数原型

c 复制代码
char* strerror ( int errnum );

头文件

c 复制代码
#include <string.h>

功能

每一个错误码都是有对应的错误信息

而一个错误码的数字是整数,很难理解是什么意思

  1. 所以strerror函数 就能将错误数字翻译成错误信息,并以对应字符串指针形式返回

  2. 不过strerror函数只能针对标准库中的函数发生错误后设置的错误码的转换

参数

  • errnum:表示错误码,一般用errno传递

全局变量errno存放着错误码

使用errno需要包含头文件errno.h

返回值

  • 字符指针,是转换后的错误信息字符串的首字符地址

示例1

示例2

12.2 perror

函数原型

c 复制代码
void perror ( const char * str );
  • perror函数的功能相当于printf加上strerror

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

示例2的代码就能这么修改


总结

这篇文章详细讲解了常用的字符函数和字符串函数,希望能对你有帮助

有错误的地方希望可以得到大佬的指正
最后不要吝啬你的点赞,收藏和评论!!!
感谢你的观看

相关推荐
MediaTea2 小时前
Python 的设计哲学P08:可读性与人类语言
开发语言·python
一枝小雨2 小时前
单例模式简析:C语言实现单例模式
c语言·单例模式·嵌入式
qq_251533592 小时前
如何使用 Python 正则表达式去除空格/制表符/换行符?
开发语言·python·正则表达式
Azxcc02 小时前
c++ core guidelines解析--让接口易于使用
开发语言·c++
亭上秋和景清2 小时前
指针进阶: 回调函数
开发语言·前端·javascript
helloworddm2 小时前
NSIS编写C/C++扩展
c语言·开发语言·c++
Vanranrr2 小时前
一个由非虚函数导致的隐藏Bug:窗口显示异常问题排查与解决
开发语言·bug
曹牧2 小时前
Java:Jackson库序列化对象
java·开发语言·python
MediaTea2 小时前
Python:依赖倒置原则(DIP)
开发语言·python·依赖倒置原则