|
4. A Crude Calculator
Previous | Next Now, what we have done so far was pretty useless, so, when are we going to get to do something that actually is of some value? OK. Let's try creating our first useful program: a crude calculator. For this we'll revamp our main() function again: #include <stdio.h> #include <stdbool.h>
int main() { int vFirstArg, vSecondArg; char vOperation; bool vFinished; // Make sure our flag is initialized! vFinished = false; // Now loop until user doesn't want anymore: while( vFinished != true ) { printf( "What operation do you want to do?\n" ); scanf( "%c", &vOperation ); fpurge( stdin ); if( vOperation == '+' ) { printf( "Enter left argument: " ); scanf( "%d", &vFirstArg ); fpurge( stdin ); printf( "\nEnter right argument: " ); scanf( "%d", &vSecondArg ); fpurge( stdin ); printf( "\n%d + %d = %d\n", vFirstArg, vSecondArg, vFirstArg + vSecondArg ); } else vFinished = true; } printf( "Finished.\n" ); return 0; } The first new thing here is char, which is the variable type used for a single character. Note that single characters are usually enclosed in single quotes, aka apostrophes, unlike the usual bunch of text like what we hand to printf() (However, there is also text of 1 character in length, I'll explain that more closely later). To hand a char to printf() or scanf(), use the %c format sequence. The second new type is bool, which is short for boolean. A boolean is a value that can only have 2 states, either false or true (think of this as an on/off switch). It is defined in the header stdbool.h that we're now including in addition to stdio.h. An example: If you want to write a program that drives a car, you might want to have the driver check whether it's raining before starting to drive. You'd then use a boolean variable named e.g. isItRaining to remember this, so you can have your commands that hit the brakes when the car needs to stop check isItRaining. If it is raining, you might want to use the more careful braking code so your car doesn't get out of control. Anyway, if it rains, you'd assign the value true to it, while on good days you'd set it to false. Variables that contain booleans are often also called flags -- this comes from US postal mail boxes, which have a little flag on them which can be turned up to indicate to the postman that it contains mail to be picked up. Now, the first line after the variable declarations assigns the value false to our bool variable vFinished. This is necessary since a newly-declared variable contains garbage. Not zero, not true, not false, just any arbitrary value. If your program wants to use a variable, make sure you have assigned it a value. Assigning a value to a variable the first time is usually also called initializing a variable. The next line is something new: The While-Loop. A while loop takes the following form: while( <condition> ) <command>; And does the command <command> repeatedly, while the boolean value <condition> is true. That is, it checks whether <condition> is true, if not just goes on with the rest of the program, but if it is, does <command> and checks <condition> again. If it is still true, it just repeats this behaviour endlessly until <condition> becomes false. Note that there is no semicolon behind the braces around the condition.  If you have a loop that just seems to get stuck, never doing something, or an if statement that just always seems to think it was true, check whether you accidentally put a semicolon after the condition. A single lone semicolon is considered an "empty command" or a "no-operation". I.e. you're asking the computer to do nothing by accident. while and if lines do not end in a semicolon.  So, why is this called a "loop"? Well, if you draw a line from each command to the next as the computer does what the command tells it to, in the case of while, there will actually be a line going back up from the last command inside the loop to the while statement, making a nice small little looped circle. If you're wondering why we need to do the same commands repeatedly, it's time for a bit of storytelling again: Every computer program is usually just started, then runs its main() function and quits again. That's what all our previous programs did: They spilled some text to the terminal and then disappeared again. But more advanced programs can do lots of different things, and even do them in sequence. The art of programming is delaying the end of main() until the user has been able to do what she wanted and signals to us that it's time for our program to go. To achieve this, a program usually repeatedly asks the user to enter what she wants to do and then does that. And then asks again, does that, asks again ... until the user enters a special thing to do that tells us the user wants to exit our program (also called to quit). When that happens we have to cause our loop to end. For this reason we have vFinished. It's false when we start our program and stays this way until the user asks us to quit. At that moment, we set it to true to indicate we want to stop repeating our commands and finish.  Be careful with your loops. If you don't write the condition correctly or if you forget to put a line in your script that actually makes the program quit, you will have an endless loop ( infinite loop). The only way to get out of an infinite loop that you're running in Xcode is to click the little red "Tasks" stop sign in the toolbar to shoot down your program.  There are other ways to get out of a loop besides changing variables so the condition is no longer true: There is a command called break that you can use to jump out of a loop immediately, and continue with the commands below the loop. Similarly, you can use a command named continue to jump right back up to the while statement. Trouble is, while expects condition to be true while we want to repeat, whereas vFinished is true when we want to quit. Of course we could just turn vFinished into vKeepRunning and set it to true and be all hunky-dory, but you wanted to learn how to make the computer do what you want, not how to do what the computer wants, right? OK, so how do we fix this? We introduce the "is not" operator, !=. != compares what's to its left and right and if both sides have different values (for example, one of them is true and the other is false) it returns true. That is: 1 != 1 (read "one is not one") is the same as false, since you can't find an ounce of truth in the above statement. 2 != 2 (read "two is not two") is also the same as false. 1 != 2 (read "one is not two") is the same as true, as you will certainly agree that 1 is not 2, just like green is not red and a banana is not your sister (no offence to any bananas reading this). 2 != 1 (read "two is not one") is also the same as true, for obvious reasons. Note that you can compare anything using !=, be it booleans, numbers or characters (but not double-quoted text). You can even compare whatever is in a variable to the contents of another variable, but the type must match. I.e. if you are comparing a number to a variable, the variable must be of type int. If you compare true or false to a variable, the variable must be of type bool etc. So, to get back to our program: The condition of the loop is vFinished != true which is true if vFinished is false, and false if vFinished is true. Thus, it is exactly what we need here. Yeah! We won against the computer! Now an additional problem: I spoke of several commands, but a while loop may only have one command following it. What do we do? Well, there's also a solution for that: curly brackets! In C, you can use curly brackets to group several commands into one command: { vVariable = 1; vVariable = 2; }This is one command to C! (But note that they're still done one after the other by C - you can't use this to have your computer do five times the work) Thus, if we want several commands in our while loop, we just enclose them in curly braces. Note that even though there is no semicolon after the curly braces, C treats them as if there was a semicolon behind them. I.e. while( vKeepRunning ) { vVariable = 1; vVariable = 2; } is perfectly valid, just as while( vKeepRunning ) vVariable = 1; You needn't put a semicolon behind the closing curly bracket (and in most cases, you shouldn't). Now, the next two lines in the program are pretty straightforward. We ask the user what she wants to do and then we get the character the user typed using scanf(). The next part is what is interesting. Since we now have whatever the user wanted to do in our char variable vOperation, we now need to take special action depending on whatever is in vOperation. For this, we use the if conditional, which takes the form: if( <condition> ) <ifCommand>; else <elseCommand>; Where it does the command represented by <ifCommand> if <condition> is true, and <elseCommand> when <condition> is false. Note that you can leave away the entire "else" part if you want it to do nothing if <condition> is false, i.e. if( <condition> ) <ifCommand>; Note that while the if-conditional looks similar to the while-loop, an if is only executed once, whereas a while does things repeatedly. Now, we use the opposite to the "is not" operator != to compare vOperation to the values we want to handle. The opposite is the == operator, which means "is equal to". That is, if( vOperation == '+' ) does the <ifCommand> part if vOperation actually contains a "+" character, and else performs the <elseCommand> part. If you're wondering why the plus sign is enclosed in apostrophes instead of quote characters, re-read my statements on the char type above. That's pretty much all that is special about this program. The "if"-part of the "if" conditional simply asks for the two values to add and then outputs the result, using the "+" operator to add the two together. The "else" part simply sets vFinished to true, which causes "while" to stop repeating. When this happens, the program will resume execution after the end of "while"'s commands and thus write "Finished." to the screen and exit by returning zero.  Keep an eye on your equals signs. In C, = is used for assigning values, == is used for comparing them. It's easy to mix those up, which can lead to while loops that never stop or never run, or to variables that don't contain the right value. Since there are some clever tricks that can be done by assigning something in a loop's condition, the compiler may not always tell you about this error. Now you have a very crude and limited calculator that allows you to perform additions. To end the calculator session, just enter something different than a plus sign. For those of you who like to experiment, I suggest you try the following: Extend this program to also perform subtraction, multiplication and division. The multiplication operator is * and the division operator is /. Remember to guard against the user dividing a number by zero, as C does not guard against this, and your program will simply crash. Hint: You can put another if inside an if or else block. Don't forget to leave in the final "else" statement that assigns true to vFinished, though, or you won't get out of your program anymore. Below is the finished code you can check against: int main() { int vFirstArg, vSecondArg; char vOperation; bool vFinished; // Make sure our flag is initialized! vFinished = false; // Now loop until user doesn't want anymore: while( vFinished != true ) { printf( "What operation do you want to do?\n" ); scanf( "%c", &vOperation ); fpurge( stdin ); if( vOperation == '+' ) { printf( "Enter left argument: " ); scanf( "%d", &vFirstArg ); fpurge( stdin ); printf( "\nEnter right argument: " ); scanf( "%d", &vSecondArg ); fpurge( stdin ); printf( "\n%d + %d = %d\n", vFirstArg, vSecondArg, vFirstArg + vSecondArg ); } else { if( vOperation == '-' ) { printf( "Enter left argument: " ); scanf( "%d", &vFirstArg ); fpurge( stdin ); printf( "\nEnter right argument: " ); scanf( "%d", &vSecondArg ); fpurge( stdin ); printf( "\n%d - %d = %d\n", vFirstArg, vSecondArg, vFirstArg - vSecondArg ); } else { if( vOperation == '*' ) { printf( "Enter left argument: " ); scanf( "%d", &vFirstArg ); fpurge( stdin ); printf( "\nEnter right argument: " ); scanf( "%d", &vSecondArg ); fpurge( stdin ); printf( "\n%d * %d = %d\n", vFirstArg, vSecondArg, vFirstArg * vSecondArg ); } else { if( vOperation == '/' ) { printf( "Enter left argument: " ); scanf( "%d", &vFirstArg ); fpurge( stdin ); printf( "\nEnter right argument: " ); scanf( "%d", &vSecondArg ); fpurge( stdin ); if( vSecondArg == 0 ) { printf( "Flunked maths class, eh?\n" ); printf( "You can't divide by zero!\n" ); } else printf( "\n%d / %d = %d\n", vFirstArg, vSecondArg, vFirstArg / vSecondArg ); } else vFinished = true; } } } } printf( "Finished.\n" ); return 0; }  There is a second way of writing certain nested conditional statements: The switch statement. I did not introduce switch earlier because it is more limited than if/ else. It used to be a way of writing faster code, though these days, compilers are usually good enough that they can make an if just as fast. It looks like this: switch( vOperation ) { case '/': // do something... break;
case '+': // do something else... break;
default: // do this when vOperation is none of the above. break; } How a switch statement works is that the computer compares whatever integers you specify in the switch to whatever other integers you specify in the cases. So, it works only on integer values and can only compare for equality. It can't do != or > or <or >= or <= or any other comparison apart from ==. Also, the numbers after the case label must be constants, that is, you can't just say case myOtherVariable:, you have to provide an actual number. If the computer finds a case that matches the switched value, the computer does the commands after that case statement, until it encounters a break statement, or a return statement, or the end of the switch. So, if you have code like: switch( myIntVariable ) { case 1: printf( "You are the number one!\n" ); // FALLING THROUGH! No break here!
case 2: printf( "You are the number two!\n" ); break; } And myIntVariable contains a 1, It will output both "You are the number one!" and "You are the number two!", because there is no break after the first printf. However, when myIntVariable contains a 2, only the second printf will be done. If myIntVariable contains any other number, the above code will do nothing. Code like this is hard to read, but there's one main use for this: You can have several cases that do the exact same commands, e.g.: switch( myIntVariable ) { case 1: case 2: case 3: printf( "Less than four.\n" ); break;
case 4: printf( "Exactly four\n" ); break;
default: printf( "Less than one or greater than four.\n" );} Feel free to play around with switch statements a little. They are neat, and can make some code easier to read. However, in many cases, you can't use them, and in others they make the code so unreadable that you'll prefer using if instead. Also, if you forget a break when writing a switch statement, you can get unexpected behaviour, and it's hard to find such mistakes. The main reason I mention them here is because you will see code out there that uses them. There is also a default: label that can be used just like any other case, which indicates where the computer should start doing things if no other case matches the switched number. You can do the same things with default: as we mentioned above. It doesn't have to be at the end like in these examples, and you can fall through a default: label, or fall through another label after default:, whatever you need. Previous | Next Robert writes: .... confused by modern technology :-) i am amazed my Programm is working just as excepted, but it doesnt exactly look like the example shown here as result.
my (simplified) programm-structure looks like that:
if( vOperation == '+' )
{ }
else if ( vOperation == '-' )
{ }
else if ( vOperation == '*' )
{ }
else if ( vOperation == '/' )
{ }
still ok, or is it problematic in any way?
|
Uli Kusterer replies: ★ @Robert: No, that's perfectly OK. Since an "if...else" construct counts as only one command, you can provide that as the only command in an else. And since C doesn't care about how much or what whitespace you put in, you can put the "if" on the same line as the "else".
|
Joshua Friedman writes: Hey There Uli,
When I type the code above, and also when i copy and paste it into my text editor, the program runs as follows:"
What operation do you want to do?
+
Enter left argument: 1
Enter right argument: 1
-1881139919 + 1 = -1881139918
Thanks for the lessons, btw.
Joshua
|
Colton writes: I went just a step further and, in my DIVISION if statement, I not only put in the if(vSecondArg == 0) statement, I also nested this:
while(vSecondArg == 0)
{
printf("\nCan't divide by zero. Enter a nonzero int: ");
scanf("%d", &vSecondArg);
fpurge(stdin);
}
This keeps the program going, in case someone enters an accidental zero.
Just a tip :)
|
Regis writes: Hi, the division does not seem to work properly. For example, 5 / 6 = 0
Could you suggest a fix?
Thanks for the class,
|
Uli Kusterer replies: ★ Division does work properly. The code uses integers, which means it only works with whole numbers. You'd have to change the code to use doubles or floats (and %f) if you want division to produce fractional numbers.
|
Pelle writes: HEy, thanks for the great lessons. When I built the improved the calculator( aded other functions) it doesn't work. I tried copy+pasting yours and it gives the same error. At the last bracket which should be the last character in the program its gives this error.
"Parse error at end of input."
Can you help me?
|
Uli Kusterer replies: ★ Pelle,
I just copied the program and started compiling it, and it worked just fine (with the includes mentioned earlier, of course). Your error message sounds like you have some error somewhere, or your text editor adds garbage at the end of the file or so. Have you maybe forgotten a closing bracket or a semicolon? Or added ones where they shouldn't be?
|
AlphaSite writes: Hi, i was wondering if you wouldn't mind checking out my code for me and seeing why it won't properly end, should i send an email?
Also great tutorial, had this down really quickly and nice to see a mac oriented one. One last question is there an easy way to preform sq root or power calculations?
|
Bert writes: I don't know how long this has been up, but I wanted to add my thanks, and that I love puns. "Master of the Void" indeed. ;^)
|
Eric writes: Here is the code for a extended calculator with working devision. I hope this helps some people. This is a great guide so far. Thanks!
#include <stdio.h>
#include <stdbool.h>
int main()
{
int vFirstArg,
vSecondArg;
float vFirstArgDiv,
vSecondArgDiv;
char vOperation;
bool vFinished;
vFinished = false;
while (vFinished != true) {
printf( "What operation do you want to do?\n" );
scanf( "%c", &vOperation );
fpurge( stdin );
if (vOperation == '+'){
printf("Enter your first number: ");
scanf("%d", &vFirstArg );
fpurge( stdin );
printf("Enter your second number: ");
scanf("%d", &vSecondArg);
fpurge( stdin );
printf( "\n%d + %d = %d\n",
vFirstArg,
vSecondArg,
vFirstArg + vSecondArg );
}
else if (vOperation == '-'){
printf("Enter your first number: ");
scanf("%d", &vFirstArg);
fpurge(stdin);
printf("Enter your second number: ");
scanf("%d", &vSecondArg);
fpurge(stdin);
printf("\n%d - %d = %d\n",
vFirstArg,
vSecondArg,
vFirstArg - vSecondArg);
}
else if (vOperation == '/') {
printf("Enter your first number: ");
scanf("%f", &vFirstArgDiv);
fpurge(stdin);
printf("Enter your second number: ");
scanf("%f", &vSecondArgDiv);
fpurge(stdin);
if (vSecondArgDiv == 0){
while (vSecondArgDiv == 0) {
printf("Sorry, you cannot devide by zero. Please try again: \n");
scanf("%f", &vSecondArgDiv);
fpurge(stdin);
}
printf("\n%f / %f = %f\n",
vFirstArgDiv,
vSecondArgDiv,
vFirstArgDiv/vSecondArgDiv);
}
}
else if (vOperation == '*'){
printf ("Enter your first number: ");
scanf ("%d", &vFirstArg);
fpurge(stdin);
printf("Enter your second number: ");
scanf ("%d", &vSecondArg);
fpurge(stdin);
printf ("\n%d * %d = %d\n",
vFirstArg,
vSecondArg,
vFirstArg * vSecondArg);
}
}
}
|
thinkdunson writes: wouldn't "else if" be more efficient than an "if" nested inside of an "else" since it's only one thing compared to two? it might not matter here, but i work with microcontrollers, and they're much slower than a personal computer. so even that extra microsecond adds up a lot when you're in a loop. especially when you're trying to time something. anyway, here's what i came up with…
#include <stdio.h>
#include <stdbool.h>
int main()
{
// declare our variables:
int vFirstArg, vSecondArg;
char vOperation, vFinished;
// Make sure our exit condition is initialized:
vFinished = 'n';
// Loop until the user decides to exit:
while(vFinished != 'y'){
// Request the parameters of the operation:
printf("\nEnter left argument: ");
scanf("%d", &vFirstArg);
fpurge(stdin);
printf("Enter right argument: ");
scanf("%d", &vSecondArg);
fpurge(stdin);
printf("\nWhat operation do you want to do (+, -, *, or /) ? ");
scanf("%c", &vOperation);
fpurge(stdin);
// Carry out the requested operation:
if(vOperation == '+')
printf("\n%d + %d = %d\n",
vFirstArg, vSecondArg, vFirstArg + vSecondArg);
else if(vOperation == '-')
printf("\n%d - %d = %d\n",
vFirstArg, vSecondArg, vFirstArg - vSecondArg);
else if(vOperation == '*')
printf("\n%d x %d = %d\n",
vFirstArg, vSecondArg, vFirstArg * vSecondArg);
else if(vOperation == '/')
// Make sure we're not being asked to divide by zero:
if(vOperation == '/')
if(vSecondArg == 0)
printf("\nYou cannot divide by zero.\n");
else
printf("\n%d ÷ %d = %d\n",
vFirstArg, vSecondArg, vFirstArg / vSecondArg);
// Ask the user if he wants to exit the program:
printf("\nAre you finished? (y/n) ");
scanf("%c", &vFinished);
fpurge(stdin);
}
return 0;
}
|
Andrew Hobson writes: When I Build and Run I get a warning/error message that I am making a comparison between a pointer and an integer. I use Xcode version 3 and MacOS X 10.5.8. Is there something to change?
|
Matt writes: Is the only way for program to quit when I hit enter on the keyboard, or does it quit automatically? I have read over twice and may have missed it or just confused.
Great tutorial so far!
|
Uli Kusterer replies: ★ Matt,
good catch, I forgot to mention how scanf() works in enough detail. I've adjusted the previous chapter to say more closely how scanf() works, that should clear things up.
|
Uli Kusterer replies: ★ Matt, to answer your question: scanf() waits for a return before it lets your program continue, so you *have* to press return to get it to finish. If you just press return, that return will end up in vOperation, and since that is not a command we understand, we will end up in the last "else" case and set vFinished to true and end the program.
|
Uli Kusterer replies: ★ Eric, good source code you posted. Although you never put true into vFinished, so your program never really ends, it will just eternally keep looping until you shoot it down using the "Stop" button in Xcode.
|
Uli Kusterer replies: ★ Alistair, there's no need to check if vFirstArg is 0. It is a perfectly valid mathematical operation to divide 0 by anything, multiply it by anything, or add to or subtract from it. But dividing something by 0 doesn't make much sense (what would the result be?), which is why we check vSecondArg in that case.
|
Uli Kusterer replies: ★ Andrew, what is the line where you get that error? If it says you are comparing between a pointer an integer, that is usually what you are doing. You are taking a variable that is declared as an "int * foo;" and comparing it to another that is declared as "int bar;". foo has the asterisk, so is a pointer, an address of an int. bar _is_ an int. Alternately, you may have a stray "&" before a variable name. Until you've read the later chapters that describe what "&" does in detail, you should only use it when you give a parameter to scanf(). In all other cases, just use that variable normally.
|
Uli Kusterer replies: ★ AlphaSite, there are library functions to do square roots and powers. There's pow() and sqrt(). To get them, you have to #include <math.h>. Note that sqrt() only works if you change your calculator to use floating point numbers (float or double, which use %f resp. %lf in scanf() and printf() ), as most square roots are not integers, after all.
|
Teoten writes: First of all, congrats for this great tutorial. I think i'm learning a lot with this. Thanks Uli.
I've understood well I think and I understand why we have to use "else" or "else if" to continue with other operations. But I have a question, why when I just write a next "if" without the else next to it, why when I do a + operation, the program do it and then finish it?
Is something like this:
if( vOperation == '+' )
{ .... }
if ( vOperation == '-' )
{ .... }
else
vFinished = true;
}
printf( "Finished.\n" );
return 0;
}
With this, I can - all the times I want, but If I do a + operation, the program answer and then it ends. And I would like to know why.
And thanks a lot for all the tips and knowledge
|
Charles Marshall writes: In the basic addition calculator example you've got several new line characters. That's fine but I've taken them out to tighten up the text lines on the console. But in doing so I've noticed something I can't figure out: when I remove the "\n"s from the first three printf's it works fine. The line prints and the following line appears immediately below it. But if I remove the "\n" on the fourth printf ("%d + %d = %d, vFirstArg, vSecondArg, vFirstArg+vSecondArg), the "What do you want to do" line appears on the same line (as the fourth printf). Why is that? My fourth printf line ends in a semicolon just like all the others. Why doesn't the first printf line appear on the line below the equation?
Thanks!
|
Uli Kusterer replies: ★ YOU are typing the line breaks in the first three examples. You type in values (when scanf() waits for them), and press the return key. In the last case, there's no input from you, so there's no return keypress either.
|
Charles Marshall writes: In a nifty little iPhone app called C Reference I discovered the "or" boolean so I thought I'd try it out with your calculator. This is what I tried:
while(areWeDoneYet!=true)
{
printf("Please select an operation (+,-,*,/) or select 'q' to
quit:");
scanf("%c", &myOperator);
fpurge(stdin);
if(myOperator=='+')
{etc}
else if(myOperator=='-')
{etc}
else if(myOperator=='*')
{etc}
else if(myOperator=='/')
{etc}
else if(myOperator!='+'||'-'||'*'||'/'||'q')
printf("I'm sorry. That's an invalid selection.n");
else if(myOperator=='q')
areWeDoneYet=true;
}
printf("We're Done!");
return 0;
This doesn't work. It stays trapped in a loop. Selecting "q" still prints "I'm sorry. That's an invalid selection." However if I reverse the order of the last two "else if"s like this:
else if(myOperator=='q')
areWeDoneYet=true;
else if(myOperator!='+'||'-'||'*'||'/'||'q')
printf("I'm sorry. That's an invalid selection.n");
It works fine. Granted this is probably a really clumsy way of using || with != but I don't see why it fails in the first version. Does it have something to do with 'q' not being "used" or "initialized" before the appearance of the "invalid selection" else if?
(I probably deserve what I get for messing around with operators I don't fully understand!!!)
|
Uli Kusterer replies: ★ The || operator is defined as
<bool> || <bool>
I.e. it takes two bool expressions, and returns true (another bool) if one of them is true. But you aren't giving it a bool, you are giving it a char. Since a bool and a char are essentially just ints to the computer (a bool is either 0 or 1), your code takes the '-' as a number, which is something other than 0, so is automatically seen as true. So your whole expression could be re-written as "else if( true )", which is why you always end up in this case.
So, since this expects a bool, you need to provide it a bool, not just a char:
else if( myOperator != '+' || myOperator != '-' || ... )
read as "else if my operator is not plus or my operator is not minus or..." Of course, this isn't what you wanted to say. The above would also always be true, because myOperator holds exactly one value. So what you really need is another cool new operator, the "and" operator, &&:
else if( myOperator != '+' && myOperator != '-' && ... )
read as "else if my operator is not plus and my operator is not minus and ...".
PS - I posted your request here because your e-mail provider refuses messages from zathras.de.
|
Garotas* writes: Here is the source code for the calculator with switches and states for everyone interested. I have one question though. In line 86 there is a if loop for catching a user pressing "0". How could I do this with a switch?
// Crude Calculator
// C beginner tutorial on the Mac
// By "Masters of the Void"
// Case Study, November 2009
#include <stdio.h> // Defines printf etc.
#include <stdbool.h> // Defines Boolean operations.
int main() // Program start.
{
int vFirstArg, // Integers for +, -, *.
vSecondArg;
float vFirstArgDiv, // Floats for /.
vSecondArgDiv;
char vOperation, // Chars for the calculator...
vQuit; // ...and for quitting.
bool vFinished; // Loop ending condition.
// Make sure our flag is initialized!
vFinished = false;
// Now loop until user doesn't want anymore:
while(vFinished != true )
{
printf("\nWelcome to Crude Calculator!
\nWhat operation do you want to do?
\nPress (+) , (-) ,(*) or (/)\n");
scanf("%c", &vOperation); // Read.
fpurge( stdin ); // Stop reading.
switch (vOperation) // Case switch.
{
case '+': // First case: addition.
printf("Enter left argument: "); // Enter first argument.
scanf("%d", &vFirstArg);
fpurge(stdin);
printf("\nEnter right argument: "); // Enter second argument.
scanf("%d", &vSecondArg);
fpurge(stdin);
printf("\n%d + %d = %d\n", // Show result.
vFirstArg,
vSecondArg,
vFirstArg + vSecondArg);
break; // End case.
case '-': // Next case...
printf("Enter left argument: ");
scanf("%d", &vFirstArg);
fpurge(stdin);
printf("\nEnter right argument: ");
scanf("%d", &vSecondArg);
fpurge(stdin);
printf("\n%d - %d = %d\n",
vFirstArg,
vSecondArg,
vFirstArg - vSecondArg);
break;
case '*':
printf("Enter left argument: ");
scanf("%d", &vFirstArg);
fpurge(stdin);
printf("\nEnter right argument: ");
scanf("%d", &vSecondArg);
fpurge(stdin);
printf("\n%d * %d = %d\n",
vFirstArg,
vSecondArg,
vFirstArg * vSecondArg);
break;
case '/':
printf("Enter left argument: ");
scanf("%f", &vFirstArgDiv);
fpurge(stdin);
printf("\nEnter right argument: ");
scanf("%f", &vSecondArgDiv);
fpurge(stdin);
if (vSecondArgDiv == 0) // If someone divides by zero.
{
while( vSecondArgDiv == 0) // Nested if, so it is possible to re-enter second arg.
{
printf("\nYou can't divide by zero!\nEnter new right argument: ");
scanf("%f", &vSecondArgDiv);
fpurge(stdin);
}
printf("\n%f / %f = %f\n", // Show result after re-entry.
vFirstArgDiv,
vSecondArgDiv,
vFirstArgDiv / vSecondArgDiv);
}
else
printf("\n%f / %f = %f\n", // Standard result.
vFirstArgDiv,
vSecondArgDiv,
vFirstArgDiv / vSecondArgDiv);
break;
default: // Case, user pressed none of them above.
printf("Do you want to quit? (y) / (n)\n"); // Want to quit?
scanf("%c", &vQuit);
fpurge(stdin);
switch (vQuit) // New switch for quit.
{
case 'y': // Case "yes" sets quitting condition flag to "true":
vFinished = true;
break;
case'n': // "No" returns to loop.
vFinished != true;
break;
}
}
}
printf("Finished.\n"); // Outside of the while-vFinished-is-not-true loop.
return 0; // Tell OS everything is OK.
}
|
Alastair Leith writes: When declaring a string literal in printf double quotes are used ie. " ". In the if statement:
if ( vOperation == '+' )
single quotes are required (doubles give error).
When is one used and not the other and is there an underlying reason for this (to help me understand and remember it b/c in some scripting languages they are interchangeable (I think!))
|
Chris writes: I found this to be a nice clean code that also includes the floating-point division:
#include <stdio.h>
#include <stdbool.h>
int main ()
{
int vFirstArg,
vSecondArg;
double vQuotient; // for proper floating point division, as integer division sucks.
char vOperation;
bool vFinished;
//init finished flag
vFinished = false;
//begin main loop
while (! vFinished) {
printf("Mathematical operation (+, -, *, /), any other key to quit: \n");
scanf("%c", &vOperation);
fpurge(stdin);
// check to see if we're doing something, and if so, ask for arguments:
if (vOperation == '+' || vOperation == '-' || vOperation == '*' || vOperation == '/') {
printf("Enter first argument: ");
scanf("%d", &vFirstArg);
fpurge(stdin);
printf("Enter second argument: ");
scanf("%d", &vSecondArg);
fpurge(stdin);
}
// figure out what we're doing, and do it:
switch (vOperation) {
case '+':
printf("\n%d + %d = %d\n", vFirstArg, vSecondArg, vFirstArg + vSecondArg);
break;
case '-':
printf("\n%d - %d = %d\n", vFirstArg, vSecondArg, vFirstArg - vSecondArg);
break;
case '*':
printf("\n%d * %d = %d\n", vFirstArg, vSecondArg, vFirstArg * vSecondArg);
break;
case '/':
vQuotient = (double) vFirstArg / vSecondArg;
printf("\n%d / %d = %f\n", vFirstArg, vSecondArg, vQuotient);
break;
default:
vFinished = true; //get out of the loop and quit
break;
}
}
printf("Done!\n");
return 0; //Tell the OS that it's all good.
}
It does introduce a couple concepts not yet covered, specifically using the ! operator directly on a boolean in the loop, and the (double) in the division.
|
Tristan Moriarty writes: These are a great set of tutorials, thankyou! I'm having alot of fun. I was childishly pleased with my calculator and quite want to save it before moving on to the next step, but I find that if I try and create a new file in the same source folder it won't compile. Do I need to start a new Project for every new program I write, or is there some way I can include new programs in the same project? I know this isn't strictly a "C" question, and I'm not sure if my terminology is correct, but I hope you understand! Danke!
|
Uli Kusterer replies: ★ Yes Tristan, a project is essentially the wrapper for a program. There are ways to add more programs to one project, but that's a little more involved, and you generally only do that for a program that, for some reason, needs several actual program files that e.g work together.
If you want to learn more about several programs in one project, read the Xcode documentation for "targets".
|
Shadow Luster writes: Why does the complier always say that my else statement needs an ; behind it. I check and all semicolons are there.I even tried copying and pasting your code but i still got the same error. Great tutorials by the way. Lots of fun.
|
Jason writes: First, I love your tutorials. Thanks for putting this together and--more importantly--making it available!
Now my problem... XCode (version 3.2.2) really wants to put 'true' and 'false' into all caps (i.e. TRUE instead of true and FALSE instead of false). It automatically completes as I type. This gives me errors when I compile.
However, when I force it into lower case (with a series of deletes as I type and it replaces my typing with capital letters) it works beautifully.
Have you seen this before? Any thoughts?
|
Uli Kusterer replies: ★ Jason,
haven't seen that yet, but that must be Xcode's autocompletion ("CodeSense"). It will only complete things you actually inclue somewhere, so I guess you must be including some header that includes an all-upper TRUE or FALSE (maybe from a prefix header?).
FWIW, you don't have to fix it for each character. Xcode remembers what you actually typed. So if you type the whole word, and only hit the left arrow key at the end, it should restore it to lowercase again.
|
Jason writes: Thanks for the left-arrow hint.
The only headers I've used are the ones your tutorial told me to use. It's all I really know how to do at this point!
|
Byto writes: Many thanks for posting this tutorial - it really is very manageable and, strangely, quite addictive fun.
|
Jones writes: Great tutorial :) See if you can spot the small difference from the examples above...
#include <stdio.h>
#include <stdbool.h>
int main () {
float vFirstArg;
float vSecondArg;
char vOperation;
bool vFinished;
vFinished = false;
while (vFinished != true) {
printf("What operation do you want to do?\n");
scanf("%c", &vOperation);
fpurge( stdin );
switch (vOperation) {
case '+':
printf("Enter left argument: ");
scanf("%f",&vFirstArg);
fpurge(stdin);
printf("\nEnter right argument: ");
scanf("%f",&vSecondArg);
fpurge(stdin);
printf("\n%f + %f = %f\n", vFirstArg,vSecondArg,vFirstArg+vSecondArg);
break;
case '-':
printf("Enter left argument: ");
scanf("%f",&vFirstArg);
fpurge(stdin);
printf("\nEnter right argument: ");
scanf("%f",&vSecondArg);
fpurge(stdin);
printf("\n%f - %f = %f\n", vFirstArg,vSecondArg,vFirstArg-vSecondArg);
break;
case 'x':
printf("Enter left argument: ");
scanf("%f",&vFirstArg);
fpurge(stdin);
printf("\nEnter right argument: ");
scanf("%f",&vSecondArg);
fpurge(stdin);
printf("\n%f * %f = %f\n", vFirstArg,vSecondArg,vFirstArg*vSecondArg);
break;
case 'd':
printf("Enter left argument: ");
scanf("%f",&vFirstArg);
fpurge(stdin);
printf("\nEnter right argument: ");
scanf("%f",&vSecondArg);
fpurge(stdin);
printf("\n%f / %f = %f\n", vFirstArg,vSecondArg,vFirstArg/vSecondArg);
break;
default:
vFinished = true;
break;
}
}
printf("Finished.\n");
return 0;
}
|
Jack writes: Hey Uli, I was attempting to create a rudimentary quiz-type program to test what I've learned here, and in my program, I was using scanf so that the user could enter in their answer, either a,b,c, or d. I then used if( vAnswer == 'B' ) the answer was correct. However, this means the answer has to be entered in as a capital B, and if it is lowercase, it will read that it is incorrect. This seemed sort of annoying so I was wondering if there was a way to get around this without creating another if statement, for instance if( vAnswer == 'B' or 'b' ) or something like that.
|
Al writes: Uli - Just wanted to say thanks a million for providing this resource. I first started programming in HS in the 1980's on my TRS-80 in BASIC. I then moved onto Pascal and Fortran (on a mainframe) in college. Alas, I lost the bug when I chose Assembly instead of C in my junior year of college. Fast forward to today and I have the itch to learn C and then move on to Objective-C for the iPhone. So far so good, as all the old logic (and habits) are slowly coming back to me. Can't wait to see what's coming next in these tutorials!! You are making this return to coding a lot of fun, thanks!
|
Dan Kelleher writes: Hi Uli,
I just successfully finished the initial part (+ only) of the crude calculator tutorial.
My 13-year-old son, Jeremy, is starting your tutorial also. (He wants to write applications for the iPhone and iPad and Steve Jobs has convinced him it's easy!)
Your tutorial is a great place to start- Thank You!
My Question; Is there any way to execute each step of a C program one-step-at-a-time and observe the intermediate results as one can using the SuperCard Script Tracer and the Trace command ?
-Dan
|
Jack writes: Hey Uli, I had a question involving float variables. When I have one that should come out as 1, it comes out as 1.0000000, which is technically correct but it is annoying and can screw things up. So how do I change the amount of decimal points that it comes out as.
|
P. Jeezy writes: Here's a calculator that can handle decimals and
#include <stdio.h>
#include <stdbool.h>
int main ()
{
float vFirstArg,
vSecondArg;
char vOperation;
float vFirstDiv;
float vSecondDiv;
bool vFinished;
// Make sure our flag is initialized!
vFinished = false;
// Now loop until user doesn't want anymore:
while( vFinished != true )
{
printf( "What operation do you want to do?\n" );
scanf( "%c", &vOperation );
fpurge( stdin );
if( vOperation=='+')
{
printf( "Enter left argument: " );
scanf( "%f", &vFirstArg );
fpurge( stdin );
printf( "\nEnter right argument: " );
scanf( "%f", &vSecondArg );
fpurge( stdin );
printf( "\n%f + %f = %f\n",
vFirstArg,
vSecondArg,
vFirstArg + vSecondArg );
}
if (vOperation=='-')
{
printf( "Enter left argument: " );
scanf( "%f", &vFirstArg );
fpurge( stdin );
printf( "\nEnter right argument: " );
scanf( "%f", &vSecondArg );
fpurge( stdin );
printf( "\n%f - %f = %f\n",
vFirstArg,
vSecondArg,
vFirstArg - vSecondArg );
}
if (vOperation=='*')
{
printf( "Enter left argument: " );
scanf( "%f", &vFirstArg );
fpurge( stdin );
printf( "\nEnter right argument: " );
scanf( "%f", &vSecondArg );
fpurge( stdin );
printf( "\n%f * %f = %f\n",
vFirstArg,
vSecondArg,
vFirstArg * vSecondArg );
}
if (vOperation=='/')
{
printf( "Enter left argument: " );
scanf( "%f", &vFirstDiv );
fpurge( stdin );
printf( "\nEnter right argument: " );
scanf( "%f", &vSecondDiv );
fpurge( stdin );
{
if (vSecondDiv==0)
{
printf("Can't divde by zero!\n");
vFinished=true;
}
else
{
printf( "\n%f / %f = %f\n",
vFirstDiv,
vSecondDiv,
vFirstDiv / vSecondDiv );
vFinished=true;
}
}
}
else
vFinished=true;
}
printf("Finished.\n");
return 0;
}
|
Eli Ron writes: Hi Uli,
Thank you for this great tutorial! I'm learning a lot and I'm having a lot of fun doing it. I have run into a small problem. With my version of the code everything works well except that it doesn't recognize when I enter any other character that it should finish. Here is my code:
#include <stdio.h>
#include <stdbool.h>
int main()
{
int vFirstArg,
vSecondArg;
char vOperation;
bool vFinished;
// Make sure our flag is initialized!
vFinished = false;
// Now loop until user doesn't want anymore:
while(vFinished != true)
{
printf("What operation do you want to do?n");
scanf("%c", &vOperation);
fpurge(stdin);
// User makes a decision which operation to do:
if(vOperation == '+', '-', '*', '/')
{
printf("Enter left argument: ");
scanf("%d", &vFirstArg);
fpurge(stdin);
printf("nEnter right argument: ");
scanf("%d", &vSecondArg);
fpurge(stdin);
if (vOperation == '/' && vSecondArg == 0) // Takes care of 0 in denominator:
{
printf("Error - Can't divide by %d. Please try again: n", vSecondArg);
scanf("%d", &vSecondArg);
fpurge(stdin);
}
else //Computer does selected operation:
{
if (vOperation == '+')
{
printf("n%d %c %d = %dn",
vFirstArg,
vOperation,
vSecondArg,
vFirstArg + vSecondArg);
}
if (vOperation == '-')
{
printf("n%d %c %d = %dn",
vFirstArg,
vOperation,
vSecondArg,
vFirstArg - vSecondArg);
}
if (vOperation == '*')
{
printf("n%d %c %d = %dn",
vFirstArg,
vOperation,
vSecondArg,
vFirstArg * vSecondArg);
}
if (vOperation == '/')
{
printf("n%d %c %d = %dn",
vFirstArg,
vOperation,
vSecondArg,
vFirstArg / vSecondArg);
}
} //End computer's operation
}
else
vFinished = true;
}
printf("Finished.n");
return 0;
}
|
Johnny B writes: Thanks for such a wonderful site! I am struggling but know that I will eventually get it. Maybe build a dictionary of terms as I go along. Anyway Pelle's concern may be related to not having
#include <stdio.h>
#include <stdbool.h>
at the top of the program. I ran into the same thing when copying and figured it out.
Thanks Again! Hope to learn much more one step at a time
|
Mike Polinske writes: @ Eli Ron,
I think your problem is with this statement:
if(vOperation == '+', '-', '*', '/')
In C you can't just put all the values together to compare vOperator with all of them, you have to separate them with an "or" as follows:
if(vOperation == '+' || vOperation == '-' || vOperation == '*' || vOperation == '/')
@Uli,
Thanks for a great website and tutorial for learning C on the Mac.
|
Thomas writes: Hi Uli,
great tutorial. I did do a course on C but this was years back. Good little refresher:-)
I had a question regarding
printf( "n%f - %f = %fn", vFirstArg, vSecondArg, vFirstArg - vSecondArg );
Is it possible to use variable "vOperation" instead of the "-"? Then you would only need to write one "if" statement instead of four.
|
Uli Kusterer replies: ★ Thomas,
suer, you can use vOperation instead of the first minus sign, but of course you'd still have to write an if statement for doing the actual calculation.
|
Daniel Bydlowski writes: Hi Uli, thank you so much for your tutorial. For some reason my + calculator does not work. I try to type in the console 2 int numbers like 1 or 7 (1+7) and add them but nothing happens and the message "finished"
appears.
My code looks like this and I can't see what is wrong. Would you know what is wrong with it?
Thank you so much.
Best,
Daniel
#include <stdio.h>
#include <stdbool.h>
int main()
{
int vFirstArg,
vSecondArg;
char vOperation;
bool vFinished;
vFinished = false;
while (vFinished != true)
{
printf ( "What operation do you want to do?n" );
scanf ("%c", &vOperation);
fpurge(stdin);
if ( vOperation == '+' )
{
printf ("Enter left argument: " );
scanf ("%d", &vFirstArg);
fpurge(stdin);
printf( "nEnter right argument: " );
scanf("%d", &vSecondArg );
fpurge( stdin );
printf ("n%d + %d = %dn",
vFirstArg,
vSecondArg,
vFirstArg + vSecondArg );
}
else
vFinished = true;
}
printf ("Finished.n");
return 0;
}
|
Daniel Bydlowski writes: Hi Uli, thank you so much for your tutorial. For some reason my + calculator does not work. I try to type in the console 2 int numbers like 1 or 7 (1+7) and add them but nothing happens and the message "finished"
appears.
My code looks like this and I can't see what is wrong. Would you know what is wrong with it?
Thank you so much.
Best,
Daniel
#include <stdio.h>
#include <stdbool.h>
int main()
{
int vFirstArg,
vSecondArg;
char vOperation;
bool vFinished;
vFinished = false;
while (vFinished != true)
{
printf ( "What operation do you want to do?n" );
scanf ("%c", &vOperation);
fpurge(stdin);
if ( vOperation == '+' )
{
printf ("Enter left argument: " );
scanf ("%d", &vFirstArg);
fpurge(stdin);
printf( "nEnter right argument: " );
scanf("%d", &vSecondArg );
fpurge( stdin );
printf ("n%d + %d = %dn",
vFirstArg,
vSecondArg,
vFirstArg + vSecondArg );
}
else
vFinished = true;
}
printf ("Finished.n");
return 0;
} |
|
Home | Admin | Edit
Last Change: 2012-05-17 @314, © 2003-2012 by M. Uli Kusterer, all rights reserved. |
|
|