CS 112 Lab 2: File I/O, Control Structures, and the Debugger

Objectives:

In this exercise, you will:
  1. Read in a file and process its contents.
  2. Practice creating functions and throwing errors.
  3. Practice writing for loops and if statements.
  4. Use the debugger to execute a program statement by statement.

Grading Rubric

Your submission will be graded this way: 27 pts total

Part I: Finding duplicates in a collection of integers

Step 1. Create the project, main.cpp, input.txt, functions.cpp, functions.h, etc.

In Eclipse, close any other project you still have open. Then, create a new project called lab2, and in that project, create Source File main.cpp, Source File functions.cpp, Header File functions.h, and regular file input.txt.

Create your main() function and have it return 0. Compile your program.

Step 2. Implement main

In your main() function, copy-n-paste these comments:
    // 1. Ask user for filename to read.
    // 2. Ask user for the number of lines in the file.
    // 3. Open the file and assert that that succeeded.
    // 4. Dynamically allocate the array of integers called numbers.
    // 5. Read the file contents into numbers array and close the file.
    // 6. Call findDuplicate()
    // 7. Print appropriate output
  
In subsequent steps you will replace these comments with readable code (thus, making the comments unnecessary).

The findDuplicate() function will search an array of integers, looking for a duplicate number. If it finds one, it returns true, and "returns" the duplicate. If no duplicate is found, it returns false.

You can reindent your file now by doing Ctrl-a, Ctrl-i. Remember this command as it is super useful.

Step 3. Implement getting filename and number of lines in the file.

Implement steps 1 - 3 of the algorithm. Obviously, you are storing the input the user enters into appropriately named variables.

At this point, open the input.txt file and put 4 different integers into the file, one per line. Save the file.

Step 4.

For step 4 of the algorithm, use this code: int *numbers = new int[size];

replacing size with whatever variable name you chose (or change your variable name to size).

Step 5.

Replace step 5 of the algorithm with code. Try running your code to see if it works. Whether your code works or crashes, go on.

We'll finish implementing the algorithm after you do the following:

Using the debugger

Now we will start using the Eclipse debugger. A debugger can be invaluable in debugging your programs in this course, so I highly recommend you practice using it anytime you need to track down a logic error in your program. The debugger is called gdb, and can be run directly from within Eclipse.

Getting Started. Make sure your current program compiles.

To use gdb from within Eclipse, go to the Run menu and choose Debug... (Alternatively, you can just click the Debug button -- -- which should do the same thing.) Depending on how Eclipse is configured, you may or may not see a Select Preferred Launcher dialog, containing a list of ways to launch the debugger. If this dialog appears, select Standard Create Process Launcher from the list.

Eclipse should then should display a Debug dialog that looks a lot like the Run dialog. If the Debug button at the bottom is not dimmed, click it. (If it is dimmed, click the Debugger tab and check that a debugger is selected in the Debugger combo box that appears.)

The debugger uses a different perspective than the normal C/C++ perspective, so Eclipse will ask you to confirm that you want to change the perspective. (Click Yes.) Eclipse will then

  1. rebuild your program with the information needed by the debugger;
  2. display its debugging perspective;
  3. start running your program; and
  4. suspend your program at the first statement in its main() function.
Near the top-left corner of this perspective is a Debug tab. If you read through the text there, you will see that it says your program is currently suspended.

Below the Debug tab is a code window displaying your program. Note that the first statement in the main() function is highlighted, and there is a blue arrow beside that statement.

Whenever your program is suspended, Eclipse displays this blue arrow to indicate the statement that will be performed next when your program resumes execution (see below).

To the right of the Debug area you should see a Variables tab above a window in which you should see listed the variables in your main() function. Note that the value of each variable is displayed.

Being able to view all of a function's variables and their values as your program is executed is one of the most useful aspects of a debugger.

Between the Debug tab and the Variables tab is a debugging toolbar:

For our immediate purposes, the most important buttons on this toolbar are:

Press the Step over button until you get to the first cout statement. You should see the blue arrow advance. If you have variables declared but not initialized, what values do they have?

Advance the debugger slowly using Step over, especially watching what happens when you loop through reading the input file into your numbers array. Verify that your code works correctly, reading in the entire file into the array.

If you discover (or already know) that your code does not work correctly, stop and fix it. Use the debugger repeatedly to figure out your problems.

You can use the Resume button . This button "unsuspends" your program. Your program will run until it terminates (normally or abnormally), or it encounters a breakpoint, which will make it suspend again.

Once you have your code working, proceed.

Step 6. Implement and call the function to detect duplicates

The function should take as arguments: and the function returns a boolean -- true if a duplicate number is found in the array, and false if there are no duplicates in the array. I called my function findDuplicate but you may use any good descriptive name you want.

In main(), call the function (which you have not written yet). You'll need to declare dup_number first.

Now, write the prototype for the function in functions.h. Remember that the prototype is the first line of a function implementation, but without the actual implementation. Put a semi-colon on the end of the prototype, instead of the curly brackets.

In main.cpp, add #include "functions.h" in the "includes" section of the code, at the top.

Now, start to write the function implementation in functions.cpp. But, don't worry yet about the algorithm you'll use to detect the first duplicate in the array. Instead, create a dummy implementation: just set the 3rd parameter to 3, and have the function return true.

Now, back in main(), write an assert statement (or two) under your call to findDuplicate() that checks that the return value from the call was true and that the duplicate number found was 3.
Compile and run. Make any fixes you need to get this part working.

Now, we'll finally implement the algorithm for real. I'll leave it to you to figure out the algorithm. Note that my solution is not fancy and not particularly fast. I did not, for example, sort the array, and I don't recommend you do anything like that either.

You might find it useful to again use the debugger to get your function working.

If you want to quickly get to a particular point in your program, you can
  1. Set a breakpoint (see below) where you want your program to stop; and
  2. Click the Resume button.
Your program will then run without suspending until it reaches the breakpoint. This can be much faster than repeatedly clicking Step over.

To set a breakpoint, click on the left margin of the code window next to the statement where you want execution to suspend. A blue circle will appear in the margin to mark the breakpoint. E.g., you could set a breakpoint on the first line of the function, so that the debugger stops there when the function is first called.

To unset a breakpoint, click on its blue circle.

Step 7.

After your function call, print out one of 2 different statements:
If a duplicate was found, print a nice message saying a duplicate was found and its value.
If no duplicate was found, print out a message stating that fact.

DON'T DO THIS PART! Part II. Create a shiftUp() function

For this part of the lab, you and your partner will create a function that shifts up values in an array so that a new value can be inserted. E.g., suppose you have an array containing single characters:

char arr[8] = { 'a', 'b', 'c', 'd', 'e', 'f' };
Note that the array can hold 8 characters, but only the first 6 are filled in.

If we call the function shiftUp(arr, 8, 3); then all the values in the array from index 3 and upward will be shifted up one spot. So, 'd' was at index 3, but is now at index 4, 'e' was at index 4, but is now at index 5, etc.

The first parameter to the function is the array of chars to manipulate. (Because this parameter is an array, it is naturally an "in/out" parameter.) The second parameter, an unsigned, is the size of the array -- an "in" parameter. The third parameter, also an unsigned, is the index where to start shifting up from -- an "in" parameter.
The function returns void.

Note that if before the shift, there is a value at the top index of the array, it will be lost (because its value will be overwritten by the second-to-last value). That's OK.

Now, write the prototype for your function in your functions.h file and a skeleton (i.e., empty) implementation for it in functions.cpp.

Create a new main.cpp file and define main() in it and #include "functions.h" and <iostream> and <cassert>. Have main() just return 0 for now. Compile and run.

main() will be used simply as a way to test the correctness of your shiftUp() function. So, now define a small array of characters and put some values in the array. Then call shiftUp(), and then write as many assert tests as you need to convince yourself that when the function has been implemented, it is correct.

Now, implement the function and run your code.

When you are convinced your function is correct, and your tests are throrough (you'll be graded on how good your tests are), go on.

Now, add code to your shiftUp() function that checks for this bad parameter situation:

Check if the third parameter is a bad value. It must be between 0 and array size - 1. If it isn't, throw a range_error.

Note: to throw a range_error you will need to #include <stdexcept>

Add a test to main() to check that the exception is thrown when it should be. A way to do that is to try a bad function call, catch the error, and do nothing if you catch it. However, in the try part, after the function call, assert(false); which will be run only if the call to the function does not throw an exception like it should.

Turn In

Copy your lab2 folder into your /home/cs/112/current/ folder. Your submission should include your functions.cpp, functions.h, , and main.cpp files.

Only one of the partners should turn in the lab, but make sure both partners' names are in the documentation in the files.


CS > 112 > Labs > 02


This page maintained by Victor Norman.