C语言中产生segfaults的解析器

C语言中产生segfaults的解析器,c,shell,parsing,C,Shell,Parsing,在过去的两个星期里,我一直在努力让它发挥作用,但没有任何效果。 我有一个项目要创建一个实现解析和内置命令的shell。我遇到的问题是,当我向解析函数传递一个char*时,它返回,当我试图访问它的任何部分时,我得到一个segfault。我尝试过不同的方法,包括一个包含字符**的结构,但都有相同的问题,所以我猜这是我的解析器的问题。我将感谢任何帮助。 parser.c的代码: #define BUFSIZE 1024 #define TOK_BUFSIZE 64 #define TOK_DELIM

在过去的两个星期里,我一直在努力让它发挥作用,但没有任何效果。 我有一个项目要创建一个实现解析和内置命令的shell。我遇到的问题是,当我向解析函数传递一个char*时,它返回,当我试图访问它的任何部分时,我得到一个segfault。我尝试过不同的方法,包括一个包含字符**的结构,但都有相同的问题,所以我猜这是我的解析器的问题。我将感谢任何帮助。 parser.c的代码:

#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
重置为零。否则,您只需附加到当前命令

我认为把每件事都当作特殊的事情来处理会使事情复杂化。我建议简化代码,暂时不考虑重定向和背景。它们可以很容易地解决