Link to home
Start Free TrialLog in
Avatar of Paullkha
PaullkhaFlag for United States of America

asked on

OPERATOR PREC, L-VAL, R-VAL, DEREF

Hi All:
I was having problems with pointers, deref, and l-values. So I set up an excercise for myself. Below is the code that I created. IT ALL WORKS THE WAY I WANT. However, I still don't understand deref pointer, oper prec, or l-val's completely.
EX.
(x++)++; l-val missing ok (x++) is an r-val.
(from item #3 in code below)
(*first++)++; How can this work? How is this statement being parsed? Does ++ left to right and * right to left allows this stmt to be parsed?
*(first++)++; Doesn't work? l-val missing ???
Second part, if any of the examples (#3 to #6) can be arranged differently (paranthesis etc.), and still have the same output, please post, and explain.



#include <vector>
#include <typeinfo>
#include <iostream>

using namespace std;

int main (void)
{
      vector<int> v(3);
      v[0] = 5;
      v[1] = 2;
      v[2] = 7;

 int x = 1;
x++;

      vector<int>::iterator first = v.begin();
vector<int>::iterator last  = v.end();
/*
"#1 deref ptr, use val, incr ptr"
VECTOR BEFORE = 5,2,7
OUTPUT 5,2,7
VECTOR AFTER = 5,2,7
"#2 incr ptr, deref ptr, use val"
VECTOR BEFORE = 5,2,7
OUTPUT 2,7
VECTOR AFTER = 5,2,7
"#3 deref ptr, use val, incr val, incr ptr"
VECTOR BEFORE = 5,2,7
OUTPUT 5,2,7
VECTOR AFTER = 6,3,8
"#4 deref ptr, incr val, use val, incr ptr"
VECTOR BEFORE = 5,2,7
OUTPUT 6,3,8
VECTOR AFTER = 6,3,8
"#5 incr ptr, deref ptr, use val, incr val"
VECTOR BEFORE = 5,2,7
OUTPUT 2, 7
VECTOR AFTER = 5,3,8
"#6 incr ptr, deref ptr, incr val, use val"
VECTOR BEFORE = 5,2,7
OUTPUT 3, 8
VECTOR AFTER = 5,3,8
*/


/*      cout << "#1 deref ptr, use val, incr ptr" << endl;
      while (first != last)
            cout <<  *first++ << " ";
*/
/*
      cout << "#2 incr ptr, deref ptr, use val"<< endl;
      do
            cout <<  *++first << " ";
       while (first != (last - 1));
*/
/*      cout << "#3 deref ptr, use val, incr val, incr ptr"<< endl;
      while (first != last)
            cout <<  (*first++)++ << " ";
*/
/*      cout << "#4 deref ptr, incr val, use val, incr ptr"<< endl;
      while (first != last)
            cout <<  ++(*first++) << " ";
*/
/*
      cout << "#5 incr ptr, deref ptr, use val, incr val"<< endl;
      do
            cout <<  (*(++first))++ << " ";
       while (first != (last - 1));
*/
/*      cout << "#6 incr ptr, deref ptr, incr val, use val"<< endl;
      do
            cout <<  ++(*(++first)) << " ";
       while (first != (last - 1));
*/
/* this doesn't work*/
      cout << "#3 deref ptr, use val, incr val, incr ptr"<< endl;
      while (first != last)
            cout <<  *(first++)++ << " ";

  // Iterator is used to loop through the vector.
    vector<int>::iterator theIterator;



    // Output contents of theVector.
    cout << endl << "v [ " ;
    for (theIterator = v.begin(); theIterator != v.end();
         theIterator++)
    {
        cout << *theIterator;
        if (theIterator != v.end()-1) cout << ", ";
                                              // cosmetics for the output
    }
    cout << " ]" << endl ;

return (0);
}
Avatar of Paullkha
Paullkha
Flag of United States of America image

ASKER

Edited text of question.
ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of nietod
nietod

cout << "#2 incr ptr, deref ptr, use val"<< endl;
             do
             cout <<  *++first << " ";
             while (first != (last - 1));

That is fine as long as the array holds at least 1 item.   could also be *(++first) or *(first++) and woule be the same.

I'm not sure what to say about the others.  You seem to have a good grasp on it.

(*first++)++
I believe the postfix++ and() have higher precedence than *.
>>>> (*first++)++; How can this work?
>>1. return what first points to.
>>2. increment first.
>>3. increment what was returned in step 1.

Why did you start with deref the pointer?
Yes postfix ++ has higher precendence than * (it has the highest precendence actually), but because the effects of postfix ++ are delayed, it doesn't seem like it.  In

*first++

The ++ is done first, but only in a sense.  
1.  first it returns the original value of first,
2. then it changes first,
3. then * is applied to the original value of first.  (the one returned in 1)

Another way to look at this is to convert it to the equivalent overloaded operator notation.  this would be

operator *(operator++(first,0))

(you can ignore the ",0" there.  It diferentiates between prefix and postfix ++.  It indicates this one is postfix.)
The inner operator ++ saves the original first, then changes first, then returns that saved original value.    That value is then passed to operator *.
overloaded operator notation helped alot. thanks
That would mean the following(I changed to NNN to avoid confusion)
1.  (*NNN++)++  =>
operator++( (*NNN++), 0) =>
operator++( (operator *(operator++(NNN,0))),0)

2. operator ++(NNN,0) =>NNN=NNN+1, return old NNN (suppose ptr to old NNN)

3. operator *   =>derefences old NNN <-------???

4. operator ++  =>*old NNN= *old NNN + 1, return *old NNN

WHEREAS
-------

1. ++(*NNN++) =>
operator ++( (*NNN++),1) =>
operator ++( (operator * (operator++(NNN,0))),1)

2. operator ++(NNN,0) =>NNN=NNN+1, return old NNN

3. operator *   =>derefences old NNN

4. operator ++  =>*old NNN= *old NNN + 1, return *old NNN + 1
GOOD???

That all seems correct to me.

Just as a notational thing, the prefix operator ++ and -- take only 1 parameter.  This is the item they are to operate on.  (The member versions of these take no parameters, as they operate on the object of the class they are part of.)  The postfix versions of these take two parameters.  The 2nd is an int parameter.  The value of this int parameter is not specified, it could be anything, not necessarily 1 or 0.  The existance of this int is so that the two functions have unique signatures, that is so the prefix and postfix functions are different overloads.  The int value isn't really used for any other purpose.
Thanks, dummy value for prefix.
Last Question:

//y = why 39 and not 44
...int x = 4, y;
...y = (x+3) * 5 + x++;
x+3 uses the old x value of 4, even though x++ evaluates before (x+3) and changes x's value to 5.
This won't be the same for classes. REGARDLESS of how the post-fix operator is defined, correct? Why?
 I created a "Rational" class to see all this.
...Rational x(1,4), y;
...y = (x+3) * 5 + x++;
x=5/4 , this will than be used in x+3
POSTFIX FUNCTION
const Rational Rational::operator++(int dummy)
{      Rational Tmp = *this;
      numer = numer + denom;
      return (Tmp);
};

>> x+3 uses the old x value of 4, even though
>> x++ evaluates before (x+3) and changes x's
>> value to 5.
Converting to the operator function notation might have been missleading.  That is exactly what happens when you use these functions with classes that have overloaded the operators.  In that case, it is not missleading, you will get the results that are suggested by the operator function notation (because that is how the expesssion is evaluated.)  Unfortunately, if the expression involves the predefined operators, like the ones for int that appear in your equation, you might not get the same result.  This is because the C++ compiler is not required to update the value changed by the increment  or decrement operators at a specific point--like it would have to do if the increment or decrement was handled by a function.  This allows the compiler much more freedom in how it performs the calculation and therefore allows it much greater opportunity to optimize the calculation.  (These sort of expressions are very ripe for optimization too.)  So in

y = (x+3) * 5 + x++;

the value in x may be updated at any time during the evaluation of the statement.  Thus this sort of expression may yield different results on different compilers.  A classic example of this is

f(int i1, int i2)
    *   *   *
int x = 0;
f(x++,x++);

depending on the compiler the function could be called with (0,0), (1,0), or (0,1).  To make things a little more rational, the standard defines "sequence points" which are places in an expression where the value must be updated, if not updated before then.  In the f(x++,x++);  the first sequence point is the call to the function.  by the time the function is called x must be updated to 2, however the parameters will be passed before that, so the parameters might not be corrrect.  In your example, the only sequence point (I think) was the end of the statement (;), which is always a sequence point.

Concise understandable answers, great!