You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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:;
}

关键修改说明

  1. 逐块解析:不再依赖strtok的全局状态,改为手动扫描输入字符串,逐个提取X:{...}格式的方向块,不管这些块在同一行还是多行。
  2. END检测:在扫描过程中随时检查是否遇到END,无论END是单独一行还是与其他方向块同行,都会立即终止输入。
  3. 健壮性提升:增加了格式错误的处理逻辑,比如无效方向字符、缺少大括号等情况,避免程序崩溃,同时跳过无效内容继续处理后续输入。
  4. 空白兼容:全程处理输入中的空白字符,支持方向块之间任意数量的空格或制表符分隔。

修改后的程序可同时兼容两种输入格式,输入END即可终止输入。

内容的提问来源于stack exchange,提问作者Adrian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 11:25:14