我用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
为什么不是一个堆分配指针。
我想知道我是否遗漏了什么或不理解什么,或者我是否可以忽略这个警告。
1条答案
按热度按时间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);
。这是错误的。你传递了结构项的地址而不是它的值。你可能已经添加了这个额外的&
作为另一个编译器错误的修复,上面的解释应该会给予你一些提示。