`strchr` 字符串查找函数

1) 函数的概念与用途

strchr 是 C 标准库中的一个基础但极其重要的字符串处理函数,它的名字来源于"string chracter"(字符串字符)。这个函数的功能非常明确:在字符串中查找特定字符的第一次出现位置

可以将 strchr 想象成一个精准的探测器:给它一个字符串(如一段文本)和一个要查找的字符,它会从字符串开头开始扫描,一旦发现目标字符,就立即报告这个字符的准确位置。

典型应用场景包括:

  • 字符串解析:查找分隔符、特定标记或关键字符
  • 路径处理:在文件路径中查找目录分隔符(/\
  • 数据验证:检查字符串中是否包含特定字符(如电子邮件地址中的 @
  • 文本处理:在文档中查找特定字符或标记

与之前讨论的 strpbrk 函数相比,strchr 更加专注:strpbrk 查找字符集合中的任何一个字符,而 strchr 只查找单个特定字符。

调用 strchrstr, ch
从str起始位置开始扫描
当前字符 == ch?
返回指向该字符的指针
是字符串结尾'\0'?
返回NULL
移动到下一个字符

2) 函数的声明与出处

strchr 是 C 标准库(libc)的核心成员,声明在 <string.h> 头文件中:

#include <string.h>char *strchr(const char *str, int c);

这意味着在任何符合标准的 C 开发环境中,只需包含这个头文件即可使用该函数,无需额外链接其他库。

3) 参数详解:搜索目标与目标字符

  • const char *str

    • 作用:要被搜索的目标字符串(“探测区域”)
    • 要求:必须以 \0 结尾的有效字符串;如果传入 NULL,会导致未定义行为(通常是段错误)
  • int c

    • 作用:要查找的字符(“探测目标”)
    • 特点:虽然参数类型是 int,但实际上它会被转换为 char 类型进行处理
    • 特殊情况:如果要查找的字符是 '\0',函数将返回指向字符串结尾空字符的指针

4) 返回值:精确的位置指针

  • 成功时:返回指向 str 中第一次出现的字符 c 的指针

    • 这个指针直接指向原字符串中的内存位置,可以用于后续操作
    • 示例:如果 str"Hello"c'e',则返回指向 'e' 的指针
  • 失败时:返回 NULL

    • 表示在 str 中未找到字符 c
    • 重要:使用前必须检查返回值是否为 NULL,否则可能引发程序崩溃

5) 实战演示:多种使用场景

示例 1:基础用法 - 查找字符

#include <stdio.h>
#include <string.h>int main() {const char *text = "Hello, World!";char target = 'W';// 查找字符 'W'char *result = strchr(text, target);if (result != NULL) {int position = result - text;printf("找到字符 '%c',位置:%d\n", target, position);printf("从该位置开始的子串:\"%s\"\n", result);} else {printf("未找到字符 '%c'\n", target);}return 0;
}

示例 2:查找所有出现的位置

#include <stdio.h>
#include <string.h>int main() {const char *text = "Hello, World!";char target = 'l';const char *current = text;int count = 0;printf("查找字符 '%c' 的所有出现位置:\n", target);// 循环查找所有出现的位置while ((current = strchr(current, target)) != NULL) {int position = current - text;printf("位置 %d: '%c' (剩余字符串: \"%s\")\n", position, target, current);current++; // 移动到下一个字符继续查找count++;}printf("总共找到 %d 次\n", count);return 0;
}

示例 3:提取子字符串

#include <stdio.h>
#include <string.h>
#include <stdlib.h>int main() {const char *path = "/home/user/documents/file.txt";char separator = '/';// 查找最后一个分隔符const char *last_slash = strrchr(path, separator);if (last_slash != NULL) {// 提取文件名(分隔符后的部分)const char *filename = last_slash + 1;printf("完整路径: %s\n", path);printf("文件名: %s\n", filename);// 提取目录路径(分隔符前的部分)int dir_length = last_slash - path + 1;char *directory = (char*)malloc(dir_length + 1);strncpy(directory, path, dir_length);directory[dir_length] = '\0';printf("目录路径: %s\n", directory);free(directory);}return 0;
}

6) 编译方式与注意事项

编译命令:

gcc -o strchr_demo strchr_demo.c

关键注意事项:

  1. 空指针检查:使用返回值前必须检查是否为 NULL
  2. 字符串终止符:确保输入字符串以 '\0' 结尾,否则可能导致未定义行为
  3. 字符类型:注意第二个参数是 int 类型,但实际按 char 处理
  4. 查找空字符:可以查找 '\0',此时返回指向字符串结尾的指针
  5. 与相关函数的区别
    • strrchr():查找字符的最后一次出现位置
    • strpbrk(str, set):查找字符集合中的任何一个字符
    • strstr(str, substr):查找子字符串

7) 执行结果说明

示例 1 输出:

找到字符 'W',位置:7
从该位置开始的子串:"World!"

函数在字符串 "Hello, World!" 中找到了字符 'W',它位于位置 7(索引从 0 开始),并返回从该位置开始的子字符串。

示例 2 输出:

