c语言进阶部分详解(详细解析字符串常用函数,并进行模拟实现(下))

news2024/11/27 12:44:43

上篇文章介绍了一些常用的字符串函数,大家可以跳转过去浏览一下:c语言进阶部分详解(详细解析字符串常用函数,并进行模拟实现(上))_总之就是非常唔姆的博客-CSDN博客

今天接着来介绍一些: 


目录

一.字符串查找

1.strstr()

1.1示例

1.2注意事项:

1.3模拟实现

 2.strtok()

 2.1示例

2.2注意事项

 二.错误信息报告

1.strerror()

 1.1示例

1.2注意事项:

 三.内存操作函数

1.memcpy()

1.1示例

1.2注意事项

2.memmove()

 2.1示例

 2.2注意事项:

3.memset()

 3.1示例

 3.2注意事项:

 4.memcmp()

4.1示例

4.2注意事项:


一.字符串查找

1.strstr()

strstr是一个C标准库函数,用于在一个字符串中查找另一个字符串的第一次出现的位置。它的原型如下:

char *strstr(const char *haystack, const char *needle);

strstr函数接受两个参数,haystack是要搜索的字符串,needle是要查找的子字符串。函数返回一个指向第一次出现的子字符串的指针,如果找不到子字符串,则返回NULL

下面是strstr函数的工作原理:

  1. 首先,strstr函数会在haystack字符串中搜索needle字符串的第一个字符

  2. 一旦找到了与needle的第一个字符匹配的字符,strstr函数会继续比较haystack中的后续字符和needle中的字符,直到找到一个不匹配的字符或者needle中的所有字符都匹配

  3. 如果找到了完全匹配的子字符串,strstr函数会返回指向该子字符串的指针

  4. 如果在haystack中找不到子字符串,或者needle是一个空字符串,则strstr函数会返回NULL

1.1示例

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "cd";
	printf("%s", strstr(arr1, arr2));
	return 0;
}

 如果找到了完全匹配的子字符串,strstr函数会返回指向该子字符串的指针,结果如下:

1.2注意事项:

strstr函数是区分大小写的,如果要进行大小写不敏感的字符串比较,可以使用其他函数 

1.3模拟实现

char* my_strstr(const char* a1, const char* a2)
{
	char* cp = a1;
	char* str1 = a1;
	char* str2;

	while (*cp)
	{
		str1 = cp;
		str2 = a2;
		while (*str1&&*str2&&*str1 == *str2)
		{
			str1++;
			str2++;
		}
		if (*str2 == '\0')
		{
			return cp;
		}
		cp++;
	}
	return NULL;
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "cd";
	printf("%s", my_strstr(arr1, arr2));
	return 0;
}

 2.strtok()

strtok是一个C标准库函数,用于将一个字符串分割成多个子字符串。它的原型如下:

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

其中,str是要分割的字符串delim是用作分隔符的字符串。函数返回一个指向分割后的第一个子字符串的指针,如果没有更多的子字符串,则返回NULL

strtok函数使用一个静态变量来保存当前的分割位置,因此在多次调用strtok时,需要将原始字符串传递给第一次调用,而后续的调用只需要传递NULL作为第一个参数

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

 2.1示例

int main()
{
	char arr[] = "123@abc%ABC";
	char a[] = "@%";
	printf("%s\n", strtok(arr, a));
	/*printf("%s\n", strtok(NULL, a));*/
	return 0;
}

 结果如下:

 

int main()
{
	char arr[] = "123@abc%ABC";
	char a[] = "@%";
	printf("%s\n", strtok(arr, a));
	printf("%s\n", strtok(NULL, a));
	printf("%s\n", strtok(NULL, a));
	return 0;
}

 结果如下:

 充分利用性质可以写出这样的代码:

int main()
{
	char arr[] = "123@abc%ABC";
	char a[] = "@%";
	/*printf("%s\n", strtok(arr, a));
	printf("%s\n", strtok(NULL, a));
	printf("%s\n", strtok(NULL, a));*/

	for (char* ret = strtok(arr, a); ret != NULL;ret= strtok(NULL, a))
	{
		printf("%s\n", ret);
	}
	return 0;
}

2.2注意事项

需要注意的是,strtok函数会修改原始字符串,将分隔符替换为NULL字符。如果需要保留原始字符串,可以使用副本进行分割操作 


 二.错误信息报告

