8.1 指针的概念 8.2 指针变量 8.3 指针变量的基础类型 8.4 指针的运算 8.5 指针与一维数组 8.6 指针应用实例

Slides:



Advertisements
Similar presentations
第九章 指针 西安工程大学.
Advertisements

第七章 指针 计算机公共教学部.
第六章 指针 指针的概念 指针变量 指针与数组 指针与函数 返回指针值的函数.
第7章 指针 存储地址的变量的类型就是指针类型 能直接对内存地址操作, 实现动态存储管理 容易产生副作用, 初学者常会出错
二级指针与二维数组.
10.1 二级指针 10.2 指针与二维数组 10.3 指针的动态存储分配 10.4 函数指针 10.5 main函数的参数
第 6 章 第 6 章 指 针 指 针 1.
C语言程序设计.
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
6.4 字符串与指针 1. 用字符数组存放一个字符串.
第六节 二维数组和指针 二维数组的地址 对于一维数组: (1)数组名array表示数组的首地址, 即array[0]的地址;
C语言实验 第一课 标题:学号+姓名.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
第6章 指针 学习目的与要求: 了解指针的概念和相关术语 熟练掌握指向变量、数组和字符串的指针变量的使用方法 了解指向函数的指针变量
指 针 为什么要使用指针 指针变量 指针与数组 返回指针值的函数 动态内存分配 通过指针引用字符串 指向函数的指针 小 结 习 题.
第 十 章 指 针.
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
管理信息结构SMI.
辅导课程六.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
二维数组的指针表示 与复杂的指针例子 专题研讨课之三.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
C语言 程序设计基础与试验 刘新国、2012年秋.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第二章 Java语言基础.
第六章 指针 指针的概念 指针的运算 指向变量的指针 指向数组的指针 指向函数的指针 二级指针 主讲:李祥 时间:2015年10月.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
欲穷千里,更上层楼 第十章 指 针 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。指针极大地丰富了C语言的功能。 学习指针是学习C语言中最重要的一环,
第五章 习题课 电子信息与计算机科学系 曾庆尚.
第5讲 结构化程序设计(Part II) 周水庚 2018年10月11日.
第五章 指针 5.1 指针的概念 5.2 指针与数组 5.3 字符串指针.
9.1 地址、指针和变量 9.2 指针运算 9.3 指针与数组 9.4 函数与指针 9.5 程序综合举例 9.6 上机实训.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
线 性 代 数 厦门大学线性代数教学组 2019年4月24日6时8分 / 45.
C语言大学实用教程 第7章 指针 西南财经大学经济信息工程学院 刘家芬
第二章 Java基本语法 讲师:复凡.
指针 几个概念:  指针也是一种数据类型,具有指针类型的变量,称为指针变量。
第6讲 指针与引用 6.1 指针 6.2 引用.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
C语言程序设计 第一章 数据类型, 运算符与表达式 第二章 顺序程序设计 第三章 选择结构程序设计 第四章 循环控制 第五章 数组.
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
成绩是怎么算出来的? 16级第一学期半期考试成绩 班级 姓名 语文 数学 英语 政治 历史 地理 物理 化学 生物 总分 1 张三1 115
第4章 Excel电子表格制作软件 4.4 函数(一).
第九节 赋值运算符和赋值表达式.
§6.7 子空间的直和 一、直和的定义 二、直和的判定 三、多个子空间的直和.
3.16 枚举算法及其程序实现 ——数组的作用.
第二章 类型、对象、运算符和表达式.
本节内容 结构体 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第4课时 绝对值.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
ASP.NET实用教程 清华大学出版社 第4章 C#编程语言 教学目标 教学重点 教学过程 2019年5月5日.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C程序设计.
C程序设计 实验二 数据类型、运算符和表达式 第6讲
第二章 Java基本语法 讲师:复凡.
本节内容 结构体.
本节内容 指针类型的使用 视频提供:昆山爱达人信息技术有限公司.
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
C语言程序设计 第8章 指针.
基本知识 数据类型、变量、常量、运算符.
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
鸡兔同笼(续) ——选择结构.
第八章 指 针 北京邮电大学出版社.
C/C++基礎程式設計班 陣列 講師:林業峻 CSIE, NTU 3/14, 2015.
<编程达人入门课程> 本节内容 有符号数与无符号数 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
C语言基础学习 从外行到入门.
第7章 地址和指针 7.1 地址和指针的概念 7.2 指针变量的定义和指针变量的基类型 7.3 给指针变量赋值 7.4 对指针变量的操作
Presentation transcript:

8.1 指针的概念 8.2 指针变量 8.3 指针变量的基础类型 8.4 指针的运算 8.5 指针与一维数组 8.6 指针应用实例 第8章 指针基础 8.1 指针的概念 8.2 指针变量 8.3 指针变量的基础类型 8.4 指针的运算 8.5 指针与一维数组 8.6 指针应用实例

8.1 指针的概念 计算机的正常工作离不开内存储器,为了有效的管理内存储器(内存),现代计算机一般都将内存分割成字节(Byte),每个字节存储8位信息。 程序中所有的数据都存放在内存中,不同的数据类型所占用的内存单元数(字节数)不等,比如实型占?个字节,字符型占?个字节等。 为了正确地访问这些内存单元,必须为每个内存单元给定一个唯一编号。这个内存单元(字节)的唯一编号也称为地址(Address)。 如果内存中有n个字节,那么可以把地址看作0~n-1,如右图。

8.1 指针的概念 实体的地址:在程序中定义的变量、函数等称为实体,每个实体都要在内存中占用若干个连续字节,实体占用的字节中,首字节的编号称为实体的地址。 对应变量地址 假设有定义: char ch = 'B'; int i = 10; float f = 3.8;

8.1 指针的概念 指针:虽然可以用数值表示地址,但是地址的取值范围不同于整数的范围,所以一定不能用普通整型变量存储地址,而是用一种特殊的指针变量(pointer variable)存储地址。 用指针变量p存储变量i的地址时,我们就说“p指向i”。 注意:在C语言中,一种数据类型或数据结构往往都占有一组连续的内存单元。用“地址”这个概念并不能很好地描述一种数据类型或数据结构,而“指针”虽然实际上也是一个地址,但它却是一个数据结构的首地址,它是“指向”一个数据结构的,因而概念更为清楚,表示更为明确。

8.2 指针变量 指针变量的定义: 说明: 数据类型 *指针变量名; 8.2 指针变量 8.2.1 指针变量的定义 定义指针变量与定义普通变量类似,唯一的不同是在指针变量名前面要放置星号 指针变量的定义: 说明: 指针变量定义时的数据类型称为指针的基础类型,它并不决定指针变量所占存储空间的大小,而是决定指针变量所指存储空间的类型。 指针变量名前面的“*”号应与数据类型结合在一起。 数据类型 *指针变量名;

8.2.1 指针变量的定义 指针变量与普通变量的不同: 普通变量 指针变量 用途 用于存放数值 用于存放地址 数据类型的含义 8.2.1 指针变量的定义 指针变量与普通变量的不同:   普通变量 指针变量 用途 用于存放数值 用于存放地址 数据类型的含义 char a; 变量a占1个字节,用于存放字符 char *pa; 变量pa占4个字节,存放地址,pa可指向字符型的存储空间 int b; 变量b占4个字节,用于存放整数 int *pb; 变量pa占4个字节,存放地址,pb可指向整型的存储空间 double c;变量c占8个字节,用于存放实数 double *pc; 变量pc占4个字节,存放地址,pc可指向实型的存储空间

 8.2.2 指针变量的赋值 指针变量定义后必须赋予具体的地址值。 运算符“&” ,称为取地址运算符,其使用格式为: &变量名 直接赋数值?  如何获取地址并赋给指针变量的呢? 需要一个运算符 这个运算符的功能是取出变量所在内存单元的地址。 &变量名

8.2.2 指针变量的赋值 为指针变量赋地址的方法常有: 定义指针变量时直接初始化地址值 如:int a = 10, *pa = &a; 用赋值语句为指针变量赋地址值 如:int a = 10, *pa; pa = &a; 为指针变量赋另一个已赋值的指针变量 如:int a = 10, *p1, *p2; p1 = &a; p2 = p1;

8.2.3 指针变量的间接引用 将指针变量指向某个普通变量,或者指向数组的首地址,其最终目的是希望通过指针变量引用其所指存储单元的内容。 8.2.3 指针变量的间接引用 将指针变量指向某个普通变量,或者指向数组的首地址,其最终目的是希望通过指针变量引用其所指存储单元的内容。 直接引用 int a = 10; 间接引用 int *p = &a 如何利用指针变量p引用其所指存储单元a的内容呢? 运算符“*”,称为间接引用运算符,其使用格式为: *指针变量 或者 *地址

指针变量 p 存放普通变量 a 的地址,我们称指针变量 p 指向了普通变量 a 8.2.3 指针变量的间接引用 直接引用、间接引用理解 变量的“直接”访问 ——使用变量名 变量的“间接”访问 ——使用变量地址 普通变量 指针变量 20 int a = 20; a &a 变量名 20 a &a &a p 变量的 内容 指针变量 p 存放普通变量 a 的地址,我们称指针变量 p 指向了普通变量 a 变量地址

8.2.3 指针变量的间接引用 例如: int a = 10, b, *p = &a; 8.2.3 指针变量的间接引用 例如: int a = 10, b, *p = &a; b = *p; printf("b = %d\n", b); 输出? b = 10 注意:以上两个“*” 其中变量定义时的*是与int结合为“int *”,表示p被定义为int *型的指针变量; 而语句中的*是与p结合为“*p”,此时它是一个运算符,用于间接引用p所指存储单元的内容。 注意:C语言中的“*”号用法非常多,可以作为普通字符、乘号、注释符,在本章中,我们看到在定义指针变量时,用它作为指针定义符,在语句中又用它作为间接引用运算符。 执行语句“b = *p;”时,运算符*引用了p所指变量a的值,并赋给b。

8.2.3 指针变量的间接引用 初学者关于“指针变量”使用的常见错误: 错误1:直接给指针变量赋一个整数值 8.2.3 指针变量的间接引用 初学者关于“指针变量”使用的常见错误: 错误1:直接给指针变量赋一个整数值 int a = 18, *p1, *p2; p1 = a; p2 = 100; 错误2:指针未赋地址值就直接使用 int a=18, *p; *p = a; 错误3:为指针变量赋地址值时在前面加“*” int a = 10, *p; *p = &a; 错误4:利用指向空地址的指针变量访问存储单元 int a = 10, *p = NULL; *p = a;

8.2.3 指针变量的间接引用 例8-1 指针变量的定义和用法。 #include <stdio.h> int main( ) 8.2.3 指针变量的间接引用 例8-1 指针变量的定义和用法。 #include <stdio.h> int main( ) { int x = 5, y = 10; int *p, *q; p = &x; //p指向变量x q = &y; //q指向变量y printf("x=%d, y=%d\n", x, y); printf("x=%d, y=%d\n", *p, *q); return 0; } 输出? 其中指针变量与普通变量的关系

8.2.3 指针变量的间接引用 例8-2输入a和b两个整数,用指针编程,按先大后小的顺序输出a和b。 8.2.3 指针变量的间接引用 例8-2输入a和b两个整数,用指针编程,按先大后小的顺序输出a和b。 #include <stdio.h> int main( ) { int a, b, *pa, *pb, *t; printf("请输入两个整数到变量a, b中: "); scanf("%d, %d", &a, &b); pa = &a; pb = &b; if(a < b) t = pa; pa = pb; pb = t; } printf("\n较大值a: %d 较小值b: %d\n", a, b); return 0; 该段代码为什么没有达到预期的目的?

