Learn the two most basic tools for a program to communicate with the outside world.
printf is output, and scanf is input.
Learning Objectives
- Use the format specifier of
printfaccording to the data type. - Receive integers, real numbers, and strings as
scanf. - Organize the output with format options such as width/precision.
- Avoid common errors with
scanf(missing&,%lfvs%f).
Why is the input/output format so difficult?
printf/scanf are variable argument functions.
Because the compiler cannot individually check the data types of the arguments,
Look at the format string ("%d %f") to determine "how the value should be pulled out of memory."
If there is a mismatch between the format and the actual data type, a garbage value or segmentation fault will occur.
This lesson is effectively a “memorizing the format specifier table”.
Key concepts
1) Main format specifiers
| Designator | printf data type |
scanf data type |
Yes |
|---|---|---|---|
%d |
int |
int * |
printf("%d", 42) |
%u |
unsigned int |
unsigned int * |
|
%f |
double (automatic promotion) |
float * |
printf("%.2f", 3.14) |
%lf |
double |
double * |
scanf("%lf", &x) |
%c |
char (promoted to int) |
char * |
printf("%c", 'A') |
%s |
char * |
char * |
scanf("%9s", buf) |
%x, %o |
Hexadecimal/Octal integer | printf("%x", 255) → ff |
|
%zu |
size_t |
printf("%zu", sizeof(int)) |
The argument
floatinprintfis automatically promoted todoubleaccording to the calling convention and is received as%f. This is not the case inscanf, so must be%fforfloat *, and%lffordouble *.
2) Width and Precision
printf("[%5d]\n", 42); //[ 42] Width 5
printf("[%-5d]\n", 42); //[42] Left Align
printf("[%05d]\n", 42); //[00042] 0 Fill
printf("[%8.3f]\n", 3.14); //[ 3.140] Width 8, 3 decimal places
3) How to use scanf
int n;
scanf("%d", &n); //Pass the address of the variable with &
Multiple values:
int a, b;
scanf("%d %d", &a, &b); //Space/tab/newline separator
Caution: If you omit
&, likescanf("%d", n);, compilation will pass. Segmentation fault on run.
4) fgets is safe for string input
scanf("%s", ...) stops when it encounters a space and does not check the buffer size.
There is a risk of buffer overflow. For single line input, fgets is recommended.
char buf[64];
fgets(buf, sizeof(buf), stdin); //Includes line breaks
buf[strcspn(buf, "\n")] = '\0'; //Remove line breaks
See as example
Example 1 — ex01_printf.c: Various format specifiers
Execution result
Decimal: 255
Hexadecimal: ff
Octal: 377
Letter: A (Code 65)
String: Hello
Real number default: 3.141592
2-digit real number: 3.14
Exponential notation: 3.141592e+00
Key point: The same value (255) is output differently depending on the decimal specifier.
Example 2 — ex02_scanf_int.c: Enter one integer
int n;
scanf("%d", &n);
printf("Input value: %d\nDouble: %d\n", n, n * 2);
Input: 7
Execution result
Please enter an integer: Input value: 7
Double: 14
Key point: If you remove & from &n, it will compile, but execution will be broken.
Example 3 — ex03_scanf_multi.c: Entering multiple values at once
Input: 17 5
Execution result
Enter two integers separated by a space: Sum: 22
Cars: 12
Product: 85
Share: 3
Key point: Input can be separated by anything space, tab, newline.
Example 4 — ex04_format.c : width/precision
Execution result
[ 42]
[42 ]
[00042]
[ 3.1416]
[3.1416 ]
Key point: Often used when aligning columns in tabular output.
A different perspective — printf is "Form Filling"
Format: "Value is %d, percentage is %.2f%%\n"
Factor: 42 0.75
│ │
▼ ▼
Output: "Value is 42, percentage is 0.75%"
%d/%.2f in the form is blank, and the following arguments are filled in in their place.
%% is an escape to print one character, %, on the screen.
Common Mistakes
- Missing
&inscanf:scanf("%d", n)→ crash. Must be&n. %fvs%lf:%lffordoubleinput,%fforfloatinput.- Buffer overrun: Enter 9 characters in
char buf[8]; scanf("%s", buf);→ Memory damage. → Limit the width likescanf("%7s", buf)or usefgets. - Newline remaining: When
fgetsis called afterscanf("%d", ...), a blank line is read. → Absorbscanffollowed bygetchar()once, or use thefgets+sscanfpattern from the beginning. - Send
doubleto%d: The output value is meaningless (data type mismatch).
Cleanup
- For
printf/scanf, the format specifier is key and must match the data type. scanfdelivers the address (&x) of the input variable.floatis%f,doubleisprintf,%f/scanfis%lf.fgetsis safe for inputting one line of string.- You can create neat table output with width/precision (
%5d,%.2f).
Try it yourself
cd src
gcc -std=c11 -Wall -o ex01 ex01_printf.c && ./ex01
gcc -std=c11 -Wall -o ex02 ex02_scanf_int.c && echo 7 | ./ex02
gcc -std=c11 -Wall -o ex03 ex03_scanf_multi.c && echo "17 5" | ./ex03
gcc -std=c11 -Wall -o ex04 ex04_format.c && ./ex04
Application:
- Delete
&of&ninex02and compile and run. Observe the results. - Check the output when entering
b = 0inex03.