Skip to Content
Course content

80: Character I/O: getchar, putchar, fgetc, fputc

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're standing at a conveyor belt in a factory. Instead of whole boxes arriving at once, the belt delivers a single, tiny bead every second. You have one job: pick up a bead, look at its color, and if it's the right color, drop it into a collection jar. You aren't dealing with the whole shipment; you're dealing with the smallest possible unit of the product, one by one, in a loop.

In C, character I/O works exactly like that conveyor belt. Instead of reading an entire line of text or a whole file into a massive buffer, you process a single char, decide what to do with it, and then move to the next. Here is how that maps to the code:

  • The Conveyor Belt: This is your input stream (either stdin for the keyboard or a FILE pointer for a file).
  • Picking up a bead: This is getchar() or fgetc().
  • Dropping it in the jar: This is putchar() or fputc().
  • The belt stopping: This is the EOF (End Of File) marker.

The Basics: getchar and putchar

When you're just interacting with the terminal, getchar() and putchar() are your best friends. They are lean and fast. Let's say you want to write a program that "censors" the letter 'e' from anything the user types. You wouldn't need a huge array to store the string; you just process the characters as they fly by.

#include <stdio.h>

int main() {
    int c; // Note: I'm using int, not char. I'll explain why in a second.

    printf("Type something (Ctrl+D to stop):\n");

    while ((c = getchar()) != EOF) {
        if (c == 'e' || c == 'E') {
            putchar('*');
        } else {
            putchar(c);
        }
    }
    return 0;
}

The EOF Trap and why we use int

You might have noticed I declared c as an int, even though we're dealing with characters. This is a classic spot where new C programmers trip up. I've seen it a hundred times.

Here is the deal: getchar() needs to return every possible character value (0 to 255), but it also needs a way to tell you, "Hey, the stream is empty!" To do this, it returns a special value called EOF, which is typically defined as -1. If you store the result in a char, you might not be able to distinguish between the actual character with the value 255 and the EOF signal. Using an int gives us enough room to hold all character values plus the distinct EOF value.

Moving to Files with fgetc and fputc

Now, getchar() and putchar() are actually just "shortcuts." getchar() is essentially fgetc(stdin), and putchar(c) is just fputc(c, stdout). When you want to move away from the keyboard and start reading from an actual file on your hard drive, you use the f versions.

The f stands for "file" (or more accurately, "stream"). These functions require a FILE * pointer so the program knows which conveyor belt to watch.

#include <stdio.h>

int main() {
    FILE *inputFile = fopen("input.txt", "r");
    FILE *outputFile = fopen("output.txt", "w");

    if (inputFile == NULL || outputFile == NULL) {
        perror("File error");
        return 1;
    }

    int c;
    while ((c = fgetc(inputFile)) != EOF) {
        // Convert everything to uppercase on the fly
        if (c >= 'a' && c <= 'z') {
            c = c - 32; 
        }
        fputc(c, outputFile);
    }

    fclose(inputFile);
    fclose(outputFile);
    return 0;
}

I personally prefer this character-by-character approach when I'm writing parsers or simple filters. It keeps the memory footprint tiny because you only ever have one character in RAM at a time, regardless of whether the input file is ten bytes or ten gigabytes.




📋 Practical Task

Build a "Whitespace-to-Tab" Converter

Your task is to create a utility that reads from a file named raw_text.txt and writes to a file named cleaned_text.txt. The program should process the file character by character. Every time it encounters a space character ' ', it should instead write a tab character '\t' to the output file. All other characters should be copied exactly as they are.

Requirements:

  • Use fgetc to read and fputc to write.
  • Ensure you handle the EOF condition correctly using an int variable.
  • Properly close both file pointers before the program exits.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.