【问题标题】:The output still remain in buffer and print out after each child process输出仍然保留在缓冲区中并在每个子进程之后打印出来
【发布时间】:2026-02-08 17:55:01
【问题描述】:

我的情况是每次孩子处理时输出打印“p2:”。

当我键入命令行“echo NULL;echo void”时。我的 parse() 将拆分每个单词并使用 getword() 函数分配给 *newargv[] 。 getword(char *w) 基本上是在命令行中拆分每个单词。在我的情况下,“;”被视为换行符。 Getword(char * w) 在遇到分号时会返回 '\0'。

我运行程序时的输出。 p2:回显空;回显无效 空值 空白 p2: p2:

我认为它需要刷新输出缓冲区并尝试了 fflush(stdout)。但它不起作用。

这是我的 p2.c 和 p2.h

#include <stdio.h>
#include "p2.h"
#define MAXITEM 100 /* max number of words per line */


int BGFLAG = 0, INFLAG = 0, OUTFLAG = 0, AMFLAG = 0, SEMIFLAG = 0, PIPEFLAG = 0;
char argv[255]; //this array get a string from getword function
char *newargv[MAXITEM]; //this pointer array will keep the first character of argv array
char *in, *out; //pointers point to file in argv
int sizeC = 0; //check if it is EOF or not
int parse();

int main()
{
    int argc;
    signal(SIGTERM,myhandler);

    for (;;)
    {
        printf("p2: ");
        pid_t pid, child_pid;
        int status; 
        //call parse function
        argc = parse();

        if (sizeC == -1)
            break;
        if (argc == 0) //reissue prompt if line is empty
            continue;
        if (newargv[0] == NULL){
            fprintf(stderr, "Invalid command");
            continue;
        }

        child_pid = fork();
        if (child_pid < 0){
            printf("ERROR! can't fork\n");
            exit(1);
        }
        else if(child_pid == 0){ //return a new child process
            execvp(*newargv,newargv);
            printf("ERROR exec failed\n");
            exit(1);
        }
        else {
            pid = wait(NULL);
            if (pid == child_pid)
                continue;
        }


    }//end for
        killpg(getpgrp(),SIGTERM);
        printf("p2 terminated. \n");
        exit(0);

}// main

int parse()
{
    int p = 0; 

    //this pointer will keep track the argv array for each of loops
    //the getword function will not overwrite the argv array
    int ptr = 0; 
    int count = 0;
    SEMIFLAG = 0;
    int wCount = 0; //return the number of argc
    int semiColon = 0;


    /* Read from stdin to argv array. The ptr will keep track the argv array
        If it is meta character, set a flag appropriately. Otherwise,
        set the address of first char of argv to the newargv*/
    while ((sizeC = getword(argv + ptr)) > 0)
    {
        if(sizeC == 0){
            semiColon++;
            continue;
        }else{
            //Put the address of first char of each argv to the pointer array
            newargv[p] = argv + ptr;
            p++;
        }

        argv[ptr + sizeC] = '\0';
        //point to the next address of next word in argv, the getword will not overwrite the argv array
        ptr = ptr + sizeC + 1;
        wCount++;


    }//end while

    newargv[p] = NULL;
    return wCount;

}//end parse

void myhandler(){

}//end myhandler

这里是 p2.h

#include <stdio.h>
#include "getword.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <signal.h>

#define MAXITEM 100


int parse();

void myhandler();

这里是getword.c和getword.h

#include <stdio.h>
#include "getword.h"


int getword(char *w)
{
    int count = 0; //represent how many characters are read
    char iochar;
    int flag = 0; // identify a pair of single quote

    //set an infinite loop
    while (1)
    {
        iochar = getchar(); //This variable stores a character from stdin

        /*  If the array is full, the character will put back for next call.
            Return (STORAGE -1) characters*/
        if (count >= (STORAGE -1))
        {
            ungetc(iochar,stdin);
            w[count] = '\0';
            return count;
        }

        /* This block code will eleminate the leading tab */
        if (iochar == '\t') //ignore the tabs if it counters
            continue;

        /* Identify if the function hit EOF */
        if (iochar == EOF)
        {
            /* Return an empty string and -1 for size of string array
               Because the EOF put back when count > 0 and the getword() encounters right away at next call
               Therefore, the count is 0.*/
            if (count == 0)
            {
                w[count] = '\0';
                return -1;
            }
            /*  The getword() read some characters before hitting EOF
                Set a null terminator to finish a string array.
                Return the size of string array.
                Put the EOF back to stdin for next call
                to print the EOF*/
            if (count > 0)
            {
                w[count] = '\0';
                ungetc(iochar,stdin);
                return count;
            }
        }

        /*  For backslash case, treat all metacharacter 
            and space character as a normal character
            The ";" and newline char will not effect meaning of that newline
            */
        if (iochar == '\\')
        {
            //identify next character is meta-char,
            //or normal char or a single quote
            char nextC = getchar();

            /* Only put a meta-character or space into the array
                the blackslash is ignored 
                flag = 0 means the SINGLE QUOTE MOD is OFF*/
            if ((nextC == '\'' || nextC == '!' || nextC  == '>' || 
                nextC == '&' || nextC == ' ' || nextC == '\\' || nextC == '\t') 
                && flag == 0)
            {
                w[count++] = nextC;
                continue;
            }
            /*  As in a pair of single quote
                slash and meta char both put in the array
                flag = 1 means the SINGLE QUOTE MOD is ON.
                The metacharacter and backslash are treat as normal char*/
            else if ( (nextC == '!' || nextC  == '>' || 
                nextC == '&' || nextC == ' ' || nextC == '\\' || nextC ==';') 
                && flag == 1)
            {
                w[count++] = iochar;
                w[count++] = nextC;
                continue;
            }
            //the single quote character in a pair of single quote
            //treat as a normal character
            else if (nextC == '\'' && flag == 1)
            {
                w[count++] = nextC;
                continue;
            }

            //return the string if it encounters new line
            //put nextC back to stdin for next call
            //because we need to print out to determine the new line exist
            else if (nextC == '\n' || nextC == ';')
            {
                w[count] = '\0';
                ungetc(nextC,stdin);
                return count;
            }
            else
            //the normal character is put into the string array
            {
                w[count++] = nextC;
                continue;
            }
        }// end if blacknextC

        /*  Identify Space case 
            Treat a space char as a normal char if it's in a pair of single quotes.
            Treat a space char as a delimeter if it's not in a pair of single quotes*/
        if (iochar == ' ')
        {
            if (flag == 1) //SINGLE QUOTE MOD is ON
            {   
                w[count++] = iochar; //space is treat as normal character instead of a delimeter
                continue;
            }
            else if (count == 0)//ignore if it is leading char or space char
                continue;
            else
            {   
                /*Set a null delimeter and return the size of the array
                    This case space is a delimeter*/
                w[count] = '\0'; 
                return count;
            }
        }// end if space

        /*  This block of codes will identify the single quote case*/
        if (iochar == '\'')
        {
            //read the character after single quote to determine 
            //it is a newline or normal character or metacharacter
            char c = getchar();

            /*  Detect the open quote
                If it is not newline or delimeter char, put it back to stdin for next call
                and move on*/
            if (flag == 0 && (c != '>' || c !=  '<' || c !=  '!' || c !=  '&' 
                    || c !=  '|' || c !=  ' ' || c != ';' || c !='\n'))
            {
                flag = 1;
                ungetc(c,stdin);
                continue;
            }
            /*  Detect the closed quote. Set flag on.
                Put the character back to stdin and move on*/
            else if (flag == 1 && (c != '>' || c !=  '<' || c !=  '!' || c !=  '&' || c !=  '|' || c !=  ' ' || c != ';' || c !='\n'))
            {
                //Set single quote mod back to normal(OFF) (flag = 0)
                //get the character back to stdin for next call to read as normal character
                flag = 0;
                ungetc(c,stdin);
                continue;
            }
            /*  if it hit a new line, set a null delimeter to terminate the array
                return size of the string array.
                the newline char is put back to stdin to print out nextcall*/
            else                
            {
                w[count] = '\0';
                ungetc(c,stdin);
                return count;
            }
        }//end if single quote

        /*  This code handle when the character is meta-character
            It is considered as a delimeter character */
        if (iochar == '>' || iochar == '<' || iochar == '!' 
            || iochar == ';' || iochar == '\n' || iochar == '&' || iochar == '|')
        {
            /*  Special character ">!" 
                Need to read next character to identify "!" */
            if (iochar == '>')
            {
                char c = getchar();

                /*  return the string if is "!". It becomes a delimeter
                    put two characters back to stdin for next getword() call.
                    Return the size of string array before the special char*/
                if ( c == '!' && count > 0)
                {
                    w[count] = '\0';
                    ungetc(c,stdin);    
                    ungetc(iochar,stdin);
                    return count;
                }

                //Return size and the special character ">!"
                if (c == '!' && count == 0)
                {
                    w[count++] = iochar; //iochar = ">"
                    w[count++] = c; //c = "!"
                    w[count] = '\0';
                    return count;
                }

                /*  Put c and iochar back to stdin for next call
                    make sure in order, ">" need to be read first to print out the ">" char
                    The delimeter is only ">". Return the size of string array before ">"*/
                if ( c != '!' && count > 0)
                {
                    ungetc(c,stdin);
                    ungetc(iochar,stdin);
                    w[count] = '\0';
                    return count;
                }
                //put the ">" in to the array
                //make sure put the non-"!" back to stdin for next call
                //Return the meta-character ">" and size = 1
                if ( c != '!' && count == 0)
                {
                    ungetc(c,stdin);
                    w[count++] = iochar;
                    w[count] = '\0';
                    return count;
                }

            }

            /* This code identify when the character is a new line "\n" or ";" */
            if (iochar == '\n' || iochar == ';')
            {
                if (count == 0) // return an empty string
                {
                    w[count] = '\0';
                    return 0;
                }
                /*  Return a string array after newline
                    Put newline back to stdin for next call
                    to print out*/
                if (count > 0) 
                {
                    w[count] = '\0';
                    ungetc(iochar,stdin);
                    return count;
                }
            }

            /*  This code block handle the rest of the metacharacter.
                Return the size of 1 and that metacharacter if count = 0.
                Set null delimeter and return string array before the metacharacter.
                Put the metacharacter back to stdin for next call to print out.*/
            if (iochar == '<' || iochar == '!' || iochar == '&' || iochar == '|')
            {
                //return the delimeter and size of 1.
                if (count == 0)
                {
                    w[count++] = iochar;
                    w[count] = '\0';
                    return count;
                }
                /*  Set null delimiter to and return size of 1 and string array.
                    put the meta-character back to stdin for next call to get the meta-character */
                if (count > 0)
                {
                    w[count] = '\0';
                    ungetc(iochar,stdin);
                    return count;
                }
            }
        }//end if meta case

        /*  After handling all situation, this character is normal. 
            Put the normal character to the string array */
        w[count++] = iochar;

    }//end while
}// getword

