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

C语言读取文本存入struct/union后读写输出异常求解

C语言共用体封装结构体文件读写程序异常修正

需求说明

  • 开发者为C语言初学者,对结构体(struct)、共用体(union)、IO流用法掌握不充分,需实现三个核心功能
  • 读取预创建的inputfile.txt存储的学生信息,字段包含姓名、学号(ID)、年龄、奖学金获得次数、学籍状态、是否在外留学、住址、联系电话、平均学分绩点(CGPA),输入文件格式示例:

name/ ID/ age/ scholarship/ schoolstat/ abroad/ address/ phone/ cgpa
mark/ 20091111/ 20/ 1/ Yes/ No/ city,district,street,house/ 1234567890/ 3.0

  • 将读取到的信息存入union封装的struct结构体中
  • 处理后的数据写入程序自动创建的outputfile.txt,同时在控制台打印全部信息

原始问题代码

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

typedef struct{
    char name[20];
    char mail[30];
    int mobile;
}PROFESSOR;

typedef struct{
    char name[20];
    char address[50];
    char schoolstat[10];
    int scholarship[5];
    char abroad[10];
    int phone;
    int age;    
    int ID;
    float cgpa;
}STUDENT;

typedef struct{
    char type;
    union {
        PROFESSOR prof;
        STUDENT stu;
    }u;
}PERSON;
 
// Driver program
int main () {
    FILE *infile, *ofp;
    PERSON data[6];
    int i;
    char name[20];
    char address[50];
    char schoolstat[10];
    int scholarship[5];
    char abroad[10];
    int phone;
    int age;    
    int ID;
    float cgpa;
    
    infile = fopen ("inputfile.txt", "r");
    if (infile == NULL)
    {
        fprintf(stderr, "\nError opening file\n");
        exit (1);
    }
    ofp=fopen("outputfile.txt", "w");
    if(ofp==NULL){
        printf("output file open error!\n");
        return 1;
    }
    data[0].type = 'p';
    strcpy(data[0].u.prof.name, "Sam");
    strcpy(data[0].u.prof.mail, "ssss@mail.com");
    data[0].u.prof.mobile = 1234567;
    
    data[1].type = 's';
    data[2].type = 's';
    data[3].type = 's';
    data[4].type = 's';
    data[5].type = 's';
    
    int total = 0;
    int total_age=0;
    int newline=0;
    
    int res;
    char c;
    int i;
    while(1){
        res=fscanf(infile, "%d %d %d %d %s %s %s %d %f\n", name, &ID, &age, &scholarship, &schoolstat, &abroad, &address, &phone, &cgpa);
        if(res==EOF) break;
        fprintf(ofp, "%d %s %d %d %s %s %s %d %f\n", ID, name, age, scholarship, schoolstat, abroad, address, phone, cgpa);
        i++;
        if(i==5) break;
        total = total + cgpa;
        total_age = total_age + age;
        for(newline=0; newline<res; newline++){
            if(name[c]=='\0'){
                newline++;
            }
        }   
    }
    for(i=0; i<6; i++){
        switch(data[i].type){
            case 'p':
                printf("professor %s\n", data[i].u.prof.name);
                printf("%s, %d\n", data[i].u.prof.mail, data[i].u.prof.mobile);
                break;
            case 's':
                printf("student %s %d %d %d %s %s %s %d %f\n", data[i].u.stu.name, data[i].u.stu.age, data[i].u.stu.ID, data[i].u.stu.scholarship, data[i].u.stu.schoolstat, data[i].u.stu.abroad, data[i].u.stu.address, data[i].u.stu.phone, data[i].u.stu.cgpa);
                break;
        }
        printf("\n");
    }
    printf("Number of lines: %d", newline);
    fclose (infile);
    fclose(ofp);
    return 0;
}

异常表现

运行后输出不符合预期,具体现象:

  • 学生类型结构体字段全部显示为乱码或0值
  • 读取行数统计错误
  • 文件读写逻辑失效,无法正确写入学生数据

实际异常输出:

professor Sam
ssss@mail.com, 1234567

student 0 0 6486936 0 0.000000

student 0 0 6487068 0 0.000000

student 0 0 6487200 0 0.000000

student 0 0 6487332 0 0.000000

Number of lines: 0

核心错误点

  1. 变量重复定义且未初始化:函数开头定义了循环变量i,读取循环前又重复定义同名i且未赋初始值,触发未定义行为。
  2. fscanf格式与输入完全不匹配:输入文件以/作为字段分隔符,格式串却用空格做分隔;第一个字段是姓名字符串,格式串却用%d整数占位符;奖学金获得次数是单个整数,却定义为长度5的int数组;11位手机号用int存储会发生数值溢出。
  3. 读取的数据未存入目标结构体:fscanf将数据读入main函数内的临时变量,从未将临时变量的值赋值给data数组中对应学生项的结构体成员,打印时读取的是未初始化的栈内存垃圾值。
  4. 行数统计逻辑完全失效:循环内每次都会将newline变量重置为0,无法累计行数;统计时用未初始化的char变量c作为数组下标,属于未定义行为。
  5. 未跳过表头行:输入文件第一行是字段说明表头,不属于有效学生数据,代码直接从第一行开始解析,必然匹配失败。

修正后可运行代码

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

typedef struct{
    char name[20];
    char mail[30];
    long long mobile;
}PROFESSOR;

typedef struct{
    char name[20];
    char address[50];
    char schoolstat[10];
    int scholarship;
    char abroad[10];
    char phone[12];
    int age;    
    int ID;
    float cgpa;
}STUDENT;

typedef struct{
    char type;
    union {
        PROFESSOR prof;
        STUDENT stu;
    }u;
}PERSON;
 
int main () {
    FILE *infile, *ofp;
    PERSON data[6];
    int stu_idx = 1;
    char name[20];
    char address[50];
    char schoolstat[10];
    int scholarship;
    char abroad[10];
    char phone[12];
    int age;    
    int ID;
    float cgpa;
    
    infile = fopen ("inputfile.txt", "r");
    if (infile == NULL)
    {
        fprintf(stderr, "\nError opening file\n");
        exit (1);
    }
    ofp=fopen("outputfile.txt", "w");
    if(ofp==NULL){
        printf("output file open error!\n");
        fclose(infile);
        return 1;
    }

    // 初始化预置教授数据
    data[0].type = 'p';
    strcpy(data[0].u.prof.name, "Sam");
    strcpy(data[0].u.prof.mail, "ssss@mail.com");
    data[0].u.prof.mobile = 1234567;
    
    float total_cgpa = 0;
    int total_age=0;
    int line_count=0;
    char tmp_buf[1024];

    // 跳过第一行表头
    fgets(tmp_buf, sizeof(tmp_buf), infile);

    // 适配/分隔符格式读取数据
    while(fscanf(infile, " %[^/]/ %d/ %d/ %d/ %[^/]/ %[^/]/ %[^/]/ %[^/]/ %f",
        name, &ID, &age, &scholarship, schoolstat, abroad, address, phone, &cgpa) == 9)
    {
        // 读取数据存入结构体数组
        data[stu_idx].type = 's';
        strcpy(data[stu_idx].u.stu.name, name);
        strcpy(data[stu_idx].u.stu.address, address);
        strcpy(data[stu_idx].u.stu.schoolstat, schoolstat);
        data[stu_idx].u.stu.scholarship = scholarship;
        strcpy(data[stu_idx].u.stu.abroad, abroad);
        strcpy(data[stu_idx].u.stu.phone, phone);
        data[stu_idx].u.stu.age = age;
        data[stu_idx].u.stu.ID = ID;
        data[stu_idx].u.stu.cgpa = cgpa;

        // 写入输出文件
        fprintf(ofp, "%d %s %d %d %s %s %s %s %.1f\n", ID, name, age, scholarship, schoolstat, abroad, address, phone, cgpa);
        
        total_cgpa += cgpa;
        total_age += age;
        line_count++;
        stu_idx++;
        if(stu_idx >= 6) break; // 防止数组越界
    }

    // 控制台打印所有数据
    for(int i=0; i<stu_idx; i++){
        switch(data[i].type){
            case 'p':
                printf("professor %s\n", data[i].u.prof.name);
                printf("%s, %lld\n", data[i].u.prof.mail, data[i].u.prof.mobile);
                break;
            case 's':
                printf("student %s %d %d %d %s %s %s %s %.1f\n", 
                    data[i].u.stu.name, data[i].u.stu.age, data[i].u.stu.ID, 
                    data[i].u.stu.scholarship, data[i].u.stu.schoolstat, 
                    data[i].u.stu.abroad, data[i].u.stu.address, 
                    data[i].u.stu.phone, data[i].u.stu.cgpa);
                break;
        }
        printf("\n");
    }
    printf("Number of lines: %d\n", line_count);
    printf("Average CGPA: %.2f, Average age: %.2f\n", total_cgpa/line_count, (float)total_age/line_count);
    
    fclose (infile);
    fclose(ofp);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 02:48:37