Week 04


Week 041/34

Things to Note ...

In This Lecture ...

Coming Up ...


Nerds You Should Know #32/34

Next in a series on famous computer scientists ...

She developed COBOL ... and bugs!


... Nerds You Should Know #33/34

Grace Hopper

 
  • PhD in Mathematics from Yale (1934)
  • Professor of Maths at Vassar (1930's)
  • Joined U.S. Navy (research) (1943)
  • coined the term "bug" (1940's, apocryphal)
  • developed the first compiler (1950's)
  • designer of the COBOL language (1950's)
  • worked for Sperry/Rand/Univac (1960's)
  • promoted to Admiral in US Navy (1980's)
  • "retired" 1971 ... still consulting until 1992


... Nerds You Should Know #34/34

The original "bug" ...
 

 


Data Types5/34

Major classes of data types:


Atomic Data Types6/34

Families of atomic data types:

All have essentially the same set of operations ...


Enums7/34

Enumerated types (enums) ...

Example:

enum Mood { depressed, sad, well, happy };

is equivalent to the definitions:

#define depressed 0
#define sad       1
#define well      2
#define happy     3

and a new type  enum Mood  which is effectively unsigned int.


Exercise: Enumerated Types8/34

Define enumerated types for:

Show that, using these types, you can: How can you display values from such types?


Aggregate Data Types9/34

Families of aggregate data types:

Only heterogeneous types have an assignment operator.


Defining New Data Types10/34

C allows us to define new data type (names) via typedef:

typedef ExistingDataType NewTypeName;

Examples:

typedef int Integer;

typedef float Temperature;

typedef char String[100];

typedef int Matrix[20][20];


... Defining New Data Types11/34

Reasons to use typedef:


Exercise: Using typedef12/34

Suggest typedefs for the following kinds of values

  1. marks for students in a course
  2. grades for students in a course
  3. strings of up to 100 characters
  4. vectors of 10 real numbers
  5. array of strings
  6. dates
Give example literal values of each type.


Using typedef13/34

Example of using typedef to clarify variable defs:


#define NUM_WORKERS 150
#define MAX_NAME_LENGTH 60

// version 1 
char  worker[NUM_WORKERS][MAX_NAME_LENGTH];
char  status[NUM_WORKERS][3];  // e.g. "FT", "PT", ...
float salary[NUM_WORKERS];

// version 2
typedef char FullName[MAX_NAME_LENGTH];
typedef enum {casual, part_time, full_time} EmpType;
typedef float Dollars

FullName worker[NUM_WORKERS];
EmpType  status[NUM_WORKERS];
Dollars  salary[NUM_WORKERS];

strcpy(worker[i], "John");
status[i] = full_time;
salary[i] = 55325.50;


... Using typedef14/34

Possible memory layout produced by above example:

[Diagram:Pic/arrays-small.png]


... Using typedef15/34

The use of parallel arrays works in limited cases

In this example, a better approach would be


Structures16/34

A structure

Example:

struct date {
       int day;
       int month;
       int year;
}; // don't forget the semicolon!


... Structures17/34

Defining a structure itself does not allocate any memory

We need to declare a variable in order to allocate memory

struct date christmas;

The components of the structure can be accessed using the "dot" operator

christmas.day   =   25;
christmas.month =   12;
chirstmas.year  = 2015;


... Structures18/34

A structure can be passed as a parameter to a function:

void print_date(struct date d) {
	printf("%d/%d/%d\n", d.day, d.month, d.year);
}

int is_leap_year(struct date d) {
	return ( ((d.year%4 == 0) && (d.year%100 != 0))
        	 || (d.year%400 == 0) );
}


Nested Structures19/34

One structure can be nested inside another

struct date { int day, month, year; };

struct time { int hour, minute; };

struct speeding {
	char        plate[7];
	double      speed;
	struct date d;
	struct time t;
};


typedef and struct20/34

We can now define a structured data type for Worker objects:

typedef char Date[11]; // e.g. "18-08-2014"
typedef struct {
	char     name[MAX_NAME_LENGTH];          
	Date     birthday;
	EmpType  status;
	float    salary;
} WorkerT;


... typedef and struct21/34

Note: structures can be defined in two different styles:

struct Point0 {float x; float y;};

// or

typedef struct { float x; float y; } Point1;
// which would be used as
struct Point0 anumber;
Point1        anothernumber;

The definitions produce objects with identical structures.


... typedef and struct22/34

With the above WorkerT type, we declare and use variables as ...

typedef struct {...} WorkerT;

WorkerT boss;         // single struct
WorkerT worker[1500];  // array of structs

boss.status = full_time;
boss.salary = 675000.00;
strcpy(boss.name, "John Elliot");
strcpy(boss.birthday, "29-02-1958");

for (i = 0; i < 1500; i++) {
	fgets(line,60,stdin);
	strcpy(worker[i].name, line);
	scanf("%f", &worker[i].salary);
	...
}


... typedef and struct23/34

Possible memory layout produced for WorkerT object:

[Diagram:Pic/struct-small.png]

 

Note: padding is needed to ensure that birthday lies on a 4-byte boundary.

Don't normally care about internal layout, since fields are accessed by name.


Exercise: typedef and structs24/34

Define a structure for entries in this table:

[Diagram:Pic/opal-small.png]


Pointers and structs25/34

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

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; you will see it many more times this semester.


... Pointers and structs26/34

Diagram of scenario from program above:

[Diagram:Pic/structptr-small.png]


... Pointers and structs27/34

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]


Linked Structures28/34

One particularly useful kind of structure:

typedef struct Node {
	char   name[MAXNAME];
	int    value;
	struct Node *next;
} NodeT;

Allows us to build structures like:

[Diagram:Pic/list-small.png]

Note that  struct Node  is the same type as  NodeT


Exercise: Find Value in List29/34

Write a function

int valueOf(char *name, NodeT *list)

that returns the value associated with name in list.

If the name does not appear in the list, return -1.


Unions30/34

Sometimes we want a struct to be used for several purposes.

union types provide "multi-faceted" struct objects.

Example: nodes in an expression tree

[Diagram:Pic/exprtree-small.png]

All objects are nodes, but each contains an operator, a variable or a value.


... Unions31/34

One possible representation for the above:

typedef enum { Opr, Val, Var } NodeKindT;

typedef enum { add, sub, mul, div } OperatorT;

typedef struct ExprNode {
	NodeKindT ntype;  // e.g. Opr, Val, Var
        OperatorT opr;    // e.g. add, sub
        char      var[8]; // e.g. "x", "y"
        int       val;    // e.g. 5, -20
	struct ExprNode *left;  // subtree
	struct ExprNode *right; // subtree
} ExprNodeT;


... Unions32/34

A problem with this representation:

Reminder of fields:

typedef struct ExprNode {
	NodeKind ntype;         // size = 4 bytes
	Operator opr;           // size = 4 bytes
        char     var[8];        // size = 8 bytes
        int      val;           // size = 4 bytes
        struct ExprNode *left;  // size = 4 bytes
        struct ExprNode *right; // size = 4 bytes
} ExprNodeT;


... Unions33/34

Using a union, each node has storage only for largest type:

typedef struct ExprNode {
	NodeKindT ntype;        // size = 4 bytes
	union {
        	OperatorT  opr;
        	char       var[8];
        	int        val;   
	} data;                 // size = 8 bytes
	struct ExprNode *left;  // size = 4 bytes
	struct ExprNode *right; // size = 4 bytes
} ExprNodeT;

Size of ExprNodeT object = 4 + max(3,8,4) + 4 + 4 = 20 bytes.

The data field can be interpreted 3 ways (determined by ntype).


... Unions34/34

Printing an expression rooted in an ExprNodeT *:


int print(ExprNodeT *expr)
{
   switch (expr->ntype) {
   case Val: printf("%d", expr->data.val); break;
   case Var: printf("%s", expr->data.var); break;
   case Opr:
      switch (expr->data.opr) {
      case add: print(expr->left); putchar('+'); print(expr->right); break;
      case sub: print(expr->left); putchar('-'); print(expr->right); break;
      case mul: print(expr->left); putchar('*'); print(expr->right); break;
      case div: print(expr->left); putchar('/'); print(expr->right);
      }
   }
}

Note: I'm violating the style guide here


Produced: 11 Aug 2016