By the time you have completed this lab, you should be able to
Partner up (and remember to switch roles after awhile). If your regular partner is more than 5 minutes late, ask the TA to pair you with someone else for this week.
This lab's pilot should log in. You will (both) work in this account for the rest of the lab.
Create a ~/cs32/lab04 directory and make it your current directory:
mkdir ~/cs32/lab04 cd ~/cs32/lab04
Now copy all of the files for this lab from ~cs32/labs/lab04/ in the class account to your cs32/lab04 directory:
cp ~cs32/labs/lab04/* ~/cs32/lab04
With a simple program like hello.cpp, we normally compile and link in one step, and then it is ready to run like so:
g++ hello.cpp -o hello ./hello
But we can also compile the program without linking it. Type the following, and then
use ls to find out what happened:
-bash-4.2$ g++ -c hello.cpp -bash-4.2$ ls hello.* hello.cpp hello.o
Notice the new object file hello.o,
which contains the machine language instructions in binary form. In a second step we
would link this object file (just to standard libraries in this case) as follows:
g++ hello.o -o hello
That step will finally produce the executable file "hello" - but only
because we specified by the g++ option -o that the output file should
be named hello. The program is run exactly like before by typing ./hello at the prompt.
When it comes to large projects both in C and C++, it's always useful to organize your project into separate parts. When some parts of your program change, then only these parts need to be recompiled.
See the three files main.cpp, functions.cpp and functions.h. Notice that both of the .cpp files include the .h file - this is a typical case. It won't be necessary to compile functions.h by itself, as it will become part of both object files produced when the .cpp files are compiled.
Your job for Step 3:
Thought question: Why is it unnecessary to separately compile functions.h?
When first compiling your programs it's always good to use the "-Wall" and the "-g" options in order to force g++ to give you warnings about possible errors in the source code, and include extra debugging information in its output, respectively.
The -g option is also necessary in order to use the gdb debugger later in the lab.
Before proceeding to Step 4, check "man g++" command for an extensive list of g++ options.
Now imagine that you have a project with 20 different files, or even hundreds of files ...
Wouldn't it be better if we could compile all our files just by typing one command? Wouldn't it
be better and save us time if we have to compile only the files we have changed, and not all of
them? This is why we use the Makefile and the make command.
Now let's write a simple makefile to easily compile the files main.cpp, functions.cpp, and functions.h that we used on the previous section. Open a text editor and name the file "Makefile" (or "makefile"). You should always name your make files in this way.
Don't trust copy & paste with this text! Be sure to put a tab character at the beginning of every command line (in this case, the three g++ commands and the rm command) - spaces will not work.
hello: main.o functions.o g++ main.o functions.o -o hello main.o: main.cpp functions.h g++ main.cpp -c functions.o: functions.cpp functions.h g++ functions.cpp -c clean: rm hello main.o functions.o
Save Makefile. Then make a minor change to one of the source code files (main.cpp, functions.cpp or functions.h). And finally type "make" in your console. Fix Makefile if it doesn't compile the changed parts and reproduce the executable file. If it does, then find out what happens if you type "make" again. ;-)
Hey notice that everything depends ultimately on functions.h. Also notice that this header is missing the usual conditional compilation specifiers, so:
#ifndef FUNCTIONS_H #define FUNCTIONS_H
#endif
By default, make will execute whatever is necessary to produce the first target which is
hello (the executable) in this case. Alternatively, you can specify the target you want make to
make by typing it as a command line argument, as in "make hello" to execute the default another way.
Suppose that now you want to remove the objects and executable file. What should you type in your console? Be prepared to answer that question if the TA asks you.
Maybe time to switch partner roles?
Inevitably sometime you will need to debug your code. gdb is a very powerful
tool. Here we learn just the basics.
Look at buggy1.cpp to know its major parts.
(Emacs Users Hint: If you are using emacs you can see line numbers on the editor by typing M-x linum-mode. This will make your life easier. If you prefer running gdb on e-macs maybe you should try M-x gdb-many-windows in order to split your screen and be able to see variable values, gdb and e-macs all together. You gain control back to emacs by typing: C-x 0)
This program is supposed to ask a student about the courses he/she plans to register. So a non-buggy version of the program would execute like this:
Enter a course name: Computer Networks You are registered for the following 1 courses: 1. Computer Networks Do you Want to register for another course? (y/n) y Your Answer is:y Enter a course name: Computer Security You are registered for the following 2 courses: 1. Computer Networks 2. Computer Security Do you Want to register for another course? (y/n)
But this code contains errors. Your job will be to find one of them using gdb. No need to fix it now, just find it. That's the purpose of gdb - it helps you find errors in your code.
Compile the code (don't forget to compile with the -g option), and run it. Here is an example run:
Enter a course name: history You are registered for the following 1 courses: 1. history Do you Want to register for another course? (y/n) y Your Answer is:y Enter a course name: You are registered for the following 2 courses: 1. history 2. Do you Want to register for another course? (y/n) y Your Answer is:y Enter a course name: You are registered for the following 3 courses: 1. history 2. 3. Do you Want to register for another course? (y/n) y Your Answer is:y Enter a course name: You are registered for the following 4 courses: 1. history 2. 3. 4. Do you Want to register for another course? (y/n)
Hmmm... Well it seems that our program doesn't wait for our input... Let's try to debug it with gdb to see how the basic gdb commands work. Begin by starting gdb with buggy1 as its command line argument:
bash-4.2$ gdb buggy1
Then type "run" (or just "r") at the gdb prompt:
(gdb) run
The program starts and asks for user input. Push CTRL-C and write the gdb command to set a breakpoint at line 19 (You could also do the following by typing just "b 19")
(gdb) break 19
Enter "run" again, and then start the program from the beginning by typing "y" when asked:
(gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) y
This way the program will run until line 19. Write the command "step" or just "s" in order to move one step forward. Now the program asks for your input:
Enter a course name: 20 getline(cin,courseName,'\n');
Don't give your input at this time. Instead move to the next step by writing again "step" or just by hitting enter (enter repeats the previous command you had typed). After you hit enter the getline function on line 20 is called and waits for your input. So you just have to enter a course name again - "Math" for example.
Let's say we would like to know if the courseName variable has the value we assigned to it. Just run:
(gdb) print courseName
$1 = {
_M_dataplus = {
> = {
<__gnu_cxx::new_allocator> = {}, },
members of std::string::_Alloc_hider:
_M_p = 0x1001008c8 "Math"
}
}
So indeed variable courseName has the value we entered as an input ("Math"). Use the step command to move forward up to line 32. Use the "next" or "n" in order to step into and execute the subroutine trackUserAnswer(). If you wish to exit from the trackUserAnswer function you can write (f)inish. (But be aware that this function needs user input. So you can do this just after you have entered your input.)
More about breakpoints: Write command break to put a breakpoint on line 29. Now you have two breakpoints set - this new one is number 2. You can disable it by entering "disable 2" (you could also use dis 2). And you can enter "enable 2" (or "ena 2") to enable the breakpoint again, and "delete 2" (or "d 2") to delete the breakpoint.
Other stuff: Enter "help" at the gdb prompt to find out about more commands. One useful one, for example, is "list" - try it.
Ok... Now you have all the tools you need in order to find where is one of the bugs in this program. Find what exactly happens and tell your TA where the program needs fixing. You'll correct it for the homework.
| Get your TA's attention to inspect your work, and to record completion of your in-lab work. |
Don't leave early though ... begin the after-lab work below.
Step 6a. ONLY IF YOU RAN OUT OF TIME TO HAVE THE TA INSPECT YOUR WORK
If you must complete this assignment at CSIL, then you must do a few more things and submit it with the turnin program - but do NOT turn it in if the TA already checked you off. You MUST have both your name and your partner's name in appropriate comments in each file to be turned in to receive credit.
- You should already have added your name(s) in a comment to the top of functions.h in Step 4 above. If not, then do it now, save the file and test it to be sure it still works.
- Add your name(s) and the date in a comment at the top of buggy1.cpp. Then add a comment that identifies where the program needs to be fixed. Test to be sure it still compiles.
- Use turnin to turn in both functions.h and buggy1.cpp at the same time:
turnin lab04@cs32 functions.h buggy1.cpp
Each pair of students must accomplish the following to earn full credit for this lab:
buggy1.cpp also has another bug. After inserting more that 5 courses, a segmentation fault (eventually) takes place. It's obvious why, but every bug in your program is a chance to learn more useful commands to improve your programming life! Try the gdb command backtrace (or bt) to see the sequence of the commands that produce the crash. Then use the x command, and list (or l). By the way, what are your options for fixing this bug?
This week's homework includes splitting up the program from Lab03 - so be sure to retrieve a copy of your grading2.cpp from last week's lab (or do that part of Lab03 now if you did not save it from before). Create a "~/cs32/hw4/" directory in your account for this purpose.
The homework requires fixing buggy1.cpp too, so you might as well copy that file now from your ~/cs32/lab04/ to ~/cs32/hw4/ too.
At the beginning of this lab you also should have copied another program to debug. Verify that buggy2.cpp is in your lab04 directory, and then move it to your ~/cs32/hw4/ directory (using mv; or you may use cp to get a copy of this file from ~cs32/labs/lab04/ if you prefer).
You will use the turnin program to submit some of the work, and that must be done before your next lab - the TA will check for it then. A written part is also required, to be turned in at your lab next week. Please do NOT print the homework in Cooper Lab.
Each student must complete the paper part of the homework, even if you do the programming parts in pairs.
Here are the hw4 instructions.
Prepared by Stratos Dimopoulos (F11 TA), and Michael Costanzo.