8.2.3 指针变量的间接引用 例8-2输入a和b两个整数,用指针编程,按先大后小的顺序输出a和b。 8.2.3 指针变量的间接引用 例8-2输入a和b两个整数,用指针编程,按先大后小的顺序输出a和b。 #include <stdio.h> int main( ) { int a, b, *pa, *pb, t; printf("请输入两个整数到变量a, b中: "); scanf("%d, %d", &a, &b); pa = &a; pb = &b; if(a < b) t = *pa; *pa = *pb; *pb = t; } printf("\n较大值a: %d 较小值b: %d\n", a, b); return 0; 该段代码达到预期的目的,和上一段代码主要区别在哪里?

8.2.3 指针变量的间接引用 例8-2输入a和b两个整数,用指针编程,按先大后小的顺序输出a和b。 交换指针pa和pb 8.2.3 指针变量的间接引用 例8-2输入a和b两个整数,用指针编程,按先大后小的顺序输出a和b。 程序段1与程序段2不同比较 程序一中的t是指针变量 程序二中的变量t是数值型变量 int a, b, *pa, *pb, *t; int a, b, *pa, *pb, t; if(a < b) { t = pa; t = *pa; pa = pb; *pa = *pb; pb = t; *pb = t; } 交换指针pa和pb 交换pa和pb所指的内容,即交换a与b的值。

练一练 i p j B 初始化 2 选项A相当于 i = i 选项B中的 *&j 等价于 j,因此该选项相当于 i = j 若有说明:int i, j=2, *p=&i; 则能够完成 i=j 赋值功能的语句是( ) A) i=*p; B) *p=*&j; C) i=&j; D) i=**p; B i 2 j p 选项A相当于 i = i 选项B中的 *&j 等价于 j,因此该选项相当于 i = j 选项C赋值号的左侧是普通变量,右侧是地址(即指针),赋值号两侧数据类型不匹配 选项D赋值号的左侧是普通变量,右侧相当于 *i,因此该选项相当于 i = *i

练一练 p n q D 2 &n 合法的赋值语句首先必须保证赋值号左右两侧的数 据类型一致。 选项A赋值号的两侧都是指针,正确 若有说明:int n=2,*p=&n,*q=p; 则以下非法的赋值语句是______。 A) p=q; B) *p=*q; C) n=*q; D) p=n; 2 n &n q p 合法的赋值语句首先必须保证赋值号左右两侧的数 据类型一致。 选项A赋值号的两侧都是指针,正确 选项B赋值号的两侧都相当于普通变量,正确 选项C赋值号的两侧都相当于普通变量,正确 选项D赋值号的左侧是指针,右侧是普通变量,错误

练一练 以下程序的运行结果是( ) #include <stdio.h> int main( ) { int k=2, m=4, n, *pk=&k, *pm=&m, *pn=&n; *pn = *pk * (*pm); printf("%d\n", n); return 0; } A) 4 B) 6 C) 8 D) 10 C 注意:定义的时*与int结合表示定义指针变量;运算时*与指针变量集合为去内容。 *pn = *pk * (*pm);相当于 n = k * m, 既 n=8。

8.3 指针变量的基础类型 指针变量用于存储地址值(即内存单元的编号),严格来说地址是没有数据类型可言的,为什么在指针变量定义时还要指定数据类型呢?为什么称此时的数据类型为指针变量的基类型呢? 为了能正确地通过指针变量访问数据,指针变量中仅存放实体的首地址是不够的,还必须知道该实体占多少内存以及数据是如何组织的,这些信息包含在数据类型之中,因此定义了正确的指针类型,就能正确地访问实体的数据。于是,定义指针变量时的数据类型就称为指针变量的“基础类型”(简称基类型)。

练一练 D 选项A指针赋值错误 选项B指针赋值错误,double型用lf表示其格式 若有说明语句:double *p,a;则能通过scanf语句正确给输入项读入数据的程序段是( ) A) *p = &a; scanf("%lf", p);  B) *p = &a; scanf("%f", p); C) p = &a; scanf("%lf", *p);  D) p = &a; scanf("%lf", p); D 选项A指针赋值错误 选项B指针赋值错误,double型用lf表示其格式 选项C指针p已经是a的地址,*p表示a,scanf语句中需要的是变量的地址。 选项D指针p是变量a的地址。正确。

