1

I am getting an error of "lvalue required as left operand of assignment".

It assigns to the line:

if(ch=='.' || ch=='"' || ch=='(' || ch=')' || ch=='!' || ch==',' || ch=='?' || ch==';') { etc }

I just want to check if the character I'm looking at is equal to any one of those characters. Any idea on the fix?

Thank you,

0

2 Answers 2

10

ch=')' should be ch==')'. The reason you are getting that particular error is because while == has higher precedence than ||, = has lower precedence, so this:

ch == '(' || ch = ')'

is parsed as

((ch == '(') || ch) = ')'

Which is trying to assign ')' to the result of (ch == '(') || ch) which is an rvalue and not assignable. This is a common mistake, and this technique is used to avoid it:

if ('.' == ch || '"' == ch || ...)

Notice that the character literals and the variable have switched places around the ==. That way, if you accidentally type

if ('.' = ch)

You'll get a compiler error.

5
  • 2
    Yeah, I remember the technique... Somehow I couldn't bring myself to using it, because it reads so unnaturally. I'm so glad the modern IDEs detect missing = signs in conditions! Commented Dec 20, 2011 at 2:20
  • @dasblinkenlight yea, I don't use it either for the same reason, I just recommend it to people as an option Commented Dec 20, 2011 at 2:21
  • @Pubby: Probably because ch is const.
    – Xeo
    Commented Dec 20, 2011 at 2:22
  • 4
    @Pubby @Xeo == has higher precedence than ||, but = has lower precedence. Therefore it was being parsed as ('(' || ch) = ')' Commented Dec 20, 2011 at 2:23
  • 1
    This common mistake has shown up at least a couple of times today on SO alone! Commented Dec 20, 2011 at 2:28
0

Your immediate problem is that you are using = (assignment) rather the == (equality):

if(ch=='.' || ch=='"' || ch=='(' || ch=')' || ...
                                   ___^____
                                   see here

What's happening is to do with the relative precedence of the various bits. Although == will bind at a higher level than ||, a == b || c == d evaluates as (a == b) || (c == d).

However, = does not bind at a higher level so a == b || c = d evaluates as ((a == b) || c) = d). With your code, that ends up with a part expression of:

('(' || ch) = ')'

In other words, you're trying to assign ')' to the non-lvalue '(' || ch.

You actually got lucky there by not parenthesising every term (which many people do) since that would make it syntactically correct but not do what you expect at runtime:

if ((ch == '.') || (ch == '"') || (ch == '(') || (ch = ')') || ...
                                        _________^^^^^^^^^^_________
                                        will assign rather than test

The usual approach to avoid that is to put the constant first but, like you, I believe that's just plain ugly:

if (('.' == ch) || ('"' == ch) || ('(' == ch) || (')' = ch) || ...
                                                  ^^^^^^^^
                                                  / urk! \

When I'm doing that sort of thing, I tend to rely on the standard library so that my code looks better and has much less chance of being incorrect:

if (strchr (".\"()!,?;", ch) != NULL) {
    // It's valid.
}

or even better:

#define VALID_PUNCTUATION ".\"()!,?;"
if (strchr (VALID_PUNCTUATION, ch) != NULL) {
    // It's valid.
}

or even better than that, put the whole segment in a function and just use something like:

if (isValidPunctuation (ch)) {
    // It's valid.
}

(you'll still have to make sure the code in the function is correct but your mainline code will be much cleaner).

Not the answer you're looking for? Browse other questions tagged or ask your own question.