【C语言基础】:字符串函数(二)

文章目录

      • 一、strncpy函数的使用
      • 二、strncat函数的使用
      • 三、strncmp函数的使用
      • 四、strstr函数的使用和模拟实现
        • 4.1 strstr函数的使用
        • 4.2 strstr函数的模拟实现
      • 五、strtok函数的使用
      • 六、strerror函数的使用

上节回顾:【C语言基础】:字符函数和字符串函数

一、strncpy函数的使用

函数原型:

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

strncpystrcpy的区别:
在这里插入图片描述
在这里插入图片描述
从函数的参数来看,strncpystrcpy前面几个参数都是char * destination, const char * source,也就是将source的内容拷贝到destination里面去,但是strncpy函数多了一个参数size_t num,也就是对拷贝的内容有了数量上的限制,而strcpy则对拷贝的内容没有数量上的限制。

从字符串中复制字符
将源的第一个num字符复制到目标。如果在复制num个字符之前找到源C字符串的结尾(用空字符表示),则目的地将用零填充,直到向其写入总数为num个字符。

如果source大于num,则不会在destination的末尾隐式添加空字符。因此,在这种情况下,destination不应被视为以空结束的C字符串(这样读取会溢出)。

【strncpy的使用】

#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };
	strncpy(arr2, arr1, 3);
	printf("%s\n", arr2);
	return 0;
}

在这里插入图片描述
使用strncpy注意事项

  1. 是否将 \0拷贝
    首先我们要知道将arr1中的内容拷贝到arr2中,那是否会将arr1中的 \0也拷贝到arr2中呢?其实要验证这一点很简单,我们将arr2中的内容改成xxxxxxxxxxxx,然后再拷贝调试看一下。
#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = "xxxxxxxxxxxx";
	strncpy(arr2, arr1, 3);
	printf("%s\n", arr2);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
在调试的时候可以看到,strncpy并没有将 \0给拷贝过去,另外我们运行之后可以看到打印之后把abc之后的x也打印出来了,如果 \0也拷过来的话,那么用\s打印的话遇到 \0就会停止打印。

  1. 拷贝数量大于原字符数量
    在使用strncpy时如果原字符串的数量小于要求拷贝的数量会怎么样呢?arr1中有abcdef六个字符,那如果要求拷贝10个字符该怎么办呢?我们还是来调试看一下。
#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = "xxxxxxxxxxxxxxx";
	strncpy(arr2, arr1, 10);
	printf("%s\n", arr2);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
调试之后可以看到,但原字符串数量不够时,会用 \0来补充,不够10位就用 \0来不够10位。用/s打印到 \0就会停止,后面即使有内容也不会打印。

二、strncat函数的使用

函数原型:

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

从字符串中添加字符
将源的第一个num字符附加到目标,加上一个结束的空字符。
如果source中的C字符串的长度小于num,则只复制结束空字符之前的内容。

和上面的类似strncat和strcat的区别也是在于strncat函数多了一个size_t num的参数。
在这里插入图片描述
在这里插入图片描述
【strncat的使用】

#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = "xx";
	strncat(arr2, arr1, 3);
	printf("%s\n", arr2);
	return 0;
}

在这里插入图片描述
注意事项

  1. 是否追加 \0
    这里因为arr2的xx后面都是 \0,追加之后无法看出是否将 \0也追加了进来,但我们知道strcar是从 \0开始追加的,这里我们让他提前追加就行了。
    在这里插入图片描述
    可以看到,strncat会将 \0也追加进来。
  2. 追加字符数量大于原字符
    在这里插入图片描述
    调试之后可以看到,如果追加的数量大于原字符数量,那么将 \0追加完追后就不会继续追加了。

三、strncmp函数的使用

函数原型:

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

比较两个字符串的字符
比较C字符串str1和C字符串str2的最多num个字符。
这个函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续执行后面的对,直到字符不相同,直到达到终止的空字符,或者直到两个字符串中的num字符匹配,以先发生的为准。

在这里插入图片描述
在这里插入图片描述

【strncmp函数的使用】

#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abqdefgui";
	int ret = strncmp(arr1, arr2, 3);
	printf("%d\n", ret);
	return 0;
}

在这里插入图片描述
第三个参数就是最多比较的次数,如果在这之前就比较出了结果,那么后面的也将不会再比较。

四、strstr函数的使用和模拟实现

