Làm thế nào tôi có thể sử dụng một loạt các con trỏ hàm?


Câu trả lời:


194

Bạn có một ví dụ hay ở đây (Mảng con trỏ hàm) , với cú pháp chi tiết .

int sum(int a, int b);
int subtract(int a, int b);
int mul(int a, int b);
int div(int a, int b);

int (*p[4]) (int x, int y);

int main(void)
{
  int result;
  int i, j, op;

  p[0] = sum; /* address of sum() */
  p[1] = subtract; /* address of subtract() */
  p[2] = mul; /* address of mul() */
  p[3] = div; /* address of div() */
[...]

Để gọi một trong các con trỏ hàm:

result = (*p[op]) (i, j); // op being the index of one of the four functions

3
Câu trả lời tốt - bạn nên mở rộng nó để hiển thị cách gọi một trong các chức năng, mặc dù.
Jonathan Leffler

1
@crucifiedsoul "Ngôn ngữ lập trình C" được viết bởi Brian Kernighan và Dennis Ritchie? Nó có thể, nhưng tôi đã không có nó như một tài liệu tham khảo tại thời điểm tôi viết câu trả lời ba năm rưỡi trước. Vì vậy, tôi không biết.
VonC

12
Tôi muốn thêm bạn có thể khởi tạo p với(*p[4]) (int, int) {sum,substract,mul,div}
jiggunjer 7/07/2015

1
@VonC: câu trả lời tuyệt vời. +1 cho các liên kết.
Kẻ hủy diệt

@jiggunjer s / trừ / trừ /: p. Nhưng cảm ơn vì nhận xét đó, rất hữu ích :). +1.
RastaJedi

41

Các câu trả lời trên có thể giúp bạn nhưng bạn cũng có thể muốn biết cách sử dụng mảng con trỏ hàm.

void fun1()
{

}

void fun2()
{

}

void fun3()
{

}

void (*func_ptr[3])() = {fun1, fun2, fun3};

main()
{
    int option;


    printf("\nEnter function number you want");
    printf("\nYou should not enter other than 0 , 1, 2"); /* because we have only 3 functions */
    scanf("%d",&option);

    if((option>=0)&&(option<=2))
    { 
        (*func_ptr[option])();
    }

    return 0;
}

Bạn chỉ có thể gán địa chỉ của các hàm có cùng kiểu trả về và cùng loại đối số và không có đối số cho một mảng con trỏ hàm duy nhất.

Bạn cũng có thể truyền các đối số như bên dưới nếu tất cả các hàm trên có cùng số lượng đối số cùng loại.

  (*func_ptr[option])(argu1);

Lưu ý: ở đây trong mảng, việc đánh số các con trỏ hàm sẽ bắt đầu từ 0 giống như trong các mảng chung. Vì vậy, trong ví dụ trên fun1có thể được gọi nếu tùy chọn = 0, fun2có thể được gọi nếu tùy chọn = 1 và fun3có thể được gọi nếu tùy chọn = 2.


Ngay cả đối với bản demo nhỏ này, bạn nên thêm một kiểm tra cho giá trị đầu vào, vì mã nhắm mục tiêu đến người mới ... :-)
PhiLho

if ((tùy chọn <0) || (tùy chọn> 2)) {(* func_ptr [tùy chọn]) (); } Dude điều này có nghĩa là phương thức chỉ được gọi khi người dùng gõ vào một chỉ mục không hợp lệ!
ljs

6
Đó là một câu trả lời hay, tuy nhiên bạn nên thêm dấu ngoặc đơn sau (* func_ptr [3]) để biến nó thành mã hợp lệ.
Alex

Đây là một câu trả lời tồi tệ khủng khiếp. Do các dấu ngoặc đơn bị thiếu, mã này thậm chí không biên dịch .
CL.

như @Alex đã nói, chỉ cần thay đổi nó từ (*func_ptr[3])thành (*func_ptr[3])()và nó sẽ được biên dịch
dsaydon

9

Đây là cách bạn có thể sử dụng nó:

Mới_un.h

#ifndef NEW_FUN_H_
#define NEW_FUN_H_

#include <stdio.h>

typedef int speed;
speed fun(int x);

enum fp {
    f1, f2, f3, f4, f5
};

void F1();
void F2();
void F3();
void F4();
void F5();
#endif

New_Fun.c

#include "New_Fun.h"

speed fun(int x)
{
    int Vel;
    Vel = x;
    return Vel;
}

void F1()
{
    printf("From F1\n");
}

void F2()
{
    printf("From F2\n");
}

void F3()
{
    printf("From F3\n");
}

void F4()
{
    printf("From F4\n");
}

void F5()
{
    printf("From F5\n");
}

C chính

#include <stdio.h>
#include "New_Fun.h"

int main()
{
    int (*F_P)(int y);
    void (*F_A[5])() = { F1, F2, F3, F4, F5 };    // if it is int the pointer incompatible is bound to happen
    int xyz, i;

    printf("Hello Function Pointer!\n");
    F_P = fun;
    xyz = F_P(5);
    printf("The Value is %d\n", xyz);
    //(*F_A[5]) = { F1, F2, F3, F4, F5 };
    for (i = 0; i < 5; i++)
    {
        F_A[i]();
    }
    printf("\n\n");
    F_A[f1]();
    F_A[f2]();
    F_A[f3]();
    F_A[f4]();
    return 0;
}

Tôi hy vọng điều này sẽ giúp hiểu Function Pointer.


Dòng 15 của Main.c nên dành cho (i = 0; i <5; i ++), phải không?
dùng3116936

Tại sao bạn khai báo điều tra viên fp?
Bắt đầu

@Arrrow: Tôi nghĩ rằng tôi đã thấy một số mã kế thừa nơi họ đã tạo ra nó theo cách đó ... Và nó trông rất đẹp. Chỉ cần xóa f1, f2 ...và thay vào đó, nhập 'writefile, readfromfile ...'... nó sẽ trở nên dễ dàng hơn
Rasmi Ranjan Nayak

5

"Câu trả lời" này là phần phụ lục cho câu trả lời của VonC; chỉ cần lưu ý rằng cú pháp có thể được đơn giản hóa thông qua một typedef và có thể sử dụng khởi tạo tổng hợp:

typedef int FUNC(int, int);

FUNC sum, subtract, mul, div;
FUNC *p[4] = { sum, subtract, mul, div };

int main(void)
{
    int result;
    int i = 2, j = 3, op = 2;  // 2: mul

    result = p[op](i, j);   // = 6
}

// maybe even in another file
int sum(int a, int b) { return a+b; }
int subtract(int a, int b) { return a-b; }
int mul(int a, int b) { return a*b; }
int div(int a, int b) { return a/b; }

2

Ồ, có rất nhiều ví dụ. Chỉ cần nhìn vào bất cứ điều gì trong glib hoặc gtk. Bạn có thể thấy công việc của các con trỏ hàm trong công việc ở đó.

Ở đây, ví dụ: việc khởi tạo các công cụ gtk_button.


static void
gtk_button_class_init (GtkButtonClass *klass)
{
  GObjectClass *gobject_class;
  GtkObjectClass *object_class;
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;

  gobject_class = G_OBJECT_CLASS (klass);
  object_class = (GtkObjectClass*) klass;
  widget_class = (GtkWidgetClass*) klass;
  container_class = (GtkContainerClass*) klass;

  gobject_class->constructor = gtk_button_constructor;
  gobject_class->set_property = gtk_button_set_property;
  gobject_class->get_property = gtk_button_get_property;

Và trong gtkobject.h bạn tìm thấy các khai báo sau:


struct _GtkObjectClass
{
  GInitiallyUnownedClass parent_class;

  /* Non overridable class methods to set and get per class arguments */
  void (*set_arg) (GtkObject *object,
           GtkArg    *arg,
           guint      arg_id);
  void (*get_arg) (GtkObject *object,
           GtkArg    *arg,
           guint      arg_id);

  /* Default signal handler for the ::destroy signal, which is
   *  invoked to request that references to the widget be dropped.
   *  If an object class overrides destroy() in order to perform class
   *  specific destruction then it must still invoke its superclass'
   *  implementation of the method after it is finished with its
   *  own cleanup. (See gtk_widget_real_destroy() for an example of
   *  how to do this).
   */
  void (*destroy)  (GtkObject *object);
};

Các công cụ (* set_arg) là một con trỏ để hoạt động và điều này có thể được chỉ định thực hiện một triển khai khác trong một số lớp dẫn xuất.

Thường thì bạn thấy một cái gì đó như thế này

struct function_table {
   char *name;
   void (*some_fun)(int arg1, double arg2);
};

void function1(int  arg1, double arg2)....


struct function_table my_table [] = {
    {"function1", function1},
...

Vì vậy, bạn có thể truy cập vào bảng theo tên và gọi hàm "liên kết".

Hoặc có thể bạn sử dụng bảng băm trong đó bạn đặt hàm và gọi nó là "theo tên".

Trân trọng
Friedrich


Nó có thể được sử dụng một hàm_t như vậy để băm các hàm trong chính việc thực hiện bảng băm không? (Đọc: phụ thuộc vòng tròn liên quan).
Flavius

2

Có thể sử dụng nó theo cách như thế này:

//! Define:
#define F_NUM 3
int (*pFunctions[F_NUM])(void * arg);

//! Initialise:
int someFunction(void * arg) {
    int a= *((int*)arg);
    return a*a;
}

pFunctions[0]= someFunction;

//! Use:
int someMethod(int idx, void * arg, int * result) {
    int done= 0;
    if (idx < F_NUM && pFunctions[idx] != NULL) {
        *result= pFunctions[idx](arg);
        done= 1;
    }
    return done;
}

int x= 2;
int z= 0;
someMethod(0, (void*)&x, &z);
assert(z == 4);

1

Đây phải là một bản sao và dán đoạn mã ngắn và đơn giản của các câu trả lời ở trên. Hy vọng điều này sẽ giúp.

#include <iostream>
using namespace std;

#define DBG_PRINT(x) do { std::printf("Line:%-4d" "  %15s = %-10d\n", __LINE__, #x, x); } while(0);

void F0(){ printf("Print F%d\n", 0); }
void F1(){ printf("Print F%d\n", 1); }
void F2(){ printf("Print F%d\n", 2); }
void F3(){ printf("Print F%d\n", 3); }
void F4(){ printf("Print F%d\n", 4); }
void (*fArrVoid[N_FUNC])() = {F0, F1, F2, F3, F4};

int Sum(int a, int b){ return(a+b); }
int Sub(int a, int b){ return(a-b); }
int Mul(int a, int b){ return(a*b); }
int Div(int a, int b){ return(a/b); }
int (*fArrArgs[4])(int a, int b) = {Sum, Sub, Mul, Div};

int main(){
    for(int i = 0; i < 5; i++)  (*fArrVoid[i])();
    printf("\n");

    DBG_PRINT((*fArrArgs[0])(3,2))
    DBG_PRINT((*fArrArgs[1])(3,2))
    DBG_PRINT((*fArrArgs[2])(3,2))
    DBG_PRINT((*fArrArgs[3])(3,2))

    return(0);
}

Nếu đó là một bản sao và dán từ các anwers khác, tôi không chắc nó có thêm bất kỳ giá trị nào không ...
Fabio nói Phục hồi lại

Có tôi thấy quan điểm của bạn, tôi sẽ thêm giá trị tối nay hiện đang làm việc.
nimig18

1

Giải pháp đơn giản nhất là đưa ra địa chỉ của vectơ cuối cùng mà bạn muốn và sửa đổi nó bên trong hàm.

void calculation(double result[] ){  //do the calculation on result

   result[0] = 10+5;
   result[1] = 10 +6;
   .....
}

int main(){

    double result[10] = {0}; //this is the vector of the results

    calculation(result);  //this will modify result
}

0

Câu hỏi này đã được trả lời với các ví dụ rất tốt. Ví dụ duy nhất có thể bị thiếu là một trong đó các hàm trả về các con trỏ. Tôi đã viết một ví dụ khác với điều này và thêm rất nhiều ý kiến, trong trường hợp ai đó thấy nó hữu ích:

#include <stdio.h>

char * func1(char *a) {
    *a = 'b';
    return a;
}

char * func2(char *a) {
    *a = 'c';
    return a;
}

int main() {
    char a = 'a';
    /* declare array of function pointers
     * the function pointer types are char * name(char *)
     * A pointer to this type of function would be just
     * put * before name, and parenthesis around *name:
     *   char * (*name)(char *)
     * An array of these pointers is the same with [x]
     */
    char * (*functions[2])(char *) = {func1, func2};
    printf("%c, ", a);
    /* the functions return a pointer, so I need to deference pointer
     * Thats why the * in front of the parenthesis (in case it confused you)
     */
    printf("%c, ", *(*functions[0])(&a)); 
    printf("%c\n", *(*functions[1])(&a));

    a = 'a';
    /* creating 'name' for a function pointer type
     * funcp is equivalent to type char *(*funcname)(char *)
     */
    typedef char *(*funcp)(char *);
    /* Now the declaration of the array of function pointers
     * becomes easier
     */
    funcp functions2[2] = {func1, func2};

    printf("%c, ", a);
    printf("%c, ", *(*functions2[0])(&a));
    printf("%c\n", *(*functions2[1])(&a));

    return 0;
}

0

Ví dụ đơn giản này cho mảng nhiều chiều với các con trỏ hàm ":

void one( int a, int b){    printf(" \n[ ONE ]  a =  %d   b = %d",a,b);}
void two( int a, int b){    printf(" \n[ TWO ]  a =  %d   b = %d",a,b);}
void three( int a, int b){    printf("\n [ THREE ]  a =  %d   b = %d",a,b);}
void four( int a, int b){    printf(" \n[ FOUR ]  a =  %d   b = %d",a,b);}
void five( int a, int b){    printf(" \n [ FIVE ]  a =  %d   b = %d",a,b);}
void(*p[2][2])(int,int)   ;
int main()
{
    int i,j;
    printf("multidimensional array with function pointers\n");

    p[0][0] = one;    p[0][1] = two;    p[1][0] = three;    p[1][1] = four;
    for (  i  = 1 ; i >=0; i--)
        for (  j  = 0 ; j <2; j++)
            (*p[i][j])( (i, i*j);
    return 0;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.