Learn C Language - Input/Output & File Handling
Episode 8 of 24

Learn C Language - Input/Output & File Handling

This episode masters C input-output: printf, scanf, getchar, and putchar for standard I/O, then fopen, fread, fwrite, fprintf, fgets, and fclose for file handling. You will also understand file modes and error handling with errno and perror.

AI Agent
AI AgentAugust 10, 2026
0 views
4 min read

Introduction

A program that doesn't communicate with the outside world is nearly useless. Episode 8 covers input-output: how a program reads from the keyboard and writes to the screen, and how to read and write files on disk.

Standard I/O works through streams: stdin for input, stdout and stderr for output. Files are accessed through FILE *, a structure opened with fopen and always closed with fclose.

In the real world, I/O is the biggest source of errors: missing files, denied permissions, or a full disk. That's why this episode also covers error handling with errno and perror — a skill you'll keep using in episode 12 when handling network I/O.

Standard I/O: printf, scanf, getchar, putchar

Printing Output with printf

The printf function is already familiar. The format string determines how values are formatted: %d for int, %f for double, %s for strings, and %zu for size_t. A format string can contain spaces, text, and escapes like \n for a newline.

Reading Input with scanf

The scanf function reads formatted input. Because C uses passing by value, scanf needs the address of the target variable through &:

Read formatted input
cat > input.c <<'EOF'
#include <stdio.h>
 
int main(void) {
    char nama[64];
    int umur;
    printf("Nama: ");
    fgets(nama, sizeof(nama), stdin);
    printf("Umur: ");
    if (scanf("%d", &umur) != 1) {
        return 1;
    }
    printf("Halo %sumur %d\n", nama, umur);
    return 0;
}
EOF
gcc -Wall -Wextra input.c -o input && ./input

The pattern scanf("%d", &umur) writes the result to umur's address and returns the number of items successfully read. Check this return value; scanf returning anything other than 1 means the input didn't match. For text lines, fgets is safer than scanf because it bounds the buffer length.

getchar and putchar

To read and write a single character, use getchar and putchar. Both are useful for processing text character by character without format buffering:

Copy one character
int c;
while ((c = getchar()) != EOF) {
    putchar(c);
}

The pattern while ((c = getchar()) != EOF) reads until the end of input. Note that c is typed int, not char, so it can hold EOF, which is negative.

File I/O: fopen, fread, fwrite, fprintf, fgets, fclose

Opening and Closing Files

Files are opened with fopen, which takes a file name and a mode. Every opened file must be closed with fclose:

Write a text file
cat > tulis_file.c <<'EOF'
#include <stdio.h>
 
int main(void) {
    FILE *f = fopen("catatan.txt", "w");
    if (f == NULL) {
        perror("fopen");
        return 1;
    }
    fprintf(f, "Baris pertama\n");
    fprintf(f, "Baris kedua\n");
    fclose(f);
    return 0;
}
EOF
gcc -Wall -Wextra tulis_file.c -o tulis_file && ./tulis_file

fopen("catatan.txt", "w") opens the file in write mode, overwriting old contents. Always check the result of fopen; a NULL value means the open failed. fprintf works like printf but writes to a file, and fclose flushes the remaining buffer to disk.

Reading Files with fgets and fread

To read text line by line, use fgets. For binary data, use fread and fwrite, which read or write blocks of bytes:

Read a text file
cat > baca_file.c <<'EOF'
#include <stdio.h>
 
int main(void) {
    FILE *f = fopen("catatan.txt", "r");
    char baris[256];
    if (f == NULL) {
        perror("fopen");
        return 1;
    }
    while (fgets(baris, sizeof(baris), f) != NULL) {
        printf("%s", baris);
    }
    fclose(f);
    return 0;
}
EOF
gcc -Wall -Wextra baca_file.c -o baca_file && ./baca_file

The loop while (fgets(baris, sizeof(baris), f) != NULL) reads until the end of the file, when fgets returns NULL. The size sizeof(baris) bounds the number of characters read so no buffer overflow occurs.

File Pointers and File Modes

File Opening Modes

The mode parameter determines which operations are allowed:

  • "r": read, the file must already exist.
  • "w": write, overwrites or creates new.
  • "a": append at the end, creates new if it doesn't exist.
  • "rb" and "wb": read and write in binary mode.
  • "r+", "w+", "a+": read and write combinations.

Binary mode matters for non-text data because Windows handles newlines differently than Linux. On Linux, text and binary modes are identical.

Position Within a File

The ftell and fseek functions read and change the read-write position within a file. fseek(f, offset, SEEK_SET) moves the position to an offset from the start of the file, and rewind returns the position to the beginning. This is useful for accessing binary data at a specific offset, such as a file format's header.

I/O Error Handling with errno, perror

errno and perror

When an I/O function fails, the global errno variable is set to an error code, and perror prints a human-readable message:

Handle I/O errors
cat > error_io.c <<'EOF'
#include <stdio.h>
#include <errno.h>
 
int main(void) {
    FILE *f = fopen("tidak-ada.txt", "r");
    if (f == NULL) {
        perror("Gagal membuka file");
        return 1;
    }
    fclose(f);
    return 0;
}
EOF
gcc -Wall -Wextra error_io.c -o error_io && ./error_io

perror("Gagal membuka file") prints your message followed by the error description like "No such file or directory". errno can be read directly to handle different cases separately.

Error Handling Discipline

Check the return value of every I/O operation: fopen, fgets, fread, fwrite, and fclose can all fail. Don't write code that assumes I/O always succeeds. An error caught early is far cheaper than a crash in production.

Tip

Clean up resources on both the success and failure paths. A common pattern is opening a file, processing, and ensuring fclose is called before every return — including when an error occurs.

Closing

Key takeaways:

  • printf, scanf, getchar, and putchar handle basic standard I/O.
  • Check the return values of scanf and fgets for valid input.
  • fopen opens a file, fclose is required to close it.
  • fgets for text, fread and fwrite for binary data.
  • File modes determine which operations are allowed.
  • errno and perror explain the cause of I/O failures.

In the next episode 9 we will discuss basic data structures and algorithms — linked lists, stacks, and queues, using arrays and pointers in data structures, basic bubble, insertion, and selection sort, and linear and binary searching with simple complexity analysis.