📄 ct5
字号:
.NHStructures.PPThe main use of structures is to lump togethercollections of disparate variable types,so they can conveniently be treated as a unit.For example,if we were writing a compiler or assembler,we might need for each identifier information likeits name (a character array),its source line number (an integer),some type information (a character, perhaps),and probably a usage count (another integer)..E1 char id[10]; int line; char type; int usage;.E2.PPWe can make a structure out of this quite easily.We first tell C what the structure will looklike,that is, what kinds of things it contains;after that we can actually reserve storage for it,either in the same statement or separately.The simplest thing is to define it and allocatestorage all at once:.E1struct { char id[10]; int line; char type; int usage;} sym;.E2.PPThis defines.UL symto be a structure with the specified shape;.UL id,.UL line,.UL typeand.UL usageare.ulmembersof the structure.The way we refer to any particular member of the structureis.E1structure\(hyname \*. member.E2as in.E1 sym\*.type = 077; if( sym\*.usage \*= 0 ) \*.\*.\*. while( sym\*.id[j\*+] ) \*.\*.\*..ft R etc\*..E2Although the names of structure members never stand alone,they still have to be unique _there can't be another.UL idor.UL usagein some other structure..PPSo far we haven't gained much.The advantages of structures start to comewhen we have arrays of structures,or when we want to pass complicated data layoutsbetween functions.Suppose we wanted to make a symbol table for upto 100 identifiers.We could extend our definitions like.E1 char id[100][10]; int line[100]; char type[100]; int usage[100];.E2but a structure lets usrearrange this spread-out informationso all the data about a single identifer is collectedinto one lump:.E1struct { char id[10]; int line; char type; int usage;} sym[100];.E2This makes.UL syman array of structures;each array element has the specified shape.Now we can refer to members as.E1 sym[i]\*.usage\*+; /\** increment usage of i\(hyth identifier \**/ for( j=0; sym[i]\*.id[j\*+] != '\\0'; ) \*.\*.\*..ft R etc\*..E2Thus to print a list of all identifiers that haven't been used,together with their line number,.E1 for( i=0; i<nsym; i\*+ ) if( sym[i]\*.usage \*= 0 ) printf("%d\\t%s\\n", sym[i]\*.line, sym[i]\*.id);.E2.PPSuppose we now want to write a function.UL lookup(name)which will tell us if .UL namealready exists in .UL sym,by giving its index, or that it doesn't,by returning a \(mi1.We can't pass a structure to a functiondirectly _we have to either define it externally, orpass a pointer to it.Let's try the first way first..E1int nsym 0; /\** current length of symbol table \**/.SPstruct { char id[10]; int line; char type; int usage;} sym[100]; /\** symbol table \**/.SPmain( ) { \*.\*.\*. if( (index = lookup(newname)) >= 0 ) sym[index]\*.usage\*+; /\** already there \*.\*.\*. \**/ else install(newname, newline, newtype); \*.\*.\*.}.SPlookup(s) char \**s; { int i; extern struct { char id[10]; int line; char type; int usage; } sym[ ];.SP for( i=0; i<nsym; i\*+ ) if( compar(s, sym[i]\*.id) > 0 ) return(i); return(-1);}compar(s1,s2) /\** return 1 if s1\*=s2, 0 otherwise \**/ char \**s1, \**s2; { while( \**s1\*+ \*= \**s2 ) if( \**s2\*+ \*= '\\0' ) return(1); return(0);}.E2The declaration of the structure in .UL lookupisn't needed if the external definition precedes its use in the same source file,as we shall see in a moment..PPNow what if we want to use pointers?.E1struct symtag { char id[10]; int line; char type; int usage;} sym[100], \**psym; psym = &sym[0]; /\** or p = sym; \**/.E2This makes.UL psyma pointer to our kind of structure(the symbol table),then initializes it to point to the first element of.UL sym\*..PPNotice that we added something after the word.UL struct:a ``tag'' called .UL symtag\*.This puts a name on our structure definition so we canrefer to it later without repeating the definition.It's not necessary but useful.In fact we could have said.E1struct symtag { \*.\*.\*. structure definition};.E2which wouldn't have assigned any storage at all,and then said.E1struct symtag sym[100];struct symtag \**psym;.E2which would define the array and the pointer.This could be condensed further, to.E1struct symtag sym[100], \**psym;.E2.PPThe way we actually refer to an member of a structure by a pointeris like this:.E1 ptr -> structure\(hymember.E2The symbol `\(mi>'means we're pointing at a member of a structure;`\(mi>' is only used in that context..UL ptris a pointer to the (base of) a structurethat contains the structure member.The expression.UL "ptr\(mi>structure\(hymember"refers to the indicated member of the pointed-to structure.Thus we have constructions like:.E1psym->type = 1;psym->id[0] = 'a';.E2and so on..PPFor more complicated pointer expressions,it's wise to use parentheses to make it clearwho goes with what.For example,.E1struct { int x, \**y; } \**p;p->x\*+ increments x\*+p->x so does this!(\*+p)->x increments p before getting x\**p->y\*+ uses y as a pointer, then increments it\**(p->y)\*+ so does this\**(p\*+)->y uses y as a pointer, then increments p.E2.tr |.The way to remember these is that.UL \(mi>,.UL |(dot),.UL "( )"and.UL "[ ]"bind very tightly.An expression involving one of these is treated as a unit..tr ||.UL p\(mi>x,.UL a[i],.UL y\*.xand.UL f(b)are namesexactly as.UL abcis..PPIf .UL pis a pointer to a structure,any arithmetic on.UL ptakes into account the acutal size of the structure.For instance,.UL p\*+increments.UL pby the correct amount to get the next element of the array of structures.But don't assume that the size of a structure is the sumof the sizes of its members _because of alignments of different sized objects,there may be ``holes'' in a structure..PPEnough theory. Here is the lookup example, this time with pointers..E1struct symtag { char id[10]; int line; char type; int usage;} sym[100];.SPmain( ) { struct symtag \**lookup( ); struct symtag \**psym; \*.\*.\*. if( (psym = lookup(newname)) ) /\** non-zero pointer \**/ psym -> usage\*+; /\** means already there \**/ else install(newname, newline, newtype); \*.\*.\*.}.SPstruct symtag \**lookup(s) char \**s; { struct symtag \**p; for( p=sym; p < &sym[nsym]; p\*+ ) if( compar(s, p->id) > 0) return(p); return(0);}.E2The function.UL compardoesn't change:.UL `p\(mi>id'refers toa string..PPIn.UL mainwe test the pointer returned by.UL lookupagainst zero,relying on the fact that a pointer is by definition never zerowhen it really points at something.The other pointer manipulations are trivial..PPThe only complexity is the set of lines like.E1struct symtag \**lookup( );.E2This brings us toan area that we willtreat only hurriedly _ the question of function types.So far, all of our functions have returned integers(or characters, which are much the same).What do we do when the function returns something else,like a pointer to a structure?The rule is thatany function that doesn't return an.UL inthas to say explicitly what it does return.The type information goes before the function name(which can make the name hard to see).Examples:.E1char f(a) int a; { \*.\*.\*.}int \**g( ) { \*.\*.\*. }struct symtag \**lookup(s) char \**s; { \*.\*.\*. }.E2The function.UL freturns a character,.UL greturns a pointer to an integer,and.UL lookupreturns a pointer to a structure that looks like.UL symtag\*.And if we're going to use one of these functions,we have to make a declarationwhere we use it,as we did in.UL mainabove..PPNotice th parallelism between the declarations.E1 struct symtag \**lookup( ); struct symtag \**psym;.E2In effect, this says that.UL lookup(~)and.UL psymare both used the same way _as a pointer to a strcture _even though one is a variable and the other is a function.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -