程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> C語言入門知識 >> C語言中函數指針數組淺析

C語言中函數指針數組淺析

編輯:C語言入門知識
發現問題 問題分析 示例代碼

發現問題

今天,在閱讀Linux內核中關於socket的源代碼時,遇到了下面一段代碼:

struct proto_ops {
    int family;
    struct module *owner;
    int (*release)   (struct socket *sock);
    int (*bind)      (struct socket *sock,
                      struct sockaddr *myaddr,
                      int sockaddr_len);
    int (*connect)   (struct socket *sock,
                      struct sockaddr *vaddr,
                      int sockaddr_len, int flags);
    int (*socketpair)(struct socket *sock1,
                      struct socket *sock2);
    int (*accept)    (struct socket *sock,
                      struct socket *newsock, int flags);
    int (*getname)   (struct socket *sock,
                      struct sockaddr *addr,
                      int *sockaddr_len, int peer);
    unsigned int (*poll)     (struct file *file, struct socket *sock, 
                              struct poll_table_struct *wait);
    int (*ioctl)     (struct socket *sock, unsigned int cmd, unsigned long arg);
    int (*listen)    (struct socket *sock, int len);
    int (*shutdown)  (struct socket *sock, int flags);
    int (*setsockopt)(struct socket *sock, int level,
                      int optname, char __user *optval, int optlen);
    int (*getsockopt)(struct socket *sock, int level,
                      int optname, char __user *optval, int __user *optlen);
    int (*sendmsg)   (struct kiocb *iocb, struct socket *sock,
                      struct msghdr *m, size_t total_len);
    int (*recvmsg)   (struct kiocb *iocb, struct socket *sock,
                      struct msghdr *m, size_t total_len,
                      int flags);
    int (*mmap)      (struct file *file, struct socket *sock,
                      struct vm_area_struct * vma);
    ssize_t (*sendpage)  (struct socket *sock, struct page *page,
                      int offset, size_t size, int flags);
};

在這段代碼中,我們注意到proto_ops結構體的成員包括下面這樣的成員變量:

int (*release)   (struct socket *sock);

這邊是函數指針作為結構體成員變量的使用方法。

問題分析

首先,我們對C和C++中結構體以及C++類的區別進行一些說明:

C中的結構體和C++中結構體的不同之處:
在C中的結構體只能自定義數據類型,結構體中不允許有函數;
而C++中的結構體可以加入成員函數。

C++中的結構體和類的異同:
相同之處:
結構體中可以包含函數;也可以定義public、private、protected數據成員;定義了結構體之後,可以用結構體名來創建對象。但C中的結構體不允許有函數;也就是說在C++當中,結構體中可以有成員變量,可以有成員函數,可以從別的類繼承,也可以被別的類繼承,可以有虛函數。

不同之處:
結構體定義中默認情況下的成員是public,而類定義中的默認情況下的成員是private的。類中的非static成員函數有this指針,(struct中沒有是錯誤的,一直被誤導啊,經過測試struct的成員函數一樣具有this指針),類的關鍵字class能作為template模板的關鍵字,而struct不可以。

實際上,C中的結構體只涉及到數據結構,而不涉及到算法,也就是說在C中數據結構和算法是分離的,而到C++中一類或者一個結構體可以包含函數(這個函數在C++我們通常中稱為成員函數),C++中的結構體和類體現了數據結構和算法的結合。
因此,我們在閱讀純C代碼時,應該注意代碼中使用函數指針成員變量來等效地實現成員函數過程。

示例代碼

這裡,我們使用一段代碼來對函數指針成員進行相關說明:

#include 
#include 

int func1(int n)
{
    printf("func1: %d\n", n);
    return n;
}

int func2(int n)
{
    printf("func2: %d\n", n);
    return n;
}

int main()
{
    int (*a[2])(int);
    a[0] = func1;
    a[1] = func2;
    a[0](1);
    a[1](2);

    return 0;
}

我們注意上面代碼中的

int (*a[2])(int);

在這句代碼中,我們定義了這樣一個數組:

數組保存指針,什麼樣的指針呢?
形如 int func(int input) 的 func函數指針,形參為int變量,返回int變量。
因此,數組保存的是形參為單一int變量和返回值為int值得函數指針。

現在,我們定義了這樣一個數組,然後

    a[0] = func1;
    a[1] = func2;

由於我們在main函數前聲明和定義了func1和func2兩個函數(這兩個函數滿足前面所提及的函數條件),這時,我們便可以使用這兩個函數指針賦值函數指針數組。
然後,我們便可以使用數組成員來實現函數調用:

    a[0](1);
    a[1](2);

最終結果為:
這裡寫圖片描述

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved