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.
Related
This is actually related to another question I asked, but i'v narrowed down the problem and rewrote the program to be cleaner and more barebones.
The main function passes the user to a menu where they can select what they wanna do. Problem is, that every time they press the return key, it seems to log that input into the cin buffer. When the user finally makes a choice and gets passed to the appropriate function, it spits out all the enter keys they hit which can cause it to skip through the process. This is pretty annoying, especially since I wanna use VK_RETURN for the selection.
Now, I could just stick a bunch of cin.clear() and cin.ignore()'s everywhere, but from what I understand, that's bad practice. Also, it messes with the program because it forces the user to hit the enter key an extra time to get off that line and messes with formatting.
Is there a way around this? Or is cin.clear() and cin.ignore my only hope?
main.cpp
#include <limits>
#include <iostream>
#include "menu_GUI.h"
int main()
{
bool running = true;
std::string selection; //user selection for selector menu
std::string address; //address to send funds to
int amount; //amount of funds to send
std::string password; //password for wallet encryption
menu_GUI menu; //object for menu_GUI class
while(running)
{
selection = menu.mainMenu(); //collect users selection from the menu_GUI class selector function
if(selection == "send")
{
address = menu.askAddress(address); //collects the address the user wants to send funds to
if(address != "cancel"){amount = menu.askAmount(amount);} //collects the amount the user wants to send if they don't cancel
if(amount != 0){} //if the amount isn't 0, then it sends the transaction (unfinished, does nothing right now)
}
if(selection == "lock") //unfinished, but will lock the wallet
{
}
if(selection == "unlock") //unfinished, but will lock the wallet
{
}
}
return 0;
}
menu_GUI.h
#ifndef MENU_GUI_H
#define MENU_GUI_H
#include <vector>
#include <string>
class menu_GUI
{
public:
std::string mainMenu();
std::string askAddress(std::string address);
int askAmount(int amount);
void moveCursor(int x, int y);
void hideCursor();
private:
std::vector<std::string> UI {"[Send] ", "Lock ", "Unlock"};
int rightMoves = 2;
int leftMoves;
int inputDelay = 150; //modify this value to change the delay between user selector movements
std::string selection;
};
#endif // MENU_GUI_H
menu_GUI.cpp
#include "menu_GUI.h"
#include <windows.h>
#include <iostream>
#include <limits>
std::string menu_GUI::mainMenu()
{
bool selecting = true;
while(selecting)
{
hideCursor(); //hides the cursor
leftMoves = 2 - rightMoves; //sets the number of left movements remaining based on right movements remaining
for(int x = 0, y = 0; x < UI.size(); x++)
{
moveCursor(0, 0);
std::cout << "Balance: "; //displays users balance
moveCursor(0, 2);
std::cout << "Address: "; //displays users public key
moveCursor(y, 4); //prints out the map
std::cout << UI[x];
y += UI[x].length(); //sets y equal to the total length accumulated on the line so far
}
if(GetAsyncKeyState(VK_RIGHT)) //handles right key inputs
{
if(rightMoves != 0) //check if user can move right
{
switch(rightMoves)
{
case 1:
rightMoves--;
UI[1] = "Lock ";
UI[2] = "[Unlock]";
break;
//modifies the UI vector accordingly
case 2:
rightMoves--;
UI[0] = "Send ";
UI[1] = "[Lock] ";
break;
default:
break;
}
}
Sleep(inputDelay); //Delay, so that user doesn't input twice
}
if(GetAsyncKeyState(VK_LEFT)) //handles right key inputs
{
if(leftMoves != 0) //check if user can move left
{
switch(leftMoves)
{
case 1:
rightMoves++;
UI[0] = "[Send] ";
UI[1] = "Lock ";
break;
//modifies the UI vector accordingly
case 2:
rightMoves++;
UI[1] = "[Lock] ";
UI[2] = "Unlock";
break;
default:
break;
}
}
Sleep(inputDelay); //Delay, so that user doesn't input twice
}
if(GetAsyncKeyState(VK_RETURN)) //handles which selection the user chooses based on how many rightMoves remaining
{
system("cls"); //clears the screen, since it's about to display a new page
switch(rightMoves)
{
case 2:
selection = "send";
return (selection);
break;
case 1:
selection = "lock";
return (selection);
break;
case 0:
selection = "unlock";
return (selection);
break;
default:
break;
}
}
}
}
std::string menu_GUI::askAddress(std::string address) //asks user where they wanna send it
{
std::cout << "Enter where you wanna send the BigBoiCoins. Or type cancel." << std::endl;
std::cout << "Address: ";
getline(std::cin, address); //shouldn't need to check failbit. user input can be anything.
return address;
}
int menu_GUI::askAmount(int amount) //asks user how much they wanna send
{
bool inputting = true;
while(inputting)
{
std::cout << "Enter how many BigBoiCoins you wanna send. Just put 0 if you don't wanna send any." << std::endl;
std::cout << "Amount: ";
std::cin >> amount;
if(!std::cin) //checks failbit to make sure user isn't an idiot and inputs something other than a number
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "who buckaroo! That wasn't a good input. I'll let you try again, I know some of us are special." << std::endl;
}
else{inputting = false;}
}
return amount;
}
void menu_GUI::moveCursor(int x, int y) //move the cursor to the desired coords
{
static const HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
std::cout.flush();
COORD coord = { (SHORT)x, (SHORT)y };
SetConsoleCursorPosition(hOut, coord);
}
void menu_GUI::hideCursor() //hides the cursor
{
CONSOLE_CURSOR_INFO info;
info.dwSize = 100;
info.bVisible = false;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
}
You need to add some input functions to "eat" some characters. And you'd better use if(GetAsyncKeyState(KEY) & 0x8000) instead.
if (GetAsyncKeyState(VK_RETURN)& 0x8000) //handles which selection the user chooses based on how many rightMoves remaining
{
getline(std::cin,NULL);
//...
}
and
std::cin >> amount;
char c = getchar();//eat '\n'
I have created a C++ program. In this I have added many options for a user.
But in every choice I need to add a function from which a user can either choose to exit the program or can return to the main menu depending upon his choice. So can i have help in my coding.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-:
#include<iostream.h>
#include<conio.h>
void main()
clrscr();
int choice,p_card;
char text0,text1;
cout<<"\n\n\t\t\t \"Welcome to Zinc hospital\"\n\n\n";
cout<<"\tMENU\n";
cout<<"\n\n1. Emergency treatment\n\n";
cout<<"2. Common treatment\n\n";
cout<<"3. Regular checkups\n\n";
cout<<"4. Get appointment\n\n";
cout<<"5. Consult specialist\n\n";
cout<<"6. Pay due amount\n\n";
cout<<"7. Log in for new patient card\n\n";
cout<<"8. For suggestions, feedbacks and register complains\n\n";
cout<<"\n\t\t\t\t\t\t\t\tChoice______";
cin>>choice;
clrscr();
if(choice==1)
{
int e_choice;
cout<<"\n\n\n Enter the type of emergency";
cout<<"\n\n1. Accidental case";
cout<<"\n\n2. Heavy injury case";
cout<<"\n\n3. Delicate organ injury\n\n";
cout<<"4. Any other\n\n";
cout<<"\n\n\t\t\t\t\t\t\tEmergency choice____";
cin>>e_choice;
if(e_choice==4)
{
cout<<"Please specify the type of emergency ";
cin>>text0;
}
cout<<"\n\n\n\n\t\t\t \"EMERGENCY DECLARED\"\n\n\t \'Please quickly proceed to the operation theatre with patient\'";
}
if(choice==2)
{
cout<<"\n\nEnter the patient card number\n\n\t";
cout<<"\t\t\tCard No.______";
cin>>p_card;
cout<<"\n\n\t\t\tYour card has been recognized succesfully.";
cout<<"\n\n\nNow enter the specific treatment to be provided___";
cin>>text0;
cout<<"\n\n\n\n \t\t\tDATA recorded succesfully";
cout<<"\n\nYour card has been charged $10.\n\n\n\n Please proceed to counter to get the room no. and wait list serial.";
}
else if(choice==3)
{
cout<<"";//Under construction
}
else if(choice==4)
{
cout<<"";//Under construction
}
else if(choice==5)
{
cout<<"";//Under construction
}
else if(choice==6)
{
cout<<"";//Under construction
}
else if(choice==7)
{
cout<<"";//Under construction
}
else if(choice==8)
{
cout<<"";//Under construction
}
else if(choice!=1&&choice!=2&&choice!=3&&choice!=4&&choice!=5&&choice!=6&&choice!=7&&choice!=8)
{
cout<<"Invalid choice inputed";
cout<<"\n\n\n\n\n\n\t\t#Domain ERROR";
}
getch();
}
Lookup table (one of many solutions).
typedef (void) (P_Function)(void);
struct Menu_Entry
{
unsigned int selection_number;
const char * text;
P_Function p_processing_function;
};
void Process_Emergency_Treatment(void);
void Process_Common_Treatment(void);
Menu_Entry main_menu[] =
{
{1, "Emergency Treatment", Process_Emergency_Treatment},
{2, "Common Treatment", Process_Common_Treatment},
};
static const unsigned int quantity_menu_items =
sizeof(main_menu) / sizeof(main_menu[0]);
// ...
unsigned int selection;
std::cout << "Enter selection: ";
std::cin >> selection;
unsigned int index = 0U;
for (index = 0U; index < quantity_menu_items; ++index)
{
if (main_menu[index].selection_number == selection)
{
main_menu[index].p_processing_function(); // Execute the command processor.
break;
}
}
if (index >= quantity_menu_items)
{
std::cout << "\nInvalid selection, try again.\n";
}
A nice advantage to the lookup table is that when you want to add items to the menu, add an entry into table. Also, you only need to test the search loop once. Adding more entries to the table doesn't effect the execution of the search loop.
Edit 1: Fundamental menu algorithm
The fundamental algorithm can look like this:
bool selection_is_valid = false;
while (!selection_is_valid)
{
Print_Menu();
unsigned int selection = 0U;
std::cout << "Enter selection: ";
std::cin >> selection;
if (select >= MAXIMUM_CHOICES)
{
selection_is_valid = false;
}
else
{
Process_Menu_Item(selection);
selection_is_valid = true;
}
}
With a little skill you can modify the above algorithm to display until an "exist selection" is pressed.
class flight //main class flight which the user uses to book tickets
{
int booking_id;
int pnr,p_age;
char p_name[25],d_a_name[25],a_a_name[25],gender,departing_date[10],arrival_date[10],b_id;
long double price;
public:
flight()
{
static int id=0;
booking_id=id++;
}
void modfunction(int n);
};
void flight::modfunction(int n) //function for entering new values when the user has chosen to modify
{
getchar();
cout<<"Enter the passenger's name :";
gets(p_name);
cout<<"Enter the passenger age :";
cin>>p_age;
getchar();
cout<<"Enter the passenger's gender :";
cin>>gender;
getchar();
cout<<"Enter the departing date(dd-mm-yyyy) :";
gets(departing_date);
cout<<"Do you want to book return ticket with a 10% discount?(y/n) :";
cin>>return_ticket_input;
if(return_ticket_input=='y')
{
cout<<"Enter the arrival date :";
gets(arrival_date);
}
cout<<"Choose the airline.\n\n";
flights(departing_date,return_ticket_input,arrival_date);
cout<<"\n\nEnter the desired flight number :";
cin>>selected_fno;
}
void modify_ticket()//function for modifying a ticket
{
int n;
system("clear");
cout<<"Enter the booking id for modification ";
cin>>n;
flight f;
fstream fp("flight.dat",ios::binary);
ifstream ifile("flight.dat",ios::binary);
int found=0;
int count_variable = 0;
while(ifile.read((char*)&f,sizeof(f)))
{
if(n==f.retbid())
{
f.output();
f.modfunction(n);
// int s=sizeof(f) * (count_variable + 1);
fp.seekp(ifile.tellg());
fp.write((char*)&f,sizeof(f));
found = 1;
f.output();
getchar();
}
count_variable++;
}
ifile.close();
fp.close();
if(found==0)
{
cout<<"Passenger not founed!";
}
cout<<"Press any key to continue.";
getch();
}
So this is the minimal version of my problem.
The class named flight. a function called modfuction which is used to input data from the user. and another function called modify ticket used by the user to modify the record details.
The problem is even though the user enters the booking id(n) and it outputs the record, when the user tries to update it(modify) it stays the same!
please help me as this is a part of my school project!
thanks in advance!
Instead of fstream fp("flight.dat",ios::binary); write:
fstream fp("flight.dat",ios::binary|ios::in|ios::out);
P.S.: Encountered Same Problem A minute ago..
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.
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...