2011-06-08 80 views
1

我不太明白這個的目的。我已經搜索並閱讀了不同來源上似乎相同的東西,但沒有一個解釋它具體是什麼,它的目的是什麼。指針函數C中的函數說明

任何人都可以幫助我理解這個

+1

誰提出這樣的問題? – cnicutar 2011-06-08 08:04:39

+0

你基本上在事先不知道你想要調用的函數時使用函數指針。 – pmg 2011-06-08 08:17:12

回答

0

這不是那麼簡單。

當您知道指針如何與普通變量一起工作時,請考慮使用這些指針,但這次是使用函數。也就是說,現在用變量的地址替換變量的地址和指針的所有權力,現在可以通過使用指向它們的指針間接訪問函數,而不是直接使用它們的名稱。

http://www.cplusplus.com/doc/tutorial/pointers/

// my first pointer 
#include <iostream> 
using namespace std; 

int main() 
{ 
    int firstvalue, secondvalue; 
    int * mypointer; 

    mypointer = &firstvalue; 
    *mypointer = 10; 
    mypointer = &secondvalue; 
    *mypointer = 20; 
    cout << "firstvalue is " << firstvalue << endl; 
    cout << "secondvalue is " << secondvalue << endl; 
    return 0; 
} 

和輸出的上面是

firstvalue is 10 
secondvalue is 20 

現在從http://www.newty.de/fpt/intro.html#what 我們有函數指針。

//------------------------------------------------------------------------------------ 
// 1.2 Introductory Example or How to Replace a Switch-Statement 
// Task: Perform one of the four basic arithmetic operations specified by the 
//  characters '+', '-', '*' or '/'. 


// The four arithmetic operations ... one of these functions is selected 
// at runtime with a swicth or a function pointer 
float Plus (float a, float b) { return a+b; } 
float Minus (float a, float b) { return a-b; } 
float Multiply(float a, float b) { return a*b; } 
float Divide (float a, float b) { return a/b; } 


// Solution with a switch-statement - <opCode> specifies which operation to execute 
void Switch(float a, float b, char opCode) 
{ 
    float result; 

    // execute operation 
    switch(opCode) 
    { 
     case '+' : result = Plus  (a, b); break; 
     case '-' : result = Minus (a, b); break; 
     case '*' : result = Multiply (a, b); break; 
     case '/' : result = Divide (a, b); break; 
    } 

    cout << "Switch: 2+5=" << result << endl;   // display result 
} 


// Solution with a function pointer - <pt2Func> is a function pointer and points to 
// a function which takes two floats and returns a float. The function pointer 
// "specifies" which operation shall be executed. 
void Switch_With_Function_Pointer(float a, float b, float (*pt2Func)(float, float)) 
{ 
    float result = pt2Func(a, b); // call using function pointer 

    cout << "Switch replaced by function pointer: 2-5="; // display result 
    cout << result << endl; 
} 


// Execute example code 
void Replace_A_Switch() 
{ 
    cout << endl << "Executing function 'Replace_A_Switch'" << endl; 

    Switch(2, 5, /* '+' specifies function 'Plus' to be executed */ '+'); 
    Switch_With_Function_Pointer(2, 5, /* pointer to function 'Minus' */ &Minus); 
} 

,你從上面的調用,減號()函數的傳遞是然後傳遞通過指針,在這種情況下,pt2Func(...)來調用實際函數的地址看看。 請注意,在函數指針的情況下,您也將負責函數簽名。

  • float (*pt2Func)(float, float)
  • float Minus (float a, float b) { return a-b; }

正如你可以在上面看到,簽名是相同的,所以你可以在任何函數地址傳遞,呼叫會工作。

我希望這會有所幫助。

+1

發佈時請學會格式化代碼 – 2011-06-08 07:50:15

+0

@Paul,它不是我的錯,所以沒有顯示格式化按鈕或我的瀏覽器變壞了! – 2011-06-08 07:52:09

+0

您可以通過手動縮進來格式化。 – 2011-06-08 07:53:25

3

讓我們在標準C庫看看:

void qsort(void *BASE, size_t NMEMB, size_t SIZE, 
    int (*COMPAR)(const void *, const void *)); 

qsort的最後一個參數是指針比較功能比較函數用於比較數組中的兩個元素(它定義了排序)。 如果qsort()不會使用函數指針我們將不得不如果我們有不同的排序要求或新類型/結構我們想排序寫一遍又一遍qsort()

+1

基本上,Op的例子顯示函數指針允許函數作爲參數傳遞。 – 2011-06-08 07:49:10

2

