Best way of input in C console application: Differences between different types of input string in a console application C 控制台应用程序中的最佳输入方式

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

您好,我一直在做研究,我在 C 控制台应用程序中发现了三种最常见的不同类型的输入:

话虽如此,我将展示一个使用这三个函数的示例 (MCVE) 以及它们的作用:

#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;
}


这段代码,有下一个输出:

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.


所以,正如我们所看到的,可以从中得出三个结论:

hello[0] = 'h'

hello[1] = 'e'

hello[2] = 'l'

hello[3] = 'l'

hello[4] = 'o'

hello[5] = '[=18=]'

hello[0] = 'h'

hello[1] = 'e'

hello[2] = 'l'

hello[3] = 'l'

hello[4] = 'o'

hello[5] = '[=18=]'

hello[0] = 'h'

hello[1] = 'e'

hello[2] = 'l'

hello[3] = 'l'

hello[4] = 'o'

hello[5] = '\n'

hello[6] = '[=33=]'


我的结论正确吗?要添加任何信息吗?

谢谢。

你的结论是正确的。但是,在您引用的三种输入法中,只有 fgets 是安全的:

  • scanf 变成没有限制的字符串会溢出输入缓冲区;请参阅下面的修复程序。
  • gets 已弃用,因为它不可能保证缓冲区溢出安全 (why?)。

要修复 scanf,请指定缓冲区的大小,并为空终止符保留 space:

scanf("%6[^\n]", hello);

请注意,当您使用 [^\n] 格式说明符时,末尾的 s 不是必需的。

在这个答案中,我将汇总所有获得的答案,以及我继续进行的研究工作(我会在获得新信息时更新答案):

  • gets 是不安全的,反对它的是缓冲区溢出
  • 通过控制台输入最安全的方法是fgets,但它有一个缺点:该命令也读取'\n'字符。要解决这个问题,我们可以执行以下操作:

    #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 '[=10=]' 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")] = '[=10=]';
    }
    
  • scanf是一个非常强大的函数,必须了解透才能用好。说到 scanf,我将展示一个如何使用 scanf 的示例,它控制您需要的一切(大小,停止阅读时,避免 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 '[=11=]' 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 
    }