Added io ref

This commit is contained in:
Kyler Olsen 2025-11-27 20:01:27 -07:00
parent 5dd0daed8a
commit 04274e14e3
2 changed files with 352 additions and 0 deletions

View File

@ -37,5 +37,6 @@ Next: Overview
- [SE 3250 Assignment Details](./se_3250_assignment_details.html)
- [Changed](./changes.html)
- [Full Specification](./stack_lang_spec.html)
- [C Terminal I/O Reference](./io_ref.html)
---

351
docs/io_ref.md Normal file
View File

@ -0,0 +1,351 @@
---
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
2. Streams and `FILE *`
3. Opening and closing streams
4. Formatted I/O (`printf`/`scanf` families)
5. Format specifiers and `inttypes.h`
6. Character I/O
7. Line and block I/O (`fgets`, `fputs`, `fread`, `fwrite`)
8. Buffering and `setvbuf` / `fflush`
9. File positioning (`fseek`, `ftell`, `rewind`)
10. Error handling (`feof`, `ferror`, `clearerr`, `perror`)
11. Temporary files
12. Tips for safe and portable terminal I/O
13. Examples
14. POSIX terminal control (note)
---
## 1. Overview
Standard C99 defines the `<stdio.h>` interface for input/output. Its 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
```
---
## 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
---
If you want, I can:
* Add a printable PDF / cheat-sheet version.
* Expand the POSIX terminal control section with a `termios` example.
* Create a one-page cheat-sheet for printing and scanning format specifiers.