1

I am working with some legacy C code, which is quite convoluted. Here is what I have:

In the header file is declared:

int derivs(double,const double *,double *,void *);

then in the .c file with the same name is another declaration:

int derivs(double,const double *,double *,void *);

then the function is defined (in the same file):

int derivs(double t, const double y[], double dydN[], void * params)
{
     int i;

    if(y[2]>=1.0)
    {
        for(i=0;i<NEQS;i++)
        {
            dydN[i] = 0.0;
        }
    }
    else
    {
        if(y[2] > VERYSMALLNUM)/*Here for numerical issues in
                        sqrt()*/
        {
            dydN[0]= - sqrt(y[2]/FOURPI); //d phi/ d N eq. (17)
        }
        else
        {
            dydN[0] = 0.0;
        }
        dydN[1] = y[1]*y[2]; // dH / dN = eps * H
        dydN[2] = y[2]*(y[3]+2.0*y[2]); // d epsilon / dN
        dydN[3] = 2.0*y[4]-5.0*y[2]*y[3]-12.0*y[2]*y[2];

        for(i=4;i<NEQS-1;i++)
        {
            dydN[i] = (0.5*(i-3)*y[3]+(i-4)*y[2])*y[i]+y[i+1];
        }
        dydN[NEQS-1] = (0.5*(NEQS-4)*y[3]+(NEQS-5)*y[2])*y[NEQS-1];

    }
    return GSL_SUCCESS;
}

and then in another function in the same file is the following line:

z=int_de(y,Nstart,Nend,&kount,kmax,yp,xp,NEQS,derivs);

i.e., derivs is called by name only, without any arguments. The function int_de is declared as follows:

int int_de (gsl_vector *y, double N, double Nend, int *kount, int kmax,
gsl_matrix *ypp, gsl_vector *xpp, int NEQS, int (*derivs)(double,const
double *, double *,void *))

My question is how does the use of derivs in int_de work? It is called without any of its arguments.

John
  • 465
  • 1
  • 6
  • 13
  • 1
    It's not called, there are no Parentheses. Its passed. – tkausl Jun 21 '19 at 00:29
  • The declaration doesn't need the argument names, only their type. – Weather Vane Jun 21 '19 at 00:30
  • 1
    It's passing a pointer to the function. See the function definition (`int derivs(double,const double *,double *,void *);`) and the way it's passed in `int_de` (`int (*derivs)(double, const double *, double *, void *)`. – Ken White Jun 21 '19 at 00:30
  • @tkausl okay could you please explain this? What is the purpose of passing a function? – John Jun 21 '19 at 00:30
  • It is passed as a function pointer. You see the declaration for `int int_de (...int (*derivs)(double,const double *, double *,void *))` declares the type of function pointer it expects. – David C. Rankin Jun 21 '19 at 00:31
  • Why does a function need to be passed after it is already defined? Can't it just be called inside the body of the other function? – John Jun 21 '19 at 00:31
  • The purpose of passing a function pointer is that you can pass a different function that returns the same type and accepts the same argument types, which means you can use many different functions in the call to `int_de` when you need different behavior. – Ken White Jun 21 '19 at 00:32
  • 1
    The purpose of passing a function is it allows you to pass another function name and change the behavior within the function where it is used. (I give, @KenWhite is just faster `:)` – David C. Rankin Jun 21 '19 at 00:32
  • Take a look at [How do function pointers in C work?](https://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work) – David C. Rankin Jun 21 '19 at 00:37

1 Answers1

3

The answer is that the function derivs isn't being called yet - its address is being passed to int_de, which will probably call derivs using its address later. See for example https://www.geeksforgeeks.org/function-pointer-in-c/

An example of how this could be useful. In the following code, we re-use the logic in the function accumulate to get either the sum or the product of a list of ints, depending on which of add and multiply we pass in. This way, we don't have to write out the looping logic twice, which should help protect us against any copy-paste errors.

#include <stdio.h>

int add(int x, int y)
{
    return x + y;
}

int multiply(int x, int y)
{
    return x * y;
}

// We can pass any function with matching signature in as binary_operation, and
// accumulate will use it!
int accumulate(int starting_value, int length, int* values, int binary_operation(int, int))
{
    int result = starting_value;
    for (int index = 0; index < length; index++)
    {
        result = binary_operation(result, values[index]);
    }
    return result;
}

int sum(int length, int* values)
{
    return accumulate(0, length, values, add);
}

int product(int length, int* values)
{
    return accumulate(1, length, values, multiply);
}

int main(int argc, char** argv)
{
    int values[5] = { 1, 2, 3, 4, 5 };
    printf("sum of first three = %d\n", sum(3, values));
    printf("product of all five = %d\n", product(5, values));
}

Compiling and running this, I get the output:

sum of first three = 6
product of all five = 120
Sam Rice
  • 261
  • 2
  • 5