K&R C Exercise 3-2: escape — Convert Special Characters to Escape Sequences

Exercise 3-2. Write a function escape(s,t) that converts characters like newline and tab into visible escape sequences like \n and \t as it copies the string t to s. Use a switch. Write a function for the other direction as well, converting escape sequences into the real characters.

Two functions walking their input strings character by character. escape converts control characters to two-character backslash notation using switch — the natural tool here since each character maps to a specific output pair. The output buffer must be sized at least twice the input length plus one, because every character could potentially expand to two. unescape reverses the process: on seeing a backslash it peeks at the next character to decide what control character to emit, consuming two input characters to produce one output character. Both functions must null-terminate the output string, and unescape‘s loop advance is non-uniform — always increment i, but only step by two when consuming a backslash sequence.

Solution

/* K&R Exercise 3-2 — escape and unescape
 * Compile: gcc -ansi -Wall ex3-2.c -o ex3-2 */
#include <stdio.h>

void escape(char s[], char t[])
{
    int i, j;
    j = 0;
    for (i = 0; t[i] != '\0'; ++i) {
        switch (t[i]) {
        case '\n':
            s[j++] = '\\';
            s[j++] = 'n';
            break;
        case '\t':
            s[j++] = '\\';
            s[j++] = 't';
            break;
        case '\\':
            s[j++] = '\\';
            s[j++] = '\\';
            break;
        default:
            s[j++] = t[i];
            break;
        }
    }
    s[j] = '\0';
}

void unescape(char s[], char t[])
{
    int i, j;
    i = j = 0;
    while (t[i] != '\0') {
        if (t[i] == '\\') {
            ++i;
            switch (t[i]) {
            case 'n':  s[j++] = '\n'; break;
            case 't':  s[j++] = '\t'; break;
            case '\\': s[j++] = '\\'; break;
            default:   s[j++] = '\\'; s[j++] = t[i]; break;
            }
        } else {
            s[j++] = t[i];
        }
        ++i;
    }
    s[j] = '\0';
}

int main(void)
{
    char original[] = "hello\tworld\nbye";
    char escaped[64];
    char restored[64];

    escape(escaped, original);
    printf("escaped:  [%s]\n", escaped);

    unescape(restored, escaped);
    printf("restored: [%s]\n", restored);
    return 0;
}

The default case in unescape handles unknown sequences like \q by passing them through unchanged — a safe choice since the input may come from text that was not produced by escape.

Compile and Run

gcc -ansi -Wall ex3-2.c -o ex3-2
./ex3-2

Sample Output

escaped:  [hello\tworld\nbye]
restored: [hello	world
bye]

The escaped string shows literal backslash-n and backslash-t. The restored string re-contains the actual tab character (visible as whitespace) and newline.

What This Exercise Teaches

  • switch for character dispatch — cleaner than a chain of if-else when mapping individual characters to specific outputs
  • Output buffer sizing — two-character output from one-character input means the output buffer needs to be at least 2× input length + 1
  • Round-trip inverse functionsescape and unescape should be each other’s exact complement; the restored string must match the original
  • Non-uniform loop advanceunescape consumes 2 input characters (backslash + letter) to produce 1 output character

Set Up Your C Environment

← Exercise 3-1  | 
Chapter 3 Solutions  | 
Exercise 3-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>