1

I'm using a piece of code from cplusplus, and i can't get it why this code just skips the input part for password and just jumps right to the input for EMAIL.

//function to mask the input for password
    string getpass(const char *prompt, bool show_asterisk=true)
    {
      const char BACKSPACE=127;
      const char RETURN=10;

      string password;
      unsigned char ch=0;

      //cout <<prompt<<endl;

      while((ch=getch())!=RETURN)
        {
           if(ch==BACKSPACE)
             {
                if(password.length()!=0)
                  {
                     if(show_asterisk)
                     cout <<"\b \b";
                     password.resize(password.length()-1);
                  }
             }
           else
             {
                 password+=ch;
                 if(show_asterisk)
                     cout <<'*';
             }
        }
      cout <<endl;
      return password;
    }  

And here I'm calling this function:

void AgendaUI::userRegister(void)
  {
    string name, password, email, phone;
    //cout << "\n[register] [username] [password] [email] [phone]" << endl;
    cout << "\n[regist]";
    cout << "\n[username] ";
    cin >> name;
    cout << "[password] ";
    password = getpass("Enter the password",true);
    cout << "\n[email] ";
    cin >> email;
    cout << "[phone] ";
    cin >> phone;
}  

Terminal

casper
  • 35
  • 9

2 Answers2

3

Because when your user entered the username, they also entered the Enter character (that's how their terminal knew to submit the line). This character was not read by cin >> name and is still there in the buffer. Then, getpass reads it as the first character, and immediately stops.

Notice how your code is not the same as the article's code, which does not ask for a username, and shows a getpass that is rather fragile (e.g. it breaks when simply adding the basic code that you added, and seems to rely on the termios hacks that you quietly removed). In general try not to learn C++ from articles on websites. Learn it from a good book instead!

You can fix this by adding cin.ignore(256, '\n') after cin >> name, though frankly that's a bit of a hack and it would arguably be better to extract the username using std::getline instead.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • tl;dr you can't just take a function from a larger program and put it in another program, stripping away bits and adding other bits, without understanding what they do, and expect it to work the same. – Lightness Races in Orbit Nov 30 '18 at 16:38
0

i can't get it why this code just skips the input part for password

The reason is mentioned by @Lightness in his answer on what is the cause

To clear the newline that buffered after entering the username you need to clear the input stream.

For c use this fflush(stdin);

For c++ use this std::cout.flush();

OR you can do another thing as i do sometime, i.e., use a getchar(); after taking the username as input. This method is not a standard way of doing it, but it works. Sometimes we need to flush the stream along with getchar();

As by your code sample I am thinking you are trying to mask the password entered by the user.

For that you can disable the echo of the characters as you type.

Of course it will not print any fancy asterisk or any other symbol, instead the input field will be empty as the user keeps typing the password.

The code sample I used from 'here', is given below for both Windows & *nix system:

//Include other headers as well as per your program need
#ifdef WIN32
#include <windows.h>
#else
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#endif

void stdecho(bool enable = true)
{
#ifdef WIN32
    HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); 
    DWORD mode;
    GetConsoleMode(hStdin, &mode);
    if( !enable )
        mode &= ~ENABLE_ECHO_INPUT;
    else
        mode |= ENABLE_ECHO_INPUT;

    SetConsoleMode(hStdin, mode );
#else
    struct termios tty;
    tcgetattr(STDIN_FILENO, &tty);
    if( !enable )
        tty.c_lflag &= ~ECHO;
    else
        tty.c_lflag |= ECHO;
    (void) tcsetattr(STDIN_FILENO, TCSANOW, &tty);
#endif
}

The code usage is here:

cout<<"\nLogin to begin :)";
cout<<"\n\tUsername : ";
cin>>username;

getchar();   // Here I am using `getchar();` to clear the new line remains in the input buffer
             //you can also flush the input stream instead if this does not work or you can combine both

cout<<"\tPassword : ";

stdecho(false);   //From now on I am disabling the echo from `std::cin`

getline(cin, password);  //No character will show up as you type your password

stdecho(true);    //From here the `std::cin` echo will be enabled again i.e., characters will start showing up again

pashash = hash(password); //Ignore from here...
password.erase();

See this 'Reading a password from std::cin' for more details and answers.

Screenshot of how this process looks in console: Image 01 & Image 02