The "backspace" escape character '\b': unexpected behavior? - c

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?

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.

..........
^ <= 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

If you want a destructive backspace, you'll need something like
"\b \b"
i.e. a backspace, a space, and another backspace.

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.

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

Related

Adding something after \b in printf() to make it work [duplicate]

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?
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.
..........
^ <= 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
If you want a destructive backspace, you'll need something like
"\b \b"
i.e. a backspace, a space, and another backspace.
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.
Use a single backspace after each character
printf("hello wor\bl\bd\n");

why do we use \r and \b in C?

Why do we use \r and \b in C? I know that \b makes "hello\bworld" into "hellworld". but we can just write "hellworld" instead of "hello\bworld". So, what purpose does it serves in a program? This question describes what \b do , but doesn't clarify why it is used.
Its' to a large degree just historical reasons. Many characters can actually be traced back to analogue typewriters! In the past, you had computers with matrix printers instead of monitors. In those days, bold font was achieved by printing something twice in the same location.
For example, in Linux we use the character \n for a new line, but in Windows it is \r\n so what is those characters? Well \n (newline) is to move the head of the typewriter one line down and \r is the carriage return, which returns the typewriter carriage to the beginning of the line.
Many of these characters are not used very much anymore. They are mostly considered legacy. They are not really that useful in modern programming. You can use \b to go back and overwrite stuff that you have previously written, but today you would use libraries like ncurses to achieve the same thing. In the old days, you could actually use these to get pretty exact positioning of stuff, but on modern terminal emulators, that's no longer the case. For instance, old terminals had fixed sizes. The sizes may not have been standardized, but they did not change during runtime and were the same for the same machine every time you run a program.
I could consider using \b and \r if I wanted to write a cli application with some kind of progress bar. Example:
#include <stdio.h>
#include <unistd.h>
int main(void) {
int n = 0;
while(n<=100) {
printf("\rProgress: %d\%", n);
fflush(stdout);
sleep(1);
n+=10;
}
}
You could achieve the same thing with \b instead of \r, but mostly it's easier to just reprint the whole line. I cannot see any situation where I would use \b in code.
A similar thing can be done if you want to simulate human writing in a text based game. But I would say that these kind are mostly for the case where you don't have the time and/or energy to learn how to use proper modern methods.
Let's look at the first 32 characters in the ascii table:
0 Null char
1 Start of Heading
2 Start of Text
3 End of Text
4 End of Transmission
5 Enquiry
6 Acknowledgment
7 Bell
8 Back Space
9 Horizontal Tab
10 Line Feed
11 Vertical Tab
12 Form Feed
13 Carriage Return
14 Shift Out / X-On
15 Shift In / X-Off
16 Data Line Escape
17 Device Control 1 (oft. XON)
18 Device Control 2
19 Device Control 3 (oft. XOFF)
20 Device Control 4
21 Negative Acknowledgement
22 Synchronous Idle
23 End of Transmit Block
24 Cancel
25 End of Medium
26 Substitute
27 Escape
28 File Separator
29 Group Separator
30 Record Separator
31 Unit Separator
Almost all of these have been replaced by other things. For instance by higher level protocols, like tcp and such, but also by libraries like ncurses. In C, the null character is useful for strings, but it could have been solved in other ways, like making it possible to retrieve the size of an array when it's passed to a function.
You use them to overwrite something you wrote previously. You wouldn't normally use them in the same string, but in different output calls, e.g.
printf("hello");
fflush(stdout); // need to flush because we didn't write a newline
// do some stuff here
printf("\rgoodbye\n"); // This replaces hello
Those escape sequences are used today mainly for creating some kind of CLI-"GUI", for CLI-"animations", like showing a "loading progress" and some special tricks.
In the past those escape sequences were used mainly to control teleprinter and for punched cards.
For example, for deleting the last punched character on a punch card, you used:
putchar('\b'); putchar(127); /* DEL */.
\ris used to move the cursor in the beginning of above line and \n is used to move the cursor to beginning of next line.
#include <stdio.h>
#include <unistd.h>
#include<iostream>
using namespace std;
int main() {
cout<<"Hello";
cout<<"\r";
cout<<"Gone ";
}
Above program will not display Hello.
#include <stdio.h>
#include <unistd.h>
int main() {
int i=0;
int n=4;
char pattern[n];
pattern[0]=(char)179;
pattern[1]=(char)47;
pattern[2]=(char)196;
pattern[3]=(char)92;
long long int count=0;
while(count<100000000){
printf("%c",pattern[i]);
i=(i+1)%n;
printf("\r");
count++;
}
}
Test it by yourself.
\n" for new line
"\b" for a backspace, means if u print it, cursor will print and come back 1 character. For example.... cout<<"hello\bHi"; will print "HellHi". because after printing Hello, compiler found a \b escape sequence. so it came 1 character back (at 'o' of Hello) and stat printing Hi from o of Hello..... so u got HellHi instead of HelloHi.
'\r' is used for carriage return to come 1 line back or in start of line.
\b = it's purpose is backspace
\r = purpose is carriage return
\r is a carriage return character; it tells your terminal emulator to move the cursor at the start of the line.
The cursor is the position where the next characters will be rendered.
So, printing a \r allows to override the current line of the terminal emulator.
Whereas \b is backspace character it takes the cursor one character backward so that when you will type next thing the characters ahead of cursor will be overwritten.
Thus \b illustrates the working of backspace whereas carriage return simply moves the cursor to the starting of the current line.

