前言
本文面向已经掌握 C 语言基础语法、正在准备笔试面试或想彻底搞懂「数组与指针」的同学。如果你曾被 sizeof 和 strlen 的输出结果绕晕,或者看到 &a + 1、*(*(a + 1) + 1) 这类表达式就头皮发麻,那么这篇文章正是为你准备的。
本文覆盖的知识点包括:
sizeof与strlen的本质区别:一个是运算符、一个是库函数,一个算内存占用、一个数\0之前的字符个数;- 数组与指针笔试题:一维数组、字符数组、二维数组中数组名退化的各种情形;
- 指针运算笔试题:指针加减整数、指针减指针、多级指针与字符串指针数组的综合运用。
阅读建议:建议先看第 1 节把 sizeof 和 strlen 的差异吃透,再按顺序做第 2、3 节的题目。每道题请先自己写出答案,再对照解析,重点关注「数组名在什么情况下代表整个数组、什么情况下退化为首元素地址」这一条主线。文中题目均以图片形式给出,建议边看边在纸上画内存布局图,效果会好很多。
目录
1.sizeof和strlen的对比
1.sizeof
我们在之前已经学过sizeof了,sizeof是用来计算变量所占内存空间的大小的,单位为是字节 ,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。
sizeof只关注占用内存空间的大小,不在乎内存中存放什么数据。
比如:

2.strlen
strlen是C语言库函数,在使用该函数前,必须要包含对应的头文件:#include <stdio.h>,功能是求字符串长度。函数的原型如下:
c
size_t strlen(const char*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个指针之间相差的元素个数,而小地址-大地址算出来的是一个负数
&p42-&a42==-4,但是由于%d和%p打印的区别:

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

运行结果:

题目5:

解析:

题目6:

解析:

题目7:

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

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

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

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

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

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

总结
- 数组名退化规则 :只有在
sizeof(数组名)和&数组名两种场景下,数组名才表示整个数组;其余任何场合(包括作为函数实参、参与算术运算、被解引用)数组名都会退化为首元素地址,二维数组则退化为第一行(一维数组)的地址。 sizeof是运算符而非函数 :它在编译期就完成求值,括号内的表达式不会被真实计算,因此sizeof不会产生任何运行时副作用,也不会访问内存。strlen是库函数 :它从给定地址开始逐个字符向后统计,直到遇到\0才停止,因此传入的若不是以\0结尾的字符串,就可能发生越界查找,结果不可预期。sizeof与strlen的对比 :sizeof计算的是类型或变量占用的字节数(含\0),strlen统计的是\0之前的有效字符个数(不含\0);前者在编译期确定,后者在运行时遍历。- 指针运算的本质 :指针加减整数按所指类型的大小步进,指针减指针得到两者之间相差的元素个数(可能为负),而
%d与%p打印同一地址会得到截然不同的结果,做题时务必看清格式符与指针类型。