Week 01b: Abstract Data Types


Abstract Data Objects and Types


Abstract Data Types2/74

A data type is …

An abstract data type is …


... Abstract Data Types3/74

ADT interface provides

ADT implementation gives


... Abstract Data Types4/74

ADT interfaces are opaque

ADTs are important because …


... Abstract Data Types5/74

Typical operations with ADTs


Collections6/74

Common ADTs …

Collections may be categorised by …


... Collections7/74

Collection structures:

[Diagram:Pic/structures-small.png]


... Collections8/74

Or even a hybrid structure like:

[Diagram:Pic/structures2-small.png]


... Collections9/74

For a given collection type

For a given operation and data representation Generally,


ADOs and ADTs10/74

We want to distinguish …

Warning: Sedgewick's first few examples are ADOs, not ADTs.


Example: Abstract Stack Data Object11/74

Stack, aka pushdown stack or LIFO data structure

Assume (for the time being) stacks of char values

Operations:


... Example: Abstract Stack Data Object12/74

Example of use:

Stack  Operation  Return value
?  create  -
-  push a  -
a  push b  -
a b  push c  -
a b c  pop  c
a b  isempty  false


Exercise #1: Stack vs Queue13/74

Consider the previous example but with a queue instead of a stack.

Which element would have been taken out ("dequeued") first?



a


Stack as ADO15/74

Interface (a file named Stack.h)

// Stack ADO header file

void StackInit();      // set up empty stack
int  StackIsEmpty();   // check whether stack is empty
void StackPush(char);  // insert char on top of stack
char StackPop();       // remove char from top of stack

Note:


... Stack as ADO16/74

Implementation may use the following data structure:

[Diagram:Pic/stack-small.png]


... Stack as ADO17/74

Implementation (in a file named Stack.c):


#include "Stack.h"
#include <assert.h>

#define MAXITEMS 10
static struct {
   char item[MAXITEMS];
   int  top;
} stackObject;  // defines the Data Object

// set up empty stack
void StackInit() {
   stackObject.top = -1;
}

// check whether stack is empty
int StackIsEmpty() {
   return (stackObject.top < 0);
}





// insert char on top of stack
void StackPush(char ch) {
   assert(stackObject.top < MAXITEMS-1);
   stackObject.top++;
   int i = stackObject.top;
   stackObject.item[i] = ch;
}

// remove char from top of stack
char StackPop() {
   assert(stackObject.top > -1);
   int i = stackObject.top;
   char ch = stackObject.item[i];
   stackObject.top--;
   return ch;
}

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


Exercise #2: Bracket Matching18/74

Bracket matching … check whether all opening brackets such as '(', '[', '{' have matching closing brackets ')', ']', '}'

