Preliminaries
Before you begin this lab, you should read through the
CS 361 Submission Procedures. Labs and
projects that do not adhere to these procedures will not be graded.
As such, it is important that you learn how to use Git in order to submit your
code properly.
Make sure that you set up your
configuration file
correctly. Once you have done that, set up a bare repository and clone as
described using the name lab1-ptrs.git
for the repository.
Compiling, testing, and debugging pointers
From CS 261, you are probably used to running make test
frequently to compile and debug your code. For CS 361, you should break this
habit as soon as possible. The testing infrastructure is really bad
for debugging and can give you misleading information in this class. Instead,
use make test
only to find a failing test case to fix.
Then, use just make clean && make
to compile your code
and run the program manually (with or without a debugger).
Step 1: Missing type declarations
For the first part of this lab, create a Git branch called
fix-struct
and implement the following three steps using that
branch. When you are finished with these steps, merge that branch back into
your main
branch.
The code provided does not compile, because the struct
declared in movies.h
is incomplete. Fix this by adding
the necessary fields and their required types. Use the code in
main.c
(starting at line 37) to determine the types that
are needed for each field. Once this struct
is declared,
there should be no compiler errors. Run make
to confirm
that the code compiles.
Step 2: Unit Testing failure
Once you've declared the struct
fields, run make test
to identify the failing unit tests. Start with the first failing unit test
(UNIT_split_title
) and look at the code for it in
tests/public.c
. Compare that code with the split_data()
implementation in movies.c
. Do not fix the code, but determine why
it might be failing.
Step 3: Tracing segmentation faults
Now run the program using ./ptrs -m
. The code should have a
segmentation fault when you do this. Determine where the fault occurs by
starting a GDB session:
gdb --args ./ptrs -m
...
Reading symbols from ./ptrs...
(gdb)
At the first (gdb)
prompt, run start
to get to
the beginning of main()
, then continue
to let
it run. You'll then see a message that looks like the following:
Program received signal SIGSEGV, Segmentation fault.
__GI___strtok_r (s=0x555555556090 "The Shawshank Redemption,1994,Drama", delim=0x5555555560f9 ",", save_ptr=0x7ffff7fa0528 ) at ./string/strtok_r.c:72
72 ./string/strtok_r.c: No such file or directory.
(gdb)
Now run the backtrace
command and determine which line of
movies.c
caused the segmentation fault. This line is the cause
of the test failure in Step 2. Use quit
to get out of GDB,
then fix this code. (HINT: Notice that the next line uses strdup()
.
What does this function do and how does that relate to this current bug?)
Once you think you have fixed the code, run make
(NOT
make test
) to recompile the code and run the executable again
as ./ptrs -m
. If your fix is successful, you should not have a
segmentation fault and you should see the title printed out. (At least, you
should not have the same segementation fault; you may have a new one from a
different part of the code.) Once that is true, run make test
to
confirm the UNIT_split_title
test now passes.
All of the lab descriptions are set up to give you a sequence of
steps to work through that typically align with the order of the test
cases. Whenever you are passing a new test case, run git add .
and git commit
to save your progress. Then, when you are
working on the next step, you have a checkpoint that you can go back to
if you make a mess of your code.
String manipulations
Many of the biggest headaches with pointers relate to improper manipulation
of string pointers. C strings are very different from Java strings, which can
lead to common mistakes. These steps illustrate how to work with strings in a
way that C understands. Implement these two steps on a new branch called
strings
, merging the completed work back into main
.
Step 4: String parsing
Finish the rest of the split_data()
, adding just enough code
to pass the associated unit test cases. Use the comments in
split_data()
(in movies.c
) to store the
information from each token
(created by splitting the string at
each ","
) into the movie
. See how
movie.title
is set up for an example. Also refer to the
OpenCSF Appendix
for more examples of strtok()
.
Again, do not rely on make test
for debugging.
Recompile and run the code manually, convincing yourself the code is functioning
correctly. Once you are sure, then run make test
and (if successful)
add a Git commit.
Step 5: String merging
The UNIT_merge_movie
and INTEG_movies
tests
should be failing at this point. We will start with the integration test.
Do not look at the tests/outputs/INTEG_movies.diff
file. Instead,
examine the expected integration test output
(in tests/expected/INTEG_movies.txt
). Compare this with the result
of running your program manually:
Add just enough code to merge_data()
append the title, then
compile and rerun the program. If the title is being printed on the last line
of output, complete the function. When you are finished, you should pass both
the UNIT_merge_movie
and INTEG_movies
tests. (If you
are still failing the unit test, you might not have allocated memory for the
merged string property.)
Step 6: Incomplete integration tests
One common mistake in development approaches where all tests are given in
advance is that students repeatedly hammer at the test cases, running
make test
whenever you make a change to see if it passes. However,
when you do this, you never see your program's actual output and you
may not have even considered the expected output is for a particular
input.
To combat this tendency, all labs in this class include a
certain number of incomplete integration tests. Specifically, the expected
output file contains placeholder text that you must correct before the
test case will even run. In this case, you should still be failing the
INTEG_movies_inc
test with a message that
expected/INTEG_movies_inc.txt
is "not correct." You must open
this file (tests/expected/INTEG_movies_inc.txt
to be precise)
and complete it according to the instructions.
There are two types of corrections. Any line with four angle brackets
(e.g., <<<< ... >>>>
) contains
instructions and the entire line must be deleted once you are finished.
Other parts of the file use two angle brackets (e.g.,
<< ... >>
). These are placeholders that indicate
where you need to put a specific output message. When you are finished,
the angle brackets should not be there.
HINT: The tests/expected/INTEG_movies_inc.txt
file should
be identical to tests/expected/INTEG_movies.txt
when you are
finished. Make sure you do not leave any extraneous spaces.
Memory leaks and submission
Step 7: Memory leaks (optional but recommended)
If you followed the instructions above exactly (without doing more than
told to), you introduced a memory leak in Step 3. However, the scripts run by
make test
don't actually detect this one, because it is
marked as "possibly" lost instead of "definintely" lost. To identify and
fix this leak, run valgrind --leak-check=full ./ptrs -m
.
Where is there a memory leak? What causes it and how can you fix it?
Fixing memory leaks is not required for labs, but it is required for
project submissions. This step will give you practice fixing them.
Code submission
As you completed these steps, you should have created multiple Git commits
using git add
and git commit
. To submit your code
for grading, run the git push
command. If you want to confirm
that your code has been submitted, create a new clone somewhere else in your
$HOME
directory. This clone will have any code that you pushed
to your repository.