C语言字符函数与字符串函数完全指南

📑 目录

  • [📖 1. 字符分类函数](#📖 1. 字符分类函数)
    • [🎯 练习:将字符串中的小写字母转大写](#🎯 练习:将字符串中的小写字母转大写)
  • [🔄 2. 字符转换函数](#🔄 2. 字符转换函数)
  • [📏 3. strlen 的使用和模拟实现](#📏 3. strlen 的使用和模拟实现)
    • [⚠️ 易错点示例](#⚠️ 易错点示例)
    • [🛠️ strlen的模拟实现](#🛠️ strlen的模拟实现)
  • [📋 4. strcpy 的使用和模拟实现](#📋 4. strcpy 的使用和模拟实现)
    • [🛠️ strcpy的模拟实现](#🛠️ strcpy的模拟实现)
  • [🔗 5. strcat 的使用和模拟实现](#🔗 5. strcat 的使用和模拟实现)
    • [🛠️ 模拟实现strcat函数](#🛠️ 模拟实现strcat函数)
  • [⚖️ 6. strcmp 的使用和模拟实现](#⚖️ 6. strcmp 的使用和模拟实现)
    • [🛠️ strcmp函数的模拟实现](#🛠️ strcmp函数的模拟实现)
  • [✂️ 7. strncpy 函数的使用](#✂️ 7. strncpy 函数的使用)
  • [➕ 8. strncat 函数的使用](#➕ 8. strncat 函数的使用)
  • [🔍 9. strncmp 函数的使用](#🔍 9. strncmp 函数的使用)
  • [🎯 10. strstr 的使用和模拟实现](#🎯 10. strstr 的使用和模拟实现)
    • [🛠️ strstr的模拟实现](#🛠️ strstr的模拟实现)
  • [🔪 11. strtok 函数的使用](#🔪 11. strtok 函数的使用)
  • [⚠️ 12. strerror 函数的使用](#⚠️ 12. strerror 函数的使用)
    • [📝 举例:使用strerror处理文件打开错误](#📝 举例:使用strerror处理文件打开错误)
    • [💡 了解perror函数](#💡 了解perror函数)
  • [📝 小总结](#📝 小总结)
  • [❓ 经典面试题](#❓ 经典面试题)

📖 1. 字符分类函数

在编程的过程中,我们经常要处理字符和字符串,为了方便操作字符和字符串,C语言标准库中提供了一系列库函数,接下来我们就学习一下这些函数。

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

这些函数的使用方法非常类似,我们就讲解一个函数的事情,其他的非常类似:

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个字符转换函数:

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

上面的代码,我们将小写转大写,是 -32 完成的效果,有了转换函数,就可以直接使用 toupper 函数。

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 );
  • 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0')。
  • 参数指向的字符串必须要以 '\0' 结束。
  • 注意函数的返回值为 size_t,是无符号的(易错)。
  • strlen的使用需要包含头文件 <string.h>
  • 学会strlen函数的模拟实现。

⚠️ 易错点示例

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("srt1>str2\n");
    }
    return 0;
}

💡 注意 :由于 strlen 返回 size_t 是无符号类型,strlen(str2)-strlen(str1) 的结果也是无符号数,永远不会小于0。所以即使 strlen(str2) < strlen(str1),相减结果也会被解释为很大的正数,导致判断错误。建议直接比较:strlen(str2) > strlen(str1)

🛠️ strlen的模拟实现

方式1:计数器方式

c 复制代码
int my_strlen(const char * str)
{
    int count = 0;
    assert(str);
    while(*str)
    {
        count++;
        str++;
    }
    return count;
}

方式2:递归方式(不创建临时变量)

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

方式3:指针-指针方式

c 复制代码
int my_strlen(char *s)
{
    assert(str);
    char *p = s;
    while(*p != '\0' )
          p++;
    return p-s;
}

📋 4. strcpy 的使用和模拟实现

c 复制代码
char* strcpy(char * destination, const char * source );
  • Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
  • 源字符串必须以 '\0' 结束。
  • 会将源字符串中的 '\0' 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可修改。
  • 学会模拟实现。

🛠️ strcpy的模拟实现

c 复制代码
//1.参数顺序 
//2.函数的功能,停止条件 
//3.assert
//4.const修饰指针 
//5.函数返回值 
//6.题目出自《高质量C/C++编程》书籍最后的试题部分 

char* my_strcpy(char *dest, const char*src)
{        
    char *ret = dest;
    assert(dest != NULL);
    assert(src != NULL);
    while((*dest++ = *src++))
    {
        ;
    }
    return ret;
}

🔗 5. strcat 的使用和模拟实现

  • Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
  • 源字符串必须以 '\0' 结束。
  • 目标字符串中也得有 \0,否则没办法知道追加从哪里开始。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。
  • 字符串自己给自己追加,如何?

🛠️ 模拟实现strcat函数

c 复制代码
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;
}

⚖️ 6. strcmp 的使用和模拟实现

  • This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null-character is reached.
  • 标准规定:
    • 第一个字符串大于第二个字符串,则返回大于0的数字
    • 第一个字符串等于第二个字符串,则返回0
    • 第一个字符串小于第二个字符串,则返回小于0的数字
    • 那么如何判断两个字符串?比较两个字符串中对应位置上字符ASCII码值的大小。

🛠️ strcmp函数的模拟实现

c 复制代码
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 );
  • Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
  • 拷贝num个字符从源字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

➕ 8. strncat 函数的使用

c 复制代码
char * strncat ( char * destination, const char * source, size_t num );
  • Appends the first num characters of source to destination, plus a terminating null-character.(将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加一个 \0 字符)。
  • If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.(如果source指向的字符串的长度小于num的时候,只会将字符串中到 \0 的内容追加到destination指向的字符串末尾)。
c 复制代码
/* strncat example */
#include <stdio.h>
#include <string.h>

int main ()
{
    char str1[20];
    char str2[20];
    strcpy (str1,"To be ");
    strcpy (str2,"or not to be");
    strncat (str1, str2, 6);
    printf("%s\n", str1);
    return 0;
}

🔍 9. strncmp 函数的使用

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

比较str1和str2的前num个字符,如果相等就继续往后比较,最多比较num个字母,如果提前发现不一样,就提前结束,大的字符所在的字符串大于另外一个。如果num个字符都相等,就是相等返回0。

🎯 10. strstr 的使用和模拟实现

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

Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.(函数返回字符串str2在字符串str1中第一次出现的位置)。

The matching process does not include the terminating null-characters, but it stops there.(字符串的比较匹配不包含 \0 字符,以 \0 作为结束标志)。

c 复制代码
/* strstr example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="This is a simple string";
  char * pch;
  pch = strstr (str,"simple");
  strncpy (pch,"sample",6);
  printf("%s\n", str);
  return 0;
} 

🛠️ strstr的模拟实现

c 复制代码
char *  strstr (const char * str1, const char * str2)
{
        char *cp = (char *) str1;
        char *s1, *s2;
        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);
}

🔪 11. strtok 函数的使用

c 复制代码
char * strtok ( char * str, const char * sep);
  • sep 参数指向一个字符串,定义了用作分隔符的字符集合。
  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
  • strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以被strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
  • strtok函数的第一个参数不为 NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个参数为 NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。
c 复制代码
#include <stdio.h>
#include <string.h>

int main()
{
    char arr[] = "192.168.6.111";
    char* sep = ".";
    char* str = NULL;
    for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
    {
        printf("%s\n", str);
    }
    return 0;
}

⚠️ 12. strerror 函数的使用

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

strerror 函数可以把参数部分错误码对应的错误信息的字符串地址返回来。

在不同的系统和C语言标准库的实现中都规定了一些错误码,一般是放在 errno.h 这个头文件中说明的,C语言程序启动的时候就会使用一个全局的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码,存放在errno中,而一个错误码的数字是整数很难理解是什么意思,所以每一个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。

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

//我们打印一下0~10这些错误码对应的信息 
int main()
{
    int i = 0;
    for (i = 0; i <= 10; i++) {
        printf("%s\n", strerror(i));
    }
    return 0;
}

在Windows11+VS2022环境下输出的结果如下:

复制代码
No error
Operation not permitted
No such file or directory
No such process
Interrupted function call
Input/output error
No such device or address
Arg list too long
Exec format error
Bad file descriptor
No child processes

📝 举例:使用strerror处理文件打开错误

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

int main ()
{
    FILE * pFile;
    pFile = fopen ("unexist.ent","r");
    if (pFile == NULL)
        printf ("Error opening file unexist.ent: %s\n", strerror(errno));
    return 0;
}

输出:

复制代码
Error opening file unexist.ent: No such file or directory

💡 了解perror函数

也可以了解一下 perror 函数,perror函数相当于一次将上述代码中的第9行完成了,直接将错误信息打印出来。perror函数打印完参数部分的字符串后,再打印一个冒号和一个空格,再打印错误信息。

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

int main ()
{
    FILE * pFile;
    pFile = fopen ("unexist.ent","r");
    if (pFile == NULL)
        perror("Error opening file unexist.ent");
    return 0;
}

输出:

复制代码
Error opening file unexist.ent: No such file or directory

📝 小总结

本文详细介绍了C语言中12个常用的字符函数和字符串函数,包括:

函数分类 函数名 功能
🔤 字符分类 islower 判断字符类型
🔄 字符转换 toupper / tolower 大小写转换
📏 字符串长度 strlen 计算字符串长度
📋 字符串拷贝 strcpy / strncpy 复制字符串
🔗 字符串拼接 strcat / strncat 拼接字符串
⚖️ 字符串比较 strcmp / strncmp 比较字符串
🎯 字符串查找 strstr 查找子串
🔪 字符串分割 strtok 分割字符串
⚠️ 错误处理 strerror / perror 错误信息输出

面试重点提醒:

  • strlen 返回 size_t 无符号类型,直接相减容易出错
  • strcpy / strcat / strcmp 的模拟实现是面试高频考点
  • strtok 会修改原字符串,使用时注意传临时拷贝
  • strncpy / strncat / strncmp 是安全版本,限制操作长度

❓ 经典面试题

面试题1:strlen与sizeof的区别是什么?

解答:

  • strlen 是库函数,用于计算字符串长度(不包含 \0),需要包含 <string.h>,运行时计算。
  • sizeof 是运算符,用于计算变量或类型所占内存空间大小(包含 \0),编译时计算。
c 复制代码
char str[] = "hello";
printf("%zu\n", strlen(str));  // 输出 5
printf("%zu\n", sizeof(str));  // 输出 6(包含'\0')

面试题2:为什么strlen(str2)-strlen(str1)>0的判断可能出错?

解答: 因为 strlen 返回 size_t 是无符号整型,两个无符号数相减结果仍为无符号数。当 strlen(str2) < strlen(str1) 时,相减结果本应为负数,但被解释为很大的无符号正数,导致判断错误。正确做法是直接比较:strlen(str2) > strlen(str1)

面试题3:strcat能否自己给自己追加?为什么?

解答: 不能。因为 strcat 在追加时会覆盖目标字符串的 \0,然后逐字符拷贝源字符串。如果源和目标指向同一块内存,追加过程中源字符串的内容会被覆盖破坏,导致无法正确完成追加操作,最终结果不可预测。

面试题4:strcpy和memcpy有什么区别?

解答:

  • strcpy 只能用于字符串拷贝,遇到 \0 停止,不指定拷贝长度。
  • memcpy 可以拷贝任意类型的内存数据,按字节数拷贝,不依赖 \0
  • strcpy 会拷贝 \0memcpy 不会自动添加 \0

面试题5:strtok函数为什么一般要传临时拷贝?

解答: 因为 strtok 函数在找到分隔符时,会将分隔符位置替换为 \0,从而修改原字符串。如果直接操作原始字符串,会破坏原始数据。因此通常先使用 strcpy 拷贝一份临时字符串,再对临时字符串进行分割操作。

相关推荐
Scott9999HH8 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社9 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海9 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖10 小时前
JDK 26 新特性详解
java·开发语言
马优晨10 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区12 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大13 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai13 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜13 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa13 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio