Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
This part seemed simple but I can't get it to work right. It is a DO WHILE loop until they press the s or h key. I use the getchar() to absorb any extra information left in the buffer from scanf().

If I change the != to == then it works to exit the loop if I press any key except those 2 so I know the OR logic operator is working.

I would rather not look at this for a whole year (1 hour to go until new years, joke).

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>



int main()
{
	char playerResponce;
	
	printf("Press 'h' for 'Hit' or 's' for Stay:");		
	do{
		scanf("%c", &playerResponce);
		getchar();
		printf("responce is: %c\n",playerResponce);
		printf("Try again: ");
		printf("\n");
	} while(('h' != playerResponce) || ('s' != playerResponce));
	
	printf("your out");
	
	return 0;
}

-Lars
 
Probably should be && not ||

I also think the logic for just reading a single char is broken. In running this code, it works right if I just hit h or s.

If you type something like "i", Then you type "is" enter, "is" enter, the first time it reads the "i", the second time it reads the "s" and properly exits. Basically depending on the state of the stdin, your code is unreliable for all cases.

Scanf is basically unreliable for this because it won't consume the \n. If you enter two characters, the scanf will eat the first one, the getchar the second, but then you still have the \n to deal with. So when you come back around the loop, stdin is in a "funny" and unreliable state.

It's usually better to just read the line yourself and interpret it yourself with like fgets
 
Last edited:
uhhh.... Thanks...

I don't understand. If one or the other evaluates to TRUE then it should exit the loop. So if h or s are not pressed it should stay in the loop, right? With the && they should both have to be TRUE for it to exit the loop, or am I missing something?

It works so I am not complaining but I just want to understand why?

Thanks

-Lars
 
With the OR, the other option gives it an "out" to continue

int num = 1;
do{
num=2;
} while ((num != 1) || (num != 2));

In this case, this would run forever.

The first check "passes", so the loop doesn't need to check the other condition, and it loops again.

If you changed it to "num=1", then the first check would fail (the loop would want to terminate), but the second check passes, so the loop continues.

With an OR, as long as one of the conditions is met, the loop will continue.
 
do{ body; }while( condition )
stays in the loop while the condition is true.
the condition
('h' != playerResponce) || ('s' != playerResponce)
is always true because
('h' != playerResponce)
and
('s' != playerResponce)
cannot both be false at the same time.
 
Last edited:
ahhhhh..... The light was switched on. I understand now.

Thanks you very much!

-Lars
 
ahhhhh..... The light was switched on. I understand now.

Thanks you very much!

-Lars

And a tip that will safe you lots of little grey cells in your brain: Please write

Code:
(playerResponse != 'h')

and not

Code:
('h' != playerRespon[B]c[/B]e)

At the moment, you are writing tiny little toy programs. Some day you will have to handle bugs that could be anywhere in a few ten thousand lines of code, so reading speed is utterly important. Everything that reduces readability, like a comparison in the wrong order, will slow you down forever. And misspelt variable names don't bother the compiler, but again prevent you from finding things. (Say something goes wrong, and you think it might be related to a player response, so you try to find playerresponse and it's not found).
 
gnasher729 - Thanks. I originally had it that way. I was grasping at straws trying to get it to work so I swapped them.

I will make a note of that.

-Lars
 
At the moment, you are writing tiny little toy programs. Some day you will have to handle bugs that could be anywhere in a few ten thousand lines of code, so reading speed is utterly important. Everything that reduces readability, like a comparison in the wrong order, will slow you down forever.

I totally disagree with this. It is a good practice to get in the habit of writing comparisons backwards for the simple ones. Change those != to mistyped == and you have problems:

Code:
if (playerResponse = 'h')

That will assign the letter 'h' to the variable and it will equate to true every time. And you will spend possibly hours trying to figure out why.

Code:
if ('h' = playerResponse)

That will cause a compiler error, letting you know immediately that you have a problem
 
I totally disagree with this. It is a good practice to get in the habit of writing comparisons backwards for the simple ones. Change those != to mistyped == and you have problems:

Code:
if (playerResponse = 'h')

That will assign the letter 'h' to the variable and it will equate to true every time. And you will spend possibly hours trying to figure out why.

Code:
if ('h' = playerResponse)

That will cause a compiler error, letting you know immediately that you have a problem

Larswik, this is the advice you should take. I have made the "=" vs. "==" mistake at least a dozen times: the constant-first format has saved me hours of bug tracking in at least half those cases.
 
Larswik, this is the advice you should take. I have made the "=" vs. "==" mistake at least a dozen times: the constant-first format has saved me hours of bug tracking in at least half those cases.

Enable the gcc warning:
Code:
-Wparentheses
or the umbrella warning:
Code:
-Wall
which turns on -W parentheses among others.

I haven't had to track down this kind of bug since long before the millennium changed. I always use -Werror, too, so I can't ignore warnings without taking specific action to disable it.

Why work trying to find things that the computer itself is better able to find for you? Work smarter, not harder.
 
Enable the gcc warning:
Code:
-Wparentheses
or the umbrella warning:
Code:
-Wall
which turns on -W parentheses among others.

I haven't had to track down this kind of bug since long before the millennium changed. I always use -Werror, too, so I can't ignore warnings without taking specific action to disable it.

Why work trying to find things that the computer itself is better able to find for you? Work smarter, not harder.

