2017-01-07 2 views
-3

Я написал программу, которая читает командную строку со стандартного ввода и передает ее функции, которая должна анализировать ее в токенах.Почему моя функция синтаксического анализа не возвращает все ожидаемые маркеры?

Это функция парсинга:

char** parse_cmdline(char* cmdline) { 
    char ** arr = malloc(10 * sizeof(char*)); 
    for (int i =0 ; i < 10; ++i) 
     arr[i] = malloc(30 * sizeof(char)); 
    char * token = strtok(cmdline, " "); 
    int i = 0; 
    while(token != NULL) { 
     if(i > 9) arr = realloc(arr, (i+10)*sizeof(char*)); 
     arr[i] = token; 
     token = strtok(NULL, " "); 
     i++; 
    } 
    printf("flag1"); 
    return arr; 
} 

И это, как я использую это его main():

int main() { 
    int status; 
    pid_t pid; 
    pid = fork(); 

    while(1) {  
     if(pid < 0) { 
      status = -1; 
      perror("Fork"); 
     } else if(pid == 0) { 
      char* cmd; 
      printf("$"); 
      if(fgets(cmd, sizeof cmd, stdin) == NULL) break; 
      parse_cmdline(cmd); 
     } else { 
      if(waitpid(pid, &status, 0) != pid) { 
       status = -1; 
      } 
      break; 
     } 
    } 


    return 0; 
} 

Это пример ввода, который Я поставляю к моей программе:

ls l a 

Ожидаемый результат должен быть:

l 

(то есть, второй аргумент, напечатанный на моей функции синтаксического разбора)

И буквально ничего не происходит. Даже printf («флаг1»); печать. Но если я удалю char ** commands и поместил printf("%s", commands[0]); в функцию parse_cmdline, все будет работать, за исключением того, что im не назначит возврат. Почему и как это исправить?


В соответствии с просьбой, вот полнота моего кода:

#include <stddef.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 

char** parse_cmdline(char* cmdline) { 
    char ** arr = malloc(10 * sizeof(char*)); 
    for (int i =0 ; i < 10; ++i) 
     arr[i] = malloc(30 * sizeof(char)); 
    char * token = strtok(cmdline, " "); 
    int i = 0; 
    while(token != NULL) { 
     if(i > 9) arr = realloc(arr, (i+10)*sizeof(char*)); 
     arr[i] = token; 
     token = strtok(NULL, " "); 
     i++; 
    } 
    printf("%s\n", arr[1]); 
    return arr; 
} 
+0

Опубликовать минимальный, полный, поддающийся проверке пример. – EOF

+0

Что еще вам нужно? –

+0

Что-то, что я могу вставить в файл и скомпилировать, плюс вход, который я могу подключить к результату компиляции. Возможно, вывод я могу сравнить с выходом программы. – EOF

ответ

1

Эта часть выглядит странно - видеть комментарии инлайн:

char ** arr = malloc(10 * sizeof(char*)); 
for (int i =0 ; i < 10; ++i) 
    arr[i] = malloc(30 * sizeof(char));  // Here you allocate memory 
              // for holding a part of the command 

char * token = strtok(cmdline, " "); 
int i = 0; 
while(token != NULL) { 
    if(i > 9) arr = realloc(arr, (i+10)*sizeof(char*)); 

    arr[i] = token;    // But here you overwrite the pointer value and 
           // and thereby create a memory leak 

    token = strtok(NULL, " "); 
    i++; 
} 

Возможно, вы хотели бы сделать струнную копию вместо этого - как:

strcpy(arr[i], token); // Instead of arr[i] = token; 

Далее эта линия кажется странным:

if(i > 9) arr = realloc(arr, (i+10)*sizeof(char*)); 

Вы увеличиваете arr, так что оно может содержать больше char*, но это t ime вы не выделяете память для новых строк, как вы это делали вначале.

0

Во-первых, вы не выделять места для команды. Измените объявление о cmd к чему-то вроде этого:

char cmd[100]; 

Не выделение памяти вызывает неопределенное поведение, и это (а также при правильном использовании fgets исправления этого). Но вы должны также проверить с fgets(), если 100 символов были достаточно:

if (strstr(cmd, "\n") == NULL) { 
    /* the user typed more than 100 characters */ 
} 

Потому что, если они не были достаточно, то вы собираетесь разобрать неполную командную строку и, в следующий раз, когда ваш цикл перебирает входные данные, он будет разбирать более неполные команды.

Наконец, strtok возвращает указатели на маркеры вcmd, так что все эти символы массива вы выделили в начале вашей функции синтаксического анализа были утечки памяти, потому что вы заменили их с указателями от strtok внутри цикла:

arr[i] = token; 
/* this throws away the address of the 10-character array you allocated 
* at the beginning of the function. You can't free() that memory 
* anymore. Your program is "leaking" memory. */ 

Строго говоря, кстати, вы должны проверить, возвращается ли realloc действительный адрес или NULL. malloc тоже. Маловероятно, что у вас будут проблемы с этим в такой небольшой программе, но это правильная практика.

Вы также должны утилизировать разобранные команды, как только вы их использовали. Вы выделяете массив указателей с malloc и realloc, но вы никогда не делаете free их в своей программе. Несмотря на то, что программа скоро закончится, пока программа запущена, это утечка памяти. (Опять же, вряд ли вы увидите проблемы с небольшой программой, но это хорошая практика.)

Смежные вопросы