Waypoint
Waypoint

Reputation: 17743

Passing a function as a parameter

Is there any way to pass function as a parameter when starting a program in C? I am implementing an app for integral approximation, and all I need is to type a function I want to work with when starting the application. I tried (e.g.) 2/(2+2*x), but I only get back "2". When I write to application directly, there is no problem. Is there any simple way of getting this? Maybe redistribute it to more parameters? Like

app.c number number*x number *x*x number *x*x*x... ?

Thanks

Upvotes: 0

Views: 206

Answers (3)

ony
ony

Reputation: 13223

This is not an answer. Just to show that it isn't so complicated:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

typedef struct expr_s {
    char op;
    struct expr_s *exprA, *exprB;
    float value;
} expr;

int readExpr(expr *node, int argc, char *argv[]) {
    int argn = 1;
    assert(argc > 0);
    switch(argv[0][0]) {
    case '0' ... '9':
    case '-': case '.':
        node->op = '#'; // direct value
        node->value = atof(argv[0]);
        return 1;
    case 'x':
        if (argv[0][1] == '\0') { // variable
            node->op = 'x';
            return 1;
        }
        break;
    default: ;
    }
    // binary expr
    if (strcmp(argv[0], "mul") == 0) node->op = '*';
    else if (strcmp(argv[0], "add") == 0) node->op = '+';
    else if (strcmp(argv[0], "div") == 0) node->op = '/';
    else if (strcmp(argv[0], "sub") == 0) node->op = '-';
    else abort();
    node->exprA = (expr*)malloc(sizeof(expr));
    node->exprB = (expr*)malloc(sizeof(expr));
    argn += readExpr(node->exprA, argc-argn, argv+argn);
    argn += readExpr(node->exprB, argc-argn, argv+argn);
    return argn;
}

float evalExpr(expr *node, float x) {
    switch(node->op) {
    case '#': return node->value;
    case 'x': return x;
    case '*': return (evalExpr(node->exprA, x) * evalExpr(node->exprB, x));
    case '+': return (evalExpr(node->exprA, x) + evalExpr(node->exprB, x));
    case '/': return (evalExpr(node->exprA, x) / evalExpr(node->exprB, x));
    case '-': return (evalExpr(node->exprA, x) - evalExpr(node->exprB, x));
    default: abort();
    }
}

int main(int argc, char *argv[]) {
    expr rootExpr;
    float x;
    readExpr(&rootExpr, argc-1, argv+1);
    for(x=0; x < 5; x+=0.5) {
        printf("f(%f) = %f\n", x, evalExpr(&rootExpr, x));
    }
    return 0;
}

Rusult:

./playground div 2 add 2 mul 2 x
f(0.000000) = 1.000000
f(0.500000) = 0.666667
f(1.000000) = 0.500000
f(1.500000) = 0.400000
f(2.000000) = 0.333333
f(2.500000) = 0.285714
f(3.000000) = 0.250000
f(3.500000) = 0.222222
f(4.000000) = 0.200000
f(4.500000) = 0.181818

Note that if you'll use the reverse polish notation you'll see almost the same, but with stack of expr instead if subsequent call of readExpr.

Upvotes: 1

Lindydancer
Lindydancer

Reputation: 26094

Unfortunately, there is no built-in expression evaluator in C. If you only need simple expressions, and the syntax is not that important you could use reverse polish notation, as used by HP calculators way back. This system use a stack, entering a number pushes it on the stack, entering an operations pops values from the stack, calculates, and push them back. There is no need to handle parentheses, as expressions are typically written inside out.

For example, 2*x would be written as:

app 2 x mul

For example, your original expression could be written as:

app 2 2 2 x mul add div

I leave the implementation as an exercise, you should not need more than a page of code for this.

Upvotes: 2

suszterpatt
suszterpatt

Reputation: 8273

An easy way to go about this would be to store your expression in a file, give your program that file's name as an argument, and then use system() or an equivalent to have the shell interpret and evaluate the expression at runtime. This will be fairly slow however.

If you want more performance, and your functions aren't terribly complicated (e.g. you only have basic arithmetic operations), then you could write a recursive function to evaluate it. Starting from the end of the formula, walk backwards and find the operation with the lowest precedence. Recursively evaluate both sides, then apply the operation to the results. If you can't find an operator, check for parentheses around your expression, and evaluate the insides. If there are no parentheses either, then the entire expression is a single value, and can be converted to a double (ostensibly).

Upvotes: 0

Related Questions