第十章 指针 分析C程序的变量所存放的数据:  数值型数据:整数、实数  字符型数据:字符、字符串 这些变量具有以下性质:

Slides:



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

第七章 指针 计算机公共教学部.
第六章 指针 指针的概念 指针变量 指针与数组 指针与函数 返回指针值的函数.
第7章 指针 存储地址的变量的类型就是指针类型 能直接对内存地址操作, 实现动态存储管理 容易产生副作用, 初学者常会出错
二级指针与二维数组.
C语言程序设计基础 第10章 指针进阶 刘新国.
10.1 二级指针 10.2 指针与二维数组 10.3 指针的动态存储分配 10.4 函数指针 10.5 main函数的参数
第 6 章 第 6 章 指 针 指 针 1.
C语言基础——指针的高级应用 Week 05.
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
6.4 字符串与指针 1. 用字符数组存放一个字符串.
第六节 二维数组和指针 二维数组的地址 对于一维数组: (1)数组名array表示数组的首地址, 即array[0]的地址;
8.1 指针的概念 8.2 指针变量 8.3 指针变量的基础类型 8.4 指针的运算 8.5 指针与一维数组 8.6 指针应用实例
字符串与二维数组.
第九章 指针 目录 指针与指针变量的概念 变量的指针和指向变量的指针变量 数组的指针和指向数组的指针变量
C语言程序设计 第八章 函数.
4.3函数 4.3.1函数的概念及定义 1、函数的概念: 可以被其它程序调用具有 特定功能的一段相对独立的 程序(模块),称函数。
第6章 指针 学习目的与要求: 了解指针的概念和相关术语 熟练掌握指向变量、数组和字符串的指针变量的使用方法 了解指向函数的指针变量
指 针 为什么要使用指针 指针变量 指针与数组 返回指针值的函数 动态内存分配 通过指针引用字符串 指向函数的指针 小 结 习 题.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第八章 指 针 8.1 指针的概念与定义 8.2 指针作函数参数 8.3 指针与数组 8.4 指针与函数 8.5 复杂指针.
第 十 章 指 针.
项目六 用指针优化学生成绩排名 项目要求 项目分析
C语言高级编程(第四部分) 字符串 北京大学 信息科学技术学院.
第七章 函数 目录 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
走进编程 程序的顺序结构(二).
第八章 函数.
第8章 善于利用指针 8.1 指针是什么 8.2 指针变量 8.3 通过指针引用数组 8.4 通过指针引用字符串 8.5 指向函数的指针
第8章 善于利用指针 8.1 指针是什么 8.2 指针变量 8.3 通过指针引用数组 8.4 通过指针引用字符串 8.5 指向函数的指针
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
二维数组的指针表示 与复杂的指针例子 专题研讨课之三.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第8章 指针.
第八章 使用指针.
第十章 指针.
欲穷千里,更上层楼 第十章 指 针 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。指针极大地丰富了C语言的功能。 学习指针是学习C语言中最重要的一环,
第五章 习题课 电子信息与计算机科学系 曾庆尚.
第五章 指针 5.1 指针的概念 5.2 指针与数组 5.3 字符串指针.
9.1 地址、指针和变量 9.2 指针运算 9.3 指针与数组 9.4 函数与指针 9.5 程序综合举例 9.6 上机实训.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C语言复习3----指针.
概 率 统 计 主讲教师 叶宏 山东大学数学院.
C语言大学实用教程 第7章 指针 西南财经大学经济信息工程学院 刘家芬
指针 几个概念:  指针也是一种数据类型,具有指针类型的变量,称为指针变量。
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
第6讲 指针与引用 6.1 指针 6.2 引用.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
C语言程序设计 第一章 数据类型, 运算符与表达式 第二章 顺序程序设计 第三章 选择结构程序设计 第四章 循环控制 第五章 数组.
第六章 指针 C++程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
第6章 指针 6.1 指针的概念 6.2 变量与指针 6.3 数组与指针 6.4 字符串与指针 6.5 函数与指针 6.6 返回指针值的函数
第十章 指针 指针是C语言的重要概念,是C语言的特色,是C语言的精华。 10.1 地址和指针的概念 内存中的每一个字节都有一个地址。
C程序设计.
第4章 Excel电子表格制作软件 4.4 函数(一).
第九节 赋值运算符和赋值表达式.
3.16 枚举算法及其程序实现 ——数组的作用.
第8章 善于利用指针 8.1 指针是什么 8.2 指针变量 8.3 通过指针引用数组 8.4 通过指针引用字符串 8.5 指向函数的指针
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C程序设计.
第15讲 特征值与特征向量的性质 主要内容:特征值与特征向量的性质.
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C语言程序设计 第8章 指针.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第九章 指针 C程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
第八章 指 针 北京邮电大学出版社.
第7章 地址和指针 7.1 地址和指针的概念 7.2 指针变量的定义和指针变量的基类型 7.3 给指针变量赋值 7.4 对指针变量的操作
Presentation transcript:

第十章 指针 分析C程序的变量所存放的数据:  数值型数据:整数、实数  字符型数据:字符、字符串 这些变量具有以下性质: 第十章 指针 分析C程序的变量所存放的数据:  数值型数据:整数、实数  字符型数据:字符、字符串 这些变量具有以下性质:  占有一定长度的内存 单元 如:int x; x占二字节、二个单元  每一个变量都有一个地址,为无符号整数,称为地址,它不同于一般的整数。 问题:能否对地址运算? 能否用一个变量保存地址?

§10.1 指针的概念 一、数据在内存中的存放 内存:为一个连续编号(连续地址)且以一个单元为一个字节的连续存贮区。 若程序中定义了三个int变量i, j, k int i= – 5, j=5, k=10; 2000 2001 2002 2003 2004 2005 3001 – 5 +5 10 系统分配i在地址为2000的单元 j在地址为2002的单元 k在地址为2004的单元

当程序中要用它们的值时: y=i+j+k; 则系统通过一张变量名与地址对应关系表: 分别 找到i的地址为2000,将2000,2001中的数据–5读出; 找到j的地址为2002,将2002,20003中的数据5读出; 找到k的地址为2004,将2004,2005中的数据10读出。

上述过程称为变量的“ 直接访问” 直接访问:在程序中表现为直接使用存放该数据的变量名。 间接访问:如果将某一变量的地址(如i的地址2000)存放到另一个变量x,则可通过x来存取i的值。

2000  –5  –5 直接访问 i 3001  2000  –5  –5 间接访问 x i 显然,x与i是通过i的地址联系起来的,一个变量的地址—称为该变量的指针。因此,i的指针为2000,而存放地址(指针)的变量叫做指针变量。 如:x

§10.2 指针变量的定义和引用 首先明确一个概念:指针变量也有类型,因为类型涉及到所占单元数,也就是指针变量在计算时有所不同。例如:  当x为一个指向整型变量的指针变量时。 x+1: 设x原为2000,则x+12002  当x为一个指向float型的指针变量时 x+1:设x为2000,则x+12004

一、 定义指针变量的形式: 类型名 变量名 表示该变量为指向某类型变量的指针变量 如: int x; x只能指向整型变量,即只能存放整型变量的地址。

二、引用指针变量  将一个变量的地址(指针)赋给一个指针变量,用取地址运算符:& int i, j, x; x=&i; 如果将整数赋给地址量x=1000;编译会提出警告性错误,但还是有值(地址)

 存取指针变量所指向变量(目标变量)的值: 用指针运算符*, 即:*x 为 i , &为同级运算符,结合性自右至左。 则当&或&在一起时,具有抵消作用 如上例: &i相当于xi &x相当于&ix

