数据结构 - C/C++ - 串

  • 公开视频 -> 链接点击跳转公开课程
  • 博客首页 -> 链接点击跳转博客主页

字符处理

C

  • 特性

    • C语言中字符串存储在字符数组中,以空字符'\0'结束。

    • 字符串常量,const char* str = "Hello",存储在只读的数据段中。

  • 布局

    • 字符串在内存中是字符连续存储的集合,最后一个字符为空字符(ASCII值为0),用来标识当前字符串的结束。

    • 字符串可以存储在栈(局部变量)、堆(动态分配)、全局、静态区等。

  • 处理

    • C标准库提供的字符串处理函数,<string.h>头文件中,包含了字符串拷贝、拼接、比较、长度、截断等。

CPP

  • 特性

    • C++提供了std::string类型,它封装了字符数组,并且在此基础上提供了更加丰富的字符串处理业务。

    • std::string支持内存动态扩容,不需要指定缓冲区大小。

  • 布局

    • std::string内部管理与维护一个动态分配内存大小的指针,用于存储字符串数据。
  • 处理

    • std::string是标准模板库(STL)中的一部分,其实现定义在头文件<string.h>中。

串的概念

  • 串基本概念

    • 串(字符串)是由零个或多个字符组成的有限序列。

  • 串和线程表

    • 线性表指的是元素之间的线性关系,元素之间的物理结构是次要的。

    • 串是特殊的线性表,串当中的元素为字符,串整体与字串的关系。

  • 串存储结构

    • 顺序结构

      • 顺序结构基于一段连续的内存空间来存储串当中的字符序列。
    • 链式结构

      • 链式结构基于链表的形式存储字符串,每个节点可以包含一个或多个字符。
    • 块链结构

      • 块链结构基于串的分割,每一块包含一个字符数组,不同的块通过链表关联。
         

串的操作

#include <iostream>

namespace str
{
    // length       字符串长度
    // str          源字符串
    int length(const char* str)
    {
        // 参数校验
        if (str == NULL) return -1;

        // 获取长度
        int nLength = 0;
        while (*(str++) != '\0') nLength++;

        // 返回结果
        return nLength;
    }

    // Assign       字符串赋值
    // Dest         目标字符串的缓冲区
    // Sour         源字符串
    // DestSize     目标缓冲区的大小
    void Assign(char* Dest, const char* Sour, size_t DestSize)
    {
        // 参数校验
        if (Dest == NULL || Sour == NULL || DestSize == 0) return;

        // 内容赋值
        int nLength = 0;
        while (*Sour/*源字符串当前下标字符是否为空*/ && nLength < DestSize - 1/*目标缓冲区长度是否满足*/)
        {
            //Dest[nLength] = Sour[nLength];
            *Dest++ = *Sour++;
            nLength++;
        }

        *Dest = '\0';
    }

    // Concatenate  字符串拼接
    // str1         第一个字符串的缓冲区
    // str2         连接的字符串缓冲区
    // str1Size     第一个字符串的缓冲区长度
    void Concatenate(char* str1, const char* str2, size_t str1Size)
    {
        //参数校验
        if (str1 == NULL || str2 == NULL || str1Size == 0) return;

        //字符长度
        int str1length = str::length(str1);

        //字符拼接
        int i = 0;
        for (i = 0; str2[i] != '\0' && str1Size - 1 > str1length + i; i++)
        {
            str1[str1length + i] = str2[i];
        }

        //追加标记
        str1[str1length + i] = '\0';

    }

    // SunString    子串提取
    // Sour         源字符串数据
    // Dest         提取字符串空间
    // nDestSize    提取字符串容量 
    // nStart       提取字符串位置
    // nCount       提取字符串数量
    void SubString(const char* Sour, char* Dest, int nDestSize, int nStart, int nCount)
    {
        //参数校验
        if (Sour == NULL || Dest == NULL || nDestSize == 0 || nCount == 0) return;

        //起始校验
        int nSourLength = str::length(Sour);
        if (nSourLength <= nStart || nStart < 0) return;

        //长度校验
        if (nCount < 0 || nCount > nSourLength - nStart) return;

        //空间校验
        if (nCount >= nDestSize) return;

        //提取子串
        int i = 0;
        for (i = 0; i < nCount; i++)
        {
            Dest[i] = Sour[nStart + i];
        }

        //字符追加
        Dest[i] = '\0';
    }

