Written by Julie Zelenski
As you vanquish each CS107 assignment and lab, a little celebration is definitely in order, but once the excitement dies down, take a moment to reflect on how far you've come and what new knowledge and skills you have to take forward. To help you gauge your progress, for each assignment/lab, we identify some of its takeaways and offer a few thought questions you can use as a self-check on your post-task understanding. If you find the responses don't come easily, it may be a sign a little extra review is warranted. These questions are not to be handed in or graded. You're encouraged to freely discuss these with your peers and course staff to solidify any gaps in you understanding before moving on from a task. They could also be useful as review before the exams.
You now have your environment configured and edit files, make commits, and execute programs. You've also been getting into a testing mindset, developing testing strategies, and using tools such as sanity check and Valgrind. Off to a great start!
commit and submit? You should now feel acquainted with basic use of make, Mercurial, gdb, and Valgrind and have identified resources to tap info when you need more information about the tools or the C language and its libraries. You also have done a little wrangling with C-strings and I/O. All of these skills are very helpful for assignment 1!
hg diff command do?piglatin) under gdb?scanf for strings? What happens when scanning a too-long string without one? What happens when scanning a too-long string with one?strncpy null-terminate the destination string? What about strncat? Where could you look to find this information if you don't already know it?Congrats on your first complete C-program! This was great practice with C-strings, strxxx functions, dynamic memory, use of tools, and software testing. At the end of the quarter, many students recall this first assignment as one of the tougher ones -- not so much due to code/algorithm complexity, but because of the effort needed to become comfortable with the new tools/environment and find your way through the sparse, unforgiving world of C. Celebrate this important milestone and remember the investment you make now in gaining proficiency will pay off throughout the quarter.
fscanf signify? Why is it important to check it?char* has a matching prefix/suffix N chars long. What would happen if your expression were evaluated with a value for N that was longer the string's length?realloc function? What happens if you attempt to realloc a string that wasn't malloc'ed in the first place?You should be continuing to build up your gdb and Valgrind repertoire and becoming comfortable with thinking about and manipulating memory/pointers in terms of raw bytes and addresses. Arrays and pointers are ubiquitous in C and a good understanding of them is essential.
& applied to the name of a stack-allocated array (e.g. &buffer) is a legal and well-defined expression, it isn't really sensible. Explain why such use is a sure sign of an error/misunderstanding on the part of the programmer.realloc? Why doesn't realloc just re-assign the pointer when it's necessary to move the memory block?Address 0x420d50 is 0 bytes after a block of size 24 alloc'd . Your roommate insists Valgrind is off-base and paranoid because the program runs just fine. Explain to them why accessing memory "0 bytes after" is an actual problem, even though it might be asymptomatic in some contexts.lfind with an appropriate callback to re-implement the functionality of strlen.All these gyrations with CMap/CVector were to bring about a rock-solid understanding of the client use of a void* interface. The critical mastery is correctly passing/receiving the void*s flying around: what level of indirection to use, what typecasts are needed, using * and & in exactly and only the necessary places. You should know without question how to determine the necessary level of indirection and correctly apply it. It's also valuable to understand and be able to reason through the consequences of getting it wrong.
cmap_put is a char* -- where does it point to? is allocation required? who allocates it? is the pointer itself copied or its contents (the pointee)? will memory need to be freed? who will free it? What are the answers to those same questions for the void* value passed to cmap_put?int, bool, struct, or pointers to any type. In which situations is it appropriate for the element to be a pointer type? What extra precautions need to be taken by the client when storing elements of pointer type?free matches the prototype for the cleanup client callback used by CVector/CMap. However it is never the right function to use as a cleanup fn. Explain why not.Now with command of the bitwise operators and understanding of masks, you can access and manipulate bits. Be sure to have a solid grasp on the representation of unsigned values as a binary polynomial and signed values in two's complement and be comfortable relating bitwise tweaks to changes in numeric value. Know what happens on assignment between integer family types of different bitwidths and signed-ness.
memcpy and memmove and when to use each.x command? Show the x command to print a 2-member array of 4-byte integers in hex and again to print that same memory as 8 single-byte characters.size_t (unsigned). Consider the erroneous call malloc(-1), which seems to make no sense at all. What happens when you try to compile such a call? What happens when it executes?You are now unstoppable in terms of manipulating raw memory. You know how to use the type system to your advantage wherever you can, but also how to work without it where you must. You know the care required to make a proper call to memcpy/memmove, exactly where and why you need a typecast, and have increased vigilant about using the correct level of indirection.
void* in a pointer-arithmetic expression?next as assignment with typecast, key with strcpy, value using memcpy. What's the difference between those options? What makes one technique more appropriate than the others in a given situation?cvec_next use the previous to orient itself within the iteration? What happens if the client passes an invalid pointer for previous? How about for cmap_next? Would it be possible to reliably detect/assert that the client has passed an invalid pointer? Why or why not?You have worked through bit patterns for a variety of float values and learned how the representation is organized. You have a feel for the inherent compromises in this system: which values are representable, which are not, the gaps in the floating point number line, and what kind of error/approximation to expect from a floating point calculation.
ui from float f?unsigned int ui = (unsigned int)f;
unsigned int ui = *(unsigned int *)&f;
You should feel a growing mastery of bitwise manipulation. You have a solid understanding of bit patterns as they relate to the representations for ints and floats and how they dictate the behavior and limitations of the two numeric systems.
00000001 to 00000000, but the value of the exponent 2-126 is unchanged. Explain why the special case. What would be the effect if the exponent 2-127 was used for the denorms instead?pushq as an example.You now have tools for disassembling object files and have been introduced to the debugger commands used at the assembly level. The hands-on practice relating C code to its compiled assembly and reverse-engineering from assembly to C is great preparation for the upcoming binary bomb assignment.
<optimized out>?sar and shr?op1 and op2 for the branch to be taken? What changes if ja is substituted for jg?cmp op1,op2
jg target
After reverse-engineering the bomb, the assembly skills of CS107 students are unstoppable!
lea instruction is doing an address calculation versus when it is merely arithmetic?This is one of my favorites among the labs -- lots of neat exercises to explore! Having learned the gdb commands to dig around in the stack frames and being able to relate the contents of the stack to the runtime program state is valuable insight when debugging.
An important takeaway from this lab is to become familiar with various build tools (make, preprocessor, compiler, assembler, linker) and how each fits into the build process, especially so as to be able to diagnose and address any build issue you might run into now and in the future.
#include <math.h> and linking with the math library?You have dissected your way through an ELF file and learned how to insert your code into a program to monitor/probe its runtime activities and in the process written a pretty cool developer tool -- way to go!
ccp approach to interposing on a library function. How does it differ from the ld approach?Your killer reversing skills are just what is needed for examining the generated assembly and identifying gcc's cool transformations to make code run faster. Learning how to use Valgrind callgrind is another key tool to add to your developer arsenal.
push instruction require same cycles to complete as cmp or div?) Does every instance of a particular asm instruction have a fixed cost (i.e. every push same? every xor same? every mov same?) Explain.A former student likened heap allocator to a "victory lap" -- a chance to put your hard-won expertise to work and enjoy the triumph of seeing what you are now capable of! Success requires heroic skills with void* pointers, raw memory manipulation, assembly, optimization of both code/memory, and deep proficiency with tools. You have just written an allocator that competes head-on with the industrial-strength libc version -- how crazy-awesome is that??!