Random Access & Positions
fseek/ftell turn a file into an array: fixed-width records, O(1) seeks, and the update-in-place trap.
A file is an array you can index
Fixed-width records make any record reachable directly:
/* record i of width W: */
fseek(f, (long)i * W, SEEK_SET); /* SEEK_SET: from the start */
fread(buf, W, 1, f);
ftell reports the current position; SEEK_CUR moves relative, and
SEEK_END from the tail (fseek(f, 0, SEEK_END); ftell(f) is the
classical file-size idiom โ though for real sizes, prefer the OS stat
API; this is the stdlib-only version).
"r+" is read AND write โ not append
Opening with "r+" allows both directions but does not create the
file and does not move the position for you: after writing, the
position is where you stopped. "a" (append) always writes at the end
but reads nowhere. Modes are contracts โ table them once:
| mode | reads | writes | creates | truncates | |---|---|---|---|---| | "r" | โ | โ | โ | โ | | "w" | โ* | โ | โ | โ | | "a" | โ | โ | โ | โ | | "r+" | โ | โ | โ | โ | | "w+" | โ* | โ | โ | โ |
* only after rewinding; "w" truncates on open, destroying existing data โ the mode that deletes files when chosen carelessly.
Update in place: the width must match
Overwriting record i via "r+" works only if the new record has
exactly the same width โ otherwise everything after it shifts and the
file is corrupt. Variable-width updates rewrite the tail or use an
indirection (slot table) โ the reason real databases are complicated.