C语言 试图在非堆对象上调用free,但在堆对象上出现警告

kxe2p93d  于 2023-03-17  发布在  其他
关注(0)|答案(1)|浏览(172)

我用C编写了一个简单的解析器作为赋值语句,并且我试图尽可能多地重用上一个解析器中的代码。
令牌:

typedef struct token {
    const char *lexeme;   //the actual string value of the token
    Category category;  //the category of the token
} Token;

Token create_token(const char *lexeme, Category cat) {
    Token token = {.lexeme = lexeme, .category = cat};
    return token;
}

自动装置:

typedef struct automata {
    //does not directly store token but is easy to retrieve
    Category token_type;    //which type of token is the automata supposed to scan
    char *scanned;  //char buffer to store read characters from a string. Not realloced because it's been given reasonable capacity

    int lexeme_capacity;    //capacity of scanned buffer. Dynamic change is not implemented, all tokens should be at most this length
    ...
} Automata;

Automata create_automata(int num_states, char *accepted_chars,
                         int num_accepted_states, const int *accepted_states,
                         Category token_type) {
    ...
    //create and return an automata
    Automata automata = {
            .token_type = token_type,
            //TODO malloc returns an allocated pointer so it is not null but it must take into account possible overflows
            .scanned = malloc(DEFAULT_LEXEME_LENGTH * sizeof(char)),
            .lexeme_capacity = DEFAULT_LEXEME_LENGTH,
            ...
    };

    return automata;
}

Token get_token(Automata *automata) {
    // if automata is not in accepting state, it did not recognize the lexeme
    Category category = accept(automata) ? automata->token_type : CAT_NONRECOGNIZED;

    // easy to understand if written like this
    Token value = {
            .lexeme = automata->scanned,
            .category = category,
    };

    return value;
}

据我所知,我使用get_token函数创建的任何令牌都将包含一个char *来堆内存,这在我之前的任务中运行良好。
作为当前赋值语句的一部分,我希望能够从文件中读取令牌,因为我不能让令牌只包含指向文件数据的指针,所以我创建了以下函数来直接从堆栈内存中创建令牌:

Token allocate_token(const char *lexeme, size_t lexeme_len, Category cat) {
    //allocate and copy into heap memory the contents of the lexeme string
    char *heap_allocated = calloc(lexeme_len + 1, sizeof(char));
    memcpy(heap_allocated, lexeme, lexeme_len * sizeof(char));

    //create and return a token
    return create_token(heap_allocated, cat);
}

void free_token(Token *token) {
    free(&token->lexeme);
}

然而,CLion警告说free_token函数“试图在非堆对象'lexeme'上调用free”,我不明白lexeme为什么不是一个堆分配指针。
我想知道我是否遗漏了什么或不理解什么,或者我是否可以忽略这个警告。

tcomlyy6

tcomlyy61#

如果您调用free(token->lexeme),编译器应该报告您使用const限定指针调用free,这是不正确的,因为free需要char *参数。
确保使用指向已分配内存的指针调用free是您的责任,但是将其存储到const char *会使跟踪对象生存期以及区分指向堆对象的指针和指向常量数据(如字符串文本)的指针变得更加困难。
如果lexeme指向的字符串要由free释放,则它的类型应为char *,并且必须确保lexeme始终设置为NULL或设置为指向token结构所拥有的已分配内存的指针,即:只能由free_token()释放。这可能意味着使用strdup() to ensure the标记owns its lexeme '复制字符串。

编辑:

从你更新的问题中,free_token调用free(&token->lexeme);。这是错误的。你传递了结构项的地址而不是它的值。你可能已经添加了这个额外的&作为另一个编译器错误的修复,上面的解释应该会给予你一些提示。

相关问题