Lab 4
In this lab we will practice using the debugger, allocating and deallocate memory in C++.
Some introductory materials on debuggin are available at the Resources page. Note: Unless you install GNU compilers on OSX, the compiler you get from XCode is not really gcc (even though there is an alias allowing you to call it gcc). The LLVM-based compilers on Macs work with the LLVM debugger, lldb, which has a different interface from gdb but you can do everything there that you can with gdb.
Debugging
Consider the following program that allocates and uses a 2-D int array in C.
#include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { int **num; int size = 5, i, j; // Allocate memory for 2-D int array num = (int **) malloc (size * sizeof(int *)); for (i = 0; i < size; i++) num[i] = (int *) malloc (size * sizeof(int *)); // Set values for (j = 0; j < size; j++) num[i][j] = i * size + j; // Print values for (i = 0; i < size; i++) { for (j = 0; j < size; j++) { printf("%d ", num[i][j]); } printf("\n"); } // Deallocate memory for (i = 0; i <= size; i++) free(num[i]); free(num); }
Compile this program (notice the -g
flag, which we use when we plan to debug the code -- it tells the compiler to preserve symbol information for all local symbols, as well as source code details).
gcc -g -std=c11 -o num num.c
When you run this example with ./num
you will get an error "Segmentation Fault".
Use the debugger to identify the line where the program crashes. In some cases, the error is somewhere else, and we will talk about strategies for locating the origin of the problem.
After creating a version of this code that does not seg. fault, introduce an infinite loop, and use the debugger to locate the problem and fix it.
C++ dynamic memory allocation
In this task, implement the same functionality as the code above in C++. Compile with g++ -g -std=c++14
. If you encounter memory problems, use the debugger. Check for memory leaks with valgrind.
Some useful examples are given below. In C++, we allocate dynamic memory with the new operator and free it with delete. The process is otherwise the same as for C. For more details, refer to the TICPP book and/or this page.
For example, this C code allocates a 4 by 2 array of floats:
float **arr = NULL; arr = (float **) malloc(4 * sizeof(float *)); // row pointers for (int i = 0; i < 2; i++) arr[i] = (float *) malloc (2 * sizeof(float)); // columns
In C++, the equivalent code is:
float **arr = nullptr; // nullptr is the C++ equivalent of NULL arr = new float * [4]; // row pointers for (int i = 0; i < 2; i++) arr[i] = new float[2]; // columns
To free memory, in C you could do the following:
for (int i = 0; i < 2; i++) free(arr[i]); // columns free(arr); // row pointers
The equivalent code freeing memory in C++ is:
for (int i = 0; i < 2; i++) delete [] arr[i]; // columns delete [] arr; // row pointers
Note that we have to use delete []
to free arrays of pointers. If you are freeing a single pointer, then you simply use delete, e.g.,
float *ptr = new float; *ptr = 3.14; delete ptr;