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

指针(3):strlen的模拟实现和传址调用

指针(3):strlen的模拟实现和传址调用

  • 1.strlen的模拟实现
    • 1.1 streln的介绍
    • 1.2 strlen的模拟实现
    • 1.3 注意
    • 1.4 补充
  • 2.传址调用

1.strlen的模拟实现

1.1 streln的介绍

库函数strlen的功能是求字符串的长度,统计的是字符串中\0之前的字符的个数
函数原型如下:

size_tstrlen(constchar*str);

参数str接收⼀个字符串的起始地址,然后开始统计字符串中 \0 之前的字符个数,最终返回⻓度。

strlen的运用:

#include<stdio.h>#include<string.h>intmain(){intret=strlen("abcdef");printf("%d",ret);return0;}

字符串“abcdef”在内存中实际存储的是a b c d e f \0共7个字节,strlen只统计\0之前字符的数量,因此输出结果为6。

1.2 strlen的模拟实现

根据上面对strlen函数原型的分析我们可以得知,如果要模拟实现只要从起始地址开始向后逐个字符的遍历,只要不是 \0 字符,计数器就+1,这样直
到 \0 就停⽌。

接下来就让我们来完成strlen模拟实现的代码:

#include<stdio.h>size_tmy_strlen(constchar*str){size_tcount=0;while(*str){str++;count++;}returncount;}intmain(){size_tret=my_strlen("abcdef");printf("%zu\n",ret);return0;}
  1. 首先将 “abcdef” 传到函数my_strlen
  2. 设置一个计数器count用来统计该字符串\0之前的字符的个数
  3. 通过while循环遍历该字符串\0之前的字符,每循环一次指针向后移动一位,并且使得计数器count加一
  4. 遍历完成后,返回count,函数模拟完成

1.3 注意

通过观察我们可以发现模拟函数实现时,我们定义的用来接收my_strlenret的类型为size_t(无符号整数类型),而上面我们在运用strlen时,用来接收其返回值时用的ret的类型为int,但最后输出结果都正确,这是为什么呢。

这是因为字符串“abcdef”中字符数量太小,用int来接收也足够,当字符数量够大时,用int接收就会出现错误,所以最好是使用size_t 和 %zu来接收和打印,当然在字符串比较小的时候,也可以用int 和 %d来接收和打印。

此外还有一个需要注意的点,由于strlen的返回值是无符号整数,因此两个strlen相减是不能得到负数的,看下面这个例子:

if(strlen("hi")-strlen("hello")>0)

在这个例子中,看似strlen(“hi”)得到数是2,strlen(“hello”)得到的数是4,2 - 4 < 0,但是strlen返回值是size_t,不存在负数只用正数,因此strlen(“hi”) - strlen(“hello”)所得到的值是一个很大的无符号正数,因此这个式子永远大于0.

1.4 补充

根据之前章节里面所提到的指针-指针,我们可以用另一种方式来实现strlen的模拟实现,即首先记录指针的起始位置,然后遍历字符串,得到指针结束时的位置,用结束指针-起始指针即可得到字符的数量。

#include<stdio.h>size_tmy_strlen(constchar*str){constchar*start=str;while(*str){str++;}returnstr-start;}intmain(){size_tret=my_strlen("abcdef");printf("%zu\n",ret);return0;}

注意:指针相减得到的数字是有符号整数类型,但return时会将其隐式转化size_t类型,因此无需进行强制类型转化。

2.传址调用

我们学习指针是为了解决问题,那么有哪些问题是只有指针才能解决的呢?

我们来看这样一个问题:写一个函数,交换两个整型变量的值。

经过一番思考,我们可能会写出这样的代码:

#include<stdio.h>voidswap(intx,inty){intc=0;c=x;x=y;y=c;}intmain(){inta=5;intb=3;swap(a,b);printf("%d %d",a,b);return0;}

让我们运行起来看看是否能够达到目的

我们发现这并没有产生交换的后果,这是为什么呢?

让我们来通过调试观察一下。

我们发现,在main函数内部创建了变量a b,他们的地址分别为0x000000026dc6ff6c4 和 0x000000026dc6ff6e4,而在调用swap函数时,我们将 a 和 b 传递给swap函数,swap函数在函数内部创建了形参x 和 y用来接收a 和 b的值,但是x的地址是0x000000026dc6ff6a0y的地址是0x000000026dc6ff6a8x和y确实接收到了a和b的值,不过x的地址和a的地址不⼀样,y的地址和b的地址不⼀样,相当于xy是独⽴的空间,而我们又知道数据都是存储在地址所对应的内存单元当中,他们的地址不同,因此他们所对应的内存单元也就不同,那么在swap函数内部交换x和y的值,⾃然不会影响a和b,当swap函数调⽤结束后回到main函数,a和b的值没法交换。,这就是传值调⽤

因此我们可以得出结论:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参。

因此swap失败了

那我们该怎么办呢?

其实只需要将a和b的地址传递给swap函数,让swap函数通过地址间接的操作a和b的值,这样就能够达到交换a和b的值的功能了。

#include<stdio.h>voidswap(int*x,int*y){intc=0;c=*x;*x=*y;*y=c;}intmain(){inta=5;intb=3;swap(&a,&b);printf("%d %d",a,b);return0;}


由此我们看到代码成功的完成了任务这⾥调⽤swap函数的时候是将变量的地址传递给了函数,这种函数调⽤⽅式叫:传址调⽤

传址调⽤,可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量;所以未来函数中只是需要主调函数中的变量值来实现计算,就可以采⽤传值调⽤。如果函数内部要修改主调函数中的变量的值,就需要传址调⽤。

http://www.jsqmd.com/news/1394161/

相关文章:

  • AI角色一致性生成技术:从原理到Stable Diffusion实战应用
  • Carla仿真系列:7_BEV + 语义分割融合,一张鸟瞰图看懂整个场景
  • FFmpeg像素游戏超分算法:方块人风格视频4K增强实战
  • AI驱动漏洞响应:从SBOM到自动化修复的工程实践
  • 湿法冶金工艺优化:基于杜笙螯合树脂的高钴低镍体系微量镍钴分离技术方案
  • Harness Engineering实践反思:AI编程助手为何难以驾驭大型软件工程?
  • 2026年|北京密云区国内GEO服务商代理加盟靠谱推荐:选型标准、避坑要点与解析 - 小随科技
  • 从Prompt到Spec:AI编程范式的变革与规格驱动开发实践
  • Honeywell 900S75-0460 CPU 模块
  • 适配器模式实战:解决接口不兼容问题的核心技术与工程实践
  • Litellm供应链入侵实战复盘:漏洞检测、环境排查与机密兜底方案
  • 系统化增强AI代码助手:构建理解项目上下文的智能编程伙伴
  • C++ 入门核心语法详解:命名空间、输入输出、缺省参数、函数重载、引用、inline 与 nullptr
  • AI驱动PPT制作:从内容生成到视觉设计的效率革命
  • 北京防水补漏市场深度调研报告(2026)|本地靠谱服务商盘点推荐 - 捷修防水
  • 天道19-21
  • 智能硬件隐私设计避坑指南:从Meta眼镜争议看技术伦理实践
  • 招投标数字化全栈方案:AI 标书智能生成 + 电子标全流程自动化管控系统设计与落地
  • Saber 拼车“模拟器”游戏引争议:用 AI 取代编剧,官方与员工说法不一?
  • AI伦理与工程实践:从OpenAI人事变动看开发者如何构建安全护栏
  • 饿了么/淘宝闪购 sign,bxet,x-ele-check最新算法逆向
  • 寄电动车能不拆电池吗?2026年电动车托运全攻略 - 快递物流资讯
  • 三月七小助手:解放双手的崩坏星穹铁道自动化工具终极指南
  • Kimi K3 API 工程化实践:从调用到构建智能应用
  • YOLO模型部署踩坑实录:ONNX转换、TensorRT编译、推理加速常见问题
  • 苏音娱乐全套资质**背书 **公众号苏音娱乐合规创业无忧 - nuanyin
  • Windows VScode 搬家指南
  • Stable Diffusion入门第16-18天:从文生图到图生图——用一张图“导演”你的AI创作
  • 并行实验先守住数据版本和随机状态
  • 知芽深度综述报告排障指南:文献综述一键成稿时如何核对全文与引用