    // SubPosition  子串查找
    // Sour         源字符串
    // Sub          子串内容
    int SubPosition(const char* Sour, const char* Sub)
    {

        //参数校验
        if (Sour == NULL || Sub == NULL) return -1;

        //数据备份
        int nPosition = 0;
        const char* str_it;
        const char* sub_it;

        //算法定位
        for (str_it = Sour; *str_it != '\0'; str_it++)
        {
            sub_it = Sub;

            //数据匹配
            if (*str_it == *sub_it)
            {
                const char* str_temp = str_it;

                //匹配子串
                while (*str_temp && *sub_it && (*str_temp == *sub_it))
                {
                    str_temp++, sub_it++;
                }

                if (*sub_it == '\0')
                {
                    return nPosition;
                }
            }

            nPosition++;
        }

        return -1;
    }

    // Compare      字符串比较
    // str1         源字符串
    // str2         目标字符串
    int Compare(const char* str1, const char* str2)
    {
        //参数校验
        if (str1 == NULL || str2 == NULL) return -1;

        //字符比较
        while (*str1 && *str2)
        {
            if (*str1 == *str2)
            {
                str1++;
                str2++;
            }
            else
            {
                break;
            }
        }
        return *str1 - *str2;
    }

    // Insert       字符串插入
    // str1         源字符串数据
    // str2         被插入字符串数据
    // nPos         插入位置索引
    // size_str1    源字符串缓冲区总大小
    void Insert(char* str1, const char* str2, int nPos, int size_str1)
    {
        //参数校验
        if (str1 == NULL || str2 == NULL) return;

        //字符长度
        int str1len = str::length(str1);
        int str2len = str::length(str2);

        //下标越界
        if (nPos < 0 || nPos > str1len) return;

        //空间处理
        if (str1len + str2len + 1 > size_str1) return;

        //移动空间
        for (int i = str1len; i >= nPos; i--)
        {
            str1[i + str2len] = str1[i];
        }

        //数据拷贝
        for (int i = 0; i < str2len; i++)
        {
            str1[nPos + i] = str2[i];
        }

    }

    // Delete       字符串删除
    // str          源字符串数据
    // nPos         起始删除位置
    // nlength      删除字符长度
    void Delete(char* str, int nPos, int nlength)
    {
        //参数校验
        if (str == NULL) return;

        //起始校验
        int strlen = str::length(str);
        if (nPos < 0 || nPos > strlen) return;

        //删除校验
        if (nlength < 0 || (nPos + nlength) > strlen) return;

        //位置修正
        char* Start = str + nPos;
        char* End = str + nPos + nlength;

        //数据删除
        while (*End)
        {
            *Start++ = *End++;
        }

        *Start = '\0';
    }

    // Replace      字符串替换
    // str          源字符串数据
    // to_replace   被替换字符串
    // repalce      替换字符串
    // size_str     缓冲区长度
    void Replace(char* str, const char* to_replace, const char* repalce, int size_str)
    {
        //参数校验
        if (str == NULL || to_replace == NULL || repalce == NULL) return;

        //子串定位
        int nPos = str::SubPosition(str, to_replace);
        if (nPos == -1)return;

        //空间判断
        int strlen = str::length(str);
        int torlen = str::length(to_replace);
        int replen = str::length(repalce);
        if (strlen - torlen + replen > size_str) return;

        //拷贝数据
        char* pTemp = (char*)malloc(size_str);
        if (pTemp == NULL)return;

        memset(pTemp, 0, size_str);
        //00 00 00 00 00 00 00 00 00 00 00 00 00

        memcpy(pTemp, str, nPos);
        //H E L 00 00 00 00 00 00 00 00 00 00

        memcpy(pTemp + nPos, repalce, replen);
        //H E L 0 x C C 00 00 00 00 00 00

        memcpy(pTemp + nPos + replen, str + nPos + torlen, strlen - torlen - nPos);
        //H E L 0 x C C H E L L O 0

        memcpy(str, pTemp, size_str);

        free(pTemp);
    }

