Lab Session - Week 5

C pointers, dynamic memory, valgrind, gdb

Get example programs

  $ cd ~/cs31/inclass
  $ cp -r ~mauskop/public/cs31/week05/ .
  $ cd week05
  $ ls
  dynamic-memory.c      interactive-sorter.c  Makefile
  interactive-sorter.c  pass-by-reference.c 

C Pointers

In C we can treat memory addresses as values. These values are called pointers; a pointer "points" to the location in memory where another value is held. When we declare a pointer we specify the type of the value being pointed to. The lab computers are 64-bit machines, which means memory addresses, and thus pointers, require 8 bytes of memory.

// Create a pointer to x with the "address of" operator, &
// We might also say &x is a reference to x.
int x, y;
int *x_ptr = &x;

// Now the following two lines are equivalent:
x = 10;
*x_ptr = 10;

// As are these:
y = x;
y = *x_ptr;

The * is used both to denote a pointer type, as in int *x_ptr; and to dereference a pointer, as in *x_ptr = 10; or y = *x_ptr;.

There are two main ways we'll use pointers:

  1. To write functions that initialize or modify values, i.e. use the call by reference method.
  2. To facilitate the use of dynamic memory, i.e. arrays where we don't know the size until the program starts running.

Call by reference

C uses call by value, which means when we call a function its parameters get a copy of the value that was passed in. This means we typically can't modify a value within a function. The work around here is to pass references (pointers) to values, since the function can dereference the pointer and change the value at that address.

There's a contrived example of this approach in pass-by-reference.c and a more realistic example in tip-calculator.c.

Dynamic Memory Management

With statically declared arrays, as we've seen, the size of the array must be known at compile time. There are times when this limitation is annoying or even unacceptable. In these instances we can use dynamic memory (i.e. memory on the heap). Including stdlib.h gives us access to two functions, malloc and free, which allow us to manage dynamic memory.

The argument to malloc is an integer, representing a request for that number of bytes allocated as a contiguous chunk on the heap. If it succeeds, malloc returns a pointer to that chunk of memory. The pointer returned by malloc can be treated (almost) exactly like an array. This memory must be initialized before it's used. When it fails, malloc returns NULL, which is like 0, i.e. it's interpreted as false in an if statement. To malloc an integer array of size 10, we would use the following code:

int *dynamic_array;

dynamic_array = malloc(10 * sizeof(int));
if (!dynamic_array) {
  // malloc failed
}

// malloc succeeded, now we initialize and use dynamic_array

// free the memory so it can be reused
free(dynamic_array)

Once we are done using a dynamically allocated array it is essential that we call free, passing in the pointer to the chunk of heap memory. This allows our program to reuse that memory for another purpose.

There's a contrived example of dynamic memory management in dynamic-memory.c and a more realistic example in interactive-sorter.c.

valgrind

Code that makes use of dynamic memory tends to be error-prone. Valgrind is a command-line tool that helps us diagnose dynamic memory management issues. Common errors that valgrind can diagnose include: forgetting to call free, forgetting to initialize dynamic memory, and reading or writing past the bounds of a dynamically allocated array.

GDB

GDB will be helpful on lab 4 as a way of examining the internal state of your running programs. In particular, when we start using pointers and dynamic memory our programs become vulnerable to a nasty runtime error called a segmentation fault (segfault). This means, roughly, that your program is trying to access or modify a protected segment of memory. Running a program with a segfault error through gdb is helpful because it will show you the line of code that triggered the error.

References

Professor Newhall has written guides to using gdb and valgrind.