0

I am writing a code to integrate some ODEs using a leapfrog method, I have to supply a function including the derivatives to my integration method, however I'm getting a "void value not ignored as it ought to be error". I've gotten this in the past when I've mistaken types with function pointers but as far as I can see the function doesn't assign anything anywhere, it should just execute?

So my source file is here

#include "nrutil.h"
#include <math.h>
#include <stdio.h>
void leapvel(int n, double x[], double v[], double dt2, void (*derivs)(double, double [], double []))

{
        double dvdt[n];
        int i;

        (*derivs)(n, x, dvdt);

        for(i = 0; i < n; i++)
                 v[i] += dt2*dvdt[i];

}

void output(int n, double x[], double v[], double t, double dt, void (*derivs)(double, double [], double []))
{
        int i;
        double vv[n], dvdt[n];

        printf("%f", t);
        for(i = 0; i < n; i++)
                printf(" %f", x[i]);

        /*sync velocity*/

        for (i = 0; i < n; i ++)
                vv[i] = v[i];
        if (t > 0)
        {
                (*derivs)(n,x,dvdt);
                for (i = 0; i < n; i ++)
                        vv[i] -= 0.5*dt*dvdt[i];
        }

        printf("\n");
}

void leap(int n, double x[], double v[], double* t, double dt, void (*derivs)(double, double [], double []))
{
        double dvdt[n];
        int i;

        for (i = 0; i < n; i++)
                x[i] += dt*v[i];

        (*derivs)(n, x, dvdt);

        for (i = 0; i < n; i++)
                v[i] += dt*dvdt[i];

        *t += dt;
}

void leapfrog(int n, double x[], double v[], double t, double dt, double t_max, void (*derivs)(double, double [], double []))
{
/* integration time! */

/* parameters, the user has to set these, and to be honest it's going to be cumbersome either way in command line or just editing the code */
/* but since we have to run this twice! */

/* double t = 0, x[n] = {0}, v[n] = {1};
double t_max = 15, dt = 1;*/

/*this is the number of equations in derivs*/
/*int n = 1*/

int i;


output(n, x, v, t, dt, *derivs);
leapvel(n, x, v, 0.5*dt, *derivs);

while (t < t_max)
{
        leap(n, x, v, &t, dt, *derivs);
        output(n, x, v, t, dt, *derivs);
}

}

This is referenced in a short file I do intend to make a header once I figure this out as it's better practice than simply just including the source file however, for now this is what I have

#include <math.h>


void leapfrog(int n, double x[], double v[], double t, double dt, double t_max, void (*derivs)(double, double [], double []));

void derivs(int n, double x[], double dvdt[])
{
        int i;
        double accel = 0.0;

        for(i = 0; i < n; i++)
        {
                accel = -x[i];
                dvdt[i] = accel;
        }


}

int main()
{

/*frog goes {number of equations], {x initial conditions}, {v initial}, [t bottom], [t step], [t max], derivs(n,
 * x[], dvdt[]) */
int n = 1;
double x[n];
double v[n];
x[0] = 0;
v[0] = 1;

double t = 0;
double dt = 1;
double t_max = 15;
double dvdt[n];


leapfrog(n, x, v, t, dt, t_max, *derivs(n, x, dvdt)); /*I get the error on this line*/

return 0;

}

I'm probably missing something obvious here but I'm not sure.

I've tried to make the function a void pointer type function but that obviously is dangerous, and has undefined behavior, so I have a pointer to a void function now, but that gives this error. If I remove the arguments it has other weird behavior. I'm not sure how to make this work. Removing the arguments gives too few arguments obviously as it's declare above, but when I give it what it wants it gives the error.

This means the error is probably in the source file shown off first, but I can't seem to find it in there, as far as I can see I don't directly assign it to anything so all should be fine.

Pickle
  • 3
  • 2
  • For which line do you get that error? Please identify it with a comment. – Yunnosch Nov 10 '22 at 07:27
  • @SupportUkraine Please do not ask for a line number. They might answer with a number. – Yunnosch Nov 10 '22 at 07:28
  • What happens when you pass `derivs` to `leapfrog` instead? Note that the first argument of `derivs` is `int` not a `double`. – Bob__ Nov 10 '22 at 07:29
  • I have added a comment but I get it on this line "leapfrog(n, x, v, t, dt, t_max, *derivs(n, x, dvdt));" Line 44 in the code block. If I pass derivs without the * I get "invalid use of void expression" on the same line – Pickle Nov 10 '22 at 07:31
  • You don't pass a function pointer like that. Further the types doesn't match – Support Ukraine Nov 10 '22 at 07:35
  • To bob, I did correct the int/double mismatch between the functions now however that still gives me "void value not ignored as it ought to be" on line 44, the commented line – Pickle Nov 10 '22 at 07:39
  • `leapfrog(n, x, v, t, dt, t_max, *derivs(n, x, dvdt));` --> `leapfrog(n, x, v, t, dt, t_max, derivs);` – Support Ukraine Nov 10 '22 at 07:41
  • and read: https://stackoverflow.com/questions/1952175/how-can-i-call-a-function-using-a-function-pointer – Support Ukraine Nov 10 '22 at 07:42

1 Answers1

1

If you want to pass the function derivs as an argument to a function, you just write derivs. Just like the way you pass any other variable. You don't write sin(double x); it's just sin(x). Same with functions.

Here, you are calling derivs and then attempting to dereference its non-existent return value:

leapfrog(n, x, v, t, dt, t_max, *derivs(n, x, dvdt))

The compiler objects, because there is obviously no return value to dereference. But the real error was writing a function call rather than just providing the function. You should write:

leapfrog(n, x, v, t, dt, t_max, derivs)

For obscure reasons, the compiler might not complain about this incorrect function call:

output(n, x, v, t, dt, *derivs);

where you are attempting to pass the function itself rather than a pointer to a function. If you look at the prototype for output, you'll see that the last parameter is a pointer to a function, so that's what you should pass it. Anyway, there is no other option, because in C functions are not usable as objects; you can only use pointers to functions. So that call (and the other similar ones) should be written as output(n, x, v, t, dt, derivs). Unsurprisingly, that's pretty similar to the way leapfrog should be called.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
rici
  • 234,347
  • 28
  • 237
  • 341
  • Thank you so much, this was precisely it. I'm new to C and this actually explains a lot. This is a great response. If I had 15 feedback I'd give you an upvote – Pickle Nov 10 '22 at 07:47