常见的字符串函数(包含头文件string.h)和字符函数(2)

八. strstr函数

1.strstr的定义
char *strstr( const char *str1, const char *str2 );

->1. strstr查找子串(str2)在字符串(str2)中第一次出现的位置,记录并返回该位置的指针,如果找不到,则返回NULL

->2. str1:查找字符串的目标空间    str2:需要查找的对象字符串

->3. 因为strstr函数操作时不会改变形参的指向,所以我们在两个形参前面加上两个const

2.strstr的使用

例1:

记录子串在目标字符串中的位置,然后返回子串首地址

#include <stdio.h>
#include <string.h>void main(void)
{char* str1 = "Strive to improve yourself";char* str2 = "improve";char* det = strstr(str1, str2);if(ret == NULL){printf("字符串不存在!");}else{printf("%s", det);}
}

运行结果:

例2:

返回子串首地址在目标字符串中的具体位置(地址 - 地址的方法)

#include <stdio.h>
#include <string.h>void main(void)
{char* str1 = "Strive to improve yourself";char* str2 = "improve";char* det = strstr(str1, str2);int result = det - str1 + 1;if (det == NULL){printf("字符串不存在!");}else{printf("%d", result);}
}

运行结果:

例3:

记录目标空间中一共出现多少次子串

#include <stdio.h>
#include <string.h>void main(void)
{char* str1 = "Strive to improve improve yourself";char* str2 = "improve";char* p = str1;int count = 0;while (p = strstr(p, str2)){count++;p++;}printf("%d", count);
}

运行结果:

3.strstr的模拟实现
#include <stdio.h>
#include <assert.h>char* My_strstr(const char* str1, const char* str2)
{assert(str1 && str2);char* p = str1;char* s1 = str1;char* s2 = str2;while (*p){s1 = p;s2 = str2;while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2){s1++;s2++;}if (*s2 == '\0')return p;p++;}return NULL;
}int main()
{char* str1 = "abbbcdf";char* str2 = "bbc";const char* det = My_strstr(str1, str2);if (det == NULL){printf("字符串不存在!");}else{printf("%s", det);}return 0;
}

九. strtok函数

1.strtok的定义
char *strtok( char *strToken, const char *strDelimit );

->1. 作用:切割字符串。将分隔符转换成\0在将前面那个字符串的首地址返回给函数(返回\0前面的字符串)

->2. char *strToken  目标空间

->3. char  *strDelimit 标记(分隔符)

2.strtok的使用

例1:

#include <stdio.h>
#include <string.h>int main()
{const char* sep = "@.";//三个分隔符 @ . \0 别忘了字符串还带有\0char email[] = "zhangsan@@nianxi.nbaiwan";char cp[30] = { 0 };   strcpy(cp, email);  char *ret = strtok(cp, sep);if(ret != NULL){printf("%s ", ret);}return 0;
}

因为strtok函数会改变原字符串中的内容,所以一般都是使用临时拷贝的内容,并且可修改

运行结果:

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

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

例2:

#include <stdio.h>
#include <string.h>int main()
{const char* sep = "@.";char email[] = "zhangsan@@nianxi.nbaiwan";char cp[30] = { 0 };   strcpy(cp, email);  char *ret = strtok(cp, sep);if(ret != NULL){printf("%s\n", ret);}ret = strtok(NULL, sep);if(ret == NULL){printf(第二次没有找到该标记);}else{printf("%s\n", ret);}return 0;
}

如果两个标记在一起中间什么都没有,函数strtok就啥也获取不到,获取不到strtok会直接跳过

不管它,直接去找下一个标记

运行结果:

例3:

第三次分割

#include <stdio.h>
#include <string.h>int main()
{const char* sep = "@.";/* char email[] = "zhangsan@.nianxinbaiwan";*/char email[] = "zhangsan@@nianxi.nbaiwan";char cp[30] = { 0 };strcpy(cp, email);char* ret = strtok(cp, sep);if (ret != NULL){printf("%s\n", ret);}ret = strtok(NULL, sep);if (ret == NULL){printf("第二次没有找到该标记");}else{printf("%s\n", ret);}ret = strtok(NULL, sep);if (ret == NULL){printf("第三次什么也没获取到");}else{printf("%s\n", ret);}return 0;
}

运行结果:

例4:

如果strtok什么都没找到就会返回NULL

第四次从字符串末尾开始向后找,后面已经没有字符串了,所以找不到

#include <stdio.h>
#include <string.h>int main()
{const char* sep = "@.";/* char email[] = "zhangsan@nianxin.baiwan";*/char email[] = "zhangsan@@nianxi.nbaiwan";char cp[30] = { 0 };strcpy(cp, email);char* ret = strtok(cp, sep);if (ret != NULL){printf("%s\n", ret);}ret = strtok(NULL, sep);if (ret == NULL){printf("第二次没有找到该标记\n");}else{printf("%s\n", ret);}ret = strtok(NULL, sep);if (ret == NULL){printf("第三次什么也没获取到\n");}else{printf("%s\n", ret);}ret = strtok(NULL, sep);if (ret == NULL){printf("第四次什么也没获取到\n");}else{printf("%s\n", ret);}return 0;
}

运行结果:

因为每次都需要用if else来判断,有点重复不好看

所以我们将代码改进一下:

利用for循环

#include <stdio.h>
#include <string.h>int main()
{const char *sep = "@.";char email[] = "zhangsan@nianxin.baiwan";char pc[30] = { 0 };strcpy(pc, email);char *ret =0;ret = strtok(pc, sep);for(; ret != NULL; ret = strtok(NULL, sep)){printf("%s\n", ret);}return 0;
}
3.strtok的模拟实现

例1:

#include <stdio.h>
#include <string.h>
#include <assert.h>char* My_strtok(char* ps, const char* pc)
{assert(pc); //不用加上ps因为第二次用的话会传参NULLstatic char* str1 = NULL;static char* str2 = NULL;static int count = 0;static int sz1 = 0; int sz2 = 0;if(ps != NULL){str1 = ps;sz1 = strlen(ps);sz2 = strlen(pc);for(*ps; *ps != '\0'; ps++){for(int i = 0; i < sz2; i++){if(i == 0){count++;}if(*ps == *(pc + i)){*ps = '\0';str2 = ps;return str1;}}}else{str1 = str2 + 1;ps = str1;for(*ps; *ps = '\0'; ps++){for(int i = 0; i < sz2; i++){if(i == 0){count++;}if(*ps == *(pc + i)){ps = '\0';str2 = psreturn str1;}}}if(count == sz1){return NULL;}return str1;}
}
int main()
{const char* pc ="b";char email[] ="nianxinbaiwan";char ps[30] = { 0 };strcpy(ps, email);char* ret = My_strtok(ps, pc);for(; ret != NULL; ret = My_strtok(NULL, pc)){printf("%s\n", ret);}return 0;
}

十. strerror函数

1.strerror的定义
char *strerror( int errnum );

->1.返回值是字符型的指针

->2.int errnum 错误码:C语言的数据库,在执行失败的时候,都会自动设置错误码

0:No error
1:Operation not permitted
2:No such file or directory
3:No such process
4:Interrupted function call
5:Input/output error
6:No such device or address
7:Arg list too long
8:Exec format error
9:Bad file descriptor

errno - C语言设置的一个全局的错误码存放的变量

2.strerror的使用
#include <stdio.h>
#include <errno.h>int main()
{FILE* pf = fopen("idea.txt", "w");if(pf == NULL){printf("%d", strerror(errno));return 1;}fputc("w");fclose(pf);pf = NULL;return 0;
}    

运行结果:

十一. 字符分类函数

包含头文件 ctype

1.isspace -> 判断是否是空白字符,是就返回非0,不是就返回0

int a = isspace(' ');
printf("%d", a);

2.isdigit -> 判断是否是数字字符,是就返回非0,不是就返回0

 int a = isdigit('x');printf("%d", a);

3.iscntrl -> 任何控字符

4.isxdigit -> 十六进制数字,包括十进制数字,小写字母a - f,大写字母A - F

5.islower -> 小写字母a - z

