2008-08-13 85 views
452

Tôi muốn tạo một hàm thực hiện một hàm được truyền theo tham số trên một tập hợp dữ liệu. Làm thế nào để bạn vượt qua một chức năng như một tham số trong C?Làm thế nào để bạn vượt qua một hàm như một tham số trong C?

+9

Nếu bạn đang sử dụng chức năng/mảng như các biến, luôn luôn sử dụng 'typedef'. –

+2

Chúng tôi gọi nó là [Hàm con trỏ] (http://en.wikipedia.org/wiki/Function_pointer#Example_in_C) – AminM

+0

Tên hàm phải là một trình tìm kiếm hàm. Hầu hết mọi người học C bao gồm qsort sớm hay muộn mà thực hiện chính xác điều này? – mckenzm

Trả lời

583

Tuyên bố

Một nguyên mẫu cho một chức năng mà phải mất một tham số chức năng trông giống như sau:

void func (void (*f)(int)); 

này khẳng định rằng các tham số f sẽ là một con trỏ đến một chức năng trong đó có một void kiểu trả về và có một tham số int. Các chức năng sau (print) là một ví dụ của một hàm có thể được truyền cho func như một tham số vì nó là loại thích hợp:

void print (int x) { 
    printf("%d\n", x); 
} 

Chức năng Gọi

Khi gọi một hàm với một chức năng tham số, giá trị được truyền phải là con trỏ tới hàm. Sử dụng tên của hàm (không có dấu ngoặc đơn) cho điều này:

func(print); 

sẽ gọi func, chuyển chức năng in cho nó.

Function Body

Như với bất kỳ tham số, func bây giờ có thể sử dụng tên của tham số trong các cơ quan chức năng để truy cập giá trị của tham số. Giả sử rằng hàm func sẽ áp dụng hàm được truyền cho các số 0-4. Xem xét, đầu tiên, những gì các vòng lặp sẽ trông như thế để gọi in trực tiếp:

for (int ctr = 0 ; ctr < 5 ; ctr++) { 
    print(ctr); 
} 

Kể từ func 's tuyên bố tham số nói rằng f là tên cho một con trỏ đến các chức năng mong muốn, chúng ta nhớ lại lần đầu tiên rằng nếu f là một con trỏ sau đó *f là điều mà f trỏ đến (tức là hàm print trong trường hợp này). Kết quả là, chỉ thay thế mỗi lần xuất hiện in trong vòng lặp trên với *f:

void func (void (*f)(int)) { 
    for (int ctr = 0 ; ctr < 5 ; ctr++) { 
    (*f)(ctr); 
    } 
} 

Từ http://math.hws.edu/bridgeman/courses/331/f05/handouts/c-c++-notes.html

+27

Trong ví dụ mã đầu tiên và cuối cùng của bạn, * không bắt buộc. Cả định nghĩa tham số hàm và lệnh gọi hàm 'f' có thể lấy' f' giống như không có *. Nó có thể là một ý tưởng tốt để làm điều đó như bạn làm mặc dù, để làm cho nó rõ ràng rằng tham số f là một con trỏ hàm. Nhưng nó dễ bị tổn thương khá thường xuyên. – Gauthier

+4

Xem [c99, 6.9.1§14] để biết các ví dụ. Cả hai đều chính xác tất nhiên, tôi chỉ muốn đề cập đến sự thay thế. – Gauthier

+3

Thật sao? Câu trả lời được đánh giá cao nhất không tạo ra một tham chiếu đơn lẻ để sử dụng một 'typedef' cho các con trỏ hàm? Xin lỗi, phải bỏ phiếu xuống. –

2

Bạn cần phải vượt qua function pointer. Cú pháp hơi cồng kềnh, nhưng nó thực sự mạnh mẽ khi bạn làm quen với nó.

102

Câu hỏi này đã có câu trả lời cho việc xác định chức năng gợi ý, tuy nhiên họ có thể nhận được rất lộn xộn, đặc biệt là nếu bạn sẽ chuyển chúng xung quanh ứng dụng của bạn. Để tránh sự khó chịu này, tôi khuyên bạn nên gõ con trỏ hàm vào một cái gì đó dễ đọc hơn. Ví dụ.

typedef void (*functiontype)(); 

Khai báo hàm trả về void và không có đối số.Để tạo ra một con trỏ hàm để loại hình này bây giờ bạn có thể làm:

void dosomething() { } 

functiontype func = &dosomething; 
func(); 

Đối với một hàm trả về một giá trị int và mất một char bạn sẽ làm gì

typedef int (*functiontype2)(char); 

và sử dụng nó

int dosomethingwithchar(char a) { return 1; } 

functiontype2 func2 = &dosomethingwithchar 
int result = func2('a'); 

Có các thư viện có thể giúp chuyển các con trỏ hàm thành các loại có thể đọc được tốt đẹp. Thư viện boost function thật tuyệt vời và rất đáng để bạn nỗ lực!

boost::function<int (char a)> functiontype2; 

đẹp hơn nhiều so với ở trên.

+0

Nếu bạn muốn "biến một con trỏ hàm thành một loại", bạn không cần thư viện tăng. Chỉ cần sử dụng 'typedef'; nó đơn giản hơn và không yêu cầu thêm bất kỳ thư viện nào. – wizzwizz4

40

Vì C++ 11 bạn có thể sử dụng functional library để thực hiện việc này theo cách ngắn gọn và chung chung. Cú pháp là, ví dụ,

std::function<bool (int)> 

nơi bool là kiểu trả về đây của một hàm một đối số mà số đầu tiên là loại int.

tôi đã bao gồm một chương trình ví dụ dưới đây:

// g++ test.cpp --std=c++11 
#include <functional> 

double Combiner(double a, double b, std::function<double (double,double)> func){ 
    return func(a,b); 
} 

double Add(double a, double b){ 
    return a+b; 
} 

double Mult(double a, double b){ 
    return a*b; 
} 

int main(){ 
    Combiner(12,13,Add); 
    Combiner(12,13,Mult); 
} 

Đôi khi, tuy nhiên, nó là thuận tiện hơn để sử dụng một mẫu chức năng:

// g++ test.cpp --std=c++11 

template<class T> 
double Combiner(double a, double b, T func){ 
    return func(a,b); 
} 

double Add(double a, double b){ 
    return a+b; 
} 

double Mult(double a, double b){ 
    return a*b; 
} 

int main(){ 
    Combiner(12,13,Add); 
    Combiner(12,13,Mult); 
} 
+20

Câu hỏi là về C; C++ không áp dụng ở đây. –

+8

Câu hỏi cho C++ (http://stackoverflow.com/questions/6339970/c-using-function-as-parameter) được nhắc đến ở đây, vì vậy tôi nghĩ câu trả lời này được đặt ra. –

7

đèo địa chỉ của một hàm như tham số khác chức năng như được hiển thị bên dưới

#include <stdio.h> 

void print(); 
void execute(void()); 

int main() 
{ 
    execute(print); // sends address of print 
    return 0; 
} 

void print() 
{ 
    printf("Hello!"); 
} 

void execute(void f()) // receive address of print 
{ 
    f(); 
} 

Ngoài ra chúng tôi có thể vượt qua chức năng như tham số sử dụng chức năng con trỏ

#include <stdio.h> 

void print(); 
void execute(void (*f)()); 

int main() 
{ 
    execute(&print); // sends address of print 
    return 0; 
} 

void print() 
{ 
    printf("Hello!"); 
} 

void execute(void (*f)()) // receive address of print 
{ 
    f(); 
} 
Các vấn đề liên quan