指针是C语言中的一个重要概念,也是最不容易掌握的内容。指针常常用在函数的参数传递和动态内存分配中。指针与数组相结合,使引用数组成分的形式更加多样化,访问数组元素的手段更加灵活;指针与结构体相结合,利用系统提供的动态存储手段,能构造出各种复杂的动态数据结构;利用指针形参,使函数能实现传递地址形参和函数形参的要求。在“数据结构”课程中,指针的使用非常频繁,因此,要想真正掌握数据结构,就需要灵活、正确地使用指针。本节主要介绍指针变量的概念、指针变量的引用、指针与数组、函数指针与指针函数。
指针是一种变量,也称指针变量,它的值不是整数、浮点数和字符,而是内存地址。指针的值就是变量的地址,而变量又拥有一个具体值。因此,可以理解为变量名直接引用了一个值,指针间接地引用了一个值。
在理解指针之前,先来了解下地址的概念。图2-25展示了变量在内存中的存储情况。假设a、b、c、d、bPtr分别是5个变量,其中,a、b、c、d是整型变量,bPtr是指针变量。整型变量在内存中占用4个字节,变量a的存放地址是2000、2001、2002和2003四个内存单元,变量b存放在2004~2007内存单元中,变量bPtr存放在4600~4603四个内存单元中。整型变量a、b、c、d的内容分别是25、12、78、5,而指针变量bPtr的内容是一个地址,为2004开始的内存地址,即bPtr存放的是变量b的地址,换句话说,就是bPtr指向变量b的存储位置,可以用一个箭头表示从地址是4600的位置指向变量地址为2004的位置。
一个存放变量地址的类型称为该变量的“指针”。如果有一个变量用来存放另一个变量的地址,则称这个变量为指针变量。在图2-26中,qPtr用来存放变量q的地址,qPtr就是一个指针变量。
在C语言中,所有变量在使用前都需要声明。例如,声明一个指针变量的语句如下。
int *qPtr,q;
q是整型变量,表示要存放一个整数类型的值;qPtr是一个整型指针变量,表示要存放一个变量的地址,而这个变量是整数类型。qPtr叫做一个指向整型的指针。
说明 在声明指针变量时,“*”只是一个指针类型标识符,指针变量的声明也可以写成int*qPtr。
指针变量可以在声明时赋值,也可以在声明后赋值。例如,在声明时为指针变量赋值的语句如下。
int q=12 ; int *qPtr=&q;
或在声明后为指针变量赋值,语句如下。
int q=12,*qPtr; qPtr=&q;
这两种赋值方法都是把变量q的地址赋值给指针变量qPtr。qPtr=&q叫做指向变量q,其中,&是取地址运算符,表示返回变量q的地址。指针变量qPtr与变量q的关系如图2-26所示。
图2-25 指针变量在内存中的表示
图2-26 q直接引用一个值和qPtr间接引用一个变量q
直接引用和间接引用可以用日常生活中的两个抽屉来形象说明。有两个抽屉A和B,抽屉A有一把钥匙,抽屉B也有一把钥匙。为了方便,可以把两把钥匙都带在身上,需要取抽屉A中的东西时直接用钥匙A打开抽屉;也可以为了安全,把钥匙A放到抽屉B中,把抽屉B的钥匙带在身上,需要取抽屉A中的东西时,先打开抽屉B,再取出抽屉A的钥匙,然后打开抽屉A,取出需要的东西。前一种方法就相当于通过变量直接引用,后一种方法相当于通过指针间接引用。其中,抽屉B的钥匙相当于指针变量,抽屉A的钥匙相当于一般的变量。
与普通变量一样,指针变量也可以对数据进行操作。指针变量主要通过取地址运算符&和指针运算符*来存取数据。例如,&a指的是变量a的地址,*ptr表示变量ptr所指向的内存单元存放的内容。下面通过具体例子说明&和*运算符及指针变量的使用。
【例2-4】 利用变量和指针变量存取数据。
【分析】 主要考查如何利用&和*运算符来存取变量中的数据,取地址运算符&和指针运算符*是互逆的操作,应灵活掌握两个运算符的使用技巧。程序代码如下。
#include<stdio.h> void main() { int q=12; int *qPtr; /* 声明指针变量qPtr*/ qPtr=&q; /* 指针变量qPtr 指向变量q*/ /* 打印变量q 的地址和qPtr 的内容*/ printf("q 的地址是:%p\nqPtr 中的内容是:%p\n",&q,qPtr); /* 打印q 的值和qPtr 指向变量的内容*/ printf("q 的值是:%d\n*qPtr 的值是:%d\n",q,*qPtr); /* 运算符'&' 和'*' 是互逆的*/ printf("&*qPtr=%p,*&qPtr=%p\n 因此有&*qPtr=*&qPtr\n",&*qPtr,*&qPtr); }
程序运行结果如图2-27所示。
图2-27 利用变量与指针变量进行存取操作的运行结果
&和*作为单目运算符,结合性是从右到左,优先级别相同,因此对于表达式&*qPtr来说,先进行*运算,后进行&运算。因为qPtr是指向变量q的,所以*qPtr的值为q,&*qPtr就是对q取地址,即&q,q的地址。*&qPtr是先进行取地址运算即&qPtr,即qPtr的地址,然后进行*运算,那么*&qPtr就是qPtr本身,即q的地址。因此,&*qPtr和*&qPtr是等价的。
注意 指针变量只能用来存放地址,不能将一个整型值赋给一个指针变量。而且指针变量的类型应和所指向的变量的类型一致,例如整型指针只能指向整型变量,不能指向浮点型变量。指针变量是一种数据类型,表明该变量用来存放变量的地址;变量指针是变量的地址。
指针可以与变量结合,也可以与数组结合使用。指针数组和数组指针是两个截然不同的概念,指针数组是一种数组,该数组存放的是一组变量的地址。数组指针是一个指针,表示该指针是指向数组的指针。
指针可以指向变量,也可以指向数组及数组中的元素。
例如定义一个整型数组和一个指针变量,语句如下。
int a[5]={10,20,30,40,50}; int *aPtr;
这里的a是一个数组,它包含了5个整型数据。变量名a就是数组a的首地址,它与&a[0]等价。如果令aPtr=&a[0]或者aPtr=a,则aPtr也指向了数组a的首地址。如图2-28所示。
也可以在定义指针变量时直接赋值,如以下语句是等价的。
int *aPtr=&a[0]; int *aPtr; aPtr =&a[0];
与整型、浮点型数据一样,指针也可以进行算术运算,但含义却不同。当一个指针加1(或减)1并不是指针值增加(或减少)1,而是使指针指向的位置向后(或向前)移动了一个位置,即加上(或减去)该整数与指针指向对象的大小的乘积。例如对于aPtr+=3,如果一个整数占用4个字节,则相加后aPtr=2000+4*3=2012(这里假设指针的初值是2000)。同样指针也可以进行自增(++)运算和自减(--)运算。
也可以用一个指针变量减去另一个指针变量。例如,指向数组元素的指针aPtr的地址是2008,另一个指向数组元素的指针bPtr的地址是2000,则a=aPtr-bPtr的运算结果就是把从aPtr到bPtr之间的元素个数赋给a,元素个数为(2008-2000)/4=2(假设整数占用4个字节)。
我们也可以通过指针来引用数组元素。例如以下语句。
*(aPtr+2);
如果aPtr是指向a[0],即数组a的首地址,则aPtr+2就是数组a[2]的地址,*(aPtr+2)就是30。
注意 指向数组的指针可以进行自增或自减运算,但是数组名则不能进行自增或自减运算,这是因为数组名是一个常量指针,它是一个常量,常量值是不能改变的。
【例2-5】 用指针引用数组元素并打印输出。
【分析】 主要考查指针与数组结合进行的运算,有指针对数组的引用及指针的加、减运算。指针及数组对元素操作的实现如下。
#include<stdio.h> void main() { int a[5]={10,20,30,40,50}; int *aPtr,i; /* 指针变量声明*/ aPtr=&a[0]; /* 指针变量指向变量q*/ for(i=0;i<5;i++) /* 通过数组下标引用元素的方式输出数组元素*/ printf("a[%d]=%d\n",i,a[i]); for(i=0;i<5;i++) /* 通过数组名引用元素的方式输出数组元素*/ printf("*(a+%d)=%d\n",i,*(a+i)); for(i=0;i<5;i++) /* 通过指针变量下标引用元素的方式输出数组元素*/ printf("aPtr[%d]=%d\n",i,aPtr[i]); for(aPtr=a,i=0;aPtr<a+5;aPtr++,i++) /* 通过指针变量偏移引用元素的方式输出数组元素*/ printf("*(aPtr+%d)=%d\n",i,*aPtr); }
程序中共有4个for循环,其中第一个for循环是利用数组的下标访问数组的元素,第二个for循环是利用使用数组名访问数组的元素,在C语言中,地址也可以像一般的变量一样进行加、减运算,但是指针的加1和减1表示的是一个元素单元。第三个for循环是利用指针访问数组中的元素,第四个for循环则是先将指针偏移,然后访问该指针所指向的内容。
上述4种访问数组元素的方法表明,在C语言中指针的运用非常灵活。
程序运行结果如图2-29所示。
图2-28 数组的指针与数组在内存中的关系
图2-29 指针引用数组元素的运行结果
指针数组 其实也是一个数组,只是数组中的元素是指针类型的数据。换句话说,指针数组中的每一个元素都是一个指针变量。
定义指针数组的方式如下。
int *p[4];
由于[]运算符优先级比*高,p优先与[]结合,形成p[]数组形式,然后与*结合,表示该数组是指针类型的,每个数组元素是一个指向整型的变量。从字面上理解,指针数组首先是一个数组,这个数组存放的是指针类型的变量。
指针数组常常用于存储一些长度不等的字符串数据,有的读者可能会问,为什么不存放在二维数组中?这是因为字符串长度不等,若将这些字符串存放在二维数组中,就需要定义一个能容纳最长字符串的二维数组,这样就会出现一部分存储空间不能得到有效利用。
例如字符串“C Programming Language”、“Assembly Language”、“Data Structure”和“Natural Language”在二维数组中的存储情况,如图2-30所示。
图2-30 字符串在二维数组中的存储情况
不难看出,利用二维数组保存多个字符串时,为了保证能存储所有的字符串,必须按最长的字符串长度来定义二维数组的列数。为了节省存储单元,可以采用指针数组保存字符串,定义如下。
char *s[4]={"C Programming Language","Assembly Language","Java Language","Natural Language"};
在指针数组中存储字符串的情况如图2-31所示。
图2-31 字符串在指针数组中的存储情况
这样在字符串比较多且长度不一时,就可以大大地节省内存空间。
【例2-6】 用指针数组保存字符串并将字符串打印输出。
【分析】 主要考查指针的应用及对指针数组概念的理解,其实s[4]就是一个特殊的数组,s[0]、s[1]、s[2]、s[3]分别存放指向4个字符串指针,即数组保存的是各个字符串的首地址。代码如下。
#include<stdio.h> void main() { /* 定义指针数组*/ char *s[4]={"C Programming Language","Assembly Language"," Data Structure ","Natural Language"}; int n=4; /* 指针数组元素的个数*/ int i; char *aPtr; /* 第1 种方法输出:通过数组名输出字符串*/ printf(" 第1 种方法输出:通过指针数组的数组名输出字符串:\n"); for(i=0;i<n;i++) printf(" 第%d 个字符串:%s\n",i+1,s[i]); /* 第2 种方法输出:通过指向数组的指针输出字符串*/ printf(" 第2 种方法输出:通过指向数组的指针输出字符串:\n"); for(aPtr=s[0],i=0;i<n;aPtr=s[i]) { printf(" 第%d 个字符串:%s\n",i+1,aPtr); i++; } }
程序运行结果如图2-32所示。
【例2-7】 利用指针数组实现对一组变量的值按照从小到大排序,排序时交换指向变量的指针值。
【分析】 主要考查指针数组的概念及用法。让指针数组的各成分分别指向各变量,通过指针数组引用变量的值并交换之,使存放在指针数组中各分量指向的变量值从小到大顺序排列。实现代码如下。
#include<stdio.h> void bubble(int *a[],int n); void main() { int a,b,c,d,e,f,i; int *vp[]={&a,&b,&c,&d,&e,&f}; printf(" 请输入a,b,c,d,e,f 的值:"); scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f); bubble(vp,sizeof(vp)/sizeof(vp[0])); for(i=0;i<sizeof(vp)/sizeof(vp[0]);i++) printf("%4d",*vp[i]); printf("\n"); } void bubble(int *a[],int n) { int i,j,flag,t; for(i=0;i<n-1;i++) { flag=0; for(j=0;j<n-1-i;j++) if(*a[j]>*a[j+1]) { t=*a[j]; *a[j]=*a[j+1]; *a[j+1]=t; flag=1; } if(flag==0) return; } }
程序运行结果如图2-33所示。
图2-32 字符数组输出结果
图2-33 程序运行结果
数组指针 是指向数组的一个指针。如下定义。
int (*p)[4];
其中,p是指向一个拥有4个元素的数组指针,数组中每个元素都为整型。与前面刚刚介绍过的指针数组做比较,这里定义的数组指针多了一对括号,*p两边的括号不可以省略。这里定义的p仅仅是一个指针,不过这个指针有点特殊,这个p指向的是包含4个元素的一维数组。数组指针p与它指向的数组之间的关系可以用图2-34来表示。
如果有如下语句。
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; p=a;
数组指针p与数组a中元素之间的关系如图2-35所示。其中,(*p)[0]、(*p)[1]、(*p)[2]、(*p)[3]分别保存的是元素值为1、2、3、4的地址。p、p+1和p+2分别指向二维数组的第一行、第二行和第三行,p+1表示将指针p移动到下一行。
图2-34数组指针p的表示
图2-35 数组指针p与二维数组的对应关系
*(p+1)+2表示数组a第1行第2列的元素的地址,即&a[1][2],*(*(p+1)+2)表示a[1][2]的值即7,其中1表示行,2表示列。下面编程输出以上数组指针的值和数组的内容。
【例2-8】 在屏幕上打印图2-35中数组指针p及数组a中的元素。
【分析】 主要考查利用数组指针引用数组中的元素的方法。数组指针p与数组a中元素的对应关系如图2-35所示。通过利用数组指针p引用数组a中的元素并输出p的值,以验证对指针引用的正确性,加深对数组指针的理解。实现代码如下。
#include<stdio.h> void main() { int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}}; int (*p)[4]; /* 声明数组指针变量p*/ int row,col; p=a; /* 指针p 指向数组元素为4 的数组*/ /* 打印输出数组指针p 指向的数组的值*/ for(row=0;row<3;row++) { for(col=0;col<4;col++) printf("a[%d,%d]=%-4d",row,col,*(*(p+row)+col)); printf("\n"); } /* 通过改变指针p 修改数组a 的行地址,改变col 的值修改数组a 的列地址*/ for(p=a,row=0;p<a+3;p++,row++) { for(col=0;col<4;col++) printf("(*p[%d])[%d]=%p",row,col,((*p)+col)); printf("\n"); } }
程序运行结果如图2-36所示。
图2-36 打印输出数组指针和数组元素
注意 区别数组指针和指针数组。数组指针首先是一个指针,并且它是一个指向数组的指针。指针数组首先是一个数组,并且它是保存指针变量的数组。
与指针数组、数组指针一样,指针函数与函数指针也是一对孪生兄弟,也是常常容易混淆的概念。顾名思义,指针函数是一种函数,它表示函数的返回值是指针类型;函数指针是指针的一种,它表示该指针指向一个函数。
指针函数 是指函数的返回值是指针类型的函数。在C语言中,一个函数的返回值可以是整型、实型和字符型,也可以是指针类型。例如,以下是一个指针函数的定义。
float *func(int a,int b);
其中,func是函数名,前面的“*”表明返回值的类型是指针类型,因为前面的类型标识符是float,所以返回的指针是指向浮点型的。该函数有两个参数,参数类型都是整型。下面我们还是通过一个具体实例来介绍指针函数的用法。
【例2-9】 假设若干个学生的成绩在二维数组中存放,要求输入学生编号,利用指针函数实现其成绩的输出。
【分析】 主要考查指针函数的使用。学生成绩存放在二维数组中,每一行存放一个学生的成绩,通过输入学生编号,返回该学生存放成绩的地址,然后利用指针输出每一门的学生成绩。程序实现如下。
#include<stdio.h> int *FindAddress(int (*ptr)[4],int n); /* 声明查找成绩地址函数*/ void Display(int a[][4],int n,int *p); /* 声明输出成绩函数*/ void main() { int row,n=4; int *p; int score[3][4]={{83,78,79,88},{71,88,92,63},{99,92,87,80}}; printf(" 请输入学生编号(1 或2 或3). 输入0 退出程序.\n"); scanf("%d",&row); /* 输入要输出学生成绩的编号*/ while(row) { if(row==1||row==2||row==3) { printf(" 第%d 个学生的成绩4 门课的成绩是:\n",row); p=FindAddress(score,row-1); /* 调用指针函数*/ Display(score,n,p); /* 调用输出成绩函数*/ printf(" 请输入学生编号(1 或2 或3). 输入0 退出程序.\n"); scanf("%d",&row); } else { printf(" 输入不合法,请重新输入(1 或2 或3) ,输入0 退出程序.\n"); scanf("%d",&row); } } } int *FindAddress(int (*ptrScore)[4],int n) /* 查找某条学生成绩记录地址函数。通过传递的行地址找到要查找学生成绩的地址,并返回行地址*/ { int *ptr; ptr=*(ptrScore+n); /* 修改行地址,即找到学生的第一门课成绩的地址*/ return ptr; } void Display(int a[][4],int n,int *p) /* 输出学生成绩的实现函数。利用传递过来的指针输出每门课的成绩*/ { int col; for(col=0;col<n;col++) printf("%4d",*(p+col)); /* 输出查找学生的每门课成绩*/ printf("\n"); }
程序运行结果如图2-37所示。
图2-37 通过指针函数返回指针并输出成绩的运行结果
主函数通过语句p=FindAddress(score,row-1);调用指针函数*FindAddress(int(*ptrScore)[4],int n),并把二维数组的行地址传递给形式参数ptrScore,在*FindAddress(int(*ptrScore)[4],int n)中,执行语句ptr=*(ptrScore+n),返回行指针ptr,然后调用Display(score,n,p)输出成绩。在Display(int a[][4],int n,int*p)中,通过p+col改变列地址,即找到该学生成绩的每门课的位置,依次输出每门课的成绩。
指针可以指向变量、数组,也可以指向函数,指向函数的指针就是函数指针。与数组名类似,函数名就是程序在内存中的起始地址。指向函数的指针可以把地址传递给函数,也可以从函数返回给指向函数的指针。
【例2-10】 通过一个函数求两个数的乘积,并通过函数指针调用该函数。
【分析】 主要考查函数指针的调用方法。程序实现代码如下。
#include<stdio.h> /* 包含输入输出*/ int Mult(int a,int b); /* 声明两个数乘积的函数*/ void main() { int a,b; int (*func)(int,int); /* 声明一个函数指针*/ printf(" 请输入两个数:"); scanf("%d,%d",&a,&b); /* 第1 种调用函数的方法:函数名调用求两个数乘积函数*/ printf(" 第1 种调用函数的方法:函数名调用求两个数乘积的函数:\n"); printf("%d*%d=%d\n",a,b,Mult(a,b)); /* 通过函数名调用*/ /* 第2 种调用函数的方法:函数指针调用求两个数乘积的函数*/ func=Mult; /* 函数指针指向求乘积函数*/ printf(" 第2 种调用函数的方法:函数指针调用求两个数乘积函数:\n"); printf("%d*%d=%d\n",a,b,(*func)(a,b)); /* 通过函数指针调用函数*/ } int Mult(int x,int y) /* 实现求两个数乘积函数*/ { return x*y; }
程序运行结果如图2-38所示。
语句int(*func)(int,int);声明一个指向函数的指针变量,并且所指向的函数返回值为整型,它有两个整型参数。
在声明函数中,由于*运算符的优先级比()运算符高,所以()不可以省略。
语句func=Mult;表示函数指针func指向函数Mult,func和Mult均指向函数Mult的起始地址,程序在编译阶段会被翻译成一行行指令并被装入到内存区域,如图2-39所示。
图2-38 函数指针调用求两个数乘积函数的运行结果
图2-39 函数指针在内存中的表示
其中,主函数中的语句(*func)(a,b);是执行调用求两个数乘积函数的,因为函数本身就是一个地址,也可以写成func(a,b)的形式。
函数指针还可以作为参数传递给其他函数。
【例2-11】 利用函数指针作为函数参数,实现选择排序算法的升序排列和降序排列。
【分析】 主要考查函数指针作为函数参数的使用。程序实现代码如下。
#include<stdio.h> /* 包含输入输出函数*/ #define N 10 /* 数组元素个数*/ int Ascending(int a,int b); /* 是否进行升序排列*/ int Descending(int a,int b); /* 是否进行降序排列*/ void swap(int *,int *); /* 交换数据*/ void SelectSort(int a[],int n,int (*compare)(int,int));/* 选择排序,函数指针作为参数调用*/ void Display(int a[],int n); /* 输出数组元素*/ void main() { int a[N]={22,55,12,7,19,65,81,3,30,52}; int flag; while(1) { printf("1: 从小到大排序.\n2: 从大到小排序.\n0: 结束!\n"); printf(" 请输入:"); scanf("%d",&flag); switch(flag) { case 1: printf(" 排序前的数据为:"); Display(a,N); SelectSort(a,N,Ascending); /* 从小到大排序,将函数作为参数传递*/ printf(" 从小到大排列后的元素序列为:"); Display(a,N); break; case 2: printf(" 排序前的数据为:"); Display(a,N); SelectSort(a,N,Descending); /* 从大到小排序,将函数作为参数传递*/ printf(" 从大到小排列后的元素序列为:"); Display(a,N); break; case 0: printf(" 程序结束!\n"); return; break; default: printf(" 输入数据不合法,请重新输入.\n"); break; } } } /* 选择排序,将函数作为参数传递,判断是从小到大还是从大到小排序*/ void SelectSort(int a[],int n,int(*compare)(int,int)) { int i,j,k; for(i=0;i<n;i++) { j=i; for(k=i+1;k<n;k++) if((*compare)(a[k],a[j])) j=k; swap(&a[i],&a[j]); } } /* 交换数组的元素*/ void swap(int *a,int *b) { int t; t=*a; *a=*b; *b=t; } /* 判断相邻数据大小,如果前者大,升序排列需要交换*/ int Ascending(int a,int b) { if(a<b) return 1; else return 0; } /* 判断相邻数据大小,如果前者大,降序排列需要交换*/ int Descending(int a,int b) { if(a>b) return 1; else return 0; } /* 输出数组元素*/ void Display(int a[],int n) { int i; for(i=0;i<n;i++) printf("%4d",a[i]); printf("\n"); }
程序运行结果如图2-40所示。
图2-40 函数指针作为函数参数传递的排序运行结果
其中,函数SelectSort(a,N,Ascending)中的参数Asscending是一个函数名,传递给函数定义void SelectSort(int a[],int n,int(*compare)(int,int))中的函数指针compare,这样指针就指向了Asscending。从而可以在执行语句(*compare)(a[j],a[j+1])时调用函数Ascending(int a,int b)判断是否需要交换数组中两个相邻的元素,然后调用swap(&a[j],&a[j+1])进行交换。
假设有3个函数f1、f2和f3,可以把这3个函数作为数组元素存放在一个数组中,需要定义一个指向函数的指针数组指向这三个函数,代码如下。
void (*f[3])(int)={f1,f2,f3};
f是包含3个指向函数指针元素的数组,f[0]、f[1]和f[2]分别指向函数f1、f2和f3。通过函数指针f调用函数的形式如下。
f[n](m); /*n 和m 都是整数*/
【例2-12】 声明一个指向函数的指针数组,并通过指针调用函数。
【分析】 主要考查指向函数的指针数组的使用。程序实现如下。
#include<stdio.h> void f1(int n); /* 函数f1 声明*/ void f2(int n); /* 函数f2 声明*/ void f3(int n); /* 函数f3 声明*/ void main() { void (*f[3])()={f1,f2,f3}; /* 声明指向函数的指针数组*/ int flag; printf(" 调用函数请输入1 、2 或者3 ,结束程序请输入0 。\n"); scanf("%d",&flag); while(flag) { if(flag==1||flag==2||flag==3) { f[flag-1](flag); /* 通过函数指针调用数组中的函数*/ printf(" 请输入1 、2 或者3 ,输入0 结束程序.\n"); scanf("%d",&flag); } else { printf(" 请输入一个合法的数(1~3), 输入0 结束程序.\n"); scanf("%d",&flag); } } printf(" 程序结束.\n"); } void f1(int n) /* 函数f1 的定义*/ { printf(" 函数f%d: 调用第%d 个函数!\n",n,n); } void f2(int n) /* 函数f2 的定义*/ { printf(" 函数f%d: 调用第%d 个函数!\n",n,n); } void f3(int n) /* 函数f3 的定义*/ { printf(" 函数f%d: 调用第%d 个函数!\n",n,n); }
程序的运行结果如图2-41所示。
图2-41 指针调用保存在数组中的函数的运行结果
注意
函数指针不能执行像f+1、f++、f--等运算。