Search code examples
cscanffgetsgets

Best way of input in C console application: Differences between different types of inputting string in a console application C


Hi have been doing research and I have found three most common different types of input inside a C console application:

  • scanf("%[^\n]s", *char): Pick up a string until it finds a break line. It is advised not to use it due to overflow buffer problems.
  • gets(*char): Pick up a string until it finds a break line. It is equivalent to the first. It is advised not to use it due to overflow buffer problems too.
  • fgets(*char, LENGTH, *FILE): Pick up a string of LENGTH characters, from the file FILE. It is the safest of the three and the most recommended.

Having said this, I will show an example (MCVE) of the use of the three functions and what is picking up them:

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

int main(void)
{
    char hello[7]; //Will store word 'hello'; Length is 6 = 5+(1)+1 = strlen("hello")+(BreakLineChar)+NullTermination - BreakLineChar will appear (or not) depending input type
    int i;

    // SCANF()
    printf("Input HELLO: ");
    scanf("%[^\n]s",hello);
    fflush(stdin);
    printf("Length: %d\n", strlen(hello));
    for (i = 0; i < strlen(hello); i++)
    {
        printf("%i: %c\n", i, hello[i]);
    }
    printf("\n\n");

    // GETS()
    printf("Input HELLO: ");
    gets(hello);
    fflush(stdin);
    printf("Length: %d\n", strlen(hello));
    for (i = 0; i < strlen(hello); i++)
    {
        printf("%i: %c\n", i, hello[i]);
    }
    printf("\n\n");

    // FGETS()
    printf("Input HELLO: ");
    fgets(hello,sizeof(hello),stdin);
    fflush(stdin);
    printf("Length: %d\n", strlen(hello));
    for (i = 0; i < strlen(hello); i++)
    {
        printf("%i: %c\n", i, hello[i]);
    }
    printf("\n\n");

    return 0;
}


This code, have next output:

Input HELLO: hello
Length: 5
0: h
1: e
2: l
3: l
4: o


Input HELLO: hello
Length: 5
0: h
1: e
2: l
3: l
4: o


Input HELLO: hello
Length: 6
0: h
1: e
2: l
3: l
4: o
5:




Process returned 0 (0x0)   execution time : 5.757 s
Press any key to continue.


So, as we can see, three conclusions can be drawn from this:

  • scanf: Pick up user's input until '\n' char (does not pick up the character '\n'). So string hello would be:

       hello[0] = 'h'

       hello[1] = 'e'

       hello[2] = 'l'

       hello[3] = 'l'

       hello[4] = 'o'

       hello[5] = '\0'

  • gets: Equivalent to the point above. So string hello would be:

       hello[0] = 'h'

       hello[1] = 'e'

       hello[2] = 'l'

       hello[3] = 'l'

       hello[4] = 'o'

       hello[5] = '\0'

  • fgets: Pick up user's input until '\n' char (pick up the character '\ n' too). So string hello would be:

       hello[0] = 'h'

       hello[1] = 'e'

       hello[2] = 'l'

       hello[3] = 'l'

       hello[4] = 'o'

       hello[5] = '\n'

       hello[6] = '\0'


Are my conclusions correct? Any information to add?

Thank you.


Solution

  • In this answer I will make a compilation of all the answers obtained, and of the research work that I continue doing (I will update the answer as I get new information):

    • gets is insecure, one against it is buffer overflow
    • Most safe method for inputting by console is fgets, but it have a contra: This command reads '\n' character too. To solve this we can do the following:

      #include <stdio.h>
      #include <string.h>
      #define MAX_SIZE_STRING 5
      
      int main(void)
      {
          char string[MAX_SIZE_STRING+1]; // MAX_SIZE_STRING + 1 due to a string needs '\0' char at the end
          int i;
      
          printf("Input a string: ");
          fgets(string, MAX_SIZE_STRING, stdin);
      
          // Remove '\n' character inside the string:
          string[strcspn(string, "\n")] = '\0';
      }
      
    • scanf is a very powerful function, which is necessary to know it thoroughly to use it well. Speaking of scanf, I'm going to show an example of how to use scanf which controls everything you need (size, when stop reading, avoid bufferOverflow,...):

      #include <stdio.h>
      #include <string.h>
      #define MAX_SIZE_STRING 5
      #define STR_(X) #X
      #define STR(X) STR_(X)
      
      int main(void)
      {
          char string[MAX_SIZE_STRING+1]; // MAX_SIZE_STRING + 1 due to a string needs '\0' char at the end
          int i;
      
          printf("Input a string: ");
          scanf(" %" STR(MAX_SIZE_STRING) "[^\t\n]%*[^\n]", string);
          // EXPLANATION OF THE COMMNAD:
          // First blanck-space: It is used for empty string. If user entries only blank-spaces, it will no stored in the var until user input any char
          // STR(TAM_MAX): Use of preprocessor for adding a max length to the input
          // [^\t\n]: Pick up until find a '\t' or a '\n'
          // So, at the end, this command is equal to: scanf(" %5[^\t\n]s", string);
          // %*[^\n] remove end/break line (\n) so, by this way, buffer overflow is avoied 
      }