6.isupper 大写字母A - Z

7.isalpha 字母a - z或A - Z

8.isalnum 字母或数字,a - z,A - Z,0 - 9

9.ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)

10.isgraph 任何图像字符

11.isprint 任何打印字符,包括图形字符和空白字符

十二. tolower函数

1. tolower的使用
printf("%c\n", tolower('W'));

2.tosupper -> 转大写

十三. memcpy

1.memcpy的定义
void* memcpy(void* destination, const void* source, size_t num);

万能copy函数,什么类型的都可以拷贝

memcpy负责拷贝两块独立的空间中的数据

->1. void* destination 目标空间

->2. void* source 源空间

->3. size_t num 源空间总大小

2.memcpy的使用

例1:

整型拷贝

#include <stdio.h>
#include <string.h>int main()
{int arr1[] = {1, 2, 3, 4, 5, 6, 7, };int arr2[10] = { 0 };memcpy(arr2, arr1, 28);int i = 0;for(i = 0; i < sizeof(arr2)/sizeof(arr2[0]); i++){printf("%d ", arr2[i]);}return 0;
}

运行结果:

例1:

浮点型拷贝

#include <stdio.h>
#include <string.h>int main()
{float arr1[] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, };float arr2[10] = { 0.0 };memcpy(arr2, arr1, 28);int i = 0;for (i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++){printf("%d ", arr2[i]);}return 0;
}

运行结果:

tips:

strcpy和memcpy的区别:

1.复制内容不同,strcpy只能复制字符类型,而memcpy可以复制任意类型

2.所需参数不同,strcpy只需要目标空间和源空间,而memcpy在次之上还需要源空间总大小

3.用途不同,字符类的复制用strcpy,其他类型的复制使用memcpy

3.memcpy的模拟实现

我们写的这个模拟实现的memcpy是不能实现重叠空间的拷贝的

#include <stdio.h>
#include <assert.h>void* My_memcpy(void* det, const void* src, size_t num)
{assert(det&&src);void* p = det;while(num--){*(char*)det = *(char*)src;det = (char*)det + 1;src = (char*)src + 1; }return p;
}

 为什么不使用(char*)src++,(char*)det++这种写法,因为这种写法有点问题,有些编译器是不支持这样写的,被(char*)强转了就是一个临时的变量,对一个临时的变量进行操作是有问题的

用自定义函数My_memcpy进行重复空间的拷贝

#include <stdio.h>
#include <assert.h>void* My_memcpy(void* det, const void* src, size_t num)
{assert(det && src);void* p = det;while (num--){*(char*)det = *(char*)src;det = (char*)det + 1;src = (char*)src + 1;}return p;
}
void test()
{int a[] = { 1,2,3,4,5,6,7,8,9,10 };//int b[20] = { 0 };My_memcpy(a + 2, a, 28);int i = 0;for (i = 0; i < 10; i++){printf("%d ", a[i]);} 
}
int main()
{test();return 0;
}

运行结果:

由上图知:第三第四元素地址被第一第二元素地址覆盖了,后面拿第三第四元素内容和第一第二元素一样,后面的地址跟前面的同理,就会出现如图这样的结果

tips:

上面说了,memcpy用于单独的两个空间(重叠的内存也能实现,但是C中规定它只能用于单独的两个空间),那重叠内存的拷贝应该用什么函数  - > memmove

十四. memmove函数

1.memmove的定义
void *memmove( void *dest, const void *src, size_t count );

负责拷贝重复空间中的数据

->1. void* destination 目标空间

->2. void* source 源空间

->3. size_t num 需要拷贝的字节数

它的目标空间和源空间是同一个空间

2.memmove的使用
#include <stdio.h>
#include <string.h>int main()
{int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};memmove(a + 2, a, 20);int i = 0;for(i = 0; i < 10; i++){printf("%d ", a[i]);}return 0;
}

运行结果:

3.memmove的模拟实现
#include <stdio.h>
#include <assert.h>void* My_memmove(void* det, const void* src, size_t num)
{assert(det&&src);void* p = det;if (det < src){while (num--){*(char*)det = *(char*)src;det = (char*)det + 1;src = (char*)src + 1;}}else{while (num--){*((char*)det + num) = *((char*)src + num);}}return p;
}
int main()
{int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };My_memmove(a + 1, a + 2, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", a[i]);}return 0;
}

运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/36549.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot + Vue前后端项目(第二十记)

项目实战第二十记 写在前面1. 高德地图官网2. 开发文档3. 集成高德地图3.1 在public文件夹下创建config.js3.2 index.html&#xff08;在项目启动文件中引入外部的js&#xff09;3.3 点标记&#xff08;用点标记当前位置&#xff09;3.4 信息窗体&#xff08;点击当前位置&…

【MAVEN学习 | 第2篇】Maven工程创建及核心功能

文章目录 一. 基于IDEA的Maven工程创建1.1 Maven工程GAVP属性&#xff08;1&#xff09;GroupID 格式&#xff08;2&#xff09;ArtifactID 格式&#xff08;3&#xff09;Version版本号格式&#xff08;4&#xff09;Packaging定义规则 1.2 IDEA构建Maven JavaSE工程1.3 IDEA构…

Termius:现代化的SSH客户端,让服务器管理变得优雅简洁

Termius简介 是一款现代化的跨平台终端模拟器和SSH客户端。以下是对Terminus的介绍以及使用它的理由&#xff1a; 跨平台兼容性&#xff1a; Terminus支持Windows、macOS、Linux、IOS和Android&#xff0c;让用户在不同操作系统间保持一致的终端体验。优雅的用户界面&#xf…

通达信机构买卖抓牛指标公式源码

通达信机构买卖抓牛指标公式源码&#xff1a; X_1:V/CLOSE/2; X_2:SUM(IF(X_1>100 AND CLOSE>REF(CLOSE,1),X_1,0),0); X_3:SUM(IF(X_1>100 AND CLOSE<REF(CLOSE,1),X_1,0),0); X_4:SUM(IF(X_1<100 AND CLOSE>REF(CLOSE,1),X_1,0),0); X_5:SUM(IF(X_1&l…

ATA-7025:高压放大器的原理是怎样的

高压放大器是一种电子器件&#xff0c;主要用于将输入信号的电压放大到更高的水平。它在许多领域中都有重要的应用&#xff0c;包括医学影像设备、科学研究装置、激光系统等。高压放大器的原理涉及到放大器的工作原理、电路结构、工作特性等多个方面。下面将从这些方面对高压放…

.net core接入nacos注册服务并使用配置中心

1、安装依赖 Nuget包&#xff1a;nacos-sdk-csharp.Extensions.Configuration和nacos-sdk-csharp.AspNetCore 2、在appsettings.json中配置 "nacos": {"ServerAddresses": ["http://localhost:8848/"],"DefaultTimeOut": 15000,"…

各省药品集中采购平台-地方药品集采分析数据库

国家第十批药品集中采购的启动时间暂未明确&#xff0c;但即将到来&#xff0c;在5月&#xff0c;国家医保局发布了《关于加强区域协同做好2024年医药集中采购提质扩面的通知》&#xff0c;其中明确指出将“开展新批次国家组织药品和医用耗材集中带量采购&#xff0c;对协议期满…

Vue2 - 项目上线后生产环境中去除console.log的输出以及断点的解决方案

前言 当你准备将Vue.js应用程序部署到生产环境时,一个关键的优化步骤是移除代码中的所有 console.log 语句以及断点。在开发阶段,console.log 是一个非常有用的调试工具,但在生产环境中保留它们可能会影响性能和安全性。在本文中,我将向你展示如何通过使用Vue CLI 2来自动…

大语言模型在医疗领域的进展、应用和挑战_医疗大语言模型算法csdn

### 概述 本文综述了医学领域大型语言模型&#xff08;LLM&#xff09;的进展、应用和面临的挑战。大型语言模型如ChatGPT在理解和生成人类语言方面显示出了显著的能力&#xff0c;引起了广泛关注。在医学领域&#xff0c;研究人员正致力于利用LLM支持各种医疗任务&#xff0c…

13 Redis-- MySQL 和 Redis 的数据一致性

