📄 c6
字号:
.ul16. Examples..etThese examples are intended to illustratesome typical C constructions as well asa serviceable style of writing C programs..ms16.1 Inner product.etThis function returns the inner product ofits array arguments..sp .7.nf.bG double inner^(^v1, v2, n^)^ double v1^[^^]^, v2^[^^]^; { double sum^; int i^; sum = 0.0^; for ^(^i=0^; i<n^; i\fR++\fG^)^ sum \fR=+\fG v1^[^i^] \** v2^[^i^]^; return^(^sum^)^; }.fi.eG.sp .7The following version is somewhat more efficient,but perhaps a little less clear.It uses the facts that parameter arrays arereally pointers, and that all parameters are passedby value..sp .7.nf.bG double inner^(^v1, v2, n^)^ double \**v1, \**v2^; { double sum^; sum = 0.0^; while^(^n\fR\fR\(mi\(mi\fG\fG^)^ sum \fR=+\fG \**v1\fR++\fG \** \**v2\fR++\fG^; return^(^sum^)^; }.fi.eG.sp .7The declarations for the parameters are really exactlythe same as in the last example.In the first case array declarations ``^[^^^]^'' were givento emphasize that the parameters would be referredto as arrays; in the second, pointer declarationswere given because the indirection operator and++ were used..ms16.2 Tree and character processing.etHere is a complete C program^(^courtesy of R. Haight^)^ which reads a documentand produces an alphabetized list of wordsfound therein together withthe number of occurrences of each word.The method keeps a binary tree of wordssuch that the left descendant tree foreach word has all the words lexicographically smaller thanthe given word,and the right descendant has all the largerwords.Both the insertion and the printing routineare recursive..pgThe program calls the library routines \fIgetchar\fR topick up charactersand \fIexit\fR to terminate execution.\fIPrintf\fR is called to printthe results according to a formatstring.A version of\fIprintf\fR is given below ^(^\(sc16.3^)^..pgBecause all the external definitions fordata are given at the top, no \fGextern\fRdeclarations are necessary within the functions.To stay within the rules, a type declarationis given for each non-integer functionwhen the function is used beforeit is defined.However, since all suchfunctions return pointers which aresimply assigned to other pointers,no actual harm would result fromleaving out the declarations; thesupposedly \fGint\fR function values would be assignedwithout error or complaint..sp .7.nf.in .5i.bG.ta .5i 1i 3i# define nwords 100 /\** number of different words \**/# define wsize 20 /\** max chars per word \**/struct tnode { /\** the basic structure \**/ char tword^[^wsize^]^; int count^; struct tnode \**left^; struct tnode \**right^;}^;.sp .7struct tnode space^[^nwords^]^; /\** the words themselves \**/int nnodes nwords^; /\** number of remaining slots \**/struct tnode \**spacep space^; /\** next available slot \**/struct tnode \**freep^; /\** free list \**//\** \** The main routine reads words until end-of-file \^(^\(aa\\0\(aa returned from "getchar"^)^ \** "tree" is called to sort each word into the tree. \**/.ta .5i 1i 1.5i 2i 2.5i 3imain^(^^)^{ struct tnode \**top, \**tree^(^^)^; char c, word^[^wsize^]^; int i^;.sp .5 i = top = 0^; while ^(^c=getchar^(^^)^^)^ if ^(^\(aaa\(aa<=c && c<=\(aaz\(aa \(or\(or \(aaA\(aa<=c && c <=\(aaZ\(aa^)^ { if ^(^i<wsize\(mi1^)^ word^[^i\fR++\fG^]^ = c^; } else if ^(^i^)^ { word^[^i\fR++\fG^]^ = \(aa\\0\(aa^; top = tree^(^top, word^)^; i = 0^; } tprint^(^top^)^;}/\** \** The central routine. If the subtree pointer is null, \allocate a new node for it. \** If the new word and the node\(aas word are the same, increase \the node\(aas count. \** Otherwise, recursively sort the word into the left or right subtree according \** as the argument word is less or greater \than the node\(aas word. \**/struct tnode \**tree^(^p, word^)^struct tnode \**p^;char word^[^^]^;{ struct tnode \**alloc^(^^)^; int cond^;.sp .5 /\** Is pointer null? \**/ if ^(^p\fR==\fG0^)^ { p = alloc^(^^)^; copy^(^word, p\(mi>tword^)^; 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 0To illustrate a slightly different technique ofhandling the same problem, we will repeatfragments of this example with the tree nodestreated explicitly as members of an array.The fundamental change is todeal with the subscriptof the array member underdiscussion, 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 .7and \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 .7The \fIfree\fR stuff has disappeared becauseif we deal with exclusively withsubscripts some sort of map hasto be kept, which is too much trouble..pgNow the \fItree\fR routine returnsa 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 .7The other routines are changed similarly.It must be pointed out thatthis version is noticeablyless efficient than the first becauseof the multiplications whichmust be doneto compute an offset in \fIspace\fRcorresponding to the subscripts..pgThe observation that subscripts^(^like ``a^[^i^]^''^)^ are less efficientthan pointer indirection ^(^like ``\**ap''^)^holds true independently of whether or notstructures are involved.There are of course many situations where subscriptsare indispensable, and others where the lossin efficiency is worth a gain in clarity..ms16.3 Formatted output.etHere is a simplified version of the \fIprintf\fR routine, which isavailable in the C library.It accepts a string ^(^character array^)^as first argument, and prints subsequent argumentsaccording to specifications contained inthis format string.Most characters in the string are simplycopied to the output; two-character sequences beginningwith ``%'' specify that the next argumentshould 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.fiThe actual parameters for each functioncall are laid out contiguously inincreasing storage locations;therefore, a function with a variable numberof argumentsmay take the address of ^(^say^)^ its first argument,and access the remaining arguments by useof subscripting ^(^regarding the argumentsas an array^)^or by indirection combined withpointer incrementation..pgIf in such a situationthe arguments have mixed types, or if in generalone wishes to insist that an lvalue shouldbe treated as having a given type, then\fGstruct\fR declarations like those illustrated belowwill 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 argumentsare widened respectively to \fGint\fR and \fGdouble\fR,so there are effectively only two sizes of argumentsto deal with.\fIPrintf\fR calls the library routines\fIputchar\fR to write out single charactersand \fIftoa\fR to dispose offloating-point numbers..sp .7.in .5i.bG.nfprintf^(^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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -