-1

I wrote this simple calculator program in which the user can store a calculation in a variable that was inputted. I do not know how to explain this better so I'll demonstrate with an example. If the input is:

a = 1 + 2
b = 6 - 5
c = 20 * a
d = a / b
exit

Then the output should be:

3
1
60
3

See how the program retains the value of a = 1 + 2 as a = 3. Then the user can freely use a in another calculation. For example, 20 * a. Since a = 3 now, 20 * a should equal 60.

However, there is a problem with my program. If I input the following:

a = 1 + 2
b = a + 3
c = a + b
d = 20 * a

Then I get a problem with the output for lines 3 and 4. The output I am getting looks like follows:

3
6
55

As you can see it is saying that a + b = 55 when it should 9. And when I try to multiply 20 * a I don't even get an output. I am assuming that there is no output for that last line because it is not even entering the multiplication case in the code. But have no idea where the 55 is coming from.

Here is my code (I know that it is messy but it is because I have tried everything to fix this and I've had no luck):

#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <sstream>
#include <string>

using namespace std;

    char op='a';
    double num1, num2, num3=0;
    int sub1, sub2=0;
    std::string temp;

int main() {

    double var[26];
    
    bool flag = false;
    
    char eq[5];
    
    while (true) {
        
        getline(cin, temp);
        
        if (temp.compare("exit") == 0) {
            break;
        }
        
        std::stringstream os(temp);
        
        int count = 0;
        
        for(char& c : temp) {
            if(c != ' '){
                eq[count] = c;
                count++;
            }
        }
        
        /* for(std::string::size_type i = 0; i < temp.size(); ++i){
            if(temp[i] != ' '){
                eq[count] = temp[i];
                count++;
            }
        }
         */
    
        
        if(eq[0] >= 97 && eq[0] <= 122){
            num1 = eq[2] - 48;
            op = eq[3];
            num2 = eq[4] - 48;
            flag = true;
        }
        else{
            num1 = eq[0] - 48;
            op = eq[1];
            num2 = eq[2] - 48;
        }
        
        
        
        switch (op) {
        case '+':
            if(flag == true){
                var[eq[0] - 97] = num1 + num2;
            }
            if((int)num1 >= 48 && (int)num1 <= 57){
                num1 = var[(int)num1 + 48 - 97];
            }
            if((int)num2 >= 48 && (int)num2 <= 57){
                num2 = var[(int)num2 + 48 - 97];
            }
            cout << num1 + num2 << endl;
            break;

        case '-':
            if(flag == true){
                var[eq[0] - 97] = num1 - num2;
            }
            if((int)num1 >= 48 && (int)num1 <= 57){
                num1 = var[(int)num1 + 48- 97];
            }
            if((int)num2 >= 48 && (int)num2 <= 57){
                num2 = var[(int)num2 + 48- 97];
            }
            cout << num1 - num2 << endl;
            break;

        case '*':
            if(flag == true){
                var[eq[0] - 97] = num1 * num2;
            }
            if((int)num1 >= 48 && (int)num1 <= 57){
                num1 = var[(int)num1 + 48- 97];
            }
            if((int)num2 >= 48 && (int)num2 <= 57){
                num2 = var[(int)num2 + 48- 97];
            }
            cout << num1 * num2 << endl;
            break;

        case '/':
            if(flag == true){
                var[eq[0] - 97] = num1 / num2;
            }
            if((int)num1 >= 48 && (int)num1 <= 57){
                num1 = var[(int)num1 + 48- 97];
            }
            if((int)num2 >= 48 && (int)num2 <= 57){
                num2 = var[(int)num2 + 48- 97];
            }
            cout << num1 / num2 << endl;
            break;

        case '%':
            sub1 = num1;
            sub2 = num2;
            if(flag == true){
                var[eq[0] - 97] = sub1 % sub2;
            }
            if((int)num1 >= 48 && (int)num1 <= 57){
                num1 = var[(int)num1 + 48- 97];
            }
            if((int)num2 >= 48 && (int)num2 <= 57){
                num2 = var[(int)num2 + 48- 97];
            }
            cout << sub1 % sub2 << endl;
            break;

        case '^':
            if(flag == true){
                var[eq[0] - 97] = pow(num1, num2);
            }
            if((int)num1 >= 48 && (int)num1 <= 57){
                num1 = var[(int)num1 + 48- 97];
            }
            if((int)num2 >= 48 && (int)num2 <= 57){
                num2 = var[(int)num2 + 48- 97];
            }
            cout << pow(num1, num2) << endl;
            break;
        }
    }

    return 0;
}

I thought the problem was in the for loop and that is why you see that one for loop is set as a comment. I tried replacing it with another for loop but no luck. I would greatly appreciate some help with this as I have tried numerous things and nothing works. I would put on here things that I have tried but I do not want to make the post any longer. If you need any more information please let me know.

Rivf
  • 123
  • 8
  • slight piece of advice. if(flag == true) -> just change to if(flag). Much cleaner. – Ilan Keshet Oct 22 '20 at 04:23
  • 2
    also... you have a tremendous amount of magic numbers in your code... making it very hard to understand what you are doing. What is "48" / "97" / "57"? You should use the actual character. like 'a' to represent 97 – Ilan Keshet Oct 22 '20 at 04:25
  • @Ilan Keshet They were supposed to represent the characters through their ASCII. Could I just swap those to the actual characters? – Rivf Oct 22 '20 at 04:26
  • 1
    yes. if you directly replace them with ascii, that is the best practice – Ilan Keshet Oct 22 '20 at 04:28
  • C++ will automatically convert it to the ascii int value for you – Ilan Keshet Oct 22 '20 at 04:28
  • @IlanKeshet I forgot to mention that user should be able to use any variable within the a to z range. That is another reason why I thought using the ASCII values would be better. That way if the variable entered is between 97 and 122, I know it is an lowercase letter variable. – Rivf Oct 22 '20 at 04:29
  • I think you should first clean up your code and remove all the magic numbers, then if you still have problems -- let us know – Ilan Keshet Oct 22 '20 at 04:30
  • @Rivf -- Just to warn you -- if you ever need to add features to your calculator, your current code may not be flexible enough to add those features. There are formal ways of writing programs such as you've written, and it takes much more sophistication (parsing, lexical analysis, etc.). – PaulMcKenzie Oct 22 '20 at 04:30
  • I'm currently trying to debug the code... and it is extremely hard for me to read / understand because of all those magic numbers – Ilan Keshet Oct 22 '20 at 04:31
  • @PaulMcKenzie This is as far as this calculator program needs to go. I will not be adding other features but are you completely right. I was aware of this but I went with this code anyways. – Rivf Oct 22 '20 at 04:33
  • There is also a problem you have with this line: " double num1, num2, num3=0;" you create these as doubles, but then later compare with ints. Double can not exactly hold onto integers as you might think... – Ilan Keshet Oct 22 '20 at 04:33
  • @IlanKeshet I will try to clean up the code a little and post an edit. – Rivf Oct 22 '20 at 04:33
  • @IlanKeshet How could I fix that? Would I need to get rid of the comparison with ints? Because I need to keep them as doubles in order for the program to be able to complete operations with decimal numbers. – Rivf Oct 22 '20 at 04:40
  • The IDE you use should offer a way to run your code line by line and watch the variable. Upon encountering `b = a + 3`, it actually store 49 (from ASCII code of 'a'-48) + 3 into your array for 'b' – Martheen Oct 22 '20 at 04:41
  • @Rivf regardless if the above is the way to fix the problem... you should clean up the code. :) – Ilan Keshet Oct 22 '20 at 04:42
  • See [integer division](https://stackoverflow.com/questions/3602827/what-is-the-behavior-of-integer-division) on how your code will break on handling divisions. – Martheen Oct 22 '20 at 04:43
  • @Martheen I thought of that but because I used cout to print out a and it printed out 3 not 49, I thought the storing was ok. But then when I used a, a is suddenly 49. Then how could I work around this so that it works with the value and not with the ASCII? – Rivf Oct 22 '20 at 04:46
  • It store 'a' correctly for parsing with the first line, but on parsing the second line, it immediately sum num1 (that contain 49) and num2 (3) into b. Only afterward it attempt to read the backing array for 'a', but that's only displayed, not used for storing into b – Martheen Oct 22 '20 at 04:49
  • @Martheen Aaah ok, I think I am starting to get what you mean. But I still do not understand the why. Why is it displayed but not used for storing into b? I can't seem to distinguish that within the code. – Rivf Oct 22 '20 at 04:53
  • Because you do the loading from variable *after* the storing into variable. You should load the variables first – Martheen Oct 22 '20 at 05:00
  • 1
    Micronag: *C++ will automatically convert it to the ascii int value for you*. Welllll... Not quite. It will convert the character into the value of the character in the character encoding used by the compiler which is probably ASCII, but the C++ Standard doesn't mandate an encoding. This is another reason not to use magic numbers here. `'a'` is always `'a'` but `'a'` isn't always 97. – user4581301 Oct 22 '20 at 05:48

1 Answers1

1

Loading the values from your var array should be done before doing further operation, so immediately after parsing the line, load them like this

if(eq[0] >= 97 && eq[0] <= 122){
    num1 = eq[2] - 48;
    op = eq[3];
    num2 = eq[4] - 48;
    flag = true;
}
else{
    num1 = eq[0] - 48;
    op = eq[1];
    num2 = eq[2] - 48;
}

if((int)num1 >= 48 && (int)num1 <= 57){
        num1 = var[(int)num1 + 48 - 97];
}

if((int)num2 >= 48 && (int)num2 <= 57){
        num2 = var[(int)num2 + 48 - 97];
}

Inside your switch block, you can just directly do the operation, eg. for '+' case :

case '+':
        
    if(flag == true){
       var[eq[0] - 97] = num1 + num2;
    }
        
    cout << num1 + num2 << endl;
    break;
Martheen
  • 5,198
  • 4
  • 32
  • 55
  • Thank you very much. I really appreciate this. But why does the code break when I try multiply? For example if I do a = 1 + 2 and then c = 20 * a, it won't work. As you mentioned before some division operations do not work either. – Rivf Oct 22 '20 at 05:13
  • 1
    Your code right now only handles single-digit input. Again, use the debugger in your IDE to see what's happening – Martheen Oct 22 '20 at 05:18
  • I think I know what is happening. When I load the variables like such ``num1 = eq[2] - 48;``, I am only assigning whatever is in ``eq[2]`` to ``num1``. However, ``eq[2]`` is a single digit correct? Therefore if I input a two digit number like 20, ``eq[2]`` does not hold both digits, just one. – Rivf Oct 22 '20 at 06:06
  • Because I tried doing ``b = 3 * 5`` which would mean ``b = 15`` and then I did ``c = b + 10`` and the answer came out at 16 not 26. So I think it is reading the first digit of 10 only which would be 1. It is not reading both digits 1 and 0 to make 10. And again, I think that is because ``num2`` is loaded as ``num2 = eq[4] - 48;`` where ``eq[4``] is exactly where that 1 from 10 is. – Rivf Oct 22 '20 at 06:09
  • Pretty much. You can loop through the string manually and progressively *=10 the old value and add the new one (or just add the new one divided by a progressively /=10 factor once you encounter the decimal point), but you're better off just using a proper parsing functionality built-in on STL – Martheen Oct 22 '20 at 06:13
  • I hate to ask this of you when you have already contributed so much (which I appreciate) but would mind showing me how that would look like? I do not think I am quite capable enough to do it myself haha. – Rivf Oct 22 '20 at 06:15
  • https://stackoverflow.com/questions/194465/how-to-parse-a-string-to-an-int-in-c Honestly though, unless you're specifically learning C++ (perhaps taking a course), these kinds of stuff is more fun to do on languages like Python, C#, Java, Kotlin, etc – Martheen Oct 22 '20 at 06:20
  • Unfortunately, I am stuck with C++ at moment. – Rivf Oct 22 '20 at 06:21
  • Ah, c'est la vie. Then learn on how to use your debugger to show step by step on what's happening (so you don't make an assumption) and familiarize yourself with the goodies on STL – Martheen Oct 22 '20 at 06:23