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

C语言fork进程异常:段错误与代码重复执行问题求助

问题描述

我有一项C语言作业,要求根据给定的学生人数(每位学生有期中、期末两门成绩),统计及格学生的数量。需要使用fork()创建指定数量的TA(助教)子进程,每个子进程负责分区判断学生是否及格,TA的数量通过终端传入。

编写代码后遇到以下问题:

  • 出现segmentation fault(段错误)
  • 添加的打印语句(第53行)执行了(子进程数+父进程)次,尽管它位于fork()调用之前
  • 代码逻辑是创建多个TA进程,每个进程负责一个分区统计及格人数并以该数值作为退出码,父进程通过循环wait()等待子进程结束并打印其退出码
问题代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>


void main(int argc, char **argv)
{
    int Number_of_TAs = atoi(argv[1]);
    int leastgrade = atoi(argv[2]);
    int size_of_array = 0;
    int flag = 0;
    int last_visited = 0;
    int ind = 0;



    FILE* ptr;
    char ch;
 
    // Opening file in reading mode
    ptr = fopen("students.txt", "r");
 
    if (NULL == ptr) {
        printf("file can't be opened \n");
    }
 

    do {
        ch = fgetc(ptr);
        size_of_array = 2 * ((int)ch - 48);
        break;
 
    } while (ch != EOF);

 
    fclose(ptr);
    int arr_of_grades[size_of_array]; 
    int arr_of_grades2[size_of_array/2];


    
   FILE *myFile;
   myFile = fopen("students.txt", "r");

    int *dummy;
    fscanf(myFile, "%d", &dummy);
    for (int i = 0; i < size_of_array; i++)
        fscanf(myFile, "%d", &arr_of_grades[i]);
    
    int index2 = 0;
    printf("%d", size_of_array);
    printf(" ");
    for (int i = 0; i< size_of_array; i=i+2)
    {
        arr_of_grades2[index2] = arr_of_grades[i] + arr_of_grades[i+1];
        index2 = index2 + 1;
        
    
    }


    fclose(myFile);


    int pid, stat_loc;
    int passed_students = 0;
    int partion = size_of_array / (2 * Number_of_TAs );
    for (int i=0; i< Number_of_TAs; i++)
    {  
        pid = fork();
        ind = ind + partion;
    }

    if (pid == 0)
    {

        for (int i = ind; i< ind + partion; i++)
           { 
            if (arr_of_grades2[i]>=leastgrade )
                passed_students = passed_students + 1;
           }
    exit(passed_students);
    }

    else
    {   
        int sid;
        for (int i = 0; i<Number_of_TAs; i++)
        {
            sid = wait(&stat_loc);
            if(!(stat_loc & 0x00FF))
            printf(stat_loc>>8);
            printf(" ");
        }
    }

    return 0;
}
问题分析与修复

1. 段错误的核心原因

代码中int *dummy; fscanf(myFile, "%d", &dummy);是致命错误:

  • dummy是未初始化的野指针,&dummy是指针本身的内存地址,而非指针指向的有效内存
  • fscanf会把读取到的数值写入这个非法地址,直接触发段错误

修复:将指针改为普通整数变量:

int dummy;
fscanf(myFile, "%d", &dummy);

2. 子进程数量爆炸(打印重复执行的原因)

当前fork()循环逻辑错误:

  • 父进程创建子进程后,子进程会继续执行循环剩余迭代,导致创建2^N个进程(N为TA数量),而非预期的N个
  • 额外的子进程会执行后续代码,导致各种逻辑混乱

修复:子进程创建后立即跳出循环,避免继续创建新进程:

for (int i=0; i< Number_of_TAs; i++)
{  
    pid = fork();
    if (pid == 0) {
        // 子进程不再参与循环创建新进程
        break;
    }
    ind = ind + partion;
}

3. 分区索引错误

