C++ if condition not checked after goto - c++

I'm working on a simplish game (this isn't the whole code, just the bit that I'm having issues with) and I've run into this issue; After the condition is furfilled, it goes back to the start and it offers me to reenter the string, however, whatever I enter, I just get 'Not Valid'. Does anyone know why? I'm using the GNU C++ Compiler.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string command;
mainscreen:
cout << "blab";
getlinething:
cin.ignore();
getline(cin, command);
if (command == "task")
{
goto mainscreen;
}
else
{
cout << "Not valid.";
goto getlinething;
}
return 0;
}

When I run your code with a debug print it shows that each time you read a new command you are loosing the first char of the string. In fact, when I remove your cin.ignore() it works fine.
Also, have a look at this while to see if it fits your needs:
cout << "blab";
while(1){
getline(cin, command);
if(command == "task"){
cout << "blab";
getline(cin, command);
}
else{
cout << "Not valid.";
}
}

For debugging purpose at least, why not do
cout << "'" << command << "' Not valid" << endl ;

Alright, I tested it out. Without cin.ignore(), I cannot enter the data into the string at all.
The first time I enter it captures everything. So if I wrote task, the string would say 'task', however the second time I entered it, it would say 'ask'. I don't really know why it's doing that.

The cin.ignore() line will always discard one character by default (unless it encounters EOF, which would be a fairly deliberate act on cin).
So, let's say the user enters task and then hits the enter key. The cin.ignore() will discard the 't', and the command string will contain "ask". If you want to get a match, the first time through, the user will need to enter ttask. The newline will be discarded, in either case. The same will happen until a match is encountered.

Related

Understanding why unwanted iterations of a cout statement occur [duplicate]

