-1

I'm trying to code a calculator in C, and want to make one that can calculate a multiple inputs, eg, (5*9 + 1 -2). These inputs can be completely random and I'm stuck on how to do this.

I know how to initialize a variable, and ask the user input a number and all that, but if the user wanted to add up 50 random numbers, that calculator wouldn't be able to do that.

Hope you can help, or share some tips

Thanks !

Cray
  • 1
  • 1
  • 3
  • 2
    What did you try so far? – L.Butz Sep 03 '15 at 09:28
  • You need to implement some algorithms in order to do it properly, see this [answer](http://stackoverflow.com/a/15173980/1113392) for some hints on where to start – A4L Sep 03 '15 at 09:29
  • To calculate an arbitrary expression you will need some data structures like stack or expression tree to store expression nodes and than traverse them and calculate. You should try first calculating expressions without parentheses , then you'll need to split string using spaces and math operation symbols (+ - * /) as delimitors. Then depending on the current operation you'll just add current value to the sum or modify it with multiplier/divisor. – olegst Sep 03 '15 at 09:37
  • @L.Butz I have no idea where to start. I thought of saving the input into a string, then using a for loop to go through that string and take out each value and arithmetic symbol and I'm not sure where to go after that – Cray Sep 03 '15 at 10:11

4 Answers4

1

You will need to implement an expression parser that will take operator precedence into account. To me the two simplest ways to do this would be to either implement a recursive decent parser or to implement the Shunting yard algorithm.

See this for an example.

Shreevardhan
  • 12,233
  • 3
  • 36
  • 50
Chris Taylor
  • 52,623
  • 10
  • 78
  • 89
1

In order to do this, you need to read the entire line (it shouldn't be too hard), then you need to parse it and store it into some data structures.

Here are two ways I know to store and use it :

  • The first one : it's easy to do, easy to use, but not beautiful nor fast : A double linked-list with each link containing an operator or a number and a priority if it's an operator (you can use an enum + union if you want something cleaner):

    struct list {
        struct list *prev;
        struct list *next;
        char operator;
        int number;
        unsigned int priority;
    }
    

    You loop trough your string and apply an easy algorithm for priority (pseudocode):

    var priority = 0
    var array = cut string // ["5", "+", "3", "*", "(", "6", "-", "2", ")"]
    
    check string // verify the string is correct
    
    for each element of array :
        if (element is number)
            store in list
    
        else if (element is operator)
            store in list
            if (element is '*' or '/' or '%')
                set his priority to priority + 1
            else
                set his priority to priority
    
        else if (element is open parenthesis)
            priority += 2
    
        else if (element is close parenthesis)
            priority -= 2
    

    For example :

    string:

    5 + 3 * (6 - 2) - 1
    

    priorities:

      0   1    2    0
    

    Then, to do your calculations :

    while list isn't empty:
        find operator with the highest priority // if there is more than one, take the first
        calculate this operator // with the element prev and next
        replace by result in list // operator, but also prev and next
    

    An example, again, with 5 + 3 * (6 - 2) - 1 :

    first iteration:

    5 + 3 * 4 - 1
    

    then

    5 + 12 - 1
    

    then

    17 - 1       
    

    then

    16
    
  • The other (and better, even though it is a little bit harder if you're not familiar with recursion) one : A binary tree using the reverse polish notation (see here and here)

    This one is more common, so I won't explain it.

Community
  • 1
  • 1
4rzael
  • 679
  • 6
  • 17
  • 1 more question, how can I cut the string, for the line 'var array = cut string ' . Also, I didn't understand what u meant by 'check string' to see if it was correct, is there a function to do this, or was the else if parts checking it already? – Cray Sep 05 '15 at 11:33
  • @Cray In order to cut the string, you'll have to do a little bit of parsing, but you can start by cutting it with spaces (`3 + 4` become `["3", "+", "4"]`) by using [strtok](http://linux.die.net/man/3/strtok). (If you do so, every character will have to be separated by a space...) The "check string" checks syntax errors like unmatched parenthesis or two operators (or numbers) in a row (`3 + * 4` isn't a valid operation, neither is `3 4 + 5`), unknown characters (`3 + 4NINJA` isn't valid either), and so on... – 4rzael Sep 07 '15 at 08:14
0

You can use a string when you read and divide that string when you find {+,-,*,/}. And what you find between them are your numbers.

Try to add your code!

Good luck!

Kushal
  • 8,100
  • 9
  • 63
  • 82
Macpp
  • 33
  • 9
  • I thought of saving the input into a string, then using a for loop to go through that string and take out each value and arithmetic symbol and I'm not sure where to go after that. Is this the most efficient way to go? – Cray Sep 03 '15 at 10:12
  • Simple..first you have to slect the first value and save into X let's say(before first arithmetic symbol) and then at each symbol you find take the value after it and do what that symbol is meant to with the X . – Macpp Sep 03 '15 at 10:55
0

It's not a complete solution but hey it's something... try this code:

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

#define MAX_SIZE (1000)

static char tempNumStr[50] = {0};
static double parsedDoubleArr[5] = {0};
static char parsedOperators[5] = {0};

void flushTempArr(char tmpArr[50]){
    for(int i=0; i< 50; i++)
        tmpArr[i]  = 0 ;
}

int tempNumStrIterator=0;

int parsedDoubleArrIterator=0;
int parsedOperatorsIterator=0;


int main(void)
{


    char operator;
    char sourceStr[] = "(17.5 + 8)";

    for(int i = 0; sourceStr[i] != '\0'; ++i) /*iterate over string till \0 */
    {
        if (IsDigit(sourceStr[i]))
        {
            while(sourceStr[i] != '\0' && IsDigit(sourceStr[i]))
            {
                tempNumStr[tempNumStrIterator++] = sourceStr[i];
                ++i;
            }

            sscanf(tempNumStr, "%lf", &parsedDoubleArr[parsedDoubleArrIterator++]);
            flushTempArr(tempNumStr);
            tempNumStrIterator = 0;
        }

        if (IsCalcOperator(sourceStr[i]))
        {
            parsedOperators[parsedOperatorsIterator++] = sourceStr[i];
        }

        else if (IsBracket(sourceStr[i]))
        {
            //do something
            continue;
        }
    }

    //do what you want with parsedDoubleArr and parsedOperators

    return EXIT_SUCCESS;
}
Eran Peled
  • 767
  • 6
  • 6