当前位置: 首页 > news >正文

C 进阶 — 字符函数和字符串函数 ( 二 )

C 进阶 — 字符函数和字符串函数 ( 二 )

书接上回 C 进阶 — 字符函数和字符串函数 ( 一 )

1.9 strtok

参考资料 strtok 函数用法详解

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

strtok 是 [C 标准库](https://so.csdn.net/so/search?q=C 标准库&spm=1001.2101.3001.7020)中的字符串分割函数,用于将一个字符串拆分成多个部分(token),以某些字符(称为分隔符)为界限

参数

  1. str:待分割的字符串。如果是第一次调用,传入要分割的字符串;之后的调用需传入
  2. NULL,以继续上一次的分割
  3. delim:字符串,包含所有分隔符的字符集合。例如," "(空格)或 “/”(斜杠)

返回值

  1. 返回指向字符串中 当前部分 的指针
  2. 如果没有更多部分可返回,返回 NULL

用法规则

  1. 初次调用时,传入字符串 str,函数会从 str 中找到第一个部分
  2. 函数会用 '\0' 替换找到的分隔符(破坏原字符串)
  3. 后续调用时,传入 NULL,函数会继续从上次结束的位置查找下一部分
  4. 不能在多线程环境中使用,因为 strtok 使用的是静态变量保存状态
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{char str[] ="- This, a sample string.";char * pch;printf ("Splitting string \"%s\" into tokens:\n",str);pch = strtok (str," ,.-");while (pch != NULL){printf ("%s\n",pch);pch = strtok (NULL, " ,.-");}return 0;
}/* 常规分割字符串 */
int main()
{char* p = "xxxxxxxxx@.mail.com";const char* sep = ".@";char arr[30];strcpy(arr, p);	//将数据拷贝一份,处理 arr 数组内容char* str = strtok(arr, sep);for (; str != NULL; str = strtok(NULL, sep))printf("%s\n", str);return 0;
}
模拟 strtok 实现
static char* token_ptr = NULL;
char* my_strtok(char* str, const char* sep) 
{assert(sep);if (str) token_ptr = str;if (!token_ptr) return NULL;/* 遍历分割数组 */const char* s = sep;const char* res = NULL;for (; *token_ptr; s = sep, ++token_ptr){/* 遍历分割符 */while (*s){if (*token_ptr != *s) /* 当前字符和分割符不相等 */{++s;		//偏移比较下一个分割符//当前字符和分割符不相等, 且遍历完分割符时记录首元素if (!*s && !res) res = token_ptr;}else  /* 当前字符和分割符相等 */{*token_ptr = 0;if (res) return ++token_ptr, res;break;}}}token_ptr = NULL;if (res) return res;
}

1.10 strerror

char * strerror ( int errnum );
获取指向错误消息字符串的指针Interprets the value of errnum, generating a string with a message that describes the error condition as if set to errno by a function of the library.
解释 errnum 的值,生成一个字符串,其中包含一条消息,该消息描述错误条件,就像由库的函数设置为 errno 一样The returned pointer points to a statically allocated string, which shall not be modified by the program. Further calls to this function may overwrite its content (particular library implementations are not required to avoid data races).
返回的指针指向静态分配的字符串,该程序不得修改该字符串。对此函数的进一步调用可能会覆盖其内容(不需要特定的库实现来避免数据竞争)The error strings produced by strerror may be specific to each system and library implementation.
生成的错误字符串 strerror 可能特定于每个系统和库实现

返回错误码,所对应的错误信息

/* strerror example : error list */
#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));  //errno: Last error numberreturn 0;
}

字符分类函数

函数 		如果他的参数符合下列条件就返回真
iscntrl 	任何控制字符
isspace 	空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v'
isdigit 	十进制数字 0~9
isxdigit 	十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F
islower 	小写字母a~z
isupper 	大写字母A~Z
isalpha 	字母a~z或A~Z
isalnum 	字母或者数字,a~z,A~Z,0~9
ispunct 	标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 	任何图形字符
isprint 	任何可打印字符,包括图形字符和空白字符

字符转换

int tolower ( int c );
int toupper ( int c );/* isupper example */
#include <stdio.h>
#include <ctype.h>
int main ()
{int i=0;char str[]="Test String.\n";char c;while (str[i]){c = str[i];if (isupper(c)) c = tolower(c);putchar (c);i++;}return 0;
}

1.11 memcpy

void * memcpy ( void * destination, const void * source, size_t num );
  1. 函数 memcpy 从 source 的位置开始向后复制 num 个字节的数据到 destination 的内存位置
  2. 这个函数在遇到 \0 的时候并不会停下来
  3. 如果 source 和 destination 有任何的重叠,复制的结果都是未定义的
/* memcpy example */
#include <stdio.h>
#include <string.h>struct {char name[40];int age;
} person, person_copy;int main ()
{char myname[] = "Pierre de Fermat";/* using memcpy to copy string: */memcpy ( person.name, myname, strlen(myname)+1 );person.age = 46;/* using memcpy to copy structure: */memcpy ( &person_copy, &person, sizeof(person) );printf ("person_copy: %s, %d \n", person_copy.name, person_copy.age );return 0;
}
模拟 memcpy 实现
void* memcpy(void* destination, const void* source, size_t num)
{assert(destination && source);void* res = destination;while (num--)*((char*)destination)++ = *((char*)source)++;return res;
}
使用 memcpy 函数拷贝自身

src , src +3, 5

思考一下:对于数组:int arr[] = {1,2,3,4,5,6,7,8,9,10}; 能否将1,2,3,4,5 拷贝到 3,4,5,6,7 的位置??从而结果为:1,2,1,2,3,4,5,8,9,10 呢 ?

答案是不能,下面是过程解析

image-20241213114810700

由于在 memcpy 函数拷贝时,是按照字节来进行拷贝的,拷贝的数字将会覆盖原来的数字

1.12 memmove

void * memmove ( void * destination, const void * source, size_t num );

和 memcpy 的差别就是 memmove 函数处理的源内存块和目标内存块是可以重叠的(如果空间有重叠,则使用 memmove)

/* memmove example */
#include <stdio.h>
#include <string.h>
int main ()
{char str[] = "memmove can be very useful......";memmove (str+20,str+15,11);puts (str);return 0;

对于数组 arr1[]={1,2,3,4,5,6,7,8,9,10}1,2,3,4,5 放到 3,4,5,6,7 的位置 ,可以用从后往前放的方法来实现。

第一步:将 5 放在 7 的位置,第二步:将 4 放在 6 的位置,第三步:将 3 放在 5 的位置 … 这样依次按照顺序来实现

4,5,6,7,8 放在 1,2,3,4,5 的位置,按照从后往前放的方式来进行思考的话:那么:第一步:将 8 放在 5 的位置,第二步:将 7 放在 4 的位置,第三步:将 6 放在 3 的位置,第四步:将 5 放在 …(注意此时 5 的位置处,放置的不再是 5了,已经被前面的 8 替代,所以显得非常不合理)

image-20241213124559587

4,5,6,7,8 放在 1,2,3,4,5 的位置,则需要从前往后放来实现。第一步:将 4 放在 1 的位置,第二步:将 5 放在 2 的位置,第三步:将 6 放在 3 的位置 …

模拟 memmove 实现
void* memmove(void* destination, const void* source, size_t num)
{assert(destination && source);void* res = destination;/*内存重叠的情况源在前, 目标在后, 把前面部分拷贝内容到后面,需要从后往前放源在后, 目标在前, 把后面部分内容拷贝到前面,需要从前往后放*/if (destination < source) //比较地址{//从前往后放while (num--)*((char*)destination)++ = *((char*)source)++;}else{//从后往前放while (num--)*((char*)destination + num) = *((char*)destination + num);}return res;
}

1.13 memcmp

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

比较从 ptr1 和 ptr2 指针开始的 num 个字节;注意,与 strcmp 不同,该函数在找到 null 字符后不会停止比较

返回值

image-20241213125243719

/* memcmp example */
#include <stdio.h>
#include <string.h>int main ()
{char buffer1[] = "DWgaOtP12df0";char buffer2[] = "DWGAOTP12DF0";int n;n=memcmp ( buffer1, buffer2, sizeof(buffer1) );if (n>0) printf ("'%s' is greater than '%s'.\n",buffer1,buffer2);else if (n<0) printf ("'%s' is less than '%s'.\n",buffer1,buffer2);else printf ("'%s' is the same as '%s'.\n",buffer1,buffer2);return 0;
}
模拟 memcmp 实现
int memcmp(const void* ptr1, const void* ptr2, size_t num) 
{assert(ptr1 && ptr2);while (num--){if (*(char*)ptr1 != *(char*)ptr2) return *(char*)ptr1 - *(char*)ptr2;(char*)ptr1 += 1;(char*)ptr2 += 1;}return 0;
}

动手写代码前,必须先把逻辑理清楚,怎样算理清 ?就是能用汉字或画图准确的描述出自己当前的思路(可能不一定是对的),然后再按照描述把代码写出来(如果不正确则 DEBUG 排查)

假设已知当前的条件,递推出后面的情况,进行逻辑的整理,也是编程常用的思路手段(参考 KMP 的算法实现)

相关文章:

C 进阶 — 字符函数和字符串函数 ( 二 )

C 进阶 — 字符函数和字符串函数 ( 二 ) 书接上回 C 进阶 — 字符函数和字符串函数 ( 一 ) 1.9 strtok 参考资料 strtok 函数用法详解 char * strtok ( char * str, const char * sep );strtok 是 [C 标准库](https://so.csdn.net/so/search?qC 标准库&spm1001.2101.3…...

Mybatis Plus 3.0 快速入门

1、简介 MyBatis-Plus (简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 2、创建并初始化数据库 2.1、创建数据库 mybatis_plus 2.2、创建 User 表 其表结构如下: idnameageemail1Jone18test1@baomidou.com2Jack…...

RFDiffusion 计算二面角函数get_dih解读

get_dih 函数计算任意四个连续原子之间的二面角(dihedral angle),它描述了主链和侧链原子的三维空间排布。 源代码: def get_dih(a, b, c, d):"""calculate dihedral angles for all consecutive quadruples (a[i],b[i],c[i],d[i])given Cartesian coordi…...

记一次回调失败问题

问题背景&#xff1a; 客户的问题是部分订单收不到回调&#xff0c;部分订单能正常收到回调&#xff0c;而回调的字段其实都是一样的&#xff0c;这不是很奇怪么&#xff1f; 分析过程&#xff1a; 网络拓扑大概如下图 找到一笔回调异常的订单&#xff0c;在阿里云日志服务器…...

前端常用的方法

时间处理 moment时间处理函数 // 时间日期相关常用的方法变量 import moment from moment;// 获取当前时间 moment export const nowDateMoment moment(new Date()); export const nowDateY moment(new Date()).format(YYYY); export const nowDateM moment(new Date()).f…...

RK3568(六)——led设备驱动(GPIO子系统)

修改设备树文件 先关闭心跳灯功能&#xff0c;也就是在图 10.4.1.2 中第 167 行添加 status 改为 disabled&#xff0c;也就是禁止 work 这个节点&#xff0c;那么禁止心跳灯功能。 我们后面需要禁止哪个功能&#xff0c;只需要将其 status 属性改为 disabled 就可以了。 gpi…...

hbuilder 本地插件配置

插件存放路径&#xff0c;项目根目录nativeplugins下&#xff0c;没有就新建。 aar文件存放路径\nativeplugins\module\android package.json存放路径\nativeplugins\module\ 配置package.json文件 { "name": "module", "id": "modu…...

Spring Boot集成Kafka:最佳实践与详细指南

文章目录 一、生产者1.引入库2.配置文件3.配置类PublicConfig.javaMessageProducer.java 4.业务处理类 三、消费者1.引入库2.配置类PublicConfig.javaMessageConsumer.java 3.业务类 一、生产者 1.引入库 引入需要依赖的jar包&#xff0c;引入POM文件&#xff1a; <depend…...

基于Qwen2-VL模型针对LaTeX OCR任务进行微调训练 - 多图推理

基于Qwen2-VL模型针对LaTeX OCR任务进行微调训练 - 多图推理 flyfish 基于Qwen2-VL模型针对LaTeX_OCR任务进行微调训练_-_LoRA配置如何写 基于Qwen2-VL模型针对LaTeX_OCR任务进行微调训练_-_单图推理 基于Qwen2-VL模型针对LaTeX_OCR任务进行微调训练_-_原模型_单图推理 基于Q…...

详解下c语言下的多维数组和指针数组

在实际c语言编程中&#xff0c;三维及以上数组我们使用的很少&#xff0c;二维数组我们使用得较多。说到数组&#xff0c;又不得关联到指针&#xff0c;因为他们两者的联系太紧密了。今天我们就详细介绍下c语言下的多维数组(主要是介绍二维数组)和指针。 一、二维数组 1.1&am…...

免费送源码:Java+ssm+MySQL 基于微服务架构的餐饮系统的设计与实现 计算机毕业设计原创定制

摘 要 近年来,我国经济和社会发展迅速,人们物质生活水平日渐提高,餐饮行业更是发展迅速,人们对于餐饮行业的认识和要求也越来越高。传统形式的餐饮行业都是以人为本,管理起来需要很多人力、物力、财力,既不方便管理者的管理,也不方便顾客实时了解餐厅动态,给传统餐饮行业的经…...

LeetCode hot100-69-N

https://leetcode.cn/problems/valid-parentheses/description/?envTypestudy-plan-v2&envIdtop-100-liked 20. 有效的括号 已解答 简单 相关标签 相关企业 提示 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#x…...

【橘子容器】如何构建一个docker镜像

你肯定打过docker镜像是吧&#xff0c;作为一个开发这很正常&#xff0c;那么你用的什么打包方式呢&#xff0c;这里我们来梳理几种常用的docker镜像构建方式。 ps&#xff1a;这里不是太讲原理&#xff0c;更多的是一种科普和操作。因为讲原理的东西网上已经够多了。 一、Dock…...

EFAK kafka可视化管理工具部署使用

简介&#xff1a;EFAK是开源的可视化和管理软件。它允许您查询、可视化、提醒和探索您的指标&#xff0c;无论它们存储在何处。简单来说&#xff0c;它为您提供了将 Kafka 集群数据转换为漂亮的图形和可视化效果的工具。 环境&#xff1a;①操作系统&#xff1a;CentOS7.6&…...

Spring Boot 工程分层实战(五个分层维度)

1、分层思想 计算机领域有一句话&#xff1a;计算机中任何问题都可通过增加一个虚拟层解决。这句体现了分层思想重要性&#xff0c;分层思想同样适用于Java工程架构。 分层优点是每层只专注本层工作&#xff0c;可以类比设计模式单一职责原则&#xff0c;或者经济学比较优势原…...

vscode IntelliSense Configurations

IntelliSense 是一个强大的代码补全和代码分析功能&#xff0c;它可以帮助开发者提高编程效率。图中显示的是 VSCode 的 IntelliSense 配置界面&#xff0c;具体配置如下&#xff1a; Compiler path&#xff08;编译器路径&#xff09;: 这里指定了用于构建项目的编译器的完整路…...

hbase读写操作后hdfs内存占用太大的问题

hbase读写操作后hdfs内存占用太大的问题 查看内存信息hbase读写操作 查看内存信息 查看本地磁盘的内存信息 df -h查看hdfs上根目录下各个文件的内存大小 hdfs dfs -du -h /查看hdfs上/hbase目录下各个文件的内存大小 hdfs dfs -du -h /hbase查看hdfs上/hbase/oldWALs目录下…...

C++----入门篇

引言 C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库&#xff0c;以及编程范式等。熟悉C语言之后&#xff0c;对C学习有一定的帮助&#xff0c;本章节主要目标&#xff1a; 1. 补充C语言语法的不足&#xff0c;以及C是如何对C语言…...

C语言程序设计P5-5【应用函数进行程序设计 | 第五节】—知识要点:变量的作用域和生存期

知识要点&#xff1a;变量的作用域和生存期 视频&#xff1a; 目录 一、任务分析 二、必备知识与理论 三、任务实施 一、任务分析 有一个一维数组&#xff0c;内放 10 个学生成绩&#xff0c;写一个函数&#xff0c;求出平均分、最高分和最低分。 任务要求用一个函数来完…...

用 Sass 模块化系统取代全局导入,消除 1.80.0 引入的 @import 弃用警告

目录 前言 问题 import 的缺陷 命名冲突 重复导入 模块系统 use 规则 forward 规则 实际修改 前言 最初&#xff0c;Sass 使用 import 规则通过单个全局命名空间加载其他文件&#xff0c;所有内置函数也可全局使用。由于模块系统&#xff08;use 和 forward 规则&…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...

Visual Studio Code 扩展

Visual Studio Code 扩展 change-case 大小写转换EmmyLua for VSCode 调试插件Bookmarks 书签 change-case 大小写转换 https://marketplace.visualstudio.com/items?itemNamewmaurer.change-case 选中单词后&#xff0c;命令 changeCase.commands 可预览转换效果 EmmyLua…...