What are the effects of "\t" , "\r" and "\b" in c?

I'm a little confused about the following code:
#include <stdio.h>
int main()
{
printf("\nab");
printf("\bsi");
printf("\rha");
return 0;
}
When I execute the program on Linux, it prints
ha
But when I execute it on Xcode, it prints
absi
ha
I am a little confused about "\t", "\b" and "\r", and I can't figure out how the program works.
\t refers to a tab character, \r to a carriage return (think of a typewriter), and \b to a nondestructive backspace. As crvv pointed out, the same output is always sent to stdout: "\nab\bsi\rha". However, your terminal and XCode will produce different output (by choice).
Your terminal will do the following: it sees the \n, goes to a new line, it sees ab and "stores" that, but then it sees \b, so it performs a nondestructive backspace. This basically means the cursor, aka the point where new characters are written, goes back one space:
Initially:
ab
^
After encountering \b:
ab
^
Note that the cursor is now under b, so it will be overwritten if any subsequent characters result.
Next, it reads in s and then i, so we get:
asi
^
Next, it reads in \r. This is the carrage return, which on old typewriters would return the cursor to the beginning of the line. So now we have:
asi
^
Finally, it reads in ha, and because the cursor is under a, ha will overwrite as:
hai
^
Here's the thing. Note that your cursor is still under i. It is not under the next empty space, after the i. Because your program printf does not print anything after printf("\rha"), when the terminal prints your output, the cursor will remain under i.
So, what is the next thing your terminal outputs? Usually, it's the normal prompt, i.e. yourname#ubuntu. This overwrites the i, hence, you will see something like hayourname#ubuntu.
Xcode, on the other hand, does things a little differently. It consumes the \b, so the cursor doesn't go back a character, and the \r is treated as a newline, hence:
absi
ha
The program always writes "\nab\bsi\rha" to its stdout.
The difference comes from how this is displayed.
You can use gcc hello.c && ./a.out | xxd to see it.
00000000: 0a61 6208 7369 0d68 61 .ab.si.ha
\r is CR (carriage return) code. It returns the cursor to the start of line. You have "ab", then \b which is backspace. Following "si" will overwrite "b" and you have "asi". Then \r goes to the start of line and "ha" is printed in the place of "as" - the result is "hai". But the cursor is after "s" and when Bash prompt is displayed, it replaces "i" because it is the first free position after cursor. And you see "ha{prompt-message}". Add \n after \rha to see "hai".

How to enter a backspace character on a shell command line?

I am trying to do Exercise 1-10 in K&R. I've got the program working and running. So far I've come to know that the backspace character is cooked with the operating system. How can I input the backspace character in Mac OS X?
Not sure what you mean by "cooked with the operating system". I guess you're asking how to enter a backspace character on the shell command line without it being interpreted as a backspace, that is, without actually erasing the previous character.
The key combination for the ASCII backspace control character is ^H (hold down Ctrl and press H. However, pressing this combination on the shell command line simply performs the "backspace" operation. To quote a control character in Bash, which is the OS X default shell, and in Zsh you type a combination of two characters: ^V^H.
You can use (non destructive) backspace \b in printf and re-write. This way:
$ cat w.c
#include <stdio.h>
int main ()
{
printf("abcd\n");
printf("abc\bd\n");
}
$ ./w
abcd
abd
UPDATE
Same story using putchar():
$ cat w.c
#include <stdio.h>
int main ()
{
printf("abcd\n");
putchar('a');
putchar('b');
putchar('c');
putchar('\b');
putchar('d');
putchar('\n');
}
Same output...

Erase the current printed console line

How can I erase the current printed console line in C? I am working on a Linux system. For example -
printf("hello");
printf("bye");
I want to print bye on the same line in place of hello.
You can use VT100 escape codes. Most terminals, including xterm, are VT100 aware. For erasing a line, this is ^[[2K. In C this gives:
printf("\33[2K\r");
Some worthwhile subtleties...
\33[2K erases the entire line your cursor is currently on
\033[A moves your cursor up one line, but in the same column i.e. not to the start of the line
\r brings your cursor to the beginning of the line (r is for carriage return N.B. carriage returns do not include a newline so cursor remains on the same line) but does not erase anything
In xterm specifically, I tried the replies mentioned above and the only way I found to erase the line and start again at the beginning is the sequence (from the comment above posted by #Stephan202 as well as #vlp and #mantal) \33[2K\r
On an implementation note, to get it to work properly for example in a countdown scenario since I wasn't using a new line character '\n'
at the end of each fprintf(), so I had to fflush() the stream each time (to give you some context, I started xterm using a fork on a linux machine without redirecting stdout, I was just writing to the buffered FILE pointer fdfile with a non-blocking file descriptor I had sitting on the pseudo terminal address which in my case was /dev/pts/21):
fprintf(fdfile, "\33[2K\rT minus %d seconds...", i);
fflush(fdfile);
Note that I used both the \33[2K sequence to erase the line followed by the \r carriage return sequence to reposition the cursor at the beginning of the line. I had to fflush() after each fprintf() because I don't have a new line character at the end '\n'. The same result without needing fflush() would require the additional sequence to go up a line:
fprintf(fdfile, "\033[A\33[2K\rT minus %d seconds...\n", i);
Note that if you have something on the line immediately above the line you want to write on, it will get over-written with the first fprintf(). You would have to leave an extra line above to allow for the first movement up one line:
i = 3;
fprintf(fdfile, "\nText to keep\n");
fprintf(fdfile, "Text to erase****************************\n");
while(i > 0) { // 3 second countdown
fprintf(fdfile, "\033[A\33[2KT\rT minus %d seconds...\n", i);
i--;
sleep(1);
}
You can use a \r (carriage return) to return the cursor to the beginning of the line:
printf("hello");
printf("\rbye");
This will print bye on the same line. It won't erase the existing characters though, and because bye is shorter than hello, you will end up with byelo. To erase it you can make your new print longer to overwrite the extra characters:
printf("hello");
printf("\rbye ");
Or, first erase it with a few spaces, then print your new string:
printf("hello");
printf("\r ");
printf("\rbye");
That will print hello, then go to the beginning of the line and overwrite it with spaces, then go back to the beginning again and print bye.
You could delete the line using \b
printf("hello");
int i;
for (i=0; i<80; i++)
{
printf("\b");
}
printf("bye");
Usually when you have a '\r' at the end of the string, only carriage return is printed without any newline. If you have the following:
printf("fooooo\r");
printf("bar");
the output will be:
barooo
One thing I can suggest (maybe a workaround) is to have a NULL terminated fixed size string that is initialized to all space characters, ending in a '\r' (every time before printing), and then use strcpy to copy your string into it (without the newline), so every subsequent print will overwrite the previous string. Something like this:
char str[MAX_LENGTH];
// init str to all spaces, NULL terminated with character as '\r'
strcpy(str, my_string); // copy my_string into str
str[strlen(my_string)] = ' '; // erase null termination char
str[MAX_LENGTH - 1] = '\r';
printf(str);
You can do error checking so that my_string is always atleast one less in length than str, but you get the basic idea.
i iterates through char array words. j keeps track of word length. "\b \b" erases word while backing over line.
#include<stdio.h>
int main()
{
int i = 0, j = 0;
char words[] = "Hello Bye";
while(words[i]!='\0')
{
if(words[i] != ' ') {
printf("%c", words[i]);
fflush(stdout);
}
else {
//system("ping -n 1 127.0.0.1>NUL"); //For Microsoft OS
system("sleep 0.25");
while(j-->0) {
printf("\b \b");
}
}
i++;
j++;
}
printf("\n");
return 0;
}
This script is hardcoded for your example.
#include <stdio.h>
int main ()
{
//write some input
fputs("hello\n",stdout);
//wait one second to change line above
sleep(1);
//remove line
fputs("\033[A\033[2K",stdout);
rewind(stdout);
//write new line
fputs("bye\n",stdout);
return 0;
}
Click here for source.
under windows 10 one can use VT100 style by activating the VT100 mode in the current console to use escape sequences as follow :
#include <windows.h>
#include <iostream>
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#define DISABLE_NEWLINE_AUTO_RETURN 0x0008
int main(){
// enabling VT100 style in current console
DWORD l_mode;
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleMode(hStdout,&l_mode)
SetConsoleMode( hStdout, l_mode |
ENABLE_VIRTUAL_TERMINAL_PROCESSING |
DISABLE_NEWLINE_AUTO_RETURN );
// create a waiting loop with changing text every seconds
while(true) {
// erase current line and go to line begining
std::cout << "\x1B[2K\r";
std::cout << "wait a second .";
Sleep(1);
std::cout << "\x1B[2K\r";
std::cout << "wait a second ..";
Sleep(1);
std::cout << "\x1B[2K\r";
std::cout << "wait a second ...";
Sleep(1);
std::cout << "\x1B[2K\r";
std::cout << "wait a second ....";
}
}
see following link : windows VT100
there is a simple trick you can work here but it need preparation before you print, you have to put what ever you wants to print in a variable and then print so you will know the length to remove the string.here is an example.
#include <iostream>
#include <string> //actually this thing is not nessasory in tdm-gcc
using namespace std;
int main(){
//create string variable
string str="Starting count";
//loop for printing numbers
for(int i =0;i<=50000;i++){
//get previous string length and clear it from screen with backspace charactor
cout << string(str.length(),'\b');
//create string line
str="Starting count " +to_string(i);
//print the new line in same spot
cout <<str ;
}
}
Just found this old thread, looking for some kind of escape sequence to blank the actual line.
It's quite funny no one came to the idea (or I have missed it) that printf returns the number of characters written. So just print '\r' + as many blank characters as printf returned and you will exactly blank the previuosly written text.
int BlankBytes(int Bytes)
{
char strBlankStr[16];
sprintf(strBlankStr, "\r%%%is\r", Bytes);
printf(strBlankStr,"");
return 0;
}
int main(void)
{
int iBytesWritten;
double lfSomeDouble = 150.0;
iBytesWritten = printf("test text %lf", lfSomeDouble);
BlankBytes(iBytesWritten);
return 0;
}
As I cant use VT100, it seems I have to stick with that solution
echo -e "hello\c" ;sleep 1 ; echo -e "\rbye "
What the above command will do :
It will print hello and the cursor will remain at "o" (using \c)
Then it will wait for 1 sec (sleep 1)
Then it will replace hello with bye.(using \r)
NOTE : Using ";", We can run multiple command in a single go.
For me, this code, work well for serial console window with arduino
on Tera Term VT console:
SEROUT.print("\e[A\r\n\e[2K");
SEROUT.print('>');
I use '>' because on my console command i type command after '>'
use this function to clear n lines in C++
void clear_line(int n) {
std::string line_up = "\x1b[A";
std::string line_clear = "\33[2K\r";
for (int i = 0; i < n; ++i)
std::cout << line_up << line_clear << std::flush;
}
Others have already answered OP's question. Here is an answer for those wondering why carriage return behaves the way it does on their Linux machine -
The behavior of the carriage return character seems to be platform-dependent.
From section '5.2.2 Character display semantics' of the C11 standard:
\r (carriage return) Moves the active position to the initial position
of the current line.
From section '3.86 Carriage-Return Character (< carriage-return>)' of the POSIX standard (https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html):
A character that in the output stream indicates that printing should
start at the beginning of the same physical line in which the
carriage-return occurred. It is the character designated by '\r' in
the C language. It is unspecified whether this character is the exact
sequence transmitted to an output device by the system to accomplish
the movement to the beginning of the line.
It does not state whether carriage return is supposed to erase (=> populate with NUL characters) the entire line or not. My guess is that it is NOT supposed to erase.
However, on my Linux machine (tried on both x86_64 and ARM32), what I observed is that the carriage return character moved the cursor to the beginning of the current line and also populated the line with '\0' characters (NUL characters). In order to notice those NUL characters, you might have to call the write system call directly from your code instead of calling via glibc printf.
Let's take the following code snippet as an example:
printf("hello");
printf("\rbye");
Building and running this on beaglebone black (32-bit ARM) bash terminal:
ubuntu#arm:~$ ./a.out
byeubuntu#arm:~$
strace output on write syscall:
bye) = 9 9hello
+++ exited with 4 +++

Resources