为什么getline()得到前一行?

时间:2015-02-09 13:27:27

标签: c input getline

bdoetsch@Kaladin:~/Documents/School$ ./shell
Shell(pid = 6955) 1> ls
command: ls
argv[i] = ls
argv[i] = ./shell
Parent says 'child process has been forked with pid=6956'
./shell
Parent says 'wait() returned so the child with pid=-1 is finished'
Shell(pid = 6955) 2> 

这是我正在做的功课,但我有点难过。

嗨,我正在尝试编写一个shell程序,我不明白为什么getline正在获得前面的输入行。

加上程序将执行'ls -al',pwd和其他一些程序。但不仅仅是ls。

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

int tokenizer(char *str,char **argv);
void doCommand(char **argv);

int main()
{
    pid_t pid;
    char *command;
    int Num_bytes_read;
    size_t nbytes = 60;
    int NumCommand = 0;
    char **argv;

    int NumOfArgs;

    command = (char *) malloc (nbytes + 1);
    command = NULL;
    while(1)
    {   
        NumCommand++;
        printf("Shell(pid = %d) %d> ",getpid(),NumCommand);

        fflush(stdin);

        Num_bytes_read = getline(&command,&nbytes,stdin);

        printf("command: %s",command);        
        if(Num_bytes_read == -1)
        {
            printf("\n ERRor\n");
        }
        else
        {  
            int x = tokenizer(command,argv);
            int i;        

            for (i = 0; i < (x+1); ++i)
                printf ("argv[i] = %s\n",argv[i]);
            //if (strcmp(argv[0], "quit")){
            //break;
            //}
            doCommand(argv);
        }
    }
    return 0;
}

int tokenizer(char *str, char **argv)
{
    //const char s[2] = " "; 
    char ** res  = NULL;
    char * p    = strtok (str, " \n");
    int n_spaces = 0, i;
    while (p) 
    {
        res = realloc (res, sizeof (char*) * ++n_spaces);
        if (res == NULL)
            exit (-1); /* memory allocation failed */
        res[n_spaces-1] = p;
        argv[n_spaces-1]= res[n_spaces-1];

        p = strtok (NULL, " \n");
    }
    // realloc one extra element for the last NULL 

    res = realloc (res, sizeof (char*) * (n_spaces+1));
    res[n_spaces] = 0;

    argv = res;
    return n_spaces;
}      

void doCommand(char **argv)
{
    pid_t  pid;
    pid_t cpid; /* Pid of child to be returned by wait. */
    int fd[2];  // dual pipeline
    int status; /* Exit status of child. */

    int nbytes;
    int commandStatus;

    pipe(fd);

    pid = fork();   // Preceding with fork]
    if (pid < 0) 
    {   
        printf("forking child process failed\n");
        exit(1);
    }
    else if (pid == 0)     // fork for the child
    {    
        close(fd[0]); // close up reader side of pipe

        cpid = getpid();  

        /* Send "string" through the output side of pipe */  
        write(fd[1], &cpid,sizeof(cpid));
        //argv[0] = "ls";
        //argv[1] = NULL;
        commandStatus = execvp(*argv, argv);
        if (commandStatus < 0)  /* execute the command  */
        {    
            printf("Try again, command failed\n");
            exit(1);
        }
    }
    else if (pid > 1)                // fork for the parent
    {  
        close(fd[1]);

        /* Read in the child pid from the pipe */
        nbytes = read(fd[0], &cpid , sizeof(cpid));
        printf("Parent says 'child process has been forked with pid=%ld'\n",(long)cpid);
        wait(NULL);
        cpid = wait(&status);      /* wait for completion  */

        printf("Parent says 'wait() returned so the child with pid=%ld is finished'\n",(long)cpid);
    }
}

1 个答案:

答案 0 :(得分:0)

问题是argv没有真正初始化,因为你正在改变tokenizer()中的本地指针,而不是main()中的指针。

您需要做的是传递argv的地址而不是指针本身,然后像这样更改tokenizer()

int tokenizer(char *str, char ***argv)
{
    char ** res      = NULL;
    char *  p        = NULL;
    int     n_spaces = 0;

    if ((str == NULL) || (argv == NULL))
        return 0;

    p     = strtok (str, " \n"); 
    *argv = NULL;
    while (p)
    {
        res = realloc (*argv, sizeof(char *) * ++n_spaces);
        if (res == NULL)
        {
            free(*argv);
            return 0;
        }
        res[n_spaces - 1] = p;
        *argv             = res;
        p                 = strtok (NULL, " \n");
    }
    res = realloc (*argv, sizeof(char *) * (n_spaces + 1));
    if (res == NULL)
    {
        free(*argv);
        return 0;
    }
    res[n_spaces] = 0;
    *argv         = res;

    return n_spaces;
}

并在主

int x = tokenizer(command, &argv);
/*                         ^ address of argv */

你从未检查过最后一个realloc,所以我修了一些我认为你做得有点不安全的事情。

{p} exit() malloc / realloc在您的情况下失败并非真正必要,您只需free()已分配的指针并返回0,然后在main()处理。

此外,我建议在任何有意义的地方使用const限定符,例如

void doCommand(const char *const *argv)

而且,不要fflush() stdin它未定义的行为。