函数原型:

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

查找子字符串
返回指向str1中str2第一次出现的指针,如果str2不是str1的一部分,则返回空指针。
匹配过程不包括结束的空字符,但它到此为止。
字符串的比较匹配不包含 \0 字符,以 \0 作为结束标志

4.1 strstr函数的使用
#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[] = "this is an apple\n";
	const char arr2[] = "is";
	char arr3[] = "pa";
	char* p = strstr(arr1, arr2);
	char* pa = strstr(arr1, arr3);
	printf("%s\n", p);
	printf("%s\n", pa);
	return 0;
}

在这里插入图片描述
返回arr2在arr1中第一次出现的指针,如果没有匹配到,就返回空指针。

4.2 strstr函数的模拟实现

模拟实现的函数参数类型以及返回类型:从原函数可以看出,参数是接收的arr1和arr2数组首元素的地址,也就是char* 类型的,我们只是用来进行比较匹配,为了防止被修改,参数前面都要加const进行修改。原函数的返回类型是arr2在arr1中第一次出现的指针,所以返回类型就是 char*。

char* my_strstr(const char* str1, const char* str2)
{

}

模拟分析:

第一种情况
str1:abcdef\0
str2:bcd\0

这里arr1从b开始匹配一次就能匹配成功,当str2的指针指向\0时,就说明已经匹配到了,但需要有一个指针记录从哪里开始匹配的。

第二种情况
str1:abbbcdef\0
str2:bbc\0

这种情况就比较复杂,当str1中的第一个b和str2中的b匹配时,str2中的第一个和第二个都能匹配上,当第三个str2是c,而str1却是b,这时候又要回去重新进行匹配,但str2中的指针已经指向c了,没办法回去,所以这里不仅需要一个指针记录开始匹配的位置,还需要一个指针指向str2的开始位置,方便那个指针能指向回来。

第三种情况:
str1:abcdef\0
str2:bbq\0

这种情况最简单,就是匹配不到。

#include<stdio.h>

char* my_strstr(const char* str1, const char* str2)
{
	const char* s1 = NULL;
	const char* s2 = NULL;
	const char* cur = str1;
	if (*str2 == '\0')
		return (char*)str1;
	while (*cur)
	{
		s1 = cur;
		s2 = str2;
		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')  // 匹配完成
		{
			return (char*)cur;
		}
		cur++;
	}
	return NULL;  // 没找到
}

int main()
{
	char arr1[] = "this is an apple\n";
	const char arr2[] = "is";
	char arr3[] = "pa";
	char* p = my_strstr(arr1, arr2);
	char* pa = my_strstr(arr1, arr3);
	printf("%s\n", p);
	printf("%s\n", pa);
	return 0;
}

在这里插入图片描述

五、strtok函数的使用

函数原型:

char * strtok ( char * str, const char * sep );
  1. sep参数指向⼀个字符串,定义了用作分隔符的字符集合
  2. 第⼀个参数指定⼀个字符串,它包含了0个或者多个由sep字符串中⼀个或者多个分隔符分割的标
    记。
  3. strtok函数找到str中的下⼀个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串⼀般都是临时拷贝的内容并且可修改。)
  4. strtok函数的第一个参数不为NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  5. strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  6. 如果字符串中不存在更多的标记,则返回 NULL 指针。

【strtok函数的使用】

#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[] = "zhangxu@qq.com";
	char arr2[30] = { 0 };
	strcpy(arr2, arr1);
	const char* sep = "@.";
	char* ret = NULL;
	for (ret = strtok(arr2, sep); ret != NULL; ret = strtok(NULL, sep))
	{
		printf("%s\n", ret);
	}
	// ret = strtok(arr2, sep);
	// printf("%s\n", ret);

	// ret = strtok(NULL, sep);
	// printf("%s\n", ret);

	// ret = strtok(NULL, sep);
	// printf("%s\n", ret);
	return 0;
}

在这里插入图片描述

六、strerror函数的使用

函数原型:

char * strerror ( int errnum );

strerror 函数可以把参数部分错误码对应的错误信息的字符串地址返回来。
在不同的系统和C语⾔标准库的实现中都规定了一些错误码,⼀般是放在 errno.h 这个头⽂件中说明
的,C语言程序启动的时候就会使用一个全局的变量errno来记录程序的当前错误码,只不过程序启动
的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应
的错误码,存放在errno中,而一个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是
有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。

