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