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

往篇回顾
文章目录
- 往篇回顾
- 前言
- (一)字符分类函数
- (二)字符转换函数
- (三)strlen
-
- [3.1 定义](#3.1 定义)
- [3.2 strlen的模拟实现](#3.2 strlen的模拟实现)
- (四)strcpy
-
- [4.1 定义](#4.1 定义)
- [4.2 strcpy函数的模拟实现](#4.2 strcpy函数的模拟实现)
- (五)strcat
-
- [5.1 定义](#5.1 定义)
- [5.2 strcat函数的模拟实现](#5.2 strcat函数的模拟实现)
- (六)strcmp
-
- [5.1 定义](#5.1 定义)
- [5.2 strcmp函数的模拟实现](#5.2 strcmp函数的模拟实现)
- 分割线
- (七)strncpy
-
- [7.1 定义](#7.1 定义)
- [7.2 与strcpy的比较](#7.2 与strcpy的比较)
- (八)strncat
-
- [8.1 定义](#8.1 定义)
- (九)strncmp
- (十)strstr
-
- 10.1定义
- [10.2 strstr的模拟实现](#10.2 strstr的模拟实现)
- (十一)strtok
- (十二)strerror
-
- 12.1定义
- [12.2 perror](#12.2 perror)
- 总结
前言
前面我们学完了指针,下面我们我们来学习和字符相关的一些函数
正文开始
(一)字符分类函数
定义
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函数使用注意事项
-
源头字符串末尾必须有\0
-
拷贝字符串时,也会将源头字符串末尾的\0一起拷贝过去
-
目标空间得足够大,能放得下源头字符串的内容
-
目标字符串必须能修改,否则就无法拷贝过来
如果目标字符串是常量字符串,则无法被修改,即无法使用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"
参数
- str :第一次调用传入待分割的字符串的指针 ,后续再分割相同 的字符串,则传入空指针NULL
- delim: 指向所有可能包含的分隔符
返回值
- 成功分割,返回分割好的子字符串的指针
- 没有更多可以分割的子字符串,返回空指针NULL
使用步骤
- 首次调用,传入待分割字符串指针和分隔符的指针
- 再次调用,传入NULL和相同分隔符的指针
- 结束条件,当返回空指针NULL时,分割完成
注意事项
- 破坏性: strtok函数会修改原始字符串内容,因此如果想保留原始字符串,可以拷贝一份
- 连续的分隔符: 多个连续分隔符会被当做单独的分割符
- 空指针 : 如果传入空指针作为待分割字符串的指针,则行为未定义,程序报错
代码示例

(十二)strerror
前言
在不同的系统和C语言标准库的实现中都规定了一些错误码 ,一般是放在 errno.h 这个头文件中说明的
C语言程序启动的时候就会使用一个全局的变量 errno 来记录程序的当前错误码
只不过程序启动的时候 errno 是 0,表示没有错误
当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码,存放在 errno 中
12.1定义
函数原型
c
char* strerror ( int errnum );
头文件
c
#include <string.h>
功能
每一个错误码都是有对应的错误信息
而一个错误码的数字是整数,很难理解是什么意思
-
所以strerror函数 就能将错误数字翻译成错误信息,并以对应字符串指针形式返回
-
不过strerror函数只能针对标准库中的函数发生错误后设置的错误码的转换
参数
- errnum:表示错误码,一般用errno传递
全局变量errno存放着错误码
使用errno需要包含头文件errno.h
返回值
- 字符指针,是转换后的错误信息字符串的首字符地址
示例1

示例2

12.2 perror
函数原型
c
void perror ( const char * str );
- perror函数的功能相当于printf加上strerror
即 perror 函数打印完参数部分的字符串 后,再打印一个冒号和一个空格 ,再打印错误信息
示例2的代码就能这么修改

总结
这篇文章详细讲解了常用的字符函数和字符串函数,希望能对你有帮助
有错误的地方希望可以得到大佬的指正
最后不要吝啬你的点赞,收藏和评论!!!
感谢你的观看