深入剖析C语言字符串操作函数:my_strlen与my_strcpy


 
在C语言的编程世界里,字符串操作是日常开发中极为常见的任务。熟练掌握字符串操作函数,不仅能够提高代码的效率和可读性,还能为解决各种实际问题提供有力的支持。本文将深入剖析两个自定义的字符串操作函数: my_strlen 和 my_strcpy ,通过详细解读代码逻辑、分析函数的使用场景、探讨可能的优化方向以及结合实际案例进行应用,帮助读者全面掌握这两个函数的原理与应用。
 
一、函数定义与功能概述
 

 
 my_strlen 函数的功能是计算一个字符串的长度,不包括字符串结束标志 '\0' 。函数接收一个指向字符数组(即字符串)的指针 arr 作为参数。首先,使用 assert 宏对传入的指针进行非空检查,这是一种防御性编程策略,能够有效避免在指针为空时导致的程序崩溃。如果指针不为空,进入循环,通过判断当前字符是否为 '\0' 来遍历字符串,每遍历一个字符,计数器 count 就增加1,直到遇到 '\0' 结束循环,最后返回 count ,即字符串的长度。
 
1.2 my_strcpy函数
 

 
 my_strcpy 函数的作用是将一个字符串(源字符串)复制到另一个字符数组(目标数组)中。它接收两个指针参数, arr1 指向目标数组, arr 指向源字符串。同样,在函数开始时使用 assert 宏对两个指针进行非空检查。然后,通过一个 while 循环,将源字符串中的字符逐个复制到目标数组中,每次循环都将源字符串当前位置的字符赋值给目标数组的当前位置,并且两个指针都向后移动一位。当源字符串的结束标志 '\0' 被复制到目标数组时,循环结束。最后,再次将 '\0' 赋值给目标数组的下一个位置,确保目标数组以 '\0' 结尾,成为一个完整的字符串。
 
二、代码细节分析
 
2.1 assert宏的使用
 
 assert 宏是C语言标准库 <assert.h> 中提供的一个调试工具。它的作用是在程序运行时检查一个条件是否为真,如果条件为假,就会输出一条错误信息并终止程序的执行。在 my_strlen 和 my_strcpy 函数中,使用 assert 宏对传入的指针进行非空检查,这样可以在开发和调试阶段及时发现并解决由于空指针导致的错误。例如,如果在调用 my_strlen 函数时传入了一个空指针, assert(arr!= NULL) 条件为假,程序会立即终止并输出错误信息,提示开发者存在空指针问题,从而避免在后续的代码执行中出现难以调试的错误。
 
2.2 while循环的逻辑
 
在 my_strlen 函数的 while 循环中, while (*arr!= '\0') 这个条件用于判断当前字符是否为字符串结束标志。只要当前字符不是 '\0' ,就继续循环,通过 count++ 统计字符个数,同时 arr += 1 将指针向后移动一位,指向下一个字符。在 my_strcpy 函数的 while 循环中, while (*arr1++ = *arr++) 这个条件比较特殊。它首先将源字符串当前位置的字符赋值给目标数组当前位置,然后判断这个赋值表达式的结果是否为真(即是否为 '\0' ),如果不为 '\0' ,继续循环,同时两个指针都向后移动一位。当源字符串的 '\0' 被赋值给目标数组时,赋值表达式的结果为假,循环结束。最后,通过 *arr1 = *arr; 再次将 '\0' 赋值给目标数组的下一个位置,确保目标数组以 '\0' 结尾。
 
2.3 指针运算与字符处理
 
在这两个函数中,指针运算起到了关键作用。通过 arr += 1 和 arr1++ 、 arr++ 等操作,实现了对字符串中字符的逐个访问和处理。在C语言中,指针的算术运算非常灵活,能够高效地处理数组和字符串等数据结构。例如,在 my_strlen 函数中,通过不断移动指针 arr 来遍历整个字符串,统计字符个数;在 my_strcpy 函数中,通过同时移动指针 arr1 和 arr ,实现了源字符串到目标数组的逐个字符复制。
 
三、函数的使用场景
 
3.1 my_strlen的应用场景
 
字符串长度验证:在用户输入字符串时,常常需要验证输入的字符串长度是否符合要求。例如,在一个用户注册系统中,要求用户名长度在3到20个字符之间,可以使用 my_strlen 函数来验证用户输入的用户名长度是否在这个范围内。
 
动态内存分配:当需要根据字符串的长度动态分配内存时, my_strlen 函数可以提供准确的长度信息。例如,在实现一个字符串拼接函数时,需要先计算两个字符串的总长度,然后根据总长度分配足够的内存来存储拼接后的字符串。
 
字符串比较与排序:在对字符串进行比较和排序时,字符串的长度是一个重要的比较因素。例如,在实现一个按字符串长度从小到大排序的函数时,需要使用 my_strlen 函数获取每个字符串的长度,然后进行比较和排序。
 
