File Input and Output in C

Learn how C programs read and write files with the standard I/O library. Open files as streams in the right mode and connect programs to standard input, output and error. Process text one character at a time, with formatted reads and writes, and line by line with fgets. Store arrays and records in binary files with fread and fwrite, design file formats that read correctly on other machines, and jump to any record with fseek. Throughout, you check every result, explain failures with errno and clean up so that your programs fail safely and report their outcome honestly.

IntermediateLesson 7 of 8 in Programming in C Course

What you will learn

  1. Explain how C programs reach files through buffered streams, open and close files in the right mode, and use the three standard streams with command-line redirection.
    • Explain streams, buffering and text versus binary mode
      Describe what a stream and a FILE * are, how buffering and the file position work, and how text mode differs from binary mode on Windows and Unix-like systems.
    • Open and close files with fopen and fclose
      Open a file in the mode that matches the task, check that it opened, find files by path, and close every stream when the work is done.
    • Use stdin, stdout and stderr with redirection and pipes
      Use the three streams every C program starts with, send results and error messages to the right place, and let users redirect them from the command line.
  2. Process text files one character at a time, with formatted reads and writes, and line by line, choosing the safe pattern for each and testing every result.
    • Read and write one character at a time
      Use fgetc and fputc with an int variable, stop correctly at end of file, and count, copy and transform text character by character.
    • Write and read formatted text with fprintf and fscanf
      Write numbers and strings to files in a chosen layout, build file names with sprintf, and read formatted data with fscanf while checking how many items it converted.
    • Read lines safely with fgets
      Read text one line at a time with fgets, handle newlines, long lines and Windows line endings, and parse each line after reading it.
  3. Write and read raw bytes, arrays and structs with fwrite and fread, and design binary file formats that read correctly on other machines.
    • Read and write binary data with fread and fwrite
      Use fread and fwrite with the right element size and count, copy files in blocks, recognize file types by their first bytes, and store arrays and structs.
    • Design binary formats that work across machines
      Explain how type sizes, byte order and struct padding make raw binary files machine-dependent, and read and write multi-byte fields in a defined format.
  4. Find and set the file position to jump straight to the data you need, and update fixed-size records in place without rewriting the whole file.
    • Find and set the file position with ftell, fseek and rewind
      Report the current position, move to positions relative to the start, the current place or the end, compute record offsets and file sizes, and know the limits for text streams.
    • Update fixed-size records in place
      Open a file for both reading and writing, follow the rule for switching between them, and change, add or remove records without corrupting the file.
  5. Check the result of every file operation, explain failures to the user with errno, and release every resource so that programs fail safely and report success honestly.
    • Check every result and tell end of file from errors
      Know how each stdio function signals failure, use feof and ferror after a read loop ends, and catch write errors that only appear when the buffer is written.
    • Explain failures with errno, perror and strerror
      Use errno to find out why a library call failed, and print clear error messages that name the program, the file and the reason.
    • Clean up resources and report the outcome
      Close every stream on every path, leave no half-written output behind, and return an exit status that tells the truth about the result.

File Input and Output in C study guide

5 chapters

1

Open files as streams and connect programs to their input and output

Files reach a program through streams, which control access, buffering, and position. Choosing a mode can preserve old data, erase it, or force each write to the end, so opening belongs to the design of the program. The three standard streams extend the same interface to terminals, redirected files, and pipes. Understanding their connections lets you write one processing routine that works in several settings and keeps diagnostics separate from useful results.

1.1 Explain streams, buffering and text versus binary mode

A file is stored data; a stream is the channel a running program uses to reach it. The same stream functions can also work with a terminal or pipe. Include <stdio.h> and keep the stream pointer in a variable of type FILE *.

What the stream remembers

The library's FILE object tracks a buffer, the current file position, and end-of-file and error indicators. Pass its pointer to functions such as fgetc and fprintf; do not inspect or change its fields. A read or write advances the position past the data processed. In a binary file beginning with "hello\nworld\n", reading the first six bytes leaves the next read at the w.

Buffering groups small operations into larger transfers. A successful write can mean that data reached a memory buffer, with the operating-system transfer still pending. fflush(fp) sends pending output to the operating system. fclose(fp) does that before releasing the stream. Neither is a promise that data will survive a sudden power loss.

Buffering modeWhen output is transferred
Fully bufferedWhen the buffer fills, or when explicitly flushed or closed
Line bufferedAlso when a newline is written
UnbufferedAs soon as possible

Ordinary files opened with fopen are fully buffered. Interactive devices can use different buffering. A terminal or pipe does not provide ordinary file positions for jumping backward and forward.

Choose text or binary mode

Text mode handles human-readable lines. Binary mode preserves byte values without text translations. Add b to the opening mode for binary data: "rb" reads it and "wb" writes it. Images, compressed data, and raw records need binary mode even if a text-mode version appears to work on your own computer.

On Linux and macOS, a newline is one LF byte, 0x0A, and the two modes normally behave alike. On Windows, text output translates '\n' into the two bytes CR LF, 0x0D 0x0A. Text input translates CR LF back into one '\n'. Microsoft's text input also recognizes 0x1A, Ctrl+Z, as end of file.

For example, writing "a\nb\nc\n" in text mode produces six bytes on Linux or macOS and nine on Windows. Three letters contribute three bytes; three Windows line endings contribute six. Reading the Windows file in text mode on Windows gives six characters, while binary mode exposes all nine bytes.

Keep the file's bytes separate from its text

A Windows-created line read on Linux may retain "\r\n". Removing only '\n' leaves '\r', which can make a comparison with "yes" fail. A text-stream position can also reflect translation state, so save and restore text positions instead of calculating byte offsets.

C's exact text round-trip guarantee applies to printable characters, tabs, and newlines, with no space immediately before a newline and a newline ending the last line. Other byte sequences belong in binary streams. C bytes have at least eight bits; examples involving 0–255 byte values and common file formats use eight-bit bytes.

Key Takeaways

  • A FILE * gives library functions access to a stream and its state.
  • Buffered output can fail when it is flushed or closed; check those results.
  • Windows text mode translates line endings; binary mode preserves bytes.
  • Save text positions; calculate offsets in binary files.
  • Use eight-bit byte assumptions explicitly when interpreting common binary formats.

1.2 Open and close files with fopen and fclose

Choose an opening mode before you write any processing code. The mode controls whether the file must exist, whether its contents survive, and where writes go. fopen acts on the file immediately: a successful "w" open erases an existing file even if no later write occurs.

Match the mode to the task
ModeExisting fileMissing fileAccess
"r"Keeps contentsFailsRead from start
"w"Erases contentsCreatesWrite from start
"a"Keeps contentsCreatesWrite at end
"r+"Keeps contentsFailsRead and write
"w+"Erases contentsCreatesRead and write
"a+"Keeps contentsCreatesRead anywhere; write at end

Add b for binary mode; "r+b" and "rb+" mean the same thing. C11 adds exclusive creation with x in write modes, such as "wx" and "wbx": opening fails if the file exists. Use a documented mode string; extra mode letters are not portable.

Check before using the pointer

fopen returns a new stream pointer on success and NULL on failure. Missing files, inaccessible paths, and missing directories can all cause failure.

FILE *fp = fopen("scores.txt", "r");
if (fp == NULL) {
    fprintf(stderr, "Cannot open scores.txt\n");
    return EXIT_FAILURE;
}
/* Read through fp here. */
if (fclose(fp) == EOF) {
    fprintf(stderr, "Cannot close scores.txt\n");
    return EXIT_FAILURE;
}

The snippet uses <stdio.h> and <stdlib.h>. Functions such as fgetc, fprintf, and fclose need a valid stream; passing NULL is undefined behavior. fflush(NULL) is a deliberate exception that flushes all output streams.

fclose returns 0 on success and EOF on failure. Once called, the stream is finished, including when closing reports an error. Do not retry fclose on the same pointer or use it for further I/O. Close files promptly: available streams are limited, and C guarantees support for at least eight open streams, including the three standard ones.

Resolve paths from the running program

A relative path such as "data/input.txt" starts at the current working directory, not the source file's folder. Starting the program elsewhere changes what that path names. Forward slashes also work with Microsoft's C library. A backslash in a C string must be doubled, as in "C:\\data\\in.txt"; otherwise an escape such as \n can change the string.

For names supplied on the command line, use int main(int argc, char *argv[]). In a two-name copy command, argc must be 3, argv[1] is the input name, and argv[2] is the output name. Open input first so a misspelled input name does not create or erase output. If output opening fails, close the already-open input. Use distinct input and output files: opening the input first does not protect it if the output name identifies that same file.

Normal return from main or exit closes streams, but explicit closes let the program detect delayed output errors. A crash can lose buffered data; abort does not provide the normal-exit cleanup guarantee.

Key Takeaways

  • Opening with "w" erases an existing file immediately.
  • Check fopen for NULL before using the stream.
  • Relative paths start at the current working directory.
  • Close each opened stream once, and never reuse it after fclose.
  • Open copy input before output, and use distinct files.
  • C11 exclusive write modes fail when the destination exists.

1.3 Use stdin, stdout and stderr with redirection and pipes

A C program starts with three open streams: standard input stdin, standard output stdout, and standard error stderr. They usually connect to the terminal, but the shell can connect them to files or other programs. You can pass them directly to stream functions.

Keep results separate from diagnostics

