K&R C Programs Exercise 7-2

Exercise 7-2. Write a program that will print arbitrary input in a sensible way. As a minimum it should print non-graphic characters in octal or hex (according to local custom), and fold long lines.

The rules:

  • Printable characters (isprint) pass through as-is
  • \n resets the column counter; \t and other non-printable characters are shown as \ooo (4 characters)
  • A backslash itself is printed as \\ to avoid ambiguity with the escape sequences
  • Lines are folded at column 70 — if adding the next token would exceed the limit, a newline is emitted first

Solution

/* K&R Exercise 7-2 — print arbitrary input: fold long lines, octal escapes
 * Compile: gcc -ansi -Wall ex7-2.c -o ex7-2
 * Usage:   ./ex7-2 < binary_or_text_file */
#include <stdio.h>
#include <ctype.h>

#define MAXCOL 70

static int col = 0;

static void emit(const char *s, int width)
{
    if (col + width > MAXCOL) {
        putchar('\n');
        col = 0;
    }
    fputs(s, stdout);
    col += width;
}

int main(void)
{
    int  c;
    char buf[8];

    while ((c = getchar()) != EOF) {
        if (c == '\n') {
            putchar('\n');
            col = 0;
        } else if (c == '\\') {
            emit("\\\\", 2);
        } else if (isprint(c)) {
            buf[0] = (char)c; buf[1] = '\0';
            emit(buf, 1);
        } else {
            /* non-graphic: print as \ooo */
            sprintf(buf, "\\%03o", (unsigned char)c);
            emit(buf, 4);
        }
    }
    if (col > 0)
        putchar('\n');   /* ensure final newline */
    return 0;
}

Compile and Test

gcc -ansi -Wall ex7-2.c -o ex7-2

# Print a file containing tabs and a backslash
printf "Hello\tWorld\npath\\to\\file\n" | ./ex7-2

# Print binary content (first 32 bytes of /bin/ls)
dd if=/bin/ls bs=1 count=32 2>/dev/null | ./ex7-2

Sample Output

Hello\011World
path\\to\\file

\177ELF\002\001\001\000\000\000\000\000\000\000\000\000\002\000>\000\001\000\000\000

\t (ASCII 9 = octal 011) becomes \011; backslashes are doubled; the ELF magic number 0x7f becomes \177.

Design Notes

  • Why emit()? Each output token has a known display width (1 for printable chars, 2 for \\, 4 for \ooo). emit checks whether the token fits on the current line before writing, keeping the fold logic in one place.
  • Why octal, not hex? K&R uses octal throughout; \ooo is always exactly 3 digits, making it unambiguous. Hex \xhh is variable-length in some contexts. Either is fine — switch \\%03o to \\x%02x for hex output.
  • \\ escaping — without doubling backslashes, \012 is ambiguous: is the backslash literal or the start of an escape? Printing \\ for every literal backslash makes the output unambiguous.

What This Exercise Teaches

  • Column tracking — keeping a col counter and flushing with \n is the standard technique for any output that must fit within a line width
  • Token-width-aware folding — folding must account for token width before writing, not after; the emit helper prevents partial tokens from straddling a fold point
  • isprint vs isgraphisprint includes space; isgraph excludes it; for "printable in a sensible way" we want isprint so spaces pass through unchanged

Set Up Your C Environment

← Exercise 7-1  | 
Chapter 7 Solutions  | 
Exercise 7-3 →

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>