UNIVERZA EDVARDA KARDELJA V LJUBLJANI FAKULTETA ZA ELEKTROTEHNIKO Sasa DIVJAK PROGRAMIRANJE V JEZIKU C Delovno gradivo LJUBUANA 1986 UNIVERZA EDVARDA KARDELJA V LJUBLJANI FAKULTETA ZA ELEKTROTEHNIKO Sasa DIVJAK PROGRAMIRANJE V JEZIKU C Delovno gradivo LJUBLJANA 1986 Z&lOCL pj 20 -02-M* »_ (oO%. Dr. SaSa Divjak, dipl. ing., izredni profesor na Fakulteti za elektrotehniko v Ljubljani PROGRAM IRANJE V 3EZIKU C Delovno gradivo Izdala in zaloiila Fakulteta za elektrotehniko v Ljubljani \s Pripravlja Komisija za tisk — urednik Boiidar Magajn Tlsk »F. Tori«, Ljubljana Naklada 100 izvodov PROGRAMMING IN C \ H FIND QUIT r A 3.1.1. An Example C Program • The file hello.c: mainO printf("Hello world!"); • An example run: Hello world! Vs. r 3.1.1.3. About C Programs • Function definitions start with an interface section describing how they must be called. 9 The main function can have a very simple interface, as it is automatically called by the system when the program begins, and can ignore any program arguments. 0 After the interface section goes the implementation section, or outer block of the funotion. • Blocks are enclosed in curly braces, and can enclose local declarations followed by statements. 3.1.2.1. Using Character Constants • The file CharConsts.c: muin() I putchar('a'); putchar(1b')j putohar(' putchar('01); putchar(11'); putcharC putohar(1 I 1); putchar('G1); putcharC' '); putohar(1\V): ^utohar('\'1); putchar('\n'); The output; r ab 01 10 V / C-3-9 3.1.2.2. About Character Constants » Characters can be represented by their numeric character codes. i • For clarity and portability, another notation is normally used, involving the single quote (') and backslash (\) characters: j # To indicate their character codes, ordinary printable characters are simply en- • closed between single quotes, for example: 'a1 'b' 'c' 'O' '1' '2‘ i 1 + 1 1 = 1 i 0 Nonprintable character codes can be repre- sented by using a backslash character, \, followed by one to three octal digits, e.g.: •\0• for an ASCII NULL '\71 for an ASCII BELL w to represent a newline character Nr' to represent a carriage return \t' to represent a tab unambiguously § Finally, since backslash (\) and single quote (') have special meanings, they are represented as follows: ’\\• represents a single backslash •V1 represents a single quote J 3.1.2.3. Special Character Constants • For additional clarity and portability, C provides: J \ 3.1.2.4. Using Character Variables $ The file chars.c: main() ( char digit, special; lnt letter, whoKnows; digit = '8'; special = letter = ’ d • ; whoKnows = getcharO; putchar(digit)putchar(special); putchar(letter)j putchar(whoKnows); putchar(•\n'); ) An example run: q 8$dq ) C-3-12 3.1.2.5. About Character Variables • Since characters are represented by (implementation dependent) character codes, they can be represented by the same variables used to hold integer numbers. 9 C has several datatypes to represent in- tegers, depending on how large the numbers are expected to be. 0 The datatype char may be used to hold characters which will occupy only one byte, at least the values 0 through 127. 0 The datatype int should be used if an ex- tended character set with more than 128 codes is being used. 0 jnt should also be used if characters are being interspersed with special codes for end of file, etc., which do not use any of the 128 codes reserved for normal characters. 3.1.3.1. Integer Constants & Output The file: IntConst3.c mainO printf("td is the same as %d\n", 010, 8); printf("Jd is the same as Id\n", 0x10, 16); printf("Octal: lo, Decimal: %d, Hex: Jx\n", 10, 10, 10); printfO'Oct&l: to, Decimal: td, Hex: %x\n", 010, 010, 010); printf("Octal: to, Decimal: %d, Hex: *x\n", .0x10, 0x10, 0x10); } printf("%ld is a long integer\n", 123'I56789); printf("Jld Just thought it waaAn", 123L); 3.1.3.2. About Integer Constants # Integers may be represented in octal (base 8),-decimal (base 10), hexadecimal (base 16) and as character codes. • Octal constants are represented by the digits 0-7, and must have a leading zero: 010 01772*15 0177 9 Decimal con3tan.ts may be represented by the digits 0-9, but must not begin with an initial zero: 10 ‘15 100 a Hexadecimal constants may be represented by the digits 0-9, and a-f. They must begin with an initial Ox or OX: 0x10 OxffaO Oxff 4-H C-3-17 r 3.1.3.1. Integer Constants 4 Output The Output: 8 is the same as 8 16 is the same as 16 Octal: 12, Decimal: 10, Hex: a Octal: 10, Decimal: 8, Hex: 8 Octal: 20, Decimal: 16, Hex: 10 123*156789 is a long integer 123 just thought it was. .. \ 3.1.3.2. About Integer Constants Negative integer constants begin with a minus sign: -010 -123 -Oxff Integer _constants which need to be passed to functions expecting long integers can be followed by an 1 or L for long: 1000L OxabcL Integer constants which are too large to be-single precision will automatically be represented as long integers, making the 1 or L optional: 1OOOOOOOL or Just 10000000 OxabcdefL or just Oxabcdef 3.1.3.'I. About Integer Variables Integer values can be represented with or without sign, and may be of various im pleinentation dependent sizes. char will provide one byte of storage, which may or may not include a sign bit. Only values 0..127 arc safe. lnt will provide some efficient but unspecified amount of storage, usually 16 or 32 bits. int may be qualified with the words short, long and unsigned. A short lnt provides at least 16 bits of precision. A lonn lnt provides at least 32 bits of precision. V AS C-3-20 3.1.3-1!- About Integer Variables The unsigned qualifier makes available all the bits in an integer variable for rep resenting a non-negative value. short, long and unsigned may be used a3 ab breviations for short int, long int and unsigned int. 3.1.*1.1. Floating Point Constants Floating point constants are always given in decimal fractional or scientific notation. A decimal point is used to indicate the start of the fraction part. The letter e or E is used to Indicate the start of the exponent part. 123. *15 123 . *156e7 0,12e-3 All floating point constants are represented with double precision. 3.1*1.2. Floating Point Variables C provides two sizes of floating point numbers, float and double, with implementation dependent range -and precision. float represents the available single precision floating point numbers, usually with at least 32 bits. double represents the available double precision floating point numbers, usually with at least 6*1 bits. Despite the ability to store single precision floating point values, all floating point calculations are performed using double precision arithmetic. C-3-2'l r 3.1.5.1. Numerical Input/Output: The file numbers.c: main() I int nefcWorth, numKids; Float weight, height; netWorth = 1H; weight = 1‘l.007e2; /* next line could be deleted w/o effect */ numKids = 10; height = 0.1; /* to be trashed */ printf("Please enter a decimal integer printfC'and a floating point number:\n"); scanfC'Jd Jf", inumKids, iheight); Ifati ft* I a d dreii . printf( “worth is %d , chidren, %d, ", netWorlh, najnWds)) printf("weight = Jf\nand height, Jf.11, weight, height); ) 3.1.5.2. Using Arithmetic Operators: The File "NumOps.c": \ mainO I int inti, int2; float flt1, flt2; inti = 2 + 3 - 15; /* result is negative */ int2 = -inti; /* result is positive */ inti = 2+(3*5); inti = 2+3*5; int2 = (2+3)*5; inti = int2 = 6; inti = 123 /• 10; int2 = 123 % 10; flt1 = 123 / 10; flt2 = inti; int2 = fltlj /* result is 17 */ /* result is 17 */ /* result is 25 */ /» = associates */ /* right to left */ /* yields quotient 12 */ /* yields remainder 3 */ /» yields 12.3 */ /* integer to float */ /* conversion Implied */ /* result is truncated */ I J 3.1.5.3. Arithmetic Operators Integer division yields only the quotient, the remainder can be obtained with the operator J, pronounced "mod11: 1234.0 / 100 is 12.3*1 1231* / 100 is 12 123*1 I 100 is 3*t The operators », / and t are of higher precedence than + and —, but parentheses can be used to clarify or alter this pro cedence, thus: 2+3*5 is the same as 2+(3*5)t not (2+3)*5 V_±lL J C-3-30 r An Example of a C Function With One Input The file proc.c: oalnO { decode('a'); decode('O'); » _ :n{crfrce (*« decode(c) char c; } ( 7 >= < <= • Logical expressions may be combined into conjunctions and disjunctions: &4 (logical and) I| (logical or) 3.1.8.3. Precedence of the logical operators • Precedence can always be clarified or altered with parentheses, for example, these pairs have the same meaning: a > b == c > d . (a > b) == ( C>«; a M-b || c (a &J/b) || c a || b bXt o " a II (b Mro) ab (a< b) |l ( (c == 4) &JKa > b) ) 3.18.1!. A Test Expression Example File test.c: mainO I int a, b, c, d, same; a = 1; b = 2; c = 3: d a i|; same = (a < b) :: (c < d); if (a < b) printf("Jd is les3 than >d\n", a, b); If (same) printfCJd and Jd are ordered the 3ame\n", c, d); ) Output: 1 is less than 2 3 and 4 are ordered the same V A - AQ C-3-'l6 3.2.1 .2. Accessing Standard I/O Library Definitions_______________________ • Accompanying the functions in the standard I/O library are a set of definitions, which can be included into your file with the line: i/include • This line causes the C preprocessor to fetch the file stdio.h from a special sys tein area (/usr/include on UNIX) , and include its contents at this point in the current file. • The C compiler proper never sees any C preprocessor requests; it just sees normal C code. 3.2.1.1!. Variations with printf The file printf.c: main() I printf("char Jc, decimal 5d, octal Jo, hex Jx\n", 'a', 'a', 'a', 'a'); printf("float Jf, string *s", 1U.3, "hello")j } Output of the program: char a, decimal 97 > ootal 1H1, hex 61 float 11).300000, string hello i J C-3-57 - Para'aster Values are Copies Function parameters are actually local variables which start out with copies of the values handed in. Thus in the following prograa, file "varCcpy.c": aain() I char c; c = 'a' ; func(c); putchar(c); J func(c) char c; ( putchar(c); c * 'b* ; putchar(c); } The output is: aba I y C-3-59 3.2.2.1. About the Standard I/O Library t The standard I/O library provides a number of useful functions for doing I/O from C programs. I The standard I/O library is not part of the C language proper, but should be present in any C program development environment. • When you compile a C program, the standard library is automatically searched for any functions not defined by the files specified as arguments to the cc command. A - 42. r 3.2.2.2. Passing Variable Addresses • If a function is to be able to change the values of variables, it must be passed the address of those variables. • The prefix operator & takes the address of a variable. The file Clearlnt.c: mainO { int i; i = 123; Clearlnt( &i ); printfC'i = ld\n", i); } Clearlnt(pi) pt L int * pi; { printfC"Location = Jd, Old value = Jd\n", pi, *pi); •pi = 0; -------J------------------------------------------------- 3.2.2.3. Using Multiple Function Outputs Part of the file swap.c: mainO { char c1, c2; c1 = 'a'; c2 = 'b'; printfC'a = Jo, b = Jc\n", c1, c2); swap(ic1, &c2); printfC'cl = *c, c2 = Jc\n", ^ cl, c2); 3.2.2.1!. Using Variable Addresses The rest of the file swap.c: swap(p1, p2) char «p1, *p2; char temp; ^ I temp = * pi; *p1 = *p2; *p2 = temp; ] In order to use an address of, or pointer to, a variable, one must store it in a pointer variable. Pointer variables are declared by indicating what kind of value they may point to. A - 43____________________________________________________________________________________________________________ ) 3.2.2.1I. Using Variable Addresses e In the definition of a variable, asterisks indicate that the variable in question is a pointer to an object of the given datatype. No runtime operation is implied. • As part of a statement or an expression, the asterisk prefix operator, (*), refers to the data being pointed to by the pointer variable. At runtime, this corresponds to an extra memory fetch. 3.2.3.1. Reading Single Characters A Characters may be read from the standard input by the function getchar. The file getchar.c: mainO I char c; c = getcharO j char*/ getcharO ; . */ */ */ /* save the 1st /* chuck the 2nd putcharC getcharO );/* print the 3rd putchar(c); /* print the 1st } r~ 3.2.3-2. Formatted Input • The functi'on scanf reads input according to the formats specified by its format string. • scanf understands the same format codes that printf does. • Whitespace characters (spaces, newlines and tabs) inbetween format codes in the format • string will match any number of whitespace characters in the input stream. • Any extra nonwhitespace characters in the format string are expected to literally match characters in the input-stream. • scanf will keep reading until it fills all the values called for, or until the input stream deviates from the form specified by the format string. .<* V A-AH J C-3-67 3.2.3-2. Formatted Input scanf returns as its function value the number of items successfully read, or the special value EOF (defined in ) if it reaches the end of the input stream be fore it has finished. k = W("V.d 7.d *, il , Aj); if (k <12 ) complain ••• usually ... EOF = -1 Variations or scanf The file scanf.c: raainO { char c; Int i, J; 7Toat f; printf("Please type a character, in integer"); printf(" and a floating point number :\r."); scanf(" Xc Xd XT", 4c, 41, 4f); printf("You typed Xc, Xd and Xf\n prlntf("Please type I. f); top 10 teams'':\n"); i s scanft" top Xd teams", 4J); printfC'I read Xd value(s), Including the number Xd.\n", i, J>; An example run: Please type a character, an lntsger and a floating point number: x 123 3-1*159 You typed x, 123 and 3-1|*1590 Please type "top 10 teams'': top 10 teams I read 1 value(s), Including the number 10. C-3-69 A - 45 3.3.1.1. Printing a Numeric Digit r v_ Part of the file Putlnt.c: PutDigit( d ) char d; /* assertion: d is in {0..9) */ putchar( d + 101 ); 3.3.1.1. Printing a Numeric Digit Part of the file Putlnt.c: PutPosInt( i ) • int i; T*-assertion: i >= 0 */ ( if (1 > 0) ~( PutPosInt( i/10 ); PutDigitC ij 10 ); } } Jl. 1.1.*1. Using Static Variables J Initialization clauses on variable definitions apply only when variable is created. The file rand.c: int rand() T static Int seed = 31415; seed := (seed + 7227) t 23'I5; return seed; T Only function rand can see the variable seed. Without the keyword 3tatic, rand would always return (31115 + 7227) J 2345. ■ V A - AG C-M-7 4.1.1.3* The Scope of Static Variables Externally declared static variables: are visible through the rest of the file (except within blocks which redeclare the same name) do not require keyword static Internally declared variables (static or otherwise): are visible within their block (except within nested blocks which redeclare the same name) require the keyword static * -fooC ) int count moun \ '1.1.2.1. Allocation of Automatic Storage New storage is automatically allocated when: . a function is called a block is entered The same storage is automatically reclaimed when: the function returns control leaves the block Function calls & returns and block entry & exits are always nested, permitting a simple storage management scheme. ,1.2.3.' Declaring Automatic Variables • Function parameters are automatic variables: enmpii: Pred (x,y) int x,y; allocated 4 initialized at function • call visible throughout the function body (except where name reused in nested block) • Internal variables are automatic bv default: allocated at block entry initially contain a random value (unless initialization clause used) are visible throughout the block (except where name reused in nested block) V A- A7 J .21.1. Allocating Array Variables The file arrays.c: main() { char c, holdC'13, name[20]; int i, ages[100]; float max, scores[100]; e = ' X' • hold[0] '= 'U1; hold[2] = 'I' ; hold[1] = * N * hold[3] = c; printfC'Uhat's your name? "); scanfCIs", name); i = 10; agesCi] = i; agesCO] = 100; ages[99] = 0; max = 100.0; scores[0] = 0/inax; scores[1] = 1/max; scores[90] = 98/max; scores[99] = 99/max; printf("Well, Js, thata all!", name); 1 ; __________________________________________ 4.2.1.2. Ir.itialized Static Arrays File dates.c: int IsLeapYear(year) int year; return yearl<) 44 (yearl«00 i 1 JyearSlOO); long DayOfEpoch(year, month, day) int year, month, day; static int DayOffsetsU = I 0, 31. 59, 90, 120, 151 ; iTl7“?l2, 2«3, 273, 304, 33** ); long days; days * year*365 year/4 - year/100 year/400 ♦ Day0ffsets[month] ♦ day; if (month > 1 /* Feb •/ 44'IsLeapYear(year)) days**; return days; C-H-15 A - 48 4.2.2.1.' Declaring 4 Initializing Only statically allocated arrays can be initialized with an initialization clause. hmckci i screen is an array of 2*i arrays with 80 characters each. 0 1 char screen[2,l][80]; n lllJlllU LLL IiIXil is an array of *1 subarrays, each con-taining 4 integers. I'lXU is being initialized to an identity matrix. static int IW[][] = { { 1, 0, 0, 0 } , { 0, 1, 0, 0 }, I 0, 0, 1, 0 }0, 0, 0, 1 ) ); Array sizes are optional where initialization clauses make it apparent. Good practice suggests giving sizes explicitly if the size matters to the code accessing the data. «.2.3.1. Using Multidimensional Arrays The Tile 'dcmos/aultidia.c nain() I ) int src, dst; float amount, x[33[33; x[03l03 * 1; x[l3H3 = 1;x[23123 * 1; x[ 1 ][0] * 12; x[0]113 * 1 / xllHOl; X123C13 « 3; *1 *13123 « 1 / x[23H3j printf("Enter the source & destination ur.it"); printfCO = inches, 1 * feet, 2 * yards"); scanf("Xd Id", Asrc, 4dst); printf("Amount: "); scanf("Xf" , Aamour.t); printf("Result is If.", amount * > [src3ldst3>;• C- JJ- 1 9 4-43 <.2.«o. Arrays cf Unknown Size fc'does net check array index bounds, therefore: The number of elements cf an array merely being pointed to V* irrelevant: if ( size ) I v2[0] s v 1 [ 03 •» v2[ 0] ; /• modifies original caller's values •/ Vect^rAdd( Av1[1], &v2[1], size - 1 ); /• passes array slice •/ } Stylistically, the number of elements of an array parameter should appear if and only if the code is size dependent. Although the number of elements is irrelevant, the element size is needed to perform indexing operations, therefore: Dimensions of multidimensional arrays require all but the last array size. Il.2.l|.1. The Increment 4 Decrement Operators 8 The increment operator ++ increments an integer variable by 1: ++i is the same as i = i + 1 0 The decrement operator — decrements integers similarly. 8 Pre-increments and pre-decrements (applied in front) happen VectorAdd(vl, v2, size) int vU3, v2[ ], size; recursion • Post-increments plied behind) ha evaluation: i = 0; j = ++i + ++i i ==2, i evaluation posx-decrements (ap after expression /» i == 2, j == 0 »/ y / - 20 v_ r 4.2.11.3. Arrays Are Pointer Constants • Array identifiers refer to: the address of the array, i.e., the address of the first element of the array, therefore they are 3imply pointer constants • Pointer variables pointing into arrays can be stepped along sequential elements with increments & decrements. char name LZOJ / * Pc i pc = name i .Pc is ; U has the. same effect as nameM - 5 */ pc-t-* I t* now points to name CO */ /« name is a constant: , so. .. name « ••• is wrong M dtorachn W /-Z1 C-M-29 4.2.>1.7. Sharing Array Storage wain() { char BigBuf[l60]; char *cp; cp = DigBuf; cp = cp + GetLineC cp ); cp = cp + GetLineC cp ); ) Biasu^ E023 /it B&tier : Las ote^crf u/ >1.2.4.8. Arrays of Pointers raainO I char BigBuf[160]; char *lines[3]; rray of poio^ lines[0] = BigBuf; lines[1] = lines[0] + GetLineC BigBuf ); lines[2] = line3[1] + GetLineC lines[1] ); GetLineC lines[2] ); ^ putsC lines[2] ) puts( linesil] ) putsC lines[0] ) ) BigBuf )u!“'1P»ycl»~ln!?T ■ 1 1 - lines I— Note that lincs[2][5] is the 6th element of the 3rd line, just as if lines were a two dimensional array. W.WCS3* * ii possible bccau« C-Wane j ju«ran*s tesfinq from left jto ngW . j 10 c is denned before. "c!»eof J C-5-1'1 5.2.3*1• Exiting Loops Prematurely The break statement will prematurely break the inner.uost loop in which it Is enclosed. File UnCtrl.c: /• Untransiate Control Characters */ mainC) I Int c; whT 1 e ( (c s getcharO) Is EOF ) ) If ( C a 1 c s getcharO ; .If ( c >* ’«• ii c <* ) o * c - ’ S ’; else If ( C :: •?• ) c s tT77’; /• ASCII DEL •/ else IT ( a • • /• 5P •/ ) C a ^ ~r' else putchar( • *•); If ( c jj EOF ) break; putchar( c ); C-5-17 A - T-S r 5.2.3.2. Skipping to the Next Iteration The file NonUlank.c: /* Copy nonblank characters */ ma i n() I int c; I > */ continue; putchar( c ); Tcjd vJiU be con'pwss^d (wi#»at W«nb onj luu> j (jhTi"is juit an example . Could be bellfr 5.2.3-3- Cautions with break arid continue Ideally, the loop control structure should express the entire context or the evaluation of the statements in between. break destroys the "one entrance and one exit" principle of control constructs. Doth break and continue have a tendency to be overlooked by readers. Good practice is to use break and continue sparingly, and always with a comment calling attention to their use. 5.3-2.1. Spaghetti Code /* Untranslate Control Characters */ mainC) ( Int c; start: if ( (c = getcharO) == EOF ) goto end; TT ( c Is ) goto doit; c = getchar(); if ( c >= '6' U c <: 1 1 ) c = c - 101 ; else if ( 0 =s '?• ) c = '177' ; /* ASCII DEL */ else if ( c == ' ' /» SP */ ) c = else putchar(1“1); if ( c EOF ) goto end; doit: putchar( c ); goto start; V J- 26 G 6.1.1.1. Declaration & Use cf Structures The file: you.c: main() { struct "1----- char naael 20]; Tong SSN; float weight; } you; ^Structure. narr\e^ printf("Please type your first name, SSN A weight:#); scanfC'Xs Jld Jf", you.name, iycu.SSN, &ycu.weight); * i- 4 printf ("Name = 5s, SSN, = Sid, weight s'lfO, you.name, you.SSN, you .wei ght);} • •i/a W dress .because ihcit urr. \^r»ables „ (thi^ulrendy an ndd^T SSN... Social Security Mumner C-6-H 6.1.1.2. Use c f the (structure Frcm the file SayOlder.c: struct person -----------” I char name[20]; "int* age; float height, weight; 1; tft and “re variaWcs.’ of iypc ’structure, person. SiorQge. reservation for ei and rZ of ihii tyre roainO 1 struct person pi, p2; ____________________________ float ratio; printf("Enter first name, age, height & weight of 2 persons:0); CetPersonUpl); Get?erson(4p2); J_f (pi. age > p2. age) SayOlder(pi, p2); else If (p2.Bge > pi.age) 5ayCTder(p2, pi); else printf("ls is the same age as *s ", pi.name, p2.r.ame); Ar example run: Enter first name, age, height & weight cf 2 persons: John 32 6.2 182.5 Mary 33 5.8 142.0 Mary is older than John V. C-6-5 4-27 6.1.1.3. Passing Structures to Functions From the file SayOlder.c: Say01der(older, younger) ** ) 8ai -form: by Call Vjbola. sfrudure / 11 copied _________ ( } struct person older, younger; printf("%s is older than %s", older.name, younger.name); GetPersonCp) struct person *p; 1 scanf("%s Id jr %f", (* p).name, ft(*p).a|je, &( * p) .height, ?<(* p) .weight) ; - A ) (cl ollinlion 1° •he A 6.1.1.**. Efficiency i Abbreviations The file Say01dcr2.c: aalnQ ( struct person pi, p2; float ratio; printf("Enter first name, age, height \ weight of 2 persons:0); GetFerson(4p1); GetPerson(Ap2); j_f (pi. age > p2 .age) SayOlder(ipl, ip2); else If (p2.age > pi.age) SayOlder(4p2, &p1>; else \ printfCSs is the same age as 5s0, pi.name, p2.narae); ) » SayOlder(older, younger) struct person Bclder, #younger; ( srmtf'C* iv cU«u' than 7«s •, uUlts name / you«9«f-> name. }J ) CetPerson(p) struct person *p; 1 sear.fCts %d Xf If", p->rara*, \p->3ge, lp->height, 4p->weight); , ) I &«jno«• -> nw< «5 (yain4e-).nnm< ,b-t ii isclear. j C-5-7 A-28 o 6.1.1.5. Combining Structures with Arrays The file: eldest.c: main() [ Pclokr^ ^ |— struct person people[10], *p; p int i ; printf("Please input 10 person records, each with:0); pr intf(" first name, age, height ft weight :* ); for (i = 0; i < 10; i++) GetPerson(ipeople[i]); i p = &people[0]; for ( i = 1; i < 10; i++) if ( peopleti].age > p->age ) p = 4people[ i]; printf("!ts is the eldestO, p->name); ) G .1.1.5.0. Combining Structures with Rrrayc, A Butter solution */ main ( ) struct person »p, people Cto"]? •for (ij = people j peopU+ | ) beiterion (y), p= people for Ci= peopled i ^ people+i° . ?«.) If ( aije > p -> aga P - 1 > 6.1.1.6. Initializing Structures From the file: months.c: struct month J ); chnr "name; i n U numDays ; stajic struct month LeapFob = ("Feb", 29); static struct month Months[12] = ?11, ("|reb". 20), ("Mar", 31), L^' 30 .("Nay", 31), ("Jun", 30), nnU?„’ 31 ’ ["AuB". 3D, ("Sep", 30), ( Oct , 31), ("Nov", 30), ("Dec", 31) ); r*o\r\kr \"0 2.9 29 ~ST~l r~~T I is I ZED 'JUN" ’fcb' "two." •dec' \ 6.1.1.7. Limitations on Whole Structure Operation,-._____________________________ There are only three operations permissible on structures: (1) Taking the address of a structure, (2) Referencing one of the fields of a structure, and (3) Assigning (copying)’ a structure. In particular, this means that it is impossible to compare structures for equality or order with the relational operators of C. In older versions of C it is impossible to copy structures, or return them as the values of functions. In particular, this means the inability to assign structure values or pass a structure as the value of a function parameter. 6.2.2.1. Enployees and their managers (fit svjcJuh cm The file managers.c: ♦include struct employee 7 • u»uu f char •name, #title; j struct employee ‘manager; laura s I "Laura Henry", "President", NULL ), mike * I "Hike Ellis", "Chief Engineer", ilaura 1, rich = I "Rich Rocco", "Marketing Director", ilaura ), warren * I "Warren Smith", "Production Manager", &mike ); main() ShouChain( iwarren ); } ShowChain( e ) struct employee *e; 1 if ( e != NULL ) I \!/ Mi *>W pr intf("Is , IsO, e->n»me, e->title); ShowChair.( e->manager ); ) The output: Warren Smith, Production Manager Mike Ellis, Chief Engineer Laura Henry, President / \ ^ rv* N (fol*K *+* A - 30 6.2.2.2. Declaring & Initializing Linked Lists From the file Unix.c: struct charList —r char data; struct charList *next; C1 = ( ' X • , NULL } , C2 = I ' X 1 , &'C 1 ) , C3 = ( 'N' , 1C2 }, CM = ( •U', &C3 }, *Unix = &CM; ci nn IdaKl *—4 I date, I | 5.2.2.3. Traversing Linked Lists From the file Unix.c: S' xO, Unlx->data, Unix); maln() prlntf("5c at 5x6 prtntf("5c at 5xfl, Unlx->next->data , Ur.lx->next); prlntfClc at 5x0, Unlx->next->r.ext->data, Unlx->next->next); CLput(Unix); } CLputC cl ) struct charList *cl; I while (cl Is NULL) ( putcharC cl->data ); cl * cl->r.ext; ) ) An example run: U at e20 • N at etc I at el8 UNIX J C-6-22 A'M o 6.2.2.Creating List Structures Froa the file greeting.c: main() I struct chartist ‘greeting, •name; greeting = CLsakeCH1, CLmakef'i' printf("What's your name? "); name = CLgetO; CLput( greeting ); Ctput( name ); NULL))); struct charList •CLgetO int c; JLf ((c = getchar ()) return NULL; return' CL'aakct c, CLgetO ); An example run: What's your name? Greg Hi Greg C6c.urs.iow »< ftevc&se ©tbcM1. 'h'I 6.2.2.5. Creating New Storage struct charList *CLmake( d, n ) char cl; struct charList *n; I struct charList *teinp; temp = (struct charList *) inalloc( sizeof ( struct charList ) ); temp->data = d; temp->next = n; return temp; Thib li s^cd-A'c &r UNI* ( 0.^n>km call ; C-6-2M 4 - 32 6.2.2.6. Declaring & Creating Binary Trees Frca the file binTree.c: struct binTree —r int data; struct binTree Bleft, 'right; ); struct binTree *BTmake( d, 1, r ) ^ d; struct binTree *1, #r; I struct binTree "temp; temp s (struct binTree •) malloc( sizeof( struct binTree ) ); } teap->data = d; temp->left = 1; teap->right * r; return temp; aqtg Ufi I r.qht autu. le-K \ rrewt IrJt |rl»hi 6.2.2.7. Sorting With Binary Trees From the file binTree.c: nain() i , struct binTree #t; .f Int 1: • . V printf("Enter numbers to be sorted, followed by "DO); t = NULL; while ( scar.f ("Id", 4i) !« EOF ) I BTinsert( it, i ); BTinorder( t ); putchar('0); ) ) BTinorder( root ) struct binTree *root; { if (root !s NULL) ~ { BTinorder( root->left ); printf("#d ", root->data); BTinorder( root->right ); ) ) C-6-26 /I - 33 6.2.2.9. Inserting Into Binary Trees From the file binTree.o: BTinsert( pp, d ) struct binTree **pp; ink- d; I If (*pp == NULL) *pp = DTmake( d, NULL, NULL >; else i_f ( d < (*pp)->data ) DTinsert( &(*pp)->left, d ); else BTinsert( 4(*pp)->right, d ); c,trud complex (float reM,irmg;} slnict compleA add C ci, ci) struct complex ci, ci; ^ Cl.rr.ai = Ct.re.al +- c2-rtoi; Ci. irna-9 = c <• fm°.g t- c2.im*j; return c* ) Y. 1.1.1.1. The Function fopcn FILE *fopcn(filenamc, type) char "filename, "type; fopcn takes: rilenamc an operating system speoific filename type a string determining access permissions and returns: a stream descriptor (of type FILE *) for doing I/O. Access Permissions The string type can contain various character codes, including: \ - , I filp *Pp I r for read access ) w for write access j +p = wo , r /j j a for append access ^-34--------------------------------------------------- J J 7.1.1.2. Writing to an External File The file out.c: //include mainO I FILE *fp; fp = fopenC'foo", "w")j fprintf(fp, "Hello world!"); folose(fp); ) 7.1.1.3. Copying a File of Characters The file copy.c: //include tnainO I FILE »in, “out; int c; in = fopenC'foo", "r")j out = fopenC'bar", "w"); while ((c = getc(in)) 1= EOF) putc(c, out); fclose(in); fclose(out); 7.1.2.1. Single Character I/O J int gctc(stream) Returns a character from the FILE "stream; given stream, EOF on End Of File. int getcharO An abbreviation for getc(stdin). int putc(c, stream) Puts c on the given stream. char c; FILE "stream; putchar(c) putc returns the character c for convenience in expressions. An abbreviation for putc(c, stdout). ini, net II! IV* t*n rt.hu» tlx. «!»«■ tor 4Wln,\tJoul ... jlonJo'J InpJ (output) itf.am A - 55 ^,,7.1.2.2. Single String I/O i 1 char *gets(s) char “s; gets reads a string from stdin into s. The string from stdin is terminated with a newline (\n'). The string in s is terminated with an ASCII NUL (■'.O'). char *fgets(s, n, stream) char *s; int n; FILE “stream; fgets reads a string from stream into s until either n-1 characters are read, or a newline is read. The string will be NUL terminated. V For convenience in forming expressions, fgets returns s. J - r 7.1.3.1. Formatted File Input \ int scanf(format, p1, pn) char ‘format; Scans 3tdin, picking up values and putting them into the pointers p1 through pn according to the format code3 embedded in the string format. The number of items successfully read is returned, unless End Of File occurs, in which case EOF is returned. int fscanf(stream, format, p1, pn) FILE “stream; char “format; _ fscanf is the 3ame as scanf, exccpt that the named stream is scanned, instead of stdin. V J -• r 7.1.3.2. Formatted File Output \ printf(format, expl, expn) char “format; fprintf(stream, format, expl , expn) FILE ^stream; char “format; • In the case of printf, characters are written to the stream stdout. In the case of fprintf, they are written to the named stream. In either case, the values of the given expressions are written according to the corresponding format codes in format, and surrounded by any literal characters in format. The format codes are multitudinous, and compatible with those U3ed by 3canf and fscanf. C-7-l'i v_ r 7.2.2.1. Copying Strings char *strcpy(dst, src) char *dst, *src; or- 7.2.2.2.' Concatenating Strings A strcpy copics the characters of src to dst, stopping after copying the terminating NUL byte. For convenience, strcpy returns dst. char ‘strncpy(dst, src, n) char *dst, *src; int n; strncpy copies exactly n characters from src to dst. If src has fewer than n characters, it will be NUL padded. v If src has n or more characters (not count- ing its terminating NUL byte), then it will be truncated, AND dst WILL NOT BE NUL TERMINATED! char *strcat(dst, src) char *dst, *src; fHt I'OI ten Copies src onto the end of dst. dst needs to have room to store the extra characters, dst is returned. char *3trncat(dst, src, n) char *dst, *src; int nj Like strcat, strncat copies src onto dst, but will copy at most n characters, preventing overflowing dst. Even if not all of dst is copied, the resulting string will be NUL terminated. 7.2.2.3. Inspecting Strings int strlen(s) Returns the length of the char *s; NUL terminated string s. char *index(-s, c) Returns a pointer to the first char *s, c; occurrence of c in s, or 0. char *index(s, c) Returns a pointer to the last char *s, c; occurrence of c in s, or 0. V /I -37 7.2.2.1!. String Comparison v_ r int strcmp(s1, 32) char *s1 , s2j Compares si and s2 lexicographically, according to the collating sequence defined by the character codes. strcmp will return a positive number if si > s2, zero if si = s2 and a negative number if si < s2. int strncmp(s1, s2, n) char *s1, *s2; int n; strncmp compares si and s2 as if they had been truncated to at most n characters. Neither strcmp nor strncmp will compare strings with embedded digit strings in the human fashion, for example, "12" is considered to be less than 113”. 9.1.3.1. Controlling Compilation with Macros The C Preprocessor has the facility to select sections of codc based upon the value of macros. //ifdef Berk vfork(); 0 else fork(); ffendif The code is selected by either //ifdef or tfifndef (if undefined), and the flelse clause is optional. If necessary, macros can be selectively undefined with ffundef. 10.1.1.1. The Concept of a Process 'fork1 t The UNIX operating system has only one way to generate multiple parallel processes. 5 When a UNIX process issues the fork system call, it is split into two identical processes, the original and a copy. • 6 All UNIX processes have unique proccss ID numbers. The original process retains it’s process ID, and the copy receives a new one. When first split, both processes arc executing the same code in the same place, and have identical copies of "all variables. Only their different process id numbers and the values returned by the fork systems call differentiate parent from child. The parent receives the child'3 process id as the value of the fork systems call. The etiild receives the value zero. J ■VI-38 10.1.1.3. Synchronization with Child Processes___________________ The file "demos/chaplO/wait.c: raain() ( int pid 1, pid2, status; „ if ( (pid1 = forkO) == 0 ) ( ^ J printfC'l am the child process."); )exit(5); ; r pid2 = wait(istatus); I printfC'l am the parent."); \ printf("My child with pid id just died iwwt < with status %d.11, statu3j256); \ printfCIt returned exit code ?d.“, i status/256); ) C—10—6 10.1.2.2. An" Example Program Using *fork1 & * execl1__________ The file ~demos/chap10/execl.c: main() t int status; putsCThe people currently using the system are:"); if ( forkO == 0 ) execl("/bin/who", "who", 0); wait(itstatus); puts("Courtesy of the program "who1'."); C- 10-9 4-39 Creating Binary Files struct person char r.aae[103; ir.t age; float height, weight; ); rr.aint) ir.t fd;<"' static struct person pi = 1 {1C,’e’,'c',’r1,'g’,'e', • \ 0', 'NO' 21, 6.2, 1e5.3 ), pi = t I'M',' a’,' r1, • s','h',’a',’\0','\0' 27, 5.2, 105.3 ); fd s oper.t "somedata", 1); /• write access •/ write(fd, &p1, sizeof( struct person )); writeCfd, &p2, sizeof( struct person )); closet fd); '\0','\0'}, 'XO'.'XO'l, o ...rtadifi3 wrifta fd- Cfc teaJCU, ^““"0 write CM, t!’r'ount‘) cloie CW) 10.2.1.2. Random Access Files Isenk ( fd (offis-f (whertflom) struct person I char namc[10]; lnt age; floa't height, weight; 1 i maln() ( int fd; struct person pi, p2; fd = open( "somedata" , 2); /* read/write aocess */ read(fd, 4p1, sizeof( struct person )); r 5.S sLCftLi.- .4 P 2 r;-. § A S® o f ( struct person )); (lseel<(fd, 0L, 0)7> --/*"lxeraVivo''to beginning of file */ write(fd, &p2, sizeof( struct person )); write(fd, 4p1, sizeof( struct person )); ) o..^ orr.it 1.. cu^rpo^irf)*) 2.. 6nc<0fPi1t how no/]) bji* of dlj placement () C-10-12 A - 40 / 10.2.2.1. The Concept of a Pipe 6 A UNIX pipe is a connection between an output stream and an input stream, such that data written to the output stream may be read from the associated input stream. • Pipes may connect separate processes in UNIX. In fact, programs have no way of knowing in UHIX whether a file descriptor i3 associated with a pipe, a file, or a device (such as a tty). • Like buffered files, pipes have a fixed sized buffer. When the process writing to the pipe fills the buffer, it is suspended. • When a process reads from a pipe, it is suspended until there is data to read. 10,2.2.2. Creating Pipes The file "demos/chap10/pipe.c: main() r 0 o IL e. h I fitdeiM * int fildos[2]; char *s1, s2[80]; pipe(fildes); s1 = "hello"; write(fildesC1], si, strlng(s1)+1); read(fildes[0], s2, strlng(31)*1); puts(s2); •flLdes O] 10.2.2.3. Connecting Process Families with Pipes_________________ The file ~demos/chap10/whonum.c: main() ( int pipe(fildes); if ( forkO == 0 ) I dup2(fildes[03, 0); /* Install filde3[0] as stdin */ execl("/usr/bin/num", "num", 0); dup2(fildesC1], 1); /* Install filde3[1] a3 stdout */ execl("/uar/bin/who", "who", 0); V fildest2]; 0... standard in put i... Outpu.1 C-10-16 10.3*1.1. Bit Structures * Structure declarations can specify the exact number of bits to be U3ed by each field, as well as where extra padding bits should be inserted: struct I port '■.................. ( :3i unsigned ready: 1; ■' J-jTta. |<*»x» i i nt.'fJ?' " •' I/1" I I: I, S' 10.3.1.2. Bit Operators • In addition to the logical operators, C provides bitwise operators which operate on each bit of the words they are applied to: and & or I xor “ (exclusive or) invert “ (one's complement) • There are also operators for shifting words left or right by a given number of bit3: shift x left y bits: x << shift x right y bits: x >> (,nt a.,k,c; c« a^b; c »alfcj c. » -bi 10.3.2.2. Peeking & Poking with Casta / • Normally, integers and pointers are incompatible. But sometimes its necessary to specify pointer values as integer addresses: int *p; ____ * ' p = (int ») 0xff56j printf( "Memory location lx contains Id", 0xff56, »p); *P = 0; ".......-...............N #T \ ! printf("How it contains zero." ; ! corner‘<"J 10.3.2.3. Hardware Data Structure Manipulation_____________ • Hardware data structures, especially device registers in memory mapped computer address spaces, can be described as bit structures and then manipulated quite flexibly: struct port *p; p = (struct port *) 0177644; /* address of serial port. */ while (! p->ready) /* device not ready */ ; /* busy wait */ p->data = 1 A1 ; /* send an 'A' out the port */ i: ; 10.3.2.11. Free Unions 0 C provides an explicit way to overlap storage of alternative data structures, called a union. t Unions provide for the worst case alignment and storage requirements of the alternative data structures specified, but do no conversion. # Normally, unions are used only where part of a data structure will need to have values of different datatypes during different phases of a program. • However, sometimes it is necessary to access a data structure with a datatype description different from that used to create it. 0 This usage should be used quite sparingly, as it is highly dependent on non-portable assumptions about low level data representations. 10- 3.2 Aa Equivalents A ^ the sum * as a - a » Y ■ i* ai x * ihe Same a-i >, U ** 3 f, k 3 is >-s-