how scanf handles standard input vs pipelined input - c++

In the following code:
#include <cstdio>
using namespace std;
int N;
char x[110];
int main() {
scanf("%d\n", &N);
while (N--) {
scanf("0.%[0-9]...\n", x);
printf("the digits are 0.%s\n", x);
}
}
when I enter the input through file using command
./a.out < "INPUTFILE"
It works as expected but when I enter the input through std input it delay the printf function.
Why is that?
Input
3
0.1227...
0.517611738...
0.7341231223444344389923899277...
Output through file
the digits are 0.1227
the digits are 0.517611738
the digits are 0.7341231223444344389923899277
output through standard input
the digits are 0.1227
the digits are 0.517611738
The code is from a book, commpetitive programing 3 ch1_02_scanf.cpp.

Because there's an extra \n in your scanf format string, it will read and discard ALL whitespaces (spaces, newlines and tabs, if present). There needs to be an indication of the end of a whitespace sequence, so you should either hit Ctrl-D for EOF, or enter another non-WS character that lets scanf stop.
As Sid S suggests, you cam alternatively change your format string like this:
scanf(" 0.%[0-9]...", x);
The program works because when you redirect its stdin to a file, scanf will know if it reaches EOF and terminates the last input. You need to manually give an EOF when you type from console. That's the difference.

Change the second scanf() line to
scanf(" 0.%[0-9]...", x);

Related

I cant use two scanf function to Enter the letters

Why I cant use two scanf function to Enter the characters
for example
char a;
char b;
printf("a");
scanf("%c", &a);
printf("%c", a);
scanf("%c", &b);
printf("%c", b);
There are many solutions, but I want to know what is the reason why the2 scanf function does not work in characters
When you enter in a single character you're actually sending two characters to the program: the character you pressed and a newline character from when you pressed the Enter key.
Suppose you pressed "s" then Enter. The first scanf would read only the "s", leaving the newline in the input buffer. The second scanf will then immediately read the newline, which is then printed by the second printf.
If you entered two or more characters and pressed Enter, for example "abc" then Enter, the first scanf will read the "a" and the second scanf will immediately read the "b". The "c" and the newline will be left in the buffer when the program exits.
The procedure code of scanf is like that
scanf()
int readCount = 0;
copy data to buffer until newline
clear the keyboard buffer until newline
match the pattern and write to the vargs
for every pattern matched, readCount ++
return readCount;
Since every scanf will try to parse and clear the keyboard buffer until newline. so you cannot type 2 chars in the same line.
You can 2 easy solution for this.
1) scanf( "%c%c", &a, &b )
which is not general purpose
2) std::cin >> a >> b;
which is general purpose, but from my experience, this method is a bit slower than scanf.

why does my program skip steps using getline()?

I think my program skips steps because I use getline() inside While and For loops without using cin.clear() and cin.ignore(). If I'm right, where will I have to insert them?
I tried to write the code with cin.clear() and cin.ignore(10000, '\n') after each getline() (really I don't know how these functions work properly, I found them surfing on Google) and the code doesn't work correctly.
The code is :
main.cpp
#include <iostream>
#include <list>
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
#include <utility>
using namespace std;
int main(){
string S;
cout<<"insert test....input exaple: test 1"<<endl;
getline(cin, S);
while(S!="-1"){
cout<<"START WHILE"<<endl;
int nB = 0; //number of Lego Bricks;
cout<<"insert number of Lego bricks"<<endl;
cin>>nB;
for(int i=0; i<nB; i++){
cout<<"START FOR"<<endl;
cout<<"insert Lego brick (the number of faces must be even)....input example: NameBrick -> face1 face2 face3 face4...."<<endl;
getline(cin, S);
}
getline(cin, S);
}
return 0;
}
cout<<"insert number of Lego bricks"<<endl;
cin>>nB;
This is the problem. getLine() keeps reading until the next newline character. Let us say that '|' is our newline symbol.
When you write something into the terminal or when you are reading from file you have many lines to work through.
Example input(Greeting, name, age and hobby):
Hello.|
Magnus Elden|
24|
Tennis|
GetLine() will give you the entire line. The first call to getLine() will return the string "Hello." and stop since it reached a newline character, '|'.
The important part is that it stops AFTER the newline character.
Thus, the next time the first character it reads is the 'M' in "Magnus Elden".
When you get to the age part of the input, you use cin which only read the first item, be it a string or a number. As such it will stop BEFORE the newline character. The next time you call getLine() it reads until a newline character comes, but since the newline character still remains in the buffer getLine() returns immediately with "" as its return value.
That is why it seems to skip a step.
Step by step breakdown:
You input your greeting "Hello." and the buffer will then look like this:
Buffer:Hello.|
Let us say that the start of the reading is denoted by a ^. These are the steps.
Step 1.
Input:Hello.
Buffer:Hello.|
^
Function call:getLine()
Return value:"Hello."
Buffer:
Step 2.
Input:Magnus Elden
Buffer:Magnus Elden.|
^
Function call: getLine()
Return value:"Magnus Elden"
Buffer:
Step 3.
Input:24
Buffer:24|
^
Function call: cin
Return value:24
Buffer:|
Step 4.
Input:Tennis.
Buffer:|Tennis.|
^
Function call: getLine() //Remember that it runs until the first newline '|'.
Return value:""
Buffer:Tennis|
Just change the code bit to:
cout<<"insert number of Lego bricks"<<endl;
getLine(cin, s);
nB = atoi(s.c_str());
I hope this helps.
getline(cin,s) will do what you expect. The rest of the line (except the newline itself) is stored in s. And, crucially, the newline itself will be extracted and discarded.
So, if you call getline(cin,s) multiple times, each line will be read once, as you expect.
Similarly, assuming x in an int, cin >> x will read an integer. Multiple consecutive calls to cin >> x will read numbers from the input into x. Each time you call cin>>x it will skip over any whitespace before the number, then read the number. So, if you have a set of numbers, perhaps on the same line separated by spaces, or perhaps on different lines separated by newlines, then cin>>x will read them for you.
But it will not read-and-discard any whitespace after the number. Whitespace is discarded at the start of each call to cin>>x (i.e. before the number itself is read), but not after the number is read.
The problem occurs if you have a cin>>x followed by a getline. Imagine you type a number and then press enter. cin>>x will consume the number. but cin>>x will not consume the newline. Then, the getline will attempt to read the rest of the line. It will not try to read the next line. We're are still stuck on the same line as the number. You probably hit Enter immediately after entering the number, therefore the "rest of the line" is just an empty string.
There's a difference between "typing a number" and "typing a number followed by hitting the Enter key"
Thanks to all.
I solved replacing cin>> with getline how many of you suggested.
precisely:
cout<<"insert number of Lego bricks"<<endl;
cin>>nB;
with
cout<<"insert number of Lego bricks"<<endl;
getLine(cin, s);
nB = atoi(s.c_str());

skip a specific set of characters scanf is not defined?

I was reading the documentation of scanf function in this page http://en.cppreference.com/w/cpp/io/c/fscanf and I thought I understood it well until I try this
int main(){
char p[100],t[100];
scanf("%s : %s", p, t);
printf("%s %s", p, t);
}
for my input I used test : scanf for me, the result should be test : but I get test scanf where the scanf function skip the : I don't understand why, I think that nowhere explain, can someone explain me?
thanks
From cplusplus.com,
scanf reads data from stdin and stores them according to the parameter format which can only contain a white space character,a non-white space character and format specifier.
Whitespace character: the function will read and ignore any whitespace characters encountered before the next non-whitespace
character (whitespace characters include tab, space and newline).
Non-whitespace character, except format specifier (%): Any character that is not either a whitespace character (blank, newline or tab) or part of a format specifier (which begin with a %
character) causes the function to read the next character from the
stream.
Format specifiers: A sequence formed by an initial percentage sign (%) indicates a format specifier, which is used to specify the
type and format of the data to be retrieved from the stream and stored
into the locations pointed by the additional arguments.
So when you claim,
for my input I used test : scanf for me, the result should be
test : but I get test scanf where the scanf function skip the :
you are interpreting it wrong. scanf should skip the :(colon) or any character that you mention as its parameter. So when you provide an input like test CharachtersToSkip me with following code,
int main()
{
char p[100],t[100];
scanf("%s CharachtersToSkip %s", p, t);
printf("%s %s", p, t);
}
scanf will skip the characters and output only test me
Hope its clear.
if wants the out put "s=>test" only, then why you are print "t=>scanf"
just modify the code like that.
int main()
{
char p[100],t[100];
scanf("%s : %s", p, t);
printf("%s", p);
}
From the man page of scanf()
Matches a sequence of non-white-space characters;
The input string stops at white space or at the maximum field
width, whichever occurs first.
In this case, first %s will get the input until the white space character is occur. So your input is test : scanf. It will get the test for first input. Then it will skip the leading spaces, you are mentioning the : in scanf, so it will skip the colon :. Then get the next string.
For more example , try this code
int main()
{
int a;
scanf("%d ",&a);
printf("a:%d",a);
return 0;
}
In this code, scanf() don't end when you are giving the '\n' after the input.
It will wait for other than white space character occurs.

What's wrong with my program (scanf, C++)?

What wrong with this program?
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
using namespace std;
int N;
char x[110];
int main() {
scanf("%d", &N);
while (N--) {
scanf("0.%[0-9]...", &x);
printf("the digits are 0.%s\n", x);
}
return 0;
}
this is a console application in VS 2013, here is a sample input and output:
input :
1
0.123456789...
output
the digits are 0.123456789
but when I input this to this the output I get : The digits are 0
I have tried inputitng and manually and by text, in Code::Blocks and VS 2013, but neither worked. And when inputting manually, the program doesn't wait for me to input the numbers after I have entered N.
What should I do?
The scanf() in the loop fails, but you didn't notice. It fails because it can't handle a newline before the literal 0. So, fix the format string by adding a space, and the code by testing the return value from scanf():
if (scanf(" 0.%[0-9]...", x) != 1)
…oops — wrong format…
The blank in the format string skips zero or more white space characters; newlines (and tabs and spaces, etc) are white space characters.
You also don't want the & in front of x. Strictly, it causes a type violation: %[0-9] expects a char * but you pass a char (*)[100] which is quite a different type. However, it happens to be the same address, so you get away with it, but correct code shouldn't do that.
Replace
scanf("0.%[0-9]...", &x);
with
scanf(" 0.%[0-9]...", x);
You need to provide the starting location of the array which is x, not &x. Also, the space at the beginning will read all the whitespace characters and ignore it. So the \n left by scanf("%d", &N); is ignored.

scanf - program waits for another like?

In the following program, I expect that after entering a word and hitting the enter key I should immediately see the message printfed out. However, it doesn't happen until I enter some other random word. Why is that?
#include <cstdio>
#include <cstdlib>
using namespace std;
char tictac[17];
int main()
{
scanf("%s\n", tictac);
printf("%s\n", tictac);
return 0;
}
tl;dr: with scanf("%s\n", tictac); you are asking to read a string, ignore all blank characters after it and then a read a new line. The problem is since all blanks are ignored by the first one there should be a at least one non blank character between the first Enter and the second Enter (hence the need for some garbage non-blank input before the second Enter is accepted.).
Here is an example usage of \n with scanf.
char x, y;
scanf("%c", &x);
scanf("%c", &y);
printf("%c %c", x,y);
with this code you will see that entering one character and pressing Enter will directly go to the printf statement. This is because the second scanf reads the carriage return (which itself is a character) in to y.
scanf("\n%c", &y); // This is recommended to do if you have a sequence of scanfs (but not on the first one).
With this one the stray carriage return will be ignored (or matched) with \n. And the correct character will be read to y.
Now when we come to your code
scanf("%s\n", tictac);
%s tells scanf to read until it finds a blank character (space, tab or new line) and then here is the catch ignore all blank spaces till a non blank space character is met. So your scanf will ignore the Enter you pressed when you entered the string. And any blank character that follows it (try entering spaces on the second line and press enter.)
Which means this will work just fine (unlike the char version)
scanf("%s", tictac);
scanf("%s", tictac2);
Actually on Windows
Because "%s" causes the library to read the input string until it
finds some white space, the equivalent format specifier is
"%[^\0x20\t\n]", which instructs the library to read the string until
it encounters a space character (\0x20), a tab character (\t), or a
newline character (\n).
However since you have explicitly asked scanf to match \n
scanf("%s\n", tictac);
^^
it will wait until it gets another \n (after a non blank character) because the first one one was used by %s.
Drop the \n from your scanf call.
There's a good explanation of scanf here. In your case, you should remove the \n from your scanf function.