三、指针变量作为函数参数 前面讲过:函数实参 形参,于是,形参数 据值的改变不会影响实参。 但当用地址(指针变量)作参数时,与数组名类似。 则:形参、实参均为地址量。 例: swap(p1, p2) int p1, p2; { int p; p=p1; p1=p2

p2= p; } main( ) { int a, b; int x1, x2; scanf("%d,%d",&a, &b); x1=&a; x2=&b; swap(x1, x2); printf("%d,%d \n",a, b); 执行过程分析 (设a10, b20)  &a 10 x1 a &b 20 x2 b

 p1 p2 &a &b 20 10 b a &b &a x2 x1  p= p1; p1= p2; p2 =p;  p1 10 a p  p2 20  b

p1 p2 &a &b 10 20 b a &b &a x2 x1  释放p1, p2后 &a 20 &b 10 x1 a x2 b

1. 注意函数中p为普通变量,并非地址量,如p为地址量,它为哪一个变量的地址?这时: int t,*p=&t;(允许) p= p1 2. 如果swap函数中的交换语句改为: int p1, p2, p; p=p1; p1=p2; p2=p; 则仅将p1, p2的指向改变,函数返回后,p1, p2释放, a、b中的内容依然未改变。

3. 不用地址量,也未能实现交换,即: sway(p1, p2) int p1, p2; { int p; p=p1; p1=p2; p2=p; } 则:只将p1,p2的内容改变,而不能使a, b交换。

4. 结论:当需要被调函数改变调用函数中n个变量的值时,需将这n个变量的地址(用指针变量、或直接用地址量&a, &b)作为实参传给指针形参,且被调函数通过改变指针形参所指向的变量来实现实参中变量值 的改变。

§10.3 数组的指针及指向数组的指针变量 前面介绍:一个变量的地址为该变量的指针。当用一个变量来存放该地址(指针)时,称为指针变量。 §10.3 数组的指针及指向数组的指针变量 前面介绍:一个变量的地址为该变量的指针。当用一个变量来存放该地址(指针)时,称为指针变量。 又有说明: 一个数组元素相当于一个简单变量。于是,亦可用一个指针变量来指向数组元素。 不同点: 数组元素连续地占用内存单元,则当一个元素的指针已知时,其它元素的指针亦可知道。

一、数组元素指针变量的定义与引用 定义方法与简单变量指针定义相同,但引用略有不同 例: int a[10]; int p; 定义 p=&a[0]; 将a的第0个元素的地址p C语言规定: a的首地址即可用&a[0]表示,亦可用a表示 所以:p=&a[0]; 和 p=a等价

可以在定义指针变量时赋初值: int p=&a[0]; 或 int p=a; (等价于) int p; p=a; 它不同于语句: p=&a[0]; × 1. 由首地址指针来引用数组中的其它元素。 设p为a的首地址,p=a,或p=&a[0];

则p+1是什么意思? p+1为a[1]的地址,当a为int,p+1相当于地址+2, 而当a为float时,p+1相当于地址+4. 一般地: p+i  a[i] 的地址,或为a+i 引用a[i]的值: a[i], (p+i), (a+i)

2. 在搜索数组元素时,用p+i比a[i++]来得快 例:int a[10], i; int p; p=a; 则:  (a+i)和a[i]都得计算元素地址,而p++后,p可直接指向a[i]。

3. 关于指针的运算 指针运算符 与++, – –同级,且自右至左。  p++ / p – – 的作用: 若p=a或p=&a[0], 则p++相当于p=p+1, 即指向a[1] 若p=&a[5], 则p– –相当于p=p –1,即指向a[4]

 p++与(++p) p++相当于(p++) 若p=&a[0], 则:先取p的值,即 a[0]的值,再使p+1, p指向a[1]. (++p)为先使pp+1, p指向a[1], (++p)取出a[1]的值。  (p)++ 或(p) – – (p)++:将p指向的变量的值自增1; (p) – –: 将p指向的变量的值自减1。

二、数组名作函数参数 前面已叙述过,当实、形参均为数组名时,调用时将实参数组首地址传递(单向)给形参数组,使它们共享内存。 例:编写函数,将数组各元素值取反。 main ( ) { void invert( ); int a[10], i; for (i=0;i<10; i++) scanf( "%d", &a[i]); invert(a, 10);

for (i=0; i<10; i++) printf("a[%d]=%d," ,i, a[i]); } void invert(x, n) int x[ ], n; { int i; for (i=0; i<n; i++) x[i]= –x[i]; return;

前面已分析: 可用指针表示数组。即:指针运算引用数组元素,于是,可用指针变量作为形参接收实参数组首地址。 分析参数传递情况: a[10]: a[0] a[1] a[2] … a[9] a x ‖ x[0] x[1] x[9] 即:x, a共享同一段内存单元。 前面已分析: 可用指针表示数组。即:指针运算引用数组元素,于是,可用指针变量作为形参接收实参数组首地址。

for (i=x; i<(x+n) ;i++) i= – i return; } 函数改为: void invert (x, n) int x, n; { int i; for (i=x; i<(x+n) ;i++) i= – i return; } a[0] a[1] a[2] … a[9] a: x x+1 x+9  x (x+1) (x+9) 参数传递情况:

进一步分析:在主函数中也不一定要用数组名a,只要用一指针变量即可。设int p; p=&a[0], 则: invert(p, n); 即可完成同样功能 总结以上情况,有四种参数传递形式: (1) 实参、形参均为数组名 (2) 实参为数组名、形参为指针变量 (3) 实参、形参均为指针变量 (4) 实参为指针变量,形参为数组名。 特别是(3)种情况:当不是数组元素时,即实参形参均为单个指针变量时,实现了实、形参共用内存单元。

三、指向多维数组的指针和指针变量。 1. 多维数组的地址: 将一维数组内容扩充,也可用一指针变量指向多维数组,以二维数组为例加以讨论。 设: static int a[3][4] = {{1, 2, 3, 4}, { 5, 6,7, 8}, {9, 10, 11, 12}};

12 1 2 3 4 5 6 7 8 9 10 11 第1行 第2行 第3行 a[0] a[0]+1 a[0]+2 a[0]+3 a[1] a[1]+1 a[1]+2 a[1]+3 a[2] a[2]+1 a[2]+2 a[2]+3 数组名a[0] 数组名a[1] 数组名a[2] a a+1

设首地址a:2000, 则a+1:2008, a+2: 2016 从一维数组中我们认为:a[0]与a, (a+0)等价 所以:a[0][i]的地址&a[0][i]还可表示为(a+i)  a[0][i]的地址:a[0]+i, a+i, 和&a[0][i] a[1][i]的地址:a[1]+i, (a+1)+i, &a[1][i]  a[i][j]的地址:a[i]+j= (a+i)+j 于是:a[i][j]可表示为 *(*(a+i)+j)

2. 多维数组的指针 有了多维数组的地址概念后,可用指针变量来指向多维数组  指向数组元素 当用一个指针变量指向第0行的首地址后,即可搜索到全部元素。 设二维数组的大小为m*n, 则第i, j个元素相对于a[0][0]的个数为mi + j (i=0,1,…,n–1) 设:int p; p=a[0]; 则第a[I][j] 的地址为p+i  m+j

例: 设有一3×4的二维数组,利用指针逐行逐个输出元素。 main ( ) { static int a[3][4]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; int p; for (p=a[0]; p<a[0]+12; p++) { if ((p – a[0]) %4= =0) printf("\n"); printf ("%4d", p); } 注: 为什么p的初值不能写成p=a;?

 指向数组的每一行 仍为上例为例: 当p=a, 则p+1为下一行首地址,于是引用第(i, j)个元素的方法: ((p+i)+j) 第i行首地址,相当于a[i] 这时,需将p的定义改为 int (p)[4]; a) 不能去掉( ),否则为int p[4]为指针数组 b) 之所以这样定义是为了使p+1的地址为a[1], 即:移动4个元素。