【strerror函数的使用】

#include<stdio.h>
#include<string.h>

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

在这里插入图片描述

举例

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
	FILE* pFile;
	pFile = fopen("unexist.ent", "r");
	if (pFile == NULL)
		printf("Error opening file unexist.ent: %s\n", strerror(errno));
	return 0;
}

在这里插入图片描述

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

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

相关文章

【ubuntu20.04+tensorflow-gpu1.14配置】

ubuntu20.04tensorflow-gpu1.14配置 目录0. 版本注意事项说明1. 个人目录下载后配置系统环境变量2. anaconda配置所有环境&#xff08;过程简便&#xff0c;但容易出现不兼容问题&#xff09;3. 验证tensorflow-gpu4. 一些细节 目录 总结出两种方法 个人目录 下载cuda和cudnn…

分库分表场景下多维查询解决方案(用户+商户)

在采用分库分表设计时&#xff0c;通过一个PartitionKey根据散列策略将数据分散到不同的库表中&#xff0c;从而有效降低海量数据下C端访问数据库的压力。这种方式可以缓解单一数据库的压力&#xff0c;提升了吞吐量&#xff0c;但同时也带来了新的问题。对于B端商户而言&#…

赋能智能未来:AI大模型的学习之旅

随着人工智能的迅速发展&#xff0c;AI大模型已经成为技术领域的一个热点。这些模型以其强大的数据处理能力和预测精度&#xff0c;正在不断推动着科技的边界&#xff0c;并且在医疗、金融、交通等多个行业中显示出了巨大的潜力。然而&#xff0c;构建和训练一个高效的AI大模型…

C#非强签名dll搜索顺序

由于不是强签名dll&#xff0c;所以无效考虑全局程序集缓存 (GAC)。 预备工作 新建解决方案ClassLibrary1,新建类库ClassLibrary1,新建控制台程序ShowDllLoc。 利用VS添加引用。 一&#xff0c;利用app.config设置codebase&#xff0c;设置dll的加载路径为&#xff1a;code…

探索海外市场舆情:云手机助力企业赢得全球竞争

在全球化的趋势下&#xff0c;越来越多的企业将目光投向海外市场&#xff0c;迎接着无尽的商机与挑战。然而&#xff0c;随之而来的是境外市场舆情的复杂变化&#xff0c;对企业的声誉和发展带来了潜在风险。如何准确、及时地掌握境外市场的舆情动向&#xff0c;成为了企业必须…

RabbitMQ介绍及搭建

架构 RabbitMQ是实现了高级消息队列协议&#xff08;AMQP&#xff09;的开源消息代理软件&#xff0c;使用erlang语言编写&#xff0c;依赖Erlang环境运行。 Broker&#xff1a;运行消息队列服务进程的节点&#xff0c;包含Exchange、Queue&#xff1b; Producer&#xff1a;消…

C语言:自定义类型:结构体

目录 1. 前言 2. 结构体初识 3. 结构体创建变量 3.1 方法一 3.2 方法二 4. 结构体初始化 5. 结构体自引用 6. 结构体的大小 6.1 结构体对齐规则 6.2 常规结构体 6.3 结构体成员含数组 6.4 结构体嵌套结构体 6.5 为什么存在结构体对齐&#xff1f; 6.6 修改默认对…

idea创建angular项目

1.idea创建项目 idea&#xff1a;2023.2.3版本 不做赘述&#xff0c;我这里是创建模块&#xff0c;创建项目的话大同小异 2.创建完成后注意一下红色部分&#xff0c;后期需要 3.进入项目根目录 注意&#xff1a;一定要进入项目根目录&#xff0c;就是我们上面红色方框部分&a…

Java安全 反序列化(4) CC1链-LazyMap版

Java安全 反序列化(4) CC1链-LazyMap版 实验环境:存在漏洞的版本 commons-collections3.1-3.2.1 jdk 8u71之后已修复不可利⽤ 文章目录 Java安全 反序列化(4) CC1链-LazyMap版一.跟踪挖掘CC1_LazyMap原理二.完整CC1_Lazy版Poc 接着上一篇文章我们通过ChainedTransFormer实现任意…

vue3+threejs新手从零开发卡牌游戏(二):初始化场景

