Thread: Simple expressions using functions

  1. #1
    Registered User
    Join Date
    May 2010
    Posts
    27

    Simple expressions using functions

    I need to create a function to read a simple expression that can accept both float and int values, and have hit a bump in the road.

    For example: In my main routine, I need to enter Eval(2 + 3), and the main routine needs call the function to process the numbers and display the answer.

    All of my other functions work correctly with the exception of my eval function, is my error something small, or am I way off base?

    Here is my main routine and eval() function, please make suggestions on what I am doing wrong. Thank you.

    Code:
    /* Justin Fry
     * CS 133U
     * Lab5A.c
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    double eval(double);
    int fact(int);
    int perm(int);
    char doQuit(char);
    char userInput(char);
    
    
    int main() 
    {
        char userInput[2048];
        char optionA;
        char operA;
        double opers[1], answer;
        int varN, varK;
        int result;
    
      do{
        printf("Enter one of the following options: \n\
                  Q - Quit the program\n\
                  Eval(<exp>) - Evaluate a simple expression\n\
                  ! - Evaluate an integer factorial\n\
                  P(n,k) - Count k-permutations of a string of n characters\n\
             \n\ Enter your option: ");
    
          fgets(userInput,2048,stdin);
        if((strstr(userInput,"Q") != NULL) || (strstr(userInput,"q") != NULL)) {
                     optionA = doQuit(optionA);
        } else if((strstr(userInput,"Eval") != NULL) ||
           (strstr(userInput,"eval") != NULL) ||
           (strstr(userInput,"EVAL") != NULL)) { 
            answer = eval(answer);
        } else if(strstr(userInput,"!") != NULL) {
             sscanf(userInput,"%*c%d%*c", &varN);
             printf("%d! = %d\n",varN, fact(varN));;
        } else if((strstr(userInput,"P") != NULL) ||
           (strstr(userInput,"p") != NULL)) {
             sscanf(userInput,"%*c%*c%d%*c%d%*c", &varN, &varK);
             printf("A string of %d characters has %d permutations of length %d\n",
                       varN, perm(varN), varK);
        }
       } while(0 == 0);
    }  
    
    double eval(double answer)
    {
        char userInput[2048];
        char decimalCount, operA;
        int idx; 
        double opers[1], index;
    
           opers[0] = 0;
           opers[1] = 0;
           answer = 1.00;
           decimalCount = 0;         
            
    
        fgets(userInput,2048,stdin);
        for(idx = 0; idx <= strlen(userInput); idx++){
        if(userInput[idx] == '.'){
             decimalCount++;
        }
        }  if((decimalCount == 1) || (decimalCount == 2)) {                 
                  sscanf(userInput,"(%lf %c %lf%)", 
                                                &opers[0], &operA, &opers[1]);
                  switch(operA) {
                       case '+':
                       answer = opers[0] + opers[1];
                       printf("%.2lf %c %.2lf = %.2lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '-':
                       answer = opers[0] - opers[1];
                       printf("%.2lf %c %.2lf = %.2lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '/':
                       answer = (float)opers[0] / (float)opers[1];
                       printf("%.2lf %c %.2lf = %.2lf\n", 
                                     opers[0], operA, opers[1], answer);
                       break;
                       case '*':
                       answer = opers[0] * opers[1];
                       printf("%.2lf %c %.2lf = %.2lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '%':
                       answer = (int)opers[0] % (int)opers[1];
                       printf("%.2lf %c %.2lf = %.2lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '^':
                       for(index = 1; index <= opers[1]; index++) 
    
                       answer = answer * opers[0];
                       
                       printf("%.0lf %c %.0lf = %.0lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       default:
                                 answer = 0;
                                 printf("?'%c' is not a valid operator\n", operA);
                       }
            
             } else if(decimalCount == 0) {            // Evaluate simple expression
                  sscanf(userInput,"(%lf %c %lf)", 
                                                &opers[0], &operA, &opers[1]);
                  switch(operA) {
                       case '+':
                       answer = opers[0] + opers[1];
                       printf("%.0lf %c %.0lf = %.0lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '-':
                       answer = opers[0] - opers[1];
                       printf("%.0lf %c %.0lf = %.0lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '/':
                       answer = opers[0] / opers[1];
                       printf("%.0lf %c %.0lf = %.0lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '*':
                       answer = opers[0] * opers[1];
                       printf("%.0lf %c %.0lf = %.0lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '%':
                       answer = (int)opers[0] % (int)opers[1];
                       printf("%.0lf %c %.0lf = %.0lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '^':
                       for(index = 1; index <= opers[1]; index++) 
    
                       answer = answer * opers[0];
                       
                       printf("%.0lf %c %.0lf = %.0lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       default:
                                 answer = 0;
                                 printf("?'%c' is not a valid operator\n", operA);
                       }
                       }
    return answer;
    }

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    A suggestion that might make your code a bit simpler: you could convert the user's input to all lower or upper case and then check for e.g. "eval" after that. Also, there is a floating-point modulus function fmod() that you could use, and a function pow() to evaluate powers (even floating-point ones like 2^0.37).

    Now for the problems. Your opers array isn't big enough. It's declared as opers[1], but you access both opers[0] and opers[1], so you need to declare it to be at least [2]. Remember that if an array has N elements, the valid indices are [0, N-1].

    Also, while with scanf() you must use %lf for doubles (and %f for floats), for printf() the format specifier %f is used for floats and doubles.

    Finally, it looks to me like you fgets() an entire line in main() and then call fgets() again in eval(). This will not re-read the same data. What you probably want to do is to fgets() the line once in main(), and then pass around a char[] buffer or something of the remaining tokens to functions like eval().

    By the way, you can make your life a lot easier if you use prefix notation, i.e. use "+ 2 3" to represent (2+3). But if you insist on being able to process expressions like ((2*4)+8), then I'd suggest you create one function for handling (), one for +, one for *, etc. and then use recursion to break it up. Insisting that the expression be fully parenthesized, disallowing expressions like (2*4+8), also helps.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    Registered User
    Join Date
    May 2010
    Posts
    27
    Thank you,
    My program must take expressions in the form eval(2 + 3), for example, with 'eval' being the prompt for the main routine to call the eval function. the function must process the following operators: + - / * % and exponentiation. My issue is that I do not get the answer I am looking for. The 2 variables are read correctly, but my answer is not correct, I just get the default from my switch statement, which is my coded error message.

    I am not calling the function correctly, and I can not figure out why.

  4. #4
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    I pointed out a number of problems in your code. Did you try to fix any of them? As I said, the main issue here is that you are calling fgets() twice, so your program will be reading multiple lines in the process of computing the value in one "expression".

    The way you're calling eval() is just fine. I'm not sure why you're passing answer into the function where it could just return the value, but it should work just the same. It's the implementation of eval() that's flawed.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  5. #5
    Registered User
    Join Date
    May 2010
    Posts
    27
    I have made a few adjustments, but I still cannot get the program to calculate the answer correctly. The reason I had fgets twice was because I was calculating the number of decimal points to determine whether the user inputted int's or float's. I removed the fgets in my eval function, and moved my decimal count to my main routine. This forced me to separate my eval into two functions though, one for int's and the other for floats. I am also not allowed to use the math.h library which is why I am not using pow. With these changes, I am still not getting anywhere. My answer is always the default output of my switch statement, like my program is not reading the operator correctly. I am also using Dev C++, which allows %lf for double values in scanf.

    The user should input something like Eval(2 + 3)

    The program output should be 2 + 3 = 5

    It needs to do this no matter the numbers or operators provided, but the input must be in the form of 'eval(x y x), with x being a variable and y being an operator.

    Here are the changes I have made so far
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    double evalFloat(double);
    int evalInt(int);
    char doQuit(char);
    
    
    
    int main() 
    {
        char userInput[2048];
        char optionA;
        char operA;
        double opers[2], answer;
        int idx, decimalCount, varA, varN, varK;
        int result, answerA;
    
      do{
        printf("Enter one of the following options: \n\
                  Q - Quit the program\n\
                  Eval(<exp>) - Evaluate a simple expression\n\
                    \n\ Enter your option: ");
    
          fgets(userInput,2048,stdin);
          for(idx = 0; idx <= strlen(userInput); idx++){
          if(userInput[idx] == '.'){
             decimalCount++;
             }
        }
          
        if((strstr(userInput,"Q") != NULL) || (strstr(userInput,"q") != NULL)) {
                     optionA = doQuit(optionA);
        } else if((strstr(userInput,"Eval") != NULL) ||
           (strstr(userInput,"eval") != NULL) ||
           (strstr(userInput,"EVAL") != NULL)) { 
                  if((decimalCount == 1) || (decimalCount == 2)) { 
                            sscanf(userInput,"%*c%*c%*c%*c%*c%lf %c %lf%*c\n",
                                  &opers[0], &operA, &opers[1]);
                                  answer = evalFloat(answer);        
                } else {
                                   answerA = evalInt(answerA);
                }                                            
             
        } 
       } while(0 == 0);
    }
    
    
    char doQuit(char optionA)
    {
         exit(0);
    } 
      
    
    double evalFloat(double answer)
    {
        
        char operA;
        double opers[2], index;
    
           opers[0] = 0;
           opers[1] = 0;
           answer = 1.00;
                  
    
                 
                  
                  switch(operA) {
                       case '+':
                       answer = opers[0] + opers[1];
                       printf("%.2lf %c %.2lf = %.2lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '-':
                       answer = opers[0] - opers[1];
                       printf("%.2lf %c %.2lf = %.2lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '/':
                       answer = (float)opers[0] / (float)opers[1];
                       printf("%.2lf %c %.2lf = %.2lf\n", 
                                     opers[0], operA, opers[1], answer);
                       break;
                       case '*':
                       answer = opers[0] * opers[1];
                       printf("%.2lf %c %.2lf = %.2lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '%':
                       answer = (int)opers[0] % (int)opers[1];
                       printf("%.2lf %c %.2lf = %.2lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       case '^':
                       for(index = 1; index <= opers[1]; index++) 
    
                       answer = answer * opers[0];
                       
                       printf("%.0lf %c %.0lf = %.0lf\n", 
                                      opers[0], operA, opers[1], answer);
                       break;
                       default:
                                 answer = 0;
                                 printf("?'%c' is not a valid operator\n", operA);
                       }
     return answer;       
    }
    
    int evalInt(int answerA)
    {
            char operA;
            int opers[2], index;
    
           opers[0] = 0;
           opers[1] = 0;
           answerA = 1;
                  
                  switch(operA) {
                       case '+':
                       answerA = opers[0] + opers[1];
                       printf("%d %c %d = %d\n", 
                                      opers[0], operA, opers[1], answerA);
                       break;
                       case '-':
                       answerA = opers[0] - opers[1];
                      printf("%d %c %d = %d\n",  
                                      opers[0], operA, opers[1], answerA);
                       break;
                       case '/':
                       answerA = opers[0] / opers[1];
                       printf("%d %c %d = %d\n",  
                                      opers[0], operA, opers[1], answerA);
                       break;
                       case '*':
                       answerA = opers[0] * opers[1];
                      printf("%d %c %d = %d\n", 
                                      opers[0], operA, opers[1], answerA);
                       break;
                       case '%':
                       answerA = (int)opers[0] % (int)opers[1];
                       printf("%d %c %d = %d\n",  
                                      opers[0], operA, opers[1], answerA);
                       break;
                       case '^':
                       for(index = 1; index <= opers[1]; index++) 
    
                       answerA = answerA * opers[0];
                       
                       printf("%d %c %d = %d\n",
                                      opers[0], operA, opers[1], answerA);
                       break;
                       default:
                                 answerA = 0;
                                 printf("?'%c' is not a valid operator\n", operA);
                       }
    return answerA;
    }

  6. #6
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Were you planning to pass the operands and the operators to your eval function, or does it just have to guess?

    Also you should set decimalCount to some number other than 736234 before you start counting the decimal points.

  7. #7
    Registered User
    Join Date
    May 2010
    Posts
    27
    Oops,
    I forgot to set my decimalCount to 0, as for the operand and operators, how do I pass them to the eval function?

  8. #8
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by jusfry01 View Post
    Oops,
    I forgot to set my decimalCount to 0, as for the operand and operators, how do I pass them to the eval function?
    Just like you pass anything else to a function. After all, you're already passing something to the function -- now pass in the things the function actually cares about.

  9. #9
    Registered User
    Join Date
    May 2010
    Posts
    27
    I have no idea how to pass my operators to the eval function. I tried setting
    opers[0] = evalFloat(opers[0]), opers[1] = evalFloat(opers[1]), and so on, but it did not work.

  10. #10
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    functioncall(put everything in here), just as before. You'll obviously have to change your function declaration to accept three arguments instead of just one.

  11. #11
    Registered User
    Join Date
    May 2010
    Posts
    27
    I have put my two operands and answer into my function parameters, and I do not get any compiler errors now, but I do not think I am calling everything correctly. When I run the program my input might be 'eval(2 + 3), and my output is always '0 0 = 0'. this tells me that the operator is being ignored altogether, and I have no idea why all of the numbers get set to '0'.


    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    double evalFloat();
    double evalInt();
    int fact(int);
    int perm(int);
    char doQuit(char);
    void evalInput();
    
    
    int main() 
    {
        evalInput();
        return 0;
    }
    
    void evalInput()
    {
        char userInput[2048];
        char optionA;
        char operA, idx, decimalCount;
        double opersA, opersB, answer;
        int varA, varN, varK;
        int result;
    
        decimalCount = 0;
    
      printf("Enter one of the following options: \n\
                  Q - Quit the program\n\
                  Eval(<exp>) - Evaluate a simple expression\n\
                  ! - Evaluate an integer factorial\n\
                  P(n,k) - Count k-permutations of a string of n characters\n\
             \n\ Enter your option: ");
    
          fgets(userInput,2048,stdin);
          for(idx = 0; idx <= strlen(userInput); idx++){
          if(userInput[idx] == '.'){
             decimalCount++;
        }
        }
        if((strstr(userInput,"Q") != NULL) || (strstr(userInput,"q") != NULL)) {
                     optionA = doQuit(optionA);
        } else if((strstr(userInput,"Eval") != NULL) ||
           (strstr(userInput,"eval") != NULL) ||
           (strstr(userInput,"EVAL") != NULL)) { 
                if((decimalCount == 1) || (decimalCount == 2)) {
                   sscanf(userInput,"%*c%*c%*c%*c%*c%lf %c %lf%*c", 
                                                &opersA, &operA, &opersB); 
                   printf("%.3lf %c %.3lf = %.3lf\n", 
                          evalFloat(opersA), evalFloat(operA),
                           evalFloat(opersB), evalFloat(answer));
                } else if(decimalCount == 0) {
                   sscanf(userInput,"%*c%*c%*c%*c%*c%lf %c %lf%*c", 
                                                &opersA, &operA, &opersB);
                   printf("%.0lf %c %.0lf = %.0lf\n", 
                          evalInt(opersA), evalInt(operA),
                           evalInt(opersB), evalInt(answer));
                }  
             
        } else if(strstr(userInput,"!") != NULL) {
             sscanf(userInput,"%*c%d%*c", &varN);
             printf("%d! = %d\n",varN, fact(varN));;
        } else if((strstr(userInput,"P") != NULL) ||
           (strstr(userInput,"p") != NULL)) {
             sscanf(userInput,"%*c%*c%d%*c%d%*c", &varN, &varK);
             varA = fact(varN) / fact(varN - varK);
             printf("A string of %d characters has %d permutations of length %d\n",
                       varN, varA, varK);
        }
        evalInput();
        return;
    }
    
    
    char doQuit(char optionA)
    {
         exit(0);
    }
    
      
    double evalFloat(double answer, double opersA, double opersB)
    {
        char operA; 
        double index;
    
                  switch(operA) {
                       case '+':
                       answer = opersA + opersB;
                       //printf("%.2lf %c %.2lf = %.2lf\n", 
                         //             opers[0], operA, opers[1], answer);
                       break;
                       case '-':
                       answer = opersA - opersB;
                       //printf("%.2lf %c %.2lf = %.2lf\n", 
                         //             opers[0], operA, opers[1], answer);
                       break;
                       case '/':
                       answer = (float)opersA / (float)opersB;
                       //printf("%.2lf %c %.2lf = %.2lf\n", 
                         //            opers[0], operA, opers[1], answer);
                       break;
                       case '*':
                       answer = opersA * opersB;
                       //printf("%.2lf %c %.2lf = %.2lf\n", 
                         //             opers[0], operA, opers[1], answer);
                       break;
                       case '%':
                       answer = (int)opersA % (int)opersB;
                       //printf("%.2lf %c %.2lf = %.2lf\n", 
                         //             opers[0], operA, opers[1], answer);
                       break;
                       case '^':
                       for(index = 1; index <= opersB; index++) 
    
                       answer = answer * opersA;
                       
                       //printf("%.2lf %c %.2lf = %.2lf\n", 
                         //             opers[0], operA, opers[1], answer);
                       break;
                       default:
                                 answer = 0;
                           //      printf("?'%c' is not a valid operator", operA);
                       }
                       return answer;
    }
    
    
    double evalInt(double answer, double opersA, double opersB) 
    {
           char operA;
           int idx; 
           double index;
    
                  switch(operA) {
                       case '+':
                       answer = opersA + opersB;
                       //printf("%.0lf %c %.0lf = %.0lf\n", 
                         //             opers[0], operA, opers[1], answer);
                       break;
                       case '-':
                       answer = opersA - opersB;
                       //printf("%.0lf %c %.0lf = %.0lf\n", 
                         //             opers[0], operA, opers[1], answer);
                       break;
                       case '/':
                       answer = opersA / opersB;
                       //printf("%.0lf %c %.0lf = %.0lf\n", 
                         //             opers[0], operA, opers[1], answer);
                       break;
                       case '*':
                       answer = opersA * opersB;
                       //printf("%.0lf %c %.0lf = %.0lf\n", 
                         //             opers[0], operA, opers[1], answer);
                       break;
                       case '%':
                       answer = (int)opersA % (int)opersB;
                       //printf("%.0lf %c %.0lf = %.0lf\n", 
                         //             opers[0], operA, opers[1], answer);
                       break;
                       case '^':
                       for(index = 1; index <= opersB; index++) 
    
                       answer = answer * opersA;
                       
                       //printf("%.0lf %c %.0lf = %.0lf\n", 
                         //             opers[0], operA, opers[1], answer);
                       break;
                       default:
                                 answer = 0;
                         //        printf("?'%c' is not a valid operator", operA);
                       }
                       return answer;
    }

  12. #12
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Why are you calling eval* four times?
    Code:
     printf("%.0lf %c %.0lf = %.0lf\n", 
                          evalInt(opersA), evalInt(operA),
                           evalInt(opersB), evalInt(answer));
    Shouldn't it just be:
    Code:
     printf("%.0lf %c %.0lf = %.0lf\n", 
                          opersA, operA,
                           opersB, evalInt(answer));
    ?

    Actually, your functions take multiple arguments, and you only pass them one. This shouldn't even compile.

    Quzah.
    Last edited by quzah; 05-25-2010 at 04:26 PM.
    Hope is the first step on the road to disappointment.

  13. #13
    Registered User
    Join Date
    May 2010
    Posts
    27
    Thank you Quzah, I made those changes to my code, but I am still don't think I am calling the function correctly. My answer comes out as a random number. If I input 'eval(2 + 3)' the output is '2 + 3 = 23166434916019671000000000000000000000000000000000 00.

    Any ideas?

  14. #14
    Registered User
    Join Date
    May 2010
    Posts
    27
    I finally got it!!
    Thanks again for the help

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Thread safety for tiny simple functions
    By CodeMonkey in forum C++ Programming
    Replies: 16
    Last Post: 12-31-2008, 12:20 AM
  2. Replies: 7
    Last Post: 11-17-2008, 01:00 PM
  3. Simple Socialising Chat Bots
    By bengreenwood in forum C++ Programming
    Replies: 10
    Last Post: 11-28-2007, 08:42 AM
  4. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM
  5. Second Program
    By cyberCLoWn in forum C++ Programming
    Replies: 28
    Last Post: 12-08-2003, 11:48 AM