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 \nresets the column counter;\tand 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).emitchecks 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;
\ooois always exactly 3 digits, making it unambiguous. Hex\xhhis variable-length in some contexts. Either is fine — switch\\%03oto\\x%02xfor hex output. \\escaping — without doubling backslashes,\012is 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
colcounter and flushing with\nis 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
emithelper prevents partial tokens from straddling a fold point isprintvsisgraph—isprintincludes space;isgraphexcludes it; for "printable in a sensible way" we wantisprintso 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