    // Split        字符串分割
    // str          源字符串数据
    // chDelimiter  分隔符
    // outCount     子串数量
    char** Split(const char* str, char chDelimiter, int* outCount)
    {
        //参数校验
        if (str == NULL) return NULL;

        //分割数量
        int nCount_Delimiter = 1;
        for (int i = 0; str[i] != '\0'; i++)
        {
            if (str[i] == chDelimiter) ++nCount_Delimiter;
        }

        //写回数据
        *outCount = nCount_Delimiter;

        //分配空间
        char** strArr = (char**)malloc(nCount_Delimiter * sizeof(char*));
        if (!strArr) return NULL;
        memset(strArr, 0, nCount_Delimiter * sizeof(char*));

        //子串长度
        int i = 0;
        int j = 0;
        int nCount_Word = 0;
        for (i = 0, nCount_Word = 0; str[i] != '\0'; i++)
        {
            if (str[i] != chDelimiter)
            {
                nCount_Word++;
            }
            else
            {
                strArr[j++] = (char*)malloc(nCount_Word * sizeof(char) + 1);
                nCount_Word = 0;
            }       
        }
        strArr[j] = (char*)malloc(nCount_Word * sizeof(char) + 1);

        //拷贝数据
        for (i = 0, j = 0, nCount_Word = 0; str[i]; i++)
        {
            if (str[i] != chDelimiter)
            {
                strArr[j][nCount_Word++] = str[i];
            }
            else
            {
                strArr[j][nCount_Word++] = '\0';
                j++;
                nCount_Word = 0;
            }
        }

        strArr[j][nCount_Word++] = '\0';

        return strArr;
    }

}

int main()
{

    //字符长度
     const char szBuffer1[50] = "0xCC";
    int nLength = str::length(szBuffer1);

    //字符赋值
    char szBuffer2[4] = { 0 };
    str::Assign(szBuffer2, "Hello", sizeof(szBuffer2));

    //字符拼接
    char szBuffer3[50] = "Hello";
    str::Concatenate(szBuffer3, "World", sizeof(szBuffer3));

    //子串提取
    char szBuffer4[] = "Hello World";
    char szBuffer5[10] = { 0 };
    str::SubString(szBuffer4, szBuffer5, sizeof(szBuffer5), 6, 5);

    //子串查找
    char szBuffer8[] = "HELHELLHELLO";
    char szBuffer9[] = "HELLO";
    str::SubPosition(szBuffer8, szBuffer9);

    //字符比较
    char szBuffer6[] = "Hel";
    char szBuffer7[] = "Hel";
    str::Compare(szBuffer6, szBuffer7);

    //字符插入
    char szBuffer10[12] = "Hello";
    char szBuffer11[] = "0xCC";
    str::Insert(szBuffer10, szBuffer11, 1, sizeof(szBuffer10));

    //字符删除
    str::Delete(szBuffer10, 1, 4);

    //字符替换
    char szBuffer12[] = "HELHELLHELLO";
    char szBuffer13[] = "HELL";
    char szBuffer14[] = "CC";   
    str::Replace(szBuffer12, szBuffer13, szBuffer14, sizeof(szBuffer12));

    //字符分割
    int nCount = 0;
    char szBuffer15[] = "Hello,World,Ferry,0xCC";
    char** resule = str::Split(szBuffer15, ',', &nCount);

    return 0;
}

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

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

相关文章

编译原理3-自底向上的语法分析

自底向上分析 &#xff0c;就是自左至右扫描输入串&#xff0c;自底向上进 行分析&#xff1b;通过反复查找当前句型的 句柄&#xff0c; 并使 用产生式规则 将找到的句柄归约为相应的非终结符 。逐步进行“ 归约 ”&#xff0c;直到至文法的开始符号&#xff1b; 对于规范推导…

【unity实战】在Unity中使用有限状态机制作一个敌人AI

最终效果 文章目录 最终效果前言有限状态机的主要作用和意义素材下载逻辑图敌人动画配置优雅的代码文件目录状态机代码定义敌人不同状态切换创建敌人效果更多的敌人参考源码完结 前言 有限状态机以前的我嗤之以鼻&#xff0c;现在的我逐帧分析。其实之前我就了解过有限状态机&…

day03-主页模块-修改密码

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.获取用户资料在Vuex中共享登录成功跳转到主页之后&#xff0c;可以获取用户资料&#xff0c;获取的资料在Vuex中共享&#xff0c;这样用户就可以很方便的获取该信…

Leetcode刷题笔记 | 二叉树基本性质 | 一天的题量 | 5道题目 | 深度优先搜索 | 广度优先搜索 | 递归 | 遍历

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 &#x1f4cc;本期毛毛张分享的是LeetCode关于二叉树&#x1f332;的性质的一些基础题&#xff0c;做这些题目的本质还是遍历二叉树&#x1f3c3;‍➡️的过程&#…

计算机组成原理 | 储存子系统(1)概述

三级储存体系 物理与虚拟存储器 &#xff08;抽象逻辑模型&#xff09; 存储器类型 存储器的速度指标

中国民间网络外交组织(CCND)

中国民间网络外交组织Chinese Civil Network Diplomacy简称(CCDN) 是由中国网民建立起来的一个网络外交组织&#xff0c;深度贯彻党的主张和网民意志的统一&#xff0c;为保护中国中华优秀传统文化&#xff0c;民族自信&#xff0c;国家安全&#xff0c;民族利益&#xff0c;社…

昇思MindSpore学习笔记2-04 LLM原理和实践--文本解码原理--以MindNLP为例

摘要&#xff1a; 介绍了昇思MindSpore AI框架采用贪心搜索、集束搜索计算高概率词生成文本的方法、步骤&#xff0c;并为解决重复等问题所作的多种尝试。 这一节完全看不懂&#xff0c;猜测是如何用一定范围的词造句。 一、概念 自回归语言模型 文本序列概率分布 分解为每…

76. UE5 RPG 实现场景阻挡剔除功能

在俯视角游戏中&#xff0c;我们总会碰到一个问题就是&#xff0c;建筑会遮挡住角色的问题。遇到这种问题有多种解决方案&#xff0c;厂商经常使用的一种方案是&#xff0c;如果角色被遮挡&#xff0c;则使用一种纯色或者增加一些菲涅尔的效果来实现 这种效果我之前在unity内实…

SpringBoot 项目整合 MyBatis 框架,附带测试示例

文章目录 一、创建 SpringBoot 项目二、添加 MyBatis 依赖三、项目结构和数据库表结构四、项目代码1、application.yml2、TestController3、TbUser4、TbUserMapper5、TestServiceImpl6、TestService7、TestApplication8、TbUserMapper.xml9、MyBatisTest 五、浏览器测试结果六、…

一文了解什么是车载Tbox

目录 前言一、Tbox是什么呢?二、Tbox架构三、App——TSP——Tbox交互时序图四、汽车混合网关拓扑结构示例五、Tbox功能 前言 强烈建议提前阅读一下这篇文章&#xff1a;车机Tbox介绍 一、Tbox是什么呢? Tbox是汽车上的一个盒子&#xff0c;指的是Telematics BOX&#xff0c…

Michael.W基于Foundry精读Openzeppelin第61期——ERC1967Upgrade.sol