查找字符 'l' 的所有出现位置:
位置 2: 'l' (剩余字符串: "llo, World!")
位置 3: 'l' (剩余字符串: "lo, World!")
位置 10: 'l' (剩余字符串: "ld!")
总共找到 3 次

通过循环调用 strchr,找到了字符 'l' 在字符串中的所有出现位置。

示例 3 输出:

完整路径: /home/user/documents/file.txt
文件名: file.txt
目录路径: /home/user/documents/

使用 strrchr()(查找最后出现的位置)找到最后一个路径分隔符,然后分别提取目录路径和文件名。

8) 总结:strchr 的核心价值

strchr 是 C 语言字符串处理工具箱中最基础且必不可少的函数之一。它的价值在于:

  1. 高效简单:提供了一种直接的方法来查找字符串中的特定字符
  2. 广泛应用:是许多字符串处理操作的基础构建块
  3. 标准兼容:作为 C 标准库的一部分,具有高度的可移植性
字符串查找需求
如何选择函数?
查找单个特定字符
使用 strchr 或 strrchr
查找字符集合中任何一个字符
使用 strpbrk
查找子字符串
使用 strstr

最佳实践建议:

  1. 始终检查返回值:避免对 NULL 指针进行解引用
  2. 注意字符编码:对于非ASCII字符,确保理解当前环境的字符编码
  3. 考虑使用更安全的变体:在某些环境中,可以考虑使用更安全的函数如 strchr_s(C11)
  4. 性能考量:对于大量数据的重复查找,考虑使用更高效的算法

strchr 虽然简单,但却是 C 语言编程中不可或缺的工具。掌握它的正确用法和注意事项,对于编写健壮、高效的字符串处理代码至关重要。无论是处理用户输入、解析文件格式还是分析文本数据,strchr 都能提供简单而有效的解决方案。

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

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

相关文章

Redis 678

Redis 8 是当前的最新稳定版&#xff08;截至 2024 年中&#xff09;&#xff0c;它在 Redis 7 的基础上带来了更多重要改进。我们来对这三个主要版本进行一次全面的功能和性能对比。 核心演进脉络 Redis 6 (2020)&#xff1a;多线程时代的开创者。解决了网络 I/O 瓶颈&#xf…

【大白话解析】 OpenZeppelin 的 Address 库:Solidity安全地址交互工具箱​(附源代码)

🧩 一、这个文件是干嘛的?—— Address.sol 是个“工具箱” 你可以把这个 Address.sol文件理解为一个 ​​“工具箱”​​,里面装了一堆​​专门用来安全地跟别的地址(账户或合约)打交道的工具函数​​。 在区块链世界里,地址(address)可以是: ​​外部账户(EOA)…

漫谈《数字图像处理》之测不准原理

在数字图像处理中&#xff0c;提到的 “测不准原理” &#xff0c;和量子力学里由海森堡提出的 “不确定性原理” &#xff08;Heisenberg uncertainty principle&#xff0c;也叫海森堡测不准原理&#xff09;有一定的类比关系&#xff0c;但本质上并不是同一个概念。以下为详…

Linux服务测试

一、环境准备确认 确保 4 台主机&#xff08;APPSRV、STORAGESRV、ROUTERSRV、CLIENT &#xff09;网络连接正常&#xff0c;虚拟机网卡模式按要求设置&#xff08;APPSRV、STORAGESRV 为 NAT 模式&#xff1b;ROUTERSRV 为双网卡&#xff0c;NAT 仅主机模式&#xff1b;CLIE…

2.Shell脚本修炼手册---创建第一个 Shell 脚本

2. 创建第一个 Shell 脚本 文章目录2. 创建第一个 Shell 脚本2.1 什么是 Shell 脚本&#xff1f;2.1.1 脚本开头&#xff1a;告诉系统用什么程序执行2.1.2 脚本注释&#xff1a;给人看的 “说明书”2.1.3 bash 与 sh 的区别2.2 如何执行 Shell 脚本&#xff1f;方法 1&#xff…

Day22 顺序表与链表的实现及应用(含字典功能与操作对比)

day22 顺序表与链表的实现及应用&#xff08;含字典功能与操作对比&#xff09; 使用顺序表实现查字典功能 支持连续查询单词&#xff0c;输入 #quit 退出程序。数据格式示例如下&#xff1a; a\0 indef art one\r\n word mean [---buf--->] [---i--…

51单片机与stm32单片机,先学习哪一个?

纠结 51 单片机和 STM32 该先学哪个&#xff0c;就像刚学开车的人在自动挡和手动挡之间打转。有人一上来就爱开自动挡&#xff0c;踩着油门就能跑&#xff0c;不用琢磨换挡踩离合的门道&#xff1b;有人偏要从手动挡练起&#xff0c;哪怕起步时熄十几次火&#xff0c;也得搞明白…

DS 0 | 数据结构学习:前言

数据结构是CS最基础、最重要的课程之一在学习数据结构时&#xff0c;通常来讲&#xff0c;学生遇到的难点不在于对数据结构的理解&#xff0c;而在于如何写程序。即编写特定的程序&#xff0c;来实现这些数据结构&#xff0c;特别是如何按照面向对象思想将一个个数据结构设计成…

