1. 程式人生 > >轉 函式指標和指標函式用法和區別

轉 函式指標和指標函式用法和區別

函式指標和指標函式用法和區別

 

前言

函式指標和指標函式,在學習 C 語言的時候遇到這兩個東西簡直頭疼,當然還有更頭疼的,比如什麼函式指標函式、指標函式指標、陣列指標、指標陣列、函式指標陣列等等,描述越長其定義就越複雜,當然理解起來就越難,特別是剛開始學習這門語言的童鞋,估計碰到這些東西就已經要崩潰了,然後好不容易死記硬背下來應付考試或者面試,然後過了幾天發現,又是根本不會用,也不知道該在哪些地方用,這就尷尬了。
今天這裡只講兩個相對簡單的,其實上面說那些太複雜的東西也真的很少用,即便是用了理解起來很麻煩,所以莫不如先深刻理解這兩個比較容易的,並且專案中比較常用到。

正文

先來看看兩者的定義以及說明。

指標函式

定義

指標函式,簡單的來說,就是一個返回指標的函式,其本質是一個函式,而該函式的返回值是一個指標。
宣告格式為:型別識別符號 *函式名(引數表)

這似乎並不難理解,再進一步描述一下。
看看下面這個函式宣告:

int fun(int x,int y);

這種函式應該都很熟悉,其實就是一個函式,然後返回值是一個 int 型別,是一個數值。
接著看下面這個函式宣告:

int *fun(int x,int y);

這和上面那個函式唯一的區別就是在函式名前面多了一個*號,而這個函式就是一個指標函式。其返回值是一個 int 型別的指標,是一個地址。

這樣描述應該很容易理解了,所謂的指標函式也沒什麼特別的,和普通函式對比不過就是其返回了一個指標(即地址值)而已。

指標函式的寫法

int *fun(int x,int y);
int * fun(int x,int y); int* fun(int x,int y);
  • 1
  • 2
  • 3

這個寫法看個人習慣,其實如果*靠近返回值型別的話可能更容易理解其定義。

示例

(由於本人習慣於 Qt 中進行開發,所以這裡為了方便,示例是在 Qt 工程中寫的,其語法是一樣的,只是輸出方式不同)
來看一個非常簡單的示例:

typedef struct _Data{
    int a;
    int b;
}Data;

//指標函式 Data* f(int a,int b){ Data * data = new Data; data->a = a; data->b = b; return data; } int main(int argc, char *argv[]) { QApplication a(argc, argv); //呼叫指標函式 Data * myData = f(4,5); qDebug() << "f(4,5) = " << myData->a << myData->b; return a.exec(); } 

輸出如下:

f(4,5) =  4 5
  • 1

注意:在呼叫指標函式時,需要一個同類型的指標來接收其函式的返回值。
不過也可以將其返回值定義為 void*型別,在呼叫的時候強制轉換返回值為自己想要的型別,如下:

//指標函式
void* f(int a,int b){
    Data * data = new Data; data->a = a; data->b = b; return data; } 呼叫: Data * myData = static_cast<Data*>(f(4,5));

其輸出結果是一樣的,不過不建議這麼使用,因為強制轉換可能會帶來風險。

函式指標

定義

函式指標,其本質是一個指標變數,該指標指向這個函式。總結來說,函式指標就是指向函式的指標。
宣告格式:型別說明符 (*函式名) (引數)
如下:

int (*fun)(int x,int y);

函式指標是需要把一個函式的地址賦值給它,有兩種寫法:

fun = &Function;
fun = Function;

取地址運算子&不是必需的,因為一個函式識別符號就表示了它的地址,如果是函式呼叫,還必須包含一個圓括號括起來的引數表。

呼叫函式指標的方式也有兩種:

x = (*fun)();
x = fun();

兩種方式均可,其中第二種看上去和普通的函式呼叫沒啥區別,如果可以的話,建議使用第一種,因為可以清楚的指明這是通過指標的方式來呼叫函式。當然,也要看個人習慣,如果理解其定義,隨便怎麼用都行啦。

示例

int add(int x,int y){ return x+y; } int sub(int x,int y){ return x-y; } //函式指標 int (*fun)(int x,int y); int main(int argc, char *argv[]) { QApplication a(argc, argv); //第一種寫法 fun = add; qDebug() << "(*fun)(1,2) = " << (*fun)(1,2) ; //第二種寫法 fun = &sub; qDebug() << "(*fun)(5,2) = " << (*fun)(5,3) << fun(5,3); return a.exec(); } 

輸出如下:

(*fun)(1,2) =  3
(*fun)(5,2) = 2 2
  • 1
  • 2

上面說到的幾種賦值和呼叫方式我都分別使用了,其輸出結果是一樣的。

二者區別

通過以上的介紹,應該都能清楚的理解其二者的定義。那麼簡單的總結下二者的區別:

定義不同

指標函式本質是一個函式,其返回值為指標。
函式指標本質是一個指標,其指向一個函式。

寫法不同

指標函式:int* fun(int x,int y);
函式指標:int (*fun)(int x,int y);
可以簡單粗暴的理解為,指標函式的*是屬於資料型別的,而函式指標的星號是屬於函式名的。
再簡單一點,可以這樣辨別兩者:函式名帶括號的就是函式指標,否則就是指標函式。

用法不同

上面已經寫了詳細示例,這裡就不在囉嗦了。

總而言之,這兩個東西很容易搞混淆,一定要深入理解其兩者定義和區別,避免犯錯。