getword.h

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

#define STORAGE 255
      /* This is one more than the max wordsize that getword() can handle */

int getword(char *w);

【问题讨论】:

  • 这些参数的值是什么:if(execvp(*newargv,newargv) &lt; 0){
  • 我认为是-1
  • 发布的代码会导致编译器输出一长串错误和警告消息。
  • 发布的代码缺少所需的#include 语句`
  • 为了便于阅读和理解:1) 通过一个空行分隔代码块(for、if、else、while、do...while、switch、case、default)。 2) 遵循公理:每行只有一个语句,并且(最多)每条语句有一个变量声明。

标签: c shell unix operating-system


【解决方案1】:

以下代码:

  1. 更正了 cmets 中列出并由编译器暴露的问题。
  2. 干净编译
  3. 记录包含每个头文件的原因
  4. 将数据声明保留在使用它们的地方
  5. 不是一个完整的答案,因为您没有指明要触发代码退出的内容。

现在是代码:

#include <stdio.h>     // perror(), printf()
#include <stdlib.h>    // exit(), EXIT_FAILURE
#include <unistd.h>    // execvp(), fork(), pid_t
#include <sys/types.h>
#include <sys/wait.h>  // waitpid()


char **parse( void );

int main( void )
{
    for (;;)
    {
        printf("p2: ");
        //pid_t pid;
        pid_t child_pid;
        //int status;

        //call parse function
        char **argv = parse();


        child_pid = fork(); //fork a child process

        if(child_pid < 0)
        { // then error occurred
            perror( "fork failed" );
            //printf("ERROR: can't fork! exec failed\n");
            //exit(1);
            exit( EXIT_FAILURE );
        }

        else if (child_pid == 0)
        { // then child process

            execvp( argv[0], argv );
            perror( "execvp failed" );
            exit(1);
        }

        else
        { // parent process
            int status;
            waitpid( child_pid, &status, 0);
        }

    }//end for

}// main

【讨论】: