字符分类函数

C语言中有一系列的函数是做字符分类的,包含在头文件 ctype.h中

字符转换函数

C语言提功了2个字符转换函数

1
2
int tolower(int c) // 将参数传进去的大写字母转小写
int toupper(int c) // 将参数传进去的小写字母转大写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int i = 0;
char str[] = "HelLO woRLd!\n";
for (int i = 0;i < sizeof(str) / sizeof(str[0]);i++)
{
if (islower(str[i]))
{
// 小写转大写
str[i] = toupper(str[i]);
}
else if (isupper(str[i]))
{
//大写转小写
str[i] = tolower(str[i]);
}
}
printf("%s", str);

strlen

用于求一个字符串的长度,包含在头文件<string.h>中

语法格式如下:

1
size_t strlen(const char* str)
  • 字符串以 \0 结尾,strlen 是统计 \0 之前的字符个数

  • 参数指向的字符串必须以 \0 结尾

  • 返回值类型是 size_t ,是无符号型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    char arr1[] = "abc";
    char arr2[] = "abcdef";
    if (strlen(arr1) - strlen(arr2) > 0)
    {
    printf("arr1 > arr2\n");
    }
    else
    {
    printf("arr1 <= arr2\n");
    }

在这里强转成 int 在符合逻辑

1
2
3
4
5
6
7
8
9
10
11
12
// strlen 返回值类型是 size_t, 是无符号的
// 在这里强转成 int 在符合逻辑
char arr1[] = "abc";
char arr2[] = "abcdef";
if ((int)strlen(arr1) - (int)strlen(arr2) > 0)
{
printf("arr1 > arr2\n");
}
else
{
printf("arr1 <= arr2\n");
}

strlen 的模拟

简单模拟一下 strlen 的基本功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
int my_strlen_1(const char* arr)
{
// 计数器方式模拟实现 strlen
int count = 0;
int i = 0;

while (arr[i] != '\0')
{
i++;
count++;
}
return count;
}


// 指针 - 指针方式模拟实现 strlen
int my_strlen_2(const char* arr)
{
char* p = arr;
while (*p != '\0')
{
p++;
}
return p - arr;
}

// 递归模拟实现 strlen
int my_strlen_3(const char* arr)
{
if (*arr == '\0')
{
return 0;
}
// 不是 \0 就继续归
return 1 + my_strlen_3(arr + 1);
}
1
2
3
4
5
6
7
char arr1[] = "abcdefghjk";
int sz1 = my_strlen_1(arr1);
int sz2 = my_strlen_2(arr1);
int sz3 = my_strlen_3(arr1);
printf("%d\n", sz1);
printf("%d\n", sz2);
printf("%d\n", sz3);

strcpy


strcpy 用于拷贝字符串,包含在头文件<string.h>中
语法格式

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

将 source 拷贝到 destination 中

  • 源字符串必须以 ‘\0’结尾
    1
    2
    3
    4
    char arr1[] = { 'a','b','c' };
    char arr2[] = { "" };
    strcpy(arr2, arr1);
    printf("%s\n", arr2);
  • 会将源字符串的 ‘\0’也拷贝过来
    1
    2
    3
    4
    5
    6
    7
    8
    int main()
    {
    char arr1[] = "hello world!";
    char arr2[20] = "";
    strcpy(arr2, arr1);
    printf("%s\n", arr2);
    return 0;
    }
  • 目标空间必须够大
    1
    2
    3
    4
    char arr1[] = "hello world!";
    char arr2[5] = "";
    strcpy(arr2, arr1);
    printf("%s\n", arr2);
  • 目标空间必须允许修改
    1
    2
    3
    4
    5
    6
    // 目标空间必须允许修改
    char arr1[] = "hello world!";
    char *p = "";
    strcpy(p, arr1);
    printf("%s\n", p);
    return 0;

strcpy 的模拟实现

简单模拟一下 strcpy 的基本功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
char* my_strcpy(char* dest,const char* sour)
{
// 传进来的不能是空指针
assert(dest != NULL);
assert(sour != NULL);
char* ret = dest;
// 核心功能:拷贝的实现
while (*dest++ = *sour++)
{
;
}
//while (*sour != '\0')
//{
// *dest++ = *sour++; // 一行代码搞定
// //*dest = *sour;
// //dest++;
// //sour++;
//}
//*dest = *sour; // 拷贝 \0
return ret;
}

int main()
{

char arr1[] = "I LOVE C!";
char arr2[20] = "";
my_strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}

strcat

语法格式

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

用于将 source 字符串追加在 destination 后,包含在头文件<string.h>中

1
2
3
4
char arr1[20] = "I LOVE";
char arr2[20] = " C!";
strcat(arr1, arr2);
printf("%s\n", arr1);

  • 源字符串必须以 ‘\0’结尾

    1
    2
    3
    4
    char arr1[20] = "hello "; // 目标字符串有 \0
    char arr2[] = { 'w','o','r','l','d','!' }; // 源字符串无 \0
    strcat(arr1, arr2);
    printf("%s\n", arr1);
  • 目标字符串必须要有 ‘\0’

    1
    2
    3
    4
    char arr1[20] = {'h','e','l','l','o'}; // 目标字符串无 \0
    char arr2[] = " world!"; // 源字符串有 \0
    strcat(arr1, arr2);
    printf("%s\n", arr1);


这里虽然进行了正确的追加,但通过调试看到 arr1 在没有完全初始化的时候是

自动分配了 ‘\0’ 的。但是没办法保证什么时候没有初始化的内存空间都是自动分

配 ‘\0’。C 标准明确:缺少\0使用strcat属于非法写法。

  • 目标空间必须足够大

    1
    2
    3
    4
    char arr1[6] = "abcde";
    char arr2[] = "fghj";
    strcat(arr1, arr2);
    printf("%s\n", arr1);

  • 目标必须是可修改的

    1
    2
    3
    4
    char* str = "I LOVE "; // 常量字符串
    char arr[] = "C!";
    strcat(str, arr);
    printf("%s\n", str);

strcat的模拟实现

来简单实现以下 strcat 的基本功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
char* my_strcat(char* dest, const char* sour)
{
// 传进来不能是空指针
assert(dest && sour);
char* ret = dest;
// 找目标字符串中的 \0
while (*dest != '\0')
{
dest++;
}

// 从 \0 处开始追加
while (*dest++ = *sour++)
{
;
}
return ret;
}

int main()
{
char arr1[20] = "hello ";
char arr2[] = "world!";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}

strcmp

语法格式

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

用于比较两个字符串

  • str1 > str2 ,返回大于 0 的数字

  • str1 和 str2 相等,则返回0

  • str1 < str2 ,返回小于 0 的数字

  • 比较的依据是比较两个字符串上对应字符的 ASCII 值,如果相等就继续比

    较,如果存在大小关系就返回对应的值

1
2
3
4
5
6
7
8
char arr1[] = "abcd";
char arr2[] = "abcd";
char arr3[] = "abc";
char arr4[] = "efgh";

printf("%d\n", strcmp(arr1, arr2));
printf("%d\n", strcmp(arr1, arr3));
printf("%d\n", strcmp(arr1, arr4));

strcmp 的模拟实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
来简单实现以下 strcmp 的基本功能

int my_strcmp(const char* p1, const char* p2)
{
// 不让传空指针
assert(p1 && p2);
while (*p1 == *p2)
{
// 相等的话继续比
if (*p1 == '\0')
{
// 到这儿说明每个元素都是一样的
return 0;
}
p1++;
p2++;
}
// 到这儿说明不等了
// 可以返回值了
return *p1 - *p2;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main()
{
char arr1[] = "abcd";
char arr2[] = "abcd";
char arr3[] = "abc";
char arr4[] = "efgh";

printf("%d\n", strcmp(arr1, arr2));
printf("%d\n", strcmp(arr1, arr3));
printf("%d\n", strcmp(arr1, arr4));

printf("\n");

printf("%d\n", my_strcmp(arr1, arr2));
printf("%d\n", my_strcmp(arr1, arr3));
printf("%d\n", my_strcmp(arr1, arr4));
return 0;
}

strncpy

语法格式

1
char * strncpy ( char * destination, const char * source, size_t num );
  • 和 strcpy 类似,但是是从 source 中拷贝 num 个元素到 destination 中
1
2
3
4
char arr1[20] = "abcde";
char arr2[] = "efghi";
strncpy(arr1, arr2, 3);
printf("%s\n", arr1);

  • 如果 source 的长度小于 num ,则在完成拷贝后,在 destination 后追加 0 ,直到满足 num 个
    1
    2
    3
    4
    char arr1[20] = "xxxxxxxxxxxxxxx";
    char arr2[] = "world!";
    strncpy(arr1, arr2, 10);
    printf("%s\n", arr1);

strncat

语法格式

1
char * strncat ( char * destination, const char * source, size_t num );
  • 与 strcat 类似,但是是从 source 中追加 num 个元素到 destination 的末尾处

    1
    2
    3
    4
    char arr1[20] = "hello ";
    char arr2[] = "world!";
    strncat(arr1, arr2, 3);
    printf("%s\n", arr1);

  • 如果 source 的长度小于 num ,则只追加 source 中 \0 前的字符在 destination 的末尾处

1
2
3
4
char arr1[20] = "hello ";
char arr2[] = "world!";
strncat(arr1, arr2, 10);
printf("%s\n", arr1);

strncmp

语法格式

1
int strncmp ( const char * str1, const char * str2, size_t num );
  • 与 strcmp 类似,但是是比较 str1 和 str2 的前 num 个字符
1
2
3
4
5
6
7
char arr1[] = "abcd";
char arr2[] = "abce";
char arr3[] = "abccz";

printf("%d\n", strncmp(arr1, arr2, 3));
printf("%d\n", strncmp(arr1, arr2, 4));
printf("%d\n", strncmp(arr1, arr3, 4));

strstr

语法格式

1
2
3
const char * strstr ( const char * str1, const char * str2 );
或者
char * strstr (char * str1, const char * str2 );
  • 返回 str2 在 str1 中第一次出现的位置

  • 找不到的话返回空

1
2
3
4
5
6
7
char arr1[] = "hello1 hello2 hello3 hello4";
char arr2[] = "hello2";
char arr3[] = "666";
char* ret1 = strstr(arr1, arr2);
char* ret2 = strstr(arr1, arr3);
printf("%s\n", ret1); // 存在
printf("%s\n", ret2); // 不存在返回空

strstr的模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
char* p1 = str1;
char* p2 = str2;
char* ret = str1; // 用于记录 str2 在 str1 中首次出现的位置 , 初始赋值为 str1 的首元素地址
// 当 p1 和 p2 都不为'\0'
while (*p1 && *p2)
{
// 不管怎样等不等 p1 需要一直往后走 所以这里用 p1++
if (*p1++ == *p2)
{
// p1 p2 指向的元素相等时,才能继续往后比较
p2++;
}
else
{
// 不等的话则需要重置 p2 到 str2 的首元素去
p2 = str2;
// ret 需更新为当前 p1 所指向
ret = p1;
}
}

// 出这个循环说明p1 p2 至少有一个走到了 \0
if (!*p2)
{
// p2 走到 \0,说明 str1 中确实存在 str2,返回记录值
return ret;
}
// 这说明 p1 走到 \0 了,没找到
return NULL; // 没找到就返回 NULL
}