printf writes to stdout; scanf reads from stdin. getchar() reads a character from stdin, and putchar(c) writes one to stdout. puts(s) writes a string to stdout and adds a newline. Their stream forms let the same code work with a file:

void print_total(FILE *out, int total)
{
    fprintf(out, "Total: %d\n", total);
}

Calling print_total(stdout, 12) prints a result; passing an opened file pointer directs the same layout to a file. In production code, make the helper report a failed write to its caller.

Write diagnostics with fprintf(stderr, ...). A data-processing program can then produce a clean result file while explaining failures separately. An error printed to stdout can corrupt the data another program expects to read.

Let the shell choose connections

In a Unix-like shell, this command separates all three streams:

./sortnums < numbers.txt > sorted.txt 2> errors.txt

< supplies input, > creates or replaces output, >> appends output, and 2> redirects errors. The redirection operators also work in Windows Command Prompt, where the program name is commonly written as sortnums.exe. A pipe, as in generate | sortnums, sends the first program's standard output to the second program's standard input. It does not carry stderr by default.

A filter can accept an optional input name and otherwise read stdin. Keep track of ownership: close a stream your function opened, but leave a borrowed stream for its owner. For a simple command-line filter, if (in != stdin) identifies the file it opened itself.

Flush prompts before waiting for input

A terminal commonly makes stdout line buffered. A redirected file or pipe commonly makes it fully buffered. stderr is not fully buffered. This explains why output order can change when both streams are sent to one destination.

After printf("Saving..."), the text can remain in the buffer because there is no newline. Use fflush(stdout) and check for EOF when it must appear before the next operation. Flushing sends pending output; it does not read or discard input. Standard C does not define fflush(stdin) as an input-clearing operation. To discard a line, read characters until '\n' or EOF.

If a program prints two lines to stdout and a warning to stderr between them, a terminal will commonly show program order. With > out.txt 2>&1, the warning can reach the file before buffered standard output. Do not use mixed-stream display order as a record of execution order.

Return a usable result to scripts

Return EXIT_SUCCESS or 0 when the complete job succeeds and EXIT_FAILURE when it fails. Both macros are declared in <stdlib.h>. A shell command such as convert in.csv out.txt && echo done runs the second command only after success. An honest exit status matters as much as a useful diagnostic.

Key Takeaways

  • Use stdin, stdout, and stderr without opening them.
  • Send program results to stdout and diagnostics to stderr.
  • Redirection changes connections; a pipe carries standard output to standard input.
  • Flush output when a prompt must be visible immediately.
  • Return a failure exit status when the requested job fails.
2

Read and write text files

Text processing has three useful scales: individual characters, formatted values, and whole lines. The choice changes what the program can validate and how it recovers from bad input. A character loop must separate bytes from end of file; a formatted read must check its assignment count; a line reader must handle capacity and incomplete records. Worked examples show how to preserve the data actually read while keeping later parsing and reporting under control.

2.1 Read and write one character at a time

Character I/O is useful when each character determines what happens next: counting separators, changing case, or recognizing a small text format. fgetc reads one character, and fputc writes one. Both are declared in <stdio.h>.

Keep the return value in an int

fgetc(fp) returns the character as an unsigned char converted to int, or the negative constant EOF when no character is available because input ended or a read failed. On the usual eight-bit-byte systems, valid byte values run from 0 to 255. An int keeps those values separate from EOF.

int c;
while ((c = fgetc(in)) != EOF) {
    if (fputc(c, out) == EOF) {
        /* Report a write failure and clean up. */
        break;
    }
}
/* Check ferror(in) before declaring the input complete. */

A plain char can lose this distinction. With signed char, byte 0xFF can become -1 and look like end of file. With unsigned char, the negative EOF value is converted to a byte and can never compare equal to EOF.

Keep both parentheses around the assignment. In c = fgetc(in) != EOF, comparison happens first, so c receives 1 or 0 instead of the character. getc does the same reading job and may be a macro; fputc returns the written character or EOF.

Count successful reads, not attempts

The loop condition must perform the read. feof describes an earlier attempt that reached the end; it cannot predict the next attempt. A loop that checks !feof(in) and then counts unconditionally adds an extra pass at the end.

For the text "hi\nyo\n", six successful reads give six characters and two newline characters. Counting newline characters alone works for newline-terminated lines. The text "red\ngreen\nblue" has two newlines but three lines because the final "blue" is still a line.

To include a final line without a newline, track the last character as well:

size_t lines = 0;
int c, last = '\n';
while ((c = fgetc(in)) != EOF) {
    if (c == '\n') ++lines;
    last = c;
}
if (last != '\n') ++lines;

Starting last at '\n' makes an empty file count as zero lines. A read error still requires a separate failure path; a partial count is not a completed result.

Transform or look ahead

toupper from <ctype.h> can change letters before writing them. A successful fgetc result is already in the valid input range for toupper, so fputc(toupper(c), out) is safe inside the loop. Arbitrary signed char values need conversion to unsigned char before character-classification functions.

ungetc(c, in) pushes a character back so that the next read returns it again. One character of pushback is guaranteed; check for EOF if pushing back fails. This helps a parser inspect the next character without losing it. A positioning operation discards pushback.

The count describes what the selected stream mode delivers. On Windows, text mode counts a CR LF pair as one '\n'; binary mode exposes both bytes. A character count through a text stream therefore need not equal the stored byte count.

Key Takeaways

  • Keep fgetc results in int so byte values remain distinct from EOF.
  • Test each read result before processing or counting it.
  • Count a nonempty final piece without a newline as a line.
  • One character of ungetc pushback is guaranteed; seeking discards it.

2.2 Write and read formatted text with fprintf and fscanf

Formatted I/O converts between C values and readable text. fprintf writes a layout you choose; fscanf reads values that match a format. Their conversion specifications look similar, but input requires pointers to the right destination types.

Write readable values

Use %d for an int, %ld for a long, %zu for a size_t, %s for a string, and %c for a character. Output %f prints a double; a float argument is promoted to double. %% prints a percent sign.

int result = fprintf(fp, "%-8s%6.2f\n", "Oslo", 3.14159);
if (result < 0) {
    /* Handle a write failure. */
}

%-8s left-aligns "Oslo" in eight columns; %6.2f right-aligns "3.14" in six. The resulting line is "Oslo 3.14\n", and the return is 15 characters. Field width is a minimum, not an output length limit. Precision also changes stored information: %.2f writes 3.14159 as "3.14", so those extra digits cannot be recovered from the file.

A simple CSV writer can output "Lima,2024,19.5" with a fixed order and commas between fields. Text containing commas, quotation marks, or newlines needs CSV quoting. Enclose such a field in double quotes, and double any quotation mark inside it. A bare %s writer is suitable only when text fields do not contain those characters.

Format into a bounded array

sprintf has no destination-size argument. Formatting "007.jpg" needs eight bytes including the null terminator. Prefer snprintf:

char name[32];
int n = snprintf(name, sizeof name, "%03d.jpg", 7);
if (n < 0 || (size_t)n >= sizeof name) {
    /* Formatting failed or the full result did not fit. */
}

The nonnegative return is the length the complete text would need, excluding the null terminator. Equality with the buffer size already means truncation. Check negativity before converting the result to size_t.

Read the expected number of values
char name[20];
int age;
int matched = fscanf(fp, "%19s %d", name, &age);

This call succeeds completely only if it returns 2. The width 19 leaves a byte for the terminator. The array name supplies its address; the integer needs &age. For input, %f needs float *, while %lf needs double *. A mismatch is undefined behavior, not a harmless conversion.

Most conversions skip leading whitespace, including newlines. fscanf therefore does not enforce one record per line, and %s cannot read "New York" as a single value. A scan set such as %19[^,] reads up to a comma; whole-line input is often clearer for records.

On "10 abc 20", %d first stores 10 and returns 1. The next call returns 0 because "abc" does not match; that text remains unread. Testing != EOF repeats the failure forever. Test == 1, then handle invalid data separately from end of input or a stream error. A conversion result is a count of assigned values, not a truth value for the entire file.

Key Takeaways

  • Match every format specification to the argument type.
  • Bound input %s to the array size minus one.
  • Compare fscanf with the exact number of assignments expected.
  • snprintf returns the required full length; a return at least the capacity means truncation.
  • CSV text fields need quoting when they contain commas, quotes, or newlines.
  • Formatted floating-point output may discard precision.

2.3 Read lines safely with fgets

Reading a complete line before parsing it keeps each text record separate. If a record is invalid, you can report its line number and continue with the next one. fgets limits how much it writes, but you must still handle retained newlines and lines larger than the array.

Read into a known capacity
char line[256];
while (fgets(line, sizeof line, fp) != NULL) {
    /* Process this successful read. */
}
if (ferror(fp)) {
    /* Report an interrupted read. */
}

fgets reads at most one less than the capacity, stops after a newline if it encounters one, and adds a null terminator. It returns the buffer on success. A NULL result means either that no characters were available at end of file or that an error occurred; do not process the buffer after a read error.

sizeof line supplies the array capacity in this scope. In a helper whose parameter is char *line, it is the pointer's size. Pass the actual capacity separately. The old gets function cannot limit input and was removed in C11.

Recognize pieces of long lines

With char buf[8], "temperature\n" arrives as "tempera" and then "ture\n". The first call uses seven bytes for characters and one for the terminator. A successful read without a newline might be a piece of a long line or the final unterminated piece at end of file.

Choose a policy: join pieces into a larger record, process them as a continuous sequence, or reject the record and discard all of its remaining pieces. For a size limit, inspect the next character before rejecting an exactly full buffer. A next newline completes the record; EOF without a stream error completes an unterminated final line; another character means more content. Push back a character only if later code needs to read it again.

Remove only an ending you actually found

After deciding whether the record is complete, remove line endings:

line[strcspn(line, "\r\n")] = '\0';

strcspn from <string.h> finds the first listed character, or the existing terminator if neither occurs. This handles retained CR LF as well as LF. Deleting line[strlen(line) - 1] unconditionally can remove real data from a final line without a newline, and it is invalid for an empty string.

fputs(line, out) writes the string without adding a newline; puts(line) writes to stdout and adds one. A text copy can pass each successful fgets piece to fputs, checking for failure, even when a long line spans several pieces. For exact original bytes, use binary block I/O instead.

Parse and validate separately

sscanf(line, "%d %9s", &qty, item) returns 2 for "7 apples" and 0 for "seven apples". A failed parse leaves no bad token stuck in the input stream because the line was already read. Numeric conversions with sscanf still require representable input; use strtol for strict range checking.

For strtol, clear errno, pass an end pointer, and check for no digits, ERANGE, and unexpected trailing text. On "42abc", the result 42 is only a numeric prefix. For a whole-number field, allow the chosen trailing whitespace, then require the end of the string. Check the destination type's range before narrowing a valid long to int.

Key Takeaways

  • fgets keeps a newline when it fits and always reserves space for a terminator on success.
  • A full buffer without a newline needs a completeness check.
  • Pass capacities explicitly to pointer-based helpers.
  • Use strcspn to remove only a line ending that exists.
  • Read first, then parse and validate each record.
  • Check strtol for digits, range errors, and trailing data.
3

Store and load data in binary files

Binary files transfer object bytes without converting them to readable text. Element sizes and counts determine how complete arrays, records, and partial final blocks are handled. A file shared between machines also needs an explicit representation: field widths, byte order, and layout. Reading a signature is only the beginning of checking that representation; lengths and counts must be validated before the program trusts or allocates space for the remaining data.

3.1 Read and write binary data with fread and fwrite

Binary I/O transfers the bytes of objects without converting them to readable numbers or words. fread and fwrite take an address, an element size, an element count, and a stream. Their return values count complete elements, so choosing the element size determines what you can learn from the result.

Write and read arrays
int a[5] = {1, 2, 3, 4, 5};
if (fwrite(a, sizeof a[0], 5, out) != 5) {
    /* Handle a write failure. */
}

On a system with four-byte int, this writes 20 bytes and returns 5. Reading into another five-element array with the same representation can recover the values. Use "wb" and "rb" so text translations cannot alter the bytes.

For a single object, pass its address: fwrite(&rec, sizeof rec, 1, out). For objects reached through a pointer p, use fwrite(p, sizeof *p, count, out). sizeof p measures the pointer, and &p points at the pointer variable itself. Neither expresses the intended data transfer. When element size or count is zero, both functions return zero without transferring data.

Copy exactly the bytes read
unsigned char buf[512];
size_t n;
while ((n = fread(buf, 1, sizeof buf, in)) > 0) {
    if (fwrite(buf, 1, n, out) != n) {
        /* Handle failure and stop copying. */
        break;
    }
}

An element size of 1 makes n a byte count. A 1300-byte input supplies 512, 512, and 276 bytes, then zero. The last write must use 276, not the capacity 512. Writing the whole buffer adds 236 bytes left over from earlier reads.

With fread(buf, 512, 1, in), the same input returns 1, 1, then 0. The final 276 bytes are only a partial element; they are not counted, and that partial element's value is indeterminate. Choose byte elements when a partial final block is useful. Choose record-sized elements when incomplete records must be rejected.

A short fread can mean end of file or an error. Check ferror after copying and check fclose on output: a write accepted into a buffer can fail later. A partial header or record must never be treated as a complete object.

Inspect signatures and stored objects

Use unsigned char for raw bytes; on eight-bit-byte systems it holds 0–255 without negative values. JPEG data begins with 0xFF 0xD8. Camera and phone photos often continue with an APPn marker, producing the recovery pattern FF D8 FF E0 through FF D8 FF EF. That pattern is a useful candidate test; validate the format before trusting it. Some JPEGs use a different next segment.

A struct with char name[20] and an int score commonly occupies 24 bytes. A raw write includes all its stored bytes, including padding. A pointer member saves an address, not the pointed-to string. Use an embedded array or write the string's length and characters separately.

Readable text can take more space: "1000000\n" uses eight bytes on Linux and nine in Windows text mode. An explicitly encoded 32-bit integer uses four eight-bit bytes. Raw object storage is compact but ties the file to the producer's representation.

Key Takeaways

  • fread and fwrite return complete element counts, not always byte counts.
  • Use element size 1 when a partial final block matters.
  • Write the number read, not the entire buffer capacity.
  • A raw pointer member stores an address, not its target data.
  • Check short transfers and output closing.
  • Treat signatures as candidate identification, then validate the file.

3.2 Design binary formats that work across machines

A binary stream preserves bytes, but two machines can interpret the same bytes differently. A portable format defines what each byte means instead of adopting whatever layout the compiler gives an object.

Specify sizes, order, and layout

Three choices make a raw object dump machine-dependent:

ChoiceWhat can differ
Type sizeint can be two or four bytes; long commonly differs between 64-bit Windows and Linux
Byte orderThe least or most significant byte can come first
Struct layoutPadding and member offsets can change

Little-endian stores the least significant byte first. Big-endian stores the most significant byte first. The value 258, hexadecimal 0x00000102, is 02 01 00 00 in little-endian order and 00 00 01 02 in big-endian order.

A common struct layout for a char followed by an int occupies eight bytes: one byte for the character, three padding bytes, and four for the integer. Padding values are unspecified. Exact-width types from <stdint.h>, such as uint32_t, fix bit widths where provided; they do not fix byte order or remove padding. Common file-format examples assume eight-bit bytes and the availability of those types.

Decode fields explicitly

Read four bytes completely before interpreting them. For a little-endian field:

uint32_t v = (uint32_t)b[0]
           | (uint32_t)b[1] << 8
           | (uint32_t)b[2] << 16
           | (uint32_t)b[3] << 24;

Here b is an unsigned-byte array. Each cast takes place before the shift, so the arithmetic has the required unsigned width. To encode, extract the low eight bits, then the next eight, and so on. Check every output operation. Writing v directly with fwrite would put the host's byte order back into the format.

Define a complete small format

A scores format can use "SCR1" as a four-byte signature, a four-byte little-endian count, and records made of 20 name bytes plus four little-endian score bytes. The signature also identifies the version. The header is eight bytes; each record is exactly 24 bytes.

Five records occupy 128 bytes. Record index 3 begins at byte 80: skip eight header bytes and three complete records. State the name-field encoding and termination or padding policy as part of a real format; a fixed 20-byte name field is not automatically a C string.

Check a header's complete length and signature before using its fields. Then check counts and lengths against reasonable limits and the available data before allocating memory. A plausible count is not enough if later records are missing.

Read the actual format structure

Some PCM WAV files have a simple 44-byte header, with the sample rate at bytes 24–27. Bytes 44 AC 00 00 decode to 44100 samples per second. Other WAV files contain extra chunks, so a general reader follows chunk identifiers and sizes to locate the fmt chunk. Assuming one fixed header layout for every file can read an unrelated field as the rate.

Text such as CSV avoids integer-size, byte-order, and struct-padding problems and is easy to inspect. It still needs a defined field layout, quoting rules, and checked parsing. Choose it when readability and interchange matter more than compact binary representation.

Key Takeaways

  • A portable binary format defines field widths, byte order, and offsets.
  • Exact-width integer types alone do not make a struct dump portable.
  • Cast bytes to the intended unsigned width before shifting.
  • Validate the whole header and limit counts before trusting them.
  • Follow chunk structure when a format allows extra chunks.
  • A fixed-width text field needs an explicit encoding and length policy.
4

Move to any position in a file

File positions make direct access possible when records have known locations. Calculating those locations requires attention to headers, record widths, and zero-based indexes. Text positions have stricter rules because translation can change their meaning. Once a stream supports both reading and writing, positioning also controls valid direction changes. Updating one record therefore combines a location calculation with a checked sequence that preserves the surrounding data.

4.1 Find and set the file position with ftell, fseek and rewind

Sequential reads visit data in order. Random access lets a program jump to a known location, such as one record in a large file. Positioning works only when the underlying stream supports it, and the meaning of a position differs between binary and text streams.

Tell and seek

ftell(fp) returns a long position or -1L on failure. For a binary file, a position counts bytes from its start. fseek(fp, offset, whence) moves relative to a selected reference point and returns 0 on success, nonzero on failure.

ReferenceMeaning of offset
SEEK_SETFrom the start
SEEK_CURFrom the current position
SEEK_ENDFrom the end

For example, fseek(fp, -4L, SEEK_END) requests the last four bytes of a binary file on a system supporting end-relative seeks. Check the result before reading. A request on a pipe or terminal, or a request before the start of an ordinary file, can fail.

Calculate a record location

