【C语言】字符函数与字符串函数(下)

devtools/2024/9/23 9:58:31/

字符函数与字符串函数(下)

文章目录

  • 字符函数与字符串函数(下)
  • 1.tsrncpy的使用和模拟实现
    • 1.1使用示例:
    • 1.2模拟实现
  • 2.strncat的使用和模拟实现
    • 2.1使用示例:
    • 2.2模拟实现
  • 3.strncmp的使用和模拟实现
    • 3.1使用示例:
    • 3.2模拟实现
  • 4.strstr函数
    • 4.1使用示例:
    • 4.2模拟实现
  • 5.strtok函数
    • 5.1示例;
  • 6.strerror函数
  • 6.1示例:
    • 6.2额外补充


1.strncpy的使用和模拟实现
2.strncat的使用和模拟实现
3.strncmp的使用和模拟实现
4.strstr的使用和模拟实现
5.strset函数
6.strerror函数

在上一篇文章中学习了strcpy,strcat,strcmp,这一篇接着上篇继续介绍

1.tsrncpy的使用和模拟实现

在这里插入图片描述

strncpy实在strcpy的基础上可以限制拷贝过去字符的个数

函数声明:

char* strncpy(char* destination, char* source, size_t num);

注意事项:

如果源字符串的长度小于num个,则拷贝完源字符串后,在目标后面追加0,直到num个

1.1使用示例:

int main()
{char s[20] = { 0 };char a[6] = "world";strncpy(s, a, 10);printf("%s", s);return 0;
}

在这里插入图片描述

1.2模拟实现

char* my_strncpy(char* s, char* a, size_t num)
{char* m = s;//记录目标空间的初始位置int count = 0;while (count <= num){*s++ = *a++;count++;}printf("%s", m);
}
int main()
{char s[20] = { 0 };char a[15] = "hello world";my_strncpy(s, a, 8);return 0;
}

2.strncat的使用和模拟实现

在这里插入图片描述
strncat是可以指定在目标空间追加规定个字符,再追加一个’\0’.

注意事项:

如果源字符串的长度小于num的个数,只会将源字符串’\0’之前的内容追加到目标空间

函数声明:

char* strncat(char* destination, char* source, size_t num);

2.1使用示例:

int main()
{char s[20] = "hello ";char a[10] = "world";strncat(s, a, 3);printf("%s", s);return 0;
}

2.2模拟实现

char* my_strncat(char* s, char* a, size_t num)
{char* m = s;int count = 1;while (*s){s++;}while(count<=num){*s++ = *a++;count++;}printf("%s", m);
}
int main()
{char s[20] = "hello ";char a[10] = "world";my_strncat(s, a, 3);return 0;
}

在这里插入图片描述

3.strncmp的使用和模拟实现

在这里插入图片描述
比较str1和str2的前num个字符,如果相等,就继续向后比较,最多比较num个字符,如果提前找到不同,就提前结束,大的所在字符大于零一个字符;如果num个字符都相等,就返回0;

函数声明:

int strncmp(const char* str1,const char*str2,size_t num);

3.1使用示例:

int main()
{char s[10] = "abcdef";char a[10] = "abcdeg";int ret = strncmp(s, a, 5);printf("%d", ret);return 0;
}

3.2模拟实现

char* my_strncmp(char* s, char* a, size_t num)
{int count = 0;while (*s == *a)//注意这里如果是一个等号的话,就相当于把*a的值赋给了*s{s++;a++;count++;if (*s == '\0' || count==num)return 0;}return *s - *a;
}
int main()
{char s[10] = "abcdef";char a[10] = "abcdeg";int ret=my_strncmp(s, a, 5);printf("%d", ret);return 0;
}

4.strstr函数

在这里插入图片描述
函数声明:

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

在上边的图片中很容易知道该函数的返回值,同时,在strstr函数中,字符串的匹配不包含’\0’,以’\0’作为结束标志。

4.1使用示例:

int main()
{char str[30] = "This is a simple string";char* pch = 0;//创建一个指针接受strstr的返回值pch = strstr(str, "simple");strncpy(pch, "sample", 6);printf("%s",str);return 0;
}

在这里插入图片描述
到这一点代码都还是很容易理解的

4.2模拟实现

在这里插入图片描述
分析:

很明显,看图首先我们先创建了一个指针变量m来记录str1的初始位置,方便后边找到他和使用他
然后我们想找到str1中是否含有str2,那就要一个一个字符进行对比,如果是str1=‘abcdef’,str2=‘bcde’,那很容易找到

