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

C语言自学--字符函数和字符串函数

目录

1、字符分类函数

1.1、字符分类函数概述

1.2、常用字符分类函数

1.3、使用示例

1.4、注意事项

2、字符转换函数

3、strlen函数的使用与模拟实现

3.1、用计数器模拟strlen

3.2、指针相减的方式

3.3、递归的方式

4、strcpy函数的使用与模拟实现

4.1、模拟实现strcpy

4.2、表达式分解

5、strcat函数的使用与模拟实现

6、strcmp函数的使用与模拟实现

6.1、strcmp的模拟实现

7、strncpy函数的使用

7.1、strncpy函数的基本用途

7.2、关键特性

7.3、典型用法示例

7.4、注意事项

8、strncat函数的使用

8.1、strncat 函数简介

8.2、参数说明

8.3、返回值

8.4、使用示例

8.5、注意事项

8.6、常见问题

9、strncmp函数的使用

9.1、strncmp 函数简介

9.2、参数说明

9.3、返回值

9.4、使用示例

9.5、注意事项

10、strstr函数的使用与模拟实现

11、strtok函数的使用

12、strerror函数的使用

12.1、strerror 函数的基本介绍

12.2、函数参数和返回值

12.3、使用示例

12.4、注意事项


1、字符分类函数

1.1、字符分类函数概述

C语言中的字符分类函数用于判断一个字符是否属于特定类型(如字母、数字、空格等)。这些函数定义在头文件 ctype.h 中,返回值通常为 int(非零表示“真”,零表示“假”)。

1.2、常用字符分类函数

isalnum(int c)
检查字符是否为字母或数字。若 c 是字母(a-zA-Z)或数字(0-9),返回非零值。

isalpha(int c)
检查字符是否为字母。若 c 是字母(a-zA-Z),返回非零值。

isdigit(int c)
检查字符是否为十进制数字。若 c 是数字(0-9),返回非零值。

isxdigit(int c)
检查字符是否为十六进制数字。若 c0-9a-fA-F,返回非零值。

islower(int c)
检查字符是否为小写字母。若 ca-z,返回非零值。

isupper(int c)
检查字符是否为大写字母。若 cA-Z,返回非零值。

isspace(int c)
检查字符是否为空白字符。包括空格、制表符(\t)、换行符(\n)等。

iscntrl(int c)
检查字符是否为控制字符。如 ASCII 码中 0-31 或 127(DEL)。

isprint(int c)
检查字符是否为可打印字符(包括空格)。

ispunct(int c)
检查字符是否为标点符号(非字母、数字或空格的可打印字符)。

isgraph(int c)
检查字符是否为图形字符(可打印且非空格)。

1.3、使用示例
#include <stdio.h>
#include <ctype.h>
int main()
{char arr[] = "I am a Studend.";//            0123456789.....int i = 0;while (arr[i] !='\0'){if (islower(arr[i])){arr[i] -= 32;}i++;}printf("%s\n",arr);return 0;
}

1.4、注意事项
  • 函数参数类型为 int,但通常传递 char 类型时会自动转换。
  • 函数对字符的检查基于当前区域设置(locale),但默认行为遵循 ASCII 编码。
  • 若需处理宽字符(如 Unicode),需使用 wctype.h 中的函数(如 iswalpha)。

2、字符转换函数

int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写    
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写
#include <ctype.h>
#include <stdio.h>int main() {char c = 'a';printf("Uppercase: %c\n", toupper(c));return 0;
}


3、strlen函数的使用与模拟实现

size_t strlen ( const char * str );
  • 字符串以'\0'作为结束标志,strlen函数返回'\0'之前出现的字符个数(不包含'\0'
  • 参数指向的字符串必须以'\0'结尾
  • 注意函数返回值类型为size_t,是无符号整型
  • 使用strlen需要包含<string.h>头文件
3.1、用计数器模拟strlen
//用计数器模拟strlen
#include <stdio.h>
#include <assert.h>
int my_strlen(const char * str)
//const在星号左边,不允许修改内容
//const在星号右边时,表示指针的地址不可变,但可以通过指针修改其指向的数据
{int count = 0;assert(str != NULL);while (*str !='\0'){count++;str++;}return count;
}
int main()
{char arr[] = "abcdef";size_t sz = my_strlen(arr);printf("%zd",sz);return 0;
}
3.2、指针相减的方式

        指针相减的方式,知道指针开始位置和'\0'的位置,指针相减就是元素的个数。

//用指针相减模拟strlen
#include <stdio.h>
#include <assert.h>
int my_strlen(const char * str)
{assert(str != NULL);const char* start = str;//start记录开始地址//只要没有找到'\0'就一直循环,记录最后一个地址while (*str != '\0'){str++;}return str - start;}
int main()
{char arr[] = "abcdef";size_t sz = my_strlen(arr);printf("%zd",sz);return 0;
}
3.3、递归的方式

        一般不用递归的方式,除非要求不能在函数创建临时变量!!

//用递归的方式
#include <stdio.h>
#include <assert.h>
int my_strlen(const char * str)
{assert(str != NULL);if (*str != '\0'){return 1 + my_strlen(str + 1);}else{return 0;//如果第一个字符是'\0',就返回0}}
int main()
{char arr[] = "abcdef";size_t sz = my_strlen(arr);printf("%zd",sz);return 0;
}

        递归思路,递归就是大事化小(先递推下去,再回归)

4、strcpy函数的使用与模拟实现

char* strcpy(char * destination, const char * source );
//                1                    2
//将2拷贝到1中,2中必须要有'\0',拷贝的时候会一起拷贝过去
#include <stdio.h>int main()
{char arr1[] = "hell world";char arr2[20] = { 0 };strcpy(arr2,arr1);//errprintf("%s\n",arr2);return 0;
}

注意事项:

  • 源字符串必须以空字符 '\0' 结尾,没有'\0',strcpy不会停止。
  • 函数会将源字符串中的终止符 '\0' 一并复制到目标空间
  • 目标缓冲区必须预留足够空间存放源字符串及其终止符
  • 目标内存区域必须具有可写权限(可以修改)

错误示范:

#include <stdio.h>int main()
{char arr1[] = "hell world";char* p = "xxxxxxxxxxxxxxxxx";//常量字符串不能被修改strcpy(p,arr1);//errprintf("%s\n",p);return 0;
}
#include <stdio.h>int main()
{char arr1[] = "hell world";char arr2[] = { 0 };//初始化只有一个值,不能放下arr1的元素,要留够空间strcpy(arr2,arr1);//errprintf("%s\n",arr2);return 0;
}
4.1、模拟实现strcpy
#include <stdio.h>
#include <assert.h>
void my_strcpy(char *destination  , const char* source)//因为是复制,所以不希望源头对应的值被修改,可以加const
{assert(destination && source);while (*source != '\0'){*destination = *source;source++;destination++;}*destination = *source; //因为'\0'没有复制过去,要单独复制过去
}int main()
{char arr1[] = "hell world";char arr2[20] = { 0 };my_strcpy(arr2, arr1);printf("%s\n", arr2);return 0;
}

优化:

#include <stdio.h>
#include <assert.h>
//为了实现链式访问
//strcpy返回的是目标空间的起始地址
char*  my_strcpy(char* destination, const char* source)//因为是复制,所以不希望源头对应的值被修改,可以加const
//返回的是arr2的起始地址
{assert(destination && source);char* ret = destination;while (*source != '\0'){*destination = *source;source++;destination++;}*destination = *source; //因为'\0'没有复制过去,要单独复制过去return ret;//一开始把arr2的起始位置存起来,因为起始位置在上方已经变化了;//返回目标空间的起始地址
}int main()
{char arr1[] = "hell world";char arr2[20] = { 0 };char * pstr = my_strcpy(arr2, arr1);//方法2printf("%s\n", arr2);printf("%s\n", pstr);printf("%s\n", my_strcpy(arr2, arr1));//因为 my_strcpy(arr2, arr1)返回的就是目标空间的起始地址return 0;
}

再次优化:

#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* destination, const char* source)
{assert(destination && source);char* ret = destination;while (*destination++ = *source++){;}return ret;
}int main()
{char arr1[] = "hell world";char arr2[20] = { 0 };char* pstr = my_strcpy(arr2, arr1);//方法2printf("%s\n", arr2);printf("%s\n", pstr);printf("%s\n", my_strcpy(arr2, arr1));return 0;
}
4.2、表达式分解
  1. *source++部分

    • 先取source指针当前指向的字符值(*source
    • 然后将source指针自增1(++),使其指向下一个字符
    • 例如:若source指向'h',则先返回'h',然后source指向'e'
  2. *destination++部分

    • *source++返回的值赋给destination指向的字符(*destination = value
    • 然后destination指针自增1(++),准备接收下一个字符
    • 例如:若destination指向arr2[0],则先执行arr2[0] = 'h',然后destination指向arr2[1]
  3. 整体效果

    • 每次循环执行一次字符复制和两个指针的自增
    • 当遇到源字符串的'\0'时,循环终止('\0'的ASCII为0,条件判断为假)

5、strcat函数的使用与模拟实现

        strcat 是 C 语言标准库中的一个字符串拼接函数,其原型定义在 <string.h> 头文件中。函数声明如下:

char *strcat(char *dest, const char *src);
  • 功能:将 src 字符串追加到 dest 字符串的末尾(覆盖 dest 的终止空字符 '\0'),并在新字符串的末尾添加一个新的终止空字符。
  • 参数
    • dest:目标字符串,必须具有足够的空间容纳拼接后的结果。
    • src:源字符串,以 '\0' 结尾。
  • 返回值:返回指向 dest 的指针。
  • 源字符串必须以 '\0' 作为结束符
  • 目标字符串必须包含 '\0',否则无法确定追加起始位置
  • 目标缓冲区必须具有足够空间容纳源字符串内容
  • 目标缓冲区必须可修改
  • 不保证自己给自己追加。

#include <stdio.h>
#include <assert.h>char* my_strcat(char* dest, const char* src) {assert(dest && src);  // 空指针检查char* orig_dest = dest;// 定位到dest末尾while (*dest) dest++;// 逐字符复制src内容while ((*dest++ = *src++));return orig_dest;  // 返回目标字符串起始地址
}int main() {char arr1[20] = "hello ";char arr2[] = "world";printf("连接前: %s\n", arr1);my_strcat(arr1, arr2);printf("连接后: %s\n", arr1);  // 输出: hello worldreturn 0;
}


6、strcmp函数的使用与模拟实现

        strcmp是C语言标准库中的一个字符串比较函数,用于比较两个以\0结尾的字符串。其原型定义在<string.h>头文件中:

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

返回值规则:

  • str1小于str2(按字典序),返回负整数(通常为-1)。
  • str1等于str2,返回0。
  • str1大于str2,返回正整数(通常为1)。

strcmp的底层实现通常通过逐字符比较完成(比较的不是字符串的长度而是对应位置上的字符大小),直到遇到不匹配字符或字符串结束符\0

#include <stdio.h>
#include <string.h>int main() {char str1[] = "hello";char str2[] = "world";char str3[] = "hello";int result1 = strcmp(str1, str2);int result2 = strcmp(str1, str3);printf("Comparing '%s' and '%s': %d\n", str1, str2, result1);printf("Comparing '%s' and '%s': %d\n", str1, str3, result2);return 0;
} 

运行上述代码后,输出如下:

Comparing 'hello' and 'world': -15
Comparing 'hello' and 'hello': 0

还可以优化:

#include <stdio.h>
#include <string.h>int main() {char str1[] = "apple";char str2[] = "banana";char str3[] = "apple";// 比较 str1 和 str2int result1 = strcmp(str1, str2);if (result1 < 0) {printf("'%s' 小于 '%s'\n", str1, str2);} else if (result1 > 0) {printf("'%s' 大于 '%s'\n", str1, str2);} else {printf("'%s' 等于 '%s'\n", str1, str2);}// 比较 str1 和 str3int result2 = strcmp(str1, str3);if (result2 < 0) {printf("'%s' 小于 '%s'\n", str1, str3);} else if (result2 > 0) {printf("'%s' 大于 '%s'\n", str1, str3);} else {printf("'%s' 等于 '%s'\n", str1, str3);}return 0;
}
'apple' 小于 'banana'
'apple' 等于 'apple'
6.1、strcmp的模拟实现
//strcmp的模拟实现#include <stdio.h>
#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++;}return *str1 - *str2;
}int main()
{char arr1[] = "abcdef"; // a b c d e f \0char arr2[] = "abcd";   // a b c d \0int ret = my_strcmp(arr1,arr2);printf("%d\n",ret);return 0;
}

7、strncpy函数的使用

7.1、strncpy函数的基本用途

strncpy是C语言标准库中的一个字符串操作函数,用于将源字符串的指定长度内容复制到目标字符串中。其函数原型如下:

char *strncpy(char *dest, const char *src, size_t n);  
  • dest:目标字符串指针。
  • src:源字符串指针。
  • n:要复制的最大字符数。
7.2、关键特性
  1. 固定长度复制
    复制src的前n个字符到dest。若src长度小于n,剩余空间用'\0'填充;若src长度大于或等于ndest可能不以'\0'结尾。

  2. 不自动添加终止符
    n小于等于src长度,dest不会自动添加终止符'\0',需手动处理。

7.3、典型用法示例
char dest[20];  
const char *src = "Hello, World!";  
strncpy(dest, src, sizeof(dest) - 1);  
dest[sizeof(dest) - 1] = '\0'; // 确保终止符  
7.4、注意事项
  • 缓冲区溢出风险
    需确保dest有足够空间容纳n个字符(含终止符)。

  • 性能与安全性
    相比strcpystrncpy更安全但效率较低(因可能填充'\0')。现代代码可考虑snprintfstrlcpy(非标准)。


8、strncat函数的使用

8.1、strncat 函数简介

strncat 是 C 标准库中的一个字符串操作函数,用于将源字符串的前 n 个字符追加到目标字符串的末尾。其原型定义在 <string.h> 头文件中:

char *strncat(char *dest, const char *src, size_t n);
8.2、参数说明
  • dest:目标字符串缓冲区,必须足够大以容纳追加后的结果(包括终止符 \0)。
  • src:源字符串,内容将被追加到 dest 末尾。
  • n:最多追加的字符数(不包括 \0)。
8.3、返回值

返回指向目标字符串 dest 的指针。

8.4、使用示例
#include <stdio.h>
#include <string.h>int main() {char dest[20] = "Hello";const char *src = ", World!";// 追加最多 5 个字符(实际只追加 3 个字符,因为 src 较短)strncat(dest, src, 5);printf("Result: %s\n", dest); // 输出: Hello, Woreturn 0;
}
8.5、注意事项
  1. 缓冲区溢出dest 必须有足够的空间容纳追加后的字符串(包括 \0)。否则会导致未定义行为。

    • 错误示例:
      char dest[5] = "Hi";
      strncat(dest, "12345", 5); // 缓冲区溢出!
      
  2. 终止符处理strncat 会在追加完成后自动添加 \0,即使未达到 n 的限制。

  3. 性能:每次调用 strncat 都需要从 dest 开头遍历到 \0,频繁调用可能影响效率。

8.6、常见问题
  • 为什么 strncat 不返回追加的字符数?
    设计上是为了链式调用(如 strcat(a, strcat(b, c))),但实际中应避免这种用法。

  • n 为 0 时会发生什么?
    函数直接返回 dest,不做任何修改。


9、strncmp函数的使用

9.1、strncmp 函数简介

strncmp 是 C 语言标准库中的字符串比较函数,用于比较两个字符串的前 n 个字符。其原型定义在 <string.h> 中:

int strncmp(const char *str1, const char *str2, size_t n);
9.2、参数说明
  • str1:第一个待比较的字符串。
  • str2:第二个待比较的字符串。
  • n:最多比较的字符数。
9.3、返回值
  • 0:前 n 个字符完全相同。
  • 正数str1 中第一个不匹配字符的 ASCII 值大于 str2 的对应字符。
  • 负数str1 中第一个不匹配字符的 ASCII 值小于 str2 的对应字符。
9.4、使用示例

比较两个字符串的前 3 个字符:

#include <stdio.h>
#include <string.h>int main() {char str1[] = "hello";char str2[] = "heaven";int result = strncmp(str1, str2, 3); // 比较前 3 字符if (result == 0) {printf("前 3 字符相同\n");} else if (result > 0) {printf("str1 大于 str2\n");} else {printf("str1 小于 str2\n");}return 0;
}
9.5、注意事项
  • 若任一字符串长度小于 n,比较会在遇到 '\0' 时终止。
  • 安全性优于 strcmp,可避免缓冲区溢出风险。

10、strstr函数的使用与模拟实现

char *strstr(const char *str1, const char *str2);
  • str1:被搜索的主字符串。
  • str2:需要查找的子字符串。
  • 返回值:如果找到子字符串,返回指向主字符串中子字符串首次出现位置的指针;如果未找到,返回 NULL。
#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的模拟实现:

#include <stdio.h>
#include <string.h>char* my_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;
}int main()
{char str[] = "This is a simple string";char* pch;pch = strstr(str, "simple");  // 查找simple子串if (pch) {my_strstr(pch, "sample");  // 在找到的子串后继续查找sampleprintf("%s\n", str);} else {printf("Not found\n");}return 0;
}

11、strtok函数的使用

char *strtok(char *str, const char *sep);
  • sep参数指定一个字符串,其中包含用作分隔符的字符集合
  • 第一个参数str指定待分割的字符串,可能包含0个或多个由sep中分隔符分割的标记
  • strtok函数会查找str中的下一个标记,用\0替换分隔符,并返回指向该标记的指针
    • 注意:该函数会修改原字符串,建议对临时拷贝的可修改字符串进行操作
  • 当第一个参数不为NULL时:
    • 函数会查找str中的第一个标记
    • 同时保存当前处理位置供后续调用使用
  • 当第一个参数为NULL时:
    • 函数会从上一次保存的位置继续查找下一个标记
  • 如果没有更多标记可查找,则返回NULL指针
#include <stdio.h>
#include <string.h>int main() {char str[] = "apple,orange,banana";const char *delim = ",";char *token = strtok(str, delim); // 首次调用while (token != NULL) {printf("%s\n", token);token = strtok(NULL, delim); // 后续调用}return 0;
}
#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函数的使用

12.1、strerror 函数的基本介绍

        strerror 是 C 标准库中的一个函数,用于将错误码(通常存储在 errno 中)转换为可读的错误描述字符串。其原型定义在 <string.h> 头文件中:

char *strerror(int errnum);
12.2、函数参数和返回值
  • 参数errnum 是错误码,通常通过全局变量 errno 获取。
  • 返回值:返回一个指向错误描述字符串的指针。该字符串是静态分配的,不需要手动释放,但可能被后续的 strerror 调用覆盖。
12.3、使用示例

以下是一个简单的示例,展示如何使用 strerror 输出当前 errno 对应的错误信息:

#include <stdio.h>
#include <string.h>
#include <errno.h>int main() {FILE *file = fopen("nonexistent_file.txt", "r");if (file == NULL) {printf("Error: %s\n", strerror(errno));}return 0;
}
12.4、注意事项
  1. 错误码范围strerror 仅支持标准错误码。非标准错误码可能返回未知描述。

  2. 不可修改返回值:返回的字符串是只读的,尝试修改会导致未定义行为。


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

相关文章:

  • spring-boot--邮箱验证码发送--spring-boot-starter-mail
  • 3ds Max 2026安装教程(附安装包)3ds Max 2026下载详细安装图文教程
  • Genie 2:Google DeepMind 推出的基础世界模型,单张图生成 1分钟可玩 3D 世界
  • LeetCode 104. 二叉树的最大深度
  • 欧拉角描述相机的运动
  • Unity2D-Spriteshape
  • 打工人日报#20250921
  • Coolmuster Android Assistant:Windows系统下的Android设备管理专家
  • Android 的多进程机制 (Android Multi-Process Model)
  • 2025研究生数学建模通用神经网络处理器下的核内调度问题草案
  • Spring Boot 4 新特性详解:5大核心更新助力企业级开发
  • 计算机网络经典问题透视:网络利用率和网络时延之间,究竟存在着怎样一种“爱恨交织”的关系?我们梦寐以求的100%网络利用率,在现实世界中真的能够实现吗
  • requests 和 lxml 库的xpath实现
  • 前端梳理体系从常问问题去完善-工程篇(webpack,vite)
  • Go语言在K8s中的核心优势
  • 旅游门票预订系统支持微信小程序+H5
  • Requests 网络请求:Python API 交互与数据获取
  • 基于Dify实现简历自动筛选过滤
  • PHP中常见数组操作函数
  • 避坑指南:鸿蒙(harmony next)APP获取公钥和证书指纹的方法
  • Java 大视界 -- Java 大数据在智能教育学习效果评估与教学质量改进中的深度应用(414)
  • 【场景题】如何解决大文件上传问题
  • 云原生复杂多变的环境中的安全防护方案
  • Python10-逻辑回归-决策树
  • 如何生成一个不会重复随机数?
  • 【精品资料鉴赏】155页WORD大型制造企业MES制造执行系统建设方案
  • 定时计划任务
  • 【脑电分析系列】第23篇:癫痫检测案例:从频谱特征到深度学习模型的CHB-MIT数据集实战
  • `CookieStore` API
  • 数据可视化的中间表方案