我正在编写一个函数,该函数读取字符串中的所有连续空格,将指针移动到下一个非空白字符,并返回包含它找到的空白的结构"token“。
主要功能被定义为
int match_ws(const char** p, struct token* tok)其中,p指向要分析的字符串的开头,tok将在函数返回后包含结果。返回值要么是1(成功),要么是0。
match_ws开始分析作为第一个输入的字符串,并读取所有连续的空白空间,同时也推进指针。它存储它在struct中找到的所有空白(第二个输入)并返回1。如果没有找到任何空白,或者没有找到太多空白,则返回0而不修改tok。
因此,如果输入是const char* p = " . +",那么在match_ws运行之后,tok结构将包含lexeme = " " ( p开头的四个空格,以及type = WS (“空格”的枚举类型)。如果输入是const char* p = ". ; )",则函数只返回0而不修改tok,因为**p不是空格(它是一个点)。
总的来说,这是解析器的一部分,match_ws是“消耗”所有空白空间的函数--与解析器无关。我相信这个函数的行为是正确的,但是由于我对C语言没有经验,所以我想了解一下如何处理内存分配、指针、指针指针、函数定义等问题。
总的来说,我的问题涉及指针的正确使用、指针到指针的正确使用、参数类型(函数定义)的良好选择以及内存管理。
我在评论中写了我的问题,但我不太习惯C中的内存管理和编码标准,所以我希望能对代码进行审查,并欢迎所有建议。
我还添加了一些样板代码,以便可以编译和执行文件。您可以猜到,它是较大代码的一部分,但我将其简化为一个最小的示例。
#include
#include
#define MAX_LINE 100
/*
* Some boilerplate code
*/
enum token_type {
WS, // white spaces
Eof
};
struct token{
char* lexeme;
enum token_type type;
};
char consume(const char** p);
/*
* Main function to work on.
* Questions:
* - char ws[MAX_LINE] or using malloc?
* - is it OK to initialize char ws with "" ?
* - Am I appending char into ws in a optimal way?
* - is it OK to return int and modify input argument tok, or should create a new tok and return it?
* - makes sense to have pointer-to-pointer as input? Else what?
*/
int match_ws(const char** p, struct token* tok) {
/*
* Find all consecutives blanks starting from position p
* Modify the input struct token.
* Return 1 if execution was successful, 0 otherwise.
*/
if ( **p != ' ' &&
**p != '\t' &&
**p != '\r' &&
**p != '\n')
{
printf("Bad call to whitespace!!");
return 0;
}
int i = 0;
char c;
char ws[MAX_LINE] = "";
do {
if (i >= MAX_LINE) {
printf("Found more than %d white spaces", MAX_LINE);
return 0;
}
c = consume(p);
printf("WHITESPACE : Current char is |%c|\n", c);
ws[i++] = c;
}
// Here p has been already advanced by the call to consume fn
while (**p == ' ' || **p == '\t' || **p == '\r' || **p == '\n');
tok->lexeme = ws;
tok->type = WS;
return 1;
}
/*
* More boilerplate code to compile
*/
const char* type2char (enum token_type t) {
switch (t)
{
case WS: return "WS";
default: return "UNK";
}
}
void print_token(struct token* p) {
printf("<%s, %s>\n", p->lexeme, type2char(p->type));
}
char consume(const char** p) {
// Advances the pointer while reading the input
char c = **p;
(*p)++;
return c;
}
/*
* Main.
* Questions:
* - is it OK to pass arguments to match_ws via '&' notation?
* - Makes sense to have const char* line? Or just char* ?
* - Should tok be initialized somehow?
* - Is there anything that has to be free() eventually?
*/
int main() {
const char* line = " +";
struct token tok;
match_ws(&line, &tok);
print_token(&tok);
}发布于 2022-07-15 21:19:44
问题的回答
char ws[MAX_LINE]还是使用malloc?函数match_ws()应该返回指向struct token的指针。令牌应该由match_ws()函数分配,令牌的内容也应该使用malloc()来分配token->lexeme指向的字符串。现在,代码返回堆栈上一个变量的地址,这是不安全的,可能导致undefined行为 (UB)。
ws初始化char D19可以吗?用""初始化char数组是可以的。若要初始化单个字符,请使用单引号。
char添加到ws中?使用指针将是更理想的。
int和修改输入参数tok可以吗?还是应该创建一个新的tok并返回它?见第一个问题的答案。
与其使用双指针,不如使用单个指针。当输入是双指针时,可能会损坏它。
match_ws可以吗?如果不想在函数中分配令牌,则使用&标记传递令牌参数是可以的,最好不使用&标记传递D56。
const char*线有意义吗?还是只有char*?在这里使用const是合适的。
tok吗?C编程语言是一种非常不可原谅的编程语言:所有变量都应该初始化。
free()的吗?不是在目前的实现中。
在C编程语言中,检查输入字符的值是非常常见的;为检查空格提供了一个函数,为检查字母数字字符提供了另一个函数。您需要做的是包括。这样做的好处是,当前代码可能遗漏了一些isspace()会找到的空白字符。
函数原型在包含多个源文件的大型程序中非常有用,如果它们位于头文件中,则非常有用。在这样的单个文件程序中,最好将main()函数放在文件的底部,并以高于main()的适当顺序使用所有函数。请记住,编写的每一行代码都是另一行代码,bug可以在这一行代码中爬行。
https://codereview.stackexchange.com/questions/214162
复制相似问题