You are on page 1of 8

UTP LAB ASSIGNMENT - 1

Lab 1: GDB (and Functions)


This lab introduces the use of the GNU Debugger. Very generally, a debugger is a program that is designed
to help find and fix (debug) errors in a program. A few of the most useful functions of most debuggers
include:
 Stepping - the ability to step through the execution of a program one line at a time. This makes it
easier to see exactly what the program is doing at each line.
 Printing variables - the ability to print the value of any variable at any point in the program at any
time. This makes it easier to identify when a variable receives an unexpected value.
 Displaying memory - the ability to display the contents of memory. Programs don’t just store variable
values in memory. It can sometimes be useful to look at all of the memory a program is using.
 Break and/or watch points - the ability to stop a program at a particular location or when a specific
condition is met. This makes it easier to observe the execution at a particular point in the program or
under particular conditions.
To use the Gnu debugger the program should be compiled with the debugger option on:
prompt> g++ -g program.cpp
Then begin running the debugger with the program:
prompt> gdb a.out
At this point the debugger will start and the screen will display a block of text followed by the gdb prompt,
something like:
(gdb)
At this point there are a number of basic gdb commands that can be used:
 run a.out (where a.out is the program name) - This runs the program.
 break N (where N is a line number) - This will cause gdb to pause in running the program when it
reaches line N .
 break function name (where f unctionname is the name of a function) - This will cause gdb to
pause in running the program when it reaches the function with the given name.
 step - If gdb has paused the program (for example because the break command was used), this will
cause the next line in the program to be executed.
 print variable (where variable is the name of a variable) - This will print the value of the named
variable, or will give an error message if no variable with that name is currently in scope.
 continue - This causes the program to continue running normally, until the program ends or
another breakpoint is reached.

Lab Exercise
Enter the program listed below:

1
1] /* Name
2] * Section \#
3] * Lab 4
4] * Date
5] */

6] #include<iostream>
7] using namespace
std;

8] int func(int);
9] const int X = 5;

10] int main(){


11] cout << "Program is starting.\n";
12] int result;
13] int X = 10;
14] cout << "In the middle of the program.\n";
15] result = func(X);
16] cout << "The result is " << result << ".\n";
17] }

18] int func(int y)


{ 19] int answer;
20] cout << "In the function.\n";
20] answer = y;
21] answer += X;
22] int X = 20;
23] cout << "In the middle of the function.\n";
24] answer += X;
25] cout << "The function is exiting.\n";
26] return answer;
27] }

Problem 1: Hand Simulation


A hand-simulation is when you run/debug a program by playing the role of the computer. You do this by
tracing through the program and simulating what the program will do. One useful approach is to move a
thumbtack or penny or other small object through a printout of the code. You should draw boxes for each
variable, to simulate the bits of memory that hold that variable’s value. A large part of hand-simulation
is updating the contents of these boxes whenever an assignment or input statement updates the value of a
variable.
It often helps to give each variable an entire “column” and update its values by crossing out its old
value and writing its new value below the old value. The other large part of hand-simulation is to write
down in a separate area what output the program’s output statements would generate when they execute.

2
When functions are called, new boxes are created for each local variable (including parameters), and when
a function returns, local variables’ boxes are destroyed.
For example, sample set of columns for hand simulating the lab program would look like:
X result answer y Output

Hand simulate the program. Using the first table at the back of the lab record the values of the
variables X, result, answer, and y at the following lines in the program: 11, 14, 16, 20, 23, 25. For some lines,
some variables will not be defined, record that information instead of the variable’s value.

Problem 2
Using gdb and the break, step, and print variable commands record the values of the variables X, result,
answer, and y at the following lines in the program: 11, 14, 16, 20, 23, 25, in the second table in the back
of the lab. (This could be done by putting lots of extra cout statements in the program, but for this lab we
will use gdb instead.) For some of these lines you will get an error because the variable doesn’t exist within
the scope of that line.
Do not go back and change the values in your first table.

Problem 3
Answer the following questions:
1. On line 14, what is the value of result and where did it come from? If you run the program several
times, does the value of result at line 14 ever change?
2. What are the values printed for X on lines 14 and 20? Why are the printed values of X different?
3. Compare the values in Table your first and second tables? We they different at any of the lines? If so
explain the mistake you made during the hand simulation.
Turn-in:
Turn in both tables and the answers to the three questions, you don’t need to turn in the
program or sample output.

3
Name:

Table 1: Fill in the results of your hand simulation


Line Number X result Answer Y

11

14

16

20

23

25

Table 2: Fill in the results from using gdb


Line Number X result answer Y

11

14

16

20

23

25

4
Some Other Examples:
Example 1: Consider the following program
int main(int argc, char* argv[])
{
int x;
printf("Please enter an integer : ");
scanf("%d",x);
printf("the integer entered was %d \n", x);
return EXIT_SUCCESS;
}
The purpose of the program is to read an integer and print it out. But the program seg faults. Use gdb to find
the error.

Example 2: Consider the following program


int main(int argc, char* argv[])
{
FILE* fp = fopen(“argv[1]”, “r”);
char* word;
while (fscanf(fp,”%s”,word)>0)
{ }
return 0;
}
The purpose of the program is to read a set of strings from a file. But the program seg faults. Use gdb to find
the error.

Example 3 Consider the following program


int main(int argc, char* argv[])
{
printf("%ld \n", INT_MAX);
int n = INT_MAX;
int A[n]; int i = 0;
while (i<n)
A[i] = rand()%10;
return EXIT_SUCCESS;
}
The purpose of the program is to allocate an array of ints and initialize them to a random number. But the
program seg faults. Use gdb to find the error.
5
Example 4: Consider the following program,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char* argv[])
{
char* name = malloc(strlen(argv[1])) ;
name = strcpy(name,argv[1]);
printf("%s \n", name);
return EXIT_SUCCESS;
}
This code may throw a segmentation fault. Use debugger to find out where the errors are and fix them.
Example 5:
Compile the program factorial.cpp, using the -g option to include debugging information in the
executable. Run the program and enter a (small) positive integer. The program gives an incorrect answer for
the factorial of the input number. Use the debugger to find the errors.
factorial.cpp
#include <iostream>
unsigned long factorial(int n) {
unsigned long f;
int i;
for (i = 1; i < n; i++) {
f = f*i;
}
return f;
}
int main() {
int k;
cout<<"Enter a positive integer: ";
cin>>k;
unsigned long fk = factorial(k);
cout<<"Factorial is"<<fk;
return 0;
}

6
Example 6:
Debug the program selection.cpp. This program tries to use the selection sort algorithm to sort an
array. However, it crashes with a dreaded Segmentation Fault. Usually, to debug a segfault, you want to run
the program under the debugger and let it crash. You can then use debugger commands to get information
about the state of the program when it crashed. The backtrace command can be particularly useful.

After you have fixed the segmentation fault, you might find that the program still doesn't sort the
array correctly. You should find and fix that bug too.

After selection.cpp correctly sorts the array, the program will go into an infinite loop when it tries to
use the binary_search function. Use the debugger to find and fix the problem. Since you don't usually know
where a program is going into an infinite loop, note that you can use Control-C inside gdb to pause the
program. You can then inspect the state of the program, install breakpoints, and so on.

#include <iostream>

int selection_sort(int A[], int size) {


int i, j, max, temp;
for (i = size-1; i > 0; i--) {
max = 0;
for (j = 1; i <= size; j++) {
if ( A[j] > A[max] )
max = j;
}
temp = A[max];
A[max] = A[i];
A[i] = temp;
}
}

int binary_search(int item, int A[], int size) {


// searches for item in A[0], A[1], ..., A[size-1]
// returns 1 if item is found, 0 if not
int lo = 0; // left end of possible range for item
int hi = size; // right end of possible range for item
while (1) {
if (hi < lo)
7
return 0; // not found
int mid = (hi + lo) / 2;
if (A[mid] == item)
return 1; // found
if (item < A[mid])
hi = mid; // move hi to eliminate 2nd half of A
else
lo = mid; // move lo to eliminate 1st half of A
}
return 0;
}

int main() {

int list[] = { 100, 45, 89, 27, 317, 17 };


cout<<"unsorted list: \n";
for (int i = 0; i < 6; i++) {
cout<<list[i];
}
selection_sort( list, 6 );
cout<<"list in order: \n";
for (int i = 0; i < 6; i++) {
cout<<list[i];
}
cout<<"test if 42 is in the array...\n";
if ( binary_search( 42, list, 6 ) )
cout<<”YES\n";
else
cout<<”NO\n";
}

You might also like