Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
243 views
in Technique[技术] by (71.8m points)

c - Why does a loop containing getchar() exit when ' ' is entered?

I was working with K&R, and it extensively uses getchar() for input in basics. But the problem is I am unable to fully understand its behavior.

Below is a piece of code:

#include <stdio.h>

int main() {
    char c,i;
    char line[10000];
    i = 0;

    while((c=getchar()) != EOF && c!= '
') {
        line[i++] = c;
    }

    printf("%s",line);
}

The code works as expected.

My problem with this is: why it terminates when I press enter? How does it know that newline is the termination condition while I am still writing input and the program is at c=getchar()?

I know it is not the default getchar() behavior like scanf() because when I remove the newline condition, the program doesn't terminate at newline. Maybe my question exceeds the getchar() and is a general question.

Suppose my input is Hello and I press enter.

First, the c variable becomes 'H', it gets stored in line, then 'e', then 'l', then 'l', then 'o', after that it encounters the newline and loop terminates. It's well understood.

I want to know why it started reading the characters after I press enter. I was hoping for a newline and write some more characters.

question from:https://stackoverflow.com/questions/65869283/why-does-a-loop-containing-getchar-exit-when-n-is-entered

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

There are two parts to understanding that code, and there is also an error that chqrlie has made a good argument towards fixing.

Part 0: why you should use int for reading with getchar

As many have commented, using char c is dangerous if you are going to read with getchar, as getchar() returns signed integers, and most notably EOF -- which is generally #defined as -1 to signal end-of-file. Standard char may or may not have a sign - this would make your program unable to recognize -1 / EOF. So let us change the first line to

int c,i; 

Part 1: why is special

According to man, getchar() is equivalent to getc(stdin), which is equivalent to fgetc() except that it may be implemented as a macro which evaluates its stream (stdin, in this case) more than once.

Importantly, every time it is called, it consumes a character from its input. Every call to getchar returns the next character from the input, as long as there are characters to return. If none remain, it returns EOF instead.

Now, stdin, the standard input, is generally line-buffered, which means that programs will not have access to the actual characters until lines are terminated with a . You can test this with this program:

#include <stdio.h>

int main() {
    int c,i;
    char line[10000];
    i = 0;

    while((c=getchar()) != EOF && c!= 'a') { // <-- replaced `
` with `a`
        line[i++] = c;
    }

    printf("%s",line);
}

If you run it, it will still not do anything until is pressed; but when pressed, the input will finish on the 1st a (not-included). Note that output afterwards will be undefined, since there is no guarantee that there will be a to terminate the string afterwards. To avoid this pitfall, see the rewritten program at the very end.

Part 2: why does the loop condition work as it does

You can rewrite the loop condition as follows. This makes it easier to see what is going on:

// loop condition looks up next char, tests it against EOF and `
`
while((c=getchar()) != EOF && c!= '
') { line[i++] = c; }

// loop condition broken up for readability; fully equivalent to above code
while (true) {
   c = getchar();
   if (c == EOF || c == '
') {
      break; // exit loop
   } else {
      line [i++] = c;
   }
}

Epilogue: improved code

#include <stdio.h>
#define BUFSIZE 10000

int main() {
    char line[BUFSIZE]; // avoid magic number
    int c, i = 0;       // initialize at point of declaration
    
    while (i<BUFSIZE-1              // avoid buffer overflow
         && (c=getchar()) != EOF    // do not read past EOF
         && c!= '
') {             // do not read past end-of-line
        line[i++] = c;
    }

    line[i++] = 0;      // ensure that the string is null-terminated
    printf("%s",line);
    return 0;           // explicitly return "no error"
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...