Most common/idiotproof way to catch invalid input - c++

I am getting into c++ right now, and right now I want to know the most common/best way to catch invalid input. I would love answers to this wide open question, but my more specific question is as follows.
I want a char from the user. If the char is 'y' then it will repeat, if it is 'n' then the program will close. If I enter multiple chars then it will repeat as many times as chars e.g. I enter 'hello' it will show my output 5 times. I assume that it reads each char and goes through the whole loop then reads the next char in line. How can I get it to show up just one time?
bool valid = 0;
while(valid)
{
...
bool secValid = 0;
while(secValid == 0)
{
cout << "To enter another taxable income type 'y': \n\n";
char repeat = NULL;
cin >> repeat;
if(repeat == 'y')
{
valid = 0;
secValid = 0;
system("cls");
}else if(repeat == 'n')
{
return;
}else
{
secValid = 1;
}
}
}

You could structure it something like this:
while(true) {
cout << "Repeat (y/n)? ";
string line;
if(!getline(cin, line))
break; // stream closed or other read error
if(line == "y") {
continue;
} else if(line == "n") {
break;
} else {
cout << "Invalid input." << endl;
}
}
Example session:
Repeat (y/n)? y
Repeat (y/n)? foo
Invalid input.
Repeat (y/n)? n
Here we use std::getline to get a whole line of input, instead of getting one character at a time.

std::getline():
std::string line;
std::getline(std::cin, line);
if (line == "y") {
// handle yes
}
else if (line == "n") {
// handle no
}
else {
// handle invalid input
}

use std::getline from the <string> header to read a line of input into a std::string

Also when checking string for "y" or "n" is good practise to use upcased string instead. For example
std::string YES = "Y";
std::string NO = "N";
...
std::string line;
std::getline(std::cin, line);
std::transform(line.begin(), line.end(), line.begin(), std::toupper);
if (line == YES)
{
...
}
else if (line == NO)
{
..
.
}

Related

Using the newline character to break a loop in c++

I'm looking for a way to break a for loop using enter in the visual studio console.
do {
std::cin >> userInput;
if (userInput == '\n')
break;
lineStorage[lineLength] = userInput;
lineLength++;
} while(true);
This is what I have so far, but the newline character won't work for what I need it to. Any suggestions or insight would help.
P.S. I cannot use a sentinel value other than the newline character resulting from the enter button.
P.S. More context:
char lineStorage[80] = { 'a' };
char userInput = ' ';
const char lineEnd = '\n';
int lineLength = 0;
std::cout << "Enter a line:";
do {
std::cin >> userInput;
if (userInput == '\n')
break;
lineStorage[lineLength] = userInput;
lineLength++;
} while (true);
Reading with >> by default skips whitespace, and a newline is whitespace. I suggest using getline() instead:
for(int i = 0; i < 80; i++) {
if (!getline(std::cin, userInput) || userInput.empty())
break;
lineStorage[lineLength] = userInput;
lineLength++;
}
If your lineStorage is really supposed to store individual words, you can split userInput on spaces before storing the words.
Edit: now that you've shown that userInput is a single character, I think you should just use std::cin.get(userInput) to read one character at a time. That will let you get the newlines in the style of your original code.
I like the other answer better, but something like this should also work:
do {
cin.get(userInput);
if (userInput == 10) {
break;
} else {
lineStorage[lineLength] = userInput;
lineLength++;
}
} while (true);
more clear will be
#include <stdio.h>
#include <stddef.h>
int main(int argc , char *argv[])
{
char t[70]={0},x;
while(1)
{
scanf("%[^ ^\n]%c",t ,&x);
if(x == '\n') break;
}
}

std::getline not re-requesting user input in while loop [duplicate]

This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Closed 2 years ago.
I am trying to write a program where a user is asked for input and then I check if the 2 sub strings (splitting in half) is the mirror image. I want to loop continually until a user stops entering in input but my code is not looping correctly. The code works fine on the first iteration of the while loop, but then during the second iteration of the while loop, getline() does not re-request user input, it just sets std::string input to "".
I'm sure I am missing something obvious.
Code
#include <iostream>
#include <string>
#include <stack>
#include <algorithm>
using namespace std;
bool compareMirrorString(const std::string&, const std::string&);
int main()
{
std::string input;
string first_string;
string second_string;
bool result;
int input_length;
int first_string_length;
std::string quit;
cout << "Enter 2 strings to compare, seperated by a # e.g. \"abc#cba\"." << endl;
while ( true )
{
std::getline(std::cin, input);
//split string into its two component parts
input_length = input.length();
first_string_length = input_length / 2;
first_string.assign(input, 0, first_string_length);
second_string.assign(input, first_string_length + 1);
//test if two strings are mirror images of each other
result = compareMirrorString(first_string, second_string);
if (result) {
cout << "Yes they match.";
}
else {
cout << "No they do not match.";
}
cout << "\nDo you want to test another string? Y for yes, q to quit." << endl;
cin >> quit;
if (quit == "q" or quit == "Q" or quit == "quit" or quit == "Quit" or quit == "QUIT"
or quit == "no" or quit == "No")
{
break;
}
else
{
cout << "Enter another 2 strings to compare, seperated by a # e.g. \"abc#cba\"." << endl;
}
} //end of while
return 0;
}
//is second a mirror image of first?
bool compareMirrorString(const std::string& first, const std::string& second)
{
if (first.length() != second.length()) {
return false;
}
//put first_string on stack
std::stack<char> stackChar;
for (auto elem : first){
stackChar.push(elem);
}
int size = stackChar.size();
//compare first and second strings
bool compare_equal = true;
for (int i = 0; i < size; i++)
{
if (stackChar.top() == second[i])
{
stackChar.pop();
}
else
{
compare_equal = false;
break;
}
}
return compare_equal;
}
In the first iteration of the loop:
cin >> quit;
will read up to, but not including the newline character.
In the second iteration of the loop:
std::getline(std::cin, input);
will read that newline character, and hence read an empty string into input.
There are several ways to fix this
You could use getline to read the string quit
You could read input again, if it happens to be an empty string.
You could call cin.get(); after the cin >> quit to clear the newline.

Searching text file for specific user-inputted string

I'm trying to write a program which opens a text file full of words (a "dictionary" minus the definitions) and stores these values in strings to compare them against a user input to determine whether the user input is spelled correctly.
I go the program to work and do what I wanted, but I can't seem to figure out one specific detail. I want the program to continue running until the user enters "exit" as an input. The only problem is that my program continues spewing out either "input is spelled correctly" or "input is not spelled correctly" ad infinitum without giving the user a chance to input more values in.
How do I make it so the program only outputs one of these two options only once and then prompts the user for another input instead of a never-ending stream of the same statement? Thank you in advanced!
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string line; //holds values from txt file
string input; //holds user-inputted values
ifstream inputFile; //fstream operator declaration
bool isFound = false; //bool value to indicate if the string has been found
inputFile.open("dict.txt", ios::in);
if (inputFile)
{
cout << "Enter word to spellcheck (or exit to end)\n";
getline(cin, input);
while (input != "exit")
{
while (getline(inputFile, line))
{
if (input == line)
{
isFound = true;
break;
}
else
{
isFound = false;
}
}
inputFile.close();
if (isFound)
{
cout << input << " is spelled correctly.\n";
}
else
{
cout << input << " is not spelled correctly.\n";
}
}
if (input == "exit")
{
cout << "Ending program...\n";
}
}
else
{
cout << "Cannot open file\n";
}
return 0;
}
Inside the body of the
while (input != "exit")
loop the user is never asked to update the value of input. Moving getline(cin, input) into the while condition like this:
while (getline(cin, input) && input != "exit")
will solve that problem.
Then next problem is the handling of the dictionary file. It is closed in the middle of the loop, so subsequent reads from it will instantly fail. OP could reset the read pointer to the beginning of the file with inputFile.seekg(0);, but why reread the file every time.
Instead read the dictionary file into a std::set with more or less the same code as used in the search:
std::set<std::string> dictionary;
while (getline(inputFile, line))
{
dictionary.insert(line);
}
at the beginning of the program and search the set for the user's input in the loop.
if (dictionary.find(input) != dictionary.end())
{
cout << input << " is spelled correctly.\n";
}
else
{
cout << input << " is not spelled correctly.\n";
}
This should do the trick, you just need to move your getline block in the while loop, and move the file close statement outside the while loop:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdio>
using namespace std;
int main()
{
string line; //holds values from txt file
string input; //holds user-inputted values
ifstream inputFile; //fstream operator declaration
bool isFound = false; //bool value to indicate if the string has been found
inputFile.open("dict.txt", ios::in);
if (inputFile)
{
while (input != "exit")
{
// Rewind file back to beginning every time
inputFile.clear();
inputFile.seekg(0,std::ios::beg);
cout << "Enter word to spellcheck (or exit to end)\n";
getline(cin, input);
while (getline(inputFile, line))
{
if (input == line)
{
isFound = true;
break;
}
else
{
isFound = false;
}
}
if (isFound )
{
cout << input << " is spelled correctly.\n";
}
else
{
if (input != "exit"){ // Don't print message if exiting
cout << input << " is not spelled correctly.\n";
}
}
}
if (input == "exit")
{
cout << "Ending program...\n";
}
inputFile.close();
}
else
{
cout << "Cannot open file\n";
}
return 0;
}

Program Input only recognizing words not lines

I wrote this program for a school project where the user inputs up to 4 lines of text then types "end" and it repeats it to them in reverse order. It works fine, except it is recognizing a "line" to be only 1 word so if I try and type a line (Ex. the quick brown fox jumps over the log) it doesn't use that as a line but each word as a line.
#include <iostream>
using namespace std;
#include <string>
int main()
{
string l1;
string l2;
string l3;
string l4;
string l5;
bool end (false);
while (end == false)
{
cout<<"Welcome! Type one sentence then press enter, up to 4 sentences. When finished$
cin >> l1;
if (l1 == "end")
{
cout << "Error! Must enter at least 1 line of text!" << endl;
break;
}
cin >> l2;
if (l2 == "end")
{
cout<<l1<<endl;
end = true;
break;
}
cin >> l3;
if (l3 == "end")
{
cout<<l2<<endl;
cout<<l1<<endl;
end = true;
break;
}
cin >> l4;
if (l4 == "end")
{
cout<<l3<<endl;
cout<<l2<<endl;
cout<<l1<<endl;
end = true;
break;
}
cin >> l5;
if (l5 == "end")
{
cout<<l4<<endl;
cout<<l3<<endl;
cout<<l2<<endl;
cout<<l1<<endl;
end = true;
break;
}
else
{
cout<<"Error! Please enter 4 or less lines"<<endl;
break;
}
}
}
Use std::getline instead of operator>>. The operator>> reads words, not text lines.

how to avoid blank input by using getline()?

When I just press enter without input anything, getline() function also receive the blank input. How to fix it to not allow blank input(Has character and/or number and/or symbol)?
string Keyboard::getInput() const
{
string input;
getline(cin, input);
return input;
}
You can keep re-doing the getline as long as the input is blank. For example:
string Keyboard::getInput() const
{
string input;
do {
getline(cin, input); //First, gets a line and stores in input
} while(input == "") //Checks if input is empty. If so, loop is repeated. if not, exits from the loop
return input;
}
Try this:
while(getline(cin, input))
{
if (input == "")
continue;
}
string Keyboard::getInput() const
{
string input;
while (getline(cin, input))
{
if (input.empty())
{
cout << "Empty line." << endl;
}
else
{
/* Some Stuffs */
}
}
}