C程序不一致

时间:2013-12-01 21:18:15

标签: c kernighan-and-ritchie

我正在研究练习的第二个解决方案:

http://users.powernet.co.uk/eton/kandr2/krx121.html

#include <stdio.h>

#define TABSTOP 4

int main(void)
{
    size_t spaces = 0;
    int ch;
    size_t x = 0;               /* position in the line */
    size_t tabstop = TABSTOP;   /* get this from the command-line 
                                 * if you want to */

    while ((ch = getchar()) != EOF)
    {
        if (ch == ' ')
        {
            spaces++;
        }
        else if (spaces == 0) /* no space, just printing */
        {
            putchar(ch);
            x++;
        }
        else if (spaces == 1) /* just one space, never print a tab */
        {
            putchar(' ');
            putchar(ch);
            x += 2;
            spaces = 0;
        }
        else
        {
            while (x / tabstop != (x + spaces) / tabstop) 
                /* are the spaces reaching behind the next tabstop ? */
            {
                putchar('\t');
                x++;
                spaces--;
                while (x % tabstop != 0)
                {
                    x++;
                    spaces--;
                }
            }

            while (spaces > 0) /* the remaining ones are real space */
            {
                putchar(' ');
                x++;
                spaces--;
            }
            putchar(ch); /* now print the non-space char */
            x++;
        }
        if (ch == '\n')
        {
            x = 0; /* reset line position */
        }
    }

    return 0;
}

我有两个用例:

  • 5个字符,然后是2个空格,然后是一个字符,
  • 7个字符,然后是2个空格,然后是一个字符。

在用例1中,x在遇到第二个空格之前等于5,在用例2中,x在遇到第二个空格之前等于7。但在这两种情况下,在执行下一个块之前会出现2个后续空格:

while (x / tabstop != (x + spaces) / tabstop)

在这种情况下,请注意您在比较的两边用tabstop划分x。唯一的区别是在右侧,您在执行除法之前将x增加空格。这是一个重要的区别。只要空格等于0,那么两个除法将返回相同的值,比较将返回true,而while将不会执行。

但是,如果空格大于0,则此比较可能会返回false。例如,如果x为7:(7 / 4 != (7 + 1) / 4),则在这种情况下,while循环将执行。但还有另一个变数。如果x不是7,而是如果它是5,并且如果空格是2,那么它将不会执行,因为5/4 == 7/4,因为两者都产生1(我们删除余数)。

为什么在5个常规字符之后遇到第二个空格会产生不同的结果,而不是在7个常规字符后遇到第二个空格?我不明白为什么在一种情况下它会插入一个标签,而另一种情况则不会,在这两种情况下,字符后面都有2个连续的空格。

3 个答案:

答案 0 :(得分:2)

您的代码与您引用的示例不同。

您引用的示例仅在出现四个连续空格时用制表符替换四个空格。

如果“单词”在标签停止的多个之后或之后开始,您似乎希望程序用标签替换“单词”之间的空格。

两个不同的要求。

你说5个字符加上两个空格加上一个字符应该导致用一个标签替换两个空格作为一个字符,第二个“字”从标签停止处开始。

目前

while (x / tabstop != (x + spaces) / tabstop)

x的值是5,5 / 4 = 1。空格的值是2,(5 + 2)/ 4 = 1.相等。没有标签。程序正在按照程序进行操作。

您希望用制表符替换这两个空格,因为第8个字符会开始一个单词。

您的示例版本不会这样做。 x的值为7。

您似乎希望x的值为8. 5/4 = 1,8 / 4 = 2,替换标签。

当您有两个或更多空格时,更改程序以包括计数中的当前字符,看看会发生什么。

答案 1 :(得分:0)

我会在一段时间之前发布我为该练习编写的代码。在命令行上传递“TABSTOP”,如果不是,则默认为4.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BUFFER 1000

int main(int argc, char *argv[])
{
    int i = 0; 
    char c;
    int numspace = 0;
    int tablen;
    char string[BUFFER];

    tablen = !argv[1] ? 4 : atoi(argv[1]);

    for(i = 0; i < BUFFER; i++) string[i] = '\0';

    i = 0;

    for(i = 0; (c = getchar()) != EOF && i < BUFFER-1; i++) {
        if(c == ' ') {
            numspace++;
            if(numspace == tablen) {
                i -= numspace-1;
                c = '\t';
                numspace = 0;
            }
        } else if(!isblank(c)) {
            numspace = 0;
        }
        string[i] = c;
    }

    printf("\n%s\n", string);
    return 0;
}

答案 2 :(得分:0)

问题中的代码不处理输入中的任何选项卡,这是一个有争议的设计决策。它永远不会检查当前字符是否是制表符。然而,这与问题相关(尽管我认为它是程序设计中的缺陷)。

给定输入行:

abcde  fghi

当它进入'else'子句时:

  • ch == 'f'
  • x == 5
  • spaces == 2
  • tabstop == 4

第一个循环条件是:

while (x / tabstop != (x + spaces) / tabstop)

对于给定的值:

  • x / tabstop 5 / 4是1
  • (x + spaces) / tabstop (5 + 2) / 4 7 / 4是1

条件不正确,因此循环不执行;这是正确的行为。下一个循环输出两个空格,然后f

现在考虑输入:

abcdefg  hijk

我们得到:

  • ch == 'h'
  • x == 7
  • spaces == 2
  • tabstop == 4

因此,循环条件是:

  • x / tabstop 7 / 4是1
  • (x + spaces) / tabstop (7 + 2) / 4 9 / 4是2

因此,代码会循环一次,生成制表符。以下代码是:

x++;
spaces--;

这会将x设置为8,将spaces设置为1。

while (x % tabstop != 0)
{
    x++;
    spaces--;
}

由于条件为false,因此永远不会执行此循环。下一个循环输出一个空格,然后h。这是正确的,与第一种情况不同。