常见的字符串函数(包含头文件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 别忘了字符串还带有\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;
}

运行结果:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

不用再找了,这是大模型实践最全的总结

随着ChatGPT的迅速出圈&#xff0c;加速了大模型时代的变革。对于以Transformer、MOE结构为代表的大模型来说&#xff0c;传统的单机单卡训练模式肯定不能满足上千&#xff08;万&#xff09;亿级参数的模型训练&#xff0c;这时候我们就需要解决内存墙和通信墙等一系列问题&am…

Mysql索引的实现原理,B+Tree,WAL

InnoDB 引擎&#xff0c;每一个数据表有两个文件 .frm和.ibd&#xff0c;分别为表结构&#xff0c;数据和索引&#xff0c;数据挂在主索引的叶子节点上&#xff0c;此主索引称为聚簇索引。 MyISAM 引擎&#xff0c;每一个数据表有三个文件.frm和.MYI和.MYD&#xff0c;分别为表…

测试报告-HTMLTestRunner报告优化(中/英文)

引用原始的HTMLTestRunner.py文件生成的测试报告在美观性不是很好&#xff0c;使用在此文件基础上优化后的HTMLTestReportCN.py文件(生成的报告为中文)、HTMLTestReportEN.py文件(生成的报告为英文)。 1 首先新建一个Python项目 例如&#xff1a;testHtmlReport 创建case包&am…

指纹浏览器是什么?跨境多账号安全如何保证?

随着电子商务的蓬勃发展&#xff0c;越来越多的商家选择开设多店来扩大经营规模。然而多店运营也带来了一系列的挑战&#xff0c;其中之一就是账号安全。 1. 了解反检测浏览器和代理服务器 在我们开始讨论如何有效地使用反检测浏览器之前&#xff0c;我们首先需要了解这两个工…

如何用亚马逊合作伙伴网络快速上线跨境电商

目前跨境电商已成为行业发展主流&#xff0c;如何快速、低成本打造品牌海外独立站和智能客服营销中心、构建全链路跨境电商体系是出海电商商家都会遇到的难题。亚马逊云科技凭借与亚马逊电商平台易于集成的先天优势成为首选的电商解决方案平台。本文介绍了如何用亚马逊云科技平…

SpringCloud分布式微服务链路追踪方案:Skywalking

一、引言 随着微服务架构的广泛应用&#xff0c;系统的复杂性也随之增加。在这种复杂的系统中&#xff0c;应用通常由多个相互独立的服务组成&#xff0c;每个服务可能分布在不同的主机上。微服务架构虽然提高了系统的灵活性和可扩展性&#xff0c;但也带来了新的挑战&#xf…

深度学习论文撰写实验对比分析时复现其它论文方法的问题

&#x1f4aa; 专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &#x1f4dd;《暗光增强》 &a…

说一说ABAP CDS View的发展历史与特性

1. 背景 随着SAP Fiori应用程序的兴起&#xff0c;SAP领域的小伙伴接触和使用ABAP CDS View的机会也是越来越多。今天&#xff0c;让我们花些时间&#xff0c;一起在了解下这项技术的设计初衷和发展历史。 2. 设计初衷 说起ABAP CDS View&#xff0c;就不得不提及SAP HANA。…

Open AI限制来袭?用上这个工具轻松破局!

【导语】近日&#xff0c;AI领域掀起了一场不小的波澜。Open AI宣布&#xff0c;从7月9日起&#xff0c;将对部分地区的开发者实施API调用限制。这一消息对于许多依赖Open AI技术的国内初创团队来说&#xff0c;无疑是一个沉重的打击。 对于这些团队而言&#xff0c;Open AI的A…

Arcgis地统计分析工具灰色不可用 解决方法

使用Arcmap&#xff0c;调用地统计分析工具&#xff08;Geostatistical Analyst&#xff09;下的探索数据&#xff08;Explore Data&#xff09;&#xff0c;发现工具呈灰色不可用。这是由于扩展模块中没有将该模块做勾选设置导致的。下面介绍一下如何解决地统计分析工具不可用…

汇聚荣做拼多多运营第一步是什么?

汇聚荣做拼多多运营第一步是什么?在众多电商平台中&#xff0c;拼多多凭借其独特的社交电商模式迅速崛起&#xff0c;吸引了大量消费者和商家的目光。对于希望在拼多多上开店的商家而言&#xff0c;了解如何进行有效运营是成功的关键。那么&#xff0c;汇聚荣做拼多多运营的第…

web前端——HTML

目录 一、HTML概述 1.HTML是什么&#xff1f; 2.HTML具体化解释 二、HTML基本语法 1.声明 2. Head头标签 3.body身体标签 4.一个html的基本结构 5.标签 6.标签属性 ①属性的格式 ②属性的位置 ③添加多个属性 三、基本常用标签 1.超链接 2.图像标签 ①图像标…

C++编程(四)this指针 常函数 常对象 静态成员

文章目录 一、this指针&#xff08;一&#xff09;概念&#xff08;二&#xff09;显式使用this指针的场景1. 当形参和成员变量名一致时2. 返回对象自身的时候必须要使用this指针3. 在类中销毁一个对象 二、常函数和常对象&#xff08;一&#xff09;常函数1. 概念2. 语法格式 …

【2024.6.23】今日科技时事:科技前沿大事件

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

最新!AI大模型的研究热点!

引言 在人工智能的浪潮中&#xff0c;大模型研究如日中天&#xff0c;涵盖诸多研究方向&#xff0c;每个方向均承载着独特的研究焦点与挑战。 以下&#xff0c;我们将逐一探讨数个备受瞩目的研究方向&#xff0c;包括检索增强生成RAG、大模型Agent、Mamba、MoE、LoRA等&#…

【LeetCode】八、堆的使用:第K个最大元素 + 前K和高频单词

文章目录 1、Java中的堆结构2、leetcode215&#xff1a;数组中的第K个最大元素3、leetcode692&#xff1a;前K个高频单词 1、Java中的堆结构 PriorityQueue类取堆顶元素删除堆顶元素堆的元素个数遍历堆 2、leetcode215&#xff1a;数组中的第K个最大元素 这题应该快排来解&…

MyBatis~配置解析, 属性(properties)、设置(settings)

注意, 对应的名称一定要相同, 比如username就要对应username, 而且如果同时使用外部配置文件和property, 优先级是外部配置文件优先级更高 设置&#xff08;settings&#xff09; 这是 MyBatis 中极为重要的调整设置&#xff0c;它们会改变 MyBatis 的运行时行为。 下表描述了…

利用Python控制终端打印字体的颜色和格式

利用Python控制终端打印字体的颜色和格式—操作详解&#xff08;ANSI转义序列&#xff09; 一、问题描述二、ANSI转义序列三、具体代码和显示效果&#xff08;看懂这段代码&#xff0c;以后可随心控制字体的打印格式&#xff09; 欢迎学习交流&#xff01; 邮箱&#xff1a; z……

Linux系统相关函数总结

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

Android 13 为应用创建快捷方式

参考 developer.android.google.cn 创建快捷方式 来自官网的说明&#xff1a; 静态快捷方式 &#xff1a;最适合在用户与应用互动的整个生命周期内使用一致结构链接到内容的应用。由于大多数启动器一次仅显示四个快捷方式&#xff0c;因此静态快捷方式有助于以一致的方式执行…