【维生素C语言】附录:strlen 函数详解

  

  • 写在前面:本篇将专门为 strlen 函数进行讲解,总结了模拟实现 strlen 函数的三种方法,并对其进行详细的解析。手写库函数是较为常见的面试题,希望通过本篇博客能够加深大家对 strlen 的理解。

0x00 strlen函数介绍

【百度百科】strlen 所作的是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符 \0 为止,然后返回计数器值(长度不包含 \0 )。

size_t strlen(const char* str);    // 求字符串长度

📜 头文件: string.h

📚 说明:字符串以 \0 作为结束标志,strlen 返回的是在字符串中 \0 前面出现的字符个数。因为求的是字符串的长度,也就是字符的个数,所以不包括  \0 字符。(注:sizeof 包括 \0 字符)

📌 注意事项:

  • 参数指向的字符串必须以  \0  结束
  • 函数的返回值为 size_t ,即无符号整数 (unsigned) 的别名。参见宏定义:typedef unsigned int size_t;

❓ 为什么返回无符号呢?

💡 既然是求字符串长度,那么出现负数就没有意义,所以使用 size_t 

💬 使用方法演示:

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

int main() {
    char arr[] = "abcdef";
    int len = strlen(arr);
    printf("len = %d\n", len);

    return 0;
}

🚩  运行结果: 6

0x01 模拟实现:计数器(需创建临时变量)

💬 模拟实现 strlen 函数:

#include <stdio.h>

size_t my_strlen(const char* str) {
    int count = 0; //创建计数器
    while (*str != '\0') { //对 str 解引用,如果 *str 不是 \0
        str++; // 指针向后移动1位(char)
        count++; // 计数器+1
    }
    return count; //返回计数器
}

int main() {
    char arr[] = "abcdef";
    int len = my_strlen(arr);
    printf("len = %d\n", len);

    return 0;
}

💡 解析:加上 const 修饰提高代码的健壮性,用 const char* 接收传入的参数。因为 arr 数组名是首元素地址,所以需要用指针变量接收。创建变量 count 来作为计数器,在循环内进行指针加整数,直到碰到 \0 跳出循环,最后返回计数器 count

⚡ 简化: 

#include <stdio.h>

size_t my_strlen(const char* str) {
    int count = 0;
    while (*str) {
        str++;
        count++;
    }
    return count;
}

int main() {
    char arr[] = "abcdef";
    int len = my_strlen(arr);
    printf("len = %d\n", len);

    return 0;
}

0x02 模拟实现:用递归

💬 模拟实现 strlen 函数(禁止创建临时变量):

#include <stdio.h>

size_t my_strlen(const char* str) {
    if (*str != '\0') {
        return 1 + my_strlen(str + 1);
    } else {
        return 0;
    }
}

int main() {
    char arr[] = "abcdef";
    int len = my_strlen(arr);
    printf("len = %d\n", len);

    return 0;
}

💡 解析:首先进行判断,对 str 进行解引用,如果不是 \0 就返回 1 + my_strlen(str + 1) ,此时 " 1+ " 就起到了计数的作用,随后自己调用自己 my_strlen(str + 1) ,递归下去直到是 \0 为止,碰到后返回 0,随后再一步步倒回去,就可以返回长度了。当然,如果传入的字符串长度为 0,会直接走 else 返回 0。

📌 注意:不要将 my_strlen(str + 1)  写成 my_strlen(str++)  ,在这里使用 后置++ 是非常致命的!

0x03 模拟实现:指针减指针

💬 代码演示:模拟实现 strlen 函数(禁止创建临时变量):

#include <stdio.h>

size_t my_strlen(const char* str) {
    const char* start = str; //字符串的起始位置就是str
    const char* end = str;

    while (*end != '\0') {  //用来找到字符串的末尾处
        end++;
    }

    return end - start; //最后指针减指针,巧妙地得到了字符串的长度
}

int main() {
    char arr[] = "abcdef";
    int len = my_strlen(arr);
    printf("len = %d\n", len);

    return 0;
}

 💡 解析:利用 " 指针减指针得到的是元素之间元素的个数" 这一特性得到字符串的长度。首先创建 start 变量用于记录字符串的起始位置,随后创建 end 变量并找到末尾位置( 不是 \0 就往后推进的方法 )。最后返回 end - start,末尾位置减去起始位置即可得到字符串的长度。

⚡ 其实库函数就用了这种方法,真的是妙不可言!不过将代码进一步地简化了: 

#include <stdio.h>

size_t my_strlen(const char* str) {
    const char* end = str;
    while (*end++); 
    return end - str - 1;
}

int main() {
    char arr[] = "abcdef";
    int len = my_strlen(arr);
    printf("len = %d\n", len);

    return 0;
}

💡 解析:首先其实大可不必创建 start 变量,因为 str 本身就记录着起始位置。while 括号中这种情况下自然可以省去 \0 ,库函数作者直接将 end++ 的操作直接丢入判断条件中。*end++ 优先级相同,根据结合性(从右向左)。因为 while 循环条件会比循环体多执行一次,放进循环条件内的*end++ 因为这个 "特性" 多执行了一次,所以最后 end - start 要手动 -1。返回 end - start - 1 ,即字符串长度。

📌 注意事项:while 循环条件将会比循环体多执行一次。(摘自第二章)

【维生素C语言】第二章 - 分支和循环

📂 最后贴上 src 文件夹中的 strlen.c ,一起来欣赏欣赏:(和上面的代码原理一样,只是变量名不同)

/***
*strlen.c - contains strlen() routine
*
*       Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
*       strlen returns the length of a null-terminated string,
*       not including the null byte itself.
*
*******************************************************************************/

#include <cruntime.h>
#include <string.h>

#pragma function(strlen)

/***
*strlen - return the length of a null-terminated string
*
*Purpose:
*       Finds the length in bytes of the given string, not including
*       the final null character.
*
*Entry:
*       const char * str - string whose length is to be computed
*
*Exit:
*       length of the string "str", exclusive of the final null byte
*
*Exceptions:
*
*******************************************************************************/

size_t __cdecl strlen (
        const char * str
        )
{
        const char *eos = str;

        while( *eos++ ) ;

        return( eos - str - 1 );
}


本篇完

📌 [ 笔者 ]   王亦优
📃 [ 更新 ]   2021.10.1
❌ [ 勘误 ]   /* 暂无 */
📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,
              本人也很想知道这些错误,恳望读者批评指正!

📜 参考资料 

C++reference[EB/OL]. []. http://www.cplusplus.com/reference/.

Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .

百度百科[EB/OL]. []. https://baike.baidu.com/.

比特科技. C++[EB/OL]. 2021[2021.8.31]. 

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

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

相关文章

如何将 Hexo 部署到 GitHub Pages

引言 在数字时代&#xff0c;拥有个人博客是展示自己想法、分享知识和技能的绝佳方式。Hexo 是一个基于 Node.js 的静态博客生成器&#xff0c;它结合了简洁性和功能性&#xff0c;让我们可以轻松地建立并维护一个博客。而 GitHub Pages 提供了一个免费的平台来托管这些静态网站…

4核8G服务器性能怎么样?4核8G12M配置能支持多少人同时访问?

4核8G服务器性能怎么样?4核8G12M配置能支持多少人同时访问&#xff1f;腾讯云轻量4核8G12M轻量应用服务器支持多少人同时在线&#xff1f;通用型-4核8G-180G-2000G&#xff0c;2000GB月流量&#xff0c;系统盘为180GB SSD盘&#xff0c;12M公网带宽&#xff0c;下载速度峰值为…

CSP-202112-2-序列查询新解

CSP-202112-2-序列查询新解 【70分思路】 【暴力枚举】按照题目思路遍历一遍f(x)和g(x)&#xff0c;计算error(A)&#xff0c;时间复杂度为O(N)&#xff0c;时间超限。 #include <iostream> using namespace std; int main() {long long n, N, sum 0;cin >> n …

MNIST数据集介绍及基于Pytorch下载数据集

MNIST数据集介绍及基于Pytorch下载数据集 &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333;MNIST数据集介绍&#x1f333;&#x1f333;基于Pytorch下载MNIST数据集并可视化&#x1f333;&#x1f333;使用MNIST数据集进行图像分类任务&#x…

Linux操作系统基础(六):Linux常见命令(一)

文章目录 Linux常见命令 一、命令结构 二、ls命令 三、cd命令 四、mkdir命令 五、touch命令 六、rm命令 七、cp命令 八、mv命令 九、cat命令 十、more命令 Linux常见命令 一、命令结构 command [-options] [parameter]说明: command : 命令名, 相应功能的英文单词…

零基础学python之高级编程(1)---面向对象编程及其类的创建

