目录
[1. 字符分类函数](#1. 字符分类函数)
[2 字符转换函数](#2 字符转换函数)
[3 strlen](#3 strlen)
[3.1 代码演示](#3.1 代码演示)
[3.3 strlen的模拟实现](#3.3 strlen的模拟实现)
[4 strcpy](#4 strcpy)
[4.1 代码演示](#4.1 代码演示)
[4.2 模拟实现](#4.2 模拟实现)
[5 strcat](#5 strcat)
[5.1 代码演示](#5.1 代码演示)
[5.2 模拟实现](#5.2 模拟实现)
[6 strcmp](#6 strcmp)
[6.1 代码演示](#6.1 代码演示)
[6.2 模拟实现:](#6.2 模拟实现:)
[7. strncpy](#7. strncpy)
[7.1 代码演示](#7.1 代码演示)
[7.2 ⽐较strcpy和strncpy函数](#7.2 ⽐较strcpy和strncpy函数)
[8 strncat](#8 strncat)
[8.1 代码演示](#8.1 代码演示)
[8.2 strcat和strncat对⽐](#8.2 strcat和strncat对⽐)
[9.2 strcmp和strncmp⽐较](#9.2 strcmp和strncmp⽐较)
[10 strstr](#10 strstr)
[10.2 strstr的模拟实现](#10.2 strstr的模拟实现)
[11. strtok函数的使用](#11. strtok函数的使用)
[11.1 代码演示](#11.1 代码演示)
[11.2 注意事项](#11.2 注意事项)
[12 strerror函数的使用](#12 strerror函数的使用)
[12.1 代码演示](#12.1 代码演示)
[12.2 perror](#12.2 perror)
1. 字符分类函数
C语⾔中有⼀系列的函数是专⻔做字符分类的,也就是⼀个字符是属于什么类型的字符的。
这些函数的使⽤都需要包含⼀个头⽂件是 ctype.h

的使⽤⽅法:
int islower ( int c );
islower 是能够判断参数部分的 c 是否是⼩写字⺟的。
通过返回值来说明是否是⼩写字⺟,如果是⼩写字⺟就返回⾮0的整数,如果不是⼩写字⺟,则返回0。
练习:
int main()
{
//写一个代码,将字符串中的小写字母转大写,其他字符不变。
char arr[] = "I Am a Chinese.";//'\0' - 0
// 0123...
//将字符串中的字符逐个进行处理
//遇到小写,转换成大写,再输出
//如果不是小写,正常输出
int i = 0;
while (arr[i])
{
if (islower(arr[i]))
arr[i] -= 32;
printf("%c", arr[i]);
i++;
}
return 0;
}
2 字符转换函数
2个字符转换函数:
int tolower ( int c ); // 将参数传进去的⼤写字⺟转⼩写
int toupper ( int c ); // 将参数传进去的⼩写字⺟转⼤写

上⾯的代码,我们将⼩写转⼤写,是-32完成的效果,有了转换函数,就可以直接使⽤ tolower 函数。
int main(){
//写一个代码,将字符串中的小写字母转大写,其他字符不变。
char arr[] = "I Am a Chinese.";//'\0' - 0
// 0123...
//将字符串中的字符逐个进行处理
//遇到小写,转换成大写,再输出
//如果不是小写,正常输出
int i = 0;
while (arr[i])
{
if (islower(arr[i]))
arr[i] = toupper(arr[i]);
printf("%c", arr[i]);
i++;
}
return 0;
}
3 strlen
size_t strlen ( const char * str );
**功能:**统计参数 str 指向的字符串的⻓度。统计的是字符串中 '\0' 之前的字符的个数。
参数: str :指针,指向了要统计⻓度的字符串。
**返回值:**返回了 str 指向的字符串的⻓度,返回的⻓度不会是负数,所以返回类型是 size_t 。
3.1 代码演示
#include <string.h>
int main()
{
const char* str = "abcdef";
printf("%zd\n", strlen(str));
}

使⽤注意事项:
①字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前⾯出现的字符个数(不 包含 '\0' )。
② 参数指向的字符串必须要以 '\0' 结束。
③ 注意函数的返回值为 size_t ,是⽆符号的( 易错 )
④ strlen的使⽤需要包含头⽂件 <string.h>
3.2 strlen 返回值
#include <string.h>int main()
{
if (strlen("abc") - strlen("abcdef") > 0)
{
printf(">\n");
}
else
{
printf("<=\n");
}
return 0;
}
size_t 无符号的整型 >= 0
3.3 strlen的模拟实现
1,计时器
2,指针 - 指针
不能在函数内部创建临时变量,使用递归
3,递归
#include <assert.h>
size_t my_strlen(const char* str)
{
assert(str);
if (*str != '\0')
return 1 + my_strlen(str+1);
else
return 0;
}
int main()
{
char arr[] = "abc";
size_t len = my_strlen(arr);
printf("%zu\n", len);
return 0;
}
4 strcpy
代码块
char * strcpy ( char * destination, const char * source );
**功能:**字符串拷⻉,拷⻉到源头字符串中的 \0 为⽌
参数:
destination :指针,指向⽬的地空间
source :指针,指向源头数据
返回值:
strcpy 函数返回的⽬标空间的起始地址
4.1 代码演示
#include <string.h>
int main()
{
char arr1[] = "hello world";
char arr2[20] = { 0 };
char* ret = strcpy(arr2, arr1);
printf("%s\n", arr2);
printf("%s\n", ret);
//arr2 = arr1;//ok?
//因为数组名是地址,地址是一个编号,地址是常量值,不能被修改
//5 = 3;
//地址是指向空间的,但是地址不是空间
return 0;
}
使⽤注意事项:
①源字符串必须以 '\0' 结束。
②会将源字符串中的 '\0' 拷⻉到⽬标空间。
③⽬标空间必须⾜够⼤,以确保能存放源字符串。
④⽬标空间必须可修改。

4.2 模拟实现
代码1:
void my_strcpy(char* dest, char* src)
{
//拷贝\0前面的字符
while (*src != '\0')
{
*dest = *src;
src++;
dest++;
}
*dest = *src;//拷贝\0
}
int main()
{
char arr1[] = "hello world";
char arr2[20] = "xxxxxxxxxxxxxxx";
my_strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}
代码2:
void my_strcpy(char* dest, const char* src)
{
while (*dest++ = *src++)
{
;
}
}
int main()
{
char arr1[] = "hello world";
char arr2[20] = "xxxxxxxxxxxxxxx";
my_strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}
代码3:模拟实现
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
while (*dest++ = *src++)
{
;
}
return ret;//返回目标空间的起始地址
}int main()
{
char arr1[] = "hello world";
char arr2[20] = "xxxxxxxxxxxxxxx";
char* r = my_strcpy(arr2, arr1);
printf("%s\n", arr2);
printf("%s\n", r);return 0;
}
5 strcat
代码块
char * strcat ( char * destination, const char * source );
**功能:**字符串追加,把 source 指向的源字符串中的所有字符都追加到 destination 指向的空间
中。
参数:
destination :指针,指向⽬的地空间
source :指针,指向源头数据
返回值:
strcat 函数返回的⽬标空间的起始地址
5.1 代码演示
#include <string.h>
int main()
{
char arr1[20] = "hello\0xxxxxxxxxx";
char arr2[] = "world";
char* r = strcat(arr1, arr2);
printf("%s\n", arr1);
printf("%s\n", r);
return 0;
}
使⽤注意事项:
源字符串必须以 '\0' 结束。
⽬标字符串中也得有 \0 ,否则没办法知道追加从哪⾥开始。
⽬标空间必须有⾜够的⼤,能容纳下源字符串的内容。
⽬标空间必须可修改。
5.2 模拟实现
#include <assert.h>
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
//1. 目标空间的\0
while (*dest != '\0')
dest++;
//2. 拷贝
while (*dest++ = *src++)
{
;
}
return ret;
}int main()
{
char arr1[20] = "hello\0xxxxxxxxxx";
char arr2[] = "world";
char* r = my_strcat(arr1, arr2);printf("%s\n", arr1);
printf("%s\n", r);return 0;
}

6 strcmp
代码块
int strcmp ( const char * str1, const char * str2 );
功能:⽤来⽐较 str1 和 str2 指向的字符串,从两个字符串的第⼀个字符开始⽐较,如果两个字符
的ASCII码值相等,就⽐较下⼀个字符。直到遇到不相等的两个字符,或者字符串结束。
参数:
str1 :指针,指向要⽐较的第⼀个字符串
str2 :指针,指向要⽐较的第⼆个字符串
返回值:
标准规定:
第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字
第⼀个字符串等于第⼆个字符串,则返回0
第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字
6.1 代码演示
代码1:
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abc";
int r = strcmp(arr1, arr2);
if (r > 0)
printf("arr1 > arr2\n");
else if(r < 0)
printf("arr1 < arr2\n");
else
printf("arr1 == arr2\n");
return 0;
}

代码2:
int main()
{
int r = strcmp("abcdef", "abc");
if (r > 0)
printf(">\n");
else if (r < 0)
printf("<\n");
else
printf("==\n");
return 0;
}
6.2 模拟实现:
#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[] = "abc";
char arr2[] = "abcdef";
int r = my_strcmp(arr1, arr2);
if (r > 0)
printf("arr1 > arr2\n");
else if(r < 0)
printf("arr1 < arr2\n");
else
printf("arr1 == arr2\n");
return 0;
}
7. strncpy
代码块
char * strncpy ( char * destination, const char * source, size_t num );
**功能:**字符串拷⻉;将 source 指向的字符串拷⻉到 destination 指向的空间中,最多拷⻉ num
个字符。
参数:
destination :指针,指向⽬的地空间
source :指针,指向源头数据
num :从source指向的字符串中最多拷⻉的字符个数
返回值:
strncpy 函数返回的⽬标空间的起始地址
7.1 代码演示

7.2 ⽐较strcpy和strncpy函数
①strcpy 函数拷⻉到 \0 为⽌,如果⽬标空间不够的话,容易出现越界⾏为。
②strncpy 函数指定了拷⻉的⻓度,源字符串不⼀定要有 \0 ,同时在设计参数的时候,就会多⼀层
③思考:⽬标空间的⼤⼩是否够⽤, strncpy 相对 strcpy 函数更加安全。
8 strncat
代码块
char * strncat ( char * destination, const char * source, size_t num );
**功能:**字符串追加;将 source 指向的字符串的内容,追加到 destination 指向的空间,最多追
加 num 个字符。
参数:
destination :指针,指向了⽬标空间
source :指针,指向了源头数据
num :最多追加的字符的个数
**返回值:**返回的是⽬标空间的起始地址
8.1 代码演示

8.2 strcat和strncat对⽐
①参数不同, strncat 多了⼀个参数
②strcat 函数在追加的时候要将源字符串的所有内容,包含 \0 都追加过去,但是 strncat 函
数指定了追加的⻓度。
③strncat 函数中源字符串中不⼀定要有 \0 了。
④strncat 更加灵活,也更加安全。
9 strncmp
代码块
int strncmp ( const char * str1, const char * str2, size_t num );
**功能:**字符串⽐较;⽐较 str1 和 str2 指向的两个字符串的内容,最多⽐较 num 字符。
参数:
str1 :指针,指向⼀个⽐较的字符串
str2 :指针,指向另外⼀个⽐较的字符串
num :最多⽐较的字符个数
返回值:
标准规定:
第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字
第⼀个字符串等于第⼆个字符串,则返回0
第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字

9.1代码演示
int main()
{
char arr1[10] = "abcqw";
char arr2[20] = "abcdef";
int r = strncmp(arr2, arr1, 3);
if (r > 0)
printf(">\n");
else if(r < 0)
printf("<\n");
else
printf("==\n");
return 0;
}

9.2 strcmp和strncmp⽐较
①参数不同
②strncmp可以⽐较任意⻓度了
③strncmp函数更加灵活,更加安全
10 strstr
代码块
char * strstr ( const char * str1, const char * str2);
功能:
strstr 函数,查找 str2 指向的字符串在 str1 指向的字符串中第⼀次出现的位置。
简⽽⾔之:在⼀个字符串中查找⼦字符串。
strstr 的使⽤得包含<string.h>
参数:
str1 :指针,指向了被查找的字符串
str2 :指针,指向了要查找的字符串
返回值:
如果str1指向的字符串中存在str2指向的字符串,那么返回第⼀次出现位置的指针
如果str1指向的字符串中不存在str2指向的字符串,那么返回NULL
10.1代码演示
int main()
{
char arr1[] = "heheabcdefabcdef";
char arr2[] = "deq";
char* p = strstr(arr1, arr2);
if (p != NULL)
{
printf("找到了, %s\n", p);
}
else
{
printf("找不到\n");
}
return 0;
}

10.2 strstr的模拟实现
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* p = str1;
const char* s1 = NULL;
const char* s2 = NULL;
//特殊的场景的处理
if (*str2 == '\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[] = "deq";*/
char arr1[] = "abbbcdef";
char arr2[] = "bbc";
char* p = my_strstr(arr1, arr2);
if (p != NULL)
{
printf("找到了, %s\n", p);
}
else
{
printf("找不到\n");
}
return 0;
}

11. strtok函数的使用
代码块
char * strtok ( char *str, const char *delim);
功能:
分割字符串:根据 delim 参数中指定的分隔符,将输⼊字符串 str 拆分成多个⼦字符串。
修改原始字符串: strtok 会直接在原始字符串中插⼊ '\0' 终⽌符,替换分隔符的位置,因
此原始字符串会被修改。
参数:
- str :⾸次调⽤时传⼊待分割的字符串;后续调⽤传⼊ NULL ,表⽰继续分割同⼀个字符串。
- delim :包含所有可能分隔符的字符串(每个字符均视为独⽴的分隔符)。
返回值:
成功时返回指向当前⼦字符串的指针。
没有更多⼦字符串时返回 NULL 。
使⽤步骤: - ⾸次调⽤:传⼊待分割字符串和分隔符。
- 后续调⽤:传⼊ NULL 和相同的分隔符,继续分割。
- 结束条件:当返回 NULL 时,表⽰分割完成。
11.1 代码演示
int main()
{
char arr[] = "zpengwei@@yeah.net.hehe.haha@heihei";
char sep[] = "@.";
char buf[200] = { 0 };
strcpy(buf, arr);
char* p = NULL;
for (p = strtok(buf, sep); p != NULL; p = strtok(NULL, sep))
{
printf("%s\n", p);
}
//buf
//zpengwei\0yeah\0net
//char*p = strtok(buf, sep);
//printf("%s\n", p);//zpengwei
//p = strtok(NULL, sep);//yeah
//printf("%s\n", p);
//p = strtok(NULL, sep);//net
//printf("%s\n", p);
//p = strtok(NULL, sep);//返回NULL
//printf("%s\n", p);//(null)
return 0;
}
11.2 注意事项
①破坏性操作: strtok 会直接修改原始字符串,将其中的分隔符替换为 '\0' 。如果需要保留 原字符串,应先拷⻉⼀份。
**连续分隔符:**多个连续的分隔符会被视为单个分隔符,不会返回空字符串。
**空指针处理:**如果输⼊的 str 为 NULL 且没有前序调⽤,⾏为未定义。
12 strerror函数的使用
char * strerror ( int errnum );
功能:
- strerror 函数可以通过参数部分的 errnum 表⽰错误码,得到对应的错误信息,并且返回这
个错误信息字符串⾸字符的地址。- strerror 函数只针对标准库中的函数发⽣错误后设置的错误码的转换。
- strerror 的使⽤需要包含<string.h>
参数:
errnum :表⽰错误码
包含⼀个头⽂件 errno.h 。
返回值:
函数返回通过错误码得到的错误信息字符串的⾸字符的地址。
12.1 代码演示
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d: %s\n", i, strerror(i));
}
return 0;
}

举例:
#include <errno.h>
int main()
{
//C语言可以打开文件
//fopen
//如果以读的形式打开文件,文件是必须要存在的,如果文件不存在,则打开文件失败
//fopen函数就会将错误码放在errno
//同时函数会返回NULL
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
//读文件
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}

12.2 perror
也可以了解⼀下 perror 函数, perror 函数相当于⼀次将上述代码中的
printf("%s\n", strerror(errno)); 完成了,直接将错误信息打印出来。
perror 函数打印完参数部分的字符串后,再打印⼀个冒号和⼀个空格,再打印错误信息。
int main(){
//C语言可以打开文件
//fopen
//如果以读的形式打开文件,文件是必须要存在的,如果文件不存在,则打开文件失败
//fopen函数就会将错误码放在errno
//同时函数会返回NULL
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("test");
//test: 错误信息
return 1;
}
//读文件
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
