TRT
Sign in

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.

FreeAbout 15 minutes

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

Reading two integers, adding them, and printing the resultstep 1 of 5
int a, b, sum;scanf("%d", &a);scanf("%d", &b);sum = a + b;printf("Sum: %d\n", sum);
  1. variable 0a: uninitialized(looked at in this step)
  2. variable 1b: uninitialized
  3. variable 2sum: uninitialized
  4. 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:

c
#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 (&):

c
int age = 0;
printf("Enter your age: ");
scanf("%d", &age);

Here is what happens step by step:

  1. printf("Enter your age: "); writes the prompt to the terminal so the user knows the program is waiting.
  2. scanf("%d", &age); pauses execution and waits for keyboard input followed by the Enter key.
  3. The user types 21 and presses Enter, placing the characters '2', '1', and ' ' into the stdin buffer.
  4. scanf skips any leading whitespace (spaces, tabs, or newlines), reads the digits 21, converts them into the 32-bit integer 21, 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:

SpecifierWhat it reads from stdinTarget pointer typeWhitespace behavior
%dSigned base-10 integerint * (&i)Skips leading spaces, tabs, and newlines
%fFloating-point numberfloat * (&f)Skips leading whitespace
%lfDouble-precision floatdouble * (&d)Skips leading whitespace
%cExactly one characterchar * (&c)Does not skip whitespace unless preceded by a space: " %c"
%sA single whitespace-delimited wordchar * (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:

c
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 types 42, scanf returns 1.
  • If the user types hello, 'h' is not a valid digit. scanf stops immediately, leaves 'h' sitting in the input buffer, leaves age unmodified, and returns 0.
  • If you ask for two integers with scanf("%d %d", &a, &b) and the user types 10 xyz, scanf fills a with 10, fails on xyz, and returns 1.

Checking that the return value equals the exact number of items you requested guarantees that your program never computes with uninitialized memory:

c
#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:

  1. 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 stdin in memory. When scanf runs, the terminal collects characters until the user presses Enter, and hands the entire line to your program in one batch.
  2. Parsing overhead: Once the characters are in memory, scanf scans the format string character by character and converts ASCII digits (such as '2' and '5', byte values 50 and 53) 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

MistakeWhat goes wrongFix
scanf("%d", age) without &Treats age's value as a memory address and crashesPass &age so scanf receives the variable's address
Ignoring scanf's return valueFailed input leaves the variable uninitialized (garbage value)Check if (scanf("%d", &age) == 1) before using age
Using %f for a double variableWrites a 4-byte float into an 8-byte double, corrupting its bitsUse %f for float and %lf for double
scanf("%c", &ch) after reading a numberReads the leftover '' from the Enter key instead of the next characterPut 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

Something wrong with this lesson? Report a problem

Not started

Sign in to save your learning progress.

Sign in to save