CPS 100E, Fall 1996 Lab 7

More Linked Lists and Debugging

(You may find it easier to read this lab using Netscape or another browser, the URL is http://www.cs.duke.edu/~ola/courses/cps100e/lab/lab7.html)

This lab is OPTIONAL. You do NOT need to do the lab, but lab points for this lab can be used to make up for lab points lost on other labs. You can also work on the optional Word Ladder program.


The goals of this lab include doing the specific tasks outlined below and understanding general concepts behind the tasks.

Lab 7 table of contents

[ Introduction | The Program | Debugging: Using ddd | Summary of ddd Commands | Modifications To Program | Submit ]

Introduction

In this lab you'll work with linked lists and linked lists of linked lists (and doubly linked lists)

In large courses students are usually placed in smaller sections indicated by section numbers. For organizational purposes, each section will be represented by a linked list of students. The sections in a course will also be linked together in a list. A section is represented by a SectionNode.

struct SectionNode { int section; SectionNode * next; StudentNode * list; SectionNode(int sec, SectionNode * link = NULL, StudentNode * sptr = NULL) { section = sec; next = link; list = sptr; } };

A SectionNode stores the section number, a pointer to another section node, and a pointer to a linked list of students. This struct contains a constructor with default values for the pointers. A new SectionNode can be constructed with just one argument, an integer, and the two pointers will have default values of NULL.

Information for a student is shown in a StudentNode (shown below), which contains the first and last name of the student, and a pointers to nodes after and before the node (this makes the list of students a doubly-linked list.)

A constructor and a function Print are declared in the struct. If ptr points to StudentNode, then ptr->Print() invokes the Print member function, printing the name of the student in the node pointed to by ptr.

struct StudentNode { string first; // first name string last; // last name StudentNode * next; StudentNode * prev; // points to previous node StudentNode(const string & fname, const string & lname, StudentNode * after = NULL, StudentNode * before = NULL) { first = fname; last = lname; next = after; prev = before; } void Print() { cout << "\t" << first << " " << last << endl; } };

In the example below, the course cps100e has sections 2 and 3. Section 2 has two people, section 3 has 1 person. Each list of students has a dummy header node as shown.

*

Compiling/Running sections

In this section of the lab you'll copy files and then compile and run the linked list demo program.

First change into your cps100e subdirectory (type pwd to verify where you are). Create a lab7 subdirectory by typing mkdir lab7 and change into this subdirectory (be sure to check that you're in the lab7 subdirectory.) Now copy the files for the lab (don't forget the . when copying).

cp ~ola/cps100e/lab7/* .

You should see the files listed below (these are links to the files in case you use Netscape, and for users outside of Duke). This will copy one data file of names (for people in 100e).

Be sure you're in the lab7 subdirectory, and check to see that all files are there (type ls). Then, from an xterm window (at the prompt [1] ola@teer8% or similar) compile the first version of the program by typing: make sections.

This should compile several files and link them together with the library libtapestry.a. The program reads from standard input (cin). You'll redirect input so that the program reads from a file by typing:

sections < sec.dat Now the program will read from the file sec.dat. The program prints section 1 and the students in section 1, then a Segmentation fault occurs. This is a common error that occurs when working with pointers. The error message is not very helpful. Your first job is to find the place in the code that causes the segmentation fault by using ddd (a debugging tool that we want you to begin to use.)

back to lab contents


Debugging: Using ddd:

In this part of the lab you'll learn how to use ddd to find the reason that sections crashes. You will fix the bug and check to make sure that the program runs correctly.

To start the debugger, type

ddd sections & from an xterm window. Two windows will pop up on your machine. One will be the command window, and the other window will show the source code sections.cc. The windows may take a long time to pop up, so be patient.

You should run the program: either type run < sec.dat inside the command window. ddd will run the program and stop when the segmentation fault occurs. There will be an arrow (kind of greenish in color) on the left side of the source code window pointing at the line number that is causing the segementation fault. This information, the name of the file, and the line number is printed in the DDD command window (the command window is running the gdb debugger, ddd is a graphical front end to gdb. You can run gdb without the GUI front end if you're on a computer without the ability to display X windows.)

Sometimes (as in this case) the error appears to be in a function that you did not write! But usually, the error is in your program, it was caught as you were calling another function, so the execution halted inside the other function.

To find where in the program sections.cc the error occured. Type where in the command window or press the corresponding button. When your program crashed, there were many function calls on the system stack. They are shown in reverse order. Somewhere near the bottom you'll see main, line 157. On this line, main called the function PrintList, whose call is shown immediately above this line. PrintList called PrintSection which generated many recursive calls. With each call, the value of current is shown (current is a pointer, so its value is some address shown in hexadecial). In the last calll (top on the stack of calls), current has the value 0x0 which represents NULL at line 92 in the file sections.cc.

Take a look at line 92 in sections.cc (to move to a particular line, type "C-x g" in emacs. If that doesn't work, type M-x goto-line, that is, press the ESC key once followed by "x goto-line", then return, and then a line number). The line is

current->Print(); What does this line do? The pointer current points to a StudentNode, and current->Print invokes the Print function defined in the declaration of StudentNode, printing the first and last name of the student. In the debugger, above all the calls to PrintSection, there is a function call to StudentNode::Print but the pointer to the student node is NULL (0x0).

What happens when current has the value NULL? Then current->Print() doesn't make sense since there is no node. When a NULL pointer is dereferenced your program crashes and gives you a segmentation fault. It might not crash right away. In this case, as part of the dereferencing the Print function tried to print a string, so it tried to use the << operator in the string class, and it failed. That is why the first error message is from the CPstring.h file.

In the debugger, you can display the values of variables for functions that execution halts in. In your case execution halted in CPstring.h. It was called by a long chaing of functions. Let's reverse steps in the chain of function calls in sections.cc. Type up in the command window or use the corresponding button. Execution is moved back to the function StudentNode::Print. Use up again. Execution is moved back to the function PrintList when current had the value 0x0 or NULL. You'll see something like:

#3 ..... PrintSection (current=0x0) at sections.cc: 92

Use up one more time, to the previous function call of PrintList. This time current will have an address other than 0x0. Since this current is pointing to something, you can display values in its node. Click on the node and use the display button to invoke the ddd display window. You should be able to use ddd commands to find the first and last names of the student --- the first name should be DOUGLAS, the last name should be BROWN.

Fix the error above by placing an "if" check around the body of the function PrintSection, executing the body of only if current is not null. Replace the body by

if (current != 0) { current->Print(); PrintSection(current->next); }

back to lab contents


Summary of DDD buttons/commands

Useful Buttons in Source Code Window

  • Break: Set a break point at current line
  • Clear: Clear a break point at current line.
  • Print: Print the value of current variable.
  • Find << Search backwards for current text.
  • Find >> Search forwards for current text.
  • Run: Start Program from beginning until it ends or hits the first break point.
  • Step: Step into function. Run the next line of code. If the code is a function call go to first statement in the function call
  • Next: Go to Next line. Similar to Step, but if the line is a function call, Next will run the entire function and stop at the next line of code in the current function to be excuted.
  • Continue: Continue running the program from current spot until it hits the next break point or ends.

For more information, you can click on the Help option in the menu and look it up in the ddd manual.

Frequently Used Buttons in Data Window

  • Dereference: See where a pointer points to
  • Show/Hide: Show the value of the variable/object or hide it. Toggles the display ability.
  • Delete: Delete the object that is being displayed.

To find out more, click on the Help button on the menu bar and consult the DDD manual.

After you've edited the program to fix the problem, recompile and re-run the program. You should also type ls to list your files. You may have a file called core that was created when your program had a segmenation fault. This file takes up lots of space and should be removed, type rm core to remove it.

back to lab contents


Modifications to the Program:

  • Complete the function WhichSection, which returns the section number for a student (or 0 if the student is not found). You might find it useful to call the function FindStudent which is already written.

    The main function has one call to test whether or not WhichSection works correctly. You should add additional tests. Compile and run your program before moving on to the next part.

  • Write the function FindAll which searches by first name for all students in all sections with a given first name. There is a call in main to find all the Matts. Compile and run your program before moving on to the next part.

  • Write the function Remove to remove a student from a list. Because the list is doubly linked, you can call the function FindStudent to find a node with a student in it (you'll need to check all sections though). Given a pointer to a node, you can remove the node from the list it's in using next and prev pointers without the need to use a one-node look ahead or keep a trail pointer.

back to lab contents


Submitting The Lab

To submit assignments you'll run the command below, but substitute your section number (1, 2, or 3) for N.
    submit100e lab7.N README usestock.cc stlist.h stlist.cc

You can enter the files in any order.

Remember that every assignment must have a README file submitted with it (please use all capital letters). Include your name, the date, and an estimate of how long you worked on the assignment in the README file. You must also include a list of names of all those people with whom you collaborated on the assignment.