8.3 指针变量的基础类型 例如定义: 注意: char *p1; 利用p1可以访问1个字节 int *p2; 利用p2可以访问4个字节 8.3 指针变量的基础类型 例如定义: char *p1; 利用p1可以访问1个字节 int *p2; 利用p2可以访问4个字节 double *p3;, 利用p3可以访问8个字节 注意: 指针就是地址,其实有点过于绝对。 指针的类型可以相互转换,在实际应用中,转换要合理。 从语法上看,只须把指针声明语句中的指针变量名字和名字左边的指针声明符“*”去掉,剩下的就是指针所指向的类型。 void指针类型的理解。

8.3 指针变量的基础类型 例8-3 指针基类型的理解。 #include <stdio.h> int main( ) { 8.3 指针变量的基础类型 例8-3 指针基类型的理解。 #include <stdio.h> int main( ) { char a, *pa = &a; int b, *pb = &b; double c, *pc = &c; printf("普通变量的字节数: %d, %d, %d\n", sizeof(a), sizeof(b), sizeof(c)); printf("指针变量的字节数: %d, %d, %d\n", sizeof(pa), sizeof(pb), sizeof(pc)); printf("指针初始时存储的地址: %d, %d, %d\n", pa, pb, pc); pa++; pb++; pc++; printf("指针自加后存储的地址: %d, %d, %d\n", pa, pb, pc); return 0; } 指针++,表示指针后移,将在8.4.1节讲解。 注意:运算符sizeof求出各种数据类型的变量所占的字节数。

8.4 指针的运算 指针的运算和它所指向的类型有关。 在指针变量的引用中,我们认识了取地址运算符“&”和间接引用运算符“*”。 其他运算: 8.4 指针的运算 指针的运算和它所指向的类型有关。 在指针变量的引用中,我们认识了取地址运算符“&”和间接引用运算符“*”。 其他运算: 指针算术运算 指针相减 指针比较

8.4.1 指针的算术运算 指针的算术运算是针对指针指向数组或指向字符串为前提的,而且只有加上整数和减去整数这两种算术运算。 8.4.1 指针的算术运算 指针的算术运算是针对指针指向数组或指向字符串为前提的,而且只有加上整数和减去整数这两种算术运算。 指针的加、减运算表示控制指针向前或向后移动。 指针的加、减运算仅适用于存储空间连续的场合。 定义一个与数组同类型的指针变量,它的基类型与数组元素类型相同,便可以指向数组中的任何一个元素。

8.4.1 指针的算术运算 假设有定义: int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, *p; 8.4.1 指针的算术运算 假设有定义: int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, *p; 执行语句 p = a; 或者 p = &a[0]; 都表示将指针p指向数组的第一个元素。执行后如图:

8.4.1 指针的算术运算 指针p指向数组a的一个元素后,就可以通过指针的算术运算访问数组的其他元素了。 指针加上整数: 8.4.1 指针的算术运算 指针p指向数组a的一个元素后,就可以通过指针的算术运算访问数组的其他元素了。 指针加上整数: “指针 + 整数n”表示指针向后移动n个元素。 指针减去整数 “指针 – 整数n“表示指针向前移动n个元素。

8.4.1 指针的算术运算 printf("%d, %d", *p, *q); 输出? 示例: 8.4.1 指针的算术运算 printf("%d, %d", *p, *q); 输出? 示例: int a[10]={10,11,12,13,14,15,16,17,18,19}, *p, *q; p = a + 3; q = p + 3; 等价于p = &a[3]; 指针p指向a[3],此时a+3代表元素a[3]的地址。 指针q指向p后面的第3个元素,此时p+3代表元素a[6]的地址。

8.4.1 指针的算术运算 printf("%d, %d", *p, *q); 输出? 继续执行以下语句: p --; (*q)--; 8.4.1 指针的算术运算 printf("%d, %d", *p, *q); 输出? 继续执行以下语句: p --; (*q)--; 等价于p = &a[3]; 指针p指向a[3],此时a+3代表元素a[3]的地址。 等价于p = &a[3]; 指针p指向a[3],此时a+3代表元素a[3]的地址。

