一、用指针变量作函数参数的实例
思考题:
例题:从键盘输入某班学生某门课成绩(每班人数最多不超过40人,具体人数由键盘输入),是分析下列程序是否能实现计算并输出最高分以及相应学号。
#include <stdio.h>#define N 40void FindMax(int score[],long num[],int n,int pmaxscore,long pmaxnum);int main(void){int score[N],maxscore;int n,i;long num[N],maxnum;printf("How many students?");scanf("%d",&n);printf("Input student`s ID and score:\n");for(i=0;i<n;i++){scanf("%ld%d",&num[i],&score[i]);}FindMax(score,num,n,maxscore,maxnum);printf("maxscore = %d,maxnum = %ld\n",maxscore,maxnum);return 0;} void FindMax(int score[],long num[],int n,int pmaxscore,long pmaxnum){int i;pmaxscore = score[0];pmaxnum = num[0];for(i=1;i<n;i++){if(score[i]>pmaxscore){pmaxscore = score[i];pmaxnum = num[i];}}}
错误的原因在于用普通变量作函数参数进行按值调用不能再被调函数中改变相应的参数值。虽然可以用return 语句返回最高值,但return 只能返回一个值,要的到最高分即学号这样的两个值,必须使用指针变量作函数参数,即模拟按引用调用,因此需要将程序修改如下:
#include <stdio.h>#define N 40void FindMax(int score[],long num[],int n,int *pmaxscore,long *pmaxnum);int main(void){int score[N],maxscore;int n,i;long num[N],maxnum;printf("How many students?");printf("\n");scanf("%d",&n);printf("Input student`s ID and score:\n");for(i=0;i<n;i++){scanf("%ld%d",&num[i],&score[i]);}FindMax(score,num,n,&maxscore,&maxnum);printf("maxscore = %d,maxnum = %ld\n",maxscore,maxnum);return 0;} void FindMax(int score[],long num[],int n,int *pmaxscore,long *pmaxnum){int i;*pmaxscore = score[0];*pmaxnum = num[0];printf("\n");for(i=1;i<n;i++){if(score[i]>*pmaxscore){*pmaxscore = score[i];*pmaxnum = num[i];}}}
指针梳理:创建变量pmaxscore pmaxnum为整形,“FindMax(score,num,n,&maxscore,&maxnum);”
这句中&调用地址,传递给findmax,再通过值得对比,获得最大值,
“printf(“maxscore = %d,maxnum = %ld\n”,maxscore,maxnum);”
这句打印得就是获得得最大值。
由于指针形参所指向的变量的值在函数调用结束后才能被确定,因此这两个指针形参称为函数的出口参数,函数FindMax()的前三个形参再函数调用前必须确定其值,因此称为函数的入口参数。
这个题目得另一个解法:(我只做简要得原理论述,程序相对简单,容易理解)
#include <stdio.h>#define n 4int score[n];void Sum(int score[],int *sum){int i;for(i=1;i<n;i++){*sum=*sum+score[i];}}int main(){int *sum=&score[0];int i;printf("shuru:");for(i=0;i<n;i++){scanf("%d",&score[i]);} Sum(score,sum);printf("%d",*sum);}
该程序通过直接获取数组首地址,传入函数Sum中,进行处理,最后返回需要得答案。
指针得使用非常重要,需要读者进行理解,练习。
二、函数指针及其应用
函数指针(Function Pointers)就是指向函数得指针(Pointer to a Function)
指向函数得指针变量存储得是一个函数再内存中得入口地址。
冯·诺依曼体系结构强调程序与数据共同存储再内存中,函数是子程序,当然也存储在内存中,指向存储这个函数得第一条指令得地址,称为函数得入口地址。
在前面我们了解到一个数组名其实就是存储数组第一个元素得内存地址,同理,一个函数名就是这个函数得源代码在内存中得起始地址,编译器将不带()得函数名解释为该函数得入口地址,函数指针在某些场合是非常有用的。
例题:
对输入学生得数据进行排序(升序、降序)
#include <stdio.h>#define N 40int readscore(int score[]);void printscore(int score[],int n); void ascendingsort(int a[],int n);void descendingsort(int a[],int n);void swap(int *x,int *y);int main(void){int score[N],n;int order;n=readscore(score);printf("Total students are %d\n",n);printf("Enter 1 to sort in ascending order,\n");printf("Enter 2 to sort in descending order:");scanf("%d",&order);printf("Data items in original order \n");printscore(score,n);if(order==1){ascendingsort(score,n);printf("Data items in ascending order\n");}else{descendingsort(score,n);printf("Data items in descending order\n");}printscore(score,n);return 0;}int readscore(int score[]){int i=-1;do{i++;printf("Input score:");scanf("%d",&score[i]);}while(score[i]>=0);return i;}void printscore(int score[],int n){int i;for(i=0;i<n;i++){printf("%4d",score[i]);}printf("\n");}void ascendingsort(int a[],int n){int i,j,k;for(i=0;i<n-1;i++){k=i;for(j=i+1;j<n;j++){if(a[j]<a[k]) k=j;}if(k!=i) swap(&a[k],&a[i]);}}void descendingsort(int a[],int n){int i,j,k;for(i=0;i<n-1;i++){k=i;for(j=i+1;j<n;j++){if(a[j]>a[k]) k=j;}if(k!=j) swap(&a[k],&a[i]);}}void swap(int *x,int *y){int temp;temp=*x;*x=*y;*y=temp;}
修改程序,将升降排序合二为一:
#include <stdio.h>#define N 40int readscore(int score[]);void printscore(int score[],int n); void selectionsort(int a[],int n,int (*compare)(int a,int b));int ascendingsort(int a,int b);int descendingsort(int a,int b);void swap(int *x,int *y);int main(void){int score[N],n;int order;n=readscore(score);printf("Total students are %d\n",n);printf("Enter 1 to sort in ascending order,\n");printf("Enter 2 to sort in descending order:");scanf("%d",&order);printf("Data items in original order \n");printscore(score,n);if(order==1){selectionsort(score,n,ascendingsort);//函数指针指向ascending() printf("Data items in ascending order\n");}else{selectionsort(score,n,descendingsort);//函数指针指向descending()printf("Data items in descending order\n");}printscore(score,n);return 0;}int readscore(int score[]){int i=-1;do{i++;printf("Input score:");scanf("%d",&score[i]);}while(score[i]>=0);return i;}void printscore(int score[],int n){int i;for(i=0;i<n;i++){printf("%4d",score[i]);}printf("\n");}//函数功能:调用函数指针compare指向得函数实现对数组a的交换法排序void selectionsort(int a[],int n,int (*compare)(int a,int b)){int i,j,k;for(i=0;i<n-1;i++){k=i;for(j=i+1;j<n;j++){if((*compare)(a[j],a[k]))k=j;}if(k!=i) swap(&a[k],&a[i]);}} int ascendingsort(int a,int b){return a<b;}int descendingsort(int a,int b){return a>b;}void swap(int *x,int *y){int temp;temp=*x;*x=*y;*y=temp;}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FJntlZWx-1686370230305)(null)]
过于int (*compare)(int a,int b)
圆括号的优先级是最高的,因此这句话可以解释为:
compare-----> * -------> ( ) ------->int
他告诉编译器函数selectionsort()的这个形参compare是一个指针类型,该指针变量可以指向一个两个整形形参、返回值为整形的函数。即compare是一个函数指针。这里,*compare两侧的圆括号必不可少,他将 * 和compare先结合,表示compare是一个指针变量。然后,(*compare)与其后的()结合,表示该指针变量可以指向一个函数。
如果少去了compare两边的括号,就会变成
compare-----》()-------》 * ---------》 int
因此,它声明的不是一个函数指针,而是一个两个整型形参并返回整形指针的函数。