.ul 16. Examples. .et These examples are intended to illustrate some typical C constructions as well as a serviceable style of writing C programs. .ms 16.1 Inner product .et This function returns the inner product of its array arguments. .sp .7 .nf .bG double inner^(^v1, v2, n^)^ double v1^[^^]^, v2^[^^]^; { double sum^; int i^; sum = 0.0^; for ^(^i=0^; itword^)^; p\(mi>count = 1^; p\(mi>right = p\(mi>left = 0^; return^(^p^)^; } /\** Is word repeated? \**/ if ^(^^(^cond=compar^(^p\(mi>tword, word^)^^)^ \fR==\fG 0^)^ { p\(mi>count\fR++\fG^; return^(^p^)^; } /\** Sort into left or right \**/ if ^(^cond<0^)^ p\(mi>left = tree^(^p\(mi>left, word^)^; else p\(mi>right = tree^(^p\(mi>right, word^)^; return^(^p^)^; } /\** \** Print the tree by printing the left subtree, the \ given node, and the right subtree. \**/ tprint^(^p^)^ struct tnode \**p^; { while ^(^p^)^ { tprint^(^p\(mi>left^)^; printf^(^"%d: %s\\n", p\(mi>count, p\(mi>tword^)^; p = p\(mi>right^; } } /\** \** String comparison: return number ^(^>, =, <^)^ 0 \** according as s1 ^(^>, =, <^)^ s2. \**/ compar^(^s1, s2^)^ char \**s1, \**s2^; { int c1, c2^; .sp .5 while^(^^(^c1 = \**s1\fR++\fG^)^ \fR==\fG ^(^c2 = \**s2\fR++\fG^)^^)^ if ^(^c1\fR==\fG\(aa\\0\(aa^)^ return^(^0^)^; return^(^c2\(mic1^)^; } /\** \** String copy: copy s1 into s2 until the null \** character appears. \**/ copy^(^s1, s2^)^ char \**s1, \**s2^; { while^(^\**s2\fR++\fG = \**s1\fR++\fG^)^; } /\** \** Node allocation: return pointer to a free node. \** Bomb out when all are gone. Just for fun, there \** is a mechanism for using nodes that have been \** freed, even though no one here calls "free." \**/ struct tnode \**alloc^(^^)^ { struct tnode \**t^; .sp .5 if ^(^freep^)^ { t = freep^; freep = freep\(mi>left^; return^(^t^)^; } if ^(^\fR\(mi\(mi\fGnnodes < 0^)^ { printf^(^"Out of space\\n"^)^; exit^(^^)^; } return^(^spacep\fR++\fG^)^; } /\** \** The uncalled routine which puts a node on the free list. \**/ free^(^p^)^ struct tnode \**p^; { p\(mi>left = freep^; freep = p^; } .sp .7 .fi .eG .in 0 To illustrate a slightly different technique of handling the same problem, we will repeat fragments of this example with the tree nodes treated explicitly as members of an array. The fundamental change is to deal with the subscript of the array member under discussion, instead of a pointer to it. The \fGstruct\fR declaration becomes .sp .7 .nf .bG struct tnode { char tword^[^wsize^]^; int count; int left; int right; }; .fi .eG .sp .7 and \fIalloc\fR becomes .sp .7 .nf .bG alloc^(^^)^ { int t; .sp .5 t = \fR\(mi\(mi\fGnnodes; if ^(^t<=0^)^ { printf^(^"Out of space\\n"^)^; exit^(^^)^; } return^(^t^)^; } .fi .eG .sp .7 The \fIfree\fR stuff has disappeared because if we deal with exclusively with subscripts some sort of map has to be kept, which is too much trouble. .pg Now the \fItree\fR routine returns a subscript also, and it becomes: .sp .7 .nf .bG tree^(^p, word^)^ char word^[^^]^; { int cond; .sp .5 if ^(^p\fR==\fG0^)^ { p = alloc^(^^)^; copy^(^word, space^[^p^]^.tword^)^; space^[^p^]^.count = 1; space^[^p^]^.right = space^[^p^]^.left = 0; return^(^p^)^; } if ^(^^(^cond=compar^(^space^[^p^]^.tword, word^)^^)^ \fR==\fG 0^)^ { space^[^p^]^.count\fR++\fG; return^(^p^)^; } if ^(^cond<0^)^ space^[^p^]^.left = tree^(^space^[^p^]^.left, word^)^; else space^[^p^]^.right = tree^(^space^[^p^]^.right, word^)^; return^(^p^)^; } .fi .eG .sp .7 The other routines are changed similarly. It must be pointed out that this version is noticeably less efficient than the first because of the multiplications which must be done to compute an offset in \fIspace\fR corresponding to the subscripts. .pg The observation that subscripts ^(^like ``a^[^i^]^''^)^ are less efficient than pointer indirection ^(^like ``\**ap''^)^ holds true independently of whether or not structures are involved. There are of course many situations where subscripts are indispensable, and others where the loss in efficiency is worth a gain in clarity. .ms 16.3 Formatted output .et Here is a simplified version of the \fIprintf\fR routine, which is available in the C library. It accepts a string ^(^character array^)^ as first argument, and prints subsequent arguments according to specifications contained in this format string. Most characters in the string are simply copied to the output; two-character sequences beginning with ``%'' specify that the next argument should be printed in a style as follows: .sp .7 .nf %d decimal number %o octal number %c \s8ASCII\s10 character, or 2 characters if \ upper character is not null %s string ^(^null-terminated array of characters^) %f floating-point number .sp .7 .fi The actual parameters for each function call are laid out contiguously in increasing storage locations; therefore, a function with a variable number of arguments may take the address of ^(^say^)^ its first argument, and access the remaining arguments by use of subscripting ^(^regarding the arguments as an array^)^ or by indirection combined with pointer incrementation. .pg If in such a situation the arguments have mixed types, or if in general one wishes to insist that an lvalue should be treated as having a given type, then \fGstruct\fR declarations like those illustrated below will be useful. It should be evident, though, that such techniques are implementation dependent. .pg \fIPrintf\fR depends as well on the fact that \fGchar\fR and \fGfloat\fR arguments are widened respectively to \fGint\fR and \fGdouble\fR, so there are effectively only two sizes of arguments to deal with. \fIPrintf\fR calls the library routines \fIputchar\fR to write out single characters and \fIftoa\fR to dispose of floating-point numbers. .sp .7 .in .5i .bG .nf printf^(^fmt, args^)^ char fmt^[^^]^; { char \**s^; struct { char \**\**charpp^; }; struct { double \**doublep^; }; int \**ap, x, c^; .sp .5 ap = &args^; /\** argument pointer \**/ for ( ; ; ) { while^(^^(^c = \**fmt\fR++\fG^)^ != \(aa%\(aa^)^ { if^(^c \fR==\fG \(aa\\0\(aa^)^ return^; putchar^(^c^)^; } switch ^(^c = \**fmt\fR++\fG^)^ { /\** decimal \**/ case \(aad^\(aa: x = \**ap\fR++\fG^; if^(^x < 0^)^ { x = \(mix^; if^(^x<0^)^ { /\** is \(mi infinity \**/ printf^(^"\(mi32768"^)^; continue^; } putchar^(^\(aa\(mi\(aa^)^; } printd^(^x^)^; continue^; /\** octal \**/ case \(aao\(aa: printo^(^\**ap\fR++\fG^)^; continue^; /\** float, double \**/ case ^^\(aaf^\(aa: /\** let ftoa do the real work \**/ ftoa^(^\**ap.doublep\fR++\fG^)^; continue^; /\** character \**/ case \(aac\(aa: putchar^(^\**ap\fR++\fG^)^; continue^; /\** string \**/ case \(aas\(aa: s = \**ap.charpp\fR++\fG^; while^(^c = \**s\fR++\fG^)^ putchar^(^c^)^; continue^; } putchar^(^c^)^; } } /\** \** Print n in decimal^; n must be non-negative \**/ printd^(^n^)^ { int a^; if ^(^a=n/10^)^ printd^(^a^)^; putchar^(^n%10 + \(aa0\(aa^)^; } /\** \** Print n in octal, with exactly 1 leading 0 \**/ printo^(^n^)^ { if ^(^n^)^ printo^(^^(^n>>3^)^&017777^)^; putchar^(^^(^n&07^)^+\(aa0\(aa^)^; } .br .fi .eG .in 0