strtok_s详解,实现使用strtok_s分割字符串,并返回包含分割符的子串

news2024/12/24 23:12:47

1.strtok_s函数原型

strtok_s 是一个线程安全的字符串分割函数,它是 strtok 的一个变体,用于将字符串分割成一系列的标记(tokens)。与 strtok 不同,strtok_s 需要一个额外的参数来保存上下文信息,这样它就可以在不同的调用之间保持状态,而不需要使用静态变量。这使得 strtok_s 更加适合在多线程环境中使用。

strtok_s 的函数原型通常如下:

char *strtok_s(char *str, const char *delim, char **saveptr);

str:要分割的字符串。对于第一次调用,它应该是指向要分割的字符串的指针;对于后续的调用,它应该是 NULL。
delim:包含分隔符的字符串。 saveptr:指向一个 char * 的指针,用于保存上下文信息。在第一次调用时,它应该指向一个有效的
char * 变量(通常是一个局部变量),该变量将被 strtok_s 用于存储状态信息。在后续的调用中,你应该将 saveptr
的值保持不变,并直接传递给 strtok_s。

函数的工作原理如下:

在第一次调用时,strtok_s 会在 str 中查找第一个不属于 delim 中的字符,并将其视为标记的开始。然后它会继续查找直到遇到
delim 中的字符或字符串的末尾,此时它会将找到的标记的末尾设置为空字符(\0),并返回指向标记的指针。同时,它会在内部更新
saveptr 指向的位置,以便下次调用时能够继续从正确的位置开始搜索。 在后续的调用中(即当 str 为 NULL 时),strtok_s
会使用 saveptr 中保存的信息来继续搜索下一个标记。它会从 saveptr 指向的位置开始,跳过任何属于 delim
的字符,然后查找下一个标记。 当没有更多的标记可以找到时,strtok_s 将返回 NULL。

以下是一个使用 strtok_s 的示例:

#include <stdio.h>
#include <string.h>
 
int main() {
    char str[] = "This is a test string.";
    char *token;
    char *rest = str; // 用于保存 strtok_s 的上下文
 
    // 分割字符串并打印每个标记
    while ((token = strtok_s(rest, " ", &rest)) != NULL) {
        printf("Token: %s\n", token);
    }
 
    return 0;
}

在这个示例中,字符串 “This is a test string.” 被空格分割成了多个标记,并且每个标记都被打印出来。注意,rest 变量被用作 strtok_s 的上下文保存器,并在每次调用时都传递给函数。在第一次调用时,rest 指向要分割的原始字符串;在后续的调用中,rest 会被 strtok_s 更新为指向下一个要搜索的位置。

2.实现使用strtok_s分割字符串,并返回包含分割符的子串

一定要理解,strtok_s的本质是拷贝一个副本,然会在副本上做字符替换,把分割符替换成’\0’.

实现使用strtok_s分割字符串,并返回包含分割符的子串:
思路是token是每次调用strtok_s返回的分割后的子串,那么可以计算该子串的长度。在原始字符串中,使用该长度就可以找到原始字符串中,分割符是哪个。再使用该分割符和token拼接成包含分割符的子串。返回即可。

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



char get_first_char_before_delimiter(const char* str, const char* delimiter) {
    const char* pos = strstr(str, delimiter); // Find the position of the delimiter in the string
    if (pos != NULL && pos != str) { // Ensure the delimiter is found and not at the very beginning
        return *(pos - 1); // Return the character just before the delimiter
    }
    else {
        // If the delimiter is not found or is at the beginning, return a special value
        return '\0'; // Or you can handle it differently, e.g., by returning an error code
    }
}

