Written by Julie Zelenski, with modifications by Nick Troccoli
First, a quote from Will Shortz, the crossword puzzle editor of the New York Times:
A crossword puzzle is a battle between the puzzle maker and editor on one side and the solver on the other. But unlike most battles, both sides here have the same goal -- for the solver to win. A perfect puzzle may put up lots of resistance. It may, in fact, seem impossible at first. Ideally, though, in the end the solver should triumph and think, Oh, how clever I am! -- Will Shortz, How to solve a crossword puzzle.
We love the spirit of this quote as it applies to exams. We absolutely want you to come out on top! The lectures, labs, and assignments work together to guide you toward mastery of the course learning goals and the exams serve as an assessment of your progress. The absolute best outcome is everyone has a great grasp on the material to succeed on the exam. Read on for more advice on how to make that happen for you!
What To Expect
Our exams are designed to evaluate your mastery of the course learning goals. The exam questions usually will ask you to complete coding tasks and answer thought questions. The exam questions will focus on material from the assignments, labs, lecture, and reading (this list is in order of decreasing emphasis). As an example, we are not going to test you on some obscure fact out of the reading that was never even mentioned in lecture, lab, or an assignment. Answering the exam questions is typically going to require good comprehension of the foundational concepts and the ability to analyze and apply them in a given situation. We are evaluating that not only did you successfully complete the assignments and labs, but that you came away with a comprehension you can demonstrate. We generally do not ask details that can/should be looked up on demand ("How do you printf a number in hexadecimal number padded to 8 digits?").
We will give you a practice exam as a sample. Many questions will ask you to write short passages of C code. Other questions may ask you to analyze C code: to trace its behavior, to compare or contrast two versions, identify and fix flaws, or draw a picture of the memory layout. Others may ask you short questions about material or code. On the final, we will ask you to similarly analyze assembly instructions or translate between C/assembly. There may also be short-answer thought questions that ask you to reason about system behavior, coding tasks, numeric representation and limitations, performance tradeoffs, and the like.
When scoring answers, we will not be picky about minor syntax and oversights (missing braces around a block of clearly indented code, we don't ask for #include's etc.), but there are subtleties that matter immensely, e.g., a
int** is just one character different than
int*, yet there is a world of difference between the two! The lion's share of the points for a problem will be reserved for grading the critical core of the code, and it is worth it to be very careful with the details on those portions. For example, if we ask you to write a function that processes a generic array, only a tiny fraction of the points will be allocated to tasks such as initializing the counter or iterating over the right bounds, while the bulk of the points will be gained or lost in the tricky details of whether you correctly handle the
void*s. Being off-by-one in the loop is a tiny deduction, but being a level of indirection off or applying the wrong cast is a larger issue. Be sure to focus your attention accordingly!
The kind of systems coding we do in CS107 leaves much room for error, spanning the gamut from oversights such as forgetting to return the function result to more serious omissions such as failing to allocate memory for a pointer. Nearly everyone loses a few points that could have been avoided with more time and a chance to execute/test the code. However, a solid first-pass approximation that shows the correct conceptual understanding of the key issues will earn the bulk of the points and, in our analysis, deserves to be strongly distinguished from code that exhibits significant conceptual issues and would require much trial-and-error with compiler/debugger/Valgrind to turn into working code.
Before The Exam
- The long view. The mastery we are looking to assess with the exams isn't created by a night of cramming, it is built up throughout the quarter. Make it a priority to monitor your own progress and use our post-task self-checks listed at the end of each lab/assignment to identify holes or confusion to be shored up before moving on. In the ideal situation, you have established solid understanding of the material and the only exam preparation needed is practice applying your skills under exam-like conditions.
- Make reference/summary page as part of exam prep. Reviewing topics and determining what information is worth including on your reference page(s) will remind you of where we've been and help you take stock of your comfort level with the course topics. Use this opportunity to identify any areas on which you feel weak and resolve dangling issues before heading into the exam. Even if the exam format allows use of larger pool of resources, preparing your own compact summary of the critical details is useful study practice and you will appreciate having it at the ready during the exam.
- Recreate the environment. The best practice is to solve problems in an exam-like setting, without the aid of a compiler/debugger/Valgrind, and under a time limit, just as you will have to during the exam.
- Practice makes perfect. Take problems (lecture example, lab exercise, problem from the text, sample exam problem, or tasks of your own creation) and write out a solution under exam-like conditions. Review it to see how you did. This is much more valuable than a passive review of the problem and its solution where it is too easy to conclude "ah yes, I would have done that" only to find yourself adrift during the real exam when there is no provided solution to guide you!
- Get your questions answered. If there is a concept you're a bit fuzzy on, or you'd like to check your answer to a lab exercise, or you wonder why a solution is written a particular way, get those questions answered before the exam. Reach out on the forum or come to helper hours and we'd be happy to help.
During The Exam
- Spend your time wisely. Don't get stuck on any particular problem. You'll earn more points from reasonable efforts across all problems than by perfecting one answer at the cost of leaving others blank. Take into account the point value assigned to each question when budgeting your time. Be conscious of which details are worth slowing down to get it right (e.g. allocating memory, getting the right typecast, correct pointer math, and so on) and which tasks can do with just a quick first draft (e.g. an off-by-one loop index or forgetting to initialize a counter).
- Pay attention to specific instructions. A problem statement may include detailed constraints and hints such as "use only bitwise operators" or "ignore the case when the string is empty" or "must run in constant time". You may want to highlight these instructions to be sure you don't overlook them. These constraints are not intended to make things difficult; typically we are trying to guide you in the direction of a straightforward and simple solution. If we provide a hint or suggestion (e.g. "you may find it helpful to ..." or "consider using ..." or "you can assume ...") then you are free to take or leave that advice. However, stronger statements (e.g. "your solution must ..." or "your solution cannot ...") must be adhered to. If you disregard these instructions, you are likely to lose points for not meeting the problem specification and/or for errors introduced when attempting an alternative.
- Ask a question rather than answer the wrong one. If you are uncertain about what a question is asking or find some part of the question ambiguous, it's worth your time to ask the course staff for a clarification so you can be sure you are solving the right problem before you start working on it.
- Document your assumptions. If you're unsure of a language/library detail that you can't easily lookup (e.g. whether
strncatnull terminates, does right-shift do arithmetic shift) make your best guess and include a note to the grader to indicate what you're assuming and we'll do our best to grade accordingly from there. We reserve the right to make a deduction if your assumption is fundamentally wrong or significantly changes the assigned task, but with your assumptions made clear, we will at least be grading your answer within the same context in which you wrote it.
- We are lenient on syntax We are not picky about minor syntax/oversights (especially trivial details that would be flagged by compiler and easily fixed), but some small changes have enormous consequences and will be deducted for, such as an extra
- Substance AND style. For coding questions, the majority of the points are typically focused on the correctness of the code. However, there may be deductions for code that is roundabout/awkward/inefficient when more appropriate alternatives exist. We will reward the simple, direct approach for its good design decisions and such code will likely have fewer correctness issues, so the choice of appropriate design can have a large impact. For example, we expect you to leverage appropriate features from the standard libraries; re-implementing that functionality wastes your valuable time and introduces opportunity for error.
After The Exam
For most students, the assignment and exam performance are fairly well correlated but sometimes they do diverge a bit. It's pretty rare to rock the exam if your assignments didn't go well, but there are students who go into the exam with solid assignment scores and yet emerge with a disappointing outcome. What might explain this and what can you do about it?
Make sure you are mastering the material while completing the assignments. You should not complete assignments using trial or error techniques, make a change if you don't understand its implications, or only make modifications that the course staff tells you to. Even though you may get through the assignments, you won't be able to reproduce these results in an exam setting. The goal of an assignment is not to get the program to work, one way or another, it is about developing an understanding of how and why it works, and being able to take that understanding and write similar code in any environment, including one that doesn't have the luxury of a compiler/debugger/Valgrind/CA/sanitycheck to tell your whether the code is correct or not.
Gauge your comfort with the material. Did you feel like you spent a lot of time looking through your materials and clarifying concepts during the exam? Did you feel that the mistakes you made on the exam were just small oversights, or more conceptual? Use the exam results to answer these questions about your understanding of the material and use them to prepare even better for next time.
Ensure comfort in the testing environment. If you feel that one of the reasons behind how you did on the exam was lack of comfort in the testing environment (no tools, time limits, etc.), make sure to practice more in test-like conditions. Review your exam, introspect on what happened, brainstorm tactics for next time, and do some practice.
More broadly, the ability to analyze and reason about code in isolation is a valuable skill for any computer scientist. It forces you to think before you code, rather than leaning too much on the tools. At every step, you want to ensure that you understand the code you are writing, what it does, and how it works.