1
while ((eat = getchar()) != '\n' && eat != EOF); // where 'eat' is long long eat

This is the line I'm using.

The issue, you ask ? Aha ! I have to press [ENTER] twice, to actually 'send' the input to my program. (I want this to be in a function that works after both scanf and fgets )

This seems reminiscent of using a getchar() alone, but I'm a newbie and I would just solve those by removing the getchar() , which of course cannot be done here.

I'm quite confused what to do and if it is possible to implement a simple solution that doesn't force the user to press the [ENTER] key twice.

A bigger, better code snippet :

int num,q=0; static int pins[8]; char pswd[9]; char bad =1,Y_N;    
while(bad == 1) {
        printf("\nEnter (8 char) Password : ");
        getchar();
        fgets(pswd,sizeof(pswd),stdin); 
        int len = strlen(pswd); 
        if(pswd[len-1] == '\n'){
            pswd[len-1] = '\0'; 
            len--;
        }
        if(len < 8)
            printf("\nPassword less than 8 characters.\nPlease Retry.\n");
    
        else
            bad = 0;
    }
    while ((eat = getchar()) != '\n' && eat != EOF);

EDIT :

I made a stupid mistake, and this error is not being caused by the loop itself but because of the code where the function (that this code is part of) gets called. An extra getchar() in that place has caused this error. It is solved by removing that extra getchar(). Thanks to all those who helped me troubleshoot this, I apologise to you all.

user13863346
  • 327
  • 2
  • 11

2 Answers2

2

The code can be simplified by using fgets(,,stdin); and a simple while(){...} construct

int main(int argc, char *argv[])
{ 
    int bad = 1;
    char pswd[20]={0};//2x strlen of proper password + \n + NULL
    
    while(bad == 1) 
    {
         //prompt user
         printf("Enter password (8 characters) : " );
         //read user input value
         fgets(pswd, sizeof(pswd), stdin);
         //remove newline from user input
         pswd[strcspn(pswd, "\n")] = 0;
         //(replaces the need for the while loop at bottom of original post.)

         if(strlen(pswd) == 8)//test input for length
         {
              bad = 0;//exit loop if pswd good
         }
    }
    return 0;
}

You can add some try again code to handle an incorrect password

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • 1
    ryyker, removing that `getchar()` results in it skipping taking input altogether. – user13863346 Aug 10 '20 at 16:45
  • @user13863346 - I'll take another look, and re-post – ryyker Aug 10 '20 at 16:46
  • ryyker , what am I to do with simplified code that still won't work as it should ? – user13863346 Aug 10 '20 at 16:58
  • @user13863346 - what are you seeing exactly? – ryyker Aug 10 '20 at 17:01
  • I'm seeing that it doesn't 'take' input with one single press of 'Enter' . It needs two such enters to pass to the next statement, and this has happened ever since I added the while(); – user13863346 Aug 10 '20 at 17:03
  • Run the simple example above. It works for me, and it should work for you. It simply illustrates the construct. If it works for you, add just one thing at a time to see where it breaks, or to confirm the additions work. – ryyker Aug 10 '20 at 17:06
  • 1
    ryyker you are right, the loop is probably not the issue, I used this is another old program of mine and its running fine even with scanf – user13863346 Aug 10 '20 at 17:09
  • 1
    `pswd[9]` too small for "(8 char) Password" and `'\n'`, `'\0'`. – chux - Reinstate Monica Aug 10 '20 at 17:15
  • 1
    Aside: I'd use at least a 2x buffer to help eat longer, bad, passwords to provide an empty `stdin` on the next try. Yet if user is entering really long PWs, I'd exit. – chux - Reinstate Monica Aug 10 '20 at 17:21
  • @chux-ReinstateMonica - The extra length part is done. I'll look at the length test as well. – ryyker Aug 10 '20 at 17:28
  • Unclear about `memset()` usage here, but watch out for [optimizations](https://stackoverflow.com/a/28463886/2410359). – chux - Reinstate Monica Aug 10 '20 at 17:38
  • Ryyker and @chux-ReinstateMonica I'm terribly sorry to worry you. This is a silly mistake on my part, and the question has been edit to reflect that. I had overlooked some other code with a `getchar()` that followed this, causing the double-enter-issue. Thank you all, and sorry. – user13863346 Aug 11 '20 at 05:11
  • BTW, the `pswd[strcspn(pswd, "\n")] = 0;` doesn't actually replace the while loop. The while loop takes care of clearing the buffer in stdin in case of anomalously long password. If user tries a password longer than 19 chars(unlikely, but not very impossible), you will have the same issue - the next line of input will get the extra portion as input from stdin. – user13863346 Aug 11 '20 at 05:26
  • @user13863346 Your code is using `if(pswd[len-1] == '\n'){`, which is UB when the first character entered in a null character. This answer's good use of `pswd[strcspn(pswd, "\n")] = 0; ` does not have that problem. Your choice. – chux - Reinstate Monica Aug 11 '20 at 06:39
  • @chux-ReinstateMonica No, no , I'm just asking you **how** a user would enter null ? – user13863346 Aug 11 '20 at 06:42
  • 1
    @user13863346 Many keyboards accept crtl @, or by piping in input, or other means. The point is that robust code does not fall victim to nefarious users. Might be a concern for advanced users, that you can ignore for _now_. – chux - Reinstate Monica Aug 11 '20 at 06:45
1

char pswd[9]; is too small to read an 8-character password, '\n' and save as a string with its appended '\0'. OP needs a longer input buffer.

The key issue is what to do if the evil user enters a long password? Just eat it all up and try again? IMO, a user attempting to enter really long passwords should be treated as hostile and not simply an "oops". Make input buffer 2x to 4x the (8+1+1) needed to read an expected line of input. If input is full, exit. If input password length != 8, allow user to try again.


BTW if(pswd[len-1] == '\n'){ is UB if the first character read is a null character.

ryyker
  • 22,849
  • 3
  • 43
  • 87
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • You do realise that any **secure, safe** way to take input without buffer overflow will not take more than 8 chars to pswd , leaving room for the `'/0'`, and then running the while loop to clean-up stdin with eat up everything else. So if *evil user enters long password* , the first 8 chars will be stored and the rest eaten up. – user13863346 Aug 11 '20 at 02:24
  • @user13863346 That is only marginally close to the mountain of issues involved. – chux - Reinstate Monica Aug 11 '20 at 04:22
  • that's the point, I **don't** want the `'\n'` . I actually remove it if it ends up in. Its of size [9] to take **only** 8 chars and have room for `'\0'` . If an evil user (or an innocuous user) enters a *huge* password, only first 8 chars are taken, the rest eaten up. Doesn't this work just fine ? I'm genuinely asking.. Also , how can the the first character read be `NULL` ? – user13863346 Aug 11 '20 at 05:18
  • @user13863346 1) `while ((eat = getchar()) != '\n' && eat != EOF);` makes little sense to due when the prior code has already read a `'\n'`. 2) "how can the the first character read be NULL" --> By the user first entering a _null character_ - tricky, but doable. Why do you think a user can't enter a _null character_? – chux - Reinstate Monica Aug 11 '20 at 06:43
  • Chux, I didn't know it was possible(Maybe because I use a MacBook, which doesn't seem to allow this), thanks for informing me ! – user13863346 Aug 11 '20 at 07:02