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):

C
#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;
}
Input
29
Output
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

Typescanf 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
C
#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;
}
Input
3 12.50 M
Output
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:

C
#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;
}
Input
twelve
Output
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:

C
#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;
}
Input
Ada Lovelace
Output
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:

C
#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;
}
Input
a few
6
Output
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):

C
#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;
}
Input
12.5
7.25
not a number
30
Output
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.

Try it yourself · main.c
Edit the code, copy it into main.c, then compile and run it with cc -std=c17 -Wall main.c -o main && ./main. How to set up a C compiler
Input
9 4
Output
Two whole numbers: sum 13, difference 5, product 36