【字符串函数内功修炼】strlen + strstr + strtok + strerror(三)

2024-02-16 11:30

本文主要是介绍【字符串函数内功修炼】strlen + strstr + strtok + strerror(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

文章目录

  • 1. strlen - 求字符串长度
    • 🍑 函数介绍
    • 🍑 模拟实现
      • 计数器实现
      • 递归实现
      • 指针实现
  • 2. strstr - 字符串查找
    • 🍑 函数介绍
    • 🍑 模拟实现
  • 3. strtok - 字符串分割
    • 🍑 函数介绍
  • 4. strerror - 错误报告函数
    • 🍑 函数介绍
  • 5. 字符分类函数
    • 🍑 tolower、toupper - 字符转换
  • 🌟. 总结

在这里插入图片描述

1. strlen - 求字符串长度

🍑 函数介绍

size_t strlen(const char* string);

1、字符串已经 \0 作为结束标志,strlen 函数返回的是在字符串中 \0 前面出现的字符个数(不包含 \0 )。

2、参数指向的字符串必须要以 \0 结束。

3、注意函数的返回值为 size_t,也就是无符号的整型。

📝 代码示例

#include <stdio.h>int main()
{int len = my_strlen("abcdef");printf("%d\n", len);return 0;
}

🌟 运行结果

在这里插入图片描述

🍑 模拟实现

计数器实现

📝 代码示例

#include <stdio.h>
#include <assert.h>int my_strlen(const char* str) {assert(str);int cnt = 0;while (*str != '\0') {cnt++;str++;}return cnt;
}int main()
{char str[] = "abcdef";int len = my_strlen(str);printf("%d\n", len);return 0;
}

assert 是断言,判断 str 是不是空指针;

🌟 运行结果

在这里插入图片描述

递归实现

📝 代码示例

#include <stdio.h>
#include <assert.h>int my_strlen(const char* str) {assert(str);if (*str) {return 1 + my_strlen(str + 1);}elsereturn 0;
}int main()
{char str[] = "abcdef";int len = my_strlen(str);printf("%d\n", len);return 0;
}

🌟 运行结果

在这里插入图片描述

指针实现

📝 代码示例

#include <stdio.h>
#include <assert.h>int my_strlen(const char* str) {assert(str);const char* start = str; //记录首元素的地址while (*str != '\0') {str++;}return str - start; //最后一个元素的地址 - 首元素地址 = 中间的元素个数
}//升级版
int my_strlen(char *s)
{char *p = s;while(*p != ‘\0)p++;return p-s;
}int main()
{char str[] = "abcdef";int len = my_strlen(str);printf("%d\n", len);return 0;
}

🌟 运行结果

在这里插入图片描述

2. strstr - 字符串查找

🍑 函数介绍

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

strstr 函数可以在一个字符串(str1)中查找另一个字符串(str2);

如果 str2 存在于 str1 中,那么就返回 str2str1 中第一次出现的起始位置;

如果在 str1 中找不到 str2,那么就返回 空指针NULL)。

它的第一个参数是 str1 的起始位置,第二个参数是 str2 的起始位置。

📝 代码示例

假设我们在字符串 "abcdefabcdef" 中查找字符串 `“bcd”

#include <stdio.h>
#include <string.h>int main()
{char str1[] = "abcdefabcdef";char str2[] = "bcd";char* ret = strstr(str1, str2);if (NULL == ret) {printf("找不到\n");}else {printf("%s\n", ret);}return 0;
}

🌟 运行结果

在这里插入图片描述
strstr 函数的返回值是字符串 "bcd" 在字符串 "abcdefbcd" 中第一次出现的位置的起始位置,而不是出现几次就返回几个起始位置。

🍑 模拟实现

strstr 函数的模拟实现相对复杂,在实现过程中我们需要设置 3 个指针变量来辅助实现函数功能。

cur 指针: 记录每次开始匹配时的起始位置,当从该位置开始匹配时就找到了目标字符串,便于返回目标字符串出现的起始位置;当从该位置开始没有匹配成功时,则从 cur++ 处开始下一次的匹配。

s1s2 指针: 通过判断 s1s2 指针解引用后是否相等来判断每个字符是否匹配成功,若成功,则指针后移比较下一对字符;若失败,s1 指针返回 cur 指针处,s2 指针返回待查找字符串的起始位置。

例如,在字符串 "abbbcdef" 中查找字符串 "bbc"

首先 s1 指向的元素为 as2 指向的元素为 b,此时 s1s2 不相等👇
在这里插入图片描述
cur 指针后移,接着将 cur 指针赋值给 s1 指针,此时,s1 指向的元素为 bs2 指向的元素为 b,则s1s2 匹配成功👇
在这里插入图片描述
那么 cur 指针不动,s1s2 指针后移继续比较,此时,s1 指向的元素为 bs2 指向的元素为 b,则s1s2 匹配成功👇
在这里插入图片描述
那么 cur 指针不动,s1s2 指针后移继续比较,此时,s1 指向的元素为 bs2 指向的元素为 c,则s1s2 不相等👇
在这里插入图片描述
那么 cur 指针向后移一位,s1 返回 cur 指向的位置,s2 返回待查找字符串起始位置👇
在这里插入图片描述
然后开始进行下一轮的匹配,直到当 s2 指向的内容为 \0 时,便说明待查找字符串中的字符已经被找完,也说明了从当前 cur 位置开始匹配能够找到目标字符串,所以此时返回指针 cur 即可。👇
在这里插入图片描述

📝 代码示例

#include <stdio.h>char* my_strstr(const char* str, const char* substr) {const char* s1 = str;const char* s2 = substr;const char* cur = str;assert(str && substr);if (*substr == '\0') {return (char*)str;}while (*cur) {s1 = cur;s2 = substr;//1. 如果 *s1=\0,说明被查找的字符串已经走完了,不可能找到//2. 如果 *s2=\0,说明把字符串已经找完了while ((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2)) {s1++;s2++;}if (*s2 == '\0') {return (char*)cur;}cur++;}// 找不到的情况return NULL;
}int main()
{char str1[] = "abbbcdef";char str2[] = "bbc";char* ret = my_strstr(str1, str2);if (NULL == ret) {printf("找不到\n");}else {printf("%s\n", ret);}return 0;
}

🌟 运行结果

在这里插入图片描述

3. strtok - 字符串分割

🍑 函数介绍

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

strtok 函数能通过给定的一系列字符将一个字符串分割成许多子字符串的函数。

它的第一个参数 str 是需要被分割的字符串的首地址;

第二个参数 sep 是一个字符串的首地址,该字符串是用作分隔符的字符集合。

返回值是查找到的标记的首地址。

注意:

1、sep 参数是个字符串,定义了用作分隔符的字符集合

2、第一个参数指定一个字符串,它包含了 0 个或者多个由 sep 字符串中一个或者多个分隔符分割的标记。

3、strtok 函数找到 str 中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。

(注:strtok 函数会改变被操作的字符串,所以在使用 strtok 函数切分的字符串一般都是临时拷贝的内容并且可修改。)

4、strtok 函数的第一个参数不为 NULL ,函数将找到 str 中第一个标记,strtok 函数将保存它在字符串中的位置。

5、strtok 函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。

6、如果字符串中不存在更多的标记,则返回 NULL 指针。

📝 代码示例

假设我们要将字符串 "edisonchen@gmail.com""@" 字符和 "." 字符分割开

int main()
{const char* p = "@."; //分隔符的字符集合char arr[] = "edisonchen@gmail.com"; //待分割字符串char buf[50] = { 0 };strcpy(buf, arr);//将数据拷贝一份使用,防止原数据被修改char* str = NULL;str = strtok(buf, p); //第一次传参需传入待分割字符串首地址while (str != NULL) { //说明还未分割完printf("%s\n", str); //打印标记str = strtok(NULL, p); //对同一个字符串进行分割,第二次及以后的第一个参数为NULL}return 0;
}

🌟 运行结果

在这里插入图片描述
strtok 函数找到第一个标记时,将其后的 @ 字符改为 \0 并返回第一个标记的首地址,所以我们以返回的地址为首地址,开始打印字符串的时候就只会打印出 edisonchen,第二次再对该字符串调用 strtok 函数时将从 @ 字符后面开始寻找下一个标记。
在这里插入图片描述

4. strerror - 错误报告函数

🍑 函数介绍

char* strerror(int errnum);

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

📝 代码示例

我们可以先来看一下,就那些错误信息

#include <stdio.h>
#include <string.h>int main()
{int i = 0;for (i = 0; i < 10; ++i) {printf("%s\n", strerror(i));}return 0;
}

🌟 运行结果

在这里插入图片描述

但是在实际过程中肯定不可能把所有的错误代码全部打印出来,举个栗子👇

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

那么我们假设使用 fopen 打开一个不存在的文件,然后用 strerror 来显示报错信息👇

📝 代码示例

#include<stdio.h>
#include<string.h>
#include<errno.h>int main()
{FILE* pf = fopen("test.txt", "r");if (NULL == pf) {//出错误的原因是什么printf("%s\n", strerror(errno));return 0;}//读文件//...//关闭文件fclose(pf);pf = NULL;return 0;
}

🌟 运行结果

在这里插入图片描述
当我们要打开一个不存在的文件(test.txt)来阅读的时候,显然 fopen 函数会执行失败,于是 pf 指针接收的便是空指针(NULL);
 
当库函数使用的时候,如果发生错误,会把 errno 这个全局的错误变量设置为本次执行库函数产生的错误码;
 
errnoC 语言提供的一个全局变量,可以直接使用,放在 errno.h 文件中的。

5. 字符分类函数

如下表👇
在这里插入图片描述

🍑 tolower、toupper - 字符转换

这里以 tolowertoupper 为例,其他的不过多讲解

📝 代码示例

大小写互相转换

#include <stdio.h>
#include <ctype.h>int main()
{char ch = 0;ch = getchar();if (islower(ch)) {ch = toupper(ch);}else {ch = tolower(ch);}printf("%c\n", ch);return 0;
}

🌟 运行结果

大写转小写👇
在这里插入图片描述
小写转大写👇
在这里插入图片描述

📝 代码示例

str 字符串转换成小写

#include <stdio.h>
#include <ctype.h>int main()
{int i = 0;char str[] = "HELLO WORLD\n";char c;while (str[i]){c = str[i];if (isupper(c)) {c = tolower(c);}putchar(c);i++;}return 0;
}

🌟 运行结果

在这里插入图片描述

🌟. 总结

以上就是我们 C 语言中常用的字符和字符串库函数,其实理解起来不难,重要是多加使用练习😛

这篇关于【字符串函数内功修炼】strlen + strstr + strtok + strerror(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/714391

相关文章

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

函数式编程思想

我们经常会用到各种各样的编程思想,例如面向过程、面向对象。不过笔者在该博客简单介绍一下函数式编程思想. 如果对函数式编程思想进行概括,就是f(x) = na(x) , y=uf(x)…至于其他的编程思想,可能是y=a(x)+b(x)+c(x)…,也有可能是y=f(x)=f(x)/a + f(x)/b+f(x)/c… 面向过程的指令式编程 面向过程,简单理解就是y=a(x)+b(x)+c(x)

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

利用matlab bar函数绘制较为复杂的柱状图,并在图中进行适当标注

示例代码和结果如下:小疑问:如何自动选择合适的坐标位置对柱状图的数值大小进行标注?😂 clear; close all;x = 1:3;aa=[28.6321521955954 26.2453660695847 21.69102348512086.93747104431360 6.25442246899816 3.342835958564245.51365061796319 4.87

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使用了由[90]描述的第一个算法。开发者应该注意,由于数据点靠近包含的 Mat 元素的边界,返回的椭圆/旋转矩形数据

Unity3D 运动之Move函数和translate

CharacterController.Move 移动 function Move (motion : Vector3) : CollisionFlags Description描述 A more complex move function taking absolute movement deltas. 一个更加复杂的运动函数,每次都绝对运动。 Attempts to

✨机器学习笔记(二)—— 线性回归、代价函数、梯度下降

1️⃣线性回归(linear regression) f w , b ( x ) = w x + b f_{w,b}(x) = wx + b fw,b​(x)=wx+b 🎈A linear regression model predicting house prices: 如图是机器学习通过监督学习运用线性回归模型来预测房价的例子,当房屋大小为1250 f e e t 2 feet^

JavaSE(十三)——函数式编程(Lambda表达式、方法引用、Stream流)

函数式编程 函数式编程 是 Java 8 引入的一个重要特性,它允许开发者以函数作为一等公民(first-class citizens)的方式编程,即函数可以作为参数传递给其他函数,也可以作为返回值。 这极大地提高了代码的可读性、可维护性和复用性。函数式编程的核心概念包括高阶函数、Lambda 表达式、函数式接口、流(Streams)和 Optional 类等。 函数式编程的核心是Lambda

C和指针:字符串

字符串、字符和字节 字符串基础 字符串就是一串零个或多个字符,并且以一个位模式为全0的NUL字节结尾。 字符串长度就是字符串中字符数。 size_t strlen( char const *string ); string为指针常量(const修饰string),指向的string是常量不能修改。size_t是无符号数,定义在stddef.h。 #include <stddef.h>