C++ function runs more than intended - c++

When I run my program the user can log in, but if the enter in a wrong user name, it runs a check username loop again, saying that they did not enter in a valid user name. This work perfectly fine except for one thing. Say they attempt to log in in three times and the third attempt is correct and the get prompted for a password. Once they input it it ask for a second password and then a third. It seems like it is completing the function for the other attempts. I can not think of a way to check for this. Any ideas.
If you look at it you can see that I am calling UserCheck inside of getNameIndex. I am almost positive this is where the error is occurring.
The Function that checks the users:
void User_Psw::UserCheck()
{
// read from the database
ifstream fin("dataBase.txt", ios::in);
if( !fin.good() )
{
cout << "Failed to open database file." << endl;
return;
}
while (fin >> username >> password)
{
Usernames.push_back(username);
Password.push_back(password);
++sizeOfDatabase; // This may or may not be needed elsewhere.
}
// rest of the program
cout << "Username: ";
cin >> username;
getNameIndex();
cout << "Password: ";
cin >> password;
if(!PasswordMatches())
{
cout << "Access denied";
}
else
{
cout << "Success! You have logged in.";
}
}
This is the username check function
void User_Psw::getNameIndex()
{
userThere = false;
for(int i=0; i < sizeOfDatabase; i++)
{
if (Usernames[i] == username)
{
index = i;
userThere = true;
}
}
if (userThere == false)
{
cout << "\nThat user name does not exsist. \n";
cout << "Please try again. \n\n";
UserCheck();
}
}

The structure of your program is wrong.
Instead of getNameIndex calling UserCheck() again, you should have getNameIndex return a bool - true on success, false on failure. Run it inside of a loop, something like this:
bool success = false;
while (!success)
{
cout << "Username: ";
cin >> username;
success = getNameIndex();
}
Also, instead of having global variables, you should pass them to the function. Something like:
success = getNameIndex(username);
and getNameIndex() shouldn't do any I/O - the function that calls getNameIndex() should also be responsible for printing the error message. Imagine if you used getNameIndex() in a different context, such as when when the program is being run by another program or in an automated way - then printing to the console would be meaningless.

Related

I am getting the error that variable "count" is not being initialized. But it should be initializing after reading and verifying data from file. C++

I am working on Login/Registration system. So far I am getting the error that the variable "count" is used without being initialized.
bool count;
string userId, password, id, pass;
system("cls");
cout << "\t\t\n Please enter the username and password\n\n";
cout << "Username:";
cin >> userId;
cout << "Password:";
cin >> password;
//reads info from the file
ifstream readL("record.txt");
while (readL >> id >> pass) {
if (id == userId && pass == password) {
count = true;
}
else {
count = false;
}
}
readL.close();
if (count == true) {
cout << userId << " your LOGIN is successfull.\n\n";
main();
}
else {
cout << "\nLOGING error\n\nPlease check your username and password\n\n\n";
main();
}
I have second part of the code and same system works here. `
case 1: {
bool count;
string suserId, sId, spass;
cout << "\n\nEnter the username that you remember:";
cin >> suserId;
//reads the file
ifstream f2("records.txt");
while (f2 >> sId >> spass) {
if (sId == suserId) {
count = true;
}
else {
count = false;
}
}
f2.close();
if (count == true) {
cout << "\n\n\tYour account is found!\n\nYour password is " << spass << endl << endl;
main();
}
else {
cout << "\n\n\tSorry your account is not found." << endl << endl;
main();
}
break;
}
`
The only difference that in the first case it reads two variables during the while if statement, in second only Username.
But even if I am going to read only Username in the first case error is still appearing.
Your C++ compiler is smart enough to figure out that if the file could not be opened or is empty, the while loop never executes even once, and count remains uninitialized until its value is checked after the loop. That's what your C++ compiler is telling you.
Just because the input file exist or is not empty, and its contents are valid (because garbage in it will also result in the initial attempt to read it fail) is immaterial. It is logically possible for count to be uninitialized when its value gets used, hence your compiler's diagnostic.
P.S. the while loop's logic is also fatally flawed, for a different reason. But that's unrelated to the compiler diagnostic you asked about.
Maybe you should just initialize it with
bool count = false;

Try and catch with while loop: jumps to catch block even after the input is correct only if the first input was incorrect - C++

