sscanf - 不同数量的格式参数?

时间:2011-12-29 21:22:20

标签: c scanf

在我的程序中,我使用sscanf来检查字符串是否为给定格式。为此,我提供格式字符串中的参数数量,并在解析输入时检查sscanf是否返回相同的数字。

作为原始解析器的一部分,我想检查字符串是否与多种格式之一匹配。 sscanf函数是可变参数,那么如何处理需要传递的不同数量的参数?

目前,我只是将大量的参数(例如50)传递给函数,并希望格式字符串不包含更多参数。

有没有更好的方法呢?

6 个答案:

答案 0 :(得分:3)

你真的需要比scanf重的东西。您必须告诉 scanf您的输入是什么格式;它本身无法解决任何问题。

如果您有权访问POSIX,请查看regex.h它可能是您需要的一切。

否则,你就会陷入困境。如果格式相当复杂,lexyacc会很好,但除此之外,strtok或(getchar + switch}可能是最佳选择。

修改 既然你可以使用POSIX,这里有一个简单的例子,介绍如何从c中的正则表达式中提取数据。 (为简洁起见,排除了错误检查。)

char txt[] = "232343341235898dfsfgs/.f";
regex_t reg;
regmatch_t refs[MAX_REFS]; //as in, the maximum number of data you want to extract
regcomp(&reg, "3433\\([0-5]*\\).*", 0); //replace 0 with REG_EXTENDED if desired
regexec(&reg, txt, MAX_REFS, refs, 0);
regfree(&reg);

txt[refs[0].rm_eo+1] = '\0';
int n = atoi(txt+refs[0].rm_so);
printf("%d\n", n);

打印

41235

答案 1 :(得分:0)

你应该使用lex / yacc来构建一个合适的解析器。或者,首先使用strtok对字符串进行标记可能会简化您的问题。 (注意:正确使用strtok非常棘手 - 请仔细阅读其文档。)

答案 2 :(得分:0)

我不确定它是否回答了你的问题,但you use varargs in C允许函数的变量数量可变。

void myscanf(const char *fmt, ...)
{
}

答案 3 :(得分:0)

无益的答案是“不要这样做,正确编写解析器,可能使用lex和/或yaccbison”。

你问的问题的答案是“是的,你可以做到”。我不相信有任何理由可以存在更多可变参数,而不是格式要求,尽管很少会是一件坏事。我假设你有一个数组或可能的格式列表,你在循环中调用sscanf。

答案 4 :(得分:0)

您可以使用stdarg.h中提供的宏使用可变长度参数编写验证函数。

例如,

int my_validation_func(const char *format, ...) {
    va_list ap;
    char *p, *sval;
    int ival;
    float fval;

    va_start(ap, format);
    for(p=format; *p ; p++) {
        if (*p != '%') {
            continue;
        }
        switch(*++p) {
            case 'd':
                ival = va_arg(ap, int);
                break;

            case 'f':
                fval = va_arg(ap, float);
                break;

            case 's':
                for (sval = va_arg(ap, char *); *sval; sval++);
                break;

            default:
                break;
        }
    }
    va_end(ap);
}

希望这有帮助!

答案 5 :(得分:0)

如果您在编写代码时不知道 参数的数量和类型,sscanf()无法安全地执行您要执行的操作。

将50个参数传递给sscanf()是正常的(格式字符串不会消耗的参数会被计算,但会被忽略),但是与格式字符串相对应的参数必须是促销之后的预期类型;否则,行为未定义。因此,如果您想要检测是否可以使用"%d""%f"扫描字符串,则无法通过单个sscanf()调用来安全地执行此操作。 (可能你可以通过传递指向足够大的缓冲区的void*来逃避,但行为仍未定义。)

sscanf()的另一个令人讨厌的问题是它不处理数字溢出。这样:

char *s = "9999999999999999999999999";
int n;
int result = sscanf(s, "%d", &n);
printf("result = %d, n = %d\n", result, n);

有未定义的行为(假设9999999999999999999999999太大而无法存储在int中)。

可能能够做的事情是找到一个开源的sscanf实现并对其进行修改,以便只根据格式验证字符串,而不存储任何内容。 (处理实现的许可证留待练习。)如果您发现sscanf - 样式格式字符串特别方便您的问题,这是有道理的。否则,正则表达式可能是要走的路(不是在C标准中,但是很容易找到实现)。