【问题标题】:C sscanf behaviourC sscanf 行为
【发布时间】:2014-04-25 17:44:24
【问题描述】:

我正在尝试了解 sscanf 的行为,因为我已经在两个程序下执行了。

void main()
{
        char *a = "225.311";
        int x = 0, y = 0;
        sscanf(a, "%d.3%d", &x, &y);
        printf("x is %d, y is %d\n", x, y);
}

输出是

x is 255, y is 11

以下程序没有按我的预期运行。

void main()
{
        char *a = "225.311";
        int x = 0, y = 0;
        sscanf(a, "%d5.3%d", &x, &y);
        printf("x is %d, y is %d\n", x, y);
}

我期待25,11,但输出是

x is 255, y is 0

我期望sscanf 的行为应该与 sprintf 以相反的方式完全相同。但它在我的第二个程序中不起作用。如果指定的格式为%d5.3%d,则必须将5 视为分隔符。但它没有考虑和读取x 的所有数字,然后点与5.3%d 不匹配,所以它退出了。

谁能解释一下。

【问题讨论】:

  • 始终检查[s]scanf 的返回值。如果它不等于您使用的占位符的数量,那么您会意识到发生了一些错误。
  • 阅读scanf 的文档或手册页,不要假设... 这一系列的文本解析函数具有很大的功能,但我会说功能带来的责任比它更大值得,更不用说从用户的角度来看默认值可能不直观。通常最好用标准 C fgets 或 GNU/POSIX2008 getline 读取一行,然后用 sscanf 解析。

标签: c printf scanf


【解决方案1】:

这是因为%d 转换说明符意味着sscanf 将继续从a 指向的缓冲区中读取,直到在缓冲区中遇到非数字字符。这意味着在第二个示例中,%d 将在字符串文字 "225.311" 中消耗到 225

如果指定的格式是%d5.3%d,那么它必须将 5 视为 分隔符。

不,那不是真的。格式字符串中的5 意味着sscanf 将在它读取的缓冲区中完全匹配它(在读取一个int 之后)。如果匹配失败,则sscanf 将返回,y 的值保持不变。您可以通过存储sscanf 的结果来检查这一点。返回值等于成功匹配并分配的输入项数。

char *a = "225.311";
int x = 0, y = 0;
int retval = sscanf(a, "%d5.3%d", &x, &y);
printf("%d\n", retval); // prints 1

但是,请注意,如果缓冲区中的数字字符序列太长而无法放入int,则由于有符号整数溢出,行为未定义。

【讨论】:

    【解决方案2】:

    建议使用不同的格式并检查sscanf() 的结果。还要区分“0.001”和“0.1”等分数,注意位置。

    const char *a = "225.0311";
    int ipart = 0;
    unsigned fractionpart;
    int n1, n2;
    if (sscanf(a, "%d.%n%u%n", &ipart, &n1, &fractionpart, &n2) != 2) {
      Handle_BadInput();
    }
    
    printf("ipart is %d, fractionpart is %0*u\n", ipart, n2 - n1, fractionpart);
    // ipart is 225, fractionpart is 0311
    

    正如@ajay 所讨论的,"%d5.3%d" 查找int,然后是"5.3",然后是另一个int

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-03
      • 2012-12-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多