K&R Exercise 1-6 & 1-7: working with EOF

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
5
down vote

favorite












I'm working through K&R at the moment and I've found my first exercise that seems to be a good use for my first CodeReview post.



Exercise 1-6 - Verify that the expression getchar() != EOF is 0 or 1.



Exercise 1-7 - Write a program to print the value of EOF.



I've completed both of these together in the same file.



I think I've understood the question here, but let me know if I haven't. I wanted to post here before looking up any sort of "official" answer so that I could learn some stuff instead of just "going to the back of the book".



#include <stdio.h>

void main()

int c;

c = getchar();
while ((c = getchar()) != EOF == (0


Compiled with:



gcc putchar.c -o putchar


Sending EOF using:



<ctrl-d>


Runs through fine, and when I ctrl-d I get a -1 return code.







share|improve this question

















  • 7




    I don't see the exercise but (0 | 1) isn't probably what you think it is. | is bitwise OR then it's equivalent to 1. Now it then can be reduced to getchar() != EOF == 1 which is again equivalent to getchar() != EOF (because == returns 1 or 0 and it's mandated by the standard).
    – Adriano Repetti
    Jul 12 at 16:15











  • Ahhhhh right yeah I've definitely misused it then! Cheers for that, I'll have a look over my code and make an edit! Thanks.
    – John Von Neumann
    Jul 12 at 16:28






  • 2




    I think (but I may be wrong) that someone considers the question off-topic because code does not work as intended. I don't agree because close reason says (emphasis is mine) "...working correctly, to the best of the author's knowledge" then this is a perfectly fine question.
    – Adriano Repetti
    Jul 12 at 16:40






  • 2




    @AdrianoRepetti While that may have been true at the time of posting, it is no longer true (as the OP is now aware of the bug). It is also what might be considered an obvious bug (at least obvious after having encountered it many times before). OP, you can (almost) always edit your question to make it on-topic, once you have the correct solution. The only exception to that is if you have received answer (so as not to invalidate them).
    – Graipher
    Jul 12 at 17:23






  • 3




    @Graipher The code works, just not for the reason that the author thought. That misconception is perfect material to be discussed in a Code Review answer — no need to edit the question.
    – 200_success
    Jul 12 at 18:39
















up vote
5
down vote

favorite












I'm working through K&R at the moment and I've found my first exercise that seems to be a good use for my first CodeReview post.



Exercise 1-6 - Verify that the expression getchar() != EOF is 0 or 1.



Exercise 1-7 - Write a program to print the value of EOF.



I've completed both of these together in the same file.



I think I've understood the question here, but let me know if I haven't. I wanted to post here before looking up any sort of "official" answer so that I could learn some stuff instead of just "going to the back of the book".



#include <stdio.h>

void main()

int c;

c = getchar();
while ((c = getchar()) != EOF == (0


Compiled with:



gcc putchar.c -o putchar


Sending EOF using:



<ctrl-d>


Runs through fine, and when I ctrl-d I get a -1 return code.







share|improve this question

















  • 7




    I don't see the exercise but (0 | 1) isn't probably what you think it is. | is bitwise OR then it's equivalent to 1. Now it then can be reduced to getchar() != EOF == 1 which is again equivalent to getchar() != EOF (because == returns 1 or 0 and it's mandated by the standard).
    – Adriano Repetti
    Jul 12 at 16:15











  • Ahhhhh right yeah I've definitely misused it then! Cheers for that, I'll have a look over my code and make an edit! Thanks.
    – John Von Neumann
    Jul 12 at 16:28






  • 2




    I think (but I may be wrong) that someone considers the question off-topic because code does not work as intended. I don't agree because close reason says (emphasis is mine) "...working correctly, to the best of the author's knowledge" then this is a perfectly fine question.
    – Adriano Repetti
    Jul 12 at 16:40






  • 2




    @AdrianoRepetti While that may have been true at the time of posting, it is no longer true (as the OP is now aware of the bug). It is also what might be considered an obvious bug (at least obvious after having encountered it many times before). OP, you can (almost) always edit your question to make it on-topic, once you have the correct solution. The only exception to that is if you have received answer (so as not to invalidate them).
    – Graipher
    Jul 12 at 17:23






  • 3




    @Graipher The code works, just not for the reason that the author thought. That misconception is perfect material to be discussed in a Code Review answer — no need to edit the question.
    – 200_success
    Jul 12 at 18:39












up vote
5
down vote

favorite









up vote
5
down vote

favorite











I'm working through K&R at the moment and I've found my first exercise that seems to be a good use for my first CodeReview post.



Exercise 1-6 - Verify that the expression getchar() != EOF is 0 or 1.



Exercise 1-7 - Write a program to print the value of EOF.



I've completed both of these together in the same file.



I think I've understood the question here, but let me know if I haven't. I wanted to post here before looking up any sort of "official" answer so that I could learn some stuff instead of just "going to the back of the book".



#include <stdio.h>

void main()

int c;

c = getchar();
while ((c = getchar()) != EOF == (0


Compiled with:



gcc putchar.c -o putchar


Sending EOF using:



<ctrl-d>


Runs through fine, and when I ctrl-d I get a -1 return code.







share|improve this question













I'm working through K&R at the moment and I've found my first exercise that seems to be a good use for my first CodeReview post.



Exercise 1-6 - Verify that the expression getchar() != EOF is 0 or 1.



Exercise 1-7 - Write a program to print the value of EOF.



I've completed both of these together in the same file.



I think I've understood the question here, but let me know if I haven't. I wanted to post here before looking up any sort of "official" answer so that I could learn some stuff instead of just "going to the back of the book".



#include <stdio.h>

void main()

int c;

c = getchar();
while ((c = getchar()) != EOF == (0


Compiled with:



gcc putchar.c -o putchar


Sending EOF using:



<ctrl-d>


Runs through fine, and when I ctrl-d I get a -1 return code.









share|improve this question












share|improve this question




share|improve this question








edited Jul 12 at 16:17









200_success

123k14143399




123k14143399









asked Jul 12 at 15:54









John Von Neumann

1335




1335







  • 7




    I don't see the exercise but (0 | 1) isn't probably what you think it is. | is bitwise OR then it's equivalent to 1. Now it then can be reduced to getchar() != EOF == 1 which is again equivalent to getchar() != EOF (because == returns 1 or 0 and it's mandated by the standard).
    – Adriano Repetti
    Jul 12 at 16:15











  • Ahhhhh right yeah I've definitely misused it then! Cheers for that, I'll have a look over my code and make an edit! Thanks.
    – John Von Neumann
    Jul 12 at 16:28






  • 2




    I think (but I may be wrong) that someone considers the question off-topic because code does not work as intended. I don't agree because close reason says (emphasis is mine) "...working correctly, to the best of the author's knowledge" then this is a perfectly fine question.
    – Adriano Repetti
    Jul 12 at 16:40






  • 2




    @AdrianoRepetti While that may have been true at the time of posting, it is no longer true (as the OP is now aware of the bug). It is also what might be considered an obvious bug (at least obvious after having encountered it many times before). OP, you can (almost) always edit your question to make it on-topic, once you have the correct solution. The only exception to that is if you have received answer (so as not to invalidate them).
    – Graipher
    Jul 12 at 17:23






  • 3




    @Graipher The code works, just not for the reason that the author thought. That misconception is perfect material to be discussed in a Code Review answer — no need to edit the question.
    – 200_success
    Jul 12 at 18:39












  • 7




    I don't see the exercise but (0 | 1) isn't probably what you think it is. | is bitwise OR then it's equivalent to 1. Now it then can be reduced to getchar() != EOF == 1 which is again equivalent to getchar() != EOF (because == returns 1 or 0 and it's mandated by the standard).
    – Adriano Repetti
    Jul 12 at 16:15











  • Ahhhhh right yeah I've definitely misused it then! Cheers for that, I'll have a look over my code and make an edit! Thanks.
    – John Von Neumann
    Jul 12 at 16:28






  • 2




    I think (but I may be wrong) that someone considers the question off-topic because code does not work as intended. I don't agree because close reason says (emphasis is mine) "...working correctly, to the best of the author's knowledge" then this is a perfectly fine question.
    – Adriano Repetti
    Jul 12 at 16:40






  • 2




    @AdrianoRepetti While that may have been true at the time of posting, it is no longer true (as the OP is now aware of the bug). It is also what might be considered an obvious bug (at least obvious after having encountered it many times before). OP, you can (almost) always edit your question to make it on-topic, once you have the correct solution. The only exception to that is if you have received answer (so as not to invalidate them).
    – Graipher
    Jul 12 at 17:23






  • 3




    @Graipher The code works, just not for the reason that the author thought. That misconception is perfect material to be discussed in a Code Review answer — no need to edit the question.
    – 200_success
    Jul 12 at 18:39







7




7




I don't see the exercise but (0 | 1) isn't probably what you think it is. | is bitwise OR then it's equivalent to 1. Now it then can be reduced to getchar() != EOF == 1 which is again equivalent to getchar() != EOF (because == returns 1 or 0 and it's mandated by the standard).
– Adriano Repetti
Jul 12 at 16:15





I don't see the exercise but (0 | 1) isn't probably what you think it is. | is bitwise OR then it's equivalent to 1. Now it then can be reduced to getchar() != EOF == 1 which is again equivalent to getchar() != EOF (because == returns 1 or 0 and it's mandated by the standard).
– Adriano Repetti
Jul 12 at 16:15













Ahhhhh right yeah I've definitely misused it then! Cheers for that, I'll have a look over my code and make an edit! Thanks.
– John Von Neumann
Jul 12 at 16:28




Ahhhhh right yeah I've definitely misused it then! Cheers for that, I'll have a look over my code and make an edit! Thanks.
– John Von Neumann
Jul 12 at 16:28




2




2




I think (but I may be wrong) that someone considers the question off-topic because code does not work as intended. I don't agree because close reason says (emphasis is mine) "...working correctly, to the best of the author's knowledge" then this is a perfectly fine question.
– Adriano Repetti
Jul 12 at 16:40




I think (but I may be wrong) that someone considers the question off-topic because code does not work as intended. I don't agree because close reason says (emphasis is mine) "...working correctly, to the best of the author's knowledge" then this is a perfectly fine question.
– Adriano Repetti
Jul 12 at 16:40




2




2




@AdrianoRepetti While that may have been true at the time of posting, it is no longer true (as the OP is now aware of the bug). It is also what might be considered an obvious bug (at least obvious after having encountered it many times before). OP, you can (almost) always edit your question to make it on-topic, once you have the correct solution. The only exception to that is if you have received answer (so as not to invalidate them).
– Graipher
Jul 12 at 17:23




@AdrianoRepetti While that may have been true at the time of posting, it is no longer true (as the OP is now aware of the bug). It is also what might be considered an obvious bug (at least obvious after having encountered it many times before). OP, you can (almost) always edit your question to make it on-topic, once you have the correct solution. The only exception to that is if you have received answer (so as not to invalidate them).
– Graipher
Jul 12 at 17:23




3




3




@Graipher The code works, just not for the reason that the author thought. That misconception is perfect material to be discussed in a Code Review answer — no need to edit the question.
– 200_success
Jul 12 at 18:39




@Graipher The code works, just not for the reason that the author thought. That misconception is perfect material to be discussed in a Code Review answer — no need to edit the question.
– 200_success
Jul 12 at 18:39










1 Answer
1






active

oldest

votes

















up vote
4
down vote



accepted










This is a nice, clear, short attempt at the exercise.



You've avoided a couple of common problems:



  • You're correctly using int for the return value from getchar(). A common mistake is to be misled by the name and to assign directly to a char variable. That doesn't work, because truncating to char prevents EOF from being distinguished from a valid char value.

  • You've correctly matched the %d specifier to the type of EOF.


One simple way to improve your code is to get the compiler to point out weaknesses for you (by default, most C compilers are very lenient; you have to specifically ask for more warnings):



gcc -std=c11 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion putchar.c -o putchar


You can make it easier by writing a simple Makefile that contains just:



CFLAGS = -std=c11 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion


And you can then build simply with



make putchar


When you've enabled warnings, you'll see:



198374.c:3:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
void main()
^~~~


The fix for that should be obvious.




Now to the meat of the program. Firstly, before the loop we have a statement



 c = getchar();


This consumes and ignores one character. We probably didn't mean to throw that one away.




Now consider this expression:



 (c = getchar()) != EOF == (0 | 1)


We're actually comparing (after the assignment) c != EOF against 0|1. But | is the bitwise-or operator, so 0|1 evaluates to just 1. When c is not EOF, then c!=EOF is 1, and the condition is satisfied. The last time around the loop (when c becomes EOF), then c!=EOF is 0, and the loop exits.



What we want to do is save the result of c != EOF and compare that to 0 and to 1 separately. Or, even more simply for this exercise, just print it to standard output:



 do 
c = getchar();
printf("getchar() != EOF: %dn", c != EOF);
while (c != EOF);


NoteL given that we haven't been asked to copy the input to output, we shouldn't have the putchar() call.



If we really want to prove that c != EOF is always either 0 or 1, we could test it automatically:



 do 
c = getchar();
if ((c != EOF) != 0 && (c != EOF) != 1)
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;

while (c != EOF);


You might choose to use a switch statement instead of the if; I think that's clearer:



 c = getchar();
switch (c != EOF)
case 0: /* okay */
case 1: /* okay */
break;
default:
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;




Modified code



#include <stdio.h>

int main()

int c;

do
c = getchar();
switch (c != EOF)
case 0: /* okay */
case 1: /* okay */
break;
default:
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;

while (c != EOF);

printf("%dn", c);






share|improve this answer























  • Cheers for the awesome reply! Means a lot, and the Makefile stuff I had no clue about, thanks for that, works like a charm. The c = getchar() throwing away the first character I didn't know about, but I had noticed that it was happening, had no clue why though!
    – John Von Neumann
    Jul 13 at 14:33










  • "That doesn't work, becauseEOF is outside the range of any valid char." --> Not quite. EOF often has the value of -1 and a signed char typically has the range of -128 to 127. So having an EOF inside the char range is common. The "doesn't work" is due to getchar() retuning values in the unsigned char range and the negative EOF and these typical 257 different values are not distinguishable with an 8-bit char.
    – chux
    Jul 13 at 14:36










  • Oh yes - I hate these conversions between plain and unsigned char (such as with the to*() family of functions). EOF does have to have a negative value, and I mistakenly assumed that it just had to be more negative than CHAR_MIN.
    – Toby Speight
    Jul 13 at 14:49










  • Why do we do this? ` case 0: /* okay / case 1: / okay */` And not assign a success for the case statements? Except for the 1 of course.
    – John Von Neumann
    Jul 13 at 15:03











  • EDIT: Ignore me, I know why now haha. Because 0 is success so we just continue checking until EOF or an issue, hence the break on exit code 1.
    – John Von Neumann
    Jul 13 at 15:09










Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f198374%2fkr-exercise-1-6-1-7-working-with-eof%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
4
down vote



accepted










This is a nice, clear, short attempt at the exercise.



You've avoided a couple of common problems:



  • You're correctly using int for the return value from getchar(). A common mistake is to be misled by the name and to assign directly to a char variable. That doesn't work, because truncating to char prevents EOF from being distinguished from a valid char value.

  • You've correctly matched the %d specifier to the type of EOF.


One simple way to improve your code is to get the compiler to point out weaknesses for you (by default, most C compilers are very lenient; you have to specifically ask for more warnings):



gcc -std=c11 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion putchar.c -o putchar


You can make it easier by writing a simple Makefile that contains just:



CFLAGS = -std=c11 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion


And you can then build simply with



make putchar


When you've enabled warnings, you'll see:



198374.c:3:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
void main()
^~~~


The fix for that should be obvious.




Now to the meat of the program. Firstly, before the loop we have a statement



 c = getchar();


This consumes and ignores one character. We probably didn't mean to throw that one away.




Now consider this expression:



 (c = getchar()) != EOF == (0 | 1)


We're actually comparing (after the assignment) c != EOF against 0|1. But | is the bitwise-or operator, so 0|1 evaluates to just 1. When c is not EOF, then c!=EOF is 1, and the condition is satisfied. The last time around the loop (when c becomes EOF), then c!=EOF is 0, and the loop exits.



What we want to do is save the result of c != EOF and compare that to 0 and to 1 separately. Or, even more simply for this exercise, just print it to standard output:



 do 
c = getchar();
printf("getchar() != EOF: %dn", c != EOF);
while (c != EOF);


NoteL given that we haven't been asked to copy the input to output, we shouldn't have the putchar() call.



If we really want to prove that c != EOF is always either 0 or 1, we could test it automatically:



 do 
c = getchar();
if ((c != EOF) != 0 && (c != EOF) != 1)
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;

while (c != EOF);


You might choose to use a switch statement instead of the if; I think that's clearer:



 c = getchar();
switch (c != EOF)
case 0: /* okay */
case 1: /* okay */
break;
default:
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;




Modified code



#include <stdio.h>

int main()

int c;

do
c = getchar();
switch (c != EOF)
case 0: /* okay */
case 1: /* okay */
break;
default:
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;

while (c != EOF);

printf("%dn", c);






share|improve this answer























  • Cheers for the awesome reply! Means a lot, and the Makefile stuff I had no clue about, thanks for that, works like a charm. The c = getchar() throwing away the first character I didn't know about, but I had noticed that it was happening, had no clue why though!
    – John Von Neumann
    Jul 13 at 14:33










  • "That doesn't work, becauseEOF is outside the range of any valid char." --> Not quite. EOF often has the value of -1 and a signed char typically has the range of -128 to 127. So having an EOF inside the char range is common. The "doesn't work" is due to getchar() retuning values in the unsigned char range and the negative EOF and these typical 257 different values are not distinguishable with an 8-bit char.
    – chux
    Jul 13 at 14:36










  • Oh yes - I hate these conversions between plain and unsigned char (such as with the to*() family of functions). EOF does have to have a negative value, and I mistakenly assumed that it just had to be more negative than CHAR_MIN.
    – Toby Speight
    Jul 13 at 14:49










  • Why do we do this? ` case 0: /* okay / case 1: / okay */` And not assign a success for the case statements? Except for the 1 of course.
    – John Von Neumann
    Jul 13 at 15:03











  • EDIT: Ignore me, I know why now haha. Because 0 is success so we just continue checking until EOF or an issue, hence the break on exit code 1.
    – John Von Neumann
    Jul 13 at 15:09














up vote
4
down vote



accepted










This is a nice, clear, short attempt at the exercise.



You've avoided a couple of common problems:



  • You're correctly using int for the return value from getchar(). A common mistake is to be misled by the name and to assign directly to a char variable. That doesn't work, because truncating to char prevents EOF from being distinguished from a valid char value.

  • You've correctly matched the %d specifier to the type of EOF.


One simple way to improve your code is to get the compiler to point out weaknesses for you (by default, most C compilers are very lenient; you have to specifically ask for more warnings):



gcc -std=c11 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion putchar.c -o putchar


You can make it easier by writing a simple Makefile that contains just:



CFLAGS = -std=c11 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion


And you can then build simply with



make putchar


When you've enabled warnings, you'll see:



198374.c:3:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
void main()
^~~~


The fix for that should be obvious.




Now to the meat of the program. Firstly, before the loop we have a statement



 c = getchar();


This consumes and ignores one character. We probably didn't mean to throw that one away.




Now consider this expression:



 (c = getchar()) != EOF == (0 | 1)


We're actually comparing (after the assignment) c != EOF against 0|1. But | is the bitwise-or operator, so 0|1 evaluates to just 1. When c is not EOF, then c!=EOF is 1, and the condition is satisfied. The last time around the loop (when c becomes EOF), then c!=EOF is 0, and the loop exits.



What we want to do is save the result of c != EOF and compare that to 0 and to 1 separately. Or, even more simply for this exercise, just print it to standard output:



 do 
c = getchar();
printf("getchar() != EOF: %dn", c != EOF);
while (c != EOF);


NoteL given that we haven't been asked to copy the input to output, we shouldn't have the putchar() call.



If we really want to prove that c != EOF is always either 0 or 1, we could test it automatically:



 do 
c = getchar();
if ((c != EOF) != 0 && (c != EOF) != 1)
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;

while (c != EOF);


You might choose to use a switch statement instead of the if; I think that's clearer:



 c = getchar();
switch (c != EOF)
case 0: /* okay */
case 1: /* okay */
break;
default:
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;




Modified code



#include <stdio.h>

int main()

int c;

do
c = getchar();
switch (c != EOF)
case 0: /* okay */
case 1: /* okay */
break;
default:
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;

while (c != EOF);

printf("%dn", c);






share|improve this answer























  • Cheers for the awesome reply! Means a lot, and the Makefile stuff I had no clue about, thanks for that, works like a charm. The c = getchar() throwing away the first character I didn't know about, but I had noticed that it was happening, had no clue why though!
    – John Von Neumann
    Jul 13 at 14:33










  • "That doesn't work, becauseEOF is outside the range of any valid char." --> Not quite. EOF often has the value of -1 and a signed char typically has the range of -128 to 127. So having an EOF inside the char range is common. The "doesn't work" is due to getchar() retuning values in the unsigned char range and the negative EOF and these typical 257 different values are not distinguishable with an 8-bit char.
    – chux
    Jul 13 at 14:36










  • Oh yes - I hate these conversions between plain and unsigned char (such as with the to*() family of functions). EOF does have to have a negative value, and I mistakenly assumed that it just had to be more negative than CHAR_MIN.
    – Toby Speight
    Jul 13 at 14:49










  • Why do we do this? ` case 0: /* okay / case 1: / okay */` And not assign a success for the case statements? Except for the 1 of course.
    – John Von Neumann
    Jul 13 at 15:03











  • EDIT: Ignore me, I know why now haha. Because 0 is success so we just continue checking until EOF or an issue, hence the break on exit code 1.
    – John Von Neumann
    Jul 13 at 15:09












up vote
4
down vote



accepted







up vote
4
down vote



accepted






This is a nice, clear, short attempt at the exercise.



You've avoided a couple of common problems:



  • You're correctly using int for the return value from getchar(). A common mistake is to be misled by the name and to assign directly to a char variable. That doesn't work, because truncating to char prevents EOF from being distinguished from a valid char value.

  • You've correctly matched the %d specifier to the type of EOF.


One simple way to improve your code is to get the compiler to point out weaknesses for you (by default, most C compilers are very lenient; you have to specifically ask for more warnings):



gcc -std=c11 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion putchar.c -o putchar


You can make it easier by writing a simple Makefile that contains just:



CFLAGS = -std=c11 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion


And you can then build simply with



make putchar


When you've enabled warnings, you'll see:



198374.c:3:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
void main()
^~~~


The fix for that should be obvious.




Now to the meat of the program. Firstly, before the loop we have a statement



 c = getchar();


This consumes and ignores one character. We probably didn't mean to throw that one away.




Now consider this expression:



 (c = getchar()) != EOF == (0 | 1)


We're actually comparing (after the assignment) c != EOF against 0|1. But | is the bitwise-or operator, so 0|1 evaluates to just 1. When c is not EOF, then c!=EOF is 1, and the condition is satisfied. The last time around the loop (when c becomes EOF), then c!=EOF is 0, and the loop exits.



What we want to do is save the result of c != EOF and compare that to 0 and to 1 separately. Or, even more simply for this exercise, just print it to standard output:



 do 
c = getchar();
printf("getchar() != EOF: %dn", c != EOF);
while (c != EOF);


NoteL given that we haven't been asked to copy the input to output, we shouldn't have the putchar() call.



If we really want to prove that c != EOF is always either 0 or 1, we could test it automatically:



 do 
c = getchar();
if ((c != EOF) != 0 && (c != EOF) != 1)
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;

while (c != EOF);


You might choose to use a switch statement instead of the if; I think that's clearer:



 c = getchar();
switch (c != EOF)
case 0: /* okay */
case 1: /* okay */
break;
default:
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;




Modified code



#include <stdio.h>

int main()

int c;

do
c = getchar();
switch (c != EOF)
case 0: /* okay */
case 1: /* okay */
break;
default:
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;

while (c != EOF);

printf("%dn", c);






share|improve this answer















This is a nice, clear, short attempt at the exercise.



You've avoided a couple of common problems:



  • You're correctly using int for the return value from getchar(). A common mistake is to be misled by the name and to assign directly to a char variable. That doesn't work, because truncating to char prevents EOF from being distinguished from a valid char value.

  • You've correctly matched the %d specifier to the type of EOF.


One simple way to improve your code is to get the compiler to point out weaknesses for you (by default, most C compilers are very lenient; you have to specifically ask for more warnings):



gcc -std=c11 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion putchar.c -o putchar


You can make it easier by writing a simple Makefile that contains just:



CFLAGS = -std=c11 -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wconversion


And you can then build simply with



make putchar


When you've enabled warnings, you'll see:



198374.c:3:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
void main()
^~~~


The fix for that should be obvious.




Now to the meat of the program. Firstly, before the loop we have a statement



 c = getchar();


This consumes and ignores one character. We probably didn't mean to throw that one away.




Now consider this expression:



 (c = getchar()) != EOF == (0 | 1)


We're actually comparing (after the assignment) c != EOF against 0|1. But | is the bitwise-or operator, so 0|1 evaluates to just 1. When c is not EOF, then c!=EOF is 1, and the condition is satisfied. The last time around the loop (when c becomes EOF), then c!=EOF is 0, and the loop exits.



What we want to do is save the result of c != EOF and compare that to 0 and to 1 separately. Or, even more simply for this exercise, just print it to standard output:



 do 
c = getchar();
printf("getchar() != EOF: %dn", c != EOF);
while (c != EOF);


NoteL given that we haven't been asked to copy the input to output, we shouldn't have the putchar() call.



If we really want to prove that c != EOF is always either 0 or 1, we could test it automatically:



 do 
c = getchar();
if ((c != EOF) != 0 && (c != EOF) != 1)
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;

while (c != EOF);


You might choose to use a switch statement instead of the if; I think that's clearer:



 c = getchar();
switch (c != EOF)
case 0: /* okay */
case 1: /* okay */
break;
default:
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;




Modified code



#include <stdio.h>

int main()

int c;

do
c = getchar();
switch (c != EOF)
case 0: /* okay */
case 1: /* okay */
break;
default:
fprintf(stderr, "(c != EOF) was neither 0 nor 1n");
return 1;

while (c != EOF);

printf("%dn", c);







share|improve this answer















share|improve this answer



share|improve this answer








edited Jul 13 at 14:50


























answered Jul 13 at 9:26









Toby Speight

17.2k13486




17.2k13486











  • Cheers for the awesome reply! Means a lot, and the Makefile stuff I had no clue about, thanks for that, works like a charm. The c = getchar() throwing away the first character I didn't know about, but I had noticed that it was happening, had no clue why though!
    – John Von Neumann
    Jul 13 at 14:33










  • "That doesn't work, becauseEOF is outside the range of any valid char." --> Not quite. EOF often has the value of -1 and a signed char typically has the range of -128 to 127. So having an EOF inside the char range is common. The "doesn't work" is due to getchar() retuning values in the unsigned char range and the negative EOF and these typical 257 different values are not distinguishable with an 8-bit char.
    – chux
    Jul 13 at 14:36










  • Oh yes - I hate these conversions between plain and unsigned char (such as with the to*() family of functions). EOF does have to have a negative value, and I mistakenly assumed that it just had to be more negative than CHAR_MIN.
    – Toby Speight
    Jul 13 at 14:49










  • Why do we do this? ` case 0: /* okay / case 1: / okay */` And not assign a success for the case statements? Except for the 1 of course.
    – John Von Neumann
    Jul 13 at 15:03











  • EDIT: Ignore me, I know why now haha. Because 0 is success so we just continue checking until EOF or an issue, hence the break on exit code 1.
    – John Von Neumann
    Jul 13 at 15:09
















  • Cheers for the awesome reply! Means a lot, and the Makefile stuff I had no clue about, thanks for that, works like a charm. The c = getchar() throwing away the first character I didn't know about, but I had noticed that it was happening, had no clue why though!
    – John Von Neumann
    Jul 13 at 14:33










  • "That doesn't work, becauseEOF is outside the range of any valid char." --> Not quite. EOF often has the value of -1 and a signed char typically has the range of -128 to 127. So having an EOF inside the char range is common. The "doesn't work" is due to getchar() retuning values in the unsigned char range and the negative EOF and these typical 257 different values are not distinguishable with an 8-bit char.
    – chux
    Jul 13 at 14:36










  • Oh yes - I hate these conversions between plain and unsigned char (such as with the to*() family of functions). EOF does have to have a negative value, and I mistakenly assumed that it just had to be more negative than CHAR_MIN.
    – Toby Speight
    Jul 13 at 14:49










  • Why do we do this? ` case 0: /* okay / case 1: / okay */` And not assign a success for the case statements? Except for the 1 of course.
    – John Von Neumann
    Jul 13 at 15:03











  • EDIT: Ignore me, I know why now haha. Because 0 is success so we just continue checking until EOF or an issue, hence the break on exit code 1.
    – John Von Neumann
    Jul 13 at 15:09















Cheers for the awesome reply! Means a lot, and the Makefile stuff I had no clue about, thanks for that, works like a charm. The c = getchar() throwing away the first character I didn't know about, but I had noticed that it was happening, had no clue why though!
– John Von Neumann
Jul 13 at 14:33




Cheers for the awesome reply! Means a lot, and the Makefile stuff I had no clue about, thanks for that, works like a charm. The c = getchar() throwing away the first character I didn't know about, but I had noticed that it was happening, had no clue why though!
– John Von Neumann
Jul 13 at 14:33












"That doesn't work, becauseEOF is outside the range of any valid char." --> Not quite. EOF often has the value of -1 and a signed char typically has the range of -128 to 127. So having an EOF inside the char range is common. The "doesn't work" is due to getchar() retuning values in the unsigned char range and the negative EOF and these typical 257 different values are not distinguishable with an 8-bit char.
– chux
Jul 13 at 14:36




"That doesn't work, becauseEOF is outside the range of any valid char." --> Not quite. EOF often has the value of -1 and a signed char typically has the range of -128 to 127. So having an EOF inside the char range is common. The "doesn't work" is due to getchar() retuning values in the unsigned char range and the negative EOF and these typical 257 different values are not distinguishable with an 8-bit char.
– chux
Jul 13 at 14:36












Oh yes - I hate these conversions between plain and unsigned char (such as with the to*() family of functions). EOF does have to have a negative value, and I mistakenly assumed that it just had to be more negative than CHAR_MIN.
– Toby Speight
Jul 13 at 14:49




Oh yes - I hate these conversions between plain and unsigned char (such as with the to*() family of functions). EOF does have to have a negative value, and I mistakenly assumed that it just had to be more negative than CHAR_MIN.
– Toby Speight
Jul 13 at 14:49












Why do we do this? ` case 0: /* okay / case 1: / okay */` And not assign a success for the case statements? Except for the 1 of course.
– John Von Neumann
Jul 13 at 15:03





Why do we do this? ` case 0: /* okay / case 1: / okay */` And not assign a success for the case statements? Except for the 1 of course.
– John Von Neumann
Jul 13 at 15:03













EDIT: Ignore me, I know why now haha. Because 0 is success so we just continue checking until EOF or an issue, hence the break on exit code 1.
– John Von Neumann
Jul 13 at 15:09




EDIT: Ignore me, I know why now haha. Because 0 is success so we just continue checking until EOF or an issue, hence the break on exit code 1.
– John Von Neumann
Jul 13 at 15:09












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f198374%2fkr-exercise-1-6-1-7-working-with-eof%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Chat program with C++ and SFML

Function to Return a JSON Like Objects Using VBA Collections and Arrays

Will my employers contract hold up in court?