C语言如何读写二进制文件及解决读取时出现的段错误问题
C语言二进制读写结构体段错误问题分析与修复
核心问题原因
- 结构体包含指针成员,直接二进制写入无效:你定义的
new_acc结构体里有char *initials, *name, *email, *acc_type四个指针成员,调用fwrite直接写结构体时,写入的是指针指向的内存地址值,而非地址对应的字符串内容。读取时,之前申请的字符串内存已经被释放,读取到的指针属于野指针,访问时直接触发段错误。 - 内存申请大小错误:
malloc(sizeof(new_acc.name))里的new_acc.name是char*类型,64位系统下大小仅为8字节,你用scanf读入最长100字符的内容时直接发生缓冲区溢出,属于未定义行为。 - 读写逻辑错误:写入时循环写13次完全相同的结构体内容,读取时也循环读13次,属于无效逻辑,没有实际意义。
- 文件打开模式错误:二进制文件读写需要加
b标识,你用的"a"、"r"是文本模式,在部分系统下会出现字节转换问题,导致读写内容错乱。 - 打印格式错误:
printf("%s\n", new_acc.birth_day);里birth_day是struct date类型,不是字符串,用%s打印直接触发内存非法访问。
修复方案
第一步:修改结构体定义,把指针成员改成定长数组,避免指针序列化问题
struct date{ // 日期结构体 int mm, dd, yyyy; }; // 把所有字符串成员改成定长数组,确保整个结构体内容连续可直接序列化 struct Account { char initials[50], name[100], email[50], acc_type[20]; // 定长数组替代指针 char id_num[11], occupation[25], address[100]; int phone, acc_num, balance; struct date birth_day; } new_acc;
第二步:删除错误的内存申请逻辑
原来的4行malloc和对应的free代码全部删掉,定长数组的内存已经包含在结构体的内存空间里,不需要单独申请。
第三步:修复写入逻辑
void create_new(void) { system("clear"); puts("Answer the questions to make a account"); time_t l; srand((unsigned) time(&l)); new_acc.acc_num = l; printf("Enter your full name: "); scanf(" %100[^\n]", new_acc.name); printf("Enter your name with initials: "); scanf(" %50[^\n]", new_acc.initials); printf("Enter your birthday (mm/dd/yyyy): "); scanf(" %d %d %d", &new_acc.birth_day.mm, &new_acc.birth_day.dd, &new_acc.birth_day.yyyy); printf("Enter your address: "); scanf(" %100[^\n]", new_acc.address); printf("Enter your phone number: "); scanf(" %10d", &new_acc.phone); printf("Enter your id number: "); scanf(" %10[0-9a-zA-Z]", new_acc.id_num); printf("Enter your occupation: "); scanf(" %50[^\n]", new_acc.occupation); printf("Enter your email address:"); scanf(" %49s", new_acc.email); printf("Enter the account type:\n"); printf("\t#Saving\n\tFixed (1 year)\n\tFixed (2 year)\n\tFixed (3 year)\n"); scanf(" %19s", new_acc.acc_type); printf("Enter amount to deposite: $"); scanf(" %d", &new_acc.balance); // 二进制追加模式打开文件 FILE *fp = fopen("employees", "ab"); if (fp == NULL) { puts("Cannot open a file..."); return; } // 单次写入即可,不需要循环写13次 fwrite(&new_acc, sizeof(new_acc), 1, fp); fclose(fp); int out; printf("Successfully created a account!\nYour account number is %d\n", new_acc.acc_num); printf("Press 1 to exit, and 0 to go to main menu..."); scanf("%d", &out); switch (out){ case 1: exit(0); break; case 0: menu(); break; } }
第四步:修复读取逻辑
FILE *fp = fopen("employees", "rb"); // 二进制读模式打开 if (fp == NULL) { puts("Cannot open a file..."); return; } // 如果要读最后一条记录,先把文件指针移到最后一条的位置 fseek(fp, -sizeof(new_acc), SEEK_END); fread(&new_acc, sizeof(new_acc), 1, fp); fclose(fp); printf("%d\n", new_acc.acc_num); printf("%s\n", new_acc.name); printf("%s\n", new_acc.initials); // 分开打印日期成员 printf("%d/%d/%d\n", new_acc.birth_day.mm, new_acc.birth_day.dd, new_acc.birth_day.yyyy); printf("%s\n", new_acc.address); printf("%d\n", new_acc.phone); printf("%s\n", new_acc.id_num); printf("%s\n", new_acc.occupation); printf("%s\n", new_acc.email); printf("%s\n", new_acc.acc_type); printf("%d\n", new_acc.balance);
内容的提问来源于stack exchange,提问作者Aesha Amoli
相关产品推荐
相关产品推荐