当前ind的累加逻辑会导致子进程拿到错误的分区起始索引,出现分区重叠或越界:

  • 父进程每次fork后递增ind,子进程继承的是累加后的ind值,而非自己负责的分区起始位置

修复:提前计算每个子进程的分区范围,避免共享变量导致的错误:

int total_students = size_of_array / 2;
int partion = total_students / Number_of_TAs;
int remainder = total_students % Number_of_TAs; // 处理学生数无法被TA数量整除的情况

for (int i=0; i< Number_of_TAs; i++)
{  
    int start = i * partion + (i < remainder ? i : remainder);
    int end = start + partion + (i < remainder ? 1 : 0);
    pid = fork();
    if (pid == 0) {
        int count = 0;
        for (int j = start; j < end; j++) {
            if (arr_of_grades2[j] >= leastgrade) {
                count++;
            }
        }
        exit(count);
    }
}

4. 其他次要问题修复

  • void main不符合C标准,改为int main
  • 文件打开失败后未终止程序,添加exit(1)避免空指针操作:
    if (NULL == ptr) {
        printf("file can't be opened \n");
        exit(1);
    }
    
  • printf(stat_loc>>8);会将整数当作ASCII字符输出,改为printf("%d ", stat_loc >> 8);
  • 读取学生数的逻辑脆弱(仅支持个位数),改为用fscanf读取完整整数:
    int student_count;
    fscanf(ptr, "%d", &student_count);
    size_of_array = student_count * 2;
    
修复后的完整代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    if (argc != 3) {
        printf("Usage: %s <number_of_tas> <pass_score>\n", argv[0]);
        exit(1);
    }

    int Number_of_TAs = atoi(argv[1]);
    int leastgrade = atoi(argv[2]);
    int size_of_array = 0;
    int total_students = 0;

    // 读取学生数量
    FILE* ptr = fopen("students.txt", "r");
    if (NULL == ptr) {
        printf("file can't be opened \n");
        exit(1);
    }
    fscanf(ptr, "%d", &total_students);
    size_of_array = total_students * 2;
    fclose(ptr);

    int arr_of_grades[size_of_array]; 
    int arr_of_grades2[total_students];

    // 读取成绩数据
    FILE *myFile = fopen("students.txt", "r");
    if (NULL == myFile) {
        printf("file can't be opened \n");
        exit(1);
    }
    int dummy;
    fscanf(myFile, "%d", &dummy);
    for (int i = 0; i < size_of_array; i++) {
        fscanf(myFile, "%d", &arr_of_grades[i]);
    }

    // 计算每位学生的总分
    for (int i = 0, index2 = 0; i < size_of_array; i += 2, index2++) {
        arr_of_grades2[index2] = arr_of_grades[i] + arr_of_grades[i+1];
    }
    fclose(myFile);

    int pid, stat_loc;
    int partion = total_students / Number_of_TAs;
    int remainder = total_students % Number_of_TAs;

    // 创建TA子进程
    for (int i = 0; i < Number_of_TAs; i++) {
        int start = i * partion + (i < remainder ? i : remainder);
        int end = start + partion + (i < remainder ? 1 : 0);
        pid = fork();
        if (pid == 0) {
            int passed = 0;
            for (int j = start; j < end; j++) {
                if (arr_of_grades2[j] >= leastgrade) {
                    passed++;
                }
            }
            exit(passed);
        } else if (pid < 0) {
            printf("Failed to fork process\n");
            exit(1);
        }
    }

    // 父进程等待所有子进程并统计结果
    int total_passed = 0;
    for (int i = 0; i < Number_of_TAs; i++) {
        wait(&stat_loc);
        if (!(stat_loc & 0x00FF)) {
            int passed = stat_loc >> 8;
            total_passed += passed;
            printf("TA %d counted %d passed students\n", i+1, passed);
        }
    }
    printf("Total passed students: %d\n", total_passed);

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 20:10:24