C sscanf行为

时间:2014-04-25 17:44:24

标签: c printf scanf

我正在尝试理解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不匹配,因此它会退出。

有人可以解释一下。

2 个答案:

答案 0 :(得分:4)

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

  

如果指定的格式为%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,则由于有符号整数溢出,行为未定义。

答案 1 :(得分:1)

建议使用其他格式并检查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