奇怪的C程序输出随着重定向而改变

时间:2018-06-03 08:30:00

标签: c

我写了一个程序来解决K& R的练习2-2。

#include<stdio.h>

#define MAXLINE 1000

/* write an equivalent loop without using && or || */
int Getline(char s[], int lim);

int main()
{
    int len;
    char line[MAXLINE];

    while ((len = Getline(line, MAXLINE)) > 0) {
        printf("%s%15s%d\n", line, "length: ", len);
    }

    return 0;
}

int Getline(char s[], int lim)
{
    int flag = 1;
    int i = 0, c = 0;

    for (i = 0; flag == 1; ++i) {
        if (i < lim - 1) {
            if ((c = getchar()) != '\n') {
                if (c != EOF) {
                    ;
                }
                else {
                    flag = 0;
                }
            }
            else {
                flag = 0;
            }
        }
        else {
            flag = 0;
        }
        if (flag == 1) {
            s[i] = c;
        }
    }

    if (c == '\n') {
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

这个程序错了......以一种奇怪的方式。 我使用重定向运行此代码,如

./2-2 <in

文件中的

  

获取此行。

然后输出到屏幕是无数的

  

G长度:1

看起来程序陷入了循环。但是当我停止使用重定向并只输入获取此行。到终端时,虽然它仍然是错误的,但无数输出消失了。为什么呢?

2 个答案:

答案 0 :(得分:1)

问题在于:

for (i = 0; flag == 1; ++i) {
                       ^^^
                       i will always increment to at least 1
                       before the for-loop ends
                       so your function will never return 0

不是在for循环中递增,而是在插入新元素后才增加。像

    if (flag == 1) {
        s[i] = c;
        ++i;
    }

您可以使用while循环代替for循环,例如:

int i = 0;
while (flag == 1)
{
    ...
}

下一步是摆脱旗帜并使用break insted。像:

int i = 0;
while (1)
{
    if (i >= lim - 1) break;

    ...
}

您的代码将更短,更易于阅读。

答案 1 :(得分:1)

你的功能也很复杂了。如果您只想从文件中重定向该行,请将其存储在line中,并确保它 nul-terminated (并且没有尾随'\n' - 您不应该这样做'你可以做一些非常简单的事情:

int Getline (char *s, int lim)
{
    int i = 0;              /* char count - length */
    while (i < lim - 1) {   /* loop while chars fit */
        int c = getchar();  /* getchar */
        if (c == EOF)       /* validate EOF? */
            goto done;
        if (c == '\n')      /* validate newline */
            continue;
        s[i++] = c;         /* good char, increment len */
    }
    done:;
    s[i] = 0;               /* nul-terminate */
    return i;               /* return length */
}

注意:来自您之前未使用break的评论,然后一个简单的goto同样有用)

示例使用/输出

鉴于您的文件包含第"Get this line."

$ ./bin/equivloop <dat/in
Get this line.       length: 14

(注意:如果存储换行符,则长度为15,输出将在下一行)