I have the following code:
qstn:
cout << "Input customer's lastname: ";
getline(cin, lname);
if (lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ") != string::npos) {
cout << "You can only input alpha here!\n";
cin.clear();
goto qstn;
} else if (lname.empty()) {
cout << "Please enter your firstname!\n";
cin.clear();
goto qstn;
}
int lnamel = lname.length();
int strl = str.length();
int is = 0;
for (int i = 1; i < strl;) {
i++;
is++;
if (lname[i] == lname[is] && lname[i] == ' ' || lname[0] == ' ') {
cin.clear();
cout << "Please input your lastname properly!\n";
goto qstn;
}
}
// next question here
I'm having a hard time on thinking what will be the proper logic to avoid the
goto statement, since I was college I was using it but someone here said that
it's not good to use it at all cause it might ruin my code.
I tried using the do while loop but it's not smooth as goto.
Please help!
Here's an idiom I like to use:
int i;
if (std::cin >> prompt("enter an integer: ", i))
{
std::cout << "Read user input: " << i << "\n";
} else {
std::cout << "Input failed (too many attempts). Eof? " << std::boolalpha << std::cin.eof() << "\n";
}
Here, prompt is a smart input manipulator, that takes care of handling parse errors or stream failures and retrying.
It's quite generic so actually do many things, but you don't need to indicate all the options. When the manipulator is inserted into the stream it relays to the do_manip member:
template <typename Char, typename CharT>
friend std::basic_istream<Char, CharT>& operator>>(std::basic_istream<Char, CharT>& is, checked_input<T, Prompter>& manip) {
return manip.do_manip(is);
}
The do_manip handles all the logic without any gotos :) :
std::istream& do_manip(std::istream& is) {
auto attempt = [this] { return infinite() || retries_ > 0; };
while (attempt()) {
if (!infinite())
retries_ -= 1;
prompter_(out_);
if (is >> value_) {
if (!run_validators(out_))
is.setstate(is.rdstate() | std::ios::failbit);
else
break;
} else {
out_.get() << format_error_ << "\n";
}
if (attempt()) {
is.clear();
if (flush_on_error_)
is.ignore(1024, '\n');
}
}
return is;
}
You can see that there is a possibility to have validations run before accepting the input.
Here's a somewhat full-blown demo:
Live On Coliru
int main() {
using namespace inputmagic;
int i;
if (std::cin >> prompt("enter an integer: ", i)
.retries(3)
.flush_on_error(false)
.format_error("I couldn't read that (Numbers look like 123)")
.output(std::cerr)
.validate([](int v) { return v > 3 && v < 88; }, "value not in range (3,88)")
.validate([](int v) { return 0 == v % 2; })
.validate([](int v) { return v != 42; }, "The Answer Is Forbidden")
.multiple_diagnostics())
{
std::cout << "Read user input: " << i << "\n";
} else {
std::cout << "Input failed (too many attempts). Eof? " << std::boolalpha << std::cin.eof() << "\n";
}
}
You can see it will only accept valid integers
that are >3 and <88,
that are even
except 42 (forbidden number)
When entering the numbers 21, 42 and 10 on subsequent retries, you get: live
enter an integer: 21
Value not valid
enter an integer: 42
The Answer Is Forbidden
enter an integer: 10
Read user input: 10
However, if you enter 1 all the time you get this: live
enter an integer: 1
value not in range (3,88)
Value not valid
enter an integer: 1
value not in range (3,88)
Value not valid
enter an integer: 1
value not in range (3,88)
Value not valid
Input failed (too many attempts). Eof? false
Or if you read from a single line file: live
enter an integer: value not in range (3,88)
Value not valid
enter an integer: I couldn't read that (Numbers look like 123)
enter an integer: I couldn't read that (Numbers look like 123)
Input failed (too many attempts). Eof? true
Use a function:
bool getLastName(string & lname,
string & str)
{
cout << "Input customer's lastname: ";
getline(cin, lname);
if (lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")
!= string::npos)
{
cout << "You can only input alpha here!\n";
cin.clear();
return false;
}
else if (lname.empty())
{
cout << "Please enter your firstname!\n";
cin.clear();
return false;
}
int lnamel = lname.length();
int strl = str.length();
int is = 0;
for (int i = 1; i < strl;)
{
i++;
is++;
if (lname[i] == lname[is] && lname[i] == ' ' || lname[0] == ' ')
{
cin.clear();
cout << "Please input your lastname properly!\n";
return false;
}
}
return true;
}
All I've done here is replace the gotos with return false. If the program makes it to the end of the function, return true. Make the function call in a while loop:
while (!getLastName(lname, str))
{
// do nothing
}
Not only does this de-spaghettify the code, but it breaks it up into nice, small, easy to manage pieces. This is called procedural programming.
A While loop looks like your best bet. You can redo the loop with the continue keyword.
int incorrect = 0;
while(!incorrect) {
cout<<"Input customer's lastname: ";
getline(cin,lname);
if(lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")!=string::npos)
{
cout<<"You can only input alpha here!\n";
cin.clear();
continue;
}
else if(lname.empty())
{
cout<<"Please enter your firstname!\n";
cin.clear();
continue;
}
int lnamel=lname.length();
int strl=str.length();
int is=0;
for(int i=1; i<strl;)
{
i++;
is++;
if(lname[i]==lname[is]&&lname[i]==' '||lname[0]==' ')
{
cin.clear();
cout<<"Please input your lastname properly!\n";
continue;
}
incorrect = 1;
}
You need to use some do while loops
for instance this:
qstn:
cout<<"Input customer's lastname: ";
getline(cin,lname);
if(lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")!=string::npos)
{
cout<<"You can only input alpha here!\n";
cin.clear();
goto qstn;
}
else if(lname.empty())
{
cout<<"Please enter your firstname!\n";
cin.clear();
goto qstn;
}
could be re-written as this:
int flag;
do{
flag = 1;
cout<<"Input customer's lastname: ";
getline(cin,lname);
if(lname.find_first_not_of( "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ")!=string::npos)
{
flag = 0;
cout<<"You can only input alpha here!\n";
}
else if(lname.empty())
{
flag = 0;
cout<<"Please enter your firstname!\n";
}
cin.clear();
} while( flag !=1 );
feel free to use a boolean type flag, it doesn't really matter
It seems to me that your code suffers from lack of clarity of purpose.
You apparently don't want the string that's entered to include a leading space, nor multiple consecutive spaces. Other than that, only alphabetic characters should be accepted.
If the user does enter multiple consecutive spaces, I'd probably just ignore all but the first. I'd probably write the code something like this:
#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
#include <sstream>
bool non_alpha(std::string const &s) {
return !std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isalpha(c) || std::isspace(c); });
}
std::string get_name(std::string const &prompt) {
std::string result;
std::string line;
do {
std::cout << prompt;
std::getline(std::cin, line);
} while (non_alpha(line));
std::istringstream words(line);
std::string word;
while (words >> word)
result += word + ' ';
return result;
}
int main() {
auto res = get_name("Please enter last name, alpha-only\n");
if (res.empty())
std::cout << "Oh well, maybe some other time";
else
std::cout << "Thanks Mr(s). " << res << "\n";
}
I'd be tempted to consider doing roughly the same for non-alphabetic characters--rather than asking the user to re-enter from the beginning, assume it's a mistake and just ignore it.
Related
My code is mostly working except for one minor issue. While it should only accept ints, it also accepts user input that start with an int, such as 6abc for example. I saw a fix for this here, but it changed the input type to string and added a lot more lines of code. I'm wondering if there's an easier way to fix this:
int ID;
cout << "Student ID: ";
// error check for integer IDs
while( !( cin >> ID )) {
cout << "Must input an integer ID." << endl ;
cin.clear() ;
cin.ignore( 123, '\n' ) ;
}
In a word - no.
But what you can do is instead read a whole word into a std::string first, and then convert that entire word into an int, checking for errors in that conversion, eg:
int ID;
string input;
do
{
cout << "Student ID: ";
if (!(cin >> input))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
else
{
size_t pos = 0;
try
{
ID = stoi(input, &pos);
if (pos == input.size())
break;
}
catch (const std::exception &) {}
}
cout << "Must input an integer ID." << endl;
}
while (true);
Live Demo
I am currently writing a program that translates normal text to whale talk (in case you want to know what whale talk is, it is the statement ripped of consonants with u's and e's doubled)
I successfully wrote the program. But I want it to be repeated again and go through the same process until we manually exit it.
For this I used a while loop and used exit as variable. But it didn't work as expected as on second time around it did not ask for input but displayed the prompt text and skipped to the exit/no exit line.
Can you tell me what is wrong with my program? Here is my code (you can try to compile and execute it yourself):
#include <iostream>
#include <string>
#include <vector>
int main(){
bool exit = false;
//Open
std::cout<<"==========\n";
std::cout<<"WHALE TALK\n";
std::cout<<"==========\n";
std::cout<<"\n";
//main loop
while (!exit){
//Variables
std::vector<char> whaletalk;
//input
std::string input;
std::cout<<"Type the text you want to translate to whale language: ";
getline(std::cin,input);
std::cout<<"\n\nWhale talk: ";
//vowels
std::vector <char> vowels = {'a','e','i','o','u'};
//sorter
//iterating through string
for (int i = 0; i < input.size(); i++){
//iterating through vowels
for (int j = 0; j < vowels.size(); j++){
//case of vowels
if(input[i] == vowels[j]){
//case of u and e
if ((input[i] == 'u') or (input[i] == 'e')){
whaletalk.push_back(input[i]);
whaletalk.push_back(input[i]);
}
//case of vowels other than u and e
else {whaletalk.push_back(input[i]);}
}
}
}
//Output
for (int k = 0; k < whaletalk.size(); k++ ){
std::cout<<whaletalk[k];
}
std::cout<<"\n";
// exit/no exit
std::string response;
std::cout<<'\n';
std::cout<<"Do you have more to translate?(yes/no)\n\nYour response: ";
std::cin>>response;
if (response == "NO" or response == "no" or response == "No"){
exit = true;
}
}
}
Here is an image of the bug
When you use the >> operator to read a string, it only reads the next word (up to a whitespace character), and leaves everything else on the input stream, but std::cin still blocks until a new line (enter is pressed).
std::string response;
std::cout << '\n';
std::cout << "Do you have more to translate?(yes/no)\n\nYour response: ";
std::cin >> response;
if (response == "NO" or response == "no" or response == "No") {
exit = true;
This leaves just the newline in the buffer if you only typed one word (if you did say "a b" then it would leave "b\n" and response would be "a", not "a b"), and so the next std::getline will give you what was left, in this case an empty line.
int main()
{
std::string str;
std::cout << "Enter word: ";
std::cin >> str;
std::cout << "Entered '" << str << "'" << std::endl;
std::cout << "Enter line: ";
std::getline(std::cin, str);
std::cout << "Entered '" << str << "'" << std::endl;
}
Enter word: a
Entered 'a'
Enter line: Entered ''
Or if you have a space character:
Enter word: aa bb
Entered 'aa'
Enter line: Entered ' bb'
You could just always use std::getline when reading just string responses to avoid missing anything by accident (like that " bb").
std::string response;
std::cout << '\n';
std::cout << "Do you have more to translate?(yes/no)\n\nYour response: ";
std::getline(std::cin, response);
if (response == "NO" or response == "no" or response == "No") {
exit = true;
Or after any other >> operations to get whatever is "remaining" and proceed to the next line.
Another possibility is to use std::istream.ignore() to ignore remaining input up to a maxmium length and delimiter:
std::string response;
std::cout << '\n';
std::cout << "Do you have more to translate?(yes/no)\n\nYour response: ";
std::cin >> response;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if (response == "NO" or response == "no" or response == "No") {
exit = true;
In this case std::numeric_limits<std::streamsize>::max() means any amount, up to the next line \n. If the user entered say "no abc", then "abc" would be lost.
You should put these function to clear input and ignore all character except break line character:
std::cin.clear();
std::cin.ignore(32767, '\n');
below this function:
std::cin >> ...;
Here is the loop check for response:
while (true) {
if (response == "NO" or response == "no" or response == "No") {
exit = true;
break;
}
else if (response == "YES" or response == "yes" or response == "Yes")
{
break;
}
else
{
std::cout << "\nPlease only input yes or no: ";
std::cin >> response;
// Clear input
std::cin.clear();
std::cin.ignore(32767, '\n');
}
}
Full code:
#include <iostream>
#include <string>
#include <vector>
int main() {
bool exit = false;
//Open
std::cout << "==========\n";
std::cout << "WHALE TALK\n";
std::cout << "==========\n";
std::cout << "\n";
//main loop
while (!exit) {
//Variables
std::vector<char> whaletalk;
std::cout << "Type the text you want to translate to whale language: ";
//input
std::string input;
std::getline(std::cin, input);
std::cout << "\n\nWhale talk: ";
//vowels
std::vector <char> vowels = { 'a','e','i','o','u' };
//sorter
//iterating through string
for (int i = 0; i < input.size(); i++) {
//iterating through vowels
for (int j = 0; j < vowels.size(); j++) {
//case of vowels
if (input[i] == vowels[j]) {
//case of u and e
if ((input[i] == 'u') or (input[i] == 'e')) {
whaletalk.push_back(input[i]);
whaletalk.push_back(input[i]);
}
//case of vowels other than u and e
else { whaletalk.push_back(input[i]); }
}
}
}
//Output
for (int k = 0; k < whaletalk.size(); k++) {
std::cout << whaletalk[k];
}
std::cout << "\n";
// exit/no exit
std::string response;
std::cout << '\n';
std::cout << "Do you have more to translate?(yes/no)\n\nYour response: ";
std::cin >> response;
// Clear input
std::cin.clear();
std::cin.ignore(32767, '\n');
while (true) {
if (response == "NO" or response == "no" or response == "No") {
exit = true;
break;
}
else if (response == "YES" or response == "yes" or response == "Yes")
{
break;
}
else
{
std::cout << "\nPlease only input yes or no: ";
std::cin >> response;
// Clear input
std::cin.clear();
std::cin.ignore(32767, '\n');
}
}
}
return 0;
}
I have written a code about guessing a secret number, but I have a problem when an alphabetic character is given as an input instead of an integer. It halts the program. What how can I resist this problem.
srand(time(0));
int a,secret;
secret=rand() % 10 +3;
do{
cout<<"Guess the secret num between 1-10 + 3 : ";
cin>>a;
else if(a>secret)
{
cout<<"Secret num is smaller!!"<<endl;
}
else if(a<secret) {
cout<<"Secret num is greater !!"<<endl;
}
}
while(a!=secret)
cout<<" "<<endl;
cout<<""<<endl;
cout<<"Congratulations!!!! This is the secret num...."<<secret<<endl;
You don't have to, but if you still want to solve the problem, you can stream the line and get the line in number only.
Answered by Jesse Good here:
I would use std::getline and std::string to read the whole line
and then only break out of the loop when you can convert the entire
line to a double.
#include <string>
#include <sstream>
int main()
{
std::string line;
double d;
while (std::getline(std::cin, line))
{
std::stringstream ss(line);
if (ss >> d)
{
if (ss.eof())
{ // Success
break;
}
}
std::cout << "Error!" << std::endl;
}
std::cout << "Finally: " << d << std::endl;
}
In your case, because 0 is outside the allowable range this is really simple:
Initialize a to 0 and if a is 0 after extracting:
clear cin
ignore cin (Be careful to specify that you want to ignore up to the newline character: Cannot cin.ignore till EOF?)
Your final code should look something like this:
cout << "Guess the secret num between 1-10 + 3 : ";
cin >> a;
while (a != secret) {
if (a == 0) {
cin.clear();
cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
cout << "Please enter a valid number between 1-10 + 3 : ";
}
else if (a < secret) {
cout << "Secret num is smaller!!\nGuess the secret num between 1-10 + 3 : ";
}
else if (a < secret) {
cout << "Secret num is greater !!\nGuess the secret num between 1-10 + 3 : ";
}
a = 0;
cin >> a;
}
Live Example
is it possible, say your trying to do calculations so the primary variable type may be int... but as a part of the program you decide to do a while loop and throw an if statement for existing purposes.
you have one cin >> and that is to take in a number to run calculations, but you also need an input incase they want to exit:
Here's some code to work with
#include <iostream>
using namespace std;
int func1(int x)
{
int sum = 0;
sum = x * x * x;
return sum;
}
int main()
{
bool repeat = true;
cout << "Enter a value to cube: " << endl;
cout << "Type leave to quit" << endl;
while (repeat)
{
int input = 0;
cin >> input;
cout << input << " cubed is: " << func1(input) << endl;
if (input = "leave" || input = "Leave")
{
repeat = false;
}
}
}
I'm aware they wont take leave cause input is set to int, but is it possible to use a conversion or something...
another thing is there a better way to break the loop or is that the most common way?
One way to do this is read a string from cin. Check its value. If it satisfies the exit condition, exit. If not, extract the integer from the string and proceed to procss the integer.
while (repeat)
{
string input;
cin >> input;
if (input == "leave" || input == "Leave")
{
repeat = false;
}
else
{
int intInput = atoi(input.c_str());
cout << input << " cubed is: " << func1(intInput) << endl;
}
}
You can read the input as a string from the input stream. Check if it is 'leave' and quit.. and If it is not try to convert it to a number and call func1.. look at atoi or boost::lexical_cast<>
also it is input == "leave" == is the equal operator. = is an assignment operator.
int main() {
cout << "Enter a value to cube: " << endl;
cout << "Type leave to quit" << endl;
while (true)
{
string input;
cin >> input;
if (input == "leave" || input == "Leave")
{
break;
}
cout << input << " cubed is: " << func1(atoi(input.c_str())) << endl;
}
}
you can use like
int input;
string s;
cint>>s; //read string from user
stringstream ss(s);
ss>>input; //try to convert to an int
if(ss==0) //not an integer
{
if(s == "leave") {//user don't want to enter further input
//exit
}
else
{
//invalid data some string other than leave and not an integer
}
}
else
{
cout<<"Input:"<<input<<endl;
//input holds an int data
}
Hey i want to stop the user from entering integers when i ask the user to input a name. I have achieved this for an integer and a char. Can anyone help me adapt my code for a string.
int getNum()
{
int num;
std::cout << "\nWhat is your age? ";
while (!(std::cin >> num))
{
// reset the status of the stream
std::cin.clear();
// ignore remaining characters in the stream
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Enter an *integer*: ";
}
std::cout << "You entered: " << num << std::endl;
return num;
}
char getChar(string q)
{
char input;
do
{
cout << q.c_str() << endl;
cin >> input;
}
while(!isalpha(input));
return input;
}
string q = "This is a test123";
for(string::iterator i = q.begin(); i != q.end(); i++)
{
if((*i < 'A' || *i > 'z') && (*i != ' '))
{
return false;
}
}
would also be an option, if you allow for spaces and other characters.
Edit: updated for checking a single char:
char c;
bool finished = false;
printf("Please enter your sex, M/F?\n");
while(!finished)
{
cin >> c;
if(!(c == 'm' || c == 'M' || c== 'f' || c=='F'))
{
printf("Please try again...\n");
}
else
{
finished = true;
}
}
Note that c is only input, char by char, when Enter is pressed, before that the line feed does not happen.
If you plan on using std:string, then you can use this to find if the entered string has any digits or not:
if (std::string::npos != s.find_first_of("0123456789"))
{
std::cout << "digit(s)found!" << std::endl;
}