0

After I enter a string in c and store it in for example char s[100], how can I compare that string to all function names in a math.h? For example, I enter pow and the result will look like this in stored form.

s[0]='p'
s[1]='o'
s[2]='w'
s[3]='\0'

Since my string is the equivalent of pow(), I want my program to recognise that and then call pow() during execution of my program. I know it is not that hard to do string comparison within the code, but that would mean that I would have to do string comparison for every function name in the library. I don't want to do that. How is it possible to compare my string against all names in the library without hard coding every comparison?

Thank you :)

  • What's wrong with a hashtable together with a perfect hash or a tree? – deamentiaemundi Mar 24 '17 at 16:15
  • 1
    This means you have to implement something like a parser which "translates strings into function pointers". I could provide you a small sample or a ful featured C compiler (the latter has a little bit too many lines for this site). Please, provide a little bit more context and I would help. – Scheff's Cat Mar 24 '17 at 16:15
  • 1
    It is not difficult to make an array (or something similar) which maps strings to function pointers. The problem might be that the number of arguments is varying. Some of these functions have one argument, some two or even more. The types of these arguments are also differing. Any concept how this should be handled? – Scheff's Cat Mar 24 '17 at 16:26

3 Answers3

0

You can't, not without doing work yourself. There are no names of functions present at runtime in general, and certainly not of functions you haven't called.

C is not a dynamic language, names are only used when compiling/linking.

unwind
  • 364,555
  • 61
  • 449
  • 578
  • @Scheff Right, but those only apply to shared objects, and the code in the standard library (of which `math.h` is a part, of course) is not typically loaded as a shared object. – unwind Mar 27 '17 at 08:09
  • This was the result guess of my thinking (although I actually didn't investigate or test it). For "doing work yourself" I answered a sample meanwhile. – Scheff's Cat Mar 27 '17 at 08:23
0

Regular expressions in C

Try parsing the header files using FILE and use aforementioned link as a guide to check whether the function exists or not.

0

I tried to make a little sample about what I assume the questioner is looking for (eval.c):

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

/* mapping function names to function pointers and number of parameters */
struct Entry {
  const char *name; /* function name */
  double (*pFunc)(); /* function pointer */
  int nArgs; /* number of arguments */
} table[] = {
#define REGISTER(FUNC, N_ARGS) { #FUNC, &FUNC, N_ARGS }
  REGISTER(atan2, 2),
  REGISTER(pow, 2),
  REGISTER(modf, 2),
  REGISTER(sin, 1),
  REGISTER(cos, 1)
#undef REGISTER
};
/* let compiler count the number of entries */
enum { sizeTable = sizeof table / sizeof *table };

void printUsage(const char *argv0)
{
  int i;
  printf(
    "Usage:\n"
    "  %s FUNC\n"
    "  where FUNC must be one of:\n", argv0);
  for (i = 0; i < sizeTable; ++i) printf("  - %s\n", table[i].name);
}

int main(int argc, char **argv)
{
  int i;
  char *func;
  struct Entry *pEntry;
  /* read command line argument */
  if (argc <= 1) {
    fprintf(stderr, "ERROR: Missing function argument!\n");
    printUsage(argv[0]);
    return -1;
  }
  func = argv[1];
  /* find function by name */
  for (i = 0; i < sizeTable && strcmp(func, table[i].name) != 0; ++i);
  if (i >= sizeTable) {
    fprintf(stderr, "ERROR! Unknown function '%s'!\n", func);
    printUsage(argv[0]);
    return -1;
  }
  /* perform found function on all (standard) input */
  pEntry = table + i;
  for (;;) { /* endless loop (bail out at EOF or error) */
    switch (pEntry->nArgs) {
      case 1: {
        double arg1, result;
        /* get one argument */
        if (scanf("%lf", &arg1) != 1) {
          int error;
          if (error = !feof(stdin)) fprintf(stderr, "Input ERROR!\n");
          return error; /* bail out at EOF or error */
        }
        /* compute */
        result = (*pEntry->pFunc)(arg1);
        /* output */
        printf("%s(%f): %f\n", pEntry->name, arg1, result);
      } break;
      case 2: {
        double arg1, arg2, result;
        /* get two arguments */
        if (scanf("%lf %lf", &arg1, &arg2) != 2) {
          int error;
          if (error = !feof(stdin)) fprintf(stderr, "Input ERROR!\n");
          return error; /* bail out at EOF or error */
        }
        /* compute */
        result = (*pEntry->pFunc)(arg1, arg2);
        /* output */
        printf("%s(%f, %f): %f\n", pEntry->name, arg1, arg2, result);
      } break;
      default: /* should never happen */
        fprintf(stderr,
          "ERROR! Functions with %d arguments not yet implemented!\n",
          pEntry->nArgs);
        assert(0);
        return -1; /* bail out at error */
    }
  }
}

I compiled and tested this with gcc in cygwin on Windows (64 bit):

$ gcc -std=c11 -o eval eval.c

$ ./eval
ERROR: Missing function argument!
Usage:
  ./eval FUNC
  where FUNC must be one of:
  - atan2
  - pow
  - modf
  - sin
  - cos

$ echo "1 2 3 4 5 6 7 8 9 10" | ./eval pow
pow(1.000000, 2.000000): 1.000000
pow(3.000000, 4.000000): 81.000000
pow(5.000000, 6.000000): 15625.000000
pow(7.000000, 8.000000): 5764801.000000
pow(9.000000, 10.000000): 3486784401.000000

$ echo "1 2 3 4 5 6 7 8 9 10" | ./eval sin
sin(1.000000): 0.841471
sin(2.000000): 0.909297
sin(3.000000): 0.141120
sin(4.000000): -0.756802
sin(5.000000): -0.958924
sin(6.000000): -0.279415
sin(7.000000): 0.656987
sin(8.000000): 0.989358
sin(9.000000): 0.412118
sin(10.000000): -0.544021

The usage of this application: the name of the function to apply is provided as command line argument. The values (to apply function to) are provided via standard input. In the sample session, I used echo and a pipe (|) to redirect the output of echo to the input of eval. (If eval is called stand-alone the numbers may be typed in by keyboard.)

Notes:

  1. The table does the actual mapping of strings to function pointers. To solve that issue about the number of parameters, I considered this in struct Entry also.

  2. The REGISTER macro is a trick to use the identifier as string constant also. The #FUNC is a stringize macro-operation (a typical C trick to prevent errors due to typos).

  3. The sizeTable is another trick to prevent redundant definitions. I let the compiler count the number of entries. Thus, new entries may be added and it still will work without any other editing.

  4. The actual trick is to provide a function pointer where the arguments are "left out". When it is called, the correct number of arguments is used and it works. (assuming, of course, the table initialization has been implemented carefully.) However, it would be a pain to do this in C++ because the functions with distinct number of arguments would need an appropriate function pointer with matching signature - horrible casts would be necessary. (Try to compile this with g++ -std=c++11 -c eval.c to see what I mean.)

  5. For a productive solution, I would sort the entries by names (lexicographically) and apply a binary search (or even use hashing to be faster and more sophisticated). For this sample, I wanted to keep it simple.

  6. math.h provides a lot of functions in "float flavor" also. These may not be added to this sample without additional effort. To support other than double arguments

    1. some type info had to been added to the table entries
    2. the type info has to be considered somehow in the switch statement of evaluation.
  7. ...not to mention functions where argument types are distinct to each other (or return type). (I cannot remember whether math.h even provides such functions.)

Btw. this will work for non-math.h functions also...

Scheff's Cat
  • 16,517
  • 5
  • 25
  • 45
  • Hi Scheff, Thank you for the comprehensive answer :). I am mostly self taught and my programming skills are not up to date to understand all the code you wrote here :). I will go over the code you wrote bit by bit and try to understand it little by little. I never studied Struct and pointers, so it might take me a while. I really appreciate the answer, but it may take me a while to understand this with my current abilities :). I hope I can get back to you soon. Thank you again. – Arthur Speiser Mar 25 '17 at 16:07
  • @ArthurSpeiser OK, I see. I added some notes about usage to clarify what I did in the sample session (these things with `echo` and `|`). – Scheff's Cat Mar 25 '17 at 16:18