---
Title: C Terminal I/O Reference
Prev:
Next:
---

*This was generated by ChatGPT as a reference to assist in development.*

# C99 Terminal I/O Reference

A concise, practical reference for terminal (stdin/stdout/stderr) and file I/O in **C99**. Includes common functions, behavior notes, examples, and safe-usage tips.

---

## Table of contents

1. [Overview](#1-overview)
2. [Streams and `FILE *`](#2-streams-and-file)
3. [Opening and closing streams](#3-opening-and-closing-streams)
4. [Formatted I/O (`printf`/`scanf` families)](#4-formatted-io-printfscanf-families)
5. [Format specifiers and `inttypes.h`](#6-character-io)
6. [Character I/O](#6-character-io)
7. [Line and block I/O (`fgets`, `fputs`, `fread`, `fwrite`)](#7-line-and-block-io)
8. [Buffering and `setvbuf` / `fflush`](#8-buffering-and-setvbuf-fflush)
9. [File positioning (`fseek`, `ftell`, `rewind`)](#9-file-positioning)
10. [Error handling (`feof`, `ferror`, `clearerr`, `perror`)](#10-error-handling)
11. [Temporary files](#11-temporary-files)
12. [Tips for safe and portable terminal I/O](#12-tips-for-safe-and-portable-terminal-io)
13. [Examples](#13-examples)
14. [POSIX terminal control (note)](#14-posix-terminal-control-note)
15. [Quick reference: common functions](#15-quick-reference-common-functions)

---

## 1. Overview

Standard C99 defines the `<stdio.h>` interface for input/output. It’s oriented around *streams* (`FILE *`) and provides both formatted and unformatted operations. C99 also introduced `<inttypes.h>` (and `<stdint.h>`) for precise integer types and format macros.

The standard I/O streams preopened by the implementation are:

* `stdin`  — standard input (usually the keyboard/pipe)
* `stdout` — standard output (usually the terminal/pipe)
* `stderr` — standard error (usually the terminal, unbuffered)

`stdout` is usually line-buffered when connected to a terminal and fully buffered when redirected to a file.

---

## 2. Streams and `FILE *`

`FILE` is an opaque type representing an I/O stream. Use pointers to `FILE` returned by `fopen`, or the standard `stdin`/`stdout`/`stderr`.

Common operations: read/write, reposition, flush, close, and check errors.

---

## 3. Opening and closing streams

```c
#include <stdio.h>

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

`mode` examples:

* `"r"`  — read (file must exist)
* `"w"`  — write (truncate/create)
* `"a"`  — append (create if needed)
* `"r+"` — read/update
* `"w+"` — read/update (truncate/create)
* Add `b` for binary: `"rb"`, `"wb"` (on POSIX `b` is ignored but required for portability to Windows)

Always check for `NULL` from `fopen` and nonzero return from `fclose`.

---

## 4. Formatted I/O (`printf`/`scanf` families)

**Output (formatted)**

```c
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
int vprintf(const char *format, va_list ap);
```

Return value: number of characters written (excluding terminating `\0` for `snprintf`) or a negative value on error.

**Input (formatted)**

```c
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);
```

`scanf`-style functions parse input according to `format`. They are error-prone for untrusted input — prefer `fgets` + `sscanf` or manual parsing.

**Important:** Always limit field widths for `%s` and others when using `scanf` to avoid buffer overflow: `%99s` for a 100-byte buffer.

---

## 5. Format specifiers and `inttypes.h`

Common specifiers:

* `%d` — `int`
* `%i` — `int` (auto-detects base)
* `%u` — `unsigned int`
* `%ld` — `long int`
* `%lld` — `long long int`
* `%zu` — `size_t`
* `%f` — `float` (promoted to `double` in `printf`/`scanf` variadic calls — use `%f` with `double` in `printf`; `scanf` expects pointer to `float` for `%f`)
* `%lf` — `double` for `scanf` (in `printf` `%f` and `%lf` are equivalent)
* `%Lf` — `long double`
* `%c` — `char` (or `int` in `printf`), for `scanf` expects `char *`
* `%s` — NUL-terminated string
* `%p` — pointer
* `%n` — write number of characters printed so far into `int *`

For fixed-width integer types introduced in C99, use `inttypes.h` macros

```c
#include <inttypes.h>
int32_t i32;
printf("%" PRId32 "\n", i32);
```

Common macros: `PRId32`, `PRIu64`, `PRIxPTR`, etc.

---

## 6. Character I/O

```c
int getchar(void);
int putchar(int ch);
int ungetc(int ch, FILE *stream);
int fgetc(FILE *stream);
int fputc(int ch, FILE *stream);
```

* `getchar()` is equivalent to `fgetc(stdin)`.
* Return values for `fgetc`/`getchar`: next character as an unsigned char cast to `int`, or `EOF` on end-of-file or error.
* `ungetc` pushes a character back onto the stream (one character is guaranteed).

---

## 7. Line and block I/O

**Line-based**

```c
char *fgets(char *s, int size, FILE *stream);
int fputs(const char *s, FILE *stream);
```

* `fgets` reads up to `size-1` characters or until newline; the resulting string includes the newline if present and is NUL-terminated. Returns `NULL` on EOF or error.
* Use `fgets` to safely read lines from `stdin` (avoid `gets`).

**Block-based (binary)**

```c
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
```

* Returns number of elements read/written; check against `nmemb` to detect short reads/writes.

---

## 8. Buffering and `setvbuf` / `fflush`

Buffering modes:

* Fully buffered — data collected until buffer fills (default for files).
* Line buffered — buffer flushed on newline (default for interactive `stdout`).
* Unbuffered — no buffering (default for `stderr`).

Control buffering:

```c
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
int setbuf(FILE *stream, char *buf); // simpler wrapper
int fflush(FILE *stream); // flush output buffer
```

`mode` constants: `_IOFBF` (full), `_IOLBF` (line), `_IONBF` (none).

Call `fflush(stdout)` to ensure output is written (useful before `scanf` or when using `fork`).

---

## 9. File positioning

```c
int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
void rewind(FILE *stream);
```

* `whence`: `SEEK_SET`, `SEEK_CUR`, `SEEK_END`.
* For binary files larger than `LONG_MAX`, POSIX defines `fseeko`/`ftello` with `off_t` (not in C99 standard).

---

## 10. Error handling

```c
int feof(FILE *stream);
int ferror(FILE *stream);
void clearerr(FILE *stream);
```

* `ferror` indicates if an error occurred on the stream.
* `perror(const char *s)` prints a human-readable error message based on `errno`.

Example pattern:

```c
if (ferror(fp)) {
    perror("file read");
}
```

---

## 11. Temporary files

```c
FILE *tmpfile(void); // create and open a temporary binary file (removed on close)
char *tmpnam(char *s); // generate a filename
```

`tmpnam` is unsafe for race conditions; prefer `tmpfile` or platform-specific secure alternatives.

---

## 12. Tips for safe and portable terminal I/O

* Prefer `fgets` + `sscanf` (or manual parsing) over `scanf` to avoid buffer overflows and ambiguous input parsing.
* When printing into buffers, use `snprintf` to avoid overflows and to detect truncation (it returns the number of characters that would have been written).
* Validate `fread`/`fwrite` return values.
* Check `fopen` for `NULL` and call `perror`/inspect `errno` on failure.
* Use `fflush(stdout)` if mixing output with `fork()` or before expecting input on interactive programs.
* Use `setvbuf` if your program has special performance needs.
* For cross-platform portability, include `b` in mode strings for binary files (Windows requires it).
* Use `inttypes.h` macros for printing fixed-width integers.

---

## 13. Examples

### Read lines from stdin safely

```c
#include <stdio.h>
#include <string.h>

int main(void) {
    char buf[256];
    while (fgets(buf, sizeof buf, stdin)) {
        // strip newline
        size_t len = strlen(buf);
        if (len && buf[len - 1] == '\n') buf[len - 1] = '\0';
        printf("line: '%s'\n", buf);
    }
    return 0;
}
```

### Read integers robustly using `fgets` + `sscanf`

```c
#include <stdio.h>

int main(void) {
    char line[128];
    long value;
    while (fgets(line, sizeof line, stdin)) {
        if (sscanf(line, "%ld", &value) == 1) {
            printf("got: %ld\n", value);
        } else {
            fprintf(stderr, "invalid input: %s", line);
        }
    }
}
```

### Write/read binary struct to file

```c
#include <stdio.h>
#include <stdlib.h>

struct pair { int a; double b; };

int main(void) {
    struct pair p = {42, 3.14159};
    FILE *f = fopen("data.bin", "wb");
    if (!f) { perror("fopen"); return 1; }
    if (fwrite(&p, sizeof p, 1, f) != 1) { perror("fwrite"); }
    fclose(f);

    f = fopen("data.bin", "rb");
    struct pair q;
    if (!f) { perror("fopen"); return 1; }
    if (fread(&q, sizeof q, 1, f) != 1) { perror("fread"); }
    fclose(f);
    printf("read: %d %f\n", q.a, q.b);
}
```

---

## 14. POSIX terminal control (note)

C99 does **not** standardize low-level terminal control (raw mode, disabling echo, key-by-key input). On POSIX systems you can use `<termios.h>` and `tcgetattr`/`tcsetattr`. On Windows you use console APIs (`GetConsoleMode` / `SetConsoleMode`). These are outside the C standard and require conditional compilation and platform-specific code.

Example POSIX-only header include:

```c
#ifdef __unix__
#include <termios.h>
#endif
```

---

## 15. Quick reference: common functions

* `fopen`, `fclose` — open/close file
* `fread`, `fwrite` — block I/O
* `fgets`, `fputs` — line I/O
* `printf`, `fprintf`, `snprintf` — formatted output
* `scanf`, `fscanf`, `sscanf` — formatted input
* `fgetc`, `fputc`, `getchar`, `putchar` — character I/O
* `fflush`, `setvbuf` — flushing and buffering
* `fseek`, `ftell`, `rewind` — positioning
* `feof`, `ferror`, `clearerr`, `perror` — error handling
* `tmpfile`, `tmpnam` — temporary files

[Back to Top](#c99-terminal-io-reference)
