如何用fscanf解析含TAB与空行的Office结构体数据?
问题与解决方案
问题背景
定义了如下C++结构体:
struct Office { char city[50]; int employees; char desc[200]; }; struct Office office[100];
需要读取特定格式的文件,将数据填充到office数组中。文件格式如下(城市下一行的员工数前有TAB/4个空格,存在空行分隔):
Toronto 151: This is HQ Vancouver 23: This is branch office London 12: This is euro branch
目标解析结果示例:
city = "Toronto" employees = 151 desc = "This is HQ"
现有实现代码运行异常,核心需求是处理TAB/前置空格和空行。
核心问题与解决方法
1. 空行处理
读取每一行后,先判断是否为空白行(仅含换行、空格、TAB),若是则直接跳过,避免干扰解析逻辑。可以通过遍历行内字符,用isspace判断是否全为空白。
2. TAB/前置空格处理
scanf系列函数的%d格式会自动跳过所有前置空白字符(包括TAB和空格),所以不需要额外处理员工数前的TAB,只需保证格式字符串正确即可。原代码中%d[^:]是错误写法,正确格式应为%d: %[^\n],匹配数字、冒号、空格,然后读取剩余的描述文本。
修正后的完整代码
#include <stdio.h> #include <string.h> #include <ctype.h> #define MAX_OFFICES 100 struct Office { char city[50]; int employees; char desc[200]; }; int LoadOffices(const char *f, struct Office offices[], int *count) { *count = 0; FILE *fp = fopen(f, "r"); if (!fp) { return 1; // 文件打开失败返回错误码 } char buf[500]; while (*count < MAX_OFFICES && fgets(buf, sizeof(buf), fp) != NULL) { // 跳过空行 int is_empty = 1; for (size_t j = 0; buf[j] != '\0'; j++) { if (!isspace((unsigned char)buf[j])) { is_empty = 0; break; } } if (is_empty) { continue; } // 处理城市名:移除末尾换行符 buf[strcspn(buf, "\n")] = '\0'; strncpy(offices[*count].city, buf, sizeof(offices[*count].city) - 1); offices[*count].city[sizeof(offices[*count].city) - 1] = '\0'; // 确保字符串终止 // 读取员工信息行 if (fgets(buf, sizeof(buf), fp) == NULL) { break; // 文件提前结束,终止循环 } // 解析员工数和描述 int emp; char desc[200]; if (sscanf(buf, "%d: %[^\n]", &emp, desc) == 2) { offices[*count].employees = emp; strncpy(offices[*count].desc, desc, sizeof(offices[*count].desc) - 1); offices[*count].desc[sizeof(offices[*count].desc) - 1] = '\0'; (*count)++; } } fclose(fp); return 0; // 成功返回0 }
关键细节说明
- 用
strcspn快速去除行尾的换行符,避免城市名包含多余的换行字符。 sscanf的%d自动跳过前置空白,完美适配员工数前的TAB/空格。- 加入数组边界检查,防止
offices数组越界访问。 - 所有字符串拷贝都预留了终止符位置,避免缓冲区溢出。
内容的提问来源于stack exchange,提问作者Marvin
相关产品推荐
相关产品推荐

