C User Input (scanf)

User input lets a C program receive data while it is running instead of using only values written in the source code. The standard function most beginners meet first is scanf, which reads formatted text from standard input and stores converted values in variables. It is powerful, but it is also strict: the format string, variable types, memory addresses, and return value all matter.

Overview: How scanf Works

scanf is declared in <stdio.h>. It reads from standard input, usually the keyboard connected to the terminal. The user types characters, presses Enter, and those characters become input for the program. scanf then tries to match the characters against a format string such as "%d" or "%d %lf".

The important idea is that keyboard input starts as text. If the user types 42, the terminal sends the characters '4' and '2', not an integer already stored in binary form. A conversion specifier tells scanf how to translate those characters. %d converts text to an int, %lf converts text to a double, %c reads one character, and %s reads a word into a character array.

Unlike printf, scanf must write into your variables. To do that, it needs the memory address of each destination. For normal scalar variables such as int age; or double price;, you pass &age or &price. The & operator means “address of.” Character arrays used as strings are different: an array name such as name already acts like the address of its first element in this call, so you do not write &name for %s.

Syntax

scanf("format string", address1, address2, ...);
  • scanf is the input function from <stdio.h>.
  • The format string contains conversion specifiers that describe what to read.
  • Each conversion specifier needs a matching destination argument after the format string.
  • Most destination arguments must be addresses, such as &number.
  • The return value is the number of items successfully read and assigned.
Specifier Reads Destination example
%d Decimal integer &age where age is an int
%f Float value &temperature where temperature is a float
%lf Double value &price where price is a double
%c One character &grade where grade is a char
%19s A word, limited to 19 characters name where name is char name[20]

Examples

Reading One Integer

#include <stdio.h>

int main(void)
{
    int age;

    printf("Enter your age: ");

    if (scanf("%d", &age) == 1) {
        printf("Next year you will be %d.\n", age + 1);
    } else {
        printf("That was not a whole number.\n");
    }

    return 0;
}

Output:

Enter your age: Next year you will be 19.

This sample run assumes the user typed 18. The program asks scanf to read one integer with %d. If the conversion succeeds, scanf returns 1, the value is stored in age, and the program prints a calculation based on it.

Reading Multiple Values

#include <stdio.h>

int main(void)
{
    int quantity;
    double price;

    printf("Enter quantity and price: ");

    if (scanf("%d %lf", &quantity, &price) == 2) {
        printf("Items: %d\n", quantity);
        printf("Total: $%.2f\n", quantity * price);
    } else {
        printf("Could not read both values.\n");
    }

    return 0;
}

Output:

Enter quantity and price: Items: 4
Total: $30.00

This sample run assumes the user typed 4 7.5. The first conversion stores an int, and the second stores a double. Most numeric conversions skip leading whitespace, so spaces, tabs, or newlines may separate the two values.

Reading A Character After Whitespace

#include <stdio.h>

int main(void)
{
    char initial;
    int score;

    printf("Enter initial and score: ");

    if (scanf(" %c %d", &initial, &score) == 2) {
        printf("Student %c scored %d.\n", initial, score);
    } else {
        printf("Invalid record.\n");
    }

    return 0;
}

Output:

Enter initial and score: Student M scored 92.

This sample run assumes the user typed M 92. The space before %c is intentional: it tells scanf to skip any whitespace before reading the character. Without it, %c can read a leftover newline from earlier input.

Reading A Word Safely

#include <stdio.h>

int main(void)
{
    char name[20];

    printf("Enter first name: ");

    if (scanf("%19s", name) == 1) {
        printf("Hello, %s!\n", name);
    } else {
        printf("No name was read.\n");
    }

    return 0;
}

Output:

Enter first name: Hello, Ada!

This sample run assumes the user typed Ada. The array has room for 20 characters, and %19s limits input to 19 visible characters so C still has room for the string’s terminating '\0'. Plain %s has no length limit and can overflow the array.

How It Works Step By Step

  1. The program prints a prompt with printf. If the prompt has no newline, it still usually appears before input in an interactive terminal, but adding fflush(stdout) can be useful in some environments.
  2. The user types characters and presses Enter. The terminal provides those characters to standard input.
  3. scanf reads characters and compares them with the format string from left to right.
  4. Whitespace in most format strings means “skip any amount of whitespace.” Numeric specifiers also skip leading whitespace automatically.
  5. For each successful conversion, scanf stores the converted value at the address you passed.
  6. If a conversion fails, scanf stops and returns how many assignments succeeded so far.

This return value is essential. If scanf("%d", &age) returns 0, no integer was stored in age. Reading age afterward would use an uninitialized value if you had not assigned it earlier. Good input code checks the return value before trusting the variable.

Common Mistakes

Forgetting The Address Operator

For an ordinary variable, scanf("%d", age); is wrong because it passes the value of age, not the place where the value should be stored. The corrected form is scanf("%d", &age);. Passing the wrong kind of argument causes undefined behavior, which means the program may crash, corrupt memory, or appear to work by accident.

Using The Wrong Specifier

The specifier must match the destination type. Use %lf when reading a double, not %f. Use %d for an int, not for a long. Mismatches are especially dangerous because scanf relies on the format string to know what kind of pointer it received.

Expecting %s To Read A Full Sentence

%s reads one whitespace-delimited word. If the user types Ada Lovelace, %s reads only Ada. For full lines, C programmers often use fgets instead, then parse the line if needed.

Leaving Bad Input Behind

If the user types abc when %d expects an integer, scanf fails and leaves those characters waiting in the input stream. A repeated attempt to read another integer may fail again on the same characters unless the program consumes or clears the bad input. For beginner programs, printing an error and ending is often the cleanest response.

Best Practices

  • Always include <stdio.h> before using scanf.
  • Check the return value and use the variable only after the expected number of assignments succeeded.
  • Use & for ordinary variables such as int, double, and char.
  • Do not use & with a character array passed to %s; pass the array name and include a width limit.
  • Match each conversion specifier to the exact destination type.
  • Put prompts in printf, not inside the scanf format string.
  • Use a leading space before %c when you want to skip leftover whitespace.
  • Prefer fgets for full-line input or complex input validation.

Practice Exercises

  1. Write a program that asks for two integers and prints their product. Check that exactly two values were read.
  2. Write a program that asks for a temperature as a double and prints it with one digit after the decimal point.
  3. Write a program that reads a first initial and an age, then prints a short sentence. Use a leading space before %c.

Summary

  • scanf reads formatted text from standard input and stores converted values in variables.
  • The format string controls the expected input, and each specifier needs a matching destination.
  • Most variables require the address-of operator & so scanf can write into them.
  • The return value tells you how many assignments succeeded; checking it prevents many input bugs.
  • Width limits are required for safer %s input, and fgets is better for full lines.