What are the effects of "\t" , "\r" and "\b" in c? - 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".

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.

getchar and EOF

I was working on the following example of C code from Deitel & Deitel. It seems that the code is supposed to print the characters entered before EOF, in the reverse order. But I have to press EOF (ctrl+z in windows) several times and Enter key to get it done. Could you please let me know why it does not respond at the first EOF?
#include <stdio.h>
int main( void )
{
int c;
if ( ( c = getchar() ) != EOF ) {
main();
printf( "%c", c );
} /* end if */
return 0;
}
Well getchar(3) is a function that operates in buffer mode, so you have to input some characters, and press the character used to signal end of data (^D in unix, ^Z in windows)
The problem here is that windows console driver is not specified the same way as the unix tty driver, so the behaviour will, in general, not be the same... Try to test the program in a real unix environment (or linux) and see if the input, at least is reversed, as the example said.
In unix, the behaviour of terminal input is that ^D is interpreted as soon as it is pressed, but if some input is in the driver buffer before it, it will make those input available to the program (so you'll have to press it a second time to signal EOF condition, which consists in a read(2) that results in 0 characters actually read). In case you have pressed <Return> before ^D (return makes all data available to the application, with the difference that the \n char is also appended to the data read), the input buffer is empty, so the EOF condition comes inmediately, after the <return> char.
In windows, you need to press <return> for anything to be read (the ^Z to be interpreted), and things complicate.
By the way, I have executed your program on a BSD unix system, with the following result:
$ a.out
apsiodjfpaosijdfa
^D
afdjisoapfjdoispa$ _
Explanation: first line is the input line "apsiodjfpaosijdfa", followed by a \n, and ^D signalling end of input. All this data goes to the application at once, and getchar() then processes it character by character. It prints the \n first (making the line to appear below ^D) and then the input chars, reversed. As there was no \r at the beginning of data, no return is issued at end, and the prompts appears next to the output.
The final _ signals the position of the cursor at the end.
If you don't want to deal with end of data characters (or don't have any unix at hand to make the test) you can use a text file to test your program (no eof char, only the actual end of the file), by redirecting program input from a file, like in this example that uses the original source code as input:
$ a.out <pru.c
}
;0 nruter
/* fi dne */ }
;) c ,"c%" (ftnirp
;)(niam
{ ) FOE =! ) )(rahcteg = c ( ( fi
;c tni
{
) diov (niam tni
>h.oidts< edulcni#$ _
It's to do with they way the windows console is passing the CTRL+Z to the program. It's probably waiting for you to compose a line and not recognising a line until it has a non- CTRL-Z character in it. So it waits until you accidentally press space and also enter.
Just echo everything in a scratch program to see exactly what is going on.

EOF in Windows command prompt doesn't terminate input stream

Code:
#include <stdio.h>
#define NEWLINE '\n'
#define SPACE ' '
int main(void)
{
int ch;
int count = 0;
while((ch = getchar()) != EOF)
{
if(ch != NEWLINE && ch != SPACE)
count++;
}
printf("There are %d characters input\n" , count);
return 0;
}
Question:
Everything works just fine, it will ignore spaces and newline and output the number of characters input to the screen (in this program I just treat comma, exclamation mark, numbers or any printable special symbol character like ampersand as character too) when I hit the EOF simulation which is ^z.
But there's something wrong when I input this line to the program. For example I input this: abcdefg^z, which means I input some character before and on the same line as ^z. Instead of terminating the program and print out total characters, the program would continue to ask for input.
The EOF terminating character input only works when I specify ^z on a single line or by doing this: ^zabvcjdjsjsj. Why is this happening?
This is true in almost every terminal driver. You'll get the same behavior using Linux.
Your program isn't actually executing the loop until \n or ^z has been entered by you at the end of a line. The terminal driver is buffering the input and it hasn't been sent to your process until that occurs.
At the end of a line, hitting ^z (or ^d on Linux) does not cause the terminal driver to send EOF. It only makes it flush the buffer to your process (with no \n).
Hitting ^z (or ^d on Linux) at the start of a line is interpreted by the terminal as "I want to signal EOF".
You can observe this behavior if you add the following inside your loop:
printf("%d\n",ch);
Run your program:
$ ./test
abc <- type "abc" and hit "enter"
97
98
99
10
abc97 <- type "abc" and hit "^z"
98
99
To better understand this, you have to realize that EOF is not a character. ^z is a user command for the terminal itself. Because the terminal is responsible for taking user input and passing it to processes, this gets tricky and thus the confusion.
A way to see this is by hitting ^v then hitting ^z as input to your program.
^v is another terminal command that tells the terminal, "Hey, the next thing I type - don't interpret that as a terminal command; pass it to the process' input instead".
^Z is only translated by the console to an EOF signal to the program when it is typed at the start of a line. That's just the way that the Windows console works. There is no "workaround" to this behaviour that I know of.

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

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");

Resources