If statement second condition always executing - c++

I have a struct called users containing username information:
struct User{
string name;
string type;
int credit;
bool loginState;
};
My program reads in a txt file and creates an array of User struct types called "users" to store all the data. Im trying to create a function that deletes a user, so in the for loop below I'm searching for the string
userName
in the users array. If the user name exists then all the information of that user account is stored in the User temp. Otherwise an error is generated stating that the user entered does not exist.
string userName;
User temp;
cout<<"Please enter a username to delete:";
cin >> userName;
for(int i=0; i<usersSize; i++){
if((users[i].name).compare(userName) == 0){
temp.name = users[i].name;
temp.type = users[i].type;
temp.credit = users[i].credit;
temp.loginState = users[i].loginState;
}else{
cout << "Error: User does not exist";
}
}
I've tested my program and no matter what the input is, whether the user exists or not, the if statement always outputs the second condition. How can I fix this?

You need to first check if the user exists and then process the user which was found. The problem in your code is that the for loop checks all users and shows a message for all users but the one that matches (if any).
Check this code:
bool userWasFound = false;
int i;
for(i=0; i<usersSize; i++){
if((users[i].name).compare(userName) == 0){
userWasFound = true;
break;
}
}
// If no user was found, 'userWasFound' will still be 'false' at this point
if(userWasFound){
temp.name = users[i].name;
temp.type = users[i].type;
temp.credit = users[i].credit;
temp.loginState = users[i].loginState;
}else{
cout << "Error: User does not exist";
}

Use a flag to indicate that user found or not.. e.g;
bool flag=false;
for(int i=0; i<usersSize; i++){
if((users[i].name).compare(userName) == 0){
temp.name = users[i].name;
temp.type = users[i].type;
temp.credit = users[i].credit;
temp.loginState = users[i].loginState;
flag=true;
break;
}
}
if(!flag){
cout << "Error: User does not exist";
}
Hope it helped...

Related

Password validation program cpp

I am creating a password validation program and I want the password to contain the following:
* Password must be between 8 to 15 characters long...
* Password must contain at least one digit
* Password must contain at least one Uppercase
* Password must contain at least one number
* Password must contain at least one lowercase
* Password must contain at least one symbol
And if the user enters an invalid password, the program should ask the user to re-enter password. But I'm stuck on how to make the user re-enter the password if its wrong. I tried using 'goto' but its not working...
#include<ctype.h>
#include<stdbool.h>
using namespace std;
bool verify_password();
int main() {
char userName;
char password[15];
cout << "\n\t\t\t\tEnter User Name: ";
cin >> userName;
cin.clear();
cin.ignore(100, '\n');
cout << "\n\t\t\t\tEnter Password: ";
cin >> password;
bool result = verify_password();
if (result) cout<<"Verified password\n";
else {
cout<<"Invalid password\n";
cout<<result;
}
system("pause>0");
}
bool verify_password(){
int lenght = strlen(password);
if (lenght < 8 || lenght > 15) return false;
bool has_upper = false;
bool has_lower = false;
bool has_symbol = false;
bool has_digit = false;
for (int i = 0; i < lenght; i++){
if(isupper(password[i])) has_upper = true;
if(islower(password[i])) has_lower = true;
if(isdigit(password[i])) has_digit = true;
if(ispunct(password[i])) has_symbol = true;
}
if(!(has_upper && has_lower && has_digit && has_symbol)) return false;
}
I see a lot of issues with this code, but the things you should change to start:
Make your verify password function ONLY verify the password. It is currently doing more than that.
Get user input in the main() function. Once you get the password here, you can do something like:
int trys = 0;
while (trys < 3) {
cout << "Enter Password: ";
cin >> password;
if (verify_password(password)) {
cout << "valid!" << endl;
break;
}
cout << "invalid..." << endl;
++trys;
}
You can use recursion to execute the function again. Replace the following:
if(!(has_upper && has_lower && has_digit && has_symbol)){
goto checkPassword;
return false;}
With recursion, such as:
if(!(has_upper && has_lower && has_digit && has_symbol))
return verify_password();
Using goto statements is not a good practice for coding, it's much clearer to use other kind of loops like while and for.
For your problem here I would suggest to re-organize the code in smaller functions:
requestUsername() //Call it to ask user for the username
requestPassword() //Call it to ask user for password
verifyPassword() //Call it to verify the provided password
Then, you could structure your main like this:
username = requestUsername();
password = requestPassword();
while(!verifyPassword(password)) //Invalid password
{
password = requestPassword();
}
Or:
username = requestUsername();
do
{
password = requestPassword();
}while(!verifyPassword(password)) //Invalid password
Hope this helps!

How would I have string validate just the ENTER key being hit?

void Game::validate(string& str1)
{
bool exit = false;
int strLength = str1.length();
while (exit == false)
{
for (int i = 0; i < strLength; i++)
{
if(!isalpha(str1[i]) || isspace(str1[i])) //|| str1.empty())//?
{
cout << "Not a valid name, please try again: " << endl;
getline(cin, str1);
}
else if(isalpha(str1[i]))
{
exit = true;
}
}
}
I am passing down a string,i need to output the error message
if the user hits the Enter key only*. Ive tried using '\n' but isspace should take care of that(which it dosent). When i run the program and hit ENTER only, it freezes...whats wrong with it??? All other validation works except the ENTER key
Blockquote
try and print out your string before you start checking and you'll probably
see that the string is not empty even though enter key was the only input.
before you have the user input try and flush the stream.
try std::cout<<endl;

Checking user valid input and compare with the text file

I have a system where it will display a menu option for user to select and do certain action. Currently I am facing an issue on the function changepassword.
When users select the option of changing password, it will read into my text file and display all the users stored in the text file.
Then users are prompted to enter the user ID that they wish to edit. I am able to edit the records and store back into the text file. But I encounter an issue when the user initially entered a user ID that is not found in the text file. The system should show an error message and go back to the menu bar.
The checks are okay in the removeuser() function when the users enter an invalid user ID, the system will go back to menu bar, but not for changepassword().
//Main Function
int main()
{
switch(option)
case 1:
.....
break;
case 2:
....
break;
case 3:
changepassword();
break;
default break;
}
//Edit user information
void changepassword()
{
printer.printcpheader();
displayuserid(); //display list of user ID to select
string id;
cout<<" enter Cashier ID to edit :"; //getting input
cin>>id;
cout<<endl;
int i = getuserindex(id);
displayuserinfobyid(i); //display selected user ID information
string cashierID;
string password;
cout<<"";
getline(cin, cashierID);
cout<<" Cashier ID :";
getline(cin, cashierID);
cout<<" Password :";
getline(cin, password);
//storing to array
users[i].cashierID = cashierID;
users[i].pw = Decrypt(password);
writeUserDatabase();
cout<<"\E[1;32m"<<cashierID<<" info edited !!!\E [0m"<<endl;
}
//Store values to txt file
void writeUserDatabase()
{
ofstream outfile;
outfile.open ("userdatabase.txt");
if (!outfile)
{
cout << "\E[1;31mFile opened for writing failed\E[0m" << endl;
}
for(int i=0;i<MAX-1; i++) // get the index of array to be display out
{
if(users[i].cashierID!="")
{
outfile<<users[i].cashierID<<";";
outfile<<users[i].pw<<endl;
}
}
outfile.close();
}
//Display all user info
void displayuserinfobyid(int id,int k)
{
//printout selected id information, with highlighting
int i=id;
if(i!=-1)
{
if(k==1)
{
cout<<" User ID :\E[1;32m"<<users[i].cashierID<<"\E[0m"<<endl;
}
else if(k==2)
{
cout<<" User ID :"<<users[i].cashierID<<endl;
}
}
else
{
cout<<" \E[1;31mNo such User ID...\E[0m"<<endl;
}
}
//Get the index from user array
int getuserindex(string id)
{
int i=-1;
for(int i=0;i<MAX-1; i++) // get the index of array to be display out
{
if(users[i].cashierID==id)
{
return i;
}
}
return i;
}
//Remove user info
void removeuser()
{
printer.printruheader();
cout<<endl;
displayuserid(); //display list of User ID to select
string selectedid;
cout<<" enter username to remove :"; //getting input
cin>>selectedid;
cout<<endl;
int i = getuserindex(selectedid);
displayuserinfobyid(i); //display selected user ID information
if(i!=-1)
{
cout<<" are you sure you want to remove (Y/N) :"; //confirmation
char yesno;
cin>>yesno;
yesno = toupper(yesno);
if(yesno=='Y')
{
users[i].cashierID = "";
cout<<" \E[1;29mUser ID "<<selectedid<<" deleted...\E[0m"<<endl;
writeUserDatabase(); //update userdatabasefile
}
else
{
cout<<" \E[1;31mDelete Fail...\E[0m"<<endl;
}
}
}
If the problem is you want to return from the function "changePassword" after an incorrect ID was submitted, then you can just use return; as the function's return type is void.
Notice there are 3 possibilities : return, break or exit.
Break is used to break out of a loop or a switch.
For example :
for(int i = 0; i < 10; ++i) {
if(i < 5)
cout << i << endl;
else
break; // Will cause the loop to be executed 5 times only
}
Exit can be used to force the program to stop execution.
Return is used whenever you just want to return from the current function, this expects something to be returned except if the return type is void.

Error message still printing even though exit condition met and entered

I'm having quite the issue trying to figure out why these code segments are printing the error message even when I have done cout statements within the block that should return true / not print that error message. Any ideas? I'm new here so please let me know if this isn't allowed. Thanks!
Use of function:
case 'a':
{
// Format: a ID credits GPA
// Adds a student with the given student ID (ID), number of
// credits (credits), and overall GPA (GPA) to the database.
// If the student is already in the database, an error
// message should be printed indicating this.
int credits = 0;
double gpa = 0;
cin >> studentID;
cin >> credits;
cin >> gpa;
// Adds the student and checks to see if the student was actually added
// or if there was an existing student with the specified ID
bool added = addStudent(studentID, credits, gpa);
if(added == false);
{
cout << "Student already exists in database, nothing changed." << endl;
// Still prints this when executed with valid
}
break;
}
Function for adding student to array:
bool addStudent (int id, int numCredits, double gpa) {
// Check to see if student exists
if (nextEntry != 0)
{
for (int x = 0; x < 7000; x++) {
Student tmp = studentRecords[x];
if (tmp.studentId == id)
{
return false;
cout << "hey" << endl;
}
}
}
// If student does not exist, add to records database
if (nextEntry != 7000)
{
studentRecords[nextEntry].studentId = id;
studentRecords[nextEntry].numCredits = numCredits;
studentRecords[nextEntry].gpa = gpa;
nextEntry++;
return true;
// confirmed I can get here
}
return false;
}
You have an extra ; after your if (added==false) statement. This will terminate the if statement and the code after will run regardless of the check.

Program requires user to enter non duplicate numbers c++

I have written a function in a program for entering a unique number but its not working. Something is wrong with the for loop.
I need to validate that employee id is unique.
I have made a structure named employee and "emp.id" is employee id. When the user inputs an id, it should not match previous Id's which user might have entered before. This is just a function of the main program, which validates that employee id is unique.
void uniquieid()
{
int check,i;
string code;
string tempemp1;
cout<< "enter id";
cin>> code;
while(!(num-1))
{
for(i=0;i<=num-1;i++)
{
if(emp[i].id.compare(code)==0)//comparing
{
check =1;
cout<<"enter id again";
break;
}
if(check=0) //csaasc
{
emp[i].id=code;
}
}
}
getch();
}
If the order that the ids are entered doesn't matter, I would do something like (note: untested):
using EmpIds = std::set<std::string>;
void addUniqueId(EmpIds& ids)
{
std::pair<EmpIds::iterator, bool> inserted;
const char* again = "";
do {
std::cout << "enter id" << again;
again = " again";
std::string id;
if (!(std::cin >> id))
throw std::runtime_error("No more ids!");
inserted = ids.insert(id);
} while (!inserted.second);
}
There are so many things wrong with the code, but maybe it should look more like this:
void uniqueid() {
int check=1;
string code;
string tempemp1;
cout<< "enter id";
while(check) {
cin >> code;
check = 0;
for (int i = 0; i < num; ++i) {
if (emp[i].id.compare(code)==0) {
check = 1;
cout << "enter id again";
break;
}
}
if (check==0) {
/* emp[i].id=code; */
}
}
getch();
}
Note how int check=1; starts at 1 to mean that the code needs re-entering.
So while(check) means that while the code is not unique keep going.
The for loop does the compare as before, but note the idiomatic form.
The other if (check==0) is outside the for loop and this means that no duplicates were detected so code can be used. However, I'm not sure which employee the code should apply to so I've just commented out the code.
Can you post the employee structure?
Because from this, everything looks OK, but your if function refers to emp.
So something in your structure is causing the problem.
Without your structure, anyone answering probably won't be able to find the problem.
Right now, all i can advise you to do is store employee ids in a vector and iterate through it using a for loop.
You could do
void uniqueid() {
std::vector<std::string> empIds;
std::string code;
CODE TO STORE IDs INTO VECTOR HERE;
int vectorLength = empIds.size();
std::cout << "enter id";
std::cin >> code;
for (int i = 0; i < vectorLength; i++) {
if (empIds[i] == code) {
std::cout << "enter id again";
std::cin >> code;
} else {
empIds.push_back(code);
}
}
}
For a start, something like the below should work.
map <string, bool> seen;
bool isUniqueId(string id)
{
return seen[id];
}
void addId(string id)
{
seen[id] = true;
}
From main(), whenever user inputs a string id, use isUniqueId(id) to ensure its unique, and if its unique, call addId(id).
Edit : (upon request from the OP)
Your transformed code may look like below after using map.
// Global map, defaults to false
map <string, bool> seen; // seen map to store if an id is seen already or not.
void uniqueId()
{
bool good = true; // set up a good flag to check if id is good or not.
int numEmployees = 0; // Count to store number of employees with unique ids so far
string id;
cout<< "enter id\n";
cin>> id;
while(good)
{
good = false; // Assume this is unique!
if(seen[id]) // Check if we already saw this id before
{
good = true; // Alas! We already have seen this id
cout<<"enter id again\n";
continue; // If id already exists, ask for another id setting good = true;
// Note that the above continue is NOT required as loop will run again (good = true).
// Just for clarity sake.
}
else
{
// Voila, we have a new employee with unique id.
seen[id] = true; // Unique, mark as seen now
emp[numEmployees].id=code; // Note numEmployees here
numEmployees++; // Increment the count
}
}
getch();
}
At the end of while loop, you would have successfully gotten a unique id from user, otherwise it will keep asking the user for new id.