在删掉初始化中一些没用的代码后&#xff0c;在views目录下新建game文件夹&#xff0c;在里面新建一个index.vue&#xff0c;这里就当成游戏的主入口。 目录结构如下&#xff1a; 下面开始尝试创建场景&#xff1a; 一、添加一个div作为threejs的画布对象&#xff0c;之后整个…

电网的正序参数和等值电路(一)

本篇为本科课程《电力系统稳分析》的笔记。 本篇为第二章的第一篇笔记。 电力系统正常运行中&#xff0c;可以认为系统的三相结构和三相负荷完全对称。而对称三相的计算可以用一相来完成&#xff0c;其中所有给出的标称电压都是线电压的有效值&#xff0c;假定系统全部是Y-Y型…

如何将软件大规模部署到基于 Linux 的 IoT 设备

物联网( IoT) 改变了我们与世界互动的方式&#xff0c;将无数设备连接到互联网&#xff0c;从我们家中的智能恒温器到制造工厂的工业传感器。这些 IoT 设备的很大一部分依赖于 Linux 操作系统&#xff0c;因为它具有灵活性、稳健性和开源特性。 将软件大规模部署到基于 Linux …

react-jsx

react04 jsx语法 - 01 基础知识&#xff1a; jsx javascript xml(html) 把js和heml标签混合到一起 react视图编写及构建的简要流程 &#xff1a; 如何在react中使vs code支持格式化和快捷键提示&#xff1a;1, 2,修改文件后缀为jsx&#xff0c;因为webpack的打包规则中可以…

【蓝桥杯】RMQ(Range Minimum/Maximum Query)

一.概述 RMQ问题&#xff0c;是求区间最大值或最小值&#xff0c;即范围最值问题。 暴力解法是对每个询问区间循环求解&#xff0c;设区间长度n&#xff0c;询问次数m&#xff0c;则复杂度是O ( nm )。 一般还可以使用线段树求解&#xff0c;复杂度是O(mlogn)。 但还有一种…

守护数据安全,远离.locked勒索病毒:有效防御策略分享

导言&#xff1a; 随着信息技术的飞速发展&#xff0c;网络空间的安全问题日益凸显&#xff0c;其中勒索病毒便是一种严重的网络安全威胁。近年来&#xff0c;.locked勒索病毒逐渐进入人们的视野&#xff0c;其强大的破坏性和高隐蔽性使得许多个人和企业深受其害。本文将对.lo…

比堆垛机方案省电65% 实施快50% 四向车系统柔性化建设进程异军突起

对物流企业来说&#xff0c;供应链的数智化升级并非“赶时髦”&#xff0c;它需要找到一个既懂物流行业&#xff0c;又有数字化技术作基础的仓储方案提供商。而河北沃克基于AI底层技术、软硬一体化产品体系和技术创新行业经验双轮驱动的业务团队等“技术产品人才”三位一体优势…

AndroidStudio 由dolphin升级到giraffe,出现“gradle project sync failed“

1 现象描述 将AS由之前的dolphin版本升级到giraffe之后&#xff0c;接着打开以前的Android project&#xff0c;出现了"Gradle project sync failed…"的异常提示&#xff0c;在build面板中并没有出现project sync过程中报错的日志。 异常提示如下图所示&#xff1a…

知识蒸馏——深度学习的简化之道 !!

文章目录 前言 1、什么是知识蒸馏 2、知识蒸馏的原理 3、知识蒸馏的架构 4、应用 结论 前言 在深度学习的世界里&#xff0c;大型神经网络因其出色的性能和准确性而备受青睐。然而&#xff0c;这些网络通常包含数百万甚至数十亿个参数&#xff0c;使得它们在资源受限的环境下&…

【OpenGL手册19】几何着色器

目录 一、说明 二、渲染管线的逻辑 三、几何着色器 四、使用几何着色器 五、造几个房子 六、几何着色器渲染爆破物体 一、说明 如果说用顶点和片段着色器干了什么&#xff0c;其实不多。加入几何着色器&#xff0c;能够加大渲染能力&#xff0c;简化数据结构&#xff0c;…

前端项目部署后,如何提示用户版本更新

目录 前言解决方案1、public目录下新建manifest.json2、写入当前时间戳到manifest.json3、检查版本更新4、woker线程5、入口文件引入 可能出现的问题好书推荐 前言 项目部署上线后&#xff0c;特别是网页项目&#xff0c;提示正在操作系统的用户去更新版本非常 important。一般…