scanf(3)

๐Ÿ’– scanf(3) โ€” bestie edition ๐Ÿ’–

okay so you're looking at the scanf(3) page from the Library Functions Manual, and tbh this is the iconic messy queen of stdio. she scans formatted input. she's also, and I cannot stress this enough, kind of a nightmare. let's get into it ๐Ÿซถ


โœจ NAME โœจ

scanf, fscanf, vscanf, vfscanf โ€” input FILE format conversion ๐Ÿ’…

๐Ÿ“š LIBRARY ๐Ÿ“š

Standard C library (libc, -lc) โ€” she's built in, no extra drama required โœจ

๐ŸŒธ SYNOPSIS ๐ŸŒธ

#include <stdio.h>

int scanf(const char *restrict format, ...);
int fscanf(FILE *restrict stream,
           const char *restrict format, ...);

#include <stdarg.h>

int vscanf(const char *restrict format, va_list ap);
int vfscanf(FILE *restrict stream,
           const char *restrict format, va_list ap);

๐Ÿงš Feature Test Macro Requirements for glibc (see feature_test_macros(7))

for vscanf(), vfscanf():

_ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L

๐Ÿ’œ DESCRIPTION ๐Ÿ’œ

so the scanf() family scans formatted input, kinda like sscanf(3) does, except it reads from a FILE. and bestie. ngl. these functions are very difficult to use correctly ๐Ÿ˜ญ the manpage itself says it's preferable to read whole lines with fgets(3) or getline(3) and then parse them later with sscanf(3), or with something more specialized like strtol(3). like, that's the author telling you to take a different route. periodt.

scanf() reads its input from the standard input stream, aka stdin, and fscanf() reads input from the stream pointer, aka stream. two sisters, one vibe ๐ŸŒˆ

vfscanf() is the analog of vfprintf(3) โ€” it reads input from the stream pointer stream using a variable argument list of pointers (peep stdarg(3)). and vscanf() is the analog of vprintf(3), and it reads from the standard input. so it's giving "same energy, but the args come in via va_list" ๐Ÿ’…


๐ŸŽ€ RETURN VALUE ๐ŸŽ€

on success, these functions return the number of input items successfully matched and assigned. lowkey that can be fewer than you provided for, or even zero, if there's an early matching failure. zero items. nothing. we got nothing. ๐Ÿ™ˆ

the value EOF comes back if the end of input is reached before either the first successful conversion or a matching failure happens. EOF is also returned if a read error occurs โ€” in that case the error indicator for the stream gets set (see ferror(3)), and errno is set to indicate the error. so basically EOF is doing double duty and you have to check errno to know which one it is ๐Ÿ’€


๐Ÿ”ฅ ERRORS ๐Ÿ”ฅ

  • EAGAIN โ€” the file descriptor underlying stream is marked nonblocking, and the read operation would block. she's not waiting around, bestie.
  • EBADF โ€” the file descriptor underlying stream is invalid, or it's not open for reading. wrong door, no entry ๐Ÿšซ
  • EILSEQ โ€” the input byte sequence does not form a valid character.
  • EINTR โ€” the read operation was interrupted by a signal; see signal(7).
  • EINVAL โ€” not enough arguments; or format is NULL. (she counted your args and she's disappointed.)
  • ENOMEM โ€” out of memory.

๐Ÿ‘‘ ATTRIBUTES ๐Ÿ‘‘

for an explanation of the terms used in this section, see attributes(7).

  • Interface: scanf(), fscanf(), vscanf(), vfscanf() โ€” Attribute: Thread safety โ€” Value: MT-Safe locale

โญ STANDARDS โญ

C11, POSIX.1-2008. certified โœจ

๐Ÿฆ‹ HISTORY ๐Ÿฆ‹

C99, POSIX.1-2001. she's been around, she's seen things.


๐Ÿ’€ CAVEATS ๐Ÿ’€

these functions make it genuinely difficult to tell newlines apart from other white space. and that's especially problematic with line-buffered input, like the standard input stream. no cap, this will bite you.

also, these functions can't report errors after the last non-suppressed conversion specification. so errors happening at the very end? completely invisible. ๐Ÿซฅ


๐ŸŒธ BUGS ๐ŸŒธ

it is impossible to accurately know how many characters these functions have consumed from the input stream, because they only report the number of successful conversions. like. literally impossible. let that sink in ๐Ÿ˜ญ

for example, if the input is "123\n a", then

scanf("%d %d", &a, &b)

will consume the digits, the newline, and the space โ€” but not the letter a.

and that is exactly why it's so difficult to recover from invalid input. the stream is somewhere, you don't know where, and she's not telling you. ๐Ÿ™ˆ


๐ŸŒˆ SEE ALSO ๐ŸŒˆ

fgets(3), getline(3), sscanf(3)


okay that's the whole page, bestie ๐Ÿ’– this was Linux man-pages 6.20, dated 2025-09-21, and remember: read the whole line first, parse it after, and keep your errno close ๐ŸŽ€โœจ๐Ÿซถ

scanf(3)

๐Ÿ“ฆ where this page comes from
  • arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • ๐Ÿ“œ the page's license: Linux-man-pages-copyleft
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms