簡體   English   中英

試圖理解C中的函數指針

[英]Trying to understand function pointers in C

我正在嘗試理解函數指針並且正在搗亂。 我已經看到了K&R中的排序示例以及其他一些類似的示例。 我的主要問題是計算機實際上在做什么。 我創建了一個非常簡單的程序來嘗試查看基礎知識。 請參閱以下內容:

#include <stdio.h>

int func0(int*,int*);
int func1(int*,int*);

int main(){

    int i = 1;
    myfunc(34,23,(int(*)(void*,void*))(i==1?func0:func1));//34 and 23 are arbitrary inputs



}

void myfunc(int x, int y, int(*somefunc)(void *, void *)){

    int *xx =&x;
    int *yy=&y;

    printf("%i",somefunc(xx,yy));


}

int func0(int *x, int *y){

    return (*x)*(*y);

}

int func1(int *x, int *y){

    return *x+*y;
} 

程序要么根據某個變量相乘或相加兩個數字(i在主函數中 - 應該是主要的參數)。 fun0乘以兩個整數,func1將它們相加。

我知道這個例子很簡單,但是如何傳遞一個函數指針,可以在函數myfunc中放入一個條件? 即在myfunc中有以下內容:

if(i == 1)printf("%i",func0(xx,yy));

else printf("%i",func1(xx,yy));

如果我這樣做,結果將是相同的但不使用函數指針。

您對函數指針如何工作的理解很好。 您沒有看到的是軟件系統如何從使用函數指針中受益。 在使用不了解其他組件的組件時,它們變得很重要。

qsort()就是一個很好的例子。 qsort將允許您對任何數組進行排序,並且實際上並不知道組成數組的內容。 因此,如果你有一個結構數組,或更可能指向結構的指針,你將不得不提供一個可以比較結構的函數。

struct foo {
  char * name;
  int magnitude;
  int something;
};

int cmp_foo(const void *_p1, const void *_p2)
{
  p1 = (struct foo*)_p1;
  p2 = (struct foo*)_p2;

  return p1->magnitude - p2->magnitude;
}

struct foo ** foos;
// init 10 foo structures...

qsort(foos, 10, sizeof(foo *), cmp_foo);

然后將根據幅度字段對foos數組進行排序。

如您所見,這允許您對任何類型使用qsort - 您只需提供比較功能。

函數指針的另一個常見用法是回調,例如在GUI編程中。 如果希望在單擊按鈕時調用函數,則在設置按鈕時將提供指向GUI庫的函數指針。

如何將函數指針傳遞給函數myfunc中的條件

有時候不可能在那里設置一個條件:例如,如果你正在編寫一個排序算法,並且你不知道你提前排序的是什么,你根本就不能提出條件; 函數指針允許您將一段計算“插入”主算法,而不會跳過箍。

至於機制如何工作,這個想法很簡單:所有編譯的代碼都位於程序存儲器中,CPU從某個地址開始執行它。 有指令使CPU在地址之間跳轉,記住當前地址和跳轉,調用先前跳轉的地址並返回到它,等等。 當你調用一個函數時,CPU需要知道的一件事就是它在程序存儲器中的地址。 函數的名稱代表該地址。 您可以直接提供該地址,也可以將其分配給指針以進行間接訪問。 這類似於通過指針訪問值,除非在這種情況下您間接訪問代碼,而不是訪問數據。

首先,您永遠不能將函數指針強制轉換為不同類型的函數指針。 這是C中的未定義行為(C11 6.5.2.2)。

處理函數指針時,一個非常重要的建議是始終使用typedef。

因此,您的代碼可以/應該重寫為:

typedef int (*func_t)(int*, int*);

int func0(int*,int*);
int func1(int*,int*);

int main(){

    int i = 1;
    myfunc(34,23, (i==1?func0:func1)); //34 and 23 are arbitrary inputs
}

void myfunc(int x, int y, func_t func){

要回答這個問題,當您不知道函數的性質時,您希望使用函數指針作為參數。 這在編寫通用算法時很常見。

以標准C函數bsearch()為例:

void *bsearch (const void *key, 
               const void *base,
               size_t nmemb, 
               size_t size,
               int (*compar)(const void *, const void *));
              );

這是一種通用的二進制搜索算法,搜索任何形式的一維arrray,包含未知類型的數據,例如用戶定義的類型。 這里,“比較”函數比較兩個未知性質的對象是否相等,返回一個數字來表示這一點。

“如果分別考慮密鑰對象,該函數應返回小於,等於或大於零的整數,以小於,匹​​配或大於數組元素。”

該函數由調用者編寫,調用者知道數據的性質。 在計算機科學中,這被稱為“功能對象”或有時稱為“仿函數”。 它在面向對象的設計中經常遇到。

一個例子(偽代碼):

typedef struct  // some user-defined type
{
  int* ptr;
  int  x;
  int  y;
} Something_t;

int compare_Something_t (const void* p1, const void* p2)
{
  const Something_t* s1 = (const Something_t*)p1;
  const Something_t* s2 = (const Something_t*)p2;

  return s1->y - s2->y;  // some user-defined comparison relevant to the object
}

...

Something_t  search_key = { ... };
Something_t  array[] = { ... };
Something_t* result; 

result = bsearch(&search_key,
                 array,
                 sizeof(array) / sizeof(Something_t), // number of objects
                 sizeof(Something_t), // size of one object
                 compare_Something_t // function object
                );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM