当前位置: 首页 > news >正文

strlen 函数的使用与模拟实现

目录

一、strlen 函数的基本特性

二、使用注意事项

补码是计算机表示有符号整数的标准方式,其核心规则是:(后面会讲解)

具体执行过程

为什么会出现这种情况

补码计算详细解释

三、strlen 的模拟实现

方法1:计数器方式

方法2:递归方式(不创建临时变量)

方法3:指针相减方式

四、实际应用建议


一、strlen 函数的基本特性

strlen 是 C 语言标准库中用于计算字符串长度的函数,其原型如下:

size_t strlen(const char *str);

该函数具有以下特点:

  1. 以 '\0' 为结束标志:字符串必须以空字符 '\0' 结尾,函数返回的是 '\0' 前面出现的字符个数(不包含 '\0' 本身)

  2. 返回值类型:返回值为 size_t 类型,这是一个无符号整型(unsigned integer),这在比较字符串长度时容易导致错误

  3. 头文件:使用前需要包含 <string.h> 头文件


二、使用注意事项

        在这个例子中,关键问题在于 strlen() 返回的是 size_t 类型(无符号整数),而两个无符号整数相减的结果也是无符号整数,这会导致一些违反直觉的比较结果。

#include <stdio.h>
#include <string.h>int main()
{const char* str1 = "abcdef";const char* str2 = "bbb";if(strlen(str2) - strlen(str1) > 0){printf("str2 > str1\n");  // 这个分支会被执行}else{printf("str1 > str2\n");}return 0;
}

        上述代码会输出 "str2 > str1",尽管直观上 "abcdef" 比 "bbb" 长。这是因为无符号数相减的结果也是无符号数,永远不会小于0。

补码是计算机表示有符号整数的标准方式,其核心规则是:(后面会讲解)

  • 正数的补码 = 其二进制原码(和原码相同)

  • 负数的补码 = 其绝对值的二进制表示取反(按位取反)后加 1

具体执行过程

  1. strlen(str2) 返回 3(size_t 类型)

  2. strlen(str1) 返回 6(size_t 类型)

  3. 计算 3 - 6

    • 对于无符号整数,这个操作不会产生负数

    • 在32位系统中,size_t 通常是32位无符号整数

    • 3 - 6 的补码计算:

      • 3 的二进制: 0000 0000 0000 0000 0000 0000 0000 0011

      • -6 的二进制(补码): 1111 1111 1111 1111 1111 1111 1111 1010

      • 相加结果: 1111 1111 1111 1111 1111 1111 1111 1101

    • 这个结果解释为无符号整数是一个很大的正数(4294967293)

  4. 比较 (4294967293 > 0) 结果为真

为什么会出现这种情况

  • 无符号整数没有负数的概念,当减法结果为"负"时,会回绕到最大的无符号整数

  • 这是C语言中常见的安全隐患,称为"无符号整数回绕"(unsigned integer wrap-around)

补码计算详细解释

在计算机中,负数用补码表示,减法实际上是加负数的补码:

  1. 计算 -6 的补码:

    • 6 的二进制: 0000 0000 0000 0000 0000 0000 0000 0110

    • 取反: 1111 1111 1111 1111 1111 1111 1111 1001

    • 加1: 1111 1111 1111 1111 1111 1111 1111 1010 (这就是-6的补码)

  2. 计算 3 + (-6):

      0000 0000 0000 0000 0000 0000 0000 0011 (3)
    + 1111 1111 1111 1111 1111 1111 1111 1010 (-6)
    -----------------------------------------1111 1111 1111 1111 1111 1111 1111 1101 (结果)
  3. 如果解释为有符号整数,这是-3

  4. 但作为无符号整数,这是4294967293


三、strlen 的模拟实现

方法1:计数器方式

#include <assert.h>
#include <stdio.h>int my_strlen(const char* str)
{int count = 0;assert(str != NULL);  // 确保指针非空while (*str != '\0'){count++;str++;}return count;
}int main()
{const char* str1 = "abcdef";const char* str2 = "bbb";printf("%zu\n", my_strlen(str1));printf("%zu\n", my_strlen(str2));return 0;
}

方法2:递归方式(不创建临时变量)

#include <assert.h>
#include <stdio.h>int my_strlen(const char* str)
{assert(str != NULL);if (*str == '\0')return 0;elsereturn 1 + my_strlen(str + 1);
}int main()
{const char* str1 = "abcdef";const char* str2 = "bbb";printf("%zu\n", my_strlen(str1));printf("%zu\n", my_strlen(str2));return 0;
}

先拆分(递推),再回归(返回):(忘记了的话可以先回顾递归那一章节的知识点)

方法3:指针相减方式

#include <assert.h>
#include <stdio.h>int my_strlen(const char* str)
{assert(str != NULL);const char* p = str;  // 使用const保持一致性while (*p != '\0')p++;return p - str;  // 指针相减得到元素个数
}int main()
{const char* str1 = "abcdef";const char* str2 = "bbb";printf("%zu\n", my_strlen(str1));printf("%zu\n", my_strlen(str2));return 0;
}


四、实际应用建议

  1. 安全性:在实际项目中,应考虑添加参数检查(如使用assert)

  2. const修饰:使用const修饰指针参数可以防止意外修改字符串内容

  3. 性能考虑:指针相减的方式通常效率最高,递归方式最不推荐在实际项目中使用

  4. 边界情况:处理空字符串("")时应返回0,处理NULL指针时应进行错误处理

        这些实现方式展示了C语言中字符串操作的多种思路,理解它们有助于深入掌握指针和字符串处理的核心概念。

http://www.dtcms.com/a/339553.html

相关文章:

  • Kubernetes 的 YAML 配置文件-apiVersion
  • Python入门第10课:用Python操作Excel,openpyxl与pandas实用技巧
  • oracle官网下载jdk历史版本,jdk历史版本下载
  • 涡流-信号完整性分析
  • LCC-LCC谐振式无线充电系统控制技术研究的复现
  • VsCode 便携版(绿色版)下载及配置
  • 交换机原理
  • 自建知识库,向量数据库 (十)之 文本向量化——仙盟创梦IDE
  • 牛津大学xDeepMind 自然语言处理(2)
  • 【驱动】RK3576:桌面操作系统基本概念
  • 存储系统中的“脏数据”(Dirty Data)概念及其常见误解
  • uniapp 5+App项目,在android studio模拟器上运行调试
  • 光学件加工厂倚光科技:陪跑光学未来力量
  • 算法——质数筛法
  • 强化学习-CH3 最优状态值和贝尔曼最优方程
  • Spring Cloud——服务注册与服务发现原理与实现
  • 零基础从头教学Linux(Day 15)
  • sfc_os!SfcValidateDLL函数分析之cache文件版本
  • “R语言+遥感”的水环境综合评价方法实践技术应用
  • 告别 Dify 工作流,让 NL2SQL 落地更直接
  • 【动态规划:路径问题】最小路径和 地下城游戏
  • JCTools Spsc:单生产者-单消费者无锁队列
  • 使用 Map 存储值和使用对象object储存的区别
  • 18.web api 9
  • C++高频知识点(二十七)
  • three.js学习记录(第三节:平面几何体BufferGeometry)
  • ADSP-21565开发板和ADSP-21569开发板的底板设计区别
  • ComfyUI 里的 Prompt 插值器(prompt interpolation / text encoder 插值方式)的含义和作用!
  • 通信方式:命名管道
  • nuc设置脚本开机自启动