Beginner · Strings in C · topic 18 of 60 · 25 min
Reading strings safely
Explanation
Why reading text is dangerous in C
A program cannot know in advance how long a user's input will be. If it reads into a 20-byte array and the user types 100 characters, a careless function writes the extra 80 bytes over whatever comes next in memory. Attackers deliberately send long inputs to exploit this. Safe input means always telling the reading function how big the buffer is.
fgets: the standard safe way
#include <stdio.h>
#include <string.h>
int main(void) {
char name[30];
printf("Full name: ");
if (fgets(name, sizeof name, stdin) == NULL) { /* NULL: end of input or error */
return 1;
}
name[strcspn(name, "\n")] = '\0'; /* remove the newline if present */
printf("Hello, %s!\n", name); /* spaces are kept: "Ravi Kumar" */
return 0;
}fgets reads up to size - 1 characters, stops after a newline, and always adds \0. If the line is longer than the buffer, the rest stays in the input for the next read; check whether the newline was found if that matters.
scanf with strings
char city[20];
scanf("%19s", city); /* reads one word, at most 19 chars; stops at a space */
char line[100];
scanf(" %99[^\n]", line); /* reads up to a newline, skipping leading whitespace (a "scanset") */Converting text to numbers: strtol
#include <errno.h>
#include <stdlib.h>
int parse_int(const char *text, long *out) {
char *end;
errno = 0;
long v = strtol(text, &end, 10); /* base 10 */
if (end == text) return 0; /* no digits at all */
while (*end == ' ' || *end == '\n') end++;
if (*end != '\0') return 0; /* junk after the number, e.g. "12kg" */
if (errno == ERANGE) return 0; /* too big for long */
*out = v;
return 1;
}atoi("12kg") returns 12 and atoi("abc") returns 0, with no way to know the input was bad, and its behaviour on overflow is undefined. strtol reports where parsing stopped (end) and sets errno to ERANGE on overflow, so you can reject bad input. Use strtod for decimals.
A robust input pattern
- Read a whole line with fgets into a big enough buffer.
- Remove the newline.
- Parse it with strtol / strtod / sscanf and check every result.
- If it fails, print a clear message and ask again (in a loop) or exit with an error code.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Reading strings safely · 1/6
In this lesson you will read text input safely in C.
Prefer a video by a teacher? Find free videos on “c fgets vs gets vs scanf string input strtol” on YouTube ↗
In real life: Reading a quantity at a pharmacy counter
A pharmacy billing tool reads the quantity for each medicine. Staff sometimes type "2 strips" or press Enter by mistake. Reading a line with fgets and parsing with strtol lets the program reject bad input politely instead of billing a wrong quantity.
char line[32];
long qty;
for (;;) {
printf("Quantity: ");
if (!fgets(line, sizeof line, stdin)) return 1;
if (parse_int(line, &qty) && qty > 0 && qty <= 100) break;
printf("Please enter a whole number from 1 to 100.\n");
}Practice (0/3 done)
The user types "Ravi Kumar" and Enter. What does name hold after scanf("%19s", name)?
The same strict number-parsing logic as strtol with an end check, in JavaScript: write parseQuantity(text) that accepts optional surrounding spaces and a newline, then only digits, and returns the number; return null for empty text, junk like "2 strips" or "12kg", and anything longer than 9 digits (to avoid overflow).
Write a C program that asks for a 6-digit PIN code until a valid one is entered: read with fgets, remove the newline, check the length is exactly 6, every character is a digit (isdigit, with an unsigned char cast) and the first is not '0'. Then ask for an age and parse it with strtol, rejecting junk and values outside 1–120.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Characters and <ctype.h>Strings in C · same module
- Mini project: reading input from the userRust Programming · Types, control flow and functions
- Type conversion and reading inputJava Programming (Core to Spring Boot) · Getting started with Java
- Pointers and functionsPointers
- C on Linux: files and processes with system callsEmbedded C, system calls and careers
- Reading and writing text filesStructs, unions, enums and files
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Why was gets() removed from C11?
Answer: It cannot limit how much it writes, so it always risks overflow
There is no way to use gets safely.
What does fgets keep that you usually remove?
Answer: The trailing newline
Remove it with strcspn.
What does atoi("abc") return?
Answer: 0, indistinguishable from the input "0"
That is why strtol is preferred.
fgets returns NULL when…
Answer: End of input is reached (or an error occurs) before reading anything
Check it before using the buffer.
What does scanf return?Related
Answer: The number of items successfully read (or EOF)
Check it against the expected count.
Why is overwriting the return address dangerous?Related
Answer: It can redirect execution to an attacker's choice
Classic stack smashing.
Which is the best way to handle a typo in user input?Related
Answer: match on the parse result and ask again
Matching on Ok and Err lets you recover gracefully.
Which function always respects the buffer size and terminates the result?Related
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “Strings in C” before its exam: Characters and <ctype.h>, Buffer overflows and safe string handling.
- Module 4 exam: Strings in C · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Pointers. 60 topics left in the course before the final exam.