Laboratory Overview
What is new in this laboratory.
In the previous laboratories, most input came from the keyboard and most output was printed to the console. In this laboratory, you will start working with text files. This is the first step toward sorting files in the next laboratories.
console input โ file input โ command-line arguments โ reusable text processing
You will also learn why line endings differ between operating systems and how to detect them:
UNIX uses \\n, Windows uses \\r\\n, and older Mac systems used \\r.
Learning Outcomes
- open and close text files using
fopenandfclose, - read a file character by character using
fgetc, - read a file line by line using
fgets, - write text to another file using
fputcorfputs, - use
argcandargvto process command-line arguments, - count lines, words and characters in a file,
- detect UNIX, Windows and old Mac line endings,
- write readable file-processing programs without global variables,
- prepare for line-based file sorting in Laboratory 12.
How this laboratory prepares Lab 12
Before sorting text files, you need to know how to read and understand them.
| Laboratory 11 | Used later for |
|---|---|
| opening and reading text files | loading file contents for sorting |
| counting lines | allocating an array for file lines |
| command-line arguments | choosing input file and program options |
| line-ending detection | preserving or converting text-file format |
ex36.
This laboratory continues the numbering with ex37โex41.
The optional extra task uses ex42.
Task 0 โ Reminder and preparation
Step 1 โ Log in to the AGH UNIX server
ssh your_login@student.agh.edu.pl
Step 2 โ Go to the course directory
cd ~/I2PL
Step 3 โ Create the directory for Laboratory 11
mkdir lab11
cd lab11
Step 4 โ Prepare small test files
printf "one\ntwo\nthree\n" > unix.txt
printf "one\r\ntwo\r\nthree\r\n" > windows.txt
printf "one\rtwo\rthree\r" > oldmac.txt
fopen returned NULL. If a file cannot be opened,
print an error message and stop the program safely.
Task 1 โ Display a text file
Step 1 โ Create the file
nano ex37_display_file.c
Step 2 โ Required usage
./ex37_display_file file.txt
If the number of arguments is wrong, display:
Usage: ex37_display_file file
Step 3 โ Use argc and argv
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: ex37_display_file file\n");
return 1;
}
/* open argv[1] */
}
Step 4 โ Open the file
FILE *in = fopen(argv[1], "r");
if (in == NULL) {
perror(argv[1]);
return 1;
}
Step 5 โ Read character by character
int ch;
while ((ch = fgetc(in)) != EOF) {
putchar(ch);
}
fgetc returns int, not char, because it must also represent EOF.
Task 2 โ Copy a text file
Step 1 โ Create the file
nano ex38_copy_file.c
Step 2 โ Required usage
./ex38_copy_file input.txt output.txt
If the number of arguments is wrong, display:
Usage: ex38_copy_file input output
Step 3 โ Open input and output files
FILE *in = fopen(argv[1], "r");
FILE *out = fopen(argv[2], "w");
Step 4 โ Copy characters
int ch;
while ((ch = fgetc(in)) != EOF) {
fputc(ch, out);
}
Task 3 โ Count lines in a file
Step 1 โ Create the file
nano ex39_count_lines.c
Step 2 โ Required usage
./ex39_count_lines file.txt
Example output:
file: file.txt contains 23 lines.
Step 3 โ Decide how to count lines
A simple version counts '\n' characters. A more precise version also handles a file
whose last line does not end with a newline.
Hint: last line without newline
If the file is not empty and the last character is not '\n' or '\r',
then the last line should still be counted.
Task 4 โ Mini wc: lines, words and characters
Step 1 โ Create the file
nano ex40_wc.c
Step 2 โ Required usage
./ex40_wc file.txt
./ex40_wc -l file.txt
./ex40_wc -w file.txt
./ex40_wc -c file.txt
Invalid usage should display:
Usage: ex40_wc [-l | -w | -c] file
Step 3 โ Meaning of options
| Option | Meaning |
|---|---|
| no option | print lines, words and characters |
-l | print only the number of lines |
-w | print only the number of words |
-c | print only the number of characters |
Step 4 โ Count words
A simple word counter can track whether the current character is inside a word.
Use isspace from <ctype.h>.
#include <ctype.h>
Hint: word-counting state
Use an integer variable such as in_word. When a non-space character appears after
whitespace, a new word starts.
Task 5 โ Detect line-ending style
Step 1 โ Create the file
nano ex41_line_endings.c
Step 2 โ Required usage
./ex41_line_endings file.txt
Invalid usage should display:
Usage: ex41_line_endings file
Step 3 โ Detect three styles
| Style | Line ending |
|---|---|
| UNIX / Linux / modern macOS | \n |
| Windows / DOS | \r\n |
| Old Mac OS | \r |
Step 4 โ Suggested output
file.txt: UNIX
file.txt: WINDOWS
file.txt: OLD_MAC
file.txt: MIXED
file.txt: UNKNOWN
Hint: how to distinguish \r\n from \r
When you read '\r', look at the next character. If it is '\n',
count a Windows ending. Otherwise, count an old Mac ending and continue carefully.
Extra Task โ Remove comments from a C source file
Step 1 โ Create the file
nano ex42_strip_comments.c
Step 2 โ Required usage
./ex42_strip_comments input.c output.c
Invalid usage should display:
Usage: ex42_strip_comments input output
Step 3 โ Remove two kinds of comments
- C comments:
/* ... */ - C++ comments:
// ... end of line
/* or // sequence is a real comment.
For example, text inside string literals should not be treated as a comment.
Hint: use a small state machine
Track states such as: normal text, string literal, character literal, line comment, block comment and escape sequence. This is a good exercise in careful character-by-character processing.
Test Questions โ Review before the next class
Try to answer these questions before opening the answers.
1. Why should fgetc be stored in an int, not in a char?
Because fgetc must be able to return every possible character and also EOF.
EOF is not a normal character value.
2. What does argv[1] usually mean in these exercises?
It is usually the first argument passed by the user after the program name, for example the input file name.
3. Why must every successfully opened file be closed?
Closing the file releases system resources and ensures that buffered output is written correctly.
4. What is the difference between fgetc and fgets?
fgetc reads one character. fgets reads a line or part of a line into a buffer.
5. Why is line counting sometimes tricky?
A non-empty file may have a final line that does not end with a newline character. That line still has to be counted.
6. What line ending is used by Windows text files?
Windows text files usually use \r\n, called CRLF.
7. What is the main purpose of command-line arguments?
They let the user pass file names and options to the program without recompiling or editing the code.
Checklist before submission
ex37_display_file.cdisplays the content of a file,ex38_copy_file.ccopies one file to another,ex39_count_lines.ccounts lines correctly, including the last line without newline,ex40_wc.csupports-l,-w, and-c,ex41_line_endings.cdetects UNIX, Windows, old Mac, mixed or unknown style,- all programs validate their command-line arguments,
- all opened files are closed,
- no global variables are used,
- optional:
ex42_strip_comments.cremoves comments from C source files.