Exercise 1-18. Write a program to remove trailing blanks and tabs from each line of input, and delete entirely blank lines.
The challenge here is that you cannot know whether a blank or tab is “trailing” until you have seen everything that follows it on the same line. The solution splits the work into two functions: getline2 reads one line at a time (including its newline), and trim walks backward from the end of the line, skipping the newline and any spaces or tabs, then reinstates a single newline and null-terminator at the new end. If trim finds nothing but whitespace it returns 0, signalling main to discard the line entirely rather than printing an empty one.
Solution
/* Compile: gcc -ansi -Wall exercise1-18.c -o exercise1-18 */
#include <stdio.h>
#define MAXLINE 1000
int getline2(char line[], int maxline);
int trim(char line[]);
int main(void)
{
char line[MAXLINE];
int len;
while ((len = getline2(line, MAXLINE)) > 0) {
len = trim(line);
if (len > 0)
printf("%s", line);
}
return 0;
}
int getline2(char line[], int maxline)
{
int c, i;
for (i = 0; i < maxline - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
line[i] = c;
if (c == '\n')
line[i++] = '\n';
line[i] = '\0';
return i;
}
/* trim: remove trailing blanks and tabs; return new length (0 = blank line) */
int trim(char line[])
{
int i;
for (i = 0; line[i] != '\0'; ++i)
;
--i;
while (i >= 0 && (line[i] == '\n' || line[i] == ' ' || line[i] == '\t'))
--i;
if (i >= 0) {
line[i + 1] = '\n';
line[i + 2] = '\0';
return i + 2;
} else {
line[0] = '\0';
return 0;
}
}
How It Works
getline2 reads characters one at a time with getchar(), storing them in line[] up to maxline - 1 characters. If a newline is seen it is kept in the array (we need it so trim can detect it), and a null terminator is written after it.
trim first advances i to the null terminator, then steps back one (pointing at the last real character). It then decrements i for every trailing newline, space, or tab it finds. If any non-whitespace characters remain, it appends a fresh '\n' and '\0' and returns the new length. If the entire content was whitespace, it writes '\0' at position 0 and returns 0 — main treats a return value of 0 as “skip this line”.
Compile and Run
gcc -ansi -Wall exercise1-18.c -o exercise1-18
The program reads from standard input. Pipe text into it to see it strip trailing whitespace and drop blank lines:
printf "hello \t\nworld\n\n \nfoo \n" | ./exercise1-18
You can also run it interactively — type lines at the terminal and press Ctrl-D (EOF) when done.
Sample Output
Given this input (where · represents a space and → represents a tab):
hello···→ world ··· foo··
The program produces:
hello world foo
The trailing spaces and tab on line 1 are stripped. The all-whitespace line 3 is deleted entirely. Lines 2 and 4 are printed clean.
What This Exercise Teaches
- Backward scanning: trailing characters can only be identified by walking from the end of the string toward the front — a forward-only pass cannot tell whether a space is trailing until EOF or newline is seen.
- Separating concerns into functions: splitting input (getline2) from processing (trim) keeps each function simple and independently testable — a core C design habit.
- In-place string editing:
trimmodifies the array directly by placing a new null terminator, avoiding any extra memory allocation. - Using return value as a signal: returning 0 from
trimto mean “blank line” is a clean idiom — the caller does not need a separate flag variable.
Set Up Your C Environment
To compile and run this solution, you need GCC installed. If you haven’t set up C on your machine yet:
- Complete C Development Environment Setup — start here if you’re new
- Install GCC on Windows 11
- Install GCC on macOS
- Install GCC on Ubuntu/Linux
- VS Code for C Programming — recommended editor
← Exercise 1-17 |
Chapter 1 Solutions |
Exercise 1-19 →
Book:
The C Programming Language, 2nd Ed — Kernighan & Ritchie