Foundations · Module 0 · Lesson 3 of 3
Reading User Input and Building Simple Programs
Read input from the keyboard with scanf, validate the input, and combine variables, expressions, and printf into complete interactive programs.
By the end you can
- Read an integer, a floating-point number, and a character from the keyboard with scanf
- Check scanf's return value to confirm input was read successfully
- Combine input, variables, expressions, and output into interactive programs
- Write small end-to-end programs such as a temperature converter
Builds on Variables, Assignment, and Basic Expressions.
01 · A question first
Your programs so far use hard-coded values you typed into the source. What if you want a different person to run your program and supply their own numbers each time? How does scanf read text from the keyboard and store it in a variable, and why does forgetting the & before a variable crash the program?
Make a guess, then step through the trace below to check it.
02 · Watch it run
int a, b, sum;scanf("%d", &a);scanf("%d", &b);sum = a + b;printf("Sum: %d\n", sum);- variable 0a: uninitialized(looked at in this step)
- variable 1b: uninitialized
- variable 2sum: uninitialized
- variable 3stdin: waiting
Three int variables are declared but hold no known value yet.
Machine work: allocate a, b, sum on stack
03 · The idea
Start with the problem
Your temperature converter from the previous lesson works, but only for one hard-coded number:
#include <stdio.h>
int main(void) {
float celsius = 25.0f;
float fahrenheit = celsius * 9.0f / 5.0f + 32.0f;
printf("Fahrenheit: %f", fahrenheit);
return 0;
}Every time you want to convert a different temperature, you must open your editor, change 25.0f to a new number, save the file, recompile with gcc, and run the binary again. Worse, if you give the compiled program to a friend who does not have a C compiler or your source file, they can only ever see the answer for 25 degrees Celsius.
Interactive programs solve this by reading values from the person running the program while it executes. Every operating system connects a running terminal program to two standard text channels: standard output (stdout), where printf sends characters to your screen, and standard input (stdin), where characters typed on the keyboard wait in a buffer to be read. In C, you read formatted values from stdin with scanf, store them into variables in memory, compute with those variables, and print the results.
How the idea works
scanf (short for scan formatted) is the mirror image of printf. While printf takes values from variables and formats them as text on the screen, scanf reads text typed at the keyboard, parses it according to a format string, and writes the resulting binary value into a variable.
In the trace above, watch how scanf fills a and b one step at a time. On line 1, a, b, and sum are allocated on the stack, holding whatever leftover bits happened to be in those memory cells. On line 2, scanf("%d", &a) pauses the program until the user types an integer and presses Enter. Once the user enters 7, scanf converts the character '7' into the integer 7 and writes it directly into a's memory slot. Line 3 repeats the process to store 5 into b, so line 4 can add 7 + 5 and store 12 into sum.
Why scanf needs the & operator
Because C passes function arguments by value, passing a variable name like age to a function only hands the function a copy of age's current number. If scanf modified that copy, your variable in main would never change. To let scanf reach back into main and overwrite your variable, you must pass the variable's memory address using the address-of operator (&):
int age = 0;
printf("Enter your age: ");
scanf("%d", &age);Here is what happens step by step:
printf("Enter your age: ");writes the prompt to the terminal so the user knows the program is waiting.scanf("%d", &age);pauses execution and waits for keyboard input followed by the Enter key.- The user types
21and presses Enter, placing the characters'2','1', and' 'into thestdinbuffer. scanfskips any leading whitespace (spaces, tabs, or newlines), reads the digits21, converts them into the 32-bit integer21, and writes that integer to the memory address&age.
Format specifiers and whitespace rules
Like printf, scanf uses format specifiers to know what kind of text to expect and how many bytes to write at the target address:
| Specifier | What it reads from stdin | Target pointer type | Whitespace behavior |
|---|---|---|---|
%d | Signed base-10 integer | int * (&i) | Skips leading spaces, tabs, and newlines |
%f | Floating-point number | float * (&f) | Skips leading whitespace |
%lf | Double-precision float | double * (&d) | Skips leading whitespace |
%c | Exactly one character | char * (&c) | Does not skip whitespace unless preceded by a space: " %c" |
%s | A single whitespace-delimited word | char * (buffer) | Skips leading whitespace, stops at the next space or newline |
Notice two crucial details in that table:
First, printf uses %f for both float and double, but scanf distinguishes them strictly. A float occupies 4 bytes while a double occupies 8 bytes. Passing &my_double to scanf requires %lf (long float); using %f writes only 4 bytes and leaves the other 4 bytes corrupted.
Second, numeric specifiers (%d, %f, %lf) automatically skip leading spaces and leftover newline characters (' ') from earlier Enter presses. The character specifier %c does not skip whitespace by default—it reads the very next byte in the input stream, which is often the leftover ' ' from the previous line. Writing " %c" with a leading space inside the format string tells scanf to consume any pending whitespace first before reading the character:
int age;
double height;
char initial;
printf("Enter age, height (m), and first initial: ");
if (scanf("%d %lf %c", &age, &height, &initial) == 3) {
printf("Age: %d, Height: %.2f, Initial: %c", age, height, initial);
}Why it is correct
Input from the outside world is never guaranteed to match what your program expects. A user asked for an integer might type twenty, press Enter on an empty line, or close the input stream with Ctrl+D (on Linux and macOS) or Ctrl+Z (on Windows).
scanf reports whether it succeeded through its return value: an int equal to the number of variables it successfully matched and assigned, or the special constant EOF (typically -1) if the input stream ended before any item could be read.
- If you ask for one integer with
scanf("%d", &age)and the user types42,scanfreturns1. - If the user types
hello,'h'is not a valid digit.scanfstops immediately, leaves'h'sitting in the input buffer, leavesageunmodified, and returns0. - If you ask for two integers with
scanf("%d %d", &a, &b)and the user types10 xyz,scanffillsawith10, fails onxyz, and returns1.
Checking that the return value equals the exact number of items you requested guarantees that your program never computes with uninitialized memory:
#include <stdio.h>
int main(void) {
float celsius = 0.0f;
printf("Enter temperature in Celsius: ");
if (scanf("%f", &celsius) != 1) {
printf("Error: please enter a valid number.");
return 1;
}
float fahrenheit = celsius * 9.0f / 5.0f + 32.0f;
printf("%.1f Celsius is %.1f Fahrenheit", celsius, fahrenheit);
return 0;
}What it costs
Reading interactive input involves two layers of work:
- Operating system I/O buffering: Waiting for a human to type at the keyboard takes milliseconds or seconds—millions of times slower than CPU arithmetic. To avoid making a slow operating system call for every single character, the C standard library buffers
stdinin memory. Whenscanfruns, the terminal collects characters until the user presses Enter, and hands the entire line to your program in one batch. - Parsing overhead: Once the characters are in memory,
scanfscans the format string character by character and converts ASCII digits (such as'2'and'5', byte values50and53) into binary numbers (2 * 10 + 5 = 25). For keyboard input or small configuration files, this takes less than a microsecond per number.
Pitfalls and variations
| Mistake | What goes wrong | Fix |
|---|---|---|
scanf("%d", age) without & | Treats age's value as a memory address and crashes | Pass &age so scanf receives the variable's address |
Ignoring scanf's return value | Failed input leaves the variable uninitialized (garbage value) | Check if (scanf("%d", &age) == 1) before using age |
Using %f for a double variable | Writes a 4-byte float into an 8-byte double, corrupting its bits | Use %f for float and %lf for double |
scanf("%c", &ch) after reading a number | Reads the leftover '' from the Enter key instead of the next character | Put a leading space in " %c" to skip whitespace |
Where it is used
Command-line utilities, interactive shells, system installers, and competitive programming solutions all read structured input from stdin. Because stdin can be redirected from a file in the shell (./convert < temperatures.txt) or piped from another command (echo "100" | ./convert), any program you build with scanf and printf works both interactively with a human at the keyboard and automatically inside terminal pipelines.
In the next module, you will use values read from the user to make decisions with if and else, repeat work with loops, organize logic into functions, and store sequences in arrays and strings.
04 · Prove it
Question 1 of 3 · answer from memory
What does the & operator do in scanf("%d", &age);?
05 · Practice
Asked in interviews
Something wrong with this lesson? Report a problem