C语言——笔试题常考:字符函数的功能和模拟实现
本文介绍了C语言中常用的字符串处理函数包括字符分类如isdigit、字符转换如tolower、toupper、strlen、strcpy、strcat、strcmp及strncpy等。这些函数均在标准库头文件中定义用于判断字符类型、转换大小写、统计长度、拷贝、追加、比较和安全复制字符串。文中通过代码示例与模拟实现详细说明了各函数的使用方法、注意事项及底层逻辑帮助理解字符串操作的核心机制。一、字符分类函数作用字符分类函数用于对不同的字符类型进行分类。简单来说就是判断字符是否是我们想要的类型。头文件ctype.h使用方法以 isdigit 为例intisdigit(intc);参数c为需要判断的字符如果是上图函数对应类型的字符返回真反之返回假。如intiisdigit(0);//返回真intjisdigit(a);//返回假模拟实现intmy_isdigit(intc){if(c0c9)return1;//是对应类型的字符返回真elsereturn0;//不是对应类型的字符返回假}二、字符转换函数字符转换函数有以下两个inttolower(intc);//将参数传进去的⼤写字母转⼩写inttoupper(intc);//将参数传进去的小写字母转⼤写其实将大写转为小写就是完成32的效果将小写转为大写就是完成-32的效果A的ascll码为65a的ascll码为97。如#includestdio.h#includectype.hintmain(){inti0;charstr[]Test String.\n;charc;while(str[i]){cstr[i];if(islower(c))//判断是否为小写字母ctoupper(c);//-32putchar(c);i;}return0;}模拟实现intmy_toupper(intc){returnc-32;}三、strlen函数(以下函数均在string.h中)形式size_tstrlen(constchar*str);作用统计字符串的长度。准确来说是统计从给定指针到 ‘\0’ 的字符个数不算 ‘\0’ 。参数str 要统计字符串的起始地址。返回值字符个数不算 ‘\0’代码演示#includestdio.h#includestring.hintmain(){constchar*strabcdef;//创建一个长度为6的字符串printf(%zd\n,strlen(str));//调用strlen函数return0;}注意事项字符串末尾必须包含 ‘\0’否则返回值为为随机值统计个数时不包含 ‘\0’ 字符模拟实现方式1计数器形式#includestdio.h#includeassert.hsize_tmy_strlen(constchar*str){assert(str);size_tcount0;while(*str)//遇到\0停止{str;count;//每统计一个字符计数器1}returncount;}方式2指针 - 指针 形式#includeassert.hsize_tmy_strlen(constchar*str){assert(str);//检查空指针constchar*startstr;//记录起始地址while(*str)//遇到\0停止{str;}returnstr-start;//结束地址 - 起始地址}方式3递归size_tmy_strlen(constchar*str){assert(str);//检查空指针//*str不为\0的话就继续检擦下一个if(*str){str1;returnmy_strlen(str)1;//回归时返回值}//*str是\0的话返回0开始回归elsereturn0;}四、strcpy函数形式char*strcpy(char*destination,constchar*source);作用字符拷贝直到遇到 ‘\0’ 。参数destination指向目的地空间的指针source指向拷贝源头的指针返回值目的地空间的起始地址注意事项源字符串必须以 ‘\0’ 结束。会将源字符串中的 ‘\0’ 拷贝到目标空间。目标空间必须足够大以确保能存放源字符串。目标空间必须可修改。代码演示#includestdio.h#includestring.hintmain(){chararr1[10]{0};chararr2[]hello;strcpy(arr1,arr2);printf(%s\n,arr1);return0;}模拟实现char*my_strcpy(char*dest,constchar*scr){assert(destscr);//检擦空指针char*retdest;//记录起始位置(返回值)while(*dest*scr);//先吧*scr的值赋给*dest地址分别1//判断*scr是否为\0否进入下一次循环是结束returnret;}五、strcat函数形式char*strcat(char*destination,constchar*source);作用字符串追加把 source 指向的源字符串中的所有字符都追加到 destination 指向的空间中。参数destination 指针指向目的地空间source 指针指向源头数据返回值strcat 函数返回的目标空间的起始地址注意事项源字符串必须以 ‘\0’ 结束。目标字符串中也得有 \0 否则没办法知道追加从哪里开始。目标空间必须有足够的大能容纳下源字符串的内容目标空间必须可修改。代码演示:#includestdio.h#includestring.hintmain(){chararr1[20]hello ;chararr2[]world;strcat(arr1,arr2);printf(%s\n,arr1);return0;}模拟实现:char*my_strcat(char*dest,constchar*scr){assert(destscr);//检擦空指针char*retdest;//记录起始位置(返回值)while(*dest)//将dest移到\0的前面{dest;}while(*dest*scr);//先吧*scr的值赋给*dest地址分别1//判断*scr是否为\0否进入下一次循环是结束returnret;}六、strcmp函数形式功能用来比较 str1 和 str2 指向的字符串从两个字符串的第一个字符开始比较如果两个字符的ASCII码值相等就比较下⼀个字符。直到遇到不相等的两个字符或者字符串结束。参数str1 指针指向要比较的第一个字符串str2 指针指向要比较的第二个字符串返回值第一个字符串大于第二个字符串则返回大于0的数字第一个字符串等于第二个字符串则返回0第一个字符串小于第二个字符串则返回小于0的数字演示代码#includestdio.h#includestring.hintmain(){chararr1[]abcdef;chararr2[]abq;intretstrcmp(arr1,arr2);printf(%d\n,ret);if(ret0)printf(arr1 arr2\n);elseif(ret0)printf(arr1 arr2\n);elseprintf(arr1 arr2\n);return0;}模拟实现intmy_strcmp(constchar*str1,constchar*str2){assert(str1str2)//检查空指针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 函数返回的目标空间的起始地址代码演示:#includestdio.h#includestring.hintmain(){chararr1[20]{0};chararr2[]abcdefghi;char*strstrncpy(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(destscr);//检擦空指针char*retdest;//记录起始位置(返回值)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 最多追加的字符的个数返回值返回的是目标空间的起始地址代码演示#includestdio.h#includestring.hintmain(){chararr1[20]hello ;chararr2[]world;char*strstrncat(arr1,arr2,5);printf(%s\n,arr1);printf(%s\n,str);return0;}注意事项strncat 函数在源字符串中遇到 \0 会自动停止strncat 函数无论如何都会自动在字符串后面补\0目标空间必须足够大以确保能存放源字符串。目标空间必须可修改。相较于 strcatstrncat 更加灵活和安全模拟实现#includeassert.hchar*my_strncat(char*dest,constchar*scr,size_tn){assert(destscr);//检擦空指针char*retdest;//记录起始位置(返回值)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的数字演示代码#includestdio.h#includestring.hintmain(){chararr1[]abcdef;chararr2[]abcqw;intret1strncmp(arr1,arr2,3);printf(%d\n,ret1);intret2strncmp(arr1,arr2,4);printf(%d\n,ret2);return0;}strncmp可以比较任意长度。相较于strcmpstrncmp函数更加灵活更加安全模拟实现intmy_strncmp(constchar*str1,constchar*str2,size_tn){while(*str1*str2*str1n--)//如果相等 没到\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代码演示#includestdio.h#includestring.hintmain(){charstr[]This is a simple string;char*pch;pchstrstr(str,simple);if(pch!NULL)printf(%s\n,pch);elseprintf(查找的字符串不存在\n);return0;}模拟实现这里使用暴力比对模拟到了这里就有点难了我们先想一下str1str2分别指向不同的字符串如图要在str1找str2就需要不断移动str1并与str2中的内容进行对比。如果发现*str1 *str2时就需要cp1 str1指针和cp2 str2指针向后对比内容而str1和str2留在原地记录当前位置当发现*cp1 ! *cp2时就暂时不管它们了让str1继续往前走再次发现*str1 *str2cp1 str1指针和cp2 str2指针向后继续对比内容走到后面发现cp2 ‘\0’ 停下来返回str1的地址思路理清了接下来写函数吧char*my_strstr(constchar*str1,constchar*str2){assert(str1str2);//检查空指针if(!*str2)return(char*)str1;//处理str2空字符串的情况while(*str1)//如果*str1 \0直接跳出循环{constchar*cp1str1;constchar*cp2str2;//使用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。使用步骤首次调用传入待分割字符串和分隔符。后续调用传入 NULL 和相同的分隔符继续分割。结束条件当返回 NULL 时表示分割完成。演示代码intmain(){chararr[]192.168.6.111;constchar*sep.;constchar*strNULL;charbuf[30]{0};strcpy(buf,arr);//将arr中的字符串拷贝到buf中对buf的内容进行切割for(strstrtok(buf,sep);str!NULL;strstrtok(NULL,sep)){printf(%s\n,str);}return0;}注意事项破坏性操作 strtok 会直接修改原始字符串将其中的分隔符替换为 ‘\0’ 。如果需要保留原字符串应先拷贝一份。连续分隔符多个连续的分隔符会被视为单个分隔符不会返回空字符串。空指针处理如果输入的 str 为 NULL 且没有前序调用行为未定义。