C编程:如何使用带有':'分隔符的sscanf?

时间:2012-02-12 05:47:17

标签: c scanf

我一直在尝试使用sscanf从输入文本中提取小时,秒和分钟。执行sscanf函数后,只有保存秒的s变量具有正确的值。其中包含小时和分钟的hm仅包含零。请在下面建议更改我的代码。

     char text[20];
     if (fgets(text, sizeof text, stdin)!= NULL){
         char* newline = strchr(text, '\n');
         if (newline != NULL){
             *newline = '\0';
         }
     }
     uint8_t s = 0;
     uint8_t m = 0;
     uint8_t h = 0;
     sscanf(text, "%02i:%02i:%02i",&h,&m,&s);

请注意,在调试器中,text具有正确的值。

2 个答案:

答案 0 :(得分:3)

这个程序:

#include <stdio.h>

int main(void)
{
    const char hhmmss[] = "10:32:54";
    int hh, mm, ss;
    if (sscanf(hhmmss, "%i:%i:%i", &hh, &mm, &ss) != 3)
        printf("Failed to scan 3 values from '%s'\n", hhmmss);
    else
        printf("From <<%s>> hh = %d, mm = %d, ss = %d\n", hhmmss, hh, mm, ss);
    return 0;
}

给出了这个输出:

From <<10:32:54>> hh = 10, mm = 32, ss = 54

%02i转换也应该有效,但数字有些多余。


修正后的问题显示变量的类型为uint8_t,在这种情况下,您必须使用<inttypes.h>中的正确转换说明符:

#include <stdio.h>
#include <inttypes.h>

int main(void)
{
    const char hhmmss[] = "10:32:54";
    uint8_t s;
    uint8_t m;
    uint8_t h;

    if (sscanf(hhmmss, "%02" SCNi8 ":%02" SCNi8 ":%02" SCNi8, &h, &m, &s) != 3)
        printf("Failed to scan 3 values from '%s'\n", hhmmss);
    else
        printf("From <<%s>> h = %d, m = %d, s = %d\n", hhmmss, h, m, s);
    return 0;
}

这产生与以前相同的输出。对于任何scanf()系列函数,格式转换说明符与传递给函数的指针类型相匹配至关重要。你可以在printf()中摆脱相当多的不匹配 - 当然是比较 - 因为默认的整数(特别是)促销,但scanf()的宽容度要低得多。

答案 1 :(得分:2)

@Jonathan Leffler的回答是完全正确的,但是......

你应该从不使用scanffscanfsscanf来解析来自文件句柄或字符串的输入,除非可能是已知的抛弃了明天的代码。它们太容易出错并且难以控制。有关scanf的各种问题的详尽摘要,我建议this series of articles。一些亮点:

  • 如果您需要阅读单个字符,请使用getchar
  • 如果您想读取字符串,scanf会遇到gets的所有缓冲区溢出问题。
  • 如果您想阅读数字,scanf的解析容易出错且难以使用。请改用strtoulstrtod
  • 如果你有更复杂的输入,一切都会更糟。

怎么办?

  • 使用比gets更好的内容读取您自己的输入,即没有缓冲区溢出问题。不要试图将字节用于解释它们。
  • 结合使用strcspnstrspnstroulstrtod以及一些自定义代码来扫描输入。

有时候这也是拖累,但到那时你通常会构建某种输入语言,无论如何都需要更多的通用技术。