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