For headerless fixed-size binary records, the zero-based index multiplied by the record width gives the starting offset. With 24-byte records, index 3 starts at byte 72. After reading that entire record, the position is 96.

long offset = 3L * (long)sizeof(struct record);
if (fseek(fp, offset, SEEK_SET) != 0) {
    /* Handle the failed move before reading. */
}

This example assumes the file was written with the same struct layout. A specified portable format uses its defined record width instead. Include header bytes when present. The third record counted from 1 is index 2, not index 3. For large indexes, validate the multiplication and ensure the result fits long before seeking.

On mainstream systems, seeking to the end and using ftell can measure a binary file: a 120-byte file with 24-byte records holds five records. Check both calls and restore the position afterward. Standard C does not require a meaningful SEEK_END for every binary stream, so the method depends on that stream's support.

Save text positions without arithmetic

Text mode can translate line endings. A returned text position is information for getting back to a place, not a count to add or subtract. A nonzero text seek uses a value previously returned by ftell for the same file, with SEEK_SET. A zero offset is permitted with any reference point.

rewind(fp) returns to the start and clears both end-of-file and error indicators. It returns no result, so use checked fseek(fp, 0L, SEEK_SET) when moving successfully must be confirmed. A successful fseek clears end of file and discards ungetc pushback, but leaves an existing error indicator set.

Keep a position token

fgetpos(fp, &pos) saves a position in fpos_t; fsetpos(fp, &pos) restores it. Check both for nonzero failure. Treat fpos_t as an opaque token, with no arithmetic. It can hold position information beyond a simple byte count.

fseek and ftell use long, which is commonly 32 bits on Windows and limits representable positions to about 2 GiB. A position token avoids tying the interface to long, but the supported file size still depends on the implementation and configuration.

Key Takeaways

  • Check fseek for nonzero and ftell for -1L.
  • A record offset includes the header and all earlier records.
  • Use zero-based indexes consistently.
  • Restore text positions with saved tokens, without offset arithmetic.
  • rewind clears both indicators; successful fseek clears end of file.
  • Positioning requires a seekable stream and representable offsets.

4.2 Update fixed-size records in place

An update stream reads and writes the same file. Use "r+b" to preserve an existing binary file while changing its records. "w+b" erases the old file immediately, and append modes force every write to the end.

Make direction changes valid

An update stream has two switching rules:

ChangeRequired action between operations
Writing to readingFlush output or perform a positioning operation
Reading to writingPerform a positioning operation, unless the read encountered end of file

Positioning functions include fseek, fsetpos, and rewind. Check functions that report a result before continuing. A direction change without the required action has undefined behavior; you cannot predict that it will merely affect the next record.

Update one complete record

Suppose a headerless file contains five 24-byte records in the same representation as struct record. To change index 3:

  1. Open with "r+b" and check the pointer.
  2. Seek to byte 72 and check success.
  3. Read exactly one complete record.
  4. Change its score member to 99.
  5. Seek back to the record's start.
  6. Write exactly one record and check the close result.

The key middle operations are:

if (fread(&rec, sizeof rec, 1, fp) != 1) {
    /* Report the incomplete input, then clean up. */
    goto cleanup;
}
rec.score = 99;
if (fseek(fp, -(long)sizeof rec, SEEK_CUR) != 0) {
    /* Report the failed seek, then clean up. */
    goto cleanup;
}
if (fwrite(&rec, sizeof rec, 1, fp) != 1) {
    /* Report the failed write, then clean up. */
    goto cleanup;
}

The enclosing function supplies a cleanup label that closes its stream and returns failure on these branches. After the read, the position is 96. Moving back 24 bytes both selects the original record and permits the read-to-write switch. A successful replacement leaves the file at 120 bytes with five records. Restoring a saved start position is another valid way to perform the update.

Decide when to rewrite

Appending a 24-byte record grows that file to 144 bytes. Seeking to the beginning of an "ab" or "a+b" stream cannot turn its next write into an overwrite; the write still goes to the current end.

An in-place replacement must fit the space it replaces. Changing "Bo,7" to "Bo,9" fits. Writing "Bo,12" over "Bo,7\n" consumes the newline and joins the following text onto the record. To grow or shrink records, write a corrected new file. Standard C has no stream function that removes a range of bytes from the middle of a file. Deletion can instead copy all surviving records or mark a fixed-size record as deleted.

Keep replacement recoverable

Check remove and rename; both return 0 on success. Whether rename replaces an existing destination is implementation-defined. Linux and macOS support replacement; Microsoft's C library fails when the destination exists.

A portable recovery plan writes and closes the new file, renames the original to a distinct backup name, and renames the new file to the original name. If installation fails, keep the backup available for restoration and report where it is. Delete the backup only after installation succeeds. This sequence supports recovery; it is not a portable atomic transaction or a guarantee against power failure.

Key Takeaways

  • Use "r+b" to update an existing file without truncating it.
  • Follow the read/write switching rule even when the intended position seems obvious.
  • Seek back after reading a record before replacing it.
  • Append-mode writes always go to the end.
  • Rewrite data when its length changes.
  • Check each replacement step and preserve a recoverable original.
5

Detect, report and recover from file errors

A file operation can fail after opening succeeded, and buffered output can fail only at closing. Reliable programs read return values, distinguish invalid data from access problems, preserve useful error information, and clean up on every path. These tasks work together: the diagnostic should explain the original failure, while the final status must also reflect failures found during cleanup. A complete copy program shows how those decisions fit into ordinary C control flow.

5.1 Check every result and tell end of file from errors

A file can open successfully and still fail during reading, writing, seeking, or closing. A robust program checks the result of the operation it actually attempted. It distinguishes a completed read from interrupted input and distinguishes malformed data from a failing stream.

Learn each failure signal
OperationSignal to handle
fopen, fgetsNULL
fgetc, fputc, fflush, fcloseEOF
fprintfA negative result
fputsEOF
fread, fwriteFewer complete elements than requested
fscanfFewer assignments than expected, or EOF
fseek, fgetpos, fsetposA nonzero result
ftell-1L

rewind, clearerr, and perror return no value. If successful movement to the start must be checked, use fseek instead of relying on a result from rewind.

Inspect the stream after a read stops

The stream keeps separate end-of-file and error indicators. feof(fp) tests the first; ferror(fp) tests the second. Each returns nonzero if its indicator is set.

while (fgets(line, sizeof line, fp) != NULL) {
    /* Process successful input. */
}
if (ferror(fp)) {
    fprintf(stderr, "Input could not be completed\n");
    /* Return failure after cleanup. */
}

The return from fgets alone does not distinguish the two stopping reasons. Similarly, fgetc returns EOF and fread returns a short count for either end of file or read failure. Do not test feof before the read to predict whether data remains.

Indicators persist. clearerr clears both, as does rewind. Successful fseek or fsetpos clears end of file, but not an existing error. Clearing an indicator acknowledges it; it does not reconnect a removed drive or repair a damaged file. Retry only when the cause has been addressed.

Separate invalid data from failed access

If fscanf(fp, "%d", &value) returns 0 on "abc", conversion failed before any assignment. Neither end of file nor a read error is required. Report an invalid field, preferably with a line number. A message about the disk would describe the wrong problem.

If a required header is read as one element and fread returns 0, the header is incomplete. Do not inspect that partially filled object. If ferror is set, report an input error; if the file ended, report truncated data. An empty file and a partial header can produce the same element count, so the expected format supplies the requirement that the header must exist.

Catch delayed output failures

A disk can fill after the program has opened its output. Buffered writes can appear successful until fflush or fclose actually transfers pending bytes. Check the final close and let it turn an otherwise successful job into failure. Do not close the same stream again afterward.

At a terminal, Ctrl+D at the start of a line on Linux or macOS, or Ctrl+Z then Enter on Windows, commonly signals end of input. clearerr(stdin) clears the resulting indicator if the program needs another attempt. The terminal action and a read error remain different causes.

Key Takeaways

  • Check each function against its own documented return value.
  • Read first, then use stream indicators to identify the stopping reason.
  • A format mismatch is invalid data, not necessarily a stream error.
  • Reject incomplete required headers and records.
  • A delayed error at output close must make the job fail.

5.2 Explain failures with errno, perror and strerror

A return value tells you that an operation failed. An error code can help explain why. Use errno only in the context of the operation's documented behavior, and preserve it before unrelated library calls can change it.

Let the operation establish failure

errno is a modifiable int expression from <errno.h>, with thread-local storage duration in C11. It starts at zero. Library calls do not reset it to zero, and a successful call can leave or set a nonzero value. Testing errno after a successful fopen therefore does not tell you that the open failed.

On POSIX systems, a failed fopen sets an error code. Microsoft's C library also provides file error codes. Standard C does not require fopen to set errno. Portable reporting can clear it before the open and use a general message if no code was supplied:

errno = 0;
FILE *fp = fopen(name, "r");
if (fp == NULL) {
    int saved = errno;
    if (saved != 0)
        fprintf(stderr, "Cannot open %s: %s\n",
                name, strerror(saved));
    else
        fprintf(stderr, "Cannot open %s\n", name);
    return EXIT_FAILURE;
}

This snippet also needs <stdio.h>, <stdlib.h>, and <string.h>. Saving the code immediately keeps later reporting or cleanup calls from replacing the original reason. A saved code is useful even if the eventual message is printed much later.

Choose a message function

perror(label) writes the label, a colon and space, the current error message, and a newline to stderr. A typical missing-file message is "missing.txt: No such file or directory"; exact wording depends on the system.

strerror(code) returns the library's message for a supplied code, so it fits a custom diagnostic naming the program, operation, and file. Do not modify the returned string. Use strerror(saved) after cleanup instead of asking for the new value of errno.

C defines EDOM, ERANGE, and EILSEQ. Common file codes such as ENOENT, EACCES, EEXIST, and ENOSPC are supplied by POSIX and widely available C libraries. Match your code to the interface and platform you target. Do not assume numeric code values or exact English message text are universal.

Handle an ambiguous return value

For some functions, the result alone cannot distinguish success from a range error. strtol can return LONG_MAX as a valid number or as the result of overflow. Clear errno before converting, then inspect the documented range code:

errno = 0;
char *end;
long value = strtol(text, &end, 10);
if (end == text) {
    /* No digits were converted. */
} else if (errno == ERANGE) {
    /* The value is outside the long range. */
} else {
    /* Validate trailing characters and the target range. */
}

A useful diagnostic gives the user something to act on. Name the file and attempted action; preserve the system reason when available. Send it to stderr, leaving stdout available for valid result data.

Key Takeaways

  • Use the function result to establish failure before interpreting errno.
  • Save errno immediately before reporting or cleanup calls.
  • perror uses current errno; strerror accepts a saved code.
  • Reset errno before strtol and check ERANGE.
  • Include the file and attempted action in a diagnostic.

5.3 Clean up resources and report the outcome

Error handling is complete only when resources are released and the program reports the real outcome. Plan ownership when you open a stream, and make every later path honor that plan.

Give every open one close

If input opening fails, there is no stream to close. If output opening fails after input succeeded, close the input. If copying fails after both opened, close both, check the output close, and keep a failure status. Closing a pointer twice is not extra protection; it uses a finished stream.

Early-return code usually closes resources in reverse order. A shared cleanup label is useful when several failure paths need the same work. Initialize pointers to NULL, keep a failure status by default, and set success only after the processing phase finishes.

The following complete program copies distinct input and output files in binary mode. It uses generic messages because standard C does not require every stdio failure to supply errno.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    FILE *in = NULL, *out = NULL;
    int status = EXIT_FAILURE;
    int output_acquired = 0;
    unsigned char buf[512];
    size_t n;

    if (argc != 3) {
        fprintf(stderr, "Usage: %s input output\n", argv[0]);
        return EXIT_FAILURE;
    }
    in = fopen(argv[1], "rb");
    if (in == NULL) {
        fprintf(stderr, "Cannot open input: %s\n", argv[1]);
        goto cleanup;
    }
    out = fopen(argv[2], "wb");
    if (out == NULL) {
        fprintf(stderr, "Cannot open output: %s\n", argv[2]);
        goto cleanup;
    }
    output_acquired = 1;
    while ((n = fread(buf, 1, sizeof buf, in)) > 0) {
        if (fwrite(buf, 1, n, out) != n) {
            fprintf(stderr, "Write failed: %s\n", argv[2]);
            goto cleanup;
        }
    }
    if (ferror(in)) {
        fprintf(stderr, "Read failed: %s\n", argv[1]);
        goto cleanup;
    }
    status = EXIT_SUCCESS;

cleanup:
    if (out != NULL && fclose(out) == EOF) {
        fprintf(stderr, "Close failed: %s\n", argv[2]);
        status = EXIT_FAILURE;
    }
    if (in != NULL && fclose(in) == EOF) {
        fprintf(stderr, "Close failed: %s\n", argv[1]);
        status = EXIT_FAILURE;
    }
    if (output_acquired && status != EXIT_SUCCESS) {
        if (remove(argv[2]) != 0)
            fprintf(stderr, "Cannot remove incomplete output: %s\n",
                    argv[2]);
    }
    return status;
}

The input loop processes only bytes actually read. A short write jumps to cleanup; an input error is checked after the loop. The output close can still change success into failure. Removal is attempted only when this run successfully opened the output, so an opening failure does not trigger deletion of an unrelated file. The distinct-file requirement matters: "wb" would erase input if the two names identified the same file.

Preserve important existing data

Direct output opening cannot undo truncation. To replace valuable data, write under a separate temporary name first. Check every write and final close before renaming. Keep the original under a backup name until the new file is installed; check every rename and remove. If installation fails, report the recoverable file's location instead of deleting it.

A helper should close what it opened and return a success or failure result to its caller. The caller can decide whether to retry or exit. Returning EXIT_FAILURE after any incomplete step lets a script stop before a dependent action, such as deleting the original after a backup.

Key Takeaways

  • Initialize stream ownership and keep failure as the default status.
  • Close every successfully opened stream exactly once on every path.
  • Let a close failure change the final status.
  • Remove incomplete output only when this run created or opened it.
  • Write replacements separately and preserve the original until installation succeeds.
  • Helpers report failures to their callers so callers can choose recovery.

File Input and Output in C examples

5 Walkthroughs

1

Open a stream without losing existing data

12 steps
Choose a file mode, trace text translation, and connect the same processing code to standard streams.
  1. 1
    IntroductionDecide what must survive

    A program is about to save results. Before it opens anything, decide whether old data must survive and whether the file contains readable lines or exact bytes. Those choices determine the mode, and a wrong one can erase old data.

    You will trace one write from the program's text through its stream (the library's channel to a file or terminal), then choose where normal results and diagnostics should go (the standard streams). Opening is already an operation on the file, so this decision comes before the first write.

  2. 2
    ExplanationReach data through a stream

    A stream is the standard library's channel to a file, terminal, or pipe. Keep its handle as a FILE * from <stdio.h> and pass it to functions such as fprintf.

    The library object remembers the buffer, position, and status indicators. You do not edit its fields. A file position advances as data is processed; a terminal or pipe cannot be treated as an ordinary file for seeking.

  3. 3
    ExampleTrace newlines to stored bytes

    Writing "a\nb\nc\n" supplies three letters and three newline characters. On Linux or macOS, the text file holds six bytes. On Windows, each newline becomes CR LF, giving nine stored bytes.

    Reading that Windows file in Windows text mode restores six characters. Binary input exposes all nine bytes. The program's text and the stored byte sequence are different views of the same lines.

  4. 4
    ConnectionChoose a mode for an image

    A byte sequence in a compressed image can contain values that text mode translates. Adding b selects binary mode and preserves those values.

    This explains why an image reader that works with "r" on Linux can fail on Windows. It must use "rb" because it handles a defined sequence of bytes, not lines that the library should translate.

  5. 5
    ChallengeCheck a character count

    On Windows, a text-mode write stores "m\nn\n". How many bytes does the resulting file contain, and why?

    ---reveal---

    It contains six bytes: two letters plus two CR LF pairs. The four characters supplied by the program expand because each newline becomes two stored bytes. In binary mode, those same four supplied bytes would be written without that translation.

  6. 6
    ExplanationChoose preservation before access

    For an existing file, "r" permits reading, "w" erases and permits writing, and "a" keeps the data and appends. A + permits both input and output.

    Use "r+" to preserve an existing file for updates. "w+" still erases it. C11 "wx" fails if the file exists, which makes it useful when an existing destination must be protected.

  7. 7
    TipAcquire and release one stream

    After FILE *fp = fopen(name, "r");, test fp == NULL before any stream operation. Failure supplies no stream to process or close.

    On success, the program owns a stream that needs one fclose. Check that close too. The stream is finished after the call even when closing fails; retrying a close uses a stream that is no longer valid.

  8. 8
    ChallengeProtect the old log

    An existing log must keep its entries, and a new line must be added. A learner chooses "w" because the task writes. What mode should be used, and when would "w" destroy the old entries?

    ---reveal---

    Use "a". Mode "w" destroys existing contents as soon as opening succeeds, even before a write. The choice must protect the log during opening, not only during the later processing code.

  9. 9
    ExplanationSeparate results from explanations

    The already-open streams are stdin for input, stdout for results, and stderr for diagnostics. A function accepting FILE *out can write the same layout to a file or to stdout.

    A shell can redirect standard output to a file or pipe it to another program. Keep diagnostic text on stderr, so a machine-readable result does not acquire error messages between its data rows.

  10. 10
    Key InsightMake buffered text appear

    Output may wait in a memory buffer. Terminal standard output is commonly line buffered; redirected output is commonly fully buffered. Standard error is not fully buffered.

    A prompt without a newline can need checked fflush(stdout) before input begins. Flushing does not discard input. To skip an unwanted input line, consume characters through its newline or end of file.

  11. 11
    ChallengeTrace a filter output

    A filter reads standard input, writes results to standard output, and writes errors to standard error. It runs as filter < raw.txt > clean.txt. Where should a rejected-record message appear, and what status should it return if it cannot complete the job?

    ---reveal---

    The diagnostic goes to the inherited error destination, commonly the terminal. Return EXIT_FAILURE. The result file stays separate from the message, and the shell can detect failure.

  12. 12
    RecapUse a deliberate stream lifecycle

    Choose preservation and text-versus-binary behavior before opening. Check that opening produced a stream, process only through valid pointers, and close each stream you own once.

    Standard streams let the shell supply the connections. Separate results from diagnostics and return a status that describes the completed job. These choices let the same small program work interactively, with files, or inside a pipeline.

2

Read a text record and validate its contents

