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;