C 中的 fgets 和 sscanf

fgets and sscanf in C

我有一个文件,我正在尝试从中提取整数和字符。

10 20
0 0 #
1 0 |
2 0 |
3 0 |
3 1 -
3 2 -
3 3 -
3 4 >

我当前的代码是:

while(fgets(line, sizeof(line), snakeFile) != NULL)
{
    if(sscanf(line, "%d %d", &ROW, &COL) == 2)
    {
        printf("ROW: %d, COL: %d\n", ROW, COL);
    }
    
    else
    {
        sscanf(line, "%d %d %c\n", &xPos, &yPos, &zType);
        printf("xPos: %d, yPos: %d, zType: %c\n", xPos, yPos, zType);
    }

}

但是我得到的输出是:

ROW: 10, COL: 20
ROW: 0, COL: 0
ROW: 1, COL: 0
ROW: 2, COL: 0
ROW: 3, COL: 0
ROW: 3, COL: 1
ROW: 3, COL: 2
ROW: 3, COL: 3
ROW: 3, COL: 4

我希望它获取前两个整数并将其存储在 ROW 和 COL 中,然后它下面的其余行分别存储在 xPos、yPos 和 zType 中。

您似乎正在使用条件

if(sscanf(line, "%d %d", &ROW, &COL) == 2)

确定您当前是否正在处理第一行。但是,此条件无法确定这一点,因为该条件对所有行都为真,而不仅仅是第一行。函数 scanf 将成功匹配 2 个数字,然后忽略该行的其余部分。

您可以做的一件事是将该行更改为

if ( sscanf(line, "%d %d %c\n", &xPos, &yPos, &zType) == 3 )

并交换 ifelse 块的内容。这应该有效,因为除了第一行之外的所有行都满足此条件。

但是,更简单的解决方案是不尝试处理循环内的第一行,而是处理循环外的那一行:

if( sscanf( line, "%d %d", &ROW, &COL) != 2 )
{
    fprintf( stderr, "Conversion failure!\n" );
    exit( EXIT_FAILURE );    
}

printf("ROW: %d, COL: %d\n", ROW, COL);

while ( fgets(line, sizeof(line), snakeFile) != NULL )
{
    if ( sscanf(line, "%d %d %c", &xPos, &yPos, &zType) == 3 )
    {
        printf(
            "xPos: %d, yPos: %d, zType: %c\n",
             xPos, yPos, zType
        );
    }
    else
    {
        fprintf(
            stderr,
            "Warning: Conversion failure occurred on one line! This could\n"
            "be harmless, for example it could be caused by an empty\n"
            "line at the end of the file.\n"
        );
    }
}

请注意,您可能需要添加 #include <stdlib.h> 才能调用函数 exit

sscanf(line, "%d %d", &ROW, &COL) == 2 匹配 OP 示例的每一行,因为每一行都以 2 个数字开头。


如果 整个 行被扫描,一个真正简洁的测试方法使用 " %n" 来存储扫描的偏移量。

即使文件的最后一行缺少 '\n'

// if(sscanf(line, "%d %d", &ROW, &COL) == 2)
int n = 0;
sscanf(line, "%d %d %n", &ROW, &COL, &n);
if (n > 0 && line[n] == '[=10=]') {
  printf("ROW: %d, COL: %d\n", ROW, COL);
} else {
  int n = 0;
  sscanf(line, "%d %d %c %n", &xPos, &yPos, &zType, &n);
  if (n > 0 && line[n] == '[=10=]') {
    printf("xPos: %d, yPos: %d, zType: %c\n", xPos, yPos, zType);
  } else {
    printf("No match\n");
  }
}

如果扫描包含必需的后缀,这也很有效。

考虑如下输入:

< 0 0 # >
< 1 0 | >
< 2 0 | >

然后用" < %d %d %c > %n"扫描