有没有一种方法可以控制何时(或在何处)gets()或fgets()函数开始使用Input?

时间:2018-06-29 17:00:24

标签: c scanf fgets

首先,我想提一下我是编程新手。

我试图编写一个包含多个输入的程序,其中最后一个是字符串,当我使用gets()或fgets()函数时,它们从先前输入完成后读取输入。例如:

INSERT INTO categories(
            category_id, name, created_time, description)
    VALUES (?, ?, ?, ?);

样本输入/输出:

printf("Enter decimal:\n");
scanf("%d",&x);
printf("Enter string:\n");
gets(str[100]);
printf("%d\n%s",x,str);

但是,如果输入如下:

Enter decimal:
3\n            //If I change line after inputting the decimal the program continues as if it already read the string
Enter string:
3  

我想这就是gets()和fgets()函数的工作方式,但是有没有一种方法可以控制它,或者有替代方法(输入的字符串可能会很长 )

谢谢。

2 个答案:

答案 0 :(得分:2)

详细了解C standard IO。请注意,gets已过时且危险,但现已从C标准中删除。您永远不要使用它(请忘记它已经存在)。假设fgets(str, sizeof(str), stdin)gets array ,例如,假设您是str,而不是呼叫消失的char。声明为char str[100];

您可能会用fgets(甚至是getline(3),请参阅this)读整行,然后可能使用sscanf(或strtolstrtok,或使用您自己的lexingparsing技术)。

请注意,sscanf(如fscanfscanf)返回已扫描的项目计数(并接受%n),但并不关心行尾。您需要使用它。

请仔细阅读正在使用的功能的文档。

在读取真实文件时,您还可以使用fseek(带有ftell)在文件中重新定位。这在控制台上将不起作用(因为终端通常不是seekable终端。)

也许您可以使用一些terminal相关的库(例如ncursesreadline)。这些不在C11标准n1570中,并且可能在您的操作系统上不可用(但是在Linux和某些其他OS上,您已经拥有它们)。

请记住,您的stdin并不总是终端。考虑一下redirectionspipelines

另请参阅How to Debug Small Programs。确保使用所有警告和调试信息来编译代码(如果使用GCC,则为gcc -Wall -Wextra -g)。

如果您使用的是Linux或某些POSIX操作系统,请注意 stdin file descriptor 0(名为STDIN_FILENO)有关。因此,如果您要等到输入可用,请考虑在该文件描述符上使用poll(2)

PS。您的问题确实不清楚。我只是猜出你想做什么...。阅读更多文档后,请考虑对其进行改进...

答案 1 :(得分:1)

您的代码中存在多个问题:

  • gets()已过时且存在风险,因为未将目标数组大小传递给该函数,因此如果用户输入过长,它就不能防止缓冲区溢出。最终,它已从最新版本的C标准中删除。请改用fgets()
  • 混合scanf()fgets()容易出错,因为scanf()会使部分用户输入处于待处理状态,例如用户在数字后键入换行符,并且该待处理的输入将被读取fgets()来完成,在这种情况下,由于待定的换行符正是fgets()期望结束其输入的内容,因此将立即返回。

我建议使用fgets()逐行读取输入,并使用sscanf将输入转换为期望的类型。它具有允许轻松恢复错误的额外优势。

这是修改后的版本:

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

int main() {
    char buf[100];
    int x;

    for (;;) {
        printf("Enter decimal: ");
        if (!fgets(buf, sizeof buf, stdin))
            return 1;
        if (sscanf(buf, "%d", &x) == 1)
            break;
        printf("Invalid input: not a number\n");
    }
    for (;;) {
        printf("Enter string:\n");
        if (!fgets(buf, sizeof buf, stdin))
            return 1;
        buf[strcspn(buf, "\n")] = '\0';  // strip the trailing newline if any
        if (buf[0] != '\0')
            break;
        printf("Invalid input: empty string\n");
    }
    printf("%d\n%s\n", x, buf);
    return 0;
}