Cin not read my inputs - c++

It must be that I'm tired but I can't seem to figure out why my program will not read my cin values for init and end which is supposed to be a start and an end point for my program. The way its setup for input is the first line is the amount of cases then there will be a new line which will be a string then on the next line there will be two integers separated by a space so I feel the way I built it is correct but when I debug the code the values for init and end never change whether I initialize the variable or not.
int case_count;
string name;
int init = 0;
int end = 0;
cin >> case_count;
cin.ignore(numeric_limits<::streamsize>::max(),'\n');
for (int i = 0; i < case_count; ++i) {
cout << "Case " << i << "\n";
getline(cin, name);
cin.ignore(numeric_limits<::streamsize>::max(), '\n');
cin >> init;
cin >> end;
Example input
3
flap
1 3
swoop
0 9
flip
0 6
Its making it hard to continue with the rest of the code.

The problem is that you call ignore in the loop. The problem with this is that std::getline extracts (and throws away) the newline character, meaning your ignore call in the loop will read and discard the next line (the one with the two numbers).
Besides that, when using the input operator to read numbers or strings, the operator will skip leading white-space, so even if getline didn't read the newline, it would still have worked without the ignore call.
However, there is a newline left over in the input stream after you read the numbers, and the next iteration the std::getline call will pick up that newline and then name will be empty, so you should, as suggested by M.M in a comment, move the ignore call to last in the loop.

Related

How do I drop/ignore characters past a certain number in getline?

I am trying out dynamic memory allocation. I want to dynamically allocate memory, enough for a string of 10 characters. If the user inputs more than 10, I only want 10 characters pulled in getline (plus the newline character, I suppose) and subsequently stored in correct size dynamic memory, printed, and deleted. Below is my code:
#include <iostream>
using namespace std;
int main() {
char cont = 'N';
do{
char *input = new char[11];
cout << "This program dynamically allocates memory for a string of
characters up to 10 in length\n";
cout << "Enter a string less than or equal to 10 characters:\n";
cin.getline(input, 11, '\n');
cout << "Your string is:\n";
cout << input << endl << endl;
delete input;
cout << "Would you like to enter another? \"Y\" to continue\n";
cin >> cont;
cin.ignore();
} while (toupper(cont) == 'Y');
Everything works fine if the user inputs up to 10 characters. It can repeat forever.
However if the user inputs more than 10 characters the program does not prompt the user to continue and instead just ends. ABCDEFGHIJ works but ABCDEFGHIJK breaks.
I thought this is because there is still something in cin that is being read in to input, which is not 'Y' and the program therefore ends. However if you go through one loop and set cont to 'Y' first, and then input ABCDEFGHIJK, the program goes infinite without ever inputting anything to overwrite 'Y'.
Another thing I noticed is getline seems to pull the correct amount of characters it stores characters ABCDEFGHIJ in input, even if ABCDEFGHIJK was entered.I thought perhaps 'K' was left in cin, so I tried ABCDEFGHIJY but 'Y' was not saved in to cont.
I also tried various cin.clear() variations before the next prompt for input, and nothing worked.
I think I am misunderstanding how getline works with the overload I am using.
First let me tell you, that doing this with a string is a ton easier, but if you want to do it the hard, allocating way...
Problem:
When you read with std::cin, and some condition isn't met, for example, reading a string as an int, or running out of specified characters, the failbit is set. This makes your istream look crazy
Fix:
Put a check after the getline call, test if the fail bit is set, if it is, reset the flags.
/* ... */
cin.getline(input, 11, '\n'); // Read input
if ( cin.fail() ) { // Check if getline failed
// -- > Remind the user of the limits here < --
// Clear flags
cin.clear();
cin.ignore();
}
/* ... */
Your getline variation has the arguments: char_type * Output, std::streampos MaxLength, char_type Delimeter. Sets failbit if the number of bytes to read is greater than the maximum length (AFAIK).
Sources:
std::basic_istream::fail()
std::basic_istream::getline()
Wish luck with your dynamic allocations, COlda

Possible to have multiple while (cin>>input)

I would like to know if it's possible to have multiple while (cin>>(variable)) as in the following code:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v1, v2;
int input;
while (cin>>input)
v1.push_back(input);
while (cin>>input)
v2.push_back(input);
return 0;
}
The logic of my program is to let user define the number of elements and value of each element in two sets of int vectors.
However, I realized that after entering the first set of numbers for the first vector (ending with an EOF), I'm unable to enter the second set of numbers for the second vector and the program terminates promptly. I suspect that EOF meant for the first cin for the first vector was processed by the second cin for the second vector as well.
Is there any way for the program above to run correctly i.e. having more than one while (cin)?
When you do while (cin>>input) you are effectively asking the input stream cin to produce integers until the stream has gone bad (i.e. an EOF was encountered, the steam was unable to convert the user's input to an integer, or maybe there was another problem).
After the loop terminates the state of the stream will still be in whatever state caused it to stop the loop. In order to continue reading from cin until another EOF token is encountered you will need to first clear the eof fail bit, this can be done (as πάντα ῥεῖ points out) by using cin.clear(). However, you should check the state of cin first, in case the input failed for another reason (perhaps the user entered a word instead of a number).
Two options might be: check that only the eof bit was set, or you can only unset the eof bit:
if (cin.eof())
{
std::cout << "Yay, reached an EOF" << std::endl;
}
cin.clear(std::ios_base::eofbit);
You need to call cin.clear(); after it was ended with EOF (i.e. CTRL-D or CTRL-Z), to reuse it again.
This while loop reads until the end of the file has been reached.
There is nothing more after the end, so any further read will fail.
You have to design another way so your program knows (i.e., has a condition) when the first set of numbers has finished.
There are usually two options:
read the number of values first
int count;
std::cin >> count;
for (int i = 0; i < count; i++) {
std::cin >> input;
v1.push_back(input);
}
// read into v2 …
or have a delimiting value, i.e. a special value that is not valid. In this case, I will take negative numbers as invalid.
std::vector<int> *v_input = &v1; // first read to v1
while (std::cin << input) {
if (input >= 0)
v_input->push_back(input);
else {
// invalid value, thus push numbers to the next vector
if (v_input == &v1)
v_input = &v2;
else
// invalid value while reading values for v2 - do not read any more lines
break;
}
}
However, you could also first read whole lines as a string and test, e.g., if the string is empty. If yes, input values to v2 instead of v1. Of the input is not empty, convert to int and push to the current vector.

cin.getline() skipping first iteration

I'm practicing with c string / pointers and can't solve this simple problem. cin.getline() isn't prompting user input for the first iteration, but does so for the consecutive strings. (I arbitrarily chose 10 as the char limit).
Am I overlooking something extremely simple?
void getStrings() {
int num;
cout << "How many strings? ";
cin >> num;
const int numStrings = num;
char** stringSet = (char**) malloc(numStrings * sizeof(char*));
for (int i = 0; i < numStrings; i++) {
*(stringSet + i) = (char*) malloc(10);
cout << "String " << i << ": ";
cin.getline(stringSet[i], 10);
cout << endl;
}
Setting aside the fact that it's generally inadvisable to use bare pointers in C++ when things like the standard library's std::string are available, you should not use malloc. For example: Instead of (char*) malloc(10), you should write new char[10] and remember to delete[] *(stringSet+i) at the end of your program.
That said, the line:
cin >> num
... extracts only the first number it comes across. It will fail (and cin will set its fail bit, and will need to be reset with cin.reset()) if it encounters any non-whitespace characters before it encounters a number.
But it stops extracting from the input after that. In your input stream is still whatever whitespace or other characters were still present in your input. For example, if you ran this program and typed "2 foobar" before pressing enter, it would immediately print:
String 1: foobar
String 2:
This is because the stream still contains "foobar\n".
In order to get the behavior you're looking for you will probably want to add this before your loop:
cin.ignore();
That will clear the stream of anything that's there.
cin >> num;
This will prompt the user for some input. Assuming the user does what's expected of them, they will type some digits, and they will hit the enter key. The digits will be stored in the input buffer, but so will a newline character, which was added by the fact that they hit the enter key. cin will parse the digits to produce an integer, which it stores in the num variable. It stops at the newline character, which remains in the input buffer. Later, you call getline, which looks for a newline character in the input buffer. It finds one immediately, so it doesn't need to prompt the user for any more input. So it appears that the first call to getline didn't do anything, but actually it did.
What do you mean by " isn't prompting user input for the first iteration"? I read that to mean "isn't printing the prompt for the input of the first string", but based on your code, I think it means "is printing the prompt for the input of the first two strings before it reads input."
cin >> num reads a number, the whole number, and nothing but the number. It does not read whatever follows the number, like a newline. So the first getline reads the newline character which you've already typed.
By the way, you should use cerr instead of cout for user prompts.
cout should be reserved for actual output. That makes scripting much easier, because you can redirect cout independent of cerr, and because you don't want to capture prompts in the program results anyway.

Is there a way to have user input multiple char arrays at once c++

I currently have a function that takes a array of 4 characters and returns another value based on that sequence of characters.
What I want is to have the user input a whole line of characters and then create a loop to go over each "sub- group of characters" and then return the result for all of them.
My initial thinking is to somehow use push_back to keep adding the arrays to a vector.
I don't know how long the entire array will be, but it should be a product of 3.
As an example, right now I am able to do :
char input [4] ;
cin >> input;
int i = name_index[name_number(input)];
cout << name[i].fullName;
But what I would like is the user ti input multiple name abbreviations at once
I would change your sample from this:
char input [4] ;
cin >> input;
int i = name_index[name_number(input)];
cout << name[i].fullName;
To this:
string input;
cin >> input;
const int i = name_index[name_number(input)];
cout << name[i].fullName;
Then you can start using a vector to track multiple inputs:
vector<string> inputs;
string line;
while (cin >> line)
{
if (line == "done")
break;
inputs.push_back(line);
}
for (unsigned int i = 0; i < inputs.size(); ++i)
{
cout << "inputs[" << i << "]: " << inputs[i] << endl;
//const int index = name_index[name_number(inputs[i])];
//cout << name[index].fullName;
}
You asked for an explanation of line. The line while (cin >> line) tries to take text from the standard input and put it into line. By default, this will stop when it encounters whitespace (space, tab, return, etc.) If it succeeds, then the body of the while loop is executed and we add what was input to the vector. If not, then we assume we're at the end of input and stop. We can then process the vector. (In the code linked below, I just output it since I don't know what name_index or name_number are.
(Working code here)
The way cin works, is it will accept any amount of input and separate them each by spaces, when you ask for specific input it prompts the user to give input, and then only takes the very first string (up until the space). If there are any more input after that, another cin >> input will just retrieve that value without prompting the user again. You can tell when the actual end of the input is reached when there is only a newline character left. This code should allow you to type in multiple strings separated by spaces and then process them all at once after the user enters the text:
char input[4];
do // Start our loop here.
{
// Our very first time entering here, it will prompt the user for input.
// Here the user can enter multiple 4 character strings separated by spaces.
// On each loop after the first, it will pull the next set of 4 characters that
// are still remaining from our last input and use it without prompting the user
// again for more input.
// Once we run out of input, calling this again will prompt the user for more
// input again. To prevent this, at the end of this loop we bail out if we
// have come accros the end of our input stream.
cin >> input;
// input will be filled with each 4 character string each time we get here.
int i = name_index[name_number(input)];
cout << name[i].fullName;
} while (cin.peek() != '\n'); // We infinitely loop until we reach the newline character.
EDIT: Also, keep in mind that allocating only 4 characters to input does not account for the end of string character '\0' that will be tacked on the end. If the user inputs 4 characters then it will actually access bad memory when it assigns the string to your input. There are 4 characters + 1 end character which means you need a minimum of 5 characters allocated for your input. The best way is to just use std::string as it will size itself properly even if the user enters more than 4 characters.

My for loop is executing more times than is expected

I have the following for loop executing within my program and I can't see how it's design correlates with the output I'm receiving.
cout << no_of_lines << endl;
for (int count = 0; count < no_of_lines + 1; count ++)
{
getline(Device, line, '=');
cout << line << endl;
}
This is the output:
3
DeviceName
GPU
Manufacturer
Intel
GraphicalRam
128MB
And this is the file DeviceList
DeviceName=GPU
Manufacturer=Intel
GraphicalRam=128MB
In the loop, no_of_lines refers to the number of lines in the file, in this case 3. I have provided this output as verification that the loop is only executing once per line. Can anyone tell me why this loop is executing more times than is expected? I'm guessing it's because of my inclusion of = as the deliminator, and that the loop is somehow executing an additional time before incrementing, but then why does it stop on the deliminator on the last line, requiring me to add 1 to the loop limit?
This http://www.cplusplus.com/reference/string/getline/ is your friend here. The documentation says that when delem character is passed to getline, it reads up to delem char is found or end of file is reached. '\n' is not treated differently. Once it find delem char it discards it and fills line whatever it read until that point. Next time you call getline, it continues to read from where it left. so in this case, each call reads as follows.
DeviceName
GPU\nManufacturer
Intel\nGraphicalRam
128MB\n
'\n' in the above string is basically newline character. it's not really backslash followed by n (2 characters). its just single newline character '\n'. Just for understanding purposes I used it that way.
For clarity, here is the complete code(compiled and tested).
#include <iostream>
#include <string>
using namespace std;
int main()
{
int no_of_lines = 3;
string line;
cout << no_of_lines << endl;
for (int count = 0; count < no_of_lines + 1; count++)
{
getline(cin, line, '=');
cout << line << endl ;
}
return 0;
}
By now I hope its clear to you why you need to call getline 4 times.
your loop executes no_of_lines+1 times.
I assume you want the delimiter to be '='. However, when the delimiter is '=', then \n is not a delimiter. Hence line will contain \n (say, on the second getline). And so the number of lines displayed is not equal to the number of times the loop executes.
When you use = as line delimiter, \n is not used as line delimiter.
So you get strings containing newline characters.
When you output such a string, it's presented as two or more lines (due to the newlines it contains).
Cheers & hth.,
You want it to count thrice, but your loop is counting 0,1,2,3,4, i.e 5 iterations.