!= not workign like I expect

Discussion in 'Mac Programming' started by larswik, Dec 31, 2010.

  1. larswik macrumors 68000

    Joined:
    Sep 8, 2006
    #1
    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
     
  2. ulbador, Dec 31, 2010
    Last edited: Dec 31, 2010

    ulbador macrumors 68000

    ulbador

    Joined:
    Feb 11, 2010
    #2
    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
     
  3. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #3
    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
     
  4. ulbador macrumors 68000

    ulbador

    Joined:
    Feb 11, 2010
    #4
    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.
     
  5. dmi, Dec 31, 2010
    Last edited: Jan 1, 2011

    dmi macrumors regular

    Joined:
    Dec 21, 2010
    #5
    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.
     
  6. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #6
    ahhhhh..... The light was switched on. I understand now.

    Thanks you very much!

    -Lars
     
  7. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #7
    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).
     
  8. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #8
    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
     
  9. ulbador macrumors 68000

    ulbador

    Joined:
    Feb 11, 2010
    #9
    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
     
  10. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #10
    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.
     
  11. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #11
    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.
     
  12. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #12
    Does that work for the condition ? then : else embedded format if you enclose it in parens (as I always do anyway)?
     
  13. lloyddean macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #13
    Ternary statement
     
  14. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #14
    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.
     
  15. JustSomeDude macrumors regular

    Joined:
    Apr 10, 2010
    #15
    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
     
  16. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #16
    Try it. See what happens.

    Or don't you have a compiler handy?
     
  17. lloyddean macrumors 6502a

    Joined:
    May 10, 2009
    Location:
    Des Moines, WA
    #17
    As your post implies you're just not use-to it, which is not a valid reason for not using it!
     
  18. ulbador macrumors 68000

    ulbador

    Joined:
    Feb 11, 2010
    #18
    Going to be the same issue though in Java, PHP, pickyourCstylelanguage and many many others that don't provide this functionality.
     
  19. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #19
    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.
     
  20. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #20
    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.
     
  21. balamw Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #21
    Double operators are boolean, single operators are bitwise.

    I usually think of the bitwise ones as only being useful when you are trying to do multiple logical operations at one time (think flag manipulation).

    http://www.cprogramming.com/tutorial/bitwise_operators.html

    B
     
  22. chown33, Jan 1, 2011
    Last edited: Jan 1, 2011

    chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #22
    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
     
  23. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #23
  24. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #24
    And the fact that this:

    Code:
    x >= y || x == z
    Adds nothing to this:

    Code:
    x >= y
     
  25. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #25
    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
     

Share This Page