This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Closed 3 years ago.
I am working with some C++ code. I have a while-loop set up to allow me to run through some code x-number of times. The while loop terminates once the user indicates that they do not want to run through the code again.
#include <iostream>
#include <string>
using namespace std;
char request;
int main() {
while (request != 'N')
{
string getCode = "";
while (getCode.length() != 3)
{
cout << "Please enter your container's region code (A or B followed by two-number identification)" << endl;
getline(cin, getCode);
if (getCode.length() != 3)
{
cout << "Error" << endl;
}
}
//clear the screen
system("cls");
//get letter
if (getCode.at(0) == 'A' || getCode.at(0) == 'B')
{
if ((getCode.at(1) >= '0' && getCode.at(1) <= '9') && (getCode.at(2) >= '0' && getCode.at(2) <= '9'))
{
if (getCode.at(0) == 'A')
{
cout << "The shipping charge is $25" << endl;
}
else if (getCode.at(0) == 'B')
{
cout << "The shipping charge is $30" << endl;
}
}
else
{
cout << "Error" << endl;
}
}
else
{
cout << "Error...Please enter the code as A or B followed by two numbers" << endl;
}
//Again?
cout << "Would you like to enter in another shipping identification number?" << endl;
cin >> request;
}
cout << "Thank you" << endl;
//End Program
system("pause");
return 0;
}
When I indicated that yes (entering 'Y' to the 'Would you like to enter in another shipping identification number question') I would like to run through the code again, the program outputs an unwanted 'Please enter your container's region code (A or B followed by two-number identification' and 'error' statement. Also please note, the code is inside 'int main()' and that I have properly formatted my 'include' statements.
Your question is to understand why this is happening, so here's the explanation. The code you wrote states thusly:
string getCode = "";
while (getCode.length() != 3)
{
cout << "Please enter your container's region code...
As you see, getCode is always initialized to an empty string. Immediately afterwards, if its length is not 3, this question is outputted.
You need to understand that your computer will always do exactly what you tell it to do. Your computer will not do what you want it to do, but only what you tell it to do. The above is what you told your computer to do, and your computer will always obediently follow its strict instructions, every time it runs this code. That's pretty much the explanation, and there's nothing more to understand.
This section of code is inside another loop, and you indicated that you do not wish the prompt to appear on second and subsequent iteration of the loop, only on the initial one.
However, there's nothing in your instructions to your computer, above, that specify this. You didn't tell your computer that this is what it should do, so why do you expect your computer to do that, entirely on its own? Every time your computer executes these statements shown above, this is exactly what will happen. Nothing more, nothing less. Whether it's the first time inside the outer while loop, or on each subsequent time the while loop iterates, it doesn't matter. The code always does exactly the same thing: getCode gets created and set to an empty string, and because its length is not 3, the inner while loop runs, prints the prompt and calls std::getline to read a line of text from std::cin. At the end of your while loop, if your instructions to your computer indicate that it should run the code in the while loop again, from the beginning (because that's what the while loop does), then the above instructions get executed.
If you now understand why your computer does this (because that's what you told it to do), then you should easily figure out what to tell your computer so it doesn't do this. If you want your computer to print the prompt only the first time it executes the while loop, then this is exactly what you need to tell your computer: set a flag before the while loop, print the prompt only if the flag is set (with all other existing logic remaining the same), and then clear this flag afterwards, so the next time the while loop runs, your computer will do exactly what you told it to do, and not print the prompt.
when I indicate 'Y' to the prompt 'Would you like to enter in another shipping identification number?', it outputs the following: 'Please enter your container's region code (A or B followed by two-number identification)' 'error' 'Please enter your container's region code (A or B followed by two-number identification' . When I input 'Y' I only want it to output 'Please enter your container's region code (A or B followed by two-number identification)'...I only want it to output once
Now that I understand your question, what's happening is an newline (\n) is getting added to the std::cin buffer at these lines right here:
//Again?
cout << "Would you like to enter in another shipping identification number?" << endl;
cin >> request;
This makes even more sense especially when combined with your other comment:
Before int main() there should be a 'char request;
So request a single char. That means when you type something like this:
Y
The newline is added to std::cin as well. That can't be stored in a single char, and the >> may not remove it either. That means it's just sitting here.
What this does is when you get to your if statement at the beginning of the loop again:
while (request != 'N')
{
string getCode = "";
while (getCode.length() != 3)
{
cout << "Please enter your container's region code (A or B followed by two-number identification)" << endl;
getline(cin, getCode);
if (getCode.length() != 3)
{
cout << "Error" << endl;
}
}
getline() sees the newline you added previously and instantly returns an empty string. Empty strings have a length of 0, so it fails your if statement, which prints the error.
The solution is simple, just tell std::cin to ignore the newline:
//Again?
cout << "Would you like to enter in another shipping identification number?" << endl;
cin >> request;
cin.ignore(1, '\n');

Why is this code exiting at this point?

I'm new to C++. I stumbled upon one tutorial problem, and I thought I'd use the few things I have learnt to solve it. I have written the code to an extent but the code exits at a point, and I really can't figure out why. I do not want to go into details about the tutorial question because I actually wish to continue with it based on how I understood it from the start, and I know prospective answerers might want to change that. The code is explanatory, I have just written few lines.
Here comes the code:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
double average_each_student() {
cout << "\n>Enter your scores seperated by spaces and terminated with a period\n"
<< ">Note: scores after total number of six will be truncated.\n"
<< endl;
double sum = 0, average = 0;
int user_input, counter = 0;
const double no_of_exams = 6;
while(cin >> user_input) {
++counter;
if(counter < 5) sum += 0.15 * user_input;
else if(counter > 4 && counter < 7) sum += 0.20 * user_input;
}
return sum / no_of_exams;
}
int reg_number() {
cout << "Enter your registration number: " << endl;
int reg_numb;
cin >> reg_numb;
return reg_numb;
}
int main() {
vector<int> reg_num_list;
vector<double> student_average;
reg_num_list.push_back(reg_number());
student_average.push_back(average_each_student());
string answer;
cout << "\n\nIs that all??" << endl;
//everything ends at this point.
//process returns 0
cin >> answer;
cout << answer;
}
The code exits at cout << "\n\nIs that all??" << endl;. The rest part after that is not what I intend doing, but I'm just using that part to understand what's happening around there.
PS: I know there are other ways to improve the whole thing, but I'm writing the code based on my present knowledge and I wish to maintain the idea I'm currently implementing. I would appreciate if that doesn't change for now. I only need to know what I'm not doing right that is making the code end at that point.
The loop inside average_each_student() runs until further input for data fails and std::cin gets into failure state (i.e., it gets std::ios_base::failbit set).
As a result, input in main() immediately fails and the output of what was input just prints the unchanged string. That is, your perception of the program existing prior to the input is actually wrong: it just doesn't wait for input on a stream in fail state. Since your output doesn't add anything recognizable the output appears to do nothing although it actually prints an empty string. You can easily verify this claim by adding something, e.g.
std::cout << "read '" << answer << "'\n";
Whether it is possible to recover from the fail state on the input stream depends on how it failed. If you enter number until you indicate stream termination (using Ctrl-D or Ctrl-Z on the terminal depending on what kind of system you are using), there isn't any way to recover. If you terminate the input entering a non-number, you can use
std::cin.clear();
To clear the stream's failure stated. You might want to ignore entered characters using
std::cin.ignore(); // ignore the next character
or
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// ignore everything up to the end of the line
use cin.clear(); before cin >> answer; That will fix the problem. But you are not controlling the input. it just runs out to cin..

Why is cout printing twice when I use getline?

I'm trying to read in a string of text using getline. For some reason, it prints 'Please enter your selection' twice:
Please enter your selection
Please enter your selection
If I key invalid text, it loops again, and only prints the one time each loop thereafter.
while (valid == false) {
cout << "Please enter your selection" << endl;
getline (cin,selection);
// I have a function here which checks if the string is valid and sets it to true
// if it is valid. This function works fine, so I have not included it here. The while
// look breaks correctly if the user enters valid input.
}
Does anybody have any idea why this may be occurring?
Thank you
Probably there's something still in the input buffer from a previous operation when you enter the loop.
It's picked up by the getline, found to be invalid, then the loop runs again.
By way of example, let's say that, before you enter the loop, you read a single character. But, in cooked mode, you'll need to enter the character and a newline before it's actioned.
So, you read the character and the newline is left in the input buffer.
Then your loop starts, reads the newline, and deems it invalid so it then loops back to get your actual input line.
That's one possibility though, of course, there may be others - it depends very much on the code before that loop and what it does with cin.
If that is the case, something like:
cin.ignore(INT_MAX, '\n');
before the loop may fix it.
Alternatively, you may want to ensure that you're using line-based input everywhere.
Here's some code to see that scenario in action:
#include <iostream>
#include <climits>
int main(void) {
char c;
std::string s;
std::cout << "Prompt 1: ";
std::cin.get (c);
std::cout << "char [" << c << "]\n";
// std::cin.ignore (INT_MAX, '\n')
std::cout << "Prompt 2: ";
getline (std::cin, s);
std::cout << "str1 [" << s << "]\n";
std::cout << "Prompt 3: ";
getline (std::cin, s);
std::cout << "str2 [" << s << "]\n";
return 0;
}
Along with a transcript:
Prompt 1: Hello
char [H]
Prompt 2: str1 [ello]
Prompt 3: from Pax
str2 [from Pax]
in which you can see that it doesn't actually wait around for new input for prompt 2, it just gets the rest of the line you entered at prompt 1, because the characters e, l, l, o and \n are still in the input buffer.
When you uncomment the ignore line, it acts in the manner you'd expect:
Prompt 1: Hello
char [H]
Prompt 2: from Pax
str1 [from Pax]
Prompt 3: Goodbye
str2 [Goodbye]
I would use debugger (for example gdb in linux) to check why. Why make a theories when you can find out the real answer?

Using cin.get() in a tight loop

I'm not new to programming, but I am relatively new to C++. I would like to distribute simple console applications so I can help others as I learn. The vast majority of machines on the campus of my university are windows based, and have the Borland compiler installed by default. I prefer to do my development on a Linux-based system with g++ and other tools. So I'd like to add some cross-platform way of leaving the program running until the user presses enter. That way, the user is able to view the output even if he or she double clicked on the exe rather than running it in the console in windows. To do this, I wrote something similar to:
#include <iostream>
using namespace std;
int main()
{
float val1, val2;
bool wait = true;
cout << "Please enter the first value to add: ";
cin >> val1;
cout << "Please enter the second value to add: ";
cin >> val2;
cout << "Result: " << val1 + val2 << endl << endl;
cout << "Press enter to exit...";
while (wait)
{
if (cin.get() == '\n')
wait = false;
}
return 0;
}
Using the code above, the program exits after displaying the result. However, if you comment out the cin calls, it works as expected. This leads me to believe that cin.getline is picking up my enter key press from my last data entry. I suspect this is due to the tightness of the loop. I have learned that there is no cross-platform sleep function in C++, so that is not an option. What else can I do to make this work?
You can add
cin.ignore(1);
or
cin.ignore(INT_MAX, '\n');
before you call cin.get(). This will ignore the newline left from the user entering the second number or all the characters in the buffer until a newline.
Also you neither need to compare the return value of get to '\n' nor put it in a loop. The user has to hit enter for get to return, so
cout << "Press enter to exit...";
cin.ignore(INT_MAX, '\n');
cin.get();
Is sufficient.
What happens if you do
cout << "Press enter to exit...";
while (wait)
{
if (cin.get() == '\n')
wait = false;
}
Is that the loop is entered, and cin.get() is called. The user can enter any amount of text at the console as he wants. Say they entered
Hello
in the console. Then the user presses the Enter key. cin.get() returns H, and ello\n is still left in the buffer. You compare H with \n and see that they are not equal, continue the loop. cin.get() is called and since there is already text in the buffer, returns e immediately. This loop continues wasting time until it gets to the last character of the buffer which is \n and it compares true with \n so the loop breaks. As you can see, this is a waste of time.
If you do put cin.get() in a loop and compare the return value of it with \n, there is also the danger of cin coming to an end-of-file before an \n is encountered. I believe the effect of this on your program would be an infinite loop, but I'm not sure since I can't try it on Windows.
Also, even though you don't need to use a loop in the first place, you are wasting even more time with a bool because you could reduce the loop to
while (true)
if (cin.get() == '\n') break;
After cin >> you should ignore all the characters in the buffer until the `\n' with
#include <limits> // for std::numeric_limits as indicated by Marlon
std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
Then you can wait for the next line with:
cout << "Press enter to exit...";
cin.get();

Ignore Spaces Using getline in C++ [duplicate]

This question already has answers here:
Need help with getline() [duplicate]
(7 answers)
Closed 7 years ago.
Hey, I'm trying to write a program that will accept new tasks from people, add it to a stack, be able to display the task, be able to save that stack to a text file, and then read the text file. The issue comes when I am trying to accept input from the user, whenever you enter a string with a space in it, the menu to choose what to do just loops. I need a way to fix this. Any help would be greatly appreciated.
// basic file io operations
#include <iostream>
#include <fstream>
#include <stack>
#include <string>
using namespace std;
int main () {
//Declare the stack
stack<string> list;
//Begin the loop for the menu
string inputLine;
cout << "Welcome to the to-do list!" << endl;
//Trying to read the file
ifstream myfile ("to-do.txt");
if(myfile.is_open()){
//read every line of the to-do list and add it to the stack
while(myfile.good()){
getline(myfile,inputLine);
list.push(inputLine);
}
myfile.close();
cout << "File read successfully!" << endl;
} else {
cout << "There was no file to load... creating a blank stack." << endl;
}
int option;
//while we dont want to quit
while(true){
//display the options for the program
cout << endl << "What would you like to do?" << endl;
cout << "1. View the current tasks on the stack." << endl;
cout << "2. Remove the top task in the stack." << endl;
cout << "3. Add a new task to the stack." << endl;
cout << "4. Save the current task to a file." << endl;
cout << "5. Exit." << endl << endl;
//get the input from the user
cin >> option;
//use the option to do the necessary task
if(option < 6 && option > 0){
if(option == 1){
//create a buffer list to display all
stack<string> buff = list;
cout << endl;
//print out the stack
while(!buff.empty()){
cout << buff.top() << endl;
buff.pop();
}
}else if (option == 2){
list.pop();
}else if (option == 3){
//make a string to hold the input
string task;
cout << endl << "Enter the task that you would like to add:" << endl;
getline(cin, task); // THIS IS WHERE THE ISSUE COMES IN
cin.ignore();
//add the string
list.push(task);
cout << endl;
}else if (option == 4){
//write the stack to the file
stack<string> buff = list;
ofstream myfile ("to-do.txt");
if (myfile.is_open()){
while(!buff.empty()){
myfile << buff.top();
buff.pop();
if(!buff.empty()){
myfile << endl;
}
}
}
myfile.close();
}else{
cout << "Thank you! And Goodbye!" << endl;
break;
}
} else {
cout << "Enter a proper number!" << endl;
}
}
}
You have to add cin.ignore() right after options is chosen:
//get the input from the user
cin >> option;
cin.ignore();
And cin.ignore() is not necessary after your getline:
getline(cin, task); // THIS IS WHERE THE ISSUE COMES IN
//cin.ignore();
The problem is in options - if you didn't call cin.ignore() after it, options will contain end of line and loop will continue...
I hope this helps.
Don't do this:
while(myfile.good())
{
getline(myfile,inputLine);
list.push(inputLine);
}
The EOF flag is not set until you try and read past the EOF. The last full line read read up-to (bit not past) the EOF. So if you have have zero input left myfile.good() is true and the loop is enetered. You then try and read a line and it will fail but you still do the push.
The standard way of reading all the lines in a file is:
while(getline(myfile,inputLine))
{
list.push(inputLine);
}
This way the loop is only entered if the file contained data.
Your other problem seems to stem from the fact that you have:
std::getline(std::cin,task); // THIS is OK
std::cin.ignore(); // You are ignoring the next character the user inputs.
// This probably means the next command number.
// This means that the next read of a number will fail
// This means that std::cin will go into a bad state
// This means no more input is actually read.
So just drop the cin.ignore() line and everything will work.
Instead of using ">>" directly on your stream you might consider using getline and then attempting to fetch your option from that. Yes, it's less "efficient" but efficiency isn't generally an issue in such situations.
You see, the problem is that the user could enter something silly here. For example, they could enter something like "two", hit enter, and then your program is going to pitch a fit as it happily continues trying to decipher an empty option over and over and over and over again. The user's only recourse the way you have it set up (and the way those recommending use of ignore() are recommending) is to kill your program. A well behaved program doesn't respond in this way to bad input.
Thus your best option is not to write brittle code that can seriously break down with the most modest of user ignorance/malfunction, but to write code that can handle error conditions gracefully. You can't do that by hoping the user enters a number and then a newline. Invariably, someday, you'll bet poorly.
So, you have two options to read your option. First, read a full line from the user, make sure the stream is still good, and then turn the string you get into a stream and try to read your integer out of it, making sure this other stream is still good. Second option, attempt to read a number, verify that the stream is still good, read a line and make sure the stream is still good and that your string is empty (or just ignore it if it isn't, your choice).
#Vladimir is right. Here is the mechanism behind the bug:
When you enter option '3', what you actually put into stream is "3\n". cin >> option consumes "3" and leaves "\n". getline() consumes "\n" and your call to ignore() after getline() waits for user input.
As you can see, teh sequence of events is already not what you expected.
Now, while ignore() is waiting for input, you type in your line. That line you're typing is what will go to "cin >> option.
If you just give it one symbol, ignore() will dispose of it for you, and option will be read correctly. However, if you give it non-numeric symbols, stream will set failbit when trying to read the option. From that point on, your stream will refuse to do anything. Any << or getline will not set any new values in the variables they are supposed to change. You'll keep 3 in option and "" in task, in a tight loop.
Things to do:
always check cin.eof(), cin.fail() and cin.bad().
always initialize your variables and declare them in the narrowest scope possible (declare option=0 right before it's read).
I just figured out a way to kind of hack through it, not the greatest but it works. Create a character array, and then accept input in the array, and then put everything into the array into the string.
char buff[256];
cout << endl << "Enter the task that you would like to add:" << endl;
cin >> task;
task += " ";
cin.getline(buff, 256);
for(int i = 1; buff[i] != 0; i++){
task += buff[i];
}