ECE 209 Structures

Heterogeneous data

char *Name[50] ;
char  Abbrev[50][2] ;
int   Population[50] ;
Name[12]       = "North Carolina" ;
Abbrev[12][0]  = 'N' ;
Abbrev[12][1]  = 'C' ;
Population[12] = 9222414 ;

Is placing these values in three different arrays convenient, logical, or efficient?

Structure

struct state {
  char *Name ;
  char Abbrev[2] ;
  int Population ;
}

struct state NC ;

NC.Name       = "North Carolina" ;
NC.Abbrev[0]  = 'N' ;
NC.Abbrev[1]  = 'C' ;
NC.Population = 9222414 ;

struct definition

Effectively introduces a new programmer defined type. Some programmers prefer typedef's for structures.

typedef struct state State ;

State NC ;

The dot operator

The dot operator joins a structure variable with a field or member name.

The . operator has the highest precedence level and has left-to-right precedence. Other operators at this level as:

A horrendous example of this would be f("United States")[30].Popluation++ used as a expression; however, you do often find long sequences such as USA[12].Name[0].

LC-3 and structures

Consider each structure as having its own symbol table.

fieldstructoffsetsize
Abbrevstate12
Namestate01
Populationstate31

The offset of NC.Population would be the offset of NC plus the offset of Population.

Structures as variables

In ANSI C, one structure can be assigned (with =) to another and structures can be passed to and returned from functions. This involves copying the entire structure and is reasonable only with very small structures.

Initialization of structures

struct state NC = { "North Carolina", {'N','C'}, 9222414 } ;

Arrays of structures

There is nothing unusual here.

struct state USA[50] ;

USA[12].Name       = "North Carolina" ;
USA[12].Abbrev[0]  = 'N' ;
USA[12].Abbrev[1]  = 'C' ;
USA[12].Population = 9222414 ;

Nested structures

Structures nested a couple of levels can be useful.

struct county {
  char *Name ;
  char  Population ;
  struct state State ;
}

struct county Haywood ;

Haywood.Name = "Haywood" ;
Haywood.State.Name = "North Carolina" ;

Dynamic allocation of structures using pointers

This may seem odd, but it turns out to be very common.

struct state *pNC ;

pNC = (struct state *)malloc(sizeof(struct state)) ;

It is so common that P->F is a way of saying (*P).F in C. (Question: Why are the parentheses needed?)

pNC->Name       = "North Carolina" ;
pNC->Abbrev[0]  = 'N' ;
pNC->Abbrev[1]  = 'C' ;
pNC->Population = 9222414 ;

Linked lists

It only gets worse. Often structures are chained in links with recursively defined structures.

struct StateNode {
  struct state value ;
  struct StateNode *next ;
}

struct StateNode *firstState ;
struct StateNode *lastState ;

Useful function

Here's a useful function for our example.

struct StateNode *AllocateState(char *name, char *abbr, int pop) {
  struct StateNode *R = (struct StateNode *)malloc(sizeof(struct StateNode)) ;
  R->value.Name       = name ;
  R->value.Abbrev[0]  = abbr[0] ;
  R->value.Abbrev[1]  = abbr[1] ;
  R->value.Population = pop ;
  R->next             = (struct StateNode *)NULL ;
  return R ;
}

Dangerous function

Consider the folly of the following.

struct StateNode *BadAllocateState(char *name, char *abbr, int pop) {
  struct StateNode R ;
  R.value.Name       = name ;
  R.value.Abbrev[0]  = abbr[0] ;
  R.value.Abbrev[1]  = abbr[1] ;
  R.value.Population = pop ;
  R.next             = (struct StateNode *)NULL ;
  return &R ;
}

Allocating for the first state

There are some historic inacuracies in this example. There were no computers when Delaware ratified the constitution.

firstNode = AllocateState("Delaware", "DE", 55000) ;
lastNode  = firstNode ;

Allocating for the twelfth state

struct newNode = AllocateState("North Carolina", "NC", 37000) ;
lastNode->next = newNode ;
lastNode          = newNode ;

Some linked list examples

Counting the number of states

int NumberStates(struct StateNode *s) {
  int number = 0 ;
  while (s != NULL) {
    ++number ;
    s = s->next ;
  }
  return number ;
}

Finding the state with the largest population

char * MostPeople(struct StateNode *s) {
  int mostPeople = 0 ;
  char *biggestState ;
  while (s != NULL) {
    if (s->value.population > mostPeople) {
      mostPeople = s->value.population ;
      biggestState = s->value.Name ;
    }
    s = s->next ;
  }
  return biggestState ;
}

Updating the population of North Carolina

void PlusPlusNC(struct StateNode *s) {
  while (strncmp(s->value.Abbrev, "NC", 2))
    s = s->next ;
  }
  s->value.population++ ;
}

Reversing the Dakotas

void DakotaSwitch(struct StateNode *s) {
  struct StateNode *Dakota1 ;
  struct StateNode *Dakota2 ;
  while (strncmp(s->next->value.Abbrev, "ND", 2)
         && strncmp(s->next->value.Abbrev, "SD", 2)) {
    s = s->next ;    
  }
  Dakota1 = s->next ;
  Dakota2 = Dakota1->next ;
  s->next = Dakota2 ;
  Dakota1->next = Dakota2->next ;
  Dakota2->next = Dakota1 ;
}