home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Trees / V6 / usr / doc / ctut / ct5 < prev    next >
Encoding:
Text File  |  1975-06-26  |  8.0 KB  |  392 lines

  1. .NH
  2. Structures
  3. .PP
  4. The main use of structures is to lump together
  5. collections of disparate variable types,
  6. so they can conveniently be treated as a unit.
  7. For example,
  8. if we were writing a compiler or assembler,
  9. we might need for each identifier information like
  10. its name (a character array),
  11. its source line number (an integer),
  12. some type information (a character, perhaps),
  13. and probably a usage count (another integer).
  14. .E1
  15.     char    id[10];
  16.     int    line;
  17.     char    type;
  18.     int    usage;
  19. .E2
  20. .PP
  21. We can make a structure out of this quite easily.
  22. We first tell C what the structure will look
  23. like,
  24. that is, what kinds of things it contains;
  25. after that we can actually reserve storage for it,
  26. either in the same statement or separately.
  27. The simplest thing is to define it and allocate
  28. storage all at once:
  29. .E1
  30. struct {
  31.     char    id[10];
  32.     int    line;
  33.     char    type;
  34.     int    usage;
  35. } sym;
  36. .E2
  37. .PP
  38. This defines
  39. .UL sym
  40. to be a structure with the specified shape;
  41. .UL id,
  42. .UL line,
  43. .UL type
  44. and
  45. .UL usage
  46. are
  47. .ul
  48. members
  49. of the structure.
  50. The way we refer to any particular member of the structure
  51. is
  52. .E1
  53. structure\(hyname \*. member
  54. .E2
  55. as in
  56. .E1
  57.     sym\*.type = 077;
  58.     if( sym\*.usage \*= 0 ) \*.\*.\*.
  59.     while( sym\*.id[j\*+] ) \*.\*.\*.
  60. .ft R
  61.        etc\*.
  62. .E2
  63. Although the names of structure members never stand alone,
  64. they still have to be unique _
  65. there can't be another
  66. .UL id
  67. or
  68. .UL usage
  69. in some other structure.
  70. .PP
  71. So far we haven't gained much.
  72. The advantages of structures start to come
  73. when we have arrays of structures,
  74. or when we want to pass complicated data layouts
  75. between functions.
  76. Suppose we wanted to make a symbol table for up
  77. to 100 identifiers.
  78. We could extend our definitions like
  79. .E1
  80.     char    id[100][10];
  81.     int    line[100];
  82.     char    type[100];
  83.     int    usage[100];
  84. .E2
  85. but a structure lets us
  86. rearrange this spread-out information
  87. so all the data about a single identifer is collected
  88. into one lump:
  89. .E1
  90. struct {
  91.     char    id[10];
  92.     int    line;
  93.     char    type;
  94.     int    usage;
  95. } sym[100];
  96. .E2
  97. This makes
  98. .UL sym
  99. an array of structures;
  100. each array element has the specified shape.
  101. Now we can refer to members as
  102. .E1
  103.     sym[i]\*.usage\*+;    /\** increment usage of i\(hyth identifier \**/
  104.     for( j=0; sym[i]\*.id[j\*+] != '\\0'; ) \*.\*.\*.
  105. .ft R
  106.        etc\*.
  107. .E2
  108. Thus to print a list of all identifiers that haven't been used,
  109. together with their line number,
  110. .E1
  111.     for( i=0; i<nsym; i\*+ )
  112.         if( sym[i]\*.usage \*= 0 )
  113.             printf("%d\\t%s\\n", sym[i]\*.line, sym[i]\*.id);
  114. .E2
  115. .PP
  116. Suppose we now want to write a function
  117. .UL lookup(name)
  118. which will tell us if 
  119. .UL name
  120. already exists in 
  121. .UL sym,
  122. by giving its index, or that it doesn't,
  123. by returning a \(mi1.
  124. We can't pass a structure to a function
  125. directly _
  126. we have to either define it externally, or
  127. pass a pointer to it.
  128. Let's try the first way first.
  129. .E1
  130. int    nsym    0;    /\** current length of symbol table \**/
  131. .SP
  132. struct {
  133.     char    id[10];
  134.     int    line;
  135.     char    type;
  136.     int    usage;
  137. } sym[100];        /\** symbol table \**/
  138. .SP
  139. main( ) {
  140.     \*.\*.\*.
  141.     if( (index = lookup(newname)) >= 0 )
  142.         sym[index]\*.usage\*+;        /\** already there \*.\*.\*. \**/
  143.     else
  144.         install(newname, newline, newtype);
  145.     \*.\*.\*.
  146. }
  147. .SP
  148. lookup(s)
  149.    char \**s; {
  150.     int i;
  151.     extern struct {
  152.         char    id[10];
  153.         int    line;
  154.         char    type;
  155.         int    usage;
  156.     } sym[ ];
  157. .SP
  158.     for( i=0; i<nsym; i\*+ )
  159.         if( compar(s, sym[i]\*.id) > 0 )
  160.             return(i);
  161.     return(-1);
  162. }
  163.  
  164. compar(s1,s2)        /\**  return 1 if s1\*=s2, 0 otherwise \**/
  165.    char \**s1, \**s2; {
  166.     while( \**s1\*+ \*= \**s2 )
  167.         if( \**s2\*+ \*= '\\0' )
  168.             return(1);
  169.     return(0);
  170. }
  171. .E2
  172. The declaration of the structure in 
  173. .UL lookup
  174. isn't needed if the external definition precedes its use in the same source file,
  175. as we shall see in a moment.
  176. .PP
  177. Now what if we want to use pointers?
  178. .E1
  179. struct  symtag {
  180.     char    id[10];
  181.     int    line;
  182.     char    type;
  183.     int    usage;
  184. } sym[100], \**psym;
  185.  
  186.     psym = &sym[0];    /\** or p = sym; \**/
  187. .E2
  188. This makes
  189. .UL psym
  190. a pointer to our kind of structure
  191. (the symbol table),
  192. then initializes it to point to the first element of
  193. .UL sym\*.
  194. .PP
  195. Notice that we added something after the word
  196. .UL struct:
  197. a ``tag'' called 
  198. .UL symtag\*.
  199. This puts a name on our structure definition so we can
  200. refer to it later without repeating the definition.
  201. It's not necessary but useful.
  202. In fact we could have said
  203. .E1
  204. struct    symtag {
  205.     \*.\*.\*. structure definition
  206. };
  207. .E2
  208. which wouldn't have assigned any storage at all,
  209. and then said
  210. .E1
  211. struct    symtag    sym[100];
  212. struct    symtag    \**psym;
  213. .E2
  214. which would define the array and the pointer.
  215. This could be condensed further, to
  216. .E1
  217. struct    symtag    sym[100], \**psym;
  218. .E2
  219. .PP
  220. The way we actually refer to an member of a structure by a pointer
  221. is like this:
  222. .E1
  223.     ptr -> structure\(hymember
  224. .E2
  225. The symbol `\(mi>'
  226. means we're pointing at a member of a structure;
  227. `\(mi>' is only used in that context.
  228. .UL ptr
  229. is a pointer to the (base of) a structure
  230. that contains the structure member.
  231. The expression
  232. .UL "ptr\(mi>structure\(hymember"
  233. refers to the indicated member of the pointed-to structure.
  234. Thus we have constructions like:
  235. .E1
  236. psym->type = 1;
  237. psym->id[0] = 'a';
  238. .E2
  239. and so on.
  240. .PP
  241. For more complicated pointer expressions,
  242. it's wise to use parentheses to make it clear
  243. who goes with what.
  244. For example,
  245. .E1
  246. struct { int x, \**y; } \**p;
  247. p->x\*+    increments x
  248. \*+p->x    so does this!
  249. (\*+p)->x    increments p before getting x
  250. \**p->y\*+    uses y as a pointer, then increments it
  251. \**(p->y)\*+    so does this
  252. \**(p\*+)->y    uses y as a pointer, then increments p
  253. .E2
  254. .tr |.
  255. The way to remember these is that
  256. .UL \(mi>,
  257. .UL |
  258. (dot),
  259. .UL "( )"
  260. and
  261. .UL "[ ]"
  262. bind very tightly.
  263. An expression involving one of these is treated as a unit.
  264. .tr ||
  265. .UL p\(mi>x,
  266. .UL a[i],
  267. .UL y\*.x
  268. and
  269. .UL f(b)
  270. are names
  271. exactly as
  272. .UL abc
  273. is.
  274. .PP
  275. If 
  276. .UL p
  277. is a pointer to a structure,
  278. any arithmetic on
  279. .UL p
  280. takes into account the acutal size of the structure.
  281. For instance,
  282. .UL p\*+
  283. increments
  284. .UL p
  285. by the correct amount to get the next element of the array of structures.
  286. But don't assume that the size of a structure is the sum
  287. of the sizes of its members _
  288. because of alignments of different sized objects,
  289. there may be ``holes'' in a structure.
  290. .PP
  291. Enough theory. Here is the lookup example, this time with pointers.
  292. .E1
  293. struct symtag {
  294.     char    id[10];
  295.     int    line;
  296.     char    type;
  297.     int    usage;
  298. } sym[100];
  299. .SP
  300. main( ) {
  301.     struct symtag \**lookup( );
  302.     struct symtag \**psym;
  303.     \*.\*.\*.
  304.     if( (psym = lookup(newname)) )    /\** non-zero pointer \**/
  305.         psym -> usage\*+;        /\** means already there \**/
  306.     else
  307.         install(newname, newline, newtype);
  308.     \*.\*.\*.
  309. }
  310. .SP
  311. struct symtag \**lookup(s)
  312.    char \**s; {
  313.     struct symtag \**p;
  314.     for( p=sym; p < &sym[nsym]; p\*+ )
  315.         if( compar(s, p->id) > 0)
  316.             return(p);
  317.     return(0);
  318. }
  319. .E2
  320. The function
  321. .UL compar
  322. doesn't change:
  323. .UL `p\(mi>id'
  324. refers to
  325. a string.
  326. .PP
  327. In
  328. .UL main
  329. we test the pointer returned by
  330. .UL lookup
  331. against zero,
  332. relying on the fact that a pointer is by definition never zero
  333. when it really points at something.
  334. The other pointer manipulations are trivial.
  335. .PP
  336. The only complexity is the set of lines like
  337. .E1
  338. struct symtag \**lookup( );
  339. .E2
  340. This brings us to
  341. an area that we will
  342. treat only hurriedly _ the question of function types.
  343. So far, all of our functions have returned integers
  344. (or characters, which are much the same).
  345. What do we do when the function returns something else,
  346. like a pointer to a structure?
  347. The rule is that
  348. any function that doesn't return an
  349. .UL int
  350. has to say explicitly what it does return.
  351. The type information goes before the function name
  352. (which can make the name hard to see).
  353. Examples:
  354. .E1
  355. char f(a)
  356.    int a; {
  357.     \*.\*.\*.
  358. }
  359.  
  360. int \**g( ) { \*.\*.\*. }
  361.  
  362. struct symtag \**lookup(s) char \**s; { \*.\*.\*. }
  363. .E2
  364. The function
  365. .UL f
  366. returns a character,
  367. .UL g
  368. returns a pointer to an integer,
  369. and
  370. .UL lookup
  371. returns a pointer to a structure that looks like
  372. .UL symtag\*.
  373. And if we're going to use one of these functions,
  374. we have to make a declaration
  375. where we use it,
  376. as we did in
  377. .UL main
  378. above.
  379. .PP
  380. Notice th parallelism between the declarations
  381. .E1
  382.     struct symtag \**lookup( );
  383.     struct symtag \**psym;
  384. .E2
  385. In effect, this says that
  386. .UL lookup(~)
  387. and
  388. .UL psym
  389. are both used the same way _
  390. as a pointer to a strcture _
  391. even though one is a variable and the other is a function.
  392.