文章目录

  • 一、strlen - 求字符串长度
    • 1.函数介绍
    • 2.模拟实现(三种方式)
  • 二、strstr - 字符串查找
    • 1.函数介绍
    • 2.模拟实现
  • 三、strtok - 字符串分割
  • 四、strerror、perror - 错误报告函数
    • 1.strerror
    • 2.perror

一、strlen - 求字符串长度

1.函数介绍

size_t strlen( const char *string );

strlen函数是一个用于求字符串长度的库函数。它的参数是被求长度的字符串的起始地址,返回值是一个无符号整型。
注意:

  • 参数指向的字符串要以’\0’结束。
  • strlen返回的是在字符串中’\0’之前出现的字符个数(不包含’\0’)。
  • 注意函数的返回值为size_t,是无符号的(易错)。

举个例子,比如我们要求字符串"abcdef"的长度。

#include<stdio.h>
#include<string.h>
int main()
{char arr[] = "abcdef";size_t ret = strlen(arr);return 0;
}

数组arr的数组名就是该数组的起始地址,我们定义一个size_t型的变量ret便能接收函数的返回值,结果是6。

2.模拟实现(三种方式)

方式一:计数器的方式
我们定义一个变量为count,如果传入的指针指向的内容不是’\0’,那么count++,同时指针后移一位,循环往复,直到找到’\0’时返回count即可。

size_t my_strlen1(const char* str)
{size_t count = 0;//计数器while (*str){count++;str++;}return count;
}

方式二:递归的方式
我们一进入函数体就判断传入指针指向的内容是否为’\0’,如果是就返回0,不是就返回1+my_strlen2(str+1),如此进行下去,直到递归到内层时找到’\0’,这时再一步步将值返回回来即可。

size_t my_strlen2(const char* str)
{if (*str == '\0')return 0;elsereturn 1 + my_strlen2(str + 1);
}

方式三:指针-指针的方式
进入函数体时,我们事先定义一个指针变量将传入的指针保存下来,然后将传入的指针向后移,直到遇到’\0’时,我们返回当前指针与保存的指针的差值即可。(指针与指针的差的绝对值是两个指针之间的元素个数)

size_t my_strlen3(const char* str)
{const char* p = str;//保存起始位置while (*str != '\0')str++;return str - p;
}

二、strstr - 字符串查找

1.函数介绍

char *strstr( const char *string, const char *strCharSet );

strstr函数可以在一个字符串(字符串1)中查找另一个字符串(字符串2),如果字符串2存在于该字符串1中,那么就返回被字符串2在字符串1中第一次出现的起始位置,如果在字符串1中找不到字符串2,那么就返回空指针(NULL)。它的第一个参数是字符串1的起始位置,第二个参数是字符串2的起始位置。
注意:

  • 若字符串2为空字符串,则返回字符串1的起始位置。

举个例子,比如我们在字符串"abcdefbcd"中查找字符串"bcd"。

#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = "abcdefbcd";char arr2[] = "bcd";char* ret = strstr(arr1, arr2);//在arr1中查找arr2字符串第一次出现的位置if (ret != NULL)printf("%s\n", ret);elseprintf("找不到\n");return 0;
}

注意:strstr函数的返回值是字符串"bcd"在字符串"abcdefbcd"中第一次出现的位置的起始位置,而不是出现几次就返回几个起始位置。

2.模拟实现

strstr函数的模拟实现相对复杂,在实现过程中我们需要设置3个指针变量来辅助实现函数功能。
cp指针: 记录每次开始匹配时的起始位置,当从该位置开始匹配时就找到了目标字符串,便于返回目标字符串出现的起始位置;当从该位置开始没有匹配成功时,则从cp++处开始下一次的匹配。
p1和p2指针: 通过判断p1和p2指针解引用后是否相等来判断每个字符是否匹配成功,若成功,则指针后移比较下一对字符;若失败,p1指针返回cp指针处,p2指针返回待查找字符串的起始位置。

例如,在字符串"abbbcdef"中查找字符串"bbc":
刚刚开始时3个指针的指向如图所示:

若p1与p2匹配不成功,则cp指针后移,接着将cp指针赋值给p1指针:

此时,p1与p2匹配成功,那么cp指针不动,p1和p2指针后移继续比较:

当p1与p2匹配不成功时,cp指针后移一位,p1返回cp位置,p2返回待查找字符串起始位置:

从此位置开始下一轮的比较:

直到当p2指向的内容为\0时,便说明待查找字符串中的字符已经被找完,也说明了从当前cp位置开始匹配能够找到目标字符串,所以此时返回指针cp即可。

char* my_strstr(const char* str1, const char* str2)
{assert(str1 != NULL);//断言,当str1为空指针报错assert(str2 != NULL);//断言,当str2为空指针报错const char* cp = str1;//记录开始匹配时的起始位置if (*str2 == '\0')//要查找的字符串为空字符串return (char*)str1;while (*cp){const char* p1 = cp;const char* p2 = str2;while ((*p1!='\0') && (*p2!='\0') && (*p1 == *p2)){p1++;p2++;}if (*p2 == '\0')//目标字符串已被查找完return (char*)cp;cp++;}return NULL;//找不到目标字符串
}

三、strtok - 字符串分割

char *strtok( char *strToken, const char *strDelimit );

strtok函数能通过给定的一系列字符将一个字符串分割成许多子字符串的函数。它的第一个参数是需要被分割的字符串的首地址;第二个参数是一个字符串的首地址,该字符串是用作分隔符的字符集合。返回值是查找到的标记的首地址。
注意:

  • strtok函数找到strToken中的一个标记时,会将其用 \0结尾并返回这个标记的首地址。
  • strtok函数会改变strToken函数,所以在使用strtok函数切分的字符串都是临时拷贝的内容并且可修改。
  • strtok函数的第一个参数不为NULL时,函数将找到strToken中的第一个标记,并保存它在字符串中的位置。
  • strtok函数的第一个参数为NULL时,函数将从同一个字符串中被保存的位置开始查找它的下一个标记。
  • 若字符串中不存在更多的标记,则返回NULL指针。

举个例子,比如我们要将字符串"2957055542@qq.com"以"@“字符和”."字符分割开。

#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = "2957055542@qq.com";//待分割字符串char arr2[] = "@.";//分隔符的字符集合char arr3[20] = { 0 };strcpy(arr3, arr1);//将数据拷贝一份使用,防止原数据被修改char* token = strtok(arr3, arr2);//第一次传参需传入待分割字符串首地址while (token != NULL)//说明还未分割完{printf("%s\n", token);token = strtok(NULL, arr2);//对同一个字符串进行分割,第二次及以后的第一个参数为NULL}return 0;
}


注意:当strtok函数找到第一个标记时,将其后的’@‘字符改为’\0’并返回第一个标记的首地址,所以我们以返回的地址为首地址开始打印字符串的时候就只会打印出2957055542,第二次再对该字符串调用strtok函数时将从’@'字符后面开始寻找下一个标记。

四、strerror、perror - 错误报告函数

1.strerror

char *strerror( int errnum );

strerror函数可以把错误码转换为对应的错误信息,返回错误信息对应字符串的起始地址。

2.perror

void perror( const char *string );

perror函数可以打印一个错误信息,无返回值。

我们需要知道,库函数在使用的时候如果发生错误,都会有对应的错误码,而这些错误码都会被存放在errno这个全局变量中,如果要使用这个全局变量,我们需要引其对应的头文件:#include<errno.h>

举个例子:
注:fopen函数的功能是打开一个文件,当其执行成功时会返回打开文件的首地址,执行失败时会返回一个空指针(NULL)。

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{FILE* pf = fopen("test.txt", "r");//打开test.txt文件阅读if (pf == NULL){printf("%s\n", strerror(errno));perror("fopen");}return 0;
}


当我们要打开一个不存在的文件(test.txt)来阅读的时候,显然fopen函数会执行失败,于是pf指针接收的便是空指针(NULL)。
strerror: 只负责将错误码转换为对应的错误信息,不打印。
perror: 直接打印错误信息,并且我们可以自己加上注释来明确错误来源于哪个库函数。

字符串函数中的求长度、查找、分割和错误报告函数(strlen,strstr,strtok,strerror)相关推荐

  1. strlen strstr strtok strerror 函数解析及模拟实现

    文章目录 一.strlen 求字符串长度 1.函数介绍 2.模拟实现(三种方式) 二.strstr 字符串查找 1.函数介绍 2.模拟实现 三.strtok 字符串分割 四.strerror perr ...

  2. C语言试题三十一之判断字符串是否为回文?若是则函数返回1,主函数中输出yes,否则返回0,主函数中输出no。回文是指顺读和倒读都是一样的字符串。

    1. 题目 请编写函数function,该函数的功能是:判断字符串是否为回文?若是则函数返回1,主函数中输出yes,否则返回0,主函数中输出no.回文是指顺读和倒读都是一样的字符串. 2 .温馨提示 ...

  3. 写一个在一个字符串(n)中寻找一个子串(m)第一个位置的函数。

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...

  4. c程序:定义函数areaZ,功能是求圆锥体积。在主函数中输入半径r和高h,调用函数areaZ求体积,并在主函数中输出圆锥的体积,其中变量r,h均为double型数据。(公式v=h*3.14*r2/3)

    /*定义函数areaZ,功能是求圆锥体积.在主函数中输入半径r和高h,调用函数areaZ求体积,并在主函数中输出圆锥的体积,其中变量r,h均为double型数据.(公式v=h*3.14*r2/3)*/ ...

  5. R语言ggplot2可视化散点图(scatter plot)、aes函数中的fill参数为连续变量、使用scale_fill_distiller函数自定义指定连续变量的颜色填充方案

    R语言ggplot2可视化散点图(scatter plot).aes函数中的fill参数为连续变量.使用scale_fill_distiller函数自定义指定连续变量的颜色填充方案 目录

  6. SKB中的各种长度、数据指针和操作函数

    skb结构体中的长度和数据指针 len: 线性区和分片区域的总长度 data_len:分片区域frag page中的数据长度 len-data_len: 当前协议层中的线性区长度 head:线性区的起 ...

  7. matlab中函数求导 求反,关于一个函数的反函数求导问题,一个超复杂函数……急啊!...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 我在做课设,现在时间很紧了-- 关于一个函数的反函数求导问题,用matlab弄出来的超复杂函数-- 函数的大概形式是:L_bc=f(k); 我想求的是:k ...

  8. python展开 c函数中的宏预处理_最基本的宏函数 课后习题9.2 (C语言代码)

    解题思路 利用宏函数. 函数. 本题的难点肯定不在算法, 应该是宏函数! 带参宏定义的一般形式为:#define 宏名(形参表) 字符串; 在字符串中含有各个形参. 带参宏调用的一般形式为: #def ...

  9. matlab求反函数的函数,关于一个函数的反函数求导问题,一个超复杂函数……急啊!...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 我在做课设,现在时间很紧了-- 关于一个函数的反函数求导问题,用matlab弄出来的超复杂函数-- 函数的大概形式是:L_bc=f(k); 我想求的是:k ...

最新文章

  1. c语言输入身高计算标准体重_女人身高165cm标准体重是多少?
  2. web项目获取运行时...\WEB-INF\classes目录下文件
  3. extjs 限制上传文件类型_如何让extjg 支持选择多文件上传
  4. skynet给集群中的一个节点配置多个通道
  5. .htaccess伪静态实例记录
  6. matlab光学远轴光的折射,光学课后习题
  7. java虚拟内存扩展_Java 8虚拟扩展方法
  8. Linux 命令之 killall 命令-使用进程的名称来杀死一组进程
  9. 如何落地云原生DevOps?
  10. linux 虚拟机添加网卡
  11. 【英语天天读】Man's Youth
  12. ubuntu没有进入图形界面解决办法
  13. python map函数filter函数 day16
  14. 13. Zigbee应用程序框架开发指南 - 多网络支持
  15. 台式计算机未识别网络,台式机显示未识别网络怎么办
  16. 基于vue2全家桶实现的,仿移动端QQ
  17. IDEA 在hdfs中创建目录
  18. Docker学习之三:docker镜像管理
  19. Windows日志分析(中)
  20. 计算机bios无法进入,启动系统后无法进入BIOS怎么办

热门文章

  1. Java学到什么程度才能叫精通?
  2. web前端学习(四):基于koa的EggJs框架,优雅而又完美的Nodejs框架
  3. JAVA并发编程-synchronized-脏读
  4. 送外卖真的能够做到月入过万吗?
  5. 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(5)有趣的指针
  6. 130个微信小程序源码资源免费领取
  7. 【English】十大词性之连词
  8. css实现网页背景图片位置不随滚动条改变
  9. 2019海南大学计算机研究生分数线,2021海南大学研究生分数线一览表(含2019-2020历年复试)...
  10. 零基础学习python第一课总结