(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 numbers from the command line. 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.
Example:
void calc(int argc, char **argv, int op){
int i = 1, s = 0, x = 0;
char sign = (op == 1) ? '+' : '-';
if(isHex(argv[i], strlen(argv[i])))
s = (x =convertHex(argv[i], strlen(argv[i])));
else
s = atoi(argv[i]);
for(i = 2;i<argc;i++){
//Add
if(op == 1){
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(" %c ", sign);
else
printf(" %c ", sign);
}
//Repeat for subtract
//Print total
printf("%d\n", s);
}
}
But that seems like just making 1 function larger without really optimizing anything.
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.