4

I am a noob teaching myself to program in C using The C Programming Language, Second Edition (by K&R). In Chapter 1 Section 1.5.1 File Copying, the authors touch very briefly on operational precedence when making comparison between values, underscoring the importance of using parenthesis, in this case, to ensure that assignment is made to the variable 'c' before the comparison is evaluated. They make the assertion that:

    c = getchar() != EOF

is equivalent to

    c = (getchar() != EOF)

Which "has the undesired effect of setting c to 0 or 1, depending on whether or not the call of getchar encountered end of file"

The authors then pose Excercise 1-6 - Verify that the expression getchar () != EOF is 0 or 1

Based on the author's previous assertion, this seemed almost trivial so I created this code:

#include <stdio.h>

main()
{
    int c;

    while (c = (getchar() != EOF))
        putchar(c);
}

Unfortunately, when I run the program, it simply outputs whatever characters I type in the command window rather than the expected string of 1 or 0 if EOF is encountered.

While I am a noob, I think I get the logic that the authors are trying to teach and yet I can not demonstrate this simple task. In this case, should not the variable c take on the value that the comparison expression evaluated to rather than whatever character getchar() happens to fetch, particularly because of the location of the parenthesis? If c is indeed taking on the value of the comparison, putchar() should only output 0 or 1 and yet, as formulated, it outputs what I type in the command window. What am I doing wrong? What do I not understand? Could it be my compiler? I am coding in in Visual Studio 2017 Community edition on Windows 10 on x64 architecture. I have Tiny C Compiler but have not tried executing from command prompt with TCC yet.

iBug
  • 30,581
  • 7
  • 64
  • 105
H3G3moKnight
  • 115
  • 7
  • 1
    The integer values `0` or `1` are not really printable characters in any encoding. Use e.g. `printf("%d\n", i)` instead. – Some programmer dude Nov 26 '17 at 05:28
  • Maybe OP is seeing whatever input OP gives..Yes those are not something menaingful – user2736738 Nov 26 '17 at 05:29
  • Maybe `((c = getchar()) != EOF)`?? – David C. Rankin Nov 26 '17 at 05:31
  • Guys. I'm amazed at your rapid commenting speed. – iBug Nov 26 '17 at 05:32
  • And NO it is not your compiler. Make sure you are using the VS Developer Console and using `cl` (`cl.exe`) from the command line with the minimum options `cl /nologo /Wall /Ox /Feyourexe /Tc yoursource.c` (you can add `/Fo`, e.g. `/Foobjfile` to name the object file as well) It helps to have `obj` and `bin` subdirectories to keep your soucefile dir clean and use `/Foobj/thename /Febin/thename /Tc thename.c` to put the object files in the `obj` subdir and the executables in the `bin` subdir. Good luck. (use `/wd####` to suppresse individual warnings) – David C. Rankin Nov 26 '17 at 05:37
  • I poked this code into a mingw-gcc environment and changed to `putchar(c?'1':'0');` and got no output. I put an `fflush(stdout);` after the `putchar()` and then I see output, but only after hitting enter. I think the POSIX implementations of this function may vary from the expectations of the K&R authors. – lockcmpxchg8b Nov 26 '17 at 05:37
  • @lockcmpxchg8b Because **input and output are both line-buffered**. – iBug Nov 26 '17 at 05:47
  • @lockcmpxchg8b So standard C library function no longer operate they way that K&R authors would have understood them in their time? Are standard libraries truly standard across platform or are they platform dependent? – H3G3moKnight Nov 26 '17 at 05:49
  • @H3G3moKnight You may not be understanding ***line-buffered*** correctly. – iBug Nov 26 '17 at 05:50
  • @Someprogrammerdude This was helpful, thanks. – H3G3moKnight Nov 26 '17 at 05:50
  • @iBug: I think I don't understand it well enough either. Do you happen to have a reference? – lockcmpxchg8b Nov 26 '17 at 05:52
  • @lockcmpxchg8b There's already [one](https://stackoverflow.com/a/36573578/5958455) on Stack Overflow. – iBug Nov 26 '17 at 05:53
  • @lockcmpxchg8b And [the GNU manual for libc](http://www.gnu.org/s/libc/manual/html_node/Buffering-Concepts.html). – iBug Nov 26 '17 at 05:54
  • @DavidC.Rankin you misread the question – M.M Nov 26 '17 at 06:53
  • @M.M - chock another up to my misread list -- certainly isn't my first, and probably won't be my last... – David C. Rankin Nov 26 '17 at 07:31
  • @AnttiHaapala How did you add 3 dupe links? – iBug Nov 26 '17 at 08:03
  • @iBug Mjölnir wielders can add up to 5 dupe links with a simple edit functionality. – Antti Haapala Nov 26 '17 at 08:04

2 Answers2

4

When you run the program, the characters that you see doesn't come from your program. It's the console (or terminal)'s echo funcion that shows whatever character you have typed (and you can even erase them before you hit Enter). Your program only outpus characters with ASCII code 0 or 1, both of which are invisible.

If you change putchar(c) to printf("%d", c) you'll be able to see a sequence of 1s. No zero will appear because when c becomes zero, the loop stops and it won't be printed.

Characters '0' and '1' have the ASCII code of 48 and 49, respectively, despite the fact that your terminal may use another encoding. If you want to output a literal number 0, use the character notation. You can also try putchar(48) but don't use this too much (You'll later find out that it's highly discouraged to use magic numbers in your program).

putchar('0');
        ^ ^

The assertion that

c = getchar() != EOF;

is equivalent to

c = (getchar() != EOF);

is because of operator precedence. The operator != (inequality) has a higher precedence over = (value assignment), so it gets evaluated prior to assignment.

Finally, it's extremely rare for someone to have written that. The correct intention is to write this:

while ( (c = getchar()) != EOF )
iBug
  • 30,581
  • 7
  • 64
  • 105
2

The thing is c = (getchar() != EOF) it will get one input character and then it compares. Result will be 1 in case it is not EOF. Then it is assigned. The value of assignment statement is the value that is being assigned. It enters the loop. Prints the character having ascii value 1. But that character is non-printable so you don't see anything.

Once it gets EOF it will break from the loop. So you never get to see anything other than the character which has ascii value of 1.(Even you don't see that also as it is non-printable). These are known as ascii-control characters. (Not belong to the printable class).

Also you said as c=0 or c=1 it should print 0 or 1. Then try this simple code

int c= 68;
putchar(c);

Check the output and you will get the idea what happens when we try to print. It's the character whose ascii code is 68, that is printed, not the value 68.

The right way to do it would be ((c = getchar()) != EOF).

Originally I mentioned that on some machines it prints some funny characters. The representation of the non-printable characters depend on the used charset. It might be some non-standard encoding (non-unicode) which assigns to the ascii code 1 some representation.(breaking the idea of nonprintables)

user2736738
  • 28,590
  • 4
  • 37
  • 52