Following is the code for a login program that inputs the username, and then the password, while echoing '*' for every character entered, and then compares the username and password to preset values to see if they match and exits the program if it is true, else it goes back to the beginning.
int main()
{
int i = 0; string u; char parr[i + 1], ch;
while (1)
{
system("cls");
cout << "Enter username." << endl;
cin >> u;
system("cls");
cout << "Enter password." << endl;
i = 0;
while (1)
{
tag:ch = getch();
if (ch == '\r')
{
break;
}
if (ch == '\b')
{
cout << '\b';
--i;
ch = '\0';
parr[i] = '\0';
cout << ' ' << '\b';
goto tag;
}
parr[i] = ch;
ch = '*';
cout << ch;
++i;
}
parr[i] = '\0';
string p = "password";
if (u == "username" && parr == p)
{
system("cls");
cout << "Welcome!";
break;
}
else
{
system("cls");
cout << "Username and password entered does not match! Please try again.";
}
getch();
}
getch();
}
Now, here's the problem: Recently, I found out that this method of input (for the password) doesn't work as intended with Backspace, Delete, or the arrow keys. All of these keys input certain symbols instead of deleting characters or moving the cursor. So I tried out a workaround (currently only) for the backspace key. All worked fine- the previous character was deleted when I pressed backspace, but in the end, after the comparison with the preset values, it showed that the password doesn't match.
If you could please help me in the following:
*Working backspace functionality (and delete and arrow keys if possible)
*Pressing Esc at ANY point of the program quits it.
*I have used goto in this program, whose atrocities we all already know of. Please suggest me a way to avoid this, and also to make all this code neater than its current messy state.
Use continue instead of goto. In your case this will do the same: jump to the start of the loop.
Then run a debugger and watch what happens with your array if you input backspaces.
Related
I want to take 8 char password from user and then when she/he wanted to enter, I wanted it to be whatever size she/he enter. However, the code doesn't stop until it reaches 8 char, even I press 'enter', it takes it as a char and create '*'. I want its size to be whatever user write and then user press 'enter', it will take these characters as password to see if it is matched with registered password. For example;
User register password as 'wellcode'
After that, user write in login screen 'well' then enter(in my code it lasts until I reach 8 characte
'Login failed! will be written
Is there a way to do that in C++?
bool CheckCredentials(string);
char pass[8], inPass[8];
int main()
{
fstream encrypted;
bool done = false;
while (!done)
{
cout << "1. Register a password" << endl;
cout << "2. Login your password" << endl;
cout << "3. Exit" << endl;
int menuChoice;
cin >> menuChoice;
if (menuChoice == 1)
{
ifstream ifile;
ifile.open("password.txt");
if (ifile){}
else
{
cout << "New password must contain only 8 characters: ";
for (int i = 0; i < 8; i++)
{
pass[i] = _getch(); _putch('*');
}
ofstream l("password.txt", ios::out);
if (!l.is_open()) {
cout << "could not open file \n";
}
for (int i = 0; i < 8; i++)
{
l << pass[i];
}
l.close();
cout << "\n\n";
}
}
else if (menuChoice == 2)
{
cout << "Password: ";
for (int i = 0; i < 8; i++)
{
inPass[i] = _getch(); _putch('*');
}
if (CheckCredentials(inPass) == true)
{
cout << "\nLogin sucessful!" << "\n\n";
}
else
{
cout << "\nLogin failed!"
}
}
else if (menuChoice == 3)
{
done = true;
break;
}
}
return 0;
}
bool CheckCredentials(string inPass)
{
string s;
bool status = false;
ifstream f;
f.open("password.txt");
if (!f.is_open())
{
cout << "Unable to open file!\n";
}
else if (f)
{
while (!f.eof())
{
f >> s;
if (inPass == s)
{
status = true;
}
else
{
status = false;
}
}
}
f.close();
return status;
}
Your code is
for (int i = 0; i < 8; i++)
{
inPass[i] = _getch();
_putch('*');
}
Obviously that loops exactly eight times, doesn't matter what you type.
If you want to stop the loop early then you must write the code to test for that possibility. Something like
int inPassLength = 0;
for (int i = 0; i < 8; i++)
{
char ch = _getch();
if (ch == '\n') // quit loop if enter is pressed
break;
inPass[inPassLength++] = ch;
putch('*');
}
You also need to add a variable to record how long the password is (since it may not be exactly 8 characters any more) that's what inPassLength is in the code above.
Your loop for (int i = 0; i < 8; i++) runs exactly eight times so you read exactly eight characters.
Instead you need to discover the user completing the password by pressing enter key and break the loop in that case. Additionally you need to consider the real number of characters the user entered, not again iterate exactly eight times to output the characters.
Then you haven't considered at all the user deleting input again! It would be pretty unhandy to see additional asterisks appear on pressing backspace key!
To cover all this I recommend using std::string instead and iterate endlessly, such as follows:
std::string pw;
for(;;)
{
char c = getch();
if(c == '\n')
{
break;
}
if(c == '\b')
{
putch('\b'); // remove character from screen
pw.resize(pw.length() - 1); // remove character from storage
}
else
{
putch('*');
pw += c;
}
}
if(pw.length() > 8)
{
// too long!
}
else
{
std::ofstream l /*...*/;
l << pw; // just output the entire string at once...
}
Note: This is entirely untested code! If you find a bug, please fix yourself.
Note, too, that this answer does not cover every potential user behaviour (pressing backspace is just the most prominent one), e.g. pressing the arrow keys to move the cursor, del button (even at input end), ... To cover some of these you might fall back to even more low level API (GetKeyState and similar).
I'm looking for a method to limit the visible user input using std::cin.
#include <iostream>
int main()
{
std::cout << "Enter your planet:\n";
string planet;
std::cin >> planet; // During the prompt, only "accept" x characters
}
What the user sees if they enter earth or any other word exceeding 4 characters before pressing enter:
Enter your planet:
eart
This is assuming the character limit is 4, note that the 'h' is missing. The console does not display any other character once it has exceeded the character limit. and this is before you press the enter key.
Kinda like typing in an input box like password fields, but it only allows 5 characters, so typing any other character goes unnoticed
A better analogy would be the maxlength attribute for text input in HTML.
That can't be achieved portably, because OS consoles aren't part of C++ standard. In windows, you could use <windows.h> header - it provides console handles etc., but since you didn't specify OS you are using, the is no point in posting windows-only code here (since it might not meet your needs).
EDIT:
Here is (not perfect) code that will limit visible input of the user:
#include <iostream>
#include <windows.h>
#include <conio.h>
int main()
{
COORD last_pos;
CONSOLE_SCREEN_BUFFER_INFO info;
std::string input;
int keystroke;
int max_input = 10;
int input_len = 0;
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
std::cout << "Input (max 10) characters, press ENTER to prompt:" << std::endl;
GetConsoleScreenBufferInfo(handle, &info);
last_pos = info.dwCursorPosition;
while(true)
{
if(kbhit())
{
keystroke = _getch();
//declare what characters you allow in input (here: a-z, A-Z, 0-9, space)
if(std::isalnum(keystroke) || keystroke == ' ')
{
if(input_len + 1 > max_input)
continue;
++input_len;
std::cout << char(keystroke);
input += char(keystroke);
GetConsoleScreenBufferInfo(handle, &info);
last_pos = info.dwCursorPosition;
}
else if(keystroke == 8) //backspace
{
if(input_len - 1 >= 0)
{
--input_len;
input.pop_back();
COORD back_pos {short(last_pos.X-1), last_pos.Y};
SetConsoleCursorPosition(handle, back_pos);
std::cout << ' ';
SetConsoleCursorPosition(handle, back_pos);
GetConsoleScreenBufferInfo(handle, &info);
last_pos = info.dwCursorPosition;
}
}
else if(keystroke == 13) //enter
{
std::cout << std::endl;
break;
}
}
}
std::cout << "You entered: " << std::endl
<< input << std::endl;
}
After a few days of experimenting, I found another solution that seems to be quite easy to grasp as it is somewhat beginner level and without requiring any knowledge of windows programming.
NOTE:
The conio.h library function _getch() could easily be replaced with the getchar() function;
I'm not saying the previous answer was not okay, but this solution is sort of aimed towards beginners with only basic knowledge of c++
char ch;
string temp;
ch = _getch();
while(ch != 13)// Character representing enter
{
if(ch == '\b'){ //check for backspace character
if(temp.size() > 0) // check if string can still be reduced with pop_back() to avoid errors
{
cout << "\b \b"; //
temp.pop_back(); // remove last character
}
}
else if((temp.size() > 0) || !isalpha(ch))// checks for limit, in this case limit is one
{ //character and also optional checks if it is an alphabet
cout << '\a'; // for a really annoying sound that tells you know this is wrong
}else {
temp.push_back(ch); // pushing ch into temp
cout << ch; // display entered character on screen
}
ch = _getch();
}
This could probably use some tweaks, because it's definitely not perfect, but I think it is easy enough to understand, at least I hope so
I'm currently working on a program and thinking if it is possible to implement another restrictions for the user input. The restrictions that I made as of now is that the user is only allow to input alpha and spaces, hitting enter without any input will not be also accepted.
cout<<"Input customer's lastname\t\t: ";
getline(cin,lname);
if(lname.find_first_not_of("abcdefghijklmnopqrstuvwxyz ")!=string::npos)
{
cout<<"You can only input alpha here!\n";
cin.clear();
goto p1;
}
else if(lname.empty())
{
cout<<"Please enter your lastname!\n";
cin.clear();
goto p1;
}
The another restrictions that I want is if the user input is all spaces, the program will also show a message. Second, I wonder if it's possible to detect the input if the user typed it properly like (de la Cruz) the words should be only separated by one space and if not another message will show. I cant think on how to do it, I already did some research but I couldn't found any similar to this with C++. I don't know if this is possible since I'm just starting to learn C++, or maybe I don't have enough logic at all. :(
A little help from me on checking for spaces.
bool has_only_spaces(const std::string& str)
{
return str.find_first_not_of (' ') == str.npos;
}
bool has_two_consecutive_spaces(const std::string& str)
{
for (unsigned int i = 1; i < str.length(); i++)
{
if ((str[i - 1] == str[i]) && (str[i] == ' '))
{
return true;
}
}
return false;
}
int main()
{
std::string lname;
std::cout << "Input customer's last name: ";
getline(std::cin, lname);
if (has_only_spaces(lname) || has_two_consecutive_spaces(lname))
{
std::cout << "Not a valid input" << std::endl;
std::cin.clear();
}
}
Create a function to check whether the input is valid. Use the function in a while loop.
bools isInputValid(std::string const& input)
{
// add all the checks
}
Use it as:
std::cout << "Enter input\n";
while ( getline(std::cout, line) )
{
if ( isInputValid(line) )
{
break;
}
std::cout << "Input is not vaild. Try again\n";
}
How can I get my code to detect me hitting the enter key? I tried using cin.get() without any success. Also when the enter key is pressed, I'd like to change a boolean x from true to false.
Why doesn't this work?
if (cin.get() == '\n'){
x = false;
}
I'd like to end my loop (and thus and the program) when the enter key is pressed (see code below)
All code (simple rock, paper, scissors game):
#include <iostream>
#include <string>
#include <cstdlib> //random
#include <time.h> //pc time
using namespace std;
int main()
{
string rpsYou;
string rpsCom;
string winner;
bool status = true;
while (status){
cout << "Welcome to Rock, Scissors, Paper!\nYou'll have to compete against the computer."
" Please enter 'Rock', 'Paper' or 'Scissors' here: ";
cin >> rpsYou;
//Random number
srand (time(NULL));
int randomNum = rand() % 4; // -> (rand()%(max-min))+min;
//Computers guess
if (randomNum ==1){
rpsCom = "Rock";
}
else if (randomNum ==2){
rpsCom = "Paper";
}
else {
rpsCom = "Scissors";
}
//First letter to capital
rpsYou[0] = toupper(rpsYou[0]);
if (rpsYou == "Rock" || rpsYou == "Paper" || rpsYou == "Scissors"){
cout << "You: " << rpsYou << "\nComputer: " << rpsCom << "\n";
}
else {
cout << "ERROR: Please enter 'Rock', 'Paper' or 'Scissors'.";
}
if ( (rpsYou == "Rock" && rpsCom == "Rock") ||
(rpsYou == "Paper" && rpsCom == "Paper") ||
(rpsYou == "Scissors" && rpsCom == "Scissors") ){
cout << "Tie :|";
}
else if( (rpsYou =="Rock" && rpsCom =="Scissors") ||
(rpsYou =="Paper" && rpsCom =="Rock") ||
(rpsYou =="Scissors" && rpsCom =="Paper")){
cout << "Congratulations! You won! :)";
}
else{
cout << "Oh no! You lost! :(";
}
}
return 0;
}
You could do:
cout << "Hit enter to stop: ";
getline(cin, rpsYou);
if (input == "") {
status=false;
}
This is assuming there's nothing in the user input, (i.e: the user just simply presses enter)
You can't detect what key was pressed in standard C++. It's platform dependent. Here is a similar question that might help you.
Sounds like you are thinking of getting key presses "in real time", like might be useful in a game for example. But cin does not work like that. There is no way to "detect when user presses enter" in standard C++! So you can not end the program when user presses enter. What you can do is end the program when user enters empty line, or when user enters for example "quit" (or whatever, up to you), but every user input must end in them pressing enter.
Reading from cin is just like reading from a text file, except this text file gets a new line every time user presses enter. So closest thing to detecting user pressing enter is using std::getline:
std::string line
std::getline(std::cin, line);
This will get all characters from stdin until a newline (or until end of file), which usually means user pressed enter, when this is used in a console application. Note that the actual end-of-line will not be stored in the string, so if user just pressed enter without typing anything else, line will be empty string.
Looking at question after edit, you could replace cin >> rpsYou; with getline(cin, rpsYou);. You might then also want to add trimming the string you read, in case user for example typed extra spaces.
I am trying to read a pasword and while I read it , display ** .
cout << "\n Insert password : ";
loop1:
string passw1 = "";
char ch = _getch();
while (ch != 13) // enter = char 13
{
if (!isalnum(ch))
{
cout << "\n\n Invalid character! Please insert the password again! ";
goto loop1;
}
passw1.push_back(ch);
cout << "*";
ch = _getch();
}
If I press for example , BACKSPACE , or SPACE or something that is not alpha-numerical , everything goes as planned. The problem is when I press any F key , or DELETE , HOME , INSERT , END , PG UP , PG DOWN , when the program crashes . Could you help me avoid the crash ? I would like to show an error message if an invalid key is pressed , not to have my program crash.
Let's see if I understand what you're trying to do (in pseudocode):
Prompt the user for a password
Wait for the user to press any key
While the key pressed is not the enter key
If the entered key is an alphanumeric
Add the character to the password string
Print an asterisk on the screen
Accept another character
Else
Alert the user that they entered a non-alphanumeric
Clear out the string and have the user start over again
End If
End While
If that's not what you're after, then modify to taste.
What I think is happening is that you're not capturing all of the possible characters when you test what key was pressed. If DEL is giving you trouble, then figure out how to catch it or handle it (remove an asterisk from the screen, and delete a character from the string).
Good luck!
It crashes on my Win7 x64 VS2010 system as well. Turns out _gech() is returning 224 for the DEL key, which is -32 in a signed char. This is causing isalnum() to assert internally.
I changed the char to an int (which is what _getch() is returning and isalnum() takes for a parameter) and the overflow problem went away. unsigned char works as well.
int main( )
{
cout << "\n Insert password : ";
loop1:
string passw1 = "";
int ch = _getch();
while (ch != 13) // enter = char 13
{
if (!isalnum(ch))
{
cout << "\n\n Invalid character! Please insert the password again! ";
goto loop1;
}
passw1.push_back(ch);
cout << "*";
ch = _getch();
}
return 0;
}
Yields (pressing DEL each time):
Insert password :
Invalid character! Please insert the password again! *
Invalid character! Please insert the password again! *
Use the is alphanumeric function - isalnum(char c ) to check if the parameter c is either a decimal digit
or an uppercase or a lowercase letter.
And then filter out characters less than 32 or higher than 122 like this : if (c > 32 && c <122) { Get_Password(); }
This MS Windows specific code below is not portable. For Linux/*NIX/BSD see this : Hide password input on terminal
#include <iostream>
#include <string>
#include <conio.h>
int main()
{
std::string password;
char ch;
const char ENTER = 13;
std::cout << "enter the password: ";
while((ch = _getch()) != ENTER)
{
if (ch > 32 && ch<122)
{
if (isalnum(ch))
{
password += ch;
std::cout << '*';
}
}
}
std::cout <<"\nYour password is : " << password<<"\n\n";
return 0;
}