复杂一点的情况就是出现如图所示的情况,当我们对比一半的时候发现出现不一样了

那怎末解决呢?
确定一个对比的起点,从这个起点开始一一比较,不符合,向后走,再以后一个字符作为比较的起点

因此我们又创建了两个指针变量,e1 和e2,首先以e1为起点,从e2开始一点点比较,出现不符合时,e1向后移一位,作为起点,e2重新开始与以e1+1为起点的字符串开始一一比较

char* my_strstr(const char* a, const char* b)
{char* m = a;char* e1;//记录a开始比较的位置char* e2;//记录b开机比较的位置if (!*b)return a;//排除掉b是空指针的情况,如果是空指针返回awhile (*m){e1 = m;//一个一个位置开始比较e2 = b;while (*e1 && *e2 && *e1 == *e2)//确保*e1和*e2都不为空{e1++;e2++;}if (*e2 == '\0')//说明找到了str2最后的位置,此时的m的位置就是str2首次出现的位置return m;m++;//当出现不同,并且也没有走到str2的最后时,说明此时的起点不对,向后移一位在开始一个一个比较}return (NULL);//当m一直向后走寻找新的起点,一直都没找到时返回空指针
}
int main()
{char a[20] = "aaabcdef";char b[10] = "aabcdd";char* pch=my_strstr(a, b);if (pch != (NULL))printf("有");elseprintf("无");return 0;
}

在这里插入图片描述
上边给的代码例子就是当我们以第二个a为起点的时候,找到最后发现不同的情况

5.strtok函数

在这里插入图片描述
函数声明;

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

上面图片的解释可能不太好理解,再来解析一下这个函数的用法
sep这个参数它指向了一个字符串,定义了一个用作分隔符的字符集合

str指定一个字符串,它包含了0个或多个sep中一个或多个分隔符分割的标志

strtok找到str中的下一个标记,并将其用’\0\结尾,返回一个指向这个标记的指针
需要注意的是,strtok函数会改变str字符串的内容,所以被分割的字符串通常是临时拷贝的,且可以修改的

strtok的第一个参数不是空指针时,函数将找到str中的第一个标记,并保存他在字符串中的位置

strtokd的第一个参数是空指针时,函数在同一字符串被保存的位置开始,找下一个标记

如果不再存在更多的标记,返回空指针

5.1示例;

int main()
{char s[100] = "123.4.56";char* sep = ".";char* str = NULL;for (str = strtok(s, sep); str != NULL; str = strtok(NULL, sep))//初始化先找到第一个标记,调整部分是第一个参数是空指针,就在标记的地方继续找下一个标记//条件是str不是空指针,因为如果找不到下一个标记,就会返回空指针{printf("%s\n", str);}return 0;
}

在看一个,理解一下

int main()
{char s[100] = "_this,a simple thing";char* pch;printf("Splitting string\"%s\"into tokens\n", s);//先把字符串s 加进来输出pch = strtok(s, "_, ");//先找到第一个标记,这里设置的间隔标记有三个分别是- ,和空格注意'\0'不能做分隔符,读到'\0'字符串就结束了while (pch != NULL){printf("%s\n", pch);pch = strtok(NULL, "_, ");//从上一次标记开始向后找到下一个标记}return 0;
}

理解完上边的例子,下边这个就很容易理解了

int main()
{char s[20] = "hello,wor\0ld";char* pch;for (pch = strtok(s, ",\0"); pch != NULL; pch = strtok(NULL, ",\0")){printf("%s", pch);//输出hellowor}return 0;
}

6.strerror函数

char* strerror(int errnum);

strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来

注意:

1.不同的系统和c语言标准库都规定了一些错误码,一般是放在<errno.h>这个头文件
2.C语言使用一个全局变量errno来记录程序的当前错误,程序启动时errno为0;表示没有错误
3.当使用标准库函数发生错误时,就会将对应的错误码放在errno中,strerror函数就可以把错误对应的错误信息字符串的地址返回

6.1示例:

#include<errno.h>
int main()
{//printf(strerror(errno));int i = 0;for (i = 0; i <= 10; i++){printf("%s\n", strerror(i));//展示出可能出现的错误的原因}return 0;
}

在这里插入图片描述
写一个代码看看他是怎么使用的

int main()
{FILE* pFile;//声明了一个指向FILE类型的指针pFile,用于文件操作pFile = fopen("unexit.ent", "r");//使用fopen函数尝试以只读模式('r')打开名为unexit.ent的文件,并返回文件的指针赋值给pFile;if (pFile == NULL)//判断文件是否为空,若为空打开失败,输出失败的原因{printf("error opening file unexit.ent:%s\n", strerror(errno));//这个失败的原因是我根本就没有这个文件}return 0;
}

在这里插入图片描述

6.2额外补充

也可以了解一下perror函数
他相当于一次把打印和调用strerror函数完成了,将直接把错误信息打印出来,并且在他打印完参数后,会打印一个冒号和空格再打印错误信息

int main()
{FILE* pFile;pFile = fopen("unexit.ent", "r");if (pFile == NULL){perror("error opening file unexit.ent");//这个失败的原因是我根本就没有这个文件}return 0;
}

在这里插入图片描述

作者有话说:作者只是一直刚学的小白,以上理解均是作者学习完后对知识的理解,如有错误和不当,感谢指出,如感到有帮助,请留下一个👍


http://www.ppmy.cn/devtools/97282.html

相关文章

【一文详解】内外网文件摆渡系统如何搭建安全数传通道?

内外网文件摆渡系统主要应用于做了隔离的内外网之间&#xff0c;或者多个网络&#xff08;比如生产网、测试网、办公网&#xff09;之间的文件数据传输&#xff0c;涉及的行业主要包括集成电路、金融、电力、能源、医院、高新技术、新能源、科研机构、生物医药等&#xff0c;内…

qt-15综合实例(电子时钟)-多态重写鼠标单击和移动事件

综合实例-电子时钟 知识点digiclock.hdigiclock.cppmain.cpp运行图 知识点 setWindowOpacity(0.5);//设置窗体透明度 QTimer* Timer new QTimer(this);//新建一个定时器 connect(Timer,SIGNAL(timeout()),this,SLOT(ShowTime())); Timer->start(1000);//启动定时器 digic…

MySQL中处理JSON数据:大数据分析的新方向

1. 简介 1.1. 概述 在MySQL中处理JSON数据的能力是在MySQL 5.7版本中引入的,并在后续的版本中不断得到增强。这使得MySQL能够直接操作和查询JSON格式的数据,极大地扩展了其处理复杂数据结构的能力。 1.2. 主要特点 灵活性与可扩展性 :JSON允许开发者存储不规则和嵌套的数…

开始使用 AWS SAM CLI

了解如何使用 AWS SAM CLI 在本地调试 lambda 函数 欢迎来到雲闪世界。我们将学习 AWS SAM CLI 的概念。SAM 是无服务器 应用程序 模型的缩写&#xff0c;是 Amazon Web Services 提供的一个框架&#xff0c;可以利用它在本地机器上构建应用程序并将其直接部署到 AWS Lambdas。…

使用 MyBatis-Plus 的 <choose> 标签实现动态 SQL

在使用 MyBatis-Plus 进行开发时&#xff0c;我们经常需要处理复杂的 SQL 查询&#xff0c;这时动态 SQL 的功能显得尤为重要。MyBatis 提供了 <choose> 标签来帮助我们在动态 SQL 中实现条件判断。在本文中&#xff0c;我们将详细探讨如何在 MyBatis-Plus 中使用 <ch…

后端Web之Web服务器(以Tomcat为例)

目录 1.Web服务器 2.Tomcat介绍 3.Tomcat使用 4.SpringBootWeb入门解析 1.Web服务器 Web服务器是一种软件或硬件系统&#xff0c;用于托管网站和Web应用程序&#xff0c;并处理客户端&#xff08;如浏览器&#xff09;的HTTP请求。它是任何Web应用程序的基础&#xff0c;选…

Android笔试面试题AI答之Kotlin(11)

文章目录 49. Kotlin中的Sequence&#xff0c;为什么它处理集合操作更加高效&#xff1f;1. 惰性求值2. 逐个元素处理3. 避免中间集合的创建4. 支持无限序列5. 性能对比 50. Kotlin中的Coroutines与线程有什么区别&#xff1f;有哪些优点&#xff1f;一、协程与线程的区别二、协…

《Docker:实现开发环境一致性与高效部署的利器》

目录 介绍Docker 优势&#xff1a;Docker 的核心价值Docker在软件开发中的影响结语 介绍 Docker 是一个开源的应用容器化平台&#xff0c;它允许开发者将应用程序及其所有依赖项打包到一个独立的容器中。Docker 的基本概念包括&#xff1a; 镜像&#xff08;Image&#xff09;…