8.4.1 指针的算术运算 注意: (1)++:指针与++结合使得指针向后移动基类型对应的一个单元。 8.4.1 指针的算术运算 注意: (1)++:指针与++结合使得指针向后移动基类型对应的一个单元。 (2)- -:指针与--结合使得指针向前移动基类型对应的一个单元。 (3)间接引用运算符“*”和算术运算符++、--的优先级相同,但是按自右向左的方向结合,因此,--*p相当于--(*p)。但是表达式(*p)-- 与 *p-- 的结果则不同,前者是先取p所指存储单元的值,然后将值减1作为表达式的值;后者是将*p作为表达式的值,然后使指针变量p本身减1,即指针p发生移动。

8.4.1 指针的算术运算 ++与*结合解析 --与*结合同++与*结合。 表达式 含义解析 ++(*p)或++ *p 8.4.1 指针的算术运算 ++与*结合解析 表达式 含义解析 ++(*p)或++ *p 先取指针所指存储空间里的内容,然后将内容自增作为表达式的值 * ++p或*(++p) 先自增p(即p后移一个单元),然后取出此时p所指存储单元的内容并作为表达式的值 *p++或*(p++) 表达式的值是*p,然后再自增p(即p后移一个单元) (*p)++ 表达式的值是*p,然后再自增p所指存储单元里的内容 --与*结合同++与*结合。

8.4.1 指针的算术运算 (1)&*p (2)*&a (3)++(*p) (4)++*p (5)*(++p) (6)*++p 8.4.1 指针的算术运算 练习:思考以下各表达式的含义 假设有定义 int a, *p = &a; (1)&*p (2)*&a (3)++(*p) (4)++*p (5)*(++p) (6)*++p (7)(*p)++ (8)*p++ (9)*(p++) —— 相当于&a —— 相当于a —— 表示先取内容,然后内容自增 —— 与 ++(*p) 等价 —— 表示指针先后移,再取内容 —— 与 *( ++p) 等价 —— 表示先取内容,内容再自增 —— 表示先取内容,指针再后移 ——指针后移再取值

8.4.2 指针相减 对于指向同一数组或同一字符串的两个指针,可以通过两个指针相减计算两个指针之间的距离(通过数组元素的个数来度量)。 8.4.2 指针相减 对于指向同一数组或同一字符串的两个指针,可以通过两个指针相减计算两个指针之间的距离(通过数组元素的个数来度量)。 假如p指向a[1],q指向a[4],则q – p就相当于4 – 1,其结果为3,表示q所指空间距离p所指空间有3个单元的距离。

8.4.2 指针相减 int a[5]={10, 20, 30, 40, 50}, *p, *q, i, j, m; p = &a[1]; 8.4.2 指针相减 int a[5]={10, 20, 30, 40, 50}, *p, *q, i, j, m; p = &a[1]; q = &a[4]; i = q – p; j = p – q; m = *q - *p; 计算后i的值是3 计算后j的值是-3 计算后m的值是30

8.4.3 指针比较 在关系表达式中可以用关系运算符(>、>=、<、<=、==、!=)对两个指针进行比较。但是,只有当两个指针指向了同一数组时,用关系运算符进行指针的比较才有意义,其结果依赖于指针指向的数组中元素的相对位置。 p < q ?

8.4.3 指针比较 例8-4 定义一个子函数,输出图8-11中指针p和q之间的元素,p、q作为函数形参。 8.4.3 指针比较 例8-4 定义一个子函数,输出图8-11中指针p和q之间的元素,p、q作为函数形参。 #include <stdio.h> int fun(int *p, int *q) { int *m; for(m = p; m <= q; m++) printf("%d ", *m); } printf("\n"); return 0; 图 8‑11 指针p、q的指向关系 int main( ) { int a[5] = {10,20, 30, 40, 50}; fun(&a[1], &a[4]); return 0; }

