Console and file I/O (stdio.h)¶
Include stdio.h. The predefined streams stdin, stdout, and
stderr are available.
Types, Macros, and Streams¶
| Name | Meaning |
|---|---|
NULL |
Null pointer constant, defined as 0 if not already defined. |
EOF |
End-of-file / error return value, -1. |
SEEK_SET |
fseek origin: beginning of file. |
SEEK_CUR |
fseek origin: current file position. |
SEEK_END |
fseek origin: end of file. |
BUFSIZ |
Default buffer size, 256. |
L_tmpnam |
Minimum buffer size for tmpnam(), 13. |
TMP_MAX |
Distinct filenames available from tmpnam() per session, 1000. |
_IOFBF |
Fully buffered setvbuf mode. |
_IOLBF |
Line buffered setvbuf mode. |
_IONBF |
Unbuffered setvbuf mode. |
FOPEN_MAX |
Maximum C89 stream count exposed by the header, 8. |
FILE |
Stream handle type. |
fpos_t |
File position type for fgetpos/fsetpos; holds a 32-bit byte offset. |
stdin |
Predefined console input stream. |
stdout |
Predefined console output stream. |
stderr |
Predefined console diagnostic stream. |
Functions¶
| Function | Summary |
|---|---|
void clearerr(FILE *stream) |
Clear a stream's EOF and error flags. |
int fclose(FILE *stream) |
Close a stream. |
int feof(FILE *stream) |
Test whether a stream has reached end-of-file. |
int ferror(FILE *stream) |
Test whether a stream has an error flag set. |
int fflush(FILE *stream) |
Flush buffered console output. |
int fgetc(FILE *stream) |
Same as getc. |
int fgetpos(FILE *stream, fpos_t *pos) |
Store the current position of stream into *pos; returns 0 on success. |
char *fgets(char *s, int n, FILE *stream) |
Read a line from a stream. |
FILE *fopen(const char *filename, const char *mode) |
Open a file stream. |
int fprintf(FILE *stream, const char *format, ...) |
Formatted output to a stream. |
int fputc(int c, FILE *stream) |
Same as putc. |
int fputs(const char *s, FILE *stream) |
Write a string to a stream without adding a newline. |
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) |
Read elements from a stream. |
FILE *freopen(const char *path, const char *mode, FILE *stream) |
Close stream and reopen path/mode on the same FILE slot. |
int fscanf(FILE *stream, const char *format, ...) |
Parse formatted input from a stream. |
int fseek(FILE *stream, long offset, int whence) |
Reposition a stream. |
int fsetpos(FILE *stream, const fpos_t *pos) |
Set stream position from *pos (previously returned by fgetpos); returns 0 on success. |
long ftell(FILE *stream) |
Report the current stream position. |
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) |
Write elements to a stream. |
int getc(FILE *stream) |
Read one character from a stream. |
int getch(void) |
Read one console key without echo. |
int getchar(void) |
Read one character from the console, blocking until available. |
char *gets(char *s) |
Unsafe console line input with no bounds checking; prefer fgets. |
int kbhit(void) |
Poll for a waiting console key without consuming it. |
void perror(const char *s) |
Print a prefix plus the current error text. |
int printf(const char *format, ...) |
Formatted output to the console stdout. |
int putc(int c, FILE *stream) |
Write one character to a stream. |
int putchar(int c) |
Write one character to the console. |
int puts(const char *s) |
Write a string plus a newline to the console. |
int remove(const char *filename) |
Delete a file. |
int rename(const char *oldname, const char *newname) |
Rename a file. |
void rewind(FILE *stream) |
Reposition a stream to the beginning. |
int scanf(const char *format, ...) |
Parse formatted input from the console stdin. |
void setbuf(FILE *stream, char *buf) |
Configure console buffering with a default size. |
int setvbuf(FILE *stream, char *buf, int mode, size_t size) |
Configure console buffering mode and buffer storage. |
int snprintf(char *s, size_t n, const char *format, ...) |
Formatted output into a caller-supplied string buffer, bounded to at most n-1 characters plus a terminating NUL (C99); n=0 writes nothing at all, not even a NUL. Always returns the number of characters that would have been written had n been unbounded, matching sprintf's return value. |
int sprintf(char *s, const char *format, ...) |
Formatted output into a caller-supplied string buffer. |
int sscanf(const char *s, const char *format, ...) |
Parse formatted input from a string. |
FILE *tmpfile(void) |
Create a temporary file opened for update; removed at program exit. |
char *tmpnam(char *s) |
Generate a filename not used by any current tmpfile() handle; if it is non-NULL write it there, else use an internal static buffer. |
int ungetc(int c, FILE *stream) |
Push c back onto stream; the next read returns c. Only one character of pushback per stream is guaranteed. Returns c on success, EOF on failure. |
int vfprintf(FILE *stream, const char *format, va_list ap) |
Formatted stream output from a va_list. |
int vprintf(const char *format, va_list ap) |
Formatted console output from a va_list. |
int vsnprintf(char *s, size_t n, const char *format, va_list ap) |
Formatted, bounded string output from a va_list (C99); see snprintf. |
int vsprintf(char *s, const char *format, va_list ap) |
Formatted string output from a va_list. |
Runtime model¶
stdin, stdout, and stderr are console pseudo-streams. They are available
for portable-looking code, but they do not consume real file slots. Real file
streams are opened by fopen. FOPEN_MAX is 8 because C89 counts the three
standard streams too; on this CP/M runtime that means the three console
pseudo-streams plus five concurrent real file streams.
Console output is cheap
putchar, puts, and integer printf write through the console routine
that is already part of every program. The stream-oriented functions
(fputc/fputs/fprintf) have special stdout/stderr console paths at
runtime, but their blocks also include real-file fallbacks; using them can
therefore link more file I/O support than console-only calls need. Prefer
the console functions for console-only work.
See the appendix for the size figures.
File streams¶
fopen looks at the first mode character: "r" opens an existing file, "w"
creates/truncates a file, and "a" creates the file if needed. The optional
"+" and "b" characters are accepted but do not change the runtime behavior;
"a" does not automatically seek to end, so call fseek(fp, 0L, SEEK_END) if
you need append positioning. CP/M has no atomic append operation, so programs
that share or alternate writes to the same file must coordinate at a higher
level.
For a complete program, see the worked file-reading example.
Formatted I/O¶
printf-family output¶
The printf family shares one base formatting engine for characters, strings,
16-bit integers, and literal percent signs. The inline-argument forms are used
the usual way:
printf("count=%d name=%s hex=%04x\n", n, name, addr);
sprintf(line, "%ld bytes", total);
fprintf(stderr, "error %d\n", errno);
The v… variants take a va_list (from
stdarg.h) for wrappers that forward a format string; see the worked
logging-wrapper example.
Automatic runtime selection
For a compile-time literal format, dcc detects float, long, hexadecimal, and
octal conversions at each call and selects the smallest matching runtime
entry. A non-literal format conservatively includes all optional paths.
-f / -ffloatio and -fl / -flongio force float or long support on
every printf-family call; they are not required for literal formats. The
-fno-*io forms force paths off and are unsafe when a matching conversion
can reach a call. These options do not add floating-point input.
printf conversions¶
| Specifier | Meaning |
|---|---|
%d, %i |
Signed 16-bit decimal. |
%u |
Unsigned 16-bit decimal. |
%o |
Unsigned 16-bit octal. |
%x, %X |
Unsigned 16-bit hex (lower / upper case). |
%c |
Single character. |
%s |
NUL-terminated string. |
%f |
32-bit float in fixed decimal notation. |
%% |
A literal percent sign. |
Length modifiers:
l— 32-bitlongconversions:%ld,%lu,%lx,%lX.%lsprints a 16-bit wide string by emitting each character's low byte.z—size_twidth. Sincesize_tis 16-bit here,%zu/%zdand friends behave like the plain 16-bit conversions.
Field width and flags:
- A decimal field width (
%6d,%10s,%8lx) pads with spaces on the left for characters, strings, and integer conversions.%fdoes not apply field width. - The
-flag (%-6d) left-justifies%c,%s, and integer conversions within the field.%lsuses right justification only. - A leading
0flag on integer conversions (%04d,%08lx) zero-pads when there is no-flag and no explicit precision. - A precision on integer conversions (
%.4d) zero-fills to at least that many digits. - A positive precision on
printf%f(%.2f) controls the number of digits after the decimal point. Without a positive precision,%fprints six fractional digits.%falways emits a decimal point. - String precision (
%.3s) is not implemented;%sprints the whole string.
printf("|%6d|%-6d|%.4d|\n", 42, 42, 42); /* | 42|42 |0042| */
printf("%lu items, %lx flags\n", count, mask);
printf("%.2f\n", ratio);
Not supported: the +, space, and # flags, and * (run-time) width or
precision. Output conversions such as %e, %g, %p, and %n are not
implemented. %f is supported across printf, sprintf, fprintf, their
v... variants, snprintf, and vsnprintf. Use fixed widths and precisions in
the format string.
scanf-family input¶
scanf, sscanf, and fscanf share a separate, non-floating C89 subset. A
whitespace character in the format skips any amount of input whitespace, and a
non-% character must match literally.
| Specifier | Meaning |
|---|---|
%d |
Signed decimal integer. |
%i |
Signed integer with base auto-detected (0, 0x). |
%u |
Unsigned decimal integer. |
%x, %X |
Unsigned hexadecimal, optional 0x prefix. |
%o |
Unsigned octal. |
%c |
Character input; does not skip leading whitespace. |
%s |
Non-whitespace string, NUL-terminated by the runtime. |
%% |
A literal percent sign. |
Supported modifiers:
- A decimal field width limits the maximum input consumed by a conversion.
*suppresses assignment (input is consumed but no argument is read).his accepted for integer conversions; sinceshortis the same size asint, it behaves like the plain conversion.lstores integer conversions through along */unsigned long *.- Integer conversions skip leading whitespace and accept an optional
+or-.%iauto-detects decimal, octal (0), or hexadecimal (0x/0X). %sskips leading whitespace and writes a terminating NUL.%cdoes not skip whitespace; without a width it reads exactly one character, and with a width it does not add a terminating NUL.
int value;
char word[16];
long big;
sscanf("-12 hello 0x2a", "%d %s %i", &value, word, &value);
sscanf("123456", "%ld", &big);
For a complete, tested program, see the worked
sscanf parsing example.
Not supported: floating input (%f, %e, %g), scansets (%[...]), %n, and
%p. No DCC C Compiler option enables floating-point scanf input.
Character and string I/O¶
putchar and puts write to the console. putc and fputc are separate C
names that map to stream-character output, and getc and fgetc likewise
share the stream-character input path. fgets reads up to n-1 characters and
terminates the buffer with NUL; fputs writes a string without adding a newline.
getchar is the console input form. In the runtime it calls CP/M BDOS function
1 (console input), so it waits for a character and returns that character as a
non-negative int. For real file streams, getc and fgetc read through the
low-level _read routine. See
CP/M extensions for more on
the non-blocking convention.
gets is provided for C89 compatibility only. It cannot limit the number of
characters written to the destination buffer; use fgets for new code.
For non-blocking console input, use kbhit() to test whether a key is waiting,
then getch() to read it. kbhit() never blocks; getch() only blocks if you
call it when no key is ready, so the two are normally paired:
#include <stdio.h>
int main(void)
{
int ch;
puts("Press Q to quit.");
for (;;) {
if (kbhit()) { /* non-blocking: a key is waiting */
ch = getch(); /* safe: will not block here */
if (ch == 'q' || ch == 'Q')
break;
putchar(ch);
}
/* do other periodic work here */
}
return 0;
}
Because getch() builds on BDOS function 6 (which uses 0 as its "no
character" sentinel), this convention is best for keyboard polling and command
loops, not for input protocols where a NUL byte is meaningful. getch() and
getchar() flush any pending buffered console output before they block, so a
prompt printed just before them is always visible first.
Block I/O¶
fread and fwrite transfer nmemb elements of size bytes and return the
number of complete elements transferred. A zero element size returns zero.
File-stream writes are write-through. Console writes through stdout or
stderr use the console output buffer described below.
Positioning and status¶
fseek repositions a real file stream using SEEK_SET, SEEK_CUR, or
SEEK_END. ftell reports the current stream position, and rewind seeks to
the beginning and clears the EOF flag. feof, ferror, and clearerr inspect
or reset the per-file status flags.
fflush(NULL), fflush(stdout), and fflush(stderr) all flush the console.
Calling fflush on a real file stream is accepted; file writes are already
write-through.
Console output buffering¶
Console output (printf, puts, putchar, fputs/fwrite/fprintf to
stdout/stderr) is buffered. Characters accumulate in a buffer and are
sent to CP/M in batches, which is far faster than one BDOS call per character.
The buffer is drained automatically:
- when it fills,
- when a newline is written (in the default line-buffered mode),
- on
fflush(), - before any blocking console input (
getchar,getch,scanf,fgets), so a prompt printed just before input is always visible first, - and at normal program exit (
mainreturn,exit()).
setvbuf returns 0 on success, non-zero only for an invalid mode. setbuf
is shorthand for setvbuf(fp, buf, buf ? _IOFBF : _IONBF, BUFSIZ).
setvbuf must be called before any output on the stream. The mode is one
of:
| Mode | Meaning |
|---|---|
_IOFBF |
Fully buffered — drain only when the buffer fills, on fflush, before input, or at exit. |
_IOLBF |
Line buffered — additionally drain at each newline. This is the default. |
_IONBF |
Unbuffered — drain after every character. |
If you pass a non-NULL buf (with size >= 2), the runtime adopts your
buffer: console output is accumulated there and a larger buffer means fewer
BDOS calls. One byte of size is reserved internally, so the usable capacity is
size - 1. A NULL buf (or size < 2) uses the runtime's small internal
buffer instead.
Buffer lifetime
An adopted buffer must remain valid for as long as the stream uses it. Before
freeing it, detach it first — e.g. setvbuf(stdout, NULL, _IOLBF, 0) — so
the automatic exit-time flush does not touch freed memory.
setvbuf/setbuf only configure the console (stdout/stderr). Called on
a file stream they are accepted but have no effect. stdout and stderr share
the one console buffer, so their output is interleaved in the exact order
written.
#include <stdio.h>
#include <stdlib.h>
char *buf = malloc(4096);
setvbuf(stdout, buf, _IOFBF, 4096); /* batch up to ~4 KB before each flush */
for (i = 0; i < 1000; i++)
printf("line %d\n", i); /* accumulates; few BDOS calls */
setvbuf(stdout, NULL, _IOLBF, 0); /* detach before freeing */
free(buf);