C
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Arrays and Strings
-
Section 5: Pointers
-
Section 6: Memory Management
-
Section 7: Structures and Unions
-
Section 8: The Preprocessor and Build Process
-
Section 9: Standard Library: stdio.h
-
Section 10: Standard Library: stdlib.h
-
Section 11: Standard Library: string.h
-
Section 12: Standard Library: ctype.h and wctype.h
-
Section 13: Standard Library: math.h, complex.h, fenv.h, tgmath.h
-
Section 14: Standard Library: Type and Limit Headers
-
Section 15: Standard Library: Error Handling and Debugging
-
Section 16: Standard Library: Localization and Encoding
-
Section 17: Standard Library: time.h
-
Section 18: Standard Library: Concurrency (C11)
-
Section 19: POSIX and System Programming (unistd.h)
-
Section 20: More Data Structures
-
Section 21: Algorithms in C
-
Section 22: Bitwise Operations
-
Section 23: Command-Line Programs
-
Section 24: Debugging and Best Practices
-
Section 25: Compiler and Language Internals
-
Section 26: Embedded and Cross-Platform Considerations
-
Section 27: Networking Basics
-
Section 28: Practical Projects
-
Section 29: Interview Practice
-
Section 30: C23 Modern Features
-
Section 31: More Practice and Review
219: Building a Basic File Compression Tool (RLE)
Run-Length Encoding (RLE) is one of the simplest forms of data compression. It doesn't use complex math or dictionaries; it just looks for sequences of the same data value and replaces them with a single value and a count. If you have a file that looks like AAAAABBBCC, RLE turns it into 5A3B2C. It's not great for a standard English novel, but for simple images or files with lots of repeated padding, it's surprisingly effective.
Designing the Encoding Loop
I want to create a tool that reads a source file and writes a compressed version to a destination file. My general plan is to keep a counter, iterate through the file, and every time the next character differs from the current one, I'll write the count and the character to the output. I'm keeping this simple: I'll assume the input is basic ASCII text.
#include <stdio.h>
#include <stdlib.h>
void compress_file(FILE *src, FILE *dest) {
int current = fgetc(src);
if (current == EOF) return;
int count = 1;
int next;
while ((next = fgetc(src)) != EOF) {
if (next == current) {
count++;
} else {
fprintf(dest, "%d%c", count, current);
current = next;
count = 1;
}
}
// I'll handle the final sequence here...
}
The "Last Run" Trap
Here is where I usually trip up when I'm rushing. I wrote the loop above, tested it on a file that ended with AAA, and noticed the output was missing the last three characters entirely. Why? Because the fprintf only triggers when the character changes. When the loop hits EOF, it exits immediately, leaving that final count and character sitting in memory without ever writing them to the disk.
It's a classic "off-by-one" logic error. To fix this, I just need to call the print function one last time after the while loop finishes to flush out whatever was being tracked.
// ... inside compress_file, after the while loop ...
fprintf(dest, "%d%c", count, current);
}
Wiring Up the File Handles
Now I need a main function to handle the actual file opening and closing. I'm using fopen with "rb" and "wb" because treating files as binary is generally a safer habit in C, even for text, as it prevents the runtime from messing with newline translations on Windows.
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage: %s input.txt output.rle\n", argv[0]);
return 1;
}
FILE *src = fopen(argv[1], "rb");
if (!src) {
perror("Error opening source file");
return 1;
}
FILE *dest = fopen(argv[2], "wb");
if (!dest) {
perror("Error opening destination file");
fclose(src);
return 1;
}
compress_file(src, dest);
fclose(src);
fclose(dest);
printf("Compression complete.\n");
return 0;
}
One thing to keep in mind: this specific implementation has a flaw. If your input file contains numbers (like 11122), the output (3122) becomes ambiguous. In a production tool, I'd use a non-numeric delimiter or a fixed-width binary header for the count, but for learning the logic of RLE, this approach is the clearest way to see the algorithm in action.
📋 Practical Task
Build the RLE Decompression Tool
You've now seen how to compress a file using Run-Length Encoding. Now, you need to write the inverse. Create a program called decompress.c that reads an RLE-compressed file (e.g., 5A3B2C) and expands it back to its original form (AAAAABBBCC).
Requirements:
- The program should take two command-line arguments: the compressed input file and the decompressed output file.
- Use
fscanforfgetcto read the count (integer) and the character. - Use a loop to write the character to the output file the specified number of times.
- Ensure you handle file errors (e.g., file not found) gracefully.
There are no comments for now.