// 函数声明
char get_left_char(const char* str, const char* address);
// 函数定义
char get_left_char(const char* str, const char* address) {
    if (address == str) {
        // 地址指向字符串的第一个字符,没有左边紧接着的字符
        return NULL;
    }
    else {
        // 返回左边紧接着的字符的地址
        return *((char*)(address - 1));
    }
}
// Function to split string by delimiters and return an array of substrings
char** split_string(const char* str, const char* delimiters, int* count) {
    char* copy = (char*)malloc(strlen(str) + 1);  // Allocate memory for the copy of the input string
    if (!copy) {
        perror("Failed to allocate memory for copy");
        return NULL;
    }
    strcpy(copy, str);  // Copy the input string to avoid modifying it

    char* token, * rest = copy;
    char** result = NULL;
    int capacity = 10;  // Initial capacity for result array
    int idx = 0;

    result = (char**)malloc(capacity * sizeof(char*));
    if (!result) {
        perror("Failed to allocate memory for result");
        free(copy);
        return NULL;
    }
    int len = 0,init = 1;
    while ((token = strtok_s(rest, delimiters, &rest))) {

        char tempstr;
        if (init)
        {
            init = 0;
            tempstr = get_first_char_before_delimiter(str, token);
        } else{
                tempstr = *(str + len);
        }
        len = len + strlen(token) + 1;
        printf("str =%c\n", tempstr);
        char* new_token = (char*)malloc(strlen(token) + 2);  // Allocate memory for the new token
        if (!new_token) {
            perror("Failed to allocate memory for token");
            for (int i = 0; i < idx; i++) {
                free(result[i]);
            }
            free(result);
            free(copy);
            return NULL;
        }


        char strArray[2] = {'\0'};
        strArray[0] = tempstr;
        strcpy(new_token, strArray);
        strcat(new_token, token);  // Copy the token to the new memory location
        result[idx++] = new_token;

        if (idx >= capacity) {
            capacity *= 2;
            result = (char**)realloc(result, capacity * sizeof(char*));
            if (!result) {
                perror("Failed to reallocate memory for result");
                for (int i = 0; i < idx; i++) {
                    free(result[i]);
                }
                free(result);
                free(copy);
                return NULL;
            }
        }
    }

    *count = idx;
    free(copy);
    return result;
}
// Function to free the array of substrings
void free_split_string(char** strings, int count) {
    for (int i = 0; i < count; i++) {
        free(strings[i]);
    }
    free(strings);
}
int main()
{
    const char* str = "?VT=100!PT=20?ADT=100&30";
    const char* delimiters = "!?&";
    int count;
    char** substrings = split_string(str, delimiters, &count);//str

    if (substrings) {
        for (int i = 0; i < count; i++) {
            printf("cmd=%s\n", substrings[i]);
        }
    }
    return 0;
}

运行结果:
在这里插入图片描述

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

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

相关文章

Docker--Docker是什么和对Docker的了解

Docker 的本质 Docker的本质是LXC&#xff08;Linux容器&#xff09;之类的增强版&#xff0c;它本身不是容器&#xff0c;而是容器的易用工具。 Docker通过虚拟化技术&#xff0c;将代码、依赖项和运行环境打包成一个容器&#xff0c;并利用隔离机制来使得容器之间互相独立、…

