**(This is homework, however I have a working solution that I'm trying to improve upon)**

I'm working on a program that adds or subtracts up to 15 decimal or hexadecimal numbers from the command line. You run the program with the arguments and then choose the option from a menu. I.e.:`./main 5 10 15 20` will take in those four arguments and allow you to either add or subtract.

I have a working program, but I am trying to optimize it to reduce some redundancy. Basically my add and subtract functions are identical other than some sign switches, and I feel like there might be a better way. Here is what I have so far (the program can accept decimal input, or hex input formatted with a preceding 0x, which is why there are a sections dealing with those conversions):

```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

void menu(char **options){
  for(int i = 0; i < 3; ++i){
    printf("%d. %s\n", i, options[i]);
  }
  printf("Menu Item: ");
}

int isHex(char *argv, int len){
  
  if(argv[0] == '0' && (argv[1] == 'x' || argv[1] == 'X')){
    for (int i = 2; i < len; ++i)
      if(!isxdigit(argv[i]))
        return 0;
    return 1;
  }

  return 0;
}

int convertHex(char *hexVal, int len){

  int dec_val = 0;
  int base = 1;

  for (int i=len-1; i>=2; i--) {    
    if (hexVal[i]>='0' && hexVal[i]<='9'){ 
        dec_val += (hexVal[i] - 48)*base; 
        base = base * 16; 
    } 

    else if (hexVal[i]>='A' && hexVal[i]<='F') { 
        dec_val += (hexVal[i] - 55)*base;
        base = base*16; 
    } 
  }
  
  return dec_val; 
}

void add(int argc, char **argv){
  int i = 1, s = 0, x = 0;

  if(isHex(argv[i], strlen(argv[i])))
    s = (x =convertHex(argv[i], strlen(argv[i])));

  else
    s = atoi(argv[i]); 

  printf("%s + ", argv[i]);

  for(i = 2;i<argc;i++){
    if(isHex(argv[i], strlen(argv[i]))){
      s += (x = convertHex(argv[i], strlen(argv[i])));
      printf("%s", argv[i]);
    }

    else{
      printf("%s", argv[i]);
      s += atoi(argv[i]);
    }

    if(i == argc-1)
      printf(" = ");
    else
      printf(" + ");
   }

   printf("%d\n", s);
}

void sub(int argc, char **argv){

  int i = 1, s = 0, x = 0;

  if(isHex(argv[i], strlen(argv[i])))
    s = (x =convertHex(argv[i], strlen(argv[i])));

  else
    s = atoi(argv[i]); 

  printf("%s - ", argv[i]);

  for(i = 2;i<argc;i++){
    if(isHex(argv[i], strlen(argv[i]))){
      s -= (x = convertHex(argv[i], strlen(argv[i])));
      printf("%s", argv[i]);
    }

    else{
      printf("%s", argv[i]);
      s -= atoi(argv[i]);
    }

    if(i == argc-1)
      printf(" = ");
    else
      printf(" - ");
   }

   printf("%d\n", s);
}

int main(int argc,char** argv){

  char *choices[] = {"Exit", "Addition", "Subtraction"};
  void (*calc[])(int, char**) = {NULL, add, sub};


  if(argc < 3)
    fprintf(stderr, "You must enter at least two arguments.\n");

  else if(argc > 16)
    fprintf(stderr, "You cannot enter more than 15 arguments.\n");

  else{

    int ch=1;
    while(ch!=0){   
      menu(choices);
      scanf("%d",&ch);

      switch(ch){
        case 0:
          exit(0);
          break;

        case 1:
          calc[1](argc,argv);
          break;
        
        case 2:
          calc[2](argc,argv);
          break;
          
        default:
          printf("Enter valid option\n");
          break;
      }
    }

    exit(EXIT_SUCCESS);
  }

  exit(EXIT_FAILURE);
}
```

The relevant functions are add/sub. It gets tricky because of needing to output the operations to the user. My initial inclination was to go with something like an op-code 1 = add, 2 = sub, but I don't know if that just adds more if-checks in one function and ultimately makes it as long or harder to read.

***EDIT: removed alternative implementation that wasn't much better.***

Does anyone have any suggestions or helpful advice for reducing the redundancy with add/sub (if its even possible)? Its not entirely necessary, but I'd appreciate any assistance.


***EDIT: Updated semi-improved code, now with more functionality:***

```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define min(a, b) ((a) < (b) ? (a) : (b))
#define maxItems 15

typedef struct _Menu {
  int count;
  char *items[maxItems];
} Menu;

char *choices[] = {"Exit", "Addition", "Subtraction", "Multiplication", "Division", "Modulo", "Reverse Input"};
int count = sizeof(choices)/sizeof(choices[0]);

int printMenu(const Menu *menu){
  int ch;
  printf("\n");
  for (int i=0; i<menu->count; i++) 
    printf("%d. %s\n", i, menu->items[i]);

  printf("\nMenu Item: ");
  scanf("%d",&ch);
  return ch;
}

void strrev(char *str){

    if (str == 0)
      return;

    if (*str == 0)
      return;

    /* get range */
    char *start = str;
    char *end = start + strlen(str) - 1; /* -1 for \0 */
    char temp;

    /* reverse */
    while (end > start){
      /* swap */
      temp = *start;
      *start = *end;
      *end = temp;

      /* move */
      ++start;
      --end;
    }
}

void rev(int argc, char **argv){
  for (int i = argc-1; i > 0; --i){
    strrev(argv[i]);
    printf("%s ", argv[i]);
  }
  
  printf("\n");
}

int add(int a, int b){
  return a+b;
}

int sub(int a, int b){
  return a-b;
}

int mult(int a, int b){
  return a*b;
}

float divi(int a, int b){
  return a/b;
}

int mod(int a, int b){
  return a%b;
}

int applyOperator(int argc, char **argv, int (*op)(int, int)) {
  int retval = strtol(argv[0], NULL, 0);

  for (int i = 1; i < argc; ++i) {
    retval = op(retval, strtol(argv[i], NULL, 0));
  }

  return retval;
}

void printList(int argc, char **argv, const char *sep) {
  printf("%s", argv[1]);
  
  for (int i = 2; i < argc; ++i) {
      printf("%s%s", sep, argv[i]);
  }
}

//Attempting implementation of function dispatch table
int (*calc[])(int, int) = {add, sub, mult};

int main(int argc,char** argv){

  Menu menu;
  menu.count = min(count, maxItems);
  
  for (int i=0; i < menu.count; i++)
    menu.items[i] = choices[i];

  if(argc < 3)
    fprintf(stderr, "You must enter at least two arguments.\n");

  else if(argc > 16)
    fprintf(stderr, "You cannot enter more than 15 arguments.\n");

  else{

    int ch=1;
    while(ch!=0){   
      ch = printMenu(&menu);

      switch(ch){
        case 0:
          exit(0);
          break;

        case 1:
          printList(argc, argv, " + ");
          printf(" = %d\n", applyOperator(argc, argv, calc[0]));
          break;
        
        case 2:
          printList(argc, argv, " - ");
          printf(" = %d\n", applyOperator(argc, argv, calc[1]));
          break;
          
        case 3:
          printList(argc, argv, " * ");
          printf(" = %d\n", applyOperator(argc, argv, calc[2]));
          break;
          
        case 4: //Divides just the first two args.
          printf("%s / %s", argv[1], argv[2]);
          printf(" = %f\n", divi(strtol(argv[1], NULL, 0), strtol(argv[2], NULL, 0)));
          break;
          break;
        
        case 5: //Mods just the first two args.
          printf("%s mod %s", argv[1], argv[2]);
          printf(" = %d\n", mod(strtol(argv[1], NULL, 0), strtol(argv[2], NULL, 0)));
          break;
          
        case 6:
          rev(argc,argv);
          break;
          
        default:
          printf("Enter valid option\n");
          break;
      }
    }

    exit(EXIT_SUCCESS);
  }

  exit(EXIT_FAILURE);
}
```