肯尼斯·里科《C和指针》第13章 高级指针话题(1)进一步探讨指向指针的指针变量的高级声明

news2025/1/20 13:30:50

13.1 进一步探讨指向指针的指针

上一章使用了指向指针的指针,用于简化向单链表插入新值的函数。另外还存在许多领域,指向指针的指针可以在其中发挥重要的作用。这里有一个通用的例子:

这些声明在内存中创建了下列变量。如果它们是自动变量,则无法猜测它们的初始值。

有了上面这些信息之后,请问下面各条语句的效果是什么呢?

①如果ppi是个自动变量,它就未被初始化,这条语句将打印一个随机值。如果它是个静态变量,这条语句将打印0。

②这条语句将把存储ppi的地址作为十进制整数打印出来。这个值并不是很有用。

③这条语句的结果是不可预测的。对ppi不应该执行间接访问操作,因为它尚未被初始化。

接下来的两条语句用处比较大。

ppi = π

这条语句把ppi初始化为指向变量pi。以后就可以安全地对ppi执行间接访问操作了。

*ppi = &i;

这条语句把pi(通过ppi间接访问)初始化为指向变量i。执行完上面最后两条语句之后,这些变量变成了下面这个样子:

现在,下面各条语句具有相同的效果:

i='a';
*pi='a';
**ppi='a';

在一条简单的对i赋值的语句就可以完成任务的情况下,为什么还要使用更为复杂的涉及间接访问的方法呢?这是因为简单赋值并不总是可行,例如链表的插入。在那些函数中,无法使用简单赋值,因为变量名在函数的作用域内部是未知的。函数所拥有的只是一个指向需要修改的内存位置的指针,所以要对该指针进行间接访问操作以访问需要修改的变量。

在前一个例子中,变量i是一个整数,pi是一个指向整型的指针。但ppi是一个指向pi的指针,所以它是一个指向整型的指针的指针。假定我们需要另一个变量,它需要指向ppi。那么,它的类型当然是“指向整型的指针的指针的指针”,而且它应该像下面这样声明:

int  ***pppi;

间接访问的层次越多,需要用到它的次数就越少。但是,一旦真正理解了间接访问,无论出现多少层间接访问,我们应该都能十分轻松地应付。

只有当确实需要时,才应该使用多层间接访问。不然的话,程序将会变得更庞大、更缓慢并且更难于维护。

批注:上面的描述看懂并不困难,但是需要结合具体例子来理解吧。

13.2 高级声明

在使用更高级的指针类型之前,我们必须观察它们是如何声明的。前面的章节介绍了表达式声明的思路以及C语言的变量如何通过推论进行声明。我们在第8章声明指向数组的指针时已经看到过一些推论声明的例子。现在通过观察一系列越来越复杂的声明进一步探索这个话题。

首先来看几个简单的例子:

int        f;      /* 一个整型变量 */
int        *f;    /* 一个指向整型的指针 */

不过,请回忆一下第2个声明是如何工作的:它把表达式*f声明为一个整数。根据这个事实,肯定能推断出f是个指向整型的指针。C声明的这种解释方法可以通过下面的声明得到验证:

int*    f, g;

它并没有声明两个指针。尽管它们之间存在空白,但星号是作用于f的,只有f才是一个指针。g只是一个普通的整型变量。

下面是另外一个例子,以前曾见过:

int        f();

它把f声明为一个函数,它的返回值是一个整数。旧式风格的声明对函数的参数并未提供任何信息。它只声明f的返回值类型。现在将使用这种旧式风格,这样例子看上去简单一些,后面再回到完整的原型形式。

下面是一个新例子:

int        *f();

要想推断出它的含义,必须确定表达式*f( )是如何进行求值的。首先执行的是函数调用操作符(),因为它的优先级高于间接访问操作符。因此,f是一个函数,它的返回值类型是一个指向整型的指针

接下来的一个声明更为有趣:

int    (*f)();

确定括号的含义是分析这个声明的一个重要步骤。这个声明有两对括号,每对的含义各不相同。第2对括号是函数调用操作符,但第1对括号只起到聚组的作用。它迫使间接访问在函数调用之前进行,使f成为一个函数指针,它所指向的函数返回一个整型值

函数指针?是的,程序中的每个函数都位于内存中的某个位置,所以存在指向那个位置的指针是完全可能的。函数指针的初始化和使用将在本章后面详述。

现在,下面这个声明应该是比较容易弄懂了:

int        *(*f)();

