CS210 Lab: Replit and Linked List Debugging


Prelab Questions:

For a review of relevant topics click here.

Highlights of This Lab:

Lab Exercise: Exercise link

Click the little computer above for a detailed description.
For this excercise you will debug a program and demonstrate the correct results to your lab instructor.


1. Introduction to Replit


Replit is an online compiler for C++. If you haven't already, follow these instructions to join the Replit Team for this lab. All lab exercises will be performed and submitted through Replit.

While Replit has several advantages, such as cloud storage and compatibility, there are a few potential problems you should be aware of when using it:

  1. Since Replit is online only, there is potential for network outages. Please keep this in mind when approaching assignment deadlines
  2. Using the run button will only compile from a file named main.cpp, which means if you are using other cpp files as your main, it will not work without adding a configuration file.

For an example, copy the following simple program to the main.cpp, found in the file menu on the left hand side of your Replit:


Try clicking the run button. The console window on the right should prompt you for your name, and greet you after you have entered it

Alternatively, you could enter the following into the console window:

	g++ main.cpp -o hello

	./hello

This should compile your main.cpp into an executable, a compiled file that you can "execute" to perform it's defined tasks, and run it. The result should be the same.

You should make sure you are comfortable using the g++ compiler on command line, as some labs in the future will require it.

1.2 How to compile, link and execute a program with multiple files?

The preceding section showed the procedure for creating a C++ program with only one file component. However, when you are working on a large program, you would break your program into smaller, more manageable parts. In other words, your project would contain more than one C++ source file. You can create each file yourself, just like you did above, or you can add C++ source files from somewhere else.

The following section demonstrates how to create, compile, and execute a project with more than one file.

Right click on these files and click "save link as" or "save target as" (depending on your browser). Make note of where you save them to.

  1. date.h
  2. date.cpp
  3. main.cpp

Once you have the files saved, you can either click and drag them into the files menu on the left of your Replit, or click the dots in the top right and "upload file." You will be prompted to overwrite the main.cpp file - do so.

You can view the contents of these files simply by clicking on them. You should be able to click the run button to view the results because we are compiling a file named "main.cpp". The program should tell you today's date and a fictional birthday.

Next, enter the following lines into the console:

	g++ main.cpp date.cpp -o date

	./date

Again, this will compile the separate files into a single executable named date, which will run, producing the same output as before.


2. Debugging C++ Programs

Like most people, you may find that your programs do not work as you expected the first time you run them. To find out what is wrong, you might use cout statements to follow the line of execution of your code. This works, but later, when things are fixed, you must remember to remove all the extra cout statements.

You can use a debugger to find errors in your code during run-time instead. However, before we get into the details of how to use this debugger, some terminology might be useful.

Syntax Errors
  • Errors in code due to not following the rules of the language.
  • These errors are caught by the compiler or interpreter.
Semantic Errors
  • Code follows the rules, but it does not do as you intended.
  • These errors are NOT caught by the compiler or interpreter.
  • They can cause a program to crash or hang.
Logic Errors
  • Variables do not contain correct data or program doesn't go down right path.
Debugger
  • Allows you to see what is happening when you run your program so that you can determine the location of semantic and logic errors.
  • Can break (suspend) the execution of the program to examine code, view or change variable values, etc.
Breakpoints
  • "A breakpoint tells the debugger that an application should break, or pause, execution at a certain point."
  • Allows you to suspend exececution so that your program runs until it reaches a breakpoint (in the form of a place or condition that you would like to examine in more detail). You can then walk through the code line by line or instruction by instruction.

You may find the visual basic reference page https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/error-types helpful for further understanding

As a general overview to debug your project you must:

When your program is stopped at a breakpoint, your program and debugger are said to be in break mode.

To debug a program, use the following steps:

  1. Click on the debugger option in the left menu bar
  2. Set a breakpoint at the part of the code you want to watch. If you are watching a loop, it is a good idea to set a breakpoint at the top and bottom of the loop
  3. Click the Run button in the debugger interface (not the run button above the text editor, that one does not debug)
  4. Execution will pause at the break point you set. You can have a look at the names of the variables that are set, and what their values are at that point of the code. If you are looking at arrays or objects, you will need to click the dropdown arrow to see all of the values.
  5. Click the next button to "walk through" the code one line at a time, keeping an eye on the values you are interested in
  6. You can click the next breakpoint button to go the the next point of interest you have set, but if you have not set a second breakpoint this will end your ability to debug
  7. 3. Sample Exercise--Debugging

    The location:	ftp://ftp.cs.uregina.ca/pub/class/210/ftp/VCIntro 
    
    The file:       debug.cpp 
    

    Follow these steps to debug debug.cpp program:

    1. Set up a project for this program. Save the file and either drag it into your file menu or click the upload button and select the file from your downloads.
    2. Change your Repl configuration. Since we are not compiling a file named "main.cpp" we need to change the .replit file to say:
      	language = "c++"
      	run = "g++ debug.cpp -o debug; ./debug"
      
    3. Run the program as usual to see how it works. Do not use the debugger yet.  Enter 1, 2, 3, 4, 5 as the input.  The first thing you will notice is that the five numbers printed out by the program are not the same numbers that you have just entered. Therefore, something is wrong with the program.  We will use the debugger to find out what is wrong.
    4. Unfortunately, the Replit debugger is still in beta, and has problems if there are multiple definitions on "int main()" in the project. You will need to comment out the main function in main.cpp
    5. Set up a break point. As we mentioned earlier, a breakpoint is any point in the executable code where the execution stops. A breakpoint pauses the execution of a program so that the programmer can take a look at what is going on inside the program when it runs. At this point, we do not know what caused the program to go wrong, so we set up a breakpoint after the first cout, next to the first cin statement by clicking in the left margin beside that line of code . Since it is a good idea to have a break point at the top and bottom of a loop, also place one to the left of the for statement:
      A screenshot of the Replit text editor.  The programmer has set a debug point on line 30 by clicking on the margin beside for, and a second point on line 33 beside cin, which are indicated by dots
    6. Run the program with debugging. Click the run button in the debugging window. The program will start to execute, then stop at the breakpoint. Notice that the values that are being set in this for loop are being displayed under a variables header. Currently, you should have i = 0. Click the drop down arrow beside Values to see the numbers the array is holding.
      A screenshot of the debug window.  The values dropdown shows that [0] = 4197280, [1] = 0, [2] = 4196384, [3] = 0,  [4] = 1005948880, i = 0
    7. Step through the program. Click the single arrow to walk through the loop one line at a time. Every time you are prompted to enter a value, make sure you enter something and press enter - the debugger won't proceed while it is waiting for user input. Watch what happens with the values in the array as you pass the cin statement. You will need to keep expanding the array dropdown. Notice that only value in [1] changes.

      Examine the code in the source code window, and you will find that inside the first loop block, the statement
      cin >> Values[1];
      should read: cin >> Values[i];;
      otherwise, all the keyboard input will go to Values[1]. Change this line of code; recompile and rerun the program and it should work properly.

    If you are still having trouble, consider checking out 10 Common Programming Mistakes in C++


    4. Review of Linked lists

    A linked list is a data structure that strings together a collection of nodes. Each node typically contains a data item and a pointer to the memory address of the next node in the list. This means that the list must be travelled in order, or sequentially, from front to back, starting at a special node called the head, and there is no way to travel backwards through the list. Here is a graphical representation of a linked list:

    a picture of a linked list.  It has 5 boxes.  The first is labelled head, and points to a box with a 4, which points to a box with a 16, which points to a box with a 23, which points to a box labelled tail with 55.

    A linked list typically has the following functions:

    1. Create the list
    2.      First, create a node initialized with a data value and a NULL pointer. 
                     Set the "head" to point to the first node.
                     Set up a current-pointer to the first node (or "head").
                     Get a data value for the next node.
                     While more nodes to add
                     {
                        Create a new node initialized with the data value and a NULL pointer. 
                        Set the current-pointer link member ("next") to the new node.
                        Set the current-pointer to point to the new node.
                        Get a data value for the next node.
                     }
      	
      
    3. Append an Item to the List
    4.      //Find the end of the list...
                     Set a current-pointer to the "head".
                     While current-pointer link member ("next") is not NULL
                     {
                        Set the current-pointer to the "next" node in the list.
                     }
                     //Now current-pointer points to the last node...
                     Create a new node initialized with the "item" and a NULL pointer. 
                     Set the current-pointer link member ("next") to this new node.
      
    5. Print the List
    6.  
         Set a current-pointer to the "head".
                     While current-pointer is not NULL
                     {
                         Print the data member ("datum") of the current node
                         Set the current-pointer to the "next" node in the list.
                     }
      
    7. Insert a Node Into the List
    8.      Set a previous-pointer to NULL.
                     Set a current-pointer to the "head".
                     //Find where your want to insert into the list...
                     While the new data member > current-pointer value
                     {
                        //Move both pointers along in the list...
                        Set the previous-pointer to the current-pointer
                        Set the current-pointer to the "next" node in the list.
                     }
                     Create a new node initialized with the "item" and current-pointer. 
                     Set the link member in the previous_pointer to the new node.
      
    9. Delete a Node From the List
    10.           If "item" is in the first node
                     {
                         Set a delete-pointer to the first node.
                         Change the "head" pointer to the second node.
                         Delete the node indicated by delete-pointer 
                     }
                     Else
                     {
                         Set a previous-pointer to the "head".
                         While previous-pointer->next is not equal to NULL and 
                               previous-pointer->next->datum is not equal to "item"
                         {
                            Set the previous-pointer to the "next" node in the list.
                         }
                         If you have not reached the end of the list 
                         {
                            Set a delete-pointer to the node to be deleted (Note: it is
                                the node after previous-pointer).
                            Set the link member ("next") of the previous-pointer to the
                                "next" node after delete-pointer.
                            Delete the node indicated by delete-pointer.
                         }
                         Otherwise, print a "not found" message
                     }
      	  
      

    5. Lab Exercise


    The lab exercise can be found in Replit teams as "Lab 1", with all the files already there. However, if you need back up files, they can be found here:
    
    The files: LinkedList.cpp,LinkedList.h, and main.cpp 
    

    Copy these files into the file window on your Replit. Since this file is named "main.cpp", you shouldn't need a .replit configuration file, but if you would like one for reference, you would write:

    	language = "c++"
    
    	run = "g++  main.cpp LinkedList.cpp -o ./a.out; ./a.out"
    

    When you are finished, your program should be able to delete items from the list, or provide an error message when the item is not found. Your program must not crash or core dump when the item is not found.


    Example output:

    a screenshot of the replit output showing the user trying to remove 10 from the linked list.  Since the item was not found in the list, the program prints item 10 not found


    © Copyright: Department of Computer Science, University of Regina.