☰
C语言——笔试题常考:字符函数的功能和模拟实现
2026/9/27 22:40:04 网站建设 项目流程

本文介绍了C语言中常用的字符串处理函数,包括字符分类(如isdigit)、字符转换(如tolower、toupper)、strlen、strcpy、strcat、strcmp及strncpy等。这些函数均在标准库头文件中定义,用于判断字符类型、转换大小写、统计长度、拷贝、追加、比较和安全复制字符串。文中通过代码示例与模拟实现,详细说明了各函数的使用方法、注意事项及底层逻辑,帮助理解字符串操作的核心机制。


一、字符分类函数

作用:字符分类函数用于对不同的字符类型进行分类。简单来说就是判断字符是否是我们想要的类型。

头文件:<ctype.h>

使用方法:以 isdigit 为例

intisdigit(intc);

参数c为需要判断的字符
如果是上图函数对应类型的字符返回真,反之返回假。
如:

inti=isdigit('0');//返回真intj=isdigit('a');//返回假

模拟实现:

intmy_isdigit(intc){if(c>='0'&&c<='9')return1;//是对应类型的字符,返回真elsereturn0;//不是对应类型的字符,返回假}

二、字符转换函数

字符转换函数有以下两个

inttolower(intc);//将参数传进去的⼤写字母转⼩写inttoupper(intc);//将参数传进去的小写字母转⼤写

其实将大写转为小写就是完成+32的效果,将小写转为大写就是完成-32的效果(A的ascll码为65,a的ascll码为97)。

如:

#include<stdio.h>#include<ctype.h>intmain(){inti=0;charstr[]="Test String.\n";charc;while(str[i]){c=str[i];if(islower(c))//判断是否为小写字母c=toupper(c);//-32putchar(c);i++;}return0;}

模拟实现:

intmy_toupper(intc){returnc-32;}

三、strlen函数(以下函数均在<string.h>中)

形式:

size_tstrlen(constchar*str);

作用:统计字符串的长度。准确来说是统计从给定指针到 ‘\0’ 的字符个数(不算 ‘\0’ )。

参数:str 要统计字符串的起始地址。

返回值:字符个数(不算 ‘\0’)

代码演示:

#include<stdio.h>#include<string.h>intmain(){constchar*str="abcdef";//创建一个长度为6的字符串printf("%zd\n",strlen(str));//调用strlen函数return0;}

注意事项:

  • 字符串末尾必须包含 ‘\0’,否则返回值为为随机值
  • 统计个数时不包含 ‘\0’ 字符

模拟实现:

  • 方式1:计数器形式
#include<stdio.h>#include<assert.h>size_tmy_strlen(constchar*str){assert(str);size_tcount=0;while(*str)//遇到\0停止{str++;count++;//每统计一个字符,计数器+1}returncount;}
  • 方式2:指针 - 指针 形式
#include<assert.h>size_tmy_strlen(constchar*str){assert(str);//检查空指针constchar*start=str;//记录起始地址while(*str)//遇到\0停止{str++;}returnstr-start;//结束地址 - 起始地址}
  • 方式3:递归
size_tmy_strlen(constchar*str){assert(str);//检查空指针//*str不为\0的话,就继续检擦下一个if(*str){str+=1;returnmy_strlen(str)+1;//回归时,返回值++}//*str是\0的话,返回0,开始回归elsereturn0;}

四、strcpy函数

形式:

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

作用:字符拷贝,直到遇到 ‘\0’ 。

参数:
destination:指向目的地空间的指针
source:指向拷贝源头的指针

返回值:目的地空间的起始地址

注意事项:

  • 源字符串必须以 ‘\0’ 结束。
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可修改。

代码演示:

#include<stdio.h>#include<string.h>intmain(){chararr1[10]={0};chararr2[]="hello";strcpy(arr1,arr2);printf("%s\n",arr1);return0;}

模拟实现:

char*my_strcpy(char*dest,constchar*scr){assert(dest&&scr);//检擦空指针char*ret=dest;//记录起始位置(返回值)while(*dest++=*scr++);//先吧*scr的值赋给*dest;地址分别+1;//判断*scr是否为\0(否:进入下一次循环,是:结束)returnret;}

五、strcat函数

形式:

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

作用:字符串追加,把 source 指向的源字符串中的所有字符都追加到 destination 指向的空间中。

参数:
destination :指针,指向目的地空间
source :指针,指向源头数据

返回值:strcat 函数返回的目标空间的起始地址

注意事项:

  • 源字符串必须以 ‘\0’ 结束。
  • 目标字符串中也得有 \0 ,否则没办法知道追加从哪里开始。
  • 目标空间必须有足够的大,能容纳下源字符串的内容
  • 目标空间必须可修改。

代码演示:

#include<stdio.h>#include<string.h>intmain(){chararr1[20]="hello ";chararr2[]="world";strcat(arr1,arr2);printf("%s\n",arr1);return0;}

模拟实现:

char*my_strcat(char*dest,constchar*scr){assert(dest&&scr);//检擦空指针char*ret=dest;//记录起始位置(返回值)while(*dest)//将dest移到\0的前面{dest++;}while(*dest++=*scr++);//先吧*scr的值赋给*dest;地址分别+1;//判断*scr是否为\0(否:进入下一次循环,是:结束)returnret;}

六、strcmp函数

形式:

功能:用来比较 str1 和 str2 指向的字符串,从两个字符串的第一个字符开始比较,如果两个字符的ASCII码值相等,就比较下⼀个字符。直到遇到不相等的两个字符,或者字符串结束。

参数:
str1 :指针,指向要比较的第一个字符串
str2 :指针,指向要比较的第二个字符串

返回值:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字

演示代码:

#include<stdio.h>#include<string.h>intmain(){chararr1[]="abcdef";chararr2[]="abq";intret=strcmp(arr1,arr2);printf("%d\n",ret);if(ret>0)printf("arr1 > arr2\n");elseif(ret==0)printf("arr1 == arr2\n");elseprintf("arr1 < arr2\n");return0;}

模拟实现:

intmy_strcmp(constchar*str1,constchar*str2){assert(str1&&str2)//检查空指针while(*str1==*str2&&*str1)//如果相等 && 没到 \0 进行循环{str1++;str2++;}return*str1-*str2;//返回两个的差值}

七、strncpy函数

char*strncpy(char*destination,constchar*source,size_tnum);

作用:字符串拷贝;将 source 指向的字符串拷贝到 destination 指向的空间中,最多拷贝 num个字符。

参数:
destination :指针,指向目的地空间
source :指针,指向源头数据
num :从source指向的字符串中最多拷贝的字符个数

返回值:
strncpy 函数返回的目标空间的起始地址

代码演示:

#include<stdio.h>#include<string.h>intmain(){chararr1[20]={0};chararr2[]="abcdefghi";char*str=strncpy(arr1,arr2,5);printf("%s\n",arr1);printf("%s\n",str);return0;}

注意事项:

  • 如果需要拷贝的字符串小于等于num ,则无法拷贝源字符串中的 ‘\0’ (如下图1)
  • 如果需要拷贝的字符串大于num ,则会根据num的值添加相应个数的 ‘\0’ (如下图2)
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可修改。

图一

图二

模拟实现:

char*my_strncpy(char*dest,constchar*scr,size_tn){assert(dest&&scr);//检擦空指针char*ret=dest;//记录起始位置(返回值)while(n--&&*scr)//如果n减为0,或*scr变为0,跳出循环{*dest++=*scr++;//吧*scr的值赋给*dest;地址分别+1;}while(n--)//如果n还没用完,补上剩余的'\0'{*dest++='\0';}returnret;}

八、strncat

形式:

char*strncat(char*destination,constchar*source,size_tnum);

作用:字符串追加;将 source 指向的字符串的内容,追加到 destination 指向的空间,最多追加 num 个字符。

参数:
destination :指针,指向了目标空间
source :指针,指向了源头数据
num :最多追加的字符的个数

返回值:返回的是目标空间的起始地址

代码演示:

#include<stdio.h>#include<string.h>intmain(){chararr1[20]="hello ";chararr2[]="world";char*str=strncat(arr1,arr2,5);printf("%s\n",arr1);printf("%s\n",str);return0;}

注意事项:

  • strncat 函数在源字符串中遇到 \0 会自动停止
  • strncat 函数无论如何都会自动在字符串后面补\0
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可修改。
  • 相较于 strcat,strncat 更加灵活和安全

模拟实现:

#include<assert.h>char*my_strncat(char*dest,constchar*scr,size_tn){assert(dest&&scr);//检擦空指针char*ret=dest;//记录起始位置(返回值)while(*dest)//将dest移到\0的前面{dest++;}while(n--&&*scr)//判断*scr 和 n 是否为\0(否:进入下一次循环,是:结束){*dest++=*scr++;//吧*scr的值赋给*dest;地址分别+1;}*dest='\0';//记得补上\0returnret;}

strncmp函数

intstrncmp(constchar*str1,constchar*str2,size_tnum);

功能:字符串比较;比较 str1 和 str2 指向的两个字符串的内容,最多比较 num 字符。

参数:
str1 :指针,指向一个比较的字符串
str2 :指针,指向另外一个比较的字符串
num :最多比较的字符个数

返回值:
第⼀个字符串大于第二个字符串,则返回大于0的数字
第⼀个字符串等于第二个字符串,则返回0
第⼀个字符串小于第二个字符串,则返回小于0的数字

演示代码:

#include<stdio.h>#include<string.h>intmain(){chararr1[]="abcdef";chararr2[]="abcqw";intret1=strncmp(arr1,arr2,3);printf("%d\n",ret1);intret2=strncmp(arr1,arr2,4);printf("%d\n",ret2);return0;}

strncmp可以比较任意长度。相较于strcmp,strncmp函数更加灵活,更加安全

模拟实现:

intmy_strncmp(constchar*str1,constchar*str2,size_tn){while(*str1==*str2&&*str1&&n--)//如果相等 && 没到\0 && n不为0 进行循环{str1++;str2++;}return*str1-*str2;//返回两个的差值}

strstr函数

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

功能:
strstr 函数,查找 str2 指向的字符串在 str1 指向的字符串中第一次出现的位置。
简而言之:在一个字符串中查找子字符串。

参数:
str1 :指针,指向了被查找的字符串
str2 :指针,指向了要查找的字符串

返回值:
如果str1指向的字符串中存在str2指向的字符串,那么返回第一次出现位置的指针
如果str1指向的字符串中不存在str2指向的字符串,那么返回NULL

代码演示:

#include<stdio.h>#include<string.h>intmain(){charstr[]="This is a simple string";char*pch;pch=strstr(str,"simple");if(pch!=NULL)printf("%s\n",pch);elseprintf("查找的字符串不存在\n");return0;}

模拟实现:(这里使用暴力比对模拟)
到了这里就有点难了,我们先想一下,str1,str2分别指向不同的字符串,如图:

要在str1找str2,就需要不断移动str1,并与str2中的内容进行对比。

如果发现*str1 == *str2时,就需要cp1 = str1指针和cp2 = str2指针向后对比内容,而str1和str2留在原地记录当前位置


当发现*cp1 != *cp2时,就暂时不管它们了,让str1继续往前走

再次发现*str1 = *str2,cp1 = str1指针和cp2 = str2指针向后继续对比内容

走到后面发现cp2 == ‘\0’ 停下来返回str1的地址

思路理清了,接下来写函数吧:

char*my_strstr(constchar*str1,constchar*str2){assert(str1&&str2);//检查空指针if(!*str2)return(char*)str1;//处理str2空字符串的情况while(*str1)//如果*str1 == '\0'直接跳出循环{constchar*cp1=str1;constchar*cp2=str2;//使用cp1和cp2向后检查while(*cp1==*cp2&&*cp1&&*cp2){cp1++;cp2++;}if(*cp2=='\0')//检查到*cp2 == \0(走完字符串str2了)return(char*)str1;//返回地址,结束str1++;//调整变量,进行下一轮检查}returnNULL;}

strtok 函数的使用

char*strtok(char*str,constchar*delim);

功能

  • 分割字符串:根据 delim 参数中指定的分隔符,将输入字符串 str 拆分成多个子字符串。
  • 修改原始字符串: strtok 会直接在原始字符串中插入 ‘\0’ 终止符,替换分隔符的位置,因此原始字符串会被修改。

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

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

使用步骤

  1. 首次调用:传入待分割字符串和分隔符。
  2. 后续调用:传入 NULL 和相同的分隔符,继续分割。
  3. 结束条件:当返回 NULL 时,表示分割完成。

演示代码:

intmain(){chararr[]="192.168.6.111";constchar*sep=".";constchar*str=NULL;charbuf[30]={0};strcpy(buf,arr);//将arr中的字符串拷贝到buf中,对buf的内容进行切割for(str=strtok(buf,sep);str!=NULL;str=strtok(NULL,sep)){printf("%s\n",str);}return0;}

注意事项:

  • 破坏性操作: strtok 会直接修改原始字符串,将其中的分隔符替换为 ‘\0’ 。如果需要保留原
    字符串,应先拷贝一份。
  • 连续分隔符:多个连续的分隔符会被视为单个分隔符,不会返回空字符串。
  • 空指针处理:如果输入的 str 为 NULL 且没有前序调用,行为未定义。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询