它和前一个声明基本相同,f也是一个函数指针,只是所指向的函数的返回值是一个整型指针,必须对其进行间接访问操作才能得到一个整型值。

现在,让我们把数组也考虑进去:

int        f[];

这个声明表示f是个整型数组。数组的长度暂时省略,因为我们现在关心的是它的类型,而不是它的长度。

下面这个声明又如何呢?

int        *f[];

这个声明又出现了两个操作符。下标的优先级更高,所以f是一个数组,它的元素类型是指向整型的指针

下面这个例子隐藏着一个圈套。不管怎样,让我们先推断出它的含义。

int        f()[];

f是一个函数,它的返回值是一个整型数组。这里的圈套在于这个声明是非法的——函数只能返回标量值,不能返回数组

这里还有一个例子,颇费思量。

int        f[]();

现在,f似乎是一个数组,它的元素类型是返回值为整型的函数。这个声明也是非法的,因为数组元素必须具有相同的长度,但不同的函数显然可能具有不同的长度。

但是,下面这个声明是合法的:

int        (*f[])();

首先,必须找到所有的操作符,然后按照正确的次序执行它们。同样,这里有两对括号,它们分别具有不同的含义。括号内的表达式*f[ ]首先进行求值,所以f是一个元素为某种类型的指针的数组。表达式末尾的( )是函数调用操作符,所以f肯定是一个数组,数组元素的类型是函数指针,它所指向的函数的返回值是一个整型值。

如果大家搞清楚了上面最后一个声明,下面这个应该是比较容易的了:

它和上面那个声明的唯一区别就是多了一个间接访问操作符,所以这个声明创建了一个指针数组,指针所指向的类型是返回值为整型指针的函数。

到现在为止,这里使用的是旧式风格的声明,目的是为了让例子简单一些。但ANSI C要求我们使用完整的函数原型,使声明更为明确。例如:

int        (*f)( int, float );
int        *(*g[])( int, float );

前者把f声明为一个函数指针,它所指的函数接受两个参数,分别是一个整型值和浮点型值,并返回一个整型值。后者把g声明为一个数组,数组的元素类型是一个函数指针,它所指向的函数接受两个参数,分别是一个整型值和浮点型值,并返回一个整型指针。尽管原型增加了声明的复杂度,但我们还是应该大力提倡这种风格,因为它向编译器提供了一些额外的信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1441591.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

6.0 Zookeeper session 基本原理详解教程

客户端与服务端之间的连接是基于 TCP 长连接,client 端连接 server 端默认的 2181 端口,也就 是 session 会话。 从第一次连接建立开始,客户端开始会话的生命周期,客户端向服务端的ping包请求,每个会话都可以设置一个…

python列表推导式(List Comprehension)

目录 1. 介绍:2. 示例3. 过滤功能4. 多重循环小结: 1. 介绍: 列表推导式是 Python 中一种简洁的语法形式,用于从一个可迭代对象中生成新的列表。它的语法形式为 [expression for item in iterable],其中expression是一…

【Larry】英语学习笔记语法篇——从句=连词+简单句

目录 三、从句连词简单句 1、必须有连词 主从结构 疑问词的词性 2、名词性从句 同位语从句 形式主语 形式宾语 that的省略 3、形容词性从句(上) 关系代词 关系词的作用 介词前置问题 4、形容词性从句(中) 定语关系…

(十四)springboot实战——spring securtity安全框架原理之启动流程

前言 本节内容主要介绍spring securtity的初始化启动流程,spring security是通过EnableWebSecurity注解来启用的,在EnableWebSecurity注解中主要引入了WebSecurityConfiguration、SpringWebMvcImportSelector、OAuth2ImportSelector、HttpSecurityConfi…

光耦固态继电器:2024年发展之路

随着科技的迅猛发展,光耦固态继电器在2024年面临着独特的机遇与挑战。本文将深入分析光耦固态继电器行业的现状,探讨其在技术创新、市场需求等方面的机遇和挑战。 光耦固态继电器技术创新的机遇: 光耦固态继电器作为电气控制领域的关键元件&…

