C语言中产生segfaults的解析器
在过去的两个星期里,我一直在努力让它发挥作用,但没有任何效果。 我有一个项目要创建一个实现解析和内置命令的shell。我遇到的问题是,当我向解析函数传递一个char*时,它返回,当我试图访问它的任何部分时,我得到一个segfault。我尝试过不同的方法,包括一个包含字符**的结构,但都有相同的问题,所以我猜这是我的解析器的问题。我将感谢任何帮助。 parser.c的代码:C语言中产生segfaults的解析器,c,shell,parsing,C,Shell,Parsing,在过去的两个星期里,我一直在努力让它发挥作用,但没有任何效果。 我有一个项目要创建一个实现解析和内置命令的shell。我遇到的问题是,当我向解析函数传递一个char*时,它返回,当我试图访问它的任何部分时,我得到一个segfault。我尝试过不同的方法,包括一个包含字符**的结构,但都有相同的问题,所以我猜这是我的解析器的问题。我将感谢任何帮助。 parser.c的代码: #define BUFSIZE 1024 #define TOK_BUFSIZE 64 #define TOK_DELIM
#define BUFSIZE 1024
#define TOK_BUFSIZE 64
#define TOK_DELIM " \t\r\n\a"
char*** Parse(char *line0){
char* null_ptr = 0;
char*** cmd = malloc(MAX_SIZE * sizeof(char**));
/*
char arg[] = argument
char* argv[] = argument array
char** cmd[] = array of argument arrays
*/
int bufsize = MAX_SIZE, cmdp = 0, argp = 0, com = FALSE, redir = FALSE;
char *token;
char* line = malloc(100*sizeof(char));
strcpy(line,line0);
token = strtok(line, TOK_DELIM);
while (token){
if (*token == ';'){ // new command string
char* tmp1 = malloc(BUFSIZE * sizeof(char));
char** tmpa = malloc(BUFSIZE * sizeof(char*));
strcpy(tmp1, token);
tmp1[sizeof(token)] = null_ptr;
tmpa[0]=tmp1;
cmd[cmdp] = tmpa;
argp = 0;
cmdp++;
com = FALSE;
redir = FALSE;
}
else if (*token == '>' || *token == '<' || token == ">>"){ // redirects
argp = 0;
char* tmp1 = malloc(BUFSIZE * sizeof(char));
char** tmpa = malloc(BUFSIZE * sizeof(char*));
strcpy(tmp1, token);
tmp1[sizeof(token)] = null_ptr;
tmpa[argp]=tmp1;
argp++;
printf("Redirect: %s\n",tmp1);
com = FALSE;
redir = TRUE;
}
else if (*token == '|'){ // pipe
printf("PIPE\n");
cmdp++;
argp = 0;
com = FALSE;
}
else if (redir){ // redirect file name
// redirect token stored in arg[]
char* tmp1 = malloc(BUFSIZE * sizeof(char));
char** tmpa = malloc(BUFSIZE * sizeof(char*));
strcpy(tmp1, token);
tmp1[sizeof(token)] = null_ptr;
tmpa[argp]=tmp1;
cmd[cmdp]=tmpa;
argp = 0;
cmdp++;
redir = FALSE;
com = FALSE;
printf("File: %s\n", token);
}
else if (token == "&") // background
{
cmdp++;
argp = 0;
char* tmp1 = malloc(BUFSIZE * sizeof(char));
char** tmpa = malloc(BUFSIZE * sizeof(char*));
strcpy(tmp1, token);
tmp1[sizeof(token)] = null_ptr;
tmpa[0]=tmp1;
cmd[cmdp]=tmpa;
printf("Background");
}
else if (!com && !redir){ // command entered
argp = 0;
char* tmp1 = malloc(BUFSIZE * sizeof(char));
char** tmpa = malloc(BUFSIZE * sizeof(char*));
strcpy(tmp1, token);
tmp1[sizeof(token)] = null_ptr;
tmpa[argp] = tmp1;
argp++;
printf("Command %s\n", token);
com = TRUE;
}
else if (com){ // argument to command, all other redirects and pipes taken care of
char* tmp1 = malloc(BUFSIZE * sizeof(char));
char** tmpa = malloc(BUFSIZE * sizeof(char*));
strcpy(tmp1, token);
tmp1[sizeof(token)] = null_ptr;
tmpa[argp] = tmp1;
argp++;
printf("Argument: %s\n", token);
//cmd[cmdp] = argv; // save current working argument array
//cmdp++;
}
// end of if else statements
token = strtok(NULL, TOK_DELIM);
} // end of while
cmdp++;
cmd[cmdp] = NULL;
return &cmd;
}
#定义BUFSIZE 1024
#定义TOK_BUFSIZE 64
#定义TOK_DELIM“\t\r\n\a”
字符***解析(字符*line0){
char*null_ptr=0;
char***cmd=malloc(最大尺寸*sizeof(char**));
/*
char arg[]=参数
char*argv[]=参数数组
char**cmd[]=参数数组的数组
*/
int bufsize=MAX_SIZE,cmdp=0,argp=0,com=FALSE,redir=FALSE;
字符*令牌;
char*line=malloc(100*sizeof(char));
strcpy(第行,第0行);
令牌=strtok(线路,TOK_DELIM);
while(令牌){
如果(*token==';'){//new命令字符串
char*tmp1=malloc(BUFSIZE*sizeof(char));
char**tmpa=malloc(BUFSIZE*sizeof(char*);
strcpy(tmp1,令牌);
tmp1[sizeof(token)]=null\u ptr;
tmpa[0]=tmp1;
cmd[cmdp]=tmpa;
argp=0;
cmdp++;
com=假;
redir=FALSE;
}
else if(*token=='>'| |*token==='当我在命令行上通过键入以下内容编译代码时:
gcc /path/to/yourcodefilename.c -Wall -Wextra
但是将/path/to/yourcodefilename.c
替换为包含最终调用您函数的主函数的代码的实际文件名(我的文件是test2.c),我收到了警告。第一个警告是:
./test2.c:21: error: 'aaa' undeclared (first use in this function)
./test2.c:21: error: (Each undeclared identifier is reported only once
./test2.c:21: error: for each function it appears in.)
我收到了其中的一些。“aaa”替换为您在函数中使用的、以前未定义的名称。这包括单词TRUE和FALSE。要更正此问题,您可以在程序顶部使用:
#define FALSE n
#define TRUE y
其中n和y分别是表示false和true的数字。另一种更正方法是包含包含“true”和“false”定义的头文件
我在几行中注意到的第二件事是:
warning: assignment makes integer from pointer without a cast
确保不要将数据从一种类型转换为另一种类型。例如,不要将字符变量设置为指针值
例如,更改:
tmp1[sizeof(token)] = null_ptr;
致:
因为为char*
指定索引意味着指定char
,而null\u ptr属于char*
类型,char*
和char
不一样。我所做的是为char
分配了一个空值
当我在命令行上通过键入以下内容编译代码时,我希望这能帮助您解决一些疑难问题:
gcc /path/to/yourcodefilename.c -Wall -Wextra
但是将/path/to/yourcodefilename.c
替换为包含最终调用您函数的主函数的代码的实际文件名(我的文件是test2.c),我收到了警告。第一个警告是:
./test2.c:21: error: 'aaa' undeclared (first use in this function)
./test2.c:21: error: (Each undeclared identifier is reported only once
./test2.c:21: error: for each function it appears in.)
我收到了其中的一些。“aaa”替换为您在函数中使用的、以前未定义的名称。这包括单词TRUE和FALSE。要更正此问题,您可以在程序顶部使用:
#define FALSE n
#define TRUE y
其中n和y分别是表示false和true的数字。另一种更正方法是包含包含“true”和“false”定义的头文件
我在几行中注意到的第二件事是:
warning: assignment makes integer from pointer without a cast
确保不要将数据从一种类型转换为另一种类型。例如,不要将字符变量设置为指针值
例如,更改:
tmp1[sizeof(token)] = null_ptr;
致:
因为为char*
指定索引意味着指定char
,而null\u ptr属于char*
类型,char*
和char
不一样。我所做的是为char
分配了一个空值
我希望这能帮助您解决一些疑难问题这里有几个问题:
- 分配
cmd
及其子数组。在函数末尾向该数组返回一个地址。该地址的类型为char****
,这不是正确的返回类型。更糟糕的是:该地址是局部变量的地址,返回后立即超出范围。返回从中获得的句柄malloc
取而代之:
char ***Parse(char *line0)
{
char ***cmd = malloc(MAX_SIZE * sizeof(*cmd));
// fill cmd
return cmd;
}
- 您的代码过长,主要是因为您编写了分配内存、复制字符串和显式null终止的步骤。(其他人指出,您没有正确地执行null终止。您还按照实际字符串长度分配1024字节的固定大小,这是非常浪费的。)您可以编写一个函数来复制字符串,或者使用非标准但广泛可用的strdup,这将使您的代码更易于阅读
- 所有的临时分配都很难遵循。例如,在分支
中,如果(!com&&!redir)
,则分配给tmpa
,但从不将该值存储在cmd
中。重定向分支也是如此
- 还不清楚何时启动新命令。在解析第一个标记之前、遇到管道之后或遇到分号之后,应该有一个新命令。您还可以启动重定向和背景符号的新命令
- 比较
token==“>>”
将始终为假:token
是行中的地址,而“>”
是存储在静态内存中的字符串文字。您应该使用strcmp
来比较两个字符串
通常,当cmdp
增加时,您希望分配一个新列表。在这种情况下,argp
重置为零。否则,您只需附加到当前命令
我认为把每件事都当作特殊的事情来处理会使事情复杂化。我建议简化代码,暂时不考虑重定向和背景。它们可以很容易地解决