编译C代码时出现以下错误。我正在使用Numerical Recipes 2nd ed。函数rk4()用于求解一阶微分方程。
我不是这个领域的专家。任何帮助将受到高度赞赏。
错误是:
first_order_DE_RK4_example1.c:75: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token
代码是:
#include "nrutil.h"
#include <stdio.h>
#include <math.h>
void rk4(float y[], float dydx[], int n, float x, float h, float yout[],
void (*derivs)(float, float [], float []));
void (*derivs)(float, float[], float[]);
int main()
{
int n; float h; float x;
float y[1];
float dydx[1];
n=1;
h=0.2;
x=0;
y[0] = 1;
dydx[0] = 5.0;
void rk4(float y[], float dydx[], int n, float x, float h, float yout[],
void (*derivs)(float, float [], float []));
return 0;
}
void rk4(float y[], float dydx[], int n, float x, float h, float yout[],
void (*derivs)(float, float [], float []))
{
int i;
float xh,hh,h6,*dym,*dyt,*yt;
dym=vector(1,n);
dyt=vector(1,n);
yt=vector(1,n);
hh=h*0.5;
h6=h/6.0;
xh=x+hh;
for (i=1;i<=n;i++)
{
yt[i]=y[i]+hh*dydx[i];
(*derivs)(xh,yt,dyt);
}
for (i=1;i<=n;i++)
{ yt[i]=y[i]+hh*dyt[i];
(*derivs)(xh,yt,dym);
}
for (i=1;i<=n;i++)
{
yt[i]=y[i]+h*dym[i];
dym[i] += dyt[i];
}
(*derivs)(x+h,yt,dyt);
for (i=1;i<=n;i++)
{
yout[i]=y[i]+h6*(dydx[i]+dyt[i]+2.0*dym[i]);
}
free_vector(yt,1,n);
free_vector(dyt,1,n);
free_vector(dym,1,n);
}
void (*derivs)(float x, float y, float dydx)
{
float rhs;
rhs = 1-x+4*y;
}
答案 0 :(得分:1)
您似乎无缘无故地使用函数指针,并将原型和声明与调用和定义混淆。
在顶部,这一变化:
void rk4(float y[], float dydx[], int n, float x, float h, float yout[],
void (*derivs)(float, float [], float []));
void (*derivs)(float, float[], float[]);
void rk4(float y[], float dydx[], int n, float x, float h, float yout[]);
void derivs(float, float[], float[]);
在main
中,这个:
void rk4(float y[], float dydx[], int n, float x, float h, float yout[],
void (*derivs)(float, float [], float []));
rk4(y, dydx, n, x, h, yout); // with some appropriate declared yout
在rk4
的定义中,
void rk4(float y[], float dydx[], int n, float x, float h, float yout[],
void (*derivs)(float, float [], float []))
void rk4(float y[], float dydx[], int n, float x, float h, float yout[])
拨打derivs
中的rk4
,
(*derivs)(xh,yt,dyt);
derivs(xh, yt, dyt);
在derivs
的定义中,
void (*derivs)(float x, float y, float dydx)
void derivs(float x, float y[], float dydx[])
然后修复rhs
。
如果您发现自己将来编写sometype (*name
而不打算使用函数指针,请停止。 =)
答案 1 :(得分:0)
在更正编译版本后,我运行diff
以系统方式报告更改。这些变化及其原因是:
8c8
< void (*derivs)(float, float[], float[]);
---
> void myprime(float, float[], float[]);
为避免混淆,我将为参数和将填充该参数的用户定义函数使用不同的名称。
用户定义的派生函数只是一个普通的函数(过程,子程序,方法),函数指针声明仅限于实际将变量声明为函数指针的地方。
14a15
> float yout[1];
添加缺少的变量声明。这将有助于程序编译,但不会运行,因为您混合了两个不同的索引范围。 float arr[N]
的标准范围是0..N-1
。 &{34;数字配方&#34;的vector
辅助函数使用指针运算,以便float *arr=vector(L,H)
的有效分配部分的索引范围是L..H
。在您的当前代码中,您混合范围0..0
和1..1
,从而访问分配范围之外的内存。将所有内容切换为矢量和索引范围1..n
。
23,24c24
< void rk4(float y[], float dydx[], int n, float x, float h, float yout[],
< void (*derivs)(float, float [], float []));
---
> rk4(y, dydx, n, x, h, yout, myprime);
调用函数看起来与声明该函数不同。在调用中,您只需使用参数的变量名称。
44,47c44,47
< {
< yt[i]=y[i]+hh*dydx[i];
< (*derivs)(xh,yt,dyt);
< }
---
> {
> yt[i]=y[i]+hh*dydx[i];
> }
> derivs(xh,yt,dyt);
首先运行循环计算下一个状态向量,然后调用微分计算一次。
将函数指针作为参数传递的想法是,然后使用它就像它是一个函数。无需添加任何解除引用等,C机制就是这样构建的。
这两点也适用于其他两个导数计算。顺便说一下,你错过了dydx
中导数的计算。这个想法可能是这个值也在例程之外用于其他目的,所以传递它可以避免双重计算。
73c74
< void (*derivs)(float x, float y, float dydx)
---
> void myprime(float x, float y[], float dydx[])
使用名称更改实现用户定义的派生函数。
75,76c76
< float rhs;
< rhs = 1-x+4*y;
---
> dydx[0] = 1-x+4*y[0];
y
和dydx
的传递参数是向量,即使在标量情况下,也必须将它们视为具有适当解引用或元素寻址的向量。
您需要实现函数声明背后的意图。衍生计算的结果将存储在dydx
。