leetcode(哈希表)49.字母异位词分组(C++详细解释)DAY5

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 示例 1: 输入: strs [“eat”, “tea”…

请手写几种js排序算法

什么是排序算法 冒泡排序选择排序插入排序快速排序归并排序(Merge Sort) 思想实现测试分析动画 快速排序 (Quick Sort) 思想实现测试分析动画 思考:快排和归并用的都是分治思想,递推公式和递归代码也非常相…

RCE(命令执行)知识点总结最详细

description: 这里是CTF做题时常见的会遇见的RCE的漏洞知识点总结。 如果你觉得写得好并且想看更多web知识的话可以去gitbook.22kaka.fun去看,上面是我写的一本关于web学习的一个gitbook,当然如果你能去我的github为我的这个项目点亮星星我会感激不尽htt…

MaxKey 单点登录认证系统——前端后端合并步骤

开发指南 | MaxKey单点登录认证系统 该项目前端是Angular项目,后端是springboot项目 以maxkey-web-app前后端合并为例 构建MaxKey统一认证前端 maxkey-web-frontend/maxkey-web-app ng build --prod --base-href /sign/static/以上sign由以下得来: 根…

Ubuntu22.04 gnome-builder gnome C 应用程序习练笔记(一)

一、序言 gnome-builder构建器是gnome程序开发的集成环境,支持主力语言C, C, Vala, jscript, python等,界面以最新的 gtk 4.12 为主力,将其下版本的gtk直接压入了depreciated,但gtk4.12与普遍使用的gtk3有很大区别,原…

问题:银行账号建立以后,一般需要维护哪些设置,不包括() #学习方法#经验分享

问题:银行账号建立以后,一般需要维护哪些设置,不包括() A.维护结算科目对照 B.期初余额初始化刷 C.自定义转账定义 D.对账单初始化 参考答案如图所示

Apktool任意文件写入漏洞分析 CVE-2024-21633

前置知识 在复现该漏洞前,有必要了解Apktool和resources.arsc相关的基础知识,方便理解后续POC的构造。 Apktool是一款流行的开源逆向工程软件,用于反编译和编译Android应用,因此,Apktool被许多其他逆向工程软件集成。…

鸿蒙开发-UI-图形-图片

鸿蒙开发-UI-组件 鸿蒙开发-UI-组件2 鸿蒙开发-UI-组件3 鸿蒙开发-UI-气泡/菜单 鸿蒙开发-UI-页面路由 鸿蒙开发-UI-组件导航-Navigation 鸿蒙开发-UI-组件导航-Tabs 文章目录 一、基本概念 二、图片资源加载 1. 存档图类型数据源 2.多媒体像素图 三、显示矢量图 四、图片…

node网站 宝塔 面板配置 防止刷新404

1.问题 我现在配置了一个网站 后台项目 放到了宝塔上 将相应的域名和项目都配置好了 域名也可以访问 但是有的时候 出现了404 类似这种404 这个资源找不到 2.说明 其实这个问题的原因是nginx 的问题 反向代理的原因 3.解决 在这个配置文件中 有个配置文件 # 防止刷新404l…

Spring第三天

一、AOP 1 AOP简介 问题导入 问题1:AOP的作用是什么? 问题2:连接点和切入点有什么区别,二者谁的范围大? 问题3:请描述什么是切面? 1.1 AOP简介和作用【理解】 AOP(Aspect Oriented Progra…

MyBatis 实现动态 SQL

MyBatis 中的动态 SQL 就是SQL语句可以根据不同的情况情况来拼接不同的sql。 本文会介绍 xml 和 注解 两种方式的动态SQL实现方式。 XML的实现方式 先创建一个数据表,SQL代码如下: DROP TABLE IF EXISTS userinfo; CREATE TABLE userinfo (id int(1…

机器学习:分类决策树(Python)

一、各种熵的计算 entropy_utils.py import numpy as np # 数值计算 import math # 标量数据的计算class EntropyUtils:"""决策树中各种熵的计算,包括信息熵、信息增益、信息增益率、基尼指数。统一要求:按照信息增益最大、信息增益率…

原生JS使用PrintJs进行表格打印 -- 遇到的问题总结

需求1:表格自动分页之后,表头在每一页都需要显示 html中表头增加 thead 标签 css样式新增: thead {display: table-header-group; /* 这个属性使thead总是在新的page-break之后重新开始 */ }需求2:表格自动分页之后,…

深度学习技巧应用36-深度学习模型训练中的超参数调优指南大全,总结相关问题与答案

大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用36-深度学习模型训练中的超参数调优指南大全,总结相关问题与答案。深度学习模型训练中的调优指南大全概括了数据预处理、模型架构设计、超参数优化、正则化策略和训练技巧等多个关键方面,以提升模型性能和泛化能力。 …

IDEA 推荐插件

grep-console 输出日志换颜色 MybatisLogFormat 直接复制mybatis的日志成完整的SQL SequenceDiagram 生成时序图