Is buf[n]++ a lvalue?

Discussion in 'C Programming' started by Stub, Nov 7, 2003.

  1. Stub

    Stub Guest

    The following code gives error C2105: '++' needs l-value.

    char buf[20];
    buf[n]++ = 'A';//buf[n]++ isn't a lvalue

    Why buf[n]++ isn't a lvalue? Is this according to C Standard or is there
    some reason for this?

    If buf[n]++ isn't a lvalue, then why the following code works?

    void func(char *a, char *b)
    {
    while(*a++=*b++){}
    }
    Stub, Nov 7, 2003
    #1
    1. Advertising

  2. Stub <> spoke thus:

    > char buf[20];
    > buf[n]++ = 'A';//buf[n]++ isn't a lvalue


    > Why buf[n]++ isn't a lvalue? Is this according to C Standard or is there
    > some reason for this?


    > If buf[n]++ isn't a lvalue, then why the following code works?


    > while(*a++=*b++){}


    Because *a++ is the same as *(a++). a is a pointer and so it's fine to
    increment it. buf[n], however, is a character, which you cannot increment.

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
    Christopher Benson-Manica, Nov 7, 2003
    #2
    1. Advertising

  3. Stub

    Artie Gold Guest

    Stub wrote:
    > The following code gives error C2105: '++' needs l-value.
    >
    > char buf[20];
    > buf[n]++ = 'A';//buf[n]++ isn't a lvalue
    >
    > Why buf[n]++ isn't a lvalue? Is this according to C Standard or is there
    > some reason for this?


    Why would you think that these two options are mutually exclusive?
    ;-). Things in the C standard *are* there for a reason!

    Most likely, however, the expression you want is:

    buf[n++] = 'A';

    >
    > If buf[n]++ isn't a lvalue, then why the following code works?
    >
    > void func(char *a, char *b)
    > {
    > while(*a++=*b++){}
    > }


    Because here the *pointers* are dereferenced (*a is an lvalue,
    yes?), the assignment is performed (yielding the expression's value)
    and finally each pointer is incremented.

    HTH,
    --ag

    --
    Artie Gold -- Austin, Texas
    Oh, for the good old days of regular old SPAM.
    Artie Gold, Nov 7, 2003
    #3
  4. Christopher Benson-Manica wrote:

    > buf[n], however, is a character, which you cannot
    > increment.


    Yes, you can.


    #include <stdio.h>

    int main(void)
    {
    char buf[] = "3.1415926";
    int n = 0;
    buf[n]++;
    printf("%s\n", buf);
    return 0;
    }

    --
    Richard Heathfield :
    "Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
    K&R answers, C books, etc: http://users.powernet.co.uk/eton
    Richard Heathfield, Nov 7, 2003
    #4
  5. Stub

    Ben Pfaff Guest

    "Stub" <> writes:

    > The following code gives error C2105: '++' needs l-value.
    >
    > char buf[20];
    > buf[n]++ = 'A';//buf[n]++ isn't a lvalue
    >
    > Why buf[n]++ isn't a lvalue? Is this according to C Standard or is there
    > some reason for this?


    Suppose buf[n]++ were an lvalue. Then buf[n]++ = 'A'; would
    invoke undefined behavior because it would modify buf[n] twice
    between sequence points: both the ++ and the = operator would
    modify buf[n]. So you really don't want buf[n]++ to be an
    lvalue.

    > If buf[n]++ isn't a lvalue, then why the following code works?
    >
    > void func(char *a, char *b)
    > {
    > while(*a++=*b++){}
    > }


    *a++ is equivalent to *(a++). a++ isn't an lvalue, but *(a++)
    is.
    --
    "It wouldn't be a new C standard if it didn't give a
    new meaning to the word `static'."
    --Peter Seebach on C99
    Ben Pfaff, Nov 7, 2003
    #5
  6. Stub

    Noah Roberts Guest

    Stub wrote:
    > The following code gives error C2105: '++' needs l-value.
    >
    > char buf[20];
    > buf[n]++ = 'A';//buf[n]++ isn't a lvalue
    >
    > Why buf[n]++ isn't a lvalue?


    because buf[n]++ evaluates to the byte value contained in buf[n]. You
    are essentially saying something like:

    'x' = 'A'

    and that just doesn't fly.

    NR
    Noah Roberts, Nov 7, 2003
    #6
  7. Stub

    Chris Torek Guest

    (Note: the quick answer to the question in the subject is "no".)

    In article <vBSqb.32449$>
    Stub <> writes:
    >The following code gives error C2105: '++' needs l-value.
    >
    >char buf[20];
    >buf[n]++ = 'A';//buf[n]++ isn't a lvalue
    >
    >Why buf[n]++ isn't a lvalue?


    The term "lvalue" has a somewhat bizarre set of definitions depending
    on which C standard you use, but in any case, the expression:

    buf[n]++

    parses the same way as:

    (buf[n])++

    which means "find the object named buf[n], obtain its current value,
    add 1 to that value, arrange to store the new sum back into buf[n]
    by the next sequence point, and produce as the value of the expression
    the value buf[n] had before any update occurs". The resulting value
    is purely a value -- it does not name an object.

    Note that buf[n] in turn is defined as *(buf + n); this will matter
    in a moment...

    >If buf[n]++ isn't a lvalue, then why the following code works?
    >
    >void func(char *a, char *b)
    >{
    > while(*a++=*b++){}
    >}


    The expression:

    *a++

    is parsed the same way as:

    *(a++)

    Note: I am avoiding the term "precedence" as it leads people into
    the trap of thinking: "precedence, that means the same as precede,
    so that must mean that the whole `preceding' thing is done first,
    then the whole `following' thing, in exactly that order". This is
    not the case: "operator precedence" merely determines a "parse" at
    compile time. In effect, it says where the parentheses would be
    if there were parentheses. The actual *runtime* order of evaluation
    is much less constrained.

    Now, *(a++) is made up of two main pieces, one being "a++" and the
    other being "*(expression)". The first piece -- "a++" -- works
    pretty much the same as "buf[n]++": it locates the object named
    "a", finds a's current value, computes a+1, schedules a+1 to be
    stuffed back into the object by the next sequence point, and
    produces the old value of "a". This is the value (not an object,
    not an lvalue) handed to the unary "*" operator. The unary "*"
    operator requires a pointer value -- which is the kind of value
    "a++" produced -- and is defined to mean "follow that pointer to
    the object to which it points".

    It is this last step -- the "follow the pointer" step -- that
    locates an object, or in the Standard's terms, gives you an "lvalue".
    In other words, the unary * operator only needs a value, and produces
    an object (or "lvalue"). This is just the opposite of "++", which
    needs an object but produces a mere value. Objects hold values;
    values are wispy, evanescent things that usually have to be stored
    back into objects right away, before they evaporate.

    Now, if buf[n] "means" *(buf + n), and if "*" just needs a value,
    then as long as buf+n produces a suitable value, all is good. The
    buf+n part of course uses the "+" operator, which needs *two*
    values, but again, it just needs values, not actual objects. If
    you want buf and/or n to change by the next sequence point, you can
    embed one or more "++" operators here:

    *(buf + n++)

    which parses as:

    *((buf) + ((n)++))

    which tells the compiler to find the value of "buf", find the value
    of "n", compute n+1, schedule n+1 to be stuffed back into n, compute
    "value of buf plus original value of n", and give that to the "*"
    operator as a pointer to follow. Exactly when "n" changes is never
    specified -- it might even change *first*, by doing something like:

    n++;
    *(buf + (n - 1))

    -- but you are assured that n will be updated by the next sequence
    point. (This is why "sequence points" are such a big deal; for
    more about them, consult the FAQ.)

    And, since a always "means" *((a) + (b)), you can rewrite
    *(buf + n++) as buf[n++], which is no doubt what you intended to
    use way back at the beginning. If you want to confuse the next
    person to maintain your code, you can even use the commutative
    property of addition to change *(buf + n++) into *(n++ + buf),
    and rewrite that as n++[buf].
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://67.40.109.61/torek/index.html (for the moment)
    Reading email is like searching for food in the garbage, thanks to spammers.
    Chris Torek, Nov 7, 2003
    #7
  8. Stub

    Eric Sosman Guest

    Christopher Benson-Manica wrote:
    >
    > Stub <> spoke thus:
    >
    > > char buf[20];
    > > buf[n]++ = 'A';//buf[n]++ isn't a lvalue

    >
    > > Why buf[n]++ isn't a lvalue? Is this according to C Standard or is there
    > > some reason for this?

    >
    > > If buf[n]++ isn't a lvalue, then why the following code works?

    >
    > > while(*a++=*b++){}

    >
    > Because *a++ is the same as *(a++). a is a pointer and so it's fine to
    > increment it. buf[n], however, is a character, which you cannot increment.


    Er, no: it's perfectly possible to increment a character.
    Here's a silly way to output the decimal digits:

    char c;
    for (c = '0'; c <= '9'; ++c)
    putchar (c);

    The problem in the O.P.'s code is that the thing on the
    left of the assignment is a value, not a variable (I'm using
    loose terminology here; words like "lvalue" are Standardese,
    used in a very precise but possibly confusing way). The
    O.P.'s attempted assignment makes as much sense as

    a + b = 'A';
    sin(x) = 'A';
    rand() = 'A';
    x++ = 'A';

    .... where all share the same characteristic: the thing on the
    left produces a value, not a reference to something storable.

    --
    Eric Sosman, Nov 7, 2003
    #8
  9. On Fri, 7 Nov 2003, Eric Sosman wrote:
    >
    > Here's a silly way to output the decimal digits:
    >
    > char c;
    > for (c = '0'; c <= '9'; ++c)
    > putchar (c);


    Here's a silly nitpick:

    #define SCHAR_MAX '9'
    #define CHAR_MAX SCHAR_MAX

    Undefined behavior upon integer overflow.

    #define UCHAR_MAX '9'
    #define CHAR_MAX UCHAR_MAX

    Infinite loop.
    :)

    -Arthur,
    non-ASCII Fridays!
    Arthur J. O'Dwyer, Nov 7, 2003
    #9
  10. Stub

    Eric Sosman Guest

    "Arthur J. O'Dwyer" wrote:
    >
    > On Fri, 7 Nov 2003, Eric Sosman wrote:
    > >
    > > Here's a silly way to output the decimal digits:
    > >
    > > char c;
    > > for (c = '0'; c <= '9'; ++c)
    > > putchar (c);

    >
    > Here's a silly nitpick:
    >
    > #define SCHAR_MAX '9'
    > #define CHAR_MAX SCHAR_MAX
    >
    > Undefined behavior upon integer overflow.
    >
    > #define UCHAR_MAX '9'
    > #define CHAR_MAX UCHAR_MAX
    >
    > Infinite loop.
    > :)


    I'm ashamed to admit it, but I actually thought
    of this possibility when writing the code shown. That
    means I've been hanging around comp.lang.c *much* too
    long, and my once-mighty brain is now merely a dusty
    attic over-filled with pedantic quibbles and nitpicks.

    There was once a regular on c.l.c. who signed himself
    "The Human Lint." Arthur and I seem to be in danger of
    becoming clones of "The Human DeathStar 9000."

    --
    Eric Sosman, Nov 7, 2003
    #10
  11. Richard Heathfield <> spoke thus:

    >> buf[n], however, is a character, which you cannot
    >> increment.


    > Yes, you can.


    Oops :( Sorry!

    --
    Christopher Benson-Manica | I *should* know what I'm talking about - if I
    ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
    Christopher Benson-Manica, Nov 10, 2003
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Roberto Gallo

    Shift - byte[] buf shift

    Roberto Gallo, Jan 27, 2004, in forum: Java
    Replies:
    3
    Views:
    2,012
    Thomas Schodt
    Jan 27, 2004
  2. Replies:
    33
    Views:
    848
  3. Kavya
    Replies:
    9
    Views:
    491
    Dik T. Winter
    Oct 28, 2006
  4. Replies:
    11
    Views:
    676
    James Kuyper
    Sep 22, 2008
  5. Julian Mehnle
    Replies:
    0
    Views:
    223
    Julian Mehnle
    Jul 17, 2003
Loading...

Share This Page