You are on page 1of 264

Introduction Acomputersystemiscomprisedofacollectionof: Processingelementsperformtransformationsondataitems CPU(centralprocessingunit) performsarithmeticoperationsoninformationstoredinmemory controlsmovementofinformationwithinmainmemory GPU(graphicscard) convertsgraphicscommandstopixeldata modernGPUsalsoworklikeparallelCPUs Diskcontroller controlsthetransferofdatabetweenthePCIbusanddisk computeserrorcorrectioncode(ECC)values

Storageelementsstoredataitemsforlateruse Cachememory veryfast"scratchpad"memoryusedforshortterm(~1second)storage volatile(contentslostatpoweroff) Mainmemory verylargebutlessfastthancache alsovolatile Disk


veryverylargebutWAYSLOWERthanmainmemory nonvolatile(unlessyoudropthecomputeronthefloor!)

Communicationelementstransferdataitemsbetweenprocessingandstorageelements InternalProcessorbus CPUtocache PCIBus CPUtomemoryandcontrollers(graphics,disk,etc) SCSIBus Controllertodevicesdisk,tape,etc. Ethernetlink Computertoanothercomputer 802.11link Wirelessconnectiontoanothercomputer

Programmingacomputer WewillconsiderasimplehypotheticalhumanpoweredcomputerwithaCPU(thehuman)andamain memoryconsistingofawallofpostofficetypeboxes.Thehumancomputerislimitedhiscapacityto understandinstructionsbutperformstheinstructionshecanunderstandwith100%reliability. Thememoryisconceptuallymodeledasa"postofficebox"system.Eachboxhasauniqueaddressor boxnumber.Addressesrangefrom0,1,2,....,n1wherenisthenumberofdifferentboxes. Eachboxcanholdexactlyoneslipofpaperwhichcontainseither:


Aninstructiontothehumanor Anintegernumber

Fundamentalmemorybehavior Memoryinbothrealandhypotheticalcomputersadherestotwofundamentalprinciples.

Thecontentofamemory"box"maybeunknowntoyoubutisNEVERUNDEFINED. Whenamemory"box"hasbeenwritteninto,itwillmaintainthevaluewrittenuntilrewritten.

Therefore,amemory"box"alwayscontainsthelastvaluewrittentoit.

Thehumancomputerinstructionset storevalue,box# store130,101 !Storesthevalue130inbox#101 store10,102!Puta10inbox#102 addbox#,box#,box# add101,102,110!Addsthevaluesstoredinbox101and102andputsthe answerinbox110 ThisdoesNOTmeanthatthevalue101+102=203goesintobox #110!Wecan'tknowwhatwillgointobox#110unlessweknow thevaluepresentlystoredinbox#101andbox#102.Sincewe alreadystored130inbox#101and10inbox#102,wemayinfer thatthevalue140willbestoredinbox110. subbox#,box#,box# sub100,200,300!Subtractsthevaluestoredinbox200fromthevaluestored inbox100andputstheanswerinbox300 halt !Programiscomplete,stop

Whenthehumancomputeristoldtostarthefetcheshisfirstinstructionfrombox0andthenproceeds sequentiallythroughbox1,box2,....untilheencountersahaltinstruction

Themissingingredients Whatwehavesofarislikeearly,crudespreadsheetmacrolanguages...somewhatusefulbutmissingtwo keyingredients(bothofwhicharepresentinmodernspreadsheetmacrolanguages). Theseingredientsare:


conditionalexecutionofagroupofinstructions repeatedexecutionofagroupofinstructions

Addingthemissingingredient Whenthehumancomputeristoldtostart,hefetchesthefirstinstructionfrombox0andthenproceeds sequentiallythroughbox1,box2,....untilheencountersahaltinstruction. Themissingingredientisthejumpc(jumpconditional)instructionwhichtellsthehumanthat

ifaspecifiedcondtionistrue,thenthenormalsequentialexecutionshouldbealteredandthe nextinstructionfetchedfromaspecifiedbox. iftheconditionisfalse,sequentialexecutionshouldproceedasnormal jumpc box#,op,box#,box# jumpc100,lt,101,10

!ifthevaluestoredinbox100islessthanthevaluestoredinbox 101thenfetchyournextinstructionfrombox10.Ifthe instructioninbox10isneitherhaltnorjumpctheinstruction fetchedafterbox10willbeinbox11.

Otherconditionsinclude nenotequal eqequal lelessthanorequalto gtgreaterthan gegreaterthanorequalto Withtheadditionofjumpcanyresultthatcanbecomputedbyanycomputercanbeobtained(albeit slowly)bythehumancomputer.

Addingthe1st100integers Problem:Add1+2+3+....+100andleavethesuminbox100. Box 0 store100,103 !Storetheupperlimitof100inbox103 1 store0,100!Initializethesumofallvaluesaddedsofarto0 2 store1,101!Initializethevaluetobeaddedtobe1initially 3 store1,102!Wealsoneedavaluetoincrementthevaluetobeadded 4 add101,100,100!addcontentsofbox101tobox100leavingsumin100 5 add102,101,101!incrementthevaluetobeaddedtobox100by1 6 jumpc101,le,103,4 !aslongasthevalueinbox101islessthanorequaltothe100inbox !103continuetoadd 7 halt

0 Boxnumber Exercises: > 100

1 101

100

102103

Whichboxesholdvaluesthatneverchange? Whatvalueswillbeinbox100and101justbeforethethirdtimetheinstructioninbox4 isexecuted? Thehumancomputerdoesn'thaveamultiplyinstruction.Writeaprogramtomultiplythe valueinbox100bythevalueinbox101leavingtheresultinbox102.

TheAlgorithm ThishypotheticalprogramiswritteninasymbolicmachinelanguagesometimescalledAssembly Language.Asstatedpreviously,itisthecasethatanyresultthatmaybecomputedonanycomputermay becomputed(thoughmuchmoreslowly!)bythehumancomputer.Thus,writingothersample programsforthehumancomputerisausefulexerciseasitprovidesusefulpracticeintheartof specifyinganalgorithm1preciselyandcorrectly. Thehumancomputeralsoillustratesanextremelyimportantconcept:thedistinctionbetweentheaddress ofamemorycell(100)andthevalueitcontains(1+2+...+100) Insummary Computerhardwarecanperformsimpleoperations(add,multiply,subtract,etc.)andperform comparisontestsveryfastandveryreliably.Nevertheless,itdoesn'tpossessevenrudimentaryproblem solvingskills.Itdoesn'tdoalgbraorcalculus.Itcanonlyexecuteaprescribedsetofsimpleoperations (aprogram!)withgreatspeedandaccuracy.Thus,thetruepowerofthecomputerissuppliedbyits humanprogrammer!!

1 AlthoughheisreputedtohaveinventedboththeIntenetandGlobalWarming,rumorsthatAlGorealsoinventedthe Algorithmarecategoricallyfalse.

10

ThehumancomputerlanguageandtheCprogramminglanguage: Cissometimesreferredtohasahighlevelassemblylanguagebecause,ofallmodernprogramming languages,Cprogramsmapmostdirectlyandnaturallytothemachinelevel.Wecanwritetheprogram thatsumsthefirst100integersinCasfollows: Clanguage"boilerplate".All programsbeginintmain(){

#include <stdio.h> int main() { int limit; int sum; int addvalue; int incr;

"memoryboxes"areidentifiedusing arbitraryvariablenamesinsteadof physicalboxnumbers

limit = 100; sum = 0; Correspondslinebylineto addval = 1; thehumancomputer incr = 1; assemblylanguageprogram. addit: sum = sum + addvalue; addvalue = addvalue + incr; if (addvalue <= limit) goto addit; fprintf(stdout, "addval =%d and sum = %d \n", addval,sum); } Thisinvokesthefprintf() functiontoprintthevaluesof addvalandsumtothescreen.

NotethatinC,avariablenameinsteadofanactualaddressisusedtoidentifytheboxinwhichthe variableresides,buttheprogramitselfislinebylineequivalent. AcomputerprogramthatwascapableoftranslatingtheCcodeabovetoAssemblyLanguageiscalleda compiler.

11

RepresentingInformationwithinaComputerSystem Wewillbeconcernedwithrepresentingthreebasictypesofinformationincomputersystem

Integer(whole)numbers (signed(positiveandnegative:14,42)and unsigned(nonnegativeonly:0,13)) Floatingpointnumbers(containafractionalpartoptionallywrittenininscientificnotatione.g., 1.3or13e1) TheLatincharactersetinwhichEnglishiswritten

Beforeturningtothedetailsoftherepresentation,wewillconsidertheorganizationofthecomputer memorysysteminwhichtheinformationisstored.

12

ComputerMemory Computermemoryisacomprisedofalargecollectionoftwostate(off/on)electricaldevicescalledbits (binarydigits).Asingleelectronicbitcanassumetwodistinctphysicalstateswhicharecommonly called{0,1}. Becauseasinglebitencodessolittleinformation,tosolveusefulproblemsitisnecessarytoaggregate bitsintolargerelements. Withtwobitswecanencode4distinctvalues,{00,01,10,11}.Thismightleadonetothinkthatthe numberofdistinctvaluesthatmaybeencodedis2xthenumberofbits,butthatwouldbeincorrect. Withthreebitswecanencodenot6but8distinctvalues{000,001,010,011,100,101,110,111}.In general,withnbitswemayrepesent2 distinctvaluesorelementsofinformation.
n

Encodingschemesusedincomputerprogramsoftenusecompletelyarbitraryencodingstorepresent informationindifferentdomains. Forexample,commonhousepetsmightbeencoded: 00dog 01cat 10Vietnamesepotbelliedpig 11bird

13

Moderncomputermemoryorganization Acomputermemoryisonedimensionalarrayofindividuallyaddressablestorageelements(analogousto thepostofficeboxesofthehumancomputer). Forreasonsdiscussedonthepreviouspage,itwasdecidedinthedesignoftheveryearliestcomputers thateachaddressableboxmustcontainmorethan1bitofinformation. Thebasicaddressableunitofmemory Theoptimalnumberofbitsinaboxisarbitraryandvariousvalueshavebeentriedthroughout computerhistory.Usingthetermbytetomeanthebasicaddressableunitofmemory,5,6,7,8,and9 bitbyteshaveallbeenused.Otherearlysystemsdesignedforscientificcomputationeschewedthebyte altogetherandorganizedtheirmemoriesusingwordscontainingupto60+bits. Basedupon

thesuccessoftheIBMSystem360(1960's)computersystem, andtherecognitionthatlifewasgoodwhenthenumberofbitsinbyteisapowerof2

invirtuallyallmoderncomputersystemsabyteiscomprisedof8bits.Halfofabyte(4bits)is sometimescalledanibble.

14

Possiblevaluesofabyteofmemory Asingle8bitbytecanencode=28=256distinctvaluesorelementsofinformation: 000000000 000000011 000000102 000000113 : : 11111110255 11111111256 Addressescontrastedtocontents Itisextremelyimportanttounderstandanddistinguish theaddressofamemoryelement(the"boxnumber") thecontentsofamemoryelement(thecontentsofthebox) Addresses beginat0andincreaseinunitstepstoN1whereNisthetotalnumberofbytesinthememory space. Contents Sinceeachbasicstorageelementconsistsofonly8bits,thereareonly28=256differentvalues thatcanbecontainedinasinglebytestorageelement.

15

Positionalnumbersystems Wehaveseenthatnumbersarestoredinacomputermemoryusingafixednumberofbinarydigitsor bitstoencodeeachvalue. Accordingly,computersperformintegerarithmeticinbase2. Numberingsystemsarecalledpositionalwhenthepositionofaparticular"digit"withinanumber determinesthedigit'scontributiontothefinalvalueofthenumber.Inthenumber666thefirst6 represents600,thesecond6represents60,andthefinalonerepresents6. Romannumeralsprovideanexampleofanonpositionalsystem.The"digit"Vmeans5regardlessof whereitappearsinthenumber.Doingarithmeticisnonpositionalsystemsisverychallenging. Experiments:ConverttheRomannumberXLVIItodecimal.MultiplyXLVbyCIV.

16

Binary(base2)anddecimal(base10)arithmetic Binaryorbase2arithmeticisapositionalsystemthatworksanalogouslytobase10butuses2rather than10distinctdigits.(Thechoiceofbase10inhumanarithmeticwasarbitraryandbaseduponthe numberoffingers(digits)possessedbytheaveragehuman.) Inbase10thenumber1234means1x10^3+2x10^2+3x10^1+4x10^0or 1000 200 30 +4 1234 Thusadigitatpositionn(n=0,1,2,3,....)isimplicitlyunderstoodtobemultipliedby10^n.

17

Binaryrepresentation Inthebinarysystem,thebitatpositionnisimplicitlyunderstoodtobemultipliedby2^n(insteadof10 ^n),andthereareonlytwodigits(bigits?). Analogoustobase10,eachpoweroftwovalue(2^n)startswitha1bitandisfollowedbyn0's. Powersoftwo(writtenindecimal)are:1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192, 16384,32768,65536.Writteninbinarythesevaluesare1,10,100,1000,10000,100000,1000000,etc.. Thus,thebinarynumber10110means1*2^4+0*2^3+1*2^2+1*2+0 16=1*2^4 0=0*2^3 4=1*2^2 2=1*2^1 +0=0*2^0 22base10=10110base2 andwehavejustdevisedanalgorithmforconvertingfrombase2tobase10! Exercise:Convert1101and11011101frombase2tobase10.

18

Countinginbase2andinbase10 Indecimalcountingeachtimetheloworderdigitexceeds9itisresetto0anda1is"carried"intothe nextcolumn(possiblycausinganotherresettozeroandcarry.) Binarycountingworkanalogously,buttheresetandcarryoccurseachtimeadigitexceeds1! Binary Decimal

0 1 10 11 100 101 110 111 1000 1001 1010 1011 1100 1101 1110 1111 10000 10001

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

Notethataswecountinbinarytheloworderdigitassumesvalues0,1,0,1,0,1. Theseconddigitsassumevalues 0,0,1,1,0,0,1,1 Thethirddigitsassumevalues 0,0,0,0,1,1,1,1 Thefourthdigitsassumevalues 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1 Exercises:Writethedecimalvalue13inbinary.Writethebinaryvalue1011indecimal.

19

Convertingfrombase10tobase2. Onecanconvertfrombase10tobasetobyasequenceofdivisionsby2. Ineachsuccessivedivisiontheremainderisabitinthebase2representation. Thequotientbecomesthedividendinthenextstageoftheoperation. Thebitsareproducedfromleastsignificant(loworder)tomostsignificant. Theprocedureendswhenthequotientbecomes0. Example:Convert67base10tobase2. 67/2=33r1<leastsignificant(2^0)bit 33/2=16r1 16/2=8r0 8/2=4r0 4/2=2r0 2/2=1r0 1/2=0r1<mostsignificant(2^6=64)bit Thus67base10=1000011base2 Onecanverifytheaccuracyofthecomputationbyconvertingtheresultbacktobase10. Here:64+2+1=67 Exercise:Convert93base10tobase2.

20

Basesotherthan2and10 Anypositiveintegercanbeusedasabase.Forexample,inbase3

Thedigits(thrigits?)are{0,1,2} Inanumber,suchas12012,eachdigitisimplicitlymultipliedbyapositionalpowerof3:1,3,9, 27,81,243,.... 2x3^0=2 1x3^1=3 0x3^2=0 2x3^3=54 +1x3^4=81 140base10

Conversionfrombase10tobase3isaccomplishedbyasequenceofdivisionsby3 49/3=16r1 16/3=5r1 5/3=1r2 1/3=0r1 Answer:1211=1*3^3+2*3^2+1*3+1=27+18+3+1=49 Exercises:Convert134base5tobase10.Convert79base10tobase4.

21

Basesthatarepowersof2 Binarynumbersareverydifficultforhumanstowriteandremember: Considerthe32bitnumber:

10110101101110111101010110111110
Basesthatarepowersof2areusefulinsimplifyingnotation. Asingledigitofabase2^nsystemrepresentsexactlynbitsofabase2system. Base#ofbits 4 2 tetral? 83 octal 16 4hexadecimal

Convertingfrombase2tobase4:(validdigits(0,1,2,3)) Base2:10111001 Base4:2321 Convertingfrombase2tobase8(validdigits(0,1,2,3,4,5,6,7)) Base2:101110001010 Base8:5612

22

Base16Hexadecimal Since16isgreaterthan10,therearenotenoughdigitsinthebase10systemtoencodeallofthesingle digitbase16numbers.Thusweaugmentthedigits09withthefirst6lettersofthealphabet. Eachbasebase16valuecorrespondstoa4bitbinarynumberasshownhere: Base16digits:{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F} binaryhexbinaryhex 00000 10008 00011 10019 00102 1010A 00113 1011B 01004 1100C 01015 1101D 01106 1110E 01117 1111F Asingle8bitbytecanalwaysbeencodedinexactly2hexadecimaldigits: Base2Base16 100110119B The9iscalledthehighordernibbleaandtheBisthelowordernibble. An32bitintegercanbeconvertedbygroupingthe32bitsintoeight4bitnibbles: 10110101101110111101010110111110 B5BBD5BE Exercise:Convert010101110111110tohexadecimal.ConvertA12BCtobinary.

23

Representingnumericvalues Morethan8bitsareneededforusefulapplicationtonumericalproblems.Thusitiscommontogroup adjacentbytesintounitscommonlycalledwords.

Multiplewordlengthsarecommon,andcommonwordlengthsinclude2bytes,4bytes,and8 bytes. Insomearchitectures(SunSparc)itisrequiredthattheaddressofeachwordbeamultipleof wordlength.Thatis,theonlyvalidaddressesof4bytewordsare0,4,8,12,16,...) Inotherarchitechtures,wordscanresideonanybyteboundary,buttheuseofunalignedwords oftencausesaperformanceproblem. Commonwordlengthsnowinclude16,32,64and128bitswhichcorrespondto2,4,8,and16 bytesperword. Wordlengthsmayalsodifferbetweenintegerandfloatingpointdatatypes. Evenwhenbytesareaggregatedintowords,addressesremainbyteorientedinmoderncomputer systems. Theaddressesof4bytewordsarethus0,4,8,12,16,....

Nevertheless,evenwiththeseaggregationstrategiescomputerarithmeticisnotthesameastrue mathematicalarithmetic.

24

Mathematicalintegerarithmetic Mathematically,theintegersconsistofacountablyinfinitesetofvalues:

,...,3,2,1,0,1,2,3,...,

Theintegerscomprisewhatiscalledaring.

Thesumoftwointegersisaninteger Thedifferenceoftwointegersisaninteger Theproductoftwointegersisaninteger Thedivisionofoneintegerbyanotherisnotdefined.

25

Computerintegerarithmetic Computerarithmeticisanapproximationofmathematicalarithmetic

Thenumberofdistinctintegersis2

word_length

wherewordlength=8,16,32,64,bits

Unliketrueintegerarithmeticonthecomputerthenumberofdistinctvaluesisfinite. Ifwordlengthis8bitsusingsignedintegerarithmeticyoucanrepresentonlythevalues128,... 1,0,1,...127 Ifyoucompute100+100yougetthewronganswerbecausethemaximumpositivenumberthat youcanrepresentwith8bitsofinformationis127 Acomputerinstructionsetsupportsintegerdivision. Ifyoucompute100/9yougetanapproximateanswer.Althoughcomputersystemsdosupport integerdivision,theydosobydiscardinganyremainder So100/9=11(insteadof11.111111..........),and2/5=0(insteadof0.4).

26

Computerintegerarithmetic Theprinciplesofarithmeticworkthesameinanypositionalsystem.Considerthedecimaladdition: 13 +9 22 Weproceedfromrighttoleftandifasumexceeds9thenitisforcedto"wraparound"andacarryinto thenextcolumnisgenerated. Inbinary0+0=0;0+1=1+0=1;and1+1=0withacarryout. Wewilluse8bitarithmeticasanexample,but16and32bitarithmeticoperatesinessentiallythesame way. 10000111129 +0010010133 10101100162

27

Finitevaluesizeandoverflow Amathematicalintegerconsistsofanunboundednumberofbits==>overflowcan'thappen. Acomputerintegerconsistsofafinitenumberofbits==>overflowcanhappen. 8bitunsignedarithmetic: Inunsignedarithmeticallvaluesareconsideredtobynonnegative. Possiblevaluesofan8bitbyteinbase10are0,1,2,...255(0,1,10,...,111111111base2) Considerwhathappenswhenwetrytocompute240+32 11110000240 0010000032 0001000016 The1bitthatcarriesoutoftheleftendoftheoperationwillbediscardedandtheanswerwecompute willbe16whichis(240+32)modulo256inmathematicalterms.Computersystemstypicallyprovide lowlevelmechanismsfordetectingwhenthesesituationsoccur,butthesemechanismstypicallyarenot availableinhighlevelprogramminglanguages!! Exercise:Add01010110+11001000inbinary.Istheansweryougetmathematicallycorrect?

28

Signed8bitarithmetic Formanyusefulapplicationsitsnecessarybeabletorepresentnegativenumbers. Mostcomputersystemsnowusea2'scomplementrepresentationfornegativenumbers.


The1'scomplementofavalueisobtainedbyinvertingallthebits. The2'scomplementisthenobtainedbyadding1tothe1'scomplement

00101101baseinteger 110100101'scomplement 110100112'scomplement

Sincethenegativeofanynumberisitstwo'scomplement,thesumofanumberanditstwo's complementisalways0. Thedifferenceabiscomputedasa+(b)ora+twos_complement(b) Unlikesignbitsystems,thetwoscomplementsystemhasonlyasingle0

29

Twoscomplementrepresentation DecBinaryHexadecimal 12810000000 80 1271000000181 1261000001082 : 2 11111110 FE 1 11111111 FF 0 00000000 00 1 00000001 01 2 00000010 02 : 126 01111110 7E 127 01111111 7F Overflowremainsaproblem 9601100000 +6801001000 10101000whichisanegativenumber! Exercise:Whatisthetwoscomplementof10110000 Exercise:Write17asatwoscomplementsignedinteger

30

Encodingthealphabet Itsusefultoencodetextincomputermemoryandfiles:

Namesofaccountholdersinfinancialrecords Textinwordprocessors Partnamesininventorysystems,etc.

Althoughtheencodingisarbitrary,therearesomeusefulcharacteristicsacodeshouldpossess:

Thelettersareencodedsequentially:'A'+1is'B' Invertingasinglebitcanconvertbetweenupperandlowercase

ThecodethatwewillbeusingiscalledASCII(AmericanStandardCodefortheInterchangeof Information).Printablecharactersstartwiththevaluehex20=32whichisthecodeforblankspace. Followingspacearemanyofthespecialcharactersthatyoufindonthekeyboard. DecHexChar 32 20 33 21 ! 34 22 " 35 23 # 36 24 $ 37 25 % 38 26 & 39 27 ' 40 28 ( 41 29 ) 42 2a * 43 2b + 44 2c , 45 2d 46 2e . 47 2f /

31

Theencodingofthecharacterrepresentationofthedigitsisintherangehex30tohex39 Dec Hex Char

48 49 : 56 57

30 0 31 1 38 8 39 9

Morespecialcharactersfollowintherangehex3Ato40 DecHexChar 58 3a : 59 3b ; 60 3c < 61 3d = 62 3e > 63 3f ? 64 40 @ Theuppercaselettersarenext DecHexChar

TheASCIIencodingoftheletterA isthebytehavingthevalue 01000001=26+20 This value is written in decimal as 65andinhexadecimalas41

65 41 A 66 42 B 67 43 C : 88 58 X 89 59 Y 90 5a Z

Anotherblockofspecialcharactersoccupyhex5Bto60 DecHexChar 91 5b [ 92 5c \ 93 5d ] 94 5e ^ 95 5f _ 96 60 `

32

Thelowercasecharactersoccupyhex61to7A. UppercaseA01000001 Lowercasea01100001 Caseconversionmaybeaccomplishedbyinvertingthebitintheredposition Dec Hex Char

97 61 a 98 62 b 99 63 c : 120 78 x 121 79 y 122 7a z


Therearealsoafewspecialcharactersthatfollowz. Exercise:Whatletterisrepresentedinhexas63?WhatisthebinaryencodingoftheUPPERcase versionofthesameletter.

33

Controlcharacters: TheASCIIencodingsbetweendecimal0and31areusedfortoencodewhatarecommonlycalled controlcharacters.Controlcharactershavingdecimalvaluesintherange1through26canbeentered fromthekeyboardbyholdingdownthectrlkeywhiletypingaletterinthesetathroughz. SomecontrolcharactershaveescapedcoderespresentationsinC,butallmaybewritteninoctal. Dec 4 8 9 10 12 13 Keystroke ctrl-D ctrl-H ctrl-I ctrl-J ctrl-L ctrl-M Name end of file backspace tab newline page eject carriage return Escaped code '\004' '\b' '\t' '\n' '\f' '\r' TheEOFcharacterhas no\letterrepresentation. Itmaybeexpressedas '\004'orforthatmatter simply4.

34

ThestructureofCprograms WewillnowpresentasomewhatformalviewofthestructureofaCprogramsothatwedon'thaveto learnexclusivelybyexample.Learningfromexamplesisveryuseful,butifweunderstandthebasic structureofthelanguagewecanbetterunderstandwhycertainconstructsarecorrectandothersarenot correct.Thisinturnallowsustobemoreefficientprogrammers.


ACprogramconsistsofacollectionofoneormorefunctions. Eachfunctionmusthaveauniquename. Exactlyoneofthefunctionmusthavethenamemain(). Whenaprogramisrun,executionstartsatthebeginningofthemain()function.

Eachfunctionconsistsofaheaderfollowedbyabasicblock. int main(void) { int ret_val; ret_val = 12; return(ret_val); } Inthefunctionheader


Thefunctionheader

Thebasicblock

intdefinesthetypeofvaluereturnedbythefunction mainisthenameofthefunction thevaluesenclosedin()identifyanyparameters(variables)thatarebeingpassedtothe function.Thereservedwordvoidmeanstherearenoparameterswillbeused.

Thebasicblockisdelimitedby{and}andconsistsof:

declarationofvariables executablecode

35

DeclaringvariablesofintegertypeintheClanguage BeforeanintegervariablecanbeusedinaCprogramitmustbedeclaredviaastatementofthe followingform:

optional_modifiertype_namevariable_name;

Theoptional_modifierThemodifierisusedtodistiguishbetweensignedandunsignedintegers. Thedefaultmodifierissigned.Tocreateanunsignedintegertheunsignedmodifiermustbe explicitlyprovided. Thetype_nameThefollowingtypenamescreateintegervalues.

char - shortint long

8bit 16bit 32bit(sometimes16) 32bit(sometimes64)

36

Variablenames:

Comprisedofupperandlowercaseletters,digits,and_ Muststartwithaletteror_ Mustnotbeareservedword(e.g.int,while,char,unsigned....)SeeappendixAofthetext Shouldnotbethenameofastandardfunctionorvariable....buthowdoIknowwhatthoseare? Thenameshouldbereflectiveofthevariables'useintheprogram.

Anysignedorunsignedintegervariablecanhold

valuesusedinarithmeticcomputation ASCIIencodedrepresentationofalphabeticandspecialcharacters

Neitherthecomputernorahumanwhoexaminesthecontentsofmemorycandetermineifavalue<= hex7F=127isbeingusedasanumberorasencodedcharacter. Exampledeclarations:

unsigned char int unsigned short long long char

red_pixel_value; image_width; loop_counter; image_size_in_bytes; image_size_in_pixels; first_letter;

37

Executablecode Executablecodeconsistsofasequenceofstatements.Statements,themselvesareconstructedfrom

expressions.

Expressionsconsistof(legal)combinationsof:

operandswhichmaybefurtherclassifiedas

constants(integer,character,floatingpoint) variables functioncalls

and

operatorswhicharediscussedonthenextpage.

38

Operands Integerconstantsmaybeexpressedas

decimalnumbers: octal(base8)numbers: hexadecimal(base16)numbers ASCIIcharacters

71mustnotstartwith0!!! 0107mustalwaysstartwith0 0x47mustalwaysstartwith0x 'G' mustbeenclosedinsinglequotes

Alloftheaboveconstantshavethesamevalue! Differentencodingsmaybefreelyintermixedinexpressions

71 + 'G' + 0x47

(Thevalueoftheaboveexpressionisdecimal71+71+71=213) Integervariablesmustbepredeclaredaspreviouslydescribed(unsigned)char,short,int,long

unsigned char pixel;


Functioncallsconsistofthenameofthefunctionbeingcalledalongwithaparenthesizedcollectionof parametervaluestobepassedtothefunction:

how_many = fscanf(stdin, %d, &input_value);

39

Operatorscanbegroupedintoseveralclasses. Fornow,wewillbeusingonlytheonesshowninred. Assignment: = Assignsthevalueoftheexpressiontotherighttothevariableontheleft. legal: x = 4 + (3 + 2 * y) illegal: x + (x - 3) = 17; Arithmetic: +, -, *, /, % Add,subtract,multiply,divide Comparative: ==, != , <, <=, >, >= equal,notequal,lessthan,lessthanorequalto,greaterthat,greaterthanorequalto Logical: not,and,or !, &&, ||

Bitwise: ~,&, |, ^ not,and,or,exclusiveor Shift: <<, >>

40

Operatorscanalsobecharacterizedbythenumberofoperandstheysupport Alloftheoperatorsshowninredsupporttwooperands..oneontheleftandoneontheright. x=5//assignment y==5//comparision z10//subtraction Someoperatorsalsosupporteitheroneortwooperands x//negation ab//subtraction Otherssupportonlyoneoperand !x//logicalnot

41

Expressionsarebuiltbycombiningoperatorsandoperands Arbitrarysequencesofoperatorsandoperands(e.g.x+*yz//=)arenotmeaningfulandare thusnotlegalintheClanguage.Ingeneralwecansaythat


operandsmustbeseparatedfromeachotherbyoperatorsandthat eachoperatormusthavethepropernumber(1or2)ofoperands.

Itmaybedifficulttodeterminethevalueoflegalexpressionssuchas:

v1 + 5 * v2 / 3 * v1
SupposeItellyouthatthevariablev1currentlyhasvalue4andv2hasvalue3. Whatisthevalueoftheaboveexpression? TheCcompilerhasasetofimmutablerulesforevaluatingsuchexpressions.TheCcompilerhasasetof immutablerulesforevaluatingsuchexpressions.Therulesarecalledprecedence(e.g.mulitiplyand dividearedonebeforeaddandsubtract)andassociativity(e.g.acollectionofmultiplyanddividesis evaluatedlefttorightso42/6*7=49andnot1),buttheyarehardtoremember. Wecanensurethatthecompilerdoeswhatwewantbybuildingourexpressionsfromparenthesizedsub expressions.Suchexpressionsarealwaysevaluatedinsideout. v1 + ((5 * v2) / (3 * v1)) v1 + (5 * (v2 / 3)) * v1 ((v1 + 5) * v2) / (3 * v1) Anevaluationtree Exercise:Createevaluationtreesandfindthevalueofeachoftheabovethreeexpressions.

42

Expressionsthataretrueorfalse IntheClanguage

anexpressionthathasthevalue0isfalse anexpressionthatdoesnothavethevalue0istrue

43

Statements

Anexpressionfollowedbyasemicolonisknownasastatement. Herearesomeexamplesofstatements:

Theassignmentstatement variable=expression; computesthevalueofexpressionandstoresthevalueinvariable x=y+z+3; Theuselessstatement: expression; computesthevalueofexpressionandthendiscardsit. x+y2/3; comparesthevalueoftwovariablesandthendiscardstheanswer x==z;

44

IntroductiontoInputandOutput Usefulcomputationsoftenrequireamechanismbywhichtheuserofaprogrammay

provideinputdatathatistobeassignedtovariables,

andanothermechanismbywhichtheprogrammay

produceoutputdatathatmaybeviewedbytheuser.

Initially,wewillassumethattheuseroftheprogram

entersinputdataviathekeyboardand viewsoutputdatainaterminalwindowonthescreen.

TheCruntimesystemautomaticallyopenstwofilesforyouatthetimeyourprogramstart:

stdinInputfromthekeyboard stdoutOutputtotheterminalwindowinwhichtheprogramwasstarted

Eventually,wewillseehowtowriteandreadfilesthatresideonthecomputer'sdisk.

45

AsimpleCprogram Cprogramsconsistofoneormorefunctions,andeveryCprogrammusthaveamain()function. Fornow,itshouldbewrittenasfollows: int main() { return(0); } CprogramsoftenrelyonfunctionsthatresideintheCruntimelibary.Thefunctionsperforminputand outputandotherusefulthingssuchastakingthesquarerootofanumber. Whenyourfunction,usesfunctionsintheruntimelibary,youmustincludeproperheaderfiles.These headerfiles:

containthedeclarationofvariablesyoumayneed allowthecompilertodetermineifthevaluesyoupasstothefunctionarecorrectintypeand number.

Ifyourprogramistousethestandardlibraryfunctionsforinputandoutput,youmustincludetheheader filestdio.hasshownbelow. #include <stdio.h> int main() { return(0); }

46

Readingintegervaluesfromstdin Toreadthevalueofasingleintegerintoourprogramweexpanditasfollows:

#include <stdio.h> int main() { int howmany; int the_int;

Commentsshouldbe usedtodescribetheuse ofvariables

// how many integers were read // the integer value

howmany = fscanf(stdin, "%d", &the_int); return(0); }


Thefscanf()functionreturnsthenumberofvaluesit suceededinreading.Iffscanf()succeedshere,then howmanywillbesetto1,becausethestatementis attemptingtoreadonlyonevalue.

Whenahumanentersnumericdatausingthekeyboard,thevaluespassedtoaprogramaretheASCII encodingsofthekeystrokesthatweremade.Forexample,whenItype:

261
3bytesareproducedbythekeyboard.Thehexadecimalencodingofthesebytesis:

32 36 31 2 6 1

- hex - ascii

Toperformarithmeticusingmynumber,itmustbeconvertedtotheinternalbinaryinteger representation.Decimal261isbinary100000101or0x105=1*16^2+5.

47

Formatconversionwithfscanf()

howmany = fscanf(stdin, "%d", &the_int);

Thefirstvaluepassedtothefscanf()functionistheidentityofthefilefromwhichyouwishto read.Notethatstdinisnotandmustnotbedeclaredinyourprogram.Itisdeclaredin<stdio.h>. Thesecondparameteristheformatstring.The%dformatcodetellsthefscanf()function thatyourprogramisexpectinganASCIIencodedintegernumbertobetypedin,andthat fscanf()functionshouldconvertthestringofASCIIcharacterstointernal2'scomplementbinary integerrepresentation. Thethirdvaluepassedtofscanf()istheboxnumberoraddressofthememorycelltowhich the_intwasassignedbythecompiler.Theuseofthe&(addressof)operatorcausesthe compilertopasstheaddressofthebox/memorycellratherthanthevalueinthebox/memorycell. Thefscanf()functionmustbepassedtheaddressofthe_intneedstheaddressbecausefscanfmust returnthevaluetothememoryspaceoftheprogram.Passinginthevaluethatispresentlyinthe heldintthe_intwouldbeuseless. Thevaluereturnedbyfscanf()andassignedtothevariablehowmanyisthenumberofvaluesit successfullyobtained.Hereitshouldbe1.Ingeneralthenumberofformatspecifiersshould alwaysequalthenumberofpointerspassedandthatnumberwillbereturnedatthecompletionof asuccessfulscan.

48

Readingtwointsinasingleread Wecanmakeasmallmodificationtoourprogramsothatitnowreadstwodistinctvaluesfromthe standardinput,stdin.

#include <stdio.h> int main() { int howmany; int another; int the_int;

// how many integers were read // a second input integer // the integer value

howmany = fscanf(stdin,"%d %d", &the_int, &another); return(0); }


Todothiswemustpasstwoformatspecifiersintheformatstringandpointerstothetwovariablesthat wewanttoreceivethetwodifferentvalues. Thenumberofvaluestobereadmustalwaysmatchtheformatcode.Herethevalueofhowmanyshould be2.Ifitisnot2,thenanonintegervalueorendoffilewasencounteredintheinput.

49

Formattedoutputwithfprintf() Sincetheprogramproducesnooutput,itsnotpossibletotellifitworked.Wecanobtainoutputwiththe fprintf()function. #include <stdio.h> int main() { int howmany; int another; int the_int; int printed; &(addressof) mandatory!!

// // // //

how many integers were read a second input integer the integer value many output values were printed

howmany = fscanf(stdin, "%d %d", &the_int, &another); printed = fprintf(stdout, "Got %d values: %d and %d \n", howmany, the_int, another); return(0); } &(addressof) verboten!!

Thefirstparameterpassedtofprintf()isthedesiredfile.Thefilestdout,likestdin,isdeclaredin <stdio.h> Thesecondparameterisagaintheformatstring.Notethatliteralvaluesthatwillappearinthe outputoftheprogrammaybeincludedintheformatstring. The%dformatcodetellsfprintf()thatitisbeingpassedthevalueofabinaryinteger. Thefprintf()functionwillconvertthebinaryintegertoastringofASCIIcharactersandsendthe characterstringtothespecifiedfile. Notethatthevaluesofthevariablesarepassedtofprintf(),buttheaddressesarepassedto fscanf()!Thisisdonebecausefprintf()doesn'tneedtostoreanythinginthememoryspaceofits caller.

50

Compilingandrunningtheprogram: /home/westall ==> gcc -g -Wall io.c /home/westall ==> ./a.out 143 893 Got 2 values: 143 and 893 Whathappensifweprovidedefectiveinput? int /home/westall ==> ./a.out 12a 567 Got 1 values: 12 and 10034336 fscanf()stopsatthefirstbadcharacter Thevalueofanotherwasneverset,Thevalue10034336iswhateverwasleftoverinthe memoryboxtowhichthevariableanotherwasassignedthelasttimeitwasused.

51

Processingmultiplepairsofvalues Wenowconsidertheproblemofprocessingmultiplepairsofnumbers.Supposewewanttoreadalarge collectionofpairsofnumbersandprinteachpairalongwithitssum. Asusualwestartwithasimplerprototypeinwhichwetrytoprocessasinglepair.

/* p2.c */ #include <stdio.h> int main() { int howmany; int num1; int num2; int sum;

// how many integers were read // the first number of the pair // the second number of the pair

howmany = fscanf(stdin, "%d %d", &num1, &num2); sum = num1 + num2; fprintf(stdout, "%d + %d = %d \n", num1, num2, sum); return(0); }
/home/westall/acad/cs101/notes06 ==> gcc -o p2 p2.c -g -Wall /home/westall/acad/cs101/notes06 ==> p2 44 33 44 +

33 =

77

52

Extensionto4pairsofnumbers Wecaneasilyextendourprogramtoallowustoprocess4pairs /* p3.c */ #include <stdio.h> int main() { int howmany; // how many integers were read int num1; // the first number of the pair int num2; // the second number of the pair int sum; howmany = fscanf(stdin, "%d %d", &num1, &num2); sum = num1 + num2; fprintf(stdout, "%d + %d = %d \n", num1, num2, sum); howmany = fscanf(stdin, "%d %d", &num1, &num2); sum = num1 + num2; fprintf(stdout, "%d + %d = %d \n", num1, num2, sum); howmany = fscanf(stdin, "%d %d", &num1, &num2); sum = num1 + num2; fprintf(stdout, "%d + %d = %d \n", num1, num2, sum); howmany = fscanf(stdin, "%d %d", &num1, &num2); sum = num1 + num2; fprintf(stdout, "%d + %d = %d \n", num1, num2, sum); return(0); } /home/westall/acad/cs101/notes06 ==> gcc -o p3 p3.c -g -Wall /home/westall/acad/cs101/notes06 ==> p3 1 3 1 + 3 = 4 3 4 3 + 4 = 7 5 6 5 + 6 = 11 7 8 7 + 8 = 15

53

Extensiontoarbitrarynumbersofpairstobeadded

Ifweknewwehadtoprocess1,000pairsofnumbers,wecouldduplicatetheexistingcode250 times! Thisapproachhas(hopefullyobvious)disadvantagesespeciallywhenextendingto 10,000,000,000pairs!

Controllingtheflowofinstructionexecution

Thesolutionliesinmechanismsusedtocontroltheflowofinstructionexecutioninaprogram. Suchmechanismspermitustoinstructthecomputertoperformataskrepetitively.

Recallthehumancomputer:

Whenaninstructionhadbeenexecuted, Thehumanfetchedhisnextinstructionfromthenext(numerically)box. Nonhumancomputersandhighlevellanguagesworkthiswaytoo! Bothhumanandnonhumancomputersprovideajumpcinstruction Iftheconditiontestedistruethen thenextinstructionisfetchedfromanewspecifiedlocationand sequentialexecutionresumesatthenewspecifiedlocation.

Thejumpcinstructionprovidesallthefirepowerthatisneededwithrespecttocontrolflowmanagement tocomputeanythingthatcanbecomputed!

54

Boolean(logical)expressions Theseexpressionsusedbytheifandwhilestatementstakeonthevalues

true(notzero)and false(zero).

Simpleexpressionscommonlyinvolvetwonumericexpressionsandacomparisonoperator:

if (value != 0) { do something } else { do something-else } while (counter < (2 * large 1)) { doing something again counter = counter + 1; }

55

Morecomplexexpressionscanbemadebyusinglogicaloperators: and && or || not ! Thegeneralformsofsuchexpressionare: (booleanexpression1&&booleanexpression2) trueifandonlyifbothexpressionsaretrue. (booleanexpression1||booleanexpression2) trueifandonlyifatleastoneoftheexpressionsistrue !booleanexpression trueifandonlyiftheexpressionisfalse.

56

Examples: Computethesmallestofthreevariablesa,b,andcknowntobedifferent.

if ((a < b) && (a < c )) min = a; else if ((b < a) && (b < c )) min = b; else min = c;
Determineifvalisbetween9and+9 Youmightbetemptedtotry: if (-9 <= val <= 9) <--- don't do it!!

Thiswillnotworkatall.InlanguageswithBooleanconstantsandvariablesitwillcausea compiletimeerror.InCtheexpressionistrue100%ofthetimeregardlessofthevalueofval. Insteadwemustuseacompoundcondition:

if ((-9 <= val) && (val <= 9))


Determineifvalisnotbetween9and+9

if (!((-9 <= val) && (val <= 9)))


whathappensifweforgetthe() or

if (!(-9 <= val) || !(val <= 9))


whichcanbewrittenas

if ((-9 > val)

|| (val > 9))

57

Managingflowofcontrolinhighlevellanguages Intheearlyhighlevellanguagesthejumpcinstructionwasrealizedas: if(someconditionistrue) gotostatement_label; somestatement1; somestatement2; statement_label: x=y+2; Likethejumpcinstructiontheifwithgotocontructpermitsustocomputeanythingthatcanbecomputed andthisconstructissupportedinCprograms. Somecontendthattheuseifwithgotomakesprograms

Ifsomeconditionistrue,then somestatement1and somestatement2willnotbe executed.

difficulttowritecorrectlyandtodebug difficultforanotherpersontoreadandunderstandandtherefore difficulttomaintain

Otherscontendthatawelldesignedprogramthatusesifwithgotoisnomoredifficulttounderstandthat onethatusesothermechanisms. Stillotherscontendthatusingothermechanismsinherentlyfacilitatesgooddesign. Thereisdoubtlesssometruthinallofthesecontentions..

58

Flowcontrolstatements Thewhilestatement while(expression) statement whilethevalueofexpressionisnotzero,repeatedlyexecutestatement while(expression) basicblock whilethevalueofexpressionisnotzero,repeatedlyexecutetheentirebasicblock. Itshouldbeclearthatthestatementorthebasicblockfollowingthewhileshouldhavetheabilityto eventuallymaketheexpressionhavethevalueFALSE(0)!!!Ifsuchisnotthecasetheresulting behavioriscalledaninfiniteloop.Theprogramwillneverterminate.

int sum; int val;

val = 0; while (val <= 100) { sum = sum + val; val = val + 1; }

Initializecontrol variable

Useecontrolvariablein booleanexpression

Modifycontrol variable

Intheaboveexamplewhenvalisequalto101,thevalueoftheexpression(val<=100)is0.

59

Uninitializedvariables Useofuninitializedvariablesisacommonerrormadebybothnoviceandexperiencedprogrammers. Thiserrorisparticularlydangerousbecauseitcancreateaprogramthatappearstoworkcorrectly. Theprogramfragmentshownonthepreviouspageisactuallybroken,becausesumwasnotinitialized.

int sum; int val;

val = 0; while (val <= 100) { sum = sum + val; val = val + 1; }

Initializecontrol variable Useecontrolvariablein booleanexpression

Modifycontrol variable

60

Preventinguninitializedvariables A100%effectivewaytopreventtheuseofuninitializedvariablesistoinitializeeveryvariablewhenit isdeclared.

int sum = 0; int val = 0; while (val <= 100) { sum = sum + val; val = val + 1; }

61

Theifstatement if(expression) statementorbasicblock else statementorbasicblock

Iftheexpressionistrue(nonzero)thenthestatementorbasicblockfollowingtheifwillbe executed. Iftheexpressionisfalse(zero)thenthestatementorbasicblockfollowingtheelsewillbe executed.

if (fscanf(stdin, "%d", &number) == 1) { sum = sum + number; } else { fprintf(stderr, "Failed to read number\n"); }

62

Thecompleteprogram

acad/cs101/notes06 ==> cat p4.c #include <stdio.h> int main() { int howmany = 0; int num1 = 0; int num2 = 0; int sum = 0;

// how many integers were read // the first number of the pair // the second number of the pair

howmany = fscanf(stdin, "%d %d", &num1, &num2); while (howmany == 2) { sum = num1 + num2; fprintf(stdout, "%d + %d = %d \n", num1, num2, sum); howmany = fscanf(stdin, "%d %d", &num1, &num2); } return(0); }
acad/cs101/notes06 ==> gcc -g -Wall p4.c -o p4 acad/cs101/notes06 ==> ./p4 1 2 1 + 2 = 3 9 -4 9 + -4 = 5 -8 3 -8 + 3 = -5 4 4 4 + 4 = 8

63

Additionaloutputformatcodes Formatcodescanspecifyhowyouwanttoseetheintegerrepresented. %c %d %x %o ConsidertheintegertobetheASCIIencodingofacharacterandrenderthatcharacter ProducetheASCIIencodingoftheintegerexpressedasadecimalnumber ProducetheASCIIencodingoftheintegerexpressedasahexadecimalnumber ProducetheASCIIencodingoftheintegerexpressedasanoctalnumber

Specifyingfieldwidth Formatcodesmaybeprecededbyanoptionalfieldwidthspecifier.Thecode%02xshownbelowforces thefieldtobepaddedwithleading0'sifnecessarytogeneratethespecifiedfieldwidth. #include <stdio.h> int main( int argc, char *argv[]) { int x = 0; int y = 78; x = 'A' + 65 + 0101 + 0x41 + '\n'; fprintf(stdout, "X = %d \n", x); fprintf(stdout, "Y = %c %3d %02x %4o \n", y, y, y, y); } /home/westall ==> gcc -o p1 p1.c /home/westall ==> p1 X = 270 Y = N 78 4e 116

Asbeforethenumberofvaluesprintedbyfprintf()isdeterminedbythenumberofdistinctformatcodes.

64

ApplicationsofControlFlowMechanisms Inthissectionwewillexaminesomebasicalgorithmsthatemploythewhileandifcontrolmechanisms. Importantapplicationsincludecombinationsof:


Countingthings Accumulating(summing)totals Searchingforspecificvalues Recurrences

Exampleswillbebaseduponacommondesign: Initializeprogramstateandreadthefirstvalue While(thenumberofvaluesreadissatisfactory) updateprogramstateasneeded readnextvalue(s) Outputfinalstate Thetypeofstatethatmustbemaintainedbytheprogramthatmustbemaintainedbytheprogramis dependentonthenatureoftheproblemandcaninclude:


indicator(true/false)variables countervariables accumulator(sum)variables previousinputvalue(s)

65

Counting:Findthenumberofvaluesinafileofintegers Heretheprogramstatethatmustbemaintainedisacounterthatmaintainsthenumberofvaluesthat havereadsofar.Aseachnewvalueisobtained,thecounterisincrmentedbyone.Acommonmistake istoforgettoinitializethevalueofacounteroraccumulatorvariable!Thismistakeisparticularlyevil becauseitcanproduceaprogramthatsometimesworksandsometimesdoesnotdependingupon whetherthelastvaluetooccupythememoryusedthethecounteroraccumulatorwasa0.Thereforewe usethetechniqueproposedearliertopreventthis.

/* p6.c */ #include <stdio.h> int main() { int counter = 0; int value = 0; int howmany = 0;

// the number of values read // the value just read // howmany values were read

counter = 0; howmany = fscanf(stdin, "%d", &value); while (howmany == 1) { counter = counter + 1; howmany = fscanf(stdin, "%d", &value); } fprintf(stdout, "The number of values was %d \n", counter); return(0); }
Sample input: -11 12 -1 15 Sample output: The number of values was 4 Sample input: 14 12 9 Sample output: The number of values was 3

66

ConditionalCounting:Findthenumberof3'sinaninputfileofintegervalues Inthisprogramthestatethatmustbemaintainedisthenumberof3'sseensofar.Therefore,itis necessarytoconditiontheincrementingofcounteruponwhetherornotthevaluejustreadwasa3. Theif()statementisdesignedforpreciselythispurpose.

/* p5.c */ #include <stdio.h> int main() { int counter = 0; int value = 0; int howmany = 0; 1 2 3 4 5 6 7 8 }

// the number of three's we've seen // the value just read // howmany values were read

counter = 0; howmany = fscanf(stdin, "%d", &value); while (howmany == 1) { if (value == 3) counter = counter + 1; howmany = fscanf(stdin, "%d", &value); } fprintf(stdout, "The number of 3's was %d \n", counter); return(0);

Sample input: 1 2 3 2 1 3 4 Sample output: The number of 3's was 2 Sample input: 3 3 3 Sample output: The number of 3's was 3 Exercise:Buildatracetablefortheexecutionofthisprogramgivenaninputof 303

67

Accumulation:Findthesumofallofthenumbersinafile Heretheprogramstatethatmustbemaintainedisthesumofallvaluesthathaveseensofar.Aseach newvalueisobtained,itsvalueisaddedtothecurrentvalueofsum.Acommonmistakeistoforgetto initializethevalueofanaccumulatorvariable!

/* p6.c */ #include <stdio.h> int main() { int sum = 0; // the sum of the single digit numbers int value = 0; // the value just read int howmany = 0; // howmany values were read 1 2 3 { 4 5 } 6 7 } fprintf(stdout, "The sum was %d \n", sum); return(0); sum = sum + value; howmany = fscanf(stdin, "%d", &value); sum = 0; howmany = fscanf(stdin, "%d", &value); while (howmany == 1)

Sample input: -11 12 -1 15 Sample output: The sum was 15 Sample input: 14 12 9 Sample output: The sum was 35 Exercise:Buildatracetablefortheexecutionofthisprogramfortheinput 132

68

ConditionalAccumulation:Findthesumofallofthepositivenumbersinafile Heretheprogramstatethatmustbemaintainedisthesumofallthepositivevaluesthathaveseensofar. Aseachnewvalueisobtained,ifthevalueispositive,itisaddedtothecurrentvalueofsum.

/* p6.c */ #include <stdio.h> int main() { int sum = 0; // the sum of the positive numbers int value = 0; // the value just read int howmany = 0; // howmany values were read sum = 0; howmany = fscanf(stdin, "%d", &value); while (howmany == 1) { if (value > 0) sum = sum + value; howmany = fscanf(stdin, "%d", &value); } fprintf(stdout, "The sum was %d \n", sum); return(0); }
Sample input: -11 12 -1 15 Sample output: The sum was 27 Sample input: 14 12 9 Sample output: The sum was 35

69

ConditionalAccumulation:Findthesumofallofthesingledigitnumbersinafile Thefirstproblemwehavetoaddressiswhatisasingledigitnumber.Wemightinitiallythinkof0,1,2, ..9,butwewouldbeforgetting9,8,..1!!Sotheprogramstatethatmustbemaintainedisthesumof allvaluesbetween[9and9]thathaveseensofar.Aseachnewvalueisobtained,itmustbetestedto seeifitisasingledigitandifsoitsvalueisaddedtothecurrentvalueofsum.

/* p6.c */ #include <stdio.h> int main() { int sum = 0; // the sum of the single digit numbers int value = 0; // the value just read int howmany = 0; // howmany values were read sum = 0; howmany = fscanf(stdin, "%d", &value); while (howmany == 1) beusedincompound { if ((value > -10) && (value < 10)) conditionstoensureproper evaluationorder sum = sum + value; howmany = fscanf(stdin, "%d", &value); } fprintf(stdout, "The sum was %d \n", sum); return(0); }
Sample input: -11 -12 -1 15 2 7 Sample output: The sum was 8 Sample input: 14 12 99 Sample output: The sum was 0 ParenthesesshouldALWAYS

70

ConditionalAccumulation:Findthesumofallofthemultidigitnumbersinafile. Thefirstproblemwehavetoaddressiswhatisamultidigitdigitnumber.Theeasiestwaytodothisis tothinkthatitsisanumberthatisnotasingledigitnumber!!Thuswesimplyinsertthenotoperatorand anothersetofparenthesesintheifexpression.Wecouldalsousetheoroperatorwritetheifexpression as:

if ((value <= -10) || (value >= 10)) Thesetwostatements if (!((value > -10) && (value < 10))) areequivalent. /* p6.c */ #include <stdio.h> int main() { int sum = 0; // the sum of the multi-digit numbers int value = 0; // the value just read int howmany = 0; // howmany values were read sum = 0; howmany = fscanf(stdin, "%d", &value); while (howmany == 1) { if (!((value > -10) && (value < 10))) sum = sum + value; howmany = fscanf(stdin, "%d", &value); } fprintf(stdout, "The sum was %d \n", sum); return(0); }
Sample input: -11 -12 -1 5 2 7 Sample output: The sum was -24 Sample input: 1 2 -9 Sample output: The sum was 0

71

Searching:Writeaprogramthatreadsacollectionofintegersfromthestandardinput.Ifthecollection containsthevalue13printyestothestandardoutput.Otherwiseprintno. Thestatethatmustbemaintainedhereisanindicator(true/false)valuethatdefineswhetherornotthe programhasencounteredavalueof13initsinput.WeusethestandardClanguageconventionof representingfalsewithavalueof0andtruewithavalueof1.

/* p9.c */ #include <stdio.h> int main() { int found13 = 0; // indicator var: 1 => found a 13 int value = 0; // the value just read int howmany = 0; // howmany values were read found13 = 0; // haven't found it yet howmany = fscanf(stdin, "%d", &value); while (howmany == 1) { if (value == 13) found13 = 1; howmany = fscanf(stdin, "%d", &value); } if (found13 == 1) fprintf(stdout, "yes\n"); else fprintf(stdout, "no\n"); return(0); }
Wecouldalsosay if (found13) here. Exercise:Whatwouldthe outputbeifthisif/else statementwereincludedin thewhileloop??

Sample input: 1 2 4 13 77 12 1 Sample output: yes Note:Thisprogramcouldbeimprovedbyhavingitprintyesandterminateassoonasitfindsthefirst 13,buttheprogramaswritteniscorrect.Inthiscourseourfocuswillbebuildingcorrectprogramsthat mightrunmoreslowlythanoptimal...notincorrectonesthatrunreallyfast.

72

Searching:Findandprintthesmallestvalueinafilecontainingacollectionofintegers. Thisproblemissomewhatmoresubtlethandeterminingwhetherornotthefilecontainsa13. Herethestatethatmustbemaintainedisthesmallestvalueseensofar.Itistemptingtoinitializethisto alargenumber.However,thatapproachisnotagoodidea.Theproperwaytohandleproblemsofthis sortistoinitializethestatevariableminvaltothefirstvalueinthefile.

/* p11.c */ #include <stdio.h> int main() { int howmany = 0; int minval = 0; int value = 0;

// how many integers were read // the minimum value seen so far // current value

howmany = fscanf(stdin, "%d", &value); minval = value; while (howmany == 1) { if (minval > value) minval = value; howmany = fscanf(stdin, "%d", &value); } fprintf(stdout, "%d\n", minval); return(0); }
Sample input: 4 -100 5 Sample output: -100 Sample input: 10000 100000 200000 Sample output: 10000

73

Searching:Writeaprogramthatreadsacollectionofintegersfromthestandardinput.Ifthecollection containsavalueof13followedbya14printyestothestandardoutput.Otherwiseprintno. Thestatethatmustbemaintainedbythisprogramismorecomplexthanthatofthepreviousone.Here anindicatorofwhetherthesubsequence{13,14}hasorhasnotbeenseenyetmustbemaintained.Itis notpossibletodetermineifsuchisthecasebylookingatonlythecurrentinputvalue.Ifthecurrent inputvalueis14,theprogrammustalsoknowwhetherthepreviousinputvaluewas13.Therefore,itis necessarytoalwaysrememberthepreviousvalue.Thevariableoldisusedforthatpurpose. Initializationisalsomorecomplicated.

/* p10.c */ #include <stdio.h> int main() { int old = 0; int value = 0; int howmany = 0; int found = 0;

// // // //

previous value current value howmany values were read found {13, 14}

howmany = fscanf(stdin, "%d", &old); howmany = fscanf(stdin, "%d", &value);


Whathappenshereiftheinputfilecontainsonly0or1values?Shouldhowmanybetestedaftereach calltofscanf()??

74

Themainloopillustratestwoimportantprogrammingtechniques:

theifstatementwithcompoundcondtions(alwaysuseparentheses) awindowmechanismfordiscardingtheoldestvalueandupdatingolder,old,andvalue.

while (howmany == 1) { if ((old == 13) && (value == 14)) { found = 1; }

old = value; howmany = fscanf(stdin, "%d", &value); } if (found) fprintf(stdout, "yes\n"); else fprintf(stdout, "no\n"); return(0); }
Sample input: 11 12 13 15 12 no Sample input: 14 no

Theorderinwhichthese assignmentsaremadeis criticaltocorrectness.

Exercise:Modifytheprogramsothatitprintsyesifandonlyifthefilecontainsatleastone13atleast one14inANYorder. Exercise:Modifytheprogramsothatitprintsyesifandonlyifthefilecontainsoneormore13'sor14's (Thisisagoodmidtermexamtypeproblem). Exercise:Modifytheprogramsothatitprintsyesifandonlyifthefilecontainsexactlyone13,and exactlyone14

75

Searching:Writeaprogramthatreadsacollectionofintegersfromthestandardinput.Ifthecollection containsavalueof13followedbya14andthenby15printyestothestandardoutput.Otherwise printno. Thestatethatmustbemaintainedbythisprogramismorecomplexthanthatofthepreviousone.Here anindicatorofwhetherthesubsequence{13,14,15}hasorhasnotbeenseenyetmustbemaintained. However,itisclearlynotpossibletodetermineifsuchisthecasebylookingatonlythecurrentinput valueandthepreviousvalue.Ifthecurrentinputvalueis15,theprogrammustalsoknowwhetherthe previousinputvaluewas14andtheonebeforethatwas13.Therefore,itisnecessarytoalways rememberthetwopreviousvalues.Thevariablesoldandolderareusedforthatpurpose.Initialization isalsomorecomplicatedasallthreevalueholdersmustbeinitialized.

/* p10.c */ #include <stdio.h> int main() { int int int int int older = 0; old = 0; value = 0; howmany = 0; found = 0; // // // // // value before that previous value current value howmany values were read found target

howmany = fscanf(stdin, "%d", &older); howmany = fscanf(stdin, "%d", &old); howmany = fscanf(stdin, "%d", &value);
Whathappenshereiftheinputfilecontainsonly1or2values?Shouldhowmanybetestedaftereach calltofscanf()??

76

Themainloopillustratestwoimportantprogrammingtechniques:

theifstatementwithcompoundcondtions(alwaysuseparentheses) awindowmechanismfordiscardingtheoldestvalueandupdatingolder,old,andvalue.

while (howmany == 1) { if ((older == 13) && (old == 14) && (value == 15)) { found = 1; }

older = old; old = value; howmany = fscanf(stdin, "%d", &value); } if (found) fprintf(stdout, "yes\n"); else fprintf(stdout, "no\n"); return(0); }
Sample input: 11 12 13 15 12 no Sample input: 14 no Exercise:Modifytheprogramsothatitprintsyesifandonlyifthefilecontainsatleastone13atleast one14andatleastone15inANYorder. Exercise:Modifytheprogramsothatitprintsyesifandonlyifthefilecontainsoneormore13's,14'sor 15's.(Thisisagoodmidtermexamtypeproblem). Exercise:Modifytheprogramsothatitprintsyesifandonlyifthefilecontainsexactlyone13,exactly 14and,andexactlyone15inANYorder.

Theorderinwhichthese assignmentsaremadeis criticaltocorrectness.

77

Astatemachineapproach Manyproblemsthatinvolvesearchingforcomplexsubsetscanbesolvedusingastatemachine.The statemachineexistsinafinitenumberofdistinctstates. 13 0 1 14 2 15

not13

13

Foreachstateandpossibleinputvaluearulespecifiesthenewstate.Foreachstateitisnecessarythata rulespecifythenextstateforallpossibleinputs.Formappingthetabletocodeitsbesttoputthe specificinputsfirst. Existingstate 0 0 1 1 1 2 2 2 3 Inputvalue 13 other 13 14 other 14 13 other any Newstate 1 0 1 2 0 3 1 0 3

78

Theruletablecanmapdirectlytoanifstructure

if ((state == 0) && (value == 13)) state = 1; else if (state == 0) state = 0; else if ((state == 1) && (value == 13)) state = 1; else if ((state == 1) && (value == 14)) state = 2; : : :
Someclevermentalmanipulationcangreatlyreducethenumberoftests!Butoversimplificationcanbea threattocorrectness!!

79

Astatemachinebasedversionoftheprogram #include <stdio.h> /* We can also use a state machine model instead of */ /* remembering old values */ /* state meaning */ /* 0 looking for 13 */ /* 1 found 13 looking for 14 */ /* 2 found 14 looking for 15 */ /* 3 found 13, 14, 15 */

int main() { int state; int value; int howmany; int found = 0;

// current value // howmany values were read // found target

howmany = fscanf(stdin, "%d", &value); while ((howmany == 1) && (state != 3)) { if (value == 13) state = 1; else if ((state == 1) && (value == 14)) state = 2; else if ((state == 2) && (value == 15)) state = 3; else state = 0; howmany = fscanf(stdin, "%d", &value); } if (state == 3) fprintf(stdout, "yes\n"); else fprintf(stdout, "no\n"); return(0); }
80

Programswithnoinput Thelasttwoexamplesthatweconsiderinthissectionarethoseinwhichtheprogramhasnoinputatall! Inbothcasesthesetofallnonnegativeintegersisimplicitlytheinputandtheproblemthatweare attemptingtosolveistofindasubsetoftheintegersthathaveaparticularproperty. Searchingandenumerating:Printalloftheintegerslessthanorequalto10000thatareperfect squares. Thisisaprobleminwhichitpaystoengagethebrainbeforeengagingthefingers.Thefirstinstinctof mostpeopleistotrytotakethesquarerootofallintegersbetween1and10000andseeifthevalueisan integer.However,abetterapproachistojustcomputethemalldirectly.Inanyproblemof enumeration(printallofthenumbersthat....)itwillbenecessarytohavefprintf()withinthemainloop (possiblyguardedbyanif.Thisisincontrasttopreviousproblemsinwhichweprintedonlythefinal stateoftheprogramattheend. /* p8.c */ #include <stdio.h> int main() { int val = 1; int valsqr = 0;

// the current value in [1, 10000] // square of the value

valsqr = val * val; while (valsqr <= 10000) { fprintf(stdout, "%d\n", valsqr); /* Compute next value and next square */ val = val + 1; valsqr = val * val; } } Sample output 1 4 9 16 : 10000

81

Recurrences:Supposethefirsttwonumbersofasequenceofnumbersare{0,1}.Supposeeach subseqentnumberisthesumofitstwoimmediatepredecessors.Wemanuallycomputeafewtermsof thesequenceasfollows: 0+1=1>{0,1,1} 1+1=2>{0,1,1,2} 1+2=3>{0,1,1,2,3} 2+3=5>{0,1,1,2,3,5} 3+5=8>{0,1,1,2,3,5,8} Problem:Printthefirsttwentytermsofthissequence Hereweneedtorecyclethestrategyfromthe{13,14,15}probleminwhichwelearnedhowto rememberawindowofthreevalues. /* p7.c */ #include <stdio.h> int main() { int old; int older; int new; int counter;

// // // //

most recent old value; less recent old value; new value; number of values printed so far

older = 0; fprintf(stdout, "%d\n", older); old = 1; fprintf(stdout, "%d\n", old); Whynotuse counter = 2; while (counter <= 20) while (counter < 20) here { new = old + older; fprintf(stdout, "%d\n", new); counter = counter + 1; older = old; old = new; } }

82

Exercises 1. Write a program that reads one integer value at a time from the standard input. If the collection of input integers contains at least one 7 and at least one 11, the program should write "yes" (without the "s) to the standard output. Otherwise it should write "no" to the standard output. 7 7 4 5 3 no 7 7 4 2 11 24 yes 2. Write a program that reads one integer value at a time from the standard input. If the collection of input integers contains a 7 followed immediately by an 11, the program should write "yes" (without the "s) to the standard output. Otherwise it should write "no" to the standard output. 7 7 4 2 11 24 no 7 7 4 7 11 24 yes 3. Write a program that reads PAIRS of integers from the standard input. If the sum of the two integers in a pair is 10 then the program should print the pair to the standard output. 4 4 4 4 7 6 7 6

4. Write a program that reads PAIRS of integers from the standard input. The program should print the number of pairs whose sum is 20 to the standard output 21 -1 20 1 1 5. Write a program that reads PAIRS of integers from the standard input. The program should compute sum of each pair and print the largest sum found to the standard output. 2 2 2 2 8 3 6 2 -5

83

UseoftheCommandLine Outputredirection Thefprintf(stdout,)functionsendsitsoutputtoalogicalfilecommonlyknownasthestandardoutputor simplystdout. WhenaprogramisrunintheUnixenvironment,thelogicalfilestdoutisbydefaultassociatedwiththe screenbeingviewedbythepersonwhostartedtheprogram. The>operatormaybeusedonthecommandlinetocausethestandardoutputtoberedirectedtoadisk residentfile: acad/cs101/examples/notes ==> p8 > squares.txt Afilecreatedinthiswaymaybesubsequentlyviewedusingthecatcommand(oreditedusingatext editor). acad/cs101/examples ==> cat squares.txt | more 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225

84

Inputredirection IntheUnixenvironmentthestandardinputorstdinisbydefaultboundtothekeyboardoftheperson whorunsaprogram.Likethestdoutthestdinmayalsoberedirectedtoafile.Whenthestdinis redirected,theprogramreadsitsinputfromthediskfiletowhichthestdinhasbeenredirected.Tl redirectbothstdinandstdoutuse: p4 < p4in.txt > p4out.txt

wheninvokedinthismannerwhentheprograma.outreadsfromthestdinviascanf()or fscanf(stdin,.)theinputwillactuallybereadfromafilenamedp4in.txtandanydatawrittentothestdout willendupinthefilep4out.txt. acad/cs101/examples/notes ==> cat p4in.txt 3 4 5 6 7 8 9 11

acad/cs101/examples/notes ==> p4 < p4in.txt > p4out.txt


acad/cs101/examples/notes ==> cat p4out.txt 3 + 4 = 7 5 + 6 = 11 7 + 8 = 15 9 + 11 = 20

85

Othercontrolmechanisms Theforloop for(initexpression;continuecondition;updateexpression) { loopbody } Theinitexpressionisexecutedonetime Thecontinueconditionisevaluatedeachiterationoftheloopbeforetheloopbodyisexecuted. Theupdateexpressionisexecutedaftertheloopbodyisexecuted. Theloopbodyisexecutedifandonlyifthecontinueconditionistrue.

#include <stdio.h> int main() { int i; for (i = 5; i < 5; i = i + 1) printf("in body with i = %d \n", i); printf("at end with i = %d \n", i); for (i = 3; i < 5; i = i + 1) printf("in body with i = %d \n", i); printf("at end with i = %d \n", i); } acad/cs101/examples/notes ==> a.out at end with i = 5 in body with i = 3 in body with i = 4 at end with i = 5

86

Thedo...while()loop do { loopbody; }while(continuecondition); Thisstructureissimilarthethewhile()loop,butunlike,thewhileloop,


theloopbodywillalwaysbeexecutedatleastonetime. asemicolonmustfollowwhile(continuecondition);

#include <stdio.h> int main() { int i = 15; do { printf("in body with i = %d \n", i); i = i + 1; while (i < 10);

} }

acad/cs101/examples/notes ==> a.out in body with i = 15

87

Alteringcontrolflowwithinaloop Twosinglewordstatementsmaybeusedtoaltercontrolflowwithinaloop: Thebreakstatement exittheloopcontainingthebreakimmediately executioncontinuesatthelineimmediatelyfollowingthebreak #include<stdio.h>

int main() { int i; int j; for (i = 0; i < 3; i = i + 1) { for (j = 0; j < 3; j = j + 1) { printf("in body with (i, j) = (%d, %d)\n", i, j); if (i == j) break; } } } acad/cs101/examples/notes in body with (i, j) = (0, in body with (i, j) = (1, in body with (i, j) = (1, in body with (i, j) = (2, in body with (i, j) = (2, in body with (i, j) = (2, ==> a.out 0) 0) 1) 0) 1) 2)

Useofbreakisdiscouragedasproperdesigncanalmostalwaysproduceanequallysimple implementationwithrequiringbreak.

88

Hereisaanexampleofanequivalentprogramthatdoesnotcontainthebreak;

int main() { int i; int j; for (i = 0; i < 3; i = i + 1) { for (j = 0; j <= i; j = j + 1) { printf("in body with (i, j) = (%d, %d)\n", i, j); } } }

89

Thecontinuestatement causesatransferofcontroltotheendoftheloopbypassingtheremainderofthestatementsin thebodyoftheloop.

#include <stdio.h> #include <math.h> int main() { float val; float sqrtval; float sum; while (fscanf(stdin, "%f", &val) == 1) { printf("\n%8.2f ", val); if (val < 0) continue; sqrtval = sqrt(val); sum = sum + sqrtval; printf(" %8.2f %8.2f ", sqrtval, sum); } } 1.00 2.00 4.00 -4.00 5.00 1.00 1.41 2.00 2.24 1.00 2.41 4.41 6.65

Aswiththebreakstatement,itisalmostalwaysthecasethatuseofthecontinuestatementcanalwaysbe avoidedbycarefuldesign.

90

Theswitchstatement Similarinfunctiontotheif,elseif,elseifconstruct. switch(expression) { caseconst1: statement1; statement2; break; caseconst2: statement3; break; default: statement4; } Thisisequivalentto: if(expression==const1) { statement1; statement2: } elseif(expression==const2) { statement3; } else { statement4; } Differences withif/elseconst1andconst2maybeexpr1andexpr2 thebreakstatementmayberemovedintheswitchtoallowfallthrough.

91

Example:Countingareacodeinstances

#include <stdio.h> int main() { int areacode; int sum864 = 0; int sum803 = 0; int other = 0; while (scanf("%d", &areacode) == 1) { switch (area) { case 803: sum803 += 1; break; case 864: sum864 += 1; break; default: other += 1; } }
}

92

Thequestionmarkoperator condition?trueexpression:falseexpression Theconditionisevaluatedandiftruetrueexpressionwillbeexecutedandthevalueoftheentire expressionwillbethevalueofthetrueexpression. Otherwisethefalseexpressionwillbeexecutedandthevalueoftheentireexpressionwillbethe valueofthefalseexpression.

#include <stdio.h> #include <math.h> int main() { float val; float sqrtval; float sum; while (fscanf(stdin, "%f", &val) == 1) { printf("\n%8.2f %8.2f ", val, val > 0 ? sqrt(val): 0.0); } } 1.00 2.00 4.00 -4.00 5.00 1.00 1.41 2.00 0.00 2.24

93

Thecommaoperator e1,e2 Thisoperatorcanbeusedwhenitisdesiredtoplacetwo(ormore)expressionswhereoneisnormally used.Thevalueoftheexpressionisthevalueofe2.

for (i = 0, j = n - 1; i < n; i++, j--) { out[j] = in[i]; } #include <stdio.h> int in[10]; int out[10]; int main() { int i, j; int k; int m; for (i = 0, j = 9; i < 10; m++, k++, i++, j--) out[j] = in[i]; }

94

Functions FunctionsarethebuildingblocksofCprograms. Aprogramthatismorethan25lineslongshouldbecomprisedofseparatefunctionsthatarenotlonger than25lines!Advantagesoftheuseoffunctionsinclude:


Facilitatestopdowndesign Facilitatesbottomupimplementationandtesting Improvesprogramreadability...properfunctionnamingcanmakeaprogramnearlyself documenting. Reductionofnesting Facilitatesreuseofcode

FromtheLinuxkernelCodingStyleGuide Chapter5:Functions Functionsshouldbeshortandsweet,anddojustonething.Theyshouldfitononeortwoscreenfulsof text(theISO/ANSIscreensizeis80x24),anddoonethinganddothatwell. Themaximumlengthofafunctionisinverselyproportionaltothecomplexityandindentationlevelof thatfunction.So,ifyouhaveaconceptuallysimplefunctionthatisjustonelong(butsimple) casestatement,whereyouhavetodolotsofsmallthingsforalotofdifferentcases,it'sOKtohavea longerfunction. However,ifyouhaveacomplexfunction,andyoususpectthatalessthangiftedfirstyearhighschool studentmightnotevenunderstandwhatthefunctionisallabout,youshouldadheretothe maximumlimitsallthemoreclosely.Usehelperfunctionswithdescriptivenames(youcanaskthe compilertoinlinethemifyouthinkit'sperformancecritical,anditwillprobablydoabetterjobofit thanyouwouldhavedone). Anothermeasureofthefunctionisthenumberoflocalvariables.Theyshouldn'texceed510,oryou're doingsomethingwrong.Rethinkthefunction,andsplititintosmallerpieces.Ahumanbraincan generallyeasilykeeptrackofabout7differentthings,anythingmoreanditgetsconfused.Youknow you'rebrilliant,butmaybeyou'dliketounderstandwhatyoudid2weeksfromnow.

95

Functiondefinitions ACfunctioniscomprisedof4components.Thefirstthreearecollectivelyreferredtoasthefunction header.


thetypeofvaluereturnedbythefunction thenameofthefunction parenthesizeddeclarationoffunctionparameters(valuespassedtothefunctionbyitscaller). abasicblockcontaininglocalvariabledeclarationsandexecutablecode

int sum( int a, /* Values to be added... */ int b) /* these are provided by my caller */ { int total; total = a + b; return(total); }
Ifafunctionistoreturna valueitmustbeEXPLICITLY returnedinthisway forgettingtoreturntheresult isacommonerror.

96

Invokingafunction ACfunctioniscalledorinvokedbyjustusingitsnameanywhereavariableorconstantmightbeusedin anexpression:

int main() { int num = 0; num = sum(4, 5); num = num + sum(num, 6); }

Actualargumentspassedtothe functionmaybeconstantsor variables.Parameternamesused withinthefunctioncorrespond positionallytotheactual arguments!

Whenanexpressionisevaluated,thevaluereturnedbythefunctionreplacesitsinvocationinthe expression.Sohere,thefirstcalltosum()willreturna9and9willbeassignedtonum.Thenthe secondcallwillreturna15andsothefinalvalueofnumwillbe15. NOTES:

Localvariablenamespacesofdifferentfunctionsarecompletelydisjoint.Icandeclarealocal variablecalledtotalinmain()anditwillbecompletelyindependentofthetotalinsum. Thecorrespondencebetweentheformalparameters(a,andb)insum()withtheactualarguments (4,and5)inmain()ispositional.Whenthisprogramruns,ifweweretoinclude fprintf(stdout, "%d %d\n", a,b); insum(),wewouldseeaholdsthevalue4andbholds5duringthefirstcallandaholdsthe value9andbholdsthevalue6duringthesecondcall. Therefore,thenumberandtypesoftheactualargumentsusedwheninvokingafunctionshould exactlymatchtheformalparametersofthefunctiondefinition.

97

Parameterpassing Therearemanypossiblemechanismsbywhichparametersmaybepassed. ThestandardClanguageusespassbyvalueforpassingallscalardatatypes. Inthisapproachacopyoftheparameterisplacedonthestack.Thecalledfunctionisfreetomodifythe copyasitwishes,butthiswillhavenoeffectonthevalueheldbythecaller.

/* Parameter passing 1 */ int try_to_mod( int a) { printf("The address of try's a is %p\n", &a); a = 15; } int main() { int a = 20; printf("The address of main's a is %p\n", &a); try_to_mod(a); printf("a = %d \n", a); return(0); } class/215/examples ==> a.out The address of main's a is 0xbffff884 The address of try's a is 0xbffff870 a = 20
Notethatthetwovariables namedaoccupydifferent memorylocations.

98

TheorderoffunctionsinaCprogram: TheClanguagegenerallyrequiresthatallentitesbedefinedinaprogrambeforetheyarereferenced.

acad/cs101/examples/notes ==> cat p24.c int main() { x = sum(5, 3); int x; return(0); } int sum( int a, int b) { return(a + b); }
acad/cs101/examples/notes ==> gcc -Wall p25.c p25.c: In function main: p25.c:5: error: x undeclared (first use in this function) p25.c:5: error: (Each undeclared identifier is reported only once p25.c:5: error: for each function it appears in.) p25.c:5: warning: implicit declaration of function sum p25.c:6: warning: unused variable x

99

Forfunctionstherulemayappearsomewhatrelaxed. Thecompilermayproduceawarninginsteadofanerrorandproceedtocompiletheprogram. Manypeoplebelievethisrelaxationisabadidea. Herewefixthedeclarationofx

acad/cs101/examples/notes ==> int main() { int x; x = sum(5, 3); return(0); } int sum( int a, int b) { return(a + b); }
Thecompilationworksbutproducesanastygram. acad/cs101/examples/notes ==> gcc -Wall p24.c p24.c: In function main: p24.c:6: warning: implicit declaration of function sum acad/cs101/examples/notes ==>

100

Othertimesthecompilermaygenerateanerror. Theerroroccursbecausethedefaultreturntypeforanundeclaredfunctionisint.

Atline7sumwasimplicitlyassumedtoreturnint. Atline15sumwasseentoactuallyreturnunsignedchar

#include <stdio.h> int main() { int x;


Line7 x = sum(11, 3); fprintf(stdout, "%d \n", x); return(0);

} unsigned char sum( int a, int b) { return(a + b); }


Line15

acad/cs101/examples/notes ==> gcc -Wall p29.c p29.c: In function main: p29.c:7: warning: implicit declaration of function sum p29.c: At top level: p29.c:15: error: conflicting types for sum p29.c:7: error: previous implicit declaration of sum was here

101

Consequencesofignoringthewarning Eventhoughonlyawarningmayissuedbythecompiler,youmaygetadefectiveresultwhenthe functionisnotdefinedatthetimeitiscalled. Herethecompilercan'tknowwhattypeofparameterssumisexpecting.Therefore,itpassesitafloating pointconstant11.0andint3.Thesumfunctionassumesthatitsfirstparameterisanintandbigtrouble ensues.

#include <stdio.h> int main() { int x; x = sum(11.0, 3); printf("%d \n", x); return(0); } int sum( int a, int b) { return(a + b); }
acad/cs101/examples/notes ==> !gcc -Wall acad/cs101/examples/notes ==> gcc -Wall p27.c p27.c: In function main: p27.c:7: warning: implicit declaration of function sum Whentheprogramactuallyruns,thefloatingpointrepresentationof11.0istreatedasanintegerbysum andbigtroubleensues.

acad/cs101/examples/notes ==> a.out 1076232192

102

Avoidingthewarningsandtheerrors Onewaytodothisisjusttoorderfunctionssothatthedefinitionalwaysappearsbefore thefirstinvocationofthefunction. acad/cs101/examples/notes ==> cat p28.c

#include <stdio.h> int sum( int a, int b) { return(a + b); } int main() { int x; x = sum(11.0, 3); printf("%d \n", x); return(0); } acad/cs101/examples/notes ==> a.out 14

103

Functionprototypes Theorderingstrategyproposedonthepreviouspagecan'tsolvetheproblemintwosituations:

Thefunctiondefinitionislocatedinanothersourcemodule(.cfile) Twoormorefunctionsaremutuallyreferential.acallsbwhichcallscwhichcallsa.

Aprototypeisafunctionheaderwhichisfollowedbyasemicoloninsteadofabasicblock.The prototypetellsthecompiler:

thetypeofvaluereturnedbythefunction thetypeofeachparameter

Whenthecompilerhasthisinformationitwillgeneratecodethatwillautomagicallycoerceactual argumentstothecorrecttype. Anexampleprototypeforoursumfunctionisthus:

int sum(int a, int b);

104

Properuseofprototypes Whentheprototypeisplacedatthestartofthesourcemodule,theplacementofthefunctionbecomes irrelevantandevenselfreferentialfunctionsworkproperly.

#include <stdio.h> int sum(int a, int b); int main() { int x;


Theprototype

Compilernowgeneratescodeto convertthefloatvaluetoint beforepassingittosum!

x = sum(11.0, 3); printf("%d \n", x); return(0); } int sum( int a, int b) { return(a + b); } acad/cs101/examples/notes ==> gcc -Wall p30.c acad/cs101/examples/notes ==> a.out 14 acad/cs101/examples/notes ==>

105

Prototypesand.h(header)files IndevelopinglargescaleCprogramextensiveuseofbothCLibraryfunctionsanduserwritten functionsiscommon.Suchprogramsarealsocomprisedofmultiple.cfileswithintramodulefunction callsbeingcommon. Physicallyincludingalltheprototypesineachsourcemoduleandkeepingthemsyncrhonizedinthe eventofchangesisnotfeasible.Thereforefunctionheaderfilesareusedtoconsolidateprototypes.Such filesarecommonlycalled.hfilesandareincludedintothesourcefileatcompiletimebymeansofthe #includedirective.

Functionprototypesforstandardlibraryfunctionssuchasfscanf()andfprintf()arealways availableina.hfile.Failuretoincludetheproper.hfilecanleadtofailureofyourprogram.Use of<>notationinstructstheCcompilertosearchthestandardlibrary/usr/includeforthe.h file.

#include <stdio.h>

Programmersalsocreatetheirown.hfilescontainingprototypesforthefunctionsthattheywrite. Useof""notationinstructstheCcompilertolookinthecurrentworkingdirectory.

#include "myhdrs.h"

106

PPMImages Representationsofimagedata

Images(e.g.digitalphotos)consistofarectangulararrayofdiscretepictureelementscalled pixels. Animageconsistingof200rowsof300pixelsperrowcontains200x300=60,000individual pixels. ThePortablePixMap(.ppm)formatisaparticularlysimplewayusedtoencodearectangular image(picture)asuncompresseddatafile. The.ppmfilecanviewedwithanumberoftoolsincludingxv,display,andgimp. OtherwellknownformatsincludeJPEG(.jpg),TIFF(.tif),GIF(.gif),andPNG(.png)

107

Wecanuse.ppmtorepresenttwotypesofimages Grayscaleimages

correspondtoblack/whitephotographs eachpixelconsistsof1bytewhichshouldberepresentedasunsignedchar avalueof0issolidblack avalueof255isbrightwhite intermediatearegrayvaluesofincreasingbrightness.

Colorimages

correspondtocolorphotographs eachpixelconsistsof3byteswitheachbyterepresentedbyanunsignedchar thisformatiscallRGBthreebytesrepresentthe redcomponent greencomponent bluecomponent Whenred==green==blueagrayscalecolorisproduced.Thus,agrayscalepicturecanbe stored(somewhatinefficiently)inacolorppmfilebutacolorimagecanneverbestoredina grayscalefile. (255,255,255)isbrightwhite

Colorsareadditive

(255,255,0) =red+green=brightyellow (255,0,255) =red+blue=magenta(purple) (0,255,255) =blue+green=cyan(turquoise) (255,255,255)=red+green+blue=white

108

TheIrishnationalflag: Itcanbequitechallengingtofigureouttheprecise(R,G,B)intensitiesthatareneededtoproducea particularcolor.

AWikipedialookupcanhelp: Scheme RGB Hex Green 015499 #009A63 White 255255255 #FFFFFF Orange 25513061 #FF823D

109

PPMfilestructure ppmheader packedimagedata The.ppmheader

P6 # This is a comment # So is this... (X, y) dimensions follow 600 400 # Maximum value of a pixel. Ours will always be 255 255

TheP6indicatesthisisacolorimage(P5meansgrayscale) Thewidthoftheimageis600pixels Theheightoftheimageis400pixels The255isthemaximumvalueofapixel. Followingthe255isa\n(0x0a)character.

Theimagedata

Theredcomponentoftheupperleftpixelmustimmediatlyfollowthenewline. Theremustbeatotalof3x600x400=720,000bytesofdata.

110

Buildinga.ppmfile /* p12.c */ /* Construct a solid color image of the specified color */ /* Input data /* width in pixels height in pixels /* red value green value blue value #include <stdio.h> void make_ppm_header(int width, int height); void make_ppm_pixel(unsigned char r, unsigned char g, unsigned char b); void make_ppm_image(int width, int height, unsigned char r, unsigned char g, unsigned char b); int main( { int width; int height; int count = 0; unsigned int red; unsigned int green; unsigned int blue; /* Read image dimensions and pixel color */ */ */ */

fscanf(stdin, "%d %d", &width, &height); fscanf(stdin, "%d %d %d", &red, &green, &blue);
/* Create the .ppm the image file */

make_ppm_image(width, height, red, green, blue);


return(0); }

111

Writinga.ppmheader Themissionofmake_ppm_header()istoprintaproper.ppmheadertothestandardoutput.Asingle newlineshouldimmediatelyfollowthe255.Insertingextraspacecharactersproducescolorshiftsin whichredbecomesgreen,greenbecomesblueandbluebecomesred.!!

void make_ppm_header(int wd, int ht) { fprintf(stdout, "P6\n"); fprintf(stdout, "%d %d 255\n", wd, ht); return; }
Writingasinglepixel The%cformatcodemustbeusedtowritethepixelvalueasasinglebytewithoutconversiontoASCII textthat%dwouldproduce.Insertingextraspacecharactersherealsoproducescolorshifts.

void make_ppm_pixel(unsigned char r, unsigned char g, unsigned char b) { fprintf(stdout, "%c%c%c", r, g, b);
} %cformatpreventsdataconversion %cformatgenerates1byteofoutput noblankspacespermittedinformatstring

112

Creatingthe.ppmimage

void make_ppm_image(int width, int height, unsigned char r, unsigned char g, unsigned char b) { int count = 0;
/* Write the ppm header */

make_ppm_header(width, height); /* Write the ppm data */ while (count < (width * height)) { make_ppm_pixel( r, g, b); count = count + 1; } }

113

Sampleinputfile

class/101/examples ==> cat pic1.in 200 150 200


Widthandheightinpixels

64 224 IntensityofR,G,andBpixels.

Runningtheprogramwithinputandoutputredirection

p12 < pic1.in > pic1.ppm


Viewingthedatawithahexadecimal/ASCIIdumputilityshowsthattheheadercomprisesthefirst15 bytesofthefile.TheremainderofthefilecontainsthebytesC840E0repeated150x200=30,000 times.

od -t x1a pic1.ppm | more 0000000 50 36 0a 32 30 30 20 31 35 30 20 32 35 35 0a c8 P 6 nl 2 0 0 sp 1 5 0 sp 2 5 5 nl H 0000020 40 e0 c8 40 e0 c8 40 e0 c8 40 e0 c8 40 e0 c8 40 @ ` H @ ` H @ ` H @ ` H @ ` H @ 0000040 etc


Notethat 200base10isc8base16 64base10is40base16(andistheASCIIcodeforthe@character) 224base10isE0base16 Thelslcommandcommandcanbeusedtoshowthesizeoftheentirefile

class/101/examples ==> ls -l pic1.ppm -rw------- 1 westall iiimd 90015 Sep 13 13:03 pic1.ppm
15(headerlength) 3x200x150=90000(imagedata) 90015

114

Thisistheimage:

115

Buildinga.ppmfilepart2 /* p12b.c */ /* /* /* /* /* /* /* Construct a continuously varying color image The red component is a function of pixel row The blue component is a function of pixel col The blue component is 0 Input data width in pixels height in pixels red value green value blue value */ */ */ */ */ */ */

#include <stdio.h> void make_ppm_header(int width, int height); void make_ppm_row(int width, int height, int row); void make_ppm_image(int width, int height); int main() { int width; int height; /* Read image dimensions and pixel color */

fscanf(stdin, "%d %d", &width, &height);


/* Write the image data */

make_ppm_image(width, height);
return(0); }

116

Writinga.ppmheader The.ppmheaderwriterfunctionweusedbeforecanjustberecycled!Thisiswhatismeantby facilitatingreuseofcode!

void make_ppm_header(int wd, int ht) { fprintf(stdout, "P6\n"); fprintf(stdout, "%d %d 255\n", wd, ht); return; }
Thesameistrueofthepixelwriter

