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

父子进程场景下如何将共享内存中的学生数据写入文本文件?

解决共享内存数据写入文件的问题

Hey,我来帮你搞定这个从共享内存读取学生数据写入文件的问题。你的核心问题是没有正确解析共享内存里的struct student数据,咱们一步步修正,先看问题出在哪,再给你完整的解决方案。

问题分析

  1. 指针类型错误:你把共享内存附加后的char*指针直接当作学生数据来访问,但没有转换成struct student*类型,导致无法正确解析每个学生的姓名和分数。
  2. 读取时机不对:父进程在wait(NULL)之前就附加了共享内存,这时候子进程可能还没写完数据,读取到的内容不完整。
  3. 共享内存大小固定:你用固定的100字节创建共享内存,当学生数量较多时,会超出内存大小导致数据损坏。
  4. fprintf格式错误:你原来的fprintf只输出了姓名,没有正确输出分数,格式字符串缺少对应的占位符。

修正后的完整代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>

struct student {
    char name[20];
    float marks;
};

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

    int n = atoi(argv[1]);
    if (n <= 0) {
        printf("Invalid number of students\n");
        exit(1);
    }

    key_t key = 10;
    // 根据学生数量动态计算共享内存大小,避免溢出
    size_t shm_size = n * sizeof(struct student);
    int shmID = shmget(key, shm_size, 0666 | IPC_CREAT | IPC_EXCL);
    if (shmID == -1) {
        perror("shmget failed");
        exit(1);
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("fork failed");
        shmctl(shmID, IPC_RMID, NULL);
        exit(1);
    }

    if(pid == 0) {
        // 子进程:写入学生数据到共享内存
        struct student* child_at = (struct student*) shmat(shmID, NULL, 0);
        if (child_at == (void*)-1) {
            perror("shmat child failed");
            exit(1);
        }

        printf("Number of students: %d\n", n);
        for (int i = 0; i < n; ++i) {
            printf("For student %d\nEnter name: ", i+1);
            scanf("%s", child_at[i].name); // 直接写入共享内存,不需要本地数组
            printf("Enter marks: ");
            scanf("%f", &child_at[i].marks);
        }

        // 打印验证写入的数据
        printf("\n\tName\tMarks\t\n");
        for(int i = 0; i < n; i++) {
            printf("\t%s\t%.2f\t\n", child_at[i].name, child_at[i].marks);
        }

        int d1 = shmdt(child_at);
        if (d1 == -1) {
            perror("shmdt child failed");
        }
        exit(0);
    } else if (pid > 0) {
        // 父进程:等待子进程完成,读取共享内存数据并写入文件
        wait(NULL); // 确保子进程完全写入数据

        struct student* parent_at = (struct student*) shmat(shmID, NULL, 0);
        if (parent_at == (void*)-1) {
            perror("shmat parent failed");
            shmctl(shmID, IPC_RMID, NULL);
            exit(1);
        }

        FILE *fptr = fopen("student.txt", "w");
        if(fptr == NULL) {
            perror("fopen failed");
            shmdt(parent_at);
            shmctl(shmID, IPC_RMID, NULL);
            exit(1);
        }

        // 直接从共享内存读取数据写入文件,也可以复制到本地数组再写入
        fprintf(fptr, "Name\t\tMarks\n");
        fprintf(fptr, "------------------------\n");
        for (int i = 0; i < n; i++) {
            fprintf(fptr, "%s\t\t%.2f\n", parent_at[i].name, parent_at[i].marks);
        }

        fclose(fptr);
        int d2 = shmdt(parent_at);
        if (d2 == -1) {
            perror("shmdt parent failed");
        }
        shmctl(shmID, IPC_RMID, NULL);
    }

    return 0;
}

关键修改点说明

  1. 动态计算共享内存大小:根据学生数量n乘以单个struct student的大小来创建共享内存,避免固定大小导致的溢出问题。
  2. 子进程直接写入共享内存:去掉了本地的stuarr数组,直接把数据写入共享内存的指针,减少内存复制,更高效。
  3. 父进程等待后再附加共享内存:先调用wait(NULL)等待子进程完成写入,再附加共享内存,确保读取到完整的数据。
  4. 正确转换指针类型:把共享内存附加后的指针转换成struct student*,这样可以像访问普通数组一样直接访问每个学生的数据。
  5. 修复fprintf格式:添加了分数的占位符%.2f,并优化了文件输出的格式,让内容更清晰。
  6. 增加错误检查:对shmget、fork、shmat、fopen等系统调用的返回值进行错误检查,方便调试问题。

测试方法

编译并运行程序,比如:

gcc -o student_shm student_shm.c
./student_shm 2

输入两个学生的姓名和分数后,查看student.txt文件,就能看到正确写入的数据了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 18:44:04