K&R C Exercise 1-18: Remove Trailing Blanks and Delete Blank Lines

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: trim modifies the array directly by placing a new null terminator, avoiding any extra memory allocation.
  • Using return value as a signal: returning 0 from trim to 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:

← Exercise 1-17  | 
Chapter 1 Solutions  | 
Exercise 1-19 →

Book:

The C Programming Language, 2nd Ed — Kernighan & Ritchie

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>