347 lines
9.9 KiB
Markdown
347 lines
9.9 KiB
Markdown
---
|
||
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)
|