The Hardest Test I Ever Gave (C++)
lbrandy.github.com
lbrandy.github.com
The thing is, those questions demonstrate a certain type of playfulness in dealing with the subject. It is not uncommon for good students to think of this type of questions when they design their first tests, precisely because those are the kinds of questions that they like to think about themselves. What they fail to recognize is that those questions are incredibly hard for others precisely because of their playfulness.
So those questions are useful for quickly recognizing really good students (students that are so good that they transcend the requirements of the course and can deal with the subject on this playful level), but they should only make up a very small portion of any test. And teachers should probably warn their students about this type of question...
Also I write C++ for living and I was not entirely sure if "y = x++3;" was valid or not (turns out it is an error but "y = x+ +3;" is fine, which I would have guessed but would not have been quite certain).
Edit: Now that I think about, I believe that "x = (x++ == 3 + x % (x=x=3));" is undefined behavior. I guess the question is not asking about that but regardless, that's a stupid thing to ask.
Later in college, I remember hating the assembly tests where you had to keep track of what numbers were in what address, and whether you were adding what was on the stack or in some register or the address or what was in the address and making a mistake in the very beginning could ruin the whole problem. Not fun, not sure how useful, but certainly gave you an appreciation of what was going on.
Ask them about compiler errors. For example, what does "undefined reference to `vtable for Foo'" mean?
Then some style guide [0] might be helpful. Make them write the rvalue expression to the left of comparisons, because "if (3 = x)" is an error then. Or some "assert (this != NULL)" in methods.
Ask about semantics, like "What is the difference between a move and a copy constructor?" or "Write a program to demonstrate the difference between any two of static_cast,dynamic_cast,reinterpret_cast,const_cast,implicit cast" or "When should you use unique_ptr instead of shared_ptr?"
[0] http://google-styleguide.googlecode.com/svn/trunk/cppguide.x...
Actually, now I think of it... all the questions were related to operators, except the last one which was a trick question. If all the questions bar one were in regards to operators only, then this isn't a particularly good test.
It tests if a student is able to follow a program's logic with rigor. It tests if you don't interpret the code but actually read it "as is".
Question#1 and Question#2 are less intelligent.
Also, no template test? Are you testing C with classes or C++ ? ;)
I think that's the problem with a lot of first time test (or interview) makers, they make their questions into trick/puzzle questions where they want the test taker to guess what the writer had in their mind.
--edited because I skimmed over the last question and assumed it was printing the values of the variables not the strings--
OP, you did your students a disservice. You should've just assigned a "practicum" exam instead.
2. It is not because a language is not a good option for teaching that it isn't worth using.
BTW After hours of debate, I still think that C is not a bad option for teaching purposes, mainly because it has a very simple syntax and almost NO api which generally introduce confusion.
2. OK. (I didn't make that claim, did I?) C / C++ has it's uses. I use it when I have to (embedded systems, systems programming, and performance). But I don't use it willingly.
I TA'd a course in C for EE's. It was fine. I think it probably helped them in many ways. Anecdote: My favorite course as an undergrad was building our own wire-wrapped 8086 computer. You quickly learn to appreciate assembly (versus manually loading registers), and then quickly learn to appreciate the C compiler.
There was a similar one about pointers. We called it "Star Wars".
Obviously you did not have the joy of working with people who write their own byzantine 1k LoC formatting code for cases that would have been perfectly covered by printf (and yes, this was on a system where a printf implementation was available).
1e: this is undefined behavior (-Wsequence-point) x can be literally anything.
3. a typical mistake that the compiler both warns about and that anyone who has taken a course on C should be able to immediately recognize
bonus 1. void main(int)???
This test is indeed quite evil, especially considering it was for freshman students. I have to admit, though, that the bonus question was great.
if (y = z)
and cout << 'j' << 'k';If, on the other hand, you just silently "correct" the question in your mind, you will fail - especially in a course on programming, because the point is exactly that you have to learn to deal with computers that do not silently "correct" the program that you give them.
That get me to think "this is the evillest thing I can imagine" =)
Hardly the point of the test. Though not sure the point of the test...
1a) will give an error
2a) 2
2b) -10
2c) 4
2d) This is clever, haha. Answer: 5
2e) true (or 1)
5) "This is the answer." because of
if (y = z)
Bonus) jkBut yeah, gcc throws an error
If you put the parenthesis it works
x+ +3 works.
x++3 doesn't.
Technically speaking though, the compiler could see it as x+ +3, but it could equally see it as x ++3, which has two compiler errors: firstly, that's not actually a valid expression, and secondly (at least as I checked in the C99 standard, under section 6.5.3.1 on postfix increment and decrement operators) the lvalue must be modifiable.
All I guess I'm saying here is that it could technically be a typo which leads to invalid syntax, or it could be technically correct, so most compilers will treat it as a syntax error.
Someone above said that gcc was being "closer to the standard", but the standard never attempts to cover this particular corner case. So the gcc devs have done something, to my mind, quite sensible. They treat it as a possible syntax error because it could either be:
x+ +3;
x++ 3;
x ++3;
I'm more interested in how it handles x+++x; - I'd imagine that it's a syntax error. It could be: x++ + x;
x + ++x;
x+ + +x;
The C99 standard doesn't actually explain how to handle this. Perhaps they believe you shouldn't be so daft.I'll stand by original statement that it's a syntax error and most good compilers will treat it as such, even if it is logical to treat x++3 as x+ +3.
Edit: scratch that ALL completely. I forgot about operator precedence.
If you take x++3, then suffix increment is a higher operator than suffix decrement and addition. In other words, the compiler will always try to evaluate the expression as
x++ 3;
In other words, it's a syntax error. It can never evaluate to x + +3, because that's at a lower operator precedence.Thus, it's a syntax error. Take that, downvoter of my original comment.
Edit x2: Definitive answer is here: https://news.ycombinator.com/item?id=5200523
Some days it just doesn't pay to get out of bed... :-)
Similar text to that C++ text is in C99 at 6.4 [Lexical elements], paragraph 4. Paragraph 6 considers the example x+++++y (which is similar to your example), noting that it is to be parsed as x ++ ++ + y. (I guess it uses distinct variables x and y to avoid any distractions due to sequence point issues -- which are immaterial here as the thing fails to parse anyway.)
What it could see is not a valid argument. A compiler could "see" all kinds of absolutely valid situations as invalid, but it doesn't.
5//3
as two division operators and throw an error, but it considers it a comment (to be fair, comments are probably removed by a pre-processor). x+ +3;
I always thought the unary plus operator is a complete waste, and shouldn't be implemented. I can't imagine a situation when it's needed.EDIT: technically, it's a bug in GCC. It sees "x++" and assumes it's a unary increment, followed by a hardcoded 3. It definitely should consider that it's an addition followed by a unary plus (which has higher precedence than addition). But I guess it's an ambiguous syntax, and GCC is just being strict.
"If the input stream has been parsed into preprocessing tokens up to a given character, the next preprocessing token is the longest sequence of characters that could constitute a preprocessing token, even if that would cause further lexical analysis to fail."
This is the same reason why (prior to C++11) nested templates have to be written with an excess space: "std::vector<std::list<int> > foo". (C++11 has a lexer hack to allow a >> token to be valid here and equivalent to two > > tokens.)
For this ++ example, if you want the valid parse, you get to put the space in yourself, just like we're used to for nested templates. This is the trade-off for having a fast mostly conceptually-separate lexer.
Unary plus is nice if you want to write out the symmetry in things like "int signum[] = { -1, 0, +1 }" and I expect there are meaningful uses in ensuring desired conversions occur in some overloading situations (though there would of course be a case for being explicit...).