C程序文件写入异常:除最后一条外其余记录结束时间缺失
问题:办公时间记录写入文件时缺失结束时间(除最后一条)
我开发的C程序在插入办公时间时出现异常:除最后一条录入的记录外,其余所有记录的结束时间都未被写入文件。
预期文件内容:
1 Monday 2 p.m. 3 p.m. 2 Friday 4 p.m. 7 p.m. 3 Thursday 5 p.m. 9 p.m.
实际写入内容:
1 Monday 2 p.m. 2 Friday 4 p.m. 3 Thursday 5 p.m. 9 p.m.
代码片段
结构体与全局变量
#define MAX_ELEMENTS 100 #define MAXIMUM_LENGTH 50 typedef struct { char teacher; int id; char day[MAXIMUM_LENGTH]; char startingTime[MAXIMUM_LENGTH]; char endingTime[MAXIMUM_LENGTH]; } officehours; officehours list[MAX_ELEMENTS]; int c = 0; char filenamep[20];
存储记录到文件的函数
void store_office_hour(char teacher, officehours data[], int count, char* filename) { FILE* fp = fopen(filename, "w"); if (fp == NULL) { printf("ERROR in %s: Unable to open file.\n", __func__); return; } for (int i = 0; i < count; i++) { fprintf(fp, "%d %s %s %s\n", data[i].id, data[i].day, data[i].startingTime, data[i].endingTime); fprintf(stderr, "DEBUG: %d %s %s %s \n", data[i].id, data[i].day, data[i].startingTime, data[i].endingTime); } fclose(fp); }
插入新记录的函数
void insert_office_hour(char teacher) { filenamep[0] = teacher; filenamep[1] = '\0'; strcat(filenamep, ".txt"); FILE* fp = fopen(filenamep, "r"); if (fp != NULL) { c = 0; while (fscanf(fp, "%d %s %s %s", &list[c].id, list[c].day, list[c].startingTime, list[c].endingTime) == 4) { c++; } fclose(fp); } if (c >= MAX_ELEMENTS) { printf("ERROR in %s: Database is full.\n", __func__); return; } officehours input; getchar(); printf("\t\tEnter identification number: "); scanf("%d", &input.id); getchar(); printf("\t\tEnter a day: "); read_line(input.day, MAXIMUM_LENGTH); printf("\t\tEnter starting hour: "); read_line(input.startingTime, MAXIMUM_LENGTH); printf("\t\tEnter ending hour: "); read_line(input.endingTime, MAXIMUM_LENGTH); if (find_office_hour(list, c, input.id) != -1) { printf("This office hour already exists.\n"); return; } list[c++] = input; store_office_hour(teacher, list, c, filenamep); }
读取一行输入的函数
int read_line(char str[], int n) { int ch, i = 0; while (isspace(ch = getchar())); while (ch != '\n') { if (i < n - 1) str[i++] = ch; ch = getchar(); } str[i] = '\0'; return i; }
问题根源
核心问题出在字符串的读写格式不匹配:
- 时间字段(如
2 p.m.)包含空格,但写入时使用%s格式符,会将带空格的字符串直接输出,导致一条记录被拆分为多个空白分隔的字段(比如2 p.m.会被拆成2和p.m.两个独立字段)。 - 读取现有记录时,使用
fscanf的%s格式符,该格式会在空白字符处停止解析,错误拆分带空格的时间字段。例如读取1 Monday 2 p.m. 3 p.m.时,%s会把2读入startingTime,p.m.读入endingTime,剩下的3 p.m.会被当作下一条记录的起始内容,导致原有记录的endingTime被错误覆盖,再次写入时这些记录就缺失了正确的结束时间。
解决方案
1. 修改文件写入格式,使用分隔符区分字段
修改store_office_hour函数的写入逻辑,用逗号分隔字段,避免空格导致的拆分:
void store_office_hour(char teacher, officehours data[], int count, char* filename) { FILE* fp = fopen(filename, "w"); if (fp == NULL) { printf("ERROR in %s: Unable to open file.\n", __func__); return; } for (int i = 0; i < count; i++) { // 用逗号分隔字段,确保带空格的字符串被作为整体存储 fprintf(fp, "%d,%s,%s,%s\n", data[i].id, data[i].day, data[i].startingTime, data[i].endingTime); fprintf(stderr, "DEBUG: %d,%s,%s,%s \n", data[i].id, data[i].day, data[i].startingTime, data[i].endingTime); } fclose(fp); }
2. 修改文件读取逻辑,按分隔符解析整行内容
不再使用fscanf,改用fgets读取整行,再用strtok按逗号拆分字段:
void insert_office_hour(char teacher) { filenamep[0] = teacher; filenamep[1] = '\0'; strcat(filenamep, ".txt"); FILE* fp = fopen(filenamep, "r"); if (fp != NULL) { c = 0; char line[MAXIMUM_LENGTH * 4]; // 足够容纳一行的所有内容 while (fgets(line, sizeof(line), fp) != NULL) { // 去掉行尾的换行符 line[strcspn(line, "\n")] = '\0'; // 按逗号拆分字段 char* token = strtok(line, ","); if (!token) continue; list[c].id = atoi(token); token = strtok(NULL, ","); if (!token) continue; strncpy(list[c].day, token, MAXIMUM_LENGTH - 1); list[c].day[MAXIMUM_LENGTH - 1] = '\0'; token = strtok(NULL, ","); if (!token) continue; strncpy(list[c].startingTime, token, MAXIMUM_LENGTH - 1); list[c].startingTime[MAXIMUM_LENGTH - 1] = '\0'; token = strtok(NULL, ","); if (!token) continue; strncpy(list[c].endingTime, token, MAXIMUM_LENGTH - 1); list[c].endingTime[MAXIMUM_LENGTH - 1] = '\0'; c++; if (c >= MAX_ELEMENTS) break; } fclose(fp); } // 后续插入逻辑保持不变 if (c >= MAX_ELEMENTS) { printf("ERROR in %s: Database is full.\n", __func__); return; } officehours input; getchar(); printf("\t\tEnter identification number: "); scanf("%d", &input.id); getchar(); printf("\t\tEnter a day: "); read_line(input.day, MAXIMUM_LENGTH); printf("\t\tEnter starting hour: "); read_line(input.startingTime, MAXIMUM_LENGTH); printf("\t\tEnter ending hour: "); read_line(input.endingTime, MAXIMUM_LENGTH); if (find_office_hour(list, c, input.id) != -1) { printf("This office hour already exists.\n"); return; } list[c++] = input; store_office_hour(teacher, list, c, filenamep); }
3. 修复read_line函数的边界问题
处理getchar()返回EOF的情况,避免未定义行为:
int read_line(char str[], int n) { int ch, i = 0; // 跳过开头空白,同时处理EOF while ((ch = getchar()) != EOF && isspace((unsigned char)ch)); if (ch == EOF) { str[0] = '\0'; return 0; } while (ch != '\n' && ch != EOF) { if (i < n - 1) str[i++] = ch; ch = getchar(); } str[i] = '\0'; return i; }
验证修改效果
修改后,文件内容会变成逗号分隔的格式:
1,Monday,2 p.m.,3 p.m. 2,Friday,4 p.m.,7 p.m. 3,Thursday,5 p.m.,9 p.m.
读取时会正确解析每个字段,再次写入时所有记录的结束时间都会被完整保存。
内容的提问来源于stack exchange,提问作者omrlv
相关产品推荐
相关产品推荐

