Skip to content
FollowtheDamnCode

Reference: stdio.h

printf, scanf, fgets, files, and friends.

6 minute read

Big idea

<stdio.h> is standard input/output: printing, reading, strings-as-files, and real files. Every entry below has its signature, what it does, the gotcha that bites beginners, and a one-line example.

Writing output

printf

int printf(const char *format, ...);

Prints formatted text to the screen (stdout). Returns the number of characters printed.

  • Gotcha: each % code must match its argument's type — see Format Specifiers. Never printf(text) with text you didn't write; use printf("%s", text).
  • Example: printf("%s scored %d\n", name, score);

puts

int puts(const char *s);

Prints a string and a newline.

  • Gotcha: it always adds \n — puts("hi\n") prints a blank line after.
  • Example: puts("Done.");

putchar

int putchar(int c);

Prints one character.

  • Example: putchar('*');

fprintf

int fprintf(FILE *stream, const char *format, ...);

printf to any stream: a file, stdout, or stderr (for error messages).

  • Example: fprintf(stderr, "bad input on line %d\n", line);

snprintf

int snprintf(char *buf, size_t size, const char *format, ...);

printf into a string, writing at most size bytes (including the '\0'). Returns the length the full text would have had.

  • Gotcha: prefer it to sprintf, which has no size limit and can overflow the buffer. If the return value is >= size, the text was cut short.
  • Example: char label[16]; snprintf(label, sizeof label, "P%d", id);

Reading input

scanf

int scanf(const char *format, ...);

Reads formatted input from the keyboard (stdin). Returns how many items it filled, or EOF when the input has ended.

  • Gotcha: pass addresses (&n, but not for arrays). Check the return value. %s needs a width (%19s for char[20]). %c doesn't skip whitespace; " %c" does. See Taking Input with scanf.
  • Example: while (scanf("%d", &x) == 1) sum += x;

getchar

int getchar(void);

Reads one character; returns EOF at the end of input.

  • Gotcha: store the result in an int, not a char, or you can't tell EOF from a real character.
  • Example: int c; while ((c = getchar()) != EOF) putchar(c);

fgets

char *fgets(char *buf, int size, FILE *stream);

Reads one line (up to size - 1 characters), keeping the \n. Returns NULL at end of input. The safe way to read a line. See Reading Strings.

  • Gotcha: strip the newline: buf[strcspn(buf, "\n")] = '\0';. Never use the removed gets — it can't be made safe.
  • Example: char line[100]; fgets(line, sizeof line, stdin);

sscanf

int sscanf(const char *str, const char *format, ...);

scanf, but reading from a string you already have.

  • Example: int h, m; sscanf("09:45", "%d:%d", &h, &m);

Files

fopen / fclose

FILE *fopen(const char *path, const char *mode);
int fclose(FILE *stream);

Opens a file — mode "r" read, "w" write (erases it first!), "a" append, add "b" for binary. Returns NULL on failure. fclose flushes and closes it. See Opening Files.

  • Gotcha: always check for NULL; always fclose what you open.
  • Example: FILE *f = fopen("scores.txt", "r"); if (f == NULL) { perror("scores.txt"); return 1; }

fscanf / fputs / fgetc / fputc

int fscanf(FILE *stream, const char *format, ...);
int fputs(const char *s, FILE *stream);
int fgetc(FILE *stream);
int fputc(int c, FILE *stream);

The file versions of scanf, puts (without the added newline), getchar, and putchar. See Reading and Writing Files.

  • Example: while (fscanf(f, "%d", &x) == 1) count++;

fread / fwrite

size_t fread(void *dst, size_t size, size_t count, FILE *stream);
size_t fwrite(const void *src, size_t size, size_t count, FILE *stream);

Read or write raw bytes — count items of size bytes each. Return how many whole items were transferred.

  • Example: fwrite(scores, sizeof scores[0], n, f);

feof / ferror

int feof(FILE *stream);
int ferror(FILE *stream);

After a read fails, say whether it was the end of the file or an error.

  • Gotcha: while (!feof(f)) loops once too many — feof is only true after a read has failed. Loop on the read's own return value instead.

perror

void perror(const char *prefix);

Prints prefix: <reason from errno> to stderr. See Error Handling.

  • Example: perror("fopen"); → fopen: No such file or directory

remove / rename

int remove(const char *path);
int rename(const char *old, const char *new);

Delete or rename a file. Return 0 on success.

Constants

  • EOF — a negative int meaning "no more input".
  • stdin, stdout, stderr — the three standard streams.
  • NULL, size_t — also defined here (and in several other headers).
A few stdio functions together
#include <stdio.h>
#include <string.h>

int main(void) {
    char line[64];
    int n = 0;
    while (fgets(line, sizeof line, stdin) != NULL) {
        line[strcspn(line, "\n")] = '\0';
        char label[80];
        snprintf(label, sizeof label, "%d: %s", ++n, line);
        puts(label);
    }
    printf("%d lines\n", n);
    return 0;
}
input
first line
second, with spaces
output
1: first line
2: second, with spaces
2 lines

Run and edit it in the app.

Why store getchar()'s result in an int rather than a char?

Check yourself

Which function reads a whole line safely?

What does fopen return when it can't open the file?