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

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

0x00 strlen函数介绍

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

cpp 复制代码
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

💬 使用方法演示:

cpp 复制代码
#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 函数:

cpp 复制代码
#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

⚡ 简化:

cpp 复制代码
#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 函数(禁止创建临时变量):

cpp 复制代码
#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 函数(禁止创建临时变量):

cpp 复制代码
#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,末尾位置减去起始位置即可得到字符串的长度。

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

cpp 复制代码
#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 ,一起来欣赏欣赏:(和上面的代码原理一样,只是变量名不同)

cpp 复制代码
/***
*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 );
}

本篇完

cpp 复制代码
📌 [ 笔者 ]   王亦优
📃 [ 更新 ]   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]. |

相关推荐
q5673152312 分钟前
在 Bash 中获取 Python 模块变量列
开发语言·python·bash
许野平37 分钟前
Rust: 利用 chrono 库实现日期和字符串互相转换
开发语言·后端·rust·字符串·转换·日期·chrono
也无晴也无风雨41 分钟前
在JS中, 0 == [0] 吗
开发语言·javascript
狂奔solar1 小时前
yelp数据集上识别潜在的热门商家
开发语言·python
朱一头zcy1 小时前
C语言复习第9章 字符串/字符/内存函数
c语言
此生只爱蛋1 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
blammmp1 小时前
Java:数据结构-枚举
java·开发语言·数据结构
何曾参静谧2 小时前
「C/C++」C/C++ 指针篇 之 指针运算
c语言·开发语言·c++
暗黑起源喵2 小时前
设计模式-工厂设计模式
java·开发语言·设计模式
WaaTong2 小时前
Java反射
java·开发语言·反射