i'm writing a code to receive password input. Below is my code... the program run well but the problem is other keys beside than numerical and alphabet characters also being read, for example delete, insert, and etc. can i know how can i avoid it? tq...
string pw="";
char c=' ';
while(c != 13) //Loop until 'Enter' is pressed
{
c = _getch();
if(c==13)
break;
if(c==8)
{
if(pw.size()!=0) //delete only if there is input
{
cout<<"\b \b";
pw.erase(pw.size()-1);
}
}
if((c>47&&c<58)||(c>64&&c<91)||(c>96&&c<123)) //ASCii code for integer and alphabet
{
pw += c;
cout << "*";
}
}
Filter using isalnum() for alpha-numeric or isalpha() for only alphabets.
Also, you are checking c == 13 twice, following will suffice.
while(1){
//
if(c == 13)
break;
//
}
if( isalnum(c) ){
// 'c' is acceptable
}
Some assertion is failing during execution which throws that error.
If you have access to it, you are much better off using the GNU getpass function.
Related
I'm writing a program to read a piece of text and put it in the correct grammar. All punctuation marks and newlines in the text are preceded by a ':'. One of the functions of my program is adding spaces between words that are read from the text file. However, I don't want it to do that all the time. Since ':.' marking the end of a sentence is a new word and not part of the previous word, it'll add a space between the last word and the period.
"... at the zoo ."
Instead of this:
"... at the zoo."
I'm trying to write a function that looks at the next word in the array to see if it's a colon.
Here's what I tried, among other things:
int isColon(char madLib[][256], int numWords)
{
numWords++;
char* k = madLib[numWords];
if (*k == ':')
{
cout << "{*k}";
return true;
}
else
return false;
}
Here is the output: {╠}
Without incrementing the counter (numWords), it displays the first letter without any problem.
However, I need it to look to the next word.
What do I do? Any suggestions?
Here is the code that actually displays the text:
int readFile(const char fileName[])
{
ifstream fin(fileName);
//if error when opening file, it will return true
if (fin.fail())
{
return true;
}
char madLib[256][256];
int numWords = 0;
while (fin >> madLib[numWords])
{
bool isSpace = true;
bool noPrint = false;
char* k = madLib[numWords];
while (*k)
{
if (*k == ':')
{
k++;
if (*k == '!')
cout << endl,
isSpace = false;
else if (*k == '.')
cout << ".";
else if (*k == ',')
cout << ", ";
else if (*k == '<')
cout << "\"",
isSpace = false;
else if (*k == '>')
cout << "\" ";
else
displayArray(madLib, numWords),
noPrint = true;
}
else
{
if (noPrint == false)
cout << *k;
}
k++;
}
if (isSpace == true && isColon(madLib, numWords) == false)
cout << " ";
noPrint = false;
numWords++;
}
fin.close();
return 0;
}
In my humble opinion, the main problem is that you are still working in complete C-Style mode. With all errors that result out of that.
You are using pointers and C-Style arrays. Recommendation: Do not and never use raw pointers for owned memory in C++.
Recommendation: Do not use C-style arrays in C++ (or only, if you know what your are doing).
Btw: You are using the wrong syntax for passing an 2d-array (which you should not use in the first place) to your functions. The array is decaying to a pointer.
You have huge risks for out of bounds problems using your magic numbers 256.
But your specific problem is resulting from a wrong design. You read a word, and then, before you have read the next word, you already check this none existing word.
Look at your code. You are doing fin >> something, then operate on this something, then you are calling your subfunction to check the next word. But this has not yet been read.
So, the recommendation is: At first read all words into your array, and then, afterwards, check your array content.
I hope this helps
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
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.
I'm currently making a login form for my project, but I can't move on on this one. I want my program to delete a character(in password) when I'm pressing the backspace button, but the program is not reading it.
Here's my code
string username, password, power;
char ast=' ';
int aste = 0, accessLevel;
ofstream addAcc;
addAcc.open("Accounts.txt");
cout<<"Username: ";cin.ignore();getline(cin, username);
cout<<"Password: ";
do
{
ast = getch();
if (ast == 13 || ast == ' ' )
{
break;
}
if(ast==8 || password!="")
{
cout<<"\b \b";
password.erase(password.size()-1);
}
cout<<"*";
password+=ast;
aste ++;
}while(ast!=13 || ast!=' ');
do
{
cout<<"Enter Access Level(0-1): ";cin>>accessLevel;
switch(accessLevel)
{
case 0:
{
power = "Cashier";
break;
}
case 1:
{
power = "Manager";
break;
}
default:
cout<<"Invalid access level."<<endl;
}
}while(accessLevel>1||accessLevel<0);
Thank you for those who will help.
On some platforms getch() will return the DEL character (ascii 127) when you hit BACKSPACE. So change your line
if(ast==8 || password!="")
to
if((ast==8 || ast==127) && !password.empty())
You probably don't want to erase a character everytime that password is not an empty string either, so I removed || password!="" from the condition too. Instead you want to erase one character only if the password is not empty. So you need an && instead of an ||.
Also note, that you're adding the character returned by getch() unconditionally. So if the user enters BACKSPACE, you erase the last character, but append BACKSPACE to the password. So you should only append the character returned by getch() if it was not a BACKSPACE (or DEL).
Thus your code might look like this:
if((ast==8 || ast==127) && !password.empty())
{
cout<<"\b \b";
password.erase(password.size()-1);
aste--;
}
else
{
password+=ast;
cout<<"*";
aste++;
}
do
{
c = _getch();
if (c == 13 || c == ' ') // checking ascii key 13 pressed or no
{
break;
}
if (c == 8 || c == 127)
{
if (Password.size() != 0){
cout << "\b \b";
Password.erase(Password.size() - 1);
StarNum--;
}
}
else {
Password += c;
cout << "*";
StarNum++;
}
} while (c != 13 || c != ' ');
Use
#include <conio.h>
and
ch = _getch();
instead ch = getch();
and also change the condition like this
if(ch == 8)
{
password.erase(password.size()-1);
aste--;
}else
{
password +=ch;
aste++;
}
My issue is I am trying my first attempt at writing a very basic lexical analyzer for ascii text files. so far, it reads and compares to my token list properly, however I am unable to grab the final token without a space or pressing enter. I've tried using the delimiter ^Z ASCII 26 as another selection before comparing the string to my token list. This failed to work. I've also tried moving the f->eof() check to below the comparison location to see if it will snag it then check the eof flag. I've had no luck. could anyone possibly enlighten me? The code is below for the read method. m_TokenList is just a vector of type string.
void CelestialAnalyzer::ReadInTokens(ifstream *f){
vector<string> statement;
vector<string> tokens;
string token;
char c;
do{
f->get(c); // Read in each character
if(f->eof())
break;
if(c == '\n' || c == ' ' || c == '^Z' || c == '\r'){ // 26 ASCII ^Z (end of file marker)
for(unsigned int i=0; i<m_TokenList.size(); i++){
if(!token.compare(m_TokenList[i])){
tokens.push_back(token);
token.clear();
}
}
} else {
token.push_back(c); // Add it to the token array
}
} while (true);
f->close();
for(unsigned int i=0; i<tokens.size(); i++){
cout << "Found Token: " << tokens[i].c_str() << endl;
}
}
The m_TokenList is initialized as
CelestialAnalyzer::CelestialAnalyzer(){
m_TokenList.push_back("KEY"); // Prints data
m_TokenList.push_back("GETINPUT"); // Grabs user data
m_TokenList.push_back("+"); // Addition/Concation
m_TokenList.push_back("-"); // Subtraction
m_TokenList.push_back("=="); // Equator
m_TokenList.push_back("="); // Assignment
m_TokenList.push_back(";"); // End statement
m_TokenList.push_back(" "); // Blank
m_TokenList.push_back("{"); // Open Grouping
m_TokenList.push_back("}"); // Close Grouping
m_TokenList.push_back("("); // Parameter opening
m_TokenList.push_back(")"); // Parameter closing
for(unsigned int i=48; i<=57; i++){
string s; s.push_back((char)i);
m_TokenList.push_back(s); s.clear();
}
}
A test file for reading is this simple example.
1 + 2 = KEY
It will register all but 'KEY' unless there is a space or a newline after it.
Why don't you just delete:
if(f->eof())
break;
and use
if(f->eof() || c == '\n' || c == ' ' || c == '^Z' || c == '\r'){
then break afterwards? That way, when you hit EOF, you will add whatever remaining token you have.
Alternately, you could just check if the token is nonempty after you break out of the loop, and add it in that case.
What about double 'new line'? As I know, in several messenger protocol regard \r\n\r\n with the end of the message. I think it's pretty reasonable. :)