void make_ppm_pixel(unsigned char r, unsigned char g, unsigned char b) { fprintf(stdout, "%c%c%c", r, g, b); }

117

Sincethecolordependsonthe(row,col)locationofthepixel,wenowbuildtheimageonerowata time.Theredcomponentgetssteadilybrighterasweproceedtoptobottomintheimageandthegreen componentgetsbrighterasweproceedlefttoright.Thereforethebottomrightoftheimageshouldbe yellow.

void make_ppm_image(int width, int height) { int row = 0;


/* Write the ppm header */

make_ppm_header(width, height); /* now build the image one row at a time */

while (row < height) { make_ppm_row(width, height, row); row = row + 1; } } void make_ppm_row(int width, int height, int row) { int col = 0; unsigned char r; unsigned char g; while (col < width) { r = 255 * row / height; g = 255 * col / width; make_ppm_pixel(r, g, 0); col = col + 1; } }

118

119

Arrays Arraysprovideausefulwaytoaccessablockofadajcentmemorycellsusing

asinglenameand anumericindex

Anarrayof100integersisdeclaredasfollows:

int nums[100];
Thisdeclaration

reserves100ints=4x100bytesofcontinuousmemory thefirstintinthearrayisaccessedusingindex0

nums[0]

= x;

thelastintinthearrayisaccessedusingindex99

nums[99] = y;

Thetermwordwillsometimesbeusedasasynonymforint. Notewell:Thecontextinwhichthe"subscript"valueisuseddetermineswhatitmeans: Hereitmeansreserveme100ints:

int nums[100];
Hereitmeansassign15toaspecficelementinthearray

nums[100] = 15; Notethatsuchanassignmentisillegal,butitwillbeperformedanyway.This isaverycommonerrorinprogramsthatusearrays.

120

Variablesasarrayindices Therealpowerofthearrayisthecapabilitytouseavariabletoaccessindividualcells.Whatdoes thefollowingloopdo?

ndx = 0; while (ndx < 100) { nums[ndx] = ndx; ndx = ndx + 1; }


Howaboutthisone?

ndx = 0; nums[0] = 0; while (ndx < 100) { ndx = ndx + 1; nums[ndx] = nums[ndx - 1] + 1; }

121

Whentouseanarray Beginningprogrammerssometimesencounteranirresistableurgetousearrayswheretheyarenot needed.Pleaseresistthisurge! Reasonstouseanarray


Thealgorithmbeingusedrequiresrepeatedaccesstoawholecollectionofvalues(e.g.sorting). Economiesofscaleininput/outputexceedtheperformancepenaltyoffillingalargearray. Characterarraysarecommonlyusedtostorewordsorsentences.

Noneofthealgorithmsthatwerepreviouslypresentedforcounting,summing,searchingandrecurrences requireanarrayandnoarrayshouldbeusedinproblemsofthesetypes. Foranyproblemthatrequiresyoutoreadan"unknown"numberofvaluesfromstandardinput,thereis nowayforyoutoknowinadvancehowlargetomakethearray!!

122

Passingarraysasparameters WesawearlierthattheClanguageusespassbyvaluewhenscalartypessuchasintsarepassedas parameterstofunctions.Inthisapproach


Acopyofthevalueispassedtothefunction Thefunctionmaymodifiyitscopyoftheparameter butthevalueownedbythecallerofthefunctionwillnotbechanged.

ThestandardClanguageusespassbyaddressforpassingallarraydatatypes. Inthisapproachtheaddressofoftheparameterispassedtothefunction.

Thecalledfunctioncanusethisaddresstoaccessandmodifytheactualarraythatisownedbythe caller.

123

Arrayparameterexample Thenameb[]inthetry_to_mod()functionisknownasanaliasforthenamea[]inthemain()function becausebothnamesrefertothesamephysicalmemorylocations.

/* Parameter passing 2 */ int try_to_mod( int b[]) { printf("The address of try's b is %p\n", &b[0]); b[0]= 15; } int main() { int a[3];
Asseeninapreviousexample,an arraycanbepassedbysimply usingitsname:

try_to_mod(a);

a[0] = 20; a[1] = 30; printf("The address of main's a is %p\n", &a[0]); try_to_mod(&a[0]); printf("a[0] = %d \n", a[0]); return(0); } The address of main's a is 0xbf879624 The address of try's b is 0xbf879624 a[0] = 15
Unlikethepreviousexamplethe try_to_mod()functionsucceedsin changingdataownedbyitscaller. Notethatthevariablesnameda inmain()andbintry_to_mod() occupythesamememory locations.

124

Aproblemthatdoesrequiretheuseofanarray Theobjectiveofthisexampleistoreadinacollectionofvaluesfromthestandardinputandprintthose thatarelessthanorequaltotheaverage.Itisimpossibletoknowwhattheaverageisbeforeallthe valueshavebeenread.Thereforeitisnecessaryto"remember"allofthevaluesastheyarereadinby storingthemintoadjacentelementsinanarray. Thesolutionwillconsistofthreesteps.


Readvaluesintoanarrayanddeterminethenumberofvaluesread. Processthearraycomputingtheaveragevalue Processthearrayprintingvaluesthatarelessthanorequaltotheaverage

/* p14.c */ #include <stdio.h> int fill_array(int data[]); int find_average(int data[], int counter); void print_small(int data[], int counter, int avg); int main() { int values[100]; // holds up to 100 input values int counter; // the number of values read in int average; // average of the values counter = fill_array(values); average = find_average(values, counter); print_small(values, counter, average); return(0); }

125

Readinganunknownnumberofintegersintoanarray

int fill_array(int data[]) { int howmany; // howmany values were read /* Initialize and read first integer into array */ int counter = 0; howmany = fscanf(stdin, "%d", &data[0]);
Wecouldsay &data[counter] here

Inthisloopweaccomplishtwoobjectives:(1)theremainingvaluesarereadintothearrayand(2)the numberofvaluesismaintainedincounter..

while (howmany == 1) { counter = counter + 1; howmany = fscanf(stdin, "%d", &data[counter]); }


return(counter); }

Theorderofthethe twostatementsis criticaltocorrectness

Exercise:Whatwillhappenifweshouldchangetheorderofthetwostatementsintheloop?

126

Computingtheaverageoftheelementsinthearray Thisnextfunctionshowshowtocarryoutaspecificnumberofiterationsofaloop.Thisprocedure requirestwovariables:

counterthetotalnumberofiterationstobemadewhichisequaltothenumber ofelementsactuallyreadintothearray. ndxthecurrentiterationnumberwhichtakesonthevalues0,1,...counter1

int find_average( int data[], int counter)


{

int ndx = 0; int sum = 0; int average = 0;

Remembertoinitialize ndxandsum

/* When the read loop ends the value of counter */ /* is the number of elements in the array and */ /* so (counter 1) is the largest valid index */ while (ndx < counter) { sum = sum + data[ndx]; ndx = ndx + 1; } average = sum / counter; return(average);
} Wecan'tsay data[0] here

Forgettingtoincrementtheindexisa verycommonwaytoaccidentally createaninifiniteloop.

127

Printingtheonlythoseelementswhosevalueis<=totheaverage. Inthisfunctionanothercompletepassismadeovertheentirearray.Needlesstosayitiscriticalto remembertosetthevalueofndxto0beforestartingtheloop.

void print_small( int data[], int counter, int avg)


{

int ndx = 0;

Itisabsolutelynecesssaryto initializendx

while (ndx < counter) { if (data[ndx] <= avg) fprintf(stdout, "%d \n", ndx = ndx + 1; }
} Runningtheprogramproducestheexpectedoutput: ==> p14 1 10 2 9 3 8 4 7 5 6 1 2 3 4 5

data[ndx]);

128

Aproblemwithnopleasantsolution Whatifthenumberofvaluesintheinputfileis110?

Theprogramaswrittenwilloverwriteunallocatedmemorycausingeitheraprogramfaultor incorrectoutput! Oneapproachcouldbetojustaborttheprogramiftoomanynumbersareprovidedintheinput.

while (howmany == 1) { counter = counter + 1; if (counter == 100) { fprintf(stderr, Too many values \n); exit(-1); } Acalltotheexit()function howmany = fscanf(stdin, "%d", terminatestheprogram! &data[counter]);
}

129

Analternativeapproachistoprocessonlythefirst100values.

while ((howmany == 1) && (counter < 99)) { counter = counter + 1; howmany = fscanf(stdin, "%d", &data[counter]); }
Butobviouslywhatwewouldreallylikeisasolutionthatworksforallpossiblenumbersofinputvalues whichisanimportantreasontoavoidusinganarrayifyoudon'thaveto!!!

130

Usingexpressionsasarrayindexes Itisperfectlylegal(anduseful)touseexpressionsasindexesintoanarray. Forexamplewecanassignvaluestotable[4],table[5],andtable[6]inthefollowingways.

int table[10]; int k; k = 5; table[k 1] = 15; table[k] = 10; table[k + 1] = 5;


