使用指针编辑文件中结构体数据的问题求助
结构体数据文件读写与编辑的问题修复
问题现象
- 编辑指定学生数据时,新数据总是追加到文件末尾,无法覆盖目标结构体位置
- 文件中存在多个结构体数据,但
fread仅能读取前2条
原始代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> struct studentdata{ int student_number; char student_name[40]; int student_id; char student_address[60]; int phone_number; }; void main(){ FILE *p; struct studentdata insert; int edit_student; int location; struct studentdata change; struct studentdata *edit; edit = &change; p = fopen("students.txt","a"); printf("Insert student\n\n "); printf("Student Number: "); scanf("%d", &insert.student_number); printf("Student Name: "); scanf("%s", &insert.student_name); printf("Student ID: "); scanf("%d", &insert.student_id); printf("Address: "); scanf("%s", &insert.student_address); printf("Phone Number: "); scanf("%d", &insert.phone_number); printf("\tData saved sucessfully.\n"); fwrite(&insert, sizeof(struct studentdata), 1, p); fclose(p); p = fopen("students.txt","r+"); while(fread(&change,sizeof(struct studentdata),1,p)){ printf("Student Number: %d\n", change.student_number); printf("Student Name: %s\n", change.student_name); printf("Student ID: %d\n", change.student_id); printf("Address: %s\n", change.student_address); printf("Phone Number: %d\n", change.phone_number); if (feof(p)) break; } printf("Please input the student number you want to edit:"); scanf("%d",&edit_student); fseek(p, 0, SEEK_SET); system("cls"); while(fread(&change,sizeof(struct studentdata),1,p)){ if ( change.student_number == (edit_student) ){ location = ftell(p); setbuf(stdin, NULL); printf("Current student name: %s\n", change.student_name); printf("\New student name: "); scanf("%s", &edit->student_name); printf("Current Student ID: %d\n", change.student_id); printf("\tNew Student ID: "); scanf("%d", &edit->student_id); printf(" Current Address: %s\n", change.student_address); printf("\tAddress / CP: "); scanf("%s", &edit->student_address); printf("Current Phone Number: %d\n", change.phone_number); printf("\tPhone Number: "); scanf("%d", &edit->phone_number); location = ftell(p); fwrite(&edit,sizeof(struct studentdata),1,p); fclose(p); break; } if (feof(p)) break; } }
问题原因分析
1. 编辑时无法覆盖目标数据的原因
- 调用
fread找到目标结构体后,ftell(p)返回的是读取完该结构体后的位置,而非结构体起始位置,直接写入会写到下一个结构体的位置 - 写入时错误传递了
&edit(指针的地址),而不是edit(指针指向的结构体数据),导致写入的是指针值而非结构体内容 - 没有在写入前将文件指针移动到目标结构体的起始位置
2. fread只能读取2条数据的原因
- 第一次读取循环中,
while(fread(...))本身会在读取到文件末尾时终止,但额外添加了if(feof(p)) break;,干扰了正常读取流程,导致提前终止 - 文件打开使用文本模式,可能因换行符转换破坏结构体的二进制布局,导致读取异常
修复后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> struct studentdata{ int student_number; char student_name[40]; int student_id; char student_address[60]; int phone_number; }; int main(){ FILE *p; struct studentdata insert; int edit_student; long location; // 用long存储ftell返回值,避免溢出 struct studentdata change; struct studentdata *edit = &change; // 二进制追加模式写入,避免文本模式的换行转换问题 p = fopen("students.txt","ab"); if(p == NULL){ perror("Failed to open file for writing"); return 1; } printf("Insert student\n\n"); printf("Student Number: "); scanf("%d", &insert.student_number); printf("Student Name: "); scanf("%s", insert.student_name); // 数组名本身是地址,无需& printf("Student ID: "); scanf("%d", &insert.student_id); printf("Address: "); scanf("%s", insert.student_address); printf("Phone Number: "); scanf("%d", &insert.phone_number); printf("\tData saved successfully.\n"); fwrite(&insert, sizeof(struct studentdata), 1, p); fclose(p); // 二进制读写模式打开,保证结构体读写一致 p = fopen("students.txt","rb+"); if(p == NULL){ perror("Failed to open file for reading"); return 1; } printf("\nAll student data:\n"); // 移除多余feof判断,fread返回值直接控制循环 while(fread(&change, sizeof(struct studentdata), 1, p)){ printf("Student Number: %d\n", change.student_number); printf("Student Name: %s\n", change.student_name); printf("Student ID: %d\n", change.student_id); printf("Address: %s\n", change.student_address); printf("Phone Number: %d\n\n", change.phone_number); } // 重置文件指针到开头 fseek(p, 0, SEEK_SET); // 编辑指定学生 printf("Please input the student number you want to edit: "); scanf("%d", &edit_student); system("cls"); int found = 0; while(fread(&change, sizeof(struct studentdata), 1, p)){ if(change.student_number == edit_student){ found = 1; // 计算结构体起始位置:读取后的位置减去结构体大小 location = ftell(p) - sizeof(struct studentdata); // 定位到结构体起始位置 fseek(p, location, SEEK_SET); printf("Current student name: %s\n", change.student_name); printf("New student name: "); scanf("%s", edit->student_name); printf("Current Student ID: %d\n", change.student_id); printf("New Student ID: "); scanf("%d", &edit->student_id); printf("Current Address: %s\n", change.student_address); printf("New Address: "); scanf("%s", edit->student_address); printf("Current Phone Number: %d\n", change.phone_number); printf("New Phone Number: "); scanf("%d", &edit->phone_number); // 写入修改后的结构体,传递正确的结构体地址 fwrite(edit, sizeof(struct studentdata), 1, p); printf("\tData updated successfully.\n"); break; } } if(!found){ printf("Student number %d not found.\n", edit_student); } fclose(p); return 0; }
关键修复点
- 将文件打开模式改为二进制模式(
rb+/ab),避免文本模式下的换行符转换破坏结构体的二进制布局 - 修正
ftell的位置计算:读取完结构体后,文件指针在结构体末尾,需减去结构体大小得到起始位置,再用fseek定位写入 - 写入时传递
edit(结构体指针)而非&edit(指针的地址),确保写入的是结构体数据 - 移除循环内多余的
feof判断,while(fread(...))本身会在读取失败或到末尾时终止循环 - 数组名本身就是地址,
scanf读取字符串时无需加&(如insert.student_name而非&insert.student_name) - 标准
main函数返回int类型,替换void main - 添加文件打开失败的错误判断,增强程序健壮性
内容的提问来源于stack exchange,提问作者JackJones90
相关产品推荐
相关产品推荐

