Worksheet C Pointers

This worksheet covers a few elements of pointers in C that will be used in this course. You should have seen this material in the introductory classes (or from the classes that were used to waive the introductory classes).

Questions and Completion

There is nothing to hand in for the worksheet, but you should definitely work through it in order to prepare for the quiz and homework.

If you have questions as you go through this worksheet, please feel free to post them on the discussion forum.

C Memory Allocation and Pointers

Pointers

Consider the following C program.
Replace the comments with code, so that the value of x is 10 when it is printed.

#include <stdio.h>
#include <stdlib.h>

void update (int* p) {
  /* TODO */
}

int main () {
  int x = 5;
  update (/* TODO */);
  printf ("%d\n", x);
}

Solution: Pointers

Allocation Location

Consider the following C program.

#include <stdio.h>
#include <stdlib.h>

int x = 5;

int main () {
  int y = 10;
  int* p = (int*) malloc (sizeof (int));
}

Answer the following questions:

  1. Where in memory is x allocated?

  2. Where in memory is y allocated?

  3. Where in memory is p allocated?

  4. Where in memory is p pointing to?

Solution: Allocation Location

Call-Stack Allocation

Consider the following C program.

#include <stdio.h>
#include <stdlib.h>

void countdown (int n) {
  if (n <= 0) {
    printf ("done\n");
  } else {
    printf ("counting down\n");
    countdown (n - 1);
  }
}

int main () {
  countdown (5);
}

When it is executed:

  1. What will be printed?

  2. What is the maximum number of activation records (also known as stack frames) on the call stack at one point during execution?

Solution: Call-Stack Allocation

Dangling Pointer

Consider the following two C programs. Which one of these programs is problematic and why?

#include <stdio.h>
#include <stdlib.h>

int foo (int n) {
  int result = 2 * n;
  return result;
}

int main () {
  int x = foo (5);
  int y = foo (7);
  printf ("%d\n", x);
  printf ("%d\n", y);
}
#include <stdio.h>
#include <stdlib.h>

int* foo (int n) {
  int result = 2 * n;
  return &result;
}

int main () {
  int* p = foo (5);
  int* q = foo (7);
  printf ("%p %d\n", p, *p);
  printf ("%p %d\n", q, *q);  
}

Solution: Dangling Pointer

Solutions

Solution: Pointers

#include <stdio.h>
#include <stdlib.h>

void update (int* p) {
  *p = 10;
}

int main () {
  int x = 5;
  update (&x);
  printf ("%d\n", x);
}
$ gcc -o pointers-01-solution pointers-01-solution.c
$ ./pointers-01-solution 
10

Solution: Allocation Location

  1. Global memory.

  2. In an /activation record/ for main (also known as /stack frame/) stored on the /call stack/.

  3. In an /activation record/ for main (also known as /stack frame/) stored on the /call stack/.

  4. On the heap.

Solution: Call-Stack Allocation

  1. This is printed.

    counting down
    counting down
    counting down
    counting down
    counting down
    done
  2. There are at least 8 activation records on the call stack when done is printed by printf. There may be more since we do not know the implementation of printf.

    • main
    • count with n = 5
    • count with n = 4
    • count with n = 3
    • count with n = 2
    • count with n = 1
    • count with n = 0
    • printf

Solution: Dangling Pointer

The first program is fine.

The second program is problematic because p is a /dangling pointer/ after foo returns. That is, p contains a pointer to an area of memory that is not defined, and when it is dereferenced (using *p) the behavior is not guaranteed: it might be 10, some other value, or crash the program. This happens because the result variable is allocated in the activation record for foo, and the address of result is returned from foo, but the activation record for foo is deallocated (hence the memory storing result is also deallocated) when foo returns.