I'm new to C programming, I'm practicing while loop using getchar(). But I'm confusing about these two while loop code.
This is the first code:
char c;
c=getchar();
while(c != 'X')
c=getchar();
printf("Thanks for finally inputting an X.\n");
I undestand that this function will printf until the user enter X.
Here is the second code:
char c;
while((c=getchar()) != 'X');
printf("Thanks for finally inputting an X");
Which did the same thing as the last function, but I don't really understand while((c=getchar()) != 'X'); It means to me that when the user enters other characters than X, it will be true and print the sentence.
Look closely at the while in the second snippet:
char c;
// here ----------------v
while((c=getchar()) != 'X');
printf("Thanks for finally inputting an X");
There is a ; immediately after the while. This means that the body of the loop is empty. So the loop will continue to run just the condition until it is false, i.e. when c is equal to 'X'.
Both approaches are equivalent, but the second is more concise and uses less code:
Evaluating the condition (c = getchar()) != 'X') first calls getchar() to read a byte from the standard input, store in into c, which by the way should be defined as an int, and compares this byte with 'X', continuing the loop until the user finally types an X (followed by a return) because the body of the while loop is an empty statement.
The main problem with this approach is the program does not test for EOF, so it will perform a costly infinite loop if the standard intput reaches the end of file without ever reading an X.
Here is a better alternative:
int c;
while ((c = getchar()) != EOF) {
if (c == 'X') {
printf("Thanks for finally inputting an X\n");
break;
}
}
To avoid the confusing syntax while((c=getchar()) != 'X'); some programmers would use an empty block:
while ((c = getchar()) != 'X') {
}
Possiblity with an obnoxious comment:
while ((c = getchar()) != 'X') {
/* do nothing */
}
I personally prefer a redundant continue:
while ((c = getchar()) != 'X')
continue;
Note also that this syntactic issue is also present in other languages inspired by C: C++, java, javascript, C#, Objective C, etc.
These two code snippets are equivalent in behavior.
In order to understand the second snippet, you need to remember that what exists in the inner parentheses in this case, will be evaluated first.
So, this:
while((c=getchar()) != 'X');
will have the expression:
c = getchar()
evaluated first. Now, as you already know, the method getchar will be executed, receive the character the user input, and it will assign it to the variable c.
Now our expression looks like this:
while((c) != 'X');
but since c is just a character, it's surrounding parentheses do not have an effect anymore, and we have right now:
while(c != 'X')
which is the same as the the condition of the while loop in the first code snippet, that you already understand.
Tip: Read about operators precedence, which will help you understand why the parentheses are needed - otherwise you'd get a different, most probably unwanted, behavior.
The reason is that the != operator has higher precedence than the assignment operator. Using parentheses imposes the order of evaluation we desire.
Related
The title pretty much says it all, so here's the code:
#include <stdio.h>
/* Program counts blanks, tabs, and newlines */
int main(void)
{
int c;
int b, t, nl;
b = 0;
t = 0;
nl = 0;
while ((c = getchar()) != EOF)
if (c == ' ')
++b;
if (c == '\t')
++t;
if (c == '\n')
++nl;
printf("Input has %d blanks, %d tabs, and %d newlines\n", b, t, nl);
return 0;
}
I don't understand why this doesn't work. It counts the blanks no problem, but then when it comes to the rest their values always get printed as 0.
More than a "here's how it should be" answer, I'd really like a "it doesn't work because... you need to do this because..." answer please. I'm trying to grasp the concepts and actually understand the language more than just know what works and what doesn't.
Thanks! You guys have been already helped tons :).
It's because you're missing braces for your while loop. Without those braces, the only thing inside the while is the first if statement. That's why it's only counting blanks, because you go through the whole file doing that one if statement then, after exiting the loop, c is EOF so neither of the other two if statements will be true.
That was a tricky one, it's hard to see because the indentation looks like it should work but, unlike Python, the compiler doesn't use indentation to figure out where things are :-)
If you put a opening brace after the while and a closing brace before the printf, it should count everything.
In other words, this is what your compiler sees:
while ((c = getchar()) != EOF) {
if (c == ' ')
++b;
}
if (c == '\t')
++t;
if (c == '\n')
++nl;
whereas you want:
while ((c = getchar()) != EOF) {
if (c == ' ')
++b;
if (c == '\t')
++t;
if (c == '\n')
++nl;
}
I see a lot of "always require braces" here. That's fine, and it will prevent this from happening, but I tend to prefer to always use a good editor. Emacs, for example, will automatically indent C code to make this sort of thing very obvious. Your 2nd and third if statements wouldn't indent as far as they are.
Another alternative, if you dislike braces, is to use else if where you use if. Don't do that, but do understand it.
I am learning C from the book "The C Programming Language";
my question is about something I observed while trying to reformulate with few lines of code regarding input and output:
why is it needed to give the getchar() function a value of a certain integer in order to have it store all the text in the input?
For example with this code putchar() is printing all that I type;
int c;
while ((c = getchar()) != EOF)
putchar(c)
But, why isn't it the same if I write:
while (getchar() != EOF)
putchar(getchar());
In the latter case, for example, if I write "okok", the program is then printing "kk".
I think the reason is within some property of getchar(), that I wasn't able to get;
for example, if I write a character counting program, and I want to exclude new lines, I also observed that it's working if I write it as:
int nc, c;
nc = 0;
while ((c = getchar()) != EOF)
if (c != '\n')
++nc;
printf("%d", nc);
But it's not able instead to distinguish correctly the '\n' when using getchar() directly instead of c integer:
while ((c = gethar()) != EOF)
if (getchar() != '\n')
++nc;
printf("%d", nc);
My purpose it is just to understand, as I wouldn't like to learn this just by memory, and in the book it is written that getchar() is working using int values, so I wonder if there is something that I missed about properties of getchar() despite reading several times, also searching in different questions in stack overflow regarding the getchar() topic.
When you write
while (getchar() != EOF)
putchar(getchar());
It always
reads one character and checks it for EOF,
reads one (another) character and prints it,
repeats.
Therefore, in your "okok" example, the odd 'o' characters are read, compared to EOF and discarded, and only the even 'k's make it through.
If you wanted to print all of the input characters, you would have to restructure your code. For example, to call getchar() once, save the return value to a variable, then use the already read value twice - check it for EOF and print it.
while (1) { /* loop forever (until break is called) */
int ch = getchar();
if (ch == EOF)
break;
putchar(ch);
}
getchar() function gets one char from the input and returns it.
while (getchar() != EOF)
putchar(getchar());
You have used the getchar() function two times.
For the input 'okok'
'o' will be returned in while (getchar() != EOF).
'k' will be returned in putchar(getchar());
Since you have written putchar() here it will get the char 'k' and prints it.
And again the process continues and prints only 'k'.
So the output will be 'kk'
To get the value 'okok' and print it try
do
{
char c=getchar();
if(c!=EOF)putchar(c);
}while(c!=EOF);
I can determine if a number is even or odd in many ways. My aim here was not that - it was to test out a specific bitwise operation. Here's the codelet:
#include <stdio.h>
int main(){
unsigned int c;
while(c=getchar()!='\n')
(c&1)==0?printf("Even"):printf("Odd");
printf("\n");
}
My inputs on the terminal are manual and of the type: "1234567890" or "asdf5678", always closed with a \n, which is why I don't need to account for EOF.
The outputs I get are basically strings of "OddOdd..." , exactly corresponding in number to the number of characters typed, as expected, but only returning "Odd" for all characters.
Am I missing out something really basic? As already stated, I am not interested in solving a general problem - I am interested in finding out why this specific piece of code is not working when its logic is sound. Is it something to do with the order of evaluation? (left to right etc) I can't see it being a matter of Operator Precedence as I have enclosed the & operation in brackets, superceding the precedence of ==
The problem you have is on this line:
while (c = getchar() != '\n')
And is due to operator precedence. Specifically, the != operator has a higher precedence than =. Adding parentheses shows what is really happening:
while (c = (getchar() != '\n'))
The condition will be 1, which is odd, whenever the result of getchar is not '\n'.
To fix this, add parentheses to group the operations correctly:
while ((c = getchar()) != '\n')
This however ignores the fact that getchar returns EOF on failure. If the stdin was EOF, this would loop forever, waiting for a newline that never comes. The variable c should be at least an int instead of unsigned int, to match the return type of getchar.
The expression in the while statement
while(c=getchar()!='\n')
is equivalent to
while( c = ( getchar() != '\n' ) )
As the expression getchar() != '\n' always yields 1 except when Enter key is pressed then within the body of the loop there is outputted the string literal "Odd".
You need
while( ( c = getchar() ) != '\n' )
In any case it would be better to write
int c;
while( ( c = getchar() ) != EOF && c != '\n' )
Also in my opinion it would be more readable to write
printf( "%s ", (c&1) == 0 ? "Even" : "Odd" );
instead of
(c&1)==0?printf("Even"):printf("Odd");
Playing around with code examples from K&R in Codeblocks on Windows 10 (Danish language). The following example works as expected:
#include <stdio.h>
int main() {
char c = 'a';
putchar(c);
}
However, the following prints a series of boxes with question marks, the same number as the number of characters I type:
#include <stdio.h>
int main() {
char c;
while (c = getchar() != '\n') {
putchar(c);
}
}
So it looks like an encoding issue. When run, a command prompt opens with "C:\Users\username\Desktop\filename.exe" in the header, and my username contains the Danish character "å" which is replaced by a "Õ". The command prompt uses the CP 850 character set.
(By the way, I'm not checking if the character equals EOF, since that produces odd results. Pressing enter prints the expected number of boxes, plus one for \n, but it doesn't end the program.)
You are seeing a problem of operator precedence here. As you can see on this chart, = has a lower precedence than !=.
This means that getchar() != '\n' is evaluated first.
To the compiler your code looks like this:
#include <stdio.h>
int main() {
char c;
while (c = (getchar() != '\n')) {
putchar(c);
}
}
Since 'c' is getting an incorrect value (the true/false evaluation of the expression), the output is incorrect, and the program gives the behavior you are seeing, however
#include <stdio.h>
int main() {
char c;
while ((c = getchar()) != '\n') { //<----notice brackets around c=getchar
putchar(c);
}
}
gives the output you are expecting. This illustrates the fact that you should always put brackets around such expressions to be safe.
This line is bad.
while (c = getchar() != '\n')
It should be:
while ((c = getchar()) != '\n')
There are already some correct answers within the scope of the question but there are a couple of wider problems that you need to address.
Firstly getchar() returns an int and it is important that you define the variable that takes the return value as an int so you can differentiate errors and end of file from valid chars.
Secondly, if you receive end of file or there is an error on stdin before the program encounters a \n, your code will loop forever. This is what the man page on my laptop says about getchar()
If successful, these routines return the next requested object from the stream. Character values are returned as an unsigned char converted to an int. If the stream is at end-of-file or a read error occurs, the routines return EOF.
So once getchar() returns EOF it will return EOF all the time. You need to address this in your loop condition:
#include <stdio.h>
int main()
{
int c; // c declared as int
while ((c = getchar()) != EOF && c != '\n'))
{
putchar(c);
}
if (c == EOF)
{
// handle errors and end of file as you see fit
}
}
Edit: You get the boxes because of the lack of parenthesis around the assignment, look at this question for reference as to why you should have parenthesis around an assignment used as a truth value...
Also, there is something else that is also wrong with this program, consider this example:-
For example:
What you actually wanted:-
ABCD
< newline >
What you actually typed:-
ABCD
And since the program didn't find the '\n' anywhere in the code, it leads to undefined behavior since it goes out of bounds to find it...
There are two possible solutions when your input does not contain a '\n':-
Use EOF (Suggested by many since it the best possible solution for accepting every input...)
int main() {
char c;
while ((c = getchar()) != '\n') /* Always remember to put parenthesis around
an assignment in a condition... */
putchar(c);
}
Add a newline to your input:-
int main() {
char c;
// Use fputc to modify input...
fputc('\n', stdin);
while ((c = getchar()) != '\n') /* Always remember to put parenthesis around
an assignment in a condition... */
putchar(c);
}
But, beware! This method will stop at the first iteration of newline it gets, so if you have something outside of the '\n', well it won't be printed...
This was my own experiment to understand what goes under the hood, what does this program mean to the compiler?
main()
{
int c;
printf("%d\n",c);
printf("%d ", getchar());
while ((c == getchar()) != EOF){
putchar(c);
}
}
When I say c must equal getchar() (c == getchar()), does it not proceed through the while loop? Now I am really confused of my own code, of what c must mean!
Also, in this code:
main()
{
int c;
c = getchar()
while ((c = getchar()) != EOF)
putchar(c);
}
if we modify the int c to int c = getchar(), why cannot we somply write like this:
while (c != EOF)(
putchar(c);
c = getchar();
}
The compiler should know from the previous statement that c = getchar(), why have to write the statement again? Sorry, if I am confused.
while ((c==getchar()) != EOF) {
...
}
is a while loop. It evaluates the condition for each iteration of the loop and terminates only if the condition is false.
In your case, the condition is:
(c==getchar()) != EOF)
which is a nonsensical expression, but let's examine it anyway:
First, the program will evaluate:
getchar()
This grabs a keystroke from standard input. The value of the expression is the value of the key.
Then:
c==getchar()
This takes the result of getchar() and compares it to whatever is currently in c. In your first program, c is uninitialized, so its value is indeterminate. If c had a defined value, then c==getchar() would evaluate to either true or false. Since c had no defined value, c==getchar() also has no defined value.
Now the program evaluates:
(c==getchar())
Which would still be true or false, except that in your case it is undefined.
The program next considers:
(c==getchar()) != EOF
That is, it compares the true-false value to EOF; this makes no particular sense, and in your case we still have the undefined behavior of an uninitialized c.
In sum, if c were initialized, the expression would fetch a key from standard input and then compare either true or false to EOF. As I said, it is a nonsensical expression.
You're saying you want to look under the hood? Great! Let's dive in :)
while ((c == getchar()) != EOF)
As others have noted, this should be while ((c = getchar()) != EOF). The reason you do assignment (=) rather than equality testing (==) is because you're actually rolling two lines of code into one: c = getchar(); and while(c != EOF). So if the current character being read is k, the program evaluates it in a way kind of like this:
while ((c = getchar()) != EOF)
while ((c = 'k') != EOF)
while (('k') != EOF)
while ('k' != EOF)
while (1) // true
And it has the convenient side effect that c still has k inside for whatever you're planning on doing.
The other problem is here:
int c;
printf("%d\n",c);
printf will complain because you don't have anything assigned to c yet. It's been "declared", but not "initialized." It can't print something that's not there - and if it can, it would surely print something you don't want.
You have an extra equal sign that you need to remove:
while ((c == getchar()) != EOF){
should be
while ((c = getchar()) != EOF){
Here is what is happening. When (c == getchar()) is executed, to begin with c is uninitialized, so it has some garbage value. That garbage value is compared to the next character in the input stream, to see if they are the same. The result of the comparison is going to be 0 (if they are different) or 1 (if they are same). The latter is very unlikely, but it is theoretically possible that by some lucky (?) chance, the garbage value does happen to match the next character in the input stream.
That 0 or 1 is then compared to see whether it matches EOF. Well, EOF is going to be some negative value; that's what it is by definition. Obviously 0 or 1 will never match any negative value, so your loop will be infinite.
As for your second code fragment:
c = getchar();
while ((c = getchar()) != EOF) {
You're not checking whether the first character is EOF, as the value of c after the first getchar() will be immediately replaced by the assignment in the while condition. Assuming that there is a non-EOF first character, your code will work.
As for your third code fragment:
c = getchar();
while (c != EOF) { // corrected your typo of ( instead of {
putchar(c);
c = getchar();
}
The reason why you have to write c = getchar() again inside your while loop is to update the value of c with the second and subsequent characters in the input stream. Otherwise, it will always compare the current value of c, which is the first character in the input stream, to EOF, and this too will be an infinite loop unless the first character does happen to be EOF.
The most concise way of accomplishing what you want is:
int c;
while ((c = getchar()) != EOF)
putchar (c);
... just like your second code fragment, minus the extra line that does the first getchar() and assigns it to c.
c == getchar() != EOF means
c == getchar() is true if c and the result returned from getchar() are the same.
c == getchar() will always be not equal to EOF (since neither true not false equals EOF) so the program should infinite loop printing the character that randomly showed up here since you never initialized c int c;.