i starts as 3. Then it's immediately incremented by 3 (making it 6) and tested against 0. 6 is not equal to 0, so the first half of the && clause succeeds. i is not greater than 6 so the second half fails, but i still gets incremented to 7 afterward as the postfix increment is used.

Both sides of the || are tested because one might be true, so i is then incremented before testing the left clause of the right hand &&. This fails because i is now 8, and the test is asking if i is greater than 8. This is an && test, so the right hand clause doesn't need to be checked if the left hand clause fails, so i is not incremented further by 3.

Both && statements failed, and i remains 8, so your output is the body of the else clause.

This one is relatively easy. In the first loop i is always incremented, but only after testing against 5.

The end result is that a[0] is never modified, but a[1] through a[4]are. At the end of the loop, i is 6, so the second loop decrements it immediately to 5. Then the condition decrements it again before testing against 0. The result is that you have a perfect reversal of the first loop.

printmax((i++),(j++));

This one is also relatively easy, but you need to recognize that macros are textual replacement. That means your printmax is replaced with this:

If this professor worked for me, I'd fire him! This is a perfect example of "Those who can, do. Those who can't, teach."... He is trying to be overly cleaver and illustrate how you can twist meaning in programming logic. 1) it violates the KISS principal. 2) it doesn't really teach the student proper programming practices. 3) has this person EVER written a significant program that has had any social or other impact?