news 2026/10/28 1:51:55

C语言入门,深入理解指针(6)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言入门,深入理解指针(6)

前言

本文面向已经掌握 C 语言基础语法、正在准备笔试面试或想彻底搞懂「数组与指针」的同学。如果你曾被sizeof和strlen的输出结果绕晕,或者看到&a + 1、*(*(a + 1) + 1)这类表达式就头皮发麻,那么这篇文章正是为你准备的。

本文覆盖的知识点包括:

  • sizeof与strlen的本质区别:一个是运算符、一个是库函数,一个算内存占用、一个数\0之前的字符个数;
  • 数组与指针笔试题:一维数组、字符数组、二维数组中数组名退化的各种情形;
  • 指针运算笔试题:指针加减整数、指针减指针、多级指针与字符串指针数组的综合运用。

阅读建议:建议先看第 1 节把sizeof和strlen的差异吃透,再按顺序做第 2、3 节的题目。每道题请先自己写出答案,再对照解析,重点关注「数组名在什么情况下代表整个数组、什么情况下退化为首元素地址」这一条主线。文中题目均以图片形式给出,建议边看边在纸上画内存布局图,效果会好很多。

目录

  • 前言
  • 1.sizeof和strlen的对比
    • 1.sizeof
    • 2.strlen
    • 3.sizeof和strlen的对比
  • 2.数组和指针笔试题解析
    • 1.一维数组
    • 2.字符数组
    • 3.二维数组
  • 3.指针运算笔试题解析
  • 总结

1.sizeof和strlen的对比

1.sizeof

我们在之前已经学过sizeof了,sizeof是用来计算变量所占内存空间的大小的,单位为是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。
sizeof只关注占用内存空间的大小,不在乎内存中存放什么数据。
比如:

2.strlen

strlen是C语言库函数,在使用该函数前,必须要包含对应的头文件:#include <stdio.h>,功能是求字符串长度。函数的原型如下:

size_tstrlen(constchar*str);

我们在之前已经模拟实现过这个函数,这里就不做过多的演示了。
strlen函数统计的是从参数str存放的地址开始往后统计\0之前字符的个数,strlen函数直到遇到\0才会停止查找,有时候可能会存在越界查找。

3.sizeof和strlen的对比

2.数组和指针笔试题解析

首先我们先回忆一下数组名的意义:
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3.除了以上2种情况以外,数组名均表示首元素的地址。

1.一维数组

注:题目%d均换成%zu
题目:

解析:

2.字符数组

代码1:

解析:

代码2:

解析:

代码3:

解析:

代码4:

解析:

代码5:

解析:

代码6:

解析:

3.二维数组

代码1:

解析:

关于sizeof并不会真实地去访问数据的解释:在编译链接阶段,sizeof就将括号里面的表达式转化为了二进制的指令,等到运行代码时,sizeof括号内的表达式早就不存在了。
例如:

运行结果:

我们通过运行结果可以发现s没有发生改变,说明了sizeof括号里的表达式并不会真实的计算

3.指针运算笔试题解析

题目1:

解析:

题目2:

解析:

但是在16进制下,是要打印8个16进制的比特位的,所以结果为:

题目3:

解析:

题目4:

解析:我们先来分析一下

指针-指针的结果是2个指针之间相差的元素个数,而小地址-大地址算出来的是一个负数
&p[4][2]-&a[4][2]==-4,但是由于%d和%p打印的区别:

但是%d打印在屏幕上的是原码,-4就是10进制的,转化为原码还是-4
%p的打印如下图:

运行结果:

题目5:

解析:

题目6:

解析:

题目7:

解析:
在打印之前,变量之间的关系应该是这样的:

按printf函数的打印顺序,分别称第几次打印
第一次打印:

cpp++,再解引用,打印得到POINT,接着因为++改变了原来cpp的指向,所以第二次打印的图是基于第一次打印完成的图继续做的
第二次打印:

++cpp,解引用得到cp[3],cp–,得到c,c存放的是E的地址,加3往后得到的是E,最后打印出来的是ER
第三次打印的图是基于第二次打印完成的图继续做的
第三次打印:

第四次打印的图是基于第二次打印完成的图继续做的
第四次打印:


cpp-1解引用得到是c+2的地址,再此基础上减1,得到的是c[1]里面存放的N的地址,再加1,得到的是E的地址,最后打印得到EW。
运行结果:

总结

  1. 数组名退化规则:只有在sizeof(数组名)和&数组名两种场景下,数组名才表示整个数组;其余任何场合(包括作为函数实参、参与算术运算、被解引用)数组名都会退化为首元素地址,二维数组则退化为第一行(一维数组)的地址。
  2. sizeof是运算符而非函数:它在编译期就完成求值,括号内的表达式不会被真实计算,因此sizeof不会产生任何运行时副作用,也不会访问内存。
  3. strlen是库函数:它从给定地址开始逐个字符向后统计,直到遇到\0才停止,因此传入的若不是以\0结尾的字符串,就可能发生越界查找,结果不可预期。
  4. sizeof与strlen的对比:sizeof计算的是类型或变量占用的字节数(含\0),strlen统计的是\0之前的有效字符个数(不含\0);前者在编译期确定,后者在运行时遍历。
  5. 指针运算的本质:指针加减整数按所指类型的大小步进,指针减指针得到两者之间相差的元素个数(可能为负),而%d与%p打印同一地址会得到截然不同的结果,做题时务必看清格式符与指针类型。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 1:51:55

非谓语动词的含义

非谓语动词是英语语法中较难的内容&#xff0c;非谓语动词形式多样&#xff0c;位置随意&#xff0c;容易和谓语动词混淆&#xff0c;影响我们判断句子的主干。那么到底什么是非谓语动词呢&#xff1f;非谓语动词怎么使用&#xff1f;一、非谓语动词的定义顾名思义&#xff0c;…

作者头像 李华
网站建设 2026/10/28 1:51:07

AFFiNE 内网离线部署:镜像导入 + 编排 + 常见报错排查

第 1 章 名词认一遍名词一句话解释Docker运行容器的引擎镜像程序打包好的"毛坯房"容器镜像跑起来的实例Compose用一个 YAML 管理多个容器bind mount宿主机目录挂进容器&#xff1b;删容器不删目录named volumeDocker 管理的卷&#xff1b;down -v 会删migration启动前…

作者头像 李华
网站建设 2026/10/28 1:50:26

启元 Q1 的数字身体 从 URDF 看懂机器人关节

一台机器人还没接上电源&#xff0c;开发者已经可以在电脑里查看它的身体结构。软件依据什么判断哪里是肩膀、手肘朝哪个方向弯&#xff0c;甚至前臂会不会碰到躯干&#xff1f;这些问题&#xff0c;需要先读懂机器人的模型文件。 这次从启元机器人官方开发者社区的资料下载页…

作者头像 李华
网站建设 2026/10/28 1:49:17

K8S:scale 与 delete pod 核心区别

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华