int main()
{
// strstr 的使用
char arr1[] = "hello1 hello2 hello3 hello4";
char arr2[] = "hello2";
char arr3[] = "666";
char* ret1 = strstr(arr1, arr2);
char* ret2 = strstr(arr1, arr3);
char* ret3 = my_strstr(arr1, arr2);
char* ret4 = my_strstr(arr1, arr3);
printf("%s\n", ret1); // 存在
printf("%s\n", ret2); // 不存在返回空
printf("\n");
printf("%s\n", ret3); // 不存在返回空
printf("%s\n", ret4); // 不存在返回空
return 0;
}

strtok

语法格式

1
char * strtok ( char * str, const char * delimiters );
  • delimiters 指向的字符串定义了用作分隔符的字符合集

  • str 指向的字符串包含0个或多个由 delimiters 字符串中一个或者多个分隔

    符分割的标记

  • strtok 函数找到 str 中的下一个标记,并用 \0 结尾,返回一个指向这个标
    记的指针

    1
    2
    3
    4
    5
    6
    7
    // strtok 的使用
    // strtok 函数找到 str 中的下一个标记,并用 \0 结尾,返回一个指向这个标记的指针,这说明使用 strtok 这个函数后
    // str 指向的字符串可能会被修改
    char arr1[] = "xxxxx@qq.com";
    const char* str = "@.";
    strtok(arr1, str);
    printf("%s\n", arr1);


  • strtok 函数的第一个函数不为 NULL, 函数将 str 中第一个标记,strtok 函数

    将保存它在字符串中的位置

  • strtok 函数的第一个函数为 NULL, 函数将在同一个字符串中被保存的位置

    开始,查找下一个标记保存它在字符串中的位置

1
2
3
4
5
6
7
8
9
10
11
12
// strtok 的使用
// strtok 函数的第一个函数不为 NULL, 函数将 str 中第一个标记,strtok 函数将保存它在字符串中的位置
// strtok 函数的第一个函数为 NULL, 函数将在同一个字符串中被保存的位置开始,查找下一个标记
// 这意味着,若想使用 strtok 在同一个字符串内继续查找分隔符,就需要传 NULL 了
char arr1[] = "xxxxx@qq.com";
const char* str = "@.";
char*p1 = strtok(arr1, str);
printf("%s\n", p1);
char* p2 = strtok(NULL, str);
printf("%s\n", p2);
char* p3 = strtok(NULL, str);
printf("%s\n", p3);

  • 如果字符串中不存在更多的标记,则返回 NULL
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    char arr1[] = "xxxxx@qq.com";
    const char* str = "@.";
    char* p1 = strtok(arr1, str);
    printf("%s\n", p1);
    char* p2 = strtok(NULL, str);
    printf("%s\n", p2);
    char* p3 = strtok(NULL, str);
    printf("%s\n", p3);
    char* p4 = strtok(NULL, str);
    printf("%s\n", p4);

strerror

语法格式

1
char * strerror ( int errnum );

返回参数部分的错误码对应的错误信息的字符串地址

在不同的系统和C语言标准库中规定了一些错误码,一般放在 errno.h 中。

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

默认为 0 表示没有错误,当使用标准库函数出现某种错误时,就会将对应的错误

码放到 errno 中

strerror 可以将对应的错误信息字符串的地址返回

1
2
3
4
for (int i = 0;i <= 10;i++)
{
printf("%d:%s\n", i, strerror(i));
}

perror

语法格式

1
void perror ( const char * str );

该函数先打印传给 perror 的字符串,然后打印冒号,在打印空格,最后打印对应错误

码的错误信息

1
2
3
4
5
6
int main()
{
errno = 2;
perror("这是perror演示");
return 0;
}