JVM-(8)JVM启动的常用命令以及参数

JVM启动的常用命令以及参数 在上文 JVM 堆内存逻辑分区 中已经使用过一些 jvm 启动命令&#xff0c;本文着重讲述JVM启动命令用法以及一些常用的参数 一. 基本命令格式 java [options] classname [args...] java [options] -jar filename.jar [args...]① [options] - 命令行…

GO学习记录七——上传/下载文件功能,添加启动运行工具

本来计划是学习Docker部署的&#xff0c;研究了一天没搞出来&#xff0c;得出结论是需要翻墙&#xff0c;懒得弄了&#xff0c;暂时放置。 一、以下是&#xff0c;上传/下载代码&#xff0c;和之前是重复的&#xff0c;只多添加了&#xff0c;上传/下载功能。 测试目录为工程根…

SQL中对视图的操作命令汇总

以下是基于搜索结果整理的SQL视图操作命令汇总&#xff0c;按功能分类说明&#xff1a; 一、创建视图 使用 CREATE VIEW 语句定义视图&#xff0c;需指定视图名称和基础查询表达式&#xff1a; CREATE VIEW view_name AS SELECT column1, column2, ... FROM table_name WHER…

【Spring Cloud 微服务】2.守护神网关Gateway

目录 1.API网关的作用 2.Spring Cloud Gateway 是什么&#xff1f; 3.核心由来与背景 1. 微服务架构的挑战&#xff1a; 2. API 网关模式的兴起&#xff1a; 3. Zuul 的局限性&#xff1a; 4. Spring Cloud Gateway 的诞生&#xff1a; 4.核心特征&#xff1a; 5.核心概…

解读商业智能BI,数据仓库中的元数据

之前的文章讨论过数据分析、数据治理、数据仓库等等&#xff0c;即使是非业内人员从字面意思&#xff0c;也是可以了解一二的&#xff0c;但是&#xff0c;很多人对于元数据可能就比较陌生了。那么&#xff0c;今天我们就来聊一聊元数据管理。数据仓库要说元数据&#xff0c;那…

3 种无误的方式删除 Itel 手机上的短信

如果你希望释放存储空间、保护隐私&#xff0c;或者准备出售或转让手机&#xff0c;删除 Itel 手机上的短信是一个实用的步骤。无论是收件箱中充斥着垃圾短信、过时的对话还是敏感内容&#xff0c;删除不需要的短信可以让你的消息体验更加干净和安全。本文将向你介绍 3 种简单且…

【学习笔记】网络安全专用产品类别与参考标准

一、基本标准 1.1 关键设备 网络关键设备认证依据的强制标准为 GB 40050-2021。 1.2 专用产品 网络安全专用产品认证依据的强制标准为 GB 42250-2022。 二、数据备份与恢复产品标准 相关标准&#xff1a; GB/T 29765-2021《信息安全技术 数据备份与恢复产品技术要求与测试评…

Pytho“张量”(Tensor)和 Java的“向量”(Vector)区别和联系

在Python和Java中&#xff0c;“张量”&#xff08;Tensor&#xff09;和“向量”&#xff08;Vector&#xff09;是两个不同语境下的概念&#xff0c;它们的设计目标、功能和应用场景存在显著差异&#xff0c;但也存在一定的共性。以下从区别和联系两方面详细说明&#xff1a;…

Ubuntu部署K8S集群

Ubuntu部署K8S集群 本例以三台Ubuntu24.04为例,1master节点2worker节点 环境准备 修改hostname,三台服务器分别执行 hostnamectl set-hostname k8s-master01hostnamectl set-hostname k8s-worker01hostnamectl set-hostname k8s-worker02 配置静态ip(不同系统修改方法略微差…

openEuler系统安装Ascend Docker Runtime的方法

在openEuler系统中使用NPU前一定要安装Ascend Docker Runtime,也是在安装CANN和mis-tei前的必备工作。 使用容器化支持、整卡调度、静态vNPU调度、动态vNPU调度、断点续训、弹性训练、推理卡故障恢复或推理卡故障重调度的用户,必须安装Ascend Docker Runtime。 下面是具体的安…

控制对文件的访问:Linux 文件系统权限管理总结

在 Linux 系统中&#xff0c;文件权限是保障系统安全和数据完整性的核心机制。红帽企业 Linux 9.0通过一套灵活且精细的权限控制体系&#xff0c;让用户能够精确管理文件和目录的访问范围。本章将系统梳理 Linux 文件系统权限的核心概念、管理方法及高级应用&#xff0c;为系统…

ansible中roles角色是什么意思?

文章目录一、介绍二、Ansible Roles目录编排三、创建role四、playbook调用角色五、roles中tags使用免费个人运维知识库&#xff0c;欢迎您的订阅&#xff1a;literator_ray.flowus.cn 一、介绍 角色是ansible自1.2版本引入的新特性&#xff0c;用于层次性、结构化地组织playbo…