大数据新视界 -- 大数据大厂之 Impala 性能优化:优化数据加载的实战技巧(下)(16/30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【测试框架篇】单元测试框架pytest(3):用例执行参数详解

一、前言 上一篇内容介绍了用例编写的规则以及执行用例&#xff0c;执行用例时我们发现有些print输出内容&#xff0c;结果没有给我们展示&#xff0c;这是因为什么原因呢&#xff1f;接下来我们会针对这些问题进行阐述。 二、参数大全 我们可以在cmd中通过输入 pytest -h 或…

设计模式-七个基本原则之一-开闭原则 + SpringBoot案例

开闭原则:(SRP) 面向对象七个基本原则之一 对扩展开放&#xff1a;软件实体&#xff08;类、模块、函数等&#xff09;应该能够通过增加新功能来进行扩展。对修改关闭&#xff1a;一旦软件实体被开发完成&#xff0c;就不应该修改它的源代码。 要看实际场景&#xff0c;比如组内…

Android Room框架使用指南

Room框架使用指南 项目效果创建应用,配置Gradle1、在app Module的build.gradle配置kapt插件2、配置依赖:3、配置依赖包版本号创建实体类创建DAO1、DAO简介2、WordDao设计以及相关注解说明3、监听数据变化添加Room数据库1、Room数据库简介2、实现Room数据库实现存储库实现View…

前端开发中常用的包管理器(npm、yarn、pnpm、bower、parcel)

文章目录 1. npm (Node Package Manager)2. Yarn (Yarn Package Manager)3. pnpm4. Bower5. Parcel总结 前端开发中常用的包管理器主要有以下几个&#xff1a; 1. npm (Node Package Manager) 简介&#xff1a; npm 是 Node.js 的默认包管理器&#xff0c;也是最广泛使用的包…

C++builder中的人工智能(23):在现代C++ Windows上轻松录制声音

在这篇文章中&#xff0c;我们将探讨如何在现代C Windows上轻松录制声音。声音以波形和数字形式存在&#xff0c;其音量随时间变化。在C Builder中&#xff0c;使用Windows设备进行录音非常简单。要录制声音&#xff0c;在多设备应用程序中&#xff0c;必须使用FMX.Media.hpp头…

科目一汇总笔记2024

知识点&#xff0c;一天看一遍&#xff1b;提前一周即可&#xff1b;真实考试比“驾校宝典”模拟题简单。 1 知识点汇总 2 错题总结 增驾1轻 2中 3重 能见度 200 100 50 速度60 40 20 两条车道是:100 60 三条车道是:110 90 60 四条车道是:110 90 90 60 高速小车最高120其…

【详细】如何优雅地删除 Docker 容器与镜像

内容预览 ≧∀≦ゞ 镜像与容器的区别删除容器和镜像的具体步骤1. 删除容器步骤 1&#xff1a;查看当前运行的容器步骤 2&#xff1a;停止容器步骤 3&#xff1a;删除容器 2. 删除镜像步骤 1&#xff1a;查看镜像列表步骤 2&#xff1a;删除镜像 3. 删除所有容器和镜像 使用 1Pa…

华为eNSP:AAA认证(pap和chap)telnet/ssh

pap模式 一、拓扑图 二、配置过程 1、这个型号路由器是不带串口的&#xff0c;所以需要添加串口板卡 2、加入串行接口卡槽 右击路由&#xff0c;选择设置&#xff0c;将串口板卡拖动到路由器扩展槽&#xff0c;并开机即可 3、认证方路由器配置 [r8]aaa #进入aaa认证 [r8-a…

HCIP—快速生成树协议(RSTP)实验配置

一、回顾STP和STP的缺点和不足 1.STP的概述&#xff1a; STP&#xff08;生成树协议&#xff09;是一种用于在网络中防止产生环路的链路管理协议。 2.STP的作用&#xff1a; 解决二层环路&#xff0c;防止广播报文产生。但是网络拓扑收敛较慢&#xff0c;影响通信质量。 3…

qt QSyntaxHighlighter详解

1、概述 QSyntaxHighlighter是Qt文本处理框架中的一个强大工具&#xff0c;它专门用于实现文本编辑器中的语法高亮功能。通过自定义高亮规则&#xff0c;QSyntaxHighlighter可以实现对代码编辑器、富文本编辑器中的关键字、注释等内容的高亮显示。这一功能对于提升代码的可读性…

PyQt5 加载UI界面与资源文件

步骤一: 使用 Qt Designer 创建 XXX.ui文件 步骤二: 使用 Qt Designer 创建 资源文件 步骤三: Python文件中创建相关类, 使用 uic.loadUi(mainwidget.ui, self ) 加载UI文件 import sys from PyQt5 import QtCore, QtWidgets, uic from PyQt5.QtCore import Qt f…

国家级财经类211/985学科院校招收申请制硕士

国家级财经类211/985学科院校招收申请制硕士 ◎免试入学&#xff0c;边学边考&#xff0c;申硕便捷&#xff1b; ●1.5-2年制&#xff0c;无需辞职&#xff0c;远程学习&#xff1b; ◎考试方式灵活&#xff0c;可多次申考&#xff1b; ●申请考核制&#xff0c;学信网报名注…

Spring Boot - 扩展点 EnvironmentPostProcessor源码分析及真实案例

文章目录 概述EnvironmentPostProcessor 作用EnvironmentPostProcessor 实现和注册创建类并实现接口注册到 Spring Boot常见应用场景 源码分析1. EnvironmentPostProcessor 接口定义2. 扩展点加载流程3. 加载 EnvironmentPostProcessor 实现类4. EnvironmentPostProcessor 执行…

解决表格出现滚动条样式错乱问题

自定义表格出现滚动条时&#xff0c;会因为宽度不对等导致样式错乱&#xff1b; 解决思路&#xff1a; 监听表格数据的变化&#xff0c;当表格出现滚动条时&#xff0c;再调用更新宽度的方法updateWidth&#xff0c;去改变表格头部的宽度&#xff0c;最终保持表格头部和内容对…

.NET中通过C#实现Excel与DataTable的数据互转

在.NET框架中&#xff0c;使用C#进行Excel数据与DataTable之间的转换是数据分析、报表生成、数据迁移等操作中的常见需求。这一过程涉及到将Excel文件中的数据读取并加载至DataTable中&#xff0c;以便于利用.NET提供的丰富数据处理功能进行操作&#xff0c;同时也包括将DataTa…

albert模型实现微信公众号虚假新闻分类

项目源码获取方式见文章末尾&#xff01; 600多个深度学习项目资料&#xff0c;快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【基于CNN-RNN的影像报告生成】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实现…

java的JJWT 0.91在jdk21中报错的解决方法

参考了很多其他人的办法&#xff0c;只有这种方式可以解决问题 JSON Web Token&#xff08;缩写 JWT&#xff09; 目前最流行、最常见的跨域认证解决方案&#xff0c;前端后端都需要会使用的东西 如果根据黑马的视频&#xff0c;导入了阿里云OSS的相关依赖&#xff0c;自然不会…

最高提升20倍吞吐量!豆包大模型团队发布全新 RLHF 框架,现已开源!

文章来源&#xff5c;豆包大模型团队 强化学习&#xff08;RL&#xff09;对大模型复杂推理能力提升有关键作用&#xff0c;然而&#xff0c;RL 复杂的计算流程以及现有系统局限性&#xff0c;也给训练和部署带来了挑战。传统的 RL/RLHF 系统在灵活性和效率方面存在不足&#x…