K&R C Exercise 1-2: Escape Sequences in printf

Exercise 1-2. Experiment to find out what happens when printf‘s argument string contains \c, where c is some character not listed above.

The escape sequences K&R lists in section 1.5 are: \n (newline), \t (tab), \b (backspace), \" (double quote), and \\ (backslash). The exercise asks what happens with everything else.

Approach

The key insight is that printf never sees the escape sequences — the compiler resolves them into raw byte values when it compiles the string literal. By the time your program runs, \n is already byte 0x0A in memory. This means the answer to “what happens with \c?” is really a question about your compiler, not about printf at all.

Three categories of \c sequences exist in ANSI C, beyond the five K&R mentions:

  1. Defined in C but not listed in K&R section 1.5. The C standard specifies \a (alert/bell), \f (form feed), \r (carriage return), \v (vertical tab), \0 (null), and \? (question mark). These work reliably on every conforming C compiler.
  2. Numeric escapes. Octal (\101) and hexadecimal (\x41) let you encode any byte value directly. These are part of ANSI C89.
  3. Undefined sequences. Anything else — \c, \g, \j, \y, and so on — is undefined behaviour in C89/ANSI C. The standard makes no guarantee. In practice, GCC warns and emits the character after the backslash, but you cannot rely on that.

Solution

/* Exercise 1-2: Experiment with printf escape sequences               */
/* Compile: gcc -ansi -Wall ex1-2.c -o ex1-2                          */

#include <stdio.h>

int main(void)
{
    /* === Defined in C but absent from K&R's section 1.5 list === */

    /* \a : alert (bell) -- byte value 7; may produce a beep       */
    printf("\\a alert:          [\\a = \a] <-- listen for a beep\n");

    /* \f : form feed -- byte value 12; advances page on printers  */
    printf("\\f form feed:      [\\f = \f]\n");

    /* \r : carriage return -- byte value 13; moves cursor to col 0 */
    printf("\\r carriage ret:   [BEFORE\rAFTER ]\n");   /* AFTER overwrites BEFORE */

    /* \v : vertical tab -- byte value 11                           */
    printf("\\v vertical tab:   [\\v = \v]\n");

    /* \? : literal question mark (historically avoids trigraphs)   */
    printf("\\? question mark:  [\\? = \?]\n");

    /* \0 : null byte -- printf STOPS reading the format string here */
    printf("\\0 null truncates: [visible part\0 hidden part]\n");

    /* === Numeric escapes (ANSI C89) === */

    /* Octal: one to three octal digits after the backslash         */
    printf("\\101 (octal 65):   [\\101 = \101]\n");    /* 'A' */
    printf("\\012 (octal 10):   [\\012 = \012]\n");    /* newline */

    /* Hexadecimal: \x followed by hex digits (ANSI C89 addition)  */
    printf("\\x41 (hex 65):     [\\x41 = \x41]\n");    /* 'A' */

    /* === Undefined sequences -- ANSI C89: undefined behaviour ===  */
    /* gcc -ansi -Wall prints:                                        */
    /*   warning: unknown escape sequence: '\c'   (and so on)        */
    /* In practice gcc emits the bare character after the backslash. */
    printf("\\c (undefined):    [\\c = \c]\n");
    printf("\\g (undefined):    [\\g = \g]\n");
    printf("\\j (undefined):    [\\j = \j]\n");

    return 0;
}

Compile and Run

Always use -Wall here — it is the whole point of the exercise:

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

GCC will print warnings like these before it even produces a binary:

ex1-2.c:30:37: warning: unknown escape sequence: '\c' [-Wunknown-escape-sequence]
ex1-2.c:31:37: warning: unknown escape sequence: '\g' [-Wunknown-escape-sequence]
ex1-2.c:32:37: warning: unknown escape sequence: '\j' [-Wunknown-escape-sequence]

The defined sequences compile cleanly with no warnings.

Sample Output

Output varies by terminal, but on a typical Linux/macOS terminal you will see:

\a alert:          [\a = ] <-- listen for a beep
\f form feed:      [\f =
                         ]
AFTER ]
\v vertical tab:   [\v =
                        ]
\? question mark:  [\? = ?]
\0 null truncates: [visible part
\101 (octal 65):   [\101 = A]
\012 (octal 10):   [\012 =
]
\x41 (hex 65):     [\x41 = A]
\c (undefined):    [\c = c]
\g (undefined):    [\g = g]
\j (undefined):    [\j = j]

Notes on specific sequences:

Sequence Byte value Effect on terminal
\a 7 Bell/alert — may beep or flash the terminal
\f 12 Form feed — vertical spacing (printer-era)
\r 13 Cursor moves to column 0; next output overwrites the line
\v 11 Vertical tab — effect is terminal-dependent
\? 63 Identical to ?; included to avoid C trigraph parsing
\0 0 printf stops here — output is silently truncated
\101 65 Letter A (octal 101 = decimal 65)
\x41 65 Letter A (hex 41 = decimal 65)
\c, \g, \j undefined GCC warns; typically emits c, g, j — but not guaranteed

What This Exercise Teaches

  • Escape sequences are a compiler feature, not a runtime one. The compiler turns \n into byte 0x0A at compile time. By the time printf runs, there are no backslashes left in the string — only bytes.
  • C defines more escape sequences than K&R’s introductory list. K&R section 1.5 shows only the most common five. ANSI C89 standardises seven more: \a, \f, \r, \v, \0, \', and \?, plus octal and hex numeric escapes.
  • The null byte terminates C strings. \0 embedded in a format string silently cuts off everything after it. This is a source of subtle bugs when string data is constructed carelessly.
  • -Wall catches undefined behaviour at compile time. The undefined \c sequences produce no error by default — the program compiles and runs quietly. Only -Wall reveals the problem. This is why building with warnings enabled is non-negotiable.
  • C89 vs C99 treatment of unknown escapes. In C89, an unrecognised \c is undefined behaviour (the compiler may do anything). In C99 and later it became a constraint violation requiring a diagnostic. If you compile with -std=c99 or higher, GCC treats it as an error.

Set Up Your C Environment

This is a Chapter 1 exercise — if you are just getting started with C, you will need GCC installed and a good editor. Here are the quick-start guides:

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