text versus binary mode
Two ways to treat a file: as plain prose to be read by a person, or as a stream of raw bytes that mean whatever your program decides. The difference looks invisible until line endings get involved - and then it can quietly corrupt your data. Text mode lets the library tidy up line endings for you; binary mode says 'hands off, give me the bytes exactly as they are.'
Concretely, the issue is how a line ending is represented. Unix-like systems end a line with a single byte, newline (LF, 0x0A). Windows ends a line with two bytes, carriage-return then newline (CR LF, 0x0D 0x0A). When you open a stdio stream in text mode, the C library on Windows translates between these: on read it strips the CR so your program sees just LF, and on write it adds a CR before each LF. That is convenient for text but disastrous for non-text data, where a byte that just happens to equal 0x0D or 0x0A is real data, not a line ending - silently inserting or removing CR bytes corrupts the file. Binary mode (the "b" in fopen modes like "rb" and "wb") turns this translation off: every byte goes in and comes out exactly as stored. On Unix-like systems text and binary mode are identical (there is no translation to do), which is why Unix programmers often forget the distinction exists - until their code runs on Windows.
Why it matters: this is a classic cross-platform trap. A program that reads an image or a compiled file in text mode on Windows will mangle it, dropping or adding bytes around every 0x0A. The rule is simple: open anything that is not line-based human text in binary mode. And even within text, the LF-versus-CRLF mismatch is why a file edited on one system can look like it has weird ^M characters or be all on 'one line' on another - the line-ending convention, not the content, differs.
FILE *img = fopen("photo.png", "rb"); /* binary: bytes come out exactly as stored */ FILE *txt = fopen("notes.txt", "r"); /* text: on Windows, CRLF <-> LF translation */
Use "rb"/"wb" for any non-text file; in text mode Windows rewrites line endings under you.
On Unix-like systems text and binary mode are identical, so the bug only appears when your code reaches Windows. A line ending is LF (0x0A) on Unix and CRLF (0x0D 0x0A) on Windows; never open binary data in text mode.