- 註冊時間
- 2006-10-8
- 最後登錄
- 2019-6-20
- 主題
- 查看
- 積分
- 1306
- 閱讀權限
- 110
- 文章
- 1393
- 相冊
- 0
- 日誌
- 1
狀態︰
離線
|
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;
}
上面寫法會比較快的精神在於,讓迴圈內的東西越簡單越好,因為迴圈通常是程式花最多時間的地方。 |
|