Assignment 0: Refresher

Assignment 0: Refresher

This assignment contains a few exercises to help you get back up to speed on some basic skills you'll need for CS 111. You should already have learned most or all of these things in previous classes such as CS 107, so this should be a relatively easy assignment.

Learning Goals

  • Remember how to login to the myth machines.
  • Remember how to use the gdb debugger to debug a program.
  • Refamiliarize yourself with some of the basic C++ template classes, such as std::vector, std::map, and std::unordered_map.
  • Remember how to write object-oriented programs with classes, methods, and instance variables.
  • Remember how to use the sanitycheck and submit tools to test and submit assignments.

Using the Myth Cluster

All of the assignments for this class will require you to login to the myth cluster using ssh. Hopefully this will be familiar to you from prior experience in CS 107. If not, we recommend that you consult the CS 107 Getting Started Guide. You may also find useful a Web page on Choosing a Text Editor. Among other things, it describes how you can edit documents locally on your laptop while doing your compilation and testing on the myth cluster.

We will use the same general flow for working an assignments that is used in CS 107. For details, please consult the Working on Assignments Web page from CS 107. This page will walk you through how to get the starter code for an assignment and how to compile, test, and submit your work.

Starter Code

To get started on the assignment, login to the myth cluster and retrieve a copy of the starter code by entering the following command into a console window:

git clone /afs/ir/class/archive/cs/cs111/cs111.1236/repos/assign0/$USER assign0

Be sure to type the command exactly as above, including the $USER, or copy and paste the text just to be safe. This command will create a git repository containing starter code for the assignment and place it in a new folder called assign0 in your current working directory.

If the command fails with an error that the repository does not exist, double-check for typos in the command, and make sure you are logged into a myth machine. If these checks don't fix the problem, then you were probably not on the Axess enrollment list at the time we created the student starter repos. Please post a private question on Ed and include your SUNet ID so we can manually set up the starter code for you. Make sure to enroll in Axess as soon as possible (if you haven't already) so that the starter code is automatically generated for you in the future.

The starter code contains the following relevant files for your work on the assignment:

  • questions.txt: a text file where you will answer questions for the assignment
  • buggy.c: a provided (buggy!) program that you will use to get practice with the gdb debugger
  • moviecredits.cc: a program that you will complete to print out the cast for various movies
  • moviecredits-util.cc: a file that constructs a test database for moviecredits.cc; you do not need to modify this file.
  • Makefile: contains instructions for how to compile all the assignment programs. You can run the make command and it will compile all the programs on the assignment for you.
  • movie.hh and movie.cc: the definition of the Movie class you will be implementing
  • movietest.cc: a test program for the Movie class; you will modify this to add one additional test of your own
  • tools: contains symbolic links to the sanitycheck and submit programs for testing and submitting your work.
  • samples: a symbolic link to the shared directory for this assignment. It contains:
    • buggy_soln, moviecredits_soln and movietest_soln; provided fully-implemented sample solutions

Exercise 1: Administrivia

Before beginning work on this project you must complete a few administrative tasks:

  • First, read the CS 111 Honor Code Policy to refresh yourself on the Stanford Honor Code and the specific ways it should nine your behavior in this class.
  • Complete the CS 111 Honor Code Form to test your understanding of the Honor Code. You must complete this form as part of this assignment.
  • Open the file questions.txt in your favorite text editor, enter your name at the top, and fill out the "Exercise 1 portion" of the file by adding your initials in the appropriate boxes.

Exercise 2: The GDB Debugger

The gdb debugger is an valuable tool for debugging C and C++ programs. It allows you to pinpoint the source of a crash, set breakpoints to pause your program mid-execution, print variable values, step through your code, and more. Here are some resources about gdb that you might find useful:

If you're not yet comfortable using gdb, this quarter is a great time to develop that skill. You'll find that skill useful in the future, both in classes and in jobs. To provide some practice with gdb, we've created a program called buggy.c that crashes when running on certain inputs. It is a short program that was meant to test a function lastN, which checks a string to be sure its length is a multiple of N characters, then extracts the last N characters of the string. However, the program doesn't quite work as expected:

  1. Open buggy.c and read through the code to get a sense of what it is doing. Use the manual pages to look up information for any functions you want to read more about - for instance, to read up on the strcpy function, run man strcpy (you can also access manual pages by entering commands such as "man strcpy" into your favorite Web search engine). Compile all assignment programs by running make (or make clean to remove the compiled executables) and run the program by specifying command line arguments like this: ./buggy hello or ./buggy hello cs111. Compare with the provided (non-buggy) sample solution at samples/buggy_soln to see the intended behavior.
  2. Run the program again using gdb, invoking it with the same arguments that caused it to crash. Then answer Questions 2A and 2B in questions.txt.
  3. If you haven't already done so, use gdb to determine the cause of the crash. The problem can be fixed with a one-line change to the program; make that change.

Exercise 3: C++ STL Collections

In C++, we have the advantage of various data structures ("collections") we can use to store data, such as maps, sets, etc. If you took CS106B, you may be familiar with the Stanford Libraries data structures, which are specific to CS106B. But C++ has its own built-in set of standard STL ("Standard Template Library") collections in the language itself, which are similar to the CS106B versions. This exercise will give you practice using the STL vector and map, and you can read more on your own about others, such as set and unordered_map.

You will probably want to access reference documentation for the C++ library while programming, and there are two popular Web sites that provide C++ reference documentation online: CPlusPlus and CPPReference. We've created a page with quick links to reference documentation for the most important classes you'll use in this class.

vector

A C++ vector is a resizable array that can hold objects of any type (all the objects in a given instance must have the same type). You construct one by specifying the type in <>, and you can access elements by index, add/remove elements, etc.

Here is a short example program that appends entries to a vector and then prints them out. For iterating over elements in a vector, you can iterate using a regular loop counter, or you can use something called a "range-based for loop", as in this example:

vector<int> nums;

// Add elements 0-9, each time appending to the back.
for (int i = 0; i < 10; i++) {
    nums.push_back(i);
}

// Regular for loop - prints 0-9
for (size_t i = 0; i < nums.size(); i++) {
    cout << nums[i] << endl;
}

// Same, but range-based for loop.
for (int& num : nums) {
    cout << num << endl;
}

Check out a reference page for information on other methods.

map

A C++ map stores key-value pairs and allows you to lookup values that correspond to particular keys. You specify the types of the keys and values in <> when declaring the map.

Here is a short example program that adds entries to a map, checks if an entry is in the map, and then prints all entries out. For iterating over key/value pairs in a map, you can use a similar "range-based for loop" - note the somewhat quirky syntax below:

// First type is key, second type is value.
map<int, int> numsMap;

// Add 0->1, 1->2, 2->3, 3->4, etc. (value = key + 1).
for (int i = 0; i < 10; i++) {
    numsMap[i] = i+1;
}

// This should print "12 is not in the map"
if (numsMap.find(12) != numsMap.end()) {
    cout << "12 is in the map" << endl;
} else {
    cout << "12 is not in the map" << endl;
}

// Range-based for loop - we access each pair as a const reference
// to avoid making copies. "Auto" means "auto-detect" the type;
// we generally discourage using auto because it obscures the type
// information, which is useful. However, in this case it's OK
// because the type is somewhat complex and not very helpful (we know
// that key will have the type of a key and value will have the type
// of a value).
for (const auto& [key, value] : numsMap) {
    cout << key << ": " << value << endl;
}

However, a word of caution: if a key is not in the map, using [] will insert it! This is called auto-insertion, and is sometimes useful, but can also cause problems. In other words:

map<int, string> numToStrMap;

// 2 is not in the map, but trying to access it with []
// will auto-add an entry for it with an empty string value,
// and then return that!
string nonExistentValue = numToStrMap[2];

cout << nonExistentValue << endl;    // Will be empty string
cout << numToStrMap.size() << endl;  // Will print 1!

Therefore, it's good practice to check if something is in a map (e.g., using the find method) before you try to access it.

Going to the Movies

To get practice with using STL vector and map, we've provided the scaffolding for a program moviecredits.cc that reads in a movie information database and prints out information about each movie and its cast. You can run it by specifying either "small" or "large" for what dataset to read from:

./moviecredits small

Try running the sample solution to see its intended behavior:

./samples/moviecredits_soln small

You must make two changes to this file. First, fill in the implementation of the build_movie_map method, which has the following signature:

void build_movie_map(const vector<Movie>& movies, map<string, vector<string>>& movieMap);

build_movie_map takes in a vector of Movie structs and copies information from the vector to a map (which is initially empty). The map is passed by reference, so build_movie_map modifies the caller's copy. This function should go through the vector in order and populate the map with information about each movie, using the movie's title as the key and its list of actors as the corresponding value. You can find the definition of Movie at the top of moviecredits.cc.

It's possible for multiple movies to have the same name (eg. remakes). If, when adding an entry to the map, you see that an entry already exists with the same movie name, you should modify the name of the new entry to include the year as part of the name, to disambiguate it (hint: use the to_string function to convert a number to a string). To be more precise, if movies contains 2 entries for a movie named "Popular Movie", one from 1950 and one from 1990, you should use the title "Popular Movie" for the first instance and "Popular Movie (1990)" for the second.

In addition to filling in the body of build_movie_map you should also add code to the main function to print out the key/value pairs in the map. The output should be sorted by title. One of the nice things about a C++ map is that it sorts its contents, so if you iterate over it in the normal way, the entries will be in alphabetical order sorted by movie name. Thus, the order of entries in the map will be different from the order in the original vector, which was sorted by release date. Run the sample solution to see the expected output format; note that you will also need to iterate over the vector of actors for each movie in order to print them.

To test, try running tools/sanitycheck; it will run tests for both the small and large datasets and compare your output with the sample solution.

Our solution for this function is approximately 15 lines, not including comments.

Exercise 4: Movie Class

A class allows us to define our own variable type with methods we can call on it (like object.method()) and with instance variables inside it. This CS106B page gives a great refresher on classes and object-oriented programming. Another good resource is this reference. In particular:

  • The constructor is called whenever an object of that type is created; it is responsible for initializing the state of the new object (instance variables).
  • The destructor is called whenever an object of that type goes away (e.g. it's on the heap and deleted, or it's on the stack and it goes out of scope); it is responsible for cleaning up state, such as heap-allocated instance variables.
  • An instance method is a function that you call on an object of that type; that method has access to all of that object's instance variables when it runs.
  • An instance variable is state within the class; each object of that type has its own copy of any instance variables.

This exercise is intended to refresh your knowledge about basic class design. You will implement a simple class that manages Movie objects (note: these objects are totally different from the Movie objects in Exercise 3). Each object stores information about one movie, including its title, the actors in the movie, and the role that each actor played. Take a look at the header file movie.hh: it defines the methods and drives how each method should behave, but it doesn't implement any of the methods; the method implementations are in movie.cc.

Fill in the bodies of the methods in movie.cc so that they implement the behaviors documented in movie.hh. You will also need to add private instance variables in movie.hh to store information about each movie. You may need to add #include statements for library packages that you use in your solution, and you can create private helper methods if needed. The methods in movie.cc require only a few lines of code each (in some cases a single line will do the job).

We have written a test program movietest.cc, which contains 5 tests to exercise the class; once you have run make, you can invoke a single test with the command ./movietest N, where N is a number from 1 to 5. This will invoke a method named testN in movietest.cc. Open the file movietest.cc and find method test3, which implements test 3. Then answer Question 4A in questions.txt. When you are debugging the assignments for this class, you should read the code of the tests, like those in movietest.cc, so that you understand exactly what's happening.

Once it appears that all five of the tests are behaving as you expect, invoke the command tools/sanitycheck. This will run all of the tests and compare their output with the sample solution (this is the approach we will use to test your submission).

When you have completed your implementation of Movie, answer Question 4B in questions.txt.

Submitting

Once you are finished working and have saved all your changes, submit by running the submit tool in the tools folder: tools/submit. Make sure that you have answered all of the questions in questions.txt before submitting.

We recommend you do a trial submission in advance of the deadline to allow time to work through any snags. You may submit as many times as you like; we will grade the latest submission. Submitting a stable but unpolished/unfinished version is like an insurance policy. If the unexpected happens and you miss the deadline to submit your final version, the earlier submit will earn points. Without a submission, we cannot grade your work. You can confirm the timestamp of your latest submission in your course gradebook.

Grading

Here is a recap of the work that will be graded on this assignment:

  • questions.txt: confirming enrollment information and answering a few questions.
  • buggy.c: fixing the buggy program.
  • moviecredits.cc: your implementation of build_movie_map.
  • movie.hh and movie.cc: your implementation of the Movie class.

We will grade your code using the provided sanity check tests and also possible additional autograder tests. We will also review your code for style grading. Check out our course style guide for tips and guidelines for writing code with good style!

Credits: this assignment was created by Nick Troccoli.