125

So I'm finally reading through K&R, and I learned something within the first few pages, that there is a backspace escape character, \b.

So I go to test it out, and there is some very odd behavior:

#include <stdio.h>

main ()
{
    printf("hello worl\b\bd\n");
}

The output is

hello wodl

Can anyone explain this?

poke
  • 369,085
  • 72
  • 557
  • 602
OregonTrail
  • 8,594
  • 7
  • 43
  • 58

5 Answers5

179

Your result will vary depending on what kind of terminal or console program you're on, but yes, on most \b is a nondestructive backspace. It moves the cursor backward, but doesn't erase what's there.

So for the hello worl part, the code outputs

hello worl
          ^

...(where ^ shows where the cursor is) Then it outputs two \b characters which moves the cursor backward two places without erasing (on your terminal):

hello worl
        ^

Note the cursor is now on the r. Then it outputs d, which overwrites the r and gives us:

hello wodl
         ^

Finally, it outputs \n, which is a non-destructive newline (again, on most terminals, including apparently yours), so the l is left unchanged and the cursor is moved to the beginning of the next line.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 2
    If it doesn't erase then why is the "r" gone? – cesoid May 18 '16 at 14:04
  • 1
    @cesoid: *"Your result will vary depending on what kind of terminal or console program you're on"* – T.J. Crowder May 18 '16 at 14:06
  • It's just that your example doesn't fit the output, so it isn't an example of a possible explanation. – cesoid May 18 '16 at 14:11
  • 9
    @cesoid The `r` is replaced with `d`. The explanation still fits. – syockit Jun 10 '16 at 01:21
  • 1
    @syockit Thanks. I didn't realize the cursor was "on" the character. I'm always thinking of word processors where they show it "between" characters (or terminal windows where it always inserts rather than overwrites). The edited explanation makes this clear. – cesoid Jun 10 '16 at 14:21
  • 1
    @cesoid: Interesting about the terminal. In Windows, the `cmd.exe` and `command.com` terminals don't always insert (you can use the Ins key to toggle the behavior). I was surprised to find that Gnome Terminal on my main \*nix computer always inserts, doesn't even seem to have a preference for it much less toggle based on the Ins key. Never noticed that before. Clearly I almost never want typeover. :-) – T.J. Crowder Jun 10 '16 at 14:25
130
..........
^ <= pointer to "print head"
            /* part1 */
            printf("hello worl");
hello worl
          ^ <= pointer to "print head"
            /* part2 */
            printf("\b");
hello worl
         ^ <= pointer to "print head"
            /* part3 */
            printf("\b");
hello worl
        ^ <= pointer to "print head"
            /* part4 */
            printf("d\n");
hello wodl

^ <= pointer to "print head" on the next line
pmg
  • 106,608
  • 13
  • 126
  • 198
  • If the cursor after part 4 is at the 'l' letter, shouldn't it be replaced by the '\n'? (resulting in "hello wor") – lucas_turci Sep 06 '16 at 13:31
  • 1
    @lucas_turci: the thing is that the `'\n'` does not have a representation on screen. What is already there stays the same; not replaced by a space or any other character representation. – pmg Sep 06 '16 at 13:47
50

If you want a destructive backspace, you'll need something like

"\b \b"

i.e. a backspace, a space, and another backspace.

Peter K.
  • 8,028
  • 4
  • 48
  • 73
  • This still leaves the space character there isn't it? – Pacerier May 14 '14 at 20:54
  • Well, yes, but the subsequent `\b` will mean the next output character will overwrite it. – Peter K. May 15 '14 at 01:53
  • 1
    What if there is *no* subsequent character? – Pacerier May 18 '14 at 17:00
  • Then it doesn't matter, does it? – Peter K. May 18 '14 at 21:48
  • It doesn't matter if it's simply "display to screen". But what if there's a device that *reads* in your character display? Then there would be one extra character. How do we remove the last character? – Pacerier May 19 '14 at 15:54
  • 4
    Hmm. Unless your device implements a "delete last character" option (e.g. DEL / `0x7f`) , I'm stumped. – Peter K. May 19 '14 at 16:49
  • You can delete a character with a backspace and by printing the ascii character `0x7f`, like so: `printf("\b%c\b", 0x7f)`. But that doesn't always work for me. It depends on the terminal. Sometimes, the terminal outputs a funny character. – mgarey Jan 19 '17 at 02:01
  • @RestlessC0bra : files are a whole other level of pain. See [this question and the answers there](http://stackoverflow.com/q/17013067/12570). – Peter K. Mar 29 '17 at 00:39
8

Not too hard to explain... This is like typing hello worl, hitting the left-arrow key twice, typing d, and hitting the down-arrow key.

At least, that is how I infer your terminal is interpeting the \b and \n codes.

Redirect the output to a file and I bet you get something else entirely. Although you may have to look at the file's bytes to see the difference.

[edit]

To elaborate a bit, this printf emits a sequence of bytes: hello worl^H^Hd^J, where ^H is ASCII character #8 and ^J is ASCII character #10. What you see on your screen depends on how your terminal interprets those control codes.

Nemo
  • 70,042
  • 10
  • 116
  • 153
2

Use a single backspace after each character printf("hello wor\bl\bd\n");

John Conde
  • 217,595
  • 99
  • 455
  • 496
Dorothea
  • 37
  • 1