COMP9024 ♢ Week 02a ♢Dynamic Data Structures ♢ (22T0)

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [0/97]
❖ Pointers

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [1/97]
❖ Pointers

Reminder: In a linked list

[Diagram:Pic/linkedList2.png]

Benefits:

In C, linked lists are implemented using pointers and dynamic memory allocation

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [2/97]
❖ Sidetrack: Numeral Systems

Numeral system … system for representing numbers using digits or other symbols.

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [3/97]
❖ ... Sidetrack: Numeral Systems

Decimal representation

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [4/97]
❖ ... Sidetrack: Numeral Systems

Binary representation

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [5/97]
❖ ... Sidetrack: Numeral Systems

Hexadecimal representation

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [6/97]
❖ Exercise : Conversion Between Different Numeral Systems

  1. Convert 74 to base 2
  2. Convert 0x2D to base 10
  3. Convert 0b1011111000101001 to base 16
    • Hint: 1011111000101001
  4. Convert 0x12D to base 2
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [7/97]
  1. 0b1001010
  2. 45
  3. 0xBE29
  4. 0b100101101
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [8/97]
❖ Memory

Computer memory … large array of consecutive data cells or bytes
  • char … 1 byte    int,float … 4 bytes    double … 8 bytes
When a variable is declared, the operating system finds a place in memory to store the appropriate number of bytes.

If we declare a variable called k

  • the place where k is stored is denoted by &k
  • also called the address of k
It is convenient to print memory addresses in Hexadecimal notation

[Diagram:Pic/memoryAddresses.png]

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [9/97]
❖ ... Memory

Example:

int k;
int m;

printf("address of k is %p\n", &k);
printf("address of m is %p\n", &m);

address of k is BFFFFB80           
address of m is BFFFFB84

This means that

Note the use of %p as placeholder for an address ("pointer" value)
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [10/97]
❖ ... Memory

When an array is declared, the elements of the array are guaranteed to be stored in consecutive memory locations:

int array[5];

for (i = 0; i < 5; i++) {
   printf("address of array[%d] is %p\n", i, &array[i]);
}

address of array[0] is BFFFFB60                         
address of array[1] is BFFFFB64
address of array[2] is BFFFFB68
address of array[3] is BFFFFB6C
address of array[4] is BFFFFB70

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [11/97]
❖ Application: Input Using scanf()

Standard I/O function scanf() requires the address of a variable as argument

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [12/97]
❖ Exercise : Using scanf

Write a program that

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [13/97]


#include <stdio.h>

void collatz(int n) {
   printf("%d\n", n);
   while (n != 1) {
      if (n % 2 == 0)
	 n = n / 2;
      else
	 n = 3*n + 1;
      printf("%d\n", n);
   }
}

int main(void) {
   int n;
   printf("Enter a positive number: ");
   if (scanf("%d", &n) == 1 && (n > 0))  /* test if scanf successful
                                            and returns positive number */
      collatz(n);
   return 0;
}

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [14/97]
❖ Pointers

A pointer

A pointer occupies space in memory, just like any other variable of a certain type

The number of memory cells needed for a pointer depends on the computer's architecture:

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [15/97]
❖ ... Pointers

Suppose we have a pointer p that "points to" a char variable c.

Assuming that the pointer p requires 2 bytes to store the address of c, here is what the memory map might look like:

[Diagram:Pic/pointer.png]

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [16/97]
❖ ... Pointers

Now that we have assigned to p the address of variable c

Operator * is used to access the object the pointer points to The * operator is sometimes described as "dereferencing" the pointer, to access the underlying variable
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [17/97]
❖ ... Pointers

Things to note:

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [18/97]
❖ Examples of Pointers

int *p; int *q; // this is how pointers are declared
int a[5];
int x = 10, y;

 p = &x;      // p now points to x
*p = 20;      // whatever p points to is now equal to 20
 y = *p;      // y is now equal to whatever p points to
 p = &a[2];   // p points to an element of array a[]
 q = p;       // q and p now point to the same thing

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [19/97]
❖ Exercise : Pointers

What is the output of the following program?

 1  #include <stdio.h>
 2
 3  int main(void) {
 4     int *ptr1, *ptr2;
 5     int i = 10, j = 20;
 6
 7     ptr1 = &i;
 8     ptr2 = &j;
 9
10     *ptr1 = *ptr1 + *ptr2;
11     ptr2 = ptr1;
12     *ptr2 = 2 * (*ptr2);
13     printf("Val = %d\n", *ptr1 + *ptr2);
14     return 0;
15  }

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [20/97]

Val = 120
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [21/97]
❖ ... Examples of Pointers

Can we write a function to "swap" two variables?

The wrong way:


void swap(int a, int b) {
   int temp = a;                     // only local "copies" of a and b will swap
   a = b;
   b = temp;
}

int main(void) {
   int a = 5, b = 7;
   swap(a, b);
   printf("a = %d, b = %d\n", a, b); // a and b still have their original values
   return 0;
}

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [22/97]
❖ ... Examples of Pointers

In C, parameters are "call-by-value"

We can achieve "simulated call-by-reference" by passing pointers as parameters
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [23/97]
❖ ... Examples of Pointers

Can we write a function to "swap" two variables?

The right way:


void swap(int *p, int *q) {
   int temp = *p;                  // change the actual values of a and b
   *p = *q;
   *q = temp;
}

int main(void) {
   int a = 5, b = 7;
   swap(&a, &b);
   printf("a = %d, b = %d\n", a, b);  // a and b now successfully swapped
   return 0;
}

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [24/97]
❖ Pointer Arithmetic

A pointer variable holds a value which is an address.

C knows what type of object is being pointed to

Example:

int a[6];   // assume array starts at address 0x1000
int *p;
p = &a[0];  // p contains 0x1000
p = p + 1;  // p now contains 0x1004

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [25/97]
❖ ... Pointer Arithmetic

For a pointer declared as   T *p;   (where T is a type)

The value of k can be positive or negative.

Example:

int a[6];   (addr 0x1000)       char s[10];   (addr 0x2000)
int *p;     (p == ?)           char *q;      (q == ?)
p = &a[0];  (p == 0x1000)       q = &s[0];    (q == 0x2000)
p = p + 2;  (p == 0x1008)       q++;          (q == 0x2001)

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [26/97]
❖ Pointers and Arrays

An alternative approach to iteration through an array:

Example:

int a[6];
int *p;
p = &a[0];
while (p <= &a[5]) {
    printf("%2d ", *p);
    p++;
}

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [27/97]
❖ ... Pointers and Arrays

Pointer-based scan written in more typical style

[Diagram:Pic/pointerscan.png]


Note: because of pointer/array connection   a[i] == *(a+i)

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [28/97]
❖ Arrays of Strings

One common type of pointer/array combination are the command line arguments

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [29/97]
❖ ... Arrays of Strings

./seqq 10 20


[Diagram:Pic/argcargv.png]


Each element of argv[] is

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [30/97]
❖ ... Arrays of Strings

More detail on how argv is represented:

./seqq 5 20

[Diagram:Pic/argv2.png]

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [31/97]
❖ ... Arrays of Strings

main() needs different prototype if you want to access command-line arguments:

int main(int argc, char *argv[]) { ...

<stdlib.h> defines useful functions to convert strings:
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [32/97]
❖ Exercise : Command Line Arguments

Write a program that

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [33/97]


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

void collatz(int n) {
   ...
}

int main(int argc, char *argv[]) {
   if (argc != 2) {
      printf("Usage: %s number\n", argv[0]);
      return 1;
   }
   int n = atoi(argv[1]);
   if (n > 0)
      collatz(n);
   return 0;
}

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [34/97]
❖ ... Arrays of Strings

argv can also be viewed as double pointer (a pointer to a pointer)

⇒ Alternative prototype for main():

int main(int argc, char **argv) { ...

Can still use argv[0], argv[1], …

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [35/97]
❖ Pointers and Structures

Like any object, we can get the address of a struct via &.

typedef char Date[11];  // e.g. "03-08-2017"
typedef struct {
    char  name[60];
    Date  birthday;
    int   status;      // e.g. 1 (≡ full time)
    float salary;
} WorkerT;

WorkerT w;  WorkerT *wp;
wp = &w;
// a problem ...
*wp.salary = 125000.00;
// does not have the same effect as
w.salary = 125000.00;
// because it is interpreted as
*(wp.salary) = 125000.00;

// to achieve the correct effect, we need
(*wp).salary = 125000.00;
// a simpler alternative is normally used in C
wp->salary = 125000.00;

Learn this well; we will frequently use it in this course.

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [36/97]
❖ ... Pointers and Structures

Diagram of scenario from program above:

[Diagram:Pic/structptr.png]

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [37/97]
❖ ... Pointers and Structures

General principle …

If we have:


SomeStructType s;
SomeStructType *sp = &s;  // declare pointer and initialise to address of s

then the following are all equivalent:

s.SomeElem    sp->SomeElem    (*sp).SomeElem

[Diagram:Pic/structptr2.png]

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [38/97]
❖ Memory

Reminder:

Computer memory … large array of consecutive data cells or bytes
  • char   … 1 byte
  • int,float   … 4 bytes
  • double   … 8 bytes
  • any_type *   … 8 bytes (on CSE lab computers)
Memory addresses shown in Hexadecimal notation

[Diagram:Pic/memoryAddresses.png]

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [39/97]
❖ C execution: Memory

An executing C program partitions memory into:

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [40/97]
❖ ... C execution: Memory

[Diagram:Pic/memory.png]

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [41/97]
❖ Exercise : Memory Regions


int numbers[] = { 40, 20, 30 };

void insertionSort(int array[], int n) {
   int i, j;
   for (i = 1; i < n; i++) {
      int element = array[i];
      for (j = i-1; j >= 0 && array[j] > element; j--)
         array[j+1] = array[j];
      array[j+1] = element;
   }
}

int main(void) {
   insertionSort(numbers, 3);
   return 0;
}

Which memory region are the following objects located in?

  1. insertionSort()
  2. numbers[0]
  3. n
  4. array[0]
  5. element
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [42/97]
  1. code
  2. global
  3. stack
  4. global
  5. stack
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [43/97]
❖ Dynamic Data Structures

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [44/97]
❖ Dynamic Memory Allocation

So far, we have considered static memory allocation

Examples:

int   x;     // 4 bytes containing a 32-bit integer value
char *cp;    // 8 bytes (on CSE machines)
             //   containing address of a char
typedef struct {float x; float y;} Point;
Point p;     // 8 bytes containing two 32-bit float values
char  s[20]; // array containing space for 20 1-byte chars

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [45/97]
❖ ... Dynamic Memory Allocation

In many applications, fixed-size data is ok.

In many other applications, we need flexibility.

Examples:

char name[MAXNAME];   // how long is a name?
char item[MAXITEMS];  // how high can the stack grow?
char dictionary[MAXWORDS][MAXWORDLENGTH];
                     // how many words are there?
                     // how long is each word?

With fixed-size data, we need to guess sizes  ("large enough").

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [46/97]
❖ ... Dynamic Memory Allocation

Fixed-size memory allocation:

Dynamic memory allocation: But how to do this in C?
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [47/97]
❖ Dynamic Data Example

Problem:

Example input:   6 25 -1 999 42 -16 64

How to define the vector?

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [48/97]
❖ ... Dynamic Data Example

Suggestion #1: allocate a large vector; use only part of it

#define MAXELEMS 1000

// how many elements in the vector
int numberOfElems;
scanf("%d", &numberOfElems);
assert(numberOfElems <= MAXELEMS);

// declare vector and fill with user input
int i, vector[MAXELEMS];
for (i = 0; i < numberOfElems; i++)
   scanf("%d", &vector[i]);

Works ok, unless too many numbers; usually wastes space.

Recall that assert() terminates program with standard error message if test fails.

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [49/97]
❖ ... Dynamic Data Example

Suggestion #2: create vector after count read in

#include <stdlib.h>

// how many elements in the vector
int numberOfElems;
scanf("%d", &numberOfElems);

// declare vector and fill with user input
int i, *vector;
size_t numberOfBytes;
numberOfBytes = numberOfElems * sizeof(int);

vector = malloc(numberOfBytes);
assert(vector != NULL);

for (i = 0; i < numberOfElems; i++)
   scanf("%d", &vector[i]);

Works unless the heap is already full  (very unlikely)

Reminder: because of pointer/array connection   &vector[i] == vector+i

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [50/97]
❖ The malloc() function

Recall memory usage within C programs:

[Diagram:Pic/memusage.png]

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [51/97]
❖ ... The malloc() function

malloc() function interface

void *malloc(size_t n);

What the function does:

Note: size_t is essentially an unsigned int
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [52/97]
❖ ... The malloc() function

Example use of malloc:

[Diagram:Pic/malloc1.png]

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [53/97]
❖ ... The malloc() function

Things to note about   void *malloc(size_t):

Required size is determined by   #Elements * sizeof(ElementType)
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [54/97]
❖ Exercise : Dynamic Memory Allocation

Write code to

  1. create space for 1,000 speeding tickets (cf. Lecture Week 1)
  2. create a dynamic m×n-matrix of floating point numbers, given m and n
How many bytes need to be reserved in each case?
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [55/97]
  1. Speeding tickets:

    
    typedef struct {
    	int day, month, year; } DateT;
    typedef struct {
    	int hour, minute; } TimeT;
    typedef struct {
    	char plate[7]; DateT d; TimeT t; } TicketT;
    

    TicketT *tickets;
    tickets = malloc(1000 * sizeof(TicketT));
    assert(tickets != NULL);
    

    28,000 bytes allocated

  2. Matrix:

    float **matrix;
    
    // allocate memory for m pointers to beginning of rows
    matrix = malloc(m * sizeof(float *));
    assert(matrix != NULL);
    
    // allocate memory for the elements in each row
    int i;
    for (i = 0; i < m; i++) {
       matrix[i] = malloc(n * sizeof(float));       
       assert(matrix[i] != NULL);
    }
    

    8m + 4·mn bytes allocated

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [56/97]
❖ Exercise : Memory Regions

Which memory region is tickets located in? What about *tickets?

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [57/97]
  1. tickets is a variable located in the stack
  2. *tickets is in the heap (after malloc'ing memory)
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [58/97]
❖ ... The malloc() function

malloc() returns a pointer to a data object of some kind.

Things to note about objects allocated by malloc():

The function free() releases objects allocated by malloc()
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [59/97]
❖ ... The malloc() function

Usage of malloc() should always be guarded:

int *vector, length, i;
…
vector = malloc(length*sizeof(int));
// but malloc() might fail to allocate
assert(vector != NULL);
// now we know it's safe to use vector[]
for (i = 0; i < length; i++) {
	… vector[i] …
}

Alternatively:


int *vector, length, i;
…
vector = malloc(length*sizeof(int));
// but malloc() might fail to allocate
if (vector == NULL) {
	fprintf(stderr, "Out of memory\n");
	exit(1);
}
// now we know its safe to use vector[]
for (i = 0; i < length; i++) {
	… vector[i] …
}

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [60/97]
❖ Memory Management

void free(void *ptr)

Things to note:
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [61/97]
❖ ... Memory Management

Warning! Warning! Warning! Warning!

Careless use of malloc() / free() / pointers

Such errors are very difficult to track down and debug.

Must be very careful with your use of malloc() / free() / pointers.

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [62/97]
❖ ... Memory Management

If an uninitialised or otherwise invalid pointer is used, or an array is accessed with a negative or out-of-bounds index, one of a number of things might happen:

The first is the most desirable, but cannot be relied on.
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [63/97]
❖ ... Memory Management

Given a pointer variable:

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [64/97]
❖ ... Memory Management

Typical usage pattern for dynamically allocated objects:

// single dynamic object e.g. struct
Type *ptr = malloc(sizeof(Type));  // declare and initialise
assert(ptr != NULL);
… use object referenced by ptr e.g. ptr->name …
free(ptr);

// dynamic array with "nelems" elements
int nelems = NumberOfElements;
ElemType *arr = malloc(nelems*sizeof(ElemType));
assert(arr != NULL);
… use array referenced by arr e.g. arr[4] …
free(arr);

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [65/97]
❖ Memory Leaks

Well-behaved programs do the following:

A program which does not free() each object before the last reference to it is lost contains a memory leak.

Such programs may eventually exhaust available heapspace.

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [66/97]
❖ Exercise : Dynamic Arrays

Write a C-program that

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [67/97]
❖ Sidetrack: Standard I/O Streams, Redirects

Standard file streams:

Executing a C program causes main(…) to be invoked
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [68/97]
❖ ... Sidetrack: Standard I/O Streams, Redirects

The streams stdin, stdout, stderr can be redirected

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [69/97]
❖ Linked Lists as Dynamic Data Structure

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [70/97]
❖ Self-referential Structures

[Diagram:Pic/linkedList2.png]

Reminder: To realise a "chain of elements", need a node containing

In C, we can define such nodes as:

typedef struct node {
   int data;
   struct node *next;
} NodeT;

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [71/97]
❖ ... Self-referential Structures

Note that the following definition does not work:

typedef struct {
   int data;
   NodeT *next;
} NodeT;

Because NodeT is not yet known (to the compiler) when we try to use it to define the type of the next field.

The following is also illegal in C:

struct node {
   int data;
   struct node recursive;    
};

Because the size of the structure would have to satisfy sizeof(struct node) = sizeof(int) + sizeof(struct node) = ∞.

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [72/97]
❖ Memory Storage for Linked Lists

Linked list nodes are typically located in the heap

Variables containing pointers to list nodes Pointers to the start of lists are often
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [73/97]
❖ ... Memory Storage for Linked Lists

Create a new list node:

NodeT *makeNode(int v) {
   NodeT *new = malloc(sizeof(NodeT));
   assert(new != NULL);
   new->data = v;       // initialise data
   new->next = NULL;    // initialise link to next node
   return new;          // return pointer to new node
}

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [74/97]
❖ ... Memory Storage for Linked Lists

[Diagram:Pic/linkedList3.png]

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [75/97]
❖ Iteration over Linked Lists

When manipulating list elements

To iterate over a linked list:
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [76/97]
❖ ... Iteration over Linked Lists

[Diagram:Pic/listIterate1.png]

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [77/97]
❖ ... Iteration over Linked Lists

Standard method for scanning all elements in a linked list:

NodeT *list;  // pointer to first Node in list
NodeT *p;     // pointer to "current" Node in list

p = list;
while (p != NULL) {
	… do something with p->data 
	p = p->next;
}

// which is frequently written as

for (p = list; p != NULL; p = p->next) {
	… do something with p->data 
}

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [78/97]
❖ ... Iteration over Linked Lists

Check if list contains an element:

int inLL(NodeT *list, int d) {
   NodeT *p;
   for (p = list; p != NULL; p = p->next)
      if (p->data == d)      // element found
         return true;
   return false;             // element not in list
}

Print all elements:

void showLL(NodeT *list) {
   NodeT *p;
   for (p = list; p != NULL; p = p->next)
      printf("%6d", p->data);
}

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [79/97]
❖ Modifying a Linked List

Insert a new element at the beginning:

NodeT *insertLL(NodeT *list, int d) {
   NodeT *new = makeNode(d);  // create new list element
   new->next = list;          // link to beginning of list
   return new;                // new element is new head
}

Delete the first element:

NodeT *deleteHead(NodeT *list) {
   assert(list != NULL);  // ensure list is not empty
   NodeT *head = list;    // remember address of first element
   list = list->next;     // move to second element
   free(head);
   return list;           // return pointer to second element
}

What would happen if we didn't free the memory pointed to by head?

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [80/97]
❖ Exercise : Freeing a list

Write a C-function to destroy an entire list.

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [81/97]
Iterative version:

void freeLL(NodeT *list) {
   NodeT *p, *temp;

   p = list;
   while (p != NULL) {
      temp = p->next;
      free(p);
      p = temp;
   }
}

Why do we need the extra variable temp?

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [82/97]
❖ Doubly-linked Lists

Doubly-linked lists are a variation on "standard" linked lists where each node has a pointer to the previous node as well as a pointer to the next node.

[Diagram:Pic/linked-list-types.png]

You can find one possible implementation of the above doubly-linked list ADT in the directory "dllist", under "Programs" for this lecture.

.

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [83/97]
❖ Abstract Data Structures: ADTs

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [84/97]
❖ Abstract Data Types

Reminder: An abstract data type is …

E.g. does a client want/need to know how a Stack is implemented?

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [85/97]
❖ ... Abstract Data Types

Typical operations with ADTs

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [86/97]
❖ ... Abstract Data Types

ADT interface provides

ADT implementation gives ADTs are important because …
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [87/97]
❖ Stack as ADT

Interface (in stack.h)

// provides an opaque view of ADT
typedef struct StackRep *stack;

// set up empty stack
stack newStack();
// remove unwanted stack
void dropStack(stack);
// check whether stack is empty
int StackIsEmpty(stack);
// insert an int on top of stack
void StackPush(stack, int);
// remove int from top of stack
int StackPop(stack);

ADT stack defined as a pointer to an unspecified struct named StackRep

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [88/97]
❖ Sidetrack: Defining Structures

Structures can be defined in two different styles:

typedef struct { int day, month, year; } DateT;
// which would be used as
DateT somedate;

// or

struct date { int day, month, year; };
// which would be used as
struct date anotherdate;

The definitions produce objects with identical structures.

It is possible to combine both styles:

typedef struct date { int day, month, year; } DateT;
// which could be used as
DateT       date1, *dateptr1;
struct date date2, *dateptr2;

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [89/97]
❖ Stack ADT Implementation

Linked list implementation (stack.c):

Remember: stack.h includes  typedef struct StackRep *stack;


#include <stdlib.h>
#include <assert.h>
#include "stack.h"

typedef struct node {
   int data;
   struct node *next;
} NodeT;

typedef struct StackRep {
   int    height;   // #elements on stack
   NodeT *top;      // ptr to first element
} StackRep;

// set up empty stack
stack newStack() {
   stack S = malloc(sizeof(StackRep));     
   S->height = 0;
   S->top = NULL;
   return S;
}

// remove unwanted stack
void dropStack(stack S) {
   NodeT *curr = S->top;
   while (curr != NULL) {  // free the list
      NodeT *temp = curr->next;
      free(curr);
      curr = temp;
   }
   free(S);           // free the stack rep
}







// check whether stack is empty
int StackIsEmpty(stack S) {
   return (S->height == 0);
}

// insert an int on top of stack
void StackPush(stack S, int v) {
   NodeT *new = malloc(sizeof(NodeT));  
   assert(new != NULL);
   new->data = v;
   // insert new element at top
   new->next = S->top;
   S->top = new;
   S->height++;
}

// remove int from top of stack
int StackPop(stack S) {
   assert(S->height > 0);
   NodeT *head = S->top;
   // second list element becomes new top
   S->top = S->top->next;
   S->height--;
   // read data off first element, then free
   int d = head->data;
   free(head);
   return d;
}

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [90/97]
❖ Sidetrack: Make/Makefiles

Compilation process is complex for large systems.

How much to compile?

The make command assists by allowing
COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [91/97]
❖ ... Sidetrack: Make/Makefiles

Example multi-module program …

[Diagram:Pic/modules.png]

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [92/97]
❖ ... Sidetrack: Make/Makefiles

make is driven by dependencies given in a Makefile

A dependency specifies

target : source1 source2commands to build target from sources

e.g.

game : main.o graphics.o world.o
	gcc -o game main.o graphics.o world.o

Rule: target is rebuilt if older than any sourcei

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [93/97]
❖ ... Sidetrack: Make/Makefiles

A Makefile for the example program:

game : main.o graphics.o world.o
	gcc -o game main.o graphics.o world.o

main.o : main.c graphics.h world.h
	gcc -Wall -Werror -std=c11 -c main.c

graphics.o : graphics.c world.h 
	gcc -Wall -Werror -std=c11 -c graphics.c

world.o : world.c
	gcc -Wall -Werror -std=c11 -c world.c

Things to note:

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [94/97]
❖ ... Sidetrack: Make/Makefiles

If make arguments are targets, build just those targets:

make world.o
gcc -Wall -Werror -std=c11 -c world.c

If no args, build first target in the Makefile.

make
gcc -Wall -Werror -std=c11 -c main.c
gcc -Wall -Werror -std=c11 -c graphics.c
gcc -Wall -Werror -std=c11 -c world.c
gcc -o game main.o graphics.o world.o

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [95/97]
❖ Exercise : Makefile

Write a Makefile for the binary conversion program (Exercise 6, Problem Set Week 1) and the new Stack ADT.

COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [96/97]
❖ Summary


COMP9024 (22T0) ♢ Week 02a ♢ Dynamic Data Structures ♢ [97/97]


Produced: 20 Dec 2021