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?
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 ;
Effectively introduces a new programmer defined type.
Some programmers prefer typedef
's for structures.
typedef struct state State ; State NC ;
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]
.
Consider each structure as having its own symbol table.
field | struct | offset | size |
---|---|---|---|
Abbrev | state | 1 | 2 |
Name | state | 0 | 1 |
Population | state | 3 | 1 |
The offset of NC.Population
would be the
offset of NC
plus the offset of Population
.
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.
struct state NC = { "North Carolina", {'N','C'}, 9222414 } ;
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 ;
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" ;
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 ;
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 ;
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 ; }
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 ; }
There are some historic inacuracies in this example. There were no computers when Delaware ratified the constitution.
firstNode = AllocateState("Delaware", "DE", 55000) ; lastNode = firstNode ;
struct newNode = AllocateState("North Carolina", "NC", 37000) ; lastNode->next = newNode ; lastNode = newNode ;
int NumberStates(struct StateNode *s) { int number = 0 ; while (s != NULL) { ++number ; s = s->next ; } return number ; }
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 ; }
void PlusPlusNC(struct StateNode *s) { while (strncmp(s->value.Abbrev, "NC", 2)) s = s->next ; } s->value.population++ ; }
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 ; }