如何让C语言程序同时兼容两种格式的方向数据输入?
问题描述
需要实现一个C语言程序,兼容两种输入格式:
- 每行一个方向数据,例如
N:{-4,2,1} - 所有方向数据放在同一行,例如
N:{1,2} W:{3,4} E:{5,6} S:{7,8}
原程序依赖EOF终止输入,但Windows环境下无法生效,已改为输入END标识输入结束。目前两种格式单独运行正常,但需要实现同时兼容。
现有代码
辅助函数与读取函数
#include <stdio.h> #include <string.h> #include <ctype.h> #define MAX_TOKENS 100 // 假设MAX_TOKENS是已定义的常量 char *skip_whitespace(char *str) { // 跳过前导空白字符 while (*str == ' ' || *str == '\t') str++; return str; } void read_tokens(int *north, int *west, int *east, int *south, int *north_size, int *west_size, int *east_size, int *south_size) { // 输入缓冲区 char buffer[MAX_TOKENS]; // 逐行读取输入 while (fgets(buffer, MAX_TOKENS, stdin) != NULL) { // 移除换行符 buffer[strcspn(buffer, "\n")] = 0; // 检查是否为END,若是则终止输入 if (strcmp(buffer, "END") == 0) break; // 按大括号拆分方向标识和数据 char *direction_token = strtok(buffer, "{"); char *tokens = strtok(NULL, "}"); // 获取方向字符 char direction = direction_token[0]; // 跳过数据部分的空白 tokens = skip_whitespace(tokens); // 按逗号拆分数字 char *token = strtok(tokens, ","); // 根据方向存储数据 if (direction == 'N') { while (token != NULL) { token = skip_whitespace(token); north[*north_size] = atoi(token); (*north_size)++; token = strtok(NULL, ","); } } else if (direction == 'W') { while (token != NULL) { token = skip_whitespace(token); west[*west_size] = atoi(token); (*west_size)++; token = strtok(NULL, ","); } } else if (direction == 'E') { while (token != NULL) { token = skip_whitespace(token); east[*east_size] = atoi(token); (*east_size)++; token = strtok(NULL, ","); } } else if (direction == 'S') { while (token != NULL) { token = skip_whitespace(token); south[*south_size] = atoi(token); (*south_size)++; token = strtok(NULL, ","); } } else { // 无效方向,输出错误 printf("Nespravny vstup.\n"); } } }
主函数
int main(void) { // 存储各方向数据的数组 int north[MAX_TOKENS], west[MAX_TOKENS], east[MAX_TOKENS], south[MAX_TOKENS]; // 各数组的有效元素数量 int north_size = 0, west_size = 0, east_size = 0, south_size = 0; printf("Input:\n"); // 读取输入数据 read_tokens(north, west, east, south, &north_size, &west_size, &east_size, &south_size); // 输出各方向数据 printf("N: { "); for (int i = 0; i < north_size; i++) printf("%d, ", north[i]); printf("}\n"); printf("W: { "); for (int i = 0; i < west_size; i++) printf("%d, ", west[i]); printf("}\n"); printf("E: { "); for (int i = 0; i < east_size; i++) printf("%d, ", east[i]); printf("}\n"); printf("S: { "); for (int i = 0; i < south_size; i++) printf("%d, ", south[i]); printf("}\n"); return 0; }
解决方案
现有代码的核心问题是:仅能处理每行单个方向块的输入,当一行包含多个方向块时,只会解析第一个方向,剩余内容会被丢弃。要兼容两种格式,需修改read_tokens函数,改为逐块解析方向数据,而非逐行处理。
修改后的read_tokens函数
void read_tokens(int *north, int *west, int *east, int *south, int *north_size, int *west_size, int *east_size, int *south_size) { char buffer[MAX_TOKENS]; while (fgets(buffer, MAX_TOKENS, stdin) != NULL) { buffer[strcspn(buffer, "\n")] = 0; char *ptr = buffer; ptr = skip_whitespace(ptr); while (*ptr != '\0') { // 检查是否遇到END,终止所有输入 if (strncmp(ptr, "END", 3) == 0 && (ptr[3] == '\0' || isspace(ptr[3]))) { goto end_input; } // 验证方向字符有效性 if (!strchr("NWES", *ptr)) { printf("Nespravny vstup.\n"); // 跳过无效内容,继续处理后续字符 while (*ptr != '\0' && !isspace(*ptr)) ptr++; ptr = skip_whitespace(ptr); continue; } char dir = *ptr; ptr++; // 跳过方向后的冒号和空白 while (*ptr != '\0' && (*ptr == ':' || isspace(*ptr))) ptr++; // 检查是否存在左大括号 if (*ptr != '{') { printf("Nespravny vstup.\n"); while (*ptr != '\0' && !isspace(*ptr)) ptr++; ptr = skip_whitespace(ptr); continue; } ptr++; // 跳过左大括号 // 找到右大括号位置 char *end_brace = strchr(ptr, '}'); if (!end_brace) { printf("Nespravny vstup.\n"); break; } // 临时替换右大括号为'\0',方便拆分数字 char temp = *end_brace; *end_brace = '\0'; // 解析数字部分 char *num_token = skip_whitespace(ptr); while (num_token != NULL && *num_token != '\0') { char *comma = strchr(num_token, ','); if (comma) *comma = '\0'; num_token = skip_whitespace(num_token); int val = atoi(num_token); // 根据方向存储数据 switch (dir) { case 'N': north[(*north_size)++] = val; break; case 'W': west[(*west_size)++] = val; break; case 'E': east[(*east_size)++] = val; break; case 'S': south[(*south_size)++] = val; break; } if (!comma) break; num_token = comma + 1; } // 恢复右大括号 *end_brace = temp; // 移动到右大括号之后,跳过空白 ptr = end_brace + 1; ptr = skip_whitespace(ptr); } } end_input:; }
关键修改说明
- 逐块解析:不再依赖
strtok的全局状态,改为手动扫描输入字符串,逐个提取X:{...}格式的方向块,不管这些块在同一行还是多行。 - END检测:在扫描过程中随时检查是否遇到
END,无论END是单独一行还是与其他方向块同行,都会立即终止输入。 - 健壮性提升:增加了格式错误的处理逻辑,比如无效方向字符、缺少大括号等情况,避免程序崩溃,同时跳过无效内容继续处理后续输入。
- 空白兼容:全程处理输入中的空白字符,支持方向块之间任意数量的空格或制表符分隔。
修改后的程序可同时兼容两种输入格式,输入END即可终止输入。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

