Thread: Write a program to model a simple calculator

  1. #1
    Registered User
    Join Date
    Nov 2010
    Posts
    36

    Question Write a program to model a simple calculator

    Hi there i'm working on an assignment and i have hit a problem.
    Here is the question:

    Write a program to model a simple calculator. Each data line should consist of the next operation to be preformed from the list below and the right operand. Assume the left operand is the accumulator value (initial value of 0). You need a function scan_data with two output parameters that returns the operator and right operand scanned from the data line. You need a function do_next_op that performs the required operation. do_next_op has two input parameters (the operator and operand) and one input/output parameter (the accumulator). The valid operators are:

    + add
    - subtract
    * multiply
    / divide
    ^ power (raise left operand to the power of the right operand)
    q quit

    Your calculator should display the accumulator value after each operation. A sample run follows.
    + 5.0
    Result so far is 5.0
    ^ 2
    Result so far is 25.0
    / 2.0
    Result so far is 12.5
    q 0
    final result is 12.5


    So far this is what i have down for this
    insert
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    
    void help(void);
    void scan_data(char sign, float num);
    void do_next_op(char sign, float num);
    
    int main() 
    {
        int x, y, sum;
    	char op, temp;
    	
    	scan_data('p',9);
    	
    	return 0;
    }
    
    void help(void)
    {
     char op[3] ;
     char text[9];
    		FILE *help;
    
    help = fopen("operator.txt","w");
    fprintf(help,"%s\t%s\n", "+" , "add");
    fprintf(help,"%s\t%s\n", "-" , "subtract");
    fprintf(help,"%s\t%s\n", "*" , "multiply");
    fprintf(help,"%s\t%s\n", "/" , "divide");
    fprintf(help,"%s\t%s\n", "^" , "power");
    fprintf(help,"%s\t%s", "q" , "quit");
    
    fclose(help);
    
    help = fopen("operator.txt", "r");
    
    while(!feof(help))
    {
    	fscanf(help, "%s\t%s", &op, &text);
    printf("%s\t%s\n", op, text);
    }
    
    fclose(help);
    }
    
    void scan_data(char sign, float num)
    {
    	
        char op, temp;
    	float num1;
    		
    			scanf("%c", &temp);
    			printf("Enter an operator [^,*,/,+,-, q(quit), h(help)]:\n");
    			scanf("%c", &op);
    			
    		
    			
    			if(op=='q'||op=='Q')
    			{
    				exit(0);
    			}
    			if(op=='h'||op=='H')
    			{
    				help();
    				
    			}
    
    				printf("Enter a number to calculate for: ");
    				scanf("%f", &num1);
    				printf("%c%1.2f\n",op ,num1);
    				
    				do_next_op(op, num1);
    	
    	
    
    }
    
    void do_next_op(char sign, float num)
    {
    	float sum = 0;
    	
    	
    	switch(sign)
    	{
    	case('^'):
    	{
    		sum=pow(sum,num);
    		printf("The result so far is %1.2f\n", sum);
    		scan_data('p',9);
    	}
    	
    	case('*'):
    		{
    		sum=sum*num;
    		printf("The result so far is %1.2f\n", sum);
    		scan_data('p',9);
    		
    		}
    	case('/'):
    		{
    		if(sign=='/')
    		{
    		 if(num<=0)
    		{
    			 printf("Can not divide by 0\n");
    			 scan_data('p',9);
    			}
    			if(num>0)
    			{
    			
    			sum=sum/num;
    			printf("The result so far is %1.2f\n", sum);
    			scan_data('p',9);
    			}
    			
    		}
    		
    		
    		}
    	case('+'):
    		{
    			sum=sum+num;
    			printf("The result so far is %1.2f\n", sum);
    			scan_data('p',9);
    				
    		}
    	case('-'):
    	{
    		sum=sum-num;
    		printf("The result so far is %1.2f\n", sum);
    		scan_data('p',9);
    		
    	}
    	default:
    		break;
    	
    
    	}
    }
    Sorry if its a bit messy or confusing in certain places, I like to fix these things up after my test runs work.

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Code:
    	case('/'):
    		{
    		if(sign=='/')
    Seems a bit redundant to me. I think perhaps you added that in an attempt to make it work because you're missing break statements in your switch.

    Code:
    while(!feof(help))
    Cprogramming.com FAQ > Why it's bad to use feof() to control a loop
    I'm not sure why you're even writing to that file, unless you have to create it for its own sake.

    Also, your program doesn't seem to be doing what is required. You prompt for operators and numbers separately, while the directions say to accept it all on one line.

    You shouldn't have to use recursion to repeat the calculations, either. It should be as straightforward as
    Code:
    char op;
    float value = 0.0f, temp;
    while(scanf("%c%d", &op, &temp) == 2) {
        switch(op) {
        case '^':
            value = pow(value, temp);
            break;
        /* ... */
        }
    
        printf("So far: %f\n", value);
    }
    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
    Nov 2010
    Posts
    36
    I changed my case statements to have breaks in them. The function that writes to a file is extra and does not need attention. Thanks for the tip on not using FEOF as a condition for a loop. Without having recursion in my do_next_op function. How will it be able to accumulate another command. As the program is now it will do the first command and calculate whatever you throw in for an operator and number by 0. Then ends the program. Also as far as the commands on one line go i am not worried about that at the moment. How will my functions be able to accumulate the sum value?

    Code:
    void scan_data(char sign, float num)
    {
    	
        char op, temp;
    	float num1;
    		
    	do{
    		scanf("%c", &temp);
    			printf("Enter an operator [^,*,/,+,-, q(quit), h(help)]:\n");
    			
    			scanf("%c", &op);
    			
    			if(op=='h'||op=='H')
    			{
    				help();
    				
    			}
    
    		
    			printf("Enter a number to calculate for: ");
    			scanf("%f", &num1);
    			printf("%c%1.2f\n",op ,num1);
    			do_next_op(op, num1);
    	}while(op=='q'||op=='Q');
    	
    	
    
    }
    
    void do_next_op(char sign, float num)
    {
    	float sum = 0;
    	
    	switch(sign)
    	{
    	case('^'):
    	{
    		sum=pow(sum,num);
    		printf("The result so far is %1.2f\n", sum);
    		break;
    	}
    	
    	case('*'):
    		{
    		sum=sum*num;
    		printf("The result so far is %1.2f\n", sum);
    		break;
    		
    		}
    	case('/'):
    		{
    		if(sign=='/')
    		{
    		 if(num<=0)
    		{
    			 printf("Can not divide by 0\n");
    			 
    			}
    			if(num>0)
    			{
    			
    			sum=sum/num;
    			printf("The result so far is %1.2f\n", sum);
    			
    			}
    			
    		}
    		
    		break;
    		}
    	case('+'):
    		{
    			sum=sum+num;
    			printf("The result so far is %1.2f\n", sum);
    			break;
    				
    		}
    	case('-'):
    	{
    		sum=sum-num;
    		printf("The result so far is %1.2f\n", sum);
    		break;
    		
    	}
    	default:
    		break;
    	
    
    	}
    }

  4. #4
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Without having recursion in my do_next_op function. How will it be able to accumulate another command. As the program is now it will do the first command and calculate whatever you throw in for an operator and number by 0. Then ends the program. Also as far as the commands on one line go i am not worried about that at the moment. How will my functions be able to accumulate the sum value?
    You have already implemented your code without using mutual recursion; you've used a loop instead of calling scan_data() again inside of do_next_op(). That's how you can keep the program looping.

    As for the sum value: obviously once you've calculated the new accumulator value in do_next_op(), you need to get that information back to scan_data() somehow so that you can keep using this value. The easiest way is to return the modified value back from do_next_op().
    Code:
    void scan_data(char sign, float num) {
        float num = 0.0f;
        do {
            // ...
            num = do_next_op(op, num1);
            // ...
        } while( /*...*/ );
    }
    
    float do_next_op(char sign, float num) {
        // change num in switch statement ...
        return num;
    }
    Something like that.

    Look again closely at the example I have in my previous post. It's not separating the code out into two functions, but using just one block of code with one loop to do all the work. Maybe you can try to understand how it works and apply the same ideas to your own code. If you want to separate the code for handling an operator out into a function, that's great, but make sure you can get the modified value back into the calling function, by using a return value.
    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
    Nov 2010
    Posts
    36
    Thanks dwk, I was not aware that i could return a value for a function that had two seperate parameter types such that a functions such as

    float do_next_op(char sign, float num, float sum); could return a value such as a float i thought a function prototype such as that had to be void because it was working with different type of parameters such as char and float and lets say int. So because i realized that here is the finished product %100 working for anyone else stuck on the same question.

    Code:
    #include <stdio.h>
    #include<stdlib.h>
    #include <math.h>
    
    
    void help(void);
    void scan_data(char sign, float num);
    float do_next_op(char sign, float num, float sum);
    
    
    int main() 
    {
    	printf("Hit enter to turn the calculator on");
    	scan_data('x',1);
    	
    	return 0;
    }
    
    
    
    void scan_data(char sign, float num)
    {
    	
        char op, temp;
    	float sum;
    	sum = 0;
    	
    	do{
    			
    		scanf("%c", &temp);
    		printf("Enter an operator [^,*,/,+,-, q(quit), h(help)]:\n");
    		scanf("%c", &op);
    			
    		if(op=='q'||op=='Q')
    		{
    			printf("The last result was %1.2f\n", sum);
    			exit(0);
    		}
    			
    		if(op=='h'||op=='H')
    		{
    			help();		
    		}
    		
    		else
    		{
    			printf("Enter a number to calculate for: ");
    			scanf("%f", &num);
    			printf("%c%1.2f\n",op ,num);
    			sum = do_next_op(op, num, sum);
    		}
    		
    
    		}while(op!='q'||op!='Q');
    	
    }
    
    float do_next_op(char sign, float num, float sum)
    {
    	
    	
    	switch(sign)
    	{
    		case('^'):
    		
    			sum =  pow(sum,num);
    			printf("The result so far is %1.2f\n", sum);
    			
    			return sum;
    			break;
    
    	
    		case('*'):
    		
    			sum = sum * num;
    			printf("The result so far is %1.2f\n", sum);
    			
    			return sum;
    			break;
    		
    		case('/'):
    		
    		
    		if(num<=0)
    		{
    			printf("Can not divide by 0\n");
    			printf("The result so far is %1.2f\n", sum);
    			
    			return sum;
    			 
    			 
    		}
    			
    		else if(num>0)
    		{
    			
    			sum=sum/num;
    			printf("The result so far is %1.2f\n", sum);
    			
    			return sum;
    			
    		}
    			break;
    	
    		case('+'):
    		
    			sum=sum+num;
    			printf("The result so far is %1.2f\n", sum);
    			
    			return sum;
    			break;
    				
    		
    		case('-'):
    	
    			sum=sum-num;
    			printf("The result so far is %1.2f\n", sum);
    			
    			return sum;
    			break;
    		
    	
    		default:
    			break;
    		
    	}
    }
    	
    void help(void)
    {
    	printf("%s\t%s\n", "+" , "add");
    	printf("%s\t%s\n", "-" , "subtract");
    	printf("%s\t%s\n", "*" , "multiply");
    	printf("%s\t%s\n", "/" , "divide");
    	printf("%s\t%s\n", "^" , "power");
    	printf("%s\t%s\n", "q" , "quit");
    		
    }

  6. #6
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Looks good. I have a few comments about style. You'll notice that you have the code
    Code:
    			printf("The result so far is %1.2f\n", sum);
    			
    			return sum;
    in (almost) every single one of your switch cases. If you move this outside the switch it makes the code much cleaner.
    Code:
    float do_next_op(char sign, float num, float sum)
    {
            switch(sign)
            {
                    case('^'):
                            sum =  pow(sum,num);
                            break;
                    
                    case('*'):
                            sum = sum * num;
                            break;
                    
                    case('/'):
                            if(num<=0)
                            {
                                    printf("Can not divide by 0\n");
                            }
                            else if(num>0)
                            {
                                    sum=sum/num;
                            }
                            break;
                    
                    case('+'):
                            sum=sum+num;
                            break;
                    
                    case('-'):
                            sum=sum-num;
                            break;
                    
                    default:
                            break;
            }
            
            printf("The result so far is %1.2f\n", sum);
            
            return sum;
    }
    I point this out because I'm not sure if you understand how switch statements work, given that you have a break after each return. When you enter a switch statement, you examine the value you're switching on; then, if there's a match in any of the cases, you jump immediately to that position and continue executing. If there's no match, you goto the default case (or skip the switch entirely if there are no matches and no default case).

    Once you're inside a switch statement, you don't stop once you reach another case label. This is what break is for: it ends the switch statement, so that execution will continue on the line after the switch. Thus generally we put a break after each case; but you can use the "fall-through" effect to your advantage sometimes. For example:
    Code:
    int bored(int times) {
        printf("I've done that");
        switch(times) {
        default:
        case 3:
            printf(" and again");
        case 2:
            printf(" and again");
        case 1:
            printf(" and again");
        case 0:
        }
        printf(" before.\n");
    }
    
    /** Output:
            bored(0)  -> I've done that before.
            bored(1)  -> I've done that and again before.
            bored(2)  -> I've done that and again and again before.
            bored(3)  -> I've done that and again and again and again before.
            bored(4)  -> like 3.
        and so on.
    */
    Note that there is no break at all; in the first cases I want execution to continue onto the next cases, and in the last case there's no need for a break since all it would do is jump execution to the code following the switch, which is what would happen anyway as we fall off the end of the switch statement.

    Another point: you presumably have
    Code:
    		scanf("%c", &temp);
    to remove the newline that occurs after someone has entered a number like "123\n". As you know, the scanf("%f") doesn't deal with the newline and you have to do it yourself. However, there are nicer ways of doing this rather than having the user hit enter. For example, you could use
    Code:
    while(getchar() != '\n') {}
    after the scanf("%f") statement. This has the advantage of not breaking if the user enters something like "123garbage\n".

    Last comments: scan_data() doesn't need to take any arguments anymore. Also, tolower() in ctype.h converts a character like 'Q' to the lowercase equivalent, 'q'.
    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.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Could someone please write a simple program for me?!
    By danjer242 in forum C++ Programming
    Replies: 1
    Last Post: 03-28-2010, 10:43 PM
  2. How to write a program
    By Tashfique in forum C++ Programming
    Replies: 4
    Last Post: 10-17-2008, 11:28 AM
  3. Replies: 4
    Last Post: 02-21-2008, 10:39 AM
  4. Replies: 1
    Last Post: 10-13-2004, 12:15 PM