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

前言

本文面向已经掌握 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。

运行结果:

总结

  1. 数组名退化规则 :只有在 sizeof(数组名) 和 &数组名 两种场景下,数组名才表示整个数组;其余任何场合(包括作为函数实参、参与算术运算、被解引用)数组名都会退化为首元素地址,二维数组则退化为第一行(一维数组)的地址。
  2. sizeof 是运算符而非函数 :它在编译期就完成求值,括号内的表达式不会被真实计算,因此 sizeof 不会产生任何运行时副作用,也不会访问内存。
  3. strlen 是库函数 :它从给定地址开始逐个字符向后统计,直到遇到 \0 才停止,因此传入的若不是以 \0 结尾的字符串,就可能发生越界查找,结果不可预期。
  4. sizeof 与 strlen 的对比 :sizeof 计算的是类型或变量占用的字节数(含 \0),strlen 统计的是 \0 之前的有效字符个数(不含 \0);前者在编译期确定,后者在运行时遍历。
  5. 指针运算的本质 :指针加减整数按所指类型的大小步进,指针减指针得到两者之间相差的元素个数(可能为负),而 %d 与 %p 打印同一地址会得到截然不同的结果,做题时务必看清格式符与指针类型。
相关推荐
略略略咯咯1 小时前
33333
开发语言·windows·python
垆边人似月.1 小时前
第三篇:函数、文件与异常处理 / Functions, Files & Exception Handling
开发语言·python
云和数据.ChenGuang1 小时前
项目打开后没有主类
开发语言·人工智能·langchain·1024程序员节
鬼手点金1 小时前
缓存作为架构约束
开发语言·前端·人工智能·python·microsoft·缓存·架构
Navigator_Z1 小时前
LeetCode //C - 1306. Jump Game III
c语言·算法·leetcode
SEO_juper1 小时前
Node.js 页面主题聚焦度检测:title 和正文各说各的,AI 也读不懂
开发语言·人工智能·node.js·seo·外贸独立站
软件技术NINI1 小时前
基于PHP和MySQL的快递代收点管理系统的设计与实现
开发语言·javascript·数据库·mysql·毕业设计·php·毕设
Dovis(誓平步青云)2 小时前
一个分区超温就全棚浇水,控制系统怎样按区下策略
开发语言·前端·javascript·人工智能·机器学习
kiracrimson2 小时前
编码简述:内存里没有文字,只有一张对照表
开发语言·c++·二进制·计算机组成原理