如何使用scanf-C处理比预期更少的输入

时间:2018-03-05 11:13:09

标签: c input scanf

我需要从用户输入中收到可以有2种形式的char int floatchar int,但我不会#39知道会给出哪一个。我试过这个:

int main(){
    char letter;
    int num;
    float value;
    while(getchar()!=EOF){
        scanf(" %c %d %f", &letter, &num, &value);
        printf("%c\n", letter);
        printf("%d\n", num);
        printf("%f\n", value);
    }
    return 0;
}

这个问题是当我提供这样的输入时:

? 12345
g 12345 45.6
? 12345

Output given:                      Expected Output:
1                                  ?
2345                               12345
0.000000                           0.000000
1                                  g
2345                               12345
45.599998                          45.599998
?                                  ?
12345                              12345
45.599998                          45.599998

为什么忽略charchar位置的部分号码?有办法解决这个问题吗?

3 个答案:

答案 0 :(得分:1)

在这种情况下,最好首先将用户输入检索为char *(fgets-like),然后使用sscanf(而不是scanf,sscanf)解析它。 您必须检查sscanf的返回值,以便了解输入用户的格式是否正确。

如果您需要在解析后检查是否没有垃圾值(例如" g 12345 45.6 garbagevalue"),您可以在之后添加%c并检查值是否已更改。

char   letter;
int    integerNumber;
double floatingNumber;
char   end;
char *userInput = ...;

end = '\0';
if (sscanf(userInput, "%c %d %f%c", &letter, &integerNumber, &floatingNumber, &end) == 3 && end == '\0') {
    // First form
} else {
    end = '\0';
    if (sscanf(userInput, "%c %d%c", &letter, &integerNumber, &end) == 2 && end == '\0') {
        // Second form
    } else {
        // Error : Input not strictly "%c %d %f" or "%c %d"
    }
}

听起来不错?

答案 1 :(得分:1)

我想知道从键盘读取数据块到键盘上的字符串然后用sscanf进行分析会更简单,如下面的大纲所示

#define MAX_INPUT 100

char data_input[MAX_INPUT];
int finished=0, test;

char letter;
int num;
float value;

while (finished==0) {
  // scanf("%s",data_input); //taken out after useful comments below
  fgets(data_input,100,stdin);  //replacement from comments...

  // insert code using sscanf to read in data from user
  test=sscanf(data_input, "%c %d %f", &letter, &num, &value);

  if (test==3) 
  {
    //success - sscanf successfully assigned 3 values... 

    // (ony if you have everything you need then....)
      finished =1; 
  } else if (test==2){
     // insert something to try to test if data from two data entries is ok....

    // (ony if you have everything you need then....)
      finished =1; 
  } else {
    printf("problem with data entry - please type again\n");
  }
}

向@ Tom's道歉,因为sscanf的使用是他首次提出的......

答案 2 :(得分:1)

这里有几个问题:

  1. 缺少的字符。当您第一次执行while(getchar()!=EOF)时,您正在使用流中的第一个字符,恰好是'?'。后续的scanf()无法再检索到它,因此它会抓取下一个非空格字符,该字符恰好是以下数字的'1'

    在读取'1'之后,将解析该数字的其余部分,并提供结果2345

    以下转换尝试解析float,但下一个非空白字符是g,因此无法读取浮点数,转换失败。

  2. 您无法检查,转化成功的次数。 scanf()尽职尽责地返回成功转化的次数,但您忽略了这一点。

    如果您检查了返回值,您会发现第一个scanf()调用返回2,因为字符和整数转换成功完成,但浮点转换失败。

    同样,第二个scanf()调用应返回3,表示所有三次转换都成功。对scanf()的最后一次通话应该再次返回2

  3. while(getchar()!=EOF)中某个角色的吞噬会在第二行再次咬你,这次是'g'scanf()获得之前从流中删除的scanf()有机会阅读它。

    第二次调用'\n'成功终止后,while(getchar()!=EOF)字符将保留在流中。因此,以下scanf() gogbles up和第三个'?'调用最终可以正确获取行上的第一个字符(scanf())。

  4. 浮点转换在第三个输入行上再次失败,并且相应的变量保持不变,并且您无法通过忽略getchar()的返回值来检测此情况。

  5. 长话短说:

    • 每次scanf()来电都会消耗scanf()无法读取的字符。

    • 忽略返回值的任何man scanf调用都是错误。没有检查,你就不知道你实际上读过任何东西。

    顺便说一下:man getcharconst oneHour: number = 1000 * 60 * 60; const projection: {} = { tag: 1 }; const filter: {} = { battleLogMonitorFrequency: interval, profileRefreshedAt: { $lt: new Date(snapDate.valueOf() - interval * oneHour) } }; const profileCursorTrophies: QueryCursor<IPlayerProfileModel> = PlayerProfile.find(filter, projection).sort({ trophies: -1 }) .limit(50000).lean().cursor(); await profileCursorTrophies.eachAsync( (profile: IPlayerProfileModel) => { outDatedProfileTags.push(profile.tag); }, { parallel: 100 } ); 本来可以告诉你我刚说过的一切。知道如何阅读联机帮助页是值得的。