YREA-SLS/docs/io_ref.md

9.9 KiB
Raw Blame History

Title Prev Next
C Terminal I/O Reference

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)
  15. Quick reference: common functions

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

#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)

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)

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:

  • %dint
  • %iint (auto-detects base)
  • %uunsigned int
  • %ldlong int
  • %lldlong long int
  • %zusize_t
  • %ffloat (promoted to double in printf/scanf variadic calls — use %f with double in printf; scanf expects pointer to float for %f)
  • %lfdouble for scanf (in printf %f and %lf are equivalent)
  • %Lflong double
  • %cchar (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

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

Common macros: PRId32, PRIu64, PRIxPTR, etc.


6. Character I/O

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

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)

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:

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

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

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:

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

11. Temporary files

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

#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

#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

#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:

#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