3.2 my_strcpy的应用场景
 
字符串复制与初始化:在很多情况下,需要将一个已知的字符串复制到另一个字符数组中进行处理或存储。例如,在实现一个字符串处理函数时,可能需要先将输入的字符串复制到一个临时数组中,然后对临时数组进行操作,而不影响原始字符串。
 
字符串拼接:在实现字符串拼接功能时,通常需要先将一个字符串复制到目标数组的起始位置,然后再将另一个字符串追加到目标数组的后面。 my_strcpy 函数可以用于完成前半部分的复制操作。
 
字符串替换:当需要在一个字符串中替换某个子字符串时,可以先将原字符串中不需要替换的部分复制到目标数组中,然后将替换后的子字符串复制到目标数组的相应位置,最后再将原字符串中剩余的部分复制到目标数组的后面。
 
四、优化与改进
 
4.1 my_strlen函数的优化
 
虽然 my_strlen 函数的基本实现已经能够满足大部分需求,但在一些特殊情况下,可以考虑进行优化。例如,在处理非常长的字符串时,按字节逐个比较的方式效率较低。可以利用现代CPU的特性,一次读取多个字节进行比较,这样可以减少比较次数,提高效率。下面是一个基于按字(4字节或8字节,取决于CPU架构)读取的优化版本:
 

 
这个优化版本利用了 uint32_t 类型一次读取4个字节,通过巧妙的位运算来快速判断是否存在 '\0' 字符,从而减少了比较次数,提高了效率。但需要注意的是,这种优化版本的代码复杂度较高,可读性较差,并且依赖于特定的CPU架构和字节序,在实际应用中需要根据具体情况进行权衡。
 
4.2 my_strcpy函数的优化
 
 my_strcpy 函数的优化思路与 my_strlen 类似,可以利用CPU的特性进行批量复制。例如,在支持SSE指令集的CPU上,可以使用SSE指令一次复制16个字节,大大提高复制效率。下面是一个简单的基于SSE指令的优化示例(假设环境支持SSE指令集):
 

 

 
这个优化版本使用了SSE指令中的 _mm_loadu_si128 和 _mm_storeu_si128 函数,一次加载和存储16个字节,通过 _mm_testz_si128 函数判断是否复制到了 '\0' 字符。当遇到 '\0' 字符时,退出循环,然后使用普通的字符复制方式将剩余的字符复制完。同样,这种优化依赖于特定的硬件环境和指令集,在实际应用中需要谨慎使用。
 
五、实际案例应用
 
5.1 字符串统计程序
 
假设我们要开发一个简单的字符串统计程序,用于统计输入字符串中单词的个数、字符的个数以及最长单词的长度。可以使用 my_strlen 函数来统计字符个数,结合一些字符串处理逻辑来统计单词个数和最长单词的长度。以下是一个简单的实现示例:
 

 

 

 

 


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

#define MAX_LENGTH 1000

int my_strlen(const char * arr);

int main()
{
    char input[MAX_LENGTH];
    printf("请输入一个字符串: ");
    fgets(input, MAX_LENGTH, stdin);
    input[strcspn(input, "\n")] = '\0'; // 去除换行符

    int char_count = my_strlen(input);
    int word_count = 0;
    int max_word_length = 0;
    int current_word_length = 0;
    int i = 0;

    while (input[i]!= '\0')
    {
        if (isspace(input[i]))
        {
            if (current_word_length > 0)
            {
                word_count++;
                if (current_word_length > max_word_length)
                {
                    max_word_length = current_word_length;
                }
                current_word_length = 0;
            }
        }
        else
        {
            current_word_length++;
        }
        i++;
    }

    if (current_word_length > 0)
    {
        word_count++;
        if (current_word_length > max_word_length)
        {
            max_word_length = current_word_length;
        }
    }

    printf("字符个数: %d\n", char_count);
    printf("单词个数: %d\n", word_count);
    printf("最长单词长度: %d\n", max_word_length);

    return 0;
}

int my_strlen(const char * arr)
{
    assert(arr!= NULL);
    int count = 0;
    while (*arr!= '\0')
    {
        count++;
        arr += 1;
    }
    return count;
}
 
  在这个示例中, my_strlen 函数用于统计输入字符串的总字符个数。通过遍历字符串,结合 isspace 函数判断字符是否为空白字符,从而统计单词个数和最长单词的长度。
 
5.2 字符串加密程序
 
假设我们要实现一个简单的字符串加密程序,将字符串中的每个字符按照一定的规则进行替换。可以使用 my_strcpy 函数将原始字符串复制到一个新的数组中,然后在新数组上进行加密操作。以下是一个简单的凯撒密码加密示例:
 


 
在这个示例中, my_strcpy 函数将原始字符串复制到 encrypted 数组中,然后通过遍历 encrypted 数组,对每个字符进行凯撒密码加密操作,将加密后的字符存储回 encrypted 数组,最后输出原始字符串和加密后的字符串。
 
六、总结
 
通过对 my_strlen 和 my_strcpy 函数的深入剖析,我们不仅了解了它们的基本实现原理和代码细节,还探讨了它们的使用场景、优化方向以及在实际案例中的应用。这两个函数是C语言字符串操作的基础,掌握它们对于编写高效、健壮的C语言程序至关重要。在实际编程中,我们可以根据具体的需求和场景,灵活运用这两个函数,并结合其他字符串处理函数和技巧,实现各种复杂的字符串处理功能。同时,对于性能要求较高的场景,可以考虑对这两个函数进行优化,利用硬件特性和高效的算法来提高程序的执行效率。希望本文能够帮助读者更好地理解和掌握C语言字符串操作的精髓,为今后的C语言编程之路打下坚实的基础。
 
[此处插入一张表示字符串操作流程的图片,例如一个简单的流程图展示my_strcpy函数的复制过程]
 
[此处插入一张表示优化前后性能对比的图片,例如使用柱状图展示优化前后my_strlen函数处理不同长度字符串的时间对比]
 
以上图片可以使用专业的绘图工具(如Visio、Graphviz等)绘制,然后插入到博客中相应的位置,以增强博客的可视化效果和可读性。具体的图片内容和样式可以根据实际需要进行设计和调整。

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

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

相关文章

《苍穹外卖》项目学习记录-Day10来单提醒

type&#xff1a;用来标识消息的类型&#xff0c;比如说type1表示来单提醒&#xff0c;type2表示客户催单。 orderId&#xff1a;表示订单id&#xff0c;因为不管是来单提醒还是客户催单&#xff0c;这一次提醒都对应一个订单。是用户下了某个单或者催促某个订单&#xff0c;这…

数据结构与算法之栈: LeetCode 2042. 检查句子中的数字是否递增 (Ts版)

检查句子中的数字是否递增 https://leetcode.cn/problems/check-if-numbers-are-ascending-in-a-sentence/description/ 描述 句子是由若干 token 组成的一个列表&#xff0c;token 间用 单个 空格分隔&#xff0c;句子没有前导或尾随空格。每个 token 要么是一个由数字 0-9 …

fpga系列 HDL:XILINX Vivado Vitis 高层次综合(HLS) 实现 EBAZ板LED控制(上)

目录 创建工程创建源文件并编写C代码C仿真综合仿真导出RTL CG导出RTL错误处理&#xff1a; 创建工程 创建源文件并编写C代码 创建源文件(Souces下的hlsv.h和hlsv.cpp&#xff0c;Test Bench下的test_hlsv1.cpp)&#xff1a; hlsv1.h #ifndef HLSV1 #define HLSV1 #include &l…

JVM栈溢出线上环境排查

#查看当前Linux系统进程ID、线程ID、CPU占用率&#xff08;-eo后面跟想要展示的列&#xff09; ps H -eo pid,tid,%cpups H -eo pid,tid,%cpu |grep tid #使用java jstack 查看进程id下所有线程id的情况 jstack pid 案例2 通过jstack 排查死锁问题 #启动java代码 jstack 进…

91,【7】 攻防世界 web fileclude

进入靶场 <?php // 包含 flag.php 文件 include("flag.php");// 以高亮语法显示当前文件&#xff08;即包含这段代码的 PHP 文件&#xff09;的内容 // 方便查看当前代码结构和逻辑&#xff0c;常用于调试或给解题者提示代码信息 highlight_file(__FILE__);// 检…

Joplin 插件在Vscode中无法显示图片

1.问题 在vscode里面装好joplin插件之后&#xff0c;无法显示图片内容。 粘贴的图片可以再vscode中显示&#xff0c;无法再joplin客户端显示 2.解决方法 这种情况是因为和vscode自带的MD编辑器的预览模式有冲突&#xff0c;或者没用通过专用方式上传图片。 方法一&#xff…

FreeRTOS从入门到精通 第十七章(软件定时器)

参考教程&#xff1a;【正点原子】手把手教你学FreeRTOS实时系统_哔哩哔哩_bilibili 一、软件定时器简介 1、定时器的概念与种类 &#xff08;1&#xff09;定时器的概念&#xff1a;从指定的时刻开始&#xff0c;经过一个指定时间&#xff0c;然后触发一个超时事件&#xf…

2025年美赛B题-结合Logistic阻滞增长模型和SIR传染病模型研究旅游可持续性-成品论文

模型设计思路与创新点&#xff1a; 建模的时候应该先确定我们需要建立什么类的模型&#xff1f;优化类还是统计类&#xff1f;这个题需要大量的数据分析&#xff0c;因此我们可以建立一个统计学模型。 统计学建模思路&#xff1a;观察规律&#xff0c;建立模型&#xff0c;参…

9.2k star!PiliPala一个第三方B站客户端!

软件介绍 链接 PiliPala一个在Github上收获9.2k star的开源第三方bilibili客户端&#xff0c;支持安卓和ios端安装使用。应用界面简洁无广、除核心功能外无任何冗余功能和服务&#xff0c;让我们可以尽情的享受内容带给我们的快乐。 基础的功能如登录、点赞收藏、评论、关注、…

unity学习23:场景scene相关,场景信息,场景跳转

目录 1 默认场景和Assets里的场景 1.1 scene的作用 1.2 scene作为project的入口 1.3 默认场景 2 场景scene相关 2.1 创建scene 2.2 切换场景 2.3 build中的场景&#xff0c;在构建中包含的场景 &#xff08;否则会认为是失效的Scene&#xff09; 2.4 Scenes in Bui…

论文笔记(六十三)Understanding Diffusion Models: A Unified Perspective(五)

Understanding Diffusion Models: A Unified Perspective&#xff08;五&#xff09; 文章概括基于得分的生成模型&#xff08;Score-based Generative Models&#xff09; 文章概括 引用&#xff1a; article{luo2022understanding,title{Understanding diffusion models: A…

Linux中 端口被占用如何解决

lsof命令查找 查找被占用端口 lsof -i :端口号 #示例 lsof -i :8080 lsof -i :3306 netstat命令查找 查找被占用端口 netstat -tuln | grep 端口号 #示例 netstat -tuln | grep 3306 netstat -tuln | grep 6379 ss命令查找 查找被占用端口 ss -tunlp | grep 端口号 #示例…

苍穹外卖第一天

角色分工 技术选型 pojo子模块 nginx反向代理 MD5密码加密

IP服务模型

1. IP数据报 IP数据报中除了包含需要传输的数据外&#xff0c;还包括目标终端的IP地址和发送终端的IP地址。 数据报通过网络从一台路由器跳到另一台路由器&#xff0c;一路从IP源地址传递到IP目标地址。每个路由器都包含一个转发表&#xff0c;该表告诉它在匹配到特定目标地址…

Kafka下载

一、Kafka下载 下载地址&#xff1a;https://kafka.apache.org/downloads 二、Kafka安装 因为选择下载的是 .zip 文件&#xff0c;直接跳过安装&#xff0c;一步到位。 选择在任一磁盘创建空文件夹&#xff08;不要使用中文路径&#xff09;&#xff0c;解压之后把文件夹内容…

使用 Motor-CAD 脚本实现 Maxwell 电机模型的 Ansys 自动化

在本博客中&#xff0c;我将展示如何使用 Ansys Motor-CAD 自动创建的电机设计脚本在 Ansys Maxwell 中自动创建电机模型。我以无刷永磁电机为例介绍工作流程。 汽车CAD 将 Motor-CAD 设计导出为脚本文件以在 Maxwell 中运行。 导出电机 CAD 设计 在菜单条中选择“工具”选项…

《逆向工程核心原理》第三~五章知识整理

查看上一章节内容《逆向工程核心原理》第一~二章知识整理 对应《逆向工程核心原理》第三章到第五章内容 小端序标记法 字节序 多字节数据在计算机内存中存放的字节顺序分为小端序和大端序两大类 大端序与小端序 BYTE b 0x12; WORD w 0x1234; DWORD dw 0x12345678; cha…

使用 SpringBoot+Thymeleaf 模板引擎进行 Web 开发

目录 一、什么是 Thymeleaf 模板引擎 二、Thymeleaf 模板引擎的 Maven 坐标 三、配置 Thymeleaf 四、访问页面 五、访问静态资源 六、Thymeleaf 使用示例 七、Thymeleaf 常用属性 前言 在现代 Web 开发中&#xff0c;模板引擎被广泛用于将动态内容渲染到静态页面中。Thy…

MongoDB快速上手(包会用)

MongoDB快速上手&#xff08;包会用&#xff09; MongoDB 介绍 &#x1f431;‍&#x1f4bb; MongoDB 是一个开源的 文档型数据库&#xff0c;它使用类似 JSON 的 BSON&#xff08;二进制 JSON&#xff09;格式来存储数据&#xff0c;具有高性能、可扩展性和灵活性。它适用于…

STC32通用GPIO中断,库函数配置方式 AI8051U和STC32G已测试没有问题

近来STC的单片机已经出到32位了&#xff0c;并且个人自己打板测试了几个型号&#xff0c;相比之前的51完全不是一个量级&#xff0c;可以通过以下这张图片中的信息来感受一下如今的32位8051单片机的强大&#xff0c;也是很很期待25年的这一新作了&#xff01; 配图为AI8052U或…