Dataslope logoDataslope

Input and Output

printf, scanf, format specifiers, and reading data the program didn't already know

Up to this point our programs have always known their inputs in advance — they were hard-coded into the source. A real program needs to talk to the outside world: read from the keyboard, write to the terminal, read from files. This is I/O, short for input/output.

C provides I/O through the standard library <stdio.h>. The philosophy is small, simple, and printable. Everything you read or write is a stream of bytes.

Printing with printf

You've used printf since the first chapter. Time to look at it properly.

printf(format_string, args...);

The format string is text with embedded conversion specifications like %d, %s, %f, each of which is replaced by the corresponding argument.

SpecTypeExample
%dintprintf("%d", 42);
%ldlongprintf("%ld", 1000000L);
%uunsigned intprintf("%u", 100u);
%fdouble (yes, double not float)printf("%f", 3.14);
%.2fdouble with 2 decimal placesprintf("%.2f", 3.14159);
%cchar (printed as a character)printf("%c", 'A');
%schar * (a C string)printf("%s", "hello");
%xint printed in hexadecimalprintf("%x", 255);
%%a literal %printf("50%%");
Code Block
C 17 (201710L)

Field width and padding

You can ask for a minimum field width — useful for tables:

Code Block
C 17 (201710L)
  • %-10s — string in a 10-wide field, left-justified (the -).
  • %5d — integer in a 5-wide field, right-justified (the default).

Tiny formatting tricks like these are how plain-text reports stay readable.

Reading with scanf

scanf reads input from the keyboard (or any redirected source). Its format string looks similar to printf's but with one critical difference: you must pass the address of each variable to fill (using the & operator).

int n;
scanf("%d", &n);    // read an int into n

&n means "the memory address of n". scanf needs the address so it can write the new value into your variable. (When we cover pointers, this will make even more sense.)

Code Block
C 17 (201710L)

Why `if (scanf(...) == 1)`?

`scanf` returns the number of items it successfully read. Always check it. If the user types `hello` when you asked for a number, `scanf` returns `0` and your variable is unchanged (and probably uninitialized!).

Reading multiple values

Format specifiers in scanf skip whitespace between values (except for %c).

Code Block
C 17 (201710L)

scanf and strings

Reading a string with %s reads one whitespace-delimited word and never reads more characters than fit in your buffer if you use a width:

char name[32];
scanf("%31s", name);   // read at most 31 chars + null terminator

Always specify the maximum width when reading strings with scanf, or your program is one long input away from a buffer overflow. We'll return to strings and buffers in upcoming chapters.

getchar and putchar — one character at a time

For character-by-character I/O, the standard library offers getchar() and putchar().

Code Block
C 17 (201710L)

This is a tiny, classic loop. Why is c an int rather than a char? Because getchar returns EOF (typically -1) to signal "no more input", and EOF must be distinguishable from every valid character — including 0xFF. Storing the result in a char would make that distinction impossible.

Standard streams

Every C program automatically has three streams open:

StreamC nameDefault
inputstdinthe keyboard
outputstdoutthe terminal
errorsstderralso the terminal

printf writes to stdout. scanf reads from stdin. For error messages, use fprintf(stderr, "oops: %s\n", msg);. Separating errors lets a user redirect them differently from normal output.

Formatted vs unformatted I/O

printf and scanf are formatted I/O — they understand types and format specifications. There are also unformatted I/O functions like fgets (read a line into a buffer) and fputs (write a string) that operate on raw bytes. For real input handling in larger programs, fgets is usually safer than scanf:

char line[256];
if (fgets(line, sizeof(line), stdin) != NULL) {
    // line now holds at most 255 characters + a null terminator
    // (it may include a trailing '\n')
}

We'll see more of fgets in the chapter on strings.

Challenge: print a small invoice

Challenge
C 17 (201710L)
Format an invoice line

Two variables item (string) and qty (int) and unit_price (double) are set to "Widget", 5, and 3.50. Print exactly:

Item: Widget    Qty: 5  Unit: $3.50  Total: $17.50

Use the field widths:

  • %-8s for item
  • plain %d for qty
  • %.2f for prices
QuestionSelect one

Which format specifier should you use to print a double with three digits after the decimal point?

%d

%f

%s

%.3f

QuestionSelect one

Why does scanf require the & operator in front of integer variables, as in scanf("%d", &n);?

Because the C standard forbids passing values directly to scanf.

Because scanf needs the address of n to write the parsed value back into it.

Because & converts n to a string suitable for parsing.

Because %d requires a special pointer type.

On this page