Pointers & Dynamic Memory Allocation

Pointers in C and C++ give us direct access to memory locations. One of the most common usages is to provide a pass by reference mechanism for function parameters. They are also used with dynamic memory allocation which enables creating memory spaces as needed during program execution. Freeing the memory explicitly when done using it is also the programmer’s job in these languages.

Also see the Arrays and Strings notes for material related to pointers and those structures.

Pointers

These are variables that hold memory addresses, providing indirect access to the referenced location.

Operators for pointers

We use two operators in conjunction with pointers. The & operator when applied to a variable returns that variable. This enables us the access the address of a variable in order to store it in a pointer variable. The * operator is called the dereferencing operator; it returns value being pointed to, that stored in the memory location held by the pointer variable. The following code snippet demonstrates these basic operations. Both operators have unary operator precedence, but one tier below () and [] operations.

int a, *toa;  // a is a plain int, toa is a pointer to (memory address of) an int
toa = &a; // toa contains the memory address of a -- its a "pointer to a"
printf("%d",*toa)  // dereference above toa to get the underlying int and print it out

Pointers and parameter passing

Swap example using pointers to pass by reference:

void swap(int * a, int * b) 
// a and b are pointers to integers: addresses of memory locations containing ints
{
	int temp = *a; // dereference a (follow the pointer) to get to underlying integer
	*a = *b;       // "*a =" follows the pointer to get the integer's location, puts what b points to there.
	*b = temp;
}

int main()
{
    int x = 10, y = 5;
    swap(&x, &y);  // pass addresses which are of type "int *"
    printf("%d %d\n", x, y);  // now 5, 10
}

Pointer arithmetic

Pointers to pointers

Dynamic Memory Allocation in C

Real Programs need dynamic memory. Arrays we have used up to now must have fixed size from when program launched. Often we need to let program data storage grow unboundedly (up to available memory on the computer). The solution is dynamic memory allocation.

Memory Allocation functions

void * calloc (size_t numels, size_t sizeofel)
    e.g. int * arr = calloc (10,sizeof(int)); // arr[0] .. arr[9] are fresh 0'd array elements after this statement

void * malloc (size_t size)
    e.g. char * str = malloc(sizeof(char) * 10); // can copy a 9-character string into fresh str now

void * realloc (void *ptr, size_t size)

For all of the *alloc functions above, if allocation fails the function returns null. We should explicitly check for this:

char * memory = malloc(400000);
if (!memory)  // remember null == 0, 0 is false
   printf("Failed to allocate the amount of memory you requested\n");

Deallocating memory

void free(void *ptr)

Valgrind

Dynamic Memory Allocation in C++

This section will be added later.