2

This program does the following:

  1. Scans a string of text char input[15];
  2. Compares it to char password[ ] = "1sure";
  3. Loops if the strings do not match.
  4. Terminates if the strings match.

The program loops while the strings do not match. However, I also want the program to loop if nothing is input and the user simply presses enter. I tried using an isgraph function but this causes the program to crash. I commented that section out in the code. Can someone suggest how to get the program to loop if there is no input?

#include <stdio.h>
#include <string.h>

int main()
{
    char password[] = "1sure";
    char input[15];

    do
    {
        printf("Password: ");
        scanf("%s", input);

        if(strcmp(password,input)==0)
        {
            printf("Password accepted.");
            putchar('\n');
            return(0);
        }
        /*else if(isgraph(input)==0)
        {
            printf("No input detected."); //Program crashes with this segment.
            continue;
        }*/
        else
        {
            printf("\nInvalid password.\n");
            continue;
        }
    }
    while(1);
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
grammer
  • 245
  • 3
  • 14
  • 1
    Use [`fgets()`](http://en.cppreference.com/w/c/io/fgets) instead of `scanf` and cull the newline. – WhozCraig Mar 23 '15 at 04:54
  • 2
    The call to `scanf`, `scanf("%s", input);` will not complete until the user enters some non white space text. Just pressing Enter will not result in nothing being read to `input` -- the program will just wait. – R Sahu Mar 23 '15 at 04:55
  • It is simpler include the newline in the output message when the password is accepted than to use `printf()` plus `putchar()`. Don't forget that standard error is intended for reporting error messages. – Jonathan Leffler Mar 23 '15 at 05:04

4 Answers4

3

The program could look the following way

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main( void )
{
    char password[] = "1sure";
    char input[15];

    do
    {
        printf("\nPassword: ");

        if ( fgets( input, sizeof( input ), stdin ) == NULL )
        {
            printf( "An error occured or input was interrupted\n" );
            return 0;
        }

        size_t n = strlen( input );

        while ( n && isspace( input[n-1] ) ) input[--n] = '\0';

        if ( input[0] == '\0' )
        {
            printf("No input detected.\n");
            continue;
        }
        else if( strcmp( password, input ) == 0 )
        {
            printf("Password accepted.\n");
            return(0);
        }
        else
        {
            printf("\nInvalid password.\n");
            continue;
        }
    } while(1);
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

The scanf function skips leading whitespace when used with %s and most other specifiers. Whitespace includes newlines, so it is not possible to detect a blank line with scanf.

Instead you can read a line with fgets. Note that I have added error checking:

if ( ! fgets(input, sizeof input, stdin) )
    break;

Unfortunately fgets has a quirk in that it puts the newline character into the buffer, so you have to remove that; one way to do that is:

char *newline = strchr(input, '\n');
if ( newline )
    *newline = '\0';

Then you can go on to strcmp and the rest of your loop.


Other notes: If you didn't get compiler errors for isgraph(input) then you need to figure out how to invoke your compiler properly. That code is illegal and if errors are not shown then you may be missing out on other useful information that the compiler could be telling you.

Also, there is no point having else after return. A return statement cannot fail. A continue as the last line of the loop is similarly redundant.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • 1
    `if ( input[strlen(input) - 1] == '\n' )` can invoke UB. Recommend http://stackoverflow.com/a/28462221/2410359 or insure `*input != 0`. – chux - Reinstate Monica Mar 23 '15 at 05:23
  • @chux I don't see how it can cause UB; `fgets` cannot return non-null and also yield anything other than a non-empty null-terminated string. (Well, I guess it could if the buffer size was 1) – M.M Mar 23 '15 at 05:32
  • `fgets()` reads a _line_ (`char` up to and including `'\n'`), not a _string_ (`char` up to and including `'\0'`). Input could contain embedded `'\0'` such as "\0abc\n". `fgets()` in this case fills `input` with "\0abc\n\0". Then `input[strlen(input) - 1] = '\0';` is setting a value before the array `input`. – chux - Reinstate Monica Mar 23 '15 at 05:39
  • @chux well, text streams are not allowed to contain `\0`, and `stdin` is a text stream. But I will concede that there could be buggy implementations around so my code is unsafe in practice. Fixing! – M.M Mar 23 '15 at 05:42
  • 1
    Hmm "text streams are not allowed to contain `\0`" I see nothing in C the asserts that - as troublesome as embedded null characters are. Also consider text file encoded UTF16 which has plenty of embedded `'\0'` and code unsuspectingly attempting to `fgets()` that. – chux - Reinstate Monica Mar 23 '15 at 05:47
  • 1
    @chux I see nothing in the standard either... I must have trusted some untrustworthy text :) – M.M Mar 23 '15 at 06:00
0

Check the return value of scanf (it should return 1) to continue the rest of the code

printf("Password: ");
char line[15];
if(fgets(line,15,stdin)!=NULL) {
   if(scanf("%s", input)==1) {
      if(strcmp(password,input)==0) {
   ...
   }
}
dvhh
  • 4,724
  • 27
  • 33
  • Just checking the return value of `scanf("%s",input)` is not a complete fix for all the reasons enumerated above (leading newlines, undefined behaviour...) – chqrlie Mar 23 '15 at 10:10
  • @chqrlie thanks for the feedback I will amend the answer – dvhh Mar 23 '15 at 11:17
0

Simply check the return value of scanf.

if ( scanf("%s",input) != 1 )
       continue;
...
...

Or else you can do like this.

while( scanf("%s",input) != 1 )// It will continue the loop until the correct input come.
       continue;
Karthikeyan.R.S
  • 3,991
  • 1
  • 19
  • 31
  • 3
    This won't work unforturnately. The `scanf("%s")` can only fail if EOF occurs. `%s` consumes leading whitespace, including newlines. – M.M Mar 23 '15 at 04:59
  • `scanf("%s",input)` can cause a buffer overflow. Carefully crafted input may cause an invalid password to be accepted (among other undefined behaviour) – chqrlie Mar 23 '15 at 10:06