例:有一个班,3个学生,各学4门课,计算总平均分数,以及第n个学生的成绩。 程序如下: main ( ) { void average( ); void search ( ); static float score [3] [4]={{65, 67, 70, 60},{80,87,90,81}, {90,99,100,98}}; average (*score, 12); /*求12个分数的平均分8*/ search( score,2); /*求第2个学生成绩*/ }

void average (p, n) float *p; int n; {float *p_end; float sum=0, aver; p_end=p+n-1; for (; p<=p_end; p++) sum=sum+(*p); aver=sum/n; printf("average=%5.2f\n", aver); }

void search (p, n) float (*p) [4]; int n; {int i; printf("the scores of No.%d are:\n", n); for (i=0; i<4; i++) printf("%5.2f ", *(*(p+n)+i)); }

程序运行结果如下: average=82.25 the scores of No. 2 are: 90.00 99.00 100.00 98.00

应有举例: 设有三个学生,各有四门功课,求总的平均分,各学生总分,且将三个学生的成绩按总分排序。 要求用指针变量:  实参可用指向数组的指针变量(实数组名)  实参可用指向一维数组的指针变量;即: 数组名

一、流程图: 指针,指向一维数组 输入三学生单科成绩 学生人数 计算各学生总分 调用函数sumscore(p,n) 指向二维数组 人数 计算总平均分 调用函数average(p,n) 返回值float 人数 按各学生总分排序 调用函数sort(p,n) 指向一维数组 打印各科成绩总分及总平均分 调用函数printscore(p,n) 人数 指向二维数组 结束