Michael.W基于Foundry精读Openzeppelin第61期——ERC1967Upgrade.sol 0. 版本0.1 ERC1967Upgrade.sol 1. 目标合约2. 代码精读2.1 _getImplementation() internal && _upgradeTo(address newImplementation) internal2.2 _upgradeToAndCall(address newImplementation,…

常见反爬及应对

一&#xff0c;特殊混淆的还原 1.1 还原 AAEncode 与 JJEncode AAEncode是一种JavaScript代码混淆算法&#xff0c;利用它&#xff0c;可以将代码转换成 颜文字 表示的JavaScript代码。 去掉代码最后的 (‘‘)&#xff0c;这是函数的自调用&#xff0c;去除后就是函数的声明…

【计算机网络仿真】b站湖科大教书匠思科Packet Tracer——实验13 静态路由配置错误导致的路由环路问题

一、实验目的 1.验证静态路由配置错误导致的路由环路问题&#xff1b; 二、实验要求 1.使用Cisco Packet Tracer仿真平台&#xff1b; 2.观看B站湖科大教书匠仿真实验视频&#xff0c;完成对应实验。 三、实验内容 1.构建网络拓扑&#xff1b; 2.验证路由环路。 四、实验…

探囊取物之多形式登录页面(基于BootStrap4)

基于BootStrap4的登录页面&#xff0c;支持手机验证码登录、账号密码登录、二维码登录、其它统一登录 低配置云服务器&#xff0c;首次加载速度较慢&#xff0c;请耐心等候&#xff1b;演练页面可点击查看源码 预览页面&#xff1a;http://www.daelui.com/#/tigerlair/saas/pr…

【AI提升】如何使用大模型:本机离线和FastAPI服务调用

大模型本身提供的功能&#xff0c;类似于windows中的一个exe小工具&#xff0c;我们可以本机离线调用然后完成具体的功能&#xff0c;但是别的机器需要访问这个exe是不可行的。常见的做法就是用web容器封装起来&#xff0c;提供一个http接口&#xff0c;然后接口在后端调用这个…

electron教程(二)控制应用程序的事件生命周期

1.will-finish-launching 当应用程序完成基础的启动的时候被触发&#xff0c;在 Windows 和 Linux 中, will-finish-launching 事件与 ready 事件是相同的; 在 macOS 中&#xff0c;这个事件相当于 NSApplication 中的 applicationWillFinishLaunching 提示。 app.on(will-fi…

Andrej Karpathy提出未来计算机2.0构想: 完全由神经网络驱动!网友炸锅了

昨天凌晨&#xff0c;知名人工智能专家、OpenAI的联合创始人Andrej Karpathy提出了一个革命性的未来计算机的构想&#xff1a;完全由神经网络驱动的计算机&#xff0c;不再依赖传统的软件代码。 嗯&#xff0c;这是什么意思&#xff1f;全部原生LLM硬件设备的意思吗&#xff1f…

机械设备制造企业MES系统解决方案介绍

机械设备制造行业涵盖了各类工业设备、工程机械、农业机械等多个领域&#xff0c;对生产精度、质量控制和效率提出了较高要求。为了提升生产效率、保证产品质量并满足客户需求&#xff0c;越来越多的机械设备制造企业引入了MES系统。本文将详细介绍MES系统在机械设备制造行业的…

魔镜魔镜,我要变得更漂亮!按需搭配一键叠穿,效果拿下新SOTA!中山大学字节智创数字人团队提出虚拟试穿新框架

魔镜魔镜,我要变得更漂亮!按需搭配一键叠穿,效果拿下新SOTA!中山大学&字节智创数字人团队提出虚拟试穿新框架。 多件衣服按指定穿法一键虚拟试穿! 中山大学&字节智创数字人团队提出了一个名为MMTryon的虚拟试穿框架,可以通过输入多个服装图像及指定穿法的文本指…

COB封装的LED显示屏是什么?

COB&#xff08;Chip on Board&#xff09;封装的LED显示屏&#xff0c;是一种采用先进倒装COB封装技术的显示屏&#xff0c;其中LED芯片是直接被安装并封装在PCB电路板上&#xff0c;而不是先对单个封装再焊接至电路板&#xff0c;与SMD&#xff08;Surface Mount Device&…