当我尝试从一串字符中获取一个数字时,该函数总是返回零

时间:2014-10-04 14:03:08

标签: c parsing pointers char

编辑:所以看起来问题是getNum应该转换为float的字符串实际上不是包含令牌的所有字符的字符串。相反,它包含紧跟在令牌之后的字符,通常是NaN,因此atof将其转换为0.我不确定为什么会出现这种情况。

我正在研究一种评估算术表达式的扫描仪+解析器。我正在尝试实现一个获取令牌(存储为字符串)的方法,该令牌是一个数字并将其转换为浮点数,但无论令牌是什么,它总是返回0。

我获得了get_character函数的代码,我不确定是否正确。我在解析它发生的事情时遇到了一些麻烦,所以我不确定:

int get_character(location_t *loc)
{
    int rtn;
        if (loc->column >= loc->line->length) {
        return 0;
    }
    rtn = loc->line->data[loc->column++];
    if (loc->column >= loc->line->length && loc->line->next) {
        loc->line = loc->line->next;
        loc->column = 0;
    }
    return rtn;
}

我在我的getNum()函数中使用它,假设它是正确的。它如下:

static float getNum(){
    char* tokenstr;
    tokenstr = malloc(tok.length * sizeof(char));

    int j;
    for(j = 0; j < tok.length; j++){
        tokenstr[j] = get_character(&loc);
    }
    match(T_LITERAL); /*match checks if the given token class is the same as the token
                        class of the token currently being parsed.  It then moves the
                        parser to the next token.*/
    printf("%f\n", atof(tokenstr));
    return atof(tokenstr);

}

以下是了解上述功能中所发生情况所需的一些其他信息。这些是有关组织输入数据的一些struct文件的详细信息。

为了存储和查找令牌,使用了三种类型的结构。 line_t结构,location_t结构和token_t结构。这些代码已发布,但总结一下:

  • 行包含一个字符数组(来自该行的输入) 输入文件),一个int为行的长度,一个int为 行号作为标识的形式,以及指向下一个的指针 读入内存的输入行。

  • 位置包含指向特定行的指针,以及一个int 指定该行的特定“列”。

  • 令牌包含一个用于令牌长度的int,一个描述令牌开始位置的位置,以及描述解析器所用令牌类型的令牌类。

这些结构的代码:

typedef struct line {
    char * data;
    int line_num;
    int length; /* number of non-NUL characters == index of trailing NUL */
    struct line * next;
} line_t;

typedef struct {
    line_t *line;
    int column;
} location_t;

typedef struct {
    token_class tc;
    location_t location;
    int length;     /* length of token in characters (may span lines) */
} token_t;

2 个答案:

答案 0 :(得分:0)

看来,默认行为是提取一个字符,然后在返回之前前进到下一个字符。

然而,如果超出行长度(或者匹配值未初始化为小于行长度),函数将前进。

试试这个:

if (loc->column >= loc->line->length) {
    loc->line = loc->line->next;
    loc->column = 0;
    return 0;
}

确保列位置已正确初始化。

就个人而言,我会将功能更改为:

int get_character(location_t *loc)
{
    int rtn = 0;

    if (loc->column < loc->line->length) {
        rtn = loc->line->data[loc->column++];
    }

    if (loc->column >= loc->line->length && loc->line->next) {
        loc->line = loc->line->next;
        loc->column = 0;
    }

    return rtn;
}

我还会为列和长度使用无符号值,只是为了避免负数组指示的可能性。

答案 1 :(得分:0)

我发现此代码存在许多潜在问题:

char* tokenstr;
tokenstr = malloc(tok.length * sizeof(char));

int j;
for(j = 0; j < tok.length; j++){
    tokenstr[j] = get_character(&loc);
}
match(T_LITERAL); /*match checks if the given token class is the same as the token
                    class of the token currently being parsed.  It then moves the
                    parser to the next token.*/
printf("%f\n", atof(tokenstr));
return atof(tokenstr);

您为新的令牌字符串tokenstr创建空间,您复制它但不会在之后终止它,也不会为令牌和字符串终结符\0分配足够的空间。并且最后有一个内存泄漏,因为tokenstr不是free。我可能会考虑更改类似的内容:

char* tokenstr;
float floatVal;

/* Make sure we have enough space including \0 to terminate string */
tokenstr = malloc((tok.length + 1) * sizeof(char));

int j;
for(j = 0; j < tok.length; j++){
    tokenstr[j] = get_character(&loc);
}
/* add the end of string \0 character */
tokenstr[j] = '\0'

match(T_LITERAL); /*match checks if the given token class is the same as the token
                    class of the token currently being parsed.  It then moves the
                    parser to the next token.*/

floatVal = atof(tokenstr);

/* Free up the `malloc`ed tokenstr as it is no longer needed */
free(tokenstr);

printf("%f\n", floatVal);
return floatVal;