二、程序 1. 主函数 main ( ) { void sumscore ( ); float average( ); void sort( ); void printscore( ); static float score[3][5]={{65, 80, 90, 100}, {80, 66, 75, 90}, {58, 60, 90, 83}};

sumscore(score, 3); printf("\n average=%f", average(score, 3)); sort(score, 3); printscore(score, 3); }

2. sumscore函数–––求总分 void sumscore(p, n) float p; int n; { float aver, p_end; p_end=p+5  n –1; for (; p<=p_end; p=p+5) (p+4)= p+ p(p+1)+ (p+2)+ (p+3); }

3. average函数–––求总平均分 float average(p, n) float (p)[5]; int n; { float aver=0.0; int i; for (i=0; i<n; i++) aver=aver+ ((p+i)+4); aver=aver/n return(aver); }

3. sort函数–––排序 有二种方法:(1)循环时用简单变量 (2)循环时用指针变量 方法(1) void sort (p, n) float p; int n; { int i, j, k, m; float t; for (i=0; i<n –1; i++)

{ k=i; for (j=i+1; j<n; j++) if ((p+4+5  i)< (p+4+5  j)) k=j; if (k!=i) for (m=0; m<5; m++) {t= (p+m+5  i); (p+m+5  i)= (p+m+5  k); (p+m+5  k)=t; }

方法(2) void sort (p, n) float p int n; { float p1, p_end, k, t; int m; p_end=p+5  n –1; p=p+4; for (; p<p_end –5; p+=5)

{ k=p; for (p1=p+5; p1<p_end; p1+=5) if (p< p1) k=p1; if (k!=p) for (m=0; m<5; m++) { t= (p –m); (p – m)= (k1 – m); (k1 –m)=t; }

4. printscore函数–––打印输出 void printscore(p, n) float (p)[5]; int n; { int i, j; printf("\n A B C D sum\n"); for (i=0; i<0; i++ ) { printf("\n"); for (j=0; j<4; j++) prinft("%5.2f", ((p+i)+j)); }

§9.4 字符串指针和指向字符串的指针变量 一、字符串指针的定义 形式 char p; 表示p为指针变量,可指向一个字符串的首地址。 例:main( ) { char p; char s[ ]="I am a student!" ; p=s;

进一步:main( ) { char p="I am a student!"; … 或者: main ( ) { char p; p="I am a student!"; … 则: p: I (p+3):m

1. “…”一个串代表示该串的首地址 2. 在输入(scanf)和输出(printf)中,也可用%s将整个串一次输入/输出 例:将字符串a复制到字符串b 1)用字符数组实现 2)用字符指针实现 1) main ( ) { char a[ ]="I am a teacher!"; char b[20]; int i;

for (i=0; (a+i)!=' \0'; i++) (b+i)= (a+i); (b+i)= ' \0'; printf("string a is: %s\n", a); printf("string b is:"); for (i=0; b[i]= ' \o'; i++) printf("%c", b[i]); printf("\n"); }

2) 用指针变量实现 main ( ) { char a[ ]= "I am a teacher!"; char b[20], p1, p2; int i; p1=a; p2=b; for (; p1!='\0'; p1++, p2++) p2= p1; p2= ' \0'; … 同上 }

二、字符串指针作函数参数 与数值变量指针一样,字符串指针,字符串数组均可作为函数参数 结果:可在函数中改变实参内容。 例: 用函数调用实现字符串的复制 方法:(1)字符数组作参数 void copy_string (from, to) char from[ ], to[ ]; { int i=0; while (from[i]!='\0')

{to[i]=from[i]; i++} to[i]='\0 '; } main ( ) {char a[ ]="I am a teacher"; char b[ ]="You are a student"; printf("string_a=%s\n string_b=%s\n", a,b); copy_string(a, b); printf("\n string_a=%s\n string_b=%s\n", a, b)

运行结果: string_a=I am a teacher string_b=You are a student string_a=I am a teacher string_b=I am a teacher 分析a, b前后的内容。b中仍保留原来的一部分内容。但输出b中内容时,遇到第一个'\0'时结束。 在main中也用字符串指针: char a="I am a teacher".; char b="You are a student." …

(2) 形参用字符指针变量 void copy_string (from, to) char from, to; { for (; from!='\0 '; from ++, to++) to = from; to = ' \0 '; } 或:将for改用while while (from!= ' \0 ' ) {to= from; to++; from++;}

进一步:while((to = from)!='\0') {from++;to++;} 实际上'\0'的ASCII码为0,故可将 while ((to ++ = from++)!=0) 简化为: while (to++ = from++)

字符数组作参数的实、形参调用的四种情况 实参 形参 数组名 数组名 数组名 字符指针 字符指针 字符指针…… 字符指针 数组名

三、字符数组与字符指针变量 前面介绍中,字符数组与字符指针变量在使用中具有一定的统一性,但它们之间仍有以下区别: 1. 赋值方式不同: 对字符数组只能对各个元素赋值,不可将整个串赋给数组名, 即:char a[14]; a ="Good Morning! "; 若用指针变量,即可将整个字符串赋值: char a a= "Good Morning! ";

2. 定义数组后,系统给它分配内存单元。具有确定的内存地址,但指针变量定义后,若未对它赋地址,则它并不指向任何单元。 如果:char a; scanf("%s", a); 则:系统十分危险,由于a可能指向一个系统单元,因此,就会破坏该单元的值。 应改为:char str[10], a; a=&str[0]; 或a=str; scanf("%s", a);

3. 指针变量的值可以改变,而数组名(首地址)是不可改变的,即:在程序中不可直接对数组名赋值。 下面的用法不允许: char str[ ]={"Good! "}; str=str+7; 4. 指针变量在确定了值后,可以采用数组元素的方法引用指向的值: char a[ ]={"Good"}; char b=&a[0]; printf("%c", b[2]):

5. 可用指针变量(代表一个字符串)存放格式控制序列,即: char format format="a=%d, b=%f \n"; printf(format, a, b);  当然,format也可为一数组,但赋值时不如指针变量那样方便。

§10.5 函数的指针及指向函数的指针变量 基本概念:前面已述,每一个变量有地址,于是可用一个指针变量来保存,而一个函数实际上为存放在内存中的一段程序,它有一个入口地址––––称为函数的指针。 存放函数指针的变量–––指向函数的指针变量。

一、用函数指针变量调用函数 1. 函数指针变量的定义 形式:类型标识符 (变量名) ( ) 例:int (p) ( ); 表示p为一个函数指针变量,用于存放一个函数的入口地址,但该函数的返回值必须为int型。

2. 给函数指针变量赋值 函数指针变量=函数名; 它不是实参,不是调用,而是将入口地址赋给该变量。 3. 通过函数指针变量调用函数的方法 (函数指针变量名) (实参表列)

例: 求a、b中最大者函数。 int max(x, y) int x, y; { int z; z=z(x>y)? x:y; return(z); } main ( ) { int max( ); int (p)( ); int a, b, c; p=max; scanf("a=%d, b=%d", &a,&b); c=(p) (a, b) printf("max value=%d", c) 4. 对函数指针变量进行运算无意义。

二、函数指针变量作为函数参数 前面介绍过:简单变量、数组名、指针变量均可作为函数的参数。 能否用函数指针变量作参数呢? 当然可以! 意义:当一个函数被调用后,执行过程中需根据实际情况调用f1, f2,或调用f3, f4,于是在该函数中即可用函数指针变量作形式参数。

例:sub (x1, x2) int (x1 )( ), (x2 )( ); { int a, b, i, j; a=(x1) (i); b=(x2) (i, j)  } 于是,可用 sub(f1, f2)或sub(f3, f4)调用sub,表示执行sub时,根据实参传递过来的函数入口地址而调用f1, f2或f2, f4.

例2. 设计一个函数process, 每次实现不同的功能,当用不同的函数名作实参调用process时,process再去调用相应的函数。 程序如下: main ( ) {int max( ), min( ), add( ); int a, b; printf("enter a and b:"); scanf("%d, %d", &a, &b);

printf("max="); process(a, b, max); printf("min=") process(a, b, min); printf("sum="); process(a, b, add); }

max(x, y) int x, y; {int z; if (x>y) z=x; else z=y; return(z); } min(x, y) int x, y; {int z; if (x<y) z=x; else z=y; return(z); }

process (x, y, fun) int x, y; int (* fun) ( ); {int result; result=(*fun) (x,y); printf("%d\n", result); } add(x, y) int x, y; {int z; z=x+y; return(z); }

运行情况如下: enter a and b:2, 6 max=6 min=2 sum=8 注:当用函数名作参数时,不论函数返值类型如何均应作说明,以与变量名相区别。

§10.6 返回值指针值的函数 本概念比较简单,既然函数返回值可以是整、实型等数据。当然也可以是指针值,只是函数定义形式略有不同: 类型标识符 函数名(形参表列) 例: 有若干个学生的成绩(每个学生有4门课程),要求在用户输入学生序号以后,能输出该学生的全部成绩。用指针函数来实现。

程序如下: main ( ) {static float score [ ] [4]={{60,70,80,90}, {56,89,67, 88}, {34, 78, 90, 66}}; float * search ( ); float * p; int i, m; printf("enter the number of student:"); scanf("%d", &m); printf("The scores of No. %d are :\n", m);

p=search (score, m); for (i=0; i<4; i++) printf("%5.2f\t", * (p+i)); } float * seaarch (pointer, n) float (* pointer) [4]; int n; {float * pt; pt= * (pointer +n); return (pt);

运行情况如下: enter the number of student: 1 The scpres pf Mp. 1 are: 56.00 89.00 67.00 88.00

§10.7 指针数组和指向指针的指针 一、指针数组 数组–––同种类型的数据集合。 当每一个元素均为指针类型数据时,该数组被称为指针数组。 1. 定义形式 类型说明符 数组名[常量] 例:int p[10]; p为指针型数组,其每一个元素为一指针型变量。用来存入一组地址。

2. 应用 一个重要的应用––––存放一组字符串 一般情况下,当有一组字符串,如一组书名,也可用二维字符数组存放,但存在二个问题:  字符串长度不一,于是只得以最长字符串的长度作为二维数组列数,造成空间浪费。  在对字符串排序时,若交换数组元素,时间太长。 所以,用指针数组(一维)保存各字符串首地址,且交换时只需交换指针数组各元素––首地址即可解决上述二个问题。

例:将若干字符串按字母顺序(由小到大)输出。 main ( ) {void sort ( ); void print ( ); static char * name[ ]={"Follow me", "BASIC", "Great Wall", "FORTRAN", "Computer design"}; int n=5; sort (name, n); print(name, n); }

void sort (name, n) char *name [ ]; int n; {char *temp; int i, j, k; for (i=0; i<n-1; i++) {k=i; for (j=i+1; j<n; j++) if (strcmp (name [k], name[j])>0 k=j;

if (k ! =i) temp=name[i], name[i]=name[k]; name[k]=temp;} } void print (name, n) char * name[ ]; int n; {int i; for (i=0; i<n; i++) } printf ("%s\n", name[i]);

运行结果为: BASIC Computer design FORTRAN Follow me Great Wall

二、指向指针的指针 将指针变量的概念拓广: 一个数据变量有地址,则可用一指针变量来存放该地址。那么一指针变量也有地址,可否用另一个指针变量来存放?回答是肯定的。 &p &x pp p x 定义形式: int p, pp;

例: main( ) { static char * name [ ]={"Follow me", "BASIC", "Great Wall", "FORTRAN", "Computer design"}; char * * p; int i; for (i=0; i<5; i++) {p=name+i; printf ("%s\n", * p);} }

运行结果如下: Follow me BASIC Great Wall FORTRAN Computer design name[0]

一组字符串只能用指针数组存放: char name[ ]={"Good", "Bad ", "Are ", "Teacher ",}; 于是每一个元素name[i]为字符串指针变量 char p; p=&name[i]; 或 p=name+i; 则: p就表示第i个字符串的首地址,可用p输出字符串,指向指针的指针称为二级间接访问。如:int x, p, p; 则 p=&x; pp=&p; 则 p表示x

三、指针数组作main( )函数的形式: main( )既可为无参函数,也可为有参函数 有参函数形式: main (argc, argv) int argc; char argv[ ]; … 那么它的实参从何而来?分析DOS系统下的命令: c:\> copy FILE1.C FILE2.C

其中:copy为命令 FILE1.C 和FILE2.C为其参数。 对于一个在DOS下运行的C程序,也可以给一些参数: c:> zou 参数1 参数2 …参数n–1 当以这种方式运行C程序,则argcn, argv为指针数组,每一个元素指向包含命令在内的n个字符串。 即: argv[0]"zou" argv[1] "参数1" … argv[n –1]  "参数n –1 "

例:编写main( )函数,将后面的参数输出: main (argc, argv) int argc; char argv[ ]; { while (argc>1) { ++argv; printf("%s\n", argv); – – argc; }

上述文件设为file1 则运行时 file1 China Beijing Changsha China Beijing Changsha