在21世纪的我用C语言探寻世界本质——字符函数和字符串函数(2)

news2025/2/25 10:18:32

在这里插入图片描述

人无完人,持之以恒,方能见真我!!!
共同进步!!

文章目录
  • 一、strncpy函数的使用
  • 二、strncat函数的使用
  • 三、strncmp函数的使用
  • 四、strstr的使用和模拟实现
  • 五、strtok函数的使用
  • 六、strerror和perror函数的使用
    • 1.strerror函数
    • 2.perror函数

一、strncpy函数的使用

我们之前学习的strcpy的作用是把源字符串拷贝到目标空间内,而且经过我们的模拟实现,我们也意识到它拷贝的时候会把目标空间的内容给替换了,我们可以来测试一下:

在这里插入图片描述

可以看到,将arr2的内容拷贝到arr1中时,把arr1原本的内容替换了,那假设我们不想让它全部拷贝过来,只是拷取一部分OK不OK

这个时候就要引入我们带n的字符串函数,那个多出来的n就代表数量,是我们想拷贝字符串时,要拷贝的字符的个数
而不带n的字符串函数和带n的字符串函数的根本区别是带n的字符串函数更灵活,可以指定拷贝的字符的个数,所以也叫带n的字符串函数为受限制的字符串函数,不带n的为不受限制的字符串函数

接下来我们来看看本次讲到的strncpy函数的原型:

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

它的参数与strcpy的区别就是多了最后一个参数,它的作用就是指定我们要拷贝的字符的个数
它的特点如下:

  • 拷num个字符从源字符串到标空间
  • 如果源字符串的度于num,则拷完源字符串之后,在标的后边追加,直到num个
#include <stdio.h>
#include <string.h>

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

在这里插入图片描述

可以看到只拷贝了arr2中的前三个字符进arr1,并且覆盖了arr1的前三个字符,这就是strncpy的作用
至于strncpy的模拟实现,与strcpy的模拟实现相似,这里就不再过多讲解

二、strncat函数的使用

strncat也是带n家族的一员,多n的原因和strncpy差不多,就是用来指定要追加到目标空间的字符的个数,它的原型如下:

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

它的特点是:

  • 将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加个 字符
  • 如果source指向的字符串的字符个数于num的时候,只会将字符串中到 的内容追加到destination指向的字符串末尾

了解到这里我们来尝试使用一下strncat,把arr2的前3个字符追加到arr1里,如下:

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

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

运行结果:

在这里插入图片描述

如果后面的第三个参数num大于arr2的大小会发生什么呢?
运行结果:

在这里插入图片描述

调试结果:

在这里插入图片描述

三、strncmp函数的使用

strncmp的作用就是比较str1和str2的前num个字符,如果相等就继续往后较,最多较num个字

如果在这num个字符中发现不样,就看此时哪个字符串更大,前者大就返回大于0的数,如果后者大,就返回小于0的数如果num个字符都相等,就是相等返回0

我们来看看它的原型:

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

我们来使用它比较arr1和arr2前三个字符的大小:

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

int main()
{
	char arr1[20] = "abcdef";
	char arr2[20] = "ghijklmn";
	int ret = strncmp(arr1, arr2, 3);
	printf("在前三个字符的比较中,");
	if (ret > 0)
		printf("arr1 > arr2
");
	else if (ret < 0)
		printf("arr1 < arr2
");
	else
		printf("arr1 = arr2
");
	return 0;
}

运行结果:

在这里插入图片描述

四、strstr的使用和模拟实现

这是一个对我们来说比较新的函数,我们来仔细介绍一下使用方法以及它的模拟实现,它的作用就是返回后一个字符串在前一个字符串中第次出现的位置

并且字符串的较匹配不包含 字符,以 作为结束标志

接下来我们来看看strstr的原型:

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

它的原型中参数看起来很简单,就是两个字符串,那它的返回值是啥捏?
有两种情况:

  • 如果在字符串str1中找到了字符串str2,那么就返回str1中找到str2的起始位置,
  • 如果没有在字符串str1中找到字符串str2,那么就返回一个NULL

所以在使用的时候,我们就可以通过它的返回值来确认是否找到对应的字符串,如果返回非空指针,那么就是找到了,返回空指针就是没有找到,接下来我们用实例来加深理解:

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

void isfind(const char* x)
{
	if (x)
		printf("找到了
");
	else
		printf("没找到
");
}

int main()
{
	char arr1[20] = "abcdef";
	char arr2[20] = "ghijklmn";
	char arr3[20] = "cde";
	isfind(strstr(arr1, arr2));
	isfind(strstr(arr1, arr3));
	return 0;
}

运行结果:

在这里插入图片描述

我们来模拟实现一下 strstr

  1. 函数命名:my_strstr
  2. 函数参数:可以照抄strstr函数的原型,如下:
const char* my_strstr ( const char* str1, const char* str2);
  1. 函数实现:
    (1)老样子,assert进行断言
    (2)然后我们来分析这个函数可能出现的情况,按照我们正常去想,就会想到首先就去看str1和str2指向的字符相不相等,不相等就两个指针都++,往后找,直到它们指向的字符相等
    (3)随后往后开始找,但是会出现一个问题,万一这一次匹配不上,只有前几个字符相等,后面并不相等,那我们怎么找到之前开始匹配的位置呢?如图:

在这里插入图片描述

(4)所以我们让str1和str2直接往后走是不妥的,这样一旦匹配失败,我们就记不住当时开始匹配的位置,也就不能进行下一次匹配,所以我们可以重新创建三个指针变量
(5)有两个用来装下str1,一个用来代替str1往后走,一个用来记住当前第一次匹配的位置,至于str1就老老实实待在原地,不要动
(6)还有一个用来装str2,这样如果匹配失败,就把str2重新赋值给这个变量,让它重新指向str2的开头,创建如下:

const char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* s1 = str1;//代替str1用来往后匹配字符
	const char* s2 = str2;//代替str2用来往后匹配字符
	const char* cp = str1;//记录开始匹配字符的位置
}

(7)有了以上的经验,我们为了避免犯错,可以使用思路比较简单的暴力匹配,就是创建一个循环,我们对cur进行解引用,只要里面不是结束标志,我们就进入循环,然后看这个位置的字符是否和str2的第一个字符相等

(8)如果不相等,我们就让cp++,让我们的当前位置往前挪动一下,如果相等,就进行完整的匹配,这里还是有两种情况,一是如果完全匹配那么就返回cp,就是我们开始匹配时的位置,二是如果不能完全匹配那么就还是让cp++,并且将cp重新赋值给s1,将str2重新赋值给s2

(9)现在我们就来看进行一次匹配的过程,也很简单,我们还是创建一个while循环,如果s1和s2解引用不是 ,并且解引用后相等,那我们就让s1和s2加加,一直往后走,当循环结束时,我们就判断s2解引用后是否是 ,如果是说明完全匹配上了,就返回cp,不是那么说明没有完全匹配,就让cp++,开始下一次循环查找

(10)最后一步就是,如果我们遍历了s1中的所有字符,还是发现两个字符串没有完全匹配的地方,就直接返回空指针NULL

const char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	if(*str2 == '')
	{
	  return (char*)str1;
	}
	const char* s1 = str1;
	const char* s2 = str2;
	const char* cp = str1;

	while (*cp)
	{
		s1 = cp;//重新赋值
		s2 = str2;//重新赋值
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '')
			return cp;
		cp++;
	}
	return NULL;
}

这是一般的情况:

在这里插入图片描述

我们换一种更复杂的情况测试:

在这里插入图片描述

可以看到我们实现的函数还是成功帮我们完成了任务,这里的strstr函数的实现就到此结束了,模拟实现这个函数要考虑多种情况,希望大家能够下来多敲敲,欢迎大家在评论区留言!

五、strtok函数的使用

这也是一个新函数,它的作用是什么呢?它可以按照我们给出的分隔符来分割我们的字符串,现在我们先来了解一下它的原型:

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

接下来我们来总结一下它的特点:

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

比如我们的邮箱由两个分隔符分隔开来,就是@符合和(.)点号,我们想把这个邮箱地址分隔开来可以这样操作:

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

int main()
{
	char arr1[] = "BANZHANCHAXIANG@163.com";
	char arr2[] = "@.";
	char* ret1 = strtok(arr1, arr2);
	char* ret2 = strtok(NULL, arr2);
	char* ret3 = strtok(NULL, arr2);
	printf("%s
%s
%s
", ret1, ret2, ret3);
	return 0;
}

运行结果:
在这里插入图片描述
可以看到我们成功把这个邮箱分成了三个部分,但是有一个问题,这里有两个分隔符我们就写了三行代码,这样的代码看起来是不是很挫,而且如果有n个分隔符,就会变得很麻烦,这时候就可以用下面的方法

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

int main()
{
	char arr1[] = "BANZHANCHAXIANG@163.com";
	char arr2[] = "@.";
	char* p = NULL;
	for (p = strtok(arr1, arr2); p != NULL; p = strtok(NULL, arr2))
	{
		printf("%s
", p);
	}
	return 0;
}

运行结果:

在这里插入图片描述

我们利用for循环初始化只进行一次的技巧来调用第一次的strtok,并且将它赋值给p指针,随后我们调用strtok的第一个参数就只需要传空指针,就可以写在循环的调整部分

而中间的循环结束条件为什么设置为不等于NULL呢?因为当我们的字符串分隔完毕,没有分隔符后,函数就会返回一个空指针,p也就等于空指针了,此时用来退出循环刚好

六、strerror和perror函数的使用

1.strerror函数

strerror 函数可以把参数部分错误码对应的错误信息的字符串地址返回来

在不同的系统和C语标准库的实现中都规定了些错误码,般是放在errno.h 这个头件中说明的,C语程序启动的时候就会使个全局的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表没有错误

但是如果当我们在使标准库中的函数的时候发了某种错误,就会将对应的错误码,存放在errno中,而个错误码的数字是整数很难理解是什么意思,所以每个错误码都是有对应的错误信息的

strerror函数就可以将错误对应的错误信息字符串的地址返回,可以用%s的形式将错误信息打印出来

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

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

在Windows11+VS2022环境下输出的结果如下:

在这里插入图片描述

我们可以测试使用文件操作测试一下:

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
 FILE * pFile;
 pFile = fopen ("data.txt","r");
 if (pFile == NULL)
 printf ("fopen: %s
", strerror(errno));
 return 0;
}

在当前路径的代码目录上并没有data.txt这个文件,自然不能打开文件进行读操作,所以这个代码会在errno.h中产生一个错误码,这个时候我们就把这个错误码打印出来
在这里插入图片描述

2.perror函数

接下来我们也可以了解下 perror 函数,perror函数的使用更加简单方便,可以直接将错误信息打印出来

perror函数的参数里可以写上可能出现错误的命令的名字,它可以打印参数部分的字符串后,再打印个冒号和个空格,再打印错误信息

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
 FILE * pFile;
 pFile = fopen ("data.txt","r");
 if (pFile == NULL)
 perror("fopen");
 return 0;
}

在这里插入图片描述

到这里我们一些常见的函数基本介绍完了,大家也可以自行去这个网站学习 cplusplus,下一期我们继续学习内存函数的使用和模拟实现!!!

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

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

相关文章

Cursor vs VSCode:主要区别与优势分析

Cursor - The AI Code Editor 1. AI 集成能力 Cursor的优势 原生AI集成&#xff1a; # Cursor可以直接通过快捷键调用AI # 例如&#xff1a;按下 Ctrl K 可以直接获取代码建议 def complex_function():# 在这里&#xff0c;你可以直接询问AI如何实现功能# AI会直接在编辑器中…

利用 360 安全卫士极速版关闭电脑开机自启动软件教程

在使用电脑的过程中&#xff0c;过多的开机自启动软件会严重拖慢电脑的开机速度&#xff0c;影响我们的使用体验。本教程中简鹿办公将详细介绍如何使用 360 安全卫士极速版关闭电脑开机自启动软件&#xff0c;让您的电脑开机更加迅速流畅。 一、打开 360 安全卫士极速版 在电…

电子信息工程自动化 基于单片机的居室安全报警系统

摘要 本课题设计了基于STM32F103C6T6单片机为主控核心的居室安全报警系统。为了解决家庭居室的安全监控&#xff0c;通过温湿度芯片SHT30、烟雾传感器MQ-2、天然气传感器MQ-4来获取居室的温湿度、烟雾、天然气含量&#xff0c;使用了一个热释电传感器、菲涅耳透镜、红外传感信…

2025年的预测:从扩容到隐私的Web3全景图

2025年&#xff0c;Web3领域将迎来更多技术突破与创新应用。从扩容技术的蓬勃发展到隐私保护的「ChatGPT时刻」&#xff0c;区块链生态正在逐步完善和扩展。这篇文章基于Equilibrium的年度预测报告&#xff0c;梳理了Web3在未来一年的关键趋势&#xff0c;提供了一幅从扩容到隐…

挑战用React封装100个组件【010】

Hello&#xff0c;大家好&#xff0c;今天我挑战的组件是这样的&#xff01; 今天这个组件是一个打卡成功&#xff0c;或者获得徽章后的组件。点击按钮后&#xff0c;会弹出礼花。项目中的勋章是我通过AI生成的&#xff0c;还是很厉害的哈&#xff01;稍微抠图直接使用。最后面…

解决Windows与Ubuntu云服务器无法通过Socket(udp)通信问题

今天在写Socket通信代码的时候&#xff0c;使用云服务器自己与自己通信没有问题&#xff0c;但是当我们把客户端换为Windows系统的时候却无法发送信息到Linux当中&#xff0c;耗时一上午终于搞定了&#x1f612;。 问题&#xff1a; 如上图&#xff0c;当我在windows的客户端…

MYSQL - 索引详解

一 什么是索引&#xff1f; 实际上在上一篇介绍MYSQL的体系结构当中我们稍微提及了一点&#xff0c;在引擎层&#xff0c;我们提到不同的引擎对应的索引的实现方式&#xff0c;选择是不一样的。 简单理解&#xff0c;索引&#xff08;index&#xff09;其实就是一种帮助MYSQL高…

美联众合,24H京西宠物医院,魏燕庸医误诊

16 骚饼发布了一篇小红书笔记&#xff0c;快来看吧&#xff01; &#x1f606; 5srdmSgkXxTDw8w &#x1f606; http://xhslink.com/a/3N7dcpgca470&#xff0c;复制本条信息&#xff0c;打开【小红书】App查看精彩内容&#xff01; 魏燕 在猫咪血常规指标&#xff1a;TP总蛋白…

outlook软件配置邮箱提示“到邮件服务器的加密连接不可用”

outlook软件配置邮箱提示“到邮件服务器的加密连接不可用” 问题描述&#xff1a; outlook软件里邮箱提示“已断开”或配置邮箱时提示“到邮件服务器的加密连接不可用”。 解决方案&#xff1a; 一、更改注册表&#xff08;可先导出备份&#xff09; winr&#xff0c;输入re…

【求助】Tinymce组件异常

版本号 { "tinymce/tinymce-vue": "^3.0.1", "tinymce": "^5.10.9", "vue": "^2.6.10", }问题&#xff1a; 就是红框处点击后没有菜单出现&#xff0c;下面是正常的

Y20030002 微信+Java+Jsp+Servlet+MySQL的问卷调查小程序的设计与实现 源代码 配置文档 全套资料

问卷调查微信小程序 1.摘要2. 系统开的背景和意义3. 国内外研究现状4. 系统功能5.界面展示6.源码获取 1.摘要 摘 要&#xff1a;本文深入研究并实现了一个基于微信小程序的问卷调查系统。微信小程序问卷调查系统借助于微信小程序的便捷性和普及性&#xff0c;为用户提供了一个…

Java 导出Excel高亮

Java 导出Excel高亮 1 依赖2 代码结果 1 依赖 <!-- hutool-all --> <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.34</version> </dependency><!-- Apache POI 主库 …

LabVIEW气缸摩擦力测试系统

基于LabVIEW的气缸摩擦力测试系统实现了气缸在不同工作状态下摩擦力的快速、准确测试。系统由硬件平台和软件两大部分组成&#xff0c;具有高自动化、精确测量和用户友好等特点&#xff0c;可广泛应用于精密机械和自动化领域。 ​ 项目背景&#xff1a; 气缸作为舵机关键部件…

SwiftUI 列表(或 Form)子项中的 Picker 引起导航无法跳转的原因及解决

概述 在 SwiftUI 的界面布局中&#xff0c;列表&#xff08;List&#xff09;和 Form 是我们秃头码农们司空见惯的选择。不过大家是否知道&#xff1a;如果将 Picker 之类的视图嵌入到列表或 Form 的子项中会导致导航操作无法被触发。 从上图可以看到&#xff1a;当在 List 的…

ansible基础教程(下)

一、playbook 简介&#xff1a; playbook 是 ansible 用于配置&#xff0c;部署&#xff0c;和管理被控节点的剧本。 通过 playbook 的详细描述&#xff0c;执行其中的一系列 tasks &#xff0c;可以让远端主机达到预期的状态。 使用场景&#xff1a; 像执行shell命令与写…

华为网络设备配置文件备份与恢复(上传、下载、导出,导入)

在日常运维工作中&#xff0c;会经常存在网络割接的情况&#xff0c;为了保证网络割接失败时能重新回退至原有配置&#xff0c;从而不影响原有的办公环境&#xff0c;在网络割接前的备份工作就非常有必要了。 备份方式&#xff1a;FTP 备份技术&#xff1a;PC客户端<---&g…

【计算机网络】期末速成(2)

部分内容来源于网络&#xff0c;侵删~ 第五章 传输层 概述 传输层提供进程和进程之间的逻辑通信&#xff0c;靠**套接字Socket(主机IP地址&#xff0c;端口号)**找到应用进程。 传输层会对收到的报文进行差错检测。 比特流(物理层)-> 数据帧(数据链路层) -> 分组 / I…

<工具 Claude Desktop> 配置 Brave Search MCP Server

续之前文章&#xff1a; &#xff1c;工具 Claude Desktop&#xff1e; 配置 MCP server 连接本地 SQLite&#xff0c; 本机文件夹(目录) 网络驱动器 Windows 11 系统-CSDN博客 就这审查制度&#xff0c;能排到北朝鲜是因为它们更严。 配置 Brave Search MCP Server 什么是 B…

城电科技 | 光伏景观长廊 打造美丽乡村绿色低碳示范区 光伏景观设计方案

光伏景观长廊是一种结合了光伏发电技术和零碳景观设计的新型公共公共设施&#xff0c;光伏景观长廊顶上的光伏板不仅可以为周边用电设备提供清洁电能&#xff0c;而且还能作为遮阳设施使用&#xff0c;为人们提供一个美丽又实用的休闲娱乐空间。 光伏景观长廊建设对打造美丽乡…

Gitee配置以及如何将本地项目提交到远程仓库

文章目录 准备远程仓库配置注册新建仓库 配置git 生成ssh&#xff0c;输入以下命令&#xff0c;然后连敲三次回车键配置公钥本地代码上传 准备 1.本地下载git 2.注册远程仓库账号 远程仓库配置 注册 官网&#xff1a;https://gitee.com 完成注册 新建仓库 头像->设置-…