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

news2024/12/26 11:26:20

八. 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 别忘了字符串还带有\0
    char 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因为第二次用的话会传参NULL
    static 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 = ps
                       return 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.coloradmin.cn/o/1871245.html

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

相关文章

Java毕业设计 基于SSM vue药店管理系统小程序 微信小程序

Java毕业设计 基于SSM vue药店管理系统小程序 微信小程序 SSM 药店管理系统小程序 功能介绍 用户 登录 注册 首页 药品信息 药品详情 加入购物车 立即购买 收藏 购物车 立即下单 新增收货地址 我的收藏管理 用户充值 我的订单 留言板 管理员 登录 个人中心 修改密码 个人信息…

【深度学习】python之人工智能应用篇--跨模态生成技术

跨模态生成技术概述 跨模态生成技术是一种将不同模态的数据&#xff08;如文本、图像、音频、视频等&#xff09;进行融合和转换的技术。其目标是通过将一个模态的数据作为输入&#xff0c;生成与之对应的另一个模态的输出。这种技术对于突破单一模态的局限性&#xff0c;提高…

【九】【QT开发应用】WebRTC的sigslot源码和使用WebRTC的sigslot使用编写信号槽

WebRTC&#xff08;Web Real-Time Communication&#xff09; 是一个开源项目&#xff0c;提供实时通信能力&#xff0c;广泛应用于视频、音频和数据传输。在WebRTC的实现中&#xff0c;sigslot库用于信号和槽机制&#xff0c;以实现事件驱动的编程模型。 WebRTC的sigslot部分…

如何精准分析人形机器人运动数据?

全球“机器换人”进程加速,人形机器人有望成为AI下一个重要落地应用场景;EtherCAT-Analyzer具备分析人形机器人所有关节和电池与主站的通讯信息,快速掌握节点网络状态! 前言 随着人形机器人行业的发展及《中国制造2025》的全面实施,传统的脉冲模式控制很大程度上制约了机…

一个例子理解傅里叶变换的计算过程

假设我们有一个简单的信号&#xff0c;由两个不同频率的正弦波组成&#xff0c;我们希望通过傅里叶变换来分析其频谱。 示例信号 假设我们有一个信号 &#xff1a; 这个信号由两个频率成分组成&#xff1a;一个50 Hz的正弦波和一个120 Hz的正弦波&#xff0c;后者的振幅是前者…

用一个实例看如何分享大量照片 续篇二,关于Exif (Exchangeable Image File) - 可交换图像文件

续篇二&#xff1a;说说关于照片隐含的 Exif (Exchangeable Image File) 可交换图像文件 数码照片的Exif 参数有很多&#xff0c;重要的Exif信息&#xff1a;拍摄日期、时间、拍摄器材、GPS信息。 当然这主要对自己的档案有意义&#xff0c;如果放到网上还是建议抹去这些信息。…

微服务框架中的Eureka和Ribbon的个人理解

微服务框架需要学习的东西很多&#xff0c;基本上我把它分为了五个模块&#xff1a; 第一&#xff1a;微服务技术模块 分为三个常用小模块&#xff1a; 1.微服务治理&#xff1a; 注册发现 远程调用 配置管理 网关路由 2.微服务保护&#xff1a; 流量控制 系统保护 熔断降级 服…

数据转换 | Matlab基于R对称点模式(symmetric dot pattern, SDP)一维序列信号转二维时频图象

目录 效果分析基本介绍程序设计参考资料获取方式 效果分析 基本介绍 数据转换 | Matlab基于R对称点模式(symmetric dot pattern, SDP)一维序列信号转二维时频图象 SDP常被用于信号分析和深度学习模式识别。 SDP是一种基于极坐标系的图像表示方法&#xff0c;可以直接将原始信…

ECMAScript6介绍及环境搭建

这实际上说明&#xff0c;对象的解构赋值是下面形式的简写。 let { foo: foo, bar: bar } { foo: ‘aaa’, bar: ‘bbb’ }; 也就是说&#xff0c;对象的解构赋值的内部机制&#xff0c;是先找到同名属性&#xff0c;然后再赋给对应的变量。真正被赋值的是后者&#xff0c;而…

基于sivaco设计仿真PT型IGBT和NPT型IGBT结构

本项目基于使用仿真软件SIVACO来仿真研究PT型和NPT型的IGBT结构特点&#xff0c;并且通过仿真研究对于不同的掺杂浓度、沟道宽度等对器件的特性产生不同的影响。 资料获取到咸&#x1f41f;&#xff1a;xy591215295250 \\\或者联系wechat 号&#xff1a;comprehensivable &…

IND83081芯片介绍(二)

七、典型应用 上面显示了独立的CAN收发器&#xff0c;而下面则显示了多个iND83081可以共享同一个CAN收发器的应用场景。通过这些连接&#xff0c;iND83081可以实现对多个LED的驱动和控制&#xff0c;同时与外部MCU进行通信 。 八、ELINS接口 1.ELINS简介 ELINS是一种从接口&a…

PHP 网络通信底层原理分析

大家好&#xff0c;我是码农先森。 引言 我们日常的程序开发大多数都是以业务为主&#xff0c;很少会接触到底层逻辑。对于我们程序员来说&#xff0c;了解程序的底层运行逻辑&#xff0c;更有助于提升我们对程序的理解。我相信大多数的人&#xff0c;每天基本上都是完成业务…

利用labelme制作自己的coco数据集(labelme转coco数据集)

最近刚接触学习mmdetection&#xff0c;需要用到coco格式的数据集。 1.安装labelme 建议在conda(base)环境下安装&#xff08;前提是需要下载anaconda&#xff09;,下面是我已经装过的情况。 2.进入labelme环境下 中间可能会提示安装其它库&#xff0c;自行装上就行。 这里的…

5种u盘加密技巧分享,保护保护您的数据隐私

怎么给电脑U盘加密呢&#xff1f;U盘作为一种便携式存储设备&#xff0c;常常用于传输和存储敏感信息。由于U盘的易于丢失或被盗的特点&#xff0c;U盘加密显得尤为重要。今天教大家如何给电脑U盘加密&#xff0c;推荐3款优秀的U盘加密软件&#xff0c;并提供操作方法和注意事项…

51单片机看门狗定时器配置

测试环境 单片机型号&#xff1a;STC8G1K08-38I-TSSOP20&#xff0c;其他型号请自行测试&#xff1b; IDE&#xff1a;KEIL C51&#xff1b; 寄存器配置及主要代码 手册中关于看门狗的寄存器描述如下&#xff1a; 启动看门狗&#xff0c;需将B5位EN_WDT置1即可&#xff0c;…

数据结构与算法基础(王卓)--学习笔记

1 数据结构分类 1.1 逻辑结构分类 集合结构线性结构&#xff1a;线性表、栈、队列、串树形结构图形结构 1.2 物理结构分类 逻辑结构在计算机中的真正表示方式&#xff08;又称为映射&#xff09;称为物理结构&#xff0c;也可叫做存储结构 顺序存储结构&#xff1a;数组链…

嵌入式学习——数据结构(双向无头有环链表、内核链表、栈)——day48

1. 约瑟夫环问题——双向无头回环链表 1.1 问题描述 给定 ( n ) 个人&#xff08;编号为 ( 1, 2, \ldots, n )&#xff09;&#xff0c;他们围成一个圈。从第一个人开始报数&#xff0c;每报到第 ( k ) 个人时&#xff0c;杀掉这个人&#xff0c;然后从下一个人重新开始报数。…

一些硬件知识(十二)

1、请说明一下滤波磁珠和滤波电感的区别。 因此磁珠通常用于模数地的连接。 磁珠由导线穿过铁氧体组成&#xff0c;直流电阻很小&#xff0c;在低频时阻抗也很小&#xff0c;对直流信号几乎没有影响。 在高频&#xff08;几十兆赫兹以上&#xff09;时磁珠阻抗比较大&#xff0…

事务处理概述

一、引言 1、决定数据库应用系统性能的DBMS的关键实现技术——事务处理技术 事务处理技术是为了解决早期的DBMS产品在应用过程中遇到的现实问题而在后续的DBMS产品中加以实现的技术 2、比如在银行系统中&#xff0c;账户转账是常见的业务&#xff0c;是金融学中的交易trans…

【MLP-BEV(7)】深度的计算。针孔相机和鱼眼相机对于深度depth的采样一个是均匀采样,一个是最大深度均匀采样

文章目录 1.1 问题提出1.1 看看DD3D 的深度是怎么处理的给出代码示例 1.2 我们看看BEVDepth的代码 1.1 问题提出 针孔相机和鱼眼相机的投影模型和畸变模型不一样&#xff0c;如果对鱼眼的模型不太了解可以到我的这篇博客【鱼眼镜头11】Kannala-Brandt模型和Scaramuzza多项式模…