Treatment of \b in template strings to printf in C - c

Can someone please explain or point me to a reference that explains why in the code snippets below the line printed in the first includes the whole word hello, while in the second it consists only of the letters he? I thought the backspace escape characters would delete the last three letters regardless of the newline escape. I've read the GNU documentation on printf but couldn't find anything on point.
int main(void)
{
printf("hello\b\b\b\n");
return 0;
}
int main(void)
{
printf("hello\b\b\b");
return 0;
}

This isn't really a question about C or printf. In each case the code does exactly what it says: in the first example it outputs the 9 characters h e l l o \b \b \b \n and in the second it likewise outputs 8 characters. If you write standard output to a file that's exactly what the file will contain. But if you write to a terminal, your terminal may handle \b by backspacing, and so your question is really about your terminal. You have not said what terminal you are using.
One common way for the backspace character to behave is by moving the cursor one position left, but not actually erasing the character in that position. The next character output will be written over it.
In your first example, you move the cursor back to the first l, but then you never write anything over it or any other character. Then \n doesn't change any character on the screen, but just moves the cursor to the next line. So you still see hello on the preceding line.
In your second example, the cursor is left over the first l when your program terminates. So the next program to write output to the terminal will write over that character (unless the next program's first write is \n or something like that). That next program might be your shell, and so the characters from your shell prompt probably overwrite the llo, so you don't see them.

Two key things to keep in mind:
Output to the console isn't immediately rendered when you use printf(): the output is buffered. Two ways to immediately (synchronously) flush the output buffer to the console is to print a newline via printf("\n"), or manually flush the buffer via fflush(stdout).
If you use the \b escape sequence, you will move the cursor one "space" back/left, but printing a newline character won't necessarily clear the rest of the line. If you were to manually print new characters over the old ones (i.e. printf("Hello\b\b\b \n")) the output would be more like what you're expecting.
Additionally, if you want to do some advanced command-line menus, graphics, etc, you'll need to use something like libncurses.
Finally, the following example should help give a better idea on the typically behavior involving your question.
#include <stdio.h>
#include <unistd.h>
#define DELAY (2) /* seconds */
int main(void)
{
printf("Example DELAY:\n");
printf("------------------------------------------------------------------------\n");
printf("hello\b\b\b\n");
sleep(DELAY);
printf("\n\n");
printf("Example 2:\n");
printf("------------------------------------------------------------------------\n");
printf("hello\b\b\b");
sleep(DELAY);
printf("...");
sleep(DELAY);
fflush(stdout);
sleep(DELAY);
printf("\n\n");
printf("Example 3:\n");
printf("------------------------------------------------------------------------\n");
fflush(stdout);
printf("hello\b\b\b");
fflush(stdout);
sleep(DELAY);
printf("...");
sleep(DELAY);
fflush(stdout);
sleep(DELAY);
printf("\n\n");
return 0;
}

Related

Printing text too often?

i am new to c and have used python before. This whole buffer overflow stuff is really breaking my mind.
#include <stdio.h>
int main(){
char str1[3];
while(true){
scanf("%2s", str1);
printf("test\n");
}
}
This is a little code i've written to test the syntax and the stdio library. I was really suprised when the program outputted "test" multiple times, depending on how many characters i entered. So for example, when I entered two characters, it printed "test" two times. Can anyone please tell me why this is happening and how I can fix it?
You can figure out what happens by modifying your code as follows:
#include <stdio.h>
int main(){
char str1[3];
while( 1 ){
scanf("%2s", str1);
printf("test: %s\n", str1);
}
}
which simply prints the contents of the str1 alongside of the "test" string.
Here is an example output for an input string of 1234567:
1234567
test: 12
test: 34
test: 56
test: 7
The scanf("%2s", str1); statement reads two characters from the stdin and assings them to the str1. The read characters are "popped" from the input stream, i.e., they are removed. If the stdin happens to contain more characters, the excess ones are left untouched. Therefore, for the given input, when the first scanf is returned, the str1 containes 12\0, and the stdin contains 34567.
Since these are in the infinite loop, the code repeats, scanf gets called again, reading the first two characters from the stdin again, only this time finds 34.
And the process repeats, untill there are no characters left on the stdin, then the scanf waits for the user input, presumably as you would have expected.
Basically, scanf keeps reading instead of waiting for user input, since the stdin already contains something to read.
So for example, when I entered two characters, it printed "test" two times.
This on the other hand, does not make sense, as it should be printing "test" for N/2 times, rounded up, where N is the number of characters you enter.
There is not much that I can suggest for "fixing this", since it is not really clear what you are expecting. But if you want to get rid of the remaining characters in the stdin, you can check this.
You need to clear your input buffer as per this answer
Otherwise, you'll read from the stdin, print it, jump back to the loop head and continue reading, if there is still something in the buffer.
Each time through the loop, scanf("%2s", str1) reads at most 2 non-whitespace characters from the input stream. If there are more than 2 non-whitespace characters available in the stream, the loop will continuously call scanf (and printf) until scanf blocks waiting for data. If the input stream contains ffff\n and has not yet been closed (eg, a user is entering data interactively from a tty), the first 2 calls to scanf will immediately return and printf will be called twice. The 3rd call to scanf will block until more data is available, or the stream is closed, or there is an error.

Is getc() and getchar() well-defined function?

printf("%c %c", getc(stdin), getc(stdin));
rewind(stdin); printf("\n");
printf("%c %c", getchar(), getchar());
output
s
s
s
s
I wrote the source code like that and I pressed s, enter, s, enter sequentially on windows console application using vs2017. Console shows me what I put and print output when I press the key. The result's appearance is like s, enter, enter, space, s, s, enter, enter, space, s. Did I use the function in wrong way?
Q1. I pressed s, enter sequentially, but why output is reversed?
Q2. At output's third line and sixth line, why is there exist whitespace like  s not s?.
Explaining the output
The arguments to a function can be evaluated in any order that the compiler chooses.
The original code looked like this (missing printf("\n"); compared to the revised code):
printf("%c %c", getc(stdin), getc(stdin));
rewind(stdin);
printf("%c %c", getchar(), getchar());
Your 'output' in the question is extremely difficult to read and interpret. However, I'm reasonably sure that what you show consists of both your input and the program's output.
You say you type s enter twice. The output you get, copied from the question, is:
s
s
s
s
The first s and the newline that follows are what you typed. The blank line is there because the newline was read by the getc(stdin) that appears first in the argument list, then there's the blank from the format string, and the s which was read by the getc(stdin) that appears second in the argument list. Your compiler, it seems, evaluates the arguments right to left — but you should not rely on that.
Now we run into a problem; there's a newline after the second s that isn't accounted for by the code you showed when I wrote this answer. Since then, you've added the printf("\n"); which explains the output you saw.
Putting that aside, the third s is followed by a newline and is what you typed. And again, the blank line is from the newline and then space and s is the rest of the output, and there's probably a newline after that too.
JFTR, when I run your code (program getc73 compiled from getc73.c), I see:
$ getc73
s
ss
s$
$
The $ is my prompt; the first s is what I type; then the newline, blank and s are printed (with no newline at the end); then the second s on the third line is my next s and return, followed by the newline and blank s. Since there's no newline at the end, my prompt appears immediately after the fourth s. I hit return to print another prompt at the start of the line.
Why rewind(stdin) is a no-op
You can't successfully execute an fseek() call on a terminal device. They don't have any storage so you can't move around like that. The rewind() function is effectively:
void rewind(FILE *fp)
{
fseek(fp, 0, SEEK_SET);
}
So, the rewind(stdin) call fails to rewind, but it has no way to report that to you because it returns no value. It does no good; it doesn't do any harm either. If it had worked, you would not have needed to enter the information twice.
If the standard input had been a file instead of a terminal, then the rewind would succeed — disks are seekable.
Improved formatting
If you were on a POSIX system, I'd suggest you used a feature of POSIX printf() that allows you to print the same argument more than once:
#include <stdio.h>
int main(void)
{
printf("[%1$c] %1$d [%2$c] %2$d\n", getc(stdin), getc(stdin));
printf("[%1$c] %1$d [%2$c] %2$d\n", getchar(), getchar());
return 0;
}
When I run that on my terminal (it's a Mac running macOS Mojave 10.14.6 using GCC 9.2.0), I get:
s
[
] 10 [s] 115
s
[
] 10 [s] 115
The lines with just the s on them are what I typed; the other lines show that the newline is printed before the letter s.
This probably won't work for you in VS2017 — the manual for printf() formats on Windows strongly suggests it won't work. Your best bet, probably, is to use:
#include <stdio.h>
int main(void)
{
printf("%d %d\n", getc(stdin), getc(stdin));
printf("%d %d\n", getchar(), getchar());
return 0;
}
That generates:
s
10 115
s
10 115
Choosing a good format to show what you're seeing is an art form. Don't forget to include newlines at the end of (most) printf() format strings. Obviously, if you're building up a line of output piecemeal, you don't want newlines at the end of intermediate formats, but the majority of printf() statements should have a newline at the end of the format.

Why "\r " deletes my previous printed line but "\r" it doesn't

When I print some line, if I want to overwrite for example the first character, I use \r because is the carriage return character but it prints only one character after this one, my whole line is overwritten.
This is some code that I made for this question.
#include <stdio.h>
int main(){
printf("-------");
printf("\r ");
return 0;
}
using this code my output is: with one space.
Now I change a little bit the code. The only change is that in my second printf I delete the space after \r
#include <stdio.h>
int main(){
printf("-------");
printf("\r");
return 0;
}
using this second code my output is "-------" (without quotes)
my expected output: " ------"
Why this is not working?
\r is Carriage Return. It sends the "carriage" (cursor, in modern times) back to the beginning of the same line. It does not by itself erase anything--just moves the cursor. Apparently your terminal has the behavior that printing a character at the beginning of a line erases the rest of the line. That's not guaranteed, I think.
On many systems if you want to clear the current line you must print \r followed by as many spaces as the line had characters on it.

Character counting program not outputting anything?

Sorry for asking such a simple question, I'm still learning C and going through the basics first.
I'm creating a character counting program and yet when I execute the program and try to input "h" for example and then press enter a new line appears and nothing is outputted onto that line?
Code:
#include <stdio.h>
/* Copy input and count characters 2nd version */
main() {
double cc;
for(cc = 0; getchar() != EOF; ++cc);
printf("%.0f\n", cc);
}
Once you have finished entering characters, you have to signal the end of input stream by pressing Ctrl-D. Otherwise your program will continue waiting for more input.
P.S. Why are you using a double variable for the counter? An integer type would be more appropriate.
Maybe (I'm not sure what exactly do you want) you have an extra ; after the for(), which mean an empty statement. So your program will run the empty statement (in other words, do nothing) until the end of input (if the input is terminal, you may need a CTRL+D), and then print (once) the number of characters.
If you want your program to print the counter after every char in the input, remove that ;, so the printf will be in the loop.
Include this line at the end you will get output:
return 0;

peek at input buffer, and flush extra characters in C

If I want to receive a one character input in C, how would I check to see if extra characters were sent, and if so, how would I clear that?
Is there a function which acts like getc(stdin), but which doesn't prompt the user to enter a character, so I can just put while(getc(stdin)!=EOF);? Or a function to peek at the next character in the buffer, and if it doesn't return NULL (or whatever would be there), I could call a(nother) function which flushes stdin?
Edit
So right now, scanf seems to be doing the trick but is there a way to get it to read the whole string, up until the newline? Rather than to the nearest whitespace? I know I can just put "%s %s %s" or whatever into the format string but can I handle an arbitrary number of spaces?
You cannot flush the input stream. You will be invoking undefined behavior if you do. Your best bet is to do:
int main() {
int c = getchar();
while (getchar() != EOF);
return 0;
}
To use scanf magic:
#include <stdio.h>
#include <stdlib.h>
#define str(s) #s
#define xstr(s) str(s)
#define BUFSZ 256
int main() {
char buf[ BUFSZ + 1 ];
int rc = scanf("%" xstr(BUFSZ) "[^\n]%*[^\n]", buf);
if (!feof(stdin)) {
getchar();
}
while (rc == 1) {
printf("Your string is: %s\n", array);
fflush(stdout);
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);
if (!feof(stdin)) {
getchar();
}
}
return 0;
}
You can use getline to read a whole line of input.
Alternatively (in response to your original question), you can call select or poll on stdin to see if there are additional characters to be read.
I had a similar problem today, and I found a way that seems to work. I don't know the details of your situation, so I don't know if it will work for you or not.
I'm writing a routine that needs to get a single character from the keyboard, and it needs to be one of three specific keystrokes (a '1', a '2', or a '3'). If it's not one of those, the program needs to send and error message and loop back for another try.
The problem is that in addition to the character I enter being returned by getchar(), the 'Enter' keystroke (which sends the keystroke to the program) is saved in an input buffer. That (non-printing) newline-character is then returned by the getchar() facility in the error-correction loop, resulting further in a second error message (since the newline-character is not either a '1', a '2', nor a '3'.)
The issue is further complicated because I sometimes get ahead of myself and instead of entering a single character, I'll enter the filename that one of these options will request. Then I have a whole string of unwanted characters in the buffer, resulting in a long list of error messages scrolling down the screen.
Not cool.
What seems to have fixed it, though, is the following:
c = getchar(); // get first char in line
while(getchar() != '\n') ; // discard rest of buffer
The first line is the one that actually uses the character I enter. The second line disposes of whatever residue remains in the input buffer. It simply creates a loop that pulls a character at a time from the input buffer. There's no action specified to take place while the statement is looping. It simply reads a character and, if it's not a newline, goes back for the next. When it finds a newline, the loop ends and it goes on to the next order of business in the program.
We can make a function to clear the keyboard buffer, like this:
#include <stdio.h>
void clear_buffer(){
char b;
//this loop take character by character in the keyboard buffer using
//getchar() function, it stop when the variable "b" was
//enter key or EOF.
while (((b = getchar()) != '\n') && (b != EOF));
}
int main()
{
char input;
//get the input. supposed to be one char!
scanf("%c", &input);
//call the clearing function that clear the buffer of the keyboard
clear_buffer();
printf("%c\n",input); //print out the first character input
// to make sure that our function work fine, we have to get the
// input into the "input" char variable one more time
scanf("%c", &input);
clear_buffer();
printf("%c\n",input);
return 0;
}
Use a read that will take a lot of characters (more than 1, maybe 256), and see how many are actually returned. If you get more than one, you know; if you only get one, that's all there were available.
You don't mention platform, and this gets quite tricky quite rapidly. For example, on Unix (Linux), the normal mechanism will return a line of data - probably the one character you were after and a newline. Or maybe you persuade your user to type ^D (default) to send the preceding character. Or maybe you use control functions to put the terminal into raw mode (like programs such as vi and emacs do).
On Windows, I'm not so sure -- I think there is a getch() function that does what you need.
Why don't you use scanf instead of getc, by using scanf u can get the whole string.

Resources