Reading User Input
Programs become interactive when they read input. C offers scanf for quick formatted reading and fgets for reading whole lines safely. Input is where most beginner C programs break, so this lesson focuses on reading reliably and handling bad input.
scanf
scanf reads values using the same kind of format string as printf. You pass the address of each variable with &, so scanf can store into it (lesson 31 explains addresses):
#include <stdio.h> int main(void) { int age; printf("How old are you? "); scanf("%d", &age); printf("Next year you'll be %d.\n", age + 1); return 0; }
29
How old are you? Next year you'll be 30.
The input shown was typed by the user. (When input comes from a keyboard, it is also echoed on screen; here it was supplied separately, so it doesn't appear in the output.)
Several values and types
| Type | scanf specifier |
|---|---|
int | %d |
long / long long | %ld / %lld |
float | %f |
double | %lf — not %f! |
char | " %c" (the space skips whitespace first) |
| a word (string) | %31s with a width limit |
#include <stdio.h> int main(void) { int quantity; double price; char size; printf("Quantity, price and size (S/M/L): "); scanf("%d %lf %c", &quantity, &price, &size); printf("%d x size %c = %.2f\n", quantity, size, quantity * price); return 0; }
3 12.50 M
Quantity, price and size (S/M/L): 3 x size M = 37.50
Whitespace in the format string, and before most specifiers, skips any spaces and newlines — so values can be on one line or several.
Always check the return value
scanf returns how many values it successfully stored. If the user types something that isn't a number, it stores nothing and returns 0 — and your variable keeps its old (possibly uninitialised) value:
#include <stdio.h> int main(void) { int n = 0; printf("Enter a number: "); if (scanf("%d", &n) != 1) { printf("That wasn't a number.\n"); return 1; } printf("Double: %d\n", n * 2); return 0; }
twelve
Enter a number: That wasn't a number.
(This program exits with status 1 to signal the error.) scanf returns EOF (a negative value) if input ends before anything is read.
Reading lines with fgets
scanf("%s") stops at the first space, and without a width it can overflow your array. To read a whole line — like a full name — use fgets, which never writes more than the size you give it:
#include <stdio.h> #include <string.h> int main(void) { char name[50]; printf("Full name: "); if (fgets(name, sizeof name, stdin) == NULL) { return 1; } name[strcspn(name, "\n")] = '\0'; // remove the newline fgets keeps printf("Hello, %s! Your name has %zu characters.\n", name, strlen(name)); return 0; }
Ada Lovelace
Full name: Hello, Ada Lovelace! Your name has 12 characters.
fgets keeps the newline character at the end of the line; the strcspn line finds it and replaces it with the end-of-string marker. Lesson 29 covers these string functions.
The robust pattern: read a line, then parse it
Mixing scanf and fgets causes a classic bug: scanf("%d") leaves the newline in the input, so the next fgets immediately reads an empty line. The reliable approach is to always read whole lines with fgets, then convert with sscanf or strtol:
#include <stdio.h> int read_int(const char *prompt, int *out) { char line[64]; for (;;) { printf("%s", prompt); if (fgets(line, sizeof line, stdin) == NULL) return 0; // input ended if (sscanf(line, "%d", out) == 1) return 1; printf("Please enter a whole number.\n"); } } int main(void) { int guests; if (read_int("How many guests? ", &guests)) { printf("Setting %d places.\n", guests); } return 0; }
a few 6
How many guests? Please enter a whole number. How many guests? Setting 6 places.
Bad input is rejected and the question repeated, and an empty or ended input stream is handled too. The int *out parameter is a pointer, which lets the function store its result in the caller's variable (lesson 34).
Reading until the input ends
A loop over fgets processes every line until the end of input — whether that's a file redirected into the program (./main < data.txt) or the user pressing Ctrl+D (Ctrl+Z, Enter on Windows):
#include <stdio.h> int main(void) { char line[100]; int count = 0; double total = 0; while (fgets(line, sizeof line, stdin) != NULL) { double value; if (sscanf(line, "%lf", &value) == 1) { total += value; count++; } } printf("%d values, total %.2f\n", count, total); return 0; }
12.5 7.25 not a number 30
3 values, total 49.75
Try it yourself
Ask for two numbers on one line and print their sum, difference and product. Check that two values were read.
9 4
Two whole numbers: sum 13, difference 5, product 36