1.strerror()

strerror是一个C标准库函数,用于将错误码转换为对应的错误信息字符串。它的原型如下:

char * strerror( int errnum );

其中,errnum是错误码。函数返回一个指向错误信息字符串的指针

  • errnum是一个整数类型的错误码,通常用于表示函数调用或操作的结果状态
  • errno是一个全局变量,用于存储最近一次发生的错误码。当函数调用或操作失败时,它们通常会设置errno为一个非零的错误码,以指示错误的类型

 1.1示例

输出1~10分别代表的错误信息:

int main()
{
	for (int i = 1; i <= 10; i++)
	{
		printf("%s\n", strerror(i));
	}
	return 0;
}

结果如下:
 

1.2注意事项:

strerror函数返回的指针指向的是一个静态分配的字符串,因此在多线程环境下不是线程安全的


 三.内存操作函数

1.memcpy()

memcpy是一个标准C库函数,用于将一段内存区域的数据复制到另一段内存区域。它的函数原型如下:

void *memcpy(void *dest, const void *src, size_t n);

其中,dest是目标内存区域的指针,src是源内存区域的指针,n是要复制的字节数。

memcpy函数将源内存区域的n个字节复制到目标内存区域中。如果源和目标区域重叠,memcpy函数的行为是未定义的。如果需要处理重叠区域的复制,可以使用memmove函数(下面介绍)

这个函数在遇到 '\0' 的时候并不会停下来 

1.1示例

int main() 
{
    char src[] = "Hello, world!";
    char dest[20];

    memcpy(dest, src, strlen(src) + 1);

    printf("source string: %s\n", src);
    printf("copied string: %s\n", dest);
    return 0;
}

结果如下:

 

1.2注意事项

需要注意的是,memcpy函数不会自动添加字符串结束符\0,因此在复制字符串时需要将\0一起复制。在上面的示例中,strlen(src) + 1计算了源字符串的长度,并将其加1,以便复制\0 

2.memmove()

memmove是一个标准C库函数,用于将一段内存区域的数据复制到另一段内存区域,与memcpy函数类似。但是,memmove函数可以处理源和目标区域重叠的情况,而memcpy函数则不能

memmove函数的函数原型如下:

void *memmove(void *dest, const void *src, size_t n);

其中,dest是目标内存区域的指针,src是源内存区域的指针,n是要复制的字节数。

memmove函数将源内存区域的前n个字节复制到目标内存区域中。如果源和目标区域重叠,memmove函数会确保复制的结果是正确的,即使源和目标区域重叠。因此,memmove函数比memcpy函数更安全,但通常也更慢

 2.1示例

int main() 
{
    char str[] = "123456";
    memmove(str,str+3,3);
    printf("%s\n", str);
    return 0;
}

 结果如下:

 2.2注意事项:

需要注意的是,memmove函数和memcpy函数一样,不会自动添加字符串结束符\0,因此在复制字符串时需要将\0一起复制

3.memset()

memset是一个用于设置内存块内容的函数。它可以将指定的内存块中的每个字节都设置为特定的值。

memset函数的原型如下:

void *memset(void *ptr, int value, size_t num);

参数说明:

  • ptr:指向要设置的内存块的指针。
  • value:要设置的值,以整数形式提供。
  • num:要设置的字节数。

memset函数将ptr指向的内存块的num个字节设置为value指定的值

 3.1示例

int main() 
{
    char str[20] = { 0 };
    memset(str, 'A', 10);
    printf("%s\n", str);
    return 0;
}

 结果如下:

 3.2注意事项:

需要注意的是,memset函数是按字节进行设置的,因此对于非字符类型的数组,需要将value参数转换为相应的字节表示

 4.memcmp()

memcmp函数用于比较两个内存区域的内容是否相同,其原型如下:

int memcmp(const void *ptr1, const void *ptr2, size_t num);

参数说明:

  • ptr1:指向第一个内存区域的指针。
  • ptr2:指向第二个内存区域的指针。
  • num:要比较的字节数。

memcmp函数将ptr1指向的内存区域和ptr2指向的内存区域的前num个字节进行比较,返回值如下:

  • 如果两个内存区域相同,返回0。
  • 如果第一个内存区域小于第二个内存区域,返回负整数。
  • 如果第一个内存区域大于第二个内存区域,返回正整数

