购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.3 指针

指针是C语言中的一个重要概念,也是最不容易掌握的内容。指针常常用在函数的参数传递和动态内存分配中。指针与数组相结合,使引用数组成分的形式更加多样化,访问数组元素的手段更加灵活;指针与结构体相结合,利用系统提供的动态存储手段,能构造出各种复杂的动态数据结构;利用指针形参,使函数能实现传递地址形参和函数形参的要求。在“数据结构”课程中,指针的使用非常频繁,因此,要想真正掌握数据结构,就需要灵活、正确地使用指针。本节主要介绍指针变量的概念、指针变量的引用、指针与数组、函数指针与指针函数。

2.3.1 什么是指针

指针是一种变量,也称指针变量,它的值不是整数、浮点数和字符,而是内存地址。指针的值就是变量的地址,而变量又拥有一个具体值。因此,可以理解为变量名直接引用了一个值,指针间接地引用了一个值。

在理解指针之前,先来了解下地址的概念。图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的钥匙相当于一般的变量。

2.3.2 指针变量的间接引用

与普通变量一样,指针变量也可以对数据进行操作。指针变量主要通过取地址运算符&和指针运算符*来存取数据。例如,&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是等价的。

注意 指针变量只能用来存放地址,不能将一个整型值赋给一个指针变量。而且指针变量的类型应和所指向的变量的类型一致,例如整型指针只能指向整型变量,不能指向浮点型变量。指针变量是一种数据类型,表明该变量用来存放变量的地址;变量指针是变量的地址。

2.3.3 指针与数组

指针可以与变量结合,也可以与数组结合使用。指针数组和数组指针是两个截然不同的概念,指针数组是一种数组,该数组存放的是一组变量的地址。数组指针是一个指针,表示该指针是指向数组的指针。

1.指向数组元素的指针

指针可以指向变量,也可以指向数组及数组中的元素。

例如定义一个整型数组和一个指针变量,语句如下。


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 指针引用数组元素的运行结果

2.指针数组

指针数组 其实也是一个数组,只是数组中的元素是指针类型的数据。换句话说,指针数组中的每一个元素都是一个指针变量。

定义指针数组的方式如下。


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 程序运行结果

3.数组指针

数组指针 是指向数组的一个指针。如下定义。


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 打印输出数组指针和数组元素

注意 区别数组指针和指针数组。数组指针首先是一个指针,并且它是一个指向数组的指针。指针数组首先是一个数组,并且它是保存指针变量的数组。

2.3.4 指针函数与函数指针

与指针数组、数组指针一样,指针函数与函数指针也是一对孪生兄弟,也是常常容易混淆的概念。顾名思义,指针函数是一种函数,它表示函数的返回值是指针类型;函数指针是指针的一种,它表示该指针指向一个函数。

1.指针函数

指针函数 是指函数的返回值是指针类型的函数。在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.函数指针

指针可以指向变量、数组,也可以指向函数,指向函数的指针就是函数指针。与数组名类似,函数名就是程序在内存中的起始地址。指向函数的指针可以把地址传递给函数,也可以从函数返回给指向函数的指针。

【例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.函数指针数组

假设有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--等运算。
9sj/8RDNKMLB2ti9ETTkst9tU6N0kWtihsvncm0gRw11CuaelGf30lIdwcdUOoDm

点击中间区域
呼出菜单
上一章
目录
下一章
×