學習了數組之后,我們知道數組是在內存中申請一塊內存空間;數組名代表內存塊的首地址,通過數組名可以訪問內存塊中的數據。
在相城等地區(qū),都構建了全面的區(qū)域性戰(zhàn)略布局,加強發(fā)展的系統(tǒng)性、市場前瞻性、產品創(chuàng)新能力,以專注、極致的服務理念,為客戶提供做網站、成都網站設計 網站設計制作按需開發(fā),公司網站建設,企業(yè)網站建設,品牌網站設計,成都營銷網站建設,外貿網站制作,相城網站建設費用合理。
那么,對于函數,它也是存放在內存塊中的一段數據。例如下面的函數:
void func( int a )
{
printf( "in func, a = %d " , a );
}
此時,定義了一個函數名是func的函數。可以如下調用該函數:
func(100);
此時,就進入了func函數的函數體中執(zhí)行。可以看到, 函數名如同數組名一樣,代表函數所在內存塊的首地址 。通過數組名可以訪問數組在內存塊中申請的內存,同理,通過函數名,可以訪問函數在內存中存放的數據。
所以,函數名就代表了該函數在內存塊中存放的首地址。那么,函數名是表示一個地址,就可以把這個地址值存放在某一個指針變量中,然后,通過指針變量訪問函數名指向的函數。
在C語言中,提供了函數指針變量,可以存放函數名表示的地址。函數指針變量的定義格式如下:
返回數據類型 (*函數指針變量名)(形參列表)
對比函數的定義如下:
返回數據類型 函數名(形參列表)
可以看到,函數指針變量的定義,與函數的定義格式基本一樣,唯一的區(qū)別是把“函數名”轉換為“*(函數指針變量名)”;總結如下:
(1) 使用指針降級運算符*來定義,表示這個是一個指針。
(2) 指針降級運算符*不可以靠近返回數據類型,例如“返回數據類*”就表示函數的返回類型是一個指針。那么,為了讓指針降級運算符*能夠修飾函數指針變量,就用小括號()把指針降級運算符*與函數指針變量名包含起來。
定義了函數指針變量之后,可以把函數名賦給函數指針變量。因為,函數名就表示函數在內存塊中的首地址,所以,可以直接把一個地址賦值給函數指針變量。格式如下:
函數指針變量 = 函數名;
最終,可以通過函數指針變量調用函數,調用的格式與通過函數名調用完全一樣,通過函數指針變量調用函數,有如下形式:
方法1:函數指針變量(實參列表);
方法2:(*函數指針變量名)(實參列表);
很多情況下,我們更傾向于使用第一種形式,因為,它的使用方式更接近于通過函數名調用函數。
下面根據程序測試例子來看看怎么樣應用函數指針變量。
深入學習,可以交個朋友,工人人人號:韋凱峰linux編程學堂
程序運行結果如下:
深入學習,可以交個朋友,工人人人號:韋凱峰linux編程學堂
可以看到,我們定義了func函數和函數指針變量pfunc,然后,把函數名func設置給函數指針變量pfunc,最終,通過函數指針變量pfunc調用函數。
因為函數指針變量存放的就是函數名表示的地址,所以,函數指針變量與函數名一樣,可以直接通過函數指針變量調用函數。
注意:我們在學習指針的時候,可以把一個int類型的變量地址賦值給int類型的指針;但是,不可以把int類型變量的地址,賦值給double類型的指針。這就是變量數據類型不一致的問題。
同樣的道理,定義函數的時候,函數的返回數據類型和形參列表都不一樣,所以,函數指針變量能夠接收的函數名,它們定義的 函數返回數據類型和形參列表必須一致 ,此時,就如同變量與指針變量類型一致時,才可以把變量的地址賦值給指針變量一樣。
如下是一個測試例子:
深入學習,可以交個朋友,工人人人號:韋凱峰linux編程學堂
程序編譯結果如下:
深入學習,可以交個朋友,工人人人號:韋凱峰linux編程學堂
可以看到,我們把func函數的形參列表修改為double,但是,函數指針變量pfunc定義的形參列表為int類型,此時,函數和函數指針變量的定義格式不一致,所以,不可以把函數名表示的地址設置給函數指針變量。我們來總結一下:
(1) 在Ubuntu系統(tǒng)中,使用GCC編譯,提示warning警告,但是,程序可以編譯通過,可以運行。
(2) 在Windows系統(tǒng)中,使用Visual Studio工具,無法編譯該代碼,提示類型不一致。
(3) 從代碼的嚴謹方面來說,是不可以設置類型不一致的數據。所以,我們應該編寫嚴謹的代碼,函數定義的類型,與函數指針類型不一致的時候,不可以把函數名,賦值給函數指針變量。
函數指針變量的定義很重要,我們需要牢記和理解它們使用的方式。下面多舉幾個例子說明函數指針變量的定義和使用。
int func( void );
int (*pfunc)( void );
pfunc = func;
此時,定義func函數,它的返回值類型是int類型,形參列表是void,那么,定義pfunc函數指針變量的時候,它的返回值類型與形參列表都必須與func一樣。
char * func1( int x, int y, int x);
char * (*pfunc1)( int , int , int );
pfunc1 = func1;
char * (*pfunc1)( int x, int y, int x);
我們再總結一下:
(1) 函數名表示函數在內存塊中的首地址,可以直接把函數名賦值給函數指針變量;
(2) 定義函數指針變量的時候,函數返回數據類型和形參列表必須與要指向函數的定義一致;
在最上面加一句這樣的定義
typedef void*(*pFn)();
pFn可以這樣理解:首先pFn是一個指針,指針指向一個函數(或者說pFn是一個函數指針),此函數返回一個無類型的指針。最終定義的變量及函數都是指針罷了,不過是指針的類型不同。所以在編譯時會有警告,說指針類型不匹配。但對于程序來講,都是可以在特定的上下文中使用的。
運行結果是
t1,t2交替出現。
其實void也可以換為其它的類型如int, double等
又想到一個很好的辦法:
這次編譯不會有警告,運行也不會出錯。
示例代碼如下所示
#include stdio.h
long t1();
long t2();
int main()
{
long(*fn)()= (long (*)()) t1 ;
while(1){
fn = (long (*)()) fn();
}
}
long t1()
{
printf("t1\n");
return (long)t2 ;
}
long t2()
{
printf("t2\n");
return (long)t1 ;
}
語言中,指針是一種類型,被稱為“指針類型”。指針類型描述的是一個地址,這個地址指向內存中另外一個對象的位置。簡單地說,指針表示的是它所指向對象的地址。
1、比較point,*point,point三者的區(qū)別
對于int * point;
point:是指針變量,其內容是地址量。
*point:是指針變量的目標變量,即指針指向的那個變量,其內容是數據。
point:是指指針變量本身所占據的存儲地址。
2、指針與數組
用指針和數組名在訪問內存中的數據時,他們的表現形式是等價的,因為他們都是地址量。
數組名表示整個數組的首地址,可以看作是固定地址的指針,不能被賦值。
數組名無須賦初值,而指針在使用前必須賦初值。
3、字符指針和字符串
字符串是一個字符數組,字符串以‘\0’結束。printf函數的%s格式輸出字符時,是從給定的地址開始,到遇上第一個‘\0’字符時結束。
對字符指針初始化,是將字符串的首地址賦給指針。
4、指針型函數
所謂指針型函數,即返回值是指針(地址)的函數。
5、多級指針
指向指針的指針(**p)就是二級指針,指向指針的指針的指針(***p)是3級指針。
多級指針類似于間接尋址。
6、指向函數的指針
C語言中的函數名表示函數的首地址,即函數執(zhí)行的人口地址。
定義形式:[存儲類型][數據類型標示符](*指向函數的指針變量名)();
例子: int(*fun)();//指向函數的指針 , int * fun(); //指針型函數,注意(* fun)括號不能少
7、動態(tài)指針
當需要一大片內存的時候,最好使用動態(tài)分配。
使用malloc函數:void * malloc(size_t size)。
例子:
int * pn=malloc(10*sizeof(int));
double *pd=malloc(10*sizeof(double));
void*?f(int);?//一個指針函數f
void*(*p)(int)?=?f;?//一個指向f的函數指針p
根據你的定義,使用LinkList定義的變量是指針變量,而加上*即LinkList *C表示的是指向指針的指針,表示二級指針變量。
你的合并函數是一個沒有返回值的函數,所以你在函數體內更改C要達到更改實參的效果,你必須傳入實參的地址。
如果是一級指針,C接收實參指向的對象地址,如果此時在函數體內對C進行賦值,只是改變了函數體內C的指向,實參還是指向原來的地址。函數內是改變不了實參C本身的指向,只有傳入實參C變量本身的地址,那么形參就要定義指向指針的變量來接收實參。
以上是一種方法,另外一種方法就是通過函數返回值,返回新合并的鏈表的頭。那函數類型就可以改為:
LinkList MergeList(LinkList a, LinkList b)。
這可以多練習好好理解一下。
/*
函數指針,關鍵是后面兩個字“指針”,顧名思義,是一個指向函數的指針
原理:函數在創(chuàng)建好了后,函數的代碼會在內存中占有個位置,這時我們創(chuàng)造一個指針來指向這個地址,這個指針就叫函數指針
函數指針不可以移動,想要移動指針的位置來指向函數的下一個指令的想法是錯誤的
函數指針的要求,
1,首先這個指針,要和函數的返回類型一樣
2,指針的*和名字,要用小括號括起來//不括起來就是指針函數了,意思就變成,函數返回一個指針了
3,最右邊的小括號里形參位置的類型,形參的個數,也要和函數定義時的形參一致,只要類型,不要形參名即可,
但是加上形參名也可以,沒毛病,看上去也更清晰
*/
#include
void swapchar(char *a, char *b)
{
char t;
t = *a;
*a = *b;
*b = t;
}
void swapchar2(char * a2, char * b2)
{
printf("this is swapchar2");
}
int main(void)
{
char chf = 'a', chg = 'j';
void(*p)(char * a, char * b);//定義函數指針、形參名字a、b可有可無,但有的話看上去更清晰,只要函數定義的類型、參數類型、以及參數個數,與這個指針一致,那么這個指針p,就可以指向它
p = swapchar;//p指針接管swapchar函數,只要給函數名字,就可以給過去了
printf("chf=%c,chg=%c ", chf, chg);
p(chf, chg);
printf("chf=%c,chg=%c ", chf, chg);
p = swapchar2;//這里把swapchar2函數的地址,給了p,這時p從swapchar地址,轉移到了swapchar2這里。
p(chf,chg);
return 0;
}
名稱欄目:c語言函數定義指針 c語言中指針的定義
地址分享:http://www.chinadenli.net/article38/doocdsp.html
成都網站建設公司_創(chuàng)新互聯,為您提供網站內鏈、微信小程序、手機網站建設、域名注冊、網站策劃、企業(yè)網站制作
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