4.1示例

int main() 
{
    char str1[20] = "Hello, world!";
    char str2[20] = "Hello, world!";
    int result1 = memcmp(str1, str2, strlen(str1));
   
    printf("result = %d\n", result1);
    return 0;
}

结果如下:


 

4.2注意事项:

memcmp函数比较的是字节,因此对于非字符类型的数组,比较的结果可能与预期不同 

 


好了各位,这次的内容就先整理到这里吧!下次按照学习计划就打了结构体的部分知识内容啦! 

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

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

相关文章

scala数组函数合集

目录 1. 添加类函数 2.生成类函数 3.删除类函数 4.查找类函数 5.统计类函数 6.修改类函数 7.判断类函数 8.获取集合元素 9.集合操作类函数 10.转换类函数 11.工具类函数 12.集合内与集合间计算函数 在 scala 中Array数组是一种可变的、可索引的数据集合 创建数组…

C/C++ 进程间通信system V IPC对象超详细讲解(系统性学习day9)

目录 前言 一、system V IPC对象图解 1.流程图解&#xff1a; ​编辑 2.查看linux内核中的ipc对象&#xff1a; 二、消息队列 1.消息队列的原理 2.消息队列相关的API 2.1 获取或创建消息队列&#xff08;msgget&#xff09; 实例代码如下&#xff1a; 2.2 发送消息到消…

关于Jupyter markdown的使用

一级标题 #空格 标题1 二级标题 ## 空格 标题2 三级标题 ###空格 标题3 无序&#xff1b; 有序&#xff1a; 数学符号&#xff1a;

MySQL:主从复制-基础复制(6)

环境 主服务器 192.168.254.1 从服务器&#xff08;1&#xff09;192.168.254.2 从服务器&#xff08;2&#xff09;192.168.253.3 我在主服务器上执行的操作会同步至从服务器 主服务器 yum -y install ntp 我们去配置ntp是需要让从服务器和我们主服务器时间同步 sed -i /…

1.Linux入门基本指令

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 01.ls指令 02.pwd指令 03.cd指令 04.touch指令 05.mkdir指令(重要) 06.rmdir&&rm指令(重要) 07.man指令(重要) 08.cp指令(重要) 09.mv指令(重要) 10.cat指令 nano指令 echo指令 输出重定向 追加重…

day25--JS进阶(递归函数,深浅拷贝,异常处理,改变this指向,防抖及节流)

目录 浅拷贝 1.拷贝对象①Object.assgin() ②展开运算符newObj {...obj}拷贝对象 2.拷贝数组 ①Array.prototype.concat() ② newArr [...arr] 深拷贝 1.通过递归实现深拷贝 2.lodash/cloneDeep实现 3.通过JSON.stringify()实现 异常处理 throw抛异常 try/catch捕获…

强化学习------DQN算法

简介 DQN&#xff0c;即深度Q网络&#xff08;Deep Q-network&#xff09;&#xff0c;是指基于深度学习的Q-Learing算法。Q-Learing算法维护一个Q-table&#xff0c;使用表格存储每个状态s下采取动作a获得的奖励&#xff0c;即状态-价值函数Q(s,a)&#xff0c;这种算法存在很…

数据结构:链式二叉树

上一章讲了堆,堆是完全二叉树的顺序存储结构,本章将要全面讲解一下二叉树的链式存储结构即链式二叉树 我们已经学习了二叉树的概念和性质了,本章重点学习二叉树相关操作,可以更好的理解分治算法思想;也需要对递归有更深次的理解. 其实普通的链式二叉树的增删查改没有什么意义,…

COLLABORATIVE DESIGNER FOR SOLIDWORKS® 新功能

共享和标注 优点&#xff1a;收件人在浏览器中访问共享文 件&#xff0c;无需安装3DEXPERIENCE 平台应用程序。 • 与 SOLIDWORKS 中来自您组织内部或外部的任何人无缝 共享您的设计。 • 直接将评论和标注附加到您的设计作品中&#xff0c;便于立即获得 反馈。 支持 SOLIDWO…

深入理解强化学习——强化学习的基础知识

分类目录&#xff1a;《深入理解强化学习》总目录 在机器学习领域&#xff0c;有一类任务和人的选择很相似&#xff0c;即序贯决策&#xff08;Sequential Decision Making&#xff09;任务。决策和预测任务不同&#xff0c;决策往往会带来“后果”&#xff0c;因此决策者需要为…

Centos7安装MongoDB7.xxNoSQL数据库|设置开机启动(骨灰级+保姆级)

一: mongodb下载 MongoDB 社区免费下载版 MongoDB社区下载版 [rootwww tools]# wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-7.1.0-rc4.tgz 二: 解压到指定目录 [rootwww tools]# mkdir -p /usr/local/mongodb [rootwww tools]# tar -zxvf mongodb-…

Linux目录和文件查看命令

一、Linux 的目录结构 Linux 的目录结构是一个树状结构&#xff0c;以根目录&#xff08;/&#xff09;为起点&#xff0c;以下是常见的 Linux 目录结构的主要内容&#xff1a; / 根路径 ├── bin: 存放系统指令&#xff08;命令&#xff09;&#xff0c;如ls、cp、mv等&…

ARM-流水灯

.text .global _start _start: 1、设置GPIOE寄存器的时钟使能 RCC_MP_AHB$ENSETR[4]->1 0x50000a28LDR R0,0X50000A28 LDR R1,[R0] 从R0起始地址的4字节数据取出放在R1 ORR R1,R1,#(0X3<<4) 第4位设置为1 STR R1,[R0] 写回2、设置PE10、PE8、PF10管脚为输出模式 …

Observability:使用 OpenTelemetry 对 Node.js 应用程序进行自动检测

作者&#xff1a;Bahubali Shetti DevOps 和 SRE 团队正在改变软件开发的流程。 DevOps 工程师专注于高效的软件应用程序和服务交付&#xff0c;而 SRE 团队是确保可靠性、可扩展性和性能的关键。 这些团队必须依赖全栈可观察性解决方案&#xff0c;使他们能够管理和监控系统&a…

学习记忆——数学篇——案例——算术——记忆100内质数

文章目录 质数表歌诀记忆法100以内的质数歌谣质数口决一百以内质数口诀100以内素数歌 规律记忆法100以内6的倍数前、后位置上的两个数&#xff0c;只要不是5或7的倍数&#xff0c;就一定是质数个数没有用该数除以包括7在内的质数 分类记忆法数字编码法谐音记忆法 100以内的质数…

Matlab随机变量的数字特征

目录 1、均值&#xff08;数学期望&#xff09; 2、中位数 3、几何平均数 4、调和平均数 5、数据排序 6、众数 7、极差&#xff08;最大值和最小值之差&#xff09; 8、方差与均方差&#xff08;标准差&#xff09; 9、变异系数 10、常见分布的期望与方差的计算 11、协方…

ElasticSearch 学习8 :ik分词器的扩展,及java调用ik分词器的analyzer

1.前言&#xff1a; 上篇已经说过ik的集成&#xff0c;这篇说下ik的实际使用 2.2、IK分词器测试 IK提供了两个分词算法ik_smart 和 ik_max_word ik_smart&#xff1a;为最少切分ik_max_word&#xff1a;为最细粒度划分。 2.2.1、最小切分示例 #分词器测试ik_smart POST _…

互联网项目有哪些值得做的

互联网已经融入了我们生活的方方面面&#xff0c;从电商巨头到科技创新&#xff0c;互联网带来的变革和便利无处不在。而在这个信息广泛的时代&#xff0c;越来越多的人开始思考如何利用互联网去创造价值。现如今&#xff0c;互联网项目的形式多种多样&#xff0c;有些让我们的…

剑指offer——JZ79 判断是不是平衡二叉树 解题思路与具体代码【C++】

一、题目描述与要求 判断是不是平衡二叉树_牛客题霸_牛客网 (nowcoder.com) 题目描述 输入一棵节点数为 n 二叉树&#xff0c;判断该二叉树是否是平衡二叉树。 在这里&#xff0c;我们只需要考虑其平衡性&#xff0c;不需要考虑其是不是排序二叉树 平衡二叉树&#xff08;…

【Java 进阶篇】深入了解HTML表单标签

HTML&#xff08;Hypertext Markup Language&#xff09;表单标签是网页开发中的重要组成部分&#xff0c;用于创建各种交互式元素&#xff0c;允许用户输入、提交和处理数据。本文将深入探讨HTML表单标签&#xff0c;包括如何创建表单、各种输入元素、表单属性以及一些最佳实践…