Part of C in 100s

C in 100 Seconds: scanf | Episode 12

Celest KimCelest Kim

Video: C in 100 Seconds: scanf — Read Numbers and Strings from the User | Episode 12 by Taught by Celeste AI - AI Coding Coach

Take the quiz on the full lesson page
Test what you've read · interactive walkthrough

C scanf: Read Numbers and Strings From the User

scanf("%d", &age); reads an int. scanf("%s", name); reads a word. Format specifiers like printf's, but in reverse — and the & is critical for non-arrays.

scanf is C's built-in input parser. Powerful but treacherous — buffer overflows, format mismatches, and partial reads make it a frequent bug source. Episode 13 covers the safer alternative fgets.

The basic shape

#include <stdio.h>

int main() {
  int age;
  printf("Enter age: ");
  scanf("%d", &age);
  printf("You are %d years old\n", age);

  char name[50];
  printf("Enter name: ");
  scanf("%s", name);
  printf("Hello, %s!\n", name);

  return 0;
}

Two reads — one int, one word.

Format specifiers (mostly like printf)

Type Specifier
int %d
unsigned %u
long %ld
long long %lld
float %f
double %lf (note: lowercase L+f, required for double in scanf)
char %c
string (word) %s

Note: in printf, %f covers both float and double (because float promotes). In scanf, you need %f for float and %lf for double — they take pointers to different sizes, no promotion.

The & — pass-by-pointer

int x;
scanf("%d", &x);   // pass address of x

scanf writes to the variable through a pointer. You pass &x (address of x), not x. Without &, scanf would treat the value as the address — typically a segfault.

The exception: arrays.

char name[50];
scanf("%s", name);   // no & — array decays to pointer

name (an array) automatically becomes &name[0] when passed. Same as %s working without &.

%s reads ONE WORD

char name[50];
scanf("%s", name);    // reads until first whitespace

%s stops at the first whitespace (space, tab, newline). Input "Alice Smith" — only "Alice" is read; "Smith" stays in the input buffer for the next read.

To read a line with spaces, use fgets (next episode) or %[^\n] (read until newline).

Buffer overflow risk

char name[10];
scanf("%s", name);   // input "verylongname" — overflow!

%s writes until whitespace. If input is longer than the buffer, it stomps memory. Critical security bug; the gets function was so bad it's been removed from the C standard.

The safe form: specify max length:

char name[10];
scanf("%9s", name);   // read at most 9 chars (+ \0 = 10)

But fgets(name, 10, stdin) is even simpler and clearer (next episode).

Reading multiple values

int a, b;
scanf("%d %d", &a, &b);   // expects two ints separated by whitespace

Format string can have multiple specifiers. The user types "5 10" and a = 5, b = 10. The space in the format matches any whitespace (including newlines) in the input.

int month, day, year;
scanf("%d/%d/%d", &month, &day, &year);   // user types "5/15/2024"

Literal characters in the format must match the input. / must be where the input has /.

Return value: how many were parsed

int x;
int n = scanf("%d", &x);
if (n != 1) {
  printf("That wasn't a number!\n");
}

scanf returns the number of successful conversions. For one specifier, success returns 1; failure returns 0 (no input matched) or EOF (input exhausted).

Always check the return value. If parsing fails, your variable has garbage from before — using it is a bug.

Mixing scanf and fgets

This trips up everyone:

int age;
char name[50];

scanf("%d", &age);            // user types "25\n"; scanf reads 25, leaves \n
fgets(name, 50, stdin);       // immediately reads the leftover \n!

After scanf("%d", ...) reads "25", the newline \n stays in the buffer. The next fgets reads it as an empty line.

Fix: consume the newline:

scanf("%d", &age);
getchar();   // discard the leftover \n
fgets(name, 50, stdin);

Or skip whitespace in scanf format strings (some specifiers like %s skip leading whitespace; %c doesn't).

The cleanest approach: just use fgets for everything and parse with sscanf.

%c reads ONE CHAR (including whitespace)

char ch;
scanf(" %c", &ch);   // leading space SKIPS whitespace

The leading space in " %c" makes scanf skip whitespace before reading. Without it, %c would read the first byte (often the leftover newline from a previous scanf).

Practical input idioms

// Read an int with retry
int x;
while (scanf("%d", &x) != 1) {
  printf("Invalid. Try again: ");
  // discard rest of line
  while (getchar() != '\n');
}

// Read multiple lines until EOF
int n;
while (scanf("%d", &n) == 1) {
  printf("%d\n", n);
}

Common mistakes

Forgetting &. scanf("%d", x); — if x is int, this writes to address 5 (or whatever). Crash.

Using %lf in printf for double. Wrong — printf uses %f for both. %lf in printf is undefined behavior on some compilers; works on others.

Buffer overflow with %s. Always cap with %Ns (where N is buffer-size minus 1).

Mixing scanf("%d", ...) and fgets. Leftover newline confuses things.

Not checking return value. Failed parses leave variables uninitialized; using them is a bug.

Wrong format type. int x; scanf("%lf", &x); — passing pointer to int but expecting double. Memory stomped.

Why fgets is usually better

scanf mixes parsing and reading. For real input, separate them:

char line[100];
fgets(line, sizeof(line), stdin);   // read full line, bounded
int x;
sscanf(line, "%d", &x);              // parse from string

Cleaner error handling, no leftover-newline trap, no buffer overflow. Episode 13 walks through fgets in depth.

What's next

Episode 13: fgets — safe input. The right way to read user input. Bounded read, full line including spaces, predictable behavior.

Recap

scanf("%d", &x) reads an int into x. & for non-arrays; arrays decay automatically. %s reads one word; bounded with %Ns. %lf for double in scanf (vs %f in printf). Return value = successful conversions. Mixing with fgets traps you on leftover newlines. Always check return value. For real input, prefer fgets + sscanf.

Next episode: fgets.

Ready? Take the quiz on the full lesson page →
Test what you've learned. Watch the lesson and try the interactive quiz on the same page.