【问题标题】:Return Value of sscanfsscanf 的返回值
【发布时间】:2018-10-18 12:56:22
【问题描述】:

我正在阅读有关 sscanf 的信息,我遇到了这个:

返回值 这些函数中的每一个[包括 s_sscanf()] 返回成功转换和分配的字段数;返回值不包括已读取但未分配的字段。返回值 0 表示未分配任何字段。如果在第一次转换之前出现错误或到达字符串末尾,则返回值为 EOF。

我正在对我的输入文件进行错误检查,我想确保我得到一个有效的行,所以我尝试使用 sscanf 但我如何确保该行中没有比我预期的更多的字段。因此,如果我在一行中有 3 个值,但我只需要两个,那么这对我来说是无效的行,但是当我使用 sscanf 时,我只读取 2 个变量,其余的被忽略。我如何检查整行以确保行中没有垃圾但我不确定会发生什么,所以它不像我可以添加另一个变量,因为用户可以输入任何内容。有人向我提到您可以在 sscanf 函数中使用 *,但我不确定我是如何无法在代码中实现它的任何地方找到它的。

【问题讨论】:

  • 从理论上解释您的代码,请发布您的代码及其输入和输出。否则很难消化。
  • 没有代码我只是想了解 sscanf @kiranBiradar 的返回值以及如果您有未分配的额外字段会发生什么以及如何检查错误
  • 如果您有额外的字段,scanf 会在扫描它们之前停止。你可能需要fgets 然后strtok
  • “它不像我可以添加另一个变量” - 为什么不呢?为%c 格式添加一个虚拟变量并检查(在这种情况下)sscanf 是否返回 2(OK)或 3(行尾垃圾)
  • 但是如果超过 3 个我不能继续添加一个虚拟变量怎么办?我可以吗 ? @ReAl

标签: c file scanf


【解决方案1】:

scanf() 系列函数返回成功分配的数量。如果代码需要三个输入项,则无法仅从 sscanf() 返回的值判断是否提供了三个或更多输入项。

scanf() 函数通过读取字符、尝试匹配该字符、进行赋值(如果适用)然后移动到下一个字符或从函数调用返回来操作。有一个转换说明符%n,它存储到目前为止在此过程中读取的字符数(不增加读取的字符数)。此转换说明符可用于确定输入是否已被 sscanf() 调用耗尽。

下面的代码提供了一个演示。 fgets() 收集的输入行包含换行符,除非输入太大而无法放入缓冲区数组。这里buffer[] 足够大,可以存储合理大小的输入,但更健壮的代码会更仔细地处理超大输入。当sscanf()扫描输入字符串时,会依次读取每个字符,直到出现匹配失败或到达字符串末尾,所以匹配"%d %d %d %n"后预期读取的字符数与输入的长度相同字符串,包括任何尾随空白字符。

#include <stdio.h>
#include <string.h>

#define BUF_SZ  1024

int main(void)
{
    char buffer[BUF_SZ];
    int x, y, z;
    int pos;

    printf("Enter three integers: ");
    fflush(stdout);

    // get user input
    if (fgets(buffer, sizeof buffer, stdin) != NULL) {

        // first check: does input match 3 integers?
        if (sscanf(buffer, "%d %d %d %n", &x, &y, &z, &pos) != 3) {
            puts("Incorrectly formatted input");
        } else {
            // second check: did sscanf() finish at the end of the buffer?
            int expected = strlen(buffer);
            if (pos != expected) {
                puts("Extra input in buffer");
                printf("expected = %d, pos = %d\n", expected, pos);
        } else {
            // everything OK
            printf("You entered: %d, %d, %d\n", x, y, z);
            }
        }
    }

    return 0;
}

示例交互:

>$ ./a.out 
Enter three integers: 1 2 3
You entered: 1, 2, 3
>$ ./a.out 
Enter three integers: 1 2
Incorrectly formatted input
>$ ./a.out 
Enter three integers: 1 2 3 4
Extra input in buffer
expected = 8, pos = 6

如果希望禁止尾随 空格 字符,则可以使用 "%d %d %d%n" 代替。请注意,为了使其正常工作,必须从buffer[] 中删除换行符,以便不将其计为额外输入。一种典型的方法是使用buffer[strcspn(buffer, "\r\n")] = '\0'

int main(void)
{
    char buffer[BUF_SZ];
    int x, y, z;
    int pos;

    printf("Enter three integers: ");
    fflush(stdout);

    // get user input
    if (fgets(buffer, sizeof buffer, stdin) != NULL) {

        // first check: does input match 3 integers?
        if (sscanf(buffer, "%d %d %d%n", &x, &y, &z, &pos) != 3) {
            puts("Incorrectly formatted input");
        } else {
            // remove trailing newline character
            buffer[strcspn(buffer, "\r\n")] = '\0';
            // second check: did sscanf() finish at the end of the buffer?
            int expected = strlen(buffer);
            if (pos != expected) {
                puts("Extra input in buffer");
                printf("expected = %d, pos = %d\n", expected, pos);
        } else {
            // everything OK
            printf("You entered: %d, %d, %d\n", x, y, z);
            }
        }
    }

    return 0;
}

【讨论】:

  • 谢谢——这让我不必编写或多或少相同的代码!
  • @JonathanLeffler -- 乐意效劳! ;)
【解决方案2】:

您可以首先为您确定必须存在的值提供转换说明符,然后添加“赋值分配修饰符”以捕获任何剩余的输入。我不确定您说的是 sscanf、fscanf 还是 scanf;我将仅使用 scanf 来说明。 以下程序读取 2 个整数,并将任何剩余的输入放在一个字符串变量中,其大小是动态分配的:

更新:使用 sscanf 代替 scanf。

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
    int a,b;
    char *s;
    int n;
    char src[]="1 2 This is the remainder";
    n=sscanf(src,"%d %d %m[^\n]",&a,&b,&s);
    if(n>2)
        printf("s=%s\n", s), free(s);
    return 0;
}

$ ./a.out 
s=This is the remainder

【讨论】:

  • 请注意,m 修饰符并非在所有平台上都可用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-29
  • 2016-04-16
  • 1970-01-01
  • 1970-01-01
  • 2013-12-31
相关资源
最近更新 更多