**(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); } ```