2013-03-21 2 views
8

사용자가 입력 한 인수를 execvp()에 전달하려고합니다.사용자 입력에서 execvp()에 배열 전달

지금까지 문자열을 분할했습니다. 사용자가 ls -a을 입력하면 temp은 "ls"로 저장되고 "-a"다음에 NULL 문자가 저장됩니다. 나는 정확히 이것을 execvp에 가리키는 방법을 잘 모르겠습니다. 예제에서는 execvp(temp[position], temp)을 사용하여 보았습니다. 나는 그 순간에 그것을하려고하는 방법이 잘못되었다는 것을 알고 있습니다. 그러나 나는 그것을 올바르게하는 방법을 잘 모릅니다! 지금은 세분화 오류가 발생합니다.

int main(int argc, char *argv[]) 
{ 
    char line[124]; 
    int size = 124; 
    char *temp = NULL; 

    while(fgets(line, size, stdin) != NULL) { 
     if (strcmp(line, "exit\n") == 0) { 
      exit(EXIT_SUCCESS); 
     } 
     temp = strtok(line, " "); 
     while (temp != NULL) { 
      printf("%s\n", temp); 
      temp = strtok(NULL, " "); 
     } 
     execvp(temp, &temp);  
    } 
    return EXIT_SUCCESS; 
} 
+2

'argc' 또는'argv'를 사용하지 않으므로'int main (void)'를 사용할 수 있습니다. 필자는 습관적으로 사용하는 컴파일러 옵션으로 몇 가지 경고를 방지합니다. –

+0

@JonathanLeffler 나중에 사용하겠습니다. 지금은이 시점에 있지 않습니다. – caerulean

+1

충분하지만 - SSCCE ([짧은, 자체 포함, 올바른 예 (http://sscce.org/)])의 경우, 축소 된 예제에 중요하지 않은 모든 것을 제거하려고 노력합니다. 사소한 문제입니다. 아주 미미합니다. 대부분의 프로그램은 당신보다 저격에 훨씬 더 많은 기회를 제공합니다. –

답변

6

문제는 temp이 단일 포인터이므로 execvp()에 대한 포인터 배열을 전달해야한다는 것입니다.같은

뭔가 : 인수 목록은 단지 main()에서 argv[argc] == NULL처럼 터미네이터로 널 포인터를받은 것을

enum { MAX_ARGS = 64 }; 
    char *args[MAX_ARGS]; 
    char **next = args; 

    temp = strtok(line, " "); 
    while (temp != NULL) 
    { 
     *next++ = temp; 
     printf("%s\n", temp); 
     temp = strtok(NULL, " "); 
    } 
    *next = NULL; 
    execvp(args[0], args); 

참고. 분명히, 나는 오류 검사 (만약 당신이 63 ​​개 이상의 인수를 넘겨 준다면, args 배열을 오버 플로우시킬 것이다)를 생각해 보지 않았다. 그러나 여기에는 핵심 아이디어가 포함되어 있습니다. 이 예제와


, 내가 일을 ls의 간단한 명령을받을 수없는 것, 내가 mkdirecho 시도하고 그들이 잘 작동하는 것 같다. ls을 전달하면 execvp()에서 -1이 반환됩니다.

나는 문제가 무엇인지 잘 모르겠어요 - 나를 위해이 모든 작업을 :

  • ls
  • ls -l
  • ls -l madump.c (madump.c이 디렉토리에있는 파일 될 일이 어디 내가 테스트 중이 야)

코드는 다음과 같습니다.

나는 그것의 이름 끝에 줄 바꿈이있는 디렉토리를 생성 한 후, strtok() 토큰 목록에 \n을 추가
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 

int main(void) 
{ 
    char line[1024]; 

    while (fgets(line, sizeof(line), stdin) != NULL) 
    { 
     if (strcmp(line, "exit\n") == 0) 
      exit(EXIT_SUCCESS); 

     char *args[64]; 
     char **next = args; 
     char *temp = strtok(line, " \n"); 
     while (temp != NULL) 
     { 
      *next++ = temp; 
      printf("%s\n", temp); 
      temp = strtok(NULL, " \n"); 
     } 
     *next = NULL; 

     puts("Checking:"); 
     for (next = args; *next != 0; next++) 
      puts(*next); 

     execvp(args[0], args); 
    } 

    return EXIT_SUCCESS; 
} 

참고. 성가신 친구들과 교묘 한 반 (半) 교육 수준의 적들에게는 좋지만 다른 대부분의 관점에서는 불쾌합니다. 실제로 그렇게하기 전에 execvp()으로 전달 될 데이터를 어떻게 출력하는지 주목하십시오. 종종 puts() 대신 printf("<<%s>>\n", *next);을 사용하여 인수의 시작 및 끝 위치를 명확하게 나타낼 수 있습니다.

명령 (doit)를 실행의 출력했다 :

$ ./doit 
ls -l madump.c 
ls 
-l 
madump.c 
Checking: 
ls 
-l 
madump.c 
-rw-r--r-- 1 jleffler staff 2352 Jul 28 2011 madump.c 
$ 
당신이 당신의 버전 거죠 무엇

?

+0

execvp를 호출하기 전에 arg에 temp에 무엇이든 추가 할 필요가 없습니까? – caerulean

+1

('args에'temp '에있는 내용을 추가하는 것)은'next'를 통해 수행되고 있습니다. 처음에'* next'는 args [0]을 가리 킵니다; 'temp'의 값은'args [0]'에 복사되고'next'는'args [1]'을 가리 키도록 증가됩니다; 헹구고 반복하십시오. 덧붙여 말하자면, 코드에'fork()'도있을 것입니다. 그렇지 않으면 명령이 처음 성공적으로 실행될 때 프로그램이 멈추게됩니다. –

+0

args 배열을 현재 16 크기로 유지했습니다. 이 작업을 얻은 후에는 여러 프로세스를 처리 할 수 ​​있도록 fork()를 구현할 것입니다. – caerulean

1

나는 execvp에 NULL 포인터를 전달하기 때문에 segfault를 추측하고 있습니다. 호출 바로 위의 루프가이를 보장합니다.

지금하려는 작업을 수행하려면 현재 temp이라고하는 문자열 포인터의 배열을 만들어야합니다. 호출하는 프로그램의 배열은 argv이됩니다. 그래서 명령은 대개 프로그램 이름 인 execvp (temp[0], temp) - argv[0]으로 사용됩니다.

따라서 문자열 포인터의 배열을 만들고 각각이 line의 토큰 화 된 단어를 가리 키도록하십시오. 영리를 원한다면 직접 line을 가리킬 수도 있지만 malloc을 사용해야 할 수도 있습니다. 그렇게한다면, '단어'가 나오는 즉시 문자를 \0으로 설정해야합니다.

2

while(temp != NULL) 완료 후 코드가 현재 보이는 것처럼 temp은 NULL입니다!

execvp 인수는 새로운 화상 처리 할 파일의 경로가 될 것으로 예상하고있다. 두 번째 인수는 NULL로 끝나는 문자열의 배열로 예상되며 해당 배열의 마지막 멤버는 NULL 포인터이고 첫 번째 멤버는 첫 번째 인수에 지정된 파일의 파일 이름입니다.

고려, 코드 대신 다음 while 루프이를 구현하려면 :

char **argList = NULL; 
unsigned int numArgs = 0; 
while (temp != NULL) { 
    numArgs++; 

    /* Reallocate space for your argument list */ 
    argList = realloc(argList, numArgs * sizeof(*argList)); 

    /* Copy the current argument */ 
    argList[numArgs - 1] = malloc(strlen(temp) + 1, 1); /* The +1 for length is for the terminating '\0' character */ 
    snprintf(argList[numArgs - 1], strlen(temp) + 1, "%s", temp); 

    printf("%s\n", temp); 
    temp = strtok(NULL, " "); 
} 

/* Store the last NULL pointer */ 
numArgs++; 
argList = realloc(argList, numArgs * sizeof(*argList)); 
argList[numArgs - 1] = NULL; 

/* Finally, pass this to execvp */ 
execvp(argList[0], argList); 
/* If you reach here, execvp() failed */ 

I (예 : realloc 또는 malloc가 실패 할 때와 같은) 일부 오류 검사를하지 않습니다 위에 제공된 코드를하지만, 기본적으로 유지 마음에 이러한 점 :

  1. 인수 1 : 경로 이름 메모리에 넣어 것입니다 파일의.
  2. 인수 2 : 목록의 첫 번째 구성원 = 파일 이름, 마지막 멤버 = NULL 포인터의 인수는입니다.

좀 더 명확하고 간단한 예를 보려면 the documentation을 확인하십시오.

+0

'temp'가'line' 배열의 부분을 가리 키기 때문에 문자열을 복사 할 필요가 없습니다. 문자열을 복사한다면'strdup()'를 사용하는 것이 좋습니다. 'snprintf()'는 흥미 롭습니다. 명시 적'\ 0'은 실제로 불필요합니다. 이미 어쨌든 끝에는 null이 될 것입니다. 마지막'sprintf()'는 당신이 생각하는대로하지 않습니다. ''\ 0 ''에 충분한 공간 만 할당 한 변수에'(null)'과 같은 문자열을 쓰거나 충돌을 일으킨다. –

+0

오 와우,'strdup()'에 대해서는 전혀 몰랐습니다. 대신 그걸 사용하는 것이 훨씬 깔끔해 보입니다. 오, 그래'snprintf()'는 '\ 0'을 복사합니다. 나는 당신의 마지막 요점을 이해하지 못했습니다. 실제로, 나는'strlen ((char *) 0)'= 크래시를 깨달았다. '(char *) 0' ='(null)'그래서 저는 메모리를 할당하는 방법을 알지 못합니다. 어떤 제안? –

+0

마지막 루프 후 sprintf() 대신'argList [numArgs - 1] = NULL;'(또는'NULL' 대신에'0')을 사용하십시오. 배열의 마지막 값은 널 포인터 여야합니다. 이론적으로 메모리 할당이 성공했는지 확인해야합니다. 또한, 코드를 조금 더 어렵게 만들지 만, 한 번에 한 블록 씩 증가 시키면 2 차 동작을 피하기 위해 (예 : 한 번에 64 개 포인터) 블록에서 'argList'를위한 메모리를 할당하는 것이 좋습니다 . 그러나, 그것은 나중에 세련됩니다. –