1.如果去掉static的話,return a[n]返回的就是一個局部變量的地址,那么它的值可能被修改。
創(chuàng)新互聯(lián)建站服務項目包括茂南網(wǎng)站建設、茂南網(wǎng)站制作、茂南網(wǎng)頁制作以及茂南網(wǎng)絡營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關系等,向廣大中小型企業(yè)、政府機構等提供互聯(lián)網(wǎng)行業(yè)的解決方案,茂南網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務的客戶以成都為中心已經(jīng)輻射到茂南省份的部分城市,未來相信會繼續(xù)擴大服務區(qū)域并繼續(xù)獲得客戶的支持與信任!
2.字符串就是一個指針,也就是一個地址
char *str="i love you";
printf("%s\n", str);
printf("%c\n", *str);
str表示字符串,是指針(地址)
*str表示字符串的第一個字符,也就是'i'
簡言之,函數(shù)指針就是指向函數(shù)(函數(shù)入口地址)的指針,指針函數(shù)就是返回數(shù)據(jù)類型為指針的函數(shù)
函數(shù)指針:void (*fun)(); 指針函數(shù):type *fun();其中type為數(shù)據(jù)類型,比如char,int等等
學習了數(shù)組之后,我們知道數(shù)組是在內存中申請一塊內存空間;數(shù)組名代表內存塊的首地址,通過數(shù)組名可以訪問內存塊中的數(shù)據(jù)。
那么,對于函數(shù),它也是存放在內存塊中的一段數(shù)據(jù)。例如下面的函數(shù):
void func( int a )
{
printf( "in func, a = %d " , a );
}
此時,定義了一個函數(shù)名是func的函數(shù)??梢匀缦抡{用該函數(shù):
func(100);
此時,就進入了func函數(shù)的函數(shù)體中執(zhí)行。可以看到, 函數(shù)名如同數(shù)組名一樣,代表函數(shù)所在內存塊的首地址 。通過數(shù)組名可以訪問數(shù)組在內存塊中申請的內存,同理,通過函數(shù)名,可以訪問函數(shù)在內存中存放的數(shù)據(jù)。
所以,函數(shù)名就代表了該函數(shù)在內存塊中存放的首地址。那么,函數(shù)名是表示一個地址,就可以把這個地址值存放在某一個指針變量中,然后,通過指針變量訪問函數(shù)名指向的函數(shù)。
在C語言中,提供了函數(shù)指針變量,可以存放函數(shù)名表示的地址。函數(shù)指針變量的定義格式如下:
返回數(shù)據(jù)類型 (*函數(shù)指針變量名)(形參列表)
對比函數(shù)的定義如下:
返回數(shù)據(jù)類型 函數(shù)名(形參列表)
可以看到,函數(shù)指針變量的定義,與函數(shù)的定義格式基本一樣,唯一的區(qū)別是把“函數(shù)名”轉換為“*(函數(shù)指針變量名)”;總結如下:
(1) 使用指針降級運算符*來定義,表示這個是一個指針。
(2) 指針降級運算符*不可以靠近返回數(shù)據(jù)類型,例如“返回數(shù)據(jù)類*”就表示函數(shù)的返回類型是一個指針。那么,為了讓指針降級運算符*能夠修飾函數(shù)指針變量,就用小括號()把指針降級運算符*與函數(shù)指針變量名包含起來。
定義了函數(shù)指針變量之后,可以把函數(shù)名賦給函數(shù)指針變量。因為,函數(shù)名就表示函數(shù)在內存塊中的首地址,所以,可以直接把一個地址賦值給函數(shù)指針變量。格式如下:
函數(shù)指針變量 = 函數(shù)名;
最終,可以通過函數(shù)指針變量調用函數(shù),調用的格式與通過函數(shù)名調用完全一樣,通過函數(shù)指針變量調用函數(shù),有如下形式:
方法1:函數(shù)指針變量(實參列表);
方法2:(*函數(shù)指針變量名)(實參列表);
很多情況下,我們更傾向于使用第一種形式,因為,它的使用方式更接近于通過函數(shù)名調用函數(shù)。
下面根據(jù)程序測試例子來看看怎么樣應用函數(shù)指針變量。
深入學習,可以交個朋友,工人人人號:韋凱峰linux編程學堂
程序運行結果如下:
深入學習,可以交個朋友,工人人人號:韋凱峰linux編程學堂
可以看到,我們定義了func函數(shù)和函數(shù)指針變量pfunc,然后,把函數(shù)名func設置給函數(shù)指針變量pfunc,最終,通過函數(shù)指針變量pfunc調用函數(shù)。
因為函數(shù)指針變量存放的就是函數(shù)名表示的地址,所以,函數(shù)指針變量與函數(shù)名一樣,可以直接通過函數(shù)指針變量調用函數(shù)。
注意:我們在學習指針的時候,可以把一個int類型的變量地址賦值給int類型的指針;但是,不可以把int類型變量的地址,賦值給double類型的指針。這就是變量數(shù)據(jù)類型不一致的問題。
同樣的道理,定義函數(shù)的時候,函數(shù)的返回數(shù)據(jù)類型和形參列表都不一樣,所以,函數(shù)指針變量能夠接收的函數(shù)名,它們定義的 函數(shù)返回數(shù)據(jù)類型和形參列表必須一致 ,此時,就如同變量與指針變量類型一致時,才可以把變量的地址賦值給指針變量一樣。
如下是一個測試例子:
深入學習,可以交個朋友,工人人人號:韋凱峰linux編程學堂
程序編譯結果如下:
深入學習,可以交個朋友,工人人人號:韋凱峰linux編程學堂
可以看到,我們把func函數(shù)的形參列表修改為double,但是,函數(shù)指針變量pfunc定義的形參列表為int類型,此時,函數(shù)和函數(shù)指針變量的定義格式不一致,所以,不可以把函數(shù)名表示的地址設置給函數(shù)指針變量。我們來總結一下:
(1) 在Ubuntu系統(tǒng)中,使用GCC編譯,提示warning警告,但是,程序可以編譯通過,可以運行。
(2) 在Windows系統(tǒng)中,使用Visual Studio工具,無法編譯該代碼,提示類型不一致。
(3) 從代碼的嚴謹方面來說,是不可以設置類型不一致的數(shù)據(jù)。所以,我們應該編寫嚴謹?shù)拇a,函數(shù)定義的類型,與函數(shù)指針類型不一致的時候,不可以把函數(shù)名,賦值給函數(shù)指針變量。
函數(shù)指針變量的定義很重要,我們需要牢記和理解它們使用的方式。下面多舉幾個例子說明函數(shù)指針變量的定義和使用。
int func( void );
int (*pfunc)( void );
pfunc = func;
此時,定義func函數(shù),它的返回值類型是int類型,形參列表是void,那么,定義pfunc函數(shù)指針變量的時候,它的返回值類型與形參列表都必須與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) 函數(shù)名表示函數(shù)在內存塊中的首地址,可以直接把函數(shù)名賦值給函數(shù)指針變量;
(2) 定義函數(shù)指針變量的時候,函數(shù)返回數(shù)據(jù)類型和形參列表必須與要指向函數(shù)的定義一致;
01
指針函數(shù)通常是指函數(shù)返回值是指針的一類函數(shù),如圖所示。
02
函數(shù)指針是指指向某個具體函數(shù)的指針變量,在程序設計時可以用來調用某個特定函數(shù)或者做某個函數(shù)的參數(shù)。其形式一般如圖:
03
指針函數(shù)與函數(shù)指針本質上的區(qū)別是,指針函數(shù)是一個帶指針的函數(shù),總的來說還是一個函數(shù),如圖就是一個帶*name指針的函數(shù)
04
函數(shù)指針是指向函數(shù)的指針變量,本質上還是一個指針,其格式如下,可以看到和指針函數(shù)的格式非常像,所以一定要用心留意。
如果在程序中定義了一個函數(shù),那么在編譯時系統(tǒng)就會為這個函數(shù)代碼分配一段存儲空間,這段存儲空間的首地址稱為這個函數(shù)的地址。而且函數(shù)名表示的就是這個地址。既然是地址我們就可以定義一個指針變量來存放,這個指針變量就叫作函數(shù)指針變量,簡稱函數(shù)指針。
那么這個指針變量怎么定義呢?雖然同樣是指向一個地址,但指向函數(shù)的指針變量同我們之前講的指向變量的指針變量的定義方式是不同的。例如:
int(*p)(int, int);
這個語句就定義了一個指向函數(shù)的指針變量 p。首先它是一個指針變量,所以要有一個“*”,即(*p);其次前面的 int 表示這個指針變量可以指向返回值類型為 int 型的函數(shù);后面括號中的兩個 int 表示這個指針變量可以指向有兩個參數(shù)且都是 int 型的函數(shù)。所以合起來這個語句的意思就是:定義了一個指針變量 p,該指針變量可以指向返回值類型為 int 型,且有兩個整型參數(shù)的函數(shù)。p 的類型為 int(*)(int,int)。
所以函數(shù)指針的定義方式為:
函數(shù)返回值類型 (* 指針變量名) (函數(shù)參數(shù)列表);
“函數(shù)返回值類型”表示該指針變量可以指向具有什么返回值類型的函數(shù);“函數(shù)參數(shù)列表”表示該指針變量可以指向具有什么參數(shù)列表的函數(shù)。這個參數(shù)列表中只需要寫函數(shù)的參數(shù)類型即可。
我們看到,函數(shù)指針的定義就是將“函數(shù)聲明”中的“函數(shù)名”改成“(*指針變量名)”。但是這里需要注意的是:“(*指針變量名)”兩端的括號不能省略,括號改變了運算符的優(yōu)先級。如果省略了括號,就不是定義函數(shù)指針而是一個函數(shù)聲明了,即聲明了一個返回值類型為指針型的函數(shù)。
那么怎么判斷一個指針變量是指向變量的指針變量還是指向函數(shù)的指針變量呢?首先看變量名前面有沒有“*”,如果有“*”說明是指針變量;其次看變量名的后面有沒有帶有形參類型的圓括號,如果有就是指向函數(shù)的指針變量,即函數(shù)指針,如果沒有就是指向變量的指針變量。
一、
假設函數(shù) void f(int b[])
(1)有定義int a[15],調用f(a),傳遞的是首地址。
(2)如果是調用f(a[1])相當于調用f(a+1),傳遞的還是地址,不是整個數(shù)組。
二、和一中說的一樣,依然是地址。
三、不是,是第二行的地址,不是第二列,C和fortran不一樣,是以行為主序的。例如:
int arr[3][4];
int (*a)[4] = arr;
a指向arr[0],第一行行地址
a+1指向arr[1],第二行行地址