函數當作函數的參數

C 語言的標準函式庫中,有某些函式需要另一個函式當作輸入之參數。 使用者可以自訂一個函式,放到某個 C 提供的函式裡面。 這裡我們以 qsort() 做為例子。

qsort() 定義於 stdlib.h 裡面,它的機器碼已經在標準函式庫中, 不必另外鍊結。其宣告如下

void qsort(void* v, size_t N, size_t size, int (*compar)(const void *, const void *))
其中 v 是一個序列,其維度是 N,而 qsort() 就是要將 v[0], v[1], v[2], ..., v[N-1] 依據某種規則來排序,從「小」排到「大」。 每一個 v[i] 屬於某種資料型態,該型態的資料含量是 size。 在上面的宣告中,您看到一種資料型態 size_t 其實它是用 typedef 衍生出來的型態。通常 size_t 就是無號整數。 最精彩的,就是 qsort() 的第四個參數了。 這個參數是一個函式,此函式的局部名字是 compar。但是,就如同所有函式的參數一樣, 名字並不重要;主函式可以用任何名字的參數來呼叫函式,只要資料型態正確就好。 qsort() 假設第四個參數是一個函式,該函式 由此可見,qsort() 是一個「萬用」排序函式。 只要您將需要排序的物件,以序列資料結構呈現, 並且自己定義一個比大小的函式,則 qsort() 就能幫您排序。 qsort() 在執行當中,會呼叫
compar(v[i], v[j])
藉此得知 v[i]v[j] 的「大小」,以便決定它們的順序。

以下 mysort.c 便是 qsort() 的一個示範。 我們將十個雙精度浮點數從大排到小。


#include <stdio.h>
#include <stdlib.h>
#define N 10

int mycomp(const void*, const void*);

main () {
    double v[N]={3,6,-1,9,2,5,4,8,9,0};
    int i;
    for (i=0; i<N; ++i)
        printf("%.0f\n", v[i]);
    qsort(v, N, sizeof(double), mycomp);
    putchar('\n');
    for (i=0; i<N; ++i)
        printf("%.0f\n", v[i]);
}

/* 在 mycomp() 中,故意顛倒大小的定義,使得 qsort() 能從大排到小 */

int mycomp(const void *s, const void *t) {
    double *x, *y;
    x = (double*)s;
    y = (double*)t;
    if (*x < *y)
        return 1;
    else if (*x > *y)
        return -1;
    else
        return 0;
}

注意,為了避免無謂的警告訊息,我先強制 mycomp() 裡面的指標改變資料型態,然後才做計算。

習題

  1. 利用 qsort() 來做字串排序,從 Z 排到 A,大小寫視為相同, 而非字母的符號則依 ASCII 編號來排序。

[ 前一節 ]‧[ 後一節 ]‧[ 回目錄 ]



注意:此處所有文件均為原著,個別的版權宣告日後會一一公布, 整體版面設計亦尚未完成。但仍請勿抄襲文字與圖片,以免觸犯著作權法。

Created: Nov 21, 2001
Last Revised: Nov 21, 2001
© Copyright 2001 Wei-Chang Shann 單維彰

shann@math.ncu.edu.tw