User input from keyboard not loading??

People,

Just going through some quick exercises in Dr. Stroustrup's book "Principles & Practices..." and I am using code that HE gives for getting user input to fill a vector of integers. I print a simple message and then ask the user for numbers...

He has the following for simply filling vector<int> my_nums below. BUT, when I run this code the compiler has no problems and I fall straight throught this input loop without being able to input ANY integers. Did I miss something about user input using std::cin???


1
2
3
  for(int holding; std::cin>>holding;){
        my_nums.push_back(holding);
  }



Why does this not work as the god doctor suggests? The headers I am including in my program are as follows==>


#include <iostream>
#include <vector>
#include <exception>
#include <string>
#include <stdio.h>

This has GOT to be a simple mistake..... so what the heck y'all??

P.S. - I am getting back into C++ after a long hiatus so I am going through the book and exercises..... I feel like a tool! LOL

Xanadu
I put that loop in my editor, surrounded with main and a vector of nums.....did fine.

Post the entire thing instead.
Unless you've redirected stdin from a finite-length stream (like a file), how would that for- loop ever know when to stop?

EDIT: Ok, you could crash it by entering a letter or an asterisk or something, but then you are left having to clear up the stream afterward.
Last edited on
Ok kids,

Here is the FULL code (top to bottom)….. I'm using CodeBlocks (Ver 16.01) and compiler is set to C++14 ==>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <vector>
#include <exception>
#include <string>
#include <stdio.h>

using namespace std;

/* The program asks for a list of integers from the user and prints them using a function print_nums() after loading into a vector*/

void print_nums(const vector<int>&, const string&);  //declare print_nums()

int main()
{
    string label;  //user's phrase for labeling input numbers
    vector<int> my_nums;    //user vector of integers

    std::cout<<"Please give a units/label for your numbers: ";
    std::cin>>label;
    std::cout<<"\n\nPlease input your integers followed by RETURN to end: ";
    
    for(int holding; std::cin>>holding;){
            my_nums.push_back(holding);
    }

//didn't call print_nums() yet because I'm falling through the input above!!
   
    cout<<"Got past the for loop\n";  //simple print statement for checking..


    return 0;
}   //end main routine

void print_nums(const vector<int>& nums, const string& label){

    cout<<label<<"\n\n";

    for(unsigned int i=0; i<nums.size(); ++i){
        cout<<nums[i]<<"\n";
    }

}   //end of print_nums function 


Does this help to critique a little better? Again, I think I'm just supposed to be reading the input buffer but I am not sure I've redirected stdin in any way or have screwed something else up. But that's why I'm asking you guys! BTW, should I migrate AWAY from codeblocks and just get MS VisStudio or MS VisStudio CODE??

Let me know what you guys think!

And as usual..... thanks for the guidance and instruction for us morons! LOL

Xanadu
Just going through some quick exercises in Dr. Stroustrup's book "Principles & Practices..."
Which exercise from which chapter?

I am using code that HE gives
Which code from which chapter?

I fall straight throught this input loop without being able to input ANY integers

Your input seems fine, but, as lastchance said, it never stops.
You need <something> to stop it, for example a condition:
1
2
3
for(int holding; std::cin >> holding && holding != 0; /**/) {
    my_nums.push_back(holding);
}

In for(int holding; std::cin>>holding;),
the input operation std::cin>>holding; is used as the loop condition.

std::cin>>holding; evaluates to true if an integer is successfully read,
otherwise (if the input fails) it is false

To exit from this loop, enter a non-integer character (say an x) so that the input fails.
Hello Xanadu4ever,

When you enter a label what do you actually put? A single word or something that contains a space?

Andy
It's also worth asking... are you running this through some web application, through a local IDE (e.g. Visual Studio), or through the command-line directly?
Last edited on
Gentlemen,

I get this "for loop" to read-in integers from pages 122/123 in chapter 4.

NOW, he (the good Dr.) does use his OWN special header named: "std_lib_facilities.h".... so I am not sure if the header has something in in it that makes this all easier? (I am NOT using the header as you can tell from my code above - I simply use the standard headers we all have access to...).

Like JLBorges said.... I think the loop is designed to just stop when you DON'T input an integer..... so I will re-test that again. I will also try some other termination schemes as well. But I thought this would work and have no reason to believe why it shouldn't considering the author....????

Thanks for the help so far..... going to try some of these ideas and see what I get.

Xanadu
Hello Xanadu4ever,

Put your call to the function back it will not hurt to call it. It will help you understand what is happening though.

When you have put the function call back run the program an when asked for a label put My_Numbers. When the function is called it will print what it was able to put in the in the variable "label". Then rerun the program and put My Numbers. Then see what the function prints. This should give you an idea of what is happening. If not let me know.

Again, I think I'm just supposed to be reading the input buffer but I am not sure I've redirected stdin in any way or have screwed something else up.
No you have not redirected std in any way that I can see. And Yes you are working from the input buffer as the keyboard does not go directly into the variable. There is a hint in there.

NOW, he (the good Dr.) does use his OWN special header named: "std_lib_facilities.h".... so I am not sure if the header has something in in it that makes this all easier?
No I do not believe it adds anything special just header files that you may not need at this time. But it has been awhile since I looked at that header file to know all of what is in it. I feel that what you are doing is a better learning tool than to use something that is easy just because the person who wrote the book (I mean any book) wants to put off covering a topic until a later time, so they take the easy out. This also applies to the line using namespace std; // <--- Best not to use.

The for loop as designed is actually an endless loop as long as you enter a number each time. Pressing "Enter" just goes to the next line and waits for you to enter something more. Trying to enter a blank line does not work.

Ways out would be to press "Ctrl + d" (Unix/Linux) or "Ctrl + z" (Windows). This will signal "eof". Or enter something that is not a number. Understanding how the program works I just enter a letter when I am done to cause "std::cin" to fail and end the for loop. And "std::cin" is never used after the for loop it is not a problem.

Hope that helps,

Andy

Hello Xanadu4ever,

I forgot to mention.
should I migrate AWAY from codeblocks and just get MS VisStudio or MS VisStudio CODE??

CodeBlocks is good and many people use it. I use VS Community, the free version, because in the beginning it was the only IDE I knew about, but I find that the free version covers everything I need and has more features than I may ever use.

I would suggest not changing, but adding VS because you will find some differences between the two in the way they work.

A quick example is <iostream>, in VS, will eventually include the header files
1
2
3
4
5
<climits>
<cmath>
<cstdio>
<cstdlib>
<streambuf>

I have not checked the <iostream> in the MinGW compiler to see what they include, but it may be different.

Having two different compilers will allow you to check your programs in two different environments.

Hope that helps,

Andy
@Xanadu,

I’ve basically duplicated @Handy Andy’s findings here.

I put your code as is in Visual Studio 2019 CE.

It asked for labels, then “please input your integers…..”

Then it took integers, over and over. “Return” doesn’t stop it (it continues even if zero is the evaluation for holding).

I happen to know that consoles “end” input with ctrl-Z, so I entered ctrl-Z.

That ended input, and THEN I got the “Got past the for loop” message.

Probably according to plan, but….

Further, if I enter any letters, the input sequence ends, as @JLBorges states.

I decided to append the “print_nums” function, which prints the list from input.

The “special header” named “std_lib_facilities.h” isn’t really all that special. It would amount to a pre-compiled header collection of simple, standard library includes.

He’s just letting the details of which headers to include for a later chapter (harmless to skip ahead).

I’m not personally familiar with CodeBlocks (heard about it, but not used it). Like @Handy Andy, I use Visual Studio (several versions, some for particular project requirements) on Windows, Xcode on MAC (though I don’t actually like Xcode).

I can recommend Visual Studio. If you decide to try it, select among the options to install the Clang/LLVM compiler. Microsoft’s compiler is ok, but it’s behind relative to C++17 (fairly good up to C++14), but Clang/LLVM is a lot more current. There are also ways to install GCC (though GCC isn’t known for it’s optimizer, it is known to be among the first to implement all the new C++ features).

In my version of this book, Stroustrup does mention how these loops terminate.

He points out that the subject is dealt with in more depth by chapter 10.6, which also covers various error handling in streams.
Last edited on
Well folks,

That is odd then! And what I mean by ODD is that when I run it==>

1.) the use of cin ONLY grabs the first word in my label variable even though I type multiple space separated words and ending with a RETURN ...... NOT the whole phrase!! Is this to be expected if one does NOT use getline() instead?

2.) I do NOT get to input ANY integers! It literally drops right through that "for" loop and I see the final "Got past the for loop" message.

Here's what the output looks like (using an online compiler...) ==>

Please give a units/label for your numbers: The numbers you typed are==>


Please input your integers followed by RETURN to end: The

Got past the for loop



Now my question to you guys is...... WHY are you all able to get this to work and I can not?? This does NOT sound cool at all! Is this a compiler issue?

Urge to kill ....... RISING!!!

Xanadu
You've given us the key in this last post.

cin>>s

where S is a string will take input UP TO A SPACE AND STOP.

It will leave any additional WORDS separated by space for the next cin, which is now in your loop expecting integers.

Since the next WORD isn't an integer, it breaks the loop (this is described somewhere in Stroustrup's book)

So...it's working for you too. Just, still not what you're expecting, because "enter units label" is usually something like "ms" or "s" or "in" or "mm"....which, if you enter that, works more like you're expecting.

So, yes, even for us, if we answer the first question with any spaces and additional words, it works as written but does NOT take any integers....and that's by design
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <vector>
#include <string>

// The program asks for a list of integers from the user
// and prints them using a function print_nums() after loading into a vector

void print_nums( const std::vector<int>&, const std::string& );

int main() {

    std::string label;  //user's phrase for labeling input numbers
    std::cout << "Please enter a units/label for your numbers followed by RETURN: ";
    // std::getline: read  complete line of input (everything up to a new line)
    // http://www.cplusplus.com/reference/string/string/getline/
    std::getline( std::cin, label );

    std::vector<int> my_nums;    //user vector of integers
    std::cout << "\nPlease input your integers. End input "
              << "by entering any non-numeric character:\n" ;
    for( int holding ; std::cin>>holding ; ) my_nums.push_back(holding);

    print_nums( my_nums, label ) ;
}

void print_nums( const std::vector<int>& nums, const std::string& label ) {

    std::cout << "\n\n--------------\n" << label << "\n--------------\n" ;

    // range based loop: for every integer v in vector nums
    // http://www.stroustrup.com/C++11FAQ.html#for
    for( int v : nums ) std::cout << v << '\n' ;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;

void print_nums( const string &str, const vector<int>& V )
{
   cout << str << '\n';
   for ( int i : V ) cout << i << ' ';
   cout << '\n';
}

int main()
{
   string label, line;
   cout << "Enter a label: ";
   getline( cin, label );
   
   cout << "Enter a line of numbers, ended by return: ";
   getline( cin, line );
   stringstream ss( line );
   vector<int> nums;
   for ( int i; ss >> i; ) nums.push_back( i );

   print_nums( label, nums );
}


Enter a label: Just a demonstration
Enter a line of numbers, ended by return: 3 1 4 1 5 9
Just a demonstration
3 1 4 1 5 9 


That way:
(a) you don't need a sentinel to end the input (although you do need all numbers on one line);
(b) you don't need to clear up the stream afterwards, as you would need to do by ending it with non-numeric input should you need any more cin operations afterwards.

I can't see any good reason for putting stdin in a failed state if you don't have to.




Minor variant:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <sstream>
#include <vector>
#include <iterator>
#include <string>
using namespace std;

void print_nums( const string &str, const vector<int>& V )
{
   cout << str << '\n';
   for ( int i : V ) cout << i << ' ';
   cout << '\n';
}

int main()
{
   char sentinel = '*';
   string label, line;
   cout << "Enter a label: ";
   getline( cin, label );
   
   cout << "Enter numbers (on any number of lines), ended by " << sentinel << '\n';
   getline( cin, line, sentinel );
   stringstream ss( line );
   vector<int> nums( istream_iterator<int>{ ss }, {} );

   print_nums( label, nums );
}


Enter a label: This is a very bad demo
Enter numbers (on any number of lines), ended by *
1 2 3
4 5 6
7 *
This is a very bad demo
1 2 3 4 5 6 7 
Last edited on
@lastchange, "I can't see any good reason for putting stdin in a failed state if you don't have to."

It's a 101 course, a very early chapter, for a student just now learning C++.

While you've present a much better version, most of the material you posted in 6 chapters or more later in the OP's book
As Niccolo stated,

This is a rudimentary lesson I'm working on BUT thankfully I am completely following all of your suggestions and totally agree with the advice. I DID end up using "getline()" to get ALL of the user input and that naturally works so thanks for the confirmation that getline is in fact the way to go (as intuition pointed out!) and also re-writing that section with getline.

I am ABOUT to get into streams so Lastchance's suggestion is ALSO very apropos but like Niccolo and JLBorges are hinting at.... I'm trying to do this "by the book's lesson" and the current "level" for each chapter - but I DO agree with you guys that screwing up the input for the rest of the program is not desirable and will be looking forward to I/O streams in the next few chapters.

I'm going to drop JLBorges code VERBATIM into the compiler and see what goes down. I will report back to you guys what it does and HOPEFULLY it works and refuses to vomit. If not, I will let you know what problems I find.

Thanks again everyone for the input and concise advice! Too many times you ask for advice and people give you very convoluted or esoteric instructions (Essentially answering a completely different problem or re-writing it their own wayy) and you're stuck figuring out "what's wrong" on your own after reading a bunch of nonsense.

You guys didn't do that and I am grateful! You realize that me understanding WHY it is wrong is more important than the dumb little program or knowing about something I haven't explored yet! For that I am grateful.

I will have MORE rudimentary questions coming as I fumble through the chapter's exercises - but as you all said I'm learning more screwing it up than I would if I got it right first!! So please bare with me - I intend to get up to speed very quickly since I am getting BACK into C++ after a few years hiatus. Thankfully things are returning fast and I am tracking with you guys.

Good work people!

Xanadu
OK,

JLBorges code worked flawlessly on my compiler. As you all stated the initial use of "cin" screwed up the following use of the input buffer and totally messed up the outcome of the program even though the logic was correct from the book.

I dropped the code in verbatim and here is what I got when I put in a phrase and some test numbers==>

Please enter a units/label for your numbers followed by RETURN: Here's your numbers!==>

Please input your integers. End input by entering any non-numeric character:
52 89 56 -158 321 -78945 23 -54 l


--------------
Here's your numbers!==>
--------------
52
89
56
-158
321
-78945
23
-54


BTW, that terminating character is a lower case "L" and NOT a "1" just to put your minds at rest! NOT a good choice in retrospect!


So, thank you all for the advice and as you all aptly stated - it worked for me too..... it screwed up where it was supposed to due to a partially full buffer from before!

Xanadu
In a way, that was Stoustrup's purpose. He uses simple approaches to show what they do, and then explores improvements (by chapter 10, you're dealing with most of the solutions).
Topic archived. No new replies allowed.