SOGO論壇
  登入   註冊   找回密碼
查看: 474|回覆: 0
列印 上一主題 下一主題

[技術文章] 指標陣列函數 [複製連結]

Rank: 11Rank: 11Rank: 11Rank: 11

熱心參予論壇活動及用心回覆主題勳章 數位硬體勳章

狀態︰ 離線
跳轉到指定樓層
1
發表於 2012-7-17 09:50:12 |只看該作者 |倒序瀏覽
C語言允許陣列指標和函數三者混合宣告,以表達複雜的資料結構。對於要撰寫比較複雜的應用程式來說,了解這三者的關係是非常必要的。例如下面的變數x到底是甚麼?

char (*x[])();

要看懂這些東西,首先要查型別與運算裡有關優先權與結合序的表格,得到()[]是第一優先權左結合,而*是第二優先權右結合。在看變數宣告時,如同運算式的推演過程,必須遵守C程式語言對*()[]的優先權定義。接下來請讀者背誦下面的口訣

    看見[]就說array[] of
    看見*就說pointer to
    看見變數後面的()就說function() returning

上述口訣配合*()[]的優先權,依序找出其執行的順序,每看到運算符號就把這幾句口訣念出來。因此變數的意義如下面範例

char *x;         // x: a pointer to char
char x[3];       // x: an array[3] of char
char x();        // x: a function() returning char
char *x[3];      // x: an array[3] of pointer to char
char (*x)[3];    // x: a pointer to array[3] of char
char **x;        // x: a pointer to pointer to char
char *x();       // x: a function() returning pointer to char
char *x()[3];    // x: a function() returning array[3] of pointer to char
char (*x[])();   // x: an array[] of pointer to function() returning char
char (*x())();   // x: a function() returning pointer to function() returning char
char (*(*x)[])(int, int); // x: a pointer to array[] of pointer to function(int,int) returning char

讀者在閱讀上面範例時,千萬不要把這些英文翻成中文! 英文文法是後面修飾前面,比中文更能確切表達文句的意義,因此在處理這些複雜宣告時,用英文去了解即可。

在讀運算式時,則每看到一個運算符號,就把宣告前面的口訣拿掉一個,就是該運算式的意義

char *x;         // x: a pointer to char
*x : a char

char *x[3];      // x: an array[3] of pointer to char
x[0] : a pointer to char

char **x;        // x: a pointer to pointer to char
*x : a pointer to char

char *x();       // x: a function() returning pointer to char
x() : a pointer to char

char *x()[3];    // x: a function() returning array[3] of pointer to char
x()[1] : a pointer to char

下面的宣告摘錄自"The C Programming Language"第二版的第122頁,請讀者寫出其宣告意義,並參考該書核對答案,相信可以增強讀者的自信:

char **argv;
int (*daytab)[13];
int *daytab[13];
void *comp();
void (*comp)();
char (*(*x())[])();
char (*(*x[3])())[5];

以下是計算積分的程式範例,用到pointer to function的觀念

#include <stdio.h>
#include <math.h>

/*
* 計算平方
*/
double square(double x) {
    return x * x;
}

/*
* 計算三次方
*/
double cube(double x) {
    return x * x * x;
}

/*
* 計算f()在(x,y)之間以n等份來逼近的積分數值,使用梯形法
*/
double integral(double (*f)(double), int n, double x, double y) {
    int i;
    double gap = (y - x) / n;
    double fy1 = (*f)(x);
    double fy2 = (*f)(x + gap);
    double area = 0;
    for (i = 0; i < n; i++) {
        area += (fy1 + fy2) * gap / 2; // 使用梯形面積公式
        fy1 = fy2;
        fy2 = (*f)(x + gap * (i + 1)); //下底
    }
    return area;
}

int main() {
    char fun[100];
    int n;
    double x, y;
    double (*f)(double); // f: a pointer to function(double) returning double
    while (scanf("%99s",fun) != EOF) { // EOF定義於stdio.h內,一般系統上為-1
        if (strcmp(fun,"square")==0) {
            f = square;
        } else if (strcmp(fun,"cube")==0) {
            f = cube;
        } else if (strcmp(fun,"sqrt")==0) {
            f = sqrt; // sqrt is defined in math.h
        } else if (strcmp(fun,"cbrt")==0) {
            f = cbrt; // cbrt is defined in math.h
        } else if (strcmp(fun,"end")==0) {
            break;
        } else {
            printf("Unknown function\n");
            continue;
        }
        scanf("%d%lf%lf", &n, &x, &y);
        printf("Integral of %s from %lf to %lf is: %lf\n", fun, x, y, integral(f, n, x, y));
    }
    return 0;
}

如果要讓積分算得更快的話,integral也可改寫如下

double integral(double (*f)(double), int n, double x, double y) {
    int i;
    double area = ((*f)(x) + (*f)(y)) / 2.0L;
    double gap = (y - x) / n;
    double next = x;
    for (i = 1; i < n; i++) {
        area += (*f)(next += gap);
    }
    return area * gap;
}

上面寫法會比較快的精神在於,讓迴圈內的東西越簡單越好,因為迴圈通常是程式花最多時間的地方。
喜歡嗎?分享這篇文章給親朋好友︰
               感謝作者     

請注意︰利用多帳號發表自問自答的業配文置入性行銷廣告者,將直接禁訪或刪除帳號及全部文章!
您需要登錄後才可以回覆 登入 | 註冊


本論壇為非營利自由討論平台,所有個人言論不代表本站立場。文章內容如有涉及侵權,請通知管理人員,將立即刪除相關文章資料。侵權申訴或移除要求:abuse@oursogo.com

GMT+8, 2025-2-6 17:41

© 2004-2025 SOGO論壇 OURSOGO.COM
回頂部