我一直在阅读有关函数作为参数的函数,特别是在C中,它们使用函数指针。让我们假设我想实现牛顿拉夫森方法(用一种简单的方法)来计算非线性方程中的零点。
double derivative(double f(double), double x)
{
double h = 1e-9;
return (f(x + h) - f(x)) / h;
}
double newton_raphson(double f(double), double x0, double tol)
{
double xk, diff;
do
{
xk = x0 - f(x0) / derivative(f, x0);
diff = fabs(xk - x0);
x0 = xk;
} while (diff >= tol);
return xk;
}
因此,要计算导数的近似值,我需要一个返回double的函数,并将double作为参数。对于计算函数的根,给定其他参数也是如此。我的问题是,为什么这与将函数参数声明为函数指针不同?例如,将输入参数f声明为函数指针而不仅仅是函数...
答案 0 :(得分:7)
参数f
是derivative
和newton_raphson
中指向函数的指针。
double derivative(double f(double), double x) { ... }
完全等同于
double derivative(double (*f)(double), double x) { ... }
只是,前者看起来更好 - 通常当你可以省略括号时,你应该这样做。毕竟它们都相当于
double ((((derivative)))(double (((*(f))))(double ((trouble))), double ((x)))) { ... }
我希望只会在IOCCC中使用。
但是,如果您要声明,定义变量(不是函数参数),则需要使用
double (*f)(double);
as
double f(double);
只是一个函数声明。
6.7.6.3 C11草案n1570的函数声明符(包括原型)说:
参数声明为''函数返回 类型 ''应调整为''指针 功能返回 类型 '',如6.3.2.1。
和 6.9.1函数定义进一步说明
[...]每个参数的类型按照6.7.6.3中的描述调整参数类型列表;结果类型应该是一个完整的对象 类型。
另外它有以下例子:
示例2
要将一个功能传递给另一个功能,可以说
int f(void); /* ... */ g(f);
然后
g
的定义可能会读取void g(int (*funcp)(void)) { /* ... * (*funcp)(); /* or funcp(); ... */ }
或等效
void g(int func(void)) { /* ... */ func(); /* or (*func)(); ... */ }
答案 1 :(得分:0)
与普通数据指针一样,函数指针可以作为参数传递,也可以从函数返回。函数的名称包含函数的地址。
我的问题是,为什么这与将函数参数声明为函数指针不同?例如,将输入参数f声明为函数指针而不仅仅是函数...
答案是编译器将两种形式视为相同。 但是为了您的代码的可读性,请使用您的示例代码所具有的声明,即
double derivative(double f(double), double x) { ... }
即使在C中,下面给出的函数定义也将被解释为相同 -
void foo(int a[]) // or int a[10]
{
...
}
void foo(int *a)
{
...
}