Sscanf在提取字符串时的行为不正常

时间:2013-11-10 22:01:57

标签: c scanf

我有一个SPARQL查询,例如“select?Y?Z where ......”。我想要做的就是提取变量“?Y”和“?Z”。我写了以下循环:

char *p = "select ?Y ?Z where condition";
char *array[2];

p += strlen("select");        /* advancing the pointer */

for(int i = 0; i < 2; i++)
{
        sscanf(p, "%m[?a-zA-Z] %[^\n]", array[i], p);    /* 'm' tells sscanf to perform dynamic memory allocation */
        printf("%s, ", array[i]);
        printf("%s, ", p);
}

但是,我没有得到预期的行为。 array [1]包含garbage,array [2]包含null。

2 个答案:

答案 0 :(得分:2)

基于http://man7.org/linux/man-pages/man3/scanf.3.html
例如,有

char *p;
n = scanf("%m[a-z]", &p);

我认为你应该改变你的

sscanf(p, "%m[?a-zA-Z] %[^\n]", array[i], p);

sscanf(p, "%m[?a-zA-Z] %[^\n]", &array[i], p);

了解%mchar **的搭配方式与char*的搭配方式。

我建议您阅读THIS讨论。

我还注意到你的pchar *,你用字符串常量初始化它,然后尝试通过调用sscanf来覆盖它。

除此之外,您在同一个函数调用中读取和写入内存p。我不是100%肯定在这里,但那可能是未定义的行为。

希望它有所帮助。

答案 1 :(得分:1)

你有几个问题。其中zubergu answer正确诊断出两个:{1}通过char *需要char **(见scanf()),以及(2)试图覆盖你正在扫描的字符串,它首先是readonly,并且在任何情况下都会调用未定义的行为。

另一个原因是你没有从sscanf()检查退货状态。你可能需要这样的东西:

char *p = "select ?Y ?Z where condition";
char *array[2];

p += strlen("select");

for (int i = 0; i < 2; i++)
{
    int offset;
    if (sscanf(p, " %m[?a-zA-Z]%n", &array[i], &offset) != 1)
        ...report error and break loop...
    printf("%s, ", array[i]);
    p += offset;
}

注意转换规范之前的空白以跳过前导空格。

如果您的sscanf()版本支持该表示法,则此代码应该可以正常运行:

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

int main(void)
{
    char *p = "select ?Y ?Z where condition";
    char *array[2] = { 0, 0 };
    int i;
    int j;

    p += strlen("select");

    for (i = 0; i < 2; i++)
    {
        int offset;
        printf("p = <<%s>>\n", p);
        if (sscanf(p, " %m[?a-zA-Z]%n", &array[i], &offset) != 1)
            break;
        printf("%d: <<%s>> (offset = %d)\n", i, array[i], offset);
        p += offset;
    }
    printf("%d: all done\n", i);

    for (j = 0; j < i; j++)
        free(array[j]);
    return 0;
}

Mac OS X 10.9不支持m修饰符;老版本的Linux也没有(注意自己:必须更新可用的VM)。在Ubuntu 12.04衍生产品上测试时,我得到了输出:

p = << ?Y ?Z where condition>>
0: <<?Y>> (offset = 3)
p = << ?Z where condition>>
1: <<?Z>> (offset = 3)
2: all done