I'm trying to check if the user has entered their name correctly, with or without space i.e. Joe Bloggs. They cannot have special characters or numbers in their name or it will pop up with an error message i.e. Jo3_Bl0ggs. What I'm trying to do is if they enter their name in the wrong format, an error message will be alerted and the program will ask the user to enter their name again, until they enter it correctly.
I'm using a while loop to do this so if it's correct, I change the value of the flag and break out of the loop, if not I'll rerun the setName() function which asks for their name.
However the problem I'm having is that if they enter for the first time and it's incorrect, it asks them to enter their name again and if the second input is correct a message will say "Welcome Joe Bloggs", but the loop will continue and ask them to enter their name in again.
The only way I can avoid this problem is if the first input is correct, but that kind of defeats the whole point of the try and catch block.
Below is the two functions I'm concerned with. If someone can point me in the right direction, then that would be great. I'm new to c++ which is why I'm a bit confused about this.
inputclass::inputclass(){//empty constructor}
void inputclass::validateName(string name){
int flag = 1;
while ( flag == 1){
try{
for (int i=0; i < name.length(); i++){
if (name[i] != ' '){
if (!isalpha(name[i])){
cout << "You have entered incorrectly. Please try again. " << endl;
cin.clear(); //I'm trying to clear input buffer but still doesn't work
cin.ignore(256, '\n');
setName();
throw 0; //do i need this?
break; //do i need breaks?
}else if(i == name.length()-1){
cout << "Welcome to the program " << name << endl;
flag = 2; //break out of while loop
break; //not sure if this does anything
}
}
}
}catch (int e){
cout << "There's been an error" << endl;
setName(); //until input is correct, this will ask the user for their name.
}
}
}
void inputclass::setName(){
string name;
cout << "Please enter your name: " << endl;
getline(cin, name);
validateName(name);
}
My honest opinion is that your algorithm logic itself is wrong. Validation should be done as a consequence of input. The input itself should be the decision point of recycling on validation failure
1. Write a simple validation function
This is easier than you may think, in particular since the standard library provides some neat algorithms for doing much of the iteration work for you.
2. Integrate your validation function exclusively in setName(); not the opposite.
Your input mechanics should take said-input, validate, and if invalid, loop on the input. The validator should exclusively be returning yea or nay. Leave the input mechanics to the input function, and don't trigger them from the validator. A validator is for just that; validating, not cycling input loops.
The first of these is fairly simple since the standard library provides you with most of the algorithms you need. The sample below uses a functor to do this, but C++11 could easily do this with a lambda instead:
struct is_not_space_or_alpha
{
bool operator()(char c) const
{
return c != ' ' && !std::isalpha(static_cast<unsigned char>(c));
}
};
static bool is_valid_name(const std::string& name)
{
return !name.empty() &&
name.end() != std::find_if(name.begin(), name.end(), is_not_space_or_alpha());
}
With that, your setName() becomes the location where validation is a consequence of input; the validation doesn't internally trigger more input. That is left to the caller (setName()) to decide:
std::string name;
while (true)
{
std::cout << "Please enter your name: ";
std::flush(std::cout);
if (std::getline(std::cin, name) && is_valid_name(name))
{
std::cout << "Welcome to the program " << name << "!\n";
break;
}
std::cout << "You have entered incorrectly. Please try again. \n";
std::cin.clear();
}
Sample Output
Please enter your name: Monkey777
You have entered incorrectly. Please try again.
Please enter your name: Wiley Coyote
Welcome to the program Wiley Coyote!
The Bottom Line: Don't trigger input from validation. Instead, trigger validation from input and act accordingly.

Login from txt file with attempt limits

i'm totally new to C++ and this forum. I tried searching the codes and found a piece of code but it doesn't work as what I wanted. I want a login that check every line of the txt file and grant access to the system if the username and password is correct.
string line = " ";
ifstream readfile("Login.txt");
string username, password, adminname, adminpass;
cout << "\nEnter Username: ";
cin >> username;
cout << "\nEnter Password: ";
cin >> password;
while (getline(readfile, line))
{
stringstream iss(line);
iss >> adminname >> adminpass;
//Login Success Function
if (username == adminname && password == adminpass)
{
cout << "\nLOGIN SUCCESSFUL!";
}
}
//Login Fail Function
{
int fail = 5;
while (fail > 0)
{
cout << "Error! Invalid Username and Password. Please reenter.\n";
cout << "You have " << fail << " tries left.\n";
cout << "\nEnter Username: ";
cin >> username;
cout << "\nEnter Password: ";
cin >> password;
fail--;
}
cout << "\nACCESS DENIED!";
}
The txt file consists of 1st line (admin123 password123), 2nd line (admin admin).
The login worked fine if I entered correctly however, if I enter wrong username or password I just stuck in the while loop until it shows access denied even if I enter correct username and password for the second try.
Can anyone help me to fix this? If possible please include the comments(the //) so that I am able to learn from it. Thanks in advance.
Since you mention in the comments that this is an assignment, I'm going to keep this pretty general.
In your program, you prompt once for username and password, then read through the file to see if there is a match.
If there is no match, you then prompt for username and password again in a loop, but do not check to see if they are valid. This is what the problem is. Each time you get a new username and password, check to see if they are valid.
There are (at least) two possible approaches:
Include the "fail" and re-prompt logic around the code that reads the file. So you get a username and password, then read the file checking for a match. If no match, do it again. In this case, you would be reading the file each time. For a large data-set, this could get slow. For this problem, it should be fine.
Read the file once and save the values (Have you studied arrays, vectors, or other data structures? You need at least some of those things to do this). I would use a std::map here because it is direct access and would be the smallest amount of code, but there are many other ways to do this as well.
Here is a possible way to do it with re-reading the file. Note that this mostly just re-organizing the code you already have:
bool success = false; //use this as part of our loop condition
int fail = 5;
while (!success && fail > 0) //loop until we succeed or failed too much
{
//get the username and password
cout << "\nEnter Username: ";
cin >> username;
cout << "\nEnter Password: ";
cin >> password;
//open the file and see if we have a match
ifstream readfile("Login.txt");
while (getline(readfile, line))
{
stringstream iss(line);
iss >> adminname >> adminpass;
//Login Success Function
if (username == adminname && password == adminpass)
{
//we have a match, so set success to true so we exit the loop
success = true;
}
}
if (!success) //we did not find a match in the file
{
//so we output the message
cout << "Error! Invalid Username and Password. Please reenter.\n";
cout << "You have " << fail << " tries left.\n";
fail--;
}
}
//now we know if we had success or not, so report it
if (success)
{
cout << "\nLOGIN SUCCESSFUL!";
}
else
{
cout << "\nACCESS DENIED!";
}

Stop a program from running in c++ if bool is false

I am using an if statement to get the users input with a bool value, if they enter 1 then the program continues to execute, if they enter 0 then I want the program to stop running completely. This is the code im using.
bool subscription;
cout << "Would you like to purchase a subscription to our newspaper?\n";
cout << "Enter 1 if yes, and 0 if no. ";
cin >> subscription;
if(subscription == false)
{
cout << "We're sorry you don't want our services.";
//this is where i want the program to stop, after it outputs that line.
}
else if(subscription == true)
{
cout << "\nPlease enter your first and last name. ";
}
I have tried using return 0; after the cout statement, but that didn't work, it would just output the statement and then continue on with the program.
I also tried exit(); and that did the exact same thing.
The problem is that instead of the comparison operator you are using the assignment operator
if(subscription = false)
{
cout << "We're sorry you don't want our services.";
//this is where i want the program to stop, after it outputs that line.
}
else if(subscription = true)
{
cout << "\nPlease enter your first and last name. ";
}
In thsi expression of the if statement
if(subscription = false)
you assigned false to subscription and the expression is also equal to false. As the result the compound statement of this if statement is not executed.
Change the code as
if(subscription == false)
{
cout << "We're sorry you don't want our services.";
//this is where i want the program to stop, after it outputs that line.
}
else if(subscription == true)
{
cout << "\nPlease enter your first and last name. ";
}
It would be even better if you would write
if( subscription )
{
cout << "\nPlease enter your first and last name. ";
}
else
{
cout << "We're sorry you don't want our services.";
// here you can place the return statement
}
#include <iostream>
using namespace std;
int main()
{
bool subscription;
cout << "Would you like to purchase a subscription to our newspaper?"<<endl;
cout << "Enter 1 if yes, and 0 if no. "<<endl;
cin >> subscription;
if(!subscription){
cout << "We're sorry you don't want our services."<<endl;
//this is where i want the program to stop, after it outputs that line.
return -1;
}
else{
cout << "\nPlease enter your first and last name. "<<endl;
return 0;
}
}
A couple of guidelines:
Do not use var = true or var = false (use double == for comparison)
Do not user boolean variables var == true in comparisons with true or false, just use them directly as boolean conditions
Put "<<"endl" when using streams for line breaks better than \n
Use return in main function will return in that place, thus finishing your program.

Reading in Encrypted Username/Password

I am in the process of developing a console application that acts as a Diary. At this stage I am developing the login authentication and have hit a bit of a wall! As I will be dealing with text files for both my login and diary storage, I would like to encrypt these text files from prying eyes.
Now, the problem is I do not know how to go about the decrypt >> check user&&pass >> encrypt again.
Would it be along these lines?:
Program Loads
Decrypt passwords.txt
If at any point the program closes, encryptFile() is ran.
Validate user entry
Encrypt passwords.txt
If I am along the right lines how do I go about implementing this? I searched for encryption tutorials for text files using c++ and they were not very helpful.
Here is my butchered beginner password.txt code, where shall I go from here? If there is an encryption tutorial/article you recommend that I missed please post it!
void checkPasswordFile() {
string username;
string password;
string passwordAgain;
string userIn;
string passIn;
string line;
ifstream passwordFile("passwords.txt");
istringstream instream;
if (passwordFile.good()) {
cout << "\t==================================" << endl;
cout << "\t----------------------------------" << endl;
cout << "\tYou are a returning user, please fill in your details" << endl;
while(!passwordFile.eof()) {
getline(passwordFile, line);
instream.clear();
instream.str(line);
username = line;
getline(passwordFile, line);
instream.clear();
instream.str(line);
password = line;
}
do {
cout << "Username: " << endl;
cin >> userIn;
cout << "Password: " << endl;
cin >> passIn;
if (userIn == username && passIn == password) {
displayMenu();
} else {
cout << "Username and Password Do Not Match, Try Again" << endl;
}
} while(userIn != username && passIn != password);
} else {
cout << "file no exist";
ofstream passwordFile;
passwordFile.open ("passwords.txt", ios:: in | ios::app);
cout << "\t==================================" << endl;
cout << "\t----------------------------------" << endl;
cout << "\tThis is your first run, please enter a username and password" << endl;
cout << "\tUsername: " << endl;
cin >> username;
cout << "\tPassword: " << endl;
cin >> password;
/*
Do Loop:
Prompts Re-Entry if PasswordAgain is not equal to Password
*/
do {
cout << "Re-Type Password: ";
cin >> passwordAgain;
if(password != passwordAgain) {
cout << "Passwords Do Not Match! Try Again" << endl;
}
} while(password != passwordAgain);
passwordFile << username << "\n";
passwordFile << password;
}
}
Thank you very much for your time.
p.s for the life of me I cannot find out how to do:
Username:[cin>>username] on the same console line, sorry for doubling up but didn't deem it a big enough question for its own post! Thanks.
EDIT:
I have succesfully been able to decrypt the username and pass when created and stored in the text file. Then when the user comes back, what they entered is encrypted and compared with the file.
Problem being this only works for short words, user pass works, but username and password does not... any ideas why? Here is my encryption code:
char encryptKey = 'h';
cout << "\tUsername: ";
cin >> userIn;
cout << "\tPassword: ";
cin >> passIn;
for (int i = 0; i < userIn.size(); i++) {
userIn[i] ^= encryptKey;
}
for (int x = 0; x < passIn.size(); x++) {
passIn[x] ^= encryptKey;
}
if (userIn == username && passIn == password) {
displayMenu();
} else {
cout << "\tUsername and Password Do Not Match, Try Again" << endl;
}
The right thing to is not to encrypt the passwords file - the issue is that the encryption key for the file would need to be stored somewhere that the program can access it, which would make it relatively easy to find and abuse.
Instead, you should be using password hashing (using a strong hash algorithm like SHA1). A hash algorithm is a algorithm that deterministically maps a piece of text onto a large number (called its hash), and is designed to be irreversible without great effort. The basic concept is that you take the password, use it to compute its hash, and then store that hash. Later, when the user enters the password to log in, you compute its hash again and compare the resulting hash to the stored hash. Even if someone gains access to the hashes, they do not obtain the password, which is important, because people often share passwords between applications. Don't implement your own SHA1 hash - see "What is the best encryption library in C/C++?" for a list of libraries.
You must also use salting and key stretching to defend against common brute force attacks.