Swappingadajacentvaluesinaarrayisalsoausefulthingtodoinsortingoperations(andinthecodelab assignment);

int table[10]; int k; k = 5; if (table[k] > table[k + 1]) { table[k] = table[k + 1]; table[k + 1] = table[k]; }

Anincorrectapproachto swapping

Thisapproachwon'twork!Byplayinghumancomputerwecanseethatthevalueoftable[k]isdestroyed andlostforeverandbothtable[k]andtable[k+1]endupwiththeoriginalvalueoftable[k+1]. Exercise:Ifweinterchangetheorderoftheassignmentswillitfixtheproblem.Willtheresultsbe differentbutstillbroken?

131

Acorrectsolutiontotheswappingproblem Toavoiddestroyingthecontentsofoneoftheelementswemustuseatemporaryholdingvariable;

int table[10]; int k; int temp; k = 5; if (table[k] > table[k + 1]) { [1] temp = table[k]; [2] table[k] = table[k + 1]; [3] table[k + 1] = temp } table[k]
10 2

table[k + 1]
5

temp
??

[1] [2] [3]

temp gets the value 10 table[5] gets the value 5 table[6] getst the value 10

132

Designingasolutiontotheswappingproblemincodelab Inthisproblemyoumust examineeachpairofadjacentvaluesinthearray swaptheadjacentvaluesiftheyareoutoforder Whenconfrontingproblemssuchasthisoneitisveryusefulto

startbysolvingafewexamplesbyhand.

because

Untilyoufullyunderstandtheproblemandhowtosolveitmanuallyyoucan'thopetobeableto tellacomputerhowtodoit! Theexamplesyouhavesolvedbyhandmakeusefultestcases

Fromthisexampleyoumightinferthatallyouneedtodoismovethefirst(orlargest)valuetotheendof thearray. Initialstate: 2311122135 afterk=0 1123122135 afterk=1 1112232135 afterk=2 1112212335 afterk=3 1112213235 afterk=4 1112213523

NOTE:Therehappentobesix elementsinthisarrayso counter=6.Butthelargest valuekcantakeonis4.

Butthisoneshowsyouthatallthevaluescanmove. 419322517

133

Identifyingandfixingerrors Regardlessofyourapproacheitheryourinitialdesignoryourinitialimplementationorbotharelikelyto beWRONG. Theabilitytodiscoverwhatwhenwrongisjustasimportantastheabilitytodesignandimplementthe solution. Therearethreerationalapproachesandallthreecanbeuseful:

Playhumancomputerandmanuallywalkthroughyourcodenotingallchangesofstate.The primarydisadvantageofthisapproachisthatifyoumisunderstandthesemanticsofthelanguage, yourwalkthroughwillyieldincorrectresults. Instrumentyourprogramwithdiagnosticprintsdirectedtothestandarderror.

int table[10]; int k; int temp; if (table[k] > table[k + 1]) { fprintf(stderr, swapping elements %d and %d \n, k, k + 1); temp = table[k]; table[k] = table[k + 1]; table[k + 1] = temp fprintf(stderr, new value of table[%d] is %d \n, k, table[k]); fprintf(stderr, new value of table[%d] is %d \n, k + 1, table[k + 1]); }
Themaindisadvantageofthistechniqueisthepossiblityfordataoverload.Soyouwanttostart withshorttestcases.

Usegdb(myfavorite)

134

Initializingscalarsandarrays. Bothscalarvaluesandarraysmaybeinitializedwhentheyaredeclared:

int counter = 0; int sum = 0;


Bewareof int counter, sum = 0;

Irecommendusingthis approachinallprograms youwrite.

Itwillinitializesumbutnotcounter! AlthoughCsupportsit,Irecommendagainstdeclaringmultiplevariablesinasingledeclaration. Wheninitializinganarray,


theinitializersmustbeenclosedin{} youmayprovidefewerthanthesizeofthearray youmaynotprovidemorethanthesizeofthearray

int table[5] = {7, 9, 8};


Now

table[0] = 7, table[1] = 9, table[2] = 8, table[3] = ?, and table[4] = ?

135

Usinganarrayofcounters SupposeaninputfilecontainsacollectionofsingledigitnonnegativeintegersandIwanttocounthow many0's,1's,2'setcthatthereareinthecollection.Yourinitialinstinctmaybetocreateamaximally uglycollectionofifs

if (val == 0) counters[0]= counters[0] + 1; else if (val == 1) counters[1] = counters[1] + 1; else if (val == 2)

136

Theproperapproachissurprisinglysimpleandshouldresideforeverinyourmentaltoolchest.

#include <stdio.h> int main() { int counters[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // counters[0] counts 0's etc. int howmany = 0; // howmany values were read int ndx = 0; // array index howmany = fscanf(stdin, "%d", &ndx); while (howmany == 1) { counters[ndx] = counters[ndx] + 1; howmany = fscanf(stdin, "%d", &ndx); } }

137

Processingcharacterdata ThecharvariablecanholdtheASCIIencodingofasingleletterofthealphabet.

char x;
Toreadacharacterintoacharvariablethe%cformatcodecanbeused.Aswithintegersitisnecessary topasstheaddressofthevariabletofscanf()

howmany = fscanf(stdin, %c, &x);


Here,eachcalltofscanf()consumesexactlyonecharacter.Itwilltake17callstoconsumethefollowing data:15fortheletters,1fortheblankspace(0x20)andoneforthenewline(0x0a).

Hello there World


Printingthevalueofacharactervariablecanbeaccomplishedinananalogousway:

howmany = fprintf(stdout, %c, x);


Aswithintswepassvaluesnotaddressestofprintf(). Singlecharactervariableshavelimitedutilityinacomputerprogram.Wemightencodegender(M/F) inasinglecharacterbutweoftenneedtostorewholewordsorphrases. Wordsorphrasesarecommonlycalledcharacterstringsorsimplystrings.

138

Characterarrays

TheClanguagehasnocharacterstringdatatype. Insteadcharacterstringssuchaswordsandsentencesarestoredincharacterarrays. Abytehavingthevaluebinary0indicatestheendofthestring. The%sformatcodeisusedtoread/writestringswithfscanf/fprintf

/* p13.c */ #include <stdio.h> char word[6] = {'H', 'e', 'l', 'l', 'o', 0}; int main() { fprintf(stdout, "%s\n", &word[0]); }
class/101/examples ==> p13 Hello class/101/examples ==> Warning,leavingoffthetrailing0isfatal. Ausefulshorthand: Thenotationaboveisclearlytedious...soahandysubstituteisprovided.

Stringsmaybeimplicitlycreatedusingthedoublequoteoperator(aswehaveseeninformat strings).

char word[] = Hello;

139

Readingandprintingwiththe%sformat. Aswesawearlier,individualwhitespacecharactersareconsumedoneatatimewhilereadingwiththe %cformatcode.Thewhitespacecharactersaretreateddifferentlywhenusingthe%sformat.Withthe %sformateachtimeawhitespacecharacterappearsitisinterpretedasadelimiterendingthecurrent string.

howmany = fscanf(stdin, %s, word); howmany = fprintf(stdout, %s, word);

fscanfwillisreadintothearraylocationspecifed.Asbeforeitreturnsthenumberofelements read.Hereitwillreturn1andnotthelengthofthestringifitissuccessful. fscanf()willautomagicallyappendtherequiredbyteof0usedtoindicatetheendofmemory residentstrings fscanf()assumesthatthetheprogramhasprovidedsufficientspacetoholdtheentirestring.If thisisnottrue,memorywillbeoverwrittenandtheerrormayormaynotbedetectedbythe operatingsystem. fprintf()withthe%sformatcodedoesnotprintthe0bytethatterminatesthestring. Ifthe0byteismissingfprintf()willkeepprintingjunkuntilitreachesa0byte! Incontrastto%cand%dformatcodestheaddressofthestringispassedtoBOTHfscanf()and fprintf()

140

Astringprocessingprogram

/* p16.c */ #include <stdio.h> int main() { char c[100]; int howmany; howmany = fscanf(stdin, "%s", &c[0]); while (howmany == 1) { fprintf(stdout, "%s \n", &c[0]); howmany = fscanf(stdin, "%s", &c[0]); } return(0); } p14.in a b c d e acad/cs101/examples/notes ==> p16 < p14.in a b c d e

141

Multicharacterstrings Wecanseethatthisbehaviorpersistsevenwhenmulticharacterstringsareused: p16.in 0 - 61 62 63 20 64 65 66 09 67 68 69 0d 6a 6b 6c 6d a b c d e f g h i j k l m 10 - 6e 6f 0a 70 0a n o p

acad/cs101/examples/notes ==> p16 < p16.in abc def ghi jklmno p Wecanconfirmthatfscanf()willreturnthenumberofcompletestringsreadandnotthenumberof charactersinthestring.Thiswillalwaysbe1whenaformatcodecontainingasingle%ssucceeds.Itis howeverpossibletoreadmorethanonestringinasinglecalltofscanf().

howmany = fscanf(stdin, %s %s, word1, word2);


Ifthisreadsucceedsavalueof2willbereturned.

142

Readingmixedstringandintegerdata: Itiscommontoneedtoreadamixtureoftextandintegerdata.Thisiseasilydoneifandonlyifyou knowinadvancewheretoexpecttextandwheretoexpectintegers:

char id[16]; int dimension; howmany =fscanf(stdin, "%s %d", &id[0], &dimension); while (howmany == 2) { process_input_value(&id[0], &dimension); howmany =fscanf(stdin, "%s %d", id, &dimension); fprintf(stdout, %s %d\n, id, dimension); }
Theinputdata:

width 400 depth 600 height 200

143

StringFunctions

TheCStandardLibrarycontainsacollectionoffunctionsusedtomanipulatestrings. Someofthemoreusefulonesare:strcat,strchr,strcmp,strcpy,strcspn,strdup,strlen,strncat, strncmp,strncpy,strrchr,andstrstr. TousetheClibraryfunctionsbesuretoincludethefunctionprototypesbydoing: #include<string.h>

Fordetailsonhowtousethemusethemancommand. man strchr NAME strchr, strrchr, strchrnul - locate character in string SYNOPSIS #include <string.h> char *strchr(const char *s, int c); char *strrchr(const char *s, int c); RETURN VALUE The strchr() and strrchr() functions return a pointer to the matched character or NULL if the character is not found.

144

Buildingastringfunction Tousethestandardlibraryfunction,justcallitasyouwouldastandardI/Ofunctionpassingitproper parameters. Inlabwewillconstructourownversionofsomeofthem.Thestrchr()functionsearchesastringforthe occurrenceofaparticularcharacter.Ifthecharacterisfound,itsaddressisreturnedtothecaller. Otherwise0isreturned.

char *my_strchr( char str[], char c) { int ndx = 0; while (str[ndx] != 0) { if (str[ndx] == c) return(&str[ndx]); ndx = ndx + 1; } return(0); }

145

Commandlinearguments Itisoftenusefultopassargumentstoaprogramviathecommandline.Forexample, gcc -g -Wall -o p10 p10.c


Elementsofthecommandlinearepartitionedbywhitespacecharacters. Eachargumentisalwayspassedasastandard0terminatedcharacterstring.

InthiscasetheCcompiler,gcc,isbeingpassed6differentarguments. ArgumentValue

0 1 2 3 4 5

gcc -g -Wall -o p10 p10.c

146

Printingcommandlinearguments Whenaprogramisstartedfromthecommandline,thecharacterstrings(separatedbywhitespace) comprisingtheprogramnameandtheremainingargumentsarecopiedbytheOperatingSysteminto memoryspaceoccupiedbythenewprogramandatableorarrayofaddressesispassedtothemain function.Thesevaluescanbeaccessedbythemain()functionasshownbelow.

/* printargs.c */ #include <stdio.h> int main( int argc, /* number of command line arguments */ char *argv[]) /* array of addresses of the arguments */ { int ndx = 0; while (ndx < argc) { fprintf(stdout, "%s\n", argv[ndx]); ndx = ndx + 1; } }
Whentheprogramisinvokedasfollows: ==> printargs -Wall -o hello -g myprog.c Thefollowingoutputisproduced: printargs -Wall -o hello -g myprog.c

147

Processingnumericalarguments Supposeyoumissionistowriteaprogramnamedflagwhosefunctionistoproducea.ppmimageofa flag.Yourprogramistobeinvokedas:

flag width-of-flags-in-pixels --flag 800

Thevalue800ispassedtoyourprogramasacharacterstringconsistingofthreebytesofdata: 0x38,0x30,0x30 Tousethevalueinyourprogramyoumustconvertittoaninteger. Thesscanf()functionscansfromastringinsteadofafileandcandowhatyouneed.

#include <stdio.h> #include <stdlib.h> int main( int argc, /* number of cmd line args */ int *argv[]) /* array of arg addresses */ { int width = 0; int howmany = 0; if (argc < 2) { fprintf(stderr, "usage is flag width-in-pix\n"); exit(1); } howmany = sscanf(argv[1], "%d", &width); fprintf(stderr, "Width = %d \n", width); }

148

Structureddatatypes Sofarwehaveconsideredonlybasicdatatypes(int,char)andarraysofbasicdatatypes.Itisoften usefultohaveamechanismbywhichaprogrammermaycreatenewdatatypeswhichareaggregations ofpreviouslyexistingtypes.ThestructureprovidesusthiscapabilityintheClanguage. ACstructureisdeclaredasfollows:

struct pixel_type { unsigned char r; unsigned char g; unsigned char b; };


Thevariablescomprisingthestructure(r,g,b)areknownasmembersorelements.

Notethatstructpixel_typeisthenameofaprogrammerdefinedstructuredatatype. Itisnotthenameofavariable. Theuseof_typeasasuffixisnotrequiredbutcanhelpyourememberwhatnameisatypeand whatnameisavariable.

149

Creatinganinstanceofastructured. Tocreateaninstanceofanintorchartypeweusethetypenamefollowedbyaprogrammerselected variablename:

int sum; char code;


Thesameapproachisusedwithstructuretypes.Youjustgivethetypenameandfollowitbyavariable nameofyourchoosing. Todeclareaninstance(variable)oftypestructpixel_typeuse:

struct pixel_type pixel;


struct pixel_type pixel isthenameofthetype isthenameofavariableoftypestructpixel_type

Tosetorreferencecomponentsofthestructurepixelusetheform:

structure-instance-name.element-name pixel.r = 250; pixel.g = 250; pixel.b = 0; // make Mr. Pixel yellow

Thestructurevariablepixeloccupies3bytesofstorage.

150

Abad(butsyntacticallylegal)idea. TheClanguageissensitivetothecontextinwhichanameisusedandsothefollowingwillnotcause compileerrors,butitsaverybadpractice.

struct pix { unsigned char r; unsigned char g; unsigned char b; }; struct pix pix;

151

Usingthetypedeffacility Becauseitcanbepainfultohavetotypethewordstructoverandoverandover...TheClanguage makesitpossibletocreateastructuredtypeandgiveitastandalonetypename.

typedef struct pixel_type { unsigned char r; unsigned char g; unsigned char b; } pixel_t;
Atypenamecreatedwithtypedefmaybeusedjustlikeaprimitivetypeincreatinginstancesofthe structuredtype.

pixel_t newpix;

152

Arraysofstructures Wecanalsocreateanarrayofstucturetypes.

struct pixel_type { unsigned char r; unsigned char g; unsigned char b; }; struct pixel_type pixmap[600 * 800];
Toaccessanindividualelementofthearrayplacethesubscriptnexttothenameitindexes

pixmap[15].r = 250;

153

StructuresandArrayswithinstructures Itiscommonforstructurestocontainelementswhicharethemselvesstructuresorarraysofstructures. Inthesecasesthestructuredefinitionsshouldappearininsideoutorder.Thisisdonetocomplywith theusualruleofnotreferencinganamebeforeitisdefined.Sincetheimage_typestructurecontainsan elementwhichisapixel_typestructure.Thepixel_typedefinitionmustappearfirstinthesourcecode.

typedef struct pixel_type { unsigned char r; unsigned char g; unsigned char b; } pixel_t;
Forthemajorprojectinthecoursewillbebeconstructinganimagemanipulationprogram.Wewillbe usingastructureofthisform:

typedef struct image_type { char filename[64]; /* name of disk resident file */ char id[4]; /* P5 gray or P6 color */ int width; /* Width in pixel cols */ int height; /* depth in pixel rows */ pixel_t pixels[1024*1024]; /* The pixel data */ } image_t;
Asbeforewecancreateaninstanceofourimagestructurebydeclaring:

struct image_type input;


or

image_t output;
Eachoneofthesevariablesoccupies64+4+4+4+3*2 =3,145,804bytesofstorage!!! Itshouldbeclearthatwecannotprocessimageshavingmorethan1024*1024pixelsusingthis structure!
20

154

Accessingelementsoftheimage_tstructure Elementsofthestructuremaybeaccessedasdescribedbefore:

output.width = 640; output.height = 480; output.pixels[0].r = 255; // make first pixel yellow output.pixels[0].g = 255; output.pixels[0].b = 0;
Fordeterminingwheretoputthe[]andthe.usethefollowingrule: Subscriptsarerequiredincode

immediatelyfollowinganynamedeclaredasanarray andareallowednowhereelse!

Youmightalsobetemptedtotrysomethinglike:

output.filename

= "image1.ppm";

However,theClanguagehasnostringassignmentcapabilityandyouwillgetacompilererror. Youcanreadfilenamefromthestandardinputusing:

howmany = fscanf(stdin, "%s",


orcopyastringtoitbyusing:

&output.filename[0]);

strcpy(&output.filename[0],

image1.ppm);

155

Addressesofstructures: Becausestructurescanbesoverylarge Itisinefficienttopassthemasparametersfromonefunctiontoanother. Thereforewetypicallypasstheaddressofthestructureinsteadofthestructureitself. Passingtheaddressofastructurealsomakeitpossibleforthecalledfunctiontomodifyelements thestucture. Wecommonlycallavariablethatholdstheaddressofanothervariableapointer Todeclareanaddress/pointervariable


webeginthedeclarationwiththenameofthetypepointedto buttotellthecompilerthisisapointertothestructureandnotaninstanceofthestructurewe prefacethevariablenamewiththe*character

struct pixel_type *pixptr;


or(assumingweusedtypedef)

pixel_t *pixptr;
Toaccesselementsofthestructureviaapointerweusethe>operatorinsteadofthe.operator.

pixel_t *redptr; pixel_t redpix; redptr->r = 255; redptr->g = 0; redptr->b = 0;


but

redpix.r = 255; redpix.g = 0; redpix.b = 0;

156

Exampleofacompleteprogram Thestructuredefinitionmustprecedeanyuseofthestructuretype!

#include <stdio.h> typedef struct pixel_type { unsigned char r; unsigned char g; unsigned char b; } pixel_t; void make_cyan_pixel(pixel_t *pixptr);

Sincethe make_cyan_pixel()expects apointertothestructure wemustpasstheaddress ofthestructurehere

int main() { pixel_t pixel; // create an instance of a pixel make_cyan_pixel(&pixel); // pass address to function printf("%d %d %d \n", pixel.r, pixel.g, pixel.b); }
Accessingstructureelementsviaastructurepointer Toaccessanelementofastructureusingapointer weuse>insteadof. Sincethemain()functionis dealingwithaninstanceand make_cyan_pixel()isdealingwith apointertheymustaccessthe elementsdifferently.

void make_cyan_pixel( pixel_t *pixptr) { pixptr->r = 0; pixptr->g = 250; pixptr->b = 250; }

// make Mr. pixptr-> cyan

157

Usinga1dimensionalarraytorepresent2dimensionaldata A.ppmimageislogicallya2dimensionalentity.Theoriginisattheupperleftcorner.Thepositivex axisishorizonalpointingtotheright.Thepositiveyaxisisverticalpointingdownward. Thusthe(x,y)coordinatesofapixelareoftenalsoexpressedas(row,col)coordinateswherecol=x androw=y.Notethat(x,y)and(row,col)notationarebyconventioninconsistent:( Supposetheintegervariableswidthandheightrepresentthenumberofcolumnsandrowsintheimage. Supposeagrayscaleimageisbeingconstructedinthefollowingarray:

unsigned char image[300 * 200]; int width = 200; int height = 300; int ndx;
Ifwewishtocomputetheindexofthepixelatlocation(row,col)withintheimagethevalueofndx shouldbecomputedas:

ndx = row * width + col;


thuswecanrefertothegrayscalelevelofthepixelatlocation(row,col)eitheras:

image[ndx]
or

image[row * width + col];

Forexample,ifthevalueofwidthis10,thenthereare10pixelsperimagerow.Toreach thepixelwhose(row,column)addressis(3,5)itisnecessarytopassoverthreecompleterows (row0,row1,androw2)and5pixelsinrowthree(pixels0,1,2,3,and4). Thus,theoffsetofthepixelat(3,5)is3*10+5asshownabove.

158

Mappingtheoffsetwithinanimageto(row,col) Ifweknowthevalueofndx,theoffsetwithinanimagebutwishtocomputethevalueofrowandcol,we candividebothsidesoftheequationbywidthandseethat row remainder col width | ndx InintegerarithemeticinCthisbecomes

row = ndx / width; col = ndx row * numcols = ndx % width;


InC,theoperator%performsthemodfunction. a % bistheremainderwhenaisdividedbyb. Forexample 17 % 5 is 2. Theresultofa % bisanintegerintherange0, 1, 2, ... b-1 Thusonewaytobuildagrayscalepictureis:

ndx = 0; while (ndx < width * height) { row = ndx / numcols; col = ndx % numcols; image[ndx] = pix_value(height, width, row, col); ndx += 1; }
Herepix_value()isauserwrittenfunction.Itispassed

height,widthandrow,colcoordinatesofthepixeland computesandreturnsagrayscalevalue

159

Revisitingbuildinga.ppmfile Inthisexamplewewillrevisittheexampleonpage115ofthenotesusing

ourstructuredefinitionsand blockoutput

/* p12c.c */ /* /* /* /* /* /* /* Construct a continuously varying color image The red component is a function of pixel row The blue component is a function of pixel col The blue component is 0 Input data width in pixels height in pixels red value green value blue value
Programmerwritten.hfile containingsystemincludes, structuredefinitionsandfunction prototypedefinitions

*/ */ */ */ */ */ */

#include "image.h"

160

Theimage.hfile Itwillbeconvenienttogroupstructuredefinitionsandfunctionprototypesintoasinglesourcefilethat canbeincludedbymultiple.cfiles.

/* image.h */ #include #include #include #include #include <string.h> <stdlib.h> <stdio.h> <math.h> <malloc.h>
Includingsystemincludefileswithinthe programmerprovidedincludefileallows ustoavoidhavingtomanuallyaddthem toeachsourcecodemodule.

typedef struct pixel_type { unsigned char r; unsigned char g; unsigned char b; } pixel_t; typedef struct image_type { char filename[64]; /* name of disk resident file */ char id[4]; /* P5 gray or P6 color */ int width; /* Width in pixel cols */ int height; /* depth in pixel rows */ pixel_t pixels[1024*1024]; /* The pixel data */ } image_t;

void make_ppm_row(image_t *image, int row); void make_ppm_image(image_t *image); void make_ppm_pixel(image_t *image, int row, int col); void write_ppm_image(image_t *image); void write_ppm_header(FILE *out, image_t *image);

161

Themain()function Asbeforethemainfunctionreadsthedimensionsfromthestandardinput,butnowitmuststorethemin theimagestructure.

int main( int argc, char **argv) { image_t output; /* Make sure command line parameters were provided */ if (argc < 3) { fprintf(stderr, "Usage is a.out width height \n"); exit(1); } /* Read image dimensions from command line */ /* In the real world we should verify these are sensible */ sscanf(argv[1], "%d", &output.width); sscanf(argv[2], "%d", &output.height); strcpy(&output.id[0], "P6"); strcpy(&output.filename[0], "out1.ppm"); /* Create the image file */ make_ppm_image(&output); /* Write the image data to the output file */ write_ppm_image(&output); return(0); }

162

Constructingtheppmimage Aonerowatatimeapproachcanavoidnestedlooping

void make_ppm_image(image_t *img) { int row = 0; /* build the image one row at a time */

for (row = 0; row < img->height; row += 1) { make_ppm_row(img, row); } }


Constructingasinglerowoftheoutputimage

void make_ppm_row(image_t *img, int row) { int col = 0; for (col = 0; col < img->width; col += 1) { make_ppm_pixel(img, row, col); } }

163

Constructingasinglepixeloftheoutputimage Insteadofusingfprintf()todirectlyprintthepixelsweconstructtheentirepixelarrayintheimage structureinmemory!Thevariablendxisusedtoaccessthecorrectpixelstructure.Sincetherowand columnvaluealwaysstartwith0thecorrectoffsetintheonedimensionalpixelarrayis ndx=row*width+column

void make_ppm_pixel(image_t *img, int row, int col) { int ndx = row * img->width + col; img->pixels[ndx].r = 255 * row / img->height; img->pixels[ndx].g = 255 * col / img->width; img->pixels[ndx].b = 0; }

164

Amorecompleximage

void make_ppm_pixel(image_t *img, int row, int col) { int ndx = row * img->width + col; float radius = 0.3 * img->height; float cx, cy; float dx, dy; float dist; /* Compute the coordinates of the center pixel */ cy = img->height / 2; cx = img->width / 2; /* Compute x and y distances of this pixel from center */ dx = col cx; dy = row cy; /* Compute distance of this pixel from the center */ dist = sqrt(dx * dx + dy * dy); img->pixels[ndx].r = 255; img->pixels[ndx].g = 255; img->pixels[ndx].b = 255; /* If pixel is inside circle of radius 0.3 * height */ /* make it red. */ if (dist <= radius) { img->pixels[ndx].g = 0; img->pixels[ndx].b = 0; } }
Exercise:Whatdoestheaboveimagelooklike??

165

Writingtheppmimage Insteadofwritingtothestandardoutput,thisprogramwritesdirectlytoadiskfileofaspecfiedname. Todothisthefopen()functionmustbeusedtoopenthefile.Thefwrite()functionisusedtowritethe entireimageinasingleoperation.Thisismuchmoreefficientthatusingfprintf()foreverypixel.

void write_ppm_image(image_t *img) { int row = 0; int howmany = 0; FILE *out; /* Open the target output file for writing and */ /* verify success */ out = fopen(img->filename, "w"); if (out == 0) { fprintf(stderr, "Couldn't open %s \n", img->filename); exit(1);
} /* Write the ppm header */

write_ppm_header(out, img); /* Write the whole image in a single function call */ howmany = fwrite(img->pixels, sizeof(pixel_t), img->height * img->width, out); if (howmany != img->height * img->width) { fprintf(stderr, "Write error %d \n", howmany); exit(1);
}

166

Parametersoffopen() Thefirstparameterthatispassedtofopen()must0terminatedcharacterstringthatspecifiesthenameof afileondisk. Ifthenamedoesnotstartwith/,itisassumedtoberelativetothecurrentworkingdirectory.Suppose wewishtoreadorwriteafilenamedin.txtthatlivesindirectory/home/westall/projects Possiblewaysofspecifyingthefilenameinclude

"/home/westall/projects/in.txt"
-- worksregardlessofcurrentworkingdirectory

"projects/in.txt"
-- worksifandonlyifthecurrentworkingdirectoryis/home/westall

"in.txt"
-- worksifandonlyifthecurrentworkingdirectoryis/home/westall/projects Thesecondparameteristheaccessmode.Legalvaluesinclude "r" "w" "rw" "a" readonly writeonly readandwrite appendtoendofexistingfile

IntheM$worldab(forbinary)maybeappendedtodisablemanglingof\rand\ndata"rb" Thefopen()functionreturnsaFILE*addressvariable(pointer)whichmustbeassignedtothelocal variableyouwillusetoaccessthefile. ThetypeFILEiscreatedusingatypedefinstdio.hbuttheprogrammerdoesn'tneedtoknowtheinternal detailsofthestructure.Thistypeofstructureissometimescalledanabstractdatatype(ADT).

167

Blockinputandoutput Thefread()andfwrite()functionsarethemostefficientwaytoreadorwritelargeamountsofdata.

howmany = fread(location, element_size, number_of_elements, file_ptr); howmany = fwrite(location, element_size, number_of_elements, file_ptr); howmany = fwrite(img->pixels, sizeof(pixel_t), img->height * img->width, out);

Thefirstparameteristheaddressofthedatatobewrittenormemoryareatobereadinto. Thesecondparameterpassedtothefunctionisthesizeofabasicdataelementtobereador written Thethirdparameteristhenumberofelements.tobereadorwritten. TheforthparameteristhepointertotheFILEstructurethatwasreturnedbyfopen().

168

Writingthe.ppmheader Theonlychangesneededareto besuretowritetothefileoutandnotstdout usetheelementsiftheimage_tstructure

void write_ppm_header(FILE *out, image_t *im) { fprintf(out, "%s\n", im->id); fprintf(out, "%d %d 255\n", im->width, im->height); return; }

169

Usingdynamicallyallocatedpixelarraystorage Adisadvantageoftheapproachusedinthepreviousprogramisthatimageslargerthan1megapixel cannotbecreatedwithoutchangingtheimage_tstructureandrecompilingtheprogram.Wecanfixthis byusingadynamicallyallocatedarrayofpixels. Wereplacethepixelarrayintheimagestructurewithanaddressvariablethatpointstoanarrayofpixels asshownbelow:

typedef struct image_type { char filename[64]; char id[4]; int width; int height; pixel_t *pixels; } image_t;

/* /* /* /* /*

name of disk resident file P5 gray or P6 color Width in pixel cols depth in pixel rows Address of the pixel data

*/ */ */ */ */

Thisstructurenowoccupiesonly80bytes!! and Wecandynamicallycreatethepixelarraytohaveexactlythecorrectsize.

170

Dynamicallocationofthepixelbuffer Theonlycodechangeneededistodynamicallyallocatethepixelarrayusingthemalloc()function whichallocatestherequestedarrayandreturnsitsaddress.Theremainderoftheprogramiscompletely unchanged!

int main() { image_t output; /* Read image dimensions and pixel color */ fscanf(stdin, "%d %d", &output.width, &output.height); output.pixels = (pixel_t *)malloc(sizeof(pixel_t) * output.width * output.height); if (output.pixels == 0) { fprintf(stderr, "Malloc failed \n"); exit(1); } }

171

Useofsizeof()withstructures Thesizeof()facilityshouldalwaysbeusedindynamicallyallocationstorageforstructureddatatypesand inreadingandwritingthem. Ifthesizeofthestructurechangesastheprogramevolves,thencallstomalloc(),fread(),fwrite()will (generally)adaptcorrectly. However,itissomewhateasytodothisincorrectly.

struct pixel_type { unsigned char r; unsigned char g; unsigned char b; }; struct pixel_type pix; struct pixel_type *pixptr;
Thefollowingallhavethevalue3

sizeof(pix) sizeof(struct pixel_type) sizeof(*pixptr)


Thefollowinghasthevalue4

sizeof(struct pixel_type *) sizeof(pixptr)


Confusingtheseisacommonsourceofsomeverynastyprogrambugs.

172

Readingppmimage Whenreadinga.ppmfileitisnecessaryto:

verifythatthefilecontainsacolor(P6)ppmimage savethedimensionsintheimage_tstructure allocatethepixelbuffer readthepixeldataintothepixelbuffer

void read_ppm_image( image_t *image) { FILE *in; int howmany = 0; /* Open the target output file for reading and */ /* verify success */ in = fopen(image->filename, "r"); if (in == 0) { perror("open failed"); fprintf(stderr, "Couldn't open %s \n", image->filename); exit(1); }
Theperrorfunctionwillprint asomewhathelpfulerror messageexplainingthecause oftheproblem.

173

/* Read the ppm header */ read_ppm_header(in, image); /* Allocate the pixel buffer */ image->pixels = (pixel_t *)malloc(sizeof(pixel_t) * image->height * image->width); /* Write the data and ensure correct amount written */ howmany = fread(image->pixels, sizeof(pixel_t), image->height * image->width, in); if (howmany != image->height * image->width) { fprintf(stderr, "Read error wanted %d got %d \n", image->height * image->width, howmany); exit(1); } }

174

Readingtheppmheader

Theheaderisnotfixedformat. Itcancontainanynumberofcommentlines. Allcommentlinesmustbeginwith#

void read_ppm_header( FILE *in, struct image_type *image) { int vals[3]; // temporarily holds width, height, 255 int count = 0; // numeric values read so far char buf[256]; // trash can int howmany; int not_toomany = 1000; // loop limiter /* Read the P6 (or P5) if grayscale */ howmany = fscanf(in, "%s", &image->id[0]); if ((howmany != 1) || (image->id[0] != 'P')) { fprintf(stderr, "read_ppmhdr bad magic number \n"); exit(1); }

175

/* /* /* /*

Now consume the width, height, and maximum pixel */ value from the header... fscanf() may fail due */ to comments in the header.. When it does fgets() */ will consume the remaining data on the line. */ while ((count < 3) && (not_toomany)) { howmany = fscanf(in, "%d", &vals[count]); if (howmany == 0) fgets(buf, 256, in); else count = count + 1; not_toomany = not_toomany - 1; }

/* If something bad went wrong, abort now */ if ((not_toomany == 0) || (count != 3)) { fprintf(stderr, "read_ppm_header: broken header \n"); exit(1); }; /* This consumes the byte of whitespace following 255 */ /* and saves the image dimensions in the proper places */ fscanf(in, "%c", &buf[0]); image->width = vals[0]; image->height = vals[1]; }

176

Exercise:Createaprogramthatwillmakeamirrorimageoftheinputimage.Itshouldconsistof4 separatefiles:image.h(describedpreviously);image.c(containsread_ppm_image();and write_ppm_image());main.c(givenbelow)andmirror.c(describedbelow).

#include "image.h" int main( int argc, char *argv[]) { image_t input; image_t output; strcpy(&input.filename[0], argv[1]); strcpy(&output.filename[0], argv[2]); read_ppm_image(&input); mirror_ppm_image(&input, &output); write_ppm_image(&output); }

177

Themirror.cfile Forallproblemsitisusefultoviewtheprocessasbuildingtheoutputimageonepixelatatime.Startat thetopoftheimage(row0)andproceedacrossanddown.Thevalueofrowandcolumnwillalways representthecurrentlocationintheoutputimage.Thebasicstructureherefollowstheprevious example:make_ppm_image().

void mirror_ppm_image( image_t *inimg, image_t *outimg) {


Beforeprocessingrowsoftheoutputimage,itisnecessaryto copywidth,heightandidfrominimgtooutimg allocatethepixelbufferfortheoutputimage

} void mirror_ppm_row( image_t *inimg, image_t *outimg, int row) // current row in input and output image { } void mirror_ppm_pixel( image_t *inimg, image_t *outimg, int row, // current row in input and output image int col) // current column in OUTPUT image {

178

Structuresasfunctionparametersandreturnvalues Passingstructures,especiallypointerstostructures,isapowerfulwayforonefunctiontopassalarge amountofinformationtoanotherusingasmallnumberofparameters. Structuresasparameters Theexampleprogrambelowillustratestwoaspectsofpassingstructures

Astruct,likeanintmaybepassedasaparametertoafunction.

Infacttheprocessworksjustlikepassinganintinthat:

Thecompletestructureiscopiedontothestackwhichisveryinefficientforalargestructure. Thefunctionisunabletomodifythecaller'scopyofthestructurevariable

179

Thetry_to_mod()functionstructureversion Thisexampledemonstratesthatacalledfunctioncannotmodifythecaller'scopy.

struct work_type { int w; }; void try_to_mod(struct work_type q) { printf("q.w = %d \n", q.w); q.w = 1000; } int main() { struct work_type z; z.w = 99; try_to_mod(z); printf("z.w = %d\n", z.w); } acad/cs101/examples/notes ==> gcc -o p41 p41.c acad/cs101/examples/notes ==> p41 q.w = 99 z.w = 99 <valuewasnotmodified acad/cs101/examples/notes ==> cat p41.c

180

Avoidpassinglargestructuresasparameters!! Anotherdisadvantageofpassingstructuresbyvalueisthatcopyinglargestructuresontothestack

isveryinefficientand mayevencauseprogramfailureduetostackoverflow.

struct work_type { int w[1024 * 1024]; }; /* This fellow will cause a total of 4 Terabytes /* to be copied onto the stack. struct work_type fourMB; for (i = 0; i < 1000000; i++) slow_call(fourMB);
NotethatintheClanguageitisnotpossibletopassanarraybyvalueonthestack..Thustheonlywayto producethisbehavioristoembedthearrayinastructure!

*/ */

181

Passingpointerstostructures InwellwrittenCprogramsitismuchmorecommontopassapointertoastructureratherthanpassing theentirestructure.Twoprincipleadvantagesofdoingsoinclude:

Passingapointerrequiresthatonlyasinglewordbypushedonthestackregardlessofhowlarge thestructureis. Thecalledfunctioncannowmodifyelementsofthestructure. Itispossibleforsomeelementsofthestructuretobeinputparameters(e.g.img>filename) while Otherelementsmaybeoutputvalues(img>width,img>depth)tobefilledinbythecalled function. Whenapointerispassed,thecalledfunctionmustuse>insteadof.toaccessstructure elements.

182

Thetry_to_mod()functionwithpointertostructure Aswasthecasewhenanarrayaddressispassedtoafunction,thestructurecanalsobemodifiedwhen theaddressofthestructureinsteadofthestructureitselfispassed.

/* p42.c */ struct work_type { int w; }; void fun(struct work_type *q) { printf("q->w = %d \n", q->w); q->w = 1000; } int main() { struct work_type z; z.w = 99; fun(&z); printf("z.w = %d\n", z.w); } acad/cs101/examples/notes ==> gcc -o p42 p42.c acad/cs101/examples/notes ==> p42 q->w = 99 z.w = 1000 <---- value has been modified

183

Theconstqualifier Butwhatifyoudon'twanttherecepienttobeabletomodifythestructure?Thentheconstqualifiercan beprefixedtotheparameter.

/* p43.c */ struct work_type { int w; }; void fun(const struct work_type *q) { printf("q->w = %d \n", q->w); q->w = 1000; } int main() { struct work_type z; z.w = 99; fun(&z); printf("z.w = %d\n", z.w); } acad/cs101/examples/notes ==> gcc -g p43.c p43.c: In function `fun': p43.c:11: error: assignment of read-only member `w'

184

Thisformofprotectionisnotespeciallystrongandiseasilybypassed

/* p44.c */ struct work_type { int w; }; void fun(const struct work_type *q) { struct work_type *local; local = (struct work_type *)q; printf("q->w = %d \n", q->w); local->w = 1000; } int main() { struct work_type z; z.w = 99; fun(&z); printf("z.w = %d\n", z.w); } acad/cs101/examples/notes ==> gcc -g p44.c -o p44 acad/cs101/examples/notes ==> p44 q->w = 99 z.w = 1000

185

Structuresasreturnvaluesfromfunctions

Scalarvalues(ints,floats,etc)areefficientlyreturnedinCPUregisters Historically,structureassignmentsandthereturnofstructureswerenotsupportedinC. Butthereturnofpointersincludingpointerstostructureshasalwaysbeensupported. Nowbothstructureassignmentandstructurereturnsaresupported

/* p31.c */ struct work_type { int w; }; struct work_type *fun(void) { struct work_type work; work.w = 99; return(&work); } int main() { struct work_type *q; q = fun(); printf("%d \n", q->w); } acad/cs101/examples/notes ==> gcc -o p31 p31.c p31.c: In function `fun': p31.c:13: warning: function returns address of local variable acad/cs101/examples/notes ==> p31 99
Thereasonforthewarningisthatthefunctionisreturningapointertoavariablethatwasallocatedon thestackduringexecutionofthefunction.Suchvariablesaresubjecttobeingwipedoutbysubsequent functioncalls. 186

Thisexampleshowsthiscanindeedoccur.

/* p32.c */ struct work_type { int w; }; struct work_type *fun(void) { struct work_type work; work.w = 99; return(&work); } int fun2(int v) { int w; int x; w = v; x = w * v; return(x); } int main() { struct work_type *q; int z = 12; q = fun(); z = fun2(z); printf("%d \n", q->w); }
acad/cs101/examples/notes ==> gcc -o p32 p32.c p32.c: In function `fun': p32.c:13: warning: function returns address of local variable acad/cs101/examples/notes ==> p32 -1077017368

187

Returnofstructures Itispossibleforafunctiontoreturnastructure.Thisfacilitydependsuponthestructureassignment mechanismswhichcopiesonecompletestructuretoanother.


Thisavoidstheunsafeconditionassociatedwithreturningapointerbut incursthepossiblyextremepenaltyofcopyingaverylargestructure

/* p33.c */ struct work_type { int w; }; struct work_type fun(void) { struct work_type work; work.w = 99; return(work); } int main() { struct work_type q; struct work_type z; q = fun(); z = q; printf("%d %d \n", q.w, z.w); }
acad/cs101/examples/notes ==> gcc -g -o p33 p33.c acad/cs101/examples/notes ==> p33 99 99 acad/cs101/examples/notes ==>

188

Summary Passing/returninginstancesofstructurespotentiallyincursbigoverhead Passing/returningpointersincursalmostnooverhead Accidentalmodificationscanbepreventedwithconst

Therefore,itisrecommendedthatyouneverpassnorreturnaninstanceofastructureunlessyou haveaverygoodreasonfordoingso.

Thisproblemdoesn'tarisewitharrays.

TheonlywaytopassanarraybyvalueintheClanguageistoembeditinastructure!! Theonlywaytoreturnanarrayistoembeditinastructure

189

Floatingpoint Unlikeint,floatingpointvaluescanrepresentfractionalentitiesandarethusmoreusefulinmost scientficcomputations. TherearetwotypesoffloatingpointvariablesintheClanguage.

float double
Exampledeclarations

32 bits 64 bits

float a; double c;
Floatingpointconstantscanbeexpressedintwoways Decimalnumber Scientificnotation 1024.123 1.024123e+3

avogadro = 6.02214199e+23;

190

Formatcodesforfloatingpointinputandoutput: Therearethreebasicspecifierse,f,andg.Eachmustbeprefacedbytheletterlifadoubleprecision valueisbeingreadorprinted.Theusageofeachofthe6possiblecodesinoutputisshownbelow.

%f %lf %e
%le

singleprecisionfloatingpointnumber(float)indecimal doubleprecisionfloatingpointnumber(double)indecimal singleprecisioninscientificnotation doubleprecisioninscientificnotation singleprecisionwithautonotationselection doubleprecisionwithautonotationselection

notation notation

%g %lg

Thesizeofanoutputfieldandthenumberofdigitstotherightofthedecimalmayalsobespecifiedin outputformatstrings.Specifyingbothfieldwidthanddecimaldigitsisusefulandoftennecessarywhen tryingtomakeoutputvalues"lineup"properlyincolumns.Themodifiersshouldnotbeusedforinput.

191

Floatingpointinput Forinputitisnotnecessarytodistinguish,e,f,andg.Anyofthecodescanbeusedtoreaddecimalor scientificinputvalues.Itisnecessarytouselifreadingdoubleprecesion.

int howmany; double fpvalues[2]; howmany = fscanf(stdin, %lf %lf, &fpvalue[0], &fpvalue[1]);

Floatingpointoutput

howmany = fprintf(stdout, %8.3lf %8.3lf \n, fpvalue[0], fpvalue[1]); %8.3lfmeansprintwithfieldwidthof8characterswith3digitstotherightofthedecimal

192

Internalrepresentationoffloatingpointnumbers TheIEEE(InstituteofElectricalandElectronicsEngineers)hasproducedastandardforfloatingpoint arithmetic.Thisstandardspecifieshowsingleprecision(32bit)anddoubleprecision(64bit)floating pointnumbersaretoberepresented,aswellashowarithmeticshouldbecarriedoutonthem. Single Precision TheIEEEsingleprecisionfloatingpointstandardrepresentationrequiresa32bitword,whichmaybe representedasnumberedfrom0to31,lefttoright.


Thefirstbitisthesignbit,S,1meansnegativeand0meanspositive. thenexteightbitsaretheexponentbits,'E', andthefinal23bitsarethefraction'F':

S EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF 0 1 8 9 31
ThevalueVrepresentedbythewordmaybedeterminedasfollows:

IfE=255andFisnonzero,thenV=NaN("Notanumber") IfE=255andFiszeroandSis1,thenV=Infinity IfE=255andFiszeroandSis0,thenV=Infinity If0<E<255thenV=(1)**S*2**(E127)*(1.F)where"1.F"isintendedtorepresentthebinary numbercreatedbyprefixingFwithanimplicitleading1andabinarypoint. IfE=0andFisnonzero,thenV=(1)**S*2**(126)*(0.F)Theseare"unnormalized"values. IfE=0andFiszeroandSis1,thenV=0 IfE=0andFiszeroandSis0,thenV=0

193

Specificexamples
0 00000000 00000000000000000000000 = 0 1 00000000 00000000000000000000000 = -0 0 11111111 00000000000000000000000 = Infinity 1 11111111 00000000000000000000000 = -Infinity 0 11111111 00000100000000000000000 = NaN 1 11111111 00100010001001010101010 = NaN 0 10000000 00000000000000000000000 = +1 * 2**(128-127) * 1.0 = 2 0 10000001 10100000000000000000000 = +1 * 2**(129-127) * 1.101 = 6.5 1 10000001 10100000000000000000000 = -1 * 2**(129-127) * 1.101 = -6.5 0 00000001 00000000000000000000000 = +1 * 2**(1-127) * 1.0 = 2**(-126) 0 00000000 10000000000000000000000 = +1 * 2**(-126) * 0.1 = 2**(-127) 0 00000000 00000000000000000000001 = +1 * 2**(-126) * 0.00000000000000000000001 = 2**(-149) (Smallest positive value)

194

Floatingpointversusinteger

Integervaluesareequallyspacedonthenumberline. Thedistancebetweenanytwoadjacentintsis1

Thisisnottrueoffloatingpoint

Onehalfofallthediffrentfloatingpointnumbersliebetween0and1! Thelargestpositiveintis2^311. Thelargestpostitivefloatisontheorderof2^127 Floatsevensmallerthanthelargestpositiveinthavegreaterthanintegralspacing!

#include <stdio.h> int main() { float x; float y; x = 123456789; y = 123456791; printf("%12.0f %12.0f \n", x, y); } ==> ./a.out
123456792 123456792 Thisproblemoccursbecausewhilepositiveintshave31significantbits,floatshaveonly329=23.

195

Doubleprecision Theproblemcanberectifiedbytheuseofdoubleprecisionvariables. Theyaredeclaredasfollows: double x; Thearereadorprintedusingthe%lf,%le,or%lgformatcodes. Itisveryimportantthe%lffamilyofformatcodesbeusedwithandonlywithdoubles.

196

Mixingfloatandintinanexpression

Differentsetsofhardwarecomponentsareusedtoperformintegeroperationsandfloatingpoint operations. NOHARDWAREexiststhatcanadd,subtract,multiply.ordivideanintegeroperandanda floatingpointoperand. Therefore,wheneveranexpressioncontainsmixedmode(integerandfloatingpointoperands)the integeroperandisalwaysinvisiblyconvertedtofloatingpointbeforetheoperationisperformed. Amixedmodeexample.

int x; x = (5 / 2.0) * 4;

Ifaninteger2wereusedinthisexpression,itsvaluewouldbe8. Since2.0isafloatingpointnumber

The5willbeconvertedtofloatingpointandtheresultofthedivisionwillbe2.5 Thenthe4willbeconvertedtofloatingpointandthefinalresultwillbe10.0 Finallythe10.0willbeconvertedbacktoint10beforebeingassignedwithx.

197

Parsing Parsingistheprocessofconsumingelementsofsomeinputlanguageandmappingtheinformation containedthereintoausabledatastructure.Wewilldefineaninputlanguageforspecifyingoperations onimagesandbuildaparserthatcandigestthelanguage. Anexampleofa"sentence"inourlanguageis:

fade { in0 dive.ppm factor 0.4 out faded_dive.ppm }


Thisalternativevariantspecifiesthesameinformation.

fade { factor in0 out }

0.4 dive.ppm faded_dive.ppm

Thefollowingrulesdefineourlanguage

Wordsinasentencemustbeseparatedbyoneormorewhitespacecharacters. Eachsentencestartswiththenameofanimageoperation(fade,gray,mirror,blend,etc...) Theoperationmustbefollowedbythe{character. Followingthe{areavariablenumberofclausesoftheformparameternameparametervalues Theparameternames(likeimageoperations)arepredefinedreservedwordsinthelanguage. Foreachparametername,thetypeandnumberofparametervaluesisalwaysthesame. Aparameternameparametervaluesclausemaybefollowedbyeitheranotherparametername parametervaluesclauseorthe}characterwhichindicatestheendofasentence.

198

Implicationsoftheruleset

Thefactthatwordsinthelanguagemustbeseparatedbywhitespacemakesitpossibletousethe fscanf(stdin,...)functionwiththe%s,%d,%lfformatcodestoconsumetext,integersand doubleprecisionvaluesrespectively. Wecannotassumeanythingabouttheorderinwhichtheparameternameparametervaluesets appear. Wehaveapotentialneedtodealwithmissingparameters(e.g.factormissinginafadeoperation) or Extraneousparameters(e.g.factorspecified)inagrayoperation.

Thetargetdatastructure Forconsistencyandeaseofrememberingweusethesamenamesforeachparameterinbothour languageanditscorrespondingelementinthefollowingstructure.

typedef struct imageop_type { int opcode; // index of operation name char in0[64]; // primary input image char in1[64]; // secondary input image char out[64]; // output image int dims[2]; // dims of output for resize double factor; // factor for gray or blend } imageop_t;

199

Tablelookups Tablelookupswillcompriseanimportantelementoftheprocessing. Atableofaddressesofcharacterstringscanbeconstructedasfollows:

char *first_names[] = { "michael", "jeffrey", "shannon", "logan", "joshua", }; char *op_names[] = { "mirror", "gray", "fade", }; char *param_names[] = { "in0", "in1", "out", "dims", "factor", };

200

Thetable_lookup()function Youwillbuildatablelookupfunctionwhosemissionistoreturntheindexoftheparameterstringname intheparametertable.Itshouldreturn(1)ifthestringisnotinthetable. Thestrcmp()functionfromthestandardstringlibraryshouldbeusedtocomparethestringpointedtoby table[i]withthestringnamefori=0tocount1.

int table_lookup(char *table[], int count, char name[]) { }


Invokingtablelookup:

int count = sizeof(first_names)/sizeof(first_names[0]); int ndx = table_lookup(first_names, count, "shannon"); int ndx = table_lookup(first_names, count, "gray");

Inthefirstcasethevalueofndxshouldbesetto2. Inthesecondcaseitshouldbesetto1. Settingcountasshownisimportant..Itmakesiteasytoaddorremovetableentrieswithout havingtochangethecodethatinvokestable_lookup.

201

Buildingthecompleteparser Aninvocationoftheparserwillattempttoreadexactlyonesentenceinourinputlanguage.Theparser willreadfromthestandardinput(stdin).Laterwewillwanttobeabletoperformmultipleimage operationsinasinglerunofourprogram,butthatwillrequiremultipleinvocationsoftheparser!

int parser(imageop_t *op) {


readastringfromstdinintointocharacterarrayopname; if(nodataisread)//endoffilereached return(1); attempttolookupopameintheop_names[]table iflookupfailsprinttheinvalidopnameandexit. savethetableindexthatwasreturnedinop>opcode. invokeconsume_parameters(op)toconsumethedelimiters{},parameternames,and parametervalues. return(0);

202

Consumingtheparametersofaparticularoperation

int consume_parameters(imageop_t *op) {


readastringfromstdinintointocharacterarraypname; ensurethatpname[0]isthe{character. Ifnotprintpnameinanerrormessageandexit readastringfromstdinintointocharacterarraypname; while(pname[0]isnotthe}characterandnotendoffile) { attempttolookuppnameintheparam_names[]table ifthatfailsprinttheinvalidpnameinanerrormessageandexit. consume_parameter_values(op, table_index); readnextstringfromstdinintointocharacterarraypname; } return(0); }

203

Consumingthevaluesassociatedwithaparameter Thereexistfarmoreelegantwaystoconsumetheparametervalues,butthesimplestwayisviaabig switchstatement:

int consume_parameter_values(imageop_t *op, int ndx) { int howmany;

switch (ndx) { case 0: // param is in0 howmany = fscanf(stdin, "%s", op->in0); if (howmany != 1)
Printerrormessageandexit.

break; case 1: // param is in1 howmany = fscanf(stdin, "%s" op->in1); if (howmany != 1)


Printerrormessageandexit.

break; etc } }

204

Usingpointer(address)variableswithnonstructuredtypes Apointerisavariablewhosevalueistheaddressofanothervariable. Thesizeofthepointervariablemustbenbitswhere2 bytesisthesizeoftheaddressspace.Forthe Intelx86andSPARCsystems,addressspacesizeis4GBandwehaven=32. Theamountofspacerequiredtoholdapointervariableisalways4bytesonthesehardwareplatforms andisnotrelatedtothesizeoftheentitytowhichitpoints. Wehavepreviouslydescribedhowtodeclareapointertoastructuretype:


n

image_t

*img;

andhowtouseittoaccesselementsofthestructure:

img->width = 600;

205

Pointerstobasictypes Apointertoabasictypeindefinedinthesameway.

int short unsigned char int

*a; *b; *c; x;

Toassigntheaddressofavariableoftheappropriatetypetothepointertothepointervariable,specify thenameofthepointervariableontheleftandtheaddressofvariablepointedtoontheright.The followingassignmentstorestheaddressofxina.

a=&x;//assigntheaddressofxtopointera
Unlikestructuredtypes,basictypesdon'thaveelements!!Soa>ismeaningless. Torefertotheentitytowhichthepointerpointsprepend*

*a=132;//assignthevalue132tox(sinceanowpointstox)
Insummary

whenweuseastandaloneainaprogram,wearereferringtothepointeritself. whenweusea*ainaprogram,wearereferringwhateverapointsto..

206

Initializationofpointers Likeallvariablespointersmustbeinitializedbeforetheyareused. /* p17.c */

/* Example of a common error: failure to intialize */ /* a pointer before using it.. This program is */ /* is FATALLY flawed.... */ main() { int *ptr; *ptr = 99;

OOPS

printf("val of *ptr = %d and ptr is %p \n", *ptr, ptr); }


Butunfortunately,onLinuxthisprogramappearstowork! class/215/examples ==> p17 val of *ptr = 99 and ptr is 0x40015360 Theprogramappearstoworkbecausetheaddress0x40015360justhappenstobealegaladdressinthe addressspaceofthisprogram.Unfortunately,itmaybetheaddressofsomeothervariablewhosevalue isnow99!!! Thissituationiscommonlyreferredtoasaloosepointerandbugssuchasthesemaybeveryhardto find.

207

Modifyingtheprogramcausesfailure Wecanconvertthebugfromlatentbyactivebychangingthelocationofthevariableptr. Herewemovethelocationofthepointervariabledownthestackbydeclaringanarrayofsize200.

class/215/examples ==> cat p18.c /* p17.c */ /* Example of a common error: failure to intialize */ /* a pointer before using it */ main() { int int

a[200]; *ptr;

// force ptr to live down in uninit land

printf("val of ptr is %p \n", ptr); *ptr = 99; printf("val of *ptr = %d and ptr is %p \n", *ptr, ptr); } class/215/examples ==> p18 val of ptr is (nil) class/215/examples ==>
Notethatinthiscasethesecondprintf()isnotreachedbecausetheprogramsegfaultedanddiedwhenit illegallyattemptedtoassignthevalue99tomemorylocation0(nil).

208

Minimizinglatentloosepointerproblems

Neverdeclareapointerwithoutintializingitinthe declaration.
int *ptr = NULL; or int *ptr = 0;

NeveruseNULLassynonymforintegerorfloat0.

209

Usinggdbtofindthepointoffailure: Thegdbdebuggerisahandytoolforidentifyingthelocationatwhichaprogramfailed. Tousethedebuggeritisnecessarytocompilewiththegoption.

class/215/examples ==> gcc -g -o p18 p18.c


Tostartthedebuggerusethegdbcommandandspecifytheprogramname

class/215/examples ==> gdb p18


Atthe(gdb)promptyouwillusuallywanttotellthedebuggertohalttheprogramwhenitreachesthe startofthemain()function.Thebcommandisshortforbreakpointandtellsthedebuggerwheretostop theprogram.Afterafunctionisentered,sourcecodelinenumberscanbeusedtospecifybreakpoints.

(gdb) b main Breakpoint 1 at 0x804833b: file p18.c, line 11.

210

Tostarttheprogramusetheruncommand:

(gdb) run Starting program: /local/westall/class/215/examples/p18


Whentheprogramreachesabreakpointgdbwilltellyouanddisplaythenextlineofcodetobeexecuted.

Breakpoint 1, main () at p18.c:11 11 printf("val of ptr is %p \n", ptr);


Usethenextcommandtoexecuteasinglesourcestatement.Thenextcommandwilltreatafunctioncall asasinglestatementandnotsinglestepintothefunctionbeingcalled.Ifyouwanttosinglestepthrough thefunctionusethestepcommandtostepintoit.Theoutputoftheprintf()isintermixedwithgdb's outputandisshowninbluebelow.

(gdb) next val of ptr is (nil) 13 *ptr = 99;

211

Enteringnextagainwillcausetheprogramtoexecutetheflawedassignment.gdbwillshowyoutheline thatcausedtheerror(line#13). (gdb) next Program received signal SIGSEGV, Segmentation fault. 0x08048357 in main () at p18.c:13 13 *ptr = 99; Thewherecommandcanshowyouwherethefailureoccured(alongwithacompletefunctionactivation trace. Thewherecommandwillshowyou exactlywhatlinetheprogramdied (gdb) where #0 0x08048357 in main () at p18.c:13 on. #1 0x40049917 in __libc_start_main () from /lib/libc.so.6 (gdb)

212

Thelistcommandletsyouviewthelinesofcodesurroundingthepointoffailure.

(gdb) list 8 int a[200]; //force ptr to live in uninitland 9 int *ptr; 10 11 printf("val of ptr is %p \n", ptr); 12 13 *ptr = 99; 14 15 printf("val of *ptr = %d and ptr is %p \n", *ptr, ptr); 16 }

213

Toprintthevalueofavariableusetheprintcommand.

(gdb) print ptr $1 = (int *) 0x0


Attemptingtoprintwhatptrpointstoreaffirmswhattheproblemis:

(gdb) print *ptr Cannot access memory at address 0x0


Usetheq(quit)commandtoterminategdb

(gdb) quit The program is running. class/215/examples ==>

Exit anyway? (y or n) y

214

Correctuseofthepointer IntheClanguage,variablesthataredeclaredwithinanybasicblockareallocatedontheruntimestack atthetimethebasicblockisactivated. /* p19.c */ main() { int y; int* ptr; static int a; ptr = &y; Addresses of y and ptr 0xbffff894 0xbffff890

// assign the address of y to the pointer

*ptr = 99;

// assign 99 to what the pointer points to (y)

printf("y = %d ptr = %p addr of ptr = %p \n", y, ptr, &ptr); ptr = &a; printf("The address of a is %p \n", ptr); } class/215/examples ==> p17 y = 99 ptr = 0xbffff894 addr of ptr = 0xbffff890 The address of a is 0x804958c Notethataisheapresidentandhasanaddressfarremovedfromthestackresidentyandptr.

215

Usingapointertoprocessanarrayofnumbers Thisprogramdemonstratesandhowtoprocessadynamicallyallocatedarrayofintsusingapointer. /* p24.c */ /* This program illustrates the use of pointers in */ /* reading and processing an array of integers */ /* It also shows how to access command line args */ /* An upper bound on the number of ints to be read */ /* must be specified on the command line.. */ /* p2 1000 */ #include <stdio.h> int main( int argc, char* argv[]) {

/* number of command line args */ /* array of pointers to args */

int *base; int *loc;


int int int int

// points to start of the array // current array location

max; // maximum number of values to read in count; // actual number of values read in largest; // largest number in the array i; // want to hold 100 ints maximum;

max = 100;

216

Allocatingstorageforthearrayofints.

Themalloc()(memoryallocate)functioniscanbeusedtodynamicallyallocateanareaof memorytobeusedasanarray. Theparameterpassedtomalloc()isthesizeoftheareatobeallocated

inbytes.

Therefore,ifwewanttoallocatespacefor100ints,wemustpass400tomalloc()becauseeach intoccupies4bytes. Thesizeof()facilityshouldalwaysbeusedinsteadofcodingtheconstant4.

count = 0; base = (int *)malloc(sizeof(int) * max); loc = base;


Sizeofasingle element Numberofelements (ints)tobeallocated.

Thisoperationiscalledacast. Itisusedwhenapointerto onetypeofentityisassigned toapointertoanothertypeof entity.WithoutittheC compilerwilldeliveranasty warningmessage.

217

Readingtheinputvalues Notethatlocandnot&locispassedtofscanf().Whatwouldhappenifaprogrammeraccidentally'' passed&loc?? Alsonotethataseachintegerisreadlocisincrementedby1andnotby4.TheClanguage automagicallytakesintoaccountthesizeoftheelementpointedtowhendoingpointerarithmetic!If youweretofprintf()thevalueoflocusingthepformatcode,youwouldseethattheactualvaluedoes increaseby4eachtimeitisincremented.

/* Read in the integers from standard input making sure */ /* not to overrun the size of the array */ while (fscanf(stdin, "%d", loc) == 1) { loc = loc + 1; count = count + 1; if (count == max) break; }
Youmayalsousearraynotationwithavariabledeclaredasapointer:

&base[count] and (base + count) and loc


areallthreedifferentnamesforthesamememorylocation!Therefore,thereadloopcouldalsobe written:(unlessthedirectionstellyoutousepointernotation)

while (fscanf(stdin, "%d", &base[count]) == 1) { count = count + 1; if (count == max) break; }

218

Identifyingthelargestvalueinthearray Beforestartingthesearchforthelargestnumberthevalueoflocisresettopointtothebaseofthearray.

loc = base; // point loc to the start of the array largest = *loc; // init largest to the first value loc = loc + 1; i = 1; while (i < count) { if (largest < *loc) largest = *loc; loc = loc + 1; i = i + 1; } printf("Largest was %d \n", largest);
} Theforloop TheClanguageprovidesausefulmechanismforconsolidatingtheinitialize,test,andincrement operationsthatarerequiredwhenexecutingaloopaspecifiednumberoftimes.

for (i = 1; i < count; i = i + 1) { if (largest < *loc) largest = *loc; loc = loc + 1; }

219

Functionsthatmodifyvariablesoftheircallers Wesawearlierthatwhenafunctiontriestomodifyaparameterthatispassedtoit,ithasnoeffectonthe callerscopyofthatvariable. Acallercanallowafunctiontomodifyitsvariablesbypassingapointertothevalue: Afunctionthatswapstwointegervalues

int swap( int *x, int *y) { int temp; temp = *x; *x = *y; *y = temp; }
Acallerofthisfunctionwouldoperateasfollows.

ndx = 0; while (ndx < (count 1)) { if (a[ndx] < a[ndx + 1]) swap(&a[ndx], &a[ndx + 1]); ndx = ndx + 1; }

220

Alternativenotations Ifaisanarrayorapointerthenames&a[ndx]anda+ndxareequivalent.Thereforetheabove codemaybewrittenusingpointernotationas:

ndx = 0; while (ndx < (count 1)) { if (*(a + ndx) < *(a + ndx + 1)) swap(a + ndx, a + ndx + 1); ndx = ndx + 1; }
Afullypointerizedversion Themostefficientandreadablewaytoconstructaloopofthistypeisuseatravelingpointerandavoid thearraybaseaddressplusindexcomputationsaltogether.

int *loc = a;

// same as a + 0 == &a[0]

for (ndx = 0; ndx < (count 1); ndx = ndx+1) { if (*(loc) < *(loc + 1)) swap(loc, loc + 1); loc = loc + 1; }

221

TwodimensionalarraysinC Twodimensionalarraysaredeclaredasfollows:

double

x[4][5];

Thedeclarationabovecreates4x5=20doubleprecisionvalues.Specificelementsareaccessedas follows:

x[2][3] = sqrt(10.0);
Aswithsingledimensionarraysthelegalvaluesofthefirstsubscriptare0,1,2,3andthelegalvaluesof thesecondare0,1,2,3,4 Thevaluesarestoredinthefollowingorder:

x[0][0],

x[0][1], ... x[0][4],

x[1][0], .., x[3][4]

Thisisconsistentwithsubscriptingtechniquescommonlyusedinmathematicsinwhichthefirst subscriptcommonlyrepresentsarowandthesecondrepresentsacolumn.

222

Usingarraynamesaspointers Recallthatifwecreateaonedimensionalarray: int a[5]; wecanusethenameaasasynonymfor&a[0]. Inananalogouswaythenamex[i]isasynonymfor&x[i][0]. Thusthevalueofeitherx[i]or&x[i][0]istheaddressoftheithrowofthearray.

223

Readingandwritingof2Darraycontents: Inthisexamplewereadina3x3arrayreadingoneentirerowwitheachread:

double tab[3][3]; int howmany = 0; int i; for (i = 0; i < 3; i++) { howmany += fscanf(stdin, "%lf %lf %lf", &tab[i][0], &tab[i][1], &tab[i][2]); }
orequivalently

double tab[3][3]; int howmany = 0; int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { howmany += fscanf(stdin, "%lf", &tab[i][j]); } }

224

Thenametab[i]representsapointertotheithrowofthearray.Sothefollowingformwillalsowork.

int howmany = 0; double tab[3][3]; int i; for (i = 0; i < 3; i++) { howmany += fscanf(stdin, "%f %f %f", tab[i], tab[i] + 1, tab[i] + 2); }

225

Readingandwritingof2Darraycontents:

double tab[3][3]; int i; for (i = 0; i < 3; i++) { fprintf(stderr, "%6.2lf %6.2lf %6.2lf \n", tab[i][0], tab[i][1], tab[i][2]); }
Toagainprintthearraywith3elementsperlinethedoublynestedloopmaybeusedbut caremustbetakentoprintthenewlineinthecorrectspot.

double tab[3][3]; int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { fprintf(stderr, "%6.2lf", tab[i][j]); } fprintf(stderr, "\n"); }

226

Arraysasoperators Arraysareoftenusedasfunctionsthattransformvectorsintwodimensionalorthreedimensionalspace. Infactanylinearfunctiononanndimensionalvectorspacemayberepresentedasmultiplicationbyann xnarraywheremultiplicationisdefinedasfollows: matrix vector operatoroperandresult 01210x1+1x2+2x38 345x2=3x1+3x2+5x3=24 67836x1+7x2+8x344 Thisoperationofmultiplyingavectorbyamatrixmaybecodedasfollows:

void xform( double oper[3][3], double *opnd, double *result) { int i, j;

// operator matrix // operand vector // result vector

for (i = 0; i < 3; i++) // i is row index { *(result + i) = 0; // initialize sum! for (j = 0; j < 3; j++) //j is col index { *(result + i) += oper[i][j] * *(opnd + j); } } }

227

Colorspacetransformations RecallthatinlabtheNTSCstandardfortransmittingcolorTVsignalswasintroduced.Thecomponent ofinterestinthelabwastheluminance.Theothertwoelementsofthesignalcarrythecolorinformation andarecalledredandbluechrominance.Forhistoricalreasonstheluminanceiscommonlyreferredto asYandthechrominancevaluesasCbCrorsimplyUV.ThetransformationfromRGBspacetoYUV spaceislinearandthuscanberepresentedbya3x3array.

float _RGBtoYUV[3][3] = { { 0.299, 0.587, 0.114}, {-0.147, -0.289, 0.436}, { 0.615, -0.515, -0.100}, };

// standard luminance // blue - red - green // red - blue - green

Decodingtheabovetransformationweseethatwhenitisappliedtoan(R,G,B)vectortheresulting(Y, U,V)componentsareasshownbelow.NotethatU=Cbpostitivelyweightsbluebynegatively weightsredandgreen,butV=CrpositivelyweightsredbutnegativelyweightsGandB. ThetransformationiscalledlinearbecauseY,U,andVdependonR,G,andBtothefirstpowerno squaresorsquarerootsforexample.AlsonotethatforUandVthesumofthenegativeweightsis exactlyequaltothesumofthepositiveweights.ThustheUvaluerangesfrom0.436*255to0.436* 255.

Y = 0.299 R + 0.587 G + 0.114 B U = -0.147 R 0.289 G + 0.436 B V = 0.615 R -0.515 G 0.100 B


Ausefulwaytodobluescreencompositingistoconvert(R,G,B)to(Y,U,V)andthenchecktoseeif (UV)exceedsacertainthresholdvalue.Ifsothepixelisassumedtocomefromthebluescreen background.

228

TheinversetransformationmapsaYUVvaluebacktoRGBspace.Needlesstosay,ifyoustartwitha specificRGBvalue,mapittoYUVspaceandthenmapitbacktoRGBspace,youshouldgettheRGB valuethatyoustartedwith.

float _YUVtoRGB[3][3] = { {1.000, 0.000, 1.140}, {1.000, -0.395, -0.581}, {1.000, 2.032, 0.000}, };
TheinversetransformationfromYUVspacetoRGBspaceisshownbelow.Notethatredandblue dependonlyuponYandtheVandUchrominancevaluesrespectively.

R = 1.000 Y + 0.000 U G = 1.000 Y 0.395 U B = 1.000 Y + 2.032 U

+ 1.140 V - 0.581 V + 0.000 V

229

GeneralInputandOutput TheClanguageitselfdefinesnofacilityforI/Ooperations.I/Osupportisprovidedthroughtwo collectionsofmutuallyincomptiblefunctionlibraries LowlevelI/O open(), close(), read(), write(), lseek(), ioctl() StandardlibraryI/O fopen(), fclose() fprintf(), fscanf() fgetc(), fputc() fgets(), fputs() fread(), fwrite(), fseek() OurfocuswillbeontheuseofthestandardI/Olibrary: Functionandconstantdefinitionsareobtainedvia #includefacility.Tousethestandardlibrary functions: #include <stdio.h> #include <errno.h> openingandclosingfiles fieldatatimewithdataconversion character(byte)atatime lineatatime physicalblockatatime

230

Readingandwritingdiskresidentfiles Sofar,wehaveusedfscanf()andfprintf()toaccessonlythepredeclaredfilesstdin,stdout,and,stderr. Wecanalsodefineourownprivatefilepointers(FILE*)andbindthemtodiskfileswiththefopen() function.Afterthathasbeendone,allfileoperationsthatcanbeperformedonstdin,stdout,andstderr canalsobeperformeddirectlyonourdiskfile.

#include <stdio.h> int main() { FILE *f1; FILE *f2; int x; f1 = fopen(in.txt, r); if (f1 == 0) { perror(f1 failure); exit(1); } f2 = fopen(out.txt, w); if (f2 == 0) { perror(f2 failure); exit(2); } if (fscanf(f1, %d, &x) != 1) { perror(scanf failure); exit(2); } fprintf(f2, %d, x); fclose(f1); fclose(f2); }

231

Examplesoftheuseoftheperror()function Inthisexample,wehavenotyetcreatedin.txt class/215/examples ==> gcc -o p6 p6.c class/215/examples ==> p6 f1 failure:: No such file or directory cat: in.txt: No such file or directory Here,in.txtiscreatedwiththecatcommand: class/215/examples ==> cat > in.txt 99 Nowifwererunp6andcatout.txtweobtainthecorrectanswer class/215/examples ==> p6 class/215/examples ==> cat out.txt 99 Note: The macros scanf() and printf() may be used as abbreviations for: fscanf(stdin, ...) and fprintf(stdout, ...) Thismessagewasproducedby thecalltoperror()inthe program. Thisonewasproducedbythe catprogramitself.

232

Characteratatimeinputandoutput Thefgetc()functioncanbeusedtoreadanI/Ostreamonebyteatatime. Thefputc()functioncanbeusedtowriteanI/Ostreamonebyteatatime. Hereisanexampleofhowtobuildacatcommandusingthetwofunctions.Thep10programisbeing usedheretocopyitsownsourcecodefromstandardinputtooutput. class/215/examples ==> p10 < p10.c /* p10.c */ #include <stdio.h> main() { int c; Eventhoughfgetc()reads onebyteatatimeitreturns anintwhoseloworderbyte isthebytethatwasread.

while ((c = fgetc(stdin)) > 0) fputc(c, stdout); } Whilefputc()andfgetc()arefineforbuildinginteractiveapplications,theyareveryinefficient.and shouldneverbeusedforreadingorwritingalargevolumeofdatasuchasaphotographicimagefile.

233

Lineatatimeinputwithfgets(). Recallthatfscanf()withthe%sformatcodecanbeusedtoconsumewhitespacedelimitedstrings.The fgets()functionconsumesentirelinesatatime. Thefgets(buffer_address,buf_size,file)functioncanbeusedtoreadfromastreamuntileither: 1anewlinecharacter'\n'=10=0x0aisencounteredor 2thespecifiednumberofcharacters1hasbeenreador 3endoffileisreached. ThereisnostringdatatypeinC,butastandardconventionisthatastringisanarrayofcharactersin whichtheendisofthestringismarkedbythepresenceofabytewhichhasthevaluebinary00000000 (sometimescalledtheNULLcharacter). Thefgets()functionwillappendtheNULLcharactertowhateveritreadsin. Sincefgets()willreadinmultiplecharactersitisnotpossibletoassignwhatitreadstoasinglevariable oftypechar.

Thustheaddressabuffermustbepassed(aswasthecasewithfscanf()),and thebuffermustbeofsizeatleastbuf_size

234

Stringatatimeoutputwithfputs() Thefputs()functionwritesaNULLterminatedstringtoastream(afterstrippingofftheNULL).Thisis exactlywhatfprintf()withthe%sformatcodedoes,butfputs()maydoitinaslightlymoreefficientway. Thefollowingexampleisyetanothercatprogram,butthisoneworksonelineatatime. class/215/examples ==> p11 < p11.c 2> countem /* p11.c */ #include <stdio.h> #include <string.h> main() { unsigned char buff[1024]; int line = 0; while (fgets(buff, 1024, stdin) != 0) { fputs(buff, stdout); fprintf(stderr, "%d %d \n", line, strlen(buff)); line += 1; } } Hereistheoutputthatwenttothestandarderror.Notethateachlinethatappearedemptyhaslength1 (thenewlinecharacteritself)andthelinesthatappeartohavelength1actuallyhavelength2. class/215/examples ==> cat countem 0 12 1 1 2 19 3 20 4 1 5 7 6 2 7 24 8 18 9 1 10 24 11 18 : 20 2 235

Blockinputandoutput Thefread()andfwrite()functionsarethemostefficientwaytoreadorwritelargeamountsofdata.The secondparameterpassedtothefunctionisthesizeofabasicdataelementandthethirdparameteristhe numberofelements.Herethebasicdataelementisasinglebyteso1isused.Thefread()function returnsthenumberofelementsthatitread. Hereisastillmoreefficientimplementationofthecatlikeprogramthatcopiesstandardinputtothe standardoutput. class/215/examples ==> p12 < p12.c /* p12.c */ #include <stdio.h> main() { unsigned char buff[1024]; int len = 0; int iter = 0;

while ((len = fread(buff, 1, 1024, stdin)) != 0) { fwrite(buff, 1, len, stdout); fprintf(stderr, "%d %d \n", iter, len); iter += 1; } } 0 322 Exercises:Removingtheparenthesessurrounding (len = fread(buff, 1, 1024, stdin)) willbreaktheprogram.Explainexactlyhowandwhythingswillgowronginthiscase?Whatwill happenifleninthefwrite()isreplacedby1024?

236

Insummary Input

IfyourapplicationrequiresdataconversionfromASCIItexttointernalbinaryorfloatingpoint youmustusefscanf()withthe%dor%ffamiliesofformatcodes. Ifyouwishtoconsumeonebyteatatimeincludingwhitespacecharacterswithnodata conversionthenfgetc()orfscanf()withthe%cformatcodewillwork. IfyouwishtoreadconsumeinputtextawordatatimeandstoreitasaNULLterminatedstring withwithwhitespacecharactersremoved,thenfscanf()withthe%sformatcodeiswhatyou need. IfyouwishtoconsumeinputtextonelineatattimeandstoreitasaNULLterminatedstring withwithwhitespacecharactersincluded,thenfgets()willdothejob. Ifyouwishtoreadafixednumberofbyteswithnodataconversion,thenusefread().

Output

IfyourapplicationrequiresdataconversionfrominternalbinaryorfloatingpointtoASCIItext youmustusefprintf()withthe%dor%ffamiliesofformatcodes. Ifyouwishtooutputonebyteatatimewithnodataconversionthenfputc()orfprintf()withthe %cformatcodewillwork. IfyouwishtooutputaNULLterminatedcharacterarray,theneitherfprintf()withthe"%s" formatcodeorfputs()canbeused. Ifyouwishtowriteafixednumberofbyteswithnodataconversionthenfwrite()istheproper choice.

237

Scopeandstorageclassofvariables Thescopeofavariablereferstothoseportionsofaprogramwhereinitmaybeaccessed. Failuretounderstandscopingrulescanleadtotwoproblems: (1)Syntaxerrors(easytofindandfix) (2)Accidentallyusingthewronginstanceofavariable(sometimesveryhardonetofind). Twogeneralrulesapply (1)Thedeclarationofavariablemustprecedeanyuseofit. (2)Ifaparticularlineofcodeisinthescopeofmultiplevariablesofthesamenamethe innermostdeclarationofthevariableistheonethatisused. Specificrefinementsoftheseruleinclude: (1)thescopeofanyvariablesdeclaredoutsideanyfunctionisallcodeinthesourcemodulethat appearsafterthedefinition. (2)thescopeofanyvariabledeclaredinsideabasicblockisallcodeinthatblockandany blocksnestedwithinthatblockthatappearsafterthedefinition.

238

Improperdefinitionlocation Inthisexamplethevariableyisproperlydeclared,butitisusedbeforeitisdeclared. 1 2 3 4 5 6 7 8 9 /* p13.c */ /* this program demonstrates some of the characteristics */ /* of variable scoping in C. */ /* The scope of y and z is all lines that follow their /* definitions. Thus z may be used in f1 and f2 /* but y may be used only in f2 */ */ */

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

int z = 12; int f1( int x) { x = x + y + z; return(x); } int y = 11; int f2( int x) { x = x + y + z; }

class/215/examples ==> gcc p13.c p13.c: In function `f1': p13.c:15: `y' undeclared (first use in this function) p13.c:15: (Each undeclared identifier is reported only once p13.c:15: for each function it appears in.) p13.c: At top level: p13.c:19: `y' used prior to declaration

239

Overlappingscope Exampleprogramp14.cillustratesthatmultipledeclarationsofavariablehavingasinglenameislegal andresultsinoverlappingscope. Inthisprogramtheredoexistthreedifferentvariablesnamedy.Whentheprogramaccessesywhichyis usedisgovernedbytheinnermostdefinitionrule. /* p14.c */ /* This program illustrates that multiple different */ /* declarations of a variable having the same name */ /* may have overlapping scope. */ int y = 11; int main( ) { int y = 12; if (1) { int y, z; y = 92; printf(inner y = %d \n, y); } printf("middle y = %d \n", y); } class/215/examples ==> p14 inner y = 92 middle y = 12 Forsanedebuggingneverusemultiplevariableswiththesamenameandoverlappingscope. Notethatifyoualwayscallyourloopcountervariableiandyoualwaysdeclareitatthestartofeach function,youarenotviolatingthisguidelines.Inthiscasetherearemultiplei'sbuttheirscopesdon't overlap.

240

Storageclass Thestorageclassofavariabletheareaofmemoryinwhichavariableisstored. Thetwoavailableareasarecommonlyreferredtoastheheapandthestack. Stackresidentvariablesinclude:


parameterspassedtofunctions variablesdeclaredinsidebasicblocksthatarenotdeclaredstatic

Heapresidentvariablesinclude:

variablesdeclaredoutsideallfunctions variablesdeclaredinsidebasicblocksthataredeclaredstatic. memoryareasdynamicallyallocatedwithmalloc()

Storagefordeclaredheapresidentvariablesis

assignedatthetimeaprogramisloadedand remainsassignedforthelifeofaprogram.

Storageallocatedontheheapusingmalloc()remainsallocateduntil

eitherfree()iscalledor theprogramends.

Stackresidentvariablesare

createdatentrytothebasicblockthatcontainsthemand maybeoverwrittenatexitfromtheblock.

241

NonPersistenceofstackresidentvariables Theexamplebelowappearstocontradicttheclaimthatstorageisassignedtoastackresidentvariable onlyforthetimeinwhichtheblockisactive. Atfirstentrytof1()thevariablexisunintialized. Thevariablexissetto55beforereturningfromf1() Thevariableisstill55atentryonthesecondcall.

void f1(void) { int x; printf("At entry to f1 x = %d \n", x); x = 55; } main() { f1(); f1(); }
class/215/examples ==> p15 At entry to f1 x = -1073743532 At entry to f1 x = 55 xappearstoretainits valueatsencond entrytof1() xisuninitializedat firstentrytof1()

242

Examplep16.cshowsthattheclaimwasindeedtrueanditwasonlybadluckthatmadeitappear otherwise.

/* p16.c */ void f1(void) { int x; printf("At entry to f1 x = %d \n", x); x = 55; } void f2(void) { int z; printf("At entry to f2 z = %d \n", z); z = 102; } main() { f1(); f2(); f1(); }
class/215/examples At entry to f1 x = At entry to f2 z = At entry to f1 x = ==> p16 -1073743644 55 102

Itcanbeobservedfromtheoutputabovethatinthisparticularcasethevariableyinf1()andzinf2()are infactoccupyingthesamephysicalstorage.

243

Detailsofstackallocation Tworegisters(specialsinglewordhighspeedmemoriesinsidetheCPUchip)manageaccesstothe stack.The(E)SPstackpointerregisteralwayspointstothelastitempushedontothestack.Eachtimea newitemispushed.SPisdecrementedbyonewordandtheitemisstoredatthelocationwhoseaddress isinSP. The(E)BPbasepointerregisterprovidesafixedpointofreferenceusedforaddressingduringthe executionofafunction.TheBPregisteralwayspointstothelocationwherethecaller'sBPregisterwas preserved. Thefollowingactionsareperformedbythecallerduringafunctioncall:


Pushtheparametersontothestackinreverseorder. IssuetheCALLinstructionwhichpushestheaddressoftheinstructionfollowingtheCALLand thenjumpstothefirstinstructionofthecalledfunction.

Thecalledfunctionalwaysbeginswiththefollowingactions:

Pushthecaller'sBPregisterontothestack CopytheSPregisterintotheBPregister AllocatespaceforlocalvariablebydecrementingtheSPregister

244

/* p27.c */

int adder( int a, int b) { int d; int e; d = a + b; e = d - a; return(d); }


Atentrytothefunctionadderthestackisorganizedasfollows

Parm - 2 (b) Parm - 1 (a) Return address

<- SP (Stack pointer register)

Thecompilerproducesaprologuetothebodyofthefunctionwhichlookslike.Theebpregisteris knownasthebasepointerortheframepointer.Allstackresidentvariablesareaddressedusing base/displacementaddressingwithebpservingasthebase.

adder: pushl movl subl %ebp %esp, %ebp $8, %esp ;save caller's frame ptr ;set up my frame pointer ;allocate local vars

245

Aftertheprologcompletesthestacklooksasfollows

(ebp (ebp (ebp (ebp (ebp (ebp

+ 12) Parm - 2 (b) + 8) Parm - 1 (a) + 4) Return address + 0) Saved ebp - 4) local var (d) - 8) local var (e)

<- EBP

(Frame pointer)

<- ESP (Stack pointer)

d = a + b;

movl addl movl

12(%ebp), %eax 8(%ebp), %eax %eax, -4(%ebp)

;load b into eax ;add a to eax ;store sum at d

e = d - a;

movl movl subl movl

8(%ebp), %edx -4(%ebp), %eax %edx, %eax %eax, -8(%ebp)

;load a into edx ;load d into eax ;subtract a from d ;save result in e

return(d);

movl leave
Aftertheleaveexecutes

-4(%ebp), %eax

;copy d to return reg ;Copies EBP to ESP then POPS EBP

(ebp + 12) Parm - 2 (b) (ebp + 8) Parm - 1 (a) (ebp + 4) Return address ret

<- SP ;POPS EIP

246

Thestaticandexternmodifiers Thestaticandexternmodifiersareusedasfollows:

static int num; extern int extnum; extern char trashcan[256];


Theactionofthestaticmodifierisdependentuponthelocationofthedeclaration.

Whenusedinsidethebodyofafunction,staticforcesthevariableto 1resideontheheapinsteadofthestackandthus 2safelyretainitsvalueacrossfunctioncalls 3Butthescopeofthevariableremainsonlytheremainderofthebasicblockinwhichitis declared.

int public_val; int adder(int a) { static int sum; sum += a; return(sum); }

247

Useofstaticonvariablesdeclaredoutsidefunctionbodies Theactionofthestaticmodifierisdependentuponthelocationofthedeclaration.

Whenusedoutsidethebodyofafunctionasindeclarationofprivate_val,static 1limitsthescopeofthevariabletothissourcemodule. 2andthevariablestillremainsontheheap.

static int private_val; int adder(int a) { static int sum; sum += a; return(sum); }

248

Useoftheexternmodifier. Theexternmodifiercanbeusedtoaccessapublicvariablethatisdeclaredinanothersourcemodule.If, inanothermodule,Ineedtoaccessthevariablepublic_valthatasdeclaredpreviouslyIcandeclare:

extern int public_val; main() { public_val = 15; }


However,theuseofthestaticdeclarationwilldefeattheabilityofexternmodifiertoaccessthe variable.

extern int private_val; main() { private_val = 15; }


Thetwosourcefileswillcompilecorrectlybutthelinkerldwillfailbecausep34.cnolongerpublishes theaddressofprivate_val; class/215/examples ==> gcc p34.c p35.c /tmp/ccNrTn6K.o(.text+0x12): In function `main': : undefined reference to `private_val' collect2: ld returned 1 exit status class/215/examples ==>

Toavoidnamingconflictswhenmultipleprogrammersareworkingonalargemultimodule systemitisagoodideatomakealldeclarationsstaticexceptthoseexplicitlyagreeduponas beingsharedthroughtheexternmechanism. Theuseof"globalvariables"(variablesdeclaredinonemoduleandaccessedinanotherviathe externmechanism)shouldbeminimized.Mostprogramsdon'tneedandshouldn'tusethematall.

249

Staticappliedtofunctions Thestaticmodifiercanalsobeappliedtofunctionstomaketheminvisibleoutsidethemoduleinwhich theylive.

static int addit(int a, int b) { }


Toavoidnamingconflictswhenmultipleprogrammersareworkingonalargemultimodulesystemitis agoodideatomakeallfunctiondefinitionsstaticexceptthosethatareexplicitlyidentifiedasproviding servicestoexternalmodules.

250

Boolean(logical)andBitoperations WenowtreatsomewhatmoreformallythelogicaloperationsexpressedinCas&&,||,and!.Theseare sometimesreferredtoasBooleanoperationsbecauseoftheworkofEnglishmathematicianGeorge Boole(http://en.wikipedia.org/wiki/George_Boole)whopublishedfoundationalpapersinthemid1800's linkinglogicandalgebra. InBooleanlogicthevalue0conventionallymeansfalseand1meanstrue.Booleanvariablesare variablesthattakeonvaluesfalse(0)ortrue(1).Booleanfunctionsarefunctionsofoneormoreinput Booleanvalueswhoseoutputisalsoabooleanvariable. TherearefourdistinctfunctionsofasingleBooleanvariable.Thefunctionsaredescribedusingatruth table.f0isthefalsefunction,f1theidentityfunction,f2thenotfunctionandf3thetruefunction.Note thatthefunctionidentifier0,1,2,3issimplythedecimalrepresentationofthebinaryvaluestakenonby thefunctionwhenreadtoptobottom.(Thevaluesoff2(x)are10and10binaryis2decimal).

x 0 1

f0(x) 0 0

f1(x) 0 1

f2(x) 1 0

f3(x) 1 1

IntheClanguage,thenotfunctionisimplementedviathe!operator.Thestatement printf("%d\n",!(2<1)); willcauseavalueof1tobeprinted.Therelation2<1isfalseandso!(2<1)istrue.

251

Booleanfunctionsoftwovariables Thereare16differentfunctionsof2booleanvariables.Threeofthemthatarecommonlyusedin makinglogicalinferencesarebooleanfunctionsor,and,andxor. and: theresultistrueifandonlyifbothoperandsaretrue or: theresultistrueifeitheroperandistrue xor: theresultistrueifandonlyifexactlyoneoftheoperandsistrue.

f7(x, y)

f1(x, y)

f6(x, y)

x 0 0 1 1

y x or y x and y x xor y 0 0 0 0 1 1 0 1 0 1 0 1 1 1 1 0

All16ofthefunctionsmaybeenumeratedbycreatingacolumncontainingthebinaryrepresentationsof thevalues{0,1,2,..15} Example Complexlogicalinferencesareeasiertoevaluatealgebraicallythan"logically". Example:Isthefollowingsentencetrueorfalse! Dr.Westallisold,or(itisnotthecasethat(itisrainingandtheminimumprojectscoreis100)))or(Dr. Westallisnotold,oritisnotraining). Letx=Dr.Westallisold(T) y=Itisrainingrightnow(F) z=Theminimumscoreontheprojectis100(F) (xornot(yandz))or(notxornoty) (Tornot(FandF))or(notTornotF) (TornotF)or(ForT) (TorT)or(ForT)=TorT=T x=1 y=0 z=0

252

Proofsviatruthtables: Prove:not(xandy)==notxornoty

x 0 0 1 1
BooleanoperationsinC

y !x or !y 0 1 1 1 0 1 1 0

x and y !(x & y) 0 1 0 1 0 1 1 0

InCtherearenoBooleanvariables. 0correspondstoFalse(0) notzerocorrespondstoTrue(1) TherearethreeBooleanfunctions not! and&& or||

Inputvaluestothesefunctionsmaybeintegerorfloatingpoint.Avalueof0isFALSEandany othervalueisTRUE. Theoutputvalueisaninteger0or1.

253

Bitoperations FourofthebitoperatorsareBooleanfunctionsperformedinbitwisefashiononallofthebitsofan integerdatatype((unsigned)char,short,int,orlong). Theseoperatorsare: ~ | & ^ not or and xor

~10101010 = 01010101 10101010 & 11110000 10100000 10101010 | 11110000 11111010

10101010 ^ 11110000 01011010


Bitwiseandbooleanoperatorsarenotinterchangable 5&2=0 5&&2=1

254

Theshiftoperators >>shiftbitstowardleastsignificantbit <<shiftbitstowardmostsignificanbit Bitsshiftedoutofthevaluearelost Bitsshiftedintothelsbpositionduring<<alwaysare0. Bitsshiftedintothemsbpositionduring>>dependonsigned/unsignedint. signed unsgined =>currentmsbisduplicated =>a0isinjected.

01110001>>2=00011100 01110001<<2=11000100

255

Examplereadingabinarynumber Thisfunctionisthebinaryanalogoffscanf()withthe%d,%o,or%xformatcodes.ItreadsASCII characterrepresentationsofnumbersexpressedinbinaryandconvertsthemtobinaryintegers.For example,Iftheinputis: 1011 thevalueproducedshouldbe11=1x2^3+1x2^1+1x2^0 Itisnecessarytoconsumethecharactersoneatatime.Eachtimea1or0isconsumedtheresultis shiftedleftonebitpositionandthevaluejustconsumedisoredintotheloworderbitposition.

#include <stdio.h> #include <stdlib.h> #include <ctype.h> int bscanf( FILE *input, int *value) { int c; int result = 0; int found = 0; /* Consume any leading whitespace. The isspace() /* function returns true if c is a "whitespace" /* character. do c = fgetc(input); while (isspace(c)); /* On exit from this loop c should hold the first digit */ */ */ */

256

/* Now read one character at a time we contine while /* when c > 0 ( not end of file) and a 0 or 1 value /* is read while ((c > 0 ) && (c == '0' || (c == '1'))) { result <<= 1; // make room for new bit result |= c '0'; // insert new bit c = fgetc(input); // get next character found = 1; } *value = result; return(found); }

*/ */ */

257

Exampleprintingabinarynumber Thisfunctionisthebinaryanalogoffprintf()withthe%d,%o,or%xformatcodes

int bprintf( FILE *output, int value) { /* We can test a specific bit in an int by anding it */ /* with a "mask" that has a 1 in the specific bit */ /* position. */ unsigned int mask = 0x80000000; /* We want to skip over non-significant leading zeros /* Don't print 00000000000000000000000000001011 /* Do print 1011 */ /* So we start looking at the msb and continue until /* a 1 bit is found. while (!(mask & value)) mask >>= 1; /* Found a 1 bit.. print remaining bits as '0' or '1' */ while (mask) { (mask & value) ? fputc('1', output): fputc('0', output); mask >>= 1; } return(1); */ */

*/ */

258

Malloc'dobjects,garbagecollection,andmemoryleaks Somelanguages(e.g.Java)providesfor"automagic"garbagecollectioninwhichstorageforanobjectis magicallyreclaimedwhenallreferencestoanobjecthavegoneoutofexistence. Cprovidesnosuchmechanism. Amemoryleakissaidtohaveoccurredwhen: 1. thelastpointertoamalloc'dobjectisresetor 2. thelastpointertoamalloc'dobjectisalocalvariableinafunctionfromwhichareturnis made, Inthesecasesthemalloc'dmemoryisnolongeraccessible.Excessiveleakingcanleadtopoor performanceand,intheextreme,programfailure. TherforeCprogrammersmustrecognizewhenlastpointertomalloc'dstorageisabouttobelostanduse thefree()functioncalltoreleasethestoragebeforeitbecomesimpossibletodoso. Examplesofincorrectpointeruseandmemoryleakingarecommonlyobservedinstudentprograms

259

Problem1:Theinstantleak. Thisisanexampleofaninstantleak.Thememoryisallocatedatthetimetempisdeclaredandleaked whentempisreassignedtheaddressofthefirstobjectinthelist. obj_t *temp = malloc(sizeof(obj_t)); temp = list->head; while (temp != NULL) -- process list of objects -Twopossiblesolutions: Insertfree(temp)beforetemp=list>head; Thiseliminatestheleak,butwhatbenefitistheretoallocatingstorageandinstantly freeingit??? Changethedeclarationtoobj_t*temp=NULL; Thisisthecorrectsolution. Arationalruleofthumbisnevermallocmemoryunlessyouaregoingtowriteintoit! Anothergoodruleofthumbistoneverdeclareapointerwithoutinitializingit.

260

Problem2:Thetraditionalleak Herestorageisalsoallocatedforunivecatthetimeitisdeclared. Thecalltovl_unitvec3()writesintothatstorage. Ifthestorageisnotmalloc'd,thenunivecwillnotpointtoanythingusefulandthecalltovl_unitvec3() willproduceasegfaultorwilloverwritesomeotherpartoftheprogram'sdata.Sothismalloc()is necessary. { double *univec = malloc(3 * sizeof(double)); vl_unitvec3(dir, univec); : more stuff involving univec : return; } However,theinstantthereturnstatementisexecuted,thevalueofunivecbecomesnolongeraccessible andthememoryhasbeenleaked. Herethecorrectsolutionistoadd free(univec); justbeforethereturn; Arationalruleofthumbis:malloc'dstoragemustbefreedbeforethelastpointertoitislost.

261

Problem3:Overcompensation Theconcernaboutleakagemightleadtoanovercompensation.Forexample,anobjectloadermightdo thefollowing: { obj_t *new_obj; : new_obj = malloc(sizeof(obj_t)); : if (list->head == NULL) { list->head = list->tail = new_obj; } else { list->tail->next = new_obj; list->tail = new_obj; } free(new_obj); return(0); } Thisproblemisthereverseofamemoryleak.Alivepointertotheobjectexiststhroughthelist structure,butthestoragehasbeenfreed. Theresultsofthisare: 1. Usuallyattemptstoreferencethefreedstoragewillsucceed. 2. Thestoragewilleventuallybeassignedtoanotherobjectinalatercalltomalloc(). 3. Thenbothobjectswilloccupythesamestorage. Rationalruleofthumb:Neverfreeanobjectwhilelivepointerstotheobjectexist.Anypointerstothe freedstoragethatexistafterthereturnfromfree()shouldbesettoNULL. Tofixthisproblemthefree(new_obj)mustbedeletedfromthecode.Iftheobjectsintheobjectlistare tobefreed,itissafetodosoonlyattheendoftheraytrace. ItisnotimperativetodosoatthatpointbecausetheOperatingSystemwillreclaimallmemoryusedby theprocesswhentheprogramexits.

262

Problem 3b:

Overcompensation revisited

Thefree()functionmustbeusedonlytofreememorypreviouslyallocatedbymalloc() unsigned char buf[256]; : : free(buf); isafatalerror. Thefree()functionmustbenotbeusedtofreethesameareatwice. buf = (unsigned char *)malloc(256); : free(buf); : free(buf); is also fatal.

263

Thegeneralsolution:Referencecounting Forprogramsevenascomplicatedastheraytraceritisusuallyeasyforanexperiencedprogrammerto knowwhentofree()dynamicallyallocatedstorage. InprogramsascomplicatedastheLinuxkernelitisnot. Atechniqueknownasreferencecountingisused. typedef struct obj_type { int refcount; : : } obj_t; Atobjectcreationtime: new_obj = malloc(sizeof(obj_t)); new_obj->refcount = 1; Whenanewreferencetotheobjectiscreated my_new_ptr = new_obj; my_new_ptr->refcount += 1; Whenareferenceisabouttobereusedorlost my_new_ptr->refcount -= 1; if (my_new_ptr->refcount == 0) free(my_new_ptr); my_new_ptr = NULL; InamultithreadedenvironmentsuchasinanOSkernelitismandatorythatthetestingandupdateofthe referencecounterbedoneatomically.ThisissuewillbeaddressedinCPSC322.

264

You might also like