Does that work for the condition ? then : else embedded format if you enclose it in parens (as I always do anyway)?
 
And a tip that will safe you lots of little grey cells in your brain: Please write

Code:
(playerResponse != 'h')

and not

Code:
('h' != playerRespon[B]c[/B]e)

At the moment, you are writing tiny little toy programs. Some day you will have to handle bugs that could be anywhere in a few ten thousand lines of code, so reading speed is utterly important. Everything that reduces readability, like a comparison in the wrong order, will slow you down forever. And misspelt variable names don't bother the compiler, but again prevent you from finding things. (Say something goes wrong, and you think it might be related to a player response, so you try to find playerresponse and it's not found).

I have to agree with this. I can't remember the last time I made this kind of error, or even saw it. Having the constant first makes it more confusing to read.
 
I used to be a TA for a beginning programming class in C++ and this was a common type of problem. It's sometimes useful to use Demorgan's laws to check your logic, or at least think about it in a different way :

!(A || B) is equivalent to !A && !B
!(A && B) is equivalent to !A || !B
 
Enable the gcc warning:
Code:
-Wparentheses
or the umbrella warning:
Code:
-Wall
which turns on -W parentheses among others.

I haven't had to track down this kind of bug since long before the millennium changed. I always use -Werror, too, so I can't ignore warnings without taking specific action to disable it.

Why work trying to find things that the computer itself is better able to find for you? Work smarter, not harder.

Going to be the same issue though in Java, PHP, pickyourCstylelanguage and many many others that don't provide this functionality.
 
Going to be the same issue though in Java, PHP and many many others that don't provide this functionality.

Not an issue in Java, unless the assignment is of boolean type. Any other type (int, float, object, etc.) will fail to compile, because Java requires ONLY boolean type in all its conditionals: if, while, for.

My point is not to say it's a useless technique. My point is that there are automated ways of avoiding (or even systematically finding) bugs like this. Because programmers make mistakes and won't always put the rvalue first, even when they know they should. I can't tell you how many times I've been given code with a subtle bug, and the first thing I did was compile it with -Wall and -Werror, and presto, the bug was listed in one of the warnings/errors. The more tools one has at one's disposal, the better off one is. Especially if the tool is as simple to use as -Wall -Werror.

I also vaguely recall that there are lint-like programs for other languages where assignment in a conditional is allowed, and they generally flag this as a warning. JSLint comes to mind:
http://www.jslint.com/
Code:
var foo, bar;

foo = "foofy";
bar = "barfy";

if ( foo = bar ) { throw "All your base are belong to us!"; }
I wouldn't be surprised if there was a PHP lint, but I'm too lazy to google it.
 
Try it. See what happens.

Or don't you have a compiler handy?

Curse you for making me shift my corpulent gluteus :eek:;)

What I fail to understand is how
Code:
x >= y || x == z
differs functionally from
Code:
x >= y | x == z
For some silly reason (due to not studying the subtleties of C thoroughly) I thought the single logical operator would have a lower priority than the double operator: that
Code:
Fields&aMaskVal == theFlag
would work out to
Code:
( Fields&aMaskVal ) == theFlag
rather than the actual
Code:
Fields&( aMaskVal == theFlag )
. Since that difficult bit of education, I just have a hard time understanding why the double operators make any real difference.
 
What I fail to understand is how
Code:
x >= y || x == z
differs functionally from
Code:
x >= y | x == z

In this case, there may be little functional difference. The cost of evaluating both sides of the single-| is unlikely to be substantially different from only evaluating the first condition.

Where || and && really count is in expressions like:
Code:
somePtr != NULL  &&  somePtr->someThing == someInterestingState
Here, it's very important that the second half not be evaluated at all unless the first half is true. Or perhaps this:
Code:
somePtr != NULL  &&  someFunctionWithSideEffects(somePtr)
where you absolutely want to PREVENT the function call unless the ptr is valid.

The || conditional is the opposite: it ONLY executes the second expression when the first expression is false. If the first expression is true, the second is NOT evaluated at all. So you can use it to CAUSE the second expression to be executed ONLY when the first expression is false. It's not that commonly seen, but I have seen it used in a series of fallbacks like this:
Code:
return ( someA() || someB() || someC() || 0 );
where each function returns a non-0 value (or a non-null ptr) if and only if it can produce a valid result. The effect is that if someA() works, its value is returned, otherwise someB() is evaluated, and if it worked, that's returned, and so on down the line. The terminal 0 is in case nothing worked.

I have also seen cases where single-| was required (forcing evaluation of both sides), and someone "fixed" it to || and introduced a mysterious bug.

Also see:
http://en.wikipedia.org/wiki/Short-circuit_evaluation
 
Last edited:
Since that difficult bit of education, I just have a hard time understanding why the double operators make any real difference.

Anything non-zero is considered a positive logical value. A lot of times 1 is used, but this isn't required. So, say:
Code:
int x,y;
char *z;
...
if((x == y) & strlen(z)) {
...

If x == y evaluates to 1, if strlen of z returns an odd number this will evaluate to true. If it returns an even number it will be false. I'm not advocating this style, but often people will just think "if x isn't 0" when they test x. With &&, x must equal y, and strlen must return any value but 0 for this to be true. I guess I always use &&/|| when doing logic and &/| when doing bitwise manipulation, the way I've always assumed they were intended.

-Lee
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.