C语言从入门到进阶——第17讲:字符串函数

文章目录

  • [1. 字符分类函数](#1. 字符分类函数)
  • [2. 字符转换函数](#2. 字符转换函数)
  • [3. strlen](#3. strlen)
  • [4. strcpy](#4. strcpy)
  • [5. strcat](#5. strcat)
  • [6. strcmp](#6. strcmp)
  • [7. strncpy](#7. strncpy)
  • [8. strncat](#8. strncat)
  • [9. strncmp](#9. strncmp)
  • [10. strstr](#10. strstr)
  • [11. strtok](#11. strtok)
  • [12. strerror](#12. strerror)
  • [13. perror](#13. perror)

1. 字符分类函数

C语言中有一系列的函数是专门做字符分类的,用于判断一个字符所属的类型,这些函数的使用都需要包含头文件ctype.h

函数 如果参数符合下列条件就返回真
iscntrl 任何控制字符
isspace 空白字符:空格' ',换页 '\f',换行'\n',回车'\r',制表符'\t'或者垂直制表符'\v'
isdigit 十进制数字 '0' ~ '9' 字符
isxdigit 十六进制数字,包括所有十进制数字字符,小写字母af,大写字母AF
islower 小写字母a~z
isupper 大写字母A~Z
isalpha 字母az或AZ
isalnum 字母或者数字,az,AZ,0~9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint 任何可打印字符,包括图形字符和空白字符

这类函数的使用方法相似,以islower为例:

c 复制代码
int islower ( int c );

islower用于判断参数c是否是小写字母,若是小写字母返回非0的整数,若不是则返回0。

练习:将字符串中的小写字母转大写,其他字符不变

c 复制代码
#include <stdio.h>
#include <ctype.h>
int main ()
{
    int i = 0;
    char str[] = "Test String.\n";
    char c;
    while (str[i])
    {
        c = str[i];
        if (islower(c)) 
            c -= 32;
        putchar(c);
        i++;
    }
    return 0;
}

2. 字符转换函数

C语言提供了2个基础的字符转换函数,使用时需包含头文件ctype.h

c 复制代码
int tolower ( int c ); //将参数传进去的大写字母转小写
int toupper ( int c ); //将参数传进去的小写字母转大写

使用转换函数优化上述小写转大写的练习代码:

c 复制代码
#include <stdio.h>
#include <ctype.h>
int main ()
{
    int i = 0;
    char str[] = "Test String.\n";
    char c;
    while (str[i])
    {
        c = str[i];
        if (islower(c)) 
            c = toupper(c);
        putchar(c);
        i++;
    }
    return 0;
}

3. strlen

函数原型

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

功能 :统计参数str指向的字符串中'\0'之前的字符个数。
参数str为指向待统计长度字符串的指针。
返回值 :返回字符串的长度,返回类型为size_t(无符号整数类型),长度不会为负数。
头文件 :使用需包含<string.h>

代码演示

c 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
    const char* str = "abcdef";
    printf("%zd\n", strlen(str));
    return 0;
}

使用注意事项

  1. 字符串以'\0'作为结束标志,strlen返回'\0'前的字符个数(不包含'\0');
  2. 参数指向的字符串必须以'\0'结束;
  3. 注意函数返回值为size_t(无符号),易出现逻辑错误,示例:
c 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
    const char* str1 = "abcdef";
    const char* str2 = "bbb";
    if(strlen(str2) - strlen(str1) > 0)
        printf("str2 > str1\n");
    else
        printf("str1 > str2\n");
    return 0;
}

模拟实现

计数器方式:

c 复制代码
#include <assert.h>
int my_strlen(const char * str)
{
    int count = 0;
    assert(str); // 断言保证指针非空
    while(*str)
    {
        count++;
        str++;
    }
    return count;
}

递归方式(不创建临时变量计数器):

c 复制代码
#include <assert.h>
int my_strlen(const char * str)
{
    assert(str);
    if(*str == '\0')
        return 0;
    else
        return 1 + my_strlen(str+1);
}

指针-指针的方式:

c 复制代码
#include <assert.h>
int my_strlen(char *s)
{
    assert(s);
    char *p = s;
    while(*p != '\0')
        p++;
    return p - s;
}

4. strcpy

函数原型

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

功能 :字符串拷贝,将源字符串的内容拷贝到目标空间,直至拷贝到源字符串的'\0'为止。
参数

  • destination:指向目标存储空间的指针;
  • source:指向源字符串的指针。

返回值 :返回目标空间的起始地址。
头文件 :使用需包含<string.h>

代码演示

c 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
    char arr1[10] = {0};
    char arr2[] = "hello";
    strcpy(arr1, arr2);
    printf("%s\n", arr1);
    return 0;
}

使用注意事项

  1. 源字符串必须以'\0'结束;
  2. 会将源字符串中的'\0'拷贝到目标空间;
  3. 目标空间必须足够大,确保能存放源字符串;
  4. 目标空间必须可修改。

模拟实现

c 复制代码
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char *dest, const char*src)
{
    char *ret = dest;
    assert(dest != NULL);
    assert(src != NULL);
    while((*dest++ = *src++))
    {
        ;
    }
    return ret;
}
int main()
{
    char arr1[10] = {0};
    char arr2[] = "hello";
    my_strcpy(arr1, arr2);
    printf("%s\n", arr1);
    return 0;
}

5. strcat

函数原型

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

功能 :字符串追加,把源字符串的所有字符追加到目标空间中。
参数

  • destination:指向目标存储空间的指针;
  • source:指向源字符串的指针。

返回值 :返回目标空间的起始地址。
头文件 :使用需包含<string.h>

代码演示

c 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
    char arr1[20] = "hello ";
    char arr2[] = "world";
    strcat(arr1, arr2);
    printf("%s\n", arr1);
    return 0;
}

使用注意事项

  1. 源字符串必须以'\0'结束;
  2. 目标字符串中必须有'\0',否则无法确定追加起始位置;
  3. 目标空间必须足够大,能容纳源字符串的内容;
  4. 目标空间必须可修改。

模拟实现

c 复制代码
#include <stdio.h>
#include <assert.h>
char* my_strcat(char *dest, const char*src)
{
    char *ret = dest;
    assert(dest != NULL);
    assert(src != NULL);
    while(*dest)
    {
        dest++;
    }
    while((*dest++ = *src++))
    {
        ;
    }
    return ret;
}
int main()
{
    char arr1[20] = "hello ";
    char arr2[] = "world";
    my_strcat(arr1, arr2);
    printf("%s\n", arr1);
    return 0;
}

6. strcmp

函数原型

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

功能 :比较两个字符串,从第一个字符开始按ASCII码值比较,相等则继续比较下一个,直至遇到不相等字符或字符串结束。
参数

  • str1:指向第一个待比较字符串的指针;
  • str2:指向第二个待比较字符串的指针。

返回值(标准规定):

  • 第一个字符串大于第二个字符串,返回大于0的数字;
  • 第一个字符串等于第二个字符串,返回0;
  • 第一个字符串小于第二个字符串,返回小于0的数字。

头文件 :使用需包含<string.h>

代码演示

c 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
    char arr1[] = "abcdef";
    char arr2[] = "abq";
    int ret = strcmp(arr1, arr2);
    printf("%d\n", ret);
    if(ret > 0)
        printf("arr1 > arr2\n");
    else if(ret == 0)
        printf("arr1 == arr2\n");
    else
        printf("arr1 < arr2\n");
    return 0;
}

模拟实现

c 复制代码
#include <assert.h>
int my_strcmp (const char * str1, const char * str2)
{
    int ret = 0 ;
    assert(str1 != NULL);
    assert(str2 != NULL);
    while(*str1 == *str2)
    {
        if(*str1 == '\0')
            return 0;
        str1++;
        str2++;
    }
    return *str1-*str2;
}

7. strncpy

函数原型

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

功能 :指定长度的字符串拷贝,将源字符串的内容拷贝到目标空间,最多拷贝num个字符。
参数

  • destination:指向目标存储空间的指针;
  • source:指向源字符串的指针;
  • num:从源字符串中最多拷贝的字符个数。

返回值 :返回目标空间的起始地址。
头文件 :使用需包含<string.h>

代码演示

c 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
    char arr1[20] = {0};
    char arr2[] = "abcdefghi";
    char* str = strncpy(arr1, arr2, 5);
    printf("%s\n", arr1);
    printf("%s\n", str);
    return 0;
}

strcpystrncpy对比:

  1. strcpy拷贝到'\0'为止,目标空间不足时易出现越界行为,安全性低;
  2. strncpy指定拷贝长度,源字符串不一定要有'\0',使用时需考虑目标空间大小,更安全。

8. strncat

函数原型

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

功能 :指定长度的字符串追加,将源字符串的内容追加到目标空间,最多追加num个字符。
参数

  • destination:指向目标存储空间的指针;
  • source:指向源字符串的指针;
  • num:最多追加的字符个数。

返回值 :返回目标空间的起始地址。
头文件 :使用需包含<string.h>

代码演示:

c 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
    char arr1[20] = "hello ";
    char arr2[] = "world";
    char* str = strncat(arr1, arr2, 5);
    printf("%s\n", arr1);
    printf("%s\n", str);
    return 0;
}

strcatstrncat对比

  1. 参数不同,strncat多了num(指定追加长度)参数;
  2. strcat会追加源字符串的所有内容(包含'\0'),strncat仅追加指定长度的内容,源字符串可不包含'\0'
  3. strncat更灵活、更安全。

9. strncmp

函数原型

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

功能 :指定长度的字符串比较,比较两个字符串的内容,最多比较num个字符。
参数

  • str1:指向第一个待比较字符串的指针;
  • str2:指向第二个待比较字符串的指针;
  • num:最多比较的字符个数。
    返回值(标准规定):
  • 第一个字符串大于第二个字符串,返回大于0的数字;
  • 第一个字符串等于第二个字符串,返回0;
  • 第一个字符串小于第二个字符串,返回小于0的数字。
    头文件 :使用需包含<string.h>

代码演示

c 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
    char arr1[] = "abcdef";
    char arr2[] = "abcqw";
    int ret1 = strncmp(arr1, arr2, 3);
    printf("%d\n", ret1);
    int ret2 = strncmp(arr1, arr2, 4);
    printf("%d\n", ret2);
    return 0;
}

strcmpstrncmp对比

  1. 参数不同,strncmp多了num(指定比较长度)参数;
  2. strcmp比较整个字符串,strncmp可比较任意指定长度,更灵活、更安全。

10. strstr

函数原型

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

功能 :字符串查找,查找子字符串str2在主字符串str1中第一次出现的位置。
参数

  • str1:指向被查找的主字符串的指针;
  • str2:指向待查找的子字符串的指针。

返回值

  • 若主字符串中存在子字符串,返回第一次出现位置的指针;
  • 若不存在,返回NULL

头文件 :使用需包含<string.h>

代码演示

c 复制代码
#include <stdio.h>
#include <string.h>
int main ()
{
    char str[] ="This is a simple string";
    char * pch;
    pch = strstr (str,"simple");
    if (pch != NULL)
        printf("%s\n", pch);
    else
        printf("查找的字符串不存在\n");
    return 0;
}

模拟实现

c 复制代码
char * strstr (const char * str1, const char * str2)
{
    char *cp = (char *) str1;
    char *s1, *s2;
    //特殊情况:str2是空字符串时,直接返回str1
    if ( !*str2 )
        return((char *)str1);
    while (*cp)
    {
        s1 = cp;
        s2 = (char *) str2;
        while ( *s1 && *s2 && !(*s1-*s2) )
            s1++, s2++;
        if (!*s2)
            return(cp); //返回第一次出现的起始位置
        cp++;
    }
    return(NULL); //找不到则返回NULL
}

说明strstr的实现方式有多种,上述为暴力查找方式,还有更高效的KMP算法,可深入学习。

11. strtok

函数原型

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

功能 :字符串分割,根据delim指定的分隔符,将输入字符串str拆分成多个子字符串;会直接修改原始字符串 ,将分隔符替换为'\0'
参数

  1. str:首次调用时传入待分割的字符串;后续调用传入NULL,表示继续分割同一个字符串;
  2. delim:包含所有可能分隔符的字符串(每个字符均视为独立的分隔符)。

返回值

  • 成功时返回指向当前子字符串的指针;
  • 没有更多子字符串时返回NULL

头文件 :使用需包含<string.h>

代码演示

c 复制代码
#include <stdio.h>
#include <string.h>
int main()
{
    char arr[] = "192.168.6.111";
    const char* sep = ".";
    const char* str = NULL;
    char buf[30] = {0};
    strcpy(buf, arr); //将arr中的字符串拷贝到buf中,对buf的内容进行切割,保留原字符串
    for (str = strtok(buf, sep); str != NULL; str = strtok(NULL, sep))
    {
        printf("%s\n", str);
    }
    return 0;
}

使用注意事项

  1. 破坏性操作 :会修改原始字符串,将分隔符替换为'\0',需保留原字符串时应先拷贝;
  2. 连续分隔符会被视为单个分隔符,不会返回空字符串;
  3. 若输入的strNULL且无前序调用,行为未定义。

12. strerror

函数原型

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

功能 :将错误码转换为对应的错误信息字符串,仅针对C语言标准库函数报错后设置的错误码有效。
参数errnum为错误码,通常传递全局变量errno的值(errno记录程序当前错误码,程序启动时为0,库函数报错时会更新)。
返回值 :返回错误信息字符串的首字符地址。
头文件 :使用需包含<string.h>,使用errno需包含<errno.h>

代码演示

打印0~10错误码对应的信息:

c 复制代码
#include <errno.h>
#include <string.h>
#include <stdio.h>
int main()
{
    int i = 0;
    for (i = 0; i <= 10; i++) {
        printf("%d: %s\n", i, strerror(i));
    }
    return 0;
}

Windows11 + VS2022环境输出

复制代码
0: No error
1: Operation not permitted
2: No such file or directory
3: No such process
4: Interrupted function call
5: Input/output error
6: No such device or address
7: Arg list too long
8: Exec format error
9: Bad file descriptor
10: No child processes

结合库函数报错使用

c 复制代码
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
    FILE * pFile = NULL;
    //fopen函数以读的形式打开文件,如果文件不存在,则打开失败
    pFile = fopen ("unexist.ent", "r");
    if (pFile == NULL)
        printf ("错误信息是:%s\n", strerror(errno));
    return 1;//错误返回
}

输出

复制代码
错误信息是:No such file or directory

13. perror

函数原型

c 复制代码
void perror ( const char * str );

功能 :直接打印错误信息,等效于printf结合strerror的报错打印逻辑,先打印参数str,再打印冒号+空格,最后打印错误信息。
头文件 :使用需包含<stdio.h><errno.h>

代码演示

c 复制代码
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
    FILE * pFile = NULL;
    pFile = fopen ("unexist.ent", "r");
    if (pFile == NULL)
    {
        perror("错误信息是");
        return 1;
    }
    return 0;
}

输出

复制代码
错误信息是: No such file or directory
相关推荐
Yang-Never2 小时前
ADB ->Android 实时监控内存
android·开发语言·adb·android studio
wljy12 小时前
第十四届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组(个人见解,已完结)
c语言·c++·算法·蓝桥杯
CoderCodingNo2 小时前
【GESP】C++八级考试大纲知识点梳理 (7) 算法的时间和空间效率分析
开发语言·c++·算法
程序员zgh2 小时前
C++ 环形队列 从原理到实例演示
c语言·开发语言·数据结构·c++·学习
csbysj20202 小时前
Bootstrap 下拉菜单:全面解析与应用指南
开发语言
青瓷程序设计2 小时前
基于YOLO的安全帽佩戴检测系统~Python+模型训练+2026原创+YOLO算法
python·算法·yolo
Trouvaille ~2 小时前
【优选算法篇】拓扑排序——逻辑先后与任务依赖的终极拆解
数据结构·c++·算法·leetcode·青少年编程·蓝桥杯·拓扑学
T1an-12 小时前
博乐科技笔试题
科技·算法
XiYang-DING2 小时前
【LeetCode】118.杨辉三角
算法·leetcode·职场和发展