【问题标题】:fgets and sscanf being skipped in c?在c中跳过fgets和sscanf?
【发布时间】:2020-02-02 00:35:52
【问题描述】:

在我的代码中,我确保用户输入以下缩写类之一,但是我的 fget 导致我出现很多逻辑错误。

char class[3];
char arr3[5];
i = 0;
    while(i == 0){
        printf("Enter the class, either FR, SO, JR, SR, GR, RFR, or RSO\n");
        fgets(arr3, sizeof(arr3), stdin);

        if(sscanf(arr3, "%s", class) == 1){

            if(strcmp(class, "FR\0") == 1 || strcmp(class, "SO\0") == 1)
                i = 1;
            else if(strcmp(class, "JR\0") == 1 || strcmp(class, "SR\0") == 1)
                i = 1;
            else if(strcmp(class, "GR\0") == 1 || strcmp(class, "RFR\0") == 1)
                i = 1;
            else if(strcmp(class, "RSO\0") == 1)
                i = 1;
            else
                printf("Enter one of the classes.  Must be all caps.\n");
        }
        else if(sscanf(arr3, "%s", class) != 1)
            printf("An error has occured.\n");
    }

当我运行代码时,首先发生的是它跳过 fgets 然后打印: 输入其中一个类。必须全部大写。 这是否意味着它正在读取标准输入中已经存在的内容?

【问题讨论】:

  • class[3] 太短了,无法将 "RFR""RSO" 保存为字符串('\0' 没有空间),因此 Undefined Behavior 结果时您将未终止的class 传递给strcmp。进一步的 "\0" in ,例如"SO\0" 是多余的。 String Literal 已经提供了 nul-termianting。特点。 故事的寓意 -- 不要吝啬缓冲区大小! 此外,如果有的话,在你的代码 sn-p 之前会发生什么,stdin 很重要。请提供A Minimal, Complete, and Verifiable Example (MCVE)

标签: c scanf fgets


【解决方案1】:

继续我的评论,您有很多问题,但最大的是不要吝啬缓冲区大小!。您的下一个主要混淆点是strcmp 在字符串匹配时返回零,而不是1。不要尝试通过截断到更短的数组来删除fgets 包含的尾随'\n',只需使用strcspn 将其删除即可。

String Literal 提供 nul-termianting 字符,因此"SR\0" 中的"\0" 是多余的。摆脱它们。

但是,恭喜,您获取用户输入的基本方法(例如,循环不断地强制用户输入所需的内容)——是正确的方法。

做出这些你可以做的改变:

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

#define BUFC 1024       /* if you need a constant, #define one (or more) */

int main (void) {

    char buf[BUFC];

    while (1) {
        printf("Enter the class, either FR, SO, JR, SR, GR, RFR, or RSO\n");
        if (!fgets (buf, BUFC, stdin)) {
            fputs ("(user canceled input)\n", stdout);
            return 1;
        }
        buf[strcspn (buf, "\n")] = 0;       /* trim newline from buf */

        /* strcmp equality return is 0 */
        if (strcmp (buf, "FR") == 0 || strcmp (buf, "SO") == 0  ||
            strcmp (buf, "JR") == 0 || strcmp (buf, "SR") == 0  ||
            strcmp (buf, "GR") == 0 || strcmp (buf, "RFR") == 0 ||
            strcmp (buf, "RSO") == 0)
            break;
        else
            printf("Enter one of the classes.  Must be all caps.\n");
    }
    printf ("\nclass: %s\n", buf);
}

(注意:如果您正在为内存有限的微控制器(如 Arduino 或 TI-MSP432)进行编译,那么您可以将 BUFC 减少到 32 左右,但在x86 或 x86_64,一个 1K 到 4K 的缓冲区通常可以确保遇到的所有正常输入行都会被消耗掉——即使猫踩在键盘上)

在上面,检查fgets() 的返回允许您捕获手动生成的EOF,用户可以通过在 Linux 上按 Ctrl+dCtrl+z 在 Windows 上。

使用/输出示例

$ ./bin/enterclasses
Enter the class, either FR, SO, JR, SR, GR, RFR, or RSO
banannas
Enter one of the classes.  Must be all caps.
Enter the class, either FR, SO, JR, SR, GR, RFR, or RSO
NO
Enter one of the classes.  Must be all caps.
Enter the class, either FR, SO, JR, SR, GR, RFR, or RSO
RFR

class: RFR

查看一下,如果您还有其他问题,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-13
    • 1970-01-01
    • 2014-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-01
    相关资源
    最近更新 更多