Thread: Input a password and replace with *s

  1. #31
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >1. I have an output (printf) before the password is input, and it only appears after it has been input.
    This is a buffering problem. You need to print a newline or flush the stream (or pray the buffer gets filled up at the right time):
    Code:
    printf ( "Blah blah blah\n" ); /* Flushes automagically */
    
    printf ( "Ask for input: " ); /* Doesn't flush automatically */
    fflush ( stdout ); /* Force a flush */
    >2. The stars are output with the output above, after the whole password is input.
    >3. If the maximum number of characters is input, the program just continues.
    Post your code. These sound like flaws in your logic.
    My best code is written with the delete key.

  2. #32
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Abda92 View Post
    OK. Everything went good except for a few issues:
    1. I have an output (printf) before the password is input, and it only appears after it has been input.
    Code:
    fflush(stdout);
    before the password request.

    2. The stars are output with the output above, after the whole password is input.
    3. If the maximum number of characters is input, the program just continues. I would like it to continue only after enter is input.

    Thanks for the help
    You'll have to show the code for password input for this to be answerable - I presume it is one of the several varieties posted above, but I don't know which version you are currently using.

    I think #2 may be solved by same method as #1 - you need to fflush(stdout) after each star is printed.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #33
    Registered User
    Join Date
    Sep 2006
    Posts
    230
    I'm sorry, I forgot to post my code. Here's the password input function:
    Code:
    void getpassword(char password[], int maxlength)
    {
    	int i;
    	char c;
    
    	printf("Please input password (max. %d characters): ", KEYLENGTH);
    
    	for (i=0; i<maxlength; i++)
    	{
    		if ((c=mygetch()) == '\r') break;
    		password[i] = c;
    		if (c != '\b') putchar('*');
    		else
    		{
    			putchar('\b');
    			i--;
    		}
    	}
    	password[i] = '\0';
    }
    I hope this helps

  4. #34
    Registered User
    Join Date
    Sep 2006
    Posts
    230
    will just increasing the number of characters being input and save only the first "maxlength" characters fix problem #3?

  5. #35
    Registered User
    Join Date
    Sep 2006
    Posts
    230
    Never mind, I fixed all the problems except one: backspace.
    I just made the condition for the loog maxlength+1 to give the user a chance to press enter.
    Code:
    void getpassword(char password[], int maxlength)
    {
    	int i;
    	char c;
    
    	printf("Please input password (max. &#37;d characters): ", KEYLENGTH);
    	fflush(stdout);
    
    	for (i=0; i<maxlength+1; i++)	/* maxlength+1 just to allow the user to press enter. Or else program continues as soon as 12th char is input */
    	{
    		if ((c=mygetch()) == '\r') break;
    		if (i<maxlength) password[i] = c;
    		if (c != '\b') putchar('*');
    		else
    		{
    			putchar('\b');
    			i--;
    		}
    		fflush(stdout);
    	}
    	password[i] = '\0';
    }
    You might be thinking why I put the following if statement:
    Code:
    		if (i<maxlength) password[i] = c;
    For some reason if I don't, it just overflows the array and saves the unwanted characters, even though password has been declared as
    Code:
    char password[maxlength+1];
    Now my problem is the backspace. Even though I output it (just to remove the star) and decrement i it still saves it in the array. What can I do?

  6. #36
    Registered User
    Join Date
    Sep 2006
    Posts
    230
    MAN! Each time I fix a problem, another one comes out of nowhere!
    I fixed the backspace, I just needed to decrement i twice.
    but now when the user inputs more than 12 characters, it keeps on taking characters in, which is not bad. The problem is that the last of these unwanted characters replaces the last of the wanted characters.
    e.g. If the user inputs "abcdefghijklmnop" the password is saved as "abcdefghijkp".

    Now what ?

    EDIT: btw, here's the new code:
    Code:
    void getpassword(char password[], int maxlength)
    {
    	int i;
    	char c;
    
    	printf("Please input password (max. &#37;d characters): ", KEYLENGTH);
    	fflush(stdout);
    
    	for (i=0; i<maxlength+1; i++)	/* maxlength+1 just to allow the user to press enter. If not +1 program continues as soon as 12th char is input */
    	{
    		if ((c=mygetch()) == '\r') break;
    		if (i<maxlength && c != '\b')	/* save character in password */
    		{
    			password[i] = c;
    			putchar('*');
    		}
    		else if (c == '\b')		/* perform backspace */
    		{
    			putchar('\b');
    			i -= 2;
    		}
    		else if (c != '\b')		/* just to let the program continue looping. all extra characters are IGNORED */
    		{
    			putchar('\b');
    			i--;
    		}
    		fflush(stdout);
    	}
    	password[i] = '\0';
    }
    Last edited by Abda92; 10-02-2007 at 03:05 PM.

  7. #37
    Registered User
    Join Date
    Aug 2007
    Location
    MD, USA
    Posts
    71
    Using your last:
    void getpassword(char password[], int maxlength)
    ...and
    char mygetch(void)
    ...from above along with the following main():
    Code:
    #include <stdio.h>
    #include <windows.h>
    #define  KEYLENGTH 15
    
    void PAUSE(void){int c; while( (c=getchar()) != '\n' && c != EOF);}
    void getpassword(char password[], int maxlength);
    char mygetch(void);
    
    int main(void)
    {
      int  maxlength = 15;
      char password[KEYLENGTH + 1]      = {0};
    
      void PAUSE(void){int c; while( (c=getchar()) != '\n' && c != EOF);}
      getpassword(password, maxlength);
      printf("\n\npassword= &#37;s \n", password);
      getchar();
      return 0;
    }
    I get the following:
    Code:
    /* I type letters a thru q: */
    
    Please input password (max. 15 characters): ***************
    password= abcdefghijklmno
    /*******************************************************/
    /* I type digits 1 thru 0 twice (20 characters)
    
    Please input password (max. 15 characters): ***************
    password= 123456789012345
    The cursor moves back after 15 chars, but nothing is erased.
    (why are you doing that anyhow....)
    Also, in getpassword() :
    'i' may never reach maxlength because of all the decrementing.

    I get same behavior with or without fflush(stdout):
    program overruns the getchar() at end of main because of (stdin) leftovers.
    Try that PAUSE() function up there instead of fflush() at end of your getpassword():
    Code:
    ...snip...
            /* fflush(stdout); */
        }
        password[i] = '\0';
        PAUSE();
    }                    /* end of getpassword() */
    So... What's the problem?
    I am on a '98 msdos console. Perhaps XP or Vista consoles behave differently.
    Last edited by HowardL; 10-02-2007 at 11:16 PM.

  8. #38
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    If you want to do a "proper" backspace, you should probably do
    Code:
    puts("\b \b");

    Also, don't use a for-loop for the password entry, use a while-loop.

    Only increment the chars when accepted, and if backspace is entered, remove one letter (if there's anything already entered), by printing a backspace and decrementing the length of the string.

    When you see an enter, it's finished.

    I'm pretty sure the fflush is needed at each iteration of the loop, so don't listen to HowardL on that one.



    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #39
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Code:
    puts("\b \b");
    Actually, since puts() prints a newline at the end, perhaps this would be more appropriate:
    Code:
    printf("\b \b");
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  10. #40
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by dwks View Post
    Code:
    puts("\b \b");
    Actually, since puts() prints a newline at the end, perhaps this would be more appropriate:
    Code:
    printf("\b \b");
    Yeah, ok, if you insist :-)

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #41
    Registered User
    Join Date
    Aug 2007
    Location
    MD, USA
    Posts
    71
    re:' \b's
    Oh , I see. You are giving the user the ability to correct input... and it works. Nifty. Sorry, I did not get that before...

    I'm pretty sure the fflush is needed at each iteration of the loop, so don't listen to HowardL on that one.
    I still notice no difference with or without fflush(stdout)'s.
    I don't understand, could you explain:
    what might be left unprinted in stdout and why it would be there?

    I was suggesting PAUSE(); to unload stdin which still contains at least one character as it leaves getpassword() (...at least the last one posted above does).
    It might be the' \n' after '\r' from the '\r\n' produced when pressing ENTER to end input.
    Does the XP console behave differently in these respects than my 98 console?
    Thanks, Howard;
    Last edited by HowardL; 10-03-2007 at 11:28 PM.

  12. #42
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by HowardL View Post
    re:' \b's
    Oh , I see. You are giving the user the ability to correct input... and it works. Nifty. Sorry, I did not get that before...


    I still notice no difference with or without fflush(stdout)'s.
    I don't understand, could you explain:
    what might be left unprinted in stdout and why it would be there?
    It is common for implementations of file-io (stdio.h) to not flush every single write immediately, but to buffer up several operations together. It depends on which compiler (and related library functions you use). fflush(stdout) won't hurt and it makes it safe - this isn't a performance critical section of the code anwyays, right?
    I was suggesting PAUSE(); to unload stdin which still contains at least one character as it leaves getpassword() (...at least the last one posted above does).
    It might be the' \n' after '\r' from the '\r\n' produced when pressing ENTER to end input.
    Does the XP console behave differently in these respects than my 98 console?
    Thanks, Howard;
    Well, yes, clearing the input buffer if the password was too long for the valid input is a good idea, indeed. But it's not a replacement for fflush().

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #43
    Registered User
    Join Date
    Sep 2006
    Posts
    230
    OK everything works fine now. I had to add a validation that the character is a printing one since mygetch() takes in none-printing ones too. Here's the new function if anyone wants it:
    Code:
    void getpassword(char password[], int maxlength)
    {
    	int i=0;
    	char c;
    
    	printf("Please input password (max. &#37;d characters): ", KEYLENGTH);
    	fflush(stdout);
    
    	while (i <= maxlength)	/* just to allow the user to press enter or enter extra IGNORED characters. If not +1 program continues as soon as 12th char is input */
    	{
    		if ((c=mygetch()) == '\r') break;
    		if (i<maxlength && c != '\b' && (c >= 0x21 && c <= 0x7e))	/* save character in password as long as it's not a none-printing character */
    		{
    			password[i++] = c;
    			putchar('*');
    		}
    		else if (c == '\b' && i > 0)		/* perform backspace only if characters have already been input */
    		{
    			printf("\b \b");
    			i--;
    		}
    		fflush(stdout);
    	}
    	password[i] = '\0';
    }
    Thanks again for all the help. I hope someone else benefits from this code too.

  14. #44
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    I would use a switch instead of several if-statements, something like this:
    Code:
       int done = 0;
    ... 
       while(!done) {
          c=mygetch();
          switch(c) {
             case '\r':
             case '\n':   // Just in case. 
                done = 1;
                break;
             case '\b':
                if (i > 0)  {
                    .. 
                }
                break;
             default:
                 if (isprint(c) && i < maxlength) {
                    ... 
                 }
                 break;
    ...
    Note that the above code is designed to ALWAYS exit when the user presses enter, rather than leaving some "leftovers" in the input buffer, no matter how much input is given - it is just ignored. So if someone types in
    SomeReallyVeyLongPasswordThatDoesntFit
    you won't have some parts of it still sitting in the input buffer.

    Also, this comment doesn't make sense (in relation to the code):
    Code:
    /* just to allow the user to press enter or enter extra IGNORED characters. If not +1 program continues as soon as 12th char is input */
    I use "isprint()" to see if something is a valid character, rather than checking ascii values. It is better out of two perspectives:
    1. it allows any printable character, which is probably what you want - even if they aren't in the original ascii table, such as ä, å etc. No reason NOT to allow those.
    2. It is much more straight forward a check than the two numeric values you use, and doesn't need any explanation to anyone else reading the code that may not be quite so clued up on ascii characters.
    3. [For the benefit of the pedants that like pointing these things out] it works for other character sets than ASCII.

    If you explicitly don't want spaces in the password, you may want to add "!iswhite(c)" on to the conditions for adding characters to the string. I personally would prefer to just allow spaces, here, and if spaces are a nuisance (or some other way not valid as part of a password), make sure that spaces aren't allowed when you SET the password - it improves the security somewhat to not give away which characters are valid and invalid when you enter the password.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  15. #45
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Quote Originally Posted by matsp View Post
    I use "isprint()" to see if something is a valid character, rather than checking ascii values. It is better out of two perspectives:
    1. it allows any printable character, which is probably what you want - even if they aren't in the original ascii table, such as ä, å etc. No reason NOT to allow those.
    2. It is much more straight forward a check than the two numeric values you use, and doesn't need any explanation to anyone else reading the code that may not be quite so clued up on ascii characters.
    3. [For the benefit of the pedants that like pointing these things out] it works for other character sets than ASCII.
    You should also add:
    4. The code has already been written and thoroughly tested, so you know it works. There's no point in reinventing the wheel. Unlike code that you write, the standard functions are virtually guaranteed not to have bugs.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Password replace with * on entry
    By gasie@medemass. in forum C++ Programming
    Replies: 4
    Last Post: 11-13-2008, 02:33 PM
  2. Encryption program
    By zeiffelz in forum C Programming
    Replies: 1
    Last Post: 06-15-2005, 03:39 AM
  3. Replies: 1
    Last Post: 04-24-2005, 03:45 AM