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

K&R习题1-21:entab程序空格转制表符输出长度异常求助

K&R《C程序设计语言》习题1-21:Entab程序问题排查与修正

需求说明

编写entab程序,用最少数量的制表符(Tab)和空格替换连续空格,实现相同间距:

  • 制表位(Tab Stop)设为8
  • 当制表符或单个空格都能到达下一个制表位时,优先使用制表符

第一版代码及问题

代码实现

#include <stdio.h>

#define TAB 8

void entab(int space);

int main()
{
    int c, i;

    i = 0;

    while ((c = getchar()) != EOF)
    {
        if (c == ' ')
            ++i;

        else if (c == '\t')
            i = i + TAB;

        else
        {
            entab(i);
            i = 0;
            putchar(c);
        }
    }

    return 0;
}

void entab(int space)
{
    int i;

    for (i = 1; space >= TAB; ++i)
        if (i == TAB)
        {
            putchar('\t');
            i = 0;
            space = space - TAB;
        }

    for (i = 0; i < space; ++i)
        putchar(' ');
}

问题现象

输入内容为3个空格+1个制表符+5个空格+j时,输出的字符长度比输入更长(原截图显示:第一行是输入,第二行是输出)。

问题原因

  1. 制表符处理逻辑错误:直接给空格计数加TAB(8),但制表符的作用是跳到下一个制表位,而非固定占8个空格。比如当前处于第3个字符位置,一个制表符应占8 - 3%8 = 5个空格位置,而非直接加8。
  2. entab函数循环冗余:用i从1计数到TAB才输出制表符,逻辑完全没必要,直接计算可替换的制表符数量即可。

第二版代码及新问题

代码实现

#include <stdio.h>

#define TAB 8

void entab(int space);

int main()
{
    int c, i, l;

    i = l = 0;

    while ((c = getchar()) != EOF)
    {
        ++l;

        if (c == ' ')
            ++i;

        else if (c == '\t')
            i = i + TAB - (l%8);

        else
        {
            entab(i);
            i = 0;
            putchar(c);
        }

        if (c == '\n')
            l = 0;
    }

    return 0;
}


void entab(int space)
{
    int i;

    for (i = 0; space >= TAB; ++i)
        if (i == TAB)
        {
            putchar('\t');
            i = -1;
            space = space - TAB;
        }

    for (i = 0; i < space; ++i)
        putchar(' ');
}

问题现象

输出总是比输入少一个字符(原截图显示:输入输出长度存在明显差异)。

问题原因

  1. 位置计数时机错误:++l在处理字符前执行,导致制表位计算偏移1位,比如第一个字符未处理时l就变为1,l%8的结果出错。
  2. entab函数循环逻辑仍错误:用i计数到TAB才输出制表符的逻辑完全多余,应直接计算空格数中包含的完整制表符数量。
  3. 未处理结尾剩余空格:输入遇到EOF时,若还有未处理的累计空格,没有调用entab输出。

修正后的代码

#include <stdio.h>

#define TAB 8

void entab(int current_pos, int space_count);

int main()
{
    int c;
    int current_pos = 0;  // 当前光标位置,从0开始计数
    int space_count = 0;  // 累计连续空格数

    while ((c = getchar()) != EOF)
    {
        if (c == ' ')
        {
            space_count++;
        }
        else if (c == '\t')
        {
            // 计算制表符等效的空格数:到下一个制表位的距离
            int needed = TAB - (current_pos % TAB);
            space_count += needed;
            // 立即处理累计空格
            entab(current_pos, space_count);
            current_pos += needed;
            space_count = 0;
        }
        else
        {
            // 先处理累计的空格
            if (space_count > 0)
            {
                entab(current_pos, space_count);
                current_pos += space_count;
                space_count = 0;
            }
            // 输出当前字符并更新位置
            putchar(c);
            current_pos = (c == '\n') ? 0 : current_pos + 1;
        }
    }

    // 处理输入结束后剩余的空格
    if (space_count > 0)
    {
        entab(current_pos, space_count);
    }

    return 0;
}

void entab(int current_pos, int space_count)
{
    // 计算当前位置到下一个制表位的空格数
    int space_to_next_tab = TAB - (current_pos % TAB);

    // 优先使用制表符,确保用最少字符
    while (space_count >= space_to_next_tab)
    {
        putchar('\t');
        space_count -= space_to_next_tab;
        space_to_next_tab = TAB;  // 后续制表位间隔为完整的TAB
    }

    // 剩余空格用单个空格填充
    for (int i = 0; i < space_count; i++)
    {
        putchar(' ');
    }
}

修正要点

  1. 用current_pos准确跟踪光标位置,从0开始计数,避免偏移。
  2. 正确计算制表符的等效空格数,即到下一个制表位的距离。
  3. entab函数逻辑简化:优先输出制表符,剩余空格用单个空格填充,确保字符数量最少。
  4. 调整位置计数时机,先处理字符再更新位置。
  5. 补充处理输入结束后剩余的空格,避免遗漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 15:43:18