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 #define
d 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"
}