接着指針2,繼續學習指針!
三、數組參數、指針參數(此處不細講,只看兩個問題理解一下就好)
1.當一個函數的參數部分爲一級指針時,函數能接受什麼參數?
1)對應的類型的一級指針 2)對應類型的一維數組名
如:void f(int *a,int n) ; void f(int a[],int n);
2.當函數的參數爲二級指針時,可以接收什麼參數?
1)應用於二維數組: void f(int a[][n],int n,int m) 對於二維數組做參數一定要先指定列數!
2)普通二級指針:void f(int **p){} int a=0; int *p=&a; f(&p);
//此處只能傳入普通二級指針,不能傳入二維數組 原因:由於二維數組要先確定長度問題,因此不能像一維數組那樣直接用
數組名代替一級指針當參數
四、函數指針
1.函數指針:是指向函數的指針變量。因此“函數指針”本身首先應是指針變量,只不過該指針變量指向函數。
函數指針有兩個用途:調用函數和做函數的參數。
2.函數指針的聲明方法爲:
返回值類型 ( * 指針變量名) ([形參列表]);
如:void (*pfun)(int,int); //聲明瞭一個無返回值類型,帶兩個int 類型參數的函數指針。pfun是一個指針
注:區別於指針函數: void *pfun(int,int);//這是一個函數聲明語句 pfun是函數名。
編碼示例:
#include <stdio.h>
int max(int a,int b);
int min(int a,int b);
int main()
{
int a=3,b=8;
int (*pfun)(int,int);//定義函數指針變量
int res;
pfun=max;
res=pfun(a,b);
printf("max:%d\n",res);
pfun=min;
res=pfun(a,b);
printf("min:%d\n",res);
return 0;
}
int max(int a,int b)
{
return a>b? a:b;
}
int min(int a,int b)
{
return a<b? a:b;
}
總結:函數指針能代替相應類型的函數名工作。
補充:函數名就相當於每個函數的入口地址。所以當函數指針指向函數時就相當於找到了打開函數的鑰匙,所以可以用函數指針進入函數。
五、函數指針數組、函數指針數組的指針
1.函數指針數組:存放函數地址的數組。即數組元素全爲函數指針的數組。
如:int (*parr[10])();//該數組可存放10個int類型,無參函數的地址
用途:當要操作多個函數時可考慮用函數指針數組。
示例:轉移表(計數器的實現)
#include <stdio.h>
int add(int x,int y);//加
int sub(int x,int y);//減
int mul(int x,int y);//乘
int div(int x,int y);//除
void show();//菜單顯示
void calc(int input,int x,int y,int (*p[5])(int,int));//計算器!
int main()
{
int x=0,y=0;
int input=1;
//定義一個函數指針數組 p
int (*p[5])(int,int)={0,add,sub,mul,div};//轉移表
calc(input,x,y,p);
return 0;
}
void calc(int input,int x,int y,int (*p[5])(int,int))
{
int result=0;
while(input)
{
show();
printf( "請選擇:" );
scanf( "%d", &input);
if(input==0)
{
printf("停止計算!\n");
break;
}
if(input>=1&&input<5)
{
printf("請輸入操作數:\n");
scanf("%d %d",&x,&y);
result=p[input](x,y);
printf("result=%d\n",result);
}
}
}
void show()
{
printf( "*****************\n" );
printf( "*0:close *\n");
printf( "*1:+ 2:-*\n" );
printf( "*3:* 4:/*\n" );
printf( "*****************\n" );
}
int add(int x,int y)
{
return x+y;
}
int sub(int x,int y)
{
return x-y;
}
int mul(int x,int y)
{
return x*y;
}
int div(int x,int y)
{
return x/y;
}
2.函數指針數組的指針:是一個指針,指向函數指針數組。即數組元素全爲函數指針的數組。
如: void (*(*ppfunArr)[5]) (int,int); //就是定義了一個指針,這個指針指向的是一個長度爲5的數組,而這個數組中存儲都是 無參帶兩個int類型參數的函數的指針(地址)。可能看起來比較繞一些!下面,我將計算器用函數指針數組的指針 來實現一下。其實改動的地方不多。
重點理解:函數指針數組 是數組! 而函數指針數組的指針是指針變量的概念! 類似之前講過的 數組 和數組指針!只是在這 裏類型不僅是平常我們見的基本類型。此處類型可以看成是函數!
#include "stdafx.h"
int add(int x,int y);
int sub(int x,int y);
int mul(int x,int y);
int div(int x,int y);
void show();
//改1:void calc(int input,int x,int y,int (*p[5])(int,int))
void calc(int input,int x,int y,int (*(*pparr)[5])(int,int));//將參數 函數指針 改爲函數指針參數的指針
int main()
{
int x=0,y=0;
int input=1;
//定義一個函數指針數組
int (*p[5])(int,int)={0,add,sub,mul,div};//轉移表
//定義一個函數指針數組指針
int (*(*pparr)[5])(int,int)=&p;
calc(input,x,y,pparr);
return 0;
}
void calc(int input,int x,int y,int(*(*pparr)[5])(int,int))
{
int result=0;
while(input)
{
show();
printf( "請選擇:" );
scanf( "%d", &input);
if(input==0)
{
printf("停止計算!\n");
break;
}
if(input>=1&&input<5)
{
printf("請輸入操作數:\n");
scanf("%d %d",&x,&y);
//改2:result=p[input](x,y);
//將數組名改爲指針變量 p[i](x,y)==(*pparr)[i](x,y)
result=(*pparr)[input](x,y);
printf("result=%d\n",result);
}
}
}
void show()
{
printf( "*****************\n" );
printf( "*0:close *\n");
printf( "*1:+ 2:-*\n" );
printf( "*3:* 4:/*\n" );
printf( "*****************\n" );
}
int add(int x,int y)
{
return x+y;
}
int sub(int x,int y)
{
return x-y;
}
int mul(int x,int y)
{
return x*y;
}
int div(int x,int y)
{
return x/y;
}
總結:在我看來,凡是指向數組的指針,加上*後都可以代替數組名來使用。
不管是之前講過的 數組和數組指針 還是在這裏講的 函數指針數組和函數指針數組的指針其實本質上是一樣的東西,只是由後者的類型變複雜了,所以理解起來會困難一些!
學習完這一次課的內容,給我最深的感悟就是,所有複雜的東西都是從最原始的逐漸添加枝葉變成的大樹。遇到大問題的時候就
將其一步步簡化爲小的問題去逐個理解吸收。只有理解完了小的,最後才能拼成一個完整的知識體系。就如本章內容,其實最根
本的東西還是數組,指針的問題。
補充:
回調函數:
回調函數就是一個通過函數指針調用的函數。如果你把函數的指針(地址)作爲 參數傳遞給另一個函數,當這個指針被用來調用其所指向的函數時,我們就說這 是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條 件發生時由另外的一方調用的,用於對該事件或條件進行響應。
編碼示例: 簡單選擇排序,用回調函數實現
#include <stdio.h>
void sort(int *a,int n,bool (*pFun)(int,int));
void output(int *a,int n);
//升序
bool less(int x,int y);
//降序
bool greater(int x,int y);
int main(int argc, char* argv[])
{
int a[5]={2,1,4,5,3};
output(a,5);
printf("升序:\n");
sort(a,5,less);
output(a,5);
pirntf("降序\n");
sort(a,5,greater);
output(a,5);
return 0;
}
//不用回調函數時:只能單獨進行升序或是降序排列 void sort(int *a,int n);
//用函數指針做參數,實現函數調用
void sort(int *a,int n,bool (*pFun)(int,int))//1.加一個參數,傳遞比較方法
{
int k;int tmp;
for(int i=0;i<n;i++)
{
k=i;
for(int j=i+1;j<n;j++)
{
//if(a[j]>a[k])||if(a[j]<a[k])
if(pFun(a[j],a[k]))//2.調用函數實現比較操作
k=j;
}
if(k!=i)
{
tmp=a[k];a[k]=a[i];a[i]=tmp;
}
}
}
void output(int *a,int n)
{
printf("\n");
for(int i=0;i<n;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
bool less(int x,int y)
{
return x<y;
}
bool greater(int x,int y)
{
return x>y;
}
用了回調函數後就可以將降序和升序的選擇,作爲一個函數指針 的參數傳入排序函數中。
如果感興趣,可以先自己寫好普通的排序,再在自己的代碼上改成與上面類似的回調函數。畢竟看十遍不如自己敲一遍!
以上內容是全由個人對現階段所學知識進行的總結整理,如果有任何問題歡迎指出!謝謝。