Explanation about detecting end of line in C - c

I'm reading/practicing with this book about C language: "C Programming - A Modern Approach 2" and I stumbled upon this piece of code whose explanation is odd to me:
Since scanf doesn't normally skip white spaces, it's easy to detect the end of an input line: check to see if the character just
read is the new-line character. For example, the following loop
will read and ignore all remaining characters in the current input
line:
do {
scanf("%c", &ch);
} while (ch != '\n');
When scanf is called the next time, it will read the first character on the next input line.
I understand the functioning of the code (it exits the loop when it detects enter or '\n') but not the lesson(?).
What is the purpose of this, since to store the input from the user into &ch you HAVE to press the enter key (quitting the loop)?
Also what does "the following loop will read and ignore all remaining characters in the current input line" mean actually?

...What is the purpose of this...
For context in understanding what this code snippet can be used for, take a look at this link discussing stdio buffering.
In simplest logical terms, this technique consumes content placed in stdin until the newline character is seen. (From a user hitting the <enter> key.) This is evidently the lesson.
This effectively clears the stdin buffer of content, also described in this more robust example.
Also what does
"the following loop will read and ignore all remaining characters in
the current input line"
mean actually?
do {
scanf("%c", &ch);
} while (ch != '\n');
It means that if the new char just read by scanf is not equal to the newline character, defined as \n, it will continue to overwrite c with the next read. Once ch does equal \n, the loop will exit.

Related

unexpected output with getchar()

char c = ' ';
while(c != 'x')
{
c = getchar();
printf("threadFuncParam = %u\n", threadFuncParam);
}
In the above code snippet the print is printing threadFuncParam value twice every time I enter a character where as I expect it to print only once.
As per my understanding very first time it enters while as condition is true and and then wait for user input at getchar call on entering a character it shall print the value and then if input character is not x it shall wait for another input at getchar call, but whenever i enter a character i see 2 prints ion screen for each input. I am not able to understand why?
What i'm trying to do here is that in main thread i am taking single char input from user and in worker thread i am incrementing a counter which gets incremented every second, i print the value everytime user input a char input until user enters 'x' character.
The simple issue here is that the console (input) sends the text to the stdin only when it encounters a enter key or ctr+d.
As a result an extra \n goes into your input stream. This causes your program to read that character in the next iteration.
A simple solution would be to read all white space characters in the stream.
This can be done in multiple ways -
If you need to discard any whitespace characters (including space, tabs, vtabs, newline), you can add
scanf(" ");
before the getchar();
If you need to discard only the newlines which come as a result of pressing enter, you can add
scanf("%*[\n]")
before the getchar();
This will eat up all the \n that come before the next character. But will not eat spaces.
Finally if you want to discard only 1 \n
You can do
scanf("%*1[\n]");
Remember though, in all the cases the scanf should be immediately before the getchar() because scanf would wait till it finds the next non white space character.
All cases figured out with the help of comments from #chux.
If you tried to debug your program (its best way to learn to code), you would spot that the second value is everytime 10. In ASCII table you would find that is code for new line. Which you are pressing after the every character. Then by fast & simple searching you would find this THREAD. Where is the problem described and you would easily solve it.
char c = ' ';
while(c != 'x')
{
printf("threadFuncParam = %u\n", (char)c);
fflush(stdout);
if (scanf(" %c",&c) != 1)
{
// failed
}
}
I think the problem is in the way logic is applied. You print before you check the condition. See this for explanation:
loop 1: getchar() executed say for value 'a'.
printf() executed.
loop 2: Because c='a', condition is true. Now, getchar() is executed with 'x' value.
printf() is again executed.
loop 3: Condition is evaluated false. Loop is terminated.
So basically you should change your logic a little bit.

C skips user input from subsequent scanf statement [duplicate]

I've been having a lot of problems trying to figure out how to use scanf(). It seems to work fine with integers, being fairly straight forward scanf("%d", &i).
Where I am running into issues is using scanf() in loops trying to read input. For example:
do {
printf("counter: %d: ", counter);
scanf("%c %c%d", &command, &prefix, &input);
} while (command != 'q');
When I enter in a validly structured input like c P101, it seems to loop again before prompting me. This seems to happen even with a single:
scanf("%c", &c)
in a while loop. It'll do the loop twice before prompting me again. What is making it loop twice, and how do I stop it?
When I enter in less amount of input that programmatically wouldn't have another character or number such as q, pressing enter seems to prompt me to enter more. How do I get scanf() to process both single and double character entries?
When you enter "c P101" the program actually receives "c P101\n". Most of the conversion specifiers skip leading whitespace including newlines but %c does not. The first time around everything up til the "\n" is read, the second time around the "\n" is read into command, "c" is read into prefix, and "P" is left which is not a number so the conversion fails and "P101\n" is left on the stream. The next time "P" is stored into command, "1" is stored into prefix, and 1 (from the remaining "01") is stored into input with the "\n" still on the stream for next time. You can fix this issue by putting a space at the beginning of the format string which will skip any leading whitespace including newlines.
A similiar thing is happening for the second case, when you enter "q", "q\n" is entered into the stream, the first time around the "q" is read, the second time the "\n" is read, only on the third call is the second "q" read, you can avoid the problem again by adding a space character at the beginning of the format string.
A better way to do this would be to use something like fgets() to process a line at a time and then use sscanf() to do the parsing.
It's really broken! I didn't know it
#include <stdio.h>
int main(void)
{
int counter = 1;
char command, prefix;
int input;
do
{
printf("counter: %d: ", counter);
scanf("%c %c%d", &command, &prefix, &input);
printf("---%c %c%d---\n", command, prefix, input);
counter++;
} while (command != 'q');
}
counter: 1: a b1
---a b1---
counter: 2: c d2
---
c1---
counter: 3: e f3
---d 21---
counter: 4: ---e f3---
counter: 5: g h4
---
g3---
The output seems to fit with Robert's answer.
Once you have the string that contains the line. i.e. "C P101", you can use the parsing abilities of sscanf.
See:
http://www.cplusplus.com/reference/clibrary/cstdio/sscanf.html
For question 1, I suspect that you've got a problem with your printf(), since there is no terminating "\n".
The default behavior of printf is to buffer output until it has a complete line. That is unless you explicitly change the buffering on stdout.
For question 2, you've just hit one of the biggest problems with scanf(). Unless your input exactly matches the scan string that you've specified, your results are going to be nothing like what you expect.
If you've got an option you'll have better results (and fewer security issues) by ignoring scanf() and doing your own parsing. For example, use fgets() to read an entire line into a string, and then process the individual fields of the string — maybe even using sscanf().
Perhaps using a while loop, not a do...while loop will help. This way the condition is tested before execution of the code.
Try the following code snippet:
while(command != 'q')
{
//statements
}
Also, if you know the string length ahead of time, 'for' loops can be much easier to work with than 'while' loops. There are also some trickier ways to dynamically determine the length as well.
As a final rant: scanf() does not "suck." It does what it does and that is all.
The gets() function is very dangerous (though convenient for no-risk applications), since it does not natively do any checking of the input. It is VERY commonly known as a point of exploit, specifically buffer overflow attacks, overwriting space in registers not allocated for that variable. Therefore if you choose to use it, spend some time putting some solid error checking/correction in.
However, almost invariably, either fgets() or POSIX getline() should be used to read the line — noting that the functions both include the newline in the input string, unlike gets(). You can remove the trailing newline from string read by either fgets() or getline() using string[strcspn(string, "\n")] = '\0'; — this works reliably.

Input for examples from Kernighan and Ritchie

In section 1.5.2 of the 2nd ed. K&R introduce getchar() and putchar() and give an example of character counting, then line counting, and others throughout the chapter.
Here is the character counting program
#include <stdio.h>
main() {
long nc;
nc = 0;
while (getchar() != EOF)
++nc;
printf("%ld\n",nc);
}
where should the input come from? typing into the terminal command window and hitting enter worked for the file copying program but not for this. I am using XCode for Mac.
It seems like the easiest way would be to read a text file with pathway "pathway/folder/read.txt" but I am having trouble with that as well.
From the interactive command line, press ctrl-D after a newline, or ctrl-D twice not after newline, to terminate the input. Then the program will see EOF and show you the results.
To pass a file by path, and avoid the interactive part, use the < redirection operator of the shell, ./count_characters < path/to/file.txt.
Standard C input functions only start processing what you type in when you press the Enter key IOW.Every key you press adds a character to the system buffer (shell).Then when the line is complete (ie, you press Enter), these characters are moved to C standard buffer. getchar() reads the first character in the buffer, which also removes it from the buffer.Each successive call to getchar() reads and removes the next char, and so on. If you don't read every character that you had typed into the keyboard buffer, but instead enter another line of text, then the next call to getchar() after that will continue reading the characters left over from the previous line; you will usually witness this as the program blowing past your second input. BTW, the newline from the Enter key is also a character and is also stored in the keyboard buffer, so if you have new input to read in you first need to clear out the keyboard buffer.

C getchar vs scanf

I am confused by a piece of code found in a function I am studying:
char GetCommand( void )
{
char command;
do {
printf( "Enter command (q=quit, n=new, l=list): " );
scanf( "%c", &command );
Flush();
}
while ( (command != 'q') && (command != 'n')
&& (command != 'l') );
printf( "\n----------\n" );
return( command );
}
void Flush( void ) {
while ( getchar() != '\n' )
;
}
What I don't quite understand here is the usage of the Flush() function. I mean, the book I am reading explains it by saying that it prevents the user from inputting more than a single character and then having that character read when they are prompted for input the 2nd time.
What I don't understand is how Flush() is preventing this from happening. It doesn't DO anything. All it is is a while command. (While this is true......what?????) Doesn't make sense.
getchar() has the side effect of removing the next character from the input buffer. The loop in Flush reads and discards characters until - and including - the newline \n ending the line.
Since the scanf is told to read one and only one character (%c) this has the effect of ignoring everything else on that input line.
It would probably be more clear if the scanf was replace with
command = getchar();
but it's actually a generally bad example as it does not handle End Of File well.
In general scanf is best forgotten; fgets and sscanf work much better as one is responsible for getting the input and the other for parsing it. scanf (and fscanf) try to do too many jobs at once.
getchar reads one character from standard input. If you put it in a while loop, it will continue to read one character at a time until the condition is false.
What the Flush function is doing is reading until it encounters a newline (\n). This is the character produced when the user hits the enter key.
So, the code you gave will read one character (I'm unclear on why it uses scanf for this instead of simply getchar, which would be faster), and then discards the rest of the input until the user hits enter.
If you were to feed this program foobar, it would take the f and discard the oobar in the Flush function. Without calling flush, the f could go to one scanf, and the second scanf would get the first o.
When you enter your character and press Enter, a newline character is generated by you pressing the Enter key and it remains in the buffer. This is problematic because it will wait around until the next time you require user input and it will be used for that input. Flush is used to flush the newline character from the input buffer so you don't have that problem. Flush actually uses the newline in the input buffer when it reads it and it is discarded, so it is no longer in the buffer.

Parsing input with scanf in C

I've been having a lot of problems trying to figure out how to use scanf(). It seems to work fine with integers, being fairly straight forward scanf("%d", &i).
Where I am running into issues is using scanf() in loops trying to read input. For example:
do {
printf("counter: %d: ", counter);
scanf("%c %c%d", &command, &prefix, &input);
} while (command != 'q');
When I enter in a validly structured input like c P101, it seems to loop again before prompting me. This seems to happen even with a single:
scanf("%c", &c)
in a while loop. It'll do the loop twice before prompting me again. What is making it loop twice, and how do I stop it?
When I enter in less amount of input that programmatically wouldn't have another character or number such as q, pressing enter seems to prompt me to enter more. How do I get scanf() to process both single and double character entries?
When you enter "c P101" the program actually receives "c P101\n". Most of the conversion specifiers skip leading whitespace including newlines but %c does not. The first time around everything up til the "\n" is read, the second time around the "\n" is read into command, "c" is read into prefix, and "P" is left which is not a number so the conversion fails and "P101\n" is left on the stream. The next time "P" is stored into command, "1" is stored into prefix, and 1 (from the remaining "01") is stored into input with the "\n" still on the stream for next time. You can fix this issue by putting a space at the beginning of the format string which will skip any leading whitespace including newlines.
A similiar thing is happening for the second case, when you enter "q", "q\n" is entered into the stream, the first time around the "q" is read, the second time the "\n" is read, only on the third call is the second "q" read, you can avoid the problem again by adding a space character at the beginning of the format string.
A better way to do this would be to use something like fgets() to process a line at a time and then use sscanf() to do the parsing.
It's really broken! I didn't know it
#include <stdio.h>
int main(void)
{
int counter = 1;
char command, prefix;
int input;
do
{
printf("counter: %d: ", counter);
scanf("%c %c%d", &command, &prefix, &input);
printf("---%c %c%d---\n", command, prefix, input);
counter++;
} while (command != 'q');
}
counter: 1: a b1
---a b1---
counter: 2: c d2
---
c1---
counter: 3: e f3
---d 21---
counter: 4: ---e f3---
counter: 5: g h4
---
g3---
The output seems to fit with Robert's answer.
Once you have the string that contains the line. i.e. "C P101", you can use the parsing abilities of sscanf.
See:
http://www.cplusplus.com/reference/clibrary/cstdio/sscanf.html
For question 1, I suspect that you've got a problem with your printf(), since there is no terminating "\n".
The default behavior of printf is to buffer output until it has a complete line. That is unless you explicitly change the buffering on stdout.
For question 2, you've just hit one of the biggest problems with scanf(). Unless your input exactly matches the scan string that you've specified, your results are going to be nothing like what you expect.
If you've got an option you'll have better results (and fewer security issues) by ignoring scanf() and doing your own parsing. For example, use fgets() to read an entire line into a string, and then process the individual fields of the string — maybe even using sscanf().
Perhaps using a while loop, not a do...while loop will help. This way the condition is tested before execution of the code.
Try the following code snippet:
while(command != 'q')
{
//statements
}
Also, if you know the string length ahead of time, 'for' loops can be much easier to work with than 'while' loops. There are also some trickier ways to dynamically determine the length as well.
As a final rant: scanf() does not "suck." It does what it does and that is all.
The gets() function is very dangerous (though convenient for no-risk applications), since it does not natively do any checking of the input. It is VERY commonly known as a point of exploit, specifically buffer overflow attacks, overwriting space in registers not allocated for that variable. Therefore if you choose to use it, spend some time putting some solid error checking/correction in.
However, almost invariably, either fgets() or POSIX getline() should be used to read the line — noting that the functions both include the newline in the input string, unlike gets(). You can remove the trailing newline from string read by either fgets() or getline() using string[strcspn(string, "\n")] = '\0'; — this works reliably.

Resources