Redis-- MySQL 和 Redis 的数据一致性 先抛一下结论&#xff1a;在满足实时性的条件下&#xff0c;不存在两者完全保存一致的方案&#xff0c;只有最终一致性方案。

FlinkX学习

FlinkX学习 FlinkX安装 由于flinkx已经改名chunjun 官网已不存在 (https://gitee.com/lugela/flinkx#flinkx)这里可以看到flinkx的操作文档 1、上传并解压 unzip flinkx-1.10.zip -d /usr/local/soft/2、配置环境变量 FLINKX_HOME/usr/local/soft/flinkx-1.10 export PATH$F…

STL-迭代器

1.迭代器 1.1正向迭代器 正向迭代器是用一个类封装的&#xff0c;迭代器类。例如&#xff1a;在vector&#xff0c;string中的迭代器就相当于一个指针&#xff0c;在list类中用一个类来封装一个节点&#xff0c;实质上也还是一个指针&#xff0c;迭代器就相当于指向一个节点的…

背靠广汽、小马智行,如祺出行打得过滴滴和百度吗?

©自象限原创 作者丨艾AA 编辑丨薛黎 北京时间6月14日凌晨&#xff0c;在特斯拉股东大会上&#xff0c;马斯克阐述了对Robotaxi&#xff08;自动驾驶出租车&#xff09;商业模式的构想——特斯拉不仅会运营自己的无人驾驶出租车车队&#xff0c;还可以让特斯拉车主们的爱…

微服务开发 —— 项目环境搭建篇

环境搭建 Linux 环境搭建 Linux 环境搭建大家可以使用虚拟机 VMware、VirtualBox 等应用创建虚拟机&#xff0c;使用Vagrant也可以快捷搭建虚拟环境&#xff1b;Windows 中有 WSL2&#xff0c;Windows 中的 Docker 也对 WSL 进行了支持&#xff0c;也是一个不错的选择。或者可…

Windows - 像Linux一样使用alias

前言 阅读本文约2分钟 说明 使用doskey命令 设置别名 查看当前目录 doskey lldir 激活conda的spider环境 doskey spiderconda activate spider 退出conda环境 doskey condaqconda deactivate 查看所有别名 doskey /macros

实现设计开挂|如何设计出坚不可摧的网球拍?

数字揭秘 我们发现自己可能偶尔会以过激的方式表达沮丧或愤怒&#xff0c;哪怕是在公共场合。就算是世界级的网球运动员也无法避免偶尔的情绪爆发&#xff0c;他们有时会砸球拍来释放被压抑的情绪或应对来自竞赛的压力。 网球运动员的情绪爆发已被证明是不可避免的。哪怕是包括…

Linux系统相关函数总结

在应用程序当中&#xff0c;有时往往需要去获取到一些系统相关的信息&#xff0c;譬如时间、日期、以及其它一些系统相关信息&#xff0c;本章将向大家介绍如何通过 Linux 系统调用或 C 库函数获取这些系统信息。除此之外&#xff0c;还会向大家介绍 Linux 系统下的/proc 虚拟文…

浏览器插件利器-allWebPluginV2.0.0.14-beta版发布

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX插件直接嵌入浏览器&#xff0c;实现插件加载、界面显示、接口调用、事件回调等。支持谷歌、火狐等浏…

js删除el-table删除新增项,有的已经保存有的未经保存

有时候在弹窗中的弹窗要删除数据,有的是刚新增进来的,没有经过保存就没有id,有的已经保存过就有id 根据情况设定是否为编辑模式,如果为编辑模式就需要进行筛选删除及接口,如果不是编辑模式,只需要进行筛选删除 this.editFlag true; // 为编辑模式// 删除伤亡名单handelDel() …

数据库管理系统(DBMS)

一.数据库管理系统 1.简介 数据库管理系统(Database Management System)是一种操纵和管理数据库的大型软件&#xff0c;用于建立、使用和维护数据库&#xff0c;简称DBMS。它对数据库进行统一的管理和控制&#xff0c;以保证数据库的安全性和完整性。用户通过DBMS访问数据库中…