将一行解析为*** char时出现段错误

时间:2014-11-23 17:05:34

标签: c parsing pointers char segmentation-fault

我的代码应该将一个字符数组解析成*** char,这样它首先将它分成'|' char,然后用空格,换行符等字。样本i / o:

I = ls -l | sort | unique

O =

  *cmds[1] = {"ls", "-l", NULL};
  *cmds[2] = {"sort", NULL};
  *cmds[3] = {"unique", NULL};

上面是char数组的指针,所以用词分开然后在下面是*** char,指向上面的指针

  char **cmds[] = {1, 2, 3, NULL};

现在,我没有看到我的错误(可能是因为我不熟练使用C语言),但是程序给了segfault第二个我从parsePipe()里面调用parse(..)函数。有人可以帮忙吗?

void parse(char *line, char **argv)
{
        while (*line != '\0') {     
        while (*line == ' ' || *line == '\t' || *line == '\n')
            *line++ = '\0'; 
        *argv++ = line;     
        while (*line != '\0' && *line != ' ' && *line != '\t' && *line != '\n'){
            line++;
        }
    }
    *argv = '\0';  
}

void parsePipe(char *line, char ***cmds)
{
    char *cmd = strtok(line, "|");
    int word_counter = 0;

    while (cmd != NULL) 
    {
       printf("Printing word -> %s\n", cmd);
       word_counter++; 
       parse(cmd, *cmds++);

       cmd = strtok(NULL, "|");
    }

    printf("This string contains %d words separated with |\n",word_counter);
}


void  main(void)
{
    char  line[1024];          
    char  **cmds[64]; 
    while (1) {    
        printf("lsh -> ");   
        gets(line);     
        printf("\n");
        parsePipe(line, cmds);
    }
}

1 个答案:

答案 0 :(得分:1)

[评论太久了]

这一行

*argv++ = line; /* with char ** argv */

指无效内存,因为代码*argv[n](带有char **argv[64])没有引用任何内容。

你使用的命名不会让生活更轻松。

尝试以下命名:

void parse(char *line, char **cmd)
{
    while (*line != '\0') {     
        while (*line == ' ' || *line == '\t' || *line == '\n')
            *line++ = '\0'; 
        *cmd++ = line;     
        while (*line != '\0' && *line != ' ' && *line != '\t' && *line != '\n'){
            line++;
        }
    }
    *argv = '\0';  
}

void parsePipe(char *line, char ***cmdline)
{
    char *cmd = strtok(line, "|");
    int word_counter = 0;

    while (cmd != NULL) 
    {
       printf("Printing word -> %s\n", cmd);
       word_counter++; 
       parse(cmd, *cmdline++);

       cmd = strtok(NULL, "|");
    }

    printf("This string contains %d words separated with |\n",word_counter);
}


void  main(void)
{
    char  line[1024];          
    char  **cmdline[64]; 
    while (1) {    
        printf("lsh -> ");   
        gets(line);     
        printf("\n");
        parsePipe(line, cmdline);
    }
}

由于没有分配cmd已用过的内存。

所以

*cmd++ = line;

失败,因为cmd没有任何意义,但是被取消引用并且代码试图写入它所指向的地方,这是无处可去的,即无效的内存。


通过将char***传递给parse(char *** pcmd)并计算找到的代币,可以解决此问题

size_t nlines = 0;

...

++nlines.

和做一个

*pcmd = realloc(*pcmd, nlines + 1); /* Allocate one more as needed to later find the end of the array. */
(*pcmd)[nlines -1] = line;
(*pcmd)[nlines] = NULL; /* Initialise the stopper, marking the end of the array. */

找到每个令牌。

显然你需要这样称呼它:

 parse(cmd, cmdline++);

为了完成所有这些工作,初始化数组需要正确初始化(正如你应该做的那样):

char  **cmdline[64] = {0};