2009-08-24 2 views
3

Я пытаюсь создать программу, которая предложит пользователю команду, а затем использовать exec для выполнения этой команды.Пытается использовать execvp() в C с пользовательским входом в unix

Например, если бы они дали мне «ls -la», мне пришлось бы выполнить эту команду. Я попытался следующий код:

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 

int main() 
{ 

    int ret, num_args; 

    printf("Enter number of arguments (Example: \"ls -la\" has 1 argument): "); 
    scanf("%d", &num_args); 

    char *cmd[num_args]; 

    printf("Enter command name: "); 
    scanf("%s", &cmd[0]); 

    int i; 
    for (i = 0; i < num_args; i++) 
    { 
      printf("Enter parameter: "); 
      scanf("%s", &cmd[i]); 
    } 

    execvp(cmd[0], cmd); 
} 

Однако, когда я попытался следующий прогон он дал мне «ошибку сегментации»

$ ./a.out 
Enter number of arguments (Example: "ls -la" has 1 argument): 2 
Enter command name: ls 
Enter parameter: -la 
Enter parameter: . 
Segmentation fault 
$ 

Любые идеи?

ответ

3

Если ваша реализация поддерживает его, вы должны использовать более безопасный getline() вместо этого на scanf() или fgets(). getline() будет безопасно обрабатывать длинные строки и символы NULL. Он будет выделять достаточно памяти для соответствия всей линии. getline() может выделять память, поэтому вам придется освободить ее самостоятельно позже.

Адрес glibc getline() documentation.

Вот быстрое изменение использовать GetLine (Он по-прежнему нуждается в работе, проверку на наличие ошибок, и я полностью не проверил правильность пока):

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 

int main() 
{ 

    printf("Enter number of arguments (Example: \"ls -la\" has 1 argument): \n"); 

    char *num = NULL; 
    size_t sz = 0; 
    getline(&num, &sz, stdin); 

    int num_args; 
    sscanf(num, "%d", &num_args); 

    char *cmd[num_args+2]; 
    memset(cmd, 0, sizeof(char*) * (num_args+2)); 

    printf("Enter command name: \n"); 


    int len = getline(&cmd[0], &sz, stdin); 

    cmd[0][len-1] = '\0'; 

    int i; 
    for (i = 1; i < num_args+1; i++) 
    { 
     printf("Enter parameter: \n"); 
     sz = 0; 
     len = getline(&cmd[i], &sz, stdin); 
     cmd[i][len-1] = '\0'; 
    } 

    return execvp(cmd[0], cmd); 

} 
+0

Компилятор, похоже, не знает, что такое getline, это из-за отсутствия строки #include или только самого компилятора? – 2009-08-24 01:04:16

+0

'getline' - это функция GNU в C: http://www.gnu.org/s/libc/manual/html_node/Line-Input.html –

+0

Какой компилятор и какая операционная система? –

1

Вы фактически не выделили память для строк, на которые указывает массив cmd.

+1

Итак, как именно я это сделал? – 2009-08-24 00:30:37

+1

Посмотрите malloc/бесплатно и убедитесь, что каждому указателю в «cmd» выделено достаточно места. –

2

Кроме того, вам нужна еще одна запись в argv, которую вы переходите на номер execvp, который должен быть (char *)NULL, чтобы сообщить ему, что он достиг конца списка.

+0

И еще один для argv [0], который является именем команды (обычно). –

3

Вам необходимо выделить память для своих строк. Следующая строка только выделяет num_args ценность указателей на char:

char *cmd[num_args]; 

Прежде всего, вы будете получать num_args + 1 строки (не стоит забывать, что сама команда cmd[0]). Самый простой способ заключается в статический выделить память как массив символов буфера:

const unsigned int MAX_LEN = 512; // Arbitrary number 
char cmd[num_args + 1][MAX_LEN]; 

Однако теперь вы не можете использовать scanf для чтения в строке, так как может пользователь ввести строку, которая длиннее, чем ваш буфер символов , Вместо этого, вы должны будете использовать fgets, которые могут ограничить количество символов, пользователь может ввести:

fgets(cmd[i], MAX_LEN, stdin); 

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

+0

Попытка этого способа дала мне кучу ошибок компилятора. Это говорит cmd [num_arghs + 1] [MAX_LEN]; неверно: «синтаксическая ошибка до»; » – 2009-08-24 00:55:42

+0

@Nick Double проверьте свой код; Я написал небольшую тестовую программу, и она скомпрометирована для меня. –

+0

Woops, я забыл точку с запятой на строке 'MAX_LEN = 512'. Исправлено. –

-1

Взгляните на странице человека для зсапЕ (). Одна из самых простых вещей, которые он может сделать, - это автоматически выделять строковые буферы «на лету», вам нужно указать указатель на строку, а не просто передать строку и предоставить формат% as.

char *my_string; 
scanf("%as", &my_string); 

Тогда вам не нужно беспокоиться предварительное выделение, не нужно возиться с переполнением буфера и т.д. Только не забудьте освободить() это после того, как вы сделали с ним.

+0

Спецификация '% as' '- это не стандартное поведение С - полезно, хотя это может быть. –

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