15 steps
Move from character reads to formatted values and complete lines, handling boundaries that cause common input bugs.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionRead at the right scale
  2. 2
    ExplanationKeep a character distinct from EOF
  3. 3
    ExampleCount only a successful read
  4. 4
    ChallengeInclude the final unterminated line
  5. 5
    ExampleWrite a controlled layout
  6. 6
    TipReserve the string terminator
  7. 7
    ExplanationUse the assignment count
  8. 8
    ChallengeChoose a bounded formatted name
  9. 9
    ExplanationRead a line into known storage
  10. 10
    ExampleFollow a line across two reads
  11. 11
    TipTrim the ending without trimming data
  12. 12
    ExplanationParse the line already read
  13. 13
    ChallengeAccept an exact-fit line
  14. 14
    ChallengeReject a prefix with an invalid suffix
  15. 15
    RecapKeep reading and interpretation separate
3

Transfer bytes and define what they mean

12 steps
Copy a short final block correctly, then decode records using an explicit binary layout.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionSeparate bytes from values
  2. 2
    ExplanationChoose what the return counts
  3. 3
    ExampleFollow the final short block
  4. 4
    Key InsightDistinguish a record from a byte block
  5. 5
    ChallengeUse the successful count
  6. 6
    ExplanationDo not let the compiler design the format
  7. 7
    ExampleDecode a little-endian value
  8. 8
    ExampleLocate a record from its layout
  9. 9
    ChallengeCheck the declared amount of data
  10. 10
    ConnectionFollow the structure the format allows
  11. 11
    ChallengeRequire a complete field before decoding
  12. 12
    RecapMake transfer and format agree
4

Find a record and replace it safely

13 steps
Calculate an offset, preserve a saved position, and follow update-stream rules while replacing one record.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionJump to the data you need
  2. 2
    ExplanationSelect a reference point
  3. 3
    ExampleLocate zero-based record 3
  4. 4
    TipRestore text positions as tokens
  5. 5
    ChallengeFind the third record
  6. 6
    ExplanationPreserve the existing file
  7. 7
    ExampleRestore the record start
  8. 8
    Key InsightComplete the replacement
  9. 9
    ChallengeChoose both the mode and the move
  10. 10
    ConnectionRewrite when a record grows
  11. 11
    TipKeep installation recoverable
  12. 12
    ChallengeInterpret a completed append
  13. 13
    RecapPositioning is part of a valid update
5

Carry failure through reporting and cleanup

12 steps
Diagnose input completion, preserve the original error, and make late output failures change the final result.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionSuccess includes the final close
  2. 2
    ExplanationRead each function result
  3. 3
    ExplanationExplain why input stopped
  4. 4
    ChallengeReject a truncated header
  5. 5
    ExplanationCapture the original reason
  6. 6
    ExamplePrint from the saved code
  7. 7
    ChallengeChoose the correct diagnostic source
  8. 8
    ExplanationTrack which streams were acquired
  9. 9
    ExampleLet cleanup revise success
  10. 10
    ChallengeDecide a script's next action
  11. 11
    Key InsightKeep the original after rename failure
  12. 12
    RecapReturn the outcome of the complete job

File Input and Output in C practice questions

40 Practice Questions in 4 sets

Set 1: Choose streams and process complete input10 Practice Questions

Question 1 of 10

Which mode reads a compressed file without text translation?
  1. "r"
  2. "rb"
  3. "wb"
  4. "ab"
Show answerHide answer
Answer: B
"rb" opens an existing file for binary input, preserving its stored bytes. Plain "r" selects text mode, which can translate line endings and recognize Ctrl+Z as end of input on Windows. The write modes do not provide the requested reading access.

Question 2 of 10

A program must add a new entry to an existing log while keeping earlier entries. What opening mode fits?
  1. "w"
  2. "r"
  3. "w+"
  4. "a"
Show answerHide answer
Answer: D
Append mode keeps existing contents and places each write at the end. Mode "w" would erase the earlier log entries as soon as opening succeeds. Mode "r" preserves data but does not permit the new entry to be written; "w+" permits input and output but still erases the file.

Question 3 of 10

fgets succeeds on the last line, which contains "maple" with no newline. What does line[strlen(line) - 1] = '\0'; leave?
  1. "mapl"
  2. "maple"
  3. "maple\n"
  4. "map"
Show answerHide answer
Answer: A
The code always replaces the final stored character, so it removes the e from "maple". fgets does not invent a newline when the file has none. Locate CR or LF with strcspn before trimming, so a final line without an ending keeps all of its actual data.

Question 4 of 10

On a system with signed eight-bit char, a binary file begins with byte 0xFF and contains more data. Why can char c; while ((c = fgetc(fp)) != EOF) stop immediately?
  1. The binary mode converts 0xFF to end of file.
  2. The assignment compares before storing the byte.
  3. The byte can become -1 when converted to char.
  4. The first successful read sets the EOF indicator.
Show answerHide answer
Answer: C
fgetc returns the byte as a nonnegative int, but storing it in signed eight-bit char can turn 255 into -1. That value can compare equal to the implementation’s EOF, stopping the loop before later bytes. The parentheses are correct here; the narrowing destination type causes the problem.

Question 5 of 10

Given char tag[14]; int count;, what call safely reads one word and an integer into these objects?
  1. fscanf(fp, "%14s %d", tag, &count)
  2. fscanf(fp, "%13s %d", tag, &count)
  3. fscanf(fp, "%13s %d", tag, count)
  4. fscanf(fp, "%14s %d", tag, count)
Show answerHide answer
Answer: B
The word conversion must allow at most 13 characters so the 14-byte array retains a byte for its null terminator. The integer conversion also requires &count, a pointer to the destination. Width 14 looks like the array size but allows one more input character than the array can safely hold with its terminator.

Question 6 of 10

A report is redirected to a file. Which stream should carry a message explaining that one input record is invalid?
  1. stderr
  2. stdout
  3. stdin
  4. The report’s output stream
Show answerHide answer
Answer: A
stderr keeps diagnostics separate from the report data sent to stdout. Printing the message on stdout would place it inside the redirected report and could break its expected format. Standard input supplies data to read; it is not the destination for a diagnostic.

Question 7 of 10

A successful fwrite(a, 4, 7, fp) writes every requested element. What does it return?
  1. 4
  2. 28
  3. 7
  4. 1
Show answerHide answer
Answer: C
fwrite returns the number of complete elements written, so it returns 7. The transfer covers 28 bytes because each element has size 4, but that byte total is not the return value. Byte counts and element counts coincide only when the element size is 1.

Question 8 of 10

A 32-bit little-endian field contains the eight-bit bytes 07 02 00 00. What value does it represent?
  1. 1794
  2. 7
  3. 131079
  4. 519
Show answerHide answer
Answer: D
Little-endian order gives the first byte weight 1 and the second weight 256, producing 7 plus 512, or 519. Reading 07 02 as a big-endian pair would give 1794. The host machine’s own byte order does not change the interpretation specified by the file format.

Question 9 of 10

A binary file has a 12-byte header and 20-byte records. After seeking to byte 12, a program reads two complete records. What relative fseek call now selects the fourth record counted from 1?
  1. fseek(fp, 40L, SEEK_CUR)
  2. fseek(fp, 60L, SEEK_CUR)
  3. fseek(fp, 20L, SEEK_CUR)
  4. fseek(fp, 72L, SEEK_CUR)
Show answerHide answer
Answer: C
The two reads move from byte 12 to byte 52. The fourth record is index 3, so its start is byte 72 after the header and three earlier records; moving forward 20 bytes reaches it. Passing 72 with SEEK_CUR would add that absolute location to the current position instead of selecting it.

Question 10 of 10

A required 16-byte header is read using fread(&h, 16, 1, fp). It returns 0, ferror(fp) is zero, and feof(fp) is nonzero. How should the reader proceed?
  1. Reject the incomplete header without interpreting its fields.
  2. Interpret the header because no stream error occurred.
  3. Retry the same header read without changing any stream state.
  4. Clear the indicators and accept the zero-filled fields.
Show answerHide answer
Answer: A
No complete header arrived, and the indicators show end of file rather than a stream access error. The file is therefore missing required format data, even though the read mechanism did not fail. The object can contain a partial element with an indeterminate value, so the absence of ferror does not make its fields safe to interpret.
Set 2: Handle text boundaries and binary layouts10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A program is started in /work/run and opens "data/items.txt". Which path is resolved?
  1. /work/data/items.txt
  2. /work/run/items.txt
  3. /work/run/data/items.txt
  4. The path beside the source file
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

In a shell command producer | consumer > result.txt, where does the producer’s standard error go by default?
  1. Into the consumer’s standard input
  2. To its inherited error destination
  3. Into result.txt with the results
  4. Into the producer’s standard input
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A 1540-byte file is copied with a 600-byte buffer and fread(buf, 1, 600, in). What sizes should the successful writes use?
  1. 600, 600, 340
  2. 600, 600, 600
  3. 600, 340, 600
  4. 600, 600, 0
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

char name[8]; receives snprintf(name, sizeof name, "part-%d", 2468), which returns 9. What should the program conclude?
  1. The destination now contains the complete name.
  2. The nine-character name fits in the buffer.
  3. Nine stored bytes include the null terminator.
  4. The result was truncated and must be handled.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A validator permits at most seven content characters per line. An error-free file contains "cedars\nmaplesx". It repeatedly calls fgets(buf, 8, fp). What record boundaries must it recognize?
  1. One valid record formed by joining both pieces.
  2. One valid record: "cedars"; reject "maplesx".
  3. Two valid records: "cedars" and "maples".
  4. Two valid records: "cedars" and "maplesx".
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

An error-free input contains "north\nsouth\neast". How many lines and newline characters does it contain?
  1. 3 lines and 3 newlines
  2. 2 lines and 2 newlines
  3. 3 lines and 2 newlines
  4. 2 lines and 3 newlines
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

Two systems both provide uint32_t, but differ in byte order and struct padding. A format writer dumps struct { char kind; uint32_t count; } with one fwrite. What redesign makes the representation independent of both differences?
  1. Encode defined fields individually in a chosen byte order.
  2. Replace the member with a plain unsigned int.
  3. Write sizeof into the header and keep the dump.
  4. Keep the struct and open it with "wb".
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A text stream’s position was saved by long p = ftell(fp); and checked. After more reading, what valid call returns to it?
  1. fseek(fp, p, SEEK_CUR)
  2. fseek(fp, p, SEEK_SET)
  3. fseek(fp, p + 1, SEEK_SET)
  4. fseek(fp, -p, SEEK_END)
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A binary file has an 8-byte header and five 16-byte records. An "r+b" stream seeks to byte 40 and reads one complete record without EOF. A field is changed. What operation before writing both permits the switch and selects that same record?
  1. fseek(fp, -16L, SEEK_CUR), moving to byte 40.
  2. fseek(fp, 0L, SEEK_CUR), staying at byte 56.
  3. fseek(fp, 24L, SEEK_SET), moving to byte 24.
  4. fflush(fp), leaving the position at byte 56.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A failed library call sets errno. The program must close another stream before reporting the original cause. What should it preserve first?
  1. The current output-buffer length
  2. The next available stream pointer
  3. The current value of errno
  4. The result of a new successful call
Show answerHide answer

Save this lesson to see this answer.

Set 3: Update records and preserve trustworthy results10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

On Windows with eight-bit bytes, "x\ny\n" is written in text mode. How many stored bytes result?
  1. 4
  2. 6
  3. 8
  4. 5
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A C11 program must create a new binary export but must preserve any existing file at that name. What mode fits?
  1. "wb"
  2. "ab"
  3. "r+b"
  4. "wbx"
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A format has an 8-byte header and exactly 18-byte records. Its count field says 6 records, but the complete file is only 98 bytes. What should a reader conclude before allocating for those records?
  1. The file cannot supply the six records it declares.
  2. The count is valid because the header is complete.
  3. The file holds six records after rounding the length.
  4. The final record can be completed with zero bytes.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A complete line "64km" is passed to strtol after errno is cleared. The return is 64, errno remains 0, and end points at k. The field must be a whole integer with optional trailing whitespace. What is the correct decision?
  1. Accept because errno stayed zero.
  2. Accept after discarding the two letters.
  3. Reject because non-whitespace text remains.
  4. Reject because no numeric prefix was found.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

An error-free binary file has 27 bytes. Two calls use fread(b, 16, 1, fp) with a 16-byte array. What does the second call return, and how may its element be used?
  1. 11; its eleven bytes form a complete element.
  2. 1; the missing five bytes are filled with zeros.
  3. 0; its partial value can serve as the next record.
  4. 0; the partial element must not be interpreted.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

Input is "18 pear 26". After one successful fscanf(fp, "%d", &n), the same call returns 0 twice. Why has it not reached 26?
  1. The first read automatically consumed all three fields.
  2. The nonmatching word remains unread at the next conversion.
  3. The second read reached EOF and cleared the word.
  4. The integer destination must be changed to a double.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

What value indicates that fseek failed?
  1. A nonzero result
  2. The new byte offset
  3. Always exactly EOF
  4. Always exactly -1L
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A seekable binary file contains a 10-byte header and four 14-byte records. An "r+b" reader seeks to byte 38 and reads one complete record without EOF. It changes a field. What next operation selects the same record and permits the replacement write?
  1. fflush(fp)
  2. fseek(fp, 0L, SEEK_CUR)
  3. fseek(fp, 38L, SEEK_SET)
  4. fseek(fp, 52L, SEEK_SET)
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

All output writes returned their expected counts, but fclose(out) returns EOF. What outcome should the program report?
  1. Success because all data reached the write buffer.
  2. Success after calling fclose on the same stream again.
  3. Failure only if feof(out) is also set.
  4. Failure because buffered output may be incomplete.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

Input opens successfully, then opening output returns NULL. What should this path do before returning failure?
  1. Close input once and report the output-open failure.
  2. Close both pointers, including the null output pointer.
  3. Remove the output path even though it did not open.
  4. Return immediately and leave input open for the caller.
Show answerHide answer

Save this lesson to see this answer.

Set 4: Diagnose failures across a complete file workflow10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A program reads a Windows-created line on Linux and removes only its LF. Comparing the result with "ready" fails although the visible letters match. What retained character explains this?
  1. A tab preceding the letters
  2. A CR preceding the removed LF
  3. A second null terminator
  4. An EOF byte stored by fgets
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A program must append its normal output to a shell file named totals.txt. What redirection operator is needed?
  1. < totals.txt
  2. 2> totals.txt
  3. > totals.txt
  4. >> totals.txt
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A file has three 12-byte records with scores 10, 20, and 30. In "a+b" mode, a program seeks to byte 12, reads one record, changes its score to 25, seeks back to byte 12, and writes the record. All calls succeed. What scores do the second and last records hold afterward?
  1. Second: 20; last: 25; four records total.
  2. Second: 25; last: 30; three records total.
  3. Second: 25; last: 25; four records total.
  4. Second: 20; last: 30; three records total.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

Whole-integer records may contain at most seven content characters. With char buf[8], reads return "8642kg\n", then "1234567"; the next checked read confirms ordinary EOF. strtol finds 8642 with trailing kg in the first record and converts all digits in the second, with no range errors. Which records are valid?
  1. Accept both complete numeric prefixes.
  2. Reject both as too long for the buffer.
  3. Reject the first; accept the second.
  4. Accept only the first, which ends in LF.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A replacement is fully written and closed. Renaming the original to a backup succeeds; installing the replacement fails because its destination is now occupied. What action preserves the original without overwriting the new occupant?
  1. Delete the backup, retain the replacement, and return failure.
  2. Keep the backup and replacement, report failure, and resolve the name conflict before retrying.
  3. Rename the backup onto the occupied name without checking the result.
  4. Remove the occupied destination immediately, then retry installation.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

An error-free file contains "a\nb". A program uses int c; size_t n = 0, lines = 0; while (c = fgetc(in) != EOF) { ++n; if (c == '\n') ++lines; }. What totals result, and what correction makes it count lines correctly?
  1. n = 4, lines = 0; test feof before reading and count the final line.
  2. n = 3, lines = 1; fix assignment parentheses without handling the final line.
  3. n = 3, lines = 0; fix assignment parentheses and count the final unterminated line.
  4. n = 2, lines = 1; keep the condition and change c from int to char.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A size-1 read requests a required 12-byte header but gets 9 bytes. feof is set and ferror is clear. A successful fseek to the start follows. What remains true, and what must the parser do?
  1. EOF is clear; reject the incomplete header unless a full retry succeeds.
  2. EOF remains set; clear both flags and decode the nine bytes.
  3. The header became complete; decode it after checking feof again.
  4. The error flag is now set; report a new positioning failure.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

An input open fails and its errno is saved as open_error. Closing a previously opened output then fails and supplies a different code, saved as close_error. How should a diagnostic preserve both failures?
  1. Describe both operations with strerror(close_error); the latest code replaces earlier causes.
  2. Describe the open with perror after cleanup and suppress the close diagnostic as redundant.
  3. Describe the saved open error but return success if cleanup reached its final statement.
  4. Describe the open with strerror(open_error) and the close with strerror(close_error); return failure.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

fopen returns a valid stream, but errno still contains an earlier nonzero value. What does that value establish about this open?
  1. The stream must be closed as a failed open.
  2. It establishes no failure of this successful open.
  3. The next read is guaranteed to fail immediately.
  4. The file was opened with an incorrect access mode.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A copy acquired distinct input and output streams. Its input reports a read error; cleanup then closes output, which returns EOF. Input is still open, and the output is incomplete. What remaining actions and result protect the source and release resources?
  1. Retry closing output, close input once, remove incomplete output, preserve the source, and return failure.
  2. Close input once, remove incomplete output, preserve the source, and return success if cleanup succeeds.
  3. Clear the read error, close input once, keep both files, and return success if the last close succeeds.
  4. Close input once, attempt checked removal of incomplete output, preserve the source, and return failure.
Show answerHide answer

Save this lesson to see this answer.

Stuck on your own question? Homework Help

Key Terms

61 Key Terms, each with its definition

A

Append mode
Append mode is access that forces each output operation to the current end of the file, regardless of earlier seeks.
Seeking to byte zero in an "a+b" stream can select input but cannot redirect the next write.
Assignment count
An assignment count is the number of destination values a formatted input call successfully stores.
A two-field fscanf record is complete only when the returned assignment count is 2.

B

