How to get empty input or only ENTER in C

2019-04-02 04:42发布

问题:

Hi I'm having trouble with this simple C code since i'm very new to it.

When I try to get empty value from or get if the user only hit ENTER without typing anything. Tried few variations and still not working

The piece of code is the following:

char user_input[17] = {'\0'};
    printf("Type something: ");
    prompt = scanf("%s", user_input);

    if (prompt <= 0) {
      printf("You didn't type anythingt!\n");
      return 1;
      }

Also:

char user_input[17] = {'\0'};
    printf("Type something: ");
    scanf("%s", user_input);

    if (user_input[0] == '\0') {
      printf("You didn't type anything!\n");
      return 1;
      }

There is many variations on this forum none of them worked for me... What am I missing?

回答1:

The problem is that your scanf() call will not return until it encounters a string that is not whitespace only. You should use fgets() instead, as it prevents overflow as well.

Example:

char s[80];
fgets(s, sizeof s, stdin);
if(s[0] == '\n') {
    puts("line is empty");
}


回答2:

You can prevent the user from just pressing [enter] with scanf, but you must both:

  1. check the scanf return, and
  2. strip the newline from stdin on [enter] alone.

You must also manually prevent writing beyond the end of your string by limiting the characters scanf attempts to put in your array. Otherwise, scanf will happily try and write as many characters as are entered. (which makes line-oriented input like fgets or getline preferable)

However, if you take that all into consideration, you can do what it looks like you are attempting with scanf:

#include <stdio.h>

#define MAXS 17

void fflush_stdin();

int main () {

    char user_input [MAXS] = {0};   /* always initialize your variables */

    while (printf ("\n Type something (16 char or less): ") && 
            scanf ("%16[^\n]%*c", user_input) < 1) 
    {
        printf (" pressing [enter] doesn't count...\n");
        fflush_stdin();
    }
    printf ("\n   You entered: '%s'\n\n", user_input);

    return 0;
}

/* simple function to strip '\n` from stdin */
void fflush_stdin()
{ int c; while ((c = getchar()) != '\n' && c != EOF); }

Use/Output

$ ./bin/scanfbasic1

 Type something (16 char or less):
 pressing [enter] doesn't count...

 Type something (16 char or less):
 pressing [enter] doesn't count...

 Type something (16 char or less): 12345678901234567890

   You entered: '1234567890123456'

getline Solution

As mentioned above, line-oriented input is the preferred manner for reading strings. Two of the primary tools available are fgets and getline. Both have strengths/weaknesses. Two of the primary strengths of getline is that it (1) will allocate the line buffer for you, and (2) it returns the actual number of characters read into the buffer.

A weakness of getline is it will read all characters it is given up to the point of memory exhaustion. So if you are limiting your input to 17 (16 chars + null-terminator), it is up to you to enforce the limit. A weakness of fgets is that you have no way of knowing how many characters were actually read. All you know is fgets read somewhere between 1 and max length generally prompting the need to call strlen (or iterate over the string until the null-terminator is found.)

Both fgets and getline will include the trailing '\n' in the buffer (as it exists in the file, or as produced when you press [enter] when reading from stdin). It is never a good idea to leave stray newlines hanging off the ends of your strings, so it is generally a good idea to strip the newline after it is read.

note: getline will allocate memory for the buffer if the buffer is initially set to NULL ..and.. getline will reallocate the buffer it is given if it is insufficient to hold the input. (the current size of the allocation is maintained in 'n'). Since getline allocates/reallocates for you, you are responsible for freeing the memory when it is no longer in use.

Taking all that into consideration, the following is an equivalent getline implementation that prevents the user from leaving an empty string by simply pressing [enter] at the prompt:

#include <stdio.h>
#include <stdlib.h>

#define MAXS 17

int main (void) {

    char *ln = NULL;    /* getline requires block allocated by malloc       */
    size_t n = 0;       /* initial size of buffer, if ln NULL, n ignored    */
    ssize_t nchr = 0;   /* getline return - number of chars actually read   */

    while (printf ("\n Type something (16 char or less): ") &&
            ((nchr = getline (&ln, &n, stdin)) <= 1)) { 
        printf (" pressing [enter] doesn't count...\n");
    }

    while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
        ln[--nchr] = 0;     /* strip newline or carriage rtn    */

    if (nchr > MAXS - 1)    /* to enforce limit, check length   */
        ln[MAXS - 1] = 0;   /* if exceeds limit, null-terminate */

    printf ("\n   You entered: '%s'\n\n", ln);

    if (ln) free (ln);      /* free memory allocated by getline */

    return 0;
}

Use/Output

$ ./bin/getlinebasic_noenter

 Type something (16 char or less):
 pressing [enter] doesn't count...

 Type something (16 char or less): 12345678901234567890

   You entered: '1234567890123456'


标签: c string input