简体   繁体   中英

Weird output of a C program change with redirection

I write a program to solve Exercise 2-2 of K&R.

#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;
}

This program is wrong...in a weird way. I run this code with redirection like

./2-2 <in

with the in file

Get this line.

Then the output to the screen is countless

G length: 1

It looks like the program stuck in a loop. But when I stop using redirection and just type Get this line. to the terminal, though it is still wrong, the countless output disappeared. Why?

The problem is here:

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

Instead of incrementing in a for-loop, only increment after inserting a new element. Like

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

Instead of a for-loop, you could use a while loop, like:

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

The next step is to get rid of the flag and use break insted. Like:

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

    ...
}

Your code will be much shorter and easier to read.

You have also complicated your function quite a bit. If you simply want to get the line redirected from the file, store it in line and insure it is nul-terminated (and without the trailing '\\n' - which you shouldn't leave dangling off strings you store), you could do something quite simple like:

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 */
}

( note: from your comment about not having used break before, then a simple goto works just as well)

Example Use/Output

Given your file containing the line "Get this line."

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

(note: if you store the newline, then the length would be 15 and that output would be on the next line)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM