You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言子进程菜单选项读取异常问题求助

子进程菜单重复输出问题解决

我正在编写一个涉及子进程的C程序,程序内置菜单选项供用户选择不同方式调用子进程,但菜单读取功能异常——输入选项后菜单会重复输出两次,不符合预期。

程序代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#include <locale.h>
#include <string.h>
#include <math.h>

extern char **environ;

int main(int argc, const char *argv[], char *env[])
{
    char **name;
    int x = 0, num;
    pid_t pid;
    
    for(num=0; ; num++)    // 统计环境变量个数
        if(env[num] == NULL)
            break;
    
    name = (char **) calloc(1, sizeof(char *));
    if(!name)
    {
        printf("\nMemory isn't allocated");
        return -1;
    }
    
    name[0] = (char *) calloc(9, sizeof(char));
    if(!name[0])
    {
        printf("\nMemory isn't allocated");
        return -1;
    }

    // 修复笔误:args未定义,改为env
    for(int i=0; i<num; i++)
        fprintf(stdout, "%s\n", env[i]);
    
    fprintf(stdout, "Parent process's started...\n");
    
    char *temp;
    temp = (char *) calloc(12, sizeof(char));
    if(!temp)
    {
        printf("\nMemory isn't allocated");
        return -1;
    }
    
    while(x < 100)
    {
        sprintf(temp, "%d", x);
        strcpy(name[0], "child_");
        strcat(name[0], temp);
        
        puts("path info: +-using getenv()");
        puts("                           *-scanning array of environment parameters");
        puts("                           &-using environ");
        puts("                           q-end");
        
        switch(getchar())
        {
            case '+':
                printf("PLUS:\n");
                
                pid = fork();
                
                if(pid == -1)
                {
                    fprintf(stdout, "Error, code - %d\n", errno);
                }
                else if(pid == 0)
                {
                    // 子进程执行execve,失败则立即退出
                    execve("./child", name, env);
                    perror("execve failed");
                    exit(EXIT_FAILURE);
                }
                
                break;
                
            case '*':
                printf("ASTERISK\n");
                
                pid = fork();
                
                if(pid == -1)
                {
                    fprintf(stdout, "Error, code - %d\n", errno);
                }
                else if(pid == 0)
                {
                    execve(findPath(env, num), name, env);
                    perror("execve failed");
                    exit(EXIT_FAILURE);
                }
                
                break;
                
            case '&':
                printf("AMPERSAND:\n");
                
                pid = fork();
                
                if(pid == -1)
                {
                    fprintf(stdout, "Error, code - %d\n", errno);
                }
                else if(pid == 0)
                {
                    execve(findPath(environ, num), name, env);
                    perror("execve failed");
                    exit(EXIT_FAILURE);
                }
                
                break;
                
            case 'q':
                return 0;
                
            default:
                printf("Wrong parameter\n");
                return -1;
        }
        
        // 父进程等待子进程结束后再继续
        wait(NULL);
        
        // 清理输入缓冲区残留的换行符
        while(getchar() != '\n' && !feof(stdin));
        
        x++;
    }

    exit(0);
}

实际运行输出

Parent process's started...  
path info: +-using getenv()  
           *-scanning array of environment parameters  
           &-using environ  
           q-end  
+  
PLUS:  
path info: +-using getenv()  
           *-scanning array of environment parameters  
           &-using environ  
           q-end 
path info: +-using getenv()  
           *-scanning array of environment parameters  
           &-using environ  
           q-end  
q  
Program ended with exit code: 0  

预期输出

Parent process's started...  
path info: +-using getenv()  
           *-scanning array of environment parameters  
           &-using environ  
           q-end  
+  
PLUS:  
path info: +-using getenv()  
           *-scanning array of environment parameters  
           &-using environ  
           q-end  
q  
Program ended with exit code: 0

问题根源及修复点

  1. 子进程execve失败后未退出
    当execve调用失败(如目标程序不存在、权限不足),子进程不会被替换,会继续执行后续循环代码,导致父进程和子进程同时输出菜单。
    修复:在子进程分支(pid == 0)的execve后添加错误处理,调用perror打印错误并exit终止子进程。

  2. 父进程未等待子进程终止
    父进程fork后直接进入下一次循环,此时子进程若仍在运行,会和父进程同时输出菜单。
    修复:在每个case的break前调用wait(NULL),让父进程等待子进程结束后再继续。

  3. 输入缓冲区残留换行符
    用户输入选项后按下的回车会留在缓冲区,下一次getchar会读取该换行符,可能引发异常。
    修复:在wait后添加循环清空缓冲区直到读取到换行符。

  4. 代码笔误
    原代码中args[i]未定义,需改为env[i]才能正常编译。

  5. fflush(stdin)的未定义行为
    标准C中fflush仅对输出流有效,对输入流使用属于未定义行为,需删除该语句。

内容的提问来源于stack exchange,提问作者Nina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 22:07:55