2014-11-23 75 views
0

我的代码应该将一个字符数组解析为*** char,以便首先按'|'分割它。字符,然后通过空格,换行符等转换为单词。样品I/O:在将字符串解析成*** char时出现Seg错误

I = ls -l | sort | unique 

O =

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

是指向字符数组,由字,以便分裂,然后在下方是***炭与指针上述指针

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

现在,我没有看到我的错误(可能是因为我不熟悉C语言),但程序给出了段错误,第二次我从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); 
    } 
} 
+2

这是什么? 'char * 1 [] = {“ls”,“-l”,NULL};'你不能命名一个以数字开头的变量。 – Almo 2014-11-23 17:08:50

+0

这不是代码,它是一个示例I/O来展示它应该如何看起来像.. – user3885166 2014-11-23 17:10:34

+0

'argv'按照惯例是'char **'。不要把椅子称为桌子。 – alk 2014-11-23 17:13:13

回答

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++); 

要拥有这一切工作的inital阵列需要正确初始化(你应该无论如何做):

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

非常感谢,还有一件事 - 你使用realloc,我们不应该首先malloc变量?如果是这样,那么用什么,nlines = 0? – user3885166 2014-11-23 18:02:58

+0

@ user3885166:做'void * p = NULL; p = realloc(p,42);'和'void * p = malloc(1)一样。 p = reallc(p,42);'或者甚至是'void * p = realloc(NULL,42);' – alk 2014-11-23 18:04:48

+0

@ user3885166:对于'nlines = 0',你可以跳过'realloc'并且只给'NULL' '* pcmd'或者如果从头开始已经初始化为'NULL',则什么也不做。如果您的编译器支持,您也可以执行'(* pcmd)= realloc(pcmd,0);'但要注意,对于后一种情况,您需要调用'free(* pcmd)'。如果你定义了一个空的“* command *”,用'* pcmd = NULL'来表示,那就没有必要了。 – alk 2014-11-23 18:09:14