Laboratory 11

Laboratory 11 โ€“ Text Files, Command-line Arguments and Line Endings

This laboratory introduces text-file processing in C. You will open files, display and copy their contents, count lines, words and characters, detect line-ending styles, and start using command-line arguments for practical file-processing programs.

FILE * fopen fgetc fgets argc / argv line endings

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.

Main idea of this lab:
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 fopen and fclose,
  • read a file character by character using fgetc,
  • read a file line by line using fgets,
  • write text to another file using fputc or fputs,
  • use argc and argv to 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
File numbering convention: Laboratory 10 ended with the assessed task group ex36. This laboratory continues the numbering with ex37โ€“ex41. The optional extra task uses ex42.

Task 0 โ€” Reminder and preparation

Shown. Log in to the AGH server and prepare the working directory.

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
Always check whether fopen returned NULL. If a file cannot be opened, print an error message and stop the program safely.

Task 1 โ€” Display a text file

Implement yourself. Open a file passed as a command-line argument and print its content.

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

Implement yourself. Create a program that copies one text file into another.

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);
}
If opening the output file fails, remember to close the input file before returning.

Task 3 โ€” Count lines in a file

Implement yourself. Count how many text lines are stored 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.

This exercise prepares the function that will later be used to allocate memory for an array of lines.

Task 4 โ€” Mini wc: lines, words and characters

Implement yourself. Add simple command-line options similar to the UNIX wc tool.

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 optionprint lines, words and characters
-lprint only the number of lines
-wprint only the number of words
-cprint 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

Implement yourself. Detect whether a text file uses UNIX, Windows, old Mac or mixed line endings.

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.

This task is only about detection. Conversion between formats will be useful later, but for this laboratory detection is enough.

Extra Task โ€” Remove comments from a C source file

Optional. This task is more difficult and can be treated as an extra-credit exercise.

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
Not every /* 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.c displays the content of a file,
  • ex38_copy_file.c copies one file to another,
  • ex39_count_lines.c counts lines correctly, including the last line without newline,
  • ex40_wc.c supports -l, -w, and -c,
  • ex41_line_endings.c detects 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.c removes comments from C source files.