C语言KR圣经笔记 5.1指针和地址 5.2指针和函数参数

第五章 指针和数组

指针是包含变量地址的变量。在 C 语言中,指针被大量使用,部分原因是有时只能用指针来表达某种计算,而部分原因是相比其他方式,指针通常能带来更紧凑和高效的代码。指针和数组是紧密关联的;本章也讲探讨它们的关系,并演示如何利用这个关系。

指针曾经和 goto 语句一起,被归结为用于创建“让人不可能理解”的程序的绝妙方式。如果粗心大意地使用指针,这个说法当然是对的,而且很容易创建指向不可预料位置的指针。然而,通过训练和规范约束,指针可以用来得到清晰性和简洁性。这正是我们在本书中尽量展示的方面。

ANSI C 的主要改动是把如何操纵指针的规则给明确了,实际上就是把优秀程序员已有的实践,和优秀编译器已加强的地方,做成了强制要求。另外,void * 类型(指向 void 的指针)取代了 char * ,作为通用指针的正确类型。

5.1 指针和地址

我们先从内存组织的简化图开始。一台典型的机器有一组连续编号或者叫编址的内存单元,这些内存单元可以被各自独立操作,或者是按连续分组进行操作。通常的情况是任一个字节可以是一个 char, 一对单字节的内存单元可以被当作是 short 整型,而四个连续的字节组成一个 long。指针是一组(通常是2个或4个)可以保存地址的单元。这样,如果 c 是一个char 而 p 是指向它的指针,则我们可以用下图来表示这种情况:

一元操作符 & 给出一个对象的地址,因此如下语句

p = &c;

把 c 的地址赋给 p,而 p 被称作“指向” c。操作符 & 只能用于内存中的对象:变量和数组元素。它不能用于表达式、常量 或者寄存器(register)变量。

一元操作符 * 是 间接 或者叫 解引用 操作符;当用于指针时,它访问指针指向的对象。假定 x 和 y 是整数而 ip 是指向 int 的指针。下面这段人为构造(但没有实际用途)的代码,演示了如何声明指针,以及如何使用 & 和 *:

int x = 1, y = 2, z[10];
int *ip;        /* ip是指向int的指针 */ip = &x;        /* ip现在指向x */
y = *p;         /* y现在是1 */
*p = 0;         /* x现在是0 */
ip = &z[0];     /* ip现在指向z[0] */

x,y,z的声明不需要多说了。指针 ip 的声明为

int *ip;

这种形式旨在助记;它表示表达式 *ip 是一个 int。变量声明的语法,模仿了变量可以在其中出现的表达式的语法。这个推理也适用于函数声明。例如

double *p, atof(char *);

表示,在一个表达式中,*p 和 atof(s) 都有着 double 类型的值,而 atof 的参数是 char 的指针。

你还应当注意到有个隐含的约束:指针被限制指向一种特定的对象类型。(有一个例外,“指向 void 的指针”被用来保存任意类型的对象,但不能对它自身解引用。我们会在5.11节说明)

如果 ip 指向整数 x,则 *ip 可以出现在任何 x 可以出现的上下文中,因此

*ip = *ip + 10;

将 *ip 增加10。

一元操作符 & 和 * 比算术操作符的结合更为紧密,因此赋值表达式

y = *ip + 1

首先取出 ip 所指向的对象,将其加1,并把结果赋给 y。而

*ip += 1

会把 ip 指向的对象递增,正如

++*ip

(*ip)++

最后一个例子中的括号是必须的;如果没有括号,则表达式会对 ip 递增,而不会对它指向的内容递增,因为一元操作符 * 和 ++ 是从右至左结合。

最后,由于指针是变量,那么不解引用也可以使用它们。例如,如果 iq 是另一个 int 的指针,

iq = ip

将 ip 的内容拷贝给 iq,这样就使 iq 也指向 ip 所指的对象了。

5.2 指针和函数参数

由于C将参数传给函数时是值传递,因此没有直接的方法可以使被调函数修改调用者函数中的变量。例如,一个排序例程可能会用一个 swap 函数来交换两个无序的元素。如果写

swap(a, b);

其中 swap 函数的定义为

void swap(int x, int y)    /* 错误 */
{int temp;temp = x;x = y;y = temp;
}

但这样是不行的。因为所有调用都是值传递,swap 不能影响调用它的例程中的参数 a 和 b。上面的函数只是交换了 a 和 b 的拷贝

要得到想要的效果,方法是让调用程序传递要修改的值的指针

swap(&a, &b);

由于操作符 & 得到了变量的地址,&a 是 指向 a 的指针。在 swap 之中,参数被声明为指针,而通过它们来间接访问操作数。

void swap(int *px, int *py)    /* 交换 *px和 *py */
{int temp;temp = *px;*px = *py;*py = temp;
}

用图来表示就是:

指针参数使一个函数能够访问并改变调用它的函数中的对象。举个例子,考虑实现一个函数 getint ,该函数执行自由格式的输入转换:将一个字符流拆分成多个整数值,每次调用得到一个整数。getint 必须返回它所找到的值,也必须在没有更多输入时指示文件结束。这两个值必须通过不同的路径返回,因为不管EOF使用什么值,都有可能是一个输入整数的值。

一种解决方案是让 getint 把文件结束状态作为函数返回值,而同时使用一个指针参数来保存转换后的整数,传递回给它的调用者函数。这也是 scanf 使用的模式,详见 7.4节。

下面的循环通过调用 getint 来填充整型数组:

int n, array[SIZE], getint(int *);for (n = 0; n < SIZE && getint(&array[n]) != EOF; n++);

每次调用都将 array[n] 设置为从输入中找到的下一个整数,并对 n 递增。注意,必须将 array[n] 的地址传给 getint 。否则,getint 没有办法将转换后的整数传给调用者。

我们这个版本的 getint 在文件结尾时返回 EOF,在下一个输入不是数字时返回0,而在输入包含合法的数字时返回一个正值:

#include <ctype.h>int getch(void);
void ungetch(int);/* getint: 将下一个整数从输入存入 *pn */
int getint(int *pn)
{int c, sign;while (isspace(c = getch()))    /* 跳过空白字符 */;if (!isdigit(c) && c != EOF && c != '+' && c != '-') {ungetch(c);        /* 非数字 */return 0;}sign = (c == '-') ? -1 : 1;if (c == '+' || c =='-')c = getch();for (*pn = 0; isdigit(c); c = getch())*pn = 10 * *pn + (c - '0');*pn *= sign;if (c != EOF)ungetch(c);return c;
}

在 getint 内, *pn 自始至终 都被当作普通的 int 变量来使用。我们还使用了 getch 和 ungetch(见4.3节),因此多读但又不得不读的一个字符,就能被推回给输入。

练习5-1、在我们的getint版本中,后面没有跟数字的单独的 + 和 - 号,也被当作是合法的数字,其值为 0。修改这个问题,将这种字符推回给输入。

练习5-2、模仿 getint,写一个浮点数版本的 getfloat 函数。 getfloat 用什么类型作为其返回值? 

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

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

相关文章

2024年【安全员-B证】考试报名及安全员-B证新版试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全员-B证考试报名考前必练&#xff01;安全生产模拟考试一点通每个月更新安全员-B证新版试题题目及答案&#xff01;多做几遍&#xff0c;其实通过安全员-B证考试试题很简单。 1、【多选题】《中华人民共和国消防法…

(2023)PanGu-Draw:通过时间解耦训练和可重用的 Coop-Diffusion 推进资源高效的文本到图像合成

PanGu-Draw: Advancing Resource-Efficient Text-to-Image Synthesis with Time-Decoupled Training and Reusable Coop-Diffusion 公众&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要…

【数据结构与算法】字符串匹配(头歌习题)【合集】

目录 第1关&#xff1a;实现朴素的字符串匹配任务描述相关知识编程要求评测说明完整代码 第2关&#xff1a;实现KMP字符串匹配任务描述相关知识编程要求评测说明完整代码 第3关&#xff1a;【模板】KMP算法任务描述相关知识C STL容器string1、string的定义2、string中内容的访问…

16.综合项目实战

一、基础演练&#xff1a; 1、建库、建表 # 创建数据库 create database mysql_exampleTest; use mysql_exampleTest; # 学生表 CREATE TABLE Student( s_id VARCHAR(20), s_name VARCHAR(20) NOT NULL DEFAULT , s_birth VARCHAR(20) NOT NULL DEFAULT , s_sex VARC…

ChatGPT 对SEO的影响

ChatGPT 的兴起是否预示着 SEO 的终结&#xff1f; 一点也不。事实上&#xff0c;如果使用得当&#xff0c;它可以让你的 SEO 工作变得更加容易。 强调“正确使用时”。 你可以使用ChatGPT来帮助进行关键字研究的头脑风暴部分、重新措辞你的内容、生成架构标记等等。 但你不…

MathType 运行时错误‘53’:文件未找到:MathPage.WLL_文件未找到mathpage.wll

问题描述 环境 MathType7.4Microsoft Office 365Windows 11 问题 情景1. Microsoft Word 启动时显示 Please reload Word to load MathType addin properly 情景2. 安装MathType后在 Microsoft Word 中使用复制粘贴时报错 运行时错误‘53’ 情景3. 在 Microsoft Word 中使用 M…

Jenkins 系列:Jenkins 安装(Windows、Mac、Centos)和简介

文章目录 简介发展历史应用场景 Jenkins 安装部署先决条件硬件要求软件包下载war 包部署linux 系统部署mac 系统部署windows 系统部署安装后基本配置解锁自定义 jenkins 插件创建用户配置更新站点 配置文件 简介 Jenkins前身是 Hudson&#xff0c;使用 java 语言开发的自动化发…

mxxWechatBot微信机器人V2使用教程(图文)最全最详细

大家伙&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。 先看这里 mxxWechatBot功能列表一、前言二、适用人群三、准备工作四、获取账号五、下载资料 六、安装相关软件七、启动客户端八、注入并启动微信九、机器人的基本配置十、自定义接口开发 …

医学图像分割中的频域多轴表示学习

摘要 https://arxiv.org/pdf/2312.17030v1.pdf 最近&#xff0c;视觉Transformer (ViT)在医学图像分割&#xff08;MIS&#xff09;中得到了广泛应用&#xff0c;这归功于其在空间域应用自注意力机制来建模全局知识。然而&#xff0c;许多研究都侧重于改进空间域模型&#xff…

vue-springboot基于Javaweb的二手儿童绘本网上商城交易系统设计与实现

本二手儿童绘本交易系统是为了提高用户查阅信息的效率和管理人员管理信息的工作效率&#xff0c;可以快速存储大量数据&#xff0c;还有信息检索功能&#xff0c;这大大的满足了用户、商家和管理员这三者的需求。操作简单易懂&#xff0c;合理分析各个模块的功能&#xff0c;尽…

苏州科技大学计算机817程序设计(java) 学习笔记

之前备考苏州科技大学计算机&#xff08;专业课&#xff1a;817程序设计&#xff08;java&#xff09;&#xff09;。 学习Java和算法相关内容&#xff0c;现将笔记及资料统一整理归纳移至这里。 部分内容不太完善&#xff0c;欢迎提议。 目录 考情分析 考卷题型 刷题攻略…

关于求定积分的反函数的导数【认清原函数x变量和反函数x变量】

如图碰到该题该怎么解&#xff1f; 在纸上按①②③的顺序写出这个&#xff0c;其中①是最主要的 第②步和第③步就是在用反函数时要用到的逻辑思维&#xff0c;不是一起用的&#xff0c;你需要用②才去用②&#xff0c;你需要用③才去用③ 在纸上先写出第①步&#xff0c;即 其…

使用Microsoft托管密钥的Azure信息保护云退出

由于各种原因&#xff0c;一些组织需要一个明确定义的流程来停止使用 Azure 信息保护以及对云服务的任何依赖&#xff0c;而不会在采用之前失去对其数据的访问权限 - 以便在出现需要时做好准备。 Azure 信息保护 (AIP) 为使用自带密钥 (BYOK) 的客户和使用 Microsoft 托管密钥…

语义分割的应用及发展

语义分割(Semantic Segmentation)是一种计算机视觉领域的任务&#xff0c;旨在将一张图像中的每一个像素都分配一个语义标签&#xff0c;即将图像中的每个物体区域进行精确的分类划分。例如&#xff0c;在一张街景图中&#xff0c;语义分割可以将人、车、路、天空等每个像素分别…

子网划分问题(实战超详解)_主机分配地址

文章目录: 子网划分的核心思想 第一步,考虑借几位作为子网号 第二步,确定子网的网络地址 第三步,明确网络地址,广播地址,可用IP地址范围 一些可能出现的疑问 实战 题目一 子网划分的核心思想 网络号不变,借用主机号来产生新的网络 划分前的网络:网络号主机号 划分后的网络:原网…

高并发处理专题研究 - epoll并发编程[更新中]

文章目录 1 前置知识1.1 Socket编程基础Socket概述Socket通信模型Socket API一个简单的Socket编程实例 1.2 IO多路复用1.3 阻塞原理 2 epoll原理2.1 epoll概述2.2 epoll系统调用epoll_create()epoll_ctl()epoll_wait() 2.3 epoll工作原理 3 示例代码及演示 1 前置知识 1.1 Soc…

linux中用户账号和权限管理

一.Linux 用户分三类 1.普通用户 权限受限制的用户 2. 超级管理员 拥有至高无上权限 3. 程序用户 不是给人使用的&#xff0c;给程序用 运行程序不能使用超级管理员&#xff0c;从安全考虑 超级管理员 uid 为0 普通用户 1000~60000 &#xff0…

Linux系统使用yum安装MySQL

部署MySQL数据库有多种部署方式&#xff0c;常用的部署方式就有三种&#xff1a;yum安装、rpm安装以及编译安装。每一种安装方式都有自己的优势&#xff0c;那么企业当中通常情况下采用的是rpm和二进制安装的方式。 MySQL官网下载地址 Mysql 5.7的主要特性 更好的性能&#xf…

vue3+ts开发干货笔记

总结一下在vue3中ts的使用。当篇记录部分来自于vue官网&#xff0c;记录一下&#xff0c;算是加深印象吧。 纯干笔记&#xff0c;不断补充&#xff0c;想到什么写什么&#xff0c;水平有限&#xff0c;欢迎评论指正&#xff01; 类型标注 props <script setup lang"…

Download Monitor Email Lock下载监控器邮件锁插件

打开Download Monitor Email Lock下载监控器邮件锁插件 Download Monitor Email Lock下载监控器邮件锁插件下载监视器的电子邮件锁定扩展允许您要求用户在获得下载访问权限之前填写他们的电子邮件地址。 Download Monitor Email Lock下载监控器邮件锁插件用法 安装扩展程序后…