亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入學(xué)習(xí)C語言中的函數(shù)指針和左右法則

 更新時間:2015年08月10日 09:21:47   作者:zinss26914  
這篇文章主要介紹了深入學(xué)習(xí)C語言中的函數(shù)指針和左右法則,左右法則是一種常用的C指針聲明,需要的朋友可以參考下

通常的函數(shù)調(diào)用
    一個通常的函數(shù)調(diào)用的例子:

//自行包含頭文件
void MyFun(int x); //此處的申明也可寫成:void MyFun( int );

int main(int argc, char* argv[])
{
  MyFun(10); //這里是調(diào)用MyFun(10);函數(shù)

   return 0;
}

void MyFun(int x) //這里定義一個MyFun函數(shù)
{
  printf(“%d\n”,x);
}

    這個MyFun函數(shù)是一個無返回值的函數(shù),它并不完成什么事情。這種調(diào)用函數(shù)的格式你應(yīng)該是很熟悉的吧!看主函數(shù)中調(diào)用MyFun函數(shù)的書寫格式:
MyFun(10);
    我們一開始只是從功能上或者說從數(shù)學(xué)意義上理解MyFun這個函數(shù),知道MyFun函數(shù)名代表的是一個功能(或是說一段代碼)。
    直到——
    學(xué)習(xí)到函數(shù)指針概念時。我才不得不在思考:函數(shù)名到底又是什么東西呢?
    (不要以為這是沒有什么意義的事噢!呵呵,繼續(xù)往下看你就知道了。)

函數(shù)指針變量的申明
    就象某一數(shù)據(jù)變量的內(nèi)存地址可以存儲在相應(yīng)的指針變量中一樣,函數(shù)的首地址也以存儲在某個函數(shù)指針變量里的。這樣,我就可以通過這個函數(shù)指針變量來調(diào)用所指向的函數(shù)了。
    在C系列語言中,任何一個變量,總是要先申明,之后才能使用的。那么,函數(shù)指針變量也應(yīng)該要先申明吧?那又是如何來申明呢?以上面的例子為例,我來申明一個可以指向MyFun函數(shù)的函數(shù)指針變量FunP。下面就是申明FunP變量的方法:
void (*FunP)(int) ;   //也可寫成void (*FunP)(int x);
    你看,整個函數(shù)指針變量的申明格式如同函數(shù)MyFun的申明處一樣,只不過——我們把MyFun改成(*FunP)而已,這樣就有了一個能指向MyFun函數(shù)的指針FunP了。(當(dāng)然,這個FunP指針變量也可以指向所有其它具有相同參數(shù)及返回值的函數(shù)了。)

通過函數(shù)指針變量調(diào)用函數(shù)
    有了FunP指針變量后,我們就可以對它賦值指向MyFun,然后通過FunP來調(diào)用MyFun函數(shù)了??次胰绾瓮ㄟ^FunP指針變量來調(diào)用MyFun函數(shù)的:

//自行包含頭文件
void MyFun(int x); //這個申明也可寫成:void MyFun( int );
void (*FunP)(int ); //也可申明成void(*FunP)(int x),但習(xí)慣上一般不這樣。

int main(int argc, char* argv[])
{
  MyFun(10); //這是直接調(diào)用MyFun函數(shù)
  FunP=&MyFun; //將MyFun函數(shù)的地址賦給FunP變量
  (*FunP)(20); //這是通過函數(shù)指針變量FunP來調(diào)用MyFun函數(shù)的。
}

void MyFun(int x) //這里定義一個MyFun函數(shù)
{
  printf(“%d\n”,x);
}

    請看黑體字部分的代碼及注釋。
    運(yùn)行看看。嗯,不錯,程序運(yùn)行得很好。
    哦,我的感覺是:MyFun與FunP的類型關(guān)系類似于int 與int *的關(guān)系。函數(shù)MyFun好像是一個如int的變量(或常量),而FunP則像一個如int *一樣的指針變量。

int i,*pi;
pi=&i;  //與FunP=&MyFun比較。

    (你的感覺呢?)
    呵呵,其實(shí)不然——

調(diào)用函數(shù)的其它書寫格式
函數(shù)指針也可如下使用,來完成同樣的事情:

//自行包含頭文件
void MyFun(int x); 
void (*FunP)(int ); //申明一個用以指向同樣參數(shù),返回值函數(shù)的指針變量。

int main(int argc, char* argv[])
{
  MyFun(10); //這里是調(diào)用MyFun(10);函數(shù)
  FunP=MyFun; //將MyFun函數(shù)的地址賦給FunP變量
  FunP(20); //這是通過函數(shù)指針變量來調(diào)用MyFun函數(shù)的。

   return 0;
}

void MyFun(int x) //這里定義一個MyFun函數(shù)
{
  printf(“%d\n”,x);
}

我改了黑體字部分(請自行與之前的代碼比較一下)。
運(yùn)行試試,??!一樣地成功。
咦?

FunP=MyFun;

可以這樣將MyFun值同賦值給FunP,難道MyFun與FunP是同一數(shù)據(jù)類型(即如同的int 與int的關(guān)系),而不是如同int 與int*的關(guān)系了?(有沒有一點(diǎn)點(diǎn)的糊涂了?)
看來與之前的代碼有點(diǎn)矛盾了,是吧!所以我說嘛!
請容許我暫不給你解釋,繼續(xù)看以下幾種情況(這些可都是可以正確運(yùn)行的代碼喲?。?br /> 代碼之三:

int main(int argc, char* argv[])
{
  MyFun(10); //這里是調(diào)用MyFun(10);函數(shù)
  FunP=&MyFun; //將MyFun函數(shù)的地址賦給FunP變量
  FunP(20); //這是通過函數(shù)指針變量來調(diào)用MyFun函數(shù)的。

   return 0;
}

代碼之四:

int main(int argc, char* argv[])
{
  MyFun(10); //這里是調(diào)用MyFun(10);函數(shù)
  FunP=MyFun; //將MyFun函數(shù)的地址賦給FunP變量
  (*FunP)(20); //這是通過函數(shù)指針變量來調(diào)用MyFun函數(shù)的。

   return 0;
}

真的是可以這樣的噢!
(哇!真是要暈倒了?。?br /> 還有吶!看——

int main(int argc, char* argv[])
{
  (*MyFun)(10); //看,函數(shù)名MyFun也可以有這樣的調(diào)用格式

   return 0;
}

你也許第一次見到吧:函數(shù)名調(diào)用也可以是這樣寫的啊?。ㄖ徊贿^我們平常沒有這樣書寫罷了。)
那么,這些又說明了什么呢?
呵呵!假使我是“福爾摩斯”,依據(jù)以往的知識和經(jīng)驗(yàn)來推理本篇的“新發(fā)現(xiàn)”,必定會由此分析并推斷出以下的結(jié)論:
1. 其實(shí),MyFun的函數(shù)名與FunP函數(shù)指針都是一樣的,即都是函數(shù)指針。MyFun函數(shù)名是一個函數(shù)指針常量,而FunP是一個函數(shù)數(shù)指針變量,這是它們的關(guān)系。
2. 但函數(shù)名調(diào)用如果都得如(*MyFun)(10);這樣,那書寫與讀起來都是不方便和不習(xí)慣的。所以C語言的設(shè)計(jì)者們才會設(shè)計(jì)成又可允許MyFun(10);這種形式地調(diào)用(這樣方便多了并與數(shù)學(xué)中的函數(shù)形式一樣,不是嗎?)。
3. 為統(tǒng)一起見,F(xiàn)unP函數(shù)指針變量也可以FunP(10)的形式來調(diào)用。
4. 賦值時,即可FunP=&MyFun形式,也可FunP=MyFun。
上述代碼的寫法,隨便你愛怎么著!
請這樣理解吧!這可是有助于你對函數(shù)指針的應(yīng)用嘍!
最后——
補(bǔ)充說明一點(diǎn):在函數(shù)的申明處:

void MyFun(int );  //不能寫成void (*MyFun)(int )。
void (*FunP)(int );  //不能寫成void FunP(int )。

(請看注釋)這一點(diǎn)是要注意的。

定義某一函數(shù)的指針類型:
就像自定義數(shù)據(jù)類型一樣,我們也可以先定義一個函數(shù)指針類型,然后再用這個類型來申明函數(shù)指針變量。
我先給你一個自定義數(shù)據(jù)類型的例子。

typedef int* PINT; //為int* 類型定義了一個PINT的別名
int main()
{
 int x;
 PINT px=&x; //與int * px=&x;是等價(jià)的。PINT類型其實(shí)就是int * 類型
 *px=10; //px就是int*類型的變量 
 return 0;
}

根據(jù)注釋,應(yīng)該不難看懂吧?。m然你可能很少這樣定義使用,但以后學(xué)習(xí)Win32編程時會經(jīng)常見到的。)
下面我們來看一下函數(shù)指針類型的定義及使用:(請與上對照?。?br />

//自行包含頭文件
void MyFun(int x); //此處的申明也可寫成:void MyFun( int );
typedef void (*FunType)(int ); //這樣只是定義一個函數(shù)指針類型
FunType FunP; //然后用FunType類型來申明全局FunP變量

int main(int argc, char* argv[])
{
//FunType FunP; //函數(shù)指針變量當(dāng)然也是可以是局部的 ,那就請?jiān)谶@里申明了。 
  MyFun(10); 
  FunP=&MyFun; 
  (*FunP)(20); 

   return 0;
}

void MyFun(int x) 
{
  printf(“%d\n”,x);
}

看黑體部分:
首先,在void (*FunType)(int ); 前加了一個typedef 。這樣只是定義一個名為FunType函數(shù)指針類型,而不是一個FunType變量。
然后,F(xiàn)unType FunP;  這句就如PINT px;一樣地申明一個FunP變量。
其它相同。整個程序完成了相同的事。
這樣做法的好處是:
有了FunType類型后,我們就可以同樣地、很方便地用FunType類型來申明多個同類型的函數(shù)指針變量了。如下:

FunType FunP2;
FunType FunP3;
//……

函數(shù)指針作為某個函數(shù)的參數(shù)
既然函數(shù)指針變量是一個變量,當(dāng)然也可以作為某個函數(shù)的參數(shù)來使用的。所以,你還應(yīng)知道函數(shù)指針是如何作為某個函數(shù)的參數(shù)來傳遞使用的。
給你一個實(shí)例:
要求:我要設(shè)計(jì)一個CallMyFun函數(shù),這個函數(shù)可以通過參數(shù)中的函數(shù)指針值不同來分別調(diào)用MyFun1、MyFun2、MyFun3這三個函數(shù)(注:這三個函數(shù)的定義格式應(yīng)相同)。
實(shí)現(xiàn):代碼如下:

//自行包含頭文件 
void MyFun1(int x); 
void MyFun2(int x); 
void MyFun3(int x); 
typedef void (*FunType)(int ); //②. 定義一個函數(shù)指針類型FunType,與①函數(shù)類型一至
void CallMyFun(FunType fp,int x);

int main(int argc, char* argv[])
{
  CallMyFun(MyFun1,10); //⑤. 通過CallMyFun函數(shù)分別調(diào)用三個不同的函數(shù)
  CallMyFun(MyFun2,20); 
  CallMyFun(MyFun3,30); 
}
void CallMyFun(FunType fp,int x) //③. 參數(shù)fp的類型是FunType。
{
 fp(x);//④. 通過fp的指針執(zhí)行傳遞進(jìn)來的函數(shù),注意fp所指的函數(shù)是有一個參數(shù)的
}
void MyFun1(int x) // ①. 這是個有一個參數(shù)的函數(shù),以下兩個函數(shù)也相同
{
  printf(“函數(shù)MyFun1中輸出:%d\n”,x);
}
void MyFun2(int x) 
{
  printf(“函數(shù)MyFun2中輸出:%d\n”,x);
}
void MyFun3(int x) 
{
  printf(“函數(shù)MyFun3中輸出:%d\n”,x);
}

輸出結(jié)果:略

分析:(看我寫的注釋。你可按我注釋的①②③④⑤順序自行分析。)
 
以上部分為轉(zhuǎn)載網(wǎng)友所述。原文地址為:http://blog.pfan.cn/whyhappy/6030.html
 
 
地址跳轉(zhuǎn)
void(*reset)(void)= (void(*)(void))0。
  void(*reset)(void)就是函數(shù)指針定義,(void(*)(void))0是強(qiáng)制類型轉(zhuǎn)換操作,將數(shù)值“0”強(qiáng)制轉(zhuǎn)換為函數(shù)指針地址“0”。
  通過調(diào)用reset()函數(shù),程序就會跳轉(zhuǎn)到程序執(zhí)行的“0”地址處重新執(zhí)行。在一些其他高級單片機(jī)Bootloader中,如NBoot、UBoot、EBoot,經(jīng)常通過這些Bootloader進(jìn)行下載程序,然后通過函數(shù)指針跳轉(zhuǎn)到要執(zhí)行程序的地址處。
1   void (*theUboot)(void);
    。。。。
    theUboot = (void (*)(void))(0x30700000);
    theUboot();
    。。。。。
2   (*(void (*)(void))(0x30700000))();
強(qiáng)制類型轉(zhuǎn)換,將一個絕對地址轉(zhuǎn)換為一個函數(shù)指針,并調(diào)用這個函數(shù)以跳轉(zhuǎn)到前面提到的絕對地址.
翻譯成匯編就是:
mov r0,0x30700000;
mov pc,r0
對于(*(void (*)(void))(0x30700000))();
可以這樣理解
首先(void( * )(void) )是一個強(qiáng)制類型轉(zhuǎn)換符,他將后面的0x30700000這個無符號整數(shù)強(qiáng)制轉(zhuǎn)化為一個函數(shù)指針,該函數(shù)指針?biāo)赶虻暮瘮?shù)入口參數(shù)為 void,返回值也是void 。 如果到這步你看懂了,那么設(shè)(void (*)(void))(0x30700000)為 fp; 那么上面的表達(dá)式就可以簡化為 (*fp)();   OK,這下就清楚了吧,我們將上面轉(zhuǎn)化好的函數(shù)指針進(jìn)行引用(也就是調(diào)用函數(shù)指針指向的函數(shù))。
 

右左法則

c語言有復(fù)雜的指針聲明,都是由各種聲明嵌套構(gòu)成的。各大公司的筆試題里經(jīng)常會出現(xiàn)理解復(fù)雜指針聲明,右左法則是一個著名又常用的方法。
The right-left rule : start reading the declaration from the innermost parentheses, go rigtht, and then go left. when you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.

右左規(guī)則:首先從最里面的括號看起,然后往右看,再往左看。每當(dāng)遇到圓括號時,就應(yīng)該掉轉(zhuǎn)閱讀方向。一旦解析完圓括號里面所有的東西,就跳出圓括號。重復(fù)這個過程直到整個聲明解析完畢。

原文作者對這里進(jìn)行了修正:應(yīng)該是從未定義的標(biāo)識符開始閱讀,而不是從括號讀起,之所以是未定義的標(biāo)識符,是因?yàn)橐粋€聲明里可能有多個標(biāo)識符,但未定義的標(biāo)識符只會有一個

示例

  int (*func) (int *p); 


首先找到未定義標(biāo)識符,就是func,它的外面有一對圓括號,而且左邊是一個*,這說明func是一個指針。然后跳出括號,看右邊,也是一個括號,這說明(*func)是一個函數(shù),而func是一個指向這類函數(shù)的指針,也就是一個函數(shù)指針。這類函數(shù)具有int*類型的參數(shù),返回值類型是int

  int (*func)(int *p, int (*f)(int *)); 


func被一對括號包含,且左邊有一個*號,說明func是一個指針,然后跳出這個圓括號,先看右邊,也是一個圓括號,說明func是一個函數(shù)指針。這類函數(shù)具有int *和 int (*)(int *)這樣的形參,返回值是int。對于int (*f)(int *)的形參,分析方法跟func是一致的

  int (*func[5])(int *p); 


func右邊是一個[]運(yùn)算符,說明func是一個具有5個元素的數(shù)組,func的左邊有一個*,說明func的元素是指針,要注意這里的*不是修飾func的,而是修飾func[5]的,原因是[]運(yùn)算符的優(yōu)先級比*高,func先跟[]結(jié)合,因此*修飾的是func[5].跳出這個括號,看右邊,也是一對圓括號,說明func數(shù)組的元素是函數(shù)類型的指針,它指向的函數(shù)具有int*類型的形參,返回值類型是int

  int (*(*func)[5])(int *p); 


func被一對圓括號包圍,左邊又有一個*,那么func是一個指針,跳出括號,右邊是一個[]運(yùn)算符號,說明func是一個指向數(shù)組的指針,現(xiàn)在往左看,左邊有一個*號,說明這個數(shù)組的元素是指針,再跳出括號,向右看,右邊又有一個括號,說明這個數(shù)組的元素是指向函數(shù)的指針??偨Y(jié)一下就是:func是一個指向數(shù)組的指針,這個數(shù)組的元素是函數(shù)指針,這些指針具有int *形參,返回值為int類型的函數(shù)

  int (*(*func)(int *p))[5]; 


func是一個函數(shù)指針,這類函數(shù)具有int *類型的形參,返回值是指向數(shù)組的指針,所指向的是具有5個int類型元素的數(shù)組。

相關(guān)文章

最新評論