Big-endian order
Big-endian order places the most significant byte of a multi-byte value first in the byte sequence.
The value 258 appears as 00 00 01 02 in a big-endian 32-bit field.
Binary mode
Binary mode is stream access that preserves byte values without the character translations used for text.
Open an image with "rb" so text translation cannot change its compressed bytes.
Block copy
A block copy transfers a file through a reusable buffer, writing only the bytes supplied by each successful read.
A short final read must produce a short final write so no leftover buffer data is added.
Buffering
Buffering is the temporary collection of data in memory so that many small I/O requests can share larger transfers.
A report may remain in the output buffer until the stream is flushed or closed.
Byte order
Byte order, or endianness, is the order in which the bytes of a multi-byte value are arranged in memory or a file.
A file format specifies its byte order independently of the machine reading it.

C

Cleanup path
A cleanup path is the control-flow route that releases resources acquired before success or failure was determined.
One label can close the opened streams after several different processing failures.
clearerr
clearerr clears both a stream’s end-of-file and error indicators without correcting the cause of any failure.
After resolving an input problem, a program may clear the indicators before a controlled retry.
CSV quoting
CSV quoting encloses text fields containing commas, quotation marks, or newlines and doubles internal quotation marks.
A city name containing a comma must stay one field when the record is read again.
Current working directory
The current working directory is the running program’s reference folder for resolving relative path names.
Starting a program in another folder changes the file named by "data/input.txt".

E

End pointer
An end pointer from strtol marks the first character after the numeric prefix that the conversion accepted.
For "86cm", the pointer reaches the c, allowing a whole-number field to reject the suffix.
End-of-file indicator
The end-of-file indicator records that a previous input operation encountered the end of the stream.
It is checked after reading; testing it first cannot predict whether the next byte exists.
EOF
EOF is a negative integer constant used by character-input functions when input ends or a read error occurs.
Keep the returned value in an int so a real byte is not mistaken for this marker.
ERANGE
ERANGE is the standard range-error code used when a conversion or calculation produces a value outside its supported range.
Clear errno before strtol so an old range error cannot be mistaken for a new one.
errno
errno is a modifiable integer error-code expression whose meaning depends on a function’s documented error behavior.
Save its value immediately after a reported failure, before another library call can change it.
Error indicator
The error indicator records a stream read or write failure and remains set until explicitly cleared.
After fgets returns NULL, ferror can distinguish failed access from ordinary completion.
Exclusive creation
Exclusive creation is opening a new file only if its name does not already identify an existing file.
The C11 mode "wx" protects an existing report from being erased by the open.
Exit status
An exit status is the result a program returns to its environment so scripts can distinguish successful and failed execution.
A dependent command after && must not run after an incomplete file copy.

F

fclose
fclose is the function that flushes pending output, closes a stream, and reports success with 0 or failure with EOF.
After fclose(fp) returns, even with an error, that stream cannot be used again.
fgetc
fgetc is the function that reads a character as an unsigned-character value converted to int, or returns EOF.
A loop counts a separator only after fgetc has returned a character successfully.
fgets
fgets reads a bounded sequence of characters, keeps an encountered newline, and adds a null terminator on success.
A line longer than a 32-byte buffer is returned over several successful reads.
Field width
A field width controls a minimum output width or a maximum input width, depending on the formatted I/O function.
Input %23s leaves space for a terminator in a 24-byte character array.
FILE pointer
A FILE pointer is a value of type FILE * that gives library functions access to a stream and its stored state.
Pass fp to fgetc after checking that the open returned a valid stream pointer.
File position
A file position is the location in a stream where the next read or write begins, when that stream supports positioning.
Reading one 24-byte binary record advances the position past all 24 of its bytes.
File signature
A file signature is a defined sequence of initial bytes that helps a reader identify a file format or version.
The JPEG start marker helps locate image candidates before the remaining structure is checked.
Fixed-width integer type
A fixed-width integer type has an exact specified bit width where available, without choosing an external byte order.
A uint32_t field still needs explicit byte encoding to make an interchange file portable.
fopen
fopen is the standard-library function that opens a named file in a selected mode and returns a stream pointer or NULL.
A failed read open leaves no valid stream for a later fgetc or fclose call.
Format specification
A format specification is a percent-led instruction that selects how formatted I/O prints or converts a value.
Input %lf requires a double *, while %f requires a float * destination.
fpos_t
fpos_t is the opaque type used by fgetpos and fsetpos to save and restore all required file-position information.
A saved token is restored through the library functions, with no arithmetic on its value.
fputc
fputc is the function that writes one character to a stream and returns that character value or EOF on failure.
An uppercase filter checks each fputc after transforming the character it read.
fread
fread transfers input bytes into memory and returns the number of complete elements obtained for the requested size and count.
A short record read must be checked before any fields of the record are interpreted.
fseek
fseek requests a new file position relative to the start, current position, or end, returning nonzero on failure.
A program checks the seek before reading the record expected at the requested offset.
ftell
ftell reports a stream’s position as a long, returning -1L on failure; a text position must be treated as a saved location.
A binary record reader can check its position after consuming a complete fixed-size record.
fwrite
fwrite transfers object bytes from memory to a stream and returns the number of complete elements written.
Writing an array requires its data address, element size, and intended element count.

H

Header
A header is an initial part of a file containing identifying and structural fields needed to interpret the following data.
Check the complete signature and count before trusting the records named by a header.

I

In-place update
An in-place update replaces data within its existing file space without shifting or rewriting following records.
A changed fixed-size record must be written back at its original starting position.

L

Line parsing
Line parsing is interpreting the fields of a complete input line after that line has been read into memory.
A bad quantity can be reported with its line number before reading the next record.
Little-endian order
Little-endian order places the least significant byte of a multi-byte value first in the byte sequence.
The four bytes 02 01 00 00 represent 258 in a little-endian 32-bit field.

M

Matching failure
A matching failure occurs when input characters do not fit a requested formatted conversion, without requiring an I/O error.
Reading an integer from "oak" can return 0 while the stream’s end-of-file and error indicators remain clear.

N

Null terminator
A null terminator is the zero-valued character that marks the end of a C string without counting as its visible text.
A buffer needs one extra byte beyond the characters that fgets is allowed to read.

O

Opening mode
An opening mode is a string that tells fopen which access is allowed and whether existing contents are kept or erased.
Choosing "a" preserves earlier log entries and places each new write at the end.

P

Partial element
A partial element is an incomplete object-sized unit obtained by a read and omitted from fread’s complete-element count.
With record-sized input, remaining bytes at the end cannot be treated as a valid record.
perror
perror writes a label and the message for the current errno value to standard error, followed by a newline.
A label naming the file makes a missing-file diagnostic more useful than an unlabeled message.
Pipe
A pipe connects one program’s standard output to another program’s standard input as a flow of data.
A generator can feed a sorter directly without first saving an intermediate file.
Pushback
Pushback is returning a character to an input stream so that the next read retrieves it again.
A parser can inspect a separator and use ungetc to leave it for the next stage.

R

Random access
Random access is moving directly to a chosen location in a seekable file without reading all preceding data.
A header and fixed record width let a program calculate where a selected record starts.
Recoverable replacement
A recoverable replacement keeps an existing file available until a completed new version has been installed successfully.
If the rename that installs the new version fails, preserve the backup and report its location for restoration.
Redirection
Redirection is a shell operation that connects a program’s standard streams to files without changing its I/O code.
The operator 2> can save a program’s diagnostic messages in a separate file.
rename
rename changes a file’s name and returns 0 on success; handling an existing destination depends on the implementation.
Keep a backup available if installing a completed replacement under the original name fails.
Resource ownership
Resource ownership identifies which part of a program is responsible for releasing a stream or other acquired resource.
A helper closes a stream it opened while leaving a borrowed stream for its caller.

S

snprintf
snprintf formats text into a bounded array and returns the full required length, excluding the terminator, or a negative error.
A return equal to the capacity already indicates that the complete text did not fit.
Standard error
Standard error is the already-open stream stderr used for diagnostics independently of a program’s normal result stream.
A failed conversion can be described on stderr while valid data goes to stdout.
Standard input
Standard input is the already-open stream stdin from which a program normally receives its primary input.
With < values.txt, a filter reads file data through stdin instead of the keyboard.
Standard output
Standard output is the already-open stream stdout used for a program’s normal results and other primary output.
A shell pipe sends a converter’s stdout into another program’s standard input.
strcspn
strcspn finds the initial string length before any character in a supplied reject set, or the full length if none occurs.
Using "\r\n" as the reject set locates an ending without deleting ordinary final data.
Stream
A stream is a standard-library channel that connects a program to a sequence of input or output characters.
A reader can process a disk file or terminal input through the same stream interface.
strerror
strerror returns library-owned message text for a supplied error code, allowing a program to compose its own diagnostic.
Use a saved code when cleanup might have replaced the current value of errno.
Struct padding
Struct padding consists of extra bytes a compiler may insert between members or after the last member for alignment.
A char followed by an int can occupy eight bytes even when their sizes add to five.

T

Text mode
Text mode is stream access for readable lines in which the library can translate characters to match system conventions.
On Windows, text output changes a program’s newline into the stored CR LF sequence.

U

Update stream
An update stream is a stream opened with a + mode so that both input and output are permitted under switching rules.
Opening an existing binary record file with "r+b" preserves it for read-and-write access.

About this lesson

By StudeliReport a mistake

Make your own Study Materials

Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.

Get Started