I have this program that i took it out from: https://intcpp.tech-academy.co.uk/input-validation/ and it works fine, i did some changes because i need the program to keep asking the user to enter a valid input, so that why it has the while in there however it only asks 4 times after that 4th time the input will be valid it does not matter if it right or not, Does any one know how i can fix this. Thank you
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main () {
cout << "Please enter name:" << endl;
string userName;
getline(cin, userName);
bool rejected = false;
while (rejected == false)
{
for (unsigned int i = 0; i < userName.length() && !rejected; i++)
{
if (isalpha(userName[i]))
continue;
else if (userName[i] == ' ')
continue;
else
{
cout << "Error, Please enter Patient's name again, First Name: ";
getline(cin, userName);
rejected = false;
}
}
rejected = true;
}
system("pause");
return 0;
}
Personally I would do something like
bool is_valid_username(std::string const& username)
{
// First trim the string of all leading and trailing white-space
trim(username);
if (username.length() == 0)
return false; // Input was empty or all spaces
return std::all_of(begin(username), end(username), [](char const ch)
{
return std::isalpha(ch) || ch == ' '; // Only letters and spaces are allowed
});
}
std::string get_username()
{
std::string username;
do
{
std::cout << "Please enter username: ";
std::getline(std::cin, username);
} while (!is_valid_username(username));
return username;
}
[For the trim function please see this old answer]
The get_username function will continue to ask for a username forever if the input is either empty, all spaces, or contains non-letters or not a space.
Here's a reference for std::all_of.
Here's a reference about lambda expressions.
if (isalpha(userName[i]) || (userName[i] == ' '))
continue;
else
{
cout << "Error, Please enter Patient's name again, First Name: ";
getline(cin, userName);
i = -1; //Reset check name
}
Try it!
Change unsigned int to int
Related
Good day everyone! First off all I want to let you all know that I am a beginner at C++, so my code will have a lot of errors.
I was trying to make a program to refresh my concepts of C++. The problem I am facing is the program is asking me the email ID, but as soon as I input it, the program ends. Please let me know everything I am doing wrong and how to correct it. Thank you so much!
I decided to create a simple login program with the following algorithm:
It asks the user for their email ID.
Checks if the email is registered (in a text file)
If the email is registered, the user is prompted for the password.
If the password is correct, a success message is printed; if not, the user s given 2 more attempts.
If the email is not registered, the program prompts the user to enter a new password and tells them the password strength. An ideal password should have an uppercase letter, a lowercase letter and a digit, with the password length more than 6 characters.
data.h:
#include <iostream>
#include <string>
using namespace std;
#ifndef DATA_H
#define DATA_H
struct newAccount{
string email, password; //declaring email and password of the user
};
string readEmail(string email); //reads in the email id provided
void checkEmail(); //checks if the entered email address exists in the system
int addEmail(); //checks if the entered email address exists in the system
void checkPassword(); //checks if the password matches an already registered email id
void makeNewPassword(string& password); //this function helps the user create a secure password
#endif
data.cpp:
#include <iostream>
#include <string>
#include <fstream>
#include "data.h"
using namespace std;
newAccount tempAccount;
string readEmail(string email) //reads in the email id provided
{
cout << "Enter an email address: ";
getline(cin, tempAccount.email);
email = tempAccount.email;
return tempAccount.email;
}
void checkEmail()
{
ifstream file("database.txt");
string str;
while (getline(file, str))
{
if (str == tempAccount.email)
{
cout << "This email is already registered. Please enter your password: ";
getline(cin, tempAccount.password);
checkPassword();
}
else
{
cout << "This email is not registered. Please create a new password: ";
makeNewPassword(tempAccount.password);
}
}
}
int addEmail() //checks if the entered email address exists in the system
{
ofstream myFile("database.txt");
if (myFile.is_open())
{
myFile << tempAccount.email << endl;
myFile.close();
}
else
cout << "Unable to open file";
return 0;
}
void checkPassword() //checks if the password matches an already registered email id
{
ifstream file("database.txt");
string str;
while (getline(file, str))
{
if (checkEmail)
{
if (str == tempAccount.password)
{
cout << "Login successful! ";
getline(cin, tempAccount.password);
}
else
for (int i = 4; i > 1; i--)
{
cout << "Incorrect password! You have " << i - 1 << " tries remaining.\n";
if (str == tempAccount.password)
break;
}
}
}
}
void makeNewPassword(string &password) //this function helps the user create a secure password
{
int n = password.length();
bool hasLower = false, hasUpper = false, hasDigit = false;
for (int i = 0; i < n; i++)
{
if (islower(password[i]))
hasLower = true;
if (isupper(password[i]))
hasUpper = true;
if (isdigit(password[i]))
hasDigit = true;
}
// Displaying the strength of password
cout << "Strength of password you have entered is ";
if (hasUpper && hasDigit && hasLower && (n >= 6)) // considering a strong must be of length 6 or more
cout << "strong" << endl;
else if ((hasLower || hasUpper) && hasDigit && (n >= 6))
//when at least a lower case or uppercase is used along with digit
cout << "moderate" << endl;
else
cout << "weak" << endl;
}
main.cpp
#include <iostream>
#include <fstream>
#include "data.h"
using namespace std;
int main(){
string e, p;
readEmail(e);
checkEmail();
return 0;
}
I have created this program with the knowledge of a couple of basic C++ courses I took a few semesters ago, and using online tutorials. This is not a homework or an assignment of any kind.
In your readEmail() function, the string email is a local variable. You passed the variable to the function by value, not by reference.
Also, if you pass it by reference, then there's no need to return anything (the function should be void).
void readEmail(string& email) //reads in the email id provided
{
cout << "Enter an email address: ";
cin >> email;
}
int main() {
string e, p;
readEmail(e);
checkEmail();
return 0;
}
But if you want to return the value, than there's no need for parameter, but you need to give that return value to your variable.
string readEmail() //reads in the email id provided
{
cout << "Enter an email address: ";
cin >> email;
return email;
}
int main() {
string e = readEmail();
checkEmail();
return 0;
}
So now whenever i press A or a, it shows the login function however when i type in the correct username or password it returns 0 and i am very lost as to why it happens. It works in python but in c++ i cant get it to work. This is my code... sorry if the code is very hard to understand.
// login system with login and registration and exit
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
char choice;
char return_page;
string username;
string password;
string confirm;
string login_username;
string login_password;
void main_page();
void registration();
void login();
void login()
{
cout<<"Username: ";
cin >> login_username;
cout <<"\nPassword: ";
cin>>login_password;
}
void registration()
{
cout<<"Username: ";
cin>> username;
cout<<"\nPassword: ";
getline(cin, password);
cout << "\nConfirm password: ";
cin >> confirm;
}
void main_page()
{
cout<<"\n\t\t========Login & Registration========\n\n";
cout<<"A.Login\n";
cout<<"B.Registraion\n";
cout<<"C.Exit\n";
cout<<"Please enter which services u would prefer: ";
cin >> choice;
}
int main()
{
main_page();
if(choice == 'C' || choice=='c')
{
return 0;
}
else if(choice == 'B' || choice == 'b')
{
registration();
if(password == confirm)
{
fstream new_file;
new_file.open("registration.txt", ios::out);
if(!new_file){
cout<<"\nCannot register!";
}
else{
new_file<<username;
new_file<<password;
new_file.close();
cout<<"\nRegistration complete";
main();
}
}
else if(password!=confirm)
{
cout<<"\nThe password and confirm password is not the same, type it out again\n";
registration();
}
}
else if(choice =='A' || choice =='a')
{
login();
fstream new_file;
new_file.open("registration.txt", ios::in);
if(!new_file){
cout<<"\nCannot login because of some server issue";
}
else
{
string un;
string pw;
// reading contents of file line by line
getline(new_file,un);
getline(new_file, pw);
if(un == login_username && pw == login_password)
{
return true;
}
else
{
return false;
}
}
}
}
You need to add a newline to separate your username and password like this:
new_file << username << '\n';
new_file << password;
instead of:
new_file << username; // it will concatenate username and password without
new_file << password; // any whitespace or newline in the file
Also, you need to accept the Confirm password correctly, by using getline, the compiler skips it, use std::cin simply to get it.
After this, you'll get rid of your problem.
I have a program that does three things. Asks you how many variables you wan't, ask you to input each variable, then stores it in a vector. I have put some code that checks if your input is correct, and if it isn't, re-loops the code asking for your variable. The problem I am having is that when you type anything in around the second variable, it asks you to try again infinitely.
For instance, if I typed these values into the input:
Variable amount: 5
Please input variable 1: 8
Please input variable 2: 8
ERROR, PLEASE ENTER ONLY VALID SYMBOLS
---------------------
Please input variable 2:
It would keep outputting ERROR, PLEASE ENTER ONLY VALID SYMBOLS over and over again no matter what you typed. The code is down below, and if you have a better name for this question please let me know. (I'm not really sure what to call this)
#include <iostream>
#include <cmath>
#include <string>
#include <algorithm>
#include <vector>
#include <sstream>
using namespace std;
int inputErrorMessage()
{
cout << "\n ERROR, PLEASE ENTER ONLY VALID SYMBOLS \n";
cout << "--------------------- \n";
return 0;
}
int main()
{
// Declare the variables, vectors, etc.
int varNum = 1;
int totVar = 0;
int choice = 0;
vector<int> userNums;
double input = 0;
string checktotVar = "";
string checkInput = "";
string sym = "";
bool valid = false;
stringstream sstotVar;
stringstream ssinput;
if (choice != 6) {
while (!valid) {
valid = true;
// Ask user for how many variables they want then record it
cout << "Variable amount: ";
getline(cin, checktotVar);
sstotVar << checktotVar;
sstotVar >> totVar;
if (sstotVar.fail() || totVar <= 0) {
inputErrorMessage();
valid = false;
sstotVar.clear();
sstotVar.ignore();
}
}
valid = false;
while (!valid) {
valid = true;
// Ask the user for each variable, then record it into the array
for (int i = 0; i < totVar; ++i) {
cout << "Please input variable " << varNum << ": ";
getline(cin, checkInput);
ssinput << checkInput;
ssinput >> input;
if (ssinput.fail()) {
inputErrorMessage();
valid = false;
ssinput.clear();
ssinput.ignore();
}
if (valid == true) {
userNums.push_back(input);
varNum++;
}
}
}
}
}
ssinput >> input;
reads the one thing in ssinput right to the end of the stream while leaving the read valid. The next time around
ssinput << checkInput;
can't write into the stream because the stream hit the stream's end. That means the read also fails and
if (ssinput.fail()) {
enters the body of the if where the program clears the error
ssinput.clear();
and then promptly reads off the end of the stream with
ssinput.ignore();
causing the error all over again.
Quickest solution:
Recreate
stringstream ssinput;
on each loop iteration. So
stringstream sstotVar;
//stringstream ssinput; gone from here
and
getline(cin, checkInput);
stringstream ssinput(checkInput); // and now tighter scope recreated each loop.
ssinput >> input;
Also by keeping the stream around without emptying it out it can get very., very big.
You can also simplify your logic around
while (!valid) {
and eliminate some repeated code by moving the read validation into it's own function
int getMeANumber(const std::string & message, int min)
that loops until it gets a number and then returns that number. For example:
int getMeANumber(const std::string & message, int min)
{
while (true)
{
cout << message;
string checktotVar;
getline(cin, checktotVar);
stringstream sstotVar(checktotVar);
int totVar;
sstotVar >> totVar;
if (!sstotVar || totVar <= min)
{
inputErrorMessage();
}
else
{
return totVar;
}
}
}
Now main is this itty-bitty tiny lil' thing.
int main()
{
int choice = 0;
vector<int> userNums;
if (choice != 6)
{
int totVar = getMeANumber("Variable amount: ", 0);
for (int i = 0; i < totVar; ++i)
{
stringstream varname;
varname << "Please input variable " << i+1 << ": ";
userNums.push_back(getMeANumber(varname.str(), numeric_limits<int>::min()));
// numeric_limits<int>::min requires #include <limits>
}
}
}
Here are the issues with this code.
In this part:
if (valid == true) {
userNums.push_back(input);
varNum++;
}
you forgot to add an ssinput.clear(). This will reset the stream state (clear the error flags), otherwise you cannot use it again. That is why it stops working at the second input.
In addition, even though this works, you are pushing back a variable that you declared as double into a vector of ints. That is bound to cause issues if this was intended to store double variables, instead of truncating them and storing them as ints.
It should be:
#include <iostream>
#include <cmath>
#include <string>
#include <algorithm>
#include <vector>
#include <sstream>
using namespace std;
int inputErrorMessage()
{
cout << "\n ERROR, PLEASE ENTER ONLY VALID SYMBOLS \n";
cout << "--------------------- \n";
return 0;
}
int main()
{
// Declare the variables, vectors, etc.
int varNum = 1;
int totVar = 0;
int choice = 0;
vector<int> userNums;
double input = 0;
string checktotVar = "";
string checkInput = "";
string sym = "";
bool valid = false;
stringstream sstotVar;
stringstream ssinput;
if (choice != 6) {
while (!valid) {
valid = true;
// Ask user for how many variables they want then record it
cout << "Variable amount: ";
getline(cin, checktotVar);
sstotVar << checktotVar;
sstotVar >> totVar;
if (sstotVar.fail() || totVar <= 0) {
inputErrorMessage();
valid = false;
sstotVar.clear();
sstotVar.ignore();
}
}
valid = false;
while (!valid) {
valid = true;
// Ask the user for each variable, then record it into the array
for (int i = 0; i < totVar; ++i) {
cout << "Please input variable " << varNum << ": ";
getline(cin, checkInput);
ssinput << checkInput;
ssinput >> input;
if (ssinput.fail()) {
inputErrorMessage();
valid = false;
}
if (valid == true) {
userNums.push_back(input);
varNum++;
}
ssinput.clear();
}
}
}
}
EDIT: You need to clear the stringstream on each iteration of the loop, otherwise you're not writing to an empty stream when you grab the next input from the user, which is what's causing the .fail() method to return true after the first iteration of the loop.
How I'm I going to add another condition in case the user didn't put anything in both username and password? ( "Empty Username and/or Password - Username and Password required!. Try Again? (Y/N)" )
here's my. code.
#include "stdafx.h"
#include <iostream>;
#include <string>;
using namespace std;
string username;
string password;
string choice;
int main(int argc, const char * argv[])
{
do {
Username:
std::cout << "Enter Username: ";
std::cin >> username;
if (username != "Joven")
{
std::cout << "Invalid Username. Please try again.\n\n\n";
goto choice;
goto Username;
}
Password:
std::cout << "Enter Password: ";
std::cin >> password;
if (password != "Fabricante7188")
{
std::cout << "Invalid Password. Please try again.\n\n\n";
std::cout << "Do you want to try again? y/n \n\n";
cin >> choice;
goto Password;
}
else
{
std::cout << "Correct Username and Password - Log In Successfull.\n";
break;
choice:
std::cout << "Do you want to try again? y/n \n\n";
std::cin >> choice;
}
}while (choice != "y" && choice != "n");
if (choice != "y" && choice != "n")
{
cout << "Invalid choice.\n";
goto choice;
}
system("pause");
return 0;
}`
thanks a lot!
Using the input operation >> you can't. It will block until there is some actual non-space input followed by the Enter key (or there's an error or "end of file").
The C++ standard solution (without resorting to OS specific functionality) is to read a whole like using e.g. std::getline, strip the input of leading (and possibly trailing) spaces, and then see if the resulting string is empty or not.
My solution would be something like this: (Edited by scorch 2017/01/14 10:24 AEST)
//#include "stdafx.h" I made this a comment because I don't appear to have this file. It wasn't necessary for me. Don't know whether you need it or not.
// include statements must not end with semicolons.
#include <iostream>
#include <string>
#include <cstdlib> // Has system() function
using namespace std;
int main(int argc, const char * argv[])
{
// Always declare variables inside the function.
string username;
string password;
string choice;
bool finished = false; // Declare this.
bool askingToTryAgain = false; // For when the user is asked whether they want to try again.
do {
std::cout << "Enter Username: ";
std::getline(std::cin, username);
std::cout << "Enter Password: ";
std::getline(std::cin, password);
// Validate username and password.
if (username != "Joven" && password != "Fabricante7188") {
// If both the username and password are invalid, report it.
std::cout << "Invalid Username and Password. Try again? (y/n): ";
} else if (username == "Joven" && password == "Fabricante7188") {
// If both fields are valid, login is successful.
std::cout << "Correct Username and Password - Log In Successful.\n";
finished = true; // Login is now complete, the loop will end.
} else {
// If just one of the fields is invalid, report which one it is.
if (username != "Joven") {
std::cout << "Invalid Username. Try again? (y/n): ";
}
if (password != "Fabricante7188") {
std::cout << "Invalid Password. Try again? (y/n): ";
}
}
if (finished == false) {
// If the login was unsuccessful, await user input for whether they wish to try again or not.
askingToTryAgain = true;
do {
// Fetch user input (y/n)
std::getline(std::cin, choice);
// Validate it.
if (choice != "y" && choice != "n") {
std::cout << "Enter 'y' or 'n'\n";
} else {
askingToTryAgain = false;
if (choice == "y") {
// Nothing to do here. The parent loop will continue after this one stops.
} else if (choice == "n") {
finished = true; // The user wishes to quit.
}
}
} while (askingToTryAgain);
}
} while (finished == false);
system("pause"); // During testing I used 'sleep 4' (sleep for 4 seconds) because I'm running Linux.
return 0;
}
Also, please do yourself a favour and avoid using 'goto' as a way to control the flow of program execution. Loops and conditions are a far better solution in a structured programming language such as C++ than the 'goto' statements.
I suggest you have a look at http://cplusplus.com/ as a good reference tool.
Hope this helps.
So I want to validate the user only enters text and not numbers. If any number is input, then I ask her again for input. I thought this would do the trick, but it doesn't seem to work:
#include <iostream>
using namespace std;
int main()
{
string name = "";
cout << "Enter name: ";
getline(cin, name);
while (!cin) // or cin.fail()
{
cout << "Numbers are not allowed, input name again: ";
cin.clear();
cin.ignore(1000, '\n'); // is this even necessary since getline() already consumes spaces and new lines?
getline(cin, name);
}
}
Because the name variable is of string type, shouldn't the cin object fail when it receives a number? How can I validate it and make sure it prompts for input again when a number is entered? Also, out of curiosity since I'm asking already, if the user enters something like: Scarlett9356, what would be a good way to re-prompt for good input? Thank you.
You could validate that there are no numbers in your string by doing this:
#include <iostream>
using namespace std;
bool validName(string name)
{
if(name.length() == 0)
return false; // `name` cannot be empty
for(int i = 0; i < name.length(); i++)
if(name[i] >= '0' && name[i] <= '9')
return false; // There is a number in `name`
return true; // `name` is valid
}
int main()
{
string name = "";
cout << "Enter name: ";
getline(cin, name);
while (!validName(name))
{
cout << "Numbers are not allowed, input name again: ";
cin.clear();
cin.ignore(1000, '\n'); // is this even necessary since getline() already consumes spaces and new lines?
getline(cin, name);
}
}
Because the name variable is of string type, shouldn't the cin object fail when it receives a number?
No. Input that consists of digits is valid as string also.
You'll need to use a different strategy for making that an invalid input.
I would suggest something along the lines of:
bool is_valid_input(std::string const& name)
{
bool is_valid = true;
// Figure out the logic for deciding when the input is not valid.
// ...
if (!is_valid )
{
cout << "Numbers are not allowed, input name again: ";
}
return is_valid;
}
int main()
{
string name = "";
do
{
cout << "Enter name: ";
getline(cin, name);
}
while ( !is_valid_input(name) );
}
If you want to limit your input to only taking in string without a number in it then you can use std::any_of and std::isdigit
std::string name = "";
std::cout << "Enter name: ";
std::getline(std::cin, name);
while (std::any_of(name.begin(), name.end(), [](char ch) { return std::isdigit(ch); }))
{
std::cout << "Numbers are not allowed, input name again: ";
std::getline(std::cin, name);
}