String Input & Output
scanf("%s", ...), is also one of the most dangerous functions in the standard library when used carelessly. This page covers printing, the risk in scanf, and the safer alternative, fgets().Printing Strings with printf
%s conversion specifier tells printf to print a string: it writes characters starting at the given pointer until it hits the null terminator.#include <stdio.h>
int main(void) {
char name[] = "Ada";
printf("Hello, %s!\n", name); // Hello, Ada!
return 0;
}Reading Strings with scanf
scanf("%s", buf) reads a sequence of non-whitespace characters into buf, stopping at the first space, tab, or newline, and automatically appends a null terminator.#include <stdio.h>
int main(void) {
char name[20];
printf("Enter your name: ");
scanf("%s", name); // no & needed -- name already decays to a pointer
printf("Hi, %s!\n", name);
return 0;
}scanf with a plain %s has no idea how big your buffer is. If the user types more characters than the buffer can hold, scanf keeps writing past the end of it anyway — a textbook buffer overflow. Never use unbounded %s on input that could come from a user or any untrusted source. If you must use scanf for a string, always give it a maximum width, one less than the buffer size to leave room for the terminator: for a 20-byte buffer, use %19s, not %s.char buf[20];
scanf("%s", buf); // DANGEROUS: unbounded, can overflow buf
scanf("%19s", buf); // SAFE: reads at most 19 chars, leaves room for '\0'fgets(): The Safer Way to Read a Line
fgets() reads an entire line of input, up to a maximum number of characters you specify, and always respects the buffer size you give it. It is the recommended way to read string input in C. (See the dedicated page on gets(), puts() & fgets() for a deeper look at its full signature and return value.)#include <stdio.h>
int main(void) {
char line[50];
printf("Enter a line: ");
fgets(line, sizeof(line), stdin); // reads at most 49 chars + '\0', bounded by sizeof(line)
printf("You typed: %s", line);
return 0;
}Newline Handling: scanf vs fgets
A key practical difference between the two is what happens to the newline character the user types when they press Enter.
Function | Stops reading at | Newline in result? |
|---|---|---|
| The first whitespace character (space, tab, newline) | No -- the newline is left unread in the input buffer, not stored |
| A newline, or after | Yes -- the newline IS included in the stored string, if it fit |
fgets() keeps the newline character in the buffer, it is common to strip it afterward, for example by finding '\n' with strchr() and replacing it with '\0' if you don't want it in the string.printf("%s", str)prints a string up to (not including) its null terminatorscanf("%s", buf)has NO bounds checking -- always use a width limit like%19sfor a 20-byte bufferfgets(buf, sizeof(buf), stdin)is the safer alternative -- it always respects the buffer sizescanf("%s")stops at whitespace and discards it;fgets()stops at a newline and keeps it in the stringNever trust unbounded string input from users -- it is one of the most exploited classes of bugs in C history