面向对象编程及其类的创建 文章目录 面向对象编程及其类的创建前言一、面向过程编程和面向对象编程的概念1.面向过程编程(Procedural Programming)2.面向对象编程(Object-Oriented Programming&#xff0c;OOP) 二、面向对象编程基础1.初识类(class)和对象调用方法 2.类中的两种…

如何快速搭建springboot项目(新手入门)

一、创建项目 1.1、创建项目 1.2、配置编码 1.3、取消无用提示 1.4、取消无用参数提示 二、添加POM父依赖 <!-- 两种方式添加父依赖或者import方式 --> <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-p…

Java强训day17(选择题编程题)

选择题 编程题 题目1 import java.util.Scanner;public class Main { public static void main(String[] args) {Scanner sc new Scanner(System.in);char[] c1 sc.nextLine().toCharArray();char[] c2 sc.next().toCharArray();//取c2[0]if(c2[0]>A && c2[…

在windows server2016部署域控服务器DC

1.正常配置vmware虚拟机基础环境 2.启动虚拟机&#xff0c;会先到efi network&#xff0c;等待几分钟 3.进入boot manager&#xff0c;选择启动方式&#xff0c;记得提示CD启动的时候需要按回车&#xff0c;不然又会回到这个界面 4.选择安装版本为桌面版&#xff08;开始直接…

Web后端开发:事务与AOP

事务管理 在学习数据库时&#xff0c;讲到&#xff1a;事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位。事务会把所有的操作作为一个整体&#xff0c;一起向数据库提交或者是撤销操作请求&#xff0c;要么同时成功&#xff0c;要么同时失败。 事务的操作主要有三…

2024牛客寒假算法基础集训营3

前言 感觉有些题是有难度&#xff0c;但是是我花时间想能想的出来的题目&#xff0c;总体来说做的很爽&#xff0c;题目也不错。个人总结了几个做题技巧&#xff0c;也算是提醒自己。 1.多分类讨论 2.从特殊到一般&#xff0c;便于找规律。例如有一组数&#xff0c;有奇数和…

Java串口通信技术探究2:RXTX库单例测试及应用

目录 一、创建串口工具类二、串口工具测试三、运行时会遇到的错误JVM崩溃无法找到指定的类 本文主要介绍了Java串口通信技术探究&#xff0c;重点分析了RXTX库单例测试以及串口工具的使用。通过实例演示了如何使用SerialPortTool类进行串口操作&#xff0c;包括打开串口、关闭串…

Unity入门学习

目录 Unity环境搭建Unity引擎是什么软件下载和安装工程文件夹 Unity界面基础Scene场景和Hierarchy层级窗口Game游戏和Project工程Inspector和Console工具栏和父子关系 Unity工作原理反射机制和游戏场景预设体和资源包的导入导出 Unity脚本基础脚本基本规则生命周期函数Inspecto…

Codeforces Round 886 (Div. 4)补题

To My Critics&#xff08;Problem - A - Codeforces&#xff09; 题目大意&#xff1a;现有一个三位数&#xff0c;问能否从中抽取两个数使得和大于等于10. 思路&#xff1a;排个序&#xff0c;取大的两个即可。 #include<bits/stdc.h> using namespace std; int mai…

编译环境搭建及基础实验

1.VS code安装 Linux 版本安装 把资料盘里的安装包.deb拷贝到Ubuntu中&#xff0c; 使用如下命令安装&#xff1a; 软件图标都在目录/usr/share/applications 中&#xff0c;如图路径 复制到桌面中 Visual Studio Code 插件的安装 我们需要按照的插件有下面几个&#xff1a;…

CSS高级技巧

一、 精灵图 1.1 为什么需要精灵图&#xff1f; 1.2 精灵图&#xff08;sprites&#xff09;的使用 二、 字体图标 2.1 字体图标的产生 2.2 字体图标的优点 2.3 字体图标的下载 icomoom字库 http://icomoon.io 阿里iconfont字库 http://www.iconfont.cn/ 2.4 字体图标的引用…

深度学习的进展及其在各领域的应用

深度学习&#xff0c;作为人工智能的核心分支&#xff0c;近年来在全球范围内引起了广泛的关注和研究。它通过模拟人脑的学习机制&#xff0c;构建复杂的神经网络结构&#xff0c;从大量数据中学习并提取有用的特征表示&#xff0c;进而解决各种复杂的模式识别问题。 一、深度…

腾讯云4核8G服务器最大能承载多少用户在线?12M带宽

腾讯云轻量4核8G12M轻量应用服务器支持多少人同时在线&#xff1f;通用型-4核8G-180G-2000G&#xff0c;2000GB月流量&#xff0c;系统盘为180GB SSD盘&#xff0c;12M公网带宽&#xff0c;下载速度峰值为1536KB/s&#xff0c;即1.5M/秒&#xff0c;假设网站内页平均大小为60KB…

CSP-202012-2-期末预测之最佳阈值

CSP-202012-2-期末预测之最佳阈值 【70分思路】 本题的难点还是时间复杂度&#xff0c;暴力枚举会导致时间超限。对于每一个可能的阈值theta&#xff0c;代码都重新计算了整个predict数组&#xff0c;统计预测正确的数目&#xff0c;因为有两个嵌套的循环&#xff0c;使得时间…

ClickHouse的优缺点和应用场景

当业务场景需要一个大批量、快速的、可支持聚合运算的数据库&#xff0c;那么可选择ClickHouse。 选择ClickHouse 的原因&#xff1a; 记录类型类似于LOG&#xff0c;读取、运算远远大于写入操作选取有限列&#xff0c;对近千万条数据&#xff0c;快算的运算出结果。数据批量…