How Do I Handle User Input Robustly?
Buffer clearing, input validation loops, and formatting output for Lab 4
After this lesson, you will be able to:
- Write a reusable input validation function using
do-whileandscanfreturn checking - Check
scanf’s return value to detect non-numeric input - Use buffer clearing after
scanfto prevent leftover character issues - Build a menu-driven program that validates user choices
- Use
printffield width and precision specifiers for aligned output
When Users Type “abc” Instead of a Number
Your program expects an integer. The user types “hello”. scanf fails silently, the variable keeps its garbage value, and your program produces nonsense — or crashes.
Defensive input handling isn’t glamorous, but it’s the difference between a program that works in the lab and one that works in the real world. And since Lab 4 (the water bill calculator) requires reading multiple inputs and formatting currency, you need these patterns now.
Defensive Input Patterns
The Buffer Problem (Revisited)
Recall from Lesson 2.5: when you type 42 and press Enter, scanf("%d") reads 42 but leaves \n in the buffer. The standard fix:
scanf("%d", &value);
while (fgetc(stdin) != '\n') {} // Consume everything up to newline
Use this after every scanf call for numeric types when you’ll read more input later.
Input Validation with do-while
The standard pattern for validated input:
int get_positive_int(const char *prompt)
{
int value;
int result;
do
{
printf("%s", prompt);
result = scanf("%d", &value);
while (fgetc(stdin) != '\n') {}
if (result != 1 || value <= 0)
{
printf("Invalid input. Please enter a positive integer.\n");
}
} while (result != 1 || value <= 0);
return value;
}
This function:
- Prompts the user
- Reads input and checks
scanf’s return value - Clears the buffer
- Validates the value
- Repeats if invalid
abc when your program calls scanf("%d", &value). What does scanf return?scanf returns the number of items successfully matched and assigned. Since "abc" can't be read as %d, zero items were read. The characters stay in the input buffer (which is why you need to clear it), and value keeps whatever it had before — potentially garbage.
Why does this matter?
Every lab that reads user input needs this pattern. If you don’t check scanf’s return value, your program silently uses garbage data when the user types something unexpected. That’s how you get mysterious wrong answers that “work on my machine.”
Menu-Driven Programs
Labs often require menu-driven interfaces:
char get_menu_choice(void)
{
char choice;
do
{
printf("\nMenu:\n");
printf(" A) Add\n");
printf(" S) Subtract\n");
printf(" Q) Quit\n");
printf("Choice: ");
scanf(" %c", &choice);
while (fgetc(stdin) != '\n') {}
choice = toupper(choice);
if (choice != 'A' && choice != 'S' && choice != 'Q')
{
printf("Invalid choice!\n");
}
} while (choice != 'A' && choice != 'S' && choice != 'Q');
return choice;
}
Note the space before %c in scanf(" %c", &choice) — it skips whitespace, including leftover newlines.
Formatted Output for Labs
Lab 4 requires formatted currency output. Here’s how:
Field width for alignment:
printf("%-20s %10.2f\n", "Water charge:", 45.67);
printf("%-20s %10.2f\n", "Sewer charge:", 23.45);
printf("%-20s %10.2f\n", "Total:", 69.12);
Water charge: 45.67
Sewer charge: 23.45
Total: 69.12
Currency with commas (using setlocale):
#include <locale.h>
int main(void)
{
setlocale(LC_ALL, "en_US.utf8");
printf("Total: $%'.2f\n", 12345.67);
return 0;
}
Total: $12,345.67
The Trick: To format currency with commas in C: (1) include
<locale.h>, (2) callsetlocale(LC_ALL, "en_US.utf8")at program start, (3) use%'.2f(note the apostrophe) in your format string.
%c in scanf(" %c", &choice)?scanf("%c") would read the \n left in the buffer from a previous input — and your program would skip right past the user's next input. The space in the format string tells scanf to consume any whitespace characters first, then read the actual character the user typed.
Testing Your Input Handling
Sanity Check: Test with three categories of input: normal (expected values), boundary (0, maximum, minimum), and edge (negative numbers, letters, empty input, very large numbers). If your program handles all three, it’s solid.
while (fgetc(stdin) != '\n') {} after a scanf("%d") call, then immediately call scanf("%d") again?scanf("%d") does skip leading whitespace (so a lone \n isn't the problem — that's why option A is tempting). The real issue is leftover non-numeric characters. If the user types 42abc, scanf reads 42 and leaves abc\n in the buffer. The next scanf("%d") immediately hits abc, fails, and returns 0. The buffer-clearing loop prevents this.
Quick Check: Why check scanf's return value?
scanf returns the number of items successfully read. If the user types “abc” when you expect a number, scanf returns 0 (no items read) and the variable keeps its previous value (potentially garbage). Checking the return value lets you detect and handle invalid input.
Quick Check: What does while (fgetc(stdin) != '\n') {} do?
It reads and discards characters from the input buffer one at a time until it reaches the newline character. This clears any leftover input (including the newline from pressing Enter) that could interfere with the next scanf call.
Quick Check: Why use a space before %c in scanf(" %c", &ch)?
The space tells scanf to skip whitespace characters (spaces, tabs, newlines) before reading the character. Without it, scanf("%c") might read a leftover newline from a previous input instead of waiting for the user’s actual input.
Input Handling Is Professional Discipline
Every professional C program handles input defensively. The patterns here — buffer clearing, return value checking, validation loops — are the same patterns used in production C code. They’re not exciting, but they prevent crashes and undefined behavior.
With Week 4 complete, you can write C programs with variables, I/O, operators, control flow, functions, and solid input handling. Next comes code organization — header files and Makefiles that let you split a project across multiple files.
Big Picture: Lab 4 (water bill calculator) combines everything from Weeks 3–4: reading numeric input, computing with tiered rates, validating menu choices, and formatting currency output. The patterns in this lesson are exactly what you need.