C
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Arrays and Strings
-
Section 5: Pointers
-
Section 6: Memory Management
-
Section 7: Structures and Unions
-
Section 8: The Preprocessor and Build Process
-
Section 9: Standard Library: stdio.h
-
Section 10: Standard Library: stdlib.h
-
Section 11: Standard Library: string.h
-
Section 12: Standard Library: ctype.h and wctype.h
-
Section 13: Standard Library: math.h, complex.h, fenv.h, tgmath.h
-
Section 14: Standard Library: Type and Limit Headers
-
Section 15: Standard Library: Error Handling and Debugging
-
Section 16: Standard Library: Localization and Encoding
-
Section 17: Standard Library: time.h
-
Section 18: Standard Library: Concurrency (C11)
-
Section 19: POSIX and System Programming (unistd.h)
-
Section 20: More Data Structures
-
Section 21: Algorithms in C
-
Section 22: Bitwise Operations
-
Section 23: Command-Line Programs
-
Section 24: Debugging and Best Practices
-
Section 25: Compiler and Language Internals
-
Section 26: Embedded and Cross-Platform Considerations
-
Section 27: Networking Basics
-
Section 28: Practical Projects
-
Section 29: Interview Practice
-
Section 30: C23 Modern Features
-
Section 31: More Practice and Review
26: Practice Exercise: Building a Simple Calculator
A few years ago, I was reviewing code for a junior developer who had built a basic calculator for a utility tool. It worked perfectly—until he tried to divide by zero during a live demo for his lead. The program didn't just give a wrong answer; it crashed instantly with a segmentation fault or a floating-point exception, depending on the environment. He had focused so much on the math that he forgot that in C, the language doesn't "save" you from the hardware. It just executes the instruction, and if the hardware says "you can't do that," the OS kills your process. It was a humbling moment for him, but it's the perfect lesson in why input validation is just as important as the logic itself.
Mapping Operations to Logic
When you're building a calculator, you'll be tempted to write a long chain of if...else if statements to check which operator the user entered. While that works, it's clunky. Since we're dealing with a single char for the operator (like '+', '-', '*', '/'), a switch statement is the cleaner, more professional choice. It tells anyone reading your code, "I am choosing one path based on this specific value."
One thing I want you to watch out for is how scanf handles characters. If you've used it for integers, you know it's straightforward. But when you read a char after reading a number, scanf often picks up the newline character \n left in the buffer from when the user pressed Enter. To avoid this, put a leading space in your format string: scanf(" %c", &operator);. That tiny space tells C to skip any whitespace characters, saving you from a bug that would otherwise make your program skip the operator input entirely.
Defending Against the Crash
As we saw in my anecdote, division is the danger zone. In C, dividing a floating-point number by zero might result in inf (infinity), but dividing an integer by zero is an immediate crash. Even with floats, letting a user divide by zero is poor form. You need to wrap your division logic in a guard clause.
if (operator == '/') {
if (num2 == 0) {
printf("Error: Division by zero is undefined.\n");
} else {
printf("Result: %.2f\n", num1 / num2);
}
}
By checking the divisor before the operation happens, you move from writing a "happy path" program to writing robust software. I always tell my students: assume the user is actively trying to break your code. If you design for the worst-case scenario, the best-case scenario takes care of itself.
Keeping the Session Alive
Running a program, performing one calculation, and having it terminate is annoying for the user. To make this a real tool, you'll want to wrap the entire logic in a do...while loop. This allows the user to perform multiple calculations in one session. You can prompt them with a simple "Do you want to continue? (y/n)" at the end of each cycle. Just remember to handle that final character input with the same whitespace awareness we discussed earlier.
📋 Practical Task
Project: The Robust Arithmetic Console
Build a command-line calculator that allows a user to perform basic arithmetic without restarting the program. Your implementation must meet the following requirements:
- Continuous Loop: Use a
do...whileloop so the user can perform multiple calculations until they choose to exit by entering 'n'. - Flexible Input: Use
floatordoublefor the numbers to ensure the calculator can handle decimals. - Operator Handling: Implement a
switchstatement to handle addition (+), subtraction (-), multiplication (*), and division (/). - The Safety Guard: Explicitly check for division by zero and print a clear error message instead of allowing the program to crash.
- Buffer Management: Ensure that your
scanfcalls for characters do not accidentally consume newline characters from previous inputs.
Expected behavior example:
Enter first number: 10
Enter operator (+, -, *, /): /
Enter second number: 0
Error: Division by zero is undefined.
Would you like to perform another calculation? (y/n): y
There are no comments for now.