Why this while loop executes twice before asking for name - c++

I have a function which validates a user's first and last name. However, the while loop executes twice, and I can't find out why.... any help
string getName()
{
string name = "";
bool stop = false;
string::iterator it;
while(!stop)//name validation loop
{
cout << "enter name: ";
getline(cin, name);
for(it = name.begin(); it < name.end(); it++)
{
if(tolower(*it) > 'z' || tolower(*it) < 'a' && tolower(*it) != ' ')
{
cout << "Error, only letters! \n";
break;
}
if(it == name.end()-1) { stop = true; }
}
cout << "here\n";
}
return name;
}

It may happen if there is still some newspace character in cin buffer. std::ws extracts white spaces like newline character, space, tabulator from stream before right text. Try that:
string getName()
{
string name = "";
bool stop = false;
string::iterator it;
while(!stop)//name validation loop
{
cout << "enter name: ";
std::cin >> std::ws; // <--- drop whitespaces
getline(cin, name);
for(it = name.begin(); it < name.end(); it++)
{
if(tolower(*it) > 'z' || tolower(*it) < 'a' && tolower(*it) != ' ')
{
cout << "Error, only letters! \n";
break;
}
if(it == name.end()-1) { stop = true; }
}
cout << "here\n";
}
return name;
}

There are a few problems with your loop and this is how I'd rewrite it, keeping it as similar to your implementation as possible:
string getName()
{
bool stop;
string name;
string::iterator it;
do {
stop = true;
cout << "enter name: ";
getline(cin, name);
for(it = name.begin(); it < name.end(); it++)
{
if( (tolower(*it) > 'z' || tolower(*it) < 'a') && tolower(*it) != ' ' )
{
cout << "Error, only letters! \n";
stop = false;
break;
}
}
cout << "here\n";
} while (!stop);
return name;
}
With what you had here:
if(tolower(*it) > 'z' || tolower(*it) < 'a' && tolower(*it) != ' ')
Due to && having higher precedence, it equates to:
if(tolower(*it) > 'z' ||(tolower(*it) < 'a' && tolower(*it) != ' '))
which is not what you want.
EDIT: since ' ' (space) is < 'a' your code won't actually cause problems, but I'm not sure you did it like that on purpose.
I also don't like this: if(it == name.end()-1) { stop = true; }, and a do...while loop is better suited.
EDIT: You might also want to add a check for empty input (all whitespace), since that would seem an invalid name.
EDIT(again): Loki's right, you must have junk on the input stream before calling getName. You can use Mścisław's solution or cin.ignore().

Related

Limit input to alphabet only [a-z, A-Z,SPACE,PERIOD]

I'm trying to limit user input to certain characters only [a-z,A-Z,SPACE,PERIOD], I can't get this function right?!
void setName()
{
char fname[20];
unsigned int ascii_val;
while(ascii_val<65 || ascii_val>90)
{
cout << "First Name: ";
cin.ignore().getline(fname,20);
for(int i=0; i<sizeof(fname); i++)
{
ascii_val = toupper(fname[i]);
if(ascii_val==32 || ascii_val==46 || ascii_val==0) //Exception to allow SPACE and PERIOD
{
ascii_val=65;
};
if(ascii_val<65 || ascii_val>90)
{
cout << "Only Alphabet [a-z,A-Z,SPACE,DOT] Allowed!\n";
break;
}
}
}
newfname = fname;
}
This finally worked! if you think this is not the best solution, post your alternative please.
bool charVerify(string word)
{
for (int i = 0; i < word.size(); i++)
{
int character = toupper(word[i]);
if(character == ' ' || character == '.')
{
character='A';
}
if (character < 'A' || character > 'Z')
{
return false;
}
}
return true;
}
void setFname()
{
string fname;
cout << "Enter Name: ";
getline(std::cin.ignore(),fname);
while(1)
{
if (charVerify(fname))
{
break;
}
else
{
cout << "\tInvalid Input! Only [a-z,A-Z,SPACE,PERIOD]" << endl;
}
cin.clear();
cout << "Enter Name: ";
getline(std::cin.ignore(),fname);
}
firstname = fname;
}

How to get multiple input with char and multiple output with int? C++

I'm quite new to C++, so I apologize if I am not sounding technical. I am having a little trouble getting a multiple input and output with my code, I'm thinking I should have a loop to get the data but i'm not sure how i'd go about that in my code, I've thought about using getline() but that doesn't seem to want to work with Char.
I've tried getline but I'm not sure how to implement it with the Char input, I believe I may need a separate loop as well but again not too sure. I'm thinking it could be done to EoF as well.
Here's my code:
int main()
{
char inpval;
int outval = 0;
cout << "Enter a Roman Number to convert: " << endl;
while (cin.get(inpval))
{
inpval = toupper(inpval);
if (inpval == 'M')
outval = outval + 1000;
else if (inpval == 'D') {
inpval = cin.peek();
inpval = toupper(inpval);
if (inpval == 'M') {
outval = outval - 500;
continue;
} else {
outval = outval + 500;
continue;
}
}
//etc
cout << "The Equivalent Arabic value is:" << endl;
cout << outval << "\n";
return 0;
}
My expected output is:
(All on newline)
Input:
I
II
IV
V
VI
Output:
1
2
4
5
6
Actual output is:
Input:
I
Output:
1
P.S: The program converts Roman Numeral chars to their respected number.
Any help is appreciated!
You can take input multiple items from cin, using below syntax.
cin >> a;
cin >> b;
cin >> c;
Another way is also there
cin >> a >> b >> c;
This technique is called "operator chaining" which is similar to the above.
Do you have any problem doing it like this?
cout << "Enter a Roman Numeral" << endl;
string inpval;
cin >> inpval;
while (inpval != "exit")
{
int outval = 0;
if (inpval == "I")
outval = 1;
else if (inpval == "II")
outval = 2;
else if (inpval == "III")
outval = 3;
else if (inpval == "IV")
outval = 4;
// ect
cout << "The Equivalent Arabic value is: " << outval << endl << endl;
cout << "Enter next numeral: (type exit to exit) " << endl;
cin >> inpval;
}
Method 1: Use getchar(), Calculate/Convert Roman to integer until you encounter a space ' ',when you get a space ' ' output the integer and do the same next roman number until you get another space ' ' or newline '\n' and stop the program once you encounter newline '\n'.
Method 2:Use type std::string and take input with getline. Then iterate through the string and calculate until you find space ' ' output the number, do the same till you find next space ' ' or end when string ends.
If you know # of Roman numbers you want to convert you can put it in a loop.
Hope this helps.
Example(Method 2)
#include <bits/stdc++.h>
int value(char r)
{
if (r == 'I')
return 1;
if (r == 'V')
return 5;
if (r == 'X')
return 10;
if (r == 'L')
return 50;
if (r == 'C')
return 100;
if (r == 'D')
return 500;
if (r == 'M')
return 1000;
return -1;
}
int main()
{
int out=0;
std::string s;
std::string::iterator i; //string iterator
//for more info go to https://www.geeksforgeeks.org/stdstring-class-in-c/
getline(std::cin,s);
for (i = s.begin(); i!= s.end() ; ++i)
{
if(*i != ' ')//Encounter a space, output result and
{ //go to next roman numeral
int s1 = value(*i);
if (*(i+1) != ' ' || *(i+1) != '\0')
{
// Getting value of i+1 nth Element
int s2 = value(*(i+1));
// Comparing both values
if (s1 >= s2)
{
// Value of current symbol is greater
// or equal to the next symbol
out = out + s1;
}
else
{
out = out + s2 - s1;
i++; // Value of current symbol is
// less than the next symbol
}
}
else
{
out = out + s1;
i++;
}
}
else
{
std::cout<<out<<" ";
out = 0;
}
}
std::cout<<out<<" ";
std::cout<<std::endl;
return 0;
}
Input:
I II MM MCMIV
Output:
1 2 2000 1904

How to check every character in string?

The program will ask user to input strand which has to be composed of only ABCD and if the input contains letter other than ABCD it must show error, otherwise it should output "ok!"
string strand1;
again:
cout << "Enter String 1:\n";
cin >> strand1;
for (int i = 0; i <= strand1.length(); i++)
{
if (strand1.at(i) != 'A'&&strand1.at(i) != 'B'&&strand1.at(i) != 'C'&&strand1.at(i) != 'D')
{
cout << "Invalid Input";
system("cls");
goto again;
}
else
{
i++;
}
}
cout << "ok";
_getch();
return 0;
Move the necessary checks to a function -- isValidInput.
Use hand coded logic to check whether the input is valid or use the standard library function std::find_if to do the same.
Use the function in a while loop in the main function.
bool isNotABCD(char c)
{
return !((c == 'A') || (c == 'B') || (c == 'C') || (c == 'D'));
}
bool isValidInput(std::string const& str)
{
return (std::find_if(str.begin(), str.end(), isNotABCD) == str.end());
}
int main()
{
string strand1;
cout << "Enter String 1:\n";
while ( cin >> strand1 && !isValidInput(strand1) )
{
cout << "Invalid Input";
system("cls");
cout << "Enter String 1:\n";
}
cout << "ok";
}
Update
You can also use a simpler version of isValidInput(), Thanks to #Blastfurnace for the suggestion.
bool isABCD(char c)
{
return (c == 'A') || (c == 'B') || (c == 'C') || (c == 'D');
}
bool isValidInput(std::string const& str)
{
return (std::all_of(str.begin(), str.end(), isABCD));
}
Update 2
You can also use a still simpler version of isValidInput(), Thanks to #JorenHeit for the suggestion.
bool isValidInput(std::string const& str)
{
return (std::find_first_not_of("ABCD") == std::string::npos);
}
Your question is unclear, but after examining your code I believe the problem is that for your loop condition you are using i <= strand1.length when you should be using i < strand1.length.
The loop condition you are using will check an index out of bounds of the string. In addition, you should not be incrementing i in the else statement as that is already done in the for statement. In the future, please clearly state your question along with any error codes you are getting.

How to avoid using Backspace character with push_back?

I'm making a software as an ATM, so when the user try to enter the password the user only sees *******, but when trying to delete it doesn't delete a character. It just adds a new one. Here's my code:
string password2 = "";
cout << "PASSWORD: ";
ch = _getch();
while(ch != 13) //character 13 is enter
{
password2.push_back(ch);
cout << '*';
ch = _getch();
}
And also, I try to use pop_back(); but it doesn't work either. Can anybody help me please?
Just did a little magic and created this:
I must admit, I don't like the style... But it "works" !
#include<iostream>
#include<string>
#include <conio.h>
bool verify_pass(const std::string& pass)
{
std::string input = "";
char ch = '0';
while(true)
{
ch = getch();
if(ch == '\b')
{
if(input.size() > 0)
{
input.erase(input.begin() + input.size() - 1); // erase last char
std::cout << "\b \b";
}
}
else if(ch != '\r\n' && ch != '\n' && ch != '\r')
{
input += ch;
std::cout << '*';
}
else
break;
}
return input == pass;
}
int main()
{
std::string insecurePass = "1234";
std::cout << "Enter Password: ";
if(verify_pass(insecurePass))
std::cout << "\nCorrect!\n";
else
std::cout << "\nFalse!\n";
}
By the way, you can use the vector like I used the string, but use push_back instead of += and pop_back() should work too instead of my method with erase.

Vaildator for a string on user input

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;
}