8.5 指针与一维数组 指针如何引用数组的各个元素(8.4节)? 8.5 指针与一维数组 指针如何引用数组的各个元素(8.4节)? 数组在内存中占据连续的存储单元,每个数组元素占据的字节数相同。定义一个与数组同类型的指针变量,其基类型与数组元素类型相同,将指针指向第一个数组元素后,利用指针的移动便可引用数组的各个元素。 1. 一维数组名是地址常量 什么是常量? C语言中,数组名可以认为是一个地址常量,其地址值是数组第一个元素的地址,也就是数组所占一串连续存储单元的起始地址。由于数组名是常量,因此不能重新赋值。

   8.5 指针与一维数组 √ √ √ 假设有定义:int a[10], *p, x; 以下语句是否对,为什么? a = &x; 8.5 指针与一维数组 假设有定义:int a[10], *p, x; 以下语句是否对,为什么? a = &x; a++; a--; p = a; p=&a[3]; p = a + 1;  数组名a是常量,不能被重新赋值。  数组名a是常量,不能被重新赋值。  数组名a是常量,不能被重新赋值。 √ 数组名a是地址常量,地址赋给指针变量p是可行的。 √ a[3]是变量,变量取地址赋给指针变量p是可行的。 √ a+1是a[1]的地址,地址赋给指针变量p是可行的。

8.5 指针与一维数组 理解“数组名 + 整数” 数组名是地址,加上一个整数,表示在数组首地址的基础上后移整数个单元。于是,语句“p = a + i;”等价于“p = &a[i];”。 假设有定义:int a[10], *p = a;,则有4种等价形式都可以表示数组元素a[i]的地址: 方法一: &a[i] 方法二: &p[i] 方法三: a + i 方法四: p + i 前两种方法称为“下标法”,后两种方法称为“指针法”(也叫“地址法”)。以上等价形式的前提条件是指针p指向数组的第一个元素。

8.5 指针与一维数组 2.引用数组元素的几种方法 以上四种形式,前两种方法称为“下标法”,后两种方法称为“指针法”。 8.5 指针与一维数组 2.引用数组元素的几种方法 我们已知了存储单元的地址,在地址前加上间接引用运算符“*”,便可取出该地址对应存储单元里的内容。 假设有定义:int a[10], *p = a;,则有4种等价形式都可以表示数组元素a[i]: 方法一: a[i] 方法二: p[i] 方法三: *(a + i) 方法四: *(p + i) 以上四种形式,前两种方法称为“下标法”,后两种方法称为“指针法”。 注意区别p和a的不同,a是常量,是不能改变的;p是变量,其中的地址是可以改变的。

练一练 假设有定义:int a[5]={10,20,30,40,50}, b, *p = &a[1]; A) 20 B) 30 C) 21 D) 31 ①执行语句b = *(p++); 后,b的值是( ) ②执行语句b = *(++p); 后,b的值是( ) ③执行语句b = ++(*p); 后,b的值是( ) B B C

8.6 指针应用实例 例8-5 分别用下标法、指针法访问数组元素。 #include <stdio.h> int main( ) 8.6 指针应用实例 例8-5 分别用下标法、指针法访问数组元素。 #include <stdio.h> int main( ) { int a[5] = {5, 10 ,15, 20, 25}, i, *p; p = a; printf("----下标法输出数组元素----\n"); for(i = 0; i < 5; i++) printf("%-6d", a[i]); } printf("\n"); printf("%-6d", p[i]); } //续下页 指针p指向数组的首地址,这一步非常重要。 下标法 回忆%-6d,? 下标法

8.6 指针应用实例 例8-5 分别用下标法、指针法访问数组元素。 return 0; printf("\n"); 8.6 指针应用实例 例8-5 分别用下标法、指针法访问数组元素。 printf("\n"); printf("\n----指针法输出数组元素----\n"); for(i = 0; i < 5; i++) { printf("%-6d", *(a+i)); } printf("%-6d", *(p+i)); return 0; 指针法 指针法

8.6 指针应用实例 例8-5 分别用下标法、指针法访问数组元素。 不论使用下标法还是指针法访问数组元素,都要避免“下标越界”的问题。 8.6 指针应用实例 例8-5 分别用下标法、指针法访问数组元素。 说明: 不论使用下标法还是指针法访问数组元素,都要避免“下标越界”的问题。 使用指针变量指向数组元素时,应当注意指针变量的当前值。例如: int a[5] = {5, 10 ,15, 20, 25}, i, *p; p = &a[2]; for(i = 0; i < 3; i++) printf("%d, ", p[i]); 输出结果是a[2]、a[3]、a[4]的值15,20,25。 因为p初始并未指向a[0],而是指向a[2],因此p[i]相当于a[2+i]。

8.6 指针应用实例 例8-6 用指针指向数组并输出数组元素,要求:通过指针的移动实现此功能。 8.6 指针应用实例 例8-6 用指针指向数组并输出数组元素,要求:通过指针的移动实现此功能。 #include <stdio.h> int main( ) { int a[5] = {5, 10 ,15, 20, 25}, *p; for(p = a; p < a + 5; p++) printf("%-6d", *p); //指针法 } printf("\n"); return 0; 本例与前一例虽然完成的功能相同,但使用的方法不同,本例中未使用变量i,而是通过指针p的自增来访问数组的各元素。本例中for循环开始时,p指向a[0],每次循环p后移一个单元,当for循环结束后,p指向a[4]后面的存储空间。

8.6 指针应用实例 例8-7输入10个整数,并求这10个整数的和。#include <stdio.h> int main( ) 8.6 指针应用实例 例8-7输入10个整数,并求这10个整数的和。#include <stdio.h> int main( ) { int a[10], i, sum = 0; int *p; printf("请输入10个数: \n"); for(i = 0; i < 10; i++) scanf("%d", a + i); } for(p = a; p < a + 10; p++) sum = sum + *p; //指针法“*p”引用数组元素 printf("\n10个数的总和: %d\n", sum); return 0; 数组名加整数“a+i”表示数组元素a[i]的地址

8.6 指针应用实例 例8-8 假设有10名学生,每名学生有1门课的成绩,使用数组存储这10名学生的程序,要求使用指针操作数组,完成求总分、平均分、最高分和最低分的功能,并对10名学生按分数由高到低进行排序。 问题分析:对于该问题,先定义一个10个元素的一维数组,通过键盘输入10个成绩。定义指针变量指向数组的首地址,通过指针变量自增依次访问数组元素,并求总分、平均分、最高分和最低分;然后采用冒泡排序法实现对10个分数的降序排序。

8.6 指针应用实例 #include <stdio.h> #define N 10 int main( ) { 8.6 指针应用实例 #include <stdio.h> #define N 10 int main( ) { float a[N] = {88, 90, 78.5, 66, 91.5, 70, 82.3, 75.7, 81, 67}; float sum=0, avg=0, max=0, min=100, temp, *p; int i, j; p = a; //指针变量p指向数组a的首地址 printf("10个分数是: \n"); for(i = 0; i < N; i++) //循环10次,输出10个分数 printf("%.2f\t", p[i]); } for(p = a; p < a + N; p++) //查找最高分和最低分 //续下页

{ if(*p > max) max = *p; } if(*p < min) min = *p; sum = sum + *p; avg = sum / N; for(i=0; i < N-1; i++) //对这10个分数进行降序排序 for(j = 0; j<N-1-i; j++) if(*(a+j) < *(a+j+1)) temp = *(a+j); *(a+j) = *(a+j+1); *(a+j+1) = temp;

8.6 指针应用实例 printf("\n降序排序后的分数是: \n"); 8.6 指针应用实例 printf("\n降序排序后的分数是: \n"); for(p = a, i = 0; i < N; i++) //输出排序后的10个分数 { printf("%.2f\t", p[i]); } printf("\n\n总分: %.2f 平均分: %.2f 最高分: %.2f 最低分%.2f\n", sum, avg, max, min); return 0;