典型的例子是一個排序函數,需要你將它「指向」一個可以比較兩個元素的函數。您可以將此函數傳遞給您的比較函數,以便在需要進行比較時調用您的函數。你實際上不能傳遞函數,但你可以傳遞一個指向函數的指針,這個函數只是一個「指向」函數在內存中的位置的變量。排序功能可以使用這個指針調用你的函數。通常,指針只是存儲內存地址的變量。該內存地址就是它「指向」的地址,它可以是該地址處的任何內容 - 一個函數,一個整數,一系列以空字符結尾的字符變量。函數指針只是變量,用於存儲函數在內存中的內存地址,以便該函數可以通過其他代碼段調用。

希望解釋有幫助。

+0

這個例子顯示函數指針允許函數作爲參數傳遞給其他函數,這是很好的例子。 – 2011-06-08 07:50:35

0

函數指針用於動態調用函數。例如,你可以將一個函數指針作爲另一個函數的參數,從某種意義上說就是以這種方式提供附加功能。您也可以創建結構體,它們具有函數指針並因此具有一類成員函數,如類。如果你有一個可以在你的結構上工作的函數,那麼這可能是有用的,但他們在實際工作中可能有點不同。例如:

// Structures for our "objects" 
typedef int funcPtr(); 

struct foo { 
    int a; 
    int b; 
    funcPtr* run; 
} 

struct bar { 
    int a; 
    int b; 
    funcPtr* run; 
    char* s; 
} 

// Functions that we will use as our "member functions" 
int runOne() { 
    return 1; 
} 

int runTwo() { 
    return 2; 
} 

// Functions to create objects... kinda like new operators 
struct foo* NewFoo(int aVal, int bVal) { 
    struct foo* this = (stuct foo*)malloc(sizeof(struct foo)); 
    this->a = aVal; 
    this->b = bVal; 
    this->run = runOne; 
    return this; 
} 

struct bar* NewBar(int aVal, int bVal) { 
    struct bar* this = (stuct bar*)malloc(sizeof(struct bar)); 
    this->a = aVal; 
    this->b = bVal; 
    this->run = runTwo; 
    return this; 
} 

// Create "objects" 
struct foo* myFoo = NewFoo(10, 20); 
struct bar* myBar = NewBar(30, 40); 

// Run the run function on them (which actually runs different functions for each "object") 
int result1 = myFoo->run(); 
int result2 = myBar->run(); 

RESULT1現在將和RESULT2將。如果您的結構包含不同類型的「模塊」,並且具有類似的界面但具有不同的行爲,則可以使用這種方法。

3

採取以下:

int i = 10; 

對應的指針可以這樣定義:

int* p = &i; 

變量 「p」 是非常類似的 「i」,因爲它們都是數字。然而,'p'的值是變量'i'的內存地址,換句話說,它是存儲值10的確切內存地址。此外,'p'知道該存儲器地址處的值的類型。它知道它是一個「int」,因爲它被定義爲「int」+「star」。

類似地,考慮一個函數:

int m(char* arg1, double arg2) 
{ 
    /* do something */ 
} 

C提供來訪問該功能的存儲位置的存儲器地址的能力。函數不像一個值,例如它不能被改變,所以當一個人說出一個功能的存儲器地址時,這實際上意味着該功能的代碼所在的存儲器地址,例如,無論在花括號之間寫什麼。

但是,函數和變量之間存在相似性。他們都有一個類型。函數的類型是由:

  1. 返回類型
  2. 參數類型列表,即:
    1. 的參數#類型的參數#2
    2. 類型.. 。
    3. 參數類型#N

C將具有相同返回類型和參數類型列表的所有功能視爲「相同類型的功能」。類似於兩個被聲明爲「int i,j」的變量被認爲是相同的類型,所以具有相同簽名的兩個函數被認爲是相同的類型。

用於描述功能的類型的語法包括最低限度:返回類型和每個參數的類型(以正確的順序):

return-type (* <variable-name>)(Type-of-Param-1, Type-of-Param-2, ..., Type-of-Param-N) 

在效果上,爲了聲明指針起作用上面的「m」:

int (*p)(char*, double) = &m; 

「INT」是方法的「m」,杉對圓形托架和所述星號的語法的一部分的返回類型,「p」爲變量名, 「char *」是第一個參數的類型,「double」是第二個參數的tyep。沒有引用參數名稱 - 因爲參數的名稱與函數的類型/簽名無關。

請注意,類似於變量,方法的地址與變量的地址完全相同,即通過將其前置爲&符號。

指向函數的指針可以通過simlar傳遞給指向變量的指針,更重要的是,可以調用該特定內存地址處函數的代碼。例如,爲了通過指針'p'調用函數'm',需要如下所示:

int result = p(NULL, 10.0); 
int result = (*p) (NULL, 10.0); // alternative syntax