c++ trap

Mar 11, 2022 at 2:45am
I'm a newbie to c++ but I have a background in python, but with that
Said, I have run into a bit of a snag with my toying around with c++.
Before I ask my question, I will show you my code first.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <string>

using std::cout;
using std::cin;
using std::endl;
using std::string;

int main(){
    
    // Generic input
    int x;
    cin >> x;
    cout <<"\n";
    cout << x * 42;
    
    // getline after generic input
    string y;
    getline(cin,y);
    cout << y;
    
    return 0;
}



So when I run the code this way, it will perform the
Math operation, however, it will not continue with the
rest of the // getline after generic input code. Why is that?
Also if I wrap that code into a function and try to run it, it gives me the word
trap after the math operation, and again, why?

Thanks ahead for any explanation!!!
Last edited on Mar 12, 2022 at 5:54pm
Mar 11, 2022 at 3:36am
After cin >> x; put a line cin.ignore(1000,'\n');
Somebody will come along and explain at great length or just google it.
Last edited on Mar 12, 2022 at 3:01am
Mar 11, 2022 at 7:04am
The problem is the use of the character '\n':

cin >> x;

leaves that character in the stream.

getline(cin,y);

will use by default '\n' to determine the end of the line. Due to the previous cin there is still a '\n' in the input stream and the getline(...) returns an empty string.

You can avoid this when writing:

cin >> x >> std::ws; // Note: std::ws removes '\n'
Mar 11, 2022 at 3:23pm
>> std::ws works as desired if the next input/output is via cin.

Unfortunately, it screws up the order of the input/output operations if (as here) the next input/output is via cout.

cin.ignore(1000,'\n); maintains the intended order.




Compare:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <string>

using std::cout;
using std::cin;
using std::string;
using std::ws;

int main()
{
   int x;
   cin >> x >> ws;
   cout << '\n';
   cout << x * 42;

   string y;
   getline( cin, y );
   cout << y;
}
10
Help

420Help 


and

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <string>

using std::cout;
using std::cin;
using std::string;

int main()
{
   int x;
   cin >> x;   cin.ignore( 1000, '\n' );
   cout << '\n';
   cout << x * 42;

   string y;
   getline( cin, y );
   cout << y;
}
10

420Help
Help 


Last edited on Mar 11, 2022 at 3:29pm
Mar 11, 2022 at 4:44pm
>> ignores proceeding white-space, extracts as per the type of the extraction variable and (assuming valid extraction) until a white space char is found. This terminating white-space char is NOT extracted.

getline() extracts all data until the specified terminating char is found (\n if none specified). It does not ignore proceeding white space and extracts and discards the terminating char.

From this you can see that these 2 don't play nicely together. If >> is followed by a getline() then the white space char left by >> is treated as an input char by getline(). If this is the getline() terminating char (such as \n) then getline() is terminated with no input obtained.

Note that >> followed by >> is OK and getline() followed by >> is OK. The issue is just when >> is followed by getline(). In this case the >> terminating char (usually \n) needs to be extracted from the stream before getline(). This is the purpose of using .ignore() in this context.

Also note that if there are no chars to ignore, then .ignore() will wait until there are. So only use before .getline() in this context when getline() is preceded by >>. Don't use between consecutive uses of getline() othereise you'll loose the first char from the second getline().
Mar 11, 2022 at 9:10pm
Hey everyone! Thanks a million for your replies. While I have not searched anything yet, you all have given me
Some food for thought. I think I kind of understand what is being said but I'll need to do some digging. Thx again!
DevTurtle


Mar 11, 2022 at 9:20pm
DevTurtle wrote:
Apologies if this doesn't format right

There are some resources/links you should read that can help:
PLEASE learn to use code tags, they make reading and commenting on source code MUCH easier.

http://www.cplusplus.com/articles/jEywvCM9/
http://www.cplusplus.com/articles/z13hAqkS/

HINT: you can edit your post and add code tags.

Some formatting & indentation would not hurt either
Mar 11, 2022 at 9:57pm
@lastchance, You could put the ws in the getline instead:
 
getline( cin >> ws, y );

Mar 12, 2022 at 4:02am
@OP std::ws is a red herring. On face value it 'works', maybe, but doesn't address your issue beyond being a hack.

The following, Error Case 2 in particular, gives a fairly definitive going over of the problem including how C++streams are designed to work. [Notably clear() and numeric limits haven't been mentioned here until now ;) ]

https://www.learncpp.com/cpp-tutorial/stdcin-and-handling-invalid-input/

Most ppl here will agree that learncpp isn't a bad reference along with stackoverflow and cplusplus tutorials and reference sections.

(PS: Despite the late edit, I missed the second "'" so it is '\n' not '\n in my above.)
Mar 12, 2022 at 11:40am
DizzyDon wrote:
@lastchance, You could put the ws in the getline instead:


I did try that @DizzyDon. But it actually does exactly the same as putting it in the cin>> statement.

In this instance, mixing cin and cout statements, buffering seems to mean that only cin.ignore() gives the order of input/output operations as coded.
Topic archived. No new replies allowed.