Which of the following expressions are balanced?

  1. (a+b) * c
  2. a[i]+b[j]*c[k])
  3. (a[i]+b[j])*c[k]
  4. a(a+b]*c
  5. void f(char a[], int n) {int i; for(i=0;i<n;i++) { a[i] = (a[i]*a[i])*(i+1); }}
  6. a(a+b * c


  1. balanced
  2. not balanced (case 1: an opening bracket is missing)
  3. balanced
  4. not balanced (case 2: closing bracket doesn't match opening bracket)
  5. balanced
  6. not balanced (case 3: missing closing bracket)


... Stack as ADO20/74

Bracket matching algorithm, to be implemented as a client for Stack ADO:


#include "Stack.h"

bracketMatching(s):
|  Input  stream s of characters
|  Output TRUE if parentheses in s balanced, FALSE otherwise
|
|  for each ch in s do
|  |  if ch = open bracket then
|  |     push ch onto stack
|  |  else if ch = closing bracket then
|  |  |  if stack is empty then
|  |  |     return FALSE                    // opening bracket missing (case 1)
|  |  |  else
|  |  |     pop top of stack
|  |  |     if brackets do not match then
|  |  |        return FALSE                 // wrong closing bracket (case 2)
|  |  |     end if
|  |  |  end if
|  |  end if
|  end for
|  if stack is not empty then return FALSE  // some brackets unmatched (case 3)
|                        else return TRUE


... Stack as ADO21/74

Execution trace of client on sample input:

( [ { } ] )

Next char  Stack  Check
- empty -
( ( -
[ ( [ -
{ ( [ { -
} ( [ {  vs  }   ✓
] ( [  vs  ]   ✓
) empty (  vs  )   ✓
eof empty -


Exercise #3: Bracket Matching Algorithm22/74

Trace the algorithm on the input

void f(char a[], int n) {
   int i;
   for(i=0;i<n;i++) { a[i] = a[i]*a[i])*(i+1); }
}


Next bracket  Stack  Check
start empty -
( ( -
[ ( [ -
] ( 
) empty 
{ { -
( { ( -
) { 
{ { { -
[ { { [ -
] { {  
[ { { [ -
] { {  
[ { { [ -
] { {  
) { FALSE


... Stack as ADO24/74

Sidetrack: Character I/O Functions in C   (requires <stdio.h>)

int getchar(void);

int putchar(int ch);

Both functions do automatic type conversion


Compilation and Makefiles


Compilers26/74

Compilers are programs that

The Gnu C compiler (gcc)

[Diagram:Pic/gcc-small.png]


... Compilers27/74

Compilation/linking with gcc

gcc -c Stack.c
produces Stack.o, from Stack.c and Stack.h
gcc -c bracket.c
produces bracket.o, from bracket.c and Stack.h
gcc -o rbt bracket.o Stack.o
links bracket.o, Stack.o and libraries
producing executable program called rbt

Note that stdio,assert included implicitly.

gcc is a multi-purpose tool


Make/Makefiles28/74

Compilation process is complex for large systems.

How much to compile?

The make command assists by allowing


... Make/Makefiles29/74

Example multi-module program …

[Diagram:Pic/modules-small.png]


... Make/Makefiles30/74

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


... Make/Makefiles31/74

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 -c main.c

graphics.o : graphics.c world.h 
	gcc -Wall -Werror -c graphics.c

world.o : world.c
	gcc -Wall -Werror -c world.c

Things to note:


... Make/Makefiles32/74

If make arguments are targets, build just those targets:

prompt$ make world.o
gcc -Wall -Werror -c world.c

If no args, build first target in the Makefile.

prompt$ make
gcc -Wall -Werror -c main.c
gcc -Wall -Werror -c graphics.c
gcc -Wall -Werror -c world.c
gcc -o game main.o graphics.o world.o


Exercise #4: Makefile33/74

Write a Makefile for the bracket matching program.


From ADOs to ADTs34/74

Abstract Data Objects

Abstract Data Types In C, ADTs are implemented using pointers and dynamic memory allocation


Pointers


Sidetrack: Numeral Systems36/74

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


... Sidetrack: Numeral Systems37/74

Decimal representation


... Sidetrack: Numeral Systems38/74

Binary representation


... Sidetrack: Numeral Systems39/74

Hexadecimal representation


Exercise #5: Conversion Between Different Numeral Systems40/74

  1. Convert 1010112 to base 10
  2. Convert 7410 to base 2
  3. Convert 2D16 to base 10
  4. Convert 27310 to base 16


  1. 4310
  2. 10010102
  3. 4510
  4. 11116


... Sidetrack: Numeral Systems42/74

Conversion between binary and hexadecimal

01234567
00000001001000110100010101100111
89ABCDEF
10001001101010111100110111101111


Exercise #6: Conversion Between Binary and Hexadecimal43/74

  1. Convert 10111110001010012 to base 16
  2. Convert 101111010111002 to base 16
  3. Convert 12D16 to base 2


  1. BE2916
  2. 2F5C16
  3. 1001011012


Memory45/74

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-small.png]


... Memory46/74

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)


... Memory47/74

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


Application: Input Using scanf()48/74

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


Exercise #7: Using scanf49/74

Write a program that


Pointers50/74

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:


... Pointers51/74

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-small.png]


... Pointers52/74

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


... Pointers53/74

Things to note:


Examples of Pointers54/74

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


Exercise #8: Pointers55/74

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  }



Val = 120


... Examples of Pointers57/74

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;
}


... Examples of Pointers58/74

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

We can achieve "simulated call-by-reference" by passing pointers as parameters


... Examples of Pointers59/74

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;
}


Pointers and Arrays60/74

An alternative approach to iteration through an array:

Example:

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


... Pointers and Arrays61/74

Pointer-based scan written in more typical style

[Diagram:Pic/pointerscan-small.png]


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


Sidetrack: Pointer Arithmetic62/74

A pointer variable holds a value which is an address.

C knows what type of object is being pointed to

Example:

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


... Sidetrack: Pointer Arithmetic63/74

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)


Arrays of Strings64/74

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


... Arrays of Strings65/74

prompt$ ./seqq 10 20


[Diagram:Pic/argcargv-small.png]


Each element of argv[] is


... Arrays of Strings66/74

More detail on how argv is represented:

prompt$ ./seqq 5 20

[Diagram:Pic/argv2-small.png]


... Arrays of Strings67/74

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:


Exercise #9: Command Line Arguments68/74

Write a program that



#include <stdio.h>
#include <stdlib.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(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;
}


... Arrays of Strings70/74

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], …


Pointers and Structures71/74

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.


... Pointers and Structures72/74

Diagram of scenario from program above:

[Diagram:Pic/structptr-small.png]


... Pointers and Structures73/74

General principle …

If we have:

SomeStructType  s,   *sp = &s;

then the following are all equivalent:

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

[Diagram:Pic/structptr2-small.png]


Summary74/74



Produced: 22 Nov 2018