当前位置: 首页 > news >正文

C语言进阶知识--字符和字符串函数

目录:

  1. 字符分类函数
  2. 字符转换函数
  3. strlen的使用和模拟实现
  4. strcpy的使用和模拟实现
  5. strcat的使用和模拟实现
  6. strcmp的使用和模拟实现
  7. strncpy函数的使用
  8. strncat函数的使用
  9. strncmp函数的使用
  10. strstr的使用和模拟实现
  11. strtok函数的使用
  12. strerror函数的使用

正文开始

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

1. 字符分类函数

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

函数名功能描述
iscntrl控制字符(如退格、换行等)
isspace空白字符:空格' '、换页'\f'、换行'\n'、回车'\r'、制表符'\t'或者垂直制表符'\v'
isdigit十进制数字 '0' ~ '9' 字符
isxdigit十六进制数字,包括所有十进制数字字符、小写字母a~f、大写字母A~F
islower小写字母 a~z
isupper大写字母 A~Z
isalpha字母(包括大写和小写字母)
isalnum字母或数字
isgraph任何图形字符(不包括空白字符)
isprint任何可打印字符,包括图形字符和空白字符

这些函数的使用方法非常类似,我们以 islower 为例讲解,其他函数用法可类比:

int islower ( int c );

islower 用于判断参数 c 是否为小写字母。通过返回值判断结果:若为小写字母,返回非0的整数;若不是小写字母,返回0。

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

#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;  // 小写字母ASCII码值比大写大32,减去32转为大写putchar(c);i++;}return 0;
}

2. 字符转换函数

C语言提供了2个常用的字符转换函数:

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

上面的“小写转大写”练习,也可以用 toupper 函数简化实现,无需手动计算ASCII码差值:

#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 的使用和模拟实现

函数原型
size_t strlen ( const char * str );

功能说明

  • 字符串以 '\0' 作为结束标志,strlen 函数返回的是字符串中 '\0' 前面出现的字符个数(不包含 '\0')。
  • 注意事项
    1. 参数指向的字符串必须以 '\0' 结束,否则会导致计算结果错误(读取到随机内存内容)。
    2. 函数的返回值类型为 size_t(无符号整数),使用时需注意无符号数的运算特性(如无符号数相减不会得到负数)。
  • 使用需包含头文件 <string.h>

示例:strlen 使用注意(无符号返回值问题)

#include <stdio.h>
#include <string.h>
int main()
{const char* str1 = "abcdef";  // 长度为6const char* str2 = "bbb";     // 长度为3// 注意:strlen返回无符号数,3-6的结果是无符号数(4294967293),因此判断为真if(strlen(str2) - strlen(str1) > 0)printf("str2>str1\n");elseprintf("str1>str2\n");return 0;
}

运行结果str2>str1(因无符号数运算特性导致的“逻辑错误”,实际应比较 strlen(str1) > strlen(str2))。

strlen 的模拟实现

方式1:计数器方式
#include <assert.h>  // 用于断言
int my_strlen(const char * str)
{int count = 0;assert(str);  // 断言str不为NULL,避免空指针访问while(*str)   // 当*str不为'\0'时循环{count++;  // 计数器累加str++;    // 指针向后移动}return count;
}
方式2:递归方式(不创建临时变量计数器)
#include <assert.h>
int my_strlen(const char * str)
{assert(str);if(*str == '\0')return 0;  // 递归终止条件:遇到'\0'返回0elsereturn 1 + my_strlen(str + 1);  // 递归调用,累加字符数
}
方式3:指针-指针方式
#include <assert.h>
int my_strlen(const char * str)
{assert(str);const char *p = str;  // 保存字符串起始地址while(*p != '\0')     // 移动指针到'\0'位置p++;return p - str;       // 指针差值 = 字符个数(地址差=元素个数)
}

4. strcpy 的使用和模拟实现

函数原型

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

功能说明

source 指向的字符串(包括终止符 '\0')拷贝到 destination 指向的数组中,拷贝到 '\0' 时停止。

  • 注意事项
    1. 源字符串(source)必须以 '\0' 结束,否则会导致越界拷贝。
    2. 会将源字符串的 '\0' 拷贝到目标空间。
    3. 目标空间(destination)必须足够大,能容纳源字符串的全部内容(包括 '\0'),避免内存越界。
    4. 目标空间必须可修改(不能是常量字符串,如 const char* 指向的内容)。
  • 使用需包含头文件 <string.h>

strcpy 的模拟实现

#include <assert.h>
char* my_strcpy(char *dest, const char* src)
{char *ret = dest;  // 保存目标空间起始地址(用于返回)assert(dest != NULL && src != NULL);  // 断言指针非空// 循环拷贝:先赋值*dest = *src,再将指针向后移动,直到*src为'\0'(赋值后终止)while((*dest++ = *src++)){;  // 空语句,循环体无需额外操作}return ret;  // 返回目标字符串起始地址
}

5. strcat 的使用和模拟实现

函数原型

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

功能说明

source 指向的字符串追加到 destination 指向的字符串末尾:覆盖 destination 的终止符 '\0',并在追加后的新字符串末尾添加 '\0'

  • 注意事项
    1. 源字符串(source)必须以 '\0' 结束,否则无法确定追加的内容范围。
    2. 目标字符串(destination)必须以 '\0' 结束,否则无法确定追加的起始位置。
    3. 目标空间必须足够大,能容纳原目标字符串 + 源字符串的全部内容(包括 '\0')。
    4. 目标空间必须可修改。
    5. 禁止字符串自追加(如 strcat(str, str)):因追加时会覆盖源字符串的 '\0',导致无限循环越界。
  • 使用需包含头文件 <string.h>

strcat 的模拟实现

#include <assert.h>
char *my_strcat(char *dest, const char* src)
{char *ret = dest;  // 保存目标空间起始地址assert(dest != NULL && src != NULL);  // 断言指针非空// 1. 移动dest指针到目标字符串的'\0'位置while(*dest)dest++;// 2. 拷贝src到dest(同strcpy逻辑,包括'\0')while((*dest++ = *src++)){;}return ret;  // 返回目标字符串起始地址
}

6. strcmp 的使用和模拟实现

函数原型

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

功能说明

比较 str1str2 指向的字符串,从第一个字符开始逐字符比较ASCII码值:

  • 若对应字符相等,继续比较下一对字符;

  • 若对应字符不等,或遇到 '\0',停止比较。

  • 标准返回值规定

    1. str1 > str2(第一对不等字符中,str1 字符ASCII码更大),返回大于0的整数;
    2. str1 == str2(所有字符相等,且同时遇到 '\0'),返回0;
    3. str1 < str2,返回小于0的整数。
  • 使用需包含头文件 <string.h>

strcmp 的模拟实现

#include <assert.h>
int my_strcmp (const char * str1, const char * str2)
{assert(str1 != NULL && str2 != NULL);  // 断言指针非空// 逐字符比较,直到字符不等或遇到'\0'while(*str1 == *str2){if(*str1 == '\0')return 0;  // 同时遇到'\0',字符串相等str1++;str2++;}// 字符不等时,返回ASCII码差值(直接反映大小关系)return *str1 - *str2;
}

7. strncpy 函数的使用

函数原型

char * strncpy ( char * destination, const char * source, size_t num );

功能说明

source 指向的字符串的num 个字符拷贝到 destination 指向的空间。

  • 特殊情况处理
    1. 若源字符串长度 大于等于 num:只拷贝前 num 个字符,不追加 '\0'(需手动处理终止符);
    2. 若源字符串长度 小于 num:拷贝完源字符串(包括 '\0')后,在目标空间剩余位置填充 0(即 '\0'),直到总拷贝数为 num
  • 使用需包含头文件 <string.h>

8. strncat 函数的使用

函数原型

char * strncat ( char * destination, const char * source, size_t num );

功能说明

source 指向的字符串的num 个字符追加到 destination 指向的字符串末尾,并在最终结果后强制追加一个 '\0'

  • 特殊情况处理
    1. 若源字符串长度 大于等于 num:只追加前 num 个字符,再追加 '\0'
    2. 若源字符串长度 小于 num:只追加源字符串的全部内容(包括 '\0'),无需额外填充。
  • 使用需包含头文件 <string.h>

示例:strncat 使用

#include <stdio.h>
#include <string.h>
int main ()
{char str1[20];char str2[20];strcpy (str1,"To be ");    // str1: "To be \0"strcpy (str2,"or not to be");  // str2: "or not to be\0"strncat (str1, str2, 6);  // 追加str2的前6个字符:"or not",再追加'\0'printf("%s\n", str1);     // 输出:To be or notreturn 0;
}

9. strncmp 函数的使用

函数原型

int strncmp ( const char * str1, const char * str2, size_t num );

功能说明

比较 str1str2 指向的字符串的num 个字符,比较逻辑同 strcmp,但最多比较 num 个字符后停止。

  • 返回值规定
    返回值含义
    < 0str1 的前 num 个字符小于 str2
    = 0str1str2 的前 num 个字符完全相等
    > 0str1 的前 num 个字符大于 str2
  • 使用需包含头文件 <string.h>

10. strstr 的使用和模拟实现

函数原型

char * strstr ( const char * str1, const char * str2);

功能说明

str1 指向的字符串中,查找 str2 指向的字符串(称为“子串”)的第一次出现位置

  • 若找到,返回 str1 中指向子串起始位置的指针;
  • 若未找到(或 str2 为空字符串),返回 NULL
  • 匹配过程不包含 '\0',但遇到 '\0' 时停止。
  • 使用需包含头文件 <string.h>

示例:strstr 使用

#include <stdio.h>
#include <string.h>
int main ()
{char str[] ="This is a simple string";char * pch;pch = strstr (str,"simple");  // 在str中查找"simple",返回其起始指针if(pch != NULL)strncpy (pch,"sample",6);  // 将"simple"替换为"sample"printf("%s\n", str);          // 输出:This is a sample stringreturn 0;
}

strstr 的模拟实现

#include <assert.h>
char * strstr (const char * str1, const char * str2)
{const char *cp = str1;    // 用于遍历str1的指针const char *s1, *s2;      // s1遍历str1子串,s2遍历str2if (!*str2)               // 若str2为空字符串,直接返回str1return (char *)str1;// 遍历str1,直到cp指向'\0'while (*cp){s1 = cp;              // 记录当前str1的起始位置s2 = str2;            // 重置str2的起始位置// 逐字符比较s1和s2,直到字符不等或遇到'\0'while (*s1 && *s2 && (*s1 == *s2)){s1++;s2++;}if (!*s2)             // 若s2遍历到'\0',说明找到子串return (char *)cp;cp++;                 // 未找到,cp向后移动一位}return NULL;              // 遍历完str1仍未找到,返回NULL
}

11. strtok 函数的使用

函数原型

char * strtok ( char * str, const char * sep);

功能说明

str 指向的字符串按 sep 定义的“分隔符集合”拆分(分割为多个“标记”):

  • sep:指向一个字符串,包含所有用作分隔符的字符(如 ".-" 表示分隔符为 .-);
  • strtok 会将找到的标记末尾替换为 '\0',并返回指向该标记的指针;
  • 关键特性
    1. str 不为 NULL:函数找到 str 中第一个标记,保存其在字符串中的位置,供下次调用使用;
    2. strNULL:函数从上次保存的位置继续查找下一个标记;
    3. 若无更多标记,返回 NULL
    4. 函数会修改原字符串(替换 '\0'),因此建议传入原字符串的临时拷贝(避免破坏原数据)。
  • 使用需包含头文件 <string.h>

示例:strtok 使用(拆分IP地址)

#include <stdio.h>
#include <string.h>
int main()
{char arr[] = "192.168.6.111";  // 原字符串(可修改)char* sep = ".";               // 分隔符为 '.'char* str = NULL;// 循环拆分:首次传arr,后续传NULLfor (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep)){printf("%s\n", str);  // 依次输出每个标记:192、168、6、111}return 0;
}

12. strerror 函数的使用

函数原型

char* strerror ( int errnum );

功能说明

将错误码 errnum 转换为对应的“错误信息字符串”,并返回该字符串的地址。

  • 相关背景
    1. C语言中,错误码定义在头文件 <errno.h> 中,程序启动时全局变量 errno 初始化为0(表示无错误);
    2. 当标准库函数执行出错时,会将对应的错误码写入 errno
    3. strerror 的作用是“翻译”错误码(如 errno=2 对应 “No such file or directory”),方便开发者理解错误原因。
  • 使用需包含头文件 <string.h><errno.h>

示例1:打印0~10对应的错误信息

#include <errno.h>
#include <string.h>
#include <stdio.h>
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

示例2:结合 errno 处理文件操作错误

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{FILE * pFile;// 尝试打开不存在的文件(只读模式)pFile = fopen ("unexist.ent","r");if (pFile == NULL)  // 打开失败时,fopen返回NULL,errno被设置为对应错误码{// 打印错误信息:strerror(errno) 翻译当前errno对应的错误printf ("Error opening file unexist.ent: %s\n", strerror(errno));}return 0;
}

输出

Error opening file unexist.ent: No such file or directory

补充:perror 函数

perror 是简化版的“错误打印函数”,功能等同于 printf("xxx: %s\n", strerror(errno)),直接打印错误信息:

#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语言

http://www.dtcms.com/a/450521.html

相关文章:

  • C++中指针传递与引用传递的区别
  • 云南建设局网站首页网页浏览器主要通过ftp协议
  • 网站建设先航科技贵阳制作网站的公司
  • 做网站建设有哪些公司好耒阳住房与建设局网站
  • Helm入门
  • SpringBoot项目搭建
  • 网站导航菜单兰品牌建设助力高质量发展
  • 小游戏网站网址今天的头条新闻
  • 中专网站建设课程东莞网站系统后缀
  • 广州市学校网站建设公司网站html5自适应屏幕大小
  • 网站推广合作花钱做网站注意些什么
  • 上海缔客网站建设公司刚刚
  • C语言入门教程(第1讲):最通俗的C语言常见概念详解与实战讲解
  • 在华图做网站编辑网页设计于制作课程标准
  • 中国建设报社网站建筑工程公司注册资金要求
  • 虚拟麦克风驱动下载,支持将手机话筒映射成PC端麦克风
  • 网站开发整套视频仓库管理erp系统使用
  • 建立网站纯文字版本网页设计代码放图片
  • 公司微信网站建设方案模板下载长沙网站建设案例
  • 四大门户网站排名微信小程序应用开发
  • 建设网站需要数据库备份动漫制作专业认知报告
  • UE HTML5开发二:双向通信调用V1.0
  • 泉州企业自助建站深圳专业做网站技术
  • 【分立元件反馈类型的判断】2023-2-19
  • 想学网络营销网站建设免费做详情页的软件
  • 如何注册网站怎么注册公众号江苏建设信息网站
  • h5开发网站优点网站建设资金投入
  • UNIX下C语言编程与实践33-UNIX 僵死进程预防:wait 法、托管法、信号忽略与捕获
  • 手机如何建免费网站做外贸网站信息
  • 深圳做电子工厂的网站在网站留外链怎么做