orced version 1.0, by vivisimo, and posted in http://library.nu last modified: 2011.06.05 1 A Quick Start 1.1 Introduction Itȱisȱalwaysȱdifficultȱtoȱstartȱdescribingȱaȱprogrammingȱlanguageȱbecauseȱlittleȱ detailsȱ doȱ notȱ makeȱ muchȱ senseȱ untilȱ oneȱ knowsȱ enoughȱ toȱ understandȱ theȱ Ȉbigȱ picture.ȈȱInȱthisȱchapter,ȱIȱtryȱtoȱgiveȱyouȱaȱglimpseȱofȱtheȱbigȱpictureȱbyȱlookingȱatȱaȱ sampleȱ programȱ andȱ explainingȱ itsȱ workingsȱ lineȱ byȱ line.ȱ Thisȱ sampleȱ programȱ alsoȱ showsȱyouȱhowȱfamiliarȱproceduresȱareȱaccomplishedȱinȱC.ȱThisȱinformationȱplusȱtheȱ otherȱtopicsȱdiscussedȱinȱtheȱchapterȱintroduceȱyouȱtoȱtheȱbasicsȱofȱtheȱCȱlanguageȱsoȱ thatȱyouȱcanȱbeginȱwritingȱusefulȱprograms.ȱ ȱ Theȱ programȱ weȱ dissectȱ readsȱ textȱ fromȱ theȱ standardȱ input,ȱ modifiesȱ it,ȱ andȱ writesȱitȱtoȱtheȱstandardȱoutput.ȱProgramȱl.lȱfirstȱreadsȱaȱlistȱofȱcolumnȱnumbers.ȱTheseȱ numbersȱ areȱ pairsȱ andȱ indicateȱ rangesȱ ofȱ columnsȱ inȱ theȱ inputȱ line.ȱ Theȱ listȱ isȱ terminatedȱ withȱaȱnegativeȱnumber.ȱTheȱremainingȱinputȱlinesȱareȱreadȱandȱprinted,ȱ thenȱtheȱselectedȱcolumnsȱfromȱtheȱinputȱlinesȱareȱextractedȱandȱprimed.ȱNoteȱthatȱtheȱ firstȱcolumnȱinȱaȱlineȱisȱnumberȱzero.ȱForȱexample,ȱifȱtheȱinputȱisȱ ȱ 4 9 12 20 -1 abcdefghijklmnopqrstuvwxyz Hello there, how are you? I am fine, thanks. See you! Bye ȱ thenȱtheȱprogramȱwouldȱproduce:ȱ ȱ Original input : abcdefghijklmnopqxstuvwxyz Rearranged line: efghijmnopqrstu Download at http://www.pin5i.com/ 2ȱ Chapter 1 A Quick Start Original input : Rearranged line: Original input : Rearranged line: Original input : Rearranged line: Original input : Rearranged line: Hello there, how are you? o ther how are I am fine, thanks. fine, thanks. See you! you! Bye ȱ Theȱ importantȱ pointȱ aboutȱ thisȱ programȱ isȱ thatȱ itȱ illustratesȱ mostȱ ofȱ theȱ basicȱ techniquesȱyouȱneedȱtoȱknowȱtoȱbeginȱwritingȱCȱprograms.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** ** ** ** ** ** ** ** ** */ This program reads input lines from standard input and prints each input line, followed by just some portions of the line, to the standard output. The first input is a lint of column numbers, which ends with a negative number. The column numbers are paired and specify ranges of columns from the input line that are to be printed. For example, 0 3 10 12 -1 indicates that only columns 0 through 3 and columns 10 through 12 will be printed. #include <stdio.h> #inc1ude <stdlib.h> #include <string.h> #define MAX_COLS #define MAX_INPUT int void 20 1000 /* max # of columns to process */ /* max len of input & output lines */ read_column_numbers( int columns[], int max ); rearrange( char *output, char const *input, int n_columns, int const columns[] ); int main( void ) { int n_columns; int columns[MAX_COLS]; char input[MAX_INPUT]; char output[MAX_INPUT]; /* # of columns to process */ /* the columns to process */ /*array for input line */ /*array for output line */ ȱ Programȱ1.1ȱ Rearrangeȱcharactersȱ ȱ ȱ ȱ ȱ ȱ ȱ continueܥȱ Download at http://www.pin5i.com/ 1.1 Introduction ȱ /* ** Read the list of column numbers */ n_columns = read_column_numbers( columns, MAX_COLS ); /* ** Read, process and print the remaining lines of input */ while( gets(input ) != NULL ){ printf( "Original input : %s\n", input ); rearrange( output, input, n_columns, columns ); printf( "Rearranged line: %s\n", output ); } return EXIT_SUCCESS; } /* ** Read the list of column numbers, ignoring any beyond the specified ** maximum. */ int read_column_numbers( int columns[], int max ) { int num = 0; int ch; /* ** Get the numbers, stopping at eof or when a number is < 0. */ while( num < max && scanf( "%d", &columns[num] ) == 1 &&columns[num] >= 0 ) num +=1; /* ** Make sure we have an even number of inputs, as they are ** supposed to be paired. */ if( num % 2 != 0 ){ puts( "Last column number is not paired." ); exit( EXIT_FAILURE ); } /* ** Discard the rest of the line that contained the final ȱ Programȱ1.1ȱ Rearrangeȱcharactersȱ ȱ ȱ ȱ ȱ ȱ ȱ continueܥȱ 3 Download at http://www.pin5i.com/ 4ȱ Chapter 1 A Quick Start ** number. */ while( (ch = getchar()) != EOF && ch != '\n' ) ; return num; } /* ** Process a line of input by ** the indicated columns. The */ void rearrange( char *output, char in n_columns, int const { int col; int output_col; int len; concatenating the characters from output line is the NUL terminated, const *input, columns[] ) /* subscript for columns array */ /* output column counter */ /* length of input line */ len = strlen( input ); output_col = 0; /* ** Process each pair of column numbers. */ for( col = 0; col < n_columns; col += 2 ){ int nchars = columns[col + 1] – columns[col] + 1; /* ** If the input line isn't this long or the output ** array is full, we're done */ if( columns[col] >= len || output_col == MAX_INPUT – 1 ) break; /* ** If there isn't room in the output array, only copy ** what will fit. */ if( output_col + nchars > MAX_INPUT – 1) nchars = MAX_INPUT – output_col – 1; /* ȱ Programȱ1.1ȱ Rearrangeȱcharactersȱ ȱ ȱ ȱ ȱ ȱ ȱ continueܥȱ Download at http://www.pin5i.com/ 1.1 Introduction 5 ** Copy the relevant data. */ strncpy( output + output_col, input + columns[col], nchars ); output_col += nchars; } output[output_col] = '\0'; } Programȱ1.1ȱ Rearrangeȱcharactersȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ rearrang.cȱ 1.1.1 Spacing and Comments ȱ Now,ȱlet’sȱtakeȱaȱcloserȱlookȱatȱthisȱprogram.ȱTheȱfirstȱpointȱtoȱnoticeȱisȱtheȱspacingȱofȱ theȱprogram:ȱtheȱblankȱlinesȱthatȱseparateȱdifferentȱpartsȱfromȱoneȱanother,ȱtheȱuseȱofȱ tabsȱ toȱ indentȱ statementsȱ toȱ displayȱ theȱ programȱ structure,ȱ andȱ soȱ forth.ȱ Cȱ isȱ aȱ freeȬ formȱlanguage,ȱsoȱthereȱareȱnoȱrulesȱasȱtoȱhowȱyouȱmustȱwriteȱstatements.ȱHowever,ȱaȱ littleȱ disciplineȱ whenȱ writingȱ theȱ programȱ paysȱ offȱ laterȱ byȱ makingȱ itȱ easierȱ toȱ readȱ andȱmodify.ȱMoreȱonȱthisȱissueȱinȱaȱbit.ȱ Whileȱitȱisȱimportantȱtoȱdisplayȱtheȱstructureȱofȱtheȱprogramȱclearly,ȱitȱisȱevenȱ moreȱ importantȱ toȱ tellȱ theȱ readerȱ whatȱ theȱ programȱ doesȱ andȱ howȱ itȱ works.ȱ Commentsȱfulfillȱthisȱroleȱ ȱ ȱ /* ** ** ** ** ** ** ** ** ** */ This program reads input lines from the standard input and prints each input line, followed by just: some portions of the lines, to the standard output . The first input; is a list of column numbers, which ends with a negative number . The column numbers are paired and specify ranges of columns from the input line that are to be printed. For example, 0 3 l0 12 —l indicates that only columns 0 through 3 and columns 10 through 12 will be printed ȱ ȱ Thisȱ blockȱ ofȱ textȱ isȱ aȱ comment.ȱ Commentsȱ beginȱ withȱ theȱ /*ȱ charactersȱ andȱ endȱwithȱtheȱ*/ȱcharacters.ȱTheyȱmayȱappearȱanywhereȱinȱaȱCȱprogramȱinȱwhichȱwhiteȱ spaceȱ mayȱ appear.ȱ However,ȱ commentsȱ cannotȱ containȱ otherȱ comments,ȱ thatȱ is,ȱ theȱ Firstȱ*/ȱterminatesȱtheȱcommentȱnoȱmatterȱhowȱmanyȱ/*ȇsȱhaveȱappearedȱearlier.ȱ Download at http://www.pin5i.com/ 6ȱ Chapter 1 A Quick Start CommentsȱareȱsometimesȱusedȱinȱotherȱlanguagesȱtoȱȈcommentȱoutȈȱcode,ȱthusȱ removingȱ theȱ codeȱ fromȱ theȱ programȱ withoutȱ physicallyȱ deletingȱ itȱ fromȱ theȱ sourceȱ file.ȱThisȱpracticeȱisȱaȱbadȱideaȱinȱC,ȱbecauseȱitȱwon’tȱworkȱifȱtheȱcodeȱyou‘reȱtryingȱtoȱ getȱridȱofȱhasȱanyȱcommentsȱinȱit.ȱAȱbetterȱwayȱtoȱlogicallyȱdeleteȱcodeȱinȱaȱCȱprogramȱ isȱtheȱ#ifȱdirective.ȱWhenȱusedȱlikeȱthis:ȱ ȱ #if 0 ȱ statementsȱ #endif theȱprogramȱstatementsȱbetweenȱtheȱ #ifȱandȱtheȱ #endifȱareȱeffectivelyȱremovedȱfromȱ theȱprogram.ȱCommentsȱcontainedȱinȱtheȱstatementsȱhaveȱnoȱeffectȱonȱthisȱconstruct,ȱ thusȱitȱisȱaȱmuchȱsaferȱwayȱtoȱaccomplishȱtheȱobjective.ȱThereȱisȱmuchȱmoreȱthatȱyouȱ canȱdoȱwithȱthisȱdirective,ȱwhichȱIȱexplainȱfullyȱinȱChapterȱ14.ȱ ȱ ȱ ȱ 1.1.2 Preprocessor Directives #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_COLS #define MAX_INPUT TIP 20 1000 /* max # of columns to process */ /* max len of input & output lines */ Theseȱfiveȱlinesȱareȱcalledȱpreprocessorȱdirectives,ȱorȱjustȱdirectives,ȱbecauseȱtheyȱ areȱinterpretedȱbyȱtheȱpreprocessorȱTheȱpreprocessorȱreadsȱtheȱsourceȱcode,ȱmodifiesȱ itȱ asȱ indicatedȱ byȱ anyȱ preprocessorȱ directives,ȱ andȱ thenȱ passesȱ theȱ modifiedȱ codeȱ toȱ theȱcompiler.ȱ Inȱourȱsampleȱprogram,ȱtheȱpreprocessorȱreplacesȱtheȱfirstȱ #includeȱstatementȱ withȱtheȱcontentsȱofȱtheȱlibraryȱheaderȱnamedȱ stdio.h;ȱtheȱresultȱisȱtheȱsameȱasȱifȱtheȱ contentsȱ ofȱ stdio.hȱ hadȱ beenȱ writtenȱ verbatimȱ atȱ thisȱ pointȱ inȱ theȱ sourceȱ file.ȱ Theȱ secondȱandȱthirdȱdirectivesȱdoȱtheȱsameȱwith stdlib.hȱandȱstring.h.ȱ Theȱ stdio.hȱheaderȱgivesȱusȱaccessȱtoȱfunctionsȱfromȱtheȱStandardȱI/OȱLibrary,ȱaȱ collectionȱ ofȱ functionsȱ thatȱ performȱ inputȱ andȱ output,ȱ stdlib.hȱ definesȱ theȱ EXIT_SUCCESSȱ andȱ EXIT_FAILUREȱ symbols.ȱ Weȱ needȱ string.hȱ toȱ useȱ theȱ stringȱ manipulationȱfunctions.ȱ ȱ Thisȱtechniqueȱisȱalsoȱaȱhandyȱwayȱtoȱmanageȱyourȱdeclarationsȱifȱtheyȱareȱneededȱinȱ severalȱdifferentȱsourceȱfiles—youȱwriteȱtheȱdeclarationsȱinȱaȱseparateȱfileȱandȱthenȱuseȱ #includeȱtoȱreadȱthemȱintoȱeachȱrelevantȱsourceȱtile.ȱThusȱthereȱisȱonlyȱoneȱcopyȱofȱtheȱ declarations;ȱtheyȱareȱnotȱduplicatedȱinȱmanyȱdifferentȱplaces,ȱwhichȱwouldȱbeȱmoreȱ errorȱproneȱtoȱmaintain.ȱ Download at http://www.pin5i.com/ 1.1 Introduction TIP int void TIP 7 Theȱ otherȱ directiveȱ isȱ #define,ȱ whichȱ definesȱ theȱ nameȱ MAX_COLSȱ toȱ beȱ theȱ valueȱ 20,ȱ andȱ MAX_INPUTȱtoȱbeȱtheȱvalueȱ1000.ȱWhereverȱeitherȱnameȱappearsȱlaterȱinȱtheȱsourceȱ tile,ȱ itȱ isȱ replacedȱ byȱ theȱ appropriateȱ value.ȱ Becauseȱ theyȱ areȱ definedȱ asȱ literalȱ constants,ȱtheseȱnamesȱcannotȱbeȱusedȱinȱsomeȱplacesȱwhereȱordinaryȱvariablesȱcanȱbeȱ usedȱ(forȱexample,ȱonȱtheȱleftȱsideȱofȱanȱassignment).ȱMakingȱtheirȱnamesȱuppercaseȱ servesȱasȱaȱreminderȱthatȱtheyȱareȱnotȱordinaryȱvariables.ȱ #defineȱdirectivesȱareȱusedȱ forȱtheȱsameȱkindsȱofȱthingsȱasȱsymbolicȱconstantsȱinȱotherȱlanguagesȱandȱforȱtheȱsameȱ reasons.ȱIfȱweȱlaterȱdecideȱthatȱ20ȱcolumnsȱareȱnotȱenough,ȱweȱcanȱsimplyȱchangeȱtheȱ definitionȱofȱ MAX_COLS.ȱThereȱisȱnoȱneedȱtoȱhuntȱthroughȱtheȱprogramȱlookingȱforȱ20’sȱ toȱchangeȱandȱpossiblyȱmissingȱoneȱorȱchangingȱaȱ20ȱthatȱhadȱnothingȱtoȱdoȱwithȱtheȱ maximumȱnumberȱofȱcolumns.ȱȱ ȱ ȱ read_column_numbers( int columns[], int max ); rearrange( char *output, char const *input, int n_columns, int const columns[] ); Theseȱ declarationsȱ areȱ calledȱ functionȱ prototypes.ȱ Theyȱ tellȱ theȱ compilerȱ aboutȱ theȱ characteristicsȱ ofȱ functionsȱ thatȱ areȱ definedȱ laterȱ inȱ theȱ sourceȱ tile.ȱ Theȱ compilerȱ canȱthenȱcheckȱcallsȱtoȱtheseȱfunctionsȱforȱaccuracy.ȱEachȱprototypeȱbeginsȱwithȱaȱtypeȱ nameȱthatȱdescribesȱtheȱvalueȱthatȱisȱreturned.ȱTheȱtypeȱnameȱisȱfollowedȱbyȱtheȱnameȱ ofȱ theȱ function.ȱ Theȱ argumentsȱ expectedȱ byȱ theȱ functionȱ areȱ next,ȱ soȱ read_column_numbers returnsȱ anȱ integerȱ andȱ takesȱ twoȱ arguments,ȱ anȱ arrayȱ ofȱ integersȱandȱanȱintegerȱscalar.ȱTheȱargumentȱnamesȱareȱnotȱrequired;ȱIȱgiveȱthemȱhereȱ toȱserveȱasȱaȱreminderȱofȱwhatȱeachȱargumentȱisȱsupposedȱtoȱbe.ȱ Theȱ rearrangeȱfunctionȱtakesȱfourȱarguments.ȱTheȱfirstȱandȱsecondȱareȱpointers.ȱ Aȱ pointerȱ specifiesȱ whereȱ aȱ valueȱ residesȱ inȱ theȱ computer’sȱ memory,ȱ muchȱ likeȱ aȱ houseȱnumberȱspecifiesȱwhereȱaȱparticularȱfamilyȱresidesȱonȱaȱstreet.ȱPointersȱareȱwhatȱ giveȱ theȱ Cȱ languageȱ itsȱ powerȱ andȱ areȱ coveredȱ inȱ greatȱ detailȱ startingȱ inȱ Chapterȱ 6.ȱ Theȱsecondȱandȱfourthȱargumentsȱareȱdeclaredȱ const,ȱwhichȱmeansȱthatȱtheȱfunctionȱ promisesȱ notȱ toȱ modifyȱ theȱ callerȇsȱ arguments.ȱ Theȱ keywordȱ voidȱ indicatesȱ thatȱ theȱ functionȱdoesȱnotȱreturnȱanyȱvalueȱatȱall;ȱsuchȱaȱfunctionȱwouldȱbeȱcalledȱaȱprocedureȱinȱ otherȱlanguages.ȱ ȱ Ifȱ theȱ sourceȱ codeȱ forȱ thisȱ programȱ wasȱ containedȱ inȱ severalȱ sourceȱ tiles,ȱ functionȱ prototypesȱ wouldȱ haveȱ toȱ beȱ writtenȱ inȱ eachȱ tileȱ usingȱ theȱ function.ȱ Puttingȱ theȱ prototypesȱ inȱ headerȱ filesȱ andȱ usingȱ a #includeȱ toȱ accessȱ themȱ avoidsȱ theȱ maintenanceȱproblemȱcausedȱbyȱhavingȱmultipleȱcopiesȱofȱtheȱsameȱdeclarations.ȱ Download at http://www.pin5i.com/ 8ȱ Chapter 1 A Quick Start 1.1.3 The Main Function int main( void ) { ȱ ȱ Theseȱ linesȱ beginȱ theȱ definitionȱ ofȱ aȱ functionȱ calledȱ main.ȱ Everyȱ Cȱ programȱ mustȱhaveȱaȱmainȱfunction,ȱbecauseȱthisȱisȱwhereȱexecutionȱbegins.ȱTheȱkeywordȱ intȱ indicatesȱthatȱtheȱfunctionȱreturnsȱanȱintegerȱvalue;ȱtheȱkeywordȱ voidȱindicatesȱthatȱitȱ expectsȱ noȱ arguments.ȱ Theȱ bodyȱ ofȱ theȱ functionȱ includesȱ everythingȱ betweenȱ thisȱ openingȱbraceȱandȱitsȱmatchingȱclosingȱbrace.ȱ Observeȱhowȱtheȱindentationȱclearlyȱshowsȱwhatȱisȱincludedȱinȱtheȱfunction.ȱ ȱ int int char char n_columns; columns[MAX_COLS]; input[MAX_INPUT]; output[MAX_INPUT]; /* # of columns to process */ /* the columns to process */ /*array for input line */ /*array for output line */ Theseȱ linesȱ declareȱ fourȱ variables:ȱ anȱ integerȱ scalar,ȱ anȱ arrayȱ ofȱ integers,ȱ andȱ twoȱarraysȱofȱcharacters.ȱAllȱfourȱofȱtheseȱvariablesȱareȱlocalȱtoȱtheȱmainȱfunction,ȱsoȱ theyȱ cannotȱ beȱ accessedȱ byȱ nameȱ fromȱ anyȱ otherȱ functions.ȱ Theyȱ can,ȱ ofȱ course,ȱ beȱ passedȱasȱargumentsȱtoȱotherȱfunctions.ȱ ȱ /* ** Read the list of column numbers */ n_columns = read_column_numbers( columns, MAX_COLS ); ȱ Thisȱ statementȱ callsȱ theȱ functionȱ read_column_numbers.ȱ Theȱ arrayȱ columnsȱ andȱ theȱ constantȱ representedȱ by MAX_COLS (20)ȱ areȱ passedȱ asȱ arguments.ȱ Inȱ C,ȱ arrayȱ argumentsȱ behaveȱ asȱ thoughȱ theyȱ areȱ passedȱ byȱ reference,ȱ andȱ scalarȱ variablesȱ andȱ constantsȱareȱpassedȱbyȱvalueȱ(likeȱvarȱparametersȱandȱvalueȱparameters,ȱrespectively,ȱ inȱPascalȱorȱModula).ȱThus,ȱanyȱchangesȱmadeȱbyȱaȱfunctionȱtoȱaȱscalarȱargumentȱareȱ lostȱ whenȱ theȱ functionȱ returns;ȱ theȱ functionȱ cannotȱ changeȱ theȱ valueȱ ofȱ theȱ callingȱ programȇsȱargumentȱinȱthisȱmanner.ȱWhenȱaȱfunctionȱchangesȱtheȱvalueȱofȱanȱelementȱ ofȱanȱarrayȱargument,ȱhowever,ȱtheȱarrayȱinȱtheȱcallingȱprogramȱisȱactuallyȱmodified.ȱ ȱ TheȱruleȱaboutȱhowȱparametersȱareȱpassedȱtoȱCȱfunctionsȱactuallyȱstates:ȱ ȱ Allȱargumentsȱtoȱfunctionsȱareȱpassedȱbyȱvalue.ȱ ȱ Nevertheless,ȱanȱarrayȱnameȱasȱanȱargumentȱproducesȱtheȱcallȬbyȬreferenceȱbehavior Download at http://www.pin5i.com/ 1.1 Introduction 9 describedȱabove.ȱTheȱreasonȱforȱthisȱapparentȱcontradictionȱbetweenȱtheȱruleȱandȱtheȱ actualȱbehaviorȱisȱexplainedȱinȱChapterȱ8.ȱ ȱ /* ** Read, process and print the remaining lines of input */ while( gets(input ) != NULL ){ printf( "Original input : %s\n", input ); rearrange( output, input, n_columns, columns ); printf( "Rearranged line: %s\n", output ); } return EXIT_SUCCESS; } ȱ ȱ Theȱcommentȱdescribingȱthisȱpieceȱofȱcodeȱmightȱseemȱunnecessary.ȱHowever,ȱ theȱ majorȱ expenseȱ ofȱ softwareȱ todayȱ isȱ notȱ writingȱ itȱ butȱ maintainingȱ it.ȱ Theȱ firstȱ problemȱinȱmodifyingȱaȱpieceȱofȱcodeȱisȱfiguringȱoutȱwhatȱitȱdoes,ȱsoȱanythingȱyouȱcanȱ putȱinȱourȱcodeȱthatȱmakesȱitȱeasierȱforȱsomeoneȱ(ȱperhapsȱyou!)ȱtoȱunderstandȱitȱlaterȱ isȱ worthȱ doing.ȱ Beȱ sureȱ toȱ writeȱ accurateȱ commentȱ whenȱ youȱ changeȱ theȱ code.ȱ Inaccurateȱcommentsȱareȱworseȱthanȱnoneȱatȱall!ȱ Thisȱpieceȱofȱcodeȱconsistsȱofȱaȱwhileȱloop.ȱInȱC,ȱwhileȱloopsȱoperateȱtheȱsameȱasȱ theyȱdoȱinȱotherȱlanguages.ȱTheȱexpressionȱisȱtested.ȱIfȱitȱisȱfalse,ȱtheȱbodyȱofȱtheȱloopȱ isȱ skipped.ȱ Ifȱ theȱ expressionȱ isȱ true,ȱ theȱ bodyȱ ofȱ theȱ loopȱ isȱ executedȱ andȱ theȱ wholeȱ processȱbeginsȱagain.ȱȱ Thisȱloopȱrepresentsȱtheȱmainȱlogicȱofȱtheȱprogram.ȱInȱbrief,ȱitȱmeans:ȱ ȱ whileȱweȱwereȱableȱtoȱreadȱanotherȱlineȱofȱinputȱ printȱtheȱinputȱ rearrangeȱtheȱinput,ȱstoringȱitȱinȱoutputȱ printȱtheȱoutputȱ ȱ Theȱ getsȱ functionȱ readsȱ oneȱ lineȱ ofȱ textȱ fromȱ theȱ standardȱ inputȱ andȱ storesȱ itȱ inȱ theȱ arrayȱ passedȱ asȱ anȱ argument.ȱ Aȱ lineȱ isȱ aȱ sequenceȱ ofȱ charactersȱ terminatedȱ byȱ aȱ newlineȱ character;ȱ getsȱ discardsȱ theȱ newlineȱ andȱ storesȱ aȱ NULȱ byteȱ atȱ theȱ endȱ ofȱ theȱ line 1 .ȱ(Aȱ NULȱbyteȱisȱoneȱwhoseȱbitsȱareȱallȱ 0,ȱwrittenȱasȱaȱcharacterȱconstantȱlikeȱthis:ȱ '\0'.)ȱ getsȱ thenȱ returnsȱ aȱ valueȱ thatȱ isȱ not NULLȱ toȱ indicateȱ thatȱ aȱ lineȱ was ȱNULȱisȱtheȱnameȱgivenȱinȱtheȱASCIIȱcharacterȱsetȱtoȱtheȱcharacterȱ'\0',ȱwhoseȱbitsȱareȱallȱzero.ȱNULLȱrefersȱtoȱaȱpointerȱ whoseȱvalueȱisȱzero.ȱBothȱareȱintegersȱandȱhaveȱtheȱsameȱvalue,ȱsoȱtheyȱcouldȱbeȱusedȱinterchangeably.ȱHowever,ȱitȱisȱworthȱ usingȱtheȱappropriateȱconstantȱbecauseȱthisȱtellsȱaȱpersonȱreadingȱtheȱprogramȱnotȱonlyȱthatȱyouȱareȱusingȱtheȱvalueȱzero,ȱ butȱwhatȱyouȱareȱusingȱitȱfor.ȱ 1 Download at http://www.pin5i.com/ 10ȱ Chapter 1 A Quick Start ȱ successfullyȱread 2 .ȱWhenȱ getsȱisȱ calledȱbutȱthereȱisȱ noȱ moreȱinput,ȱ itȱ returnsȱ NULLȱ toȱ indicateȱthatȱitȱhasȱreachedȱtheȱendȱofȱtheȱinputȱ(endȱofȱtile).ȱ DealingȱwithȱcharacterȱstringsȱisȱaȱcommonȱtaskȱinȱCȱprograms.ȱAlthoughȱthereȱ isȱ noȱ ȈstringȈȱ dataȱ type,ȱ thereȱ isȱ aȱ conventionȱ forȱ characterȱ stringsȱ thatȱ isȱ observedȱ throughoutȱtheȱlanguage:ȱaȱstringȱisȱaȱsequenceȱofȱcharactersȱterminatedȱbyȱa NULȱbyte.ȱ Theȱ NULȱisȱconsideredȱaȱterminatorȱandȱisȱnotȱcountedȱasȱaȱpartȱofȱtheȱstring.ȱAȱstringȱ literalȱisȱaȱsequenceȱofȱcharactersȱenclosedȱinȱquotationȱmarksȱinȱtheȱsourceȱprogram 3 .ȱ Forȱexample,ȱtheȱstringȱliteralȱ ȱ "Hello" ȱ ȱ ȱ occupiesȱsixȱbytesȱinȱmemory,ȱwhichȱcontainȱ(inȱorder)ȱH,e,l,l,o,ȱandȱNUL.ȱ ȱ Theȱ printfȱfunctionȱperformsȱformattedȱoutput.ȱModulaȱandȱPascalȱusersȱwillȱ beȱ delightedȱ withȱ theȱ simplicityȱ ofȱ formattedȱ outputȱ inȱ C.ȱ printfȱ takesȱ multipleȱ arguments;ȱ theȱ firstȱ isȱ aȱ characterȱ stringȱ thatȱ describesȱ theȱ formatȱ ofȱ theȱ output,ȱ andȱ theȱrestȱareȱtheȱvaluesȱtoȱbeȱprinted.ȱTheȱformatȱisȱoftenȱgivenȱasȱaȱstringȱliteral.ȱ Theȱ formatȱ stringȱ containsȱ formatȱ designatorsȱ interspersedȱ withȱ ordinaryȱ characters.ȱ Theȱ ordinaryȱ charactersȱ areȱ printedȱ verbatim,ȱ butȱeachȱ formatȱ designatorȱ causesȱtheȱnextȱargumentȱvalueȱtoȱbeȱprintedȱusingȱtheȱindicatedȱformat.ȱAȱfewȱofȱtheȱ moreȱusefulȱformatȱdesignatorsȱareȱgivenȱinȱTableȱl.l.ȱIfȱ ȱ ȱ ȱ Format Meaning %d Printȱanȱintegerȱvalueȱinȱdecimal.ȱ %o Printȱanȱintegerȱvalueȱinȱoctal.ȱ %x Printȱanȱintegerȱvalueȱinȱhexadecimal.ȱ %g PrintȱaȱfloatingȬpointȱvalue.ȱ %c Printȱaȱcharacter.ȱ %s Printȱaȱcharacterȱstring.ȱ \n Printȱaȱnewline.ȱ ȱ Tableȱ1.1ȱCommonȱprintfȱformatȱcodesȱ ȱTheȱsymbolȱNULLȱisȱdefinedȱinȱtheȱheader stdio.h.ȱOnȱtheȱotherȱhand,ȱthereȱisȱnoȱpredefinedȱsymbolȱNUL,ȱsoȱifȱyouȱwishȱ toȱuseȱitȱinsteadȱofȱtheȱcharacterȱconstantȱ'\0'ȱyouȱmustȱdefineȱitȱyourselfȱ 3ȱ Thisȱ symbolȱisȱ aȱ quotationȱmark:ȱ ",ȱ andȱ thisȱ symbolȱ isȱ anȱ apostrophe:ȱ'.ȱ Theȱ penchantȱ ofȱ computerȱ peopleȱ toȱcallȱthemȱ Ȉsingleȱ quoteȈȱ andȱ Ȉdoubleȱ quoteȈȱ whenȱ theirȱ existingȱ namesȱ areȱ perfectlyȱ goodȱ seemsȱ unnecessary,ȱ soȱ Iȱ willȱ useȱ theirȱ everydayȱnames.ȱ 2 Download at http://www.pin5i.com/ 1.1 Introduction 11 theȱarrayȱinputȱcontainsȱtheȱstringȱHi friends!,ȱthenȱtheȱstatementȱ ȱ printf( "Original input : %s\n", input ); ȱ willȱproduceȱ ȱ Original input : Hi friends! terminatedȱwithȱaȱnewline.ȱ Theȱnextȱstatementȱinȱtheȱsampleȱprogramȱcallsȱtheȱrearrangeȱfunction.ȱTheȱlastȱ threeȱargumentsȱareȱvaluesȱthatȱareȱpassedȱtoȱtheȱfunction,ȱandȱtheȱfirstȱisȱtheȱanswerȱ thatȱtheȱfunctionȱwillȱconstructȱandȱpassȱbackȱtoȱtheȱmainȱfunction.ȱRememberȱthatȱitȱ isȱonlyȱpossibleȱtoȱpassȱtheȱanswerȱbackȱthroughȱthisȱargumentȱbecauseȱitȱisȱanȱarray.ȱ Theȱlastȱcallȱtoȱprintfȱdisplaysȱtheȱresultȱofȱrearrangingȱtheȱline.ȱ Finally,ȱ whenȱ theȱ loopȱ hasȱ completed,ȱ theȱ mainȱ functionȱ returnsȱ theȱ valueȱ EXIT_SUCCESS.ȱ Thisȱ valueȱ indicatesȱ toȱ theȱ operatingȱ systemȱ thatȱ theȱ programȱ wasȱ successful.ȱTheȱclosingȱbraceȱmarksȱtheȱendȱofȱtheȱbodyȱofȱtheȱmainȱfunction.ȱ ȱ ȱ ȱ ȱ ȱ 1.1.4 The read_column_numbers Function /* ** Read the list of column numbers, ignoring any beyond the specified ** maximum. */ int read_column_numbers( int columns[], int max ) { Theseȱlinesȱbeginȱtheȱdefinitionȱofȱtheȱ read_column_numbersȱfunction.ȱNoteȱthatȱ thisȱdeclarationȱandȱtheȱfunctionȱprototypeȱthatȱappearedȱearlierȱinȱtheȱprogramȱmatchȱ inȱtheȱnumberȱandȱtypesȱofȱargumentsȱandȱinȱtheȱtypeȱreturnedȱbyȱtheȱfunction.ȱItȱisȱ anȱerrorȱifȱtheyȱdisagree.ȱ Thereȱisȱnoȱindicationȱofȱtheȱarrayȱsizeȱinȱtheȱarrayȱparameterȱdeclarationȱtoȱtheȱ function.ȱThisȱformatȱisȱcorrect,ȱbecauseȱtheȱfunctionȱwillȱgetȱwhateverȱsizeȱarrayȱtheȱ callingȱ programȱ passedȱ asȱ anȱ argument.ȱ Thisȱ isȱ aȱ greatȱ feature,ȱ asȱ itȱ allowsȱ aȱ singleȱ functionȱ toȱ manipulateȱ one—dimensiona1ȱ arraysȱ ofȱ anyȱ size.ȱ Theȱ downȱ sideȱ ofȱ thisȱ featureȱisȱthatȱthereȱisȱnoȱwayȱforȱtheȱfunctionȱtoȱdetermineȱtheȱsizeȱofȱtheȱarray.ȱIfȱthisȱ informationȱisȱneeded,ȱtheȱvalueȱmustȱbeȱpassedȱasȱaȱseparateȱargument.ȱ Download at http://www.pin5i.com/ 12ȱ Chapter 1 A Quick Start Whenȱ theȱ read_column_numbersȱ functionȱ isȱ called,ȱ theȱ nameȱ ofȱ oneȱ ofȱ theȱ argumentsȱ thatȱ isȱ passedȱ happensȱ toȱ matchȱ theȱ nameȱ ofȱ theȱ formalȱ parameterȱ givenȱ above.ȱ However,ȱ theȱ nameȱ ofȱ theȱ otherȱ argumentȱ doesȱ notȱ matchȱ itsȱ correspondingȱ parameter.ȱ Asȱ inȱ mostȱ otherȱ languages,ȱ theȱ formalȱ parameterȱ nameȱ andȱ theȱ actualȱ argumentȱnameȱhaveȱnoȱrelationshipȱtoȱoneȱanother;ȱyouȱcanȱmakeȱthemȱtheȱsameȱifȱ youȱwish,ȱbutȱitȱisȱnotȱrequired.ȱ ȱ int int num = 0; ch; Twoȱ variablesȱ areȱ declared;ȱ theyȱ willȱ beȱ localȱ toȱ thisȱ function.ȱ Theȱ firstȱ oneȱ isȱ initializedȱ toȱ zeroȱ inȱ theȱ declaration,ȱ butȱ theȱ secondȱ oneȱ isȱ notȱ initialized.ȱ Moreȱ precisely,ȱ itsȱ initialȱ valueȱ willȱ beȱ someȱ unpredictableȱ value,ȱ whichȱ isȱ probablyȱ garbage.ȱTheȱlackȱofȱanȱinitialȱvalueȱisȱnotȱaȱproblemȱinȱthisȱfunctionȱbecauseȱtheȱfirstȱ thingȱdoneȱwithȱtheȱvariableȱisȱtoȱassignȱitȱaȱvalue.ȱ ȱ ȱ ** Get the numbers, stopping at eof or when a number is < 0. */ while( num < max && scanf( "%d", &columns[num] ) == 1 &&columns[num] >= 0 ) num +=1; CAUTION! 4 ȱ ȱ Thisȱ secondȱ loopȱ readsȱ inȱ theȱ columnȱ numbers.ȱ Theȱ scanfȱ functionȱ readsȱ charactersȱfromȱtheȱstandardȱinputȱandȱconvertsȱthemȱaccordingȱtoȱaȱformatȱstring— sortȱ ofȱ theȱ reverseȱ ofȱ whatȱ printfȱ does.ȱ scanfȱ takesȱ severalȱ arguments,ȱ theȱ firstȱ ofȱ whichȱ isȱ aȱ formatȱ suingȱ thatȱ describesȱ theȱ typeȱ ofȱ inputȱ thatȱ isȱ expected.ȱ Theȱ remainingȱargumentsȱareȱvariablesȱintoȱwhichȱtheȱinputȱisȱstored.ȱTheȱvalueȱretunedȱ byȱ scanfȱisȱtheȱnumberȱofȱvaluesȱthatȱwereȱsuccessfullyȱconvertedȱandȱstoredȱintoȱtheȱ arguments.ȱ ȱ ȱ Youȱmustȱbeȱcarefulȱwithȱthisȱfunctionȱforȱtwoȱreasons.ȱFirst,ȱbecauseȱofȱtheȱwayȱscanfȱ isȱimplemented,ȱallȱofȱitsȱscalarȱargumentsȱmustȱhaveȱanȱampersandȱinȱfrontȱofȱthem.ȱ Forȱ reasonsȱ thatȱ Iȱ makeȱ clearȱ inȱ Chapterȱ 8,ȱ arrayȱ argumentsȱ doȱ notȱ requireȱ anȱ ampersand 4 .ȱHowever,ȱifȱaȱsubscriptȱisȱusedȱtoȱidentifyȱaȱspecificȱarrayȱelement,ȱthenȱ anȱ ampersandȱ isȱ required.ȱ Iȱ explainȱ theȱ needȱ forȱ theȱ ampersandsȱ onȱ theȱ scalar ȱThereȱisȱnoȱharmȱinȱputtingȱanȱampersandȱinȱfrontȱofȱanȱarrayȱnameȱhere,ȱhowever,ȱsoȱyouȱmayȱuseȱoneȱifȱyouȱwish.ȱ Download at http://www.pin5i.com/ 1.1 Introduction 13 CAUTION! argumentsȱinȱChapterȱ15.ȱForȱnow,ȱjustȱbeȱsureȱtoȱputȱthemȱin.ȱbecauseȱtheȱprogramȱ willȱsurelyȱfailȱwithoutȱthem.ȱ ȱ Theȱsecondȱpitfallȱisȱtheȱformatȱcodes,ȱwhichȱareȱnotȱidenticalȱtoȱthoseȱin printfȱbutȱ similarȱ enoughȱ toȱ beȱ confusing.ȱ Tableȱ 1.2ȱ informallyȱ describesȱ aȱ fewȱ ofȱ theȱ formatȱ designatorsȱthatȱyouȱmayȱuseȱwithȱscanf.ȱNoteȱthatȱtheȱfirstȱfiveȱvalues,ȱsoȱtheȱvariableȱ givenȱasȱtheȱargumentȱmustȱbeȱprecededȱwithȱanȱampersand.ȱWithȱallȱofȱtheseȱformatȱ codesȱ(exceptȱ %c),ȱwhiteȱspaceȱ(spaces,ȱtabs,ȱnewlines,ȱetc.)ȱinȱtheȱinputȱisȱskippedȱtheȱ valueȱ isȱ encountered,ȱ andȱ subsequentȱ whiteȱ spaceȱ terminatesȱ theȱ value.ȱ Therefore,ȱ aȱ characterȱstringȱreadȱwithȱ%sȱcannotȱcontainȱwhiteȱspace.ȱThereȱareȱmanyȱotherȱformatȱ designators,ȱbutȱtheseȱwillȱbeȱenoughȱforȱourȱcurrentȱneeds.ȱ Weȱcanȱnowȱexplainȱtheȱexpressionȱ ȱ scanf( "%d", &columns[num] ) ȱ ȱ Theȱformatȱcodeȱ%dȱindicatesȱthatȱanȱintegerȱvalueȱisȱdesired.ȱCharactersȱareȱreadȱfromȱ theȱ standardȱ input,ȱ anyȱ leadingȱ whiteȱ spaceȱ foundȱ isȱ skipped.ȱ Thenȱ digitsȱ areȱ convertedȱ intoȱ anȱ integer,ȱ andȱ theȱ resultȱ isȱ storedȱ inȱ theȱ specifiedȱ arrayȱ element.ȱ Anȱ ampersandȱisȱrequiredȱinȱfrontȱofȱtheȱargumentȱbecauseȱtheȱsubscriptȱselectsȱaȱsingleȱ arrayȱelement,ȱwhichȱisȱaȱscalar.ȱ Theȱtestȱinȱtheȱwhileȱloopȱconsistsȱofȱthreeȱparts.ȱ ȱ num < max ȱ makesȱ sureȱ thatȱ weȱ doȱ notȱ getȱ tooȱ manyȱ numbersȱ andȱ overflowȱ theȱ array.ȱ scanf retumsȱtheȱvalueȱoneȱifȱitȱconvertedȱanȱinteger.ȱFinally,ȱ ȱ columns[num] >= 0 ȱ checksȱ thatȱ theȱ valueȱ enteredȱ wasȱ positive.ȱ lfȱ anyȱ ofȱ theseȱ testsȱ areȱ false.ȱ Theȱ loopȱ stops.ȱ ȱ ȱ Format Meaning Type of Variable %d int Readȱanȱintegerȱvalue.ȱ %ld long Readȱaȱlongȱintegerȱvalue.ȱ float %f Readȱaȱrealȱvalue.ȱ double %lf Readȱaȱdoubleȱprecisionȱrealȱvalue.ȱ char %c Readȱaȱcharacter.ȱ array of char %s Readȱaȱcharacterȱstringȱfromȱtheȱinput.ȱ ȱ Tableȱ1.2ȱCommonȱscanfȱformatȱcodesȱ Download at http://www.pin5i.com/ 14ȱ Chapter 1 A Quick Start TIP TheȱStandardȱdoesȱnotȱrequireȱthatȱCȱcompilersȱcheckȱtheȱvalidityȱofȱarrayȱsubscripts,ȱ andȱtheȱvastȱmajorityȱofȱcompilersȱdon’t.ȱThus,ȱifȱyouȱneedȱsubscriptȱvalidityȱchecking,ȱ youȱ mustȱ writeȱ itȱ yourself.ȱ ifȱ theȱ testȱ forȱ num < maxȱ wereȱ notȱ hereȱ andȱ theȱ programȱ readȱ aȱ fileȱ containingȱ moreȱ thanȱ 20ȱ columnȱ numbers,ȱ theȱ excessȱ valuesȱ wouldȱ beȱ storedȱ inȱ theȱ memoryȱ locationsȱ thatȱ followȱ theȱ array,ȱ thusȱ destroyingȱ whateverȱ dataȱ wasȱ formerlyȱ inȱ thoseȱ locations,ȱ whichȱ mightȱ beȱ otherȱ variablesȱ orȱ theȱ functionȇsȱ returnȱaddress.ȱThereȱareȱotherȱpossibilitiesȱtoo,ȱbutȱtheȱresultȱisȱthatȱtheȱprogramȱwillȱ probablyȱnotȱperformȱasȱyouȱhadȱintended.ȱ Theȱ &&ȱ isȱ theȱ Ȉlogicalȱ andȈȱ operator.ȱ Forȱ thisȱ expressionȱ toȱ beȱ true,ȱ theȱ expressionsȱonȱbothȱsidesȱofȱtheȱ &&ȱmustȱevaluateȱtoȱtrue.ȱHowever,ȱifȱtheȱleftȱsideȱisȱ false,ȱtheȱrightȱsideȱisȱnotȱevaluatedȱatȱall,ȱbecauseȱtheȱresultȱcanȱonlyȱbeȱfalse.ȱInȱthisȱ case,ȱ ifȱ weȱ findȱ thatȱ numȱ hasȱ reachedȱ theȱ maximumȱ value,ȱ theȱ loopȱ breaksȱ andȱ theȱ expressionȱ ȱ columns[num] CAUTION! CAUTION! ȱ isȱneverȱevaluated 5 .ȱ ȱ Beȱcarefulȱnotȱtoȱuseȱtheȱ&ȱoperatorȱwhenȱyouȱreallyȱwantȱ&&;ȱtheȱformerȱdoesȱaȱbitwiseȱ AND,ȱ whichȱ sometimesȱ givesȱ theȱ sameȱ resultȱ thatȱ &&ȱ wouldȱ giveȱ butȱ inȱ otherȱ casesȱ doesȱnot.ȱIȱdescribeȱtheseȱoperatorsȱinȱChapterȱ5.ȱ Eachȱ callȱ toȱ scanfȱ roadsȱ aȱ decimalȱ integerȱ fromȱ theȱ standardȱ input.ȱ Ifȱ theȱ conversionȱ fails,ȱ eitherȱ becauseȱ endȱ ofȱ meȱ wasȱ reachedȱ orȱ becauseȱ theȱ nextȱ inputȱ charactersȱ wereȱ notȱ validȱ inputȱ forȱ anȱ integer,ȱ theȱ valueȱ 0ȱ isȱ returned,ȱ whichȱ breaksȱ theȱ loop.ȱ Ifȱ theȱ charactersȱ areȱ legalȱ inputȱ forȱ anȱ integer,ȱ theȱ valueȱ isȱ convertedȱ toȱ binaryȱandȱstoredȱinȱtheȱarrayȱelementȱcolumns[num]. scanfȱthanȱreturnsȱtheȱvalueȱ1.ȱ ȱ Beware:ȱTheȱoperatorȱthatȱtestsȱtwoȱexpressionsȱforȱequalityȱisȱ ==.ȱUsingȱtheȱ =ȱoperatorȱ insteadȱresultsȱinȱaȱlegalȱexpressionȱthatȱalmostȱcertainlyȱwillȱnotȱdoȱwhatȱyouȱwantȱitȱ toȱdo:ȱitȱdoesȱanȱassignmentȱratherȱthanȱaȱcomparison!ȱItȱisȱaȱlegalȱexpression,ȱthough,ȱ soȱtheȱcompilerȱwon’tȱcatchȱthisȱerrorȱforȱyou 6 .ȱBeȱextremelyȱcarefulȱtoȱuseȱtheȱdoubleȱ equalȱsignȱoperatorȱforȱcomparisons.ȱIfȱyourȱprogramȱisȱnotȱworking,ȱcheckȱallȱofȱyourȱ comparisonsȱforȱthisȱerror.ȱBelieveȱme,ȱyouȱwillȱmakeȱthisȱmistake,ȱprobablyȱmoreȱthanȱ once,ȱasȱIȱhave.ȱ 5ȱȱTheȱphraseȱȈtheȱloopȱbreaksȈȱmeansȱthatȱitȱterminates,ȱnotȱthatȱitȱisȱhasȱsuddenlyȱbecomeȱdefective.ȱThisȱphraseȱcomesȱ fromȱtheȱbreakȱstatement,ȱwhichȱisȱdiscussedȱinȱChapterȱ4.ȱ 6ȱȱSomeȱnewerȱcompilersȱwillȱprintȱaȱwarningȱaboutȱassignmentsȱin ifȱand whileȱstatementsȱonȱtheȱtheoryȱthatȱitȱisȱmuchȱ moreȱlikelyȱthatȱyouȱwantedȱaȱcomparisonȱthanȱanȱassignmentȱinȱthisȱcontext.ȱ Download at http://www.pin5i.com/ 1.1 Introduction 15 Theȱ nextȱ &&ȱ makesȱ sureȱ thatȱ theȱ numberȱ isȱ testedȱ forȱ aȱ negativeȱ valueȱ onlyȱ ifȱ scanfȱwasȱsuccessfulȱinȱreadingȱit.ȱTheȱstatementȱ ȱ num += 1; ȱ addsȱ1ȱtoȱtheȱvariableȱnum.ȱItȱisȱequivalentȱtoȱtheȱstatementȱ ȱ num = num + 1; ȱ IȱdiscussȱlaterȱwhyȱCȱprovidesȱtwoȱdifferentȱwaysȱtoȱincrementȱaȱvariable 7 .ȱ ȱ ȱ /* ** Make sure we have an even number of inputs, as they are ** supposed to be paired. */ if( num % 2 != 0 ){ puts( "Last column number is not paired." ); exit( EXIT_FAILURE ); } Thisȱ testȱ checksȱ thatȱ anȱ evenȱ numberȱ ofȱ integersȱ wereȱ entered,ȱ whichȱ isȱ requiredȱ becauseȱtheȱnumbersȱareȱsupposedȱtoȱbeȱinȱpairs.ȱTheȱ % operatorȱperformsȱanȱintegerȱ division,ȱ butȱ itȱ givesȱ theȱ remainderȱ ratherȱ thanȱ theȱ quotient.ȱ Ifȱ numȱ isȱ notȱ anȱ evenȱ number,ȱtheȱremainderȱofȱdividingȱitȱbyȱtwoȱwillȱbeȱnonzero.ȱ Theȱ putsȱfunctionȱisȱtheȱoutputȱversionȱofȱ gets;ȱitȱwritesȱtheȱspecifiedȱstringȱtoȱ theȱstandardȱoutputȱandȱappendsȱaȱnewlineȱcharacterȱtoȱit.ȱTheȱprogramȱthenȱcallsȱtheȱ exit;ȱfunction,ȱwhichȱterminatesȱitsȱexecution.ȱTheȱvalueȱ EXIT_FAILUREȱisȱpassedȱbackȱ toȱtheȱoperatingȱsystemȱtoȱindicateȱthatȱsomethingȱwasȱwrong.ȱ ȱ /* ** Discard the rest of the line that contained the final ** number. */ while( (ch = getchar()) != EOF && ch != '\n' ) ; ȱ ȱ scanfȱonlyȱreadsȱasȱfarȱasȱitȱhasȱtoȱwhenȱconvertingȱinputȱvalues.ȱTherefore,ȱtheȱ remainderȱ ofȱ theȱ Lineȱ thatȱ containedȱ theȱ lastȱ valueȱ willȱ stillȱ beȱ outȱ there,ȱ waitingȱ to 7 ȱWithȱtheȱprefixȱandȱpostfixȱ++ȱoperators,ȱthereȱareȱactuallyȱfourȱwaysȱtoȱincrementȱaȱvariableȱ Download at http://www.pin5i.com/ 16ȱ Chapter 1 A Quick Start beȱread.ȱItȱmayȱcontainȱjustȱtheȱterminatingȱnewline,ȱorȱitȱmayȱcontainȱotherȱcharactersȱ too.ȱRegardless,ȱthisȱwhileȱloopȱreadsȱandȱdiscardsȱtheȱremainingȱcharactersȱtoȱpreventȱ themȱfromȱbeingȱinterpretedȱasȱtheȱfirstȱlineȱofȱdata.ȱ Theȱexpressionȱ ȱ (ch = getchar()) != EOF && ch != '\n' ȱ meritsȱ someȱ discussion.ȱ First,ȱ theȱ functionȱ getcharȱ readsȱ aȱ singleȱ characterȱ fromȱ theȱ standardȱinputȱandȱreturnsȱitsȱvalue.ȱIfȱthereȱareȱnoȱmoreȱcharactersȱinȱtheȱinput,ȱtheȱ constantȱEOFȱ(whichȱisȱdefinedȱinȱstdio.h)ȱisȱrammedȱinsteadȱtoȱsignalȱendȬofȬline.ȱ Theȱ valueȱ returnedȱ byȱ getcharȱ isȱ assignedȱ toȱ theȱ variableȱ ch,ȱ whichȱ isȱ thenȱ comparedȱ toȱ EOF.ȱ Theȱ parenthesesȱ enclosingȱ theȱ assignmentȱ ensureȱ thatȱ itȱ isȱ doneȱ beforeȱtheȱcomparison.ȱIfȱ chȱisȱequalȱtoȱ EOF,ȱtheȱexpressionȱisȱfalseȱandȱtheȱloopȱstops.ȱ Otherwise,ȱ chȱisȱcomparedȱtoȱaȱnewline;ȱagain,ȱtheȱloopȱstopsȱifȱtheyȱareȱfoundȱtoȱbeȱ equal.ȱThus,ȱtheȱexpressionȱisȱtrueȱ{causingȱtheȱloopȱtoȱrunȱagain)ȱonlyȱifȱendȱofȱlineȱ wasȱnotȱreachedȱandȱtheȱcharacterȱreadȱwasȱnotȱaȱnewline.ȱThus,ȱtheȱloopȱdiscardsȱtheȱ remainingȱcharactersȱonȱtheȱcurrentȱinputȱline.ȱ Nowȱlet’sȱmoveȱonȱtoȱtheȱinterestingȱpart.ȱInȱmostȱotherȱlanguages,ȱweȱwouldȱ haveȱwrittenȱtheȱloopȱlikeȱthis:ȱ ȱ ch = getchar(); while( ch != EOF && ch != '\n' ) ch = getchar(); TIP ȱ Getȱaȱ character,ȱ thereȱ ifȱweȇveȱnotȱ yetȱ reachedȱendȱ ofȱ tileȱ orȱ gottenȱaȱ newline,ȱ getȱanotherȱcharacter.ȱNoteȱthatȱthereȱareȱtwoȱcopiesȱofȱtheȱstatement.ȱȱ ȱ ȱ ch = getchar(); ȱ Theȱabilityȱtoȱembedȱtheȱassignmentȱinȱtheȱ whileȱstatementȱallowsȱtheȱCȱprogrammerȱ toȱeliminateȱthisȱredundantȱstatement.ȱ ȱ Theȱloopȱinȱtheȱsampleȱprogramȱhasȱtheȱsameȱfunctionalityȱasȱtheȱoneȱshownȱabove,ȱ butȱ itȱ containsȱ oneȱ fewerȱ statement.ȱ Itȱ isȱ admittedlyȱ harderȱ toȱ road,ȱ andȱ oneȱ couldȱ makeȱaȱconvincingȱargumentȱthatȱthisȱcodingȱtechniqueȱshouldȱbeȱavoidedȱforȱjustȱthatȱ reason.ȱ However,ȱ most,ȱ ofȱ theȱ difficultyȱ inȱ readingȱ isȱ dueȱ coȱ inexperienceȱ withȱ theȱ languageȱ andȱ itsȱ idioms;ȱ experiencedȱ Cȱ programmersȱ haveȱ noȱ troubleȱ readingȱ (andȱ writing)ȱ statementsȱ suchȱ asȱ thisȱ one.ȱ Youȱ shouldȱ avoidȱ makingȱ codeȱ harderȱ toȱ readȱ whenȱthereȱisȱnoȱtangibleȱbenefitȱtoȱbeȱgainedȱfromȱit,ȱbutȱtheȱmaintenanceȱadvantageȱ inȱnotȱhavingȱmultipleȱcopiesȱofȱcodeȱmoreȱthanȱjustifiesȱthisȱcommonȱcodingȱidiom.ȱ Download at http://www.pin5i.com/ 1.1 Introduction 17 TIP Aȱ questionȱ frequentlyȱ askedȱ isȱ whyȱ chȱ isȱ declaredȱ asȱ anȱ integerȱ whenȱ weȱ areȱ usingȱ itȱ toȱ readȱ characters?ȱ Theȱ answerȱ isȱ thatȱ EOFȱ isȱ anȱ integerȱ valueȱ thatȱ requiresȱ moreȱbitsȱthanȱareȱavailableȱinȱaȱcharacterȱvariable;ȱthisȱfactȱpreventsȱaȱcharacterȱinȱtheȱ inputȱ fromȱ accidentallyȱ beingȱ interpretedȱ asȱ EOF.ȱ Butȱ itȱ alsoȱ meansȱ thatȱ ch,ȱ whichȱ isȱ receivingȱ theȱ characters,ȱ mustȱ beȱ largeȱ enoughȱ toȱ holdȱ EOFȱ 100,ȱ whichȱ isȱ whyȱ anȱ integerȱisȱused.ȱAsȱdiscussedȱinȱChapterȱ3,ȱcharactersȱareȱjustȱtinyȱintegersȱanyway,ȱsoȱ usingȱanȱintegerȱvariableȱtoȱholdȱcharacterȱvaluesȱcausesȱnoȱproblems.ȱ ȱ Oneȱ finalȱ commentȱ onȱ thisȱ fragmentȱ ofȱ theȱ program:ȱ thereȱ areȱ noȱ statementsȱ inȱ theȱ bodyȱ ofȱ theȱ whileȱ statement.ȱ Itȱ turnsȱ outȱ thatȱ theȱ workȱ doneȱ toȱ evaluateȱ theȱ whileȱ expressionȱisȱallȱthatȱisȱneeded,ȱsoȱthereȱisȱnothingȱleft forȱtheȱbodyȱofȱtheȱloopȱtoȱdo.ȱ Youȱ willȱ encounterȱ suchȱ loopsȱ occasionally,ȱ andȱ handlingȱ themȱ isȱ noȱ problem.ȱ Theȱ solitaryȱsemicolonȱafterȱtheȱwhileȱstatementȱisȱcalledȱtheȱemptyȱstatement,ȱandȱitȱisȱusedȱ inȱsituationsȱlikeȱthisȱoneȱwhereȱtheȱsyntaxȱrequiresȱaȱstatementȱbutȱthereȱisȱnoȱworkȱtoȱ beȱ done.ȱ Theȱ semicolonȱ isȱ onȱ aȱ lineȱ byȱ itselfȱ inȱ orderȱ toȱ preventȱ theȱ readerȱ fromȱ mistakenlyȱassumingȱthatȱtheȱnextȱstatementȱisȱmeȱbodyȱofȱtheȱloop.ȱ ȱ return num; } ȱ ȱ Theȱ returnȱstatementȱisȱhowȱaȱfunctionȱreturnsȱaȱvalueȱtoȱtheȱexpressionȱfromȱ whichȱitȱwasȱcalled.ȱInȱthisȱcase,ȱtheȱvalueȱofȱtheȱvariableȱ numȱisȱreturnedȱtoȱtheȱcallingȱ program,ȱwhereȱitȱisȱassignedȱtoȱtheȱmainȱprogramȇsȱvariableȱn_columns.ȱ ȱ ȱ ȱ ȱ 1.1.5 The rearrange Function /* ** Process a line of input by ** the indicated columns. The */ void rearrange( char *output, char in n_columns, int const { int col; int output_col; int len; concatenating the characters from output line is the NUL terminated, const *input, columns[] ) /* subscript for columns array */ /* output column counter */ /* length of input line */ Download at http://www.pin5i.com/ 18ȱ Chapter 1 A Quick Start Theseȱstatementsȱdefineȱtheȱrearrangeȱfunctionȱandȱdeclareȱsomeȱlocalȱvariablesȱ forȱit.ȱTheȱmostȱinterestingȱpointȱhereȱisȱthatȱtheȱfirstȱtwoȱparametersȱareȱdeclaredȱasȱ pointersȱbutȱarrayȱnamesȱareȱpassedȱasȱargumentsȱwhenȱtheȱfunctionȱisȱcalled.ȱWhenȱ anȱarrayȱnameȱisȱusedȱasȱanȱargument,ȱwhatȱisȱpassedȱtoȱtheȱfunctionȱisȱaȱpointerȱtoȱ theȱ beginningȱ ofȱ theȱ array,ȱ whichȱ isȱ actuallyȱ theȱ addressȱ whereȱ theȱ arrayȱ residesȱ inȱ memory.ȱTheȱfactȱthatȱaȱpointerȱisȱpassedȱratherȱthanȱatȱcopyȱofȱtheȱarrayȱisȱwhatȱgivesȱ arraysȱtheirȱcallȱbyȱreferenceȱsemantics.ȱTheȱfunctionȱcanȱmanipulateȱtheȱargumentȱasȱ aȱpointer,ȱorȱitȱcanȱuseȱaȱsubscriptȱwithȱtheȱargumentȱjustȱasȱwithȱanȱarrayȱname.ȱTheseȱ techniquesȱareȱdescribedȱinȱmoreȱdetailȱinȱChapterȱ8.ȱ ȱ Becauseȱ ofȱ theȱ callȱ byȱ referenceȱ semantics,ȱ though,ȱ ifȱ theȱ functionȱ modifiesȱ elementsȱofȱtheȱparameterȱarray,ȱitȱactuallyȱmodifiesȱtheȱcorrespondingȱelementsȱofȱtheȱ argumentȱ array.ȱ Thus,ȱ declaringȱ columnsȱ toȱ beȱ constȱ isȱ usefulȱ inȱ twoȱ ways.ȱ First,ȱ itȱ statesȱ thatȱ theȱ intentionȱ ofȱ theȱ functionȇsȱ authorȱ isȱ thatȱ thisȱ parameterȱ isȱ notȱ toȱ beȱ modified.ȱ Second,ȱ itȱ causesȱ theȱ compilerȱ toȱ verifyȱ thatȱ thisȱ intentionȱ isȱ notȱ violated.ȱ Thus,ȱ callersȱ ofȱ thisȱ functionȱ needȱ notȱ worryȱ aboutȱ theȱ possibilityȱ ofȱ elementsȱ ofȱ meȱ arrayȱpassedȱasȱtheȱfourthȱargumentȱbeingȱchanged.ȱ ȱ ȱ len = strlen( input ); output_col = 0; /* ** Process each pair of column numbers. */ for( col = 0; col < n_columns; col += 2 ){ ȱ ȱ Theȱrealȱworkȱofȱtheȱfunctionȱbeginsȱhere.ȱWeȱfirstȱgetȱtheȱlengthȱofȱtheȱinputȱ string,ȱsoȱweȱcanȱskipȱcolumnȱnumbersȱthatȱareȱbeyondȱtheȱendȱofȱtheȱinput.ȱTheȱ forȱ statementȱinȱCȱisȱnotȱquiteȱlikeȱotherȱlanguages;ȱitȱisȱmoreȱofȱatȱshorthandȱnotationȱforȱ aȱ commonlyȱ usedȱ styleȱ ofȱ whileȱ statement.ȱ Theȱ forȱ statementȱ containsȱ threeȱ expressionsȱ (allȱ ofȱ whichȱ areȱ optional,ȱ byȱ theȱ way).ȱ Theȱ firstȱ expressionȱ isȱ theȱ initializationȱandȱisȱevaluatedȱonceȱbeforeȱtheȱloopȱbegins.ȱTheȱsecondȱisȱtheȱtestȱandȱisȱ evaluatedȱbeforeȱeachȱiterationȱofȱtheȱloop;ȱifȱtheȱresultȱisȱfalseȱtheȱloopȱterminates.ȱTheȱ thirdȱexpression,ȱisȱtheȱadjustmentȱwhichȱisȱevaluatedȱatȱtheȱendȱofȱeachȱiterationȱjustȱ beforeȱ theȱ testȱ isȱ evaluated.ȱ Toȱ illustrate,ȱ theȱ forȱ loopȱ thatȱ beginsȱ aboveȱ couldȱ beȱ rewrittenȱasȱaȱwhileȱloop:ȱ ȱ col = 0; Download at http://www.pin5i.com/ 1.1 Introduction 19 ȱ ȱ while( col < n_columns ){ bodyȱofȱtheȱloopȱ col += 2; } int nchars = columns[col + 1] – columns[col] + 1; /* ** If the input line isn't this long or the output ** array is full, we're done */ if( columns[col] >= len || output_col == MAX_INPUT – 1 ) break; /* ** If there isn't room in the output array, only copy ** what will fit. */ if( output_col + nchars > MAX_INPUT – 1) nchars = MAX_INPUT – output_col – 1; /* ** Copy the relevant data. */ strncpy( output + output_col, input + columns[col], nchars ); output_col += nchars; TIP ȱ ȱ ȱ ȱ ȱ ȱ Hereȱ isȱ theȱ bodyȱ ofȱ theȱ forȱ loop,ȱ whichȱ beginsȱ byȱ computingȱ theȱ numberȱ ofȱ charactersȱinȱthisȱrangeȱofȱcolumns.ȱThenȱitȱchecksȱwhetherȱtoȱcontinueȱwithȱtheȱloop.ȱ Ifȱtheȱinputȱlineȱisȱshorterȱthanȱthisȱstartingȱcolumn,ȱorȱifȱtheȱoutputȱlineȱisȱalreadyȱfull,ȱ thereȱisȱnoȱmoreȱworkȱtoȱbeȱdoneȱandȱtheȱbreakȱstatementȱexitsȱtheȱloopȱimmediately.ȱ ȱTheȱ nextȱ testȱ checksȱ whetherȱ allȱ ofȱ theȱ charactersȱ fromȱ thisȱ rangeȱ ofȱ columnsȱ willȱfitȱinȱtheȱoutputȱline.ȱIfȱnot,ȱncharsȱisȱadjustedȱtoȱtheȱnumberȱthatȱwillȱfit.ȱ ȱ ItȱisȱcommonȱinȱȈthrowawayȈȱprogramsȱthatȱareȱusedȱonlyȱonceȱtoȱnotȱbotherȱcheckingȱ thingsȱsuchȱasȱarrayȱboundsȱandȱtoȱsimplyȱmakeȱtheȱarrayȱȈbigȱenoughȈȱsoȱthatȱitȱwillȱ neverȱ overflow.ȱ Unfortunately,ȱ thisȱ practiceȱ isȱ sometimesȱ usedȱ inȱ productionȱ code,ȱ too.ȱ There,ȱ mostȱ ofȱ theȱ extraȱ spaceȱ isȱ wasted, butȱ itȱ isȱ stillȱ possibleȱ toȱ overflowȱ theȱ Download at http://www.pin5i.com/ 20ȱ Chapter 1 A Quick Start array,ȱleadingȱtoȱaȱprogramȱfailure 8 .ȱ ȱ Finally,ȱtheȱ strncpyȱfunctionȱcopiesȱtheȱselectedȱcharactersȱfromȱtheȱinputȱlineȱ toȱtheȱnextȱavailableȱpositionȱinȱtheȱoutputȱline.ȱTheȱfirstȱtwoȱargumentsȱtoȱstrncpyȱareȱ theȱdestinationȱandȱsource,ȱrespectively,ȱofȱaȱstringȱtoȱcopy.ȱTheȱdestinationȱinȱthisȱcallȱ isȱtheȱpositionȱ output_colȱcolumnsȱpastȱtheȱbeginningȱofȱtheȱoutputȱarray.ȱTheȱsourceȱ isȱtheȱpositionȱcolumns[col]ȱpastȱtheȱbeginningȱofȱtheȱinputȱarray.ȱTheȱthirdȱargumentȱ specifiesȱ theȱ numberȱ ofȱ charactersȱ toȱ beȱ copied 9 .ȱ Theȱ outputȱ columnȱ counterȱ isȱ thenȱ advancedȱncharsȱpositions.ȱ ȱ } output[output_col] = '\0'; } ȱ Afterȱtheȱ loopȱends,ȱtheȱoutputȱstringȱisȱ terminatedȱ withȱaȱ NULȱcharacter;ȱnoteȱ thatȱtheȱbodyȱofȱtheȱloopȱtakesȱcareȱtoȱensureȱthatȱthereȱisȱspaceȱinȱtheȱarrayȱtoȱholdȱit.ȱ Thenȱexecutionȱreachesȱtheȱbottomȱofȱtheȱfunction,ȱsoȱanȱimplicitȱ returnȱisȱexecuted.ȱ Withȱnoȱexplicitȱ returnȱstatement,ȱnoȱvalueȱcanȱbeȱpassedȱbackȱtoȱtheȱexpressionȱfromȱ whichȱtheȱfunctionȱwasȱcalled.ȱTheȱmissingȱreturnȱvalueȱisȱnotȱaȱproblemȱhereȱbecauseȱ theȱfunctionȱwasȱdeclaredȱvoidȱ(thatȱis,ȱreturningȱnoȱvalue)ȱandȱthereȱisȱnoȱassignmentȱ orȱtestingȱofȱtheȱfunction‘sȱreturnȱvalueȱwhereȱitȱisȱcalled.ȱ ȱ ȱ ȱ ȱ 1.2 Other Capabilities Theȱ sampleȱ programȱ illustratedȱ manyȱ ofȱ theȱ Cȱ basics,ȱ butȱ thereȱ isȱ aȱ littleȱ moreȱ youȱ shouldȱ knowȱ beforeȱ youȱ beginȱ writingȱ yourȱ ownȱ programs.ȱ Firstȱ isȱ theȱ putcharȱ function,ȱ whichȱ isȱ theȱ companionȱ toȱ getchar.ȱ Itȱ takesȱ aȱ singleȱ integerȱ argumentȱ andȱ printsȱthatȱcharacterȱonȱtheȱstandardȱoutput.ȱȱ Also,ȱthereȱareȱmanyȱmoreȱlibraryȱfunctionsȱforȱmanipulatingȱstrings.ȱI’llȱbrieflyȱ introduceȱaȱfewȱofȱtheȱmostȱusefulȱonesȱhere.ȱUnlessȱotherwiseȱnoted,ȱeachȱargumentȱ toȱtheseȱfunctionsȱmayȱbeȱaȱstringȱliteral,ȱtheȱnameȱofȱaȱcharacterȱarray,ȱorȱaȱpointerȱtoȱ aȱcharacter.ȱ 8ȱTheȱastuteȱreaderȱwillȱhaveȱnoticedȱthatȱthereȱisȱnothingȱtoȱpreventȱgetsȱfromȱoverflowingȱtheȱinputȱarrayȱifȱanȱextremelyȱ longȱinputȱlineȱisȱencountered.ȱThisȱloopholeȱisȱreallyȱaȱshortcomingȱofȱgets,ȱwhichȱisȱoneȱreasonȱwhyȱfgetsȱ(describedȱinȱ chapterȱ15)ȱshouldȱbeȱusedȱinstead.ȱ 9 lf the source of the copy contains fewer characters than indicated by the third argument, the destination is padded to the proper length with NUL. bytes. Download at http://www.pin5i.com/ 1.4 Summary 21 strcpyȱisȱsimilarȱtoȱstrncpyȱexceptȱthatȱthereȱisȱnoȱspecifiedȱlimitȱtoȱtheȱȱnumberȱ ofȱ charactersȱ thatȱ areȱ copied.ȱ Itȱ takesȱ twoȱ arguments:ȱ theȱ stringȱ inȱ theȱ secondȱ argumentȱisȱcopiedȱintoȱtheȱfirst,ȱoverwritingȱanyȱstringȱthatȱtheȱfirstȱargumentȱmightȱ alreadyȱcontain,ȱstrcatȱalsoȱtakesȱtwoȱarguments,ȱbutȱthisȱfunctionȱappendsȱtheȱstringȱ inȱtheȱsecondȱargumentȱtoȱtheȱendȱofȱtheȱstringȱalreadyȱcontainedȱinȱtheȱfirst.ȱAȱstringȱ literalȱmayȱnotȱbeȱusedȱasȱtheȱfirstȱargumentȱtoȱeitherȱofȱtheseȱlastȱtwoȱfunctions.ȱItȱisȱ theȱ programmersȱ responsibilityȱ withȱ bothȱ functionsȱ toȱ ensureȱ thatȱ theȱ destinationȱ arrayȱisȱlargeȱenoughȱtoȱholdȱtheȱresult.ȱ Forȱsearchingȱinȱstrings,ȱthereȱisȱstrchr,ȱwhichȱtakesȱtwoȱargumentsȱȬȱtheȱfirstȱisȱ aȱstring,ȱandȱtheȱsecondȱisȱaȱcharacter.ȱItȱsearchesȱtheȱstringȱforȱtheȱfirstȱoccurrenceȱofȱ theȱ characterȱ andȱ returnsȱ aȱ pointerȱ toȱ theȱ positionȱ whereȱ itȱ wasȱ found.ȱ Ifȱ theȱ firstȱ argumentȱ doesȱ notȱ containȱ theȱ character,ȱ aȱ NULLȱ pointerȱ isȱ returnedȱ instead.ȱ Theȱ strstrȱfunctionȱisȱsimilar.ȱItsȱsecondȱargumentȱisȱaȱstring,ȱandȱitȱsearchesȱforȱtheȱfirstȱ occurrenceȱofȱthisȱstringȱinȱtheȱfirstȱargument.ȱ ȱ ȱ ȱ ȱ 1.3 Compiling ȱ Theȱ wayȱ youȱ compileȱ andȱ runȱ Cȱ programsȱ dependsȱ onȱ theȱ kindȱ ofȱ systemȱ you’reȱ using.ȱToȱcompileȱaȱprogramȱstoredȱinȱtheȱfileȱtesting.cȱonȱaȱUNIXȱmachine,ȱtryȱtheseȱ commands:ȱ cc testing.c a.out ȱ OnȱPC’s,ȱyouȱneedȱtoȱknowȱwhichȱcompilerȱyouȱareȱusing.ȱForȱBorlandȱC++,ȱtryȱthisȱ commandȱinȱaȱMSȬDOSȱwindow:ȱ bcc testing.c testing ȱ ȱ ȱ ȱ 1.4 Summary ȱ TheȱgoalȱofȱthisȱchapterȱwasȱtoȱdescribeȱenoughȱofȱCȱtoȱgiveȱyouȱanȱoverviewȱofȱtheȱ language.ȱ Withȱ thisȱ context,ȱ itȱ willȱ beȱ easierȱ toȱ understandȱ theȱ topicsȱ inȱ theȱ nextȱ chapters.ȱ Theȱ sampleȱ programȱ illustratedȱ numerousȱ points.ȱ Commentsȱ beginȱ withȱ / *ȱ andȱ endȱ withȱ */,ȱ andȱ areȱ usedȱ toȱ includeȱ descriptionsȱ inȱ theȱ program.ȱ Theȱ preprocessorȱ directiveȱ #includeȱ causesȱ theȱ contentsȱ ofȱ aȱ libraryȱ headerȱ toȱ beȱ Download at http://www.pin5i.com/ 22ȱ Chapter 1 A Quick Start processedȱ byȱ theȱ compiler,ȱ andȱ theȱ #defineȱ directiveȱ allowsȱ youȱ toȱ giveȱ symbolicȱ namesȱtoȱliteralȱconstants.ȱ Allȱ Cȱ programsȱ mustȱ haveȱ aȱ functionȱ calledȱ mainȱ inȱ whichȱ executionȱ begins.ȱ Scalarȱargumentsȱtoȱfunctionsȱareȱpassedȱbyȱvalue,ȱandȱarrayȱargumentsȱhaveȱcallȱbyȱ referenceȱ semantics.ȱ Stringsȱ areȱ sequencesȱ ofȱ charactersȱ terminatedȱ withȱ aȱ NULȱ byte,ȱ andȱ thereȱisȱ aȱ libraryȱofȱ functionsȱtoȱ manipulateȱstringsȱinȱvariousȱways.ȱTheȱ printf functionȱ performsȱ formattedȱ output,ȱ andȱ theȱ scanfȱ functionȱ isȱ usedȱ forȱ formattedȱ input;ȱ getcharȱ andȱ putcharȱ performȱ unformattedȱ characterȱ inputȱ andȱ output,ȱ respectively.ȱ ifȱ andȱ whileȱ statementsȱ workȱ muchȱ theȱ sameȱ inȱ Cȱ asȱ theyȱ doȱ inȱ otherȱ languages.ȱ Havingȱseenȱhowȱtheȱsampleȱprogramȱworks,ȱyouȱmayȱnowȱwishȱtoȱtryȱwritingȱ someȱCȱprogramsȱofȱyourȱown.ȱIfȱitȱseemsȱlikeȱthereȱoughtȱtoȱbeȱmoreȱtoȱtheȱlanguage,ȱ youȱ areȱ right,ȱ thereȱ isȱ muchȱ more,ȱ butȱ thisȱ samplingȱ shouldȱ beȱ enoughȱ toȱ getȱ youȱ started.ȱ ȱ ȱ ȱ ȱ 1.5 Summary of Cautions 1. 2. 3. 4. Notȱputtingȱampersandsȱinȱfrontȱofȱscalarȱargumentsȱtoȱscanfȱ(pageȱ12).ȱ Usingȱprintfȱformatȱcodesȱin scanfȱ(pageȱ13).ȱ Usingȱ&ȱforȱaȱlogicalȱANDȱinsteadȱofȱ&&ȱ(pageȱ14).ȱ Using = toȱcompareȱforȱequalityȱinsteadȱof == (pageȱ14).ȱ ȱ ȱ ȱ ȱ 1.6 Summary of Programming Tips 1. 2. 3. 4. 5. 6. 7. Usingȱ#includeȱfilesȱforȱdeclarationsȱ(pageȱ6).ȱ Usingȱ#defineȱtoȱgiveȱnamesȱtoȱconstantȱvaluesȱ(pageȱ7).ȱ Puttingȱfunctionȱprototypesȱinȱ#includeȱfilesȱ(pageȱ7).ȱ Checkingȱsubscriptȱvaluesȱbeforeȱusingȱthemȱ(pageȱ14).ȱ Nestingȱassignmentsȱinȱaȱwhileȱorȱifȱexpressionȱ(pageȱ16).ȱ Howȱtoȱwriteȱaȱloopȱwithȱanȱemptyȱbodyȱ(pageȱ17).ȱ Alwaysȱcheckȱtoȱbeȱsureȱthatȱyouȱdon’tȇȱgoȱoutȱofȱtheȱboundsȱofȱanȱarrayȱ(pageȱ19).ȱ Download at http://www.pin5i.com/ 1.8 Programming Exercises 23 1.7 Questions 1. Cȱ isȱ aȱ freeȬformȱ language,ȱ whichȱ meansȱ thatȱ thereȱ areȱ noȱ rulesȱ regardingȱ howȱ programsȱ mustȱ look 10 .ȱ Yetȱ theȱ sampleȱ programȱ followedȱ specificȱ spacingȱ rules.ȱ Whyȱdoȱyouȱthinkȱthisȱis?ȱ 2. Whatȱ isȱ theȱ advantageȱ ofȱ puttingȱ declarations,ȱ suchȱ asȱ functionȱ prototypes,ȱ inȱ headerȱfilesȱandȱthenȱusing #include toȱbringȱtheȱdeclarationsȱintoȱtheȱsourceȱfilesȱ whereȱtheyȱareȱneeded?ȱ 3. Whatȱisȱtheȱadvantageȱofȱusing #define toȱgiveȱnamesȱtoȱliteralȱconstants?ȱ 4. Whatȱformatȱstringȱwouldȱyouȱuseȱwithȱ printfȱinȱorderȱtoȱprintȱaȱdecimalȱinteger,ȱ aȱ string,ȱ andȱ aȱ floatingȬpointȱ value,ȱ inȱ thatȱ order?ȱ Separateȱ theȱ valuesȱ fromȱ oneȱ anotherȱwithȱaȱspace,ȱandȱendȱtheȱoutputȱwithȱaȱnewlineȱcharacter.ȱ 5. Writeȱtheȱ scanfȱstatementȱneededȱtoȱreadȱtwoȱintegers,ȱcalledȱ quantityȱandȱ price,ȱ followedȱbyȱaȱstring,ȱwhichȱshouldȱbeȱstoredȱinȱaȱcharacterȱarrayȱcalledȱdepartment.ȱ 6. ThereȱareȱnoȱchecksȱmadeȱonȱtheȱvalidityȱofȱanȱarrayȱsubscriptȱinȱC.ȱWhyȱdoȱyouȱ thinkȱthisȱobviousȱsafetyȱmeasureȱwasȱomittedȱfromȱtheȱlanguage?ȱ 7. Theȱrearrangeȱprogramȱdescribedȱinȱtheȱchapterȱcontainsȱtheȱstatementȱ ȱ strncpy( output + output_col, input + columns[col], nchars ); Theȱ strcpyȱ functionȱ takesȱ onlyȱ twoȱ arguments,ȱ soȱ theȱ numberȱ ofȱ charactersȱ itȱ copiesȱisȱdeterminedȱbyȱtheȱstringȱspecifiedȱbyȱtheȱsecondȱargument.ȱWhatȱwouldȱ beȱ theȱ effectȱ ofȱ replacingȱ theȱ strncpyȱ functionȱ callȱ withȱ aȱ callȱ toȱ strcpyȱ inȱ thisȱ program?ȱ 8. Theȱrearrangeȱprogramȱcontainsȱtheȱstatementȱ while( gets( input ) != NULL ){ ȱ ȱ ȱ ȱ ȱ Whatȱmightȱgoȱwrongȱwithȱthisȱcode?ȱ ȱ 1.8 Programming Exercises ȱ 1. TheȱȈHelloȱworld!ȈȱprogramȱisȱoftenȱtheȱfirstȱCȱprogramȱthatȱaȱstudentȱofȱCȱwrites.ȱ Itȱprintsȱ Hello world!ȱfollowedȱbyȱaȱnewlineȱonȱtheȱstandardȱoutput.ȱThisȱtrivialȱ programȱisȱaȱgoodȱoneȱtoȱuseȱwhenȱfiguringȱoutȱhowȱtoȱrun theȱCȱcompilerȱonȱyourȱ particularȱsystem.ȱ 10 ȱOtherȱthanȱforȱtheȱpreprocessorȱdirectives.ȱ Download at http://www.pin5i.com/ 24ȱ Chapter 1 A Quick Start 2. Writeȱaȱprogramȱthatȱreadsȱlinesȱfromȱtheȱstandardȱinput.ȱEachȱlineȱisȱprintedȱonȱ theȱstandardȱoutputȱprecededȱbyȱitsȱlineȱnumber.ȱTryȱtoȱwriteȱtheȱprogramȱsoȱthatȱ itȱhasȱnoȱbuiltȬinȱlimitȱonȱhowȱlongȱaȱlineȱitȱcanȱhandle.ȱ 3. Writeȱaȱprogramȱthatȱreadsȱcharactersȱfromȱtheȱstandardȱinputȱandȱwritesȱthemȱtoȱ theȱ standardȱ output.ȱ Itȱ shouldȱ alsoȱ computeȱ aȱ checksumȱ andȱ writeȱ itȱ outȱ afterȱ theȱ characters.ȱȱ Theȱchecksumȱisȱcomputedȱinȱaȱsigned charȱvariableȱthatȱisȱinitializedȱtoȱ—1.ȱAsȱ eachȱ characterȱ isȱ readȱ fromȱ theȱ standardȱ input,ȱ itȱ isȱ addedȱ toȱ theȱ checksum.ȱ Anyȱ overflowȱ fromȱ theȱ checksumȱ variableȱ isȱ ignored.ȱ Whenȱ allȱ ofȱ theȱ charactersȱ haveȱ beenȱ written,ȱ theȱ checksumȱ isȱ thenȱ writtenȱ asȱ aȱ decimalȱ integer,ȱ whichȱ mayȱ beȱ negative.ȱBeȱsureȱtoȱfollowȱtheȱchecksumȱwithȱaȱnewȬline.ȱ Onȱ computersȱ thatȱ useȱ ASCII,ȱ runningȱ yourȱ programȱ onȱ aȱ fileȱ containingȱ theȱ wordsȱȈHelloȱworld!Ȉȱfollowedȱbyȱaȱnewlineȱshouldȱproduceȱtheȱfollowingȱoutput:ȱ Hello world! 102 4. Writeȱ aȱ programȱ thatȱ readsȱ inputȱ linesȱ oneȱ byȱ oneȱ untilȱ endȱ ofȱ fileȱ isȱ reached,ȱ determinesȱtheȱlengthȱofȱeachȱinputȱline,ȱandȱthenȱprintsȱoutȱonlyȱtheȱlongestȱlineȱ thatȱ wasȱ found.ȱ Toȱ simplifyȱ matters,ȱ youȱ mayȱ assumeȱ thatȱ noȱ inputȱ lineȱ willȱ beȱ longerȱthanȱ1000ȱcharacters.ȱ 5. Theȱstatementȱ if( columns[col] >= len … ) break; inȱtheȱrearrangeȱprogramȱstopsȱcopyingȱrangesȱofȱcharactersȱasȱsoonȱasȱaȱrangeȱisȱ encounteredȱthatȱisȱpastȱtheȱendȱofȱtheȱinputȱline.ȱThisȱstatementȱisȱcorrectȱonlyȱifȱ theȱrangesȱareȱenteredȱinȱincreasingȱorder,ȱwhichȱmayȱnotȱbeȱtheȱcase.ȱModifyȱtheȱ rearrangeȱfunctionȱsoȱthatȱitȱwillȱworkȱcorrectlyȱevenȱifȱtheȱrangesȱareȱnotȱenteredȱ inȱorder.ȱ 6. Modifyȱ theȱ rearrangeȱ programȱ toȱ removeȱ theȱ restrictionȱ thatȱ anȱ evenȱ numberȱ ofȱ columnȱvaluesȱmustȱbeȱreadȱinitially.ȱIfȱanȱoddȱnumberȱofȱvaluesȱareȱread,ȱtheȱlastȱ valuedȱindicatesȱtheȱstartȱofȱtheȱfinalȱrangeȱofȱcharacters.ȱCharactersȱfromȱhereȱtoȱ theȱendȱofȱtheȱinputȱstringȱareȱcopiedȱtoȱtheȱoutputȱstring.ȱ ȱ ȱ ȱ Download at http://www.pin5i.com/ 2 Basic Concepts Thereȱisȱnoȱdoubtȱthatȱlearningȱtheȱfundamentalsȱofȱaȱprogrammingȱlanguageȱisȱnotȱasȱ muchȱ funȱ asȱ writingȱ programs.ȱ However,ȱ notȱ knowingȱ theȱ fundamentalsȱ makesȱ writingȱprogramsȱaȱlotȱlessȱfun.ȱ ȱ ȱ ȱ 2.1 Environments ȱ Inȱanyȱ particularȱ implementationȱofȱ ANSIȱC,ȱthereȱ areȱ twoȱ distinctȱenvironmentsȱ thatȱ areȱ ofȱ interest:ȱ theȱ translationȱ environment,ȱ inȱ whichȱ sourceȱ codeȱ isȱ convertedȱ inȱ toȱ executableȱ machineȱ instructions;ȱ andȱ theȱ executionȱ environment,ȱ inȱ whichȱ theȱ codeȱ actuallyȱruns.ȱTheȱStandardȱmakesȱitȱclearȱthatȱtheseȱenvironmentsȱneedȱnotȱbeȱonȱtheȱ sameȱ machine.ȱ Forȱ example,ȱ crossȬcompilersȱ runȱ onȱ oneȱ machineȱ butȱ produceȱ executableȱ codeȱ thatȱ willȱ beȱ runȱ onȱ aȱ differentȱ typeȱ ofȱ machine.ȱ Norȱ isȱ anȱ operatingȱ systemȱ aȱ requirement:ȱ theȱ Standardȱ alsoȱ discussesȱ freestandingȱ environmentsȱ inȱ whichȱ thereȱ isȱ noȱ operatingȱ system.ȱ Youȱ mightȱ encounterȱ thisȱ typeȱ ofȱ environmentȱ inȱ anȱ embeddedȱsystemȱsuchȱasȱtheȱcontrollerȱforȱaȱmicrowaveȱoven.ȱ ȱ ȱ ȱ 2.1.1 Translation Theȱ translationȱ phaseȱ consistsȱ ofȱ severalȱ steps.ȱ First,ȱ eachȱ ofȱ theȱ (potentiallyȱ many)ȱ sourceȱtilesȱthatȱmakeȱupȱaȱprogramȱareȱindividuallyȱconvertedȱtoȱobjectȱcodeȱviaȱtheȱ compilationȱ process.ȱ Then,ȱ theȱ variousȱ objectȱ filesȱ areȱ tiedȱ togetherȱ byȱ theȱ linkerȱ toȱ formȱ aȱ single,ȱ completeȱ executableȱ program.ȱ Theȱ linkerȱ alsoȱ bringsȱ inȱ anyȱ functionsȱ fromȱ theȱ standardȱ Cȱ librariesȱ thatȱ wereȱ usedȱ inȱ theȱ program,ȱ andȱ itȱ canȱ alsoȱ searchȱ personalȱprogramȱlibrariesȱasȱwell.ȱFigureȱ2.lȱillustratesȱthisȱprocess.ȱ Download at http://www.pin5i.com/ 26ȱ Chapter 2 Basic Concepts Source code Compiler Object code Source code Compiler Object code Source code Compiler Object code Libraries Linker Executable ȱ ȱ Figureȱ2.1ȱTheȱcompilationȱprocessȱ ȱ ȱ Theȱcompilationȱprocessȱitselfȱconsistsȱofȱseveralȱphases,ȱwithȱtheȱfirstȱbeingȱtheȱ preprocessor.ȱ Thisȱ phaseȱ performsȱ textualȱ manipulationsȱ onȱ theȱ sourceȱ code,ȱ forȱ example,ȱsubstitutingȱtheȱtextȱofȱidentifiersȱthatȱhaveȱbeenȱ #define’dȱandȱreadingȱtheȱ textȱofȱtilesȱthatȱwereȱ#includeȇd.ȱ Theȱsourceȱcodeȱisȱthenȱparsedȱtoȱdetermineȱtheȱmeaningsȱofȱitsȱstatements.ȱThisȱ secondȱstageȱisȱwhereȱmostȱerrorȱandȱwarningȱmessagesȱareȱproduced.ȱObjectȱcodeȱisȱ thenȱ generated.ȱ Objectȱ codeȱ isȱ aȱ preliminaryȱ formȱ ofȱ theȱ machineȱ instructionsȱ thatȱ implementȱ theȱ statementsȱ ofȱ theȱ programsȱ calledȱ forȱ byȱ aȱ commandȬlineȱ option,ȱ anȱ optimizerȱprocessesȱtheȱobjectȱcodeȱinȱorderȱtoȱmakeȱitȱmoreȱefficient.ȱThisȱoptimizationȱ takesȱextraȱtime,ȱsoȱitȱisȱusuallyȱnotȱdoneȱuntilȱtheȱprogramȱhasȱbeenȱdebuggedȱandȱisȱ readyȱtoȱgoȱintoȱproduction.ȱWhetherȱtheȱobjectȱcodeȱisȱproducedȱdirectlyȱorȱisȱinȱtheȱ formȱ ofȱ assemblyȱ languageȱ statementsȱ thatȱ mustȱ thenȱ beȱ assembledȱ inȱ aȱ separateȱ phaseȱtoȱformȱtheȱobjectȱfileȱisȱnotȱimportantȱtoȱus.ȱ ȱ ȱ ȱ Filename Conventions ȱ Althoughȱ theȱ Standardȱ doesȱ notȱ haveȱ anyȱ rulesȱ governingȱ theȱ namesȱ usedȱ forȱ tiles,ȱ mostȱenvironmentsȱhaveȱfilenameȱconventionsȱthatȱyouȱmustȱfollow.ȱCȱsourceȱcodeȱisȱ usuallyȱputȱinȱfilesȱwhoseȱnamesȱendȱwithȱtheȱ .cȱextension.ȱFilesȱthatȱareȱ #includeȇdȱ intoȱotherȱCȱsourceȱcodeȱareȱcalledȱheaderȱfilesȱandȱusuallyȱhaveȱnamesȱendingȱinȱ.h.ȱ Differentȱ environmentsȱ mayȱ haveȱ differentȱ conventionsȱ regardingȱ objectȱ fileȱ names.ȱ Forȱ example,ȱ theyȱ endȱ withȱ .oȱ onȱ UNIXȱ systemsȱ butȱ withȱ .objȱ onȱ MSȬDOSȱ systems.ȱ Download at http://www.pin5i.com/ 2.1 Environments 27 Compiling and Linking ȱ Theȱ specificȱ commandsȱ usedȱ toȱ compileȱ andȱ linkȱ Cȱ programsȱ varyȱ fromȱ system,ȱ butȱ manyȱ workȱ theȱ sameȱ asȱ theȱ twoȱ systemsȱ describedȱ here.ȱ Theȱ Cȱ compilerȱ onȱ mostȱ UNIXȱsystemsȱisȱcalledȱcc,ȱandȱitȱcanȱbeȱinvokedȱinȱaȱvarietyȱofȱways.ȱ ȱ ȱ ȱ 1. ToȱcompileȱandȱlinkȱaȱCȱprogramȱthatȱisȱcontainedȱentirelyȱinȱoneȱsourceȱfile:ȱ cc program.c Thisȱcommandȱproducesȱanȱexecutableȱprogramȱcalled a.out.ȱAnȱobjectȱfileȱcalledȱ program.oȱisȱproduced,ȱbutȱitȱisȱdeletedȱafterȱtheȱlinkingȱisȱcomplete.ȱ ȱ 2. ToȱcompileȱandȱlinkȱseveralȱCȱsourceȱfiles:ȱ cc main.c sort.c lookup.c Theȱ objectȱ filesȱ areȱ notȱ deletedȱ whenȱ moreȱ thanȱ oneȱ sourceȱ fileȱ isȱ compiled.ȱ Thisȱ factȱ allowsȱ youȱ toȱ recompileȱ onlyȱ theȱ file(s)ȱ thatȱ changedȱ afterȱ makingȱ modifications,ȱasȱshownȱinȱtheȱnextȱcommand.ȱ ȱ 3. ToȱcompileȱoneȱCȱsourceȱfileȱandȱlinkȱitȱwhitȱexistingȱobjectȱfiles:ȱ cc main.o lookup.o sort.c 4. Toȱ compileȱ aȱ singleȱ Cȱ sourceȱ fileȱ andȱ produceȱ anȱ objectȱ fileȱ (inȱ thisȱ case,ȱ calledȱ program.o)ȱforȱlaterȱlinking:ȱ cc –c program.c 5. ToȱcompileȱseveralȱCȱsourceȱfilesȱandȱproduceȱanȱobjectȱfileȱforȱeach:ȱ cc –c main.c sort.c lookup.c 6. Toȱlinkȱseveralȱobjectȱfiles:ȱ cc main.o sort.o lookup.o ȱ ȱ ȱ Theȱ –o name optionȱ mayȱ beȱ addedȱ toȱ anyȱ ofȱ theȱ commandsȱ aboveȱ thatȱ produceȱ anȱ executableȱprogram;ȱitȱcausesȱtheȱlinkerȱtoȱstoreȱtheȱexecutableȱprogramȱinȱaȱfileȱcalledȱ name ratherȱthanȱ a.out.ȱByȱdefault,ȱtheȱlinkerȱsearchesȱtheȱstandardȱCȱlibrary.ȱTheȱȱȱȱȬ lnameȱ flagȱ tellsȱ theȱ linkerȱ toȱ alsoȱ searchȱ theȱ libraryȱ calledȱ name;ȱ thisȱ optionȱ shouldȱ appearȱlastȱonȱtheȱcommandȱline.ȱThereȱareȱotherȱoptionsȱasȱwell;ȱconsultȱyourȱsystemȇȱ documentation.ȱ Download at http://www.pin5i.com/ 28ȱ Chapter 2 Basic Concepts Borlandȱ C/C++ȱ 5.0ȱ forȱ MSȬDOS/Windowsȱ hasȱ twoȱ interfacesȱ thatȱ youȱ canȱ use.ȱ Theȱ Windowsȱ Integratedȱ Developmentȱ Environmentȱ isȱ aȱ completeȱ selfȬcontainedȱ programmingȱ toolȱ thatȱ containsȱ aȱ sourceȬcodeȱ editor,ȱ debuggers,ȱ andȱ compilers.ȱ Itsȱ useȱ isȱ beyondȱ theȱ scopeȱ ofȱ thisȱ book.ȱ Theȱ MSȬDOSȱ commandȱ lineȱ interface,ȱ though,ȱ worksȱmuchȱtheȱsameȱasȱtheȱUNIXȱcompilers,ȱwithȱtheȱfollowingȱexceptions:ȱ ȱ 1. itsȱnameȱisȱbcc;ȱ ȱ 2. theȱobjectȱfilesȱareȱnamedȱfile.obj;ȱ ȱ 3. theȱ compilerȱ doesȱ notȱ deleteȱ theȱ objectȱ fileȱ whenȱ onlyȱ aȱ singleȱ sourceȱ fileȱ isȱ compiledȱandȱlinked;ȱandȱ ȱ 4. byȱdefault,ȱtheȱexecutableȱfileȱnamedȱafterȱtheȱfirstȱsourceȱorȱobjectȱfileȱnamedȱonȱ theȱ commandȱ line,ȱ thoughȱ theȱ –enameȱ optionȱ mayȱ beȱ usedȱ toȱ putȱ theȱ executableȱ programȱinȱname.exe.ȱ ȱ ȱ ȱ ȱ 2.1.2 Execution ȱ Theȱexecutionȱofȱaȱprogramȱalsoȱgoesȱthroughȱseveralȱphases.ȱFirst,ȱtheȱprogramȱmustȱ beȱloadedȱintoȱmemory.ȱInȱhostedȱenvironmentsȱ(thoseȱwithȱanȱoperatingȱsystem),ȱthisȱ taskȱisȱhandledȱbyȱtheȱoperatingȱsystem.ȱItȱisȱatȱthisȱpointȱthatȱpreȬinitializedȱvariablesȱ thatȱarcȱnotȱstoredȱonȱtheȱstackȱareȱgivenȱtheirȱinitialȱvalues.ȱProgramȱloadingȱmustȱbeȱ arrangedȱ manuallyȱ inȱ freestandingȱ environments,ȱ perhapsȱ byȱ placingȱ theȱ executableȱ codeȱinȱreadȬonlyȬmemoryȱ(ROM).ȱȱ Executionȱofȱtheȱprogramȱnowȱbegins.ȱInȱhostedȱenvironments,ȱaȱsmallȱstartupȱ routineȱisȱusuallyȱlinkedȱwithȱtheȱprogram.ȱItȱperformsȱvariousȱhousekeepingȱchores,ȱ suchȱasȱgatheringȱtheȱcommandȱlineȱargumentsȱsoȱthatȱtheȱprogramȱcanȱaccessȱthem.ȱ Theȱmainȱfunctionȱisȱthanȱcalled.ȱ Yourȱ codeȱ isȱ nowȱ executed.ȱ Onȱ mostȱ machines,ȱ yourȱ programȱ willȱ useȱ aȱ runtimeȱ stack,ȱ whereȱ variablesȱ localȱ toȱ functionsȱ andȱ functionȱ returnȱ addressesȱ areȱ stored.ȱ Theȱ programȱ canȱ alsoȱ useȱ staticȱ memory;ȱ variablesȱ storedȱ inȱ staticȱ memoryȱ retainȱtheirȱvaluesȱthroughoutȱtheȱprogram’sȱexecution.ȱ Theȱfinalȱphaseȱisȱtheȱterminationȱofȱtheȱprogram,ȱwhichȱcanȱresultȱfromȱseveralȱ differentȱ causes.ȱ ȈNormalȈȱ terminationȱ isȱ whenȱ theȱ mainȱ functionȱ returns. 11 ȱ Someȱ executionȱ environmentsȱ allowȱ theȱ programȱ toȱ returnȱ aȱ codeȱ thatȱ indicatesȱ whyȱ theȱ programȱ stoppedȱ executing.ȱ Inȱ hostedȱ environments,ȱ theȱ startupȱ routineȱ receivesȱ 11 ȱOrȱwhenȱsomeȱfunctionȱcalls exit,ȱdescribedȱinȱChapterȱ16.ȱ Download at http://www.pin5i.com/ 2.2 Lexical Rules 29 ȱ controlȱagainȱandȱmayȱperformȱvariousȱhousekeepingȱtasks,ȱsuchȱasȱclosingȱanyȱfilesȱ thatȱtheȱprogramȱmayȱhaveȱusedȱbutȱdidȱnotȱexplicitlyȱclose.ȱTheȱprogramȱmightȱalsoȱ haveȱbeenȱinterrupted,ȱperhapsȱdueȱtoȱtheȱuserȱpressingȱtheȱbreakȱkeyȱorȱhangingȱupȱaȱ telephoneȱconnection,ȱorȱitȱmightȱhaveȱinterruptedȱitselfȱdueȱtoȱanȱerrorȱthatȱoccurredȱ duringȱexecution.ȱ ȱ ȱ ȱ 2.2 Lexical Rules ȱ Theȱ lexicalȱ rules,ȱ likeȱ spellingȱ rulesȱ inȱ English,ȱ governȱ howȱ youȱ formȱ theȱ individualȱ pieces,ȱcalledȱtokens,ȱofȱaȱsourceȱprogram.ȱ AnȱANSIȱCȱprogramȱconsistsȱofȱdeclarationsȱandȱfunctions.ȱTheȱfunctionsȱdefineȱ theȱworkȱtoȱbeȱperformed,ȱwhereasȱtheȱdeclarationsȱdescribeȱtheȱfunctionsȱand/orȱtheȱ kindȱofȱdataȱ(andȱsometimesȱtheȱdataȱvaluesȱthemselves)ȱonȱwhichȱtheȱfunctionsȱwillȱ operate.ȱCommentsȱmayȱbeȱinterspersedȱthroughoutȱtheȱsourceȱcode.ȱ ȱ ȱ ȱ 2.2.1 Characters ȱ Theȱ Standardȱ doesȱ notȱ requireȱ thatȱ anyȱ specificȱ characterȱ setȱ beȱ usedȱ inȱ aȱ Cȱ environment,ȱbutȱitȱdoesȱspecifyȱthatȱtheȱcharacterȱsetȱmustȱhaveȱtheȱEnglishȱalphabetȱ inȱ bothȱ upperȱ andȱ lowercase,ȱ theȱ digitsȱ 0ȱ throughȱ 9,ȱ andȱ theȱ followingȱ specialȱ characters.ȱ ȱ ! " # % ' ( ) * + , - . / : ; < > = ? [ ] \ ^ _ { } | ~ Theȱ newlineȱ characterȱ isȱ whatȱ marksȱ theȱ endȱ ofȱ eachȱ lineȱ ofȱ sourceȱ codeȱ and,ȱ whenȱ characterȱ inputȱ isȱ readȱ byȱ theȱ executingȱ program,ȱ theȱ endȱ ofȱ eachȱ lineȱ ofȱ input.ȱ Ifȱ neededȱbyȱtheȱruntimeȱenvironment,ȱtheȱȈnewlineȈȱcanȱbeȱaȱsequenceȱofȱcharacters,ȱbutȱ theyȱareȱallȱtreatedȱasȱifȱtheyȱwereȱaȱsingleȱcharacter.ȱTheȱspace,ȱtab,ȱverticalȱtab,ȱandȱ formȱ feedȱ charactersȱ areȱ alsoȱ required.ȱ Theseȱ charactersȱ andȱ theȱ newlineȱ areȱ oftenȱ referredȱ toȱ collectivelyȱ asȱ whiteȱ spaceȱ character,ȱ becauseȱ theyȱ causeȱ spaceȱ toȱ appearȱ ratherȱthanȱmakingȱmarksȱonȱtheȱpageȱwhenȱtheyȱareȱprinted.ȱ TheȱStandardȱdefinesȱseveralȱtrigraphsȱ–ȱaȱtrigraphȱisȱaȱsequenceȱofȱcharactersȱ thatȱrepresentsȱanotherȱcharacter.ȱTrigraphsȱareȱprovidedȱsoȱthatȱCȱenvironmentsȱcanȱ beȱimplementedȱwithȱcharacterȱsetsȱthatȱlackȱsomeȱofȱtheȱrequiredȱcharacters.ȱHereȱareȱ theȱtrigraphsȱandȱtheȱcharactersȱthatȱtheyȱrepresent.ȱ Download at http://www.pin5i.com/ 30ȱ Chapter 2 Basic Concepts ??( ??) ??! [ ] | ??< ??> ??' { } ^ ??= ??/ ??- # \ ~ ȱ Thereȱ isȱ noȱ specialȱ significanceȱ toȱ aȱ pairȱ ofȱ questionȱ marksȱ followedȱ byȱ anyȱ otherȱ character.ȱ ȱ ȱ CAUTION! Althoughȱ trigraphsȱ areȱ vitalȱ inȱ aȱ fewȱ environments,ȱ theyȱ areȱ aȱ minorȱ nuisanceȱ forȱ nearlyȱ everyoneȱ else.ȱ Theȱ sequenceȱ ??ȱ wasȱ chosenȱ toȱ beginȱ eachȱ trigrahpȱ becauseȱ itȱ doesȱ notȱ oftenȱ occurȱ naturally,ȱ butȱ thereinȱ liesȱ theȱ danger.ȱ Youȱ neverȱ thinkȱ aboutȱ trigraphsȱbecauseȱtheyȱareȱusuallyȱnotȱaȱproblem,ȱsoȱwhenȱoneȱisȱwrittenȱaccidentally,ȱ asȱinȱ ȱ ȱ printf( "Delete file (are you really sure??): " ); theȱresultingȱ]ȱinȱtheȱoutputȱisȱsureȱtoȱsurpriseȱyou.ȱ ThereȱareȱaȱfewȱcontextsȱinȱwritingȱCȱsourceȱcodeȱwhereȱyouȱwouldȱlikeȱtoȱuseȱaȱ particularȱ characterȱ butȱ cannotȱ becauseȱ thatȱ characterȱ hasȱ aȱ specialȱ meaningȱ inȱ thatȱ context.ȱForȱexample,ȱtheȱquotationȱmarkȱ "ȱisȱusedȱtoȱdelimitȱstringȱliterals.ȱHowȱdoesȱ oneȱ includeȱ aȱ quotationȱ markȱ withinȱ aȱ stringȱ literal?ȱ K&Rȱ Cȱ definedȱ severalȱ escapeȱ sequencesȱorȱcharacterȱescapesȱtoȱovercomeȱthisȱdifficulty,ȱandȱANSIȱCȱhasȱaddedȱaȱfewȱ newȱonesȱtoȱtheȱlist.ȱEscapeȱsequencesȱconsistȱofȱaȱbackslashȱfollowedȱbyȱoneȱorȱmoreȱ otherȱ characters.ȱ Eachȱ ofȱ theȱ escapeȱ sequencesȱ inȱ theȱ listȱ belowȱ representsȱ theȱ characterȱthatȱfollowsȱtheȱbackslashȱbutȱwithoutȱtheȱspecialȱmeaningȱusuallyȱattachedȱ toȱtheȱcharacter.ȱ ȱ \? Usedȱ whenȱ writingȱ multipleȱquestionȱ marksȱ toȱ preventȱ themȱfromȱbeingȱ interpretedȱasȱtrigraphs.ȱ \* Usedȱtoȱgetȱquotationȱmarksȱinsideȱofȱstringȱliterals.ȱ \' Usedȱtoȱwriteȱaȱcharacterȱliteralȱforȱtheȱcharacterȱ'.ȱ \\ Usedȱ whenȱ aȱ backslashȱ isȱ neededȱ toȱ preventȱ itsȱ beingȱ interpretedȱ asȱ aȱ characterȱescape.ȱ ȱ K&R C Thereȱareȱmanyȱcharactersȱthatȱareȱnotȱusedȱtoȱexpressȱsourceȱcodeȱbutȱareȱveryȱ usefulȱ inȱ formattingȱ programȱ outputȱ orȱ manipulatingȱ aȱ terminalȱ displayȱ screen.ȱ Characterȱescapesȱareȱalsoȱprovidedȱtoȱsimplifyȱtheirȱinclusionȱinȱyourȱprogram.ȱTheseȱ characterȱescapesȱwereȱchosenȱforȱtheirȱmnemonicȱvalue.ȱ ȱ ȱ Theȱcharacterȱescapesȱmarkedȱwithȱ†ȱareȱnewȱtoȱANSIȱCȱandȱareȱnotȱimplementedȱinȱ K&RȱC.ȱ Download at http://www.pin5i.com/ 2.2 Lexical Rules 31 ȱ \a † Alertȱ character.ȱ Thisȱ ringsȱ theȱ terminalȱ bellȱ orȱ producesȱ someȱ otherȱ audibleȱorȱvisualȱsignal.ȱ \b Backspaceȱcharacter.ȱ \f Formfeedȱcharacter.ȱ \n Newlineȱcharacter.ȱ \r Carriageȱreturnȱcharacter.ȱ \t Horizontalȱtabȱcharacter.ȱ \v † Verticalȱtabȱcharacter.ȱ \ddd dddȱrepresentsȱfromȱoneȱtoȱthreeȱoctalȱdigits.ȱThisȱescapeȱrepresentsȱtheȱ characterȱwhoseȱrepresentationȱhasȱtheȱgivenȱoctalȱvalue.ȱ \xddd † Likeȱtheȱabove,ȱexceptȱthatȱtheȱvalueȱisȱspecifiedȱinȱhexadecimal.ȱ ȱ Noteȱ thatȱ anyȱ numberȱ ofȱ hexadecimalȱ digitsȱ mayȱ beȱ includedȱ inȱ aȱ \xdddȱ sequence,ȱbutȱtheȱresultȱisȱundefinedȱifȱtheȱresultingȱvaluedȱisȱlargerȱthanȱwhatȱwillȱfitȱ inȱaȱcharacter.ȱ ȱ ȱ ȱ 2.2.2 Comments ȱ CAUTION! Cȱcommentsȱbeginȱwithȱtheȱcharactersȱ/*,ȱendȱwithȱtheȱcharactersȱ*/,ȱandȱmayȱcontainȱ anythingȱ exceptȱ */ȱ inȱ between.ȱ Whereasȱ commentsȱ mayȱ spanȱ multipleȱ linesȱ inȱ theȱ sourceȱ code,ȱ theyȱ mayȱ notȱ beȱ nestedȱ withinȱ oneȱ another.ȱ Noteȱ thatȱ theseȱ characterȱ sequencesȱdoȱnotȱbeginȱorȱendȱcommentsȱwhenȱtheyȱappearȱinȱstringȱliterals.ȱ Eachȱ commentȱ isȱ strippedȱ fromȱ theȱ sourceȱ codeȱ byȱ theȱ preprocessorȱ andȱ replacedȱ byȱ aȱ singleȱ space.ȱ Commentsȱ mayȱ thereforeȱ appearȱ anywhereȱ thatȱ whiteȱ spaceȱcharactersȱmayȱappear.ȱ ȱ A.ȱcommentȱbeginsȱwhereȱitȱbeginsȱandȱendsȱwhereȱitȱends,ȱandȱitȱincludesȱeverythingȱ onȱ allȱ theȱ linesȱ inȱ between.ȱ Thisȱ statementȱ mayȱ seemȱ obvious,ȱ butȱ itȱ wasnȇtȱ toȱ theȱ studentȱwhoȱwroteȱthisȱinnocentȱlookingȱfragmentȱofȱcode.ȱ Canȱyouȱseeȱwhyȱonlyȱtheȱfirstȱvariableȱisȱinitialized?ȱ ȱ x1 x2 x3 x4 CAUTION! = = = = 0; 0; 0; 0 /*********************** ** Initialize the ** ** counter variables. ** ***********************/ ȱ Takeȱcareȱtoȱterminateȱcommentsȱwithȱ*/ȱratherȱthanȱ*?.ȱTheȱlatterȱcanȱoccurȱifȱyouȱareȱ typingȱrapidlyȱorȱholdȱtheȱshiftȱkeyȱdownȱtooȱlong.ȱThisȱmistakeȱlooksȱobviousȱwhenȱ pointedȱout,ȱbutȱitȱisȱdeceptivelyȱhardȱtoȱfindȱinȱrealȱprograms.ȱ ȱ Download at http://www.pin5i.com/ 32ȱ Chapter 2 Basic Concepts 2.2.3 Free Form Source Code Cȱisȱaȱfreeȱformȱlanguage,ȱmeaningȱthatȱthereȱareȱnoȱrulesȱgoverningȱwhereȱstatementsȱ canȱbeȱwritten,ȱhowȱmanyȱstatementsȱmayȱappearȱonȱaȱline,ȱwhereȱspacesȱshouldȱbeȱ put,ȱ orȱ howȱ manyȱ spacesȱ canȱ occur. 12 ȱ Theȱ onlyȱ ruleȱ isȱ thatȱ oneȱ orȱ moreȱ whiteȱ spaceȱ charactersȱ(orȱaȱcomment)ȱmustȱappearȱbetweenȱtokensȱthatȱwouldȱbeȱinterpretedȱasȱaȱ singleȱlongȱtokenȱifȱtheyȱwereȱadjacent.ȱThus,ȱtheȱfollowingȱstatementsȱareȱequivalent:ȱ ȱ y=x+1; y = x + 1 ; y = x + 1; Ofȱtheȱnextȱgroupȱofȱstatements,ȱtheȱfirstȱthreeȱareȱequivalent,ȱbutȱtheȱlastȱisȱillegal.ȱ ȱ int x; int x; int/*comment*/x; intx; ȱ Thisȱfreedomȱisȱaȱmixedȱblessing;ȱyouȱwillȱhearȱsomeȱsoapboxȱphilosophyȱaboutȱthisȱ issueȱshortly.ȱ ȱ ȱ ȱ 2.2.4 Identifiers ȱ Identifiersȱ areȱ theȱ namesȱ usedȱ forȱ variables,ȱ functions,ȱ types,ȱ andȱ soȱ forth.ȱ Theyȱ areȱ composedȱ ofȱ upperȱ andȱ lowercaseȱ letters,ȱ digits,ȱ andȱ theȱ underscoreȱ character,ȱ butȱ theyȱmayȱnotȱbeginȱwithȱaȱdigit.ȱCȱisȱaȱcaseȱsensitiveȱlanguage,ȱsoȱabc,ȱAbc,ȱabC,ȱandȱABCȱ areȱfourȱdifferentȱidentifiers.ȱIdentifiersȱmaybeȱanyȱlength,ȱthoughȱtheȱStandardȱallowsȱ theȱcompilerȱtoȱignoreȱcharactersȱafterȱtheȱfirstȱ31.ȱItȱalsoȱallowsȱanȱimplementationȱtoȱ restrictȱidentifiersȱforȱexternalȱnamesȱ(thatȱis,ȱthoseȱthatȱtheȱlinkerȱmanipulates)ȱtoȱsixȱ monocaseȱcharacters.ȱ 12 ȱExceptȱforȱpreprocessorȱdirectives,ȱdescribedȱinȱChapterȱ14,ȱwhichȱareȱlineȱoriented.ȱ Download at http://www.pin5i.com/ 2.3 Program Style 33 TheȱfollowingȱCȱkeywordsȱareȱreserved,ȱmeaningȱthatȱtheyȱcannotȱalsoȱbeȱusedȱ asȱidentifiers.ȱ ȱ auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while ȱ ȱ ȱ 2.2.5 Form of a Program ȱ AȱCȱprogramȱmayȱbeȱstoredȱinȱoneȱorȱmoreȱsourceȱtiles.ȱAlthoughȱoneȱsourceȱfileȱmayȱ containȱ moreȱ thanȱ oneȱ function,ȱ everyȱ functionȱ mustȱ beȱ completelyȱ containedȱ inȱ aȱ singleȱ sourceȱ file. 13 ȱ Thereȱ areȱ noȱ rulesȱ inȱ theȱ Standardȱ governingȱ thisȱ issue,ȱ butȱ aȱ reasonableȱ organizationȱ ofȱ aȱ Cȱ programȱ isȱ forȱ eachȱ sourceȱ fileȱ toȱ containȱ aȱ groupȱ ofȱ relatedȱ functions.ȱ Thisȱ techniqueȱ hasȱ theȱ sideȱ benefitȱ ofȱ makingȱ itȱ possibleȱ toȱ implementȱabstractȱdataȱtypes.ȱ ȱ ȱ ȱ 2.3 Program Style ȱ Aȱ fewȱ commentsȱ onȱ programȱ styleȱ areȱ inȱ order.ȱ Freeformȱ languageȱ suchȱ asȱ Cȱ willȱ acceptȱ sloppyȱ programs,ȱ whichȱ areȱ quickȱ andȱ easyȱ toȱ writeȱ butȱ difficultȱ toȱ readȱ andȱ understandȱlater.ȱWeȱhumansȱrespondȱtoȱvisualȱcluesȱsoȱputtingȱthemȱinȱyourȱsourceȱ codeȱ willȱ aidȱ whoeverȱ mustȱ readȱ itȱ later.ȱ (Thisȱ mightȱ beȱ you!)ȱ Programȱ 2.1ȱ isȱ anȱ exampleȱthat,ȱalthoughȱadmittedlyȱextreme,ȱillustratesȱtheȱproblem.ȱThisȱisȱaȱworkingȱ programȱ thatȱ performsȱ aȱ marginallyȱ usefulȱ function.ȱ Theȱ questionȱ is,ȱ whatȱ doesȱ itȱ do? 14 ȱWorseȱyet,ȱsupposeȱyouȱhadȱtoȱmakeȱaȱmodificationȱtoȱthisȱprogram!ȱAlthoughȱ experiencedȱCȱprogrammersȱcouldȱfigureȱitȱoutȱgivenȱenoughȱtime,ȱfewȱwouldȱbother.ȱ Itȱ wouldȱ beȱ quickerȱ andȱ easierȱ toȱ justȱ tossȱ itȱ outȱ andȱ writeȱ aȱ newȱ programȱ fromȱ scratch.ȱ ȱTechnically,ȱaȱfunctionȱcouldȱbeginȱinȱoneȱsourceȱfileȱandȱcontinueȱinȱanotherȱifȱtheȱsecondȱwereȱ#includeȇdȱintoȱtheȱfirst.ȱ However,ȱthisȱprocedureȱisȱnotȱaȱgoodȱuseȱofȱtheȱ#includeȱdirective.ȱ 13 ȱBelieveȱitȱorȱnot,ȱitȱprintsȱtheȱlyricsȱtoȱtheȱsongȱTheȱtwelveȱDaysȱofȱChristmas.ȱTheȱprogramȱisȱaȱminorȱmodificationȱofȱoneȱ writtenȱbyȱIanȱPhillippsȱofȱCambridgeȱConsultantsȱLtd.ȱforȱtheȱInternationalȱObfuscatedȱCȱCodeȱContestȱ(seeȱ http://reality.sgi.com/csp/ioccc).ȱReprintedȱbyȱpermission.ȱCopyrightȱ©ȱ1988,ȱLandonȱCurtȱNollȱ&ȱLarryȱBassel.ȱAllȱRightsȱ Reserved.ȱPermissionȱforȱpersonal,ȱeducationalȱorȱnonȬprofitȱuseȱisȱgrantedȱprovidedȱthisȱcopyrightȱandȱnoticeȱisȱincludedȱinȱ itsȱentiretyȱandȱremainsȱunaltered.ȱAllȱotherȱusersȱmustȱreceiveȱpriorȱpermissionȱinȱwritingȱformȱbothȱLandonȱCurtȱNollȱandȱ LarryȱBassel.ȱ 14 Download at http://www.pin5i.com/ 34ȱ Chapter 2 Basic Concepts #include <stdio.h> main(t,_,a) char *a; {return!0<t?t<3?main(-79,-13,a+main(-87,1-_, main(-86, 0, a+1 )+a)):1,t<_?main(t+1, _, a ):3,main ( -94, -27+t, a )&&t == 2 ?_<13 ?main ( 2, _+1, "%s %d %d\n" ):9:16:t<0?t<-72?main(_, t,"@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+,/#{l,+,/n{n+\ ,/+#n+,/#;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K w'K:'+}e#';dq#'l q#'+d'K#!/\ +k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/+#n';d}rw' i;# ){n\ l]!/n{n#'; r{#w'r nc{nl]'/#{l,+'K {rw' iK{;[{nl]'/w#q#\ n'wk nw' iwk{KK{nl]!/w{%'l##w#' i; :{nl]'/*{q#'ld;r'}{nlwb!/*de}'c \ ;;{nl'-{}rw]'/+,}##'*}#nc,',#nw]'/+kd'+e}+;\ #'rdq#w! nr'/ ') }+}{rl#'{n' ')# }'+}##(!!/") :t<-50?_==*a ?putchar(a[31]):main(-65,_,a+1):main((*a == '/')+t,_,a\ +1 ):0<t?main ( 2, 2 , "%s"):*a=='/'||main(0,main(-61,*a, "!ek;dc \ i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"),a+1);} ȱ Programȱ2.1ȱ Mysteryȱprogramȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ mystery.cȱ ȱ ȱ ȱ Poorȱ styleȱ andȱ poorȱ documentationȱ areȱ twoȱ ofȱ theȱ reasonsȱ whyȱ softwareȱ isȱ soȱ TIP expensiveȱ toȱ createȱ andȱ maintain.ȱ Goodȱ programmingȱ styleȱ goesȱ aȱ longȱ wayȱ towardȱ makingȱ yourȱ programsȱ easierȱ toȱ read.ȱ Theȱ directȱ resultȱ ofȱ goodȱ styleȱ isȱ thatȱ theȱ programsȱ areȱ easierȱ toȱ getȱ working.ȱ Theȱ indirectȱ resultȱ isȱ thatȱ theyȱ areȱ easierȱ toȱ maintain,ȱwhichȱtranslatesȱtoȱbigȱcostȱsavings.ȱ Theȱexamplesȱinȱthisȱbookȱuseȱaȱstyleȱthatȱemphasizesȱtheȱstructureȱofȱtheȱprogramȱ throughȱjudiciousȱuseȱofȱwhiteȱspace.ȱHereȱareȱsomeȱofȱtheȱcharacteristicsȱofȱthisȱstyle,ȱ andȱwhyȱ]ȱchoseȱthemȱ ȱ 1. Aȱblankȱlineȱseparatesȱstatementsȱintoȱlogicalȱgroupsȱbasedȱonȱtheirȱfunctionality.ȱ Theȱreaderȱcanȱeasilyȱskipȱanȱentireȱgroupȱwithoutȱhavingȱtoȱreadȱeachȱlineȱofȱcodeȱ toȱseeȱwhereȱtheȱgroupȱlogicallyȱendsȱ 2. Theȱparenthesesȱinȱifȱandȱrelatedȱstatementsȱareȱpartȱofȱtheȱstatement,ȱnotȱpartȱofȱ theȱexpressionȱbeingȱtested.ȱThusȱIȱuseȱspacesȱtoȱseparateȱtheȱparenthesesȱfromȱtheȱ expressionȱ soȱ thatȱ theȱ expressionȱ standsȱ outȱ moreȱ clearly.ȱ Theȱ sameȱ isȱ trueȱ ofȱ functionȱprototypes.ȱ 3. Spacesȱ areȱ usedȱ aroundȱ mostȱ operatorsȱ inȱ orderȱ toȱ makeȱ expressionsȱ moreȱ readable.ȱSometimesȱIȱomitȱspacesȱinȱcomplexȱexpressionsȱtoȱshowȱtheȱgroupingȱofȱ theȱsubexpressions.ȱ 4. Statementsȱ thatȱ areȱ nestedȱ withinȱ otherȱ statementsȱ areȱ indentedȱ toȱ showȱ thisȱ relationship.ȱItȱisȱeasierȱtoȱlineȱupȱrelatedȱstatementsȱbyȱusingȱtabsȱtoȱindentȱratherȱ thanȱ spaces.ȱ Itȱ isȱ importantȱ toȱ useȱ aȱ largeȱ enoughȱ indentȱ toȱ beȱ ableȱ toȱ visuallyȱ Download at http://www.pin5i.com/ 2.4 Summary 35 beȱableȱtoȱvisuallyȱlocateȱmatchingȱpartsȱofȱtheȱprogramȱoverȱaȱpageȱofȱcode.ȱTwoȱ orȱthreeȱspacesȱareȱnotȱenough.ȱ Someȱpeopleȱavoidȱtabsȱbecauseȱtheyȱthinkȱtabsȱindentȱstatementsȱtooȱmuch.ȱInȱ complexȱfunctionsȱwithȱdeeplyȱnestedȱstatements,ȱtheȱlargeȱtabȱindentȱmeansȱthatȱ thereȱisȱlittleȱspaceȱleftȱonȱtheȱlineȱtoȱwriteȱtheȱstatements.ȱHoweverȱifȱtheȱfunctionȱ isȱ thatȱ complex,ȱ itȱ wouldȱ probablyȱ benefitȱ fromȱ beingȱ brokenȱ intoȱ smallerȱ functions,ȱ oneȱ ofȱ whichȱ containsȱ theȱ statementsȱ thatȱ wereȱ formerlyȱ nestedȱ soȱ deeply.ȱ 5. Mostȱcommentsȱareȱwrittenȱinȱblocks,ȱwhichȱmakesȱthemȱstandȱoutȱvisuallyȱformȱ theȱcode.ȱTheyȱareȱeasierȱforȱtheȱreaderȱtoȱfind,ȱandȱeasierȱtoȱskip.ȱ 6. Inȱtheȱdefinitionȱofȱaȱfunction,ȱtheȱreturnȱtypeȱappearsȱonȱaȱseparateȱlineȱbeforeȱtheȱ functionȱ name,ȱ whichȱ appearsȱ atȱ theȱ beginningȱ ofȱ theȱ nextȱ line.ȱ Toȱ locateȱ theȱ definitionȱofȱaȱfunction,ȱsearchȱforȱtheȱfunctionȱnameȱatȱtheȱbeginningȱofȱaȱline.ȱ Thereȱareȱmanyȱotherȱcharacteristicȱthatȱyouȱwillȱseeȱasȱyouȱstudyȱtheȱcodeȱexamples.ȱ Otherȱ programmersȱ haveȱ otherȱ personalȱ stylesȱ thatȱ theyȱ prefer.ȱ Whetherȱ youȱ adoptȱ thisȱ styleȱ orȱ aȱ differentȱ oneȱ isȱ notȱ nearlyȱ asȱ importantȱ asȱ consistentlyȱ usingȱ someȱ reasonableȱstyle.ȱIfȱyouȱareȱconsistent,ȱanyȱcompetentȱreaderȱwillȱbeȱableȱtoȱfigureȱoutȱ yourȱcodeȱeasilyȱenough.ȱ ȱ ȱ ȱ ȱ 2.4 Summary ȱ TheȱsourceȱcodeȱofȱaȱCȱprogramȱisȱstoredȱinȱoneȱorȱmoreȱfiles,ȱwithȱeachȱfunctionȱbeingȱ completelyȱ containedȱ inȱ oneȱ file.ȱ Placingȱ relatedȱ functionsȱ inȱ theȱ sameȱ fileȱ isȱ aȱ goodȱ strategy.ȱEachȱsourceȱfileȱisȱindividuallyȱcompiledȱtoȱproduceȱanȱobjectȱfile.ȱTheȱobjectȱ filesȱareȱthenȱlinkedȱtoȱformȱtheȱexecutableȱprogram.ȱThisȱmayȱorȱmayȱnotȱbeȱdoneȱonȱ theȱsameȱmachineȱthatȱwillȱeventuallyȱrunȱtheȱprogram.ȱ Theȱprogramȱmustȱbeȱloadedȱintoȱmemoryȱbeforeȱitȱcanȱbeȱexecuted.ȱInȱhostedȱ environments,ȱ thisȱ taskȱ isȱ performedȱ byȱ theȱ operatingȱ system;ȱ inȱ freestandingȱ environments,ȱtheȱprogramȱisȱoftenȱstoredȱpermanentlyȱinȱROM.ȱStaticȱvariablesȱthatȱ haveȱbeenȱinitializedȱareȱgivenȱtheirȱvaluesȱbeforeȱexecutionȱbegins.ȱExecutionȱofȱyourȱ codeȱ beginsȱ inȱ theȱ mainȱ function.ȱ Mostȱ environmentsȱ useȱ aȱ stackȱ toȱ storeȱ localȱ variablesȱandȱotherȱdata.ȱ TheȱcharacterȱsetȱusedȱbyȱaȱCȱimplementationȱmustȱincludeȱcertainȱcharacters.ȱ Trigraphsȱ allowȱ youȱ toȱ writeȱ charactersȱ thatȱ areȱ missingȱ fromȱ someȱ characterȱ sets.ȱ Escapeȱ sequencesȱ allowȱ charactersȱ withȱ noȱ printableȱ representation,ȱ suchȱ asȱ whiteȱ spaceȱcharacters,ȱtoȱbeȱincludedȱinȱaȱprogram.ȱ Download at http://www.pin5i.com/ 36ȱ Chapter 2 Basic Concepts Commentsȱbeginȱwithȱ/*ȱandȱendȱwithȱ*/,ȱandȱmayȱnotȱbeȱnested.ȱCommentsȱareȱ removedȱ byȱ theȱ preprocessor.ȱ Identifiersȱ areȱ composedȱ ofȱ letters,ȱ digits,ȱ andȱ theȱ underscoreȱ character,ȱ andȱ mayȱ notȱ beginȱ withȱ aȱ digit.ȱ Uppercaseȱ andȱ lowercaseȱ charactersȱareȱdistinctȱfromȱoneȱanotherȱinȱidentifiers.ȱKeywordsȱareȱreservedȱandȱmayȱ notȱbeȱusedȱasȱidentifiers.ȱCȱisȱaȱfreeȱformȱlanguage;ȱhowever,ȱwritingȱprogramsȱwithȱaȱ clearȱstyleȱmakesȱthemȱeasierȱtoȱreadȱandȱmaintain.ȱ ȱ ȱ ȱ 2.5 Summary of Cautions ȱ 1. Charactersȱinȱstringȱliteralsȱbeingȱmistakenlyȱinterpretedȱasȱtrigraphsȱ(pageȱ30).ȱ 2. Badlyȱwrittenȱcommentsȱcanȱunexpectedlyȱencloseȱstatementsȱ(pageȱ31).ȱ 3. Improperȱterminationȱofȱcommentsȱ(pageȱ31).ȱ ȱ ȱ ȱ 2.6 Summary of Programming Tips ȱ 1. Goodȱ styleȱ andȱ documentationȱ resultȱ inȱ programsȱ thatȱ areȱ easierȱ toȱ readȱ andȱ maintainȱ(pageȱ34).ȱ ȱ ȱ ȱ 2.7 Questions ȱ 1. Commentsȱ inȱ Cȱ doȱ notȱ nest.ȱ Whatȱ wouldȱ beȱ theȱ resultȱ ofȱ Ȉcommentingȱ outȈȱ theȱ codeȱinȱtheȱexampleȱshownȱbelow?ȱ ȱ void squares( int limit ) { /* Comment out this entire function int i; /* loop counter */ /* ** Print table of squares */ for( i = 0; i < limit; i += 1 ) printf( "%d %d0, i, i * i ); End of commented-out code */ } Download at http://www.pin5i.com/ 2.7 Questions 37 2. Whatȱareȱtheȱadvantagesȱofȱputtingȱaȱlargeȱprogramȱintoȱaȱsingleȱsourceȱfile?ȱ Whatȱareȱtheȱdisadvantages?ȱ 3. Showȱ theȱ stringȱ literalȱ thatȱ youȱ wouldȱ useȱ withȱ printfȱ inȱ orderȱ toȱ printȱ theȱ followingȱtext,ȱincludingȱtheȱquotationȱmarks:ȱ "Blunder??!??" 4. Whatȱisȱtheȱvalueȱofȱ\40?ȱOfȱ\100?ȱOfȱ\x40?ȱOfȱ\x100?ȱOfȱ\0123?ȱOfȱ\x0123?ȱ 5. Whatȱisȱtheȱresultȱofȱthisȱstatement?ȱ int x/*blah blah*/y; 6. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱdeclaration?ȱ int Case, If, While, Stop, stop; 7. Trueȱ orȱ False:ȱ Becauseȱ Cȱ (excludingȱ theȱ preprocessorȱ directives)ȱ isȱ aȱ freeȬformȱ language,ȱ theȱ onlyȱ rulesȱ thatȱ governȱ howȱ programsȱ areȱ writtenȱ areȱ theȱ syntaxȱ rules,ȱsoȱitȱdoesnȇtȱmatterȱhowȱtheȱprogramȱactuallyȱlooks.ȱ 8. Isȱtheȱloopȱinȱtheȱfollowingȱprogramȱcorrect?ȱ ȱ #include < stdio.h> int main( void ) { int x, y; x = 0; while( x < 10 ){ y = x * x; printf( "%d\t%d\n", x, y ); x += 1; } ȱ Isȱtheȱloopȱinȱthisȱprogramȱcorrect?ȱ ȱ #include <stdio.h> int main( void ) { int x, y; Download at http://www.pin5i.com/ 38ȱ Chapter 2 Basic Concepts x = 0; while( x < 10 ){ y = x * x; printf( "%d\t%d\n", x, y ); x += 1; } Whichȱprogramȱwasȱeasierȱtoȱcheck?ȱ 9. SupposeȱyouȱhaveȱaȱCȱprogramȱwhoseȱmainȱfunctionȱisȱinȱtheȱfileȱ main.cȱandȱhasȱ otherȱfunctionsȱinȱtheȱfilesȱ list.cȱandȱ report.c.ȱWhatȱcommand(s)ȱwouldȱyouȱuseȱ onȱyourȱsystemȱtoȱcompileȱandȱlinkȱthisȱprogram?ȱ 10. Howȱwouldȱyouȱmodifyȱtheȱcommandȱforȱtheȱpreviousȱquestionȱinȱorderȱtoȱlinkȱaȱ libraryȱcalledȱparseȱwithȱtheȱprogram?ȱ 11. Supposeȱ youȱ haveȱ aȱ Cȱ programȱ composedȱ ofȱ severalȱ separateȱ files,ȱ andȱ theyȱ includeȱoneȱanotherȱasȱshownȱbelow.ȱ ȱ File Includes Files main.c list.c symbol.c table.c table.h stdio.h, table.h list.h symbol.h table.h symbol.h, list.h ȱ Whichȱ filesȱ wouldȱ haveȱ toȱ beȱ recompiledȱ afterȱ youȱ makeȱ aȱ changeȱ toȱ list.c?ȱ Toȱ list.h?ȱToȱtable.h?ȱ ȱ ȱ ȱ 2.8 Programming Exercises ȱ 1. Writeȱ aȱ programȱ withȱ threeȱ functionsȱ inȱ threeȱ separateȱ sourceȱ files.ȱ Theȱ functionȱ incrementȱ shouldȱ takeȱ aȱ singleȱ integerȱ argumentȱ andȱ returnȱ theȱ valueȱ ofȱ thatȱ argumentȱplusȱone.ȱThisȱfunctionȱshouldȱbeȱinȱtheȱfile increment.cȱ Theȱ secondȱ functionȱ isȱ calledȱ negate.ȱ Itȱ alsoȱ takesȱ aȱ singleȱ integerȱ argumentȱ andȱ returnȱtheȱnegatedȱvalueȱofȱthatȱargumentȱ(forȱexample,ȱifȱtheȱargumentȱisȱ25,ȱtheȱ functionȱshouldȱreturnȱȬ25;ȱifȱtheȱargumentȱisȱȬ612,ȱtheȱfunctionȱshouldȱreturnȱ612).ȱ Theȱ finalȱ functionȱ isȱ main,ȱ inȱ theȱ fileȱ main.c,ȱ andȱ itȱ shouldȱ callȱ eachȱ ofȱ theȱ otherȱ functionsȱwithȱtheȱvaluesȱ10,ȱ0,ȱandȱȬ10ȱandȱprintȱtheȱresults.ȱ 2. WriteȱaȱprogramȱthatȱwillȱreadȱCȱsourceȱcodeȱfromȱtheȱstandardȱinputȱandȱensureȱ thatȱ theȱ bracesȱ areȱ pairedȱ correctly.ȱ Note:ȱ youȱ needȱ notȱ worryȱ aboutȱ bracesȱ thatȱ appearȱwithinȱcomments,ȱstringȱliterals,ȱorȱcharacterȱconstants.ȱ Download at http://www.pin5i.com/ 3 Data Programsȱ operateȱ onȱ data,ȱ andȱ thisȱ chapterȱ describesȱ data:ȱ itsȱ variousȱ types,ȱ itsȱ characteristics,ȱ andȱ howȱ toȱ declareȱ it.ȱ Threeȱ propertiesȱ ofȱ variablesȱ –ȱ theirȱ scope,ȱ linkage,ȱ andȱ storageȱ classȱ –ȱ areȱ alsoȱ described.ȱ Theseȱ threeȱ propertiesȱ determineȱ theȱ ȈvisibilityȈȱofȱaȱvariableȱ(thatȱis,ȱwhereȱitȱcanȱbeȱused)ȱandȱitsȱȈlifetimeȈȱ(howȱlongȱitsȱ valueȱlasts).ȱ ȱ ȱ ȱ 3.1 Basic Data Types ȱ Thereȱ areȱ onlyȱ fourȱ basicȱ dataȱ typesȱ inȱ Cȱ –ȱ integers,ȱ floatingȬpointȱ values,ȱ pointers,ȱ andȱ aggregateȱ typesȱ suchȱ asȱ arraysȱ andȱ structures.ȱ Allȱ otherȱ typesȱ areȱ derivedȱ fromȱ someȱcombinationȱofȱtheseȱfour.ȱLetȇsȱbeginȱbyȱintroducingȱtheȱintegersȱandȱfloatingȬ pointȱtypes.ȱ ȱ ȱ ȱ 3.1.1 The Integer Family ȱ Theȱintegerȱfamilyȱcontainsȱcharacters,ȱshortȱintegers,ȱintegers,ȱandȱlongȱintegers.ȱAllȱhaveȱ bothȱsignedȱandȱunsignedȱversions.ȱ ItȱsoundsȱasȱthoughȱaȱȈlongȱintegerȈȱoughtȱtoȱbeȱableȱtoȱholdȱlargerȱvaluesȱthanȱ aȱ Ȉshortȱ integer,Ȉȱ butȱ thisȱ assumptionȱ isȱ notȱ necessarilyȱ true.ȱ Theȱ ruleȱ regardingȱ theȱ relativeȱsizesȱofȱintegersȱisȱsimple:ȱ ȱ Longȱintegersȱareȱasȱleastȱasȱlargeȱasȱintegers,ȱwhichȱthemselvesȱareȱatȱleastȱasȱlargeȱasȱ shortȱintegers.ȱ Download at http://www.pin5i.com/ 40 Chapter 3 Data ȱ Type char signed char unsigned char short int unsigned short int int unsigned int long int unsigned long int K&R C Minimum Range 0ȱtoȱ127ȱ Ȭ127ȱtoȱ127ȱ 0ȱtoȱ255ȱ Ȭ32767ȱtoȱ32767ȱ 0ȱtoȱ65535ȱ Ȭ32767ȱtoȱ32767ȱ 0ȱtoȱ65535ȱ Ȭ2147483647ȱtoȱ2147483647ȱ 0ȱtoȱ4294967295ȱ ȱ Tableȱ3.1ȱMinimumȱvariableȱrangesȱ ȱ Noteȱ thatȱ thereȱ isȱ noȱ requirementȱ thatȱ aȱ longȱ integerȱ actuallyȱ beȱ longerȱ thanȱ aȱ shortȱ integer,ȱ itȱ simplyȱ cannotȱ beȱ anyȱ shorter.ȱ Theȱ ANSIȱ Standardȱ addsȱ aȱ specificationȱ forȱ theȱ minimumȱ allowableȱ rangeȱ ofȱ valuesȱ thatȱ eachȱ differentȱ typeȱ mayȱ represent,ȱ asȱ shownȱ inȱ Tableȱ 3.1.ȱ Thisȱ specificationȱ isȱ aȱ bigȱ improvementȱ overȱ K&Rȱ Cȱ whenȱ portabilityȱ amongȱ environmentsȱ isȱ important,ȱ especiallyȱ whenȱ theȱ environmentsȱ areȱ onȱmachinesȱwithȱwildlyȱdifferentȱarchitectures.ȱ Aȱ short intȱmustȱbeȱatȱleastȱ16ȱbits,ȱandȱaȱ long intȱatȱleastȱ32ȱbits. Itȱisȱupȱtoȱ theȱimplementorȱtoȱdecideȱwhetherȱtoȱmakeȱtheȱdefaultȱintȱ16ȱorȱ32ȱbits,ȱorȱsomethingȱ else.ȱ Usuallyȱ theȱ defaultȱ isȱ chosenȱ toȱ beȱ whateverȱ isȱ mostȱ naturalȱ (efficient)ȱ forȱ theȱ machine.ȱ Noteȱ thatȱ thereȱ isȱ stillȱ noȱ requirementȱ thatȱ theȱ threeȱ sizesȱ actuallyȱ beȱ different.ȱAnȱenvironmentȱforȱaȱmachineȱwithȱ32Ȭbilȱwordsȱandȱnoȱinstructionsȱtoȱdealȱ effectivelyȱwithȱshorterȱintegralȱvaluesȱcouldȱimplementȱthemȱallȱasȱ32Ȭbitȱintegers.ȱ Theȱ includeȱ file limits.h specifiesȱ theȱ characteristicsȱ ofȱ theȱ variousȱ integerȱ types.ȱ Itȱ definesȱ theȱ namesȱ shownȱ inȱ Tableȱ 3.2. limits.h alsoȱ definesȱ theȱ followingȱ names.ȱ CHAR_BITȱ isȱ theȱ numberȱ ofȱ bitsȱ inȱ aȱ characterȱ (atȱ leastȱ eight).ȱ CHAR_MINȱ andȱ CHAR_MAXȱdefineȱtheȱrangeȱforȱtheȱdefaultȱ ȱ ȱ Signed Unsigned Type Minimum Value Maximum Value Maximum Value SCHAR_MIN SCHAR_MAX UCHAR_MAX Characterȱ SHRT_MIN SHRT_MAX USHRT_MAX Shortȱintegerȱ INT_MIN INT_MAX UINT_MAX Integerȱ LONG_MIN LONG_MAX ULONG_MAX Longȱintegerȱ ȱ Talbeȱ3.2ȱLimitsȱofȱvariableȱrangesȱ Download at http://www.pin5i.com/ 3.1 Basic Data Types 41 characterȱtype;ȱtheseȱwillȱbeȱtheȱsameȱasȱeitherȱ SCHAR_MINȱandȱ SCHAR_MAXȱorȱzeroȱandȱ UCHAR_MAX.ȱ Finally,ȱ MB_LEN_MAXȱ specifiesȱ theȱ maximumȱ numberȱ ofȱ charactersȱ inȱ aȱ multibyteȱcharacter.ȱ Althoughȱ theȱ intentionȱ behindȱ charȱ variablesȱ isȱ forȱ themȱ toȱ holdȱ characters,ȱ charactersȱareȱactuallyȱtinyȱintegerȱvalues.ȱTheȱdefaultȱcharȱisȱalwaysȱeitherȱaȱ signed charȱorȱan unsigned char,ȱbutȱwhatȱyouȱgetȱdependsȱonȱtheȱcompiler.ȱThisȱfactȱmeansȱ thatȱaȱ charȱonȱdifferentȱmachinesȱmightȱholdȱdifferentȱrangesȱofȱvalues,ȱsoȱprogramsȱ thatȱuseȱ charȱvariablesȱareȱportableȱonlyȱifȱtheyȱrestrictȱtheseȱvariablesȱtoȱvaluesȱinȱtheȱ intersectionȱ ofȱ theȱ signedȱ andȱ unsignedȱ ranges,ȱ forȱ example,ȱ theȱ charactersȱ inȱ theȱ ASCIIȱcharacterȱsetȱallȱfallȱwithinȱthisȱrange.ȱ Theȱ portabilityȱ ofȱ programsȱ thatȱ useȱ charactersȱ asȱ littleȱ integersȱ canȱ beȱ improvedȱ byȱ explicitlyȱ declaringȱ theseȱ variablesȱ asȱ eitherȱ signedȱ orȱ unsigned.ȱ Thisȱ practiceȱensuresȱthatȱtheirȱsigned—nessȱisȱconsistentȱfromȱmachineȱtoȱmachine.ȱOnȱtheȱ otherȱhand,ȱdealingȱwithȱsignedȱcharactersȱonȱaȱmachineȱthatȱisȱmoreȱcomfortableȱwithȱ unsignedȱ charactersȱ willȱ beȱ lessȱ efficient,ȱ soȱ declaringȱ allȱ charȱ variablesȱ asȱ eitherȱ signedȱorȱ unsignedȱisȱprobablyȱnotȱaȱgoodȱidea.ȱAlso,ȱmanyȱlibraryȱfunctionsȱdealingȱ withȱ charactersȱ declareȱ theirȱ argumentsȱ asȱ char,ȱ whichȱ mayȱ causeȱ aȱ compatibilityȱ problemȱwithȱargumentsȱthatȱareȱexplicitlyȱdeclaredȱsignedȱorȱunsigned.ȱ TIP Whenȱportabilityȱisȱanȱissue,ȱtheȱsignedȬnessȱofȱcharactersȱposesȱaȱdilemma.ȱTheȱbestȱ compromiseȱ isȱ toȱ limitȱ theȱ valuesȱ storedȱ inȱ charȱ variablesȱ toȱ theȱ intersectionȱ ofȱ theȱ signedȱ andȱ unsignedȱ ranges,ȱ whichȱ maximizesȱ portabilityȱ withoutȱ sacrificingȱ efficiency,ȱandȱperformȱarithmeticȱonlyȱon charȱvariablesȱthatȱareȱexplicitlyȱsignedȱorȱ unsigned.ȱ ȱ ȱ ȱ Integer Literals ȱ Theȱ termȱ literalȱ isȱ anȱ abbreviationȱ forȱ literalȱ constant—anȱ entityȱ thatȱ specifiesȱ itsȱ ownȱ value,ȱ andȱ whoseȱ valueȱ cannotȱ beȱ changed.ȱ Thisȱ distinctionȱ isȱ importantȱ becauseȱ ANSIȱCȱallowsȱtheȱcreationȱofȱnamedȱconstantsȱ(variablesȱdeclaredȱtoȱbeȱ const),ȱwhichȱ areȱveryȱmuchȱlikeȱordinaryȱvariablesȱexceptȱthat,ȱonceȱinitialized,ȱtheirȱvaluesȱcannotȱ beȱchanged.ȱȱ Whenȱ anȱ integerȱ literalȱ isȱ writtenȱ inȱ aȱ program,ȱ whichȱ ofȱ theȱ nineȱ differentȱ typesȱ ofȱ theȱ integerȱ familyȱ doesȱ itȱ have?ȱ Theȱ answerȱ dependsȱ onȱ howȱ theȱ literalȱ isȱ written,ȱbutȱtheȱdefaultȱrulesȱcanȱbeȱoverriddenȱforȱsomeȱliteralsȱbyȱappendingȱaȱsuffixȱ toȱtheȱendȱofȱtheȱvalue.ȱTheȱcharactersȱ Lȱand lȱ(that’sȱanȱel,ȱnotȱtheȱdigitȱone)ȱcauseȱaȱ literalȱtoȱbeȱinterpretedȱasȱaȱlongȱintegerȱvalue,ȱandȱtheȱcharactersȱ Uȱandȱ uȱspecifyȱanȱ unsignedȱvalue.ȱAȱliteralȱmayȱbeȱdesignatedȱ unsigned longȱbyȱappendingȱoneȱofȱeachȱ toȱit.ȱ Download at http://www.pin5i.com/ 42 Chapter 3 Data Thereȱ areȱ manyȱ differentȱ waysȱ toȱ specifyȱ integerȱ literalsȱ inȱ sourceȱ code.ȱ Theȱ mostȱnaturalȱareȱdecimalȱintegerȱvalues,ȱsuchȱasȱthese:ȱ ȱ 123 65535 -275 15 Decimalȱ literalsȱ areȱ eitherȱ int,ȱ long,ȱ orȱ unsigned long.ȱ Theȱ shortestȱ typeȱ thatȱ willȱ containȱtheȱvalueȱisȱwhatȱisȱusedȱbyȱdefault.ȱ Integersȱcanȱbeȱgivenȱinȱoctalȱbyȱstartingȱwithȱtheȱdigitȱzero,ȱorȱinȱhexadecimalȱ byȱstartingȱwithȱ0x,ȱasȱinȱ ȱ 0173 0x7b 0177777 0xFFFF 000060 0xabcdef00 ȱ Theȱdigitsȱ8ȱandȱ9ȱareȱillegalȱinȱoctalȱliterals;ȱtheȱcharactersȱABCDEFȱorȱabcdefȱmayȱallȱbeȱ usedȱasȱdigitsȱinȱhexadecimalȱliterals.ȱOctalȱandȱhexadecimalȱliteralsȱareȱ int,ȱ unsigned int, longȱ,ȱorȱ unsigned long;ȱtheȱshortestȱoneȱthatȱisȱbigȱenoughȱtoȱholdȱtheȱvaluedȱisȱ whatȱisȱusedȱbyȱdefault.ȱ Andȱ thenȱ thereȱ areȱ characterȱ literals.ȱ Theseȱ alwaysȱ haveȱ typeȱ int;ȱ youȱ cannotȱ useȱtheȱunsignedȱorȱlongȱsuffixesȱonȱthem.ȱAȱcharacterȱliteralȱisȱaȱsingleȱcharacterȱ(orȱ characterȱescapeȱorȱtrigraph)ȱenclosedȱinȱapostrophies,ȱasȱinȱ ȱ 'M' '\n' \'??(' '\3777' ȱ Multibyeȱ characterȱ literalsȱ suchȱ asȱ ȇabcȇȱ areȱ allowedȱ byȱ theȱ Standard,ȱ butȱ theirȱ implementationȱ mayȱ varyȱ fromȱ oneȱ environmentȱ toȱ theȱ nextȱ soȱ theirȱ useȱ isȱ discouraged.ȱ Finally,ȱ wideȱ characterȱ literalsȱ areȱ writtenȱ asȱ anȱ Lȱ followedȱ byȱ aȱ multibyteȱ characterȱliteral,ȱasȱin:ȱ ȱ L'X' TIP L'e^' ȱ Theseȱareȱusedȱwhenȱtheȱruntimeȱenvironmentȱsupportsȱaȱlargeȱcharacterȱset.ȱ ȱ Whenȱ youȱ needȱ anȱ integerȱ literal,ȱ theȱ compilerȱ doesnȇtȱ careȱ whichȱ formȱ youȱ write,ȱ althoughȱitȱmakesȱaȱbigȱdifferenceȱtoȱaȱhumanȱreader.ȱWhichȱformȱyouȱchoose,ȱthen,ȱ shouldȱ beȱ determinedȱ byȱ theȱ contextȱ inȱ whichȱ theȱ literalȱ isȱ used.ȱ Mostȱ literalsȱ areȱ writtenȱ inȱ decimalȱ formȱ becauseȱ itȱ theȱ mostȱ naturalȱ forȱ peopleȱ toȱ read.ȱ Hereȱ areȱ aȱ coupleȱofȱexamplesȱwhereȱotherȱtypesȱofȱintegerȱliteralsȱareȱmoreȱappropriate.ȱ ȱ Technically,ȱ -275ȱ isȱ notȱ aȱ literalȱ constantȱ butȱ aȱ constantȱ expression.ȱ Theȱ minusȱ signȱ isȱ interpretedȱ asȱ aȱ unaryȱ operatorȱ insteadȱofȱbeingȱpartȱofȱtheȱnumber.ȱThisȱambiguityȱhasȱlittleȱpracticalȱconsequence,ȱthough,ȱasȱtheȱexpressionȱisȱevaluatedȱ byȱtheȱcompilerȱandȱhasȱtheȱdesireȱeffectȱ 15 Download at http://www.pin5i.com/ 3.1 Basic Data Types 43 Aȱ literalȱ thatȱ identifiesȱ certainȱ bitȱ positionsȱ withinȱ aȱ wordȱ wouldȱ beȱ betterȱ writtenȱasȱaȱhexadecimalȱorȱoctalȱvalue,ȱbecauseȱtheseȱformsȱdisplayȱmoreȱclearlyȱtheȱ specialȱnatureȱofȱtheȱvalue.ȱForȱexample,ȱtheȱvalueȱ 983040ȱhasȱaȱ1Ȭbitȱinȱpositionsȱl6— l9,ȱ butȱ youȱ wouldȱ neverȱ guessȱ itȱ fromȱ lookingȱ atȱ itsȱ decimalȱ value.ȱ Writtenȱ inȱ hexadecimal,ȱthough,ȱtheȱvalueȱisȱ 0xF0000,ȱwhichȱclearlyȱshowsȱthoseȱbitsȱasȱlȱandȱtheȱ remainingȱbitsȱ0.ȱIfȱthisȱvalueȱisȱbeingȱusedȱinȱaȱcontextȱinȱwhichȱtheseȱspecificȱbitsȱareȱ important,ȱ forȱ exampleȱ asȱ aȱ maskȱ toȱ extractȱ theȱ correspondingȱ bitsȱ fromȱ aȱ variable,ȱ thenȱ writingȱ theȱ literalȱ inȱ hexadecimalȱ makesȱ theȱ meaningȱ ofȱ theȱ operationȱ muchȱ clearerȱtoȱaȱhumanȱreader.ȱȱ lfȱaȱvalueȱisȱgoingȱtoȱbeȱusedȱasȱaȱcharacter,ȱexpressingȱtheȱvalueȱasȱaȱcharacterȱ literalȱ makesȱ clearerȱ theȱ meaningȱ thatȱ isȱ intendedȱ forȱ theȱ value.ȱ Forȱ example,ȱ theȱ statementsȱ ȱ value = value – 48; value = value – \60; ȱ areȱentirelyȱequivalentȱinȱoperationȱtoȱ ȱ value = value – '0' ; ȱ butȱ itȱ isȱ muchȱ easierȱ toȱ seeȱ fromȱ theȱ latterȱ thatȱ theȱ digitȱ storedȱ inȱ valueȱ isȱ beingȱ convertedȱfromȱaȱcharacterȱtoȱaȱbinaryȱvalue.ȱMoreȱimportantly,ȱtheȱcharacterȱconstantȱ yieldsȱ theȱ correctȱ valueȱ noȱ matterȱ whichȱ characterȱ setȱ isȱ used.ȱ soȱ itȱ improvesȱ portability.ȱ ȱ ȱ ȱ Enumerated Type ȱ Anȱ enumeratedȱ typeȱ isȱ oneȱ whoseȱ valuesȱ areȱ symbolicȱ constantsȱ ratherȱ thanȱ literal.ȱ Theseȱareȱdeclaredȱinȱthisȱfashion:ȱ ȱ enum Jar_Type { CUP, PINT, QUART, HALF_GALLON, GALLON }; ȱ whichȱdeclaresȱaȱtypeȱcalledȱJar_Type.ȱVariablesȱofȱthisȱtypeȱareȱdeclaredȱlikeȱthis:ȱ ȱ enum Jar_Type milk_jug, gas_can, medicine_bottle; ȱ Ifȱ thereȱ isȱ onlyȱ oneȱ declarationȱ ofȱ variablesȱ ofȱ aȱ particularȱ enumeratedȱ type,ȱ bothȱ statementsȱmayȱbeȱcombinedȱlikeȱthis:ȱ ȱ enum { CUP, PINT, QUART, HALF_GALLON, GALLON } ȱ ȱ milk_jug,ȱgas_can,ȱmedicine_bottle;ȱ Download at http://www.pin5i.com/ 44 Chapter 3 Data Theȱ variablesȱ areȱ inȱ factȱ storedȱ asȱ integers,ȱ andȱ theȱ valuesȱ usedȱ internallyȱ toȱ representȱtheȱsymbolicȱnamesȱareȱtheȱintegerȱvaluesȱ0ȱforȱCUP,ȱ1ȱforȱPINT,ȱetc.ȱWhereȱ appropriate,ȱspecificȱintegerȱvaluesȱmayȱbeȱspecifiedȱforȱtheȱsymbolicȱnamesȱlikeȱthis:ȱ ȱ enum Jar_Type { CUP=8, PINT=16, QUART=32, HALF_GALLON=64, GALLON=128 }; TIP ȱ Itȱisȱlegalȱforȱonlyȱsomeȱofȱtheȱsymbolsȱtoȱbeȱgivenȱvaluesȱthisȱway.ȱAnyȱsymbolȱnotȱ givenȱanȱexplicitȱvalueȱgetsȱaȱvalueȱoneȱgreaterȱthanȱtheȱsymbolȱbeforeȱit.ȱ ȱ Theȱ symbolicȱ namesȱ areȱ treatedȱ asȱ integerȱ constants,ȱ andȱ variablesȱ declaredȱ withȱ anȱ enumeratedȱtypeȱareȱactuallyȱintegers.ȱThisȱfactȱmeansȱthatȱyouȱcanȱsassingȱtheȱliteralȱȬ 623ȱ toȱ aȱ variableȱ ofȱ typeȱ Jar_Type,ȱ andȱ youȱ canȱ assignȱ theȱ valueȱ HALF_GALLONȱ toȱ anyȱ integerȱ variable.ȱ Avoidȱ usingȱ enumerationsȱ inȱ thisȱ manner,ȱ however,ȱ becauseȱ theirȱ valueȱisȱweakenedȱbyȱmixingȱthemȱindiscriminatelyȱwithȱintegers.ȱ ȱ ȱ ȱ 3.1.2 Floating-Pint Types ȱ Numbersȱsuchȱasȱ3.14159ȱandȱ6.023×1023ȱcannotȱbeȱstoredȱasȱintegers.ȱTheȱfirstȱisȱnotȱaȱ wholeȱ number,ȱ andȱ theȱ secondȱ isȱ farȱ tooȱ large.ȱ Theyȱ can,ȱ however,ȱ beȱ storedȱ asȱ floatingȬpointȱ values.ȱ Theseȱ areȱ usuallyȱ storedȱ asȱ aȱ fractionȱ andȱ anȱ exponentȱ ofȱ someȱ assumedȱbase,ȱsuchȱasȱ ȱ ȱ .3243F×161ȱ ȱ .11001001000111111×22 ȱ bothȱ ofȱ whichȱ representȱ theȱ valueȱ 3.14159.ȱ Thereȱ areȱ manyȱ differentȱ methodsȱ ofȱ representingȱfloatingȬpointȱvalues;ȱtheȱStandardȱdoesȱnotȱdictateȱanyȱspecificȱformat.ȱȱ TheȱfloatingȬpointȱfamilyȱincludes float, double, and long double types.ȱTheseȱ typesȱ usuallyȱ provideȱ singleȱ precision,ȱ doubleȱ precision,ȱ andȱ onȱ machinesȱ thatȱ supportȱ it,ȱ extendedȱ precisionȱ valuesȱ respectively.ȱ Theȱ ANSIȱ Standardȱ requiresȱ onlyȱ thatȱlongȱdoublesȱbeȱatȱleastȱasȱlongȱasȱ doubles,ȱwhichȱthemselvesȱmustȱbeȱatȱleastȱasȱ bigȱ asȱ floats. Itȱ alsoȱ imposesȱ aȱ minimumȱ range;ȱ allȱ floatingȬpointȱ typesȱ mustȱ beȱ capableȱofȱstoringȱvaluesȱinȱtheȱrangeȱȬ1037ȱthroughȱ1037.ȱ Anȱincludeȱfileȱcalledȱ float.hȱdefinesȱtheȱnamesȱ FLT_MAX,ȱ DBL_MAX,ȱ LDBL_MAXȱtoȱ theȱ maximumȱ valuesȱ thatȱ canȱ beȱ storedȱ inȱ aȱ float,ȱ double,ȱ andȱ longȱ double,ȱ respectively;ȱminimumȱvaluesȱareȱgivenȱbyȱFLT_MIN.ȱ Download at http://www.pin5i.com/ 3.1 Basic Data Types 45 DBL_MIN,ȱ andȱ LDBL_MIN.ȱ Additionalȱ namesȱ thatȱ specifyȱ certainȱ characteristicsȱ ofȱ theȱ floatingȬpointȱ implementation,ȱ suchȱ asȱ theȱ radixȱ beingȱ usedȱ andȱ theȱ numberȱ ofȱ significantȱdigitsȱtheȱdifferentȱlengthsȱhave,ȱareȱalsoȱdefinedȱhere.ȱ Floatingȱpointȱliteralsȱareȱalwaysȱwrittenȱinȱdecimalȱandȱmustȱcontainȱeitherȱaȱ decimalȱpoint,ȱanȱexponent,ȱorȱboth.ȱHereȱareȱsomeȱexamples:ȱ ȱ 3.14159 1E10 25. .5 6.023e23 ȱ Floatingȱ pointȱ literalsȱ areȱ doubleȱ valuesȱ unlessȱ theyȱ areȱ followedȱ byȱ aȱ suffix:ȱ Lȱ orȱ 1ȱ specifyȱlong double,ȱandȱFȱorȱfȱspecify float.ȱ ȱ ȱ ȱ 3.1.3 Pointers ȱ PointersȱareȱaȱmajorȱreasonȱwhyȱtheȱCȱlanguageȱisȱpopular.ȱPointersȱallowȱtheȱefficientȱ implementationȱofȱadvancedȱdataȱstructuresȱsuchȱasȱtreesȱandȱlists.ȱOtherȱlanguages,ȱ suchȱ asȱ Pascalȱ andȱ ModulaȬ2,ȱ implementȱ pointersȱ butȱ doȱ notȱ allowȱ arithmeticȱ orȱ comparisonsȱtoȱbeȱperformedȱonȱthem.ȱNorȱdoȱtheyȱallowȱanyȱwayȱofȱcreatingȱpointersȱ toȱexistingȱdataȱobjects.ȱTheȱlackȱofȱsuchȱrestrictionsȱisȱwhatȱallowsȱtheȱCȱprogrammerȱ toȱ produceȱ programsȱ matȱ areȱ moreȱ efficientȱ andȱ compactȱ thanȱ programsȱ inȱ otherȱ languages.ȱAtȱtheȱsameȱtime,ȱtheȱunrestrictedȱuseȱofȱpointersȱinȱCȱisȱtheȱcauseȱofȱmuchȱ weepingȱandȱgnashingȱofȱteethȱbyȱbothȱbeginningȱandȱexperiencedȱCȱprogrammers.ȱ Theȱ valuesȱ ofȱ variablesȱ areȱ storedȱ inȱ theȱ computerȇsȱ memory,ȱ eachȱ atȱ aȱ particularȱlocation.ȱEachȱmemoryȱlocationȱisȱidentifiedȱandȱreferencedȱwithȱanȱaddress,ȱ justȱ asȱ theȱ housesȱ onȱ aȱ streetȱ canȱ beȱ locatedȱ byȱ theirȱ address.ȱ Pointerȱ isȱ justȱ anotherȱ nameȱforȱanȱaddress;ȱatȱpointerȱvariableȱisȱaȱvariableȱwhoseȱvalueȱisȱtheȱaddressȱofȱsomeȱ otherȱmemoryȱlocation.ȱThereȱareȱoperatorsȱthatȱallowȱyouȱtoȱobtainȱtheȱaddressȱofȱaȱ variableȱ andȱ toȱ followȱ aȱ pointerȱ variableȱ toȱ theȱ valueȱ orȱ dataȱ structureȱ toȱ whichȱ itȱ points,ȱbutȱweȱwillȱdiscussȱthoseȱinȱChapterȱ5.ȱ Theȱ ideaȱ ofȱ accessingȱ dataȱ byȱ itsȱ addressȱ insteadȱ ofȱ byȱ itsȱ nameȱ frequentlyȱ causesȱconfusion.ȱItȱshouldnȇt,ȱbecauseȱyouȱhaveȱbeenȱdoingȱthisȱallȱyourȱlife.ȱLocatingȱ housesȱonȱaȱstreetȱbyȱtheirȱaddressȱisȱexactlyȱtheȱsameȱthing.ȱNoȱoneȱeverȱconfusesȱtheȱ addressȱofȱaȱhouseȱwithȱitsȱcontents;ȱnoȱoneȱeverȱmistakenlyȱwritesȱaȱletterȱtoȱȈMr.ȱ428ȱ ElmhurstȱSt.ȈȱlivingȱatȱȈRobertȱSmith.Ȉȱ Aȱpointerȱisȱexactlyȱtheȱsame.ȱImagineȱtheȱcomputerȇsȱmemoryȱasȱhousesȱalongȱ aȱveryȱlongȱstreet,ȱeachȱidentifiedȱbyȱitsȱownȱuniqueȱnumber.ȱEachȱlocationȱcontainsȱaȱ value,ȱwhichȱisȱseparateȱandȱdistinctȱfromȱitsȱaddress,ȱevenȱthoughȱbothȱaxeȱnumbers.ȱ Download at http://www.pin5i.com/ 46 Chapter 3 Data Pointer Constants ȱ Pointerȱconstantsȱareȱfundamentallyȱdifferentȱfromȱnonpointerȱconstants.ȱBecauseȱtheȱ compilerȱtakesȱcareȱofȱassigningȱvariablesȱtoȱlocationsȱinȱtheȱcomputer’sȱmemory,ȱtheȱ programmerȱ usuallyȱ hasȱ noȱ wayȱ ofȱ knowingȱ inȱ advanceȱ whereȱ someȱ particularȱ variableȱ willȱ reside.ȱ Therefore,ȱ youȱ obtainȱ theȱ addressȱ ofȱ aȱ variableȱ byȱ usingȱ anȱ operatorȱratherȱthanȱwritingȱitsȱaddressȱasȱaȱliteralȱconstant.ȱForȱexample,ȱifȱweȱwantȱ theȱaddressȱofȱtheȱvariableȱ xyz,ȱweȱcannotȱ writeȱaȱliteralȱsuchȱasȱ 0xff2044ecȱbecauseȱ weȱhaveȱnoȱwayȱofȱknowingȱwhetherȱthatȱisȱwhereȱtheȱcompilerȱwillȱactuallyȱputȱtheȱ variable.ȱIndeed,ȱanȱautomaticȱvariableȱmayȱbeȱallocatedȱatȱdifferentȱplacesȱeachȱtimeȱaȱ functionȱ isȱ called.ȱ Thus,ȱ thereȱ isȱ littleȱ useȱ forȱ pointerȱ constantsȱ expressedȱ asȱ literalȱ numericȱvalues,ȱsoȱthereȱisȱnoȱnotationȱbuiltȱintoȱCȱspecificallyȱforȱthem. 16 ȱ ȱ ȱ String Literals ȱ Manyȱ peopleȱ findȱ itȱ strangeȱ thatȱ thereȱ isȱ noȱ stringȱ typeȱ inȱ C,ȱ yetȱ theȱ languageȱ hasȱ aȱ stringȱliteral.ȱThereȱisȱinȱfactȱaȱnotionȱofȱaȱstring,ȱaȱsequenceȱofȱzeroȱorȱmoreȱcharactersȱ terminatedȱ byȱ NULȱ byte.ȱ Stringsȱ areȱ usuallyȱ storedȱ inȱ characterȱ arrays,ȱ whichȱ isȱ whyȱ thereȱ isȱ noȱ explicitȱ stringȱ type.ȱ Becauseȱ theȱ NULȱ isȱ usedȱ toȱ terminateȱ strings,ȱ itȱ isȱ notȱ possibleȱforȱaȱstringȱtoȱcontainȱ NULs.ȱThisȱrestrictionȱisȱusuallyȱnotȱaȱproblem,ȱthough;ȱ NULȱwasȱchosenȱasȱterminatorȱbecauseȱitȱhasȱnoȱprintableȱgraphicȱassociatedȱwithȱit.ȱ Stringȱ literalsȱ areȱ writtenȱ asȱ aȱ sequenceȱ ofȱ charactersȱ enclosedȱ inȱ quotationȱ marks,ȱlikeȱthese:ȱ ȱ "Hello" K&R C 16 "\aWarning!\a" "Line 1\nLine2" "" ȱ Theȱ lastȱ exampleȱ illustratesȱ thatȱ aȱ stringȱ literalȱ (unlikeȱ aȱ characterȱ literal)ȱ mayȱ beȱ empty;ȱtheȱterminatingȱNULȱbyteȱwillȱalwaysȱbeȱthere,ȱthough.ȱ ȱ Stringȱ literalsȱ causeȱ theȱ specifiedȱ charactersȱ andȱ aȱ terminatingȱ NULȱ byteȱ toȱ beȱ storedȱ somewhereȱinȱtheȱprogram.ȱK&RȱCȱmadeȱnoȱmentionȱasȱtoȱwhetherȱtheȱcharactersȱinȱaȱ stringȱ literalȱ couldȱ beȱ modifiedȱ byȱ theȱ program,ȱ butȱ itȱ explicitlyȱ statedȱ thatȱ stringȱ literalsȱwithȱidenticalȱvaluesȱwereȱstoredȱseparately.ȱManyȱimplementations,ȱtherefore,ȱ allowedȱliteralsȱtoȱbeȱmodifiedȱbyȱtheȱprogram.ȱ ANSIȱ Cȱ statesȱ thatȱ theȱ effectȱ ofȱ modifyingȱ aȱ stringȱ literalȱ isȱ undefined.ȱ Itȱ alsoȱ allowsȱtheȱcompilerȱtoȱstoreȱaȱstringȱliteralȱonceȱevenȱifȱitȱappearsȱmanyȱtimesȱinȱtheȱ sourceȱ code.ȱ Thisȱ factȱ makesȱ modifyingȱ stringȱ literalsȱ extremelyȱ risky,ȱ becauseȱ aȱ changeȱ madeȱ toȱ oneȱ literalȱ mayȱ changeȱ theȱ valueȱ ofȱ otherȱ stringȱ literalsȱ inȱ theȱ ȱThereȱisȱoneȱexception:ȱtheȱNULLȱpointer,ȱwhichȱcanȱbeȱexpressedȱasȱtheȱvalueȱzero.ȱSeeȱChapterȱ6ȱforȱmoreȱinformation.ȱ Download at http://www.pin5i.com/ 3.2 Basic Declarations 47 program.ȱ Therefore,ȱ manyȱ ANSIȱ compilersȱ doȱ notȱ letȱ youȱ modifyȱ stringȱ literals,ȱ orȱ provideȱcompileȬtimeȱoptionsȱtoȱletȱyouȱchooseȱwhetherȱorȱnotȱyouȱwantȱmodificationȱ ofȱliteralsȱtoȱbeȱallowed.ȱAvoidȱthisȱpractice:ȱifȱyouȱneedȱtoȱmodifyȱaȱstring,ȱstoreȱitȱinȱ enȱarrayȱinstead.ȱ Iȱ discussȱ stringȱ literalsȱ alongȱ withȱ pointersȱ becauseȱ usingȱ aȱ stringȱ literalȱ inȱ atȱ programȱ generatesȱ aȱ Ȉconstantȱ pointerȱ toȱ character.Ȉȱ Whenȱ aȱ stringȱ literalȱ appearsȱ inȱ anȱexpression,ȱtheȱvalueȱusedȱinȱtheȱexpressionȱisȱtheȱaddressȱwhereȱitsȱcharactersȱwereȱ stored,ȱnotȱtheȱcharactersȱthemselves.ȱThus,ȱyouȱcanȱassignȱaȱstringȱliteralȱtoȱaȱvariableȱ ofȱtypeȱȈpointerȱtoȱcharacter,Ȉȱwhichȱmakesȱtheȱvariableȱpointȱtoȱwhereȱtheȱcharactersȱ areȱstored.ȱYouȱcannotȱassignȱaȱstringȱliteralȱtoȱaȱcharacterȱarray,ȱthough,ȱbecauseȱtheȱ immediateȱvalueȱofȱtheȱliteralȱisȱaȱpointer,ȱnotȱtheȱcharactersȱthemselves.ȱ lfȱ notȱ beingȱ ableȱ toȱ assignȱ orȱ copyȱ stringsȱ soundsȱ inconvenient,ȱ youȱ shouldȱ knowȱ thatȱ theȱ standardȱ Cȱ libraryȱ includesȱ aȱ suiteȱ ofȱ functionsȱ whoseȱ purposeȱ isȱ toȱ manipulateȱ strings.ȱ Theȱ suiteȱ includesȱ functionsȱ toȱ copy,ȱ concatenate,ȱ compare,ȱ andȱ computeȱtheȱlengthȱofȱstringsȱandȱtoȱsearchȱstringsȱforȱspecificȱcharacters.ȱ ȱ ȱ ȱ 3.2 Basic Declarations ȱ Knowingȱtheȱbasicȱdataȱtypesȱisȱofȱlittleȱuseȱunlessȱyouȱcanȱdeclareȱvariables.ȱTheȱbasicȱ formȱofȱaȱdeclarationȱisȱ ȱ ȱ specifier(s)ȱdeclaration_expression_listȱ ȱ Forȱsimpleȱtypes,ȱtheȱdeclaration_expression_listȱisȱjustȱaȱlistȱofȱtheȱidentifiersȱbeingȱ declared.ȱ Forȱ moreȱ involvedȱ types,ȱ eachȱ ofȱ theȱ itemsȱ inȱ theȱ listȱ isȱ actuallyȱ anȱ expressionȱthatȱshowsȱhowȱtheȱnameȱbeingȱdeclaredȱmightȱbeȱused.ȱlfȱthisȱideaȱseemsȱ obscureȱnow,ȱdon‘tȱworry,ȱweȱexploreȱitȱinȱmoreȱdetailȱshortly.ȱ Theȱ specifier(s)ȱ includesȱ keywordsȱ thatȱ describeȱ theȱ baseȱ typeȱ ofȱ theȱ identifiersȱbeingȱdeclared.ȱSpecifiersȱmayȱalsoȱbeȱgivenȱtoȱchangeȱtheȱdefaultȱstorageȱ classȱandȱscopeȱofȱtheȱidentifier.ȱWeȱdiscussȱtheseȱtopicsȱshortly.ȱȱ YouȱsawȱsomeȱbasicȱdeclarationsȱinȱtheȱsampleȱprogramȱinȱChapterȱ1.ȱHereȱareȱ aȱcoupleȱmore.ȱ ȱ int char i; j, k, l; ȱ Theȱfirstȱdeclarationȱindicatesȱthatȱtheȱvariableȱiȱisȱanȱinteger.ȱTheȱsecondȱdeclaresȱj,ȱk,ȱ andȱlȱtoȱbeȱcharacterȱvariables.ȱ Download at http://www.pin5i.com/ 48 Chapter 3 Data Theȱspecifiersȱmayȱincludeȱkeywordsȱtoȱmodifyȱtheȱlengthȱand/orȱsignednessȱofȱ theȱidentifier.ȱTheseȱincludeȱ ȱ short long signed unsigned ȱ Also,ȱtheȱkeywordȱintȱmayȱbeȱomittedȱfromȱtheȱdeclarationȱofȱanyȱintegralȱtypeȱ ifȱ atȱ leastȱ oneȱ otherȱ specifierȱ isȱ givenȱ inȱ theȱ declaration.ȱ Thus,ȱ theȱ followingȱ twoȱ declarationsȱareȱequivalent:ȱ ȱ unsigned short int unsigned short a; a; ȱ Tableȱ 3.3ȱ showsȱ allȱ ofȱ theȱ variationsȱ onȱ theseȱ declarations.ȱ Theȱ declarationsȱ withinȱ eachȱboxȱareȱequivalent.ȱTheȱsignedȱkeywordȱisȱordinarilyȱusedȱonlyȱforȱcharsȱbecauseȱ theȱotherȱintegerȱtypesȱareȱsignedȱbyȱdefault.ȱItȱisȱimplementationȱdependentȱwhetherȱ charȱ isȱ signedȱ orȱ unsigned,ȱ soȱ charȱ isȱ equivalentȱ toȱ eitherȱ signedȱ charȱ orȱ unsigned char.ȱTableȱ3.3ȱdoesȱnotȱincludeȱthisȱequivalence.ȱ Theȱ situationȱ isȱ simplerȱ withȱ theȱ floatingȬpointȱ types,ȱ becauseȱ noneȱ ofȱ theȱ specifiersȱareȱapplicableȱexceptȱfor long double.ȱ ȱ ȱ ȱ 3.2.1 Initialization ȱ Aȱ declarationȱ mayȱ specifyȱ anȱ initialȱ valueȱ forȱ aȱ scalarȱ variableȱ byȱ followingȱ theȱ variableȱnameȱwithȱanȱequalȱsignȱandȱtheȱdesiredȱvalue.ȱForȱexample,ȱ ȱ int j = 15; ȱ declares jȱtoȱbeȱanȱintegerȱvariableȱandȱassignsȱitȱtheȱvalueȱ15.ȱWeȱreturnȱtoȱtheȱtopicȱ ofȱinitializationȱagainȱlaterȱinȱthisȱchapter.ȱ ȱ ȱ short short int int long long int signed signed signed signed signed singed short short int int long long int ȱ Tableȱ3.3ȱEquivalentȱintegerȱdeclarationsȱ unsigned unsigned unsigned unsigned unsigned unsigned short short int int long long int Download at http://www.pin5i.com/ 3.2 Basic Declarations 49 3.2.2 Declaring Simple Arrays ȱ Toȱ declareȱ aȱ oneȬdimensionalȱ array,ȱ theȱ arrayȱ nameȱ isȱ followedȱ byȱ aȱ subscriptȱ thatȱ specifiesȱ theȱ numberȱ ofȱ elementsȱ inȱ theȱ array.ȱ Thisȱ isȱ theȱ firstȱ exampleȱ ofȱ theȱ declaration_expression mentionedȱearlier.ȱForȱexample,ȱconsiderȱtheȱdeclaration:ȱ ȱ int values[20]; ȱ Theȱ obviousȱ interpretationȱ ofȱ thisȱ declarationȱ isȱ thatȱ weȱ areȱ declaringȱ anȱ arrayȱ ofȱ 20ȱ integers.ȱThisȱinterpretationȱisȱcorrect,ȱbutȱthereȱisȱaȱbetterȱwayȱtoȱreadȱtheȱdeclaration.ȱ Theȱnameȱ values,ȱwhenȱfollowedȱbyȱaȱsubscript,ȱyieldsȱanȱvalueȱofȱtypeȱ intȱ(andȱbyȱ theȱway,ȱthereȱareȱ20ȱofȱthem).ȱTheȱȈdeclarationȱexpressionȈȱshowsȱtheȱidentifierȱusedȱ inȱanȱexpressionȱthatȱresultsȱinȱaȱvalueȱofȱtheȱbaseȱtype,ȱintegerȱinȱthisȱcase.ȱ Theȱsubscriptsȱofȱarraysȱalwaysȱbeginȱatȱzeroȱandȱextendȱthroughȱoneȱlessȱthanȱ theȱ declaredȱ sizeȱ ofȱ theȱ array.ȱ Thereȱ isȱ noȱ wayȱ toȱ changeȱ thisȱ property,ȱ butȱ ifȱ youȱ absolutelyȱmustȱhaveȱanȱarrayȱwhoseȱsubscriptsȱbeginȱatȱten,ȱitȱisȱnotȱdifficultȱtoȱjustȱ subtractȱtenȱinȱeachȱofȱyourȱsubscripts.ȱȱ AnotherȱaspectȱofȱarraysȱinȱCȱisȱthatȱtheȱcompilerȱdoesȱnotȱcheckȱtheȱsubscriptsȱ toȱseeȱwhetherȱtheyȱareȱinȱtheȱproperȱrange. 17 ȱTheȱlackȱofȱcheckingȱisȱbothȱgoodȱandȱ bad.ȱItȱisȱgoodȱbecauseȱthereȱisȱnoȱtimeȱlostȱcheckingȱarrayȱsubscriptsȱthatȱareȱknownȱ toȱbeȱcorrect,ȱandȱitȱisȱbadȱbecauseȱinvalidȱsubscriptsȱareȱnotȱdetected.ȱAȱgoodȱruleȱofȱ thumbȱtoȱuseȱis:ȱ ȱ Ifȱaȱsubscriptȱwasȱcomputedȱfromȱvaluesȱthatȱareȱalreadyȱknownȱtoȱbeȱcorrect,ȱthenȱthereȱ isȱnoȱneedȱtoȱcheckȱitsȱvalue.ȱAnyȱvalueȱthatȱisȱderivedȱinȱanyȱwayȱfromȱdataȱthatȱtheȱ userȱhasȱenteredȱmustȱbeȱcheckedȱbeforeȱbeingȱusedȱasȱaȱsubscriptȱtoȱensureȱthatȱitȱisȱinȱ theȱproperȱrange.ȱ ȱ WeȱcoverȱtheȱinitializationȱofȱarraysȱinȱChapterȱ8.ȱ ȱ ȱ ȱ 3.2.3 Declaring Pointers ȱ Declarationȱ expressionsȱ areȱ alsoȱ usedȱ toȱ declareȱ pointers.ȱ Inȱ Pascalȱ andȱ Modula,ȱ aȱ declarationȱ givesȱ aȱ listȱ ofȱ identifiersȱ followedȱ byȱ theirȱ type.ȱ Inȱ C,ȱ theȱ baseȱ typeȱ isȱ given,ȱfollowedȱbyȱaȱlistȱofȱidentifiersȱusedȱinȱtheȱexpressionsȱneededȱtoȱproduceȱthatȱ baseȱtype.ȱForȱexample,ȱ ȱ Itȱ isȱ technicallyȱ possibleȱ forȱ aȱ compilerȱ toȱ accuratelyȱ checkȱ subscriptȱ valuesȱ butȱ doingȱ soȱ involvesȱ aȱ lotȱ ofȱ additionalȱ overhead.ȱ Someȱ laterȱ compilers,ȱ suchȱ asȱ Borlandȱ C++ȱ 5.0,ȱ implementȱ subscriptȱ checkingȱ asȱ aȱ debuggingȱ toolȱ thatȱ canȱ beȱ turnedȱonȱorȱoff.ȱ 17 Download at http://www.pin5i.com/ 50 Chapter 3 Data int CAUTION! *a; ȱ statesȱ thatȱ theȱ expressionȱ *aȱ resultsȱ inȱ theȱ typeȱ int.ȱ Knowingȱ thatȱ theȱ *ȱ operatorȱ performsȱindirection,ȱweȱcanȱinferȱthatȱaȱmustȱbeȱaȱpointerȱtoȱanȱinteger. 18 ȱ Theȱ freeȱ formȱ natureȱ ofȱ Cȱ makesȱ itȱ temptingȱ toȱ writeȱ theȱ asteriskȱ nearȱ theȱ type,ȱ likeȱ this:ȱ int* a; ȱ Thisȱdeclarationȱhasȱtheȱsameȱmeaningȱasȱtheȱpreviousȱone,ȱandȱitȱnowȱseemsȱtoȱmoreȱ clearlyȱdeclareȱthatȱaȱisȱofȱtype int *.ȱThisȱtechniqueȱisȱnotȱgood,ȱandȱhereȱisȱwhy.ȱ ȱ ȱ int* b, c, d; ȱ Peopleȱ naturallyȱ readȱ thisȱ statementȱ asȱ declaringȱ allȱ threeȱ variablesȱ toȱ beȱ pointersȱ toȱ integersȱbutȱitȱdoesnȇt.ȱWeȱareȱfooledȱbyȱhowȱitȱlooks.ȱTheȱasteriskȱisȱreallyȱpartȱofȱtheȱ expressionȱ *bȱ andȱ appliesȱ onlyȱ toȱ thatȱ oneȱ identifier,ȱ bȱ isȱ aȱ pointer,ȱ theȱ otherȱ twoȱ variablesȱareȱordinaryȱintegers.ȱHereȱisȱtheȱcorrectȱdeclarationȱforȱthreeȱpointers.ȱ ȱ int *b, *c, *d; ȱ ȱ Declarationsȱ ofȱ pointerȱ variablesȱ mayȱ alsoȱ specifyȱ initialȱ valuesȱ forȱ theȱ variables.ȱHereȱisȱanȱexampleȱinȱwhichȱaȱpointerȱisȱdeclaredȱandȱinitializedȱtoȱaȱstringȱ literal.ȱ ȱ char CAUTION! *message = "Hello world!"; ȱ Thisȱ statementȱ declaresȱ messageȱ toȱ beȱ aȱ pointerȱ toȱ aȱ characterȱ andȱ initializesȱ theȱ pointerȱtoȱtheȱaddressȱofȱtheȱfirstȱcharacterȱinȱtheȱstringȱliteral.ȱ ȱ Oneȱdangerȱwithȱthisȱtypeȱofȱinitializationȱisȱthatȱitȱisȱeasyȱtoȱmisinterpretȱitsȱmeaning.ȱ Inȱ theȱ previousȱ declaration,ȱ itȱ appearsȱ thatȱ theȱ initialȱ valueȱ isȱ assignedȱ toȱ theȱ expressionȱ *messageȱ whenȱ inȱ factȱ theȱ valueȱ isȱ assignedȱ toȱ messageȱ itself.ȱ Inȱ otherȱ words,ȱtheȱpreviousȱdeclarationȱisȱequivalentȱto:ȱ ȱ char message *message; = "Hello world!"; ȱIndirectionȱisȱonlyȱlegalȱonȱaȱpointerȱvalue.ȱTheȱpointerȱpointsȱtoȱtheȱresult,ȱandȱtheȱindirectionȱȈfollowsȈȱtheȱpointerȱtoȱ obtainȱtheȱresult.ȱSeeȱChapterȱ6ȱforȱȱmoreȱdetails.ȱ 18 Download at http://www.pin5i.com/ 3.3 Typedef 51 3.2.4 Implicit Declarations ȱ Thereȱ areȱ aȱ fewȱ declarationsȱ inȱ whichȱ typeȱ namesȱ mayȱ beȱ omittedȱ altogether.ȱ Functions,ȱ forȱ example,ȱ areȱ assumedȱ toȱ returnȱ integersȱ unlessȱ declaredȱ otherwise.ȱ Whenȱdeclaringȱformalȱparametersȱtoȱfunctionsȱinȱtheȱoldȱstyle,ȱanyȱparametersȱwhoseȱ declarationsȱ areȱ omittedȱ areȱ assumedȱ toȱ beȱ integers.ȱ Finally,ȱ ifȱ theȱ compilerȱ canȱ seeȱ enoughȱ toȱ determineȱ thatȱ aȱ statementȱ isȱ inȱ factȱ aȱ declaration,ȱ anȱ omittedȱ typeȱ isȱ assumedȱtoȱbeȱinteger.ȱ Considerȱthisȱprogram:ȱ ȱ int a[10]; int c; b[10]; d; f( x ) { return x + 1; } ȱ Theȱ firstȱ andȱ secondȱ linesȱ areȱ notȱ unusual,ȱ howeverȱ theȱ thirdȱ andȱ fourthȱ linesȱ areȱ illegalȱ inȱ ANSIȱ C.ȱ Theȱ thirdȱ lineȱ omitsȱ theȱ type,ȱ butȱ thereȱ isȱ enoughȱ informationȱ leftȱ thatȱ someȱ K&Rȱ compilersȱ canȱ stillȱ figureȱ outȱ thatȱ theȱ statementȱ isȱ aȱ declaration.ȱ Amazingly,ȱaȱfewȱK&Rȱcompilersȱcorrectlyȱprocessȱtheȱfourthȱlineȱasȱaȱdeclarationȱtoo.ȱ Theȱfunctionȱ fȱisȱassumedȱtoȱreturnȱanȱinteger,ȱandȱitsȱargumentȱisȱassumedȱtoȱbeȱanȱ integer.ȱ ȱ Dependingȱ onȱ implicitȱ declarationsȱ isȱ aȱ badȱ idea.ȱ Anȱ implicitȱ declarationȱ alwaysȱ leavesȱaȱquestionȱinȱtheȱreadersȱmind:ȱWasȱtheȱomissionȱofȱtheȱtypeȱintended,ȱorȱdidȱ theȱprogrammerȱsimplyȱforgetȱtheȱproperȱdeclaration?ȱExplicitȱdeclarationsȱmakeȱyourȱ intentȱclear.ȱ ȱ ȱ ȱ 3.3 Typedef ȱ Cȱ supportsȱ aȱ mechanismȱ calledȱ typedef,ȱ whichȱ allowsȱ youȱ toȱ defineȱ newȱ namesȱ forȱ variousȱ dataȱ types.ȱ Typedefsȱ areȱ writtenȱ exactlyȱ theȱ sameȱ asȱ ordinaryȱ declarationsȱ exceptȱ thatȱ theȱ keywordȱ typedefȱ appearsȱ atȱ theȱ beginning.ȱ Forȱ example,ȱ theȱ declarationȱ ȱ char *ptr_to_char; ȱ declaresȱtheȱvariableȱ ptr_to_charȱtoȱbeȱaȱpointerȱtoȱaȱcharacter.ȱButȱaddȱtheȱkeywordȱ typedefȱandȱyouȱget.ȱ Download at http://www.pin5i.com/ 52 Chapter 3 Data typedef char *ptr_to_char; ȱ whichȱ declaresȱ theȱ identifierȱ ptr_to_charȱ toȱ beȱ aȱ newȱ nameȱ forȱ theȱ typeȱ pointerȱ toȱ character.ȱ Youȱ canȱ useȱ theȱ newȱ nameȱ inȱ subsequentȱ declarationsȱ justȱ likeȱ anyȱ ofȱ theȱ predefinedȱnames.ȱForȱexample,ȱȱ ȱ ȱ ptr_to_char a; ȱ declaresȱaȱtoȱbeȱaȱpointerȱtoȱaȱcharacter.ȱȱ Usingȱ aȱ typedefȱ toȱ declareȱ types,ȱ particularlyȱ complexȱ ones,ȱ reducesȱ theȱ chancesȱ ofȱ messingȱupȱaȱdeclaration. 19 ȱFurthermore,ȱifȱyouȱshouldȱdecideȱlaterȱtoȱchangeȱtheȱtypeȱ ofȱsomeȱkindȱofȱdataȱbeingȱusedȱinȱyourȱprogram,ȱchangingȱoneȱ typedefȱisȱeasierȱthanȱ changingȱallȱdeclarationȱofȱallȱvariablesȱ(andȱfunctions)ȱinȱtheȱprogramȱthatȱdealȱwithȱ thatȱdata.ȱ ȱ Useȱ typedef ratherȱ thanȱ #defineȱ forȱ creatingȱ newȱ typeȱ names,ȱ becauseȱ theȱ latterȱ isȱ unableȱtoȱproperlyȱhandleȱpointerȱtypes.ȱForȱexample,ȱ ȱ #define d_ptr_to_char char * d_ptr_to_char a, b; ȱ declaresȱ aȱ properlyȱ butȱ declaresȱ bȱ toȱ beȱ aȱ character.ȱ Definitionsȱ ofȱ namesȱ forȱ moreȱ complexȱ types,ȱ suchȱ asȱ pointersȱ toȱ functionsȱ orȱ arrays,ȱ areȱ alsoȱ handledȱ betterȱ withȱ typedef.ȱ ȱ ȱ ȱ 3.4 Constants ȱ ANSIȱ Cȱ allowsȱ youȱ toȱ declareȱ constants,ȱ whichȱ areȱ exactlyȱ likeȱ variablesȱ exceptȱ thatȱ theirȱ valuesȱ cannotȱ beȱ changed.ȱ Youȱ useȱ theȱ constȱ keywordȱ toȱ declareȱ constants,ȱ asȱ shownȱinȱtheȱfollowingȱexamples.ȱ ȱ int const a; const int a; ȱ Bothȱ ofȱ theseȱ statementsȱ declareȱ aȱ toȱ beȱ anȱ integerȱ whoseȱ valueȱ cannotȱ beȱ changed.ȱ Pickȱwhicheverȱformȱofȱdeclarationȱyouȱfindȱeasiestȱtoȱunderstandȱandȱstickȱwithȱit.ȱ Ofȱ course,ȱ ifȱ aȇsȱ valueȱ cannotȱ beȱ changed,ȱ youȱ canȇtȱ assignȱ anythingȱ toȱ it,ȱ soȱ howȱ doȱ youȱ giveȱ itȱ aȱ valueȱ inȱ theȱ firstȱ place?ȱ Thereȱ areȱ twoȱ ways.ȱ First,ȱ youȱ canȱ initializeȱitȱinȱtheȱdeclaration,ȱlikeȱthis:ȱ 19 ȱtypedefȱisȱparticularlyȱusefulȱwithȱstructures;ȱseeȱChapterȱ10ȱforȱsomeȱexamples.ȱ Download at http://www.pin5i.com/ 3.4 Constants 53 int const a = 15; ȱ Second,ȱ constȱ formalȱ parametersȱ ofȱ aȱ functionȱ areȱ givenȱ theȱ valuesȱ ofȱ theȱ actualȱ argumentsȱwhenȱaȱfunctionȱcallȱisȱperformed.ȱȱ Theȱ situationȱ becomesȱ moreȱ interestingȱ withȱ pointerȱ variables,ȱ becauseȱ thereȱ areȱtwoȱthingsȱthatȱmightȱbeȱconstant—theȱpointerȱvariableȱandȱtheȱentityȱtoȱwhichȱitȱ points.ȱHereȱareȱsomeȱsampleȱdeclarations:ȱ ȱ int *pi; ȱ piȱisȱanȱordinaryȱpointerȱtoȱanȱinteger.ȱTheȱvariableȱ ȱ int const *pci; ȱ pciȱisȱaȱpointerȱtoȱaȱconstantȱinteger.ȱYouȱcanȱchangeȱtheȱpointer’sȱvalueȱbutȱnotȱtheȱ valueȱtoȱwhichȱitȱpoints.ȱContrastȱthisȱexampleȱwithȱcpi:ȱ ȱ int * const cpi; ȱ whichȱ isȱ aȱ constantȱ pointerȱ toȱ anȱ integer.ȱ Hereȱ theȱ pointerȱ isȱ theȱ constant;ȱ itsȱ valueȱ cannotȱchange,ȱbutȱyouȱareȱfreeȱtoȱmodifyȱtheȱintegerȱtoȱwhichȱitȱpoints.ȱ ȱ int TIP const * const cpci ȱ Finally,ȱthereȱisȱ cpci;ȱinȱthisȱexampleȱbothȱtheȱpointerȱandȱtheȱvalueȱtoȱwhichȱitȱpointsȱ areȱconstant;ȱ ȱ Useȱtheȱ constȱkeywordȱwhenȱdeclaringȱvariablesȱwhoseȱvaluesȱwillȱnotȱchange.ȱThisȱ practiceȱ notȱ onlyȱmakesȱyourȱ intentȱmoreȱ clearȱ toȱ othersȱ readingȱ theȱ program,ȱ butȱitȱ alsoȱletsȱtheȱcompilerȱcatchȱplacesȱwhereȱsuchȱaȱvalueȱisȱaccidentallyȱmodified.ȱ Theȱ #defineȱdirectiveȱisȱanotherȱmechanismȱforȱcreatingȱnamedȱconstant. 20 ȱForȱ example,ȱbothȱofȱtheȱfollowingȱstatementsȱcreateȱaȱnamedȱconstantȱforȱtheȱvalueȱ50.ȱ ȱ #define int MAX_ELEMENTS 50 const max_elements = 50; ȱ Theȱ #defineȱ formȱ isȱ moreȱ usefulȱ thanȱ theȱ constȱ variableȱ becauseȱ youȱ canȱ useȱ theȱ formerȱwhereverȱaȱliteralȱconstantȱisȱallowed,ȱsuchȱasȱinȱdeclaringȱtheȱsizeȱofȱarrays.ȱ Theȱconstantȱvariableȱcanȱonlyȱbeȱusedȱwhereȱvariableȱareȱallowed.ȱ 20 ȱSeeȱChapterȱ14ȱforȱaȱcompleteȱdescription.ȱ Download at http://www.pin5i.com/ 54 Chapter 3 Data TIP Namedȱ constantsȱ areȱ valuableȱ becauseȱ theyȱ giveȱ symbolicȱ namesȱ toȱ quantitiesȱ thatȱ wouldȱ otherwiseȱ beȱ writtenȱ asȱ literals.ȱ Definingȱ sizesȱ ofȱ arraysȱ orȱ limitsȱ onȱ loopȱ countersȱ withȱ namedȱ constantsȱ ratherȱ thanȱ literalȱ constantsȱ improvesȱ theȱ maintainabilityȱofȱtheȱ program—shouldȱaȱvalueȱhaveȱtoȱchange,ȱonlyȱtheȱdeclarationȱ needȱ beȱ touched.ȱ Itȱ isȱ muchȱ easierȱ toȱ changeȱ oneȱ declarationȱ thanȱ toȱ searchȱ throughȱ theȱ entireȱ programȱ changingȱ allȱ instancesȱ ofȱ aȱ literalȱ constant,ȱ especiallyȱ whenȱ theȱ same,ȱliteralȱvalueȱisȱusedȱforȱtwoȱorȱmoreȱdifferentȱpurposes.ȱ ȱ ȱ ȱ 3.5 Scope ȱ Whenȱ aȱ variableȱ isȱ declaredȱ inȱ oneȱ partȱ ofȱ aȱ program,ȱ itȱ canȱ beȱ accessedȱ onlyȱ inȱ aȱ certainȱ areaȱ ofȱ theȱ program.ȱ Theȱ extentȱ ofȱ thisȱ areaȱ isȱ determinedȱ byȱ theȱ identifier’sȱ scope.ȱTheȱscopeȱofȱanȱidentifierȱisȱtheȱareaȱinȱtheȱprogramȱinȱwhichȱthatȱidentifierȱmayȱ beȱused.ȱForȱexample,ȱtheȱscopeȱofȱaȱfunctionȇsȱlocalȱvariablesȱisȱlimitedȱtoȱtheȱbodyȱofȱ theȱ function.ȱ Thisȱ ruleȱ meansȱ twoȱ things.ȱ First,ȱ noȱ otherȱ functionȱ mayȱ accessȱ theseȱ variablesȱ byȱ theirȱ names,ȱ becauseȱ theȱ namesȱ areȱ notȱ validȱ outsideȱ ofȱ theirȱ scope.ȱ Second,ȱ itȱisȱlegalȱtoȱ declareȱ differentȱvariablesȱwithȱtheȱsameȱnamesȱ soȱ longȱasȱ theyȱ areȱnotȱdeclaredȱinȱtheȱsameȱscope.ȱ Theȱcompilerȱrecognizeȱfourȱdifferentȱtypesȱofȱscopeȱ–ȱfileȱscope,ȱfunctionȱscope,ȱblockȱ scope,ȱandȱprototypeȱscope.ȱTheȱlocationȱwhereȱanȱidentifierȱisȱdeclaredȱdeterminesȱitsȱ scope.ȱTheȱprogramȱskeletonȱinȱFigureȱ3.1ȱillustratesȱallȱtheȱpossibleȱlocations.ȱ ȱ ȱ ȱ 3.5.1 Block Scope ȱ Aȱlistȱofȱstatementsȱenclosedȱinȱbracesȱisȱcalledȱaȱblock.ȱAnyȱidentifiersȱdeclaredȱatȱtheȱ beginningȱ ofȱ aȱ blockȱ haveȱ blockȱ scope,ȱ whichȱ meansȱ thatȱ theyȱ areȱ accessibleȱ toȱ allȱ statementsȱinȱtheȱblock.ȱTheȱvariablesȱinȱFigureȱ3.1ȱlabeledȱsix,ȱseven,ȱnineȱandȱtenȱallȱ haveȱblockȱscope.ȱTheȱformalȱparametersȱofȱaȱfunctionȱdefinitionȱ(declarationȱfive)ȱalsoȱ haveȱblockȱscopeȱinȱtheȱfunctionȇsȱbody.ȱȱ Whenȱ blocksȱ areȱ nested,ȱ theȱ scopeȱ ofȱ identifiersȱ declaredȱ inȱ theȱ nestedȱ blocksȱ extendsȱonlyȱtoȱtheȱendȱofȱthatȱblock.ȱHowever,ȱifȱanȱidentifierȱinȱaȱnestedȱblockȱhasȱ theȱ sameȱ nameȱ asȱ oneȱ inȱ anyȱ outerȱ block,ȱ thenȱ theȱ innerȱ definitionȱ hidesȱ theȱ outerȱ one—theȱ variableȱ inȱ theȱ outerȱ blockȱ cannotȱ beȱ referencedȱ byȱ nameȱ fromȱ withinȱ theȱ innerȱblock.ȱTheȱ f inȱdeclarationȱnineȱisȱaȱdifferentȱvariableȱthanȱtheȱ fȱinȱdeclarationȱ six,ȱandȱtheȱlatterȱisȱnotȱaccessibleȱbyȱnameȱfromȱwithinȱtheȱinnerȱblock.ȱ Download at http://www.pin5i.com/ 3.5 Scope 55 ȱ 3 1 int a; 2 int b ( int c ); 4 int d ( int e ) 5 { 8 6 int f; 7 int g ( int h ); … { 9 int f, g, i; … } { 10 int i; … } } TIP K&R C ȱ Figureȱ3.1ȱIdentifierȱscopeȱexampleȱ ȱ ȱ Duplicateȱvariableȱnamesȱinȱnestedȱblocksȱshouldȱbeȱavoided.ȱThereȱisȱnoȱgoodȱreasonȱ forȱ usingȱ them,ȱ andȱ theyȱ causeȱ confusionȱ duringȱ debuggingȱ orȱ maintenanceȱ ofȱ theȱ programȱȱ Blocksȱ thatȱ areȱ notȱ nestedȱ withinȱ oneȱ anotherȱ areȱ aȱ littleȱ different.ȱ Variablesȱ declaredȱinȱeachȱblockȱareȱinaccessibleȱfromȱotherȱblocksȱbecauseȱtheirȱscopesȱdoȱnotȱ overlap.ȱBecauseȱitȱisȱimpossibleȱforȱvariablesȱinȱbothȱblocksȱtoȱexistȱatȱtheȱsameȱtime,ȱ theȱ compilerȱ isȱ freeȱ toȱ storeȱ themȱ inȱ theȱ sameȱ memoryȱ locations.ȱ Forȱ example,ȱ iȱ inȱ declarationȱ tenȱ couldȱ shareȱ theȱ sameȱ memoryȱ locationȱ asȱ anyȱ ofȱ theȱ variablesȱ inȱ declarationȱ nine.ȱ Thereȱ isȱ noȱ dangerȱ inȱ thisȱ sharing,ȱ becauseȱ onlyȱ oneȱ ofȱ theȱ non— nestedȱblocksȱcanȱbeȱactiveȱatȱanyȱtime.ȱȱ ȱ InȱK&RȱC,ȱtheȱscopeȱofȱformalȱparametersȱtoȱaȱfunctionȱbeganȱatȱtheȱdeclarationsȱofȱtheȱ parameters,ȱ whichȱ wasȱ outsideȱ ofȱ theȱ bodyȱ ofȱ theȱ function.ȱ Ifȱ thereȱ wereȱ localȱ variablesȱdeclaredȱinȱtheȱfunctionȱwithȱtheȱsameȱnamesȱasȱtheȱparameters,ȱtheyȱhidȱtheȱ parameters,ȱwhichȱwereȱthenȱinaccessibleȱanywhereȱinȱtheȱfunction.ȱInȱotherȱwords,ȱif Download at http://www.pin5i.com/ 56 Chapter 3 Data declarationȱsixȱhadȱincludedȱanȱ e,ȱthenȱtheȱbodyȱofȱtheȱfunctionȱcouldȱonlyȱaccessȱtheȱ localȱvariable;ȱ theȱparameterȱ eȱwouldȱbeȱinaccessible.ȱ Ofȱcourse,ȱnoȱ oneȱeverȱ hidesȱ aȱ parameterȱ intentionallyȱ becauseȱ thereȱ isȱ noȱ pointȱ inȱ passingȱ anȱ argumentȱ ifȱ youȱ areȱ notȱgoingȱtoȱuseȱitsȱvalueȱinȱtheȱfunction.ȱANSIȱCȱpreventsȱthisȱerrorȱfromȱhappeningȱ byȱgivingȱtheȱformalȱparametersȱblockȱscopeȱinȱtheȱfunctionȇsȱoutermostȱblock.ȱLocalȱ variablesȱ declaredȱ inȱ theȱ outermostȱ blockȱ cannotȱ haveȱ theȱ sameȱ nameȱ asȱ anyȱ ofȱ theȱ parameters,ȱbecauseȱtheyȱareȱallȱdeclaredȱinȱtheȱsameȱscope.ȱȱ ȱ ȱ 3.5.2 File Scope ȱ Anyȱidentifierȱdeclaredȱoutsideȱofȱallȱblocksȱhasȱfileȱscope,ȱmeaningȱthatȱtheȱidentifierȱ mayȱbeȱaccessedȱanywhereȱfromȱitsȱdeclarationȱtoȱtheȱendȱofȱtheȱsourceȱfileȱinȱwhichȱitȱ wasȱdeclared.ȱDeclarationsȱoneȱandȱtwoȱinȱFigureȱ3.1ȱareȱinȱthisȱcategory.ȱTheȱnamesȱ ofȱtheȱfunctionsȱdefinedȱinȱaȱfileȱhaveȱfileȱscope,ȱbecauseȱtheȱnameȱitselfȱisȱitselfȱIȱnotȱ withinȱanyȱblocksȱ(asȱinȱdeclarationȱfour).ȱIȱshouldȱpointȱoutȱthatȱdeclarationsȱwrittenȱ inȱ aȱ headerȱ tileȱ thatȱ isȱ thenȱ #includeȇdȱ intoȱ anotherȱ fileȱ areȱ treatedȱ asȱ ifȱ theyȱ wereȱ writtenȱdirectlyȱinȱtheȱincludingȱfile;ȱtheirȱscopeȱisȱnotȱlimitedȱbyȱtheȱendȱofȱtheȱheaderȱ file.ȱȱ ȱ ȱ ȱ 3.5.3 Prototype Scope ȱ Prototypeȱscopeȱappliesȱonlyȱtoȱargumentȱnamesȱdeclaredȱinȱfunctionȱprototypes,ȱasȱinȱ declarationsȱthreeȱandȱeightȱinȱFigureȱ3.1.ȱInȱaȱprototypeȱ(asȱopposedȱtoȱtheȱfunctionȱ definition)ȱtheȱargumentȱnamesȱneedȱnotȱappear.ȱIfȱtheyȱareȱgiven,ȱhowever,ȱyouȱmayȱ chooseȱanyȱnamesȱyouȱwish;ȱtheyȱneedȱnotȱmatchȱeitherȱtheȱformalȱparameterȱnamesȱ givenȱinȱtheȱfunctionȱdefinitionȱorȱtheȱnamesȱofȱtheȱactualȱargumentsȱusedȱwhenȱtheȱ functionȱ isȱ called.ȱ Prototypeȱ scopeȱ preventsȱ theseȱ namesȱ fromȱ conflictingȱ withȱ anyȱ otherȱnamesȱinȱtheȱprogram.ȱIndeed,ȱtheȱonlyȱpossibleȱconflictȱisȱusingȱtheȱsameȱnameȱ moreȱthanȱonceȱinȱtheȱsameȱprototype.ȱ ȱ ȱ ȱ 3.5.4 Function Scope ȱ Theȱfinalȱtypeȱofȱscopeȱisȱfunctionȱscope.ȱItȱappliesȱonlyȱtoȱstatementȱlabels,ȱwhichȱareȱ usedȱwith goto statements.ȱBasically,ȱfunctionȱscopeȱboilsȱdownȱtoȱaȱsimpleȱruleȱ–ȱallȱ statementȱ labesȱ inȱ aȱ functionȱ mustȱ beȱ unique.ȱ Iȱ hopeȱ thatȱ youȱ neverȱ useȱ thisȱ knowledge.ȱ Download at http://www.pin5i.com/ 3.6 Linkage 57 3.6 Linkage ȱ Afterȱ theȱ individualȱ sourceȱ filesȱ comprisingȱ aȱ programȱ areȱ compiled,ȱ theȱ objectȱ filesȱ areȱ linkedȱ togetherȱ withȱ functionsȱ fromȱ oneȱ orȱ moreȱ librariesȱ toȱ formȱ theȱ executableȱ program.ȱHowever,ȱwhenȱtheȱsameȱidentifierȱappearsȱinȱmoreȱthanȱoneȱsourceȱfile,ȱdoȱ theyȱ referȱ toȱ theȱ sameȱ entity,ȱ asȱ inȱ Pascal,ȱ orȱ toȱ differentȱ entities?ȱ Theȱ linkageȱ ofȱ anȱ identifierȱdeterminesȱhowȱmultipleȱoccurrencesȱofȱtheȱidentifierȱareȱtreated.ȱTheȱscopeȱ ofȱanȱidentifierȱisȱrelatedȱtoȱitsȱlinkage,ȱbutȱtheȱtwoȱpropertiesȱareȱnotȱtheȱsame.ȱȱ Thereȱ areȱ threeȱ typesȱ ofȱ linkage—external,ȱ internalȱ andȱ none.ȱ Identifiersȱ thatȱ haveȱnoȱlinkageȱareȱalwaysȱindividuals,ȱthatȱis,ȱmultipleȱdeclarationsȱofȱtheȱidentifierȱ areȱ alwaysȱ treatedȱ asȱ separateȱ andȱ distinctȱ entities.ȱ Internalȱ linkageȱ meansȱ thatȱ allȱ declarationsȱ ofȱ theȱ identifierȱ withinȱ oneȱ sourceȱ fileȱ referȱ toȱ aȱ singleȱ entity,ȱ butȱ declarationsȱ ofȱ theȱ sameȱ identifierȱ inȱ otherȱ sourceȱ filesȱ referȱ toȱ differentȱ entities.ȱ Finally,ȱallȱreferencesȱtoȱanȱidentifierȱwithȱexternalȱlinkageȱreferȱtoȱtheȱsameȱentity.ȱȱ Theȱ programȱ skeletonȱ inȱ Figureȱ 3.2ȱ illustratesȱ linkageȱ byȱ showingȱ allȱ ofȱ theȱ differentȱ waysȱ thatȱ namesȱ canȱbeȱ declared.ȱByȱ default,ȱ theȱ linkageȱ ofȱ identifiersȱ b,ȱ c,ȱ andȱ fȱisȱexternal;ȱandȱtheȱremainingȱidentifiersȱhaveȱnoȱlinkage.ȱThus,ȱanotherȱsourceȱ fileȱ thatȱ containsȱ aȱ similarȱ declarationȱ forȱ bȱ andȱ callsȱ theȱ functionȱ cȱ willȱ accessȱ theȱ entitiesȱdefinedȱinȱthisȱsourceȱtile,ȱ fȱhasȱexternalȱlinkageȱbecauseȱitȱisȱaȱfunctionȱname.ȱ Callsȱtoȱtheȱfunctionȱfȱinȱthisȱsourceȱfileȱwillȱbeȱlinkedȱwithȱtheȱfunctionȱdefinitionȱthatȱ appearsȱinȱsomeȱotherȱsourceȱfile,ȱorȱperhapsȱtheȱfunctionȱdefinitionȱmightȱcomeȱfromȱ aȱlibrary.ȱ Theȱkeywordsȱexternȱandȱstaticȱareȱusedȱinȱdeclarationsȱtoȱmodifyȱtheȱlinkageȱ ofȱtheȱidentifiersȱbeingȱdeclared.ȱWhenȱusedȱonȱaȱdeclarationȱofȱ ȱ ȱ ȱ 1 typedef char *a; 2 int b; 3 int c ( int d ) 4 { 5 int e; 6 int f ( int g ); … } ȱ Figureȱ3.2ȱLinkageȱexampleȱ 7 Download at http://www.pin5i.com/ 58 Chapter 3 Data somethingȱ thatȱ normallyȱ hasȱ externalȱ linkage,ȱ theȱ keywordȱ staticȱ givesȱ itȱ internalȱ linkageȱinstead.ȱForȱexample,ȱifȱdeclarationȱtwoȱwereȱwrittenȱ ȱ static int b; ȱ thenȱtheȱvariableȱbȱwouldȱremainȱprivateȱtoȱthisȱsourceȱfile;ȱreferencesȱtoȱtheȱvariableȱbȱ inȱ otherȱ sourceȱ filesȱ wouldȱ beȱ linkedȱ toȱ aȱ differentȱ variable.ȱ Similarly,ȱ definingȱ aȱ functionȱtoȱbeȱstatic,ȱforȱexample,ȱ ȱ static int c( int d ) TIP ȱ preventsȱitȱfromȱbeingȱcalledȱfromȱotherȱsourceȱfiles.ȱ staticȱ onlyȱ hasȱ thisȱ effectȱ inȱ declarationsȱ whoseȱ defaultȱ linkageȱ isȱ external.ȱ Althoughȱ itȱ isȱ legalȱ toȱ addȱ staticȱ toȱ declarationȱ five,ȱ forȱ exampleȱ itȱ hasȱ anȱ entirelyȱ differentȱeffectȱbecauseȱeȱdoesȱnotȱdefaultȱtoȱexternalȱlinkage.ȱ Theȱrulesȱforȱtheȱ externȱkeywordȱareȱmoreȱcomplicated.ȱInȱgeneral,ȱitȱspecifiesȱ externalȱlinkageȱforȱanȱidentifierȱandȱisȱusedȱtoȱgetȱaccessȱtoȱanȱentityȱthatȱisȱdefinedȱ elsewhere.ȱ Considerȱ theȱ exampleȱ inȱ Figureȱ 3.3.ȱ Declarationȱ threeȱ specifiesȱ externalȱ linkageȱ forȱ k,ȱ whichȱ givesȱ thisȱ functionȱ accessȱ toȱ anȱ externalȱ variableȱ declaredȱ inȱ anotherȱsourceȱfile.ȱ ȱ Technically,ȱ theȱ keywordȱ isȱ onlyȱ requiredȱ inȱ declarations,ȱ suchȱ asȱ numberȱ threeȱ inȱ Figureȱ3.3,ȱwhoseȱdefaultȱlinkageȱisȱnotȱexternal.ȱItsȱuseȱisȱoptionalȱinȱdeclarationsȱthatȱ haveȱfileȱscope.ȱHowever,ȱitȱisȱeasierȱforȱaȱreaderȱtoȱunderstandȱyourȱintentionsȱifȱyouȱ defineȱtheȱvariableȱonceȱandȱuseȱexternȱinȱeveryȱotherȱdeclarationȱthatȱrefersȱtoȱit.ȱ Whenȱexternȱisȱusedȱonȱtheȱfirstȱdeclarationȱinȱtheȱsourceȱfileȱforȱanȱidentifier,ȱ ȱ ȱ 1 static int i; int func() { 2 int j; 3 4 extern int k; extern int i; ... } ȱ Figureȱ3.3ȱUsingȱexternȱ Download at http://www.pin5i.com/ 3.7 Storage Class 59 itȱ specifiesȱ thatȱ theȱ identifierȱ hasȱ externalȱ linkage.ȱ Whenȱ usedȱ onȱ theȱ secondȱ orȱ subsequentȱ declarationsȱ ofȱ anȱ identifier,ȱ however,ȱ theȱ keywordȱ doesȱ notȱ changeȱ theȱ linkageȱ specifiedȱ byȱ theȱ firstȱ declaration.ȱ Forȱ example,ȱ declarationȱ fourȱ inȱ Figureȱ 3.3ȱ doesȱnotȱchangeȱtheȱlinkageȱofȱiȱestablishedȱbyȱdeclarationȱone.ȱ ȱ ȱ ȱ 3.7 Storage Class ȱ Theȱ storageȱ classȱ ofȱ aȱ variableȱ refersȱ toȱ theȱ typeȱ ofȱ memoryȱ inȱ whichȱ theȱ variable’sȱ valueȱ isȱ stored.ȱ Theȱ storageȱ classȱ ofȱ aȱ variableȱ determinesȱ whenȱ itȱ isȱ createdȱ andȱ destroyedȱandȱhowȱlongȱitȱwillȱretainȱitsȱvalue.ȱThereȱareȱthreeȱpossibleȱplacesȱtoȱstoreȱ variables:ȱ inȱ ordinaryȱ memory,ȱ onȱ theȱ runtimeȱ stack,ȱ andȱ inȱ hardwareȱ registers.ȱ Variablesȱstoredȱinȱtheseȱthreeȱplacesȱwillȱhaveȱdifferentȱcharacteristics.ȱ Theȱ defaultȱ storageȱ classȱ forȱ aȱ variableȱ dependsȱ onȱ whereȱ itȱ isȱ declared.ȱ Variablesȱdeclaredȱoutsideȱofȱanyȱblocksȱareȱalwaysȱstoredȱinȱstaticȱmemory,ȱthatȱis,ȱinȱ memoryȱthatȱisȱnotȱpartȱofȱtheȱstack.ȱThereȱisȱnoȱwayȱtoȱspecifyȱanyȱotherȱstorageȱclassȱ forȱtheseȱvariables.ȱStaticȱvariablesȱareȱcreatedȱbeforeȱtheȱprogramȱbeginsȱtoȱrunȱandȱ existȱthroughoutȱitsȱentireȱexecution.ȱTheyȱ retainȱwhateverȱvalueȱtheyȱwereȱassignedȱ untilȱaȱdifferentȱvalueȱisȱassignedȱorȱuntilȱtheȱprogramȱcompletes.ȱ Theȱdefaultȱstorageȱclassȱforȱvariablesȱdeclaredȱwithinȱaȱblockȱisȱautomatic,ȱthatȱ is,ȱonȱtheȱstack.ȱThereȱisȱaȱkeywordȱauto,ȱbutȱitȱisȱrarelyȱusedȱbecauseȱitȱdoesn’tȱchangeȱ theȱdefault.ȱAutomaticȱvariablesȱareȱcreatedȱjustȱbeforeȱtheȱprogramȱexecutionȱentersȱ theȱblockȱinȱwhichȱtheyȱwereȱdeclared,ȱandȱtheyȱareȱdiscardedȱjustȱasȱexecutionȱleavesȱ thatȱ block.ȱ Ifȱ theȱ blockȱ isȱ executedȱ severalȱ times,ȱ asȱ inȱ theȱ caseȱ ofȱ aȱ functionȱ thatȱ isȱ calledȱrepeatedly,ȱnewȱcopiesȱofȱtheȱautomaticȱvariablesȱareȱcreatedȱeachȱtime.ȱTheseȱ newȱvariablesȱmayȱorȱmayȱnotȱoccupyȱtheȱsameȱmemoryȱlocationsȱonȱtheȱstackȱasȱtheȱ previousȱinstancesȱofȱtheȱsameȱvariables,ȱandȱevenȱifȱtheyȱdoȱthereȱisȱnoȱguaranteeȱthatȱ theȱmemoryȱwasȱnotȱusedȱforȱsomeȱotherȱpurposeȱinȱtheȱmeantime.ȱWeȱthereforeȱsayȱ thatȱautomaticȱvariablesȱdisappearȱatȱtheȱendȱofȱaȱblock;ȱtheyȱgenerallyȱwillȱnotȱhaveȱ theirȱpreviousȱvaluesȱtheȱnextȱtimeȱtheȱblockȱisȱentered.ȱ Onȱvariablesȱdeclaredȱwithinȱaȱblock,ȱtheȱkeywordȱ staticȱchangesȱtheȱstorageȱ classȱ fromȱ automaticȱ toȱ static.ȱ Variablesȱ withȱ staticȱ storageȱ classȱ existȱ forȱ theȱ entireȱ durationȱ ofȱ theȱ program,ȱ ratherȱ thanȱ justȱ theȱ durationȱ ofȱ theȱ blockȱ inȱ whichȱ itȱ isȱ declared.ȱNoteȱthatȱchangingȱtheȱstorageȱclassȱofȱaȱvariableȱdoesȱnotȱchangeȱitsȱscope;ȱ itȱ isȱ stillȱ accessibleȱ byȱ nameȱ onlyȱ fromȱ withinȱ theȱ block.ȱ Theȱ formalȱ parametersȱ toȱ aȱ functionȱcannotȱbeȱdeclaredȱstatic,ȱbecauseȱargumentsȱareȱalwaysȱpassedȱonȱtheȱstackȱ toȱsupportȱrecursion.ȱ Download at http://www.pin5i.com/ 60 Chapter 3 Data Finally,ȱ theȱ registerȱ keywordȱ mayȱ beȱ usedȱ onȱ declarationsȱ ofȱ automaticȱ variablesȱ toȱ indicateȱ thatȱ theyȱ shouldȱ beȱ storedȱ inȱ theȱ machine’sȱ hardwareȱ registersȱ ratherȱthanȱinȱmemory.ȱUsually,ȱsuchȱvariablesȱcanȱbeȱaccessedȱmoreȱefficientlyȱthanȱ thoseȱ storedȱ inȱ memory.ȱ However,ȱ theȱ compilerȱ isȱ freeȱ toȱ ignoreȱ theȱ registerȱ keyword.ȱ lfȱ tooȱ manyȱ variablesȱ areȱ designatedȱ asȱ register,ȱ onlyȱ theȱ firstȱ onesȱ willȱ actuallyȱbeȱstoredȱinȱtheȱregisters,ȱandȱtheȱrestȱwillȱbeȱautomatic.ȱAȱcompilerȱthatȱdoesȱ itsȱownȱregisterȱoptimizationȱmayȱignoreȱ registerȱaltogetherȱonȱtheȱgroundsȱthatȱtheȱ compilerȱ canȱ doȱ aȱ betterȱ jobȱ decidingȱ whichȱ valuesȱ shouldȱ beȱ inȱ registersȱ thanȱ aȱ human.ȱ Typically,ȱ youȱ wantȱ toȱ declareȱ theȱ variablesȱ thatȱ areȱ usedȱ mostȱ heavilyȱ asȱ registerȱ variables.ȱ Onȱ someȱ computers,ȱ theȱ programȱ canȱ benefitȱ ifȱ weȱ declareȱ pointersȱasȱregisterȱvariables,ȱparticularlyȱthoseȱpointersȱonȱwhichȱtheȱmostȱindirectionȱ isȱ performed.ȱ Youȱ mayȱ declareȱ theȱ formalȱ parametersȱ ofȱ aȱ functionȱ asȱ registerȱ variables,ȱandȱtheȱcompilerȱwillȱgenerateȱinstructionsȱatȱtheȱbeginningȱofȱtheȱfunctionȱ toȱcopyȱtheȱvaluesȱfromȱtheȱstackȱtoȱtheȱregisters.ȱItȱisȱentirelyȱpossible,ȱhowever,ȱthatȱ theȱ spaceȱ andȱ timeȱ savingsȱ inȱ subsequentȱ accessesȱ toȱ theȱ parametersȱ mayȱ notȱ beȱ enoughȱtoȱoffsetȱtheȱoverheadȱofȱthisȱcopying.ȱ Registerȱ variablesȱ areȱ createdȱ andȱ destroyedȱ atȱ theȱ sameȱ timeȱ asȱ automaticȱ variables,ȱbutȱ thereȱ isȱ someȱ additionalȱ workȱ needed.ȱ Beforeȱ aȱ functionȱ thatȱ hasȱ usedȱ registerȱ variablesȱ returns,ȱ theȱ previousȱ contentsȱ ofȱ theȱ registersȱ mustȱ beȱ restoredȱ inȱ orderȱ toȱ ensureȱ thatȱ theȱ caller’sȱ registerȱ variablesȱ areȱ notȱ destroyed.ȱ Manyȱ machinesȱ useȱtheȱruntimeȱstackȱtoȱaccomplishȱthisȱtask.ȱWhenȱaȱfunctionȱbegins,ȱcontentsȱofȱanyȱ registersȱthatȱitȱwillȱuseȱareȱsavedȱonȱtheȱstack.ȱTheseȱvaluesȉa1ȉeȱthenȱcopiedȱbatikȱtoȱ theȱregistersȱjustȱbeforeȱtheȱfunctionȱreturns.ȱ Manyȱhardwareȱimplementationsȱdoȱnotȱassignȱaddressesȱtoȱtheȱregisters.ȱAlso,ȱ becauseȱ ofȱ theȱ savingȱ andȱ restoringȱ ofȱ registerȱ values,ȱ atȱ particularȱ registerȱ mayȱ containȱ manyȱ differentȱ valuesȱ atȱ differentȱ times.ȱ Forȱ theseȱ reasons,ȱ youȱ areȱ notȱ allowedȱtoȱtakeȱtheȱaddressȱofȱaȱregisterȱvariable.ȱ ȱ ȱ ȱ 3.7.1 Initialization ȱ Weȱnowȱreturnȱtoȱtheȱtopicȱofȱinitializationȱofȱvariablesȱinȱtheirȱdeclarations.ȱThereȱisȱ anȱ importantȱ differenceȱ inȱ howȱ initializationȱ worksȱ onȱ automaticȱ variablesȱ versusȱ staticȱvariables.ȱInitializationȱofȱvariablesȱwithȱstaticȱstorageȱclassȱisȱaccomplishedȱbyȱ placingȱ theȱ desiredȱ valueȱ inȱ theȱ executableȱ programȱ fileȱ inȱ theȱ locationȱ thatȱ willȱ beȱ usedȱ byȱ theȱ variableȱ whenȱ theȱ programȱ isȱ executing.ȱ Whenȱ thisȱ executableȱ fileȱ isȱ loadedȱ intoȱ memory,ȱ theȱ locationȱ assignedȱ toȱ theȱ variableȱ startsȱ outȱ withȱ theȱ correctȱ valueȱ alreadyȱ inȱ it.ȱ Noȱ extraȱ timeȱ isȱ takenȱ toȱ accomplishȱ thisȱ task,ȱ norȱ areȱ anyȱ instructionsȱexecutedȱinȱtheȱprogramȱtoȱdoȱit.ȱTheȱvariableȱjustȱstartsȱoutȱwithȱtheȱrightȱȱ Download at http://www.pin5i.com/ 3.8 The Static Keyword 61 value.ȱ Staticȱ variablesȱ areȱ initializedȱ toȱ zeroȱ unlessȱ anȱ explicitȱ initializationȱ specifiesȱ someȱotherȱvalueȱ Initializationȱ ofȱ automaticȱ variablesȱ takesȱ moreȱ overheadȱ becauseȱ theȱ locationȱ usedȱtoȱstoreȱtheȱvariableȱcannotȱbeȱdeterminedȱwhenȱtheȱprogramȱisȱlinked.ȱIndeed,ȱ localȱ variablesȱ inȱ aȱfunctionȱmayȱoccupyȱdifferentȱlocationsȱeachȱ timeȱtheȱfunctionȱisȱ called.ȱ Forȱ thisȱ reason,ȱ thereȱ isȱ noȱ defaultȱ initializationȱ ofȱ automaticȱ variables,ȱ andȱ explicitȱinitializationȱisȱperformedȱwithȱanȱinvisibleȱassignmentȱstatementȱinsertedȱinȱ theȱbeginningȱofȱtheȱblock.ȱ Thisȱtechniqueȱhasȱfourȱconsequences.ȱFirst,ȱinitializationȱofȱautomaticȱvariablesȱ isȱ noȱ moreȱ efficientȱ thanȱ anȱ assignmentȱ statement.ȱ Exceptȱ forȱ variablesȱ declaredȱ asȱ const,ȱ initializingȱ theȱ variableȱ inȱ itsȱ declarationȱ orȱ usingȱ assignmentȱ statementsȱ isȱ solelyȱ aȱ matterȱ ofȱ style.ȱ Second,ȱ theȱ implicitȱ assignmentȱ statementȱ causesȱ automaticȱ variablesȱ toȱ beȱ reinitializedȱ eachȱ timeȱ theȱ functionȱ (orȱ block)ȱ inȱ whichȱ theyȱ wereȱ declaredȱ isȱ entered.ȱ Thisȱ behaviorȱ isȱ quiteȱ differentȱ fromȱ staticȱ variables,ȱ whichȱ areȱ initializedȱ onlyȱ onceȱ beforeȱ theȱ programȱ beginsȱ toȱ execute.ȱ Theȱ thirdȱ consequenceȱ isȱ anȱ advantage.ȱ Becauseȱ initializationȱ isȱ performedȱ atȱ runȱ time,ȱ youȱ mayȱ useȱ anyȱ expressionȱasȱanȱinitializer,ȱforȱexample.ȱ ȱ int func( int a ) { int b = a + 3; ȱ Finally,ȱunlessȱyouȱinitializeȱthemȱexplicitly,ȱautomaticȱvariablesȱwillȱcontainȱgarbageȱ whenȱtheyȱareȱcreated.ȱ ȱ ȱ ȱ 3.8 The Static Keyword ȱ Itȱisȱindeedȱunfortunateȱthatȱtheȱstaticȱkeywordȱhasȱdifferentȱmeaningsȱwhenȱusedȱinȱ differentȱcontexts,ȱbecauseȱitȱalwaysȱcausesȱconfusionȱ forȱ beginningȱCȱ programmers.ȱ Thisȱsummaryȱandȱtheȱfollowingȱexampleȱshouldȱhelpȱclarifyȱtheȱissueȱforȱyou.ȱȱ Whenȱ usedȱ onȱ functionȱ definitions,ȱ orȱ declarationsȱ ofȱ variablesȱ thatȱ appearȱ outsideȱofȱblocks,ȱtheȱkeywordȱ staticȱchangesȱtheȱlinkageȱfromȱexternalȱtoȱinternal— theȱ storageȱ classȱ andȱscopeȱ areȱnotȱ affected.ȱ Functionsȱ andȱ variablesȱ declaredȱ inȱ thisȱ wayȱareȱaccessibleȱonlyȱfromȱwithinȱtheȱsourceȱfileȱinȱwhichȱtheyȱwereȱdeclared.ȱ Whenȱusedȱonȱvariableȱdeclarationsȱthatȱappearȱinsideȱofȱaȱblock,ȱtheȱkeywordȱ staticȱ changesȱ theȱ storageȱ classȱ fromȱ automaticȱ toȱ static—theȱ linkageȱ andȱ scopeȱ areȱ notȱaffected.ȱVariablesȱdeclaredȱinȱthisȱmannerȱareȱcreatedȱwhenȱtheȱprogramȱbeginsȱ Download at http://www.pin5i.com/ 62 Chapter 3 Data toȱ executeȱ andȱ continueȱ toȱ existȱ forȱ itsȱ entireȱ duration,ȱ insteadȱ ofȱ beingȱ createdȱ andȱ destroyedȱeveryȱtimeȱexecutionȱentersȱandȱleavesȱtheȱblock.ȱ ȱ ȱ ȱ 3.9 Scope, Linkage, and Storage Class Example ȱ Figureȱ 3.4ȱ containsȱ anȱ exampleȱ whichȱ illustratesȱ scope,ȱ linkage,ȱ andȱ storageȱ class.ȱ Declarationsȱwithȱtileȱscopeȱdefaultȱtoȱexternalȱlinkage,ȱsoȱaȱinȱlineȱ1ȱisȱ ȱ 1 2 3 int extern static a = 5; int b; int c; 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 int d( int e ) { int register static extern ... { 25 26 27 28 static int i() { ... } 29 ... int int int f = 15; b; g = 20; a; int int extern int ... e; a; h; } ... { int int ... x; e; } ... } ȱ Figureȱ3.4ȱScope,ȱlinkage,ȱandȱstorageȱclassȱexampleȱ Download at http://www.pin5i.com/ 3.9 Scope, Linkage, and Storage Class Example 63 external.ȱ Theȱ externȱ keywordȱ inȱ lineȱ 2ȱ isȱ technicallyȱ notȱ neededȱ butȱ sty1isticallyȱ desiredȱifȱ bȱisȱdefinedȱelsewhere.ȱTheȱ staticȱkeywordȱinȱlineȱ3ȱoverridesȱtheȱdefaultȱ linkageȱforȱc,ȱgivingȱitȱinternalȱlinkageȱinstead.ȱOtherȱsourceȱfilesȱthatȱdeclareȱvariablesȱ namedȱ aȱ orȱ bȱ withȱ externalȱ linkageȱ willȱ accessȱ theȱ sameȱ variablesȱ declaredȱ here.ȱ However,ȱ cȱ canȱ onlyȱ beȱ accessedȱ fromȱ withinȱ thisȱ sourceȱ fileȱ dueȱ toȱ itsȱ internalȱ linkage.ȱ Theȱstorageȱclassȱof a, b,ȱand cȱisȱstatic,ȱ meaningȱthatȱtheyȱareȱnotȱstoredȱonȱ theȱ stack.ȱ Thus,ȱ theseȱ variablesȱ areȱ createdȱ whenȱ theȱ programȱ beginsȱ executing,ȱ andȱ theyȱretainȱtheirȱvaluesȱuntilȱitȱfinishes.ȱ aȱwillȱbeȱinitializedȱtoȱfiveȱwhenȱtheȱprogramȱ begins.ȱȱ Theȱ scopeȱ ofȱ theseȱ variablesȱ extendsȱ throughȱ theȱ restȱ ofȱ thisȱ sourceȱ file,ȱ butȱ localȱ declarationsȱ ofȱ variablesȱ namedȱ aȱ andȱ bȱ inȱ linesȱ 7ȱ andȱ i3ȱ hideȱ theseȱ variablesȱ fromȱthoseȱportionsȱofȱtheȱprogram.ȱThus,ȱtheȱscopesȱofȱtheseȱfirstȱthreeȱvariablesȱare,ȱ ȱ aȱ linesȱ1Ȭ12,ȱ17Ȭ29ȱ bȱ linesȱ2Ȭ6,ȱ25Ȭ29ȱ cȱ linesȱ3Ȭ29ȱ ȱ Lineȱ4ȱdeclaresȱtwoȱidentifiers.ȱTheȱscopeȱofȱ dȱextendsȱfromȱlineȱ4ȱthroughȱtheȱ enȱofȱthisȱfile;ȱtheȱdefinitionȱofȱfunctionȱdȱservesȱasȱitsȱprototypeȱforȱanyȱfunctionsȱlaterȱ inȱthisȱsourceȱfileȱthatȱwishȱtoȱcallȱ d.ȱAsȱaȱfunctionȱname,ȱ dȱdefaultȱtoȱexternalȱlinkage,ȱ soȱ functionsȱ inȱ otherȱ sourceȱ filesȱ canȱ callȱ dȱ asȱ longȱ asȱ theyȱ haveȱ aȱ prototype. 21 ȱ Weȱ couldȱ changeȱ theȱ linkageȱ toȱ internalȱ byȱ declaringȱ theȱ function static,ȱ butȱ doingȱ soȱ wouldȱ makeȱ itȱ inaccessibleȱ fromȱ otherȱ sourceȱ files.ȱ Storageȱ classȱ isȱ notȱ anȱ issueȱ forȱ functionsȱbecauseȱcodeȱisȱalwaysȱstoredȱinȱstaticȱmemory.ȱ Theȱargumentȱ eȱhasȱnoȱlinkage,ȱsoȱweȱcanȱaccessȱitȱbyȱnameȱonlyȱfromȱwithinȱ thisȱ function.ȱ Itȱ hasȱ automaticȱ storageȱ class,ȱ soȱ itȱ comesȱ intoȱ existenceȱ whenȱ theȱ functionȱ isȱ calledȱ andȱ disappearsȱ whenȱ theȱ functionȱ returns.ȱ Itsȱ scopeȱ isȱ limitedȱ toȱ linesȱ6Ȭ11,ȱ17Ȭ19,ȱandȱ23Ȭ24ȱdueȱtoȱconflictingȱlocalȱdeclarations.ȱ Linesȱ 6Ȭ8ȱ declareȱ localȱ variables,ȱ thusȱ theirȱ scopeȱ endsȱ atȱ theȱ endȱ ofȱ theȱ function.ȱ Theyȱ haveȱ noȱ linkage,ȱ soȱ theyȱ cannotȱ beȱ accessedȱ byȱnameȱ fromȱ anywhereȱ outsideȱofȱthisȱfunctionȱ(whichȱisȱwhyȱtheyȱareȱcalledȱlocal).ȱTheȱstorageȱclassȱofȱ fȱisȱ automatic,ȱandȱitȱisȱinitializedȱtoȱ15ȱbyȱanȱimplicitȱassignmentȱstatementȱeachȱtimeȱtheȱ functionȱisȱcalled.ȱbȱhasȱregisterȱstorageȱclassȱsoȱitsȱinitialȱvalueȱisȱgarbage.ȱTheȱstorageȱ classȱofȱgȱisȱstatic,ȱsoȱitȱexistsȱthroughoutȱtheȱprogramȇsȱexecution.ȱItȱisȱinitializedȱtoȱ20ȱ onceȱatȱtheȱbeginningȱofȱexecution.ȱItȱisȱnotȱinitializedȱeachȱtimeȱtheȱfunctionȱisȱcalled.ȱ ȱActually,ȱtheȱprototypeȱisȱonlyȱrequiredȱifȱdȱreturnȱsomethingȱotherȱthanȱanȱinteger.ȱPrototypingȱallȱfunctionsȱthatȱyouȱcallȱ isȱrecommendedȱbecauseȱitȱreducesȱtheȱchancesȱforȱundetectedȱerrors.ȱ 21 Download at http://www.pin5i.com/ 64 Chapter 3 Data Theȱ declarationȱ inȱ lineȱ 9ȱ isȱ notȱ needed.ȱ Thisȱ blockȱ isȱ withinȱ theȱ scopeȱ ofȱ theȱ declarationȱinȱlineȱ1.ȱ Linesȱ12ȱandȱ13ȱdeclareȱlocalȱvariablesȱforȱtheȱblock.ȱTheyȱareȱautomatic,ȱhaveȱ noȱlinkage,ȱandȱtheirȱscopesȱextendȱthroughȱlineȱ16.ȱTheseȱvariablesȱareȱseparateȱfromȱ theȱ aȱ andȱ eȱ declaredȱ earlier,ȱ andȱ theȱ earlierȱ variableȱ areȱ inaccessibleȱ fromȱ thisȱ blockȱ becauseȱofȱtheȱnameȱconflict.ȱ Lineȱ 14ȱ makesȱ theȱ globalȱ variableȱ hȱ accessibleȱ fromȱ withinȱ theȱ block.ȱ Itȱ hasȱ externalȱ linkageȱ andȱ residesȱ inȱ staticȱ storage.ȱ Thisȱ isȱ theȱ onlyȱ declarationȱ whereȱ theȱ externȱisȱvital.ȱWithoutȱit,ȱhȱwouldȱbeȱanotherȱlocalȱvariable.ȱ Linesȱ19ȱandȱ20ȱcreateȱlocalȱvariablesȱ(automatic,ȱnoȱlinkage,ȱscopeȱrestrictedȱtoȱ thisȱblock).ȱThisȱ eȱisȱaȱdifferentȱvariableȱthanȱtheȱargumentȱ e,ȱandȱitȱisȱalsoȱaȱdifferentȱ variableȱfromȱtheȱ eȱdeclaredȱinȱlineȱ12.ȱTheȱblocksȱstartingȱatȱlinesȱ11ȱandȱ18ȱareȱnotȱ nested,ȱsoȱtheȱcompilerȱcanȱuseȱtheȱsameȱmemoryȱtoȱstoreȱtheirȱlocalȱvariables.ȱThus,ȱ thereȱisȱaȱchanceȱthatȱtheȱsameȱmemoryȱlocationȱwillȱbeȱusedȱtoȱstoreȱtheȱvariableȱ eȱinȱ bothȱblocks.ȱIfȱyouȱneedȱ eȱtoȱbeȱtheȱsameȱvariableȱinȱbothȱblocks,ȱthenȱitȱshouldnȇtȱbeȱ declaredȱasȱlocalȱtoȱthem.ȱ Finally,ȱ lineȱ 25ȱ declaresȱ theȱ functionȱ iȱ withȱ staticȱ linkage.ȱ Staticȱ linkageȱ preventsȱ itȱ fromȱ beingȱ calledȱ byȱ anyȱ functionsȱ outsideȱ ofȱ thisȱ sourceȱ file.ȱ Indeed,ȱ anotherȱsourceȱfileȱmayȱdeclareȱitsȱownȱfunctionȱcalledȱ i,ȱwhichȱwillȱbeȱseparateȱandȱ distinctȱ formȱ thisȱ one.ȱ Theȱ scopeȱ ofȱ iȱ extendsȱ fromȱ thisȱ declarationȱ toȱ theȱ enȱ ofȱ thisȱ sourceȱfile.ȱFunctionȱdȱcannotȱcallȱfunctionȱ iȱbecauseȱnoȱprototypeȱforȱ iȱappearȱpriorȱ toȱd.ȱ ȱ ȱ ȱ 3.10 Summary ȱ Entitiesȱ withȱ externalȱ linkageȱ areȱ whatȱ otherȱ languagesȱ wouldȱ termȱ globalȱ andȱ areȱ accessibleȱ toȱ allȱ functionsȱ inȱ allȱ sourceȱ files.ȱ Externalȱ linkageȱ occursȱ byȱ defaultȱ withȱ variableȱdeclarationsȱthatȱareȱnotȱinȱanyȱblockȱandȱwithȱfunctionȱdefinitions.ȱAddingȱ externȱtoȱaȱvariableȱdeclarationȱinsideȱofȱaȱblockȱcausesȱitȱtoȱreferȱtoȱglobalȱvariablesȱ ratherȱthanȱlocalȱones.ȱ Entitiesȱwithȱexternalȱlinkageȱalwaysȱhaveȱstaticȱstorageȱclass.ȱGlobalȱvariablesȱ areȱ createdȱ beforeȱ theȱ programȱ beginsȱ toȱ executeȱ andȱ existȱ throughoutȱ itsȱ execution.ȱ Theȱ localȱvariablesȱbelongingȱ toȱfunctionsȱcomeȱandȱ goȱasȱtheȱfunctionsȱexecute,ȱ butȱ theȱmachine,ȱinstructionsȱinȱtheȱfunctionsȱexistȱforȱtheȱlifeȱofȱtheȱprogram.ȱȱ Localȱ variables,ȱ thoseȱ thatȱ areȱ usedȱ inȱ aȱ functionȱ andȱ notȱ referencedȱ byȱ nameȱ fromȱanyȱotherȱfunction,ȱdefaultȱtoȱautomaticȱstorageȱforȱtwoȱreasons.ȱFirst,ȱstorageȱisȱ allocatedȱ toȱ theseȱ variablesȱ onlyȱ whenȱ theyȱ areȱ needed,ȱ thusȱ reducingȱ theȱ totalȱ memoryȱrequirementȱforȱtheȱprogram.ȱSecond,ȱallocatingȱthemȱonȱtheȱstackȱallowsȱ Download at http://www.pin5i.com/ 3.12 Summary of Programming Tips 65 ȱ Variable Type globalȱ localȱ Where Declared outsideȱofȱallȱ blocksȱ beginningȱofȱaȱ blockȱ formalȱ functionȱ parametersȱ headerȱ Stored on Stack noȱ1 yesȱ2 yesȱ2 Scope If Declared static remainderȱofȱ thisȱsourceȱfileȱ throughoutȱtheȱ blockȱ3 preventsȱaccessȱfromȱotherȱ sourceȱfilesȱ variableȱisȱnotȱstoredȱonȱtheȱ stack,ȱkeepsȱitsȱvaluedȱforȱtheȱ entireȱdurationȱofȱtheȱprogramȱ notȱallowedȱ throughoutȱtheȱ functionȱ3 ȱ ȱVariablesȱstoredȱonȱtheȱstackȱretainȱtheirȱvaluesȱonlyȱwhileȱtheȱblockȱtoȱwhichȱtheyȱareȱlocalȱ isȱactive.ȱWhenȱexecutionȱleavesȱtheȱblock,ȱtheȱvaluesȱareȱlost.ȱ 2ȱVariablesȱnotȱstoredȱonȱtheȱstackȱareȱcreatedȱwhenȱtheȱprogramȱbeginsȱexecutingȱandȱretainȱ theirȱvaluesȱthroughoutȱexecution,ȱregardlessȱofȱwhetherȱtheyȱareȱlocalȱorȱglobal.ȱ 3ȱExceptȱinȱnestedȱblocksȱthatȱdeclareȱidenticalȱnames.ȱ ȱ Tableȱ3.4ȱScope,ȱlinkage,ȱandȱstorageȱclassȱsummaryȱ ȱ ȱ recursionȱ toȱ beȱ implementedȱ efficiently.ȱ Youȱ canȱ changeȱ theȱ storageȱ classȱ ofȱ localȱ variablesȱ toȱ staticȱ ifȱ itȱ isȱ importantȱ thatȱ theȱ valuesȱ ofȱ theseȱ variablesȱ beȱ retainedȱ betweenȱexecutionsȱofȱtheȱfunction.ȱȱ ThisȱinformationȱisȱsummarizedȱinȱTableȱ3.4.ȱ ȱ ȱ ȱ 1 3.11 Summary of Cautions ȱ 1. Writingȱmisleadingȱdeclarationsȱforȱpointerȱvariablesȱ(pageȱ50).ȱ 2. Misinterpretingȱtheȱmeaningȱofȱinitializationsȱinȱpointerȱdeclarationsȱ(pageȱ50).ȱ ȱ ȱ ȱ 3.12 Summary of Programming Tips ȱ 1. Forȱtheȱbestȱportability,ȱrestrictȱcharacterȱvariablesȱtoȱvaluesȱinȱtheȱintersectionȱofȱ theȱ signedȱ andȱ unsignedȱ characterȱ rangesȱ orȱ donȇtȱ performȱ arithmeticȱ onȱ themȱ (pageȱ41).ȱ 2. Expressȱliteralsȱinȱtheȱformȱthatȱisȱmostȱnaturalȱforȱhowȱtheyȱareȱusedȱ(pageȱ42).ȱ 3. Donȇtȱmixȱintegersȱwithȱenumeratedȱvaluesȱ(pageȱ44).ȱ Download at http://www.pin5i.com/ 66 Chapter 3 Data 4. Donȇtȱdependȱonȱimplicitȱdeclarationsȱ(pageȱ51).ȱ 5. Useȱtypedefȱratherȱthanȱ#defineȱtoȱdefineȱnewȱtypeȱnamesȱ(pageȱ52).ȱ 6. Useȱconstȱtoȱdeclareȱvariablesȱthatȱwillȱnotȱchangeȱ(pageȱ53).ȱ 7. Useȱnamedȱconstantsȱratherȱthanȱliteralȱconstantsȱ(pageȱ54).ȱ 8. Donȇtȱuseȱduplicateȱvariableȱnameȱinȱnestedȱblocksȱ(pageȱ55).ȱ 9. Useȱexternȱinȱallȱdeclarationsȱforȱanȱentityȱbutȱoneȱ(pageȱ58).ȱ ȱ ȱ ȱ 3.13 Questions ȱ 1. Whatȱisȱtheȱrangeȱforȱcharactersȱandȱtheȱvariousȱintegerȱtypesȱonȱyourȱmachine?ȱ ȱ 2. WhatȱisȱtheȱrangeȱforȱeachȱofȱtheȱfloatingȬpointȱtypesȱonȱyourȱmachine?ȱ ȱ 3. Supposeȱyouȱareȱwritingȱaȱprogramȱthatȱmustȱrunȱonȱtwoȱmachinesȱwhoseȱdefaultȱ integersȱ areȱ differentȱ sizes:ȱ 16ȱ bitsȱ andȱ 32ȱ bits.ȱ Theȱ sizeȱ ofȱ longȱ integersȱ onȱ theseȱ machinesȱ isȱ 32ȱ bitsȱ andȱ 64ȱ hits,ȱ respectively.ȱ Someȱ ofȱ theȱ valuesȱ usedȱ inȱ thisȱ programȱ areȱ smallȱ enoughȱ toȱ fitȱ inȱ aȱ defaultȱ integerȱ onȱ eitherȱ machine,ȱ butȱ someȱ valuesȱ areȱlargeȱ enoughȱ toȱ requireȱ 32ȱ bits.ȱ Oneȱ possibleȱ solutionȱ isȱ toȱ simplyȱ useȱ longȱintegersȱforȱallȱvalues,ȱbutȱthisȱapproachȱwastesȱtimeȱandȱspaceȱonȱtheȱl6Ȭbitȱ machineȱforȱthoseȱvaluesȱthatȱwouldȱfitȱinȱ16ȱbitsȱandȱwastesȱtimeȱandȱspaceȱonȱtheȱ 32Ȭbitȱmachineȱasȱwell.ȱ Howȱcanȱyouȱwriteȱtheȱdeclarationsȱforȱtheseȱvariablesȱsoȱthatȱtheyȱareȱtheȱrightȱ sizeȱ forȱ bothȱ machines?ȱ Theȱ correctȱ approachȱ avoidsȱ theȱ racedȱ toȱ modifyȱ theseȱ declarationsȱwhenȱcompilingȱtheȱprogramȱonȱeitherȱmachine.ȱHint:ȱTryȱincludingȱaȱ headerȱfileȱthatȱcontainsȱdeclarationsȱspecificȱtoȱeachȱparticularȱmachine.ȱ ȱ 4. Supposeȱ youȱ haveȱ aȱ programȱ thatȱ assignsȱ aȱ long integerȱ variableȱ toȱ aȱ short integerȱ variable.ȱ Whatȱ happensȱ whenȱ youȱ compileȱ thisȱ program?ȱ Whatȱ happensȱ whenȱyouȱrunȱit?ȱDoȱyouȱthinkȱthatȱotherȱcompilersȱwillȱgiveȱtheȱsameȱresults?ȱ ȱ 5. Supposeȱ youȱ haveȱ aȱ programȱ thatȱ assignsȱ aȱ doubleȱ variableȱ toȱ aȱ float.ȱ Whatȱ happensȱwhenȱyouȱcompileȱthisȱprogram?ȱWhatȱhappensȱwhenȱyouȱrunȱit?ȱ ȱ 6. Writeȱ aȱ declarationȱ forȱ anȱ enumerationȱ thatȱ definesȱ valuesȱ forȱ coins,ȱ usingȱ theȱ symbolsȱPENNY,ȱNICKEL,ȱandȱsoȱforth.ȱ ȱ 7. Whatȱisȱprintedȱbyȱthisȱfragmentȱofȱcode?ȱ ȱ Download at http://www.pin5i.com/ 3.12 Summary of Programming Tips 67 enum Liquid { OUNCE = 1, CUP = 8, PINT = 16, ȱ QUART = 32, GALLON = 128 }; enum Liquid jar; ... jar = QART; printf( "%s\n", jar ); jar = jar + PINT; printf( "%s\n", jar ); 8. DoesȱyourȱCȱimplementationȱallowȱstringȱliteralsȱtoȱbeȱmodifiedȱbyȱtheȱprogram?ȱ Areȱthereȱanyȱ compilerȱoptionsȱthatȱ allowȱ theȱmodificationȱofȱ stringȱ literalsȱ toȱ beȱ enabledȱorȱdisabled?ȱ ȱ 9. Ifȱ theȱ integerȱ typesȱ areȱ normallyȱ signed,ȱ whatȱ isȱ theȱ purposeȱ ofȱ theȱ signedȱ keyword?ȱ ȱ 10. Canȱ anȱ unsignedȱ variableȱ holdȱ aȱ largerȱ rangeȱ ofȱ valuesȱ thanȱ aȱ signedȱ variableȱ ofȱ theȱsameȱsize?ȱ ȱ 11. Assumingȱ thatȱ theyȱ areȱ bothȱ 32ȱ bitsȱ long,ȱ whichȱ typeȱ ofȱ variableȱ canȱ holdȱ moreȱ distinctȱvalues,ȱanȱintȱorȱaȱfloat?ȱ ȱ 12. Theȱtwoȱfragmentsȱofȱcodeȱshownȱbelowȱcameȱfromȱtheȱbeginningȱofȱaȱfunction.ȱ ȱ int a = 25; int a; a = 25; ȱ Howȱdoȱtheyȱdifferȱinȱwhatȱtheyȱaccomplish?ȱ ȱ 13. Ifȱtheȱdeclarationsȱinȱ theȱcodeȱfragmentsȱinȱquestionȱ12ȱincludedȱtheȱwordȱ const,ȱ howȱwouldȱtheyȱdifferȱinȱwhatȱtheyȱaccomplished?ȱ ȱ 14. Aȱ variableȱ declaredȱ inȱ aȱ blockȱ mayȱ beȱ accessedȱ byȱ nameȱ fromȱ anywhereȱ inȱ thatȱ block.ȱTrueȱorȱfalse?ȱ ȱ 15. Supposeȱfunctionȱaȱdeclaresȱanȱautomaticȱintegerȱvariableȱcalledȱ x.ȱYouȱcanȱaccessȱ theȱvariableȱxȱfromȱaȱdifferentȱfunctionȱbyȱusingȱaȱdeclarationȱsuchȱasȱthisȱone.ȱ ȱ extern int x; ȱ Trueȱorȱfalse?ȱ ȱ 16. Supposeȱ theȱ variableȱ xȱ inȱ questionȱ 15ȱ hadȱ beenȱ declaredȱ static.ȱ Doesȱ thisȱ modificationȱchangeȱyourȱanswer?ȱ ȱ 17. Supposeȱtheȱfileȱa.cȱbeginsȱwithȱthisȱdeclaration:ȱ Download at http://www.pin5i.com/ 68 Chapter 3 Data int x; int x; int a = 5; ȱ Whatȱdeclarationȱ(ifȱany)ȱwouldȱbeȱneededȱtoȱaccessȱthisȱvariableȱfromȱaȱfunctionȱ foundȱlaterȱinȱtheȱsameȱfile?ȱ ȱ 18. Supposeȱ theȱ declarationȱ inȱ questionȱ 17ȱ includedȱ theȱ keywordȱ static.ȱ Wouldȱ thisȱ modificationȱchangeȱyourȱanswer?ȱ ȱ 19. Supposeȱtheȱfileȱa.cȱbeginsȱwithȱthisȱdeclaration:ȱ ȱ ȱ Whatȱdeclarationȱ(ifȱany)ȱwouldȱbeȱneededȱtoȱaccessȱthisȱvariableȱfromȱaȱfunctionȱ foundȱinȱaȱdifferentȱsourceȱfileȱ ȱ 20. Supposeȱ theȱ declarationȱ inȱ questionȱ 19ȱ includedȱ theȱ keywordȱ static.ȱ Wouldȱ thisȱ modificationȱchangeȱyourȱanswer?ȱ ȱ 21. Supposeȱaȱfunctionȱthatȱcontainsȱautomaticȱvariablesȱisȱcalledȱtwiceȱinȱaȱrow.ȱIsȱitȱ possibleȱthatȱtheȱvariablesȱwillȱhaveȱtheȱsameȱvaluesȱatȱtheȱbeginningȱofȱtheȱsecondȱ callȱthatȱtheyȱhadȱatȱtheȱendȱofȱtheȱfirstȱcall?ȱ ȱ 22. Whatȱisȱtheȱdifferenceȱinȱtheȱbehaviorȱofȱtheȱdeclarationȱ ȱ ȱ Whenȱitȱappearsȱinȱsideȱofȱaȱfunctionȱasȱcomparedȱtoȱwhenȱitȱappearsȱoutside?ȱ ȱ 23. Supposeȱyouȱwantedȱtoȱwriteȱtwoȱfunctions,ȱ xȱandȱ y,ȱinȱtheȱsameȱsourceȱfile,ȱthatȱ useȱtheȱfollowingȱvariables:ȱ ȱ Name Type Storage Class Linkage Scope Initialized to a int staticȱ externalȱ accessibleȱtoȱx;ȱnotȱyȱ 1ȱ b char staticȱ noneȱ accessibleȱtoȱxȱandȱyȱ 2ȱ c int automaticȱ noneȱ localȱtoȱxȱ 3ȱ d float staticȱ noneȱ localȱtoȱxȱ 4ȱ ȱ Howȱ andȱ whereȱ wouldȱ youȱ writeȱ theȱ declarationsȱ forȱ theseȱ variables?ȱ Note:ȱ Allȱ initializationȱ mustȱ beȱmadeȱinȱ theȱ declarationsȱthemselves,ȱnotȱ byȱanyȱexecutableȱ statementsȱinȱtheȱfunctions.ȱ ȱ 24. Identifyȱ anyȱ errorsȱ containedȱ inȱ theȱ followingȱ program.ȱ (Youȱ mayȱ wishȱ toȱ tryȱ compilingȱitȱtoȱbeȱsure.)ȱAfterȱyouȱhaveȱremovedȱtheȱerrors,ȱdetermineȱtheȱstorageȱ class,ȱscope,ȱandȱlinkageȱofȱeveryȱidentifier.ȱWhatȱwillȱbeȱtheȱinitialȱvalueȱofȱeachȱ variable?ȱThereȱareȱmanyȱduplicateȱidentifiers;ȱdoȱtheyȱreferȱtoȱtheȱsameȱvariableȱorȱ noȱdifferentȱones?ȱFromȱwhereȱcanȱeachȱofȱtheseȱfunctionsȱbeȱcalled?ȱ Download at http://www.pin5i.com/ 3.13 Questions 69 1 2 static int extern int w = 5; x; 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 static float func1( int a, int b, int c ) { int c, d, e = 1; ... { int d,e,w; ... { int static ... } } ... { register int extern int y; ... } } 24 static int 25 26 27 28 29 30 31 float func2( int a ) { extern int static int ... } y; y; z; b, c, d; int a, d, x; y = 2; Download at http://www.pin5i.com/ Download at http://www.pin5i.com/ 4 Statements Youȱ willȱ findȱ thatȱ Cȱ implementsȱ allȱ ofȱ theȱ statementsȱ foundȱ inȱ other,ȱ modernȱ highȬ levelȱlanguages,ȱandȱmostȱofȱthemȱworkȱtheȱwayȱyouȱwouldȱexpect.ȱTheȱ ifȱstatementȱ choosesȱ betweenȱ alternateȱ sequencesȱ ofȱ code,ȱ andȱ theȱ while,ȱ for,ȱ andȱ doȱ statementsȱ implementȱdifferentȱkindsȱofȱloops.ȱ Thereȱ areȱ someȱ differences,ȱ though.ȱ Forȱ example,ȱ Cȱ doesȱ notȱ haveȱ anȱ assignmentȱstatement;ȱanȱȈexpressionȱstatementȈȱisȱusedȱinstead.ȱTheȱswitchȱstatementȱ performsȱtheȱsameȱjobȱasȱotherȱlanguagesȱcaseȱstatements,ȱthoughȱinȱanȱunusualȱway.ȱ Beforeȱ Iȱ discussȱ theȱ detailsȱ ofȱ Cȱ statements,ȱ though,ȱ letȇsȱ reviewȱ theȱ differentȱ typefacesȱusedȱinȱsyntaxȱdescriptions.ȱCodeȱthatȱmustȱbeȱwrittenȱexactlyȱasȱshownȱisȱ setȱ inȱ Courier,ȱ whileȱ abstractȱ descriptionsȱ ofȱ codeȱ appearȱ inȱ Courier Italic.ȱ Someȱ statementsȱalsoȱhaveȱoptionalȱparts.ȱCodeȱthatȱyouȱmustȱwriteȱexactlyȱasȱshownȱifȱyouȱ decideȱtoȱuseȱtheȱoptionalȱpartȱisȱshownȱinȱ Courier Bold,ȱandȱdescriptionsȱofȱoptionalȱ partsȱ areȱ inȱ Courier Bold-Italic.ȱ Also,ȱ theȱ statementȱ syntaxȱ isȱ illustratedȱ withȱ theȱ sameȱindentationȱusedȱinȱtheȱprogramȱ examples.ȱThisȱspacingȱisȱ notȱ requiredȱ byȱ theȱ compilerȱbutȱisȱvaluableȱforȱhumanȱreadersȱ(suchȱasȱyourself).ȱ ȱ ȱ ȱ 4.1 Empty Statement ȱ TheȱsimplestȱstatementȱinȱCȱisȱtheȱemptyȱstatement,ȱwhichȱconsistsȱofȱaȱsemicolonȱallȱbyȱ itself.ȱ Theȱ emptyȱ statementȱ doesnȇtȱ performȱ anyȱ workȱ butȱ isȱ occasionallyȱ usefulȱ anyway.ȱItȱisȱusedȱinȱsituationsȱwhereȱtheȱsyntaxȱrequiresȱaȱstatement,ȱbutȱthereȱisn’tȱ anyȱworkȱtoȱbeȱperformed.ȱSomeȱofȱtheȱlaterȱexamplesȱinȱthisȱchapterȱincludeȱemptyȱ statements.ȱ Download at http://www.pin5i.com/ 72 Chapter 4 Statements 4.2 Expression Statement ȱ IfȱthereȱisȱnoȱȈassignmentȱstatementȈȱinȱC,ȱhowȱisȱassignmentȱperformed?ȱTheȱanswerȱ isȱ thatȱ assignmentȱ isȱ anȱ operationȱ justȱ likeȱ additionȱ andȱ subtraction,ȱ soȱ assignmentȱ isȱ performedȱbyȱwritingȱanȱexpression.ȱ Youȱcanȱturnȱanȱexpressionȱintoȱaȱstatementȱsimplyȱbyȱputtingȱaȱsemicolonȱatȱ theȱendȱofȱit.ȱThus,ȱstatementȱsuchȱasȱ ȱ x = y + 3; ch = getchar(); CAUTION! ȱ areȱreallyȱexpressionȱstatements,ȱnotȱassignmentȱstatements.ȱ ȱ Thisȱ distinctionȱ isȱ importantȱ toȱ understandȱ becauseȱ itȱ isȱ perfectlyȱ legalȱ toȱ writeȱ statementsȱsuchȱasȱthese:ȱ ȱ y + 3; getchar(); ȱ Whenȱtheseȱstatementsȱareȱexecuted,ȱtheȱexpressionsȱareȱevaluated,ȱbutȱtheȱresultsȱareȱ notȱ savedȱ anywhereȱ becauseȱ anȱ assignmentȱ operatorȱ wasȱ notȱ used.ȱ Theȱ firstȱ statementsȱ therefore,ȱ hasȱ noȱ effectȱ whatever,ȱ andȱ theȱ secondȱ statementȱ getsȱ theȱ nextȱ characterȱofȱinputȱbutȱthanȱignoresȱit. 22 Ifȱ itȱ seemsȱ strangeȱ thatȱ youȱ canȱ writeȱ statementsȱ thatȱ haveȱ noȱ effect,ȱ considerȱ thisȱone:ȱ ȱ printf( "Hello world!\n" ); ȱ printfȱisȱaȱfunctionȱandȱfunctionsȱreturnȱvalues,ȱyetȱtheȱvalueȱreturnedȱbyȱprintfȱ(theȱ numberȱofȱcharactersȱactuallyȱprinted)ȱisȱusuallyȱofȱnoȱconcernȱandȱthereforeȱignored.ȱ Theȱ statementȱ Ȉhasȱ noȱ effectȈȱ onlyȱ inȱ theȱ senseȱ thatȱ theȱ valueȱ ofȱ theȱ expressionȱ isȱ ignored;ȱtheȱprintfȱfunctionȱperformȱusefulȱwork.ȱSuchȱworkȱisȱcalledȱaȱsideȱeffect.ȱ Hereȱisȱanotherȱexample:ȱ ȱ a++; ȱ Thereȱ isȱ noȱ assignmentȱ operator,ȱ yetȱ itȱ isȱ aȱ perfectlyȱ reasonableȱ expressionȱ statement.ȱTheȱ ++ȱoperatorȱincrementsȱtheȱ variableȱaȱasȱ aȱsideȱeffect.ȱThereȱareȱ otherȱ operatorsȱwithȱsideȱeffects,ȱandȱIȱwillȱdiscussȱthemȱinȱtheȱnextȱchapter.ȱ ȱActually,ȱitȱcanȱaffectȱtheȱoutcomeȱofȱtheȱprogram,ȱbutȱhowȱitȱdoesȱsoȱisȱsoȱsubtleȱthatȱweȱmustȱwaitȱuntilȱChapterȱ18ȱandȱ ourȱdiscussionȱofȱtheȱruntimeȱenvironmentȱtoȱexplainȱit.ȱ 22 Download at http://www.pin5i.com/ 4.4 If Statement 73 4.3 Statement Blocks ȱ Aȱ blockȱ isȱ aȱ listȱ ofȱ declarationsȱ andȱ aȱ listȱ ofȱ statements,ȱ bothȱ optional,ȱ enclosedȱ inȱ braces.ȱTheȱsyntaxȱforȱaȱblockȱisȱstraightforward:ȱ ȱ { declarations statements } ȱ Aȱblockȱmayȱbeȱusedȱanywhereȱaȱstatementȱisȱrequired,ȱandȱitȱletsȱyouȱuseȱaȱlistȱ ofȱ statementsȱ inȱ placesȱ whereȱ theȱ syntaxȱ onlyȱ callsȱ forȱ one.ȱ Blocksȱ alsoȱ allowȱ youȱ toȱ declareȱdataȱveryȱcloseȱtoȱwhereȱitȱisȱused.ȱ ȱ ȱ ȱ 4.4 If Statement ȱ Theȱ ifȱ statementȱ inȱ Cȱ worksȱ prettyȱ muchȱ theȱ sameȱ asȱ thoseȱ inȱ otherȱ languages.ȱ Theȱ syntaxȱlooksȱlikeȱthis:ȱ ȱ if( expression ) statement else statement CAUTION! ȱ Theȱ parenthesesȱ areȱ partȱ ofȱ theȱ ifȱ statement,ȱ notȱ partȱ ofȱ theȱ expression,ȱ soȱ theyȱ areȱ requiredȱevenȱforȱsimpleȱexpressions.ȱȱ ȱ Eitherȱofȱtheȱ statementsȱmayȱbeȱaȱblockȱinstead.ȱAȱcommonȱerrorȱisȱtoȱforgetȱtoȱputȱinȱ theȱbracesȱwhenȱaddingȱaȱsecondȱstatementȱtoȱeitherȱclauseȱofȱanȱ ifȱstatement.ȱManyȱ programmersȱpreferȱtoȱuseȱtheȱbracesȱallȱtheȱtimeȱpreciselyȱtoȱavoidȱthisȱerror.ȱ Ifȱ theȱ expressionȱ isȱ true,ȱ thenȱ theȱ firstȱ statementȱ isȱ executed;ȱ otherwise,ȱ itȱ isȱ skipped.ȱ Ifȱ thereȱ isȱ anȱ elseȱ clause,ȱ thenȱ itsȱ statementȱ isȱ executedȱ onlyȱ whenȱ theȱ expressionȱisȱfalse.ȱ Thereȱ isȱ oneȱ differenceȱ betweenȱ Cȱ ifȱ statementsȱ andȱ ifȱ statementsȱ inȱ otherȱ languages.ȱCȱdoesnȇtȱhaveȱaȱBooleanȱtype;ȱintegersȱareȱusedȱforȱthisȱpurpose.ȱThus,ȱtheȱ expressionȱcanȱbeȱanyȱexpressionȱthatȱresultsȱinȱanȱintegerȱvalueȱ–ȱzeroȱmeansȱȈfalseȈȱ andȱallȱnonzeroȱvaluesȱmeanȱȈtrueȈ.ȱ Cȱhasȱallȱofȱtheȱrelationalȱoperatorsȱthatȱyouȱwouldȱexpect,ȱbutȱtheyȱproduceȱtheȱ integerȱ valuesȱ zeroȱ andȱ oneȱ ratherȱ thanȱ booleanȱ valuesȱ ȈtrueȈȱ andȱ Ȉfalse.Ȉȱ Thusȱ theȱ relationalȱoperatorsȱendȱupȱfunctioningȱtheȱsameȱasȱinȱotherȱlanguages.ȱ Download at http://www.pin5i.com/ 74 Chapter 4 Statements if( x > 3 ) printf( "Greater\n" ); else printf( "Not greater\n" ); ȱ evaluatesȱtheȱexpressionȱ x > 3,ȱwhichȱyieldsȱaȱvalueȱofȱeitherȱzeroȱorȱone.ȱIfȱtheȱvalueȱ isȱone,ȱGreaterȱisȱprinted;ȱifȱitȱisȱzero,ȱNot greaterȱisȱprinted.ȱȱ Integerȱvariablesȱcanȱalsoȱholdȱbooleanȱvalues,ȱasȱinȱthisȱexampleȱ ȱ result = x > 3; ... if( result ) printf( "Greater\n" ); else printf( "Not greater\n" ); ȱ Thisȱcodeȱfragmentȱexecutesȱexactlyȱtheȱsameȱasȱtheȱpreviousȱone;ȱtheȱonlyȱdifferenceȱ isȱ thatȱ theȱ resultȱ ofȱ theȱ comparison,ȱ whichȱ isȱ eitherȱ aȱ zeroȱ orȱ aȱ one,ȱ isȱ savedȱ inȱ aȱ variableȱandȱtestedȱlater.ȱThereȱisȱaȱpotentialȱtrapȱhere.ȱEvenȱthoughȱallȱnonzeroȱvaluesȱ areȱconsideredȱtrue,ȱcomparingȱoneȱnonzeroȱvalueȱtoȱaȱdifferentȱnonzeroȱvalueȱyieldsȱ false.ȱIȱdiscussȱthisȱproblemȱinȱmoreȱdetailȱinȱtheȱnextȱchapter.ȱȱ Whenȱ ifȱ statementsȱ areȱ nestedȱ withinȱ oneȱ another,ȱ theȱ danglingȱ elseȱ problemȱ canȱ appear.ȱ Forȱ example,ȱ toȱ whichȱ ifȱ statementȱ doesȱ theȱ elseȱ clauseȱ belongȱ inȱ theȱ followingȱfragment?ȱ ȱ if( i > 1 ) if( j > 2 ) printf( "i > 1 and j > 2\n" ); else printf( "no they're not\n" ); ȱ Theȱelseȱclauseȱisȱindentedȱstrangelyȱtoȱillustrateȱthisȱquestion.ȱTheȱanswer,ȱasȱinȱmostȱ otherȱlanguages,ȱisȱthatȱtheȱ elseȱclauseȱbelongsȱtoȱtheȱclosestȱ ifȱthatȱisȱincomplete.ȱIfȱ youȱwantȱitȱtoȱheȱassociatedȱwithȱanȱearlierȱifȱstatement,ȱyouȱmustȱcompleteȱtheȱcloserȱ ifȱeitherȱbyȱaddingȱanȱemptyȱelseȱtoȱitȱorȱbyȱenclosingȱitȱinȱaȱblockȱasȱinȱthisȱfragment.ȱ ȱ if( i > 1 ){ if( j > 2 ) printf( "i > 1 and j > 2\n" ); } else printf( "no they're not\n" ); Download at http://www.pin5i.com/ 4.5 While Statement 75 4.5 While Statement ȱ Theȱ whileȱstatementȱisȱalsoȱaȱlotȱlikeȱitsȱcounterpartȱinȱotherȱlanguages.ȱTheȱonlyȱrealȱ differenceȱisȱtheȱexpression,ȱwhichȱworksȱtheȱsameȱasȱinȱtheȱ ifȱstatement.ȱHereȱisȱtheȱ syntax.ȱ ȱ while( expression ) statement ȱ Theȱtestȱinȱthisȱloopȱisȱperformedȱbeforeȱtheȱbodyȱisȱexecuted,ȱsoȱifȱtheȱtestȱisȱinitiallyȱ false,ȱtheȱbodyȱwillȱnotȱbeȱexecutedȱatȱall.ȱAgain,ȱaȱblockȱmayȱbeȱusedȱifȱmoreȱthanȱoneȱ statementȱisȱneededȱforȱtheȱbodyȱofȱtheȱloop.ȱ ȱ ȱ ȱ 4.5.1 Break and Continue Statements ȱ Theȱ breakȱstatementȱmayȱbeȱusedȱinȱaȱ whileȱloopȱtoȱterminateȱtheȱloopȱprematurely.ȱ Afterȱ aȱ break,ȱ theȱ nextȱ statementȱ toȱ beȱ executedȱ isȱ theȱ oneȱ thatȱ wouldȱ haveȱ beenȱ performedȱhadȱtheȱloopȱterminatedȱnormally.ȱ Theȱ continueȱ statementȱ mayȱ beȱ usedȱ inȱ aȱ whileȱ loopȱ toȱ terminateȱ theȱ currentȱ iterationȱofȱtheȱloopȱprematurely.ȱAfterȱaȱ continue,ȱtheȱexpressionȱisȱevaluatedȱagainȱ toȱdetermineȱwhetherȱtheȱloopȱshouldȱexecuteȱagainȱorȱend.ȱ Ifȱ eitherȱ ofȱ theseȱ statementsȱ isȱ usedȱ withinȱ nestedȱ loops,ȱ itȱ appliesȱ onlyȱ toȱ innermostȱloop;ȱitȱisȱnotȱpossibleȱtoȱaffectȱtheȱexecutionȱofȱtheȱouterȱnestedȱloopȱwithȱaȱ breakȱorȱcontinue.ȱ ȱ ȱ ȱ 4.5.2 Execution of the While ȱ Weȱ canȱ nowȱ illustrateȱ theȱ flowȱ ofȱ controlȱ throughȱ aȱ whileȱ loop.ȱ Forȱ thoseȱ whoȱ haveȱ neverȱseenȱflowchartsȱbefore,ȱtheȱdiamondȱrepresentsȱaȱdecision,ȱtheȱboxȱrepresentsȱanȱ actionȱtoȱbeȱperformed,ȱandȱtheȱarrowsȱshowȱtheȱflowȱofȱcontrolȱbetweenȱthem.ȱFigureȱ 4.1ȱ showsȱ howȱ theȱ whileȱ statementȱ operates.ȱ Executionȱ beginsȱ atȱ theȱ top,ȱ whereȱ theȱ exprȱisȱevaluated.ȱIfȱitsȱvalueȱisȱzero,ȱtheȱloopȱterminates.ȱOtherwise,ȱtheȱbodyȱofȱtheȱ loopȱ (stmt)ȱ isȱ executedȱ andȱ controlȱ returnsȱ toȱ theȱ topȱ whereȱ theȱ wholeȱ thingȱ startsȱ again.ȱ Forȱ example,ȱ theȱ loopȱ belowȱ copiesȱ charactersȱ fromȱ theȱ standardȱ inputȱ toȱ theȱ standardȱoutputȱuntilȱtheȱendȱofȱfileȱindicationȱisȱfound.ȱ ȱ while( (ch = getchar()) != EOF ) putchar( ch ); ȱ Ifȱaȱcontinueȱstatementȱisȱexecutedȱinȱtheȱbodyȱofȱtheȱloop,ȱtheȱremainingȱstatementȱȱ Download at http://www.pin5i.com/ 76 Chapter 4 Statements == 0 expr != 0 break stmt continue ȱ ȱ Figureȱ4.1ȱExecutionȱofȱtheȱwhileȱstatementȱ ȱ ȱ ȱ inȱtheȱbodyȱareȱskippedȱandȱtheȱnextȱiterationȱbeginsȱimmediately.ȱ continueȱisȱusefulȱ inȱ situationsȱ whereȱ theȱ bodyȱ ofȱ theȱ loopȱ onlyȱ appliesȱ toȱ someȱ ofȱ theȱ valuesȱ thatȱ areȱ encountered.ȱ ȱ while( (ch = getchar()) != EOF ){ if( ch < '0' || ch > '9' ) continue; /* process only the digits */ } ȱ Theȱalternativeȱisȱtoȱinvertȱtheȱtestȱperformedȱinȱtheȱ ifȱandȱhaveȱitȱcontrolȱtheȱentireȱ bodyȱ ofȱ theȱ loop.ȱ Theȱ differenceȱ isȱ solelyȱ stylistic;ȱ thereȱ isȱ noȱ differenceȱ atȱ executionȱ time.ȱȱ Ifȱ aȱ breakȱ statementȱ isȱ executed,ȱ theȱ loopȱ exitsȱ immediately.ȱ Forȱ example,ȱ supposeȱaȱlistȱofȱvaluesȱtoȱbeȱprocessedȱisȱterminatedȱwithȱaȱnegativeȱnumber:ȱ ȱ while( scanf( "%f", &value ) == 1 ){ if( value < 0 ) break; /* process the nonnegative value */ } ȱ Anȱalternativeȱisȱtoȱincludeȱtheȱtestȱinȱtheȱwhileȱexpression,ȱlikeȱthis:ȱ ȱ while( scanf( "%f", &value ) == 1 && value >= 0 ){ Download at http://www.pin5i.com/ 4.6 For Statement 77 TIP Thisȱstyleȱmayȱbeȱdifficult,ȱhowever,ȱifȱsomeȱcomputationsȱmustȱbeȱperformedȱbeforeȱ theȱvalueȱcanȱbeȱtested.ȱȱ ȱ Occasionally,ȱ aȱ whileȱ statementȱ doesȱ allȱ theȱ workȱ inȱ itsȱ expression,ȱ andȱ thereȱ isȱ noȱ workȱleftȱforȱtheȱbody.ȱInȱthisȱcase,ȱtheȱemptyȱstatementȱisȱusedȱforȱtheȱbody.ȱItȱisȱgoodȱ practiceȱ toȱ writeȱ theȱ emptyȱ statementȱ onȱ aȱ lineȱ byȱ itself,ȱ asȱ illustratedȱ inȱ theȱ loopȱ below,ȱwhichȱdiscardsȱtheȱremainderȱofȱtheȱcurrentȱinputȱline.ȱȱ ȱ while( (ch = getchar()) != EOF && ch != '\n' ) ; ȱ Thisȱformȱclearlyȱshowsȱthatȱtheȱbodyȱofȱtheȱloopȱisȱempty,ȱmakingȱitȱlessȱlikelyȱthatȱ theȱ nextȱ statementȱ inȱ theȱ programȱ willȱ beȱ misinterpretedȱ byȱ aȱ humanȱ readerȱ asȱ theȱ bodyȱofȱtheȱloop.ȱ ȱ ȱ ȱ 4.6 For Statement ȱ Theȱ forȱstatementȱisȱmoreȱgeneralȱthanȱtheȱ forȱstatementsȱinȱotherȱlanguages.ȱInȱfact,ȱ theȱ forȱ statementȱ inȱ Cȱ isȱ reallyȱ justȱ aȱ shorthandȱ notationȱ forȱ aȱ veryȱ commonȱ arrangementȱofȱstatementsȱinȱaȱ whileȱloop.ȱTheȱsyntaxȱofȱtheȱ forȱstatementȱlooksȱlikeȱ this:ȱ ȱ for( expressions1; expresssion2; expression3 ) statement ȱ Theȱstatementȱisȱcalledȱtheȱbodyȱofȱtheȱloop.ȱexpression1 isȱtheȱinitializationȱandȱ isȱ evaluatedȱ onceȱ beforeȱ theȱ loopingȱ begins.ȱ expression2ȱ isȱ theȱ conditionȱ andȱ isȱ evaluatedȱ beforeȱ eachȱ executionȱ ofȱ theȱ body,ȱ justȱ asȱ inȱ aȱ whileȱ loop.ȱ expression3ȱ isȱ calledȱ theȱ adjustmentȱ andȱ isȱ evaluatedȱ afterȱ theȱ bodyȱ andȱ justȱ beforeȱ theȱ conditionȱ isȱ evaluatedȱ again.ȱ Allȱ threeȱ expressionsȱ areȱ optionalȱ andȱ mayȱ beȱ omitted.ȱ Aȱ missingȱ conditionȱmeansȱȈtrue.Ȉȱ Theȱbreakȱandȱcontinueȱstatementsȱalsoȱworkȱinȱaȱforȱloop.ȱbreakȱexitsȱtheȱloopȱ immediatelyȱ,ȱandȱcontinueȱgoesȱdirectlyȱtoȱtheȱadjustment.ȱ ȱ ȱ ȱ 4.6.1 Execution of a For ȱ Theȱ forȱ statementȱ isȱ executedȱ (almost)ȱ exactlyȱ theȱ sameȱ asȱ theȱ followingȱ whileȱ statement:ȱ Download at http://www.pin5i.com/ 78 Chapter 4 Statements expression1; while( expression2 ){ statement expression3; } TIP ȱ Figureȱ 4.2ȱ diagramsȱ theȱ executionȱ ofȱ theȱ forȱ statement.ȱ Canȱ youȱ seeȱ howȱ itȱ differsȱ fromȱaȱwhileȱloop?ȱ Theȱdifferenceȱbetweenȱtheȱ forȱandȱtheȱ whileȱloopsȱisȱwithȱcontinue.ȱInȱtheȱ forȱ statement,ȱ aȱ continueȱ skipsȱ theȱ nestȱ ofȱ theȱ bodyȱ ofȱ theȱ loopȱ andȱ goesȱ toȱ theȱ adjustment.ȱInȱtheȱ whileȱloop,ȱtheȱadjustmentȱisȱpartȱofȱtheȱbody,ȱsoȱaȱ continueȱskipsȱ it,ȱtoo.ȱȱ Aȱ stylisticȱ advantageȱ ofȱ theȱ forȱ loopȱ isȱ thatȱ itȱ collectsȱ allȱ ofȱ theȱ expressionsȱ thatȱ areȱ responsibleȱ forȱ theȱ operationȱ ofȱ theȱ loopȱ togetherȱ inȱ oneȱ placeȱ soȱ theyȱ areȱ easierȱ toȱ find,ȱ especiallyȱ whenȱ theȱ bodyȱ ofȱ theȱ loopȱ isȱ large.ȱ Forȱ example,ȱ theȱ followingȱ loopȱ initializesȱtheȱelementsȱofȱanȱarrayȱtoȱzero.ȱ ȱ for( i = 0; i < MAX_SIZE; i += 1 ) array[i] = 0; ȱ Theȱfollowingȱwhileȱloopȱperformsȱtheȱsameȱtask,ȱbutȱyouȱmustȱlookȱinȱthreeȱdifferentȱ placesȱtoȱdetermineȱhowȱtheȱloopȱoperates.ȱ ȱ expr1 == 0 expr2 != 0 break stmt expr3 continue ȱ ȱ Figureȱ4.2ȱExecutionȱofȱtheȱforȱstatementȱ Download at http://www.pin5i.com/ 4.7 Do Statement 79 i = 0; while( i < MAX_SIZE ){ array[i] = 0; i += 1; } ȱ ȱ ȱ 4.7 Do statement ȱ TheȱCȱ doȱstatementȱisȱveryȱmuchȱlikeȱtheȱrepeatȱstatementȱfoundȱinȱotherȱlanguages.ȱitȱ behavesȱ justȱ likeȱ aȱ whileȱ statementȱ exceptȱ thatȱ theȱ testȱ isȱ madeȱ afterȱ theȱ bodyȱ isȱ executedȱratherȱthanȱbefore,ȱsoȱtheȱbodyȱofȱtheȱloopȱisȱalwaysȱexecutedȱatȱleastȱonce.ȱ Hereȱisȱitsȱsyntax.ȱ ȱ do statement while( expression ); ȱ Asȱusual,ȱaȱblockȱmayȱbeȱusedȱifȱmultipleȱstatementsȱareȱneededȱinȱtheȱbody.ȱFigureȱ 4.3ȱshowsȱhowȱexecutionȱflowsȱaȱdoȱstatementȱ ȱ Howȱdoȱyouȱchooseȱbetweenȱaȱwhileȱandȱaȱdo?ȱ ȱ Whenȱyouȱneedȱtheȱbodyȱofȱtheȱloopȱtoȱbeȱexecutedȱatȱleastȱonce,ȱuseȱaȱdo.ȱ ȱ ȱ break stmt expr continue != 0 == 0 ȱ ȱ Figureȱ4.3ȱExecutionȱofȱtheȱdoȱstatementȱ Download at http://www.pin5i.com/ 80 Chapter 4 Statements Theȱloopȱbelow,ȱwhichȱprintsȱfromȱoneȱtoȱeightȱspacesȱtoȱadvanceȱtoȱtheȱnextȱtabȱstopȱ (setȱeveryȱeightȱcolumns),ȱillustratesȱthis.ȱ ȱ do { column += 1; putchar( ' ' ); } while( column % 8 != 0 ); ȱ ȱ ȱ 4.8 Switch Statement ȱ Theȱ switchȱ statementȱ inȱ Cȱ isȱ aȱ littleȱ unusual.ȱ Itȱ servesȱ theȱ sameȱ roleȱ asȱ theȱ caseȱ statementȱ inȱ otherȱ languages,ȱ butȱ itȱ isȱ differentȱ inȱ oneȱ veryȱ importantȱ respect.ȱ Letȇsȱ lookȱatȱtheȱsyntaxȱfirst.ȱTheȱexpressionȱmustȱproduceȱanȱintegerȱvalue.ȱ ȱ switch( expression ) statement ȱ Althoughȱ itȱ isȱ legalȱ toȱ writeȱ aȱ switchȱ statementȱ withȱ onlyȱ aȱ singleȱ statementȱ asȱ itsȱ body,ȱthereȱisȱnoȱpointȱinȱdoingȱso.ȱPracticalȱswitchȱstatementsȱlookȱlikeȱthisȱone:ȱ ȱ switch( expression ){ statement-list } ȱ Sprinkledȱthroughoutȱtheȱstatementȱlistȱareȱoneȱorȱmoreȱcaseȱlabelsȱofȱtheȱformȱ ȱ case constant-expression: CAUTION! ȱ Eachȱcaseȱlabelȱmustȱhaveȱaȱuniqueȱvalue.ȱAȱconstantȱexpressionȱisȱanȱexpressionȱthatȱisȱ evaluatedȱ atȱ compileȱ time;ȱ itȱ mayȱ notȱ containȱ anyȱ variables.ȱ Whatȱ isȱ unusualȱ isȱ thatȱ theȱcaseȱlabelsȱdoȱnotȱpartitionȱtheȱstatementȱlistȱintoȱseparateȱsections;ȱtheyȱidentifyȱ entryȱpointsȱintoȱtheȱlistȱofȱstatements.ȱ Let’sȱfollowȱtheȱexecutionȱofȱthisȱstatement.ȱFirst,ȱtheȱ expressionȱisȱevaluated.ȱ Then,ȱ executionȱ goesȱ toȱ theȱ statementȱ inȱ theȱ listȱ thatȱ isȱ identifiedȱ byȱ theȱ caseȱ labelȱ whoseȱvalueȱmatchesȱtheȱexpressionȇsȱvalue.ȱFromȱhere,ȱtheȱstatementȱlistȱisȱexecutedȱ allȱtheȱwayȱtoȱitsȱend,ȱwhichȱisȱatȱtheȱbottomȱofȱtheȱswitchȱstatement.ȱ ȱ ȱ ȱ ȱ Doȱyouȱseeȱtheȱdifferenceȱinȱtheȱexecutionȱofȱtheȱ switch?ȱExecutionȱflowsȱthroughȱcaseȱ labelsȱratherȱthanȱstoppingȱatȱthem,ȱwhichȱisȱwhyȱcaseȱlabelsȱidentifyȱentryȱpointsȱtoȱ Download at http://www.pin5i.com/ 4.8 Switch Statement 81 theȱstatementȱlistȱratherȱthanȱpartitioningȱit.ȱIfȱthisȱbehaviorȱdoesn’tȱseemȱright,ȱthereȱ isȱaȱwayȱtoȱfixȱit—theȱbreakȱstatement.ȱ ȱ ȱ ȱ 4.8.1 break in a switch ȱ Ifȱaȱbreakȱisȱencounteredȱinȱaȱswitchȱstatement,ȱexecutionȱproceedsȱimmediatelyȱtoȱtheȱ endȱ ofȱ theȱ statementȱ list.ȱ Thus,ȱ 97%ȱ ofȱ allȱ switchȱ statementsȱ inȱ Cȱ haveȱ breakȱ statementsȱatȱtheȱendȱofȱeachȱcase.ȱTheȱfollowingȱexample,ȱwhichȱexaminesȱaȱcharacterȱ enteredȱbyȱtheȱuserȱandȱinvokesȱtheȱfunctionȱthatȱitȱselects,ȱillustratesȱthisȱusage.ȱ ȱ switch( command ){ case 'A': add_entry(); break; case 'D': delete_entry(); break; case 'P': print_entry(); break; case 'E': edit_entry(); break; } ȱ Inȱeffect,ȱtheȱ breakȱstatementsȱpartitionȱtheȱstatementȱlistȱsoȱthatȱtheȱswitchȱwillȱworkȱ inȱtheȱmoreȱtraditionalȱmanner.ȱ Whatȱ isȱ theȱ purposeȱ ofȱ theȱ breakȱ inȱ theȱ lastȱ caseȱ ofȱ theȱ statement?ȱ Itȱ hasȱ noȱ effectȱatȱrunȱtime,ȱbecauseȱthereȱarenȇtȱanyȱ moreȱstatementsȱinȱtheȱswitch,ȱbutȱitȱalsoȱ doesnȇtȱ hurtȱ anything.ȱ Thisȱ breakȱ isȱ thereȱ forȱ futureȱ maintenance.ȱ Shouldȱ someoneȱ decideȱ laterȱ toȱ addȱ anotherȱ caseȱ toȱ thisȱ statement,ȱ thereȱ isȱ noȱ chanceȱ thatȱ theyȱ willȱ forgetȱtoȱaddȱaȱbreakȱatȱtheȱendȱofȱtheȱstatementsȱforȱtheȱpreviousȱcase.ȱ Theȱ continueȱhasȱnoȱeffectȱinȱaȱ switchȱstatement.ȱYouȱmayȱputȱaȱ continueȱinȱaȱ switchȱstatementȱonlyȱifȱtheȱ switchȱisȱenclosedȱbyȱaȱloop;ȱtheȱ continueȱappliesȱtoȱtheȱ loopȱratherȱthanȱtheȱswitch.ȱ Download at http://www.pin5i.com/ 82 Chapter 4 Statements Inȱ orderȱ toȱ executeȱ theȱ sameȱ groupȱ ofȱ statementsȱ withȱ twoȱ orȱ moreȱ values,ȱ multipleȱcaseȱlabelsȱareȱgiven,ȱasȱinȱthisȱexample.ȱ ȱ switch( expression ){ case 1: case 2: case 3: statement-list break; case 4: case 5: statement-list break; } ȱ Thisȱtechniqueȱworksȱbecauseȱexecutionȱflowsȱthroughȱtheȱcaseȱlabels.ȱCȱdoesȱnotȱhaveȱ anyȱshorthandȱnotationȱforȱspecifyingȱrangesȱofȱvalues,ȱsoȱeveryȱvalueȱinȱaȱrangeȱmustȱ beȱgivenȱasȱaȱseparateȱcaseȱlabel.ȱIfȱtheȱrangeȱofȱvaluesȱisȱlarge,ȱyouȱmayȱpreferȱaȱseriesȱ ofȱnestedȱifȱstatementsȱinstead.ȱ ȱ ȱ ȱ 4.8.2 Defaults ȱ Theȱnextȱquestionȱis,ȱwhatȱhappensȱifȱtheȱexpressionȇsȱvalueȱdoesȱnotȱmatchȱanyȱofȱtheȱ caseȱ labels?ȱ Nothingȱ atȱ all—theȱ statementȱ listȱ isȱ skippedȱ entirely.ȱ Theȱ programȱ doesȱ notȱ abortȱ orȱ giveȱ anyȱ indicationȱ ofȱ errorȱ becauseȱ thisȱ situationȱ isȱ notȱ consideredȱ anȱ errorȱinȱC.ȱȱ Whatȱifȱyouȱdon’tȱwantȱtoȱignoreȱexpressionȱvaluesȱthatȱdoȱnotȱmatchȱanyȱeaseȱ labels?ȱYouȱcanȱaddȱaȱdefaultȱclauseȱtoȱtheȱstatementȱlistȱbyȱwritingȱ ȱ default: TIP ȱ inȱ placeȱ ofȱ aȱ caseȱ label.ȱ Theȱ defaultȱ clauseȱ isȱ whereȱ executionȱ ofȱ theȱ statementȱ listȱ beginsȱwhenȱtheȱexpressionȱvalueȱdoesȱnotȱmatchȱanyȱofȱtheȱeaseȱlabels,ȱsoȱthereȱcanȱ beȱonlyȱoneȱofȱthem.ȱHowever,ȱitȱcanȱgoȱanywhereȱinȱtheȱstatementȱlist,ȱandȱexecutionȱ flowsȱthroughȱtheȱdefaultȱtheȱsameȱasȱaȱcaseȱlabel.ȱ ȱ Itȱ isȱ goodȱ practiceȱ toȱ useȱ aȱ defaultȱ clauseȱ inȱ everyȱ switchȱ statementȱ soȱ thatȱ illegalȱ valuesȱcanȱbeȱdetected.ȱOtherwiseȱtheȱprogramȱwillȱcontinueȱtoȱrunȱwithȱnoȱindicationȱ thatȱanȱerrorȱoccurred.ȱTheȱonlyȱreasonableȱexceptionsȱtoȱthisȱruleȱareȱwhenȱtheȱvalueȱ beingȱtestedȱhasȱbeenȱcheckedȱforȱvalidityȱearlier,ȱandȱwhenȱyouȱareȱonlyȱinterestedȱinȱ aȱsubsetȱofȱtheȱpossibleȱvalues.ȱ Download at http://www.pin5i.com/ 4.8 Switch Statement 83 4.8.3 Execution of the Switch ȱ Whyȱisȱtheȱswitchȱstatementȱimplementedȱinȱthisȱmanner?ȱManyȱprogrammersȱthinkȱ thatȱ itȱwasȱaȱmistake,ȱbutȱonceȱinȱaȱblueȱmoonȱitȱisȱ usefulȱ toȱ haveȱ controlȱ flowȱ fromȱ oneȱstatementȱgroupȱintoȱtheȱnext.ȱ Forȱexample,ȱconsiderȱaȱprogramȱthatȱcountsȱtheȱnumberȱofȱcharacters,ȱwords,ȱ andȱ linesȱ inȱ itsȱ input.ȱ Eachȱ characterȱ mustȱ beȱ counted,ȱ butȱ spaceȱ andȱ tabȱ charactersȱ alsoȱterminateȱwhateverȱwordȱtheyȱfollowed,ȱsoȱforȱthem,ȱbothȱtheȱcharacterȱcountȱandȱ theȱ wordȱ countȱ mustȱ beȱ incremented.ȱ Thenȱ thereȱ isȱ theȱ newline;ȱ thisȱ characterȱ terminatesȱaȱlineȱandȱaȱword,ȱsoȱthereȱareȱthreeȱcountersȱtoȱadjustȱforȱaȱnewline.ȱNowȱ examineȱthisȱstatement:ȱ ȱ switch( ch ){ case '\n': lines += 1; /* FALL THRU */ case ' ': case'\t': words += 1; /* FALL THRU */ default: chars += 1; } ȱ ȱ Theȱlogicȱisȱsimplerȱthanȱwhatȱwouldȱappearȱinȱaȱrealȱprogram,ȱforȱexample,ȱonlyȱtheȱ firstȱofȱaȱsequenceȱofȱspacesȱterminatesȱtheȱprecedingȱword.ȱNevertheless,ȱtheȱexampleȱ doesȱwhatȱweȱwant:ȱnewlinesȱcauseȱallȱthreeȱcountersȱtoȱbeȱincremented,ȱspacesȱandȱ tabsȱincrementȱonlyȱtwo,ȱandȱeverythingȱelseȱincrementsȱonlyȱtheȱcharacterȱcounter.ȱ ȱ TheȱFALL THRUȱcommentsȱmakeȱitȱclearȱtoȱtheȱreaderȱthatȱexecutionȱisȱsupposedȱ toȱ fallȱ throughȱ theȱ caseȱ labels.ȱ Withoutȱ theȱ comments,ȱ aȱ carelessȱ maintenanceȱ programmerȱ lookingȱ forȱ aȱ bugȱ mightȱ noticeȱ theȱ lackȱ ofȱ breakȱ statementsȱ andȱ decideȱ thatȱthisȱomissionȱisȱtheȱerrorȱandȱnotȱlookȱanyȱfurther.ȱAfterȱall,ȱitȱisȱsoȱrareȱthatȱyouȱ actuallyȱwantȱexecutionȱtoȱflowȱthroughȱtheȱcaseȱlabelsȱthatȱaȱmissingȱ breakȱstatementȱ isȱmuchȱmoreȱlikelyȱtoȱbeȱanȱerrorȱthanȱnot.ȱButȱinȱȈfixingȈȱthisȱproblem,ȱheȱwouldȱnotȱ onlyȱhaveȱmissedȱtheȱbugȱheȱwasȱoriginallyȱlookingȱfor,ȱbutȱheȱwouldȱhaveȱintroducedȱ aȱnewȱoneȱasȱwell.ȱTheȱsmallȱeffortȱofȱwritingȱtheseȱcommentsȱnowȱmightȱpayȱoffȱinȱaȱ lotȱofȱtimeȱsavedȱlater.ȱ Download at http://www.pin5i.com/ 84 Chapter 4 Statements 4.9 Goto Statement ȱ Lastly,ȱthereȱisȱtheȱgotoȱstatement,ȱwhichȱhasȱthisȱsyntax.ȱ ȱ goto statement-label; ȱ Toȱuseȱit,ȱyouȱmustȱputȱstatementȱlabelsȱbeforeȱeachȱstatementȱtoȱwhichȱyouȱwishȱtoȱgo.ȱ Statementȱlabelsȱareȱidentifiersȱfollowedȱbyȱaȱcolon.ȱgotoȱstatementsȱthatȱincludeȱtheseȱ labelsȱmayȱthenȱbeȱplacedȱanywhereȱinȱtheȱsameȱfunction.ȱ ȱ Theȱ gotoȱ isȱ aȱ dangerousȱ statement,ȱ becauseȱ whenȱ learningȱ Cȱ itȱ isȱ tooȱ easyȱ toȱ becomeȱdependentȱonȱit.ȱInexperiencedȱprogrammersȱsometimesȱuseȱ gotoȇsȱasȱaȱwayȱ toȱ avoidȱ thinkingȱ aboutȱ theȱ programȇsȱ design.ȱ Theȱ resultingȱ programsȱ areȱ nearlyȱ alwaysȱmoreȱdifficultȱtoȱmaintainȱthanȱcarefullyȱdesignedȱones.ȱForȱexample,ȱhereȱisȱaȱ programȱthatȱusesȱgotoȇsȱtoȱperformȱanȱexchangeȱsortȱofȱtheȱvaluesȱinȱanȱarray.ȱ ȱ ȱ ȱ i = 0; outer_next: if( i >= NUM_ELEMENTS – 1 ) goto outer_end; j = i + 1; inner_next: if( j >= NUM_ELEMENTS ) goto inner_end; if( value[i] <= value[j] ) goto no_swap; temp = value[i]; value[i] = value[j]; value[j] = temp; no_swap: j += 1; goto inner_next; inner_end: i += 1; goto outer_next; outer_end: ; ȱ Thisȱisȱaȱtinyȱprogram,ȱyetȱyouȱmustȱspendȱaȱconsiderableȱamountȱofȱtimeȱstudyingȱitȱ toȱunderstandȱitsȱstructure.ȱȱ ȱ Hereȱisȱtheȱsameȱprogramȱwithoutȱgoto’s.ȱItsȱstructureȱisȱmuchȱeasierȱtoȱsee.ȱ ȱ Download at http://www.pin5i.com/ 4.9 Goto Statement 85 for( i = 0; i < NUM_ELEMENTS – 1; i += 1 ){ for( j = i + 1; j < NUM_ELEMENTS; j += 1 ){ if( value[i] > value[j] ){ temp = value[i]; value[i] = value[j]; value[j] = temp; } } } ȱ ȱ However,ȱ thereȱ isȱ oneȱ situationȱ inȱ whichȱ manyȱ claimȱ thatȱ aȱ gotoȱ mightȱ beȱ appropriateȱinȱaȱwellȱstructuredȱprogram—breakingȱoutȱofȱnestedȱloops.ȱBecauseȱtheȱ breakȱ statementȱ onlyȱ affectsȱ theȱ innermostȱ loopȱ thatȱ enclosesȱ it,ȱ theȱ onlyȱ wayȱ toȱ immediatelyȱexitȱaȱdeeplyȱnestedȱsetȱofȱloopsȱisȱwithȱaȱgoto,ȱasȱshownȱinȱthisȱexample.ȱ ȱ while( condition1 ){ while( condition2 ){ while( condition3 ){ if( someȱdisasterȱ) goto quit; } } } quit: ; ȱ ȱ Thereȱ areȱtwoȱalternativesȱtoȱ usingȱ aȱgoto.ȱ First,ȱ aȱ statusȱ flagȱ canȱ beȱsetȱ whenȱ youȱwantȱtoȱexitȱallȱofȱtheȱloops,ȱbutȱtheȱflagȱmustȱthenȱbeȱtestedȱinȱeveryȱloop:ȱ enum { EXIT, OK } status; ... status = OK; while( status == OK && condition1 ){ while( status == OK && condition2 ){ while( condition3 ){ if( someȱdisasterȱ){ status = EXIT; break; } } } } Download at http://www.pin5i.com/ 86 Chapter 4 Statements Thisȱ techniqueȱ doesȱ theȱ jobȱ butȱ makesȱ theȱ conditionsȱ moreȱ complex.ȱ Theȱ secondȱ alternativeȱisȱtoȱputȱtheȱentireȱsetȱofȱloopsȱinȱaȱseparateȱfunction.ȱWhenȱdisasterȱstrikesȱ inȱtheȱinnermostȱloop,ȱyouȱcanȱuseȱaȱ returnȱstatementȱtoȱleaveȱtheȱfunction.ȱChapterȱ7ȱ discussesȱreturnȱstatements.ȱ ȱ ȱ ȱ 4.10 Summary ȱ ManyȱofȱtheȱstatementsȱinȱCȱbehaveȱtheȱsameȱasȱtheirȱcounterpartsȱinȱotherȱlanguages.ȱ Theȱ ifȱ statementȱ conditionallyȱ executesȱ statements,ȱ andȱ theȱ whileȱ statementȱ repeatedlyȱexecutesȱstatements.ȱBecauseȱCȱdoesȱnotȱhaveȱaȱbooleanȱtype,ȱbothȱofȱtheseȱ statementsȱ testȱ anȱ integerȱ expressionȱ instead.ȱ Theȱ valueȱ zeroȱ isȱ interpretedȱ asȱ false,ȱ andȱnonzeroȱvaluesȱareȱinterpretedȱasȱtrue.ȱTheȱ forȱstatementȱisȱaȱshorthandȱnotationȱ forȱ aȱ whileȱ loop;ȱ itȱ collectsȱ theȱ expressionsȱ thatȱ controlȱ theȱ loopȱ inȱ oneȱ placeȱ soȱ thatȱ theyȱareȱeasyȱtoȱfind.ȱTheȱdoȱstatementȱisȱsimilarȱtoȱaȱwhile,ȱbutȱdoȱguaranteesȱthatȱtheȱ bodyȱofȱtheȱloopȱisȱalwaysȱexecutedȱatȱleastȱonce.ȱFinally,ȱtheȱ gotoȱstatementȱtransfersȱ executionȱfromȱoneȱstatementȱtoȱanother.ȱInȱgeneral,ȱgotoȱshouldȱbeȱavoided.ȱ Cȱ alsoȱ hasȱ someȱ statementsȱ thatȱ behaveȱ aȱ littleȱ differentlyȱ thanȱ theirȱ counterpartsȱ inȱ otherȱ languages.ȱ Assignmentȱ isȱ doneȱ withȱ anȱ expressionȱ statementȱ ratherȱ thanȱ anȱ assignmentȱ statement.ȱ Theȱ switchȱ statementȱ performsȱ theȱ jobȱ ofȱ theȱ caseȱstatementȱinȱotherȱlanguages,ȱbutȱexecutionȱinȱaȱ switchȱpassesȱthroughȱtheȱcaseȱ labelsȱ toȱ theȱ endȱ ofȱ theȱ switch.ȱ Toȱ preventȱ thisȱ behavior,ȱ youȱ mustȱ putȱ aȱ breakȱ statementȱatȱtheȱendȱofȱtheȱstatementsȱforȱeachȱcase.ȱAȱdefault:ȱclauseȱinȱaȱswitchȱwillȱ catchȱ expressionsȱ whoseȱ valuesȱ doȱ notȱ matchȱ anyȱ ofȱ theȱ givenȱ caseȱ values.ȱ Inȱ theȱ absenceȱofȱaȱdefault,ȱtheȱbodyȱofȱtheȱswitchȱisȱskippedȱifȱnoneȱofȱtheȱcaseȱlabelsȱmatchȱ theȱexpressionsȱvalue.ȱ Theȱemptyȱstatementȱisȱusedȱwhenȱaȱstatementȱisȱrequiredȱbutȱthereȱisȱnoȱworkȱ needed.ȱ Statementȱ blocksȱ allowȱ youȱ toȱ writeȱ manyȱ statementsȱ inȱ placesȱ whereȱ theȱ syntaxȱ callsȱ forȱ aȱ singleȱ statement.ȱ Whenȱ aȱ breakȱ statementȱ isȱ executedȱ insideȱ ofȱ aȱ loop,ȱitȱterminatesȱtheȱloop.ȱWhenȱaȱ continueȱstatementȱisȱexecutedȱinsideȱofȱaȱloop,ȱ theȱ remainderȱ ofȱ theȱ bodyȱ isȱ skippedȱ andȱ theȱ nextȱ iterationȱ ofȱ theȱ loopȱ beginsȱ immediately.ȱInȱ whileȱandȱ doȱloops,ȱtheȱnextȱiterationȱbeginsȱwithȱtheȱtest,ȱbutȱinȱ forȱ loops,ȱtheȱnextȱiterationȱbeginsȱwithȱtheȱadjustment.ȱ Andȱthatȇsȱit!ȱCȱdoesȱnotȱhaveȱanyȱinput/outputȱstatements;ȱI/Oȱisȱperformedȱbyȱ callingȱ libraryȱ functions.ȱ Norȱ doesȱ itȱ haveȱ anyȱ exceptionȱ handlingȱ statements;ȱ theseȱ areȱalsoȱdoneȱwithȱlibraryȱfunctions.ȱ ȱ ȱ ȱ ȱ Download at http://www.pin5i.com/ 4.13 Questions 87 4.11 Summary of Cautions ȱ 1. Writingȱexpressionsȱthatȱhaveȱnoȱresultȱ(pageȱ72).ȱ 2. Beȱsureȱtoȱuseȱbracesȱaroundȱstatementȱlistȱinȱanȱifȱstatementȱ(pageȱ73).ȱ 3. Executionȱflowingȱunexpectedlyȱfromȱoneȱ caseȱofȱaȱ switchȱstatementȱintoȱtheȱnextȱ (pageȱ81).ȱ ȱ ȱ ȱ 4.12 Summary of Programming Tips ȱ 1. Inȱaȱloopȱwithoutȱaȱbody,ȱputȱtheȱsemicolonȱforȱtheȱemptyȱstatementȱonȱaȱlineȱbyȱ itselfȱ(pageȱ77.)ȱ 2. Itȱisȱeasierȱtoȱreadȱ forȱloopsȱthanȱ whileȱloopsȱbecauseȱtheȱexpressionsȱthatȱcontrolȱ theȱloopȱareȱallȱtogetherȱ(pageȱ78).ȱ 3. Useȱaȱdefault:ȱclauseȱinȱeveryȱswitchȱstatementȱ(pageȱ82).ȱ ȱ ȱ ȱ 4.13 Questions ȱ 1. Isȱtheȱfollowingȱstatementȱlegal?ȱIfȱso,ȱwhatȱdoesȱitȱdo?ȱ ȱ 3 * x * x – 4 * x + 6; ȱ 2. Whatȱisȱtheȱsyntaxȱofȱtheȱassignmentȱstatement?ȱ 3. Isȱitȱlegalȱtoȱuseȱaȱblockȱinȱthisȱmanner?ȱIfȱso,ȱwhyȱwouldȱyouȱeverȱwantȱtoȱuseȱit?ȱ ȱ ... statement { statement statement } statement 4. Howȱ wouldȱ youȱ writeȱ anȱ ifȱ statementȱ thatȱ hadȱ noȱ statementsȱ inȱ theȱ thenȱ clauseȱ butȱhadȱstatementsȱinȱtheȱ elseȱclause?ȱHowȱelse,ȱcouldȱanȱequivalentȱstatementȱbeȱ written?ȱ 5. Whatȱoutputȱisȱproducedȱfromȱtheȱloopȱbelow?ȱ int i; Download at http://www.pin5i.com/ 88 Chapter 4 Statements ... for( i = 0; i < 10; i += 1 ) printf( "%d\n", i ); 6. Whenȱmightȱaȱwhileȱstatementȱbeȱmoreȱappropriateȱthanȱaȱforȱstatement?ȱ 7. Theȱcodeȱfragmentȱbelowȱisȱsupposedȱtoȱcopyȱtheȱstandardȱinputȱtoȱtheȱstandardȱ outputȱandȱcomputeȱaȱchecksumȱofȱtheȱcharacters.ȱWhatȱisȱwrongȱwithȱit?ȱ while( (ch = getchar()) != EOF ) checksum += ch; putchar( ch ); printf( "Checksum = %d\n", checksum ); 8. Whenȱisȱtheȱdoȱstatementȱmoreȱappropriateȱthanȱaȱwhileȱorȱaȱforȱstatement?ȱ 9. Whatȱoutputȱisȱproducedȱfromȱthisȱcodeȱfragment?ȱNote:ȱTheȱ%ȱoperatorȱdividesȱitsȱ leftȱoperandȱbyȱitsȱrightȱoperandȱandȱgivesȱyouȱtheȱremainder.ȱ for( i = 1; i <= 4; i += 1 ){ switch( i % 2 ){ case 0: printf( "even\n" ); case 1: printf( "odd\n" ); } } 10. Writeȱstatementsȱthatȱreadȱanȱintegerȱvalueȱfromȱtheȱstandardȱinputȱandȱthenȱprintȱ thatȱmanyȱblankȱlines.ȱ 11. Writeȱ statementsȱ toȱ validateȱ andȱ reportȱ onȱ someȱ valuesȱ thatȱ haveȱ alreadyȱ beenȱ read.ȱIfȱxȱisȱlessȱthanȱy,ȱprintȱtheȱwordȱWRONG.ȱAlso,ȱifȱaȱisȱgreaterȱthanȱorȱequalȱtoȱb,ȱ printȱ WRONG.ȱ Otherwise,ȱ printȱ theȱ wordȱ RIGHT.ȱ Note:ȱ Inȱ caseȱ youȱ needȱ it,ȱ ||ȱ isȱ theȱ ȈorȈȱoperator.ȱ 12. Yearsȱthatȱareȱdivisibleȱbyȱfourȱareȱleapȱyears,ȱexcept,ȱthatȱyearsȱthatȱareȱdivisibleȱ byȱ 100ȱ areȱ not.ȱ However,ȱ yearsȱ thatȱ areȱ divisibleȱ byȱ 400ȱ areȱ leapȱ years.ȱ Writeȱ statementsȱ toȱ determineȱ whetherȱ theȱ valueȱ inȱ yearȱ isȱ aȱ leapȱ year,ȱ andȱ setȱ theȱ variableȱleap_yeasȱtoȱoneȱifȱitȱisȱaȱleapȱyear,ȱandȱzeroȱifȱitȱisȱnot.ȱ 13. Newspaperȱreportersȱareȱtrainedȱtoȱaskȱwho,ȱwhat,ȱwhen,ȱwhere,ȱandȱwhy?ȱWriteȱ statementsȱthatȱwillȱprintȱwhoȱifȱtheȱvariableȱwhich_wordȱisȱone,ȱwhat if the ȱ ȱ variableȱisȱtwo,ȱandȱsoȱforth.ȱIfȱtheȱvalueȱisȱnotȱinȱtheȱrangeȱoneȱthroughȱfive,ȱprintȱ don’t knowȱinstead.ȱ 14. Pretendȱ thatȱ aȱ ȈprogramȈȱ controlsȱ you,ȱ andȱ thisȱ programȱ containsȱ twoȱ function:ȱ eat_hamburger()ȱmakesȱyouȱeatȱaȱhamburger,ȱandȱ hunger()ȱreturnsȱaȱtrueȱorȱfalseȱ Download at http://www.pin5i.com/ 4.14 Programming Exercises 89 valueȱdependingȱonȱwhetherȱyouȱareȱhungry.ȱWriteȱtheȱstatementȱthatȱallowȱyouȱtoȱ eatȱasȱmanyȱhamburgersȱasȱyouȱwantȱuntilȱyouȇreȱnoȱlongerȱhungry.ȱ 15. Modifyȱyourȱanswerȱtoȱquestionȱ14ȱtoȱsatisfyȱyourȱgrandmother—Youȇveȱgotȱtoȱeatȱ something!—soȱthatȱyouȱalwaysȱeatȱatȱleastȱoneȱhamburger.ȱ 16. Writeȱ statementsȱtoȱ printȱaȱ capsuleȱ summaryȱofȱtheȱcurrentȱ weatherȱaccordingȱtoȱ theȱvaluesȱofȱtheȱvariablesȱprecipitatingȱandȱtemperature.ȱ ȱ Ifȱprecipitatingȱisȱ…ȱ andȱtemperatureȱisȱ…ȱ thenȱprintȱ…ȱ snowing <ȱ32ȱ trueȱ raining >=ȱ32ȱ cold <ȱ60ȱ falseȱ warm >=ȱ60ȱ ȱ ȱ ȱ ȱ 4.14 Programming Exercises ȱ 1. Theȱ squareȱ rootȱ ofȱ aȱ positiveȱ numberȱ nȱ canȱ beȱ computedȱ asȱ aȱ seriesȱ ofȱ approximations,ȱ eachȱ moreȱ accurateȱ thanȱ theȱ last.ȱ Theȱ firstȱ approximationȱ isȱ one;ȱ successiveȱapproximationsȱareȱgivenȱbyȱtheȱfollowingȱformula.ȱ ȱ n ai ai ai 1 2 ȱ ȱ Writeȱaȱprogramȱtoȱreadȱaȱvalueȱandȱcomputeȱandȱprintȱitsȱsquareȱroot.ȱlfȱyouȱprintȱ allȱ ofȱ theȱ approximationsȱ youȱ canȱ seeȱ howȱ quicklyȱ thisȱ methodȱ convergesȱ onȱ theȱ correctȱvalue.ȱInȱprinciple,ȱtheȱcomputationȱcouldȱgoȱonȱforever,ȱyieldingȱmoreȱandȱ moreȱaccurateȱvalues.ȱInȱpractice,ȱthough,ȱtheȱrestrictedȱprecisionȱofȱfloatingȬpointȱ variablesȱ preventsȱ theȱ programȱ fromȱ continuing.ȱ Haveȱ yourȱ programȱ stopȱ computingȱwhenȱanȱapproximationȱisȱequalȱtoȱtheȱpreviousȱone.ȱ 2. Anȱ integerȱ isȱ calledȱ primeȱ ifȱ itȱ isȱ notȱ evenlyȱ divisibleȱ byȱ anyȱ integerȱ otherȱ thanȱ itselfȱandȱone.ȱWriteȱaȱprogramȱtoȱprintȱthoseȱnumbersȱinȱtheȱrangeȱ1–100ȱthatȱareȱ prime.ȱ 3. Allȱthreeȱsidesȱofȱequilateralȱtrianglesȱareȱtheȱsameȱlength,ȱbutȱonlyȱtwoȱofȱtheȱsidesȱ ofȱanȱisoscelesȱtriangleȱareȱequal.ȱlfȱallȱofȱtheȱsidesȱofȱaȱtriangleȱareȱdifferentȱlengthsȱ Download at http://www.pin5i.com/ 90 Chapter 4 Statements itȱisȱcalledȱscalene.ȱWriteȱaȱprogramȱtoȱpromptȱforȱandȱreadȱthreeȱnumbersȱthatȱareȱ theȱlengthsȱofȱtheȱthreeȱsideȱofȱaȱtriangle.ȱTheȱprogramȱshouldȱthanȱdetermineȱwhatȱ typeȱ ofȱ triangleȱ theȱ numbersȱ represent.ȱ Hint:ȱ Whatȱ elseȱ shouldȱ theȱ programȱ beȱ lookingȱfor?ȱ 4. Writeȱtheȱfunctionȱcopy_nȱwhoseȱprototypeȱisȱshownȱbelow.ȱ void copy_n( char dst[], char src[], int n ); Theȱ functionȱ isȱ toȱ copyȱ aȱ stringȱ fromȱ theȱ arrayȱ srcȱ toȱ theȱ arrayȱ dstȱ butȱ withȱ theȱ followingȱ requirement:ȱ exactlyȱ nȱ charactersȱ mustȱ beȱ storedȱ intoȱ dst;ȱ noȱ more,ȱ noȱ less.ȱIfȱtheȱlengthȱofȱtheȱstringȱinȱ srcȱisȱlessȱthanȱ n,ȱthenȱyouȱmustȱaddȱenoughȱ NULȱ charactersȱ afterȱ theȱ copiedȱ charactersȱ toȱ getȱ aȱ totalȱ ofȱ nȱ charactersȱ stored.ȱ Ifȱ theȱ lengthȱ ofȱ theȱ stringȱ inȱ srcȱ isȱ greaterȱ thanȱ orȱ equalȱ toȱ n,ȱ thenȱ stopȱ afterȱ youȱ haveȱ storedȱtheȱnȇthȱcharacter;ȱinȱthisȱcaseȱdstȱwillȱnotȱbeȱNULȬterminated.ȱNoteȱthatȱaȱcallȱ toȱ copy_nȱ shouldȱ storeȱ somethingȱ intoȱ dst[0]ȱ throughȱ dst[n-1],ȱ andȱ onlyȱ thoseȱ locations,ȱregardlessȱofȱtheȱlengthȱofȱsrc.ȱ Ifȱ youȱ planningȱ onȱ usingȱ theȱ libraryȱ routineȱ strncpyȱ toȱ implementȱ yourȱ program,ȱyouȱareȱcongratulatedȱforȱreadingȱahead,ȱbutȱtheȱgoalȱhereȱisȱforȱyouȱtoȱ figureȱoutȱtheȱlogicȱyourself,ȱsoȱyouȱmayȱnotȱuseȱanyȱofȱtheȱlibraryȱstringȱroutines.ȱ 5. Writeȱaȱprogramȱthatȱreadsȱtheȱstandardȱinputȱlineȱbyȱlineȱandȱdocsȱtheȱfollowing:ȱ forȱeachȱsetȱofȱtwoȱorȱmoreȱidentical,ȱadjacentȱlinesȱinȱtheȱfile,ȱoneȱlineȱfromȱtheȱsetȱ shouldȱ beȱ printedȱ out;ȱ nothingȱ elseȱ shouldȱ beȱ printedȱ out.ȱ Youȱ mayȱ assumeȱ thatȱ theȱlinesȱinȱtheȱfileȱwillȱnotȱexceedȱ128ȱcharactersȱinȱlengthȱ(127ȱcharactersȱplusȱoneȱ forȱtheȱnewlineȱthatȱterminatesȱeachȱline).ȱ Considerȱtheȱinputȱfileȱshownȱbelow.ȱ ȱ This is the first line. Another line. And another. And another. And another. And another. Still more. Almost done now – Almost done now – Another line. Still more. Finished! ȱ Assumingȱ thatȱ thereȱ areȱ noȱ trailingȱ blanksȱ orȱ tabsȱ onȱ anyȱ ofȱ theȱ linesȱ (whichȱ wouldnȇtȱ beȱ visibleȱ butȱ wouldȱ makeȱ theȱ lineȱ differentȱ fromȱ itsȱ neighbors),ȱ thisȱ Download at http://www.pin5i.com/ 4.14 Programming Exercises 91 programȱwouldȱproduceȱtheȱfollowingȱoutputȱfromȱthisȱinputȱfile.ȱ ȱ ȱ ȱ And another. Almost done now –ȱ ȱ Oneȱ lineȱ fromȱ eachȱ setȱ ofȱ adjacentȱ identicalȱ linesȱ isȱ printed.ȱ Noticeȱ thatȱ ȈAnotherȱ line.ȈȱandȱȈStillȱmoreȈȱareȱnotȱprintedȱbecause,ȱalthoughȱthereȱareȱtwoȱofȱeachȱinȱtheȱ file,ȱtheyȱareȱnotȱadjacent.ȱȱ Hints:ȱ Useȱ getsȱ toȱ readȱ theȱ inputȱ lines,ȱ andȱ strcpyȱ toȱ copyȱ them.ȱ Thereȱ isȱ aȱ routineȱ calledȱ strcmpȱ thatȱ takesȱ twoȱ stringsȱ asȱ argumentsȱ andȱ comparesȱ them.ȱ Itȱ returnsȱzeroȱifȱtheyȱareȱequalȱandȱaȱnonzeroȱvalueȱifȱtheyȱareȱnot.ȱ 6. Writeȱaȱfunctionȱthatȱextractsȱaȱsubstringȱfromȱaȱstring.ȱTheȱfunctionȱshouldȱhaveȱ theȱfollowingȱprototype:ȱ ȱ int substr( char dst[], char src[], int start, int len ) ȱ Itȱ shouldȱ copyȱ theȱ stringȱ thatȱ beginsȱ startȱ charactersȱ pastȱ theȱ beginningȱ ofȱ theȱ stringȱinȱ srcȱintoȱtheȱarrayȱ dst.ȱAtȱmost lenȱnonȬNULȱcharactersȱshouldȱbeȱcopiedȱ fromȱ src.ȱ Afterȱ copying,ȱ dstȱ mustȱ beȱ NULȬterminated.ȱ Theȱ functionȱ shouldȱ returnȱ theȱlengthȱofȱtheȱstringȱstoredȱinȱdst.ȱ Ifȱ startȱspecifiesȱaȱpositionȱbeyondȱtheȱendȱofȱtheȱstringȱinȱ src,ȱorȱeitherȱ startȱ orȱlenȱareȱnegative,ȱthenȱdscȱshouldȱbeȱgivenȱtheȱemptyȱstring.ȱ 7. Writeȱaȱfunctionȱthatȱremovesȱexcessȱwhiteȱspaceȱfromȱaȱstringȱofȱcharacters.ȱTheȱ functionȱshouldȱhaveȱthisȱprototype:ȱ ȱ void deblank( char string[] ); ȱ Everyȱrunȱofȱoneȱorȱmoreȱwhiteȱspaceȱcharactersȱshouldȱbeȱreplacedȱbyȱoneȱspaceȱ character.ȱBeȱsureȱthatȱtheȱstringȱisȱterminatedȱwithȱaȱNULȱbyteȱwhenȱyouȇreȱthroughȱ withȱit!ȱ ȱ Download at http://www.pin5i.com/ ȱ ȱ Download at http://www.pin5i.com/ 5 Operators and Expressions Cȱprovidesȱallȱofȱtheȱoperatorsȱthatȱyouȱexpectȱinȱaȱprogrammingȱlanguageȱandȱmanyȱ more.ȱInȱfact,ȱoneȱofȱtheȱcharacteristicsȱofȱCȱthatȱmanyȱpeopleȱciteȱasȱaȱshortcomingȱisȱ itsȱvastȱassortmentȱofȱoperators,ȱbecauseȱtheyȱmakeȱtheȱlanguageȱharderȱtoȱmaster.ȱOnȱ theȱotherȱhand,ȱmanyȱofȱtheȱCȱoperatorsȱareȱunavailableȱinȱotherȱlanguages,ȱwhichȱisȱ partȱofȱwhatȱmakesȱCȱsuitableȱforȱsuchȱaȱwideȱvarietyȱofȱapplications.ȱ Afterȱ theȱ explanationsȱ ofȱ theȱ operators,ȱ Iȱ discussȱ theȱ rulesȱ forȱ expressionȱ evaluation,ȱincludingȱoperatorȱprecedenceȱandȱarithmeticȱconversions.ȱ ȱ ȱ ȱ 5.1 Operators Forȱtheȱpurposesȱofȱexplanation,ȱtheȱoperatorsȱareȱgroupedȱintoȱcategoriesȱaccordingȱ toȱ eitherȱ whatȱ theyȱ doȱ orȱ howȱ theyȱ areȱ used.ȱ Forȱ referenceȱ purposes,ȱ itȱ isȱ moreȱ convenientȱ toȱ groupȱ themȱ byȱ theirȱ precedence;ȱ Tableȱ5.1,ȱ whichȱ appearsȱ laterȱ inȱ thisȱ chapter,ȱisȱorganizedȱthisȱway.ȱ ȱ ȱ ȱ 5.1.1 Arithmetic ȱ Cȱprovidesȱallȱtheȱusualȱarithmeticȱoperators:ȱ ȱ + - * / % ȱ Exceptȱ forȱ %,ȱ theseȱ operatorsȱ workȱ bothȱ forȱ floatingȬpointȱ andȱ integerȱ types.ȱ Theȱ /ȱ operatorȱperformsȱaȱtruncatingȱintegerȱdivisionȱwhenȱbothȱofȱitsȱoperandsȱareȱintegers,ȱ Download at http://www.pin5i.com/ 94 Chapter 5 Operators and Expressions otherwiseȱitȱperformsȱaȱfloatingȬpointȱdivision. 23 ȱ%ȱisȱtheȱmoduloȱoperator;ȱitȱtakesȱtwoȱ integerȱ arguments,ȱ dividesȱ theȱ leftȱ operandȱ byȱ theȱ rightȱ operand,ȱ butȱ returnsȱ theȱ remainderȱratherȱthanȱtheȱquotient.ȱ ȱ ȱ ȱ 5.1.2 Shifting ȱ Assemblyȱ languageȱ programmersȱ areȱ alreadyȱ familiarȱ withȱ shifting.ȱ Hereȱ isȱ aȱ briefȱ introductionȱ forȱ wellȬadjustedȱ people.ȱ Aȱ shiftȱ simplyȱ slidesȱ theȱ bitsȱ inȱ aȱ valueȱ toȱ theȱ leftȱorȱtheȱright.ȱOnȱaȱleftȱshift,ȱbitsȱonȱtheȱleftȱsideȱofȱtheȱvalueȱareȱdiscarded,ȱandȱzeroȱ bitsȱ areȱ putȱ intoȱ theȱ spaceȱ createdȱ onȱ theȱ rightȱ sideȱ byȱ theȱ shift,ȱ Figureȱ 5.1ȱ isȱ anȱ exampleȱofȱaȱleftȱshiftȱofȱthreeȱbitsȱonȱanȱ8Ȭbitȱvalue,ȱshownȱinȱbinary.ȱTheȱbitsȱinȱtheȱ valueȱ allȱ moveȱ leftȱ byȱ threeȱ positions;ȱ theȱ onesȱ thatȱ fallȱ offȱ theȱ leftȱ endȱ areȱ lost,ȱ andȱ zerosȱareȱputȱintoȱtheȱpositionsȱvacatedȱonȱtheȱright.ȱ Rightȱshiftsȱincludeȱaȱquirkȱnotȱfoundȱinȱleftȱshifts:ȱthereȱareȱtwoȱwaysȱthatȱnewȱ bitsȱcanȱbeȱshiftedȱinȱonȱtheȱleftȱside.ȱTheȱfirstȱisȱcalledȱaȱlogicalȱshift,ȱinȱwhichȱzerosȱareȱ shiftedȱinȱonȱtheȱleftȱside.ȱTheȱotherȱisȱcalledȱanȱarithmeticȱshift.ȱAȱrightȱarithmeticȱshiftȱ putsȱcopiesȱofȱtheȱsignȱbitȱintoȱtheȱleftȱsideȱofȱtheȱvalue,ȱthusȱpreservingȱitsȱsign.ȱIfȱtheȱ valueȱ 10010110ȱ isȱ shiftedȱ rightȱ twoȱ positions,ȱ theȱ resultȱ ofȱ aȱ logicalȱ shiftȱ isȱ 00100101,ȱ butȱ theȱ resultȱ ofȱ anȱ arithmeticȱ shiftȱ isȱ 11100101.ȱ Arithmeticȱ andȱ logicalȱ leftȱ shiftsȱ areȱ identical.ȱOnlyȱtheȱrightȱshiftsȱdiffer,ȱandȱthenȱonlyȱforȱnegativeȱvalues.ȱ ȱ ȱ ȱ ȱ ȱ 0ȱȱȱȱȱ1ȱȱȱȱȱ1ȱȱȱȱȱ0ȱȱȱȱȱ1ȱȱȱȱȱ1ȱȱȱȱȱ0ȱȱȱȱȱ1 0ȱȱȱȱȱ1ȱȱȱȱȱ1ȱȱȱȱȱ0ȱȱȱȱȱ1ȱȱȱȱȱ1ȱȱȱȱȱ0ȱȱȱȱȱ1 Discardedȱ Beforeȱshiftingȱ Afterȱshiftingȱthreeȱpositions Filledȱwithȱ0ȇsȱ 0ȱȱȱȱȱ1ȱȱȱȱȱ1ȱȱȱȱȱ0ȱȱȱȱȱ1ȱȱȱȱȱ0ȱȱȱȱȱ0ȱȱȱȱȱ0 Finalȱresultȱ ȱ ȱ Figureȱ5.1ȱLeftȱshiftȱofȱthreeȱbitsȱ ȱIfȱeitherȱofȱtheȱoperandsȱofȱanȱintegerȱdivisionȱisȱnegative,ȱtheȱresultȱofȱtheȱdivisionȱisȱimplementationȱdefined.ȱReferȱtoȱtheȱ divȱfunctionȱinȱChapterȱ16ȱforȱdetails.ȱ 23 Download at http://www.pin5i.com/ 5.1 Operators CAUTION! CAUTION! 95 Theȱleftȱshiftȱoperatorȱisȱ<<ȱandȱtheȱrightȱshiftȱoperatorȱisȱ>>.ȱTheȱvalueȱgivenȱbyȱ theȱleftȱoperandȱisȱshiftedȱtheȱnumberȱofȱbitȱpositionsȱspecifiedȱbyȱtheȱrightȱoperand.ȱ Bothȱoperandsȱmustȱhaveȱanȱintegralȱtype.ȱȱ ȱ TheȱStandardȱstatesȱthatȱlogicalȱshiftsȱareȱperformedȱonȱallȱunsignedȱvaluesȱbutȱleavesȱ itȱ upȱ toȱ theȱ implementationȱ whetherȱ arithmeticȱ orȱ logicalȱ shiftsȱ areȱ usedȱ forȱ signedȱ values.ȱYouȱcanȱwriteȱaȱsimpleȱtestȱprogramȱtoȱseeȱhowȱyourȱimplementationȱworks,ȱ butȱ yourȱ testȱ isȱ noȱ guaranteeȱ thatȱ anyȱ otherȱ compilerȱ willȱ workȱ theȱ same,ȱ thusȱ programsȱthatȱdoȱrightȱshiftsȱonȱsignedȱvaluesȱareȱinherentlyȱnonȬportable.ȱ ȱ Bewareȱofȱshiftsȱlikeȱthisȱone:ȱ ȱ a << -5 ȱ WhatȱdoesȱaȱleftȱshiftȱofȱȬ5ȱbitȱpositionsȱmean?ȱAȱrightȱshiftȱofȱ5ȱbits?ȱNoȱshiftȱatȱall?ȱ Onȱ oneȱ machine,ȱ thisȱ expressionȱ actuallyȱ doesȱ aȱ leftȱ shiftȱ ofȱ 27ȱ bits—notȱ exactlyȱ intuitive.ȱ Whatȱ aboutȱ shiftȱ countsȱ thatȱ areȱ largerȱ thanȱ theȱ numberȱ ofȱ binsȱ inȱ theȱ operand?ȱ ȱ TheȱStandardȱstatesȱthatȱtheȱbehaviorȱofȱsuchȱshiftsȱisȱundefined,ȱsoȱitȱisȱupȱtoȱ theȱ implementation.ȱ However,ȱ fewȱ implementorsȱ addressȱ theseȱ situationsȱ explicitly,ȱ soȱ theȱ resultsȱ areȱ notȱ likelyȱ toȱ beȱ meaningful.ȱ Thus,ȱ youȱ shouldȱ avoidȱ usingȱ theseȱ typesȱofȱshiftsȱbecauseȱtheirȱeffectsȱareȱunpredictableȱandȱnonȬportable.ȱȱ TheȱfunctionȱshownȱinȱProgramȱ5.1ȱusesȱaȱrightȱshiftȱtoȱcountȱtheȱnumberȱofȱ1ȱ bitsȱinȱaȱvalue.ȱItȱacceptsȱanȱunsignedȱargumentȱtoȱavoidȱtheȱrightȱshiftȱambiguityȱandȱ usesȱ theȱ moduloȱ operatorȱ toȱ determineȱ whetherȱ theȱ leastȱ significantȱ bitȱ isȱ nonzero.ȱ We’1lȱ improveȱ thisȱ functionȱ laterȱ afterȱ theȱ &,ȱ <<=ȱ andȱ +=ȱ operatorsȱ haveȱ beenȱ described.ȱ ȱ ȱ ȱ 5.1.3 Bitwise ȱ TheȱbitwiseȱoperatorsȱperformȱtheȱlogicalȱoperationsȱAND,ȱOR,ȱandȱXORȱ(exclusiveȬ OR)ȱonȱtheȱindividualȱbitsȱofȱtheirȱoperands.ȱAgain,ȱassemblyȱlanguageȱprogrammersȱ areȱ familiarȱ withȱ theseȱ operationsȱ butȱ hereȱ isȱ aȱ briefȱ introductionȱ forȱ everyoneȱ else.ȱ Theȱ ANDȱ ofȱ twoȱ bitsȱ producesȱ aȱ oneȱ onlyȱ ifȱ bothȱ ofȱ theȱ bitsȱ areȱ one;ȱ otherwiseȱ theȱ resultȱisȱzero.ȱTheȱORȱofȱtwoȱbitsȱproducesȱaȱresultȱofȱzeroȱonlyȱifȱbothȱbitsȱareȱzero;ȱ otherwiseȱtheȱresultȱisȱone.ȱFinally,ȱtheȱXORȱofȱtwoȱbitsȱproducesȱaȱresultȱofȱoneȱifȱbothȱ bitsȱ areȱ different,ȱ andȱ aȱ resultȱ ofȱ zeroȱ ifȱ bothȱ bitsȱ areȱ theȱ same.ȱ Theseȱ operationsȱ areȱ summarizedȱinȱchartsȱbelow.ȱ Download at http://www.pin5i.com/ Chapter 5 Operators and Expressions 96 ȱ /* ** This function returns the number of 1-bits that appeared in ** the argument value. */ int count_one_bits( unsigned value ) { int ones; /* ** While the value still has some 1-bits in it ... */ for( ones = 0; value != 0; value = value >> 1 ) /* ** If the low-order bit is a 1, count it. */ if( value % 2 != 0 ) ones = ones + 1; return ones; } ȱ Programȱ5.1ȱCountingȱoneȱbitsȱinȱaȱvalue:ȱpreliminaryȱversionȱ ȱ ȱ ȱ ȱ ȱ Bȱ ȱ ȱ Bȱ ȱ & 0 1 ȱ | 0 1 Aȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ 0 0 0 1 0 1 A ȱ ȱ ȱ AȱANDȱBȱ 0 0 1 1 1 1 AȱORȱBȱ ȱ ȱ count_1a.cȱ ȱ ȱ ȱ A ȱ ȱ Bȱ ^ 0 1 0 0 1 1 1 0 AȱXORȱBȱ ȱ Theȱbitwiseȱoperatorsȱare:ȱ ȱ & | ^ ȱ forȱ AND,ȱ OR,ȱ andȱ XORȱ respectively.ȱ Theyȱ requireȱ integerȬtypeȱ operands,ȱ andȱ theyȱ performȱtheȱindicatedȱoperationȱonȱtheȱcorrespondingȱbitsȱofȱtheirȱoperands,ȱoneȱpairȱ ofȱ bitsȱ atȱ aȱ time.ȱ Toȱ illustrateȱ this,ȱ supposeȱ theȱ variableȱ aȱ hasȱ theȱ binaryȱ valueȱ 00101110,ȱ andȱ bȱ hasȱ theȱ binaryȱ valueȱ 01011011.ȱ Thenȱ a & bȱ resultsȱ inȱ theȱ valueȱ 00001010,ȱa | bȱgivesȱtheȱvalueȱ01111111,ȱandȱa ^ bȱproducesȱ01110101.ȱ Download at http://www.pin5i.com/ 5.1 Operators 97 Bit Manipulation ȱ Theȱ followingȱ expressionsȱ showȱ howȱ youȱ canȱ useȱ shiftingȱ andȱ bitwiseȱ operatorsȱ toȱ manipulateȱ individualȱ bitsȱ inȱ anȱ integerȱ value.ȱ Theȱ expressionsȱ assumeȱ thatȱ theȱ variableȱbit_numberȱisȱanȱintegerȱvalueȱinȱtheȱrangeȱzeroȱtoȱoneȱlessȱthanȱtheȱnumberȱ ofȱbitsȱinȱanȱintegerȱandȱthatȱtheȱbitsȱinȱanȱintegerȱareȱnumberedȱfromȱrightȱtoȱleft.ȱTheȱ firstȱexampleȱsetsȱtheȱspecifiedȱbitȱtoȱone.ȱ ȱ ȱ value = value | 1 << bit_number; ȱ Theȱnextȱclearsȱtheȱspecifiedȱbitȱtoȱzero. 24 ȱ value = value & ~ ( 1 << bit_number ); ȱ ȱ Theseȱexpressionsȱareȱoftenȱwrittenȱwithȱtheȱ|=ȱandȱ&=ȱoperators,ȱdescribedȱinȱtheȱnextȱ section.ȱFinally,ȱthisȱexpressionȱtestsȱtheȱspecifiedȱbitȱandȱisȱnonzeroȱifȱtheȱbitȱisȱset.ȱ ȱ ȱ value & 1 << bit_number ȱ ȱ ȱ 5.1.4 Assignment ȱ Finallyȱweȱgetȱtoȱtheȱassignmentȱoperator,ȱwhichȱisȱtheȱequalȱsign.ȱAssignmentȱisȱanȱ expressionȱ ratherȱ thanȱ aȱ typeȱ ofȱ statement,ȱ soȱ anȱ assignmentȱ isȱ legalȱ anywhereȱ anȱ expressionȱisȱlegal.ȱTheȱstatementȱ ȱ ȱ x = y + 3; ȱ containsȱtwoȱoperators,ȱ+ȱandȱ=.ȱTheȱadditionȱisȱperformedȱfirst,ȱsoȱtheȱoperandsȱofȱtheȱ =ȱ areȱ theȱ variableȱ xȱ andȱ theȱ valueȱ ofȱ theȱ expressionȱ y + 3.ȱ Theȱ assignmentȱ operatorȱ storesȱtheȱvalueȱofȱtheȱoperandȱonȱtheȱrightȱintoȱtheȱlocationȱspecifiedȱbyȱtheȱoperandȱ onȱ theȱ left.ȱ Butȱ anȱ assignmentȱ isȱ anȱ expression,ȱ andȱ anȱ expressionȱ hasȱ aȱ value.ȱ Theȱ valueȱofȱanȱassignmentȱexpressionȱisȱtheȱnewȱvalueȱofȱtheȱleftȱoperand,ȱwhichȱcanȱbeȱ usedȱasȱanȱoperandȱofȱanotherȱoperator,ȱasȱinȱthisȱstatement:ȱ ȱ a = x = y + 3; ȱ Theȱassignmentȱoperatorȱassociatesȱ(isȱevaluated)ȱfromȱrightȱtoȱleft,ȱsoȱthisȱstatementȱisȱ equivalentȱto:ȱ 24 ȱTheȱunaryȱ~ȱoperator,ȱtoȱbeȱdescribedȱshortly,ȱcomputesȱtheȱoneȇsȱcomplementȱofȱitsȱoperand.ȱ Download at http://www.pin5i.com/ Chapter 5 Operators and Expressions 98 a = ( x = y + 3 ); ȱ andȱhasȱexactlyȱtheȱsameȱmeaningȱas:ȱ ȱ x = y + 3; a = x; ȱ ȱ ȱ Hereȱisȱaȱslightlyȱmoreȱambitiousȱexample:ȱ r = s + ( t = u – v ) / 3; ȱ Thisȱstatementȱassignsȱtoȱ tȱtheȱvalueȱofȱtheȱexpressionȱ u – v,ȱthenȱdividesȱthatȱvalueȱ byȱ three,ȱ addsȱ s,ȱ andȱ assignsȱ theȱ resultȱ toȱ r.ȱ Althoughȱ thisȱ isȱ legal,ȱ theȱ followingȱ statementsȱareȱjustȱasȱgoodȱ ȱ t = u – v; r = s + t / 3; CAUTION! Inȱfact,ȱtheyȱareȱevenȱbetterȱbecauseȱtheyȱareȱeasierȱtoȱreadȱandȱeasierȱtoȱdebug.ȱItȱisȱ veryȱeasyȱtoȱgoȱoverboardȱwithȱembeddedȱassignmentsȱandȱwriteȱexpressionsȱthatȱareȱ difficultȱtoȱread.ȱTherefore,ȱbeforeȱyouȱuseȱthisȱȈfeature,Ȉȱbeȱsureȱthatȱitȱisȱjustifiedȱbyȱ someȱsubstantial,ȱtangibleȱbenefit.ȱ ȱ Itȱisȱincorrectȱtoȱsayȱthatȱtheȱsameȱvalueȱisȱassignedȱtoȱbothȱaȱandȱxȱinȱtheȱstatement:ȱ ȱ a = x = y + 3; ȱ Ifȱ xȱ wereȱ aȱ character,ȱ theȱ valueȱ yȱ +ȱ 3ȱ wouldȱ beȱ truncatedȱ toȱ fit;ȱ aȱ wouldȱ thenȱ beȱ assignedȱ thisȱ truncatedȱ value.ȱ Truncationȱ isȱ preciselyȱ theȱ problemȱ inȱ thisȱ commonȱ mistake:ȱ ȱ char ch; ... while( (ch = getchar()) != EOF ) ... ȱ TheȱvalueȱEOFȱrequiresȱmoreȱbitsȱthanȱaȱcharacterȱvalue,ȱwhichȱisȱwhyȱ getcharȱreturnsȱ anȱintegerȱvalue,ȱnotȱaȱcharacter.ȱHowever,ȱstoringȱitȱfirstȱinȱ chȱtruncatesȱtheȱreturnedȱ value.ȱ Thisȱ truncatedȱ valueȱ isȱ thenȱ promotedȱ toȱ anȱ integerȱ andȱ comparedȱ withȱ EOF.ȱ Whenȱthisȱerroneousȱcodeȱisȱrunȱonȱmachinesȱwithȱsignedȱcharacters,ȱreadingȱtheȱbyteȱ \377ȱ causesȱ theȱ loopȱ toȱ endȱ asȱ ifȱ endȱ ofȱ fileȱ hadȱ beenȱ reached.ȱ Whenȱ itȱ isȱ runȱ onȱ machinesȱwithȱunsignedȱcharacters,ȱtheȱloopȱneverȱends!ȱ Download at http://www.pin5i.com/ 5.1 Operators 99 Compound Assignment ȱ Thereȱisȱaȱcompoundȱassignmentȱformȱforȱeachȱofȱtheȱoperatorsȱpresentedȱsoȱfar:ȱ ȱ += <<= -= >>= *= &= /= ^= %= |= ȱ Weȱ discussȱ onlyȱ theȱ +=ȱ operatorȱ becauseȱ theȱ othersȱ workȱ theȱ sameȱ wayȱ withȱ theirȱ respectiveȱoperators.ȱTheȱ+=ȱoperatorȱisȱusedȱlikeȱthis:ȱ ȱ a += expression ȱ ItȱreadsȱȈaddȱexpressionȱtoȱaȈȱandȱisȱequivalentȱtoȱtheȱfollowingȱexpressionȱ ȱ exceptȱthatȱtheȱoperandȱonȱtheȱleftȱsideȱofȱtheȱ+=ȱ(aȱinȱthisȱcase)ȱisȱonlyȱevaluatedȱonce.ȱ Noteȱ theȱ parentheses:ȱ theyȱ ensureȱ thatȱ expressionȱ isȱ fullyȱ evaluatedȱ beforeȱ theȱ addition,ȱevenȱifȱitȱcontainsȱanȱoperatorȱwhoseȱprecedenceȱisȱlowerȱthanȱaddition.ȱ Whatȱisȱtheȱpointȱofȱhavingȱtwoȱwaysȱtoȱaddȱsomethingȱtoȱaȱvariable?ȱȱ Theȱ K&Rȱ Cȱ designersȱ thoughtȱ thatȱ compoundȱ assignmentȱ operatorsȱ allowedȱ theȱ programmerȱ toȱ writeȱ codeȱ moreȱ clearly.ȱ Plus,ȱ theȱ compilerȱ wouldȱ beȱ ableȱ toȱ produceȱmoreȱcompactȱcode.ȱNow,ȱtheȱdifferenceȱbetweenȱ a = a + 5ȱ;ȱandȱ a += 5;ȱisȱ notȱveryȱdramatic,ȱandȱmodemȱcompilersȱhaveȱnoȱtroubleȱproducingȱoptimalȱcodeȱforȱ bothȱ expressions.ȱ Butȱ considerȱ theseȱ twoȱ statements,ȱ whichȱ areȱ equivalentȱ ifȱ theȱ functionȱfȱhasȱnoȱsideȱeffects:ȱ ȱ a[ 2 * (y – 6*f(x)) ] = a[ 2 * (y – 6*f(x)) ] + 1; a[ 2 * (y – 6*f(x)) ] += 1; TIP ȱ Theȱfirstȱformȱrequiresȱthatȱtheȱexpressionȱselectingȱtheȱlocationȱtoȱbeȱincrementedȱbeȱ writtenȱ twice,ȱonceȱ onȱtheȱ leftȱandȱonceȱ onȱ theȱrightȱ sideȱofȱ theȱequalsȱsign.ȱ Becauseȱ theȱcompilerȱhasȱnoȱwayȱofȱknowingȱwhetherȱ fȱhasȱanyȱsideȱeffects,ȱitȱmustȱevaluateȱ theȱsubscriptȱexpressionȱtwice.ȱTheȱsecondȱformȱisȱmoreȱefficientȱbecauseȱtheȱsubscriptȱ isȱevaluatedȱonlyȱonce.ȱ ȱ Aȱmuchȱmoreȱimportantȱadvantageȱtoȱ+=ȱisȱthatȱitȱmakesȱtheȱsourceȱcodeȱeasierȱtoȱreadȱ andȱ write.ȱ Toȱ figureȱ outȱ whatȱ theȱ firstȱ statementȱ inȱ theȱ exampleȱ aboveȱ isȱ doing,ȱ theȱ readerȱ mustȱ closelyȱ examineȱ bothȱ subscriptȱ expressionsȱ toȱ verifyȱ thatȱ theyȱ areȱ identicalȱandȱmustȱthenȱexamineȱtheȱfunctionȱfȱtoȱseeȱwhetherȱitȱhasȱanyȱsideȱeffects.ȱ Thereȱisȱnoȱsuchȱproblemȱreadingȱtheȱsecondȱstatement.ȱItȱisȱalsoȱeasierȱtoȱwriteȱthanȱ theȱfirst,ȱwithȱfewerȱchancesȱofȱtypingȱerrors.ȱItȱisȱbecauseȱofȱtheseȱadvantagesȱthatȱyouȱ shouldȱuseȱassignmentȱoperators.ȱ Download at http://www.pin5i.com/ Chapter 5 Operators and Expressions 100 Weȱ canȱ nowȱ rewriteȱ Programȱ 5.1ȱ usingȱ assignmentȱ operatorsȱ asȱ shownȱ inȱ Programȱ 5.2.ȱTheȱassignmentȱoperatorsȱalsoȱsimplifyȱtheȱexpressionsȱtoȱsetȱandȱclearȱindividualȱ bitsȱinȱaȱvalue:ȱ ȱ value |= 1 << bit_number; value &= ~ ( 1 << bit_number ); ȱ ȱ ȱ 5.1.5 Unary ȱ Thereȱareȱaȱnumberȱofȱunaryȱoperators,ȱthatȱis,ȱoperatorsȱthatȱtakeȱonlyȱoneȱoperand.ȱ Theyȱareȱ ȱ ! ~ ++ -- + & * sizeof (type) ȱ Let’sȱlookȱatȱtheseȱoperatorsȱoneȱbyȱone.ȱȱ Theȱ !ȱoperatorȱperformsȱaȱlogicalȱnegationȱofȱitsȱoperand;ȱifȱtheȱoperandȱisȱtrueȱ theȱresultȱisȱfalse,ȱandȱifȱtheȱoperandȱisȱfalseȱtheȱresultȱisȱtrue.ȱLikeȱtheȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** This function returns the number of 1-bits that appeared in ** the argument value. */ int count_one_bits( unsigned value ) { int ones; /* ** While the value still has some 1-bits in it ... */ for( ones = 0; value != 0; value >>= 1 ) /* ** If the low-order bit is a 1, count it. */ if( ( value & 1 ) != 0 ) ones += 1; return ones; } Programȱ5.2ȱCountingȱoneȱbitsȱinȱaȱvalue:ȱfinalȱversionȱ ȱ ȱ ȱ count_1b.cȱȱ Download at http://www.pin5i.com/ 5.1 Operators 101 relationalȱ operators,ȱ thisȱ operatorȱ actuallyȱ producesȱ anȱ integerȱ result,ȱ eitherȱ zeroȱ orȱ one.ȱȱ Theȱ ~ȱoperatorȱproducesȱtheȱoneȇsȱcomplementȱofȱanȱintegerȬtypeȱoperand.ȱTheȱ oneȇsȱcomplementȱisȱobtainedȱbyȱchangingȱtheȱvalueȱofȱeachȱofȱtheȱoperandȇsȱbitsȱfromȱ oneȱtoȱzeroȱorȱfromȱzeroȱtoȱone.ȱȱ Theȱ-ȱoperatorȱproducesȱtheȱnegativeȱofȱitsȱoperand.ȱȱ Theȱ+ȱoperatorȱyieldsȱtheȱvalueȱofȱitsȱoperand;ȱinȱotherȱwords,ȱitȱdoesȱnothing.ȱItȱ isȱprovidedȱonlyȱforȱsymmetryȱwithȱ-.ȱȱ &ȱproducesȱtheȱaddressȱofȱitsȱoperand.ȱForȱexample,ȱinȱtheȱfollowingȱstatementsȱ anȱintegerȱvariableȱandȱaȱpointerȱtoȱanȱintegerȱvariableȱareȱdeclared.ȱThen,ȱtheȱaddressȱ ofȱ theȱ variableȱ aȱ isȱ determinedȱ withȱ theȱ &ȱ operatorȱ andȱ isȱ assignedȱ toȱ theȱ pointerȱ variable.ȱ ȱ int a, *b; ... b = &a; ȱ Thisȱ exampleȱ illustratesȱ howȱ youȱ giveȱ aȱ pointerȱ variableȱ theȱ addressȱ ofȱ anȱ existingȱ variable.ȱ *ȱisȱtheȱindirectionȱoperatorȱandȱisȱusedȱwithȱpointersȱtoȱaccessȱtheȱvalueȱbeingȱ pointedȱ to.ȱ Afterȱ theȱ assignmentȱ inȱ theȱ previousȱ exampleȱ isȱ performed,ȱ theȱ valueȱ ofȱ theȱexpressionȱbȱwouldȱbeȱtheȱaddressȱofȱtheȱvariableȱa,ȱbutȱtheȱvalueȱofȱtheȱexpressionȱ *bȱwouldȱbeȱtheȱvalueȱof a.ȱ Theȱ sizeofȱoperatorȱdeterminesȱtheȱsizeȱofȱitsȱoperand,ȱmeasuredȱinȱbytes.ȱTheȱ operandȱmayȱbeȱeitherȱanȱexpressionȱ(oftenȱitȱisȱjustȱaȱsingleȱvariable),ȱorȱaȱtypeȱnameȱ enclosedȱinȱparentheses.ȱHereȱareȱtwoȱexamples:ȱ ȱ sizeof( int ) sizeof x ȱ Theȱfirstȱreturnsȱtheȱnumberȱofȱbytesȱinȱanȱintegerȱvariable,ȱwhichȱofȱcourseȱdependsȱ onȱ theȱ environmentȱyouȱ areȱ using.ȱTheȱsecondȱ exampleȱ returnsȱ theȱnumberȱ ofȱ bytesȱ usedȱbyȱtheȱvariableȱ x.ȱNoteȱthatȱtheȱsizeȱofȱaȱcharacterȱvariable,ȱbyȱdefinition,ȱisȱone.ȱ Whenȱusedȱwithȱtheȱnameȱofȱanȱarray,ȱ sizeofȱreturnsȱtheȱsizeȱofȱtheȱarrayȱinȱbytes.ȱItȱ isȱlegalȱtoȱsurroundȱanȱexpressionȱoperandȱwithȱparentheses,ȱlikeȱthis:ȱ ȱ ȱ sizeof( x ) ȱ becauseȱ parenthesesȱ areȱ alwaysȱ legalȱ inȱ expressions.ȱ Determiningȱ theȱ sizeȱ ofȱ anȱ expressionȱdoesȱnotȱevaluateȱtheȱexpression,ȱsoȱ sizeof( a = b + 1 )ȱdoesȱnotȱassignȱ anythingȱtoȱa.ȱȱ Theȱ(type)ȱoperatorȱisȱcalledȱaȱcastȱandȱisȱusedȱtoȱexplicitlyȱconvertȱtheȱvalueȱofȱ anȱexpressionȱtoȱanotherȱtype.ȱForȱexample,ȱtoȱgetȱtheȱfloatingȬpointȱequivalentȱofȱtheȱ integerȱvariableȱaȱyouȱwouldȱwriteȱ Download at http://www.pin5i.com/ 102 Chapter 5 Operators and Expressions (float)a Theȱ nameȱ ȈcastȈȱ isȱ easierȱ toȱ rememberȱ ifȱ youȱ useȱ theȱ metallurgyȱ metaphor:ȱ castingȱ somethingȱintoȱaȱdifferentȱmold.ȱTheȱeastȱhasȱaȱveryȱhighȱprecedence,ȱsoȱaȱcastȱinȱfromȱ ofȱanȱexpressionȱwillȱonlyȱchangeȱtheȱtypeȱofȱtheȱfirstȱtermȱinȱtheȱexpression.ȱInȱorderȱ toȱcastȱtheȱresultȱofȱtheȱexpression,ȱyouȱmustȱencloseȱitȱinȱparentheses.ȱ Finallyȱweȱcomeȱtoȱtheȱincrementȱ++ȱandȱdecrementȱ--ȱoperators.ȱIfȱthereȱisȱanyȱ oneȱoperatorȱthatȱcapturesȱtheȱȈfeelȈȱofȱCȱprogramming,ȱitȱmustȱbeȱoneȱofȱthese.ȱEachȱ oneȱcomesȱinȱtwoȱvariations,ȱcalledȱprefixȱandȱpostfix.ȱBothȱversionsȱofȱbothȱoperatorsȱ requireȱ aȱ variable,ȱ notȱ anȱ expression,ȱ forȱ anȱ operand.ȱ Actually,ȱ theȱ restrictionȱ isȱ somewhatȱ lessȱ rigid.ȱ Whatȱ theȱ operatorsȱ reallyȱ requireȱ isȱ anȱ ȈL—value,Ȉȱ butȱ weȱ haven’tȱ coveredȱ thisȱ topicȱ yet.ȱ Theȱ gistȱ ofȱ theȱ restrictionȱ isȱ thatȱ ++ȱ andȱ --ȱ mayȱ beȱ appliedȱ onlyȱ toȱ expressionsȱ thatȱ mayȱ appearȱ onȱ theȱ leftȱ sideȱ ofȱ anȱ assignmentȱ operator.ȱ Inȱ theȱ prefixȱ versionȱ ofȱ ++,ȱ theȱ operatorȱ appearsȱ aheadȱ ofȱ theȱ operand.ȱ Theȱ operandȱ isȱ incremented,ȱ andȱ theȱ valueȱ ofȱ theȱ expressionȱ isȱ theȱ incrementedȱ valueȱ ofȱ theȱ variable.ȱ Inȱ itsȱ postfixȱ version,ȱ theȱ operatorȱ appearsȱ afterȱ theȱ operand.ȱ Theȱ operandȱisȱstillȱincremented,ȱbutȱtheȱvalueȱofȱtheȱexpressionȱisȱtheȱvalueȱtheȱoperandȱ hadȱ beforeȱ theȱ incrementȱ tookȱ place.ȱ Thisȱ ruleȱ isȱ easyȱ toȱ rememberȱ ifȱ youȱ considerȱ whereȱtheȱoperatorȱisȱplaced—beforeȱtheȱoperandȱincrementsȱbeforeȱtheȱvalueȱisȱusedȱ inȱ theȱ expression;ȱ afterȱ theȱ operandȱ incrementsȱ afterȱ itsȱ valueȱ isȱ usedȱ inȱ theȱ surroundingȱ expression.ȱ Theȱ --ȱ operatorȱ worksȱ theȱ sameȱ way,ȱ exceptȱ thatȱ itȱ decrementsȱratherȱthanȱincrementing.ȱ Hereȱareȱsomeȱexamples.ȱ ȱ int a, b, c, d; ... a = b = 10; a andȱbȱgetȱtheȱvalue 10 c = ++a; a isȱincrementedȱto 11,ȱand c getsȱtheȱvalue 11 d = b++; b isȱincrementedȱto 11,ȱbut d getsȱtheȱvalue 10 ȱ Theȱremarksȱaboveȱdescribeȱtheȱresultsȱofȱtheseȱoperatorsȱbutȱdoȱnotȱstateȱtheȱwayȱinȱ whichȱtheȱresultȱisȱobtained.ȱAbstractly,ȱbothȱtheȱprefixȱandȱpostfixȱversionsȱmakeȱatȱ copyȱofȱtheȱvariableȇsȱvalue.ȱItȱisȱthisȱcopyȱthatȱisȱusedȱinȱtheȱsurroundingȱexpressionȱ (theȱ Ȉsurroundingȱ expressionȈȱ inȱ theȱ exampleȱ aboveȱ isȱ theȱ assignment).ȱ Theȱ prefixȱ operatorȱ incrementsȱ beforeȱ makingȱ thisȱ copy,ȱ andȱ theȱ postfixȱ operatorȱ incrementsȱ afterȱmakingȱtheȱcopy.ȱItȱisȱimportantȱtoȱrealizeȱthatȱtheȱresultsȱofȱtheseȱoperatorsȱareȱ notȱ theȱ variableȱ thatȱ wasȱ modifiedȱ butȱ aȱ copyȱ ofȱ itsȱ value.ȱ Thisȱ pointȱ isȱ importantȱ becauseȱitȱexplainsȱwhyȱyouȱcannotȱuseȱtheȱoperatorsȱinȱthisȱway:ȱ Download at http://www.pin5i.com/ 5.1 Operators 103 ++a = 10; ȱ Theȱ resultȱ ofȱ ++aȱ isȱ aȱ copyȱ ofȱ theȱ valueȱ ofȱ a,ȱ notȱ theȱ variableȱ itself,ȱ andȱ youȱ cannotȱ assignȱsomethingȱtoȱaȱvalue.ȱ ȱ ȱ ȱ 5.1.6 Relational ȱ Theseȱoperatorsȱtestȱvariousȱrelationshipsȱbetweenȱtheirȱoperands.ȱAllȱtheȱusualȱonesȱ areȱprovided,ȱthoughȱthereȱisȱaȱpitfallȱinȱthisȱgroup.ȱTheȱoperatorsȱareȱ ȱ > >= < <= . != == ȱ ȱ Theȱ firstȱ fourȱ areȱ selfȱ explanatory.ȱ Theȱ !=ȱ operatorȱ testsȱ forȱ Ȉnotȱ equal,Ȉȱ andȱ theȱ == operatorȱtestsȱforȱȈisȱequalȱto.Ȉȱ Althoughȱtheȱrelationalȱoperatorsȱaccomplishȱwhatȱyouȱwouldȱexpect,ȱtheȱwayȱ inȱ whichȱ theyȱ doȱ itȱ isȱ aȱ littleȱ different.ȱ Theseȱ operatorsȱ allȱ produceȱ anȱ integer,ȱ notȱ boolean,ȱresult.ȱIfȱtheȱindicatedȱrelationshipȱholdsȱbetweenȱtheȱoperands,ȱtheȱresultȱisȱ one;ȱotherwiseȱtheȱresultȱisȱzero.ȱTheȱresultȱisȱanȱintegerȱvalueȱandȱcanȱbeȱassignedȱtoȱ integerȱ variables,ȱ butȱ whatȱ usuallyȱ happensȱ isȱ thatȱ theȱ valueȱ isȱ testedȱ inȱ anȱ ifȱ orȱ aȱ whileȱstatement.ȱRememberȱhowȱthoseȱstatementsȱwork:ȱanȱexpressionȱthatȱevaluatesȱ toȱ zeroȱ isȱ consideredȱ falseȱ andȱ anyȱ nonzeroȱ valueȱ isȱ consideredȱ true.ȱ Theȱ relationalȱ operatorsȱ workȱ theȱ sameȱ way,ȱ producingȱ zeroȱ whenȱ theȱ relationȱ docsȱ notȱ holdȱ andȱ oneȱwhenȱitȱdoes.ȱThus,ȱthereȱisȱnoȱfunctionalȱneedȱforȱaȱdistinctȱbooleanȱdataȱtype.ȱ Thisȱuseȱofȱintegersȱtoȱrepresentȱbooleanȱvaluesȱleadsȱdirectlyȱtoȱsomeȱshortcutsȱ thatȱareȱcommonlyȱusedȱwhenȱtestingȱexpressions.ȱ ȱ if( expression != 0 ) ... if( expression ) ... if( expression == 0 ) ... if( !expression ) ... ȱ Theȱ twoȱ statementsȱ inȱ eachȱ ofȱ theseȱ pairsȱ areȱ equivalentȱ toȱ oneȱ another;ȱ theȱ testȱ forȱ Ȉnotȱ equalȱ toȱ zeroȈȱ canȱ beȱ performedȱ withȱ aȱ relationalȱ operatorȱ orȱ byȱ simplyȱ testingȱ theȱvalueȱofȱtheȱexpression.ȱSimilarly,ȱtheȱtestȱforȱȈequalȱtoȱzeroȈȱcanȱalsoȱbeȱperformedȱ byȱtestingȱtheȱexpressionȇsȱvalueȱandȱthenȱtakingȱtheȱlocalȱNOTȱofȱtheȱresult.ȱWhichȱofȱ theseȱformsȱyouȱchooseȱtoȱuseȱisȱaȱmatterȱofȱstyle.ȱBeȱcarefulȱwithȱtheȱlastȱone,ȱthough.ȱ Theȱ !ȱoperatorȱhasȱhighȱprecedence,ȱsoȱifȱtheȱexpressionȱcontainsȱanyȱoperators,ȱyouȱ willȱprobablyȱhaveȱtoȱencloseȱitȱinȱparentheses.ȱ Download at http://www.pin5i.com/ 104 CAUTION! Chapter 5 Operators and Expressions IfȱthisȱerrorȱisȱnotȱtheȱmostȱcommonȱmadeȱbyȱbeginningȱCȱprogrammers,ȱitȱisȱcertainlyȱ theȱmostȱirritating.ȱMostȱotherȱlanguagesȱuseȱtheȱ=ȱoperatorȱtoȱperformȱaȱcomparison.ȱ Inȱ C,ȱ youȱmustȱuseȱ theȱ doubleȱequalȱ signȱ ==ȱ forȱ comparison;ȱ aȱ singleȱ equalȱ signȱ willȱ performȱanȱassignment.ȱ Theȱ pitfallȱ isȱ thatȱ anȱ assignmentȱ isȱ legalȱ anywhereȱ itȱ isȱ legalȱ toȱ compareȱ forȱ equality,ȱsoȱitȱisȱnotȱaȱsyntaxȱerror. 25 ȱThisȱunfortunateȱpropertyȱisȱtheȱdisadvantageȱofȱ notȱhavingȱaȱdistinctȱbooleanȱtype;ȱbothȱexpressionsȱareȱlegitimateȱintegerȱexpressions,ȱ soȱtheyȱareȱbothȱlegalȱinȱthisȱcontext.ȱ Whatȱ happensȱ ifȱ youȱ useȱ theȱ wrongȱ operator?ȱ Considerȱ thisȱ example,ȱ whichȱ looksȱperfectlyȱgoodȱtoȱPascalȱandȱModulaȱprogrammers:ȱ x = get_some_value(); if( x = 5 ) doȱsomethingȱ xȱgetsȱaȱvalueȱfromȱtheȱfunction,ȱbutȱinsteadȱofȱcomparingȱitȱtoȱtheȱliteralȱconstantȱfive,ȱ weȱassignȱfiveȱtoȱ x,ȱthusȱdestroyingȱtheȱvalueȱobtainedȱfromȱtheȱfunction. 26 ȱThisȱresultȱ isȱsurelyȱnotȱwhatȱtheȱprogrammerȱintended.ȱButȱthereȱisȱanotherȱproblem,ȱtoo.ȱTheȱifȱ statementȱ willȱ alwaysȱ beȱ trueȱ becauseȱ theȱ valueȱ ofȱ theȱ assignmentȱ expressionȱ isȱ theȱ newȱvalueȱofȱx,ȱwhichȱisȱnonzero.ȱ GetȱintoȱtheȱhabitȱofȱdoubleȬcheckingȱcomparisonsȱforȱequalityȱwhenȱyouȱwriteȱ themȱtoȱmakeȱsureȱyouȱusedȱtheȱdoubleȱequalȱsign.ȱWhenȱyouȱfindȱthatȱaȱprogramȱisȱ notȱ working,ȱ takeȱ aȱ quickȱ lookȱ atȱ yourȱ comparisons;ȱ youȱ mayȱ saveȱ yourselfȱ aȱ lotȱ ofȱ debuggingȱtime.ȱ ȱ ȱ ȱ 5.1.7 Logical ȱ Theȱlogicalȱoperatorsȱareȱ&&ȱandȱ||.ȱTheseȱoperatorsȱlookȱlikeȱtheȱbitwiseȱoperators,ȱ butȱtheirȱoperationȱisȱquiteȱdifferentȱ–ȱtheseȱvaluateȱexpressionsȱlookingȱforȱtrueȱandȱ falseȱvalues.ȱLetȇsȱlookȱatȱoneȱofȱthemȱ ȱ expression1 && expression2ȱ ȱ ȱ Theȱ resultȱ ofȱ thisȱ expressionȱ isȱ trueȱ ifȱ bothȱ expression1ȱ andȱ expression2ȱ areȱ true;ȱ ifȱ eitherȱofȱthemȱisȱfalse,ȱtheȱentireȱexpressionȱisȱfalse.ȱSoȱfar,ȱsoȱgood.ȱ ȱSomeȱcompilersȱproduceȱaȱwarningȱmessageȱforȱsuchȱsuspiciousȱexpressions.ȱInȱtheȱrareȱoccasionsȱwhenȱassignmentȱisȱ whatȱyouȱwant,ȱtryȱenclosingȱtheȱassignmentȱinȱparenthesesȱtoȱgetȱridȱofȱtheȱwarningȱmessage.ȱ 26ȱTheȱ=ȱoperatorȱusedȱinȱthisȱmannerȱisȱsometimesȱjokinglyȱcalledȱtheȱȈitȱisȱnowȈȱoperator.ȱȈIsȱxȱequalȱtoȱfive?ȱItȱisȱnow!Ȉȱ 25 Download at http://www.pin5i.com/ 5.1 Operators 105 Anȱinterestingȱaspectȱofȱthisȱoperatorȱisȱthatȱitȱcontrolsȱtheȱorderȱinȱwhichȱtheȱ subexpressionsȱareȱevaluated.ȱForȱexample,ȱlookȱatȱthisȱexpression:ȱ ȱ a > 5 && a < 10 ȱ Theȱprecedenceȱofȱ &&ȱisȱlowerȱthanȱthatȱofȱeitherȱtheȱ >ȱorȱtheȱ <ȱoperator,ȱsoȱtheȱ subexpressionsȱareȱgroupedȱlikeȱthis:ȱ ȱ ( a > 5 ) && ( a < 10 ) However,ȱdespiteȱitsȱlowerȱprecedence,ȱtheȱ&&ȱexertsȱcontrolȱoverȱtheȱevaluationȱofȱtheȱ twoȱrelationals.ȱHereȱisȱhowȱitȱworks:ȱtheȱleftȱoperandȱofȱaȱ&&ȱisȱalwaysȱevaluatedȱfirst.ȱ Ifȱitsȱvalueȱisȱtrue,ȱthenȱtheȱrightȱoperandȱisȱevaluated.ȱIfȱtheȱvalueȱofȱtheȱleftȱoperandȱ isȱfalse,ȱtheȱrightȱoperandȱisȱnotȱevaluatedȱbecauseȱitȱdoesnȇtȱmatter:ȱtheȱresultȱofȱtheȱ&&ȱ isȱalreadyȱknownȱtoȱbeȱfalse.ȱ ||ȱhasȱtheȱsameȱproperty.ȱTheȱleftȱoperandȱisȱevaluatedȱ first:ȱ ifȱ itȱ isȱ true,ȱ theȱ rightȱ operandȱ isȱ notȱ evaluatedȱ becauseȱ theȱ valueȱ ofȱ theȱ overallȱ expressionȱ hasȱ alreadyȱ beenȱ determined.ȱ Thisȱ behaviorȱ isȱ oftenȱ calledȱ shortȬcircuitedȱ evaluation.ȱ Thisȱorderingȱisȱguaranteedȱandȱisȱquiteȱuseful.ȱTheȱexampleȱbelowȱisȱillegalȱinȱ standardȱPascal:ȱ ȱ if( x >= 0 && x < MAX && array[ x ] == 0 ) ... CAUTION! ȱ InȱC,ȱtheȱcodeȱfirstȱchecksȱwhetherȱtheȱvalueȱisȱinȱtheȱlegalȱrangeȱofȱsubscriptsȱforȱtheȱ array.ȱ Ifȱ itȱ isȱ not,ȱ theȱ subscriptȱ expressionȱ isȱ skippedȱ entirely.ȱ Becauseȱ Pascalȱ fullyȱ evaluatesȱallȱexpressions,ȱanȱinvalidȱsubscriptȱwouldȱcauseȱtheȱprogramȱtoȱabortȱwithȱ aȱsubscriptȱerror,ȱdespiteȱtheȱcheckingȱthatȱtheȱprogrammerȱtriedȱtoȱdo.ȱ ȱ Theȱ bitwiseȱ operatorsȱ areȱ oftenȱ confusedȱ withȱ theȱ logicalȱ operators,ȱ butȱ theyȱ areȱ notȱ interchangeable.ȱTheȱfirstȱdifferenceȱisȱthatȱ||ȱandȱ&&ȱareȱshortȱcircuited;ȱifȱtheȱvalueȱ ofȱtheȱexpressionȱcanȱbeȱdeterminedȱfromȱtheȱleftȱoperandȱalone,ȱtheȱrightȱoperandȱisȱ notȱevaluated.ȱInȱcontrast,ȱbothȱoperandsȱofȱ|ȱandȱ&ȱareȱalwaysȱevaluated.ȱ Second,ȱ theȱ logicalȱ operatorsȱ testȱ forȱ zeroȱ orȱ nonzeroȱ values,ȱ whereasȱ theȱ bitwiseȱ operatorsȱ compareȱ theȱ correspondingȱ bitsȱ inȱ theirȱ operands.ȱ Hereȱ isȱ anȱ example:ȱ ȱ if( a < b && c > d ) ... if( a < b & c > d ) ... ȱ Becauseȱtheȱrelationalȱoperatorsȱproduceȱeitherȱ aȱzeroȱorȱaȱone,ȱtheseȱtwoȱstatementsȱ willȱhaveȱtheȱsameȱresult.ȱButȱifȱaȱisȱoneȱandȱbȱisȱtwo,ȱtheȱnextȱpairȱofȱstatementȱdoȱnotȱ produceȱtheȱsameȱresult.ȱ Download at http://www.pin5i.com/ 106 Chapter 5 Operators and Expressions if( a && b ) ... if( a & b ) ... ȱ Bothȱvaluesȱareȱnonzeroȱsoȱtheȱfirstȱstatementȱisȱtrue,ȱbutȱtheȱsecondȱisȱfalseȱbecauseȱ thereȱareȱnoȱbitȱpositionsȱthatȱcontainȱaȱoneȱinȱbothȱaȱandȱb.ȱ ȱ ȱ ȱ 5.1.8 Conditional ȱ Theȱ conditionalȱ operatorȱ takesȱ threeȱ operands.ȱ Itȱ alsoȱ controlsȱ theȱ orderȱ inȱ whichȱ itsȱ subexpressionsȱareȱevaluated.ȱHereȱisȱhowȱitȱisȱused:ȱ ȱ ȱ expression1 ? expression2 : expression3 ȱ Theȱconditionerȱoperatorȱhasȱaȱveryȱlowȱprecedence,ȱsoȱoperandsȱthatȱareȱexpressionsȱ willȱ groupȱ properlyȱ evenȱ withoutȱ parentheses.ȱ Nevertheless,ȱ manyȱ peopleȱ preferȱ toȱ parenthesizeȱtheȱsubexpressionsȱforȱtheȱsakeȱofȱclarity.ȱ ȱ expression1 isȱ evaluatedȱ first.ȱ Ifȱ itȱ isȱ trueȱ (hasȱ anyȱ nonzeroȱ value),ȱ thenȱ theȱ valueȱofȱtheȱentireȱexpressionȱisȱ expression2,ȱandȱ expression3ȱisȱnotȱevaluatedȱatȱall.ȱ Butȱifȱexpression1 isȱfalseȱ(zero),ȱthenȱtheȱvalueȱofȱtheȱconditionalȱisȱexpression3,ȱandȱ expression2 isȱnotȱevaluated.ȱ Ifȱ youȱ haveȱ troubleȱ rememberingȱ howȱ thisȱ operatorȱ works,ȱ tryȱ readingȱ itȱ asȱ question.ȱForȱexample,ȱ ȱ a > 5 ? b – 6 : c / 2 TIP ȱ isȱread:ȱȈaȱgreaterȱthanȱfive?ȱthenȱ b – 6,ȱotherwiseȱ c / 2.ȈȱTheȱchoideȱofȱtheȱquestionȱ markȱcharacterȱforȱthisȱoperatorȱwasȱnoȱaccident.ȱ ȱ Whereȱisȱtheȱconditionalȱoperatorȱused?ȱHereȱareȱtwoȱprogramȱfragments:ȱ ȱ if( a > 5 ) b = a > 5 ? 3 : -20; b = 3; else b = -20; ȱ Theȱtwoȱsequencesȱofȱcodeȱperformȱexactlyȱtheȱsameȱfunction,ȱbutȱtheȱoneȱonȱtheȱleftȱ requiresȱthatȱȈbȱ=Ȉȱbeȱwrittenȱtwice.ȱBurȱsoȱwhatȇ?ȱThereȱisȱnoȱadvantageȱtoȱusingȱtheȱ conditionalȱhere.ȱBut,ȱtakeȱaȱlookȱatȱthisȱstatement:ȱ ȱ if( a > 5 ) b[ 2 * c + d( e / 5 ) ] = 3; else b[ 2 * c + d( e / 5 ) ] = -20; Download at http://www.pin5i.com/ 5.1 Operators 107 Here,ȱ itȱ isȱ aȱ majorȱ nuisanceȱ toȱ haveȱ toȱ writeȱ theȱ subscriptȱ twice;ȱ theȱ conditionalȱ isȱ muchȱcleaner;ȱ ȱ ȱ b[ 2 * c + d( e / 5 ) ] = a > 5 ? 3 : -20; ȱ Thisȱexampleȱisȱaȱgoodȱplaceȱtoȱuseȱaȱconditionalȱbecauseȱthereȱisȱaȱtangibleȱbenefitȱinȱ doingȱ so;ȱ thereȱ isȱ lessȱ chanceȱ forȱ errorȱ typingȱ theȱ conditionalȱ thanȱ inȱ theȱ previousȱ version,ȱ andȱ theȱ conditionalȱ mayȱ resultȱ inȱ smallerȱ objectȱ codeȱ asȱ well.ȱ Afterȱ youȱ becomeȱ accustomedȱ toȱ readingȱ conditionals,ȱ itȱ isȱ nearlyȱ asȱ easyȱ toȱ readȱ asȱ theȱ ifȱ statement.ȱ ȱ ȱ ȱ 5.1.9 Comma ȱ Theȱ commaȱ operatorȱ willȱ soundȱ triteȱ atȱ first,ȱ butȱ thereȱ areȱ situationsȱ inȱ whichȱ itȱ isȱ quiteȱuseful.ȱItȱworksȱlikeȱthis:ȱ ȱ expression1, expression2, ... , expressionN ȱ Theȱ commaȱ operatorȱ separatesȱ twoȱ orȱ moreȱ expressions.ȱ Theȱ expressionsȱ areȱ evaluatedȱ oneȱ byȱ one,ȱ leftȱ toȱ right,ȱ andȱ theȱ valueȱ ofȱ theȱ entireȱ expressionȱ isȱ justȱ theȱ valueȱofȱtheȱlastȱexpressionȱinȱtheȱlist.ȱForȱexample,ȱ ȱ if( b + 1, c / 2, d > 0 ) ȱ isȱtrueȱifȱtheȱvalueȱofȱdȱisȱgreaterȱthanȱzero.ȱNoȱoneȱeverȱwritesȱcodeȱlikeȱthisȱexample,ȱ ofȱ course,ȱ becauseȱ thereȱ isȱ noȱ purposeȱ inȱ evaluatingȱ theȱ otherȱ twoȱ expressions;ȱ theirȱ valuesȱareȱjustȱdiscarded.ȱHowever,ȱtakeȱaȱlookȱatȱthisȱpieceȱofȱcode.ȱ ȱ a = get_value(); count_value( a ); while( a > 0 ){ ... a = get_value(); count_value( a ); } ȱ Theȱ testȱ inȱ thisȱ loopȱ isȱ precededȱ byȱ twoȱ separateȱ statementsȱ toȱ obtainȱ theȱ value,ȱ soȱ thereȱ mustȱ beȱ aȱ copyȱ ofȱ theseȱ statementsȱ bothȱ beforeȱ theȱ loopȱ andȱ atȱ theȱ endȱ ofȱ theȱ loop’sȱbody.ȱHowever,ȱwithȱtheȱcommaȱoperatorȱyouȱcanȱrewriteȱthisȱloopȱas:ȱ ȱ ȱ ȱ while( a = get_value(), count_value( a ), a > 0 ){ } Download at http://www.pin5i.com/ Chapter 5 Operators and Expressions 108 Youȱmightȱalsoȱuseȱanȱembeddedȱassignment,ȱlikeȱthis:ȱ ȱ ȱ while( count_value( a = get_value() ), a > 0 ){ ... } TIP Newȱthereȱisȱonlyȱaȱsingleȱcopyȱofȱtheȱcodeȱneededȱtoȱgetȱtheȱnextȱvalueȱforȱtheȱloop.ȱ Theȱ commaȱ operatorȱ makesȱ meȱ sourceȱ programȱ easierȱ toȱ maintain;ȱ ifȱ theȱ wayȱ theȱ valuesȱareȱobtainedȱshouldȱchangeȱinȱtheȱfuture,ȱthereȱisȱonlyȱoneȱcopyȱofȱtheȱcodeȱthatȱ needsȱtoȱbeȱfixed.ȱ Itȱ isȱ easyȱ toȱ goȱ overboardȱ withȱ this,ȱ though,ȱ soȱ beforeȱ usingȱ theȱ commonȱ operator,ȱaskȱyourselfȱwhetherȱitȱwouldȱmakeȱtheȱprogramȱbetterȱinȱsomeȱway.ȱIfȱtheȱ answerȱisȱno,ȱthenȱdonȇtȱuseȱit.ȱByȱtheȱway,ȱȈbetterȈȱdoesȱnotȱincludeȱȈtrickier,ȈȱȈcooler,Ȉȱ orȱȈmoreȱimpressive.Ȉȱ Hereȇsȱaȱtechniqueȱthatȱyouȱmightȱoccasionallyȱsee:ȱ ȱ while( x < 10 ) b += x; x += 1; ȱ Inȱthisȱexampleȱtheȱcommaȱoperatorȱisȱusedȱtoȱmakeȱaȱsingleȱstatementȱoutȱofȱtheȱtwoȱ assignmentsȱinȱorderȱnoȱavoidȱputtingȱbracesȱaroundȱthem.ȱThisȱpracticeȱisȱaȱbadȱidea,ȱ becauseȱtheȱsubtleȱvisualȱdifferenceȱbetweenȱaȱcommaȱandȱaȱsemicolonȱisȱtooȱeasyȱtoȱ miss.ȱ ȱ ȱ ȱ 5.1.10 Subscript, Function Call, and Structure Member Iȱdescribeȱtheȱremainingȱoperatorsȱinȱmoreȱdetailȱelsewhereȱinȱtheȱbookȱbutȱmentionȱ themȱ hereȱ forȱ completeness.ȱ Theȱ subscriptȱ operatorȱ isȱ aȱ pairȱ ofȱ brackets.ȱ Aȱ subscriptȱ takesȱ twoȱ operands:ȱ anȱ arrayȱ nameȱ andȱ anȱ indexȱ value.ȱ Actually,ȱ youȱ canȱ useȱ subscriptsȱonȱmoreȱthanȱjustȱarrayȱnames,ȱbutȱweȱwillȱdiscussȱthisȱissueȱinȱChapterȱ6.ȱ Subscriptsȱ inȱ Cȱ workȱ muchȱ likeȱ subscriptsȱ inȱ otherȱ languages,ȱ althoughȱ theȱ implementationȱ isȱ somewhatȱ different.ȱ Cȱ subscriptȱ valuesȱ alwaysȱ beginȱ atȱ zero,ȱ andȱ subscriptsȱ areȱ notȱ checkedȱ forȱ validity.ȱ Exceptȱ forȱ theirȱ precedence,ȱ subscriptȱ operationsȱareȱequivalentȱtoȱindirectionȱexpressions.ȱHereȱisȱtheȱmapping:ȱ ȱ array[ subscript ] *( array + ( subscript ) ) ȱ Theȱ factȱ thatȱ subscriptingȱ isȱ implementedȱ inȱ thisȱ wayȱ becomesȱ importantȱ whenȱ weȱ beginȱtoȱuseȱpointersȱmore,ȱinȱChapterȱ6.ȱ Download at http://www.pin5i.com/ 5.2 Boolean Values 109 Theȱȱfunctionȱcallȱoperatorȱtakesȱoneȱorȱmoreȱoperands.ȱTheȱfirstȱisȱtheȱnameȱofȱ theȱfunctionȱyouȱwishȱtoȱcall,ȱandȱtheȱremainingȱonesȱareȱtheȱargumentsȱtoȱpassȱtoȱtheȱ function.ȱ Theȱ factȱ thatȱ functionȱ callingȱ isȱ implementedȱ asȱ anȱ operationȱ impliesȱ thatȱ ȈexpressionsȈȱ mayȱ beȱ usedȱ insteadȱ ofȱ ȈconstantsȈȱ forȱ theȱ functionȱ name,ȱ whichȱ isȱ indeedȱtheȱcase.ȱTheȱfunctionȱcallȱoperatorȱisȱcoveredȱinȱChapterȱ7.ȱ The . and -> operatorsȱareȱusedȱtoȱaccessȱtheȱmembersȱofȱaȱstructure.ȱIfȱsȱisȱaȱ structureȱ variable,ȱ thenȱ s.aȱ accessesȱ theȱ memberȱ ofȱ thatȱ structureȱ namedȱ a.ȱ Theȱ ->ȱ operatorȱisȱusedȱinsteadȱof . whenȱyouȱhaveȱaȱpointerȱtoȱaȱstructureȱratherȱthanȱtheȱ structureȱ itself.ȱ Structures,ȱ theirȱ members,ȱ andȱ theseȱ operatorsȱ areȱ allȱ describedȱ inȱ Chapterȱ10.ȱ ȱ ȱ ȱ 5.2 Boolean Values ȱ CȱdoesȱnotȱhaveȱanȱexplicitȱBooleanȱtypeȱsoȱintegersȱareȱusedȱinstead.ȱTheȱruleȱis.ȱ ȱ ȱ Zeroȱisȱfalse,ȱandȱanyȱnonzeroȱvalueȱisȱtrueȱ ȱ However,ȱwhatȱtheȱStandardȱdoesnȇtȱsayȱisȱthatȱtheȱvalueȱoneȱisȱȈmoreȱtrueȈȱthanȱanyȱ otherȱnonzeroȱvalue.ȱConsiderȱthisȱcodeȱfragment:ȱ ȱ a = b = if( if( if( 25; 15; a ) ... b ) ... a == b ) ... ȱ Theȱfirstȱtestȱchecksȱwhetherȱaȱisȱnonzero,ȱwhichȱisȱtrue.ȱTheȱsecondȱtestȱcheckȱtoȱseeȱifȱ bȱisȱnotȱequalȱtoȱzero,ȱwhichȱisȱalsoȱtrue.ȱButȱtheȱthirdȱtestȱdoesȱnotȱcheckȱwhetherȱ aȱ andȱbȱareȱbothȱtrue,ȱitȱchecksȱwhetherȱtheyȱareȱequalȱtoȱeachȱother.ȱ TheȱsameȱkindȱofȱproblemȱcanȱhappenȱwithȱintegerȱvariablesȱtestedȱinȱBooleanȱ contexts.ȱ ȱ nonzero_a = a != 0; ... if( nonzero_a == ( b != 0 ) ) ... ȱ Thisȱtestȱisȱsupposedȱtoȱbeȱtrueȱifȱaȱandȱbȱareȱeitherȱzeroȱtogetherȱorȱareȱnonzeroȱ together.ȱTheȱtestȱworksȱfineȱasȱshownȱbutȱtryȱsubstitutingȱtheȱȈequivalentȈȱexpressionȱ bȱforȱ( b != 0 ).ȱ Download at http://www.pin5i.com/ 110 Chapter 5 Operators and Expressions if( nonzero_a == b ) ... CAUTION! ȱ Theȱexpressionȱisȱnoȱlongerȱtestingȱforȱ aȱandȱ bȱbeingȱzeroȱorȱnonzeroȱtogether:ȱnowȱitȱ isȱcheckingȱwhetherȱbȱhasȱaȱspecificȱintegerȱvalue,ȱnamelyȱzeroȱorȱone.ȱ ȱ Althoughȱ allȱ nonzeroȱ valuesȱ areȱ consideredȱ true,ȱ youȱ mustȱ beȱ carefulȱ whenȱ comparingȱ trueȱ valuesȱ toȱ oneȱ another,ȱ becauseȱ manyȱ differentȱ valuesȱ canȱ representȱ true.ȱ Hereȱisȱanotherȱshortcutȱthatȱprogrammersȱoftenȱuseȱwithȱifȱstatementsȱ–ȱoneȱinȱ whichȱ thisȱ sameȱ kindȱ ofȱ troubleȱ canȱ occur.ȱ Assumingȱ thatȱ youȱ haveȱ madeȱ theȱ followingȱ#defineȇs,ȱthenȱeachȱofȱtheȱpairsȱofȱstatementsȱbelowȱseemȱequivalent.ȱ ȱ #define FALSE 0 #define TRUE 1 ... if( flag == FALSE ) ... if( !flag ) ... if( flag == TRUE ) ... if( flag ) ... ȱ Butȱ theȱ secondȱ pairȱ ofȱ statementsȱ isȱ notȱ equivalentȱ ifȱ flagȱ isȱ setȱ toȱ arbitraryȱ integerȱ values.ȱItȱisȱtheȱsameȱonlyȱifȱtheȱflagȱwasȱsetȱtoȱTRUE,ȱtoȱFALSE,ȱorȱtoȱtheȱresultȱofȱaȱ relationalȱorȱlogicalȱexpression.ȱ TIP Theȱsolutionȱtoȱallȱofȱtheseȱproblemsȱisȱtoȱavoidȱmixingȱintegerȱandȱbooleanȱvalues.ȱIfȱaȱ variableȱcontainsȱanȱarbitraryȱintegerȱvalue,ȱtestȱitȱexplicitly:ȱ ȱ if( value != 0 ) ... ȱ Don’tȱ useȱ theȱ shortcutsȱ toȱ testȱ theȱ variableȱ forȱ zeroȱ orȱ nonzero,ȱ becauseȱ thoseȱ formsȱ incorrectlyȱimplyȱthatȱtheȱvariableȱisȱbooleanȱinȱnature.ȱȱ lfȱaȱvariableȱisȱsupposedȱtoȱcontainȱaȱbooleanȱvalue,ȱalwaysȱsetȱitȱtoȱeitherȱzeroȱ orȱone,ȱforȱexample:ȱ ȱ positive_cash_flow = cash_balance >= 0; ȱ Doȱ notȱ testȱ theȱ variablesȱ truthȱ valueȱ byȱ comparingȱ itȱ withȱ anyȱ specificȱ value,ȱ evenȱ TRUEȱorȱFALSE.ȱInstead,ȱtestȱtheȱvariablesȱasȱshownȱhere:ȱ ȱ if( positive_cash_flow ) ... if( !positive_cash_flow ) ... ȱ Ifȱ youȱ haveȱ chosenȱ descriptiveȱ namesȱ forȱ youȱ booleanȱ variables,ȱ thisȱ techniqueȱ willȱ rewardȱyouȱwithȱcodeȱthatȱisȱeasyȱtoȱread:ȱȈifȱpositiveȱcashȱflow,ȱthenȱ…Ȉȱ Download at http://www.pin5i.com/ 5.3 L-values and R-values 111 5.3 L-values and R-values ȱ Toȱ understandȱ theȱ restrictionsȱ onȱ someȱ ofȱ theseȱ operators,ȱ youȱ mustȱ understandȱ theȱ differenceȱ betweenȱ LȬvaluesȱ andȱ RȬvalues.ȱ Theseȱ termsȱ wereȱ coinedȱ byȱ compilerȱ writersȱmanyȱyearsȱagoȱandȱhaveȱsurvivedȱtoȱthisȱdayȱevenȱthoughȱtheirȱdefinitionsȱdoȱ notȱexactlyȱfitȱwithȱtheȱCȱlanguage.ȱ AnȱLȬvalueȱisȱsomethingȱthatȱcanȱappearȱonȱtheȱleftȱsideȱofȱanȱequalȱsignȱ(Lȱforȱ left).ȱAnȱRȬvalueȱisȱsomethingȱthatȱcanȱappearȱonȱtheȱrightȱsideȱofȱanȱequalȱsign.ȱHereȱisȱ anȱexample:ȱ ȱ a = b + 25; ȱ aȱisȱanȱLȬvalueȱbecauseȱitȱidentifiesȱaȱplaceȱwhereȱaȱresultȱcanȱbeȱstored.ȱb + 25ȱisȱanȱRȬ valueȱbecauseȱitȱdesignatesȱaȱvalue.ȱ ȱ Canȱtheyȱbeȱinterchanged?ȱ ȱ b + 25 = a; ȱ a,ȱwhichȱwasȱusedȱasȱanȱLȬvalueȱbefore,ȱcanȱalsoȱbeȱusedȱasȱanȱRȬvaleȱbecauseȱeveryȱ placeȱcontainsȱaȱvalue.ȱHowever,ȱ b + 25ȱcannotȱbeȱusedȱasȱanȱLȬvalueȱbecauseȱitȱdoesȱ notȱidentifyȱaȱspecificȱplace.ȱThus,ȱthisȱassignmentȱisȱillegal.ȱ Noteȱthatȱwhenȱtheȱcomputerȱevaluatesȱ b + 25ȱtheȱresultȱmustȱexistȱsomewhereȱ inȱ theȱ machine.ȱ However,ȱ thereȱ isȱ noȱ wayȱ thatȱ theȱ programmerȱ canȱ eitherȱ predictȱ whereȱ theȱ resultȱ willȱ beȱ orȱ referȱ toȱ theȱ sameȱ locationȱ later.ȱ Consequently,ȱ thisȱ expressionȱisȱnotȱanȱLȬvalue.ȱLiteralȱconstantsȱareȱnotȱLȬvaluesȱforȱtheȱsameȱreason.ȱ ItȱsoundsȱasȱthoughȱvariablesȱmayȱbeȱusedȱasȱLȬvaluesȱbutȱexpressionsȱmayȱnot,ȱ butȱ thisȱ statementȱ isȱ notȱ quiteȱ accurate.ȱ Theȱ LȬvalueȱ inȱ theȱ assignmentȱ belowȱ isȱ anȱ expression.ȱ ȱ int a[30]; ... a[ b + 10 ] = 0; ȱ Subscriptingȱisȱinȱfactȱanȱoperatorȱsoȱtheȱconstructȱonȱtheȱleftȱisȱanȱexpression,ȱyetȱitȱisȱ aȱlegitimateȱLȬvalueȱbecauseȱitȱidentifiesȱaȱspecificȱlocationȱthatȱweȱcanȱreferȱtoȱlaterȱinȱ theȱprogram.ȱHereȱisȱanotherȱexample:ȱ int a, *pi; ... pi = &a; *pi = 20; ȱ Download at http://www.pin5i.com/ 112 Chapter 5 Operators and Expressions Theȱ secondȱ assignmentȱ isȱ whereȱ theȱ actionȱ is:ȱ theȱ valueȱ onȱ theȱ leftȱ isȱ clearlyȱ anȱ expression,ȱyetȱitȱisȱaȱlegalȱLȬvalue.ȱWhy?ȱTheȱvalueȱinȱtheȱpointerȱ piȱisȱtheȱaddressȱofȱ aȱspecificȱlocationȱinȱmemory,ȱandȱtheȱ *ȱoperatorȱdirectsȱtheȱmachineȱtoȱthatȱlocation.ȱ WhenȱusedȱasȱanȱLȬvalue,ȱthisȱexpressionȱspecifiesȱtheȱlocationȱtoȱbeȱmodified.ȱWhenȱ usedȱasȱanȱRȬvalue,ȱitȱgetsȱtheȱvalueȱcurrentlyȱstoredȱatȱthatȱlocation.ȱ Someȱ operators,ȱ likeȱ indirectionȱ andȱ subscripting,ȱ produceȱ anȱ LȬvalueȱ asȱ aȱ result.ȱ Othersȱ produceȱ RȬvalue.ȱ Forȱ reference,ȱ thisȱ informationȱ isȱ includedȱ inȱ theȱ precedenceȱtable,ȱTableȱ5.1,ȱlaterȱinȱthisȱchapter.ȱ ȱ ȱ ȱ 5.4 Expression Evaluation ȱ Theȱ orderȱ ofȱ expressionȱ evaluationȱ isȱ determinedȱ partiallyȱ byȱ theȱ precedenceȱ andȱ associativityȱofȱtheȱoperatorsȱitȱcontains.ȱAlso,ȱsomeȱofȱtheȱexpressionȇsȱoperandsȱmayȱ needȱtoȱbeȱconvertedȱtoȱotherȱtypesȱduringȱtheȱevaluationȱ ȱ ȱ ȱ 5.4.1 Implicit Type Conversions ȱ ImagerȱarithmeticȱinȱCȱ isȱalwaysȱ performedȱwithȱ atȱ leastȱ theȱprecisionȱofȱ theȱ defaultȱ integerȱ type.ȱ Toȱ achieveȱ thisȱ precision,ȱ characterȱ andȱ shortȱ integerȱ operandsȱ inȱ anȱ expressionȱ areȱ convertedȱ toȱ integersȱ beforeȱ beingȱ usedȱ inȱ theȱ expression.ȱ Theseȱ conversionsȱareȱcalledȱintegralȱpromotions.ȱForȱexample,ȱinȱtheȱevaluationȱofȱ ȱ char ... a = b + c; a, b, c; ȱ theȱ valuesȱ ofȱ bȱ andȱ cȱ areȱ promotedȱ toȱ integersȱ andȱ thenȱ added.ȱ Theȱ resultȱ isȱ thanȱ truncatedȱtoȱfitȱintoȱa.ȱTheȱresultȱinȱthisȱfirstȱexampleȱisȱtheȱsameȱasȱtheȱresultȱifȱ8Ȭbitȱ arithmeticȱwereȱused.ȱButȱtheȱresultȱinȱthisȱsecondȱexample,ȱwhichȱcomputesȱaȱsimpleȱ checksumȱofȱaȱseriesȱofȱcharacters,ȱisȱnotȱtheȱsame.ȱ ȱ a = ( ~ a ^ b << 1 ) >> 1; ȱ ȱ Becauseȱofȱtheȱoneȇsȱcomplementȱandȱtheȱleftȱshift,ȱ8ȱbitsȱofȱprecisionȱareȱinsufficient.ȱ TheȱStandardȱdictatesȱfullȱintegerȱevaluation,ȱsoȱthatȱthereȱisȱnoȱambiguityȱinȱtheȱresultȱ ofȱexpressionsȱsuchȱasȱthisȱone. 27 ȱActually,ȱtheȱStandardȱstatesȱthatȱtheȱresultȱshallȱbeȱthatȱobtainedȱbyȱfullȱintegerȱevaluation,ȱwhichȱallowsȱtheȱpossibilityȱofȱ usingȱ8Ȭbitȱarithmeticȱifȱtheȱcompilerȱcanȱdetermineȱthatȱdoingȱsoȱwouldȱnotȱaffectȱtheȱresult.ȱ 27 Download at http://www.pin5i.com/ 5.4 Expression Evaluation 113 5.4.2 Arithmetic Conversions ȱ Operationsȱ onȱ valuesȱ ofȱ differentȱ typesȱ cannotȱ proceedȱ untilȱ oneȱ ofȱ theȱ operandsȱ isȱ convertedȱ toȱ theȱ typeȱ ofȱ theȱ other.ȱ Theȱ followingȱ hierarchyȱ isȱ calledȱ theȱ usualȱ arithmeticȱconversions:ȱȱ ȱ long double double float unsigned long int long int unsigned int int CAUTION! ȱ Theȱoperandȱwhoseȱtypeȱisȱlowerȱinȱtheȱlistȱisȱconvertedȱtoȱtheȱotherȱoperand’sȱtype.ȱ ȱ Thisȱfragmentȱofȱcodeȱcontainsȱaȱpotentialȱproblem.ȱ ȱ int int long a = 5000; b = 25; c = a * b; ȱ Theȱ problemȱ isȱ thatȱ theȱ expressionȱ a * bȱ isȱ evaluatedȱ usingȱ integerȱ arithmetic.ȱ Thisȱ codeȱworksȱfineȱonȱmachinesȱwithȱ32Ȭbitȱintegers,ȱbutȱtheȱmultiplicationȱoverflowsȱonȱ machinesȱwithȱ16Ȭbitȱintegers,ȱsoȱcȱisȱinitializedȱtoȱtheȱwrongȱvalue.ȱ Theȱ solutionȱ isȱ toȱ convertȱ oneȱ (orȱ both)ȱ ofȱ theȱ valuesȱ toȱ aȱ longȱ beforeȱ theȱ multiplication.ȱ ȱ long c = (long)a * b; ȱ Itȱ isȱ possibleȱ toȱ loseȱ precisionȱ whenȱ convertingȱ anȱ integerȱ toȱ aȱ float.ȱ Floatingȱ valuesȱ areȱ onlyȱ requiredȱ toȱ haveȱ sixȱ decimalȱ digitsȱ ofȱ precision;ȱ ifȱ anȱ integerȱ thatȱ isȱ longerȱthanȱsixȱdigitsȱisȱassignedȱtoȱaȱfloat,ȱtheȱresultȱmayȱbeȱonlyȱanȱapproximationȱofȱ theȱintegerȱvalue.ȱ Whenȱaȱfloatȱisȱconvertedȱtoȱanȱinteger,ȱtheȱfractionalȱpartȱisȱdiscardedȱ(itȱisȱnotȱ rounded).ȱIfȱtheȱnumberȱisȱtooȱlargeȱfitȱinȱanȱinteger,ȱtheȱresultȱisȱundefined.ȱ ȱ ȱ ȱ 5.4.3 Properties of Operators ȱ Thereȱareȱthreeȱfactorsȱthatȱdetermineȱtheȱorderȱinȱwhichȱcomplicatedȱexpressionȱareȱ evaluated:ȱtheȱprecedenceȱofȱtheȱoperators,ȱtheirȱassociativity,ȱandȱwhetherȱtheyȱcontrolȱ theȱ executionȱ order.ȱ Theȱ orderȱ inȱ whichȱ twoȱ adjacentȱ operatorsȱ areȱ evaluatedȱ isȱ Download at http://www.pin5i.com/ Chapter 5 Operators and Expressions 114 ȱ Oper Description Sample Usage () Groupingȱ (ȱexpȱ)ȱ () & Functionȱcallȱ Subscriptȱ Structureȱmemberȱ Structureȱpointerȱmemberȱ Postfixȱincrementȱ Postfixȱincrementȱ Logicalȱnegateȱ Oneȇȱcomplementȱ Unaryȱplusȱ Unaryȱminusȱ Prefixȱincrementȱ Prefixȱdecrementȱ Indirectionȱ Addressȱofȱ sizeof Sizeȱinȱbytesȱ (ȱtypeȱ) * Typeȱconversionȱ Multiplicationȱ Divisionȱ Integerȱremainderȱ Additionȱ Subtractionȱ Leftȱshiftȱ Rightȱshiftȱ rexp(ȱrexp,ȱ...ȱ,ȱrexp )ȱ rexp[ȱrexpȱ]ȱ lexp.member_nameȱ rexp->member_nameȱ lexp++ȱ lexp--ȱ !rexpȱ ~rexpȱ +rexpȱ -rexpȱ ++lexpȱ --lexpȱ *rexpȱ &lexpȱ sizeofȱrexpȱ sizeof(ȱtypeȱ)ȱ (ȱtypeȱ)rexpȱ rexpȱ*ȱrexpȱ rexpȱ/ȱrexpȱ rexpȱ%ȱrexpȱ rexpȱ+ȱrexpȱ rexpȱ–ȱrexpȱ rexpȱ<<ȱrexpȱ rexpȱ>>ȱrexpȱ [] . -> ++ -! ~ + ++ -* / % + << >> Result Associa tivity sameȱ asȱ N/Aȱ expȱ rexpȱ LȬRȱ lexpȱ LȬRȱ lexpȱ LȬRȱ lexpȱ LȬRȱ rexpȱ LȬRȱ rexpȱ LȬRȱ rexpȱ RȬLȱ rexpȱ RȬLȱ rexpȱ RȬLȱ rexpȱ RȬLȱ rexpȱ RȬLȱ rexpȱ RȬLȱ lexpȱ RȬLȱ rexpȱ RȬLȱ Controls Eval ȱ rexpȱ RȬLȱ Noȱ rexpȱ rexpȱ rexpȱ rexpȱ rexpȱ rexpȱ rexpȱ rexpȱ LȬRȱ LȬRȱ LȬRȱ LȬRȱ LȬRȱ LȬRȱ LȬRȱ LȬRȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ ȱ Tableȱ5.1ȱOperatorȱprecedenceȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱcontinued...ȱ ȱ determinedȱ byȱ theirȱ precedence.ȱ Ifȱ theyȱ haveȱ theȱ sameȱ precedence,ȱ theȱ orderȱ ofȱ evaluationȱisȱdeterminedȱbyȱtheirȱassociativity.ȱSimplyȱstated,ȱassociativityȱisȱwhetherȱ aȱ sequenceȱ ofȱoperatorsȱisȱ evaluatedȱ fromȱ leftȱtoȱ rightȱ orȱfromȱrightȱ toȱ left.ȱ ȱ ȱFinally,ȱ thereȱ areȱ fourȱ operatorsȱ thatȱ exertȱ someȱ controlȱ overȱ theȱ orderȱ inȱ whichȱ theȱ entireȱ expressionȱ isȱ evaluated,ȱ specifyingȱ eitherȱ thatȱ oneȱ subexpressionȱ isȱ guaranteedȱ toȱ beȱ evaluatedȱ beforeȱ anythingȱ inȱ anotherȱ subexpressionȱ isȱ computed,ȱ orȱ thatȱ aȱ subexpressionȱmayȱbeȱskippedȱentirely.ȱ Allȱofȱtheȱpropertiesȱareȱlistedȱforȱeachȱofȱtheȱoperatorsȱinȱtheȱprecedenceȱtable,ȱ Tableȱ 5.1.ȱ Theȱ columnsȱ showȱ theȱ operator,ȱ aȱ briefȱ descriptionȱ ofȱ whatȱ itȱ does,ȱ anȱ exampleȱshowingȱhowȱitȱisȱused,ȱwhatȱtypeȱofȱresultȱitȱgives,ȱitsȱassociativity,ȱandȱ Download at http://www.pin5i.com/ 5.4 Expression Evaluation Oper Description Sample Usage > Result Associativity LȬRȱ LȬRȱ LȬRȱ LȬRȱ LȬRȱ LȬRȱ LȬRȱ LȬRȱ LȬRȱ LȬRȱ LȬRȱ N/Aȱ RȬLȱ RȬLȱ RȬLȱ RȬLȱ RȬLȱ RȬLȱ RȬLȱ RȬLȱ RȬLȱ RȬLȱ RȬLȱ LȬRȱ 115 Controls Eval Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Yesȱ Yesȱ Yesȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Noȱ Yesȱ Greaterȱthanȱ rexpȱ>ȱrexpȱ rexpȱ Greaterȱthanȱorȱequalȱ rexpȱ>=ȱrexpȱ rexpȱ < Lessȱthanȱ rexpȱ<ȱrexpȱ rexpȱ <= Lessȱthanȱorȱequalȱ rexpȱ<=ȱrexpȱ rexpȱ == Equalȱtoȱ rexpȱ==ȱrexpȱ rexpȱ != Notȱequalȱtoȱ rexpȱ!=ȱrexpȱ rexpȱ & BitwiseȱANDȱ rexpȱ&ȱrexpȱ rexpȱ ^ BitwiseȱexclusiveȱORȱ rexpȱ^ȱrexpȱ rexpȱ | BitwiseȱinclusiveȱORȱ rexpȱ|ȱrexpȱ rexpȱ && LogicalȱANDȱ rexpȱ&&ȱrexpȱ rexpȱ || LogicalȱORȱ rexpȱ||ȱrexpȱ rexpȱ ?: Conditionalȱ rexpȱ?ȱrexpȱ:ȱrexpȱ rexpȱ = Assignmentȱ lexpȱ=ȱrexpȱ rexpȱ += Addȱtoȱ lexpȱ+=ȱrexpȱ rexpȱ -= Subtractȱfromȱ lexpȱ-=ȱrexpȱ rexpȱ *= Multiplyȱbyȱȱ lexpȱ*=ȱrexpȱ rexpȱ /= Divideȱbyȱ lexpȱ/=ȱrexpȱ rexpȱ %= Moduloȱbyȱ lexpȱ%=ȱrexpȱ rexpȱ <<= Shiftȱleftȱbyȱ lexpȱ<<=ȱrexpȱ rexpȱ >>= Shiftȱrightȱbyȱȱ lexpȱ>>=ȱrexpȱ rexpȱ &= ANDȱwithȱ lexpȱ&=ȱrexpȱ rexpȱ ^= ExclusiveȱORȱwithȱ lexpȱ^=ȱrexpȱ rexpȱ |= InclusiveȱORȱwithȱ lexpȱ|=ȱrexpȱ rexpȱ , Commaȱ rexpȱ,ȱrexpȱ rexpȱ ȱ Tableȱ5.1ȱOperatorȱprecedenceȱ ȱ whetherȱitȱexertsȱsomeȱcontrolȱoverȱtheȱorderȱofȱevaluationȱofȱtheȱexpressionȱinȱwhichȱ itȱ appears.ȱ Theȱ sampleȱ usageȱ indicatesȱ whereȱ LȬvaluesȱ areȱ required;ȱ theȱ termȱ lexpȱ indicatesȱanȱLȬvalueȱexpression,ȱandȱrexpȱisȱanȱRȬvalueȱexpression.ȱȱRememberȱthanȱanȱ LȬvalueȱ denotesȱ aȱ placeȱ andȱ anȱ RȬvalueȱ denotesȱ aȱ value;ȱ soȱ anȱ LȬvalueȱ mayȱ beȱ usedȱ anywhereȱ anȱ RȬvalueȱ isȱ needed,ȱ butȱ anȱ RȬvalueȱ cannotȱ beȱ usedȱ whereȱ anȱ LȬvalueȱ isȱ needed.ȱ ȱ ȱ ȱ >= 5.4.4 Precedence and Order of Evaluation Inȱanȱexpressionȱwithȱmoreȱthanȱoneȱoperator,ȱwhatȱdeterminesȱtheȱorderȱinȱwhichȱtheȱ operationsȱareȱperformed?ȱȱEachȱofȱtheȱCȱoperatorsȱisȱassignedȱaȱprecedence,ȱwhichȱ Download at http://www.pin5i.com/ 116 Chapter 5 Operators and Expressions indicatesȱitsȱrelationȱshipsȱtoȱtheȱremainingȱoperators.ȱButȱprecedenceȱaloneȱdoesȱnotȱ determineȱtheȱorderȱofȱevaluation.ȱHereȱisȱtheȱrule:ȱ ȱ Theȱorderȱofȱevaluationȱofȱtwoȱadjacentȱoperatorsȱisȱdeterminedȱbyȱtheirȱprecedence.ȱIfȱ theyȱhaveȱtheȱsameȱprecedence,ȱtheȱorderȱisȱdeterminedȱbyȱtheirȱassociativity.ȱOtherwise,ȱ theȱcompilerȱisȱfreeȱtoȱevaluateȱexpressionsȱinȱanyȱorderȱthatȱdoesȱnotȱviolateȱtheȱorderȱofȱ evaluationȱimposedȱbyȱparenthesesȱorȱbyȱtheȱcomma,ȱ&&,ȱ||,ȱorȱ?:ȱoperators.ȱ ȱ Inȱotherȱwords,ȱtheȱprecedenceȱofȱtheȱoperatorsȱinȱanȱexpressionȱonlyȱdeterminesȱhowȱ theȱcomponentsȱofȱtheȱexpressionȱareȱgroupedȱtogetherȱduringȱevaluation.ȱ Hereȱisȱanȱexample:ȱ ȱ a + b * c ȱ Inȱthisȱexpression,ȱtheȱmultiplicationȱandȱadditionȱareȱadjacent.ȱTheȱmultiplicationȱisȱ performedȱbeforeȱtheȱadditionȱbecauseȱtheȱ*ȱoperatorȱhasȱhigherȱprecedenceȱthanȱ+.ȱȱ Theȱcompilerȱhasȱnoȱchoiceȱhere:ȱtheȱmultiplicationȱmustȱoccurȱfirstȱ Hereȱisȱaȱmoreȱinterestingȱexpression:ȱ ȱ a * b + c * d + e * f ȱ Ifȱ precedenceȱ aloneȱ determinedȱ theȱ orderȱ ofȱ evaluation,ȱ allȱ threeȱ multiplicationsȱ wouldȱoccurȱbeforeȱanyȱofȱtheȱadditions.ȱInȱfact,ȱthisȱorderingȱisȱnotȱnecessary.ȱAllȱthatȱ isȱ requiredȱ isȱ thatȱ theȱ multiplicationsȱ onȱ eitherȱ sideȱ ofȱ eachȱ additionȱ beȱ performedȱ beforeȱtheȱaddition.ȱȱForȱexample,ȱtheȱexpressionȱmightȱbeȱevaluatedȱinȱtheȱfollowingȱ order.ȱTheȱboldfacedȱoperatorȱisȱtheȱoneȱbeingȱcomputedȱinȱeachȱstep.ȱ ȱ a * b c * d (a*b) + (c*d) e * f (a*b)+(c*d) + (e*f) ȱ Noticeȱthatȱtheȱfirstȱadditionȱisȱperformedȱbeforeȱtheȱlastȱmultiplication.ȱTheȱsameȱ resultȱwouldȱbeȱobtainedȱifȱtheȱexpressionȱwereȱevaluatedȱinȱthisȱorder:ȱ c * d e * f a * b (a*b) + (c*d) (a*b)+(c*d) + (e*f) Download at http://www.pin5i.com/ 5.4 Expression Evaluation CAUTION! 117 Theȱ associativityȱ forȱ additionȱ requiresȱ theȱ twoȱ additionsȱ toȱ beȱ doneȱ leftȱ toȱ right,ȱ butȱ theȱorderȱforȱtheȱrestȱofȱtheȱexpressionȱisȱnotȱconstrained.ȱȱSpecifically,ȱthereȱisnȇtȱanyȱ ruleȱthatȱrequiresȱallȱofȱtheȱmultiplicationsȱtoȱbeȱcomputedȱfirst,ȱnorȱisȱthereȱaȱruleȱthatȱ determinesȱtheȱorderȱinȱwhichȱtheyȱareȱdoneȱrelativeȱtoȱoneȱanother.ȱȱTheȱprecedenceȱ ofȱ theȱ operatorsȱ isȱ notȱ relevantȱ here.ȱ Precedenceȱ onlyȱ controlsȱ theȱ orderȱ inȱ whichȱ adjacentȱoperatorsȱareȱevaluated.ȱ ȱ Theȱ factȱthatȱ theȱorderȱofȱ expressionȱevaluationȱ isȱ notȱ completelyȱ determinedȱbyȱ theȱ precedenceȱofȱtheȱoperatorsȱmakesȱstatementsȱlikeȱthisȱoneȱdangerous.ȱ ȱ ȱ c + --c ȱ Theȱprecedenceȱofȱtheȱoperatorsȱindicatesȱthatȱtheȱ --ȱshouldȱbeȱperformedȱbeforeȱtheȱ +,ȱbutȱthereȱisȱnoȱwayȱtoȱtellȱwhetherȱtheȱleftȱoperandȱofȱtheȱ +ȱwillȱbeȱevaluatedȱbeforeȱ orȱ afterȱ theȱ rightȱ operand.ȱ Itȱ makesȱ aȱ differenceȱ withȱ thisȱ expression,ȱ becauseȱ --ȱ involvesȱ aȱ sideȱ effect.ȱ Theȱ expressionȱ producesȱ aȱ differentȱ resultȱ ifȱ --cȱ isȱ evaluatedȱ beforeȱorȱafterȱc.ȱ Theȱ Standardȱ statesȱ thatȱ theȱ valueȱ ofȱ expressionsȱ suchȱ asȱ theseȱ isȱ undefined.ȱ Althoughȱeveryȱimplementationȱwillȱproduceȱsomeȱvalueȱforȱtheȱexpression,ȱthereȱisȱnoȱ correctȱ answer.ȱ Expressionsȱ likeȱ thisȱ oneȱ areȱ thereforeȱ notȱ portableȱ andȱ mustȱ beȱ avoided.ȱ Programȱ 5.3ȱ illustratesȱ thisȱ problemȱ ratherȱ dramatically.ȱ Tableȱ 5.2ȱ listsȱ theȱ valuesȱ producedȱ byȱ thisȱ programȱ onȱ eachȱ ofȱ theseȱ implementations.ȱ Manyȱ implementationsȱ giveȱ differentȱ valuesȱ dependingȱ onȱ whetherȱ theȱ programȱ wasȱ compiledȱ withȱ orȱ withoutȱ optimization;ȱ forȱ example,ȱ usingȱ theȱ optimizerȱ withȱ gccȱ changesȱ theȱ resultȱ fromȱ Ȭ63ȱ toȱ 22.ȱ Althoughȱ eachȱ compilerȱ hasȱ evaluatedȱ theȱ expressionȱinȱaȱdifferentȱorder,ȱnoneȱofȱtheseȱanswersȱisȱwrong!ȱȱItȱisȱtheȱexpressionȱitselfȱ thatȱisȱfaulty;ȱitsȱorderȱofȱevaluationȱisȱambiguousȱbecauseȱofȱtheȱsideȱeffectsȱofȱmanyȱ ofȱtheȱtermsȱitȱcontains.ȱ ȱ ȱ ȱ ȱ /* ** A program to demonstrate that the order of expression evaluation ** is only partially determined by operator precedence. */ main() { int i = 10; i = i-- - --i * ( i = -3 ) * i++ + ++i; printf( "i = %d\n", i ); } Programȱ5.3ȱAnȱillegalȱexpressionȱȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱbad_exp.cȱ Download at http://www.pin5i.com/ 118 K&R C Chapter 5 Operators and Expressions ȱ Value Implementation Ȭ129ȱ Tandyȱ6000ȱXenixȱ3.2ȱ Ȭ95ȱ ThinkȱCȱ5.0.2ȱ(Macintosh)ȱ Ȭ86ȱ IBMȱPowerPCȱAIXȱ3.2.5ȱ Ȭ85ȱ SunȱSparcȱccȱ(aȱK&Rȱcompiler)ȱ Ȭ63ȱ gcc,ȱHPȬUXȱ9.0,ȱPowerȱCȱ2.0.0ȱ 4ȱ SunȱSparcȱaccȱ(anȱANSIȱcompiler)ȱ 21ȱ TurboȱC/C++ȱ4.5ȱ 22ȱ FreeBSDȱ2.1Rȱ 30ȱ DecȱAlphaȱOSF1ȱ2.0ȱ 36ȱ DecȱVAX/VMSȱ 42ȱ MicrosoftȱCȱ5.1ȱ ȱ Tableȱ5.2ȱResultsȱofȱillegalȱexpressionȱprogramȱ ȱ ȱ ȱ Inȱ K&Rȱ C,ȱ theȱ compilerȱ wasȱ freeȱ toȱ evaluateȱ theȱ expressionsȱ shownȱ belowȱ inȱ anyȱ order.ȱ a + b + c x * y * z ȱ Theȱreasoningȱbehindȱthisȱdecisionȱisȱthatȱtheȱvalueȱofȱb + cȱ(orȱofȱy * z)ȱmightȱstillȱbeȱ availableȱ fromȱ someȱ earlierȱ expression,ȱ soȱ itȱ wouldȱ beȱ moreȱ efficientȱ toȱ reuseȱ thatȱ valueȱthanȱcomputeȱitȱagain.ȱAdditionȱandȱmultiplicationȱareȱassociative,ȱsoȱwhereȱisȱ theȱharm?ȱ Considerȱtheȱexpressionȱbelow,ȱwhichȱusesȱsignedȱintegerȱvariables:ȱ x + y + 1 Ifȱtheȱresultȱofȱtheȱexpressionȱ x + yȱisȱlargerȱthanȱanȱintegerȱisȱcapableȱofȱstoring,ȱanȱ overflowȱhasȱoccurred.ȱOnȱsomeȱmachines,ȱtheȱresultȱofȱtheȱtestȱ ȱ if( x + y + 1 > 0 ) ȱ willȱdependȱonȱwhetherȱx + yȱorȱ y + 1ȱisȱevaluatedȱfirst,ȱbecauseȱtheȱoverflowȱoccursȱ atȱdifferentȱpointsȱinȱeachȱcase.ȱTheȱproblemȱisȱthatȱtheȱprogrammerȱcouldȱnotȱpredictȱ withȱ certaintyȱ whichȱ wayȱ theȱ compilerȱ wouldȱ evaluateȱ theȱ expression.ȱ Experienceȱ showedȱthatȱthisȱpracticeȱwasȱaȱbadȱidea,ȱsoȱitȱisȱnotȱallowedȱwithȱANSIȱCȱ Theȱfollowingȱexpressionȱillustratesȱaȱrelatedȱproblem.ȱ ȱ f() + g() + h() Download at http://www.pin5i.com/ 5.5 Summary 119 Althoughȱtheȱleftȱadditionȱmustȱbeȱperformedȱbeforeȱtheȱrightȱaddition,ȱthereȱisȱnoȱ ruleȱconstrainingȱtheȱorderȱinȱwhichȱtheȱfunctionsȱareȱcalled.ȱIfȱtheirȱexecutionȱbadȱ sideȱeffects,ȱsuchȱasȱdoingȱanyȱI/Oȱorȱmodifyingȱglobalȱvariables,ȱtheȱresultȱmayȱbeȱ differentȱforȱdifferentȱordersȱofȱevaluation.ȱIfȱtheȱorderȱmakesȱanyȱdifference,ȱuseȱ temporaryȱvariablesȱsoȱthatȱeachȱfunctionȱisȱcalledȱinȱaȱseparateȱstatement.ȱ ȱ temp = f(); temp += g(); temp += h(); ȱ ȱ ȱ 5.5 Summary ȱ Cȱ hasȱ aȱ richȱ collectionȱ ofȱ operators.ȱ ȱ Theȱ arithmeticȱ operatorsȱ includeȱ +ȱ (addition),ȱ -ȱ (subtraction),ȱ *ȱ (multiplication),ȱ /ȱ (division),ȱ andȱ %ȱ (modulo).ȱ ȱ Allȱ ofȱ theseȱ exceptȱ moduloȱworkȱwithȱbothȱintegerȱandȱfloatingȬpointȱvalues.ȱ Theȱ <<ȱandȱ >>ȱoperatorsȱperformȱleftȱandȱrightȱshifts,ȱrespectively.ȱTheȱ &,ȱ |ȱandȱ ^ȱoperatorsȱperformȱbitwiseȱAND,ȱOR,ȱandȱXORȱoperations,ȱrespectively.ȱAllȱofȱtheseȱ operatorsȱrequireȱintegralȱoperands.ȱ Theȱ =ȱ operatorȱ performsȱ assignment.ȱ Furthermore,ȱ thereȱ areȱ compoundȱ assignmentȱoperatorsȱforȱallȱofȱtheȱprecedingȱoperators:ȱ ȱ += <<= -= >>= *= &= /= ^= %= |= ȱ Theȱ compoundȱ assignmentsȱ performȱ theȱ indicatedȱ operationȱ betweenȱ theȱ leftȱ andȱ rightȱoperands,ȱandȱthenȱassignȱtheȱresultȱtoȱtheȱleftȱoperand.ȱ Theȱunaryȱoperatorsȱincludeȱ|ȱ(logicalȱNOT),ȱ-ȱ(oneȇsȱcomplement),ȱ-(negative),ȱ andȱ +ȱ (positive).ȱ Theȱ ++ȱ andȱ --ȱ operatorsȱ incrementȱ andȱ decrementȱ theirȱ operand,ȱ respectively.ȱ Bothȱ ofȱ theseȱ operatorsȱ haveȱ prefixȱ andȱ postfixȱ forms;ȱ theȱ prefixȱ formȱ returnsȱtheȱvalueȱofȱtheȱoperandȱafterȱitȱisȱmodified,ȱwhileȱtheȱpostfixȱformȱreturnsȱtheȱ valueȱbeforeȱtheȱoperandȱisȱmodified.ȱTheȱ &ȱoperatorȱreturnsȱaȱpointerȱtoȱ(theȱaddressȱ of)ȱitsȱoperand,ȱandȱtheȱ*ȱoperatorȱperformsȱindirectionȱonȱitsȱoperandȱ(whichȱmustȱbeȱ aȱpointer),ȱ sizeofȱreturnsȱtheȱsizeȱofȱitsȱoperand,ȱmeasuredȱinȱbytes.ȱȱFinally,ȱaȱcastȱisȱ usedȱtoȱchangeȱtheȱtypeȱofȱanȱexpression.ȱ Theȱrelationalȱoperatorsȱare:ȱ ȱ > >= < <= != == ȱ Eachȱoperatorȱreturnsȱeitherȱtrueȱorȱfalseȱdependingȱonȱwhetherȱtheȱoperandsȱhaveȱtheȱ indicatedȱrelationship.ȱȱTheȱlogicalȱoperatorsȱevaluateȱcomplexȱbooleanȱexpression.ȱȱ Download at http://www.pin5i.com/ 120 Chapter 5 Operators and Expressions &&ȱ isȱ trueȱ onlyȱ ifȱ bothȱ ofȱ itsȱ operandsȱ areȱ true,ȱ andȱ ||ȱ isȱ falseȱ onlyȱ ifȱ bothȱ ofȱ itsȱ operandsȱareȱfalse.ȱBothȱofȱtheȱlogicalȱoperatorsȱexertȱcontrolȱoverȱtheȱevaluationȱofȱtheȱ expressionȱ inȱ whichȱ theyȱ appear.ȱ Ifȱ theȱ resultȱ ofȱ theȱ expressionȱ canȱ beȱ determinedȱ fromȱtheȱleftȱoperand,ȱthenȱtheȱrightȱoperandȱisȱnotȱevaluated.ȱ Theȱconditionalȱoperatorȱ ?:ȱtakesȱthreeȱoperands,ȱandȱalsoȱexertsȱcontrolȱoverȱ expressionȱevaluation.ȱIfȱtheȱfirstȱoperandȱisȱtrue,ȱtheȱresultȱisȱtheȱvalueȱofȱtheȱsecondȱ operandȱandȱtheȱthirdȱoperandȱisȱnotȱevaluated.ȱOtherwise,ȱtheȱresultȱisȱtheȱvalueȱofȱ theȱthirdȱoperand,ȱandȱtheȱsecondȱisȱnotȱevaluated.ȱTheȱcommaȱoperatorȱjoinsȱtwoȱorȱ moreȱ expressions,ȱ whichȱ areȱ evaluatedȱ fromȱ leftȱ toȱ right.ȱ Theȱ resultȱ ofȱ theȱ entireȱ expressionȱisȱtheȱresultȱofȱtheȱrightmostȱsubexpression.ȱ Cȱ doesȱ notȱ haveȱ anȱ explicitȱ booleanȱ type,ȱ soȱ integerȱ expressionsȱ areȱ usedȱ toȱ representȱbooleanȱvalues.ȱHowever,ȱmixingȱbooleanȱvaluesȱwithȱarbitraryȱintegersȱinȱ expressionsȱ canȱ causeȱ errors.ȱ Toȱ avoidȱ theseȱ errors,ȱ treatȱ eachȱ variableȱ asȱ eitherȱ aȱ booleanȱorȱanȱinteger.ȱDoȱnotȱuseȱbooleanȱtestsȱonȱintegerȱvariablesȱorȱviceȱversa.ȱ AnȱLȬvalueȱisȱanȱexpressionȱthatȱcanȱbeȱusedȱonȱtheȱleftȱsideȱofȱanȱassignment;ȱitȱ denotesȱaȱplaceȱinȱtheȱcomputerȇsȱmemory.ȱAnȱRȬvalueȱdenotesȱaȱvalue,ȱsoȱitȱcanȱonlyȱ beȱusedȱonȱtheȱrightȱsideȱofȱanȱassignment.ȱEveryȱexpressionȱthatȱisȱanȱLȬvalueȱisȱalsoȱ anȱRȬvalue,ȱbutȱtheȱreverseȱisȱnotȱtrue.ȱ Operationsȱ onȱ valuesȱ ofȱ differentȱ typesȱ cannotȱ proceedȱ untilȱ oneȱ ofȱ theȱ operandsȱ isȱ convertedȱ toȱ theȱ typeȱ ofȱ theȱ other.ȱ Theȱ usualȱ arithmeticȱ conversionsȱ determineȱ whichȱ operandȱ isȱ converted.ȱ Theȱ precedenceȱ ofȱ operatorsȱ relativeȱ toȱ oneȱ anotherȱ determinesȱ theȱ orderȱ inȱ whichȱ adjacentȱ operatorsȱ willȱ beȱ evaluated.ȱ ȱ Ifȱ theirȱ precedenceȱisȱtheȱsame,ȱthenȱtheȱoperatorsȇȱassociativityȱdeterminesȱtheȱorderȱinȱwhichȱ theyȱwillȱbeȱevaluated.ȱHowever,ȱtheseȱrulesȱdoȱnotȱcompletelyȱdetermineȱtheȱorderȱofȱ evaluation,ȱandȱtheȱcompilerȱisȱfreeȱtoȱevaluateȱcomplexȱexpressionsȱinȱanyȱorderȱthatȱ doesȱ notȱ violateȱ theȱ precedenceȱ orȱ associativityȱ rules.ȱ Expressionsȱ whoseȱ resultȱ dependsȱonȱtheȱorderȱofȱevaluationȱareȱinherentlyȱnonportableȱandȱshouldȱbeȱavoided.ȱ ȱ ȱ ȱ 5.6 Summary of Cautions ȱ 1. Rightȱshiftsȱonȱsignedȱvaluesȱareȱnotȱportableȱ(pageȱ95).ȱ ȱ 2. Shiftingȱwithȱnegativeȱshiftȱcountsȱ(pageȱ95).ȱ ȱ 3. Chainedȱassignmentȱamongȱvariablesȱwithȱdifferentȱsizesȱ(pageȱ98).ȱ ȱ Download at http://www.pin5i.com/ 5.8 Question 121 4. Usingȱ=ȱratherȱthanȱ==ȱtoȱperformȱaȱcomparisonȱ(pageȱ104).ȱ 5. Usingȱ|ȱinsteadȱofȱ||,ȱorȱ&ȱinsteadȱofȱ&&ȱ(pageȱ105).ȱ 6. ComparingȱdifferentȱnonzeroȱvaluesȱasȱBooleanȱvaluesȱ(pageȱ110).ȱ 7. Theȱlocationȱtoȱwhichȱanȱexpressionȱisȱassignedȱdoesȱnotȱdetermineȱtheȱprecisionȱ withȱwhichȱtheȱexpressionȱisȱevaluatedȱ(pageȱ113).ȱ 8. Writingȱexpressionsȱwhoseȱvalueȱdependsȱonȱtheȱorderȱofȱevaluationȱ(pageȱ117).ȱ ȱ ȱ ȱ 5.7 Summary of Programming Tips ȱ 1. Usingȱassignmentȱoperatorsȱmakesȱtheȱprogramȱeasierȱtoȱmaintainȱ(pageȱ99).ȱ 2. Usingȱtheȱconditionalȱoperatorȱratherȱthanȱifȱtoȱsimplifyȱexpressionȱ(pageȱ106).ȱ 3. Usingȱtheȱcommaȱoperatorȱtoȱeliminateȱduplicateȱcodeȱ(pageȱ108).ȱ 4. Doȱnotȱmixȱintegerȱandȱbooleanȱvaluesȱ(pageȱ110).ȱ ȱ ȱ ȱ 5.8 Summary ȱ 1. Whatȱisȱtheȱtypeȱandȱvalueȱofȱtheȱexpression?ȱ ȱ (float)( 25 / 10 ) ȱ 2. Whatȱisȱtheȱresultȱofȱtheȱfollowingȱprogram?ȱ ȱ int func( void ) { static return int counter = 1; ++counter; } int main() { int answer; answer = func() – func() * func(); printf( "%d\n", answer ); } Download at http://www.pin5i.com/ 122 Chapter 5 Operators and Expressions 3. Whatȱusesȱcanȱyouȱthinkȱofȱtheȱbitwiseȱandȱshiftingȱoperators?ȱ 4. Isȱ theȱ conditionalȱ operatorȱ fasterȱ orȱ slowerȱ atȱ runȱ timeȱ thanȱ anȱ ifȱ statement?ȱ Specifically,ȱcompareȱtheseȱtwoȱcodeȱfragments:ȱ ȱ if( a > 3 ) i = a > 3 ? b + 1 : c *5; i = b + 1; else i = c * 5; ȱ 5. Yearsȱthatȱareȱdivisibleȱbyȱfourȱareȱleapȱyearsȱwithȱoneȱexceptionȱ–ȱyearsȱthatȱareȱ divisibleȱ byȱ 100ȱ areȱ not.ȱ However,ȱ yearsȱ thatȱ areȱ divisibleȱ byȱ 400ȱ areȱ leapȱ years.ȱ Writeȱ aȱ singleȱ assignmentȱ thatȱ setsȱ leap_yearȱ trueȱ ifȱ theȱ valueȱ inȱ yearȱ isȱ aȱ leapȱ year,ȱandȱfalseȱifȱitȱisȱnot.ȱ 6. Whichȱoperatorsȱhaveȱsideȱeffects,ȱandȱwhatȱareȱthey?ȱ 7. Whatȱisȱtheȱresultȱofȱthisȱcodeȱfragment?ȱ ȱ int a = 20; ... if( 1 <= a <= 10 ) printf( "In range\n" ); else printf( "Out of range\n" ); ȱ 8. Rewriteȱthisȱfragmentȱofȱcodeȱtoȱeliminateȱtheȱredundancies.ȱ ȱ a = f1( x ); b = f2( x + a ); for( c = f3( a, b ); c > 0; c = f3( a, b ) ){ statements a = f1( ++x ); b = f2( x + a ); } ȱ 9. Doesȱtheȱfollowingȱloopȱaccomplishȱwhatȱitȱisȱtryingȱtoȱdo?ȱ ȱ non_zero = 0; for( i = 0; i < ARRAY_SIZE; i += 1 ) non_zero += array[i]; if( !non_zero ) printf( "Values are all zero\n" ); else printf( "There are nonzero values\n" ); Download at http://www.pin5i.com/ 5.8 Question 123 ȱ ȱ 10. Givenȱ theȱ variableȱ declarationsȱ andȱ initializationȱ below,ȱ evaluateȱ eachȱ ofȱ theȱ followingȱ expressions.ȱ Ifȱ anȱ expressionȱ hasȱ sideȱ effectsȱ (thatȱ is,ȱ ifȱ itȱ changesȱ theȱ valueȱ ofȱ oneȱ orȱ moreȱ variables),ȱ noteȱ themȱ asȱ well.ȱ ȱ Useȱ theȱ initialȱ valuesȱ givenȱ belowȱ forȱ eachȱ variable,ȱ notȱ theȱ resultsȱ ofȱ theȱ precedingȱ expression,ȱ toȱ evaluateȱ eachȱexpression.ȱ ȱ int int int a = 10, b = -25; c = 0, d = 3; e = 20; ȱ a. b b. b++ c. –a d. a / 6 e. a % 6 f. b % 10 g. a << 2 h. b >> 3 i. a > b j. b = a k. b == a l. a & b m. a ^ b n. a | b o. ~b p. c && a q. c || a r. b ? a : c s. a += 2 Download at http://www.pin5i.com/ 124 Chapter 5 Operators and Expressions t. b &= 20 u. b >>= 3 v. a %= 6 w. d = a > b x. a = b = c = d y. e = d + ( c = a + b ) + c z. a + b * 3 aa. b >> a – 4 bb. a != b != c cc. a == b == c dd. d < a < e ee. e > a > d ff. a – 10 > b + 10 gg. a & 0x1 == b & 0x1 hh. a | b << a & b ii. a > c || ++a > b jj. a > c && ++a > b kk. ! ~ b++ ll. b++ & a <= 30 mm. a – b, c += d, e – c nn. a >>= 3 > 0 oo. a <<= d > 20 ? b && c++ : d— 11. Several expressions are listed below. Determine how each expression is being evaluated by the compiler, and remove as many parentheses as possible without changing the order of evaluation. a. a + ( b / c ) b. ( a + b ) / c c. ( a * b ) % 6 d. a * ( b % 6 ) e. ( a + b ) == 6 Download at http://www.pin5i.com/ 5.9 Programming Exercises f. !( ( a >= '0' ) && ( a <= '9' ) ) g. ( ( a & 0x2f ) == ( b | 1 ) ) && ( ( ~ c ) > 0 ) h. ( ( a << b ) – 3 ) < ( b << ( a + 3 ) ) i. ~ ( a ++ ) j. ((a == 2) || (a == 4)) && ((b == 2) || (b == 4)) k. ( a & b ) ^ ( a | b ) l. ( a + ( b + c ) ) 125 ȱ 12. Howȱ canȱ youȱ determineȱ whetherȱ aȱ rightȱ shiftȱ ofȱ aȱ signedȱ valueȱ isȱ performedȱ onȱ yourȱmachineȱasȱanȱarithmeticȱorȱaȱlogicalȱshift?ȱ ȱ ȱ ȱ 5.9 Programming Exercises ȱ 1. Writeȱaȱprogramȱthatȱreadsȱcharactersȱfromȱtheȱstandardȱinputȱandȱwritesȱthemȱtoȱ theȱ standardȱ output.ȱ Allȱ charactersȱ shouldȱ beȱ writtenȱ exactlyȱ asȱ theyȱ wereȱ readȱ exceptȱthatȱuppercaseȱlettersȱshouldȱbeȱconvertedȱtoȱlowercase.ȱ 2. Writeȱaȱprogramȱthatȱreadsȱcharactersȱfromȱtheȱstandardȱinputȱandȱwritesȱthemȱtoȱ theȱ standardȱ output.ȱ ȱ Allȱ charactersȱ shouldȱ beȱ writtenȱ exactlyȱ asȱ theyȱ wereȱ readȱ exceptȱforȱalphabeticȱcharacters,ȱwhichȱareȱencryptedȱbeforeȱbeingȱwritten.ȱȱ Theȱ encryptionȱ processȱ isȱ straightforward:ȱ eachȱ letterȱ isȱ changedȱ toȱ whateverȱ letterȱ appearsȱ 13ȱ placesȱ afterȱ (orȱ before)ȱ itȱ inȱ theȱ alphabet.ȱ Forȱ instance,ȱ anȱ Aȱ isȱ changedȱtoȱanȱ N,ȱ aȱ Bȱ isȱchangedȱtoȱanȱ O,ȱ aȱ Zȱisȱchangedȱtoȱanȱ M,ȱandȱsoȱforth.ȱȱNoteȱ thatȱ bothȱ upperȱ andȱ lowercaseȱ lettersȱ mustȱ beȱ converted.ȱ Hint:ȱ Itȱ mayȱ helpȱ toȱ rememberȱthatȱaȱcharacterȱisȱreallyȱjustȱanȱintegerȱwithȱaȱsmallȱvalue.ȱ 3. Writeȱtheȱfunctionȱ unsigned int reverse_bits( unsigned in value ); Thisȱfunctionȱreturnsȱtheȱnumberȱconstructedȱbyȱreversingȱtheȱorderȱofȱtheȱbitsȱinȱ valueȱfromȱleftȱtoȱright.ȱForȱexample,ȱonȱaȱ32Ȭbitȱmachineȱtheȱnumberȱ25ȱcontainsȱ theseȱbits:ȱ 00000000000000000000000000011001 Theȱfunctionȱshouldȱreturnȱ2,550,136,832,ȱwhichȱisȱcomposedȱofȱtheseȱbits:ȱ 10011000000000000000000000000000 Tryȱ toȱ writeȱ yourȱ functionȱ soȱ thatȱ itȱ doesȱ notȱ dependȱ onȱ theȱ integerȱ sizeȱ ofȱ yourȱ machine.ȱ Download at http://www.pin5i.com/ Chapter 5 Operators and Expressions 126 4. Writeȱaȱsetȱofȱfunctionsȱthatȱimplementȱanȱarrayȱofȱbits.ȱȱTheȱfunctionsȱshouldȱhaveȱ theȱfollowingȱprototypes:ȱ void set_bit( char bit_array[], unsigned bit_number ); void clear_bit( char bit_array[], unsigned bit_number ); void assign_bit( char bit_array[], unsigned bit_number, int value ); int test_bit( char bit_array[], unsigned bit_numlber ); Theȱfirstȱargumentȱinȱeachȱofȱtheseȱfunctionsȱisȱaȱcharacterȱarrayȱinȱwhichȱtheȱbitsȱ areȱactuallyȱstored.ȱȱTheȱsecondȱargumentȱidentifiesȱtheȱbitȱtoȱbeȱaccessed;ȱitȱisȱupȱ toȱtheȱcallerȱtoȱensureȱthatȱthisȱvalueȱisȱnotȱtooȱlargeȱforȱtheȱarrayȱbeingȱused.ȱ Theȱfirstȱfunctionȱsetsȱtheȱspecifiedȱbitȱtoȱone,ȱandȱtheȱsecondȱclearsȱit.ȱTheȱthirdȱ functionȱsetsȱtheȱbitȱtoȱzeroȱifȱtheȱ valueȱisȱzero,ȱotherwiseȱitȱsetsȱtheȱbitȱtoȱone.ȱTheȱ lastȱfunctionȱreturnsȱtrueȱifȱtheȱspecifiedȱbitȱisȱnonzero,ȱelseȱfalse.ȱ 5. Writeȱ aȱ functionȱ thatȱ willȱ storeȱ aȱ givenȱ valueȱ intoȱ specifiedȱ bitȱ positionsȱ ofȱ anȱ integer.ȱItȱshouldȱhaveȱthisȱprototype:ȱ ȱ int store_bit_field( int original_value, int value_to_stor, unsigned starting_bit, unsigned ending_bit ); ȱ Assumeȱ thatȱ theȱ bitsȱ inȱ anȱ integerȱ areȱ numberedȱ fromȱ rightȱ toȱ left.ȱ Thus,ȱ theȱ startingȱbitȱpositionȱmayȱnotȱbeȱlessȱthanȱtheȱendingȱbitȱposition.ȱ Toȱillustrate,ȱthisȱfunctionȱshouldȱreturnȱtheȱfollowingȱvalues:ȱ ȱ Original Value to Store Starting Bit Ending Bit Returned Value Value 0x0 0xffff 0xffff 0x1 0x123 0x123 4 15 13 4 4 9 0x10 0x123f 0xc7ff ȱ Hint:ȱThereȱareȱfiveȱstepsȱinȱstoringȱaȱvalueȱinȱaȱfieldȱofȱbits.ȱ ȱ 1. Constructȱ aȱ mask,ȱ aȱ valueȱ withȱ onesȱ inȱ theȱ bitȱ positionsȱ thatȱ correspondȱ toȱ theȱdesiredȱfield.ȱ Download at http://www.pin5i.com/ 5.9 Programming Exercises 127 2. Usingȱtheȱoneȇsȱcomplementȱofȱtheȱmask,ȱclearȱallȱofȱtheȱbitsȱinȱtheȱfield.ȱ 3. Shiftȱtheȱnewȱvalueȱleftȱsoȱthatȱitȱisȱalignedȱinȱtheȱfield.ȱ 4. ANDȱtheȱshiftedȱvalueȱwithȱtheȱmaskȱtoȱensureȱthatȱitȱhasȱnoȱbitsȱoutsideȱofȱ theȱfield.ȱ 5. ORȱtheȱresultingȱvalueȱintoȱtheȱoriginalȱinteger.ȱ ȱ Theȱ mostȱ difficultȱ ofȱ theseȱ tasksȱ isȱ constructingȱ theȱ mask.ȱ Youȱ mightȱ beginȱ byȱ castingȱtheȱvalueȱ~0ȱtoȱanȱunsignedȱvalueȱandȱthenȱshiftingȱit.ȱ Download at http://www.pin5i.com/ Download at http://www.pin5i.com/ 6 Pointers Itȇsȱ timeȱ weȱ talkȱ inȱ detailȱ aboutȱ pointers,ȱ becauseȱ weȱ willȱ beȱ usingȱ themȱ constantlyȱ throughoutȱtheȱrestȱofȱtheȱbook.ȱYouȱmayȱalreadyȱbeȱfamiliarȱwithȱsomeȱorȱallȱofȱtheȱ backgroundȱ informationȱ discussedȱ inȱ thisȱ chapter.ȱ ȱ Ifȱ youȱ arenȇt,ȱ studyȱ itȱ carefullyȱ becauseȱyourȱunderstandingȱofȱpointersȱwillȱrestȱonȱthisȱfoundation.ȱ ȱ ȱ ȱ 6.1 Memory and Addresses ȱ Asȱ mentionedȱ earlier,ȱ weȱ canȱ viewȱ theȱ computerȇsȱ memoryȱ asȱ aȱ rowȱ ofȱ housesȱ onȱ aȱ longȱstreet.ȱEachȱhouseȱisȱcapableȱofȱholdingȱdataȱandȱisȱidentifiedȱbyȱaȱhouseȱnumber.ȱ Thisȱ analogyȱ isȱ usefulȱ butȱ limited.ȱ Computerȱ memoriesȱ areȱ composedȱ ofȱ millionsȱofȱbits,ȱeachȱcapableȱofȱholdingȱeitherȱtheȱvalueȱ0ȱorȱtheȱvalueȱ1.ȱThisȱlimitedȱ rangeȱofȱvaluesȱisȱnotȱterriblyȱuseful,ȱsoȱbitsȱareȱusuallyȱgroupedȱtogetherȱandȱtreatedȱ asȱaȱunitȱinȱorderȱtoȱstoreȱaȱwiderȱrangeȱofȱvalues.ȱHereȱisȱaȱpictureȱofȱaȱfewȱmemoryȱ locationsȱonȱaȱrealȱmachine.ȱ ȱ 100ȱ ȱ 101ȱ ȱ 102 ȱ 103 ȱ 104 ȱ 105ȱ ȱ 106 ȱ 107 ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Eachȱofȱtheseȱlocationsȱisȱcalledȱaȱbyte,ȱandȱeachȱcontainsȱasȱmanyȱbitsȱasȱnecessaryȱtoȱ storeȱ aȱ singleȱ character.ȱ Onȱ manyȱ modernȱ machines,ȱ eachȱ byteȱ containsȱ eightȱ bits,ȱ whichȱcanȱ storeȱunsignedȱintegersȱ fromȱ0ȱ toȱ 255ȱ orȱ signedȱ integersȱfromȱȬ128ȱtoȱ 127.ȱȱ Theȱ previousȱ diagramȱ doesȱ notȱ showȱ theȱ contentsȱ ofȱ theȱ locations,ȱ thoughȱ everyȱ locationȱinȱmemoryȱalwaysȱcontainsȱsomeȱvalue.ȱEachȱbyteȱisȱidentifiedȱbyȱanȱaddress,ȱ whichȱisȱrepresentedȱinȱtheȱdiagramȱbyȱtheȱnumbersȱaboveȱeachȱbox.ȱ ȱ Download at http://www.pin5i.com/ 130ȱ Chapter 6 Pointer Toȱstoreȱevenȱlargerȱvalues,ȱweȱtakeȱtwoȱorȱmoreȱbytesȱandȱtreatȱthemȱasȱifȱtheyȱ wereȱaȱsingle,ȱlargerȱunitȱofȱmemory.ȱȱForȱexample,ȱmanyȱmachinesȱstoreȱintegersȱinȱ words,ȱeachȱcomposedȱofȱtwoȱorȱfourȱbytes.ȱȱHereȱareȱtheȱsameȱmemoryȱlocations,ȱthisȱ timeȱviewedȱasȱfourȬbyteȱwords.ȱ ȱȱ 100ȱ ȱ ȱ ȱ ȱ 104 ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Becauseȱ theyȱ containȱ moreȱ bits,ȱ eachȱ wordȱ isȱ capableȱ ofȱ holdingȱ unsignedȱ integersȱ fromȱ 0ȱ toȱ 4,294,967,295ȱ (232ȱ –ȱ 1)ȱ orȱ signedȱ integersȱ fromȱ –2,147,483,648ȱ (–231)ȱ toȱ 2,147,483,647ȱ(231ȱ–ȱ1).ȱ Noteȱthatȱevenȱthoughȱaȱwordȱcontainsȱfourȱbytes,ȱitȱhasȱonlyȱoneȱaddress.ȱȱItȱisȱ machineȬdependentȱwhetherȱtheȱaddressȱofȱaȱwordȱisȱtheȱaddressȱofȱtheȱleftmostȱbyteȱ inȱ theȱ wordȱ orȱ theȱ rightmost.ȱ Boundaryȱ alignmentȱ isȱ anotherȱ hardwareȱ issue.ȱ Onȱ machinesȱ withȱ thisȱ requirement,ȱ integersȱ canȱ onlyȱ beginȱ withȱ certainȱ bytes,ȱ usuallyȱ thoseȱwhoseȱaddressesȱareȱmultiplesȱofȱtwoȱorȱfour.ȱButȱtheseȱissuesȱareȱtheȱhardwareȱ designerȇsȱproblem,ȱandȱ theyȱrarelyȱ affectȱCȱprogrammers.ȱWeȱareȱ interestedȱ inȱ onlyȱ twoȱissues:ȱ ȱ 1. Eachȱlocationȱinȱmemoryȱisȱidentifiedȱbyȱaȱuniqueȱaddress.ȱ 2. Eachȱlocationȱinȱmemoryȱcontainsȱaȱvalue.ȱ ȱ ȱ ȱ 6.1.1 Address Versus Contents ȱ Hereȱisȱanotherȱexample,ȱthisȱtimeȱshowingȱtheȱcontentsȱofȱfiveȱwordsȱinȱmemory.ȱ ȱ 100ȱ ȱ ȱ 104 ȱ ȱ 108 ȱ ȱ 112ȱ ȱ ȱ 116 ȱ ȱ ȱ ȱ 112ȱ ȱ ȱ Ȭ1ȱ 1078523331ȱ ȱ ȱ 100ȱ ȱ ȱ 108 ȱ Fiveȱ integerȱ valuesȱ areȱ shown,ȱ eachȱ inȱ itsȱ ownȱ word.ȱ Ifȱ youȱ rememberȱ theȱ addressȱ whereȱyouȱstoredȱsomeȱvalue,ȱyouȱcanȱuseȱthatȱaddressȱlaterȱtoȱretrieveȱtheȱvalue.ȱ ȱ Itȱ isȱ cumbersomeȱ toȱ rememberȱ allȱ ofȱ thoseȱ addresses,ȱ though,ȱ soȱ oneȱ ofȱ theȱ thingsȱthatȱhighȬlevelȱlanguagesȱprovideȱisȱtheȱabilityȱtoȱreferȱtoȱmemoryȱlocationsȱbyȱ nameȱ ratherȱ thanȱ byȱ address.ȱ Hereȱ isȱ theȱ sameȱ picture,ȱ thisȱ timeȱ withȱ namesȱ substitutedȱforȱaddresses.ȱ Download at http://www.pin5i.com/ 6.2 Values and Their Types ȱ aȱ ȱ ȱ ȱ ȱ 112ȱ bȱ ȱ ȱ ȱ ȱ cȱ Ȭ1ȱ ȱ ȱ 1078523331ȱ dȱ ȱ ȱ ȱ ȱ 100ȱ eȱ ȱ ȱ 131 ȱ ȱ 108 ȱ Ofȱcourse,ȱtheseȱnamesȱareȱwhatȱweȱcallȱvariables.ȱItȱisȱimportantȱtoȱrememberȱthatȱthisȱ associationȱofȱnamesȱwithȱlocationsȱisȱnotȱ providedȱbyȱtheȱhardware,ȱitȱisȱsomethingȱ thatȱ theȱ compilerȱ doesȱ forȱ us.ȱ ȱ ȱ Allȱ variablesȱ giveȱ usȱ isȱ aȱ moreȱ convenientȱ wayȱ ofȱ rememberingȱtheȱaddresses—theȱhardwareȱstillȱaccessesȱmemoryȱlocationsȱusingȱaddresses.ȱ ȱ ȱ ȱ 6.2 Values and Their Types ȱ Nowȱletȇsȱlookȱatȱtheȱvaluesȱstoredȱinȱtheseȱlocations.ȱȱTheȱfirstȱtwoȱlocationsȱappearȱtoȱ containȱintegerȱvalues.ȱȱTheȱthirdȱisȱaȱveryȱlargeȱinteger,ȱandȱtheȱfourthȱandȱfifthȱareȱ alsoȱintegers.ȱȱOrȱsoȱitȱseems.ȱȱHereȱareȱtheȱdeclarationsȱforȱtheseȱvariables:ȱ int a = 112, b = -1; float c = 3.14; int *d = &a; float *e = &c; ȱ Theȱdeclarationsȱconfirmȱthatȱtheȱvariablesȱ aȱandȱ bȱdoȱindeedȱcontainȱintegerȱvalues,ȱ butȱ claimȱ thatȱ cȱ oughtȱ toȱ containȱ aȱ floatingȬpointȱ value.ȱ ȱ Butȱ cȱ wasȱ shownȱ inȱ theȱ illustrationȱasȱanȱinteger.ȱȱWell,ȱwhichȱisȱit,ȱanȱintegerȱorȱaȱfloatingȬpointȱnumber?ȱ Theȱ answerȱ isȱ thatȱ theȱ variableȱ containsȱ aȱ sequenceȱ ofȱ bits,ȱ 0ȇsȱ andȱ 1ȇs.ȱ Theyȱ couldȱbeȱinterpretedȱeitherȱasȱanȱintegerȱorȱasȱaȱfloatingȬpointȱnumber,ȱdependingȱonȱ theȱ mannerȱ inȱ whichȱ theyȱ areȱ used.ȱ Ifȱ integerȱ arithmeticȱ instructionsȱ areȱ used,ȱ theȱ valueȱ isȱ interpretedȱ asȱ anȱ integer.ȱ ȱ Ifȱ floatingȬpointȱ instructionsȱ areȱ used,ȱ itȱ isȱ aȱ floatingȬpointȱnumber.ȱ Thisȱfactȱleadsȱtoȱanȱimportantȱconclusion:ȱtheȱtypeȱofȱaȱvalueȱcannotȱbeȱdeterminedȱ simplyȱ byȱ examiningȱ itsȱ bits.ȱ Toȱ determineȱ itsȱ typeȱ (andȱ thereforeȱ itsȱ value)ȱ youȱ mustȱ lookȱatȱtheȱwayȱtheȱvalueȱisȱusedȱinȱtheȱprogram.ȱConsiderȱthisȱ32Ȭbitȱvalue,ȱshownȱinȱ binary:ȱ 01100111011011000110111101100010 ȱ Hereȱ areȱ aȱ fewȱ ofȱ theȱ manyȱ waysȱ thatȱ theseȱ bitsȱ mightȱ beȱ interpreted.ȱ Theseȱ valuesȱ wereȱ allȱ obtainedȱ fromȱ aȱ Motorolaȱ 68000Ȭbasedȱ processor.ȱ Anotherȱ systemȱ withȱ differentȱdataȱformatsȱandȱinstructionsȱwouldȱinterpretȱtheȱsameȱbitsȱdifferently.ȱ Download at http://www.pin5i.com/ 132ȱ Chapter 6 Pointer Type Value(s) oneȱ32Ȭbitȱintegerȱ 1,735,159,650ȱ twoȱ16Ȭbitȱintegerȱ 26,476ȱfollowedȱbyȱ28,514ȱ glob fourȱcharactersȱ floatingȬpointȱ 1.116533×1024 machineȱinstructionsȱ beg .+110ȱfollowedȱby b1e .+102ȱ ȱ ȱ ȱ Hereȱisȱaȱsingleȱvalueȱthatȱcouldȱbeȱinterpretedȱasȱfiveȱdifferentȱtypes.ȱClearly,ȱ theȱtypeȱofȱaȱvalueȱisȱnotȱsomethingȱinherentȱinȱtheȱvalueȱitselfȱbutȱdependsȱonȱhowȱitȱ isȱused.ȱThusȱtoȱgetȱcorrectȱanswers,ȱitȱisȱimportantȱtoȱuseȱtheȱvaluesȱcorrectly.ȱ Ofȱ course,ȱ theȱ compilerȱ helpsȱ usȱ avoidȱ theseȱ errors.ȱ Declaringȱ cȱ toȱ beȱ aȱ floatȱ causesȱ theȱ compilerȱ toȱ generateȱ floatingȬpointȱ instructionsȱ whenȱ accessingȱ itȱ andȱ toȱ complainȱwhenȱweȱattemptȱtoȱaccessȱitȱinȱaȱwayȱthatȱisȱnotȱappropriateȱforȱaȱ float.ȱȱItȱ isȱ nowȱ obviousȱ thatȱ theȱ diagramȱ showingȱ theȱ valuesȱ wasȱ misleading,ȱ becauseȱ itȱ showedȱtheȱintegerȱrepresentationȱofȱc.ȱȱTheȱfloatingȬpointȱvalueȱisȱreallyȱ3.14ȱ.ȱ ȱ ȱ ȱ 6.3 Contents of a Pointer Variable ȱ Gettingȱbackȱtoȱpointers,ȱletȇsȱlookȱatȱtheȱdeclarationsȱforȱtheȱvariablesȱ dȱandȱ e.ȱȱTheyȱ areȱ bothȱ declaredȱ asȱ pointers,ȱ andȱ theyȱ areȱ initializedȱ withȱ theȱ addressesȱ ofȱ otherȱ variables.ȱȱTheȱinitializationȱisȱdoneȱwithȱtheȱ &ȱoperator,ȱwhichȱproducesȱtheȱmemoryȱ addressȱofȱitsȱoperandȱ(seeȱChapterȱ5).ȱ ȱ aȱ ȱ ȱ bȱ ȱ ȱ cȱ ȱ ȱ dȱ ȱ ȱ eȱ ȱ ȱ ȱ ȱ 112ȱ ȱ ȱ Ȭ1ȱ ȱ ȱ 3.14 ȱ ȱ 100 ȱ ȱ 108 ȱ Theȱcontentsȱofȱ dȱandȱ eȱareȱaddressesȱratherȱthanȱintegersȱorȱfloatingȬpointȱnumbers.ȱȱ Indeed,ȱitȱisȱeasyȱtoȱseeȱfromȱtheȱdiagramȱthatȱtheȱcontentsȱofȱ dȱmatchȱtheȱaddressȱatȱ whichȱ aȱ isȱ storedȱ andȱ theȱ contentsȱ ofȱ eȱ matchȱ theȱ addressȱ whereȱ cȱ isȱ stored,ȱ asȱ weȱ wouldȱexpectȱfromȱtheȱinitialization.ȱItȱisȱimportantȱtoȱdistinguishȱbetweenȱtheȱaddressȱ ofȱtheȱvariableȱdȱ(112)ȱandȱitsȱcontentsȱ(100),ȱandȱtoȱrealizeȱatȱtheȱsameȱtimeȱthatȱthisȱ numberȱ 100ȱ identifiesȱ (isȱ theȱ addressȱ of)ȱ someȱ otherȱ location.ȱ Atȱ thisȱ pointȱ theȱ house/streetȱ addressȱ analogyȱ fails,ȱ becauseȱ theȱ contentsȱ ofȱ aȱ houseȱ areȱ neverȱ theȱ addressȱofȱanotherȱhouse.ȱ Beforeȱ movingȱ toȱ theȱ nextȱ step,ȱ letȇsȱ lookȱ atȱ someȱ expressionsȱ involvingȱ theseȱ variables.ȱConsiderȱtheseȱdeclarationsȱonceȱmore.ȱ Download at http://www.pin5i.com/ 6.4 Indirection Operator 133 int a = 112, b = -1; float c = 3.14; int *d = &a; float *e = &c; Whatȱisȱtheȱvalueȱofȱeachȱofȱtheseȱexpressions?ȱ a b c d e ȱ Theȱfirstȱthreeȱareȱeasy:ȱtheȱvalueȱofȱ aȱisȱ112,ȱtheȱvalueȱofȱ bȱisȱȬ1ȱandȱtheȱvalueȱofȱ cȱisȱ 3.14ȱ,ȱTheȱpointerȱvariablesȱareȱjustȱasȱeasy.ȱTheȱvalueȱofȱ dȱisȱ100,ȱandȱtheȱvalueȱofȱ eȱisȱ 108.ȱIfȱyouȱsaidȱ112ȱandȱ3.14ȱforȱ dȱandȱ e,ȱthenȱyouȇveȱmadeȱaȱveryȱcommonȱmistake.ȱȱ Theȱfactȱthatȱ dȱandȱ eȱareȱdeclaredȱasȱpointersȱdoesȱnotȱchangeȱhowȱtheseȱexpressionsȱ areȱ evaluated:ȱ theȱ valueȱ ofȱ aȱ variableȱ isȱ theȱ numberȱ storedȱ inȱ theȱ memoryȱ locationȱ assignedȱ toȱ theȱ variable.ȱ Itȱ isȱ aȱ mistakeȱ toȱ thinkȱ thatȱ youȱ automaticallyȱ goȱ toȱ theȱ locationsȱ100ȱandȱ108ȱandȱgetȱtheȱvaluesȱthereȱsimplyȱbecauseȱdȱandȱeȱareȱpointers.ȱTheȱ valueȱ ofȱ aȱ variableȱ isȱ theȱ numberȱ storedȱ inȱ theȱ memoryȱ locationȱ assignedȱ toȱ theȱ variable,ȱevenȱforȱpointerȱvariables.ȱ ȱ ȱ ȱ 6.4 Indirection Operator ȱ Theȱprocessȱofȱfollowingȱaȱpointerȱtoȱtheȱlocationȱtoȱwhichȱitȱpointsȱisȱcalledȱindirectionȱ orȱdereferencingȱtheȱpointer.ȱTheȱoperatorȱthatȱperformsȱindirectionȱisȱtheȱunaryȱ *.ȱHereȱ areȱsomeȱexamplesȱusingȱtheȱdeclarationsȱinȱtheȱpreviousȱsection.ȱ ȱ Expression R-Value Type a 112 ȱ int int b -1 ȱ c d 3 .14 100 ȱ float int * e 108 ȱ 112 ȱ float * *d *e 3 .14 int float ȱ Theȱvalueȱofȱ dȱisȱ100.ȱȱȱWhenȱweȱapplyȱtheȱindirectionȱoperatorȱtoȱ d,ȱitȱmeansȱtoȱgoȱtoȱ locationȱ 100ȱ inȱ memoryȱ andȱ lookȱ thereȱ instead.ȱ ȱ Thus,ȱ theȱ RȬvalueȱ ofȱ *dȱ isȱ 112—theȱ contentsȱofȱlocationȱ100.ȱȱȱTheȱLȬvalueȱwouldȱbeȱlocationȱ100ȱitself.ȱ Download at http://www.pin5i.com/ 134ȱ Chapter 6 Pointer Noteȱtheȱtypesȱofȱtheȱexpressionsȱinȱtheȱ listȱabove:ȱ dȱisȱaȱpointerȱtoȱanȱ integerȱ andȱdereferencingȱitȱproducesȱanȱinteger.ȱSimilarly,ȱapplyingȱindirectionȱtoȱaȱ float *ȱ producesȱaȱfloat.ȱ Normally,ȱ weȱ donȇtȱ knowȱ whichȱ locationȱ theȱ compilerȱ willȱ chooseȱ forȱ eachȱ variable,ȱ soȱ weȱ cannotȱ predictȱ theirȱ addressesȱ inȱ advance.ȱ Thus,ȱ whenȱ drawingȱ picturesȱ ofȱ pointersȱ inȱ memory,ȱ itȱ isȱ inconvenientȱ toȱ useȱ theȱ actualȱ numbersȱ forȱ addresses,ȱsoȱmostȱbooksȱuseȱarrowsȱinstead,ȱlikeȱthis:ȱ ȱ ȱ ȱ aȱ ȱ ȱ bȱ ȱ ȱ cȱ ȱ ȱ dȱ ȱ ȱ eȱ ȱ ȱ ȱ ȱ 112ȱ ȱ ȱ Ȭ1ȱ ȱ ȱ 3.14 ȱ ȱ ȱ ȱ ȱ ȱ ȱ However,ȱthisȱnotationȱcanȱbeȱmisleadingȱbecauseȱtheȱarrowsȱcanȱtrickȱyouȱintoȱdoingȱ indirectionȱ evenȱ whenȱ thereȱ isȱ noȱ indirectionȱ toȱ beȱ done.ȱ Forȱ example,ȱ whatȱ isȱ theȱ valueȱofȱtheȱexpressionȱdȱfromȱtheȱdiagramȱabove?ȱ Ifȱyouȱansweredȱ112,ȱthenȱyouȱwereȱtrickedȱbyȱtheȱarrow.ȱTheȱcorrectȱanswerȱisȱ theȱaddressȱofȱa,ȱnotȱitsȱcontents.ȱȱTheȱarrow,ȱthough,ȱseemsȱtoȱpullȱourȱeyesȱtoȱa.ȱȱItȱisȱ hardȱnotȱtoȱfollowȱtheȱarrowȱandȱthatȱisȱtheȱproblem:ȱyouȱmustȱnotȱfollowȱtheȱarrowȱ unlessȱthereȱisȱanȱindirectionȱoperator.ȱ Theȱmodifiedȱarrowȱnotationȱshownȱbelowȱtriesȱtoȱeliminateȱthisȱproblem.ȱ ȱ ȱ ȱ aȱ ȱ ȱ bȱ ȱ ȱ cȱ ȱ ȱ dȱ ȱ ȱ eȱ ȱ ȱ ȱ ȱ 112ȱ ȱ ȱ Ȭ1ȱ ȱ ȱ 3.14 ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Theȱ intentȱ isȱ toȱ showȱ theȱ valueȱ ofȱ theȱ pointerȱ withoutȱ theȱ strongȱ visualȱ cueȱ thatȱ theȱ arrowȱisȱaȱpathȱthatȱmustȱbeȱfollowed.ȱIndeed,ȱtheȱvalueȱofȱaȱpointerȱvariableȱisȱsimplyȱ aȱ collectionȱ ofȱ bitsȱ untilȱ anȱ indirectionȱ isȱ performedȱ onȱ it.ȱ Whenȱ indirectionȱ isȱ performed,ȱaȱsolidȱarrowȱisȱusedȱtoȱshowȱwhatȱactuallyȱtookȱplace.ȱ Noteȱthatȱtheȱarrowȱoriginatesȱinsideȱofȱtheȱboxȱbecauseȱitȱrepresentsȱtheȱvalueȱ storedȱ inȱ thatȱ variable.ȱ Also,ȱ theȱ arrowȱ pointsȱ toȱ aȱ location,ȱ notȱ toȱ theȱ valueȱ inȱ theȱ location.ȱThisȱnotationȱimpliesȱthatȱfollowingȱtheȱarrowȱwithȱindirectionȱproducesȱanȱ LȬvalue.ȱItȱdoes,ȱasȱweȱshallȱseeȱlater. Download at http://www.pin5i.com/ 6.5 Uninitialized and Illegal Pointers 135 Althoughȱtheȱarrowȱnotationȱisȱuseful,ȱinȱorderȱtoȱbeȱableȱtoȱuseȱitȱproperlyȱyouȱ mustȱrememberȱthatȱtheȱvalueȱofȱaȱpointerȱvariableȱisȱjustȱaȱnumber.ȱTheȱarrowȱshowsȱ theȱvalueȱofȱthisȱnumber,ȱbutȱtheȱarrowȱnotationȱdoesȱnotȱchangeȱtheȱfactȱthatȱitȱisȱjustȱ aȱnumber.ȱȱAȱpointerȱhasȱnoȱbuiltȬinȱpropertyȱofȱindirection,ȱsoȱyouȱmustȱnotȱfollowȱ theȱarrowȱunlessȱthereȱisȱartȱindirectionȱoperatorȱthatȱtellsȱyouȱtoȱdoȱso.ȱ ȱ ȱ ȱ 6.5 Uninitialized and Illegal Pointer ȱ Theȱcodeȱfragmentȱbelowȱillustratesȱaȱveryȱcommonȱerror:ȱ ȱ int *a; ... *a = 12; CAUTION! ȱ Theȱ declarationȱ createsȱ aȱ pointerȱ variableȱ calledȱ a,ȱ andȱ theȱ assignmentȱ storesȱ aȱ 12ȱ inȱ theȱlocationȱtoȱwhichȱaȱpoints.ȱ ȱ Butȱwhereȱdoesȱaȱpoint?ȱWeȱdeclaredȱtheȱvariableȱbutȱneverȱinitializedȱit,ȱsoȱthereȱisȱnoȱ wayȱ toȱ predictȱ whereȱ theȱ valueȱ 12ȱ isȱ beingȱ stored.ȱ Aȱ pointerȱ variableȱ isȱ noȱ differentȱ fromȱanyȱotherȱvariableȱinȱthisȱrespect.ȱIfȱtheȱvariableȱisȱstatic,ȱitȱisȱinitializedȱtoȱzero;ȱ butȱifȱtheȱvariableȱisȱautomatic,ȱitȱisȱnotȱinitializedȱatȱall.ȱInȱneitherȱcaseȱdoesȱdeclaringȱ aȱpointerȱtoȱanȱintegerȱȈcreateȈȱanyȱmemoryȱforȱtheȱstorageȱofȱanȱinteger.ȱ Soȱwhatȱhappensȱwhenȱthisȱassignmentȱisȱperformed?ȱIfȱyouȇreȱlucky,ȱtheȱinitialȱ valueȱ ofȱ aȱ willȱ beȱ anȱ illegalȱ address,ȱ andȱ theȱ assignmentȱ willȱ causeȱ aȱ faultȱ thatȱ terminatesȱ theȱ program.ȱ Onȱ UNIXȱ systems,ȱ thisȱ errorȱ isȱ calledȱ aȱ Ȉsegmentationȱ violationȈȱorȱaȱȈmemoryȱfault.ȈȱItȱindicatesȱthatȱyouȱhaveȱtriedȱtoȱaccessȱaȱlocationȱthatȱ isȱ outsideȱ ofȱ theȱ memoryȱ allocatedȱ toȱ yourȱ program.ȱ Onȱ aȱ PCȱ runningȱ Windows,ȱ indirectionȱ onȱ anȱ unitializedȱ orȱ illegalȱ pointerȱ isȱ oneȱ ofȱ theȱ causesȱ ofȱ Generalȱ ProtectionȱExceptions.ȱ Onȱmachinesȱthatȱrequireȱintegersȱtoȱbeȱatȱaȱparticularȱboundary,ȱaccessingȱanȱ addressȱ thatȱ isȱ onȱ theȱ wrongȱ boundaryȱ forȱ itsȱ typeȱ alsoȱ causesȱ aȱ fault.ȱ Thisȱ errorȱ isȱ reportedȱonȱUNIXȱsystemsȱasȱaȱȈbusȱerror.Ȉȱ Aȱmuchȱmoreȱseriousȱproblemȱisȱwhenȱtheȱpointerȱaccidentallyȱcontainsȱaȱlegalȱ address.ȱ Whatȱ happensȱ thenȱ isȱ simple:ȱ theȱ valueȱ atȱ thatȱ locationȱ isȱ changed,ȱ evenȱ thoughȱyouȱhadȱnotȱintendedȱtoȱchangeȱit.ȱErrorsȱlikeȱthisȱoneȱareȱveryȱdifficultȱtoȱfind,ȱ becauseȱtheȱerroneousȱcodeȱmayȱbeȱcompletelyȱunrelatedȱtoȱtheȱcodeȱthatȱisȱsupposedȱ toȱmanipulateȱtheȱvalueȱthatȱchanged.ȱBeȱextremelyȱcarefulȱthatȱpointerȱvariablesȱareȱ initializedȱbeforeȱapplyingȱindirectionȱtoȱthem!ȱ Download at http://www.pin5i.com/ 136ȱ Chapter 6 Pointer 6.6 The Null Pointer TIP CAUTION! ȱ TheȱStandardȱdefinesȱaȱNULLȱpointerȱasȱaȱpointerȱvalueȱthatȱdoesȱnotȱpointȱtoȱanythingȱ atȱall.ȱToȱmakeȱaȱpointerȱvariableȱNULLȱyouȱassignȱitȱtheȱvalueȱzero,ȱandȱtoȱtestȱwhetherȱ aȱ pointerȱ variableȱ isȱ NULLȱ youȱ compareȱ itȱ toȱ zero.ȱ Theȱ choiceȱ ofȱ theȱ valueȱ zeroȱ isȱ aȱ sourceȱ codeȱ convention;ȱ internally,ȱ theȱ valueȱ forȱ aȱ NULLȱ pointerȱ mightȱ actuallyȱ beȱ somethingȱ different.ȱ Inȱ thisȱ case,ȱ theȱ compilerȱ takesȱ careȱ ofȱ translatingȱ betweenȱ zeroȱ andȱtheȱinternalȱvalue.ȱ Theȱ conceptȱ ofȱ aȱ NULLȱ pointerȱ isȱ quiteȱ usefulȱ becauseȱ itȱ givesȱ youȱ aȱ wayȱ toȱ specifyȱ thatȱ aȱ particularȱ pointerȱ isȱ notȱ currentlyȱ pointingȱ toȱ anythingȱ atȱ all.ȱ Forȱ example,ȱaȱfunctionȱwhoseȱjobȱisȱtoȱsearchȱanȱarrayȱforȱaȱspecificȱvalueȱmayȱreturnȱaȱ pointerȱtoȱtheȱarrayȱelementȱthatȱwasȱfound.ȱȱIfȱnoȱelementȱinȱtheȱarrayȱcontainedȱtheȱ rightȱvalue,ȱaȱNULLȱpointerȱcouldȱbeȱreturnedȱinstead.ȱThisȱtechniqueȱallowsȱtheȱreturnȱ valueȱ toȱ conveyȱ twoȱ differentȱ piecesȱ ofȱ information.ȱ First,ȱ wasȱ anȱ elementȱ found?ȱȱ Second,ȱifȱanȱelementȱwasȱfound,ȱwhichȱoneȱwasȱit?ȱ ȱ ȱ Althoughȱ thisȱ techniqueȱ isȱ commonlyȱ usedȱ inȱ Cȱ programs,ȱ itȱ violatesȱ aȱ softwareȱ engineeringȱ principle.ȱ Itȱ isȱ riskyȱ forȱ aȱ singleȱ valueȱ toȱ haveȱ twoȱ differentȱ meaningsȱ becauseȱ itȱ isȱ easyȱ toȱ beȱ confusedȱ laterȱ onȱ asȱ toȱ whichȱ meaningȱ isȱ actuallyȱ intended.ȱȱ Thisȱproblemȱisȱmoreȱseriousȱinȱlargerȱprogramsȱbecauseȱitȱisȱimpossibleȱtoȱkeepȱtheȱ entireȱdesignȱinȱyourȱheadȱatȱonce.ȱȱAȱsaferȱstrategyȱisȱtoȱhaveȱtheȱfunctionȱreturnȱtwoȱ separateȱvalues:ȱtheȱfirstȱ isȱ aȱstatusȱvalueȱ indicatingȱtheȱresultȱofȱtheȱ operations,ȱ andȱ theȱ secondȱ isȱ theȱ pointer,ȱ whichȱ isȱ usedȱ onlyȱ whenȱ theȱ statusȱ indicatesȱ thatȱ aȱ matchȱ wasȱfound.ȱ Dereferencingȱ aȱ pointerȱ givesȱ youȱ theȱ valueȱ toȱ whichȱ itȱ points.ȱ Butȱ theȱ nullȱ pointer,ȱbyȱdefinition,ȱpointsȱtoȱnothingȱatȱall.ȱTherefore,ȱitȱisȱillegalȱtoȱdereferenceȱaȱ NULLȱ pointer.ȱ ȱ Beforeȱ dereferencingȱ aȱ pointer,ȱ youȱ mustȱ firstȱ makeȱ sureȱ thatȱ itȱ isȱ notȱ NULL.ȱ ȱ ȱ Whatȱ happensȱ ifȱ indirectionȱ isȱ performedȱ onȱ aȱ NULLȱ pointer?ȱ Theȱ resultȱ isȱ implementationȱ dependent.ȱ Onȱ someȱ machines,ȱ theȱ indirectionȱ accessesȱ memoryȱ locationȱ zero.ȱ Theȱ compilerȱ ensuresȱ thatȱ thereȱ arenȇtȱ anyȱ variablesȱ storedȱ atȱ locationȱ zero,ȱ butȱ theȱ machineȱ doesnȇtȱ preventȱ youȱ fromȱ accessingȱ orȱ modifyingȱ theȱ location.ȱ Thisȱ behaviorȱ isȱ veryȱ unfortunate,ȱ becauseȱ theȱ programȱ containsȱ anȱ errorȱ butȱ theȱ machineȱhidesȱitsȱsymptoms,ȱthusȱmakingȱtheȱerrorȱmoreȱdifficultȱtoȱfind.ȱ Onȱ otherȱ machines,ȱ indirectionȱ onȱ aȱ NULLȱ pointerȱ causesȱ aȱ faultȱ thatȱ terminatesȱ theȱ program.ȱ Itȱ isȱ muchȱ betterȱ toȱ announceȱ thatȱ anȱ errorȱ wasȱ discoveredȱ thanȱtoȱhideȱit,ȱbecauseȱtheȱprogrammerȱcanȱthenȱcorrectȱitȱmoreȱeasily.ȱ Download at http://www.pin5i.com/ 6.7 Pointers, Indirection, and L-values TIP 137 Itȱ wouldȱ beȱ niceȱ ifȱ allȱ pointerȱ variables,ȱ notȱ justȱ thoseȱ inȱ staticȱ memory,ȱ wereȱ automaticallyȱ initializedȱ toȱ NULL,ȱ butȱ theyȱ areȱ not.ȱ Noȱ matterȱ howȱ yourȱ machineȱ handlesȱ dereferencingȱaȱ NULLȱpointer,ȱ itȱisȱaȱgoodȱideaȱ toȱ explicitlyȱ initializeȱ allȱyourȱ pointerȱvariables.ȱUseȱtheȱdesiredȱaddressȱifȱitȱisȱknown,ȱotherwiseȱinitializeȱthemȱtoȱ NULL.ȱ Inȱ wellȬwrittenȱ programsȱ thatȱ checkȱ pointersȱ beforeȱ dereferencingȱ them,ȱ thisȱ initializationȱcanȱsaveȱyouȱaȱlotȱofȱdebuggingȱtime.ȱ ȱ ȱ ȱ 6.7 Pointers, Indirection, and L-values ȱ Canȱ expressionsȱ involvingȱ pointersȱ beȱ usedȱ asȱ LȬvalues?ȱ Ifȱ so,ȱ whichȱ ones?ȱ Aȱ quickȱ checkȱ ofȱ theȱ precedenceȱ chartȱ inȱ Tableȱ 5.1ȱ confirmsȱ thatȱ theȱ operandȱ neededȱ byȱ theȱ indirectionȱoperatorȱisȱanȱRȬvalue,ȱbutȱtheȱoperatorȱproducesȱanȱLȬvalue.ȱ Weȇllȱreturnȱtoȱanȱearlierȱexample.ȱGivenȱtheseȱdeclarationsȱ ȱ int int a; *d = &a; ȱ considerȱtheȱexpressionsȱbelow:ȱ ȱ Expression L-value Indicated Location a a Yesȱ d d Yesȱ a *d Yesȱ ȱ PointerȱvariablesȱmayȱbeȱusedȱasȱLȬvalues,ȱnotȱbecauseȱtheyȱareȱpointersȱbutȱbecauseȱ theyȱareȱvariables.ȱApplyingȱindirectionȱtoȱaȱpointerȱvariableȱindicatesȱthatȱweȱshouldȱ followȱtheȱpointer.ȱTheȱindirectionȱidentifiesȱaȱspecificȱmemoryȱlocation,ȱthusȱweȱcanȱ useȱtheȱresultȱofȱanȱindirectionȱexpressionȱasȱanȱLȬvalue.ȱFollowȱtheseȱstatements:ȱ ȱ *d = 10 - *d; d = 10 - *d; ƕ ??? ȱ Theȱfirstȱstatementȱcontainsȱtwoȱindirections.ȱTheȱexpressionȱonȱtheȱrightȱisȱbeingȱusedȱ asȱanȱRȬvalue,ȱsoȱitȱobtainsȱtheȱvalueȱinȱtheȱlocationȱtoȱwhichȱ dȱpointsȱ(theȱvalueȱofȱ a).ȱȱ TheȱindirectionȱonȱtheȱleftȱisȱbeingȱusedȱasȱanȱLȬvalue,ȱsoȱtheȱlocationȱtoȱwhichȱdȱpointsȱ (whichȱisȱa)ȱreceivesȱtheȱnewȱvalueȱcomputedȱbyȱtheȱrightȱside.ȱ Theȱ secondȱ statementȱ isȱ illegalȱ becauseȱ itȱ specifiesȱ thatȱ anȱ integerȱ quantityȱȱȱȱȱ (10 - *d)ȱbeȱstoredȱinȱaȱpointerȱvariable.ȱTheȱcompilerȱhelpsȱusȱoutȱbyȱcomplainingȱ Download at http://www.pin5i.com/ 138ȱ K&R C Chapter 6 Pointer whenȱ weȱ tryȱ toȱ useȱ aȱ variableȱ inȱ aȱ contextȱ thatȱ isȱ inconsistentȱ withȱ itsȱ type.ȱ Theseȱ warningȱandȱerrorȱmessagesȱareȱyourȱfriends.ȱTheȱcompilerȱisȱhelpingȱyouȱbyȱproducingȱ them.ȱAlthoughȱweȱwouldȱallȱpreferȱnotȱtoȱhaveȱtoȱdealȱwithȱanyȱsuchȱmessages,ȱitȱisȱaȱ goodȱideaȱtoȱcorrectȱtheȱerrorsȱrightȱaway,ȱespeciallyȱwithȱwarningȱmessagesȱthatȱdoȱ notȱabortȱtheȱcompilation.ȱItȱisȱaȱlotȱeasierȱtoȱfixȱproblemsȱwhenȱtheȱcompilerȱtellsȱyouȱ exactlyȱ whereȱ theyȱ areȱ thanȱ itȱ isȱ toȱ debugȱ theȱ programȱ later;ȱ theȱ debuggerȱ cannotȱ pinpointȱsuchȱproblemsȱnearlyȱasȱwellȱasȱtheȱcompiler.ȱ ȱ OldȱCȱcompilersȱdidȱnotȱcomplainȱwhenȱpointerȱandȱintegerȱvaluesȱwereȱintermixed.ȱ However,ȱweȱknowȱbetterȱtheseȱdays.ȱȱItȱisȱonlyȱrarelyȱusefulȱtoȱconvertȱanȱintegerȱtoȱaȱ pointerȱorȱviceȱversa.ȱUsuallyȱsuchȱconversionsȱareȱunintentionalȱerrors.ȱ ȱ ȱ ȱ 6.8 Pointers, Indirection, and Variables ȱ Ifȱyouȱthinkȱyouȇveȱmasteredȱpointers,ȱtakeȱaȱlookȱatȱthisȱexpressionȱandȱseeȱifȱyouȱcanȱ figureȱoutȱwhatȱitȱdoesȱ ȱ *&a = 25; ȱ Ifȱyouȱsaidȱthatȱitȱassignsȱtheȱvalueȱ25ȱtoȱtheȱvariableȱa,ȱcongratulations—ȱyouȇreȱright.ȱ Letȇsȱ unravelȱ theȱ expression.ȱ First,ȱ theȱ &ȱ operatorȱ generatesȱ theȱ addressȱ whereȱ theȱ variableȱ aȱisȱstored,ȱwhichȱisȱaȱpointerȱconstant.ȱ(Noteȱthatȱitȱisȱnotȱnecessaryȱtoȱknowȱ theȱ actualȱ valueȱ ofȱ theȱ constantȱ inȱ orderȱ toȱ useȱ it.)ȱ Then,ȱ theȱ *ȱ operatorȱ goesȱ toȱ theȱ locationȱwhoseȱaddressȱisȱgivenȱasȱtheȱoperand.ȱȱInȱthisȱexpression,ȱtheȱoperandȱisȱtheȱ addressȱofȱa,ȱsoȱtheȱvalueȱ25ȱisȱstoredȱinȱa.ȱ Howȱisȱthisȱstatementȱanyȱdifferentȱfromȱjustȱsayingȱa * 25;ȱ?ȱFunctionally,ȱitȱisȱ identical.ȱ Itȱ does,ȱ however,ȱ involveȱ moreȱ operations.ȱ Unlessȱ theȱ compilerȱ (orȱ optimizer)ȱrealizesȱwhatȱyouȇreȱdoingȱandȱdiscardsȱtheȱextraȱoperations,ȱtheȱresultingȱ objectȱcodeȱwillȱbeȱlargerȱandȱslower.ȱWorse,ȱtheȱadditionalȱoperatorsȱmakeȱtheȱsourceȱ codeȱ harderȱ toȱ read.ȱ Forȱ theseȱ reasons,ȱ noȱ oneȱ everȱ (intentionally)ȱ usesȱ expressionsȱ suchȱasȱ*&a.ȱ ȱ ȱ ȱ 6.9 Pointer Constants ȱ Letȇsȱ examineȱ anotherȱ expression.ȱ Assumingȱ thatȱ theȱ variableȱ aȱ isȱ storedȱ atȱ locationȱ 100,ȱwhatȱdoesȱthisȱstatementȱdo?ȱ ȱ ȱ *100 = 25; Download at http://www.pin5i.com/ 6.10 Pointers to Pointers 139 Itȱlooksȱlikeȱtheȱstatementȱassignsȱ25ȱtoȱ a,ȱbecauseȱ aȱisȱtheȱvariableȱatȱlocationȱ100.ȱButȱ notȱso!ȱTheȱstatementȱisȱactuallyȱinvalidȱbecauseȱdieȱliteralȱ100ȱisȱofȱtypeȱinteger,ȱandȱ indirectionȱcanȱonlyȱbeȱperformedȱonȱexpressionsȱofȱtypeȱpointer.ȱIfȱyouȱreallyȱwantȱtoȱ storeȱ25ȱinȱlocationȱ100,ȱyouȱmustȱuseȱaȱcast.ȱ ȱ *(int *)100 = 25; ȱ Theȱcastȱconvertsȱtheȱvalueȱ100ȱfromȱanȱȈintegerȈȱtoȱaȱȈpointerȱtoȱanȱinteger.ȈȱItȱisȱlegalȱ toȱapplyȱindirectionȱtoȱthisȱexpression,ȱsoȱifȱ aȱisȱstoredȱinȱlocationȱ100,ȱthisȱstatementȱ storesȱ theȱ valueȱ 25ȱ inȱ a.ȱ However,ȱ youȱ willȱ needȱ thisȱ techniqueȱ rarely,ȱ ifȱ ever!ȱ Why?ȱ Asȱ mentionedȱ earlier,ȱ youȱ usuallyȱ cannotȱ predictȱ whereȱ inȱ memoryȱ theȱ compilerȱ willȱ chooseȱtoȱputȱanyȱspecificȱvariable,ȱsoȱyouȱdonȇtȱknowȱitsȱaddressȱaheadȱofȱtime.ȱItȱisȱ easyȱtoȱobtainȱtheȱaddressȱofȱaȱvariableȱwithȱtheȱ&ȱoperatorȱbutȱtheȱexpressionȱwonȇtȱbeȱ evaluatedȱ untilȱ theȱ programȱ executes,ȱ soȱ itȱ isȱ tooȱ lateȱ toȱ copyȱ theȱ answerȱ intoȱ theȱ sourceȱcodeȱasȱaȱliteralȱconstant.ȱ AȱȱTheȱonlyȱreasonȱthisȱexampleȱisȱusefulȱisȱforȱtheȱfewȱtimesȱwhenȱyouȱneedȱtoȱ accessȱ aȱ specificȱ locationȱ inȱ memoryȱ byȱ itsȱ address,ȱ whichȱ isȱ neverȱ doneȱ toȱ accessȱ aȱ variableȱ butȱ ratherȱ toȱ accessȱ theȱ hardwareȱ itself.ȱ Forȱ example,ȱ anȱ operatingȱ systemȱ needsȱ toȱ communicateȱ withȱ theȱ inputȱ andȱ outputȱ deviceȱ controllersȱ toȱ startȱ I/Oȱ operationsȱ andȱ toȱ obtainȱ resultsȱ ofȱ priorȱ operations.ȱ Onȱ someȱ machines,ȱ communicationȱwithȱdeviceȱcontrollersȱisȱaccomplishedȱbyȱreadingȱandȱwritingȱvaluesȱ atȱspecificȱmemoryȱaddresses.ȱInsteadȱofȱaccessingȱmemory,ȱhowever,ȱtheseȱoperationsȱ accessȱtheȱdeviceȱcontrollerȱinterface.ȱTheseȱlocations,ȱthen,ȱmustȱbeȱaccessedȱviaȱtheirȱ addresses,ȱwhichȱareȱknownȱinȱadvance.ȱ Chapterȱ 3ȱ mentionedȱ thatȱ thereȱ isȱ noȱ builtȬinȱ notationȱ forȱ writingȱ pointerȱ constants.ȱInȱtheȱrareȱinstancesȱwhenȱtheyȱareȱrequired,ȱtheyȱareȱgenerallyȱwrittenȱasȱ integerȱliteralsȱandȱconvertedȱtoȱtheȱproperȱtypeȱwithȱaȱcast. 28 ȱ ȱ ȱ 6.10 Pointers to Pointers ȱ Weȱwillȱspendȱonlyȱaȱbriefȱmomentȱhereȱonȱanȱexampleȱthatȱsuggestsȱtopicsȱtoȱcome.ȱ Considerȱtheseȱdeclarations:ȱ ȱ int int a = 12; *b = &a; ȱ Implementationsȱ forȱ segmentedȱ machines,ȱ suchȱ asȱ theȱ Intelȱ 80x86,ȱ mayȱ provideȱ aȱ macroȱ toȱ constructȱ pointerȱ constants.ȱȱ Theȱmacroȱconvertsȱaȱsegmentȱandȱoffsetȱpairȱintoȱtheȱpointerȱvalue.ȱ 28 Download at http://www.pin5i.com/ 140ȱ Chapter 6 Pointer Theyȱallocateȱmemoryȱasȱshownȱinȱtheȱfollowingȱdiagram:ȱ ȱ aȱ ȱ ȱ ȱ bȱ 12ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Supposeȱweȱhadȱaȱthirdȱvariableȱcalledȱcȱandȱinitializedȱitȱwithȱthisȱstatement;ȱ ȱ c = &b; ȱ Hereȱisȱwhatȱmemoryȱwouldȱlookȱlike:ȱ ȱ aȱ ȱ ȱ ȱ bȱ ȱ ȱ 12ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ cȱ ȱ ȱ ȱ ȱ ȱ Theȱquestionȱis;ȱwhatȱisȱtheȱtypeȱofȱc?ȱClearlyȱitȱisȱaȱpointer,ȱbutȱwhatȱdoesȱitȱpointȱto?ȱ Theȱ variableȱ bȱ isȱ aȱ Ȉpointerȱ toȱ anȱ integer,Ȉȱ soȱ anythingȱ thatȱ pointsȱ toȱ bȱ mustȱ beȱ aȱ pointerȱtoȱaȱȈpointerȱtoȱanȱinteger,Ȉȱorȱmoreȱgenerally,ȱaȱpointerȱtoȱaȱpointer.ȱ Isȱthisȱlegal?ȱYes!ȱAȱpointerȱvariableȱisȱlikeȱanyȱotherȱvariableȱinȱthatȱitȱoccupiesȱ aȱspecificȱlocationȱinȱmemory,ȱsoȱitȱmakesȱsenseȱthatȱweȱcanȱobtainȱitsȱaddressȱwithȱtheȱ &ȱoperator. 29 Howȱwouldȱthisȱvariableȱbeȱdeclared?ȱTheȱdeclarationȱ ȱ int **c = &b; ȱ saysȱ thatȱ theȱ expressionȱ **cȱisȱ ofȱtypeȱ int.ȱTableȱ6.1ȱlistsȱsomeȱ expressionsȱthatȱ mayȱ helpȱillustrateȱthisȱconcept;ȱtheȱexpressionsȱassumeȱtheseȱdeclarations.ȱ ȱ int int int a = 12; *b = &a; **c = &b; ȱ Theȱonlyȱnewȱexpressionȱinȱtheȱtableȱisȱtheȱlastȱone,ȱsoȱletȇsȱunravelȱit.ȱTheȱ *ȱoperatorȱ hasȱ rightȬtoȬleftȱ associativity,ȱ soȱ thisȱ expressionȱ isȱ equivalentȱ toȱ *(*c).ȱ Weȱ mustȱ evaluateȱitȱfromȱtheȱinsideȱout.ȱ*cȱtakesȱusȱcoȱtheȱlocationȱtoȱwhichȱcȱpoints,ȱwhichȱweȱ knowȱtoȱbeȱtheȱvariableȱb.ȱTheȱsecondȱindirectionȱthenȱtakesȱusȱtoȱwhereȱthisȱlocationȱȱ 29 ȱExceptȱvariablesȱdeclaredȱregister.ȱ Download at http://www.pin5i.com/ 6.11 Pointer Expressions Expression Equivalent expression(s) a b *b c *c **c 12 &a a, 12 &b b, &a *b, a, 12 141 ȱ Tableȱ6.1ȱDoubleȱindirectionȱ ȱ ȱ ȱ points,ȱwhichȱisȱa.ȱTheȱonlyȱthingȱtrickyȱaboutȱpointersȱtoȱpointersȱisȱkeepingȱallȱofȱtheȱ arrowsȱ straightȱ andȱ rememberingȱ thatȱ anȱ arrowȱ isȱ followedȱ onlyȱ ifȱ anȱ indirectionȱ operatorȱcausesȱit.ȱ ȱ ȱ ȱ 6.11 Pointer Expressions ȱ Nowȱ letȇsȱ takeȱ aȱ lookȱ atȱ aȱ varietyȱ ofȱ pointerȱ expressionsȱ andȱ seeȱ howȱ theyȱ areȱ evaluatedȱ whenȱ usedȱ bothȱ asȱ RȬvaluesȱ andȱ LȬvalues.ȱ Someȱ ofȱ theseȱ expressionsȱ areȱ commonlyȱ used,ȱ batȱ notȱ all.ȱ Theȱ purposeȱ ofȱ thisȱ exerciseȱ isȱ notȱ toȱ giveȱ youȱ aȱ ȈcookbookȈȱofȱexpressionsȱbutȱratherȱtoȱbuildȱyourȱskillȱinȱreadingȱandȱwritingȱthem.ȱȱ First,ȱletȇsȱsetȱtheȱstageȱwithȱsomeȱdeclarations.ȱ ȱ char char ch = 'a'; *cp = &ch; ȱ Weȱnowȱhaveȱtwoȱvariablesȱinitializedȱlikeȱthis:ȱ ȱ cp ch a ? ȱ ȱ TheȱmemoryȱLocationȱthatȱfollowsȱ chȱisȱalsoȱshownȱbecauseȱsomeȱofȱtheȱexpressionsȱ thatȱ weȱ evaluateȱ willȱ accessȱ it,ȱ albeitȱ erroneously.ȱ Becauseȱ weȱ donȇtȱ knowȱ whatȱ itsȱ initialȱvalueȱis,ȱaȱquestionȱmarkȱisȱshown.ȱ Letȇsȱfigureȱoutȱanȱeasyȱoneȱfirstȱtoȱgetȱtheȱballȱrolling.ȱTheȱexpressionȱis:ȱ ȱ ch Download at http://www.pin5i.com/ 142ȱ Chapter 6 Pointer WhenȱusedȱasȱanȱRȬvalue,ȱthisȱexpressionȱhasȱtheȱvalueȱ'a'ȱandȱisȱillustratedȱas:ȱ ȱ cp ch a ? ȱ Theȱheavyȱovalȱindicatesȱthatȱtheȱvalueȱinȱtheȱvariableȱchȱisȱtheȱvalueȱofȱtheȱexpression.ȱ Butȱ whenȱ thisȱ expressionȱ isȱ usedȱ asȱ anȱ LȬvalue,ȱ itȱ isȱ theȱ locationȱ thatȱ countsȱ ratherȱ thanȱtheȱvalueȱthatȱitȱcontains,ȱsoȱitȱisȱillustratedȱdifferently:ȱ ȱ cp ch ? ȱ Hereȱtheȱlocationȱisȱmarkedȱwithȱaȱheavyȱbox,ȱindicatingȱthatȱtheȱlocationȱisȱtheȱresult.ȱȱ Additionally,ȱ itsȱ valueȱ isȱ notȱ shownȱ becauseȱ itȱ isnȇtȱ important;ȱ indeed,ȱ theȱ valueȱ isȱ aboutȱ toȱ beȱ replacedȱ byȱ someȱ newȱ value.ȱ Theȱ remainingȱ expressionsȱ areȱ shownȱ inȱ aȱ tabularȱform.ȱȱEachȱtableȱisȱfollowedȱbyȱaȱdescriptionȱofȱtheȱexpressionȇsȱevaluation.ȱ ȱ ȱ ȱ Expression R-value L-value cp ch a &ch ? illegalȱ ȱ ȱ ȱ AsȱanȱRȬvalue,ȱthisȱexpressionȇsȱvalueȱisȱtheȱaddressȱofȱtheȱvariableȱ ch.ȱNoteȱthatȱthisȱ valueȱ isȱ theȱ sameȱ asȱ theȱ valueȱ storedȱ inȱ theȱ variableȱ cp,ȱ butȱ theȱ expressionȱ doesnȇtȱ mentionȱ cpȱsoȱthatȇsȱnotȱwhereȱtheȱvalueȱconiesȱfrom.ȱThusȱtheȱovalȱisȱnotȱaroundȱtheȱ arrowȱ inȱ cp.ȱ Theȱ secondȱ questionȱ is,ȱ whyȱ isȱ thisȱ expressionȱ notȱ aȱ legalȱ LȬvalue?ȱ Theȱ precedenceȱtableȱshowsȱthatȱtheȱ &ȱoperatorȱproducesȱanȱRȬvalueȱasȱaȱresult,ȱandȱtheyȱ cannotȱbeȱusedȱasȱLȬvalues.ȱButȱwhy?ȱTheȱanswerȱisȱeasy.ȱWhenȱtheȱexpressionȱ &chȱisȱ evaluated,ȱ whereȱ isȱ theȱ resultȱ heldȱ inȱ theȱ computer?ȱ Itȱ mustȱ beȱ somewhere,ȱ butȱ youȱ haveȱnoȱwayȱofȱknowingȱwhere.ȱTheȱexpressionȱdoesȱnotȱidentifyȱanyȱspecificȱlocationȱ inȱtheȱmachineȇsȱmemory,ȱandȱthusȱitȱisȱnotȱaȱlegalȱLȬvalue.ȱ Download at http://www.pin5i.com/ 6.11 Pointer Expressions 143 ȱ Expression R-value L-value cp ch cp cp a ch a ? ? ȱ ȱ ȱ Youȇveȱseenȱthisȱexpressionȱbefore.ȱItsȱRȬvalueȱisȱtheȱvalueȱinȱ cp,ȱasȱindicated.ȱTheȱLȬ valueȱisȱtheȱlocationȱcp.ȱThereȱisȱnoȱindirectionȱinȱthisȱexpression,ȱsoȱyouȱdoȱnotȱfollowȱ theȱarrow.ȱ ȱ ȱ ȱ ȱ Expression R-value L-value cp &cp ch a ȱ ȱ illegalȱ ? ȱ ȱ ȱ Thisȱexampleȱisȱsimilarȱtoȱ &chȱexceptȱthatȱthisȱtimeȱweȱtakeȱtheȱaddressȱofȱtheȱpointerȱ variable.ȱTheȱtypeȱofȱthisȱresultȱisȱpointerȱtoȱpointerȱtoȱcharacter.ȱOnceȱagain,ȱtheȱvalueȱ isȱstoredȱinȱanȱunidentifiableȱlocationȱsoȱtheȱexpressionȱisȱnotȱaȱlegalȱLȬvalue.ȱ ȱ ȱ ȱ ȱ Expression R-value L-value cp *cp cp ch a ? ch ? ȱ ȱ ȱ ȱ Nowȱ weȱ haveȱ addedȱ indirectionȱ soȱ theȱ resultsȱ shouldȱ comeȱ asȱ noȱ surprise.ȱ Butȱ theȱ nextȱfewȱexpressionsȱbeginȱtoȱgetȱmoreȱinteresting.ȱ Download at http://www.pin5i.com/ Chapter 6 Pointer 144ȱ ȱ Expression R-value cp L-value ch a ? *cp + 1 illegalȱ ȱ + 1 b ȱ ȱ Thisȱ diagramȱ isȱ moreȱ involved,ȱ soȱ letȇsȱ doȱ itȱ stepȱ byȱ step.ȱ ȱ Thereȱ areȱ twoȱ operatorsȱ here. *ȱhasȱaȱhigherȱprecedenceȱthanȱ +,ȱsoȱtheȱindirectionȱisȱperformedȱfirstȱ(asȱshownȱ byȱ theȱ solidȱ arrowȱ fromȱ cpȱ toȱ ch),ȱ whichȱ getsȱ usȱ itsȱ valueȱ (indicatedȱ byȱ theȱ dottedȱ oval).ȱ ȱ Aȱ copyȱ ofȱ thisȱ valueȱ isȱ takenȱ andȱ addedȱ toȱ one,ȱ givingȱ theȱ characterȱ 'b'ȱ asȱ aȱ result.ȱTheȱdottedȱlinesȱshowȱtheȱmovementȱofȱdataȱasȱtheȱexpressionȱisȱevaluated.ȱTheȱ finalȱresultȱdoesȱnotȱresideȱinȱanyȱidentifiableȱlocation,ȱsoȱthisȱexpressionȱisȱnotȱaȱlegalȱ LȬvalue.ȱTheȱprecedenceȱtableȱconfirmsȱthatȱtheȱresultȱofȱ+ȱisȱnotȱanȱLȬvalue.ȱ ȱ Expression R-value L-value cp cp ch a ch a ? *(cp+1) ȱ 1 + 1 + ȱ Inȱthisȱexample,ȱweȇveȱaddedȱparenthesesȱtoȱtheȱpreviousȱexpression.ȱTheȱparenthesesȱ forceȱtheȱadditionȱtoȱgoȱfirst,ȱwhichȱaddsȱoneȱtoȱaȱcopyȱofȱtheȱaddressȱinȱcp.ȱȱTheȱresultȱ soȱ farȱ isȱ theȱ pointerȱ inȱ theȱ dottedȱ oval.ȱ ȱ Theȱ indirectionȱ followsȱ thisȱ arrowȱ toȱ theȱ locationȱ justȱ afterȱ ch,ȱ andȱ theȱ RȬvalueȱ ofȱ theȱ expressionȱ isȱ theȱ valueȱ inȱ thatȱ location.ȱȱ TheȱLȬvalue,ȱofȱcourse,ȱisȱtheȱlocationȱitself.ȱ Thereȱ isȱ anȱ importantȱ pointȱ toȱ beȱ learnedȱ here.ȱ Noteȱ thatȱ theȱ resultȱ ofȱ theȱ pointerȱadditionȱ isȱ anȱ RȬvalueȱ becauseȱ itȱ doesȱnotȱresideȱ inȱanyȱidentifiableȱlocation.ȱ Withoutȱ theȱ indirection,ȱ thisȱ expressionȱ wouldȱ notȱ beȱ aȱ legalȱ LȬvalue.ȱ However,ȱ theȱ indirectionȱfollowsȱtheȱpointerȱtoȱaȱspecificȱlocation.ȱThus,ȱ *(cp + 1)ȱmayȱbeȱusedȱasȱ anȱLȬvalueȱevenȱthoughȱ cp + lȱmayȱnot.ȱTheȱindirectionȱoperatorȱisȱoneȱofȱonlyȱaȱfewȱ whoseȱresultȱisȱanȱLȬvalue.ȱ Butȱ theȱ expressionȱ isȱ accessingȱ theȱ locationȱ afterȱ ch;ȱ howȱ canȱ weȱ tellȱ whatȱ residesȱthere?ȱInȱgeneral,ȱweȱcanȇt,ȱsoȱexpressionsȱlikeȱthisȱoneȱareȱillegal.ȱȱIȱdiscussȱthisȱ topicȱinȱmoreȱdepthȱlaterȱinȱthisȱchapter.ȱ Download at http://www.pin5i.com/ 6.11 Pointer Expressions ȱ Expression R-value cp 145 L-value ch a ? ++cp illegalȱ ȱ ȱ ȱ Theȱ ++ȱandȱ --ȱoperatorsȱareȱfrequentlyȱusedȱwithȱpointerȱvariables,ȱsoȱitȱisȱimportantȱ toȱ understandȱ themȱ inȱ thisȱ context.ȱ Inȱ thisȱ expression,ȱ weȱ incrementȱ theȱ pointerȱ variableȱ cp.ȱ(Toȱunclutterȱtheȱdiagrams,ȱweȱnoȱlongerȱshowȱtheȱaddition.)ȱTheȱresultȱisȱ aȱcopyȱofȱtheȱincrementedȱpointer,ȱbecauseȱtheȱprefixȱ ++ȱincrementsȱbeforeȱusingȱtheȱ valueȱ inȱ theȱ surroundingȱ expression.ȱ Theȱ copyȱ isȱ notȱ storedȱ inȱ anyȱ identifiableȱ location,ȱsoȱitȱisȱnotȱaȱlegalȱLȬvalue.ȱ ȱ Expression R-value L-value cp ch a ? cp++ illegalȱ ȱ ȱ ȱ ȱ Theȱpostfixȱ++ȱproducesȱtheȱsameȱvalueȱinȱcp,ȱbutȱitȱincrementsȱafterȱtheȱcopyȱisȱmade.ȱȱ Thus,ȱtheȱvalueȱofȱtheȱexpressionȱisȱaȱcopyȱofȱtheȱoriginalȱvalueȱofȱcp.ȱ NeitherȱofȱtheȱpreviousȱtwoȱexpressionsȱareȱlegalȱLȬvalues.ȱButȱtheyȱwouldȱbeȱifȱ weȱaddȱindirection,ȱasȱillustratedȱinȱtheȱnextȱtwoȱexpressions.ȱ ȱ ȱ Expression R-value L-value cp cp ch a ch a ? ? *++cp ȱ ȱ ȱ ȱ ȱ Here,ȱindirectionȱisȱappliedȱtoȱ theȱcopyȱofȱtheȱincrementedȱpointer,ȱsoȱtheȱRȬvalueȱisȱ theȱvalueȱinȱtheȱlocationȱfollowingȱchȱandȱtheȱLȬvalueȱisȱthatȱlocation.ȱ Download at http://www.pin5i.com/ 146ȱ Chapter 6 Pointer Expression R-value cp L-value cp ch a ch a ? ? *cp++ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Usingȱ theȱ postfixȱ ++ȱ yieldsȱ aȱ differentȱ result:ȱ theȱ RȬvalueȱ andȱ LȬvalueȱ relateȱ toȱ theȱ variableȱ ch,ȱwhichȱisȱwhereȱ cpȱoriginallyȱpointed.ȱAgain,ȱtheȱpostfixȱoperatorȱusesȱtheȱ originalȱ valueȱ ofȱ itsȱ operandȱ inȱ theȱ surroundingȱ expression.ȱ Theȱ combinationȱ ofȱ indirectionȱandȱtheȱpostfixȱ ++ȱisȱoftenȱmisunderstood.ȱȱTheȱprecedenceȱtableȱindicatesȱ thatȱ theȱ postfixȱ ++ȱ hasȱ aȱ higherȱ precedenceȱ thanȱ theȱ *,ȱ yetȱ itȱ appearsȱ asȱ itȱ theȱ indirectionȱ isȱ beingȱ performedȱ first.ȱ ȱ Inȱ fact,ȱ thereȱ areȱ threeȱ stepsȱ involved:ȱ (1)ȱ ++ȱ makesȱ aȱ copyȱ ofȱ cp,ȱ (2)ȱ theȱ ++ȱ incrementsȱ cp,ȱ andȱ finally,ȱ (3)ȱ theȱ indirectionȱ isȱ performedȱonȱtheȱcopy.ȱ ȱ Thisȱ expressionȱ isȱ oftenȱ usedȱ inȱ loopȱ toȱ sequentiallyȱ examineȱ theȱ contentsȱ ofȱ someȱ arrayȱ toȱ whichȱ theȱ pointerȱ hasȱ previouslyȱ beenȱ initialized.ȱ Someȱ exampleȱ areȱ shownȱlaterȱinȱthisȱchapter.ȱ ȱ ȱ ȱ ȱ Expression R-value L-value cp ch b ++*cp ȱ ȱ ȱ ? illegalȱ b ȱ ȱ Inȱthisȱexpression,ȱtheȱindirectionȱisȱevaluatedȱfirstȱdueȱtoȱtheȱrightȬtoȬleftȱassociativityȱ ofȱtheseȱoperators.ȱTherefore,ȱtheȱlocationȱtoȱwhichȱcpȱpointsȱisȱincremented;ȱtheȱresultȱ isȱaȱcopyȱofȱtheȱincrementedȱvalue.ȱ Theȱ lastȱ threeȱ expressionsȱ areȱ notȱ usedȱ asȱ oftenȱ asȱ someȱ ofȱ theȱ previousȱ onesȱ butȱdecipheringȱthemȱwillȱincreaseȱyourȱskill.ȱ Download at http://www.pin5i.com/ 6.11 Pointer Expressions ȱ Expression R-value cp 147 L-value ch b ? (*cp)++ illegalȱ ȱ ȱ ȱ a ȱ ȱ ȱ Withȱ theȱ postfixȱ ++,ȱ weȱ needȱ parenthesesȱ toȱ makeȱ theȱ indirectionȱ goȱ first.ȱ Thisȱ expressionȱ isȱ evaluatedȱ likeȱ theȱ previousȱ exampleȱ exceptȱ thatȱ theȱ resultȱ isȱ theȱ valueȱ thatȱchȱhadȱbeforeȱtheȱincrementȱtookȱplace.ȱ ȱ ȱ ȱ ȱ ȱ Expression R-value L-value cp ++*++cp ȱ ch ȱ a ?+1 ?+1 illegalȱ ȱ ȱ ȱ Thisȱ oneȱ looksȱ prettyȱ tricky,ȱ butȱ itȱ isnȇtȱ really.ȱ Thereȱ areȱ threeȱ operatorsȱ inȱ thisȱ expression,ȱwhichȱisȱwhatȱmakesȱitȱlookȱintimidating.ȱȱIfȱyouȱanalyzeȱthemȱoneȱbyȱone,ȱ though,ȱeachȱwillȱbeȱfamiliar.ȱȱInȱfact,ȱweȇveȱalreadyȱevaluatedȱ*++cpȱearlier;ȱallȱweȱareȱ doingȱnowȱisȱtoȱincrementȱitsȱresult.ȱȱButȱletȇsȱstartȱfromȱscratch.ȱȱRememberȱthatȱtheȱ associativityȱofȱtheseȱoperatorsȱisȱrightȱtoȱleft,ȱsoȱtheȱfirstȱthingȱthatȱhappensȱisȱ ++cp;ȱ theȱ dottedȱ ovalȱ beneathȱ cpȱ illustratesȱ theȱ firstȱ intermediateȱ result.ȱ Thenȱ weȱ applyȱ indirectionȱ toȱ thisȱ copy,ȱ whichȱ takesȱ usȱ toȱ theȱ locationȱ afterȱ ch.ȱ Theȱ secondȱ intermediateȱresultȱisȱshownȱwithȱaȱdottedȱboxȱbecauseȱtheȱnextȱoperatorȱusesȱitȱasȱanȱ LȬvalue.ȱFinally,ȱweȱapplyȱ ++ȱtoȱthisȱlocation,ȱwhichȱincrementsȱitsȱvalue.ȱȱWeȱdisplayȱ theȱvalueȱasȱ? + 1ȱbecauseȱweȱdoȱnotȱknowȱtheȱoriginalȱvalueȱofȱtheȱlocation.ȱ Download at http://www.pin5i.com/ Chapter 6 Pointer 148ȱ ȱ Expression ++*cp++ R-value ȱ ȱ ȱ ȱ ȱ ȱ L-value b cp ch b ? illegalȱ ȱ Theȱ differenceȱ betweenȱ thisȱ expressionȱ andȱ theȱ previousȱ oneȱ isȱ thatȱ theȱ firstȱ ++ȱ isȱ postfixȱinsteadȱofȱprefix,ȱsoȱitȱisȱevaluatedȱfirstȱbecauseȱofȱitsȱhigherȱprecedence.ȱTheȱ indirectionȱthenȱtakesȱusȱtoȱcpȱinsteadȱofȱtheȱfollowingȱlocation.ȱ ȱ ȱ ȱ 6.12 Examples ȱ Hereȱ areȱ someȱ sampleȱ programsȱ toȱ illustrateȱ aȱ fewȱ commonȱ pointerȱ expressions.ȱȱ Programȱ 6.1ȱ computesȱ theȱ lengthȱ ofȱ aȱ string.ȱ Youȱ shouldȱ neverȱ haveȱ toȱ writeȱ thisȱ functionȱbecauseȱtheȱlibraryȱcontainsȱone,ȱbutȱitȱisȱaȱusefulȱexample.ȱ /* ** Compute the length of a string. */ #include <stdlib.h> size_t strlen( char *string ) { int length = 0; /* ** Advance through the string, counting characters ** until the terminating NUL byte is reached. */ while( *string++ != '\0' ) length += 1; return length; } Programȱ6.1ȱStringȱlengthȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱstrlen.cȱ Download at http://www.pin5i.com/ 6.12 Examples 149 Theȱexpressionȱ *string++ȱinȱtheȱ whileȱstatementȱisȱtrueȱuntilȱtheȱpointerȱhasȱreachedȱ theȱ terminatingȱ NULȱ byte.ȱ Itȱ alsoȱ incrementsȱ theȱ pointerȱ forȱ theȱ nextȱ test.ȱ Thisȱ expressionȱevenȱhandlesȱemptyȱstringsȱproperly.ȱ ȱ Ifȱtheȱfunctionȱisȱcalledȱwithȱaȱ NULLȱpointer,ȱtheȱindirectionȱinȱtheȱ whileȱstatementȱwillȱ fail.ȱShouldȱtheȱfunctionȱcheckȱforȱthisȱconditionȱbeforeȱdereferencingȱtheȱpointer?ȱToȱ beȱ absolutelyȱ safe,ȱ itȱ should.ȱ However,ȱ thisȱ functionȱ doesȱ notȱ createȱ theȱ string.ȱ Ifȱ itȱ findsȱthatȱtheȱargumentȱisȱNULL,ȱitȱhasȱreallyȱfoundȱanȱerrorȱthatȱoccurredȱelsewhereȱinȱ theȱprogram.ȱItȱseemsȱlogicalȱthatȱtheȱpointerȱshouldȱbeȱcheckedȱwhereȱitȱwasȱcreated,ȱ becauseȱthenȱitȱneedȱbeȱcheckedȱonlyȱonce.ȱThisȱapproachȱisȱtakenȱbyȱthisȱfunction.ȱIfȱ theȱ functionȱ failsȱ becauseȱ aȱ carelessȱ clientȱ didnȇtȱ botherȱ toȱ checkȱ theȱ argument,ȱ theyȱ deserveȱwhatȱtheyȱget.ȱ Programsȱ 6.2ȱ andȱ 6.3ȱ addȱ aȱ levelȱ ofȱ indirection.ȱ Theyȱ searchȱ aȱ collectionȱ ofȱ stringsȱforȱaȱspecificȱcharacterȱvalue,ȱbutȱanȱarrayȱofȱpointersȱisȱusedȱtoȱkeepȱtrackȱofȱ theȱstrings,ȱasȱillustratedȱinȱFigureȱ6.1.ȱTheȱargumentsȱtoȱtheȱfunctionsȱareȱstrings,ȱtheȱ pointerȱ toȱ theȱ arrayȱ ofȱ pointers;ȱ andȱ value,ȱ theȱ characterȱ valueȱ weȇreȱ lookingȱ for.ȱȱȱ NoticeȱthatȱtheȱarrayȱofȱpointersȱendsȱwithȱaȱNULLȱpointer.ȱTheȱfunctionsȱwillȱcheckȱforȱ thisȱvalueȱtoȱdetermineȱwhenȱtoȱstop.ȱTheȱexpressionȱinȱ ȱ while( ( string = *strings++ ) != NULL ){ ȱ doesȱ threeȱ things:ȱ (1)ȱ itȱ copiesȱ theȱ pointerȱ thatȱ stringsȱ currentlyȱ pointsȱ toȱ intoȱ theȱ variableȱ string,ȱ (2)ȱ itȱ incrementsȱ stringsȱ toȱ pointȱ toȱ theȱ nextȱ value,ȱ andȱ (3)ȱ itȱ testsȱ whetherȱ stringȱ isȱ NULL.ȱ Theȱ innerȱ whileȱ loopȱ stopsȱ whenȱ stringȱ pointsȱ toȱ theȱ terminatingȱNULȱbyteȱatȱtheȱendȱofȱtheȱcurrentȱstring.ȱ ȱ ȱ stringsȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇAȇ ȇȱȇȱ ȇsȇȱ ȇtȇȱ ȇrȇȱ ȇiȇȱ ȇnȇȱ ȇgȇȱ 0ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇTȇȱ ȇhȇ ȇiȇȱ ȇrȇ ȇdȇ 0ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇLȇȱ ȇaȇȱ ȇsȇȱ ȇtȇȱ 0ȱ ȱ 0ȱ ȇAȇ ȇnȇ ȇoȇ ȇtȇȱ ȇhȇ ȇeȇ ȇrȇȱ 0ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Figureȱ6.1ȱArrayȱofȱpointersȱtoȱstringsȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Download at http://www.pin5i.com/ 150ȱ Chapter 6 Pointer ȱ /* ** Given a pointer to a NULL-terminated list of pointers, search ** the strings in the list for a particular character. */ #include <stdio.h> #define #define TRUE 1 FALSE 0 int find_char( char **strings, char value ) { char *string; /* the string we're looking at */ /* ** For each string in the list ... */ while( ( string = *strings++ ) != NULL ){ /* ** Look at each character in the string to see if ** it is the one we want. */ while( *string != '\0' ){ if( *string++ == value ) return TRUE; } } return FALSE; } ȱ Programȱ6.2ȱSearchȱaȱcollectionȱofȱstrings:ȱversionȱoneȱȱ ȱ ȱ ȱ ȱ Untilȱthen,ȱ ȱ ȱ ȱ ȱȱȱ ȱȱs_srch1.cȱ if( *string++ == value ) ȱ testsȱ whetherȱ theȱ currentȱ characterȱ matchesȱ theȱ desiredȱ valueȱ andȱ incrementsȱ theȱ pointerȱtoȱtheȱnextȱcharacter.ȱ Programȱ6.3ȱperformsȱtheȱsameȱfunctionȱwithoutȱmakingȱaȱcopyȱofȱtheȱpointerȱ toȱeachȱstring.ȱAsȱaȱsideȱeffect,ȱhowever,ȱthisȱprogramȱdestroysȱtheȱarrayȱofȱpointers.ȱ Thisȱsideȱeffectȱmakesȱtheȱfunctionȱlessȱusefulȱthanȱtheȱpreviousȱversion,ȱasȱitȱcanȱbeȱ usedȱonlyȱwhenȱtheȱstringsȱareȱsearchedȱonce.ȱ Download at http://www.pin5i.com/ 6.12 Examples 151 ȱ /* ** ** ** ** */ Given a pointer to a NULL-terminated list of pointers, search the strings in the list for a particular character. This version destroys the pointers so it can only be used when the collection will be examined only once. #include <stdio.h> #include <assert.h> #define #define TRUE 1 FALSE 0 int find_char( char **strings, int value ) { assert( strings != NULL ); /* ** For each string in the list ... */ while( *strings != NULL ){ /* ** Look at each character in the string to see if ** it is the one we want. */ while( **strings != '\0' ){ if( *(*strings)++ == value ) return TRUE; } strings++; } return FALSE; } ȱ Programȱ6.3ȱSearchȱaȱcollectionȱofȱstrings:ȱversionȱtwoȱȱ ȱ ȱ ȱ ȱs_srch2.cȱ ȱ ȱ ȱ Thereȱare,ȱhowever,ȱtwoȱinterestingȱexpressionsȱinȱProgramȱ6.3.ȱȱTheȱfirstȱisȱ**strings.ȱ Theȱfirstȱindirectionȱgoesȱtoȱtheȱcurrentȱpointerȱinȱtheȱarrayȱofȱpointers,ȱandȱtheȱsecondȱ followsȱ thatȱ pointerȱ toȱ theȱ currentȱ characterȱ inȱ theȱ string.ȱ Theȱ innerȱ whileȱ statementȱ testsȱthisȱcharacterȱtoȱseeȱwhetherȱtheȱendȱofȱtheȱstringȱhasȱbeenȱreached.ȱ Theȱsecondȱinterestingȱexpressionȱisȱ *(*strings)++.ȱParenthesesȱareȱneededȱinȱorderȱ forȱtheȱexpressionȱtoȱevaluateȱproperly.ȱTheȱfirstȱindirectionȱgoesȱtoȱtheȱcurrentȱ Download at http://www.pin5i.com/ 152ȱ Chapter 6 Pointer pointerȱinȱtheȱlist.ȱTheȱincrementȱaddsȱoneȱtoȱthatȱlocation,ȱbutȱtheȱsecondȱindirectionȱ worksȱonȱaȱcopyȱofȱtheȱoriginalȱvalue.ȱTheȱnetȱresultȱisȱthatȱtheȱcurrentȱcharacterȱinȱtheȱ currentȱ stringȱ isȱ testedȱ toȱ seeȱ whetherȱ weȇveȱ reachedȱ theȱ endȱ ofȱ theȱ string,ȱ andȱ theȱ pointerȱtoȱtheȱcurrentȱstringȱcharacterȱisȱincrementedȱasȱaȱsideȱeffect.ȱ ȱ ȱ ȱ 6.13 Pointer Arithmetic ȱ Programsȱ 6.1—6.3ȱ includeȱ expressionsȱ involvingȱ additionsȱ ofȱ pointerȱ valuesȱ andȱ integers.ȱIsȱitȱlegalȱtoȱperformȱanyȱarithmeticȱwithȱpointers?ȱTheȱanswerȱisȱaȱqualifiedȱ yes;ȱyouȱcanȱdoȱmoreȱthanȱjustȱadditionȱbutȱnotȱmuchȱmore.ȱ Theȱresultȱofȱaȱpointerȱplusȱanȱintegerȱisȱanotherȱpointer.ȱTheȱquestionȱis,ȱwhereȱ doesȱ itȱ point?ȱ Ifȱ youȱ addȱ oneȱ toȱ aȱ characterȱ pointer,ȱ theȱ resultȱ pointsȱ toȱ theȱ nextȱ characterȱ inȱ memory.ȱ Aȱ floatȱ occupiesȱ moreȱ thanȱ oneȱ byte;ȱ whatȱ happensȱ ifȱ youȱ incrementȱaȱpointerȱtoȱaȱfloat—doesȱtheȱresultȱpointȱsomewhereȱinsideȱofȱtheȱfloat?ȱ Fortunately,ȱ no.ȱ Whenȱ arithmeticȱ isȱ performedȱ withȱ aȱ pointerȱ andȱ anȱ integerȱ quantity,ȱ theȱ integerȱ isȱ alwaysȱ scaledȱ toȱ theȱ properȱ sizeȱ beforeȱ theȱ addition.ȱ Theȱ ȈproperȱsizeȈȱisȱtheȱsizeȱofȱwhateverȱtypeȱtheȱpointerȱisȱpointingȱat,ȱandȱtheȱȈscalingȈȱisȱ simplyȱmultiplication.ȱToȱillustrate,ȱimagineȱaȱmachineȱonȱwhichȱ floatsȱoccupyȱfourȱ bytes.ȱ Inȱ evaluatingȱ anȱ expressionȱ thatȱ addsȱ threeȱ toȱ aȱ pointerȱ toȱ aȱ float,ȱ theȱ valueȱ threeȱisȱscaledȱ(multiplied)ȱbyȱtheȱsizeȱofȱaȱ float,ȱwhichȱisȱfourȱinȱthisȱexample.ȱTheȱ valueȱactuallyȱaddedȱtoȱtheȱpointerȱisȱtwelve.ȱ Addingȱthreeȱtoȱtheȱpointerȱincreasedȱitȱbyȱtheȱsizeȱofȱthreeȱfloats,ȱnotȱbyȱthreeȱ bytes.ȱ Thisȱ behaviorȱ isȱ muchȱ moreȱ sensibleȱ thanȱ gettingȱ aȱ pointerȱ thatȱ pointsȱ somewhereȱinȱtheȱmiddleȱofȱaȱfloat.ȱTableȱ6.2ȱcontainsȱsomeȱadditionalȱexamples.ȱTheȱ beautyȱofȱscalingȱisȱthatȱpointerȱarithmeticȱdoesnȇtȱ ȱ ȱ Expression Assuming p is a … and the Size of *p Value Added to the Pointer to a ... is … Pointer char 1ȱ 1ȱ short 2ȱ 2ȱ p + 1 int 4ȱ 4ȱ double 8ȱ 8ȱ char 1ȱ 2ȱ short 2ȱ 4ȱ p + 2 int 4ȱ 8ȱ double 8ȱ 16ȱ ȱ Tableȱ6.2ȱPointerȱarithmeticȱresultsȱ Download at http://www.pin5i.com/ 6.13 Pointer Arithmetic 153 dependȱonȱtheȱtypeȱofȱtheȱpointer.ȱInȱotherȱwords,ȱtheȱexpressionȱ p + 1ȱpointsȱtoȱtheȱ nextȱ charȱifȱ pȱwasȱaȱpointerȱtoȱaȱ char.ȱItȱpointsȱtoȱtheȱnextȱ floatȱifȱ pȱwasȱaȱpointerȱtoȱaȱ float,ȱandȱsoȱforth.ȱ ȱ ȱ ȱ 6.13.1 Arithmetic Operations ȱ PointerȱarithmeticȱinȱCȱisȱrestrictedȱtoȱexactlyȱtwoȱforms.ȱTheȱfirstȱformȱis:ȱ ȱ pointer ± integer ȱ ThisȱformȱisȱdefinedȱbyȱtheȱStandardȱonlyȱforȱpointersȱthatȱareȱpointingȱatȱanȱelementȱ ofȱanȱarray,ȱsuchȱasȱthisȱone,ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ andȱ yieldsȱ aȱ resultȱ ofȱ theȱ sameȱ typeȱ asȱ theȱ pointer.ȱ Thisȱ formȱ alsoȱ worksȱ withȱ dynamicallyȱ allocatedȱ memoryȱ obtainedȱ fromȱ mallocȱ (seeȱ Chapterȱ 11),ȱ thoughȱ throughȱanȱoversightȱtheȱStandardȱfailsȱtoȱmentionȱthisȱfact.ȱ Elementsȱinȱanȱarrayȱareȱstoredȱinȱconsecutiveȱmemoryȱlocations,ȱandȱtheȱlaterȱ elementsȱhaveȱlargerȱaddressesȱthanȱtheȱearlierȱones.ȱGivenȱthisȱinformation,ȱitȱisȱeasyȱ toȱseeȱthatȱaddingȱoneȱtoȱtheȱpointerȱmovesȱitȱtoȱtheȱnextȱelementȱinȱtheȱarray,ȱaddingȱ fiveȱmovesȱitȱfiveȱelementsȱtoȱtheȱright,ȱandȱsoȱforth.ȱSubtractingȱthreeȱmovesȱitȱthreeȱ elementsȱtoȱtheȱleft.ȱȱScalingȱtheȱintegerȱensuresȱthatȱtheȱadditionȱproducesȱthisȱresultȱ noȱmatterȱwhatȱsizeȱelementsȱareȱinȱtheȱarray.ȱ Theȱ effectȱ ofȱ anȱ additionȱ orȱ aȱ subtractionȱ isȱ undefinedȱ ifȱ theȱ resultȱ pointsȱ toȱ anythingȱearlierȱthanȱtheȱfirstȱelementȱofȱtheȱarrayȱorȱifȱitȱpointsȱtoȱanyȱelementȱmoreȱ thanȱ oneȱ beyondȱ theȱ lastȱ elementȱ ofȱ theȱ array.ȱ Itȱ isȱ legalȱ forȱ theȱ pointerȱ toȱ goȱ oneȱ elementȱpastȱtheȱendȱofȱtheȱarray,ȱbutȱindirectionȱmayȱnotȱbeȱperformedȱonȱitȱthen.ȱ Timeȱ forȱ anȱ example.ȱ Hereȱ isȱ aȱ loopȱ thatȱ initializesȱ allȱ ofȱ theȱ elementsȱ ofȱ anȱ arrayȱ toȱ zero.ȱ (Chapterȱ 8ȱ discussesȱ theȱ efficiencyȱ ofȱ loopsȱ likeȱ thisȱ oneȱ comparedȱ toȱ loopsȱthatȱuseȱsubscripts.)ȱ Download at http://www.pin5i.com/ Chapter 6 Pointer 154ȱ #define N_VALUES 5 float values[N_VALUES]; float *vp; for( vp = &values[0]; vp < &values[N_VALUES]; ) *vp++ = 0; Theȱinitializationȱstepȱofȱtheȱ forȱstatementȱmakesȱ vpȱpointȱ toȱtheȱfirstȱelementȱofȱtheȱ array.ȱ ȱ ȱ vpȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Theȱ pointerȱ arithmeticȱ inȱ thisȱ exampleȱ isȱ performedȱ byȱ theȱ ++ȱ operator.ȱ Theȱ incrementȱvalue,ȱone,ȱisȱmultipliedȱbyȱtheȱsizeȱofȱaȱ float,ȱandȱthisȱvalueȱisȱaddedȱtoȱ theȱ pointerȱ vp.ȱ Afterȱ theȱ firstȱ timeȱ throughȱ theȱ bodyȱ ofȱ theȱ loop,ȱ memoryȱ looksȱ likeȱ this:ȱ ȱ ȱ vpȱ ȱ ȱ ȱ ȱ ȱ 0ȱ ȱ ȱ ȱ ȱ ȱ ȱ Afterȱfiveȱtimesȱthroughȱtheȱloop,ȱvpȱhasȱgoneȱpastȱtheȱendȱofȱtheȱarrayȱ ȱ ȱ ȱ vpȱ ȱ ȱ ȱ ȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ ȱ ȱ andȱ theȱ loopȱ stops.ȱ Withȱ subscriptȱ valuesȱ beginningȱ atȱ zero,ȱ theȱ lastȱ elementȱ ofȱ anȱ arrayȱofȱfiveȱelementsȱwillȱhaveȱaȱsubscriptȱofȱfour.ȱThus &value[N_VALUES] ȱ ȱ Download at http://www.pin5i.com/ 6.13 Pointer Arithmetic 155 representsȱtheȱaddressȱofȱtheȱfirstȱlocationȱbeyondȱtheȱrightȱendȱofȱtheȱarray.ȱȱWhenȱvpȱ reachesȱ thisȱ value,ȱ weȱ knowȱ weȱ haveȱ reachedȱ theȱ endȱ ofȱ theȱ array,ȱ andȱ theȱ loopȱ terminates.ȱ Theȱpointerȱinȱthisȱexampleȱgoesȱoneȱelementȱbeyondȱtheȱendȱofȱtheȱarray.ȱTheȱ pointerȱmayȱlegallyȱattainȱthisȱvalueȱbutȱapplyingȱindirectionȱtoȱitȱwillȱaccessȱwhateverȱ otherȱ variableȱ (ifȱ any)ȱ happensȱ toȱ resideȱ inȱ thatȱ location.ȱ Theȱ programmerȱ generallyȱ hasȱ noȱ wayȱ ofȱ determiningȱ whatȱ variableȱ thatȱ mightȱ be,ȱ whichȱ isȱ whyȱ indirectionȱ isȱ notȱallowedȱinȱthisȱcircumstance.ȱ Theȱsecondȱtypeȱofȱpointerȱarithmeticȱhasȱtheȱform:ȱ ȱ pointer - pointer ȱ Subtractingȱoneȱpointerȱfromȱanotherȱisȱallowedȱonlyȱwhenȱbothȱpointȱtoȱelementsȱofȱ theȱsameȱarray,ȱlikeȱthis:ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ p1 ȱ p2 ȱ ȱ ȱ ȱ ȱ Theȱ resultȱ ofȱ subtractingȱ twoȱ pointersȱ isȱ ofȱ typeȱ ptrdiff_t,ȱ whichȱ willȱ beȱ aȱ signedȱ integralȱ type.ȱ Theȱ valueȱ isȱ theȱ distanceȱ (measuredȱ inȱ arrayȱ elements,ȱ notȱ bytes)ȱ betweenȱtheȱtwoȱpointers,ȱbecauseȱtheȱresultȱofȱtheȱsubtractionȱisȱdividedȱ(scaled)ȱbyȱ theȱsizeȱofȱtheȱarrayȱelements.ȱForȱexample,ȱifȱ p1ȱpointsȱtoȱ array[i]ȱandȱ p2ȱpointsȱtoȱ array[j]ȱthenȱp2 – p1ȱwillȱhaveȱtheȱsameȱvalueȱasȱj – i.ȱ Letȇsȱseeȱhowȱthisȱworksȱwithȱaȱspecificȱtype.ȱȱSupposeȱtheȱarrayȱinȱtheȱpreviousȱ diagramȱconsistedȱofȱ floatsȱoccupyingȱfourȱbytesȱeach.ȱIfȱtheȱarrayȱbeganȱatȱlocationȱ 1000,ȱ thenȱ p1ȱ wouldȱ containȱ 1004ȱ andȱ p2ȱ wouldȱ containȱ 1024.ȱ Theȱ resultȱ ofȱ theȱ expressionȱ p2 – p1ȱwouldȱbeȱfive,ȱthough,ȱbecauseȱtheȱdifferenceȱbetweenȱtheȱpointerȱ valuesȱ(20)ȱisȱdividedȱbyȱtheȱsizeȱofȱeachȱelementȱ(4).ȱ Onceȱagain,ȱscalingȱmakesȱtheȱresultȱindependentȱofȱtheȱdataȇsȱtype.ȱTheȱresultȱ ofȱthisȱpointerȱsubtractionȱwillȱbeȱfiveȱnoȱmatterȱwhatȱtypeȱofȱdataȱtheȱarrayȱcontains.ȱ Isȱtheȱexpressionȱp1 - p2ȱlegal?ȱYes,ȱifȱbothȱpointersȱareȱpointingȱtoȱelementsȱofȱ theȱsameȱarray.ȱȱInȱtheȱpreviousȱexample,ȱitsȱvalueȱwouldȱbeȱ–5.ȱ Theȱ resultȱ ofȱ subtractingȱ twoȱ pointersȱ thatȱ doȱ notȱ pointȱ toȱ theȱ sameȱ arrayȱ isȱ undefinedȱ forȱ theȱ sameȱ reasonȱ thatȱ subtractingȱ theȱ addressesȱ ofȱ twoȱ housesȱ onȱ differentȱ streetsȱ doesnȇtȱ tellȱ youȱ theȱ numberȱ ofȱ housesȱ inȱ betweenȱ them.ȱ Theȱ programmerȱhasȱnoȱwayȱofȱknowingȱwhereȱtheȱtwoȱarraysȱmightȱhaveȱbeenȱallocatedȱ Download at http://www.pin5i.com/ Chapter 6 Pointer 156ȱ CAUTION! relativeȱ toȱ oneȱ another.ȱ Withoutȱ thisȱ knowledge,ȱ theȱ distanceȱ fromȱ oneȱ pointerȱ toȱ anotherȱhasȱnoȱmeaning.ȱ ȱ Inȱ practice,ȱ mostȱ compilersȱ doȱ notȱ checkȱ whetherȱ theȱ resultȱ ofȱ aȱ pointerȱ expressionȱ fallsȱ withinȱ anyȱ legalȱ bounds.ȱ Therefore,ȱ itȱ isȱ upȱ toȱ theȱ programmerȱ toȱ makeȱ sureȱ itȱ does.ȱSimilarly,ȱtheȱcompilerȱwillȱnotȱpreventȱyouȱfromȱtakingȱtheȱaddressȱofȱaȱscalarȱ variableȱ andȱ performingȱ pointerȱ arithmeticȱ onȱ it,ȱ evenȱ thoughȱ thereȱ isȱ noȱ wayȱ toȱ predictȱ whatȱ variableȱ theȱ resultȱ willȱ pointȱ to.ȱ OutȬofȬrangeȱ pointersȱ andȱ pointerȱ toȱ unknownȱvaluesȱareȱtwoȱcommonȱcausesȱofȱerrors.ȱWhenȱusingȱpointerȱarithmetic,ȱbeȱ veryȱcarefulȱthatȱtheȱresultȱpointsȱtoȱsomethingȱmeaningful.ȱ ȱ ȱ ȱ 6.13.2 Relational Operations ȱ Relationalȱ operationsȱ onȱ pointersȱ areȱ alsoȱ constrained.ȱ Itȱ isȱ possibleȱ toȱ compareȱ twoȱ pointerȱvaluesȱwithȱtheȱrelationalȱoperatorsȱȱ ȱ ȱ < <= > >= ȱ onlyȱ ifȱ theyȱ bothȱ pointȱ toȱ elementsȱ ofȱ theȱ sameȱ array.ȱ Dependingȱ onȱ whichȱ operatorȱ youȱ choose,ȱ theȱ comparisonȱ willȱ tellȱ youȱ whichȱ pointerȱ pointsȱ earlierȱ orȱ laterȱ inȱ theȱ array.ȱTheȱresultsȱofȱcomparingȱarbitraryȱpointersȱareȱnotȱdefinedȱbyȱtheȱStandard.ȱ However,ȱyouȱmayȱtestȱforȱequalityȱorȱinequalityȱbetweenȱanyȱpointers,ȱbecauseȱ theȱ resultsȱofȱ suchȱcomparisonsȱ doȱnotȱ dependȱonȱwhereȱtheȱ compilerȱhasȱchosenȱtoȱ allocateȱdata—theȱpointersȱeitherȱreferȱtoȱtheȱsameȱaddressȱorȱtoȱdifferentȱones.ȱ Letȇsȱlookȱagainȱatȱtheȱloopȱtoȱclearȱtheȱelementsȱofȱanȱarray.ȱ ȱ #define N_VALUES float values[N_VALUES]; float *vp; 5 for( vp = &values[0]; vp < &values[N_VALUES]; ) *vp++ = 0; ȱ Theȱforȱstatementȱusesȱaȱrelationalȱtestȱtoȱterminateȱtheȱloop.ȱȱTheȱtestȱisȱlegalȱbecauseȱ bothȱ vpȱ andȱ theȱ pointerȱ constantȱ pointȱ toȱ elementsȱ ofȱ theȱ sameȱ array.ȱ (Actually,ȱ theȱ pointerȱconstantȱpointsȱoneȱbeyondȱtheȱendȱofȱfileȱarray,ȱandȱwhenȱtheȱlastȱcomparisonȱ isȱmadeȱsoȱdoesȱvp,ȱbutȱindirectionȱisȱnotȱperformedȱsoȱweȇreȱsafe.)ȱUsingȱ!=ȱinsteadȱofȱ <ȱ wouldȱ alsoȱ work,ȱ becauseȱ bothȱ expressionsȱ willȱ beȱ falseȱ whenȱ vpȱ attainsȱ itsȱ finalȱ value.ȱ ȱ Download at http://www.pin5i.com/ 6.14 Summary 157 Nowȱconsiderȱthisȱloop:ȱ ȱ for( vp = &values[N_VALUES]; vp > &values[0]; ) *--vp = 0 ȱ Itȱperformsȱtheȱsameȱjobȱasȱtheȱpreviousȱloopȱexceptȱthatȱtheȱelementsȱareȱclearedȱinȱ theȱoppositeȱorder.ȱȱWeȱinitializeȱvpȱtoȱpointȱjustȱbeyondȱtheȱrightȱendȱofȱtheȱarray,ȱbutȱ theȱpointerȱisȱdecrementedȱjustȱbeforeȱtheȱindirectionȱoccurs.ȱȱWeȱstopȱtheȱloopȱwhenȱ vpȱ pointsȱ toȱ theȱ firstȱ elementȱ ofȱ theȱ array,ȱ butȱ thisȱ occursȱ afterȱ theȱ firstȱ elementȱ hasȱ alreadyȱbeenȱcleared.ȱ Someȱ mightȱ objectȱ toȱ theȱ expressionȱ *--vpȱ onȱ theȱ groundsȱ ofȱ readability.ȱ Butȱ lookȱwhatȱhappensȱtoȱthisȱloopȱwhenȱitȱisȱȈsimplified:Ȉȱ ȱ for( vp = &values[N_VALUES-1]; vp > &values[0]; vp-- ) *vp = 0; ȱ CAUTION! Nowȱvpȱisȱinitializedȱtoȱpointȱtoȱtheȱlastȱelementȱofȱtheȱarrayȱandȱisȱdecrementedȱinȱtheȱ adjustmentȱstepȱofȱtheȱforȱstatement.ȱThereȱisȱaȱproblemȱwithȱthisȱloop—doȱyouȱseeȱit?ȱ ȱ Afterȱ theȱ firstȱ elementȱ inȱ theȱ arrayȱ isȱ cleared,ȱ vpȱ isȱ decrementedȱ again,ȱ andȱ theȱ nextȱ comparisonȱisȱsupposedȱtoȱterminateȱtheȱloop.ȱButȱhereȱisȱwhereȱtheȱproblemȱoccurs:ȱ theȱcomparisonȱ vp >= &values[0]ȱisȱundefinedȱbecauseȱ vpȱhasȱmovedȱoutsideȱofȱtheȱ boundsȱofȱtheȱarray.ȱTheȱStandardȱallowsȱforȱaȱcomparisonȱwithȱaȱpointerȱthatȱpointsȱ justȱbeyondȱtheȱrightȱsideȱofȱanȱarrayȱbutȱnotȱforȱoneȱthatȱpointsȱjustȱbeyondȱtheȱleftȱ side.ȱ Inȱ practice,ȱ thisȱ loopȱ willȱ workȱ properlyȱ onȱ mostȱ ANSIȱ Cȱ implementations.ȱ Nevertheless,ȱ itȱ shouldȱ beȱ avoidedȱ becauseȱ theȱ Standardȱ doesȱ notȱ guaranteeȱ thatȱ itȱ willȱwork,ȱandȱsoonerȱorȱlaterȱyouȱareȱboundȱtoȱrunȱacrossȱaȱmachineȱonȱwhichȱitȱfails.ȱȱ Suchȱareȱtheȱproblemsȱthatȱgiveȱnightmaresȱtoȱprogrammersȱresponsibleȱforȱportableȱ code.ȱ ȱ ȱ ȱ 6.14 Summary ȱ Eachȱlocationȱinȱtheȱcomputerȇsȱmemoryȱisȱidentifiedȱbyȱanȱaddress.ȱAdjacentȱlocationsȱ areȱoftenȱgroupedȱtogetherȱtoȱallowȱlargerȱrangesȱofȱvaluesȱtoȱbeȱstored.ȱAȱpointerȱisȱaȱ valueȱthatȱrepresentsȱaȱmemoryȱaddress.ȱ Neitherȱyouȱnorȱtheȱcomputerȱcanȱdetermineȱtheȱtypeȱofȱaȱvalueȱbyȱexaminingȱ itsȱbits;ȱtheȱtypeȱisȱimplicitȱinȱhowȱtheȱvalueȱisȱused.ȱTheȱcompilerȱhelpsȱusȱbyȱensuringȱ thatȱvaluesȱareȱusedȱinȱaȱwayȱthatȱisȱappropriateȱtoȱhowȱtheyȱareȱdeclared.ȱ Download at http://www.pin5i.com/ 158ȱ Chapter 6 Pointer Theȱ valueȱ ofȱ aȱ pointerȱ variableȱ isȱ notȱ theȱ valueȱ toȱ whichȱ itȱ points.ȱ Indirectionȱ mustȱbeȱappliedȱtoȱaȱpointerȱtoȱobtainȱtheȱvalueȱthatȱitȱpointsȱto.ȱTheȱresultȱofȱapplyingȱ indirectionȱtoȱaȱȈpointerȱtoȱintegerȈȱisȱanȱinteger.ȱ Declaringȱ pointerȱ variableȱ doesȱ notȱ automaticallyȱ allocateȱ anyȱ memoryȱ inȱ whichȱtoȱstoreȱvalues.ȱBeforeȱindirectionȱcanȱbeȱperformedȱonȱtheȱpointer,ȱitȱmustȱbeȱ initializedȱ coȱ pointȱ eitherȱ toȱ existingȱ memoryȱ orȱ toȱ dynamicallyȱ allocatedȱ memory.ȱ Indirectionȱ onȱ anȱ uninitializedȱ pointerȱ variableȱ isȱ illegalȱ butȱ oftenȱ goesȱ undetected.ȱ Theȱ resultȱ mayȱ beȱ thatȱ anȱ unrelatedȱ valueȱ isȱ modified.ȱ Theseȱ errorsȱ areȱ difficultȱ toȱ debug.ȱ TheȱNULLȱpointerȱisȱaȱvalueȱthatȱisȱdefinedȱasȱpointingȱtoȱnothingȱatȱall.ȱItȱcanȱ beȱ assignedȱ toȱ aȱ pointerȱ variableȱ toȱ indicateȱ thatȱ theȱ variableȱ doesȱ notȱ pointȱ toȱ anyȱ value.ȱ Theȱ resultȱ ofȱ applyingȱ indirectionȱ toȱ aȱ NULLȱ pointerȱ isȱ implementationȱ dependent;ȱtwoȱcommonȱresultsȱareȱtoȱreturnȱtheȱvalueȱofȱmemoryȱlocationȱzeroȱandȱ toȱabortȱtheȱprogram.ȱ Aȱpointerȱvariable,ȱlikeȱanyȱotherȱvariable,ȱcanȱbeȱusedȱasȱanȱLȬvalue.ȱApplyingȱ indirectionȱ toȱ aȱ pointerȱ alsoȱ resultsȱ inȱ anȱ LȬvalueȱ becauseȱ theȱ expressionȱ identifiesȱ aȱ specificȱmemoryȱlocation.ȱ Otherȱ thanȱ theȱ NULLȱ pointer,ȱ thereȱ isȱ noȱ builtȬinȱ notationȱ forȱ expressingȱ pointerȱconstantsȱbecauseȱtheȱprogrammerȱusuallyȱhasȱnoȱwayȱofȱpredictingȱwhereȱtheȱ compilerȱ willȱ placeȱ variables.ȱ Inȱ theȱ rareȱ casesȱ whereȱ theyȱ areȱ needed,ȱ pointerȱ constantsȱcanȱbeȱcreatedȱbyȱcastingȱintegerȱvalues.ȱ Limitedȱarithmeticȱcanȱbeȱperformedȱonȱpointerȱvalues.ȱYouȱcanȱaddȱanȱintegerȱ valueȱ toȱ aȱ pointer,ȱ andȱ subtractȱ anȱ integerȱ valueȱ fromȱ aȱ pointer.ȱ Inȱ bothȱ cases,ȱ theȱ integerȱ valueȱ isȱ scaledȱ byȱ theȱ sizeȱ ofȱ theȱ pointerȇsȱ targetȱ type.ȱ Thus,ȱ addingȱ oneȱ toȱ aȱ pointerȱ makesȱ itȱ pointȱ toȱ theȱ nextȱ variableȱ regardlessȱ ofȱ theȱ sizeȱ ofȱ theȱ variablesȱ inȱ memory.ȱ However,ȱthisȱpointerȱarithmeticȱisȱpredictableȱonlyȱwithȱarrays.ȱItȱisȱillegalȱ(butȱ oftenȱ notȱ detected)ȱ toȱ performȱ arithmeticȱ onȱ anyȱ pointerȱ thatȱ doesȱ notȱ pointȱ toȱ anȱ elementȱofȱanȱarray.ȱItȱisȱalsoȱillegalȱtoȱsubtractȱfromȱaȱpointerȱifȱtheȱresultȱliesȱbeforeȱ theȱfirstȱelementȱofȱtheȱarrayȱtoȱwhichȱitȱpoints,ȱandȱtoȱaddȱtoȱaȱpointerȱifȱtheȱresultȱliesȱ moreȱ thanȱ oneȱ elementȱ afterȱ theȱ endȱ ofȱ theȱ arrayȱ toȱ whichȱ itȱ points.ȱ Theȱ resultȱ ofȱ aȱ pointerȱadditionȱmayȱpointȱoneȱelementȱbeyondȱtheȱendȱofȱtheȱarray,ȱbutȱitȱisȱillegalȱtoȱ applyȱindirectionȱtoȱthisȱresult.ȱ Twoȱ pointersȱ mayȱ beȱ subtractedȱ fromȱ oneȱ anotherȱ onlyȱ ifȱ theyȱ bothȱ pointȱ toȱ elementsȱofȱtheȱsameȱarray.ȱTheȱresultȱofȱpointerȱsubtractionȱisȱscaledȱbyȱtheȱsizeȱofȱtheȱ valuesȱ inȱ theȱ array,ȱ soȱ theȱ resultȱ isȱ theȱ numberȱ ofȱ valuesȱ separatingȱ theȱ originalȱ pointers.ȱSubtractingȱpointersȱtoȱelementsȱofȱdifferentȱarraysȱisȱanȱ(oftenȱundetected)ȱ error.ȱ ȱ Download at http://www.pin5i.com/ 6.17 Questions 159 Anyȱ pointersȱ mayȱ beȱ comparedȱ toȱ eachȱ otherȱ forȱ equalityȱ orȱ inequality.ȱ Twoȱ pointersȱ thatȱ pointȱ toȱ elementsȱ ofȱ theȱ sameȱ arrayȱ mayȱ alsoȱ beȱ comparedȱ usingȱ theȱ relationalȱoperatorsȱ <,ȱ <=,ȱ >,ȱandȱ >=ȱtoȱdetermineȱtheirȱpositionsȱinȱtheȱarrayȱrelativeȱtoȱ eachȱ other.ȱ Theȱ resultȱ ofȱ aȱ relationalȱ comparisonȱ betweenȱ unrelatedȱ pointersȱ isȱ undefined.ȱ ȱ ȱ ȱ 6.15 Summary of Cautions ȱ 1. Dereferencingȱanȱuninitializedȱpointerȱvariableȱ(pageȱ135).ȱ 2. DereferencingȱaȱNULLȱpointerȱ(pageȱ136).ȱ 3. NULLȱpointerȱargumentsȱtoȱfunctionsȱ(pageȱ149).ȱ 4. Unexpectedȱresultsȱfromȱerrorsȱinȱ pointerȱexpressionsȱthatȱareȱnotȱdetectedȱ (pageȱ 156).ȱ 5. Decrementingȱaȱpointerȱvariableȱpastȱtheȱbeginningȱofȱanȱarrayȱ(pageȱ157).ȱ ȱ ȱ ȱ 6.16 Summary of Programming Tips ȱ 1. Aȱvalueȱshouldȱonlyȱhaveȱoneȱmeaningȱ(pageȱ136).ȱ 2. SetȱpointerȱvariablesȱtoȱNULLȱwhenȱtheyȱareȱnotȱpointingȱtoȱanythingȱusefulȱ(pageȱ 137).ȱ ȱ ȱ ȱ 6.17 Questions ȱ 1. Ifȱtheȱtypeȱofȱaȱvalueȱcannotȱbeȱdeterminedȱsimplyȱbyȱlookingȱatȱitsȱbits,ȱhowȱdoesȱ theȱmachineȱknowȱhowȱtheȱvalueȱshouldȱbeȱmanipulated?ȱ 2. WhyȱdoesnȇtȱCȱhaveȱaȱwayȱofȱdeclaringȱliteralȱpointerȱconstants?ȱ 3. Supposeȱanȱintegerȱcontainsȱtheȱvalueȱ244.ȱȱWhyȱdoesnȇtȱtheȱmachineȱinterpretȱthisȱ valueȱasȱanȱaddress?ȱ 4. Onȱsomeȱmachines,ȱtheȱcompilerȱarrangesȱforȱmemoryȱlocationȱzeroȱtoȱcontainȱtheȱ valueȱzero.ȱDereferencingȱaȱNULLȱpointerȱthenȱaccessesȱthisȱlocation.ȱWhatȱareȱtheȱ consequencesȱofȱthisȱarrangement?ȱ Download at http://www.pin5i.com/ Chapter 6 Pointer 160ȱ 5. Whatȱ isȱ theȱ differenceȱ (ifȱ any)ȱ betweenȱ theȱ workȱ thatȱ isȱ requiredȱ toȱ evaluateȱ expressionsȱ(a)ȱandȱ(b)?ȱAssumeȱthatȱtheȱvariableȱoffsetȱhasȱtheȱvalueȱthree.ȱ ȱ int int int i[ 10 ]; *p = &i[ 0 ]; offset; p += offset; p += 3; (a) (b) 6. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱcodeȱsegment?ȱ int int array[ARRAY_SIZE]; *pi; for( pi = &array[0]; pi < &array[ARRAY_SIZE]; ) *++pi = 0; 7. Theȱtableȱbelowȱshowsȱtheȱcontentsȱofȱseveralȱmemoryȱlocations.ȱEachȱlocationȱisȱ identifiedȱ byȱ itsȱ addressȱ andȱ alsoȱ byȱ theȱ nameȱ ofȱ theȱ variableȱ storedȱ there.ȱ Allȱ numbersȱareȱshownȱinȱdecimal.ȱ ȱ Variable Address Contents Variable Address Contents aȱ 1040ȱ 1028ȱ oȱ 1096ȱ 1024ȱ cȱ dȱ eȱ fȱ gȱ hȱ iȱ jȱ kȱ mȱ nȱ 1056ȱ 1008ȱ 1032ȱ 1052ȱ 1000ȱ 1080ȱ 1020ȱ 1064ȱ 1044ȱ 1016ȱ 1076ȱ 1076ȱ 1016ȱ 1088ȱ 1044ȱ 1064ȱ 1020ȱ 1080ȱ 1000ȱ 1052ȱ 1008ȱ 1056ȱ qȱ rȱ sȱ tȱ uȱ vȱ wȱ xȱ yȱ zȱ ȱ 1084ȱ 1068ȱ 1004ȱ 1060ȱ 1036ȱ 1092ȱ 1012ȱ 1072ȱ 1048ȱ 2000ȱ ȱ 1072ȱ 1048ȱ 2000ȱ 1012ȱ 1092ȱ 1036ȱ 1060ȱ 1080ȱ 1068ȱ 1000ȱ ȱ ȱ Usingȱ theseȱ values,ȱ evaluateȱ eachȱ ofȱ theȱ expressionsȱ belowȱ fourȱ ways.ȱ First,ȱ assumeȱthatȱallȱtheȱvariablesȱareȱintegers,ȱandȱfindȱtheȱexpressionsȱRȬvalue.ȱThenȱ findȱitsȱLȬvalue,ȱandȱgiveȱtheȱaddressȱofȱtheȱlocationȱitȱspecifies.ȱȱNext,ȱassumeȱthatȱ allȱ theȱ variablesȱ areȱ pointersȱ toȱ integersȱ andȱ repeatȱ theȱ exercise.ȱ Note:ȱ Doȱ yourȱ addressȱarithmeticȱbasedȱonȱfourȬbyteȱintegersȱandȱpointers.ȱ Download at http://www.pin5i.com/ 6.17 Questions 161 ȱ Integers Expression R-value L-value addr Pointers to Integers R-value L-value addr a. m ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . b. v + 1 ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . c. j – 4 ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . d. a – d ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . e. v – w ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . f. &c ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . g. &e + 1 ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . h. &o – 4 ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . i. &( f + 2 ) ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . j. *g ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . k. *k + 1 ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . l. *( n + 1 ) ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . m. *h – 4 ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . n. *( u – 4 ) ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . o. *f – g ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . p. *f - *g ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . q. *s - *q ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . r. *( r – t ) ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . s. y > i ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . t. y > *i ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . u. *y > *i ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . v. **h ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . w. c++ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . x. ++c ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . y. *q++ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . z. (*q)++ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . aa. *++q ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . bb. ++*q ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . cc. *++*q ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . dd. ++*(*q)++ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . Download at http://www.pin5i.com/ Chapter 6 Pointer 162ȱ 6.18 Programming Exercises ȱ 1. Writeȱ aȱ functionȱ thatȱ willȱ searchȱ aȱ stringȱ forȱ anyȱ oneȱ ofȱ aȱ givenȱ setȱ ofȱ characters.ȱ Yourȱfunctionȱshouldȱmatchȱthisȱprototype:ȱ char *find_char( char const *source, char const *chars ); Theȱ basicȱ ideaȱ isȱ toȱ locateȱ theȱ firstȱ characterȱ inȱ theȱ sourceȱ stringȱ thatȱ matchesȱ anyȱofȱtheȱcharactersȱinȱtheȱ charsȱstring.ȱTheȱfunctionȱthenȱreturnsȱaȱpointerȱtoȱtheȱ placeȱ inȱ sourceȱ whereȱ theȱ firstȱ matchȱ wasȱ found.ȱ ȱ Ifȱ noneȱ ofȱ theȱ charactersȱ inȱ sourceȱmatchȱanyȱofȱtheȱchars,ȱthenȱaȱNULLȱpointerȱisȱreturned.ȱIfȱeitherȱargumentȱ isȱNULL,ȱorȱeitherȱstringȱisȱempty,ȱthenȱaȱNULLȱpointerȱisȱreturned.ȱ Toȱ illustrate,ȱ supposeȱ sourceȱ pointsȱ toȱ ABCDEFG.ȱ Ifȱ charsȱ pointsȱ toȱ XYZ,ȱ JURY,ȱ orȱ QQQQ,ȱ theȱ functionȱ shouldȱ returnȱ NULL.ȱ ȱ Ifȱ charsȱ pointsȱ toȱ XRCQEF,ȱ theȱ functionȱ shouldȱ returnȱ aȱ pointerȱ toȱ theȱ Cȱ inȱ source.ȱ Theȱ stringsȱ thatȱ theȱ argumentsȱpointȱtoȱareȱneverȱmodified.ȱ Asȱ itȱ happens,ȱ thereȱ isȱ aȱfunctionȱ inȱ theȱ Cȱlibraryȱ calledȱ strpbrkȱ thatȱ behavesȱ almostȱexactlyȱtheȱsameȱasȱtheȱoneȱyouȱareȱtoȱwrite.ȱButȱtheȱobjectȱofȱthisȱprogramȱ isȱforȱyouȱtoȱmanipulateȱtheȱpointersȱyourself,ȱso:ȱ a. Youȱmayȱnotȱuseȱanyȱofȱtheȱlibraryȱstringȱroutinesȱ(forȱexample,ȱ strcpy,ȱ strcmp,ȱindex,ȱetc.),ȱandȱ b. youȱmayȱnotȱuseȱsubscriptsȱanywhereȱinȱyourȱfunction.ȱ ȱ 2. Writeȱaȱfunctionȱthatȱdeletesȱaȱportionȱofȱaȱstring.ȱȱHereȱisȱitsȱprototype:ȱ int del_substr( char *str char const *substr ) Theȱ functionȱ shouldȱ firstȱ determineȱ whetherȱ theȱ stringȱ substrȱ occursȱ inȱ str.ȱ Ifȱ itȱ doesȱnot,ȱtheȱvalueȱ0ȱshouldȱbeȱreturned.ȱȱIfȱtheȱsubstringȱdoesȱappear,ȱtheȱfunctionȱ shouldȱ removeȱ itȱ byȱ copyingȱ theȱ charactersȱ inȱ strȱ thatȱ followȱ theȱ substringȱ overȱ theȱsubstringȱitself.ȱTheȱvalueȱ 1ȱshouldȱthenȱbeȱreturned.ȱIfȱtheȱsubstringȱappearsȱ severalȱtimesȱinȱtheȱfirstȱargument,ȱonlyȱtheȱfirstȱoccurrenceȱshouldȱbeȱdeleted.ȱTheȱ secondȱargumentȱshouldȱneverȱbeȱchangedȱ Toȱillustrate,ȱsupposeȱ strȱpointsȱ toȱ ABCDEFG.ȱ Ifȱ substrȱpointsȱtoȱFGH,ȱCDF,ȱ orȱ XABC,ȱ theȱ functionȱ shouldȱ returnȱ 0ȱ andȱ leaveȱ strȱ unchanged.ȱ Butȱ ifȱ substrȱ pointsȱtoȱCDE,ȱtheȱfunctionȱshouldȱchangeȱ strȱtoȱABFGȱbyȱcopyingȱtheȱcharactersȱ F,ȱ G,ȱ andȱ theȱ NULȱ byte.ȱ Theȱ functionȱ shouldȱ thenȱ returnȱ 1.ȱ Inȱ noȱ eventȱ isȱ theȱ secondȱargumentȱstringȱeverȱmodified.ȱ Asȱwithȱtheȱlastȱprogram:ȱ a. ȱ ȱ yonȱ mayȱ notȱ useȱ anyȱ ofȱ theȱ libraryȱ stringȱ routinesȱ (e.g.ȱ strcpy,ȱ strcmp,ȱ etc.),ȱandȱ Download at http://www.pin5i.com/ 6.18 Programming Exercises b. 163 youȱmayȱnotȱuseȱanyȱsubscriptsȱinȱyourȱfunction.ȱ Onȱ aȱ philosophicalȱ note,ȱ theȱ emptyȱ stringȱ isȱ aȱ substringȱ ofȱ everyȱ stringȱ butȱ removingȱanȱemptyȱsubstringȱproducesȱnoȱchangeȱinȱtheȱstring.ȱ 3. Writeȱtheȱfunctionȱreverse_string,ȱwhoseȱprototypeȱisȱshownȱbelow:ȱ ȱ void reverse_string( char *string ); Theȱ functionȱ reversesȱ theȱ charactersȱ inȱ theȱ argumentȱ string.ȱ Useȱ pointersȱ ratherȱ thanȱsubscripts,ȱandȱdoȱnotȱuseȱanyȱofȱtheȱCȱlibraryȱstringȱfunctions.ȱHint:ȱThereȱisȱ noȱneedȱtoȱdeclareȱaȱlocalȱarrayȱtoȱtemporarilyȱholdȱtheȱargumentȱstring.ȱ 4. Aȱ primeȱ numberȱ isȱ oneȱ thatȱ isȱ divisibleȱ onlyȱ byȱ itselfȱ andȱ one.ȱ Theȱ Sieveȱ ofȱ Eratosthenesȱisȱanȱefficientȱalgorithmȱforȱtheȱcomputationȱofȱprimeȱnumbers.ȱTheȱ firstȱstepȱofȱtheȱalgorithmȱisȱtoȱwriteȱdownȱallȱtheȱnumbersȱfromȱtwoȱtoȱsomeȱupperȱ limit.ȱ Inȱ theȱ restȱ ofȱ theȱ algorithm,ȱ youȱ goȱ throughȱ theȱ listȱ andȱ crossȱ outȱ numbersȱ thatȱareȱnotȱprime.ȱ Hereȱareȱtheȱremainingȱsteps.ȱStartingȱatȱtheȱbeginningȱofȱtheȱlist,ȱfindȱtheȱfirstȱ numberȱthatȱisȱnotȱcrossedȱout,ȱwhichȱwillȱbeȱtwo.ȱCrossȱoutȱeveryȱsecondȱnumberȱ inȱtheȱlistȱafterȱtwo,ȱbecauseȱtheyȱareȱallȱmultiplesȱofȱtwo.ȱThenȱrepeatȱtheseȱstepsȱ fromȱtheȱbeginningȱofȱtheȱlist.ȱTheȱfirstȱnumberȱinȱtheȱlistȱthatȱisȱnotȱcrossedȱoutȱisȱ nowȱthree,ȱsoȱcrossȱoutȱeveryȱthirdȱnumberȱafterȱthree.ȱTheȱnextȱnumberȱinȱtheȱlist,ȱ four,ȱisȱalreadyȱcrossedȱoutȱsoȱitȱisȱskipped.ȱWhenȱyouȱhaveȱfinishedȱthisȱprocess,ȱ theȱnumbersȱthatȱhaveȱnotȱbeenȱcrossedȱoutȱareȱprime.ȱ Writeȱ aȱ programȱ thatȱ implementsȱ thisȱ algorithm,ȱ usingȱ anȱ arrayȱ forȱ yourȱ list.ȱ Theȱvalueȱinȱeachȱarrayȱelementȱkeepsȱtrackȱofȱwhetherȱtheȱcorrespondingȱnumberȱ hasȱbeenȱcrossedȱout.ȱSetȱallȱelementsȱofȱtheȱarrayȱtoȱTRUEȱinitially,ȱthenȱsetȱthemȱ FALSEȱaccordingȱtoȱtheȱalgorithmȱaboveȱtoȱȈcrossȱthemȱout.ȈȱIfȱyouȱareȱworkingȱonȱ aȱ 16Ȭbitȱ machine,ȱ thinkȱ carefullyȱ whichȱ variablesȱ shouldȱ beȱ declaredȱ long.ȱ Startȱ withȱanȱarrayȱofȱ1000ȱelements.ȱIfȱyouȱuseȱanȱarrayȱofȱcharactersȬȱyouȱcanȱfindȱmoreȱ primeȱ numbersȱ thanȱ ifȱ youȱ useȱ anȱ arrayȱ ofȱ integers.ȱ Youȱ canȱ useȱ subscriptsȱ toȱ computeȱ pointersȱ toȱ theȱ beginningȱ andȱ endȱ ofȱ theȱ array,ȱ butȱ youȱ shouldȱ useȱ pointersȱtoȱaccessȱtheȱarrayȱelements.ȱ Noteȱ thatȱ noneȱ ofȱ theȱ evenȱ numbersȱ areȱ primeȱ exceptȱ forȱ two.ȱ Withȱ aȱ littleȱ thought,ȱyouȱcanȱmakeȱtheȱprogramȱmoreȱspaceȱefficientȱbyȱkeepingȱtrackȱofȱonlyȱ theȱoddȱnumbersȱwithȱyourȱarray.ȱYouȱshouldȱthenȱbeȱableȱtoȱfindȱ(roughly)ȱtwiceȱ asȱmanyȱprimeȱnumbersȱwithȱtheȱsameȱsizeȱarray.ȱ 5. ModifyȱtheȱSieveȱofȱEratosthenesȱprogramȱinȱtheȱpreviousȱproblemȱsoȱthatȱitȱusesȱ anȱarrayȱofȱbitsȱratherȱthanȱ characters,ȱ usingȱtheȱbitȱarrayȱ functionsȱdevelopedȱinȱ theȱChapterȱ5ȱprogrammingȱexercises.ȱThisȱchangeȱmakesȱtheȱprogramȱevenȱmoreȱ spaceȱ efficient,ȱatȱaȱ costȱofȱtimeȱefficiency.ȱWhatȱisȱtheȱ largestȱ primeȱ numberȱ youȱ canȱcomputeȱinȱthisȱmannerȱonȱyourȱsystem?ȱ Download at http://www.pin5i.com/ 164ȱ Chapter 6 Pointer 6. Areȱ thereȱ asȱ manyȱ largeȱ primeȱ numbersȱ asȱ thereȱ areȱ smallȱ ones?ȱ Inȱ otherȱ words,ȱ areȱthereȱasȱmanyȱprimeȱnumbersȱbetweenȱ50,000ȱandȱ51,000ȱasȱthereȱareȱbetween,ȱ say,ȱ 1,000,000ȱ andȱ 1,001,000?ȱ Useȱ theȱ previousȱ programȱ toȱ determineȱ howȱ manyȱ primeȱnumbersȱthereȱareȱbetweenȱ0ȱandȱ1000,ȱbetweenȱ1000ȱandȱ2000,ȱandȱsoȱforthȱ upȱtoȱ1,000,000ȱ(orȱasȱhighȱasȱyouȱcanȱgoȱonȱyourȱsystem).ȱWhatȱisȱtheȱtrendȱinȱtheȱ numberȱofȱprimesȱperȱthousandȱnumbers?ȱ Download at http://www.pin5i.com/ 7 Functions Thereȱ isȱ muchȱ aboutȱ functionsȱ inȱ Cȱ thatȱ isȱ similarȱ toȱ functionsȱ inȱ otherȱ languages,ȱ whichȱisȱwhyȱyouȇveȱbeenȱableȱtoȱuseȱthemȱthusȱfarȱwithȱonlyȱanȱinformalȱdiscussion.ȱȱ Howeverȱ thereȱ areȱ someȱ aspectsȱ ofȱ functionsȱ thatȱ areȱ lessȱ intuitive,ȱ soȱ thisȱ chapterȱ formallyȱdescribesȱfunctionsȱinȱC.ȱ ȱ ȱ ȱ 7.1 Function Definition ȱ Theȱ definitionȱ ofȱ aȱ functionȱ specificsȱ theȱ functionȱ body,ȱ theȱ blockȱ ofȱ statementsȱ toȱ beȱ executedȱwhenȱtheȱfunctionȱisȱcalled.ȱInȱcontrast,ȱaȱfunctionȱdeclarationȱisȱusedȱwhereȱ theȱ functionȱ isȱ beingȱ called.ȱ ȱ Aȱ declarationȱ givesȱ theȱ compilerȱ informationȱ aboutȱ theȱ functionȱsoȱthatȱitȱcanȱbeȱcalledȱcorrectly.ȱLetȇsȱlookȱfirstȱatȱdefinitions.ȱ Aȱfunctionȱisȱdefinedȱwithȱthisȱsyntax:ȱ ȱ type name( formal_parameters ) block ȱ Recallȱ thatȱ aȱ blockȱ isȱ aȱ pairȱ ofȱ bracesȱ enclosingȱ optionalȱ declarationsȱ followedȱ byȱ optionalȱstatements.ȱTheȱminimalȱfunction,ȱtherefore,ȱlooksȱlikeȱthis:ȱ ȱ function_name() { } ȱ Whenȱcalled,ȱthisȱfunctionȱsimplyȱreturns.ȱNevertheless,ȱitȱservesȱaȱusefulȱpurposeȱasȱaȱ stub,ȱ aȱ placeholderȱ forȱ codeȱ thatȱ hasȱ yetȱ toȱ beȱ implemented.ȱ Writingȱ stubs,ȱ orȱ ȈstubbingȱoutȈȱcodeȱthatȱhasȱnotȱyetȱbeenȱwritten,ȱletsȱyouȱcompileȱandȱtestȱtheȱrestȱofȱ theȱprogram.ȱ Download at http://www.pin5i.com/ 166 K&R C Chapter 7 Functions Theȱ listȱ ofȱ formalȱ parametersȱ includesȱ variableȱ namesȱ andȱ theirȱ typeȱ declarations.ȱ Theȱ blockȱ containsȱ declarationsȱ forȱ localȱ variablesȱ andȱ theȱ statementsȱ thatȱareȱexecutedȱwhenȱtheȱfunctionȱisȱcalled.ȱProgramȱ7.1ȱisȱanȱexampleȱofȱaȱsimpleȱ function.ȱ Writingȱtheȱfunctionȱtypeȱonȱaȱseparateȱlineȱfromȱtheȱfunctionȱnameȱisȱaȱmatterȱ ofȱstyle;ȱitȱmakesȱitȱeasierȱtoȱlocateȱtheȱfunctionȱnamesȱwhenȱperusingȱtheȱsourceȱcodeȱ eitherȱvisuallyȱorȱwithȱsomeȱprogram.ȱ ȱ Inȱ K&Rȱ C,ȱ theȱ typesȱ ofȱ formalȱ parametersȱ wereȱ declaredȱ inȱ aȱ separateȱ listȱ thatȱ appearedȱbetweenȱtheȱparameterȱlistȱandȱtheȱopeningȱbraceȱofȱtheȱfunctionȱbody,ȱlikeȱ this:ȱ ȱ int * find_int( key, array, array_len ) int key; int array[]; int array_len; { /* ** Find the place in an array where a particular integer value ** is stored, and return a pointer to that location. */ #include <stdio.h> int * find_int( int key, int array[], int array_len ) { int i; /* ** For each location in the array ... */ for( i = 0; i < array_len; i += 1 ) /* ** Check the location for the desired value. */ if( array[ i ] == key ) return &array[ i ]; return NULL; } Programȱ7.1ȱFindȱanȱintegerȱinȱanȱarrayȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱfind_int.cȱ Download at http://www.pin5i.com/ 7.1 Function Definition 167 ThisȱdeclarationȱformȱisȱallowedȱbyȱtheȱStandardȱmainlyȱsoȱthatȱolderȱprogramsȱcanȱbeȱ compiledȱ withoutȱ modification.ȱ Theȱ newerȱ declarationȱ styleȱ isȱ preferredȱ forȱ twoȱ reasons.ȱ First,ȱ itȱ eliminatesȱ theȱ redundancyȱ ofȱ dieȱ oldȱ style.ȱ Moreȱ importantly,ȱ itȱ allowsȱ forȱ theȱ useȱ ofȱ functionȱ prototypes,ȱ discussedȱ laterȱ inȱ thisȱ chapter,ȱ whichȱ improveȱtheȱcompilerȇsȱerrorȱcheckingȱofȱfunctionȱcalls.ȱ ȱ ȱ ȱ 7.1.1 Return Statement ȱ Whenȱexecutionȱreachesȱtheȱendȱofȱtheȱfunctionȱdefinition,ȱtheȱfunctionȱreturns,ȱthatȱis,ȱ executionȱ goesȱ backȱ toȱ whereȱ theȱ functionȱ wasȱ called.ȱ Theȱ returnȱ statementȱ allowsȱ youȱ toȱ returnȱ fromȱ anywhereȱ inȱ theȱ functionȱ body,ȱ notȱ justȱ atȱ itsȱ end.ȱ Itsȱ syntaxȱ isȱ shownȱbelow.ȱ ȱ ȱ return expression; ȱ Theȱ expressionȱisȱoptional.ȱItȱisȱomittedȱinȱfunctionsȱthatȱdoȱnotȱreturnȱaȱvalueȱtoȱtheȱ callingȱ program,ȱ whatȱ mostȱ otherȱ languagesȱ callȱ aȱ procedure.ȱ Functionsȱ thatȱ returnȱ implicitlyȱbyȱreachingȱtheȱendȱofȱtheirȱcodeȱalsoȱdoȱnotȱreturnȱaȱvalue.ȱȱProcedureȬtypeȱ functionsȱshouldȱbeȱdeclaredȱwithȱtheȱtypeȱvoid.ȱ Aȱtrueȱfunctionȱisȱcalledȱfromȱwithinȱanȱexpression,ȱandȱmustȱreturnȱaȱvalueȱthatȱ isȱ usedȱ inȱ evaluatingȱ theȱ expression.ȱ Theȱ returnȱ statementȱ inȱ theseȱ functionsȱ mustȱ includeȱ theȱ expression.ȱ Usually,ȱ theȱ expressionȱ willȱ beȱ ofȱ theȱ typeȱ thatȱ theȱ functionȱ wasȱ declaredȱ toȱ return.ȱ Anȱ expressionȱ ofȱ aȱ differentȱ typeȱ isȱ permittedȱ onlyȱ ifȱ theȱ compilerȱcanȱconvertȱitȱtoȱdieȱproperȱtypeȱthroughȱtheȱusualȱarithmeticȱconversions.ȱ Someȱprogrammersȱpreferȱtoȱwriteȱreturnȱstatementsȱlikeȱthis:ȱ ȱ return( x ); ȱ Theȱsyntaxȱdoesȱnotȱrequireȱparentheses,ȱbutȱyouȱcanȱuseȱthemȱifȱyouȱpreferȱbecauseȱ parenthesesȱareȱalwaysȱlegalȱaroundȱanȱexpression.ȱ InȱC,ȱbothȱtypesȱofȱsubprogramsȱareȱcalledȱfunctions.ȱȱItȱisȱpossibleȱtoȱcallȱaȱtrueȱ functionȱ(oneȱthatȱreturnsȱaȱvalue)ȱwithoutȱusingȱtheȱvalueȱinȱanyȱexpression.ȱInȱthisȱ situation,ȱtheȱreturnedȱvalueȱisȱjustȱdiscarded.ȱȱCallingȱaȱprocedureȬtypeȱfunctionȱfromȱ withinȱ anȱ expressionȱ isȱ aȱ seriousȱ error,ȱ though,ȱ becauseȱ anȱ unpredictableȱ (garbage)ȱ valueȱ isȱ usedȱ inȱ evaluatingȱ theȱ expression.ȱ Fortunately,ȱ modernȱ compilersȱ usuallyȱ catchȱthisȱerrorȱbecauseȱtheyȱareȱstricterȱaboutȱfunctionȱreturnȱtypesȱthanȱwereȱearlierȱ compilers.ȱ Download at http://www.pin5i.com/ 168 Chapter 7 Functions 7.2 Function Declaration ȱ Whenȱ theȱ compilerȱ encountersȱ aȱ callȱ toȱ aȱ function,ȱ itȱ generatesȱ codeȱ toȱ passȱ theȱ argumentsȱandȱcallȱtheȱfunction,ȱandȱcodeȱtoȱreceiveȱtheȱvalueȱ(ifȱany)ȱsentȱbackȱbyȱtheȱ function.ȱButȱhowȱdoesȱtheȱcompilerȱknowȱwhatȱkindsȱofȱargumentsȱ(andȱhowȱmany)ȱ theȱfunctionȱexpectsȱtoȱget,ȱandȱwhatȱkindȱofȱvalueȱ(ifȱany)ȱthatȱtheȱfunctionȱreturns?ȱ Ifȱ thereȱ isnȇtȱ anyȱ specificȱ informationȱ givenȱ aboutȱ theȱ function,ȱ theȱ compilerȱ assumesȱthatȱtheȱcallȱhasȱtheȱcorrectȱnumberȱandȱtypesȱofȱarguments.ȱItȱalsoȱassumesȱ thatȱtheȱfunctionȱwillȱreturnȱanȱinteger,ȱwhichȱusuallyȱleadsȱtoȱerrorsȱforȱfunctionsȱthatȱ returnȱnonintegralȱtypes.ȱ ȱ ȱ ȱ 7.2.1 Prototypes K&R C ȱ Itȱisȱsaferȱtoȱgiveȱtheȱcompilerȱspecificȱinformationȱaboutȱtheȱfunction,ȱwhichȱweȱcanȱ doȱ twoȱ differentȱ ways.ȱ First,ȱ ifȱ theȱ definitionȱ forȱ theȱ functionȱ appearsȱ earlierȱ inȱ theȱ sameȱsourceȱfile,ȱtheȱcompilerȱwillȱrememberȱtheȱnumberȱandȱtypesȱofȱitsȱargumentsȱ andȱtheȱtypeȱofȱitsȱreturnȱvalue.ȱItȱcanȱthenȱcheckȱallȱsubsequentȱcallsȱtoȱtheȱfunctionȱ (inȱthatȱsourceȱfile)ȱtoȱmakeȱsureȱtheyȱareȱcorrect.ȱ ȱ Ifȱaȱfunctionȱisȱdefinedȱusingȱtheȱoldȱsyntax,ȱwithȱaȱseparateȱlistȱgivingȱtheȱtypesȱofȱtheȱ arguments,ȱthenȱtheȱcompilerȱremembersȱonlyȱtheȱtypeȱofȱtheȱfunctionȇsȱreturnȱvalue.ȱȱ Noȱinformationȱisȱsavedȱonȱtheȱnumberȱorȱtypesȱofȱtheȱarguments.ȱBecauseȱofȱthisȱfact,ȱ itȱisȱimportantȱtoȱuseȱtheȱnewȱfunctionȱdeclarationȱstyleȱwheneverȱpossible.ȱ Theȱ secondȱ wayȱ toȱ giveȱ theȱ compilerȱ informationȱ aboutȱ aȱ functionȱ isȱ toȱ useȱ aȱ functionȱ prototype,ȱ whichȱ youȱ sawȱ inȱ Chapterȱ 1.ȱ Aȱ prototypeȱ summarizesȱ theȱ declarationȱ atȱ theȱ beginningȱ ofȱ theȱ functionȱ definition,ȱ thusȱ givingȱ theȱ compilerȱ completeȱ informationȱ onȱ howȱ theȱ functionȱ isȱ toȱ beȱ called.ȱ Theȱ mostȱ convenientȱ (andȱ safest)ȱwayȱtoȱuseȱaȱprototypeȱisȱtoȱputȱitȱinȱaȱseparateȱfileȱandȱthenȱ #includeȱthatȱfileȱ whereverȱitȱisȱneeded.ȱThisȱtechniqueȱavoidsȱtheȱpossibilityȱofȱmistypingȱaȱprototype.ȱ Itȱalsoȱsimplifiesȱmaintenanceȱofȱtheȱprogramȱbyȱonlyȱhavingȱoneȱphysicalȱcopyȱofȱtheȱ prototype.ȱ Shouldȱ theȱ prototypeȱ needȱ toȱ beȱ changed,ȱ thereȱ isȱ onlyȱ oneȱ copyȱ ofȱ itȱ toȱ modify.ȱ Toȱ illustrate,ȱ hereȱ isȱ aȱ prototypeȱ forȱ theȱ find_intȱ functionȱ fromȱ theȱ previousȱ example:ȱ ȱ int *find_int( int key, int array[], int len ); ȱ Noteȱ theȱ semicolonȱ atȱ theȱ end:ȱ itȱ distinguishesȱ aȱ prototypeȱ fromȱ theȱ beginningȱ ofȱ aȱ functionȱdefinition.ȱTheȱprototypeȱtellsȱtheȱcompilerȱtheȱnumberȱofȱarguments,ȱtheȱȱ ȱ Download at http://www.pin5i.com/ 7.2 Function Declaration TIP 169 typeȱ ofȱ eachȱ argument,ȱ andȱ theȱ typeȱ ofȱ theȱ returnedȱ value.ȱ Afterȱ theȱ prototypeȱ hasȱ beenȱseen,ȱtheȱcompilerȱwillȱcheckȱcallsȱmadeȱtoȱtheȱfunctionȱtoȱ makeȱsureȱthatȱtheirȱ argumentsȱareȱcorrectȱandȱthatȱtheȱreturnedȱvalueȱisȱusedȱproperly.ȱWhereȱmismatchesȱ occurȱ (forȱ example,ȱ anȱ argumentȱ ofȱ theȱ wrongȱ type)ȱ theȱ compilerȱ willȱ convertȱ theȱ valueȱtoȱtheȱcorrectȱtypeȱifȱsuchȱaȱconversionȱisȱpossible.ȱ ȱ NoteȱthatȱIȱputȱargumentȱnamesȱinȱtheȱaboveȱprototype.ȱWhileȱnotȱrequired,ȱitȱisȱwiseȱ toȱ includeȱ descriptiveȱ parameterȱ namesȱ inȱ functionȱ prototypesȱ becauseȱ theyȱ giveȱ usefulȱ informationȱ toȱ clientsȱ wishingȱ toȱ callȱ theȱ function.ȱ Forȱ example,ȱ whichȱ ofȱ theȱ followingȱtwoȱprototypesȱdoȱyouȱfindȱmoreȱuseful?ȱ ȱ char *strcpy( char *, char * ); char *strcpy( char *destination, char *source ); CAUTION! Theȱfollowingȱcodeȱfragmentȱillustratesȱaȱdangerousȱwayȱtoȱuseȱfunctionȱprototypes.ȱ ȱ void a() { int ... *func( int *value, int len ); int ... func( int len, int *value ); } void b() { } ȱ Lookȱcloselyȱatȱtheȱprototypesȱandȱyouȱwillȱseeȱthatȱtheyȱareȱdifferent.ȱTheȱargumentsȱ areȱ reversed,ȱ andȱ theȱ returnȱ valuesȱ areȱ differentȱ types.ȱ Theȱ problemȱ isȱ thatȱ eachȱ prototypeȱ isȱ writtenȱ insideȱ theȱ bodyȱ ofȱ aȱ function.ȱ Theyȱ haveȱ blockȱ scope,ȱ soȱ theȱ compilerȱ throwsȱ outȱ whatȱ itȱ learnedȱ fromȱ theȱ prototypeȱ atȱ theȱ endȱ ofȱ eachȱ functionȱ andȱneverȱdetectsȱtheȱmismatch.ȱ ȱ TheȱStandardȱstatesȱthatȱaȱfunctionȱprototypeȱmustȱmarchȱanyȱearlierȱprototypeȱ forȱ theȱ sameȱ functionȱ thatȱ isȱ inȱ scope,ȱ orȱ elseȱ anȱ errorȱ messageȱ isȱ printed.ȱ Inȱ thisȱ example,ȱ though,ȱ theȱ scopeȱ forȱ theȱ firstȱ blockȱ doesȱ notȱ overlapȱ theȱ secondȱ block.ȱȱ Therefore,ȱ theȱ mistakesȱ inȱ theȱ prototypesȱ goȱ undetected.ȱ Oneȱ orȱ theȱ otherȱ ofȱ theseȱ prototypesȱisȱwrongȱ(maybeȱboth),ȱbutȱtheȱcompilerȱneverȱseesȱtheȱcontradictionȱsoȱnoȱ errorȱmessagesȱareȱproduced.ȱ Download at http://www.pin5i.com/ 170 Chapter 7 Functions Theȱcodeȱfragmentȱbelowȱillustratesȱtheȱpreferredȱwayȱtoȱuseȱprototypes:ȱ ȱ *include "func.h" void a() { ... } void b() { ... } ȱ Theȱfileȱfunc.hȱcontainsȱtheȱprototypeȱ ȱ int *func( int *value, int len ); ȱ Thisȱtechniquesȱisȱbetterȱinȱseveralȱways.ȱ ȱ 1. Theȱprototypeȱnowȱhasȱfileȱscopeȱsoȱthatȱoneȱcopyȱofȱitȱappliesȱtoȱtheȱentireȱsourceȱ file,ȱ whichȱ isȱ easierȱ thanȱ writingȱ aȱ separateȱ copyȱ inȱ eachȱ placeȱ fromȱ whichȱ theȱ functionȱisȱcalled.ȱ 2. Theȱ prototypeȱ isȱ onlyȱ writtenȱ once,ȱ soȱ thereȱ isȱ noȱ chanceȱ forȱ disagreementsȱ betweenȱmultipleȱcopies.ȱ 3. Ifȱ theȱ functionȱ definitionȱ changes,ȱ allȱ weȱ haveȱ toȱ doȱ isȱ modifyȱ theȱ prototypeȱ andȱ recompileȱeachȱsourceȱfileȱthatȱincludesȱit.ȱ 4. Ifȱ theȱ prototypeȱ isȱ alsoȱ #includeȇdȱ intoȱ theȱ fileȱ whereȱ theȱ functionȱ isȱ defined,ȱ theȱ compilerȱwillȱbeȱableȱtoȱverifyȱthatȱtheȱprototypeȱmatchesȱtheȱfunctionȱdefinition.ȱ ȱ Byȱwritingȱtheȱprototypeȱonce,ȱweȱeliminateȱtheȱchanceȱthatȱmultipleȱcopiesȱofȱitȱdiffer.ȱ However,ȱ theȱ prototypeȱ mustȱ matchȱ theȱ functionȱ definition.ȱ Includingȱ theȱ prototypeȱ inȱtheȱfileȱwhereȱtheȱfunctionȱisȱdefinedȱletsȱtheȱcompilerȱverifyȱthatȱtheyȱmatch.ȱ Considerȱthisȱdeclaration,ȱwhichȱlooksȱambiguous:ȱ int *func(); Itȱ couldȱ beȱ eitherȱ anȱ oldȬstyleȱ declarationȱ (givingȱ theȱ returnȱ typeȱ ofȱ func)ȱ orȱ aȱ newȬ styleȱprototypeȱforȱaȱfunctionȱwithȱnoȱarguments.ȱWhichȱisȱit?ȱTheȱdeclarationȱmustȱbeȱ interpretedȱ asȱ anȱ oldȬstyleȱ declarationȱ inȱ orderȱ toȱ maintainȱ compatibilityȱ with Download at http://www.pin5i.com/ 7.2 Function Declaration 171 preȬANSIȱprograms.ȱAȱprototypeȱforȱaȱfunctionȱwithoutȱargumentsȱisȱwrittenȱlikeȱthis:ȱ ȱ int *func( void ); ȱ Theȱ keywordȱ voidȱ indicatesȱ thatȱ thereȱ arenȇtȱ anyȱ arguments,ȱ notȱ thatȱ thereȱ isȱ oneȱ argumentȱofȱtypeȱvoid.ȱ ȱ ȱ ȱ 7.2.2 Default Function Assumptions CAUTION! ȱ Whenȱaȱcallȱisȱmadeȱtoȱaȱfunctionȱforȱwhichȱnoȱprototypeȱhasȱbeenȱseen,ȱtheȱfunctionȱisȱ assumedȱtoȱreturnȱanȱintegerȱvalue.ȱThisȱcanȱleadȱtoȱerrorsȱforȱfunctionsȱwhichȱreturnȱ nonintegralȱvalues.ȱ ȱ Whileȱitȱisȱrecommendedȱthatȱallȱfunctionsȱbeȱprototyped,ȱitȱisȱespeciallyȱimportantȱtoȱ prototypeȱfunctionsȱthatȱreturnȱnonintegralȱvalues.ȱRememberȱthatȱtheȱtypeȱofȱaȱvalueȱ isȱnotȱinherentȱinȱtheȱvalueȱitself,ȱbutȱratherȱinȱtheȱwayȱthatȱitȱisȱused.ȱIfȱtheȱcompilerȱ assumesȱthatȱaȱfunctionȱreturnsȱanȱintegralȱvalue,ȱitȱwillȱgenerateȱintegerȱinstructionsȱ toȱmanipulateȱtheȱvalue.ȱIfȱtheȱvalueȱisȱactuallyȱaȱnonintegralȱtype,ȱfloatingȬpointȱforȱ example,ȱtheȱresultȱwillȱusuallyȱbeȱincorrect.ȱ Letȇsȱ lookȱ atȱ anȱ exampleȱ ofȱ thisȱ error.ȱ Imagineȱ aȱ functionȱ xyzȱ thatȱ returnsȱ theȱ floatȱvalueȱ3.14ȱ.ȱTheȱbitsȱusedȱtoȱrepresentȱthisȱfloatingȬpointȱnumberȱonȱaȱSunȱSparcȱ workstationȱareȱ ȱ 01000000010010001111010111000011 ȱ Nowȱassumeȱthatȱtheȱfunctionȱisȱcalledȱlikeȱthis:ȱ ȱ ȱ float f; ... f = xyz(); ȱ Ifȱthereȱisȱnoȱprototypeȱforȱtheȱfunction,ȱtheȱcompilerȱwillȱassumeȱthatȱitȱisȱreturningȱ anȱintegerȱandȱwillȱgenerateȱinstructionsȱtoȱconvertȱtheȱvalueȱtoȱfloatingȬpointȱbeforeȱ assigningȱitȱtoȱf.ȱ Theȱ functionȱ returnsȱ theȱ bitsȱ shownȱ above.ȱ Theȱ conversionȱ instructionsȱ interpretȱ themȱ asȱ theȱ integerȱ 1,078,523,331ȱ andȱ convertȱ thisȱ integerȱ valueȱ toȱ floatingȬ point,ȱandȱtheȱresultȱisȱstoredȱinȱf.ȱ Whyȱ wasȱ thisȱ conversionȱ doneȱ whenȱ theȱ valueȱ returnedȱ wasȱ alreadyȱ inȱ floatingȬpointȱformat?ȱTheȱcompilerȱhasȱnoȱwayȱofȱknowingȱitȱwas,ȱbecauseȱthereȱwasȱ noȱ prototypeȱ orȱ declarationȱ toȱ tellȱ itȱ so.ȱ Thisȱ exampleȱ illustratesȱ whyȱ itȱ isȱ vitalȱ forȱ functionsȱthatȱreturnȱvaluesȱotherȱthanȱintegersȱtoȱhaveȱprototypes.ȱ Download at http://www.pin5i.com/ 172 Chapter 7 Functions 7.3 Function Arguments ȱ Allȱ argumentsȱ toȱ Cȱ functionsȱ areȱ passedȱ withȱ aȱ techniqueȱ knownȱ asȱ callȱ byȱ value,ȱ whichȱ meansȱ thatȱtheȱfunctionȱ getsȱaȱcopyȱofȱtheȱargumentȱ value.ȱȱThusȱtheȱ functionȱ mayȱ modifyȱ itsȱ parametersȱ withoutȱ fearȱ ofȱ affectingȱ theȱ valuesȱ ofȱ theȱ argumentsȱ passedȱ fromȱ theȱ callingȱ program.ȱ Thisȱ behaviorȱ isȱ theȱ sameȱ asȱ valueȱ (notȱ var)ȱ parametersȱinȱModulaȱandȱPascal.ȱ TheȱruleȱinȱCȱisȱsimple:ȱallȱargumentsȱareȱpassedȱbyȱvalue.ȱȱHowever,ȱifȱanȱarrayȱ nameȱ isȱ passedȱ asȱ anȱ argumentȱ andȱ aȱ subscriptȱ isȱ usedȱ onȱ theȱ argumentȱ inȱ theȱ function,ȱthenȱmodifyingȱarrayȱelementsȱinȱtheȱfunctionȱactuallyȱchangesȱtheȱelementsȱ ofȱ theȱ arrayȱ inȱ theȱ callingȱ program.ȱ Theȱ functionȱ accessesȱ theȱ veryȱ sameȱ arrayȱ thatȱ existsȱ inȱ theȱ callingȱ program;ȱ theȱ arrayȱ isȱ notȱ copied.ȱ Thisȱ behaviorȱ isȱ termedȱ callȱ byȱ referenceȱandȱisȱhowȱvarȱparametersȱareȱimplementedȱinȱmanyȱotherȱlanguages.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Check the value for even parity. */ int even_parity( int value, int n_bits ) { int parity = 0; /* ** Count the number of 1-bits in the value. */ while( n_bits > 0 ){ parity += value & 1; value >>= 1; n_bits -= 1; } /* ** Return TRUE if the low order bit of the count is zero ** (which means that there were an even number of 1's). */ return ( parity % 2 ) == 0; } ȱ Programȱ7.2ȱParityȱcheckȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱparity.cȱ Download at http://www.pin5i.com/ 7.3 Function Arguments 173 Theȱbehaviorȱwithȱarrayȱ argumentsȱ seemsȱtoȱcontradictȱtheȱcallȱbyȱvalueȱ rule.ȱȱ Howeverȱ thereȱ isnȇtȱ aȱ contradiction—theȱ valueȱ ofȱ theȱ arrayȱ nameȱ isȱ reallyȱ aȱ pointer,ȱ andȱ aȱ copyȱ ofȱ theȱ pointerȱ isȱ passedȱ toȱ theȱ function.ȱ Aȱ subscriptȱ isȱ reallyȱ aȱ formȱ ofȱ indirectionȱandȱapplyingȱindirectionȱtoȱtheȱpointerȱaccessesȱtheȱlocationsȱthatȱitȱpointsȱ to.ȱ Theȱ argumentȱ (theȱ pointer)ȱ isȱ indeedȱ aȱ copy,ȱ butȱ theȱ indirectionȱ usesȱ theȱ copyȱ toȱ accessȱ theȱ originalȱ arrayȱ values.ȱ Weȱ returnȱ toȱ thisȱ pointȱ inȱ theȱ nextȱ chapter,ȱ butȱ forȱ nowȱrememberȱtheseȱtwoȱrules:ȱ ȱ 1. Scalarȱargumentsȱtoȱaȱfunctionȱareȱpassedȱbyȱvalue.ȱ 2. Arrayȱargumentsȱtoȱaȱfunctionȱbehaveȱasȱthoughȱtheyȱareȱpassedȱbyȱreference.ȱ ȱ Programȱ 7.2ȱ illustratesȱ theȱ callȬbyȬvalueȱ behaviorȱ ofȱ scalarȱ functionȱ arguments.ȱ Thisȱ functionȱchecksȱwhetherȱtheȱfirstȱargumentȱhasȱevenȱparity,ȱthatȱis,ȱifȱtheȱnumberȱofȱ1ȇsȱ itȱ containsȱ isȱ anȱ evenȱ number.ȱ Theȱ secondȱ argumentȱ specifiesȱ theȱ numberȱ ofȱ significantȱbitsȱinȱtheȱvalue.ȱȱTheȱfunctionȱworksȱbyȱshiftingȱtheȱvalueȱbyȱoneȱbit,ȱoverȱ andȱover,ȱsoȱthatȱeveryȱbitȱappearsȱsoonerȱorȱlaterȱinȱtheȱrightȬmostȱposition.ȱTheȱbitsȱ areȱ addedȱ together,ȱ oneȱ byȱ one,ȱ soȱ thatȱ afterȱ theȱ loopȱ endsȱ weȱ haveȱ aȱ countȱ ofȱ theȱ numberȱ ofȱ 1ȇsȱ inȱ theȱ originalȱ value.ȱ Finally,ȱ theȱ countȱ isȱ testedȱ toȱ seeȱ ifȱ itsȱ leastȱ significantȱbitȱisȱset.ȱIfȱnot,ȱtheȱnumberȱofȱ1ȇsȱwasȱeven.ȱ Theȱinterestingȱfeatureȱofȱthisȱfunctionȱisȱthatȱitȱdestroysȱbothȱofȱitsȱargumentsȱ asȱ theȱ workȱ progresses.ȱ Thisȱ techniqueȱ worksȱ fine,ȱ becauseȱ withȱ callȬbyȬvalueȱ theȱ argumentsȇȱareȱcopiesȱofȱtheȱcallerȇsȱvalues.ȱDestroyingȱtheȱcopiesȱdoesȱnotȱaffectȱtheȱ originalȱvalues.ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Exchange two integers in the calling program (doesn't work!). */ void swap( int x, int y ) { int temp; temp = x; x = y; y = temp; } Programȱ7.3aȱȱSwapȱintegers:ȱbadȱversionȱ ȱ ȱ ȱ ȱ ȱ ȱȱswap1.cȱ Download at http://www.pin5i.com/ 174 Chapter 7 Functions Programȱ7.3aȱisȱdifferent;ȱitȱwantsȱtoȱmodifyȱtheȱcallerȇsȱarguments.ȱȱTheȱintentȱ ofȱthisȱfunctionȱisȱtoȱexchangeȱtheȱcontentsȱofȱtwoȱargumentsȱinȱtheȱcallingȱprogram.ȱItȱ doesnȇtȱ work,ȱ though,ȱ becauseȱ allȱ thatȱ isȱ exchangedȱ areȱ theȱ copiesȱ ofȱ theȱ valuesȱ thatȱ wereȱsentȱtoȱtheȱfunction.ȱTheȱoriginalȱvaluesȱareȱuntouched.ȱ Toȱaccessȱtheȱcallerȇsȱvaluesȱyouȱmustȱpassȱpointersȱtoȱtheȱlocationsȱyouȱwishȱtoȱ modify.ȱTheȱfunctionȱmustȱthenȱuseȱindirectionȱtoȱfollowȱtheȱpointersȱandȱmodifyȱtheȱ desiredȱ locations.ȱ Programȱ 7.3bȱ usesȱ thisȱ technique.ȱ Becauseȱ theȱ functionȱ expectsȱ pointersȱasȱarguments,ȱweȱwouldȱcallȱitȱlikeȱthis:ȱ ȱ swap( &a, &b ); ȱ Programȱ7.4ȱsetsȱallȱofȱtheȱelementsȱofȱanȱarrayȱtoȱzero,ȱȱ n_elementsȱisȱaȱscalarȱ soȱ itȱ isȱ passedȱ byȱ value;ȱ modifyingȱ itsȱ valueȱ inȱ theȱ functionȱ doesȱ notȱ affectȱ theȱ correspondingȱargumentȱinȱtheȱcallingȱprogram.ȱOnȱtheȱotherȱhand,ȱtheȱfunctionȱdoesȱ indeedȱsetȱtheȱelementsȱofȱtheȱcallingȱprogramȇsȱarrayȱtoȱzero.ȱTheȱvalueȱofȱtheȱarrayȱ argumentȱisȱaȱpointer,ȱandȱtheȱsubscriptȱperformsȱindirectionȱwithȱthisȱpointer.ȱ Thisȱ exampleȱ alsoȱ illustratesȱ anotherȱ feature.ȱ Itȱ isȱ legalȱ toȱ declareȱ arrayȱ parametersȱ withoutȱ specifyingȱ aȱ sizeȱ becauseȱ memoryȱ isȱ notȱ allocatedȱ forȱ theȱ arrayȱ elementsȱ inȱ theȱ function;ȱ theȱ indirectionȱ causesȱ theȱ arrayȱ elementsȱ inȱ theȱ callingȱ programȱtoȱbeȱaccessedȱinstead.ȱThus,ȱaȱsingleȱfunctionȱcanȱaccessȱarrayȱofȱanyȱsize,ȱȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Exchange two integers in the calling program. */ void swap( int *x, int *y ) { int temp; temp = *x; *x = *y; *y = temp; } ȱ Programȱ7.3bȱȱSwapȱintegers:ȱgoodȱversionȱ ȱ ȱ ȱ ȱ ȱ ȱȱswap2.cȱ Download at http://www.pin5i.com/ 7.3 Function Arguments K&R C 175 ȱwhichȱ shouldȱ exciteȱ Pascalȱ programmers.ȱ However,ȱ thereȱ isnȇtȱ anyȱ wayȱ forȱ theȱ functionȱ toȱ figureȱ outȱ theȱ actualȱ sizeȱ ofȱ anȱarrayȱ argument,ȱ soȱ thisȱ informationȱ mustȱ alsoȱbeȱpassedȱexplicitlyȱifȱitȱisȱneeded.ȱ ȱ RecallȱthatȱinȱK&RȱC,ȱfunctionȱparametersȱwereȱdeclaredȱlikeȱthis:ȱ ȱ int func( a, b, c ) int a; char b; float c; { ... CAUTION! ȱ Anotherȱ reasonȱ toȱ avoidȱ thisȱ styleȱ isȱ thatȱ K&Rȱ compilersȱ handledȱ argumentsȱ aȱ littleȱ differently:ȱ charȱandȱshortȱargumentsȱwereȱpromotedȱtoȱ intȱbeforeȱbeingȱpassed,ȱandȱ floatȱ argumentsȱ wereȱ promotedȱ toȱ doubleȬȱ Theseȱ conversionsȱ areȱ calledȱ theȱ defaultȱ argumentȱpromotions,ȱandȱbecauseȱofȱthemȱyouȱwillȱfrequentlyȱseeȱfunctionȱparametersȱ inȱpreȬANSIȱprogramsȱdeclaredȱasȱintȱwhenȱinȱfactȱcharȱvaluesȱareȱpassed.ȱ ȱ Toȱ maintainȱ compatibility,ȱ ANSIȱ compilersȱ alsoȱ performȱ theseȱ conversionsȱ forȱ functionsȱ declaredȱ inȱ theȱ oldȱ style.ȱ Theyȱ areȱ notȱ doneȱ onȱ functionsȱ thatȱ haveȱ beenȱ prototyped,ȱthough,ȱsoȱmixingȱtheȱtwoȱstylesȱcanȱleadȱtoȱerrors.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Set all of the elements of an array to zero. */ void clear_array( int array[], int n_elements { /* ** Clear the elements of the array ** and working towards the first. ** avoids going off the end of the */ while( n_elements > 0 ) array[ --n_elements ] = 0; } ȱ Programȱ7.4ȱȱSetȱanȱarrayȱtoȱzeroȱ ȱ ȱ ) starting with the last Note the predecrement array. ȱ ȱ ȱ ȱ ȱ clrarray.cȱ Download at http://www.pin5i.com/ 176 Chapter 7 Functions 7.4 ADTs and Black Boxes ȱ Cȱfacilitatesȱtheȱdesignȱandȱimplementationȱofȱabstractȱdataȱtypes,ȱorȱADTs,ȱbecauseȱofȱ itsȱ abilityȱ toȱ limitȱ theȱ scopeȱ ofȱ functionȱ andȱ dataȱ definitions.ȱ Thisȱ techniqueȱ isȱ alsoȱ referredȱtoȱasȱblackȱboxȱdesign.ȱTheȱbasicȱideaȱbehindȱanȱabstractȱdataȱtypeȱisȱsimple—aȱ moduleȱ hasȱ aȱ functionalȱ specification,ȱ whichȱ statesȱ theȱ workȱ thatȱ theȱ moduleȱ willȱ perform,ȱ andȱ anȱ interfaceȱ specification,ȱ whichȱ definesȱ howȱ theȱ moduleȱ isȱ used.ȱ However,ȱusersȱofȱtheȱmoduleȱdoȱnotȱneedȱtoȱknowȱanyȱdetailsȱofȱitsȱimplementationȱ andȱareȱpreventedȱfromȱaccessingȱtheȱmoduleȱinȱanyȱwayȱotherȱthanȱwithȱtheȱdefinedȱ interface.ȱ Limitingȱaccessȱtoȱtheȱmoduleȱisȱaccomplishedȱthroughȱtheȱjudiciousȱuseȱofȱtheȱ staticȱkeywordȱtoȱrestrictȱtheȱaccessibilityȱofȱfunctionsȱandȱdataȱthatȱareȱnotȱpartȱofȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Declarations for the address list module. */ /* ** Data characteristics ** ** Maximum lengths of the various data (includes space for the ** terminating NUL byte), and maximum number of addresses. */ #define NAME_LENGTH 30 /* longest name allowed */ #define ADDR_LENGTH 100 /* longest address allowed */ #define PHONE_LENGTH 11 /* longest phone # allowed */ #define MAX_ADDRESSES 1000 /* # of addresses allowed */ /* ** Interface functions ** ** Given a name, find the corresponding address. */ char const * lookup_address( char const *name ); /* ** Given a name, find the corresponding phone number. */ char const * lookup_phone( char const *name ); ȱ Programȱ7.5aȱȱAddressȱlistȱmodule:ȱheaderȱfileȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱaddrlist.hȱ Download at http://www.pin5i.com/ 7.4 ADTs and Black Boxes 177 theȱ interface.ȱ Forȱ example,ȱ considerȱ aȱ moduleȱ thatȱ maintainsȱ anȱ address/phoneȱ numberȱlist.ȱTheȱmoduleȱmustȱprovideȱfunctionsȱtoȱlookȱupȱanȱaddressȱandȱtoȱlookȱupȱ aȱphoneȱnumberȱforȱaȱspecificȱname.ȱHowever,ȱtheȱmannerȱinȱwhichȱtheȱlistȱisȱstoredȱisȱ implementationȱdependent,ȱsoȱthisȱinformationȱisȱkeptȱprivateȱwithinȱtheȱmoduleȱandȱ isȱnotȱavailableȱtoȱtheȱclient.ȱ Theȱ nextȱ exampleȱ illustratesȱ oneȱ possibleȱ implementationȱ ofȱ thisȱ module.ȱ Programȱ7.5aȱshowsȱtheȱincludeȱfileȱthatȱdefinesȱtheȱinterfaceȱusedȱbyȱtheȱclient,ȱandȱ Programȱ7.5bȱshowsȱtheȱimplementation. 30 ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Abstract data type to maintain an address list. */ #include "addrlist.h" #include <stdio.h> /* ** The three parts to each address are kept in corresponding ** elements of these three arrays. */ static char name[MAX_ADDRESSES][NAME_LENGTH]; static char address[MAX_ADDRESSES][ADDR_LENGTH]; static char phone[MAX_ADDRESSES][PHONE_LENGTH]; /* ** This routine locates a name in the array and returns the ** subscript of the location found. If the name does not exist, ** -1 is returned. */ static int find_entry( char const *name_to_find ) { int entry; for( entry = 0; entry < MAX_ADDRESSES; entry += 1 ) if( strcmp( name_to_find, name[ entry ] ) == 0 ) return entry; Programȱ7.5bȱȱAddressȱlistȱmodule:ȱimplementationȱ ȱ ȱ ȱ ȱ continue…ȱ ȱItȱwouldȱbeȱbetterȱifȱeachȱname,ȱaddress,ȱandȱphoneȱnumberȱwereȱstoredȱinȱaȱstructure,ȱbutȱstructuresȱarenȇtȱcoveredȱuntilȱ Chapterȱ10.ȱ 30 Download at http://www.pin5i.com/ 178 Chapter 7 Functions return -1; } /* ** Given a name, look up and return the corresponding address. ** If the name was not found, return a NULL pointer instead. */ char const * lookup_address( char const *name ) { int entry; entry = find_entry( name ); if( entry == -1 ) return NULL; else return address[ entry ]; } /* ** Given a name, look up and return the corresponding phone ** number. If the name was not found, return a NULL pointer ** instead. */ char const * lookup_phone( char const *name ) { int entry; entry = find_entry( name ); if( entry == -1 ) return NULL; else return phone[ entry ]; } ȱ Programȱ7.5bȱȱAddressȱlistȱmodule:ȱimplementationȱ ȱ ȱ ȱ ȱ ȱȱaddrlist.cȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Programȱ 7.5ȱ isȱ aȱ goodȱ exampleȱ ofȱ aȱ blackȱ box.ȱ Theȱ functionalityȱ inȱ theȱ boxȱ isȱ accessedȱ throughȱ theȱ specifiedȱ interface,ȱ whichȱ inȱ thisȱ caseȱ areȱ theȱ functionȱ lookup_addressȱandȱ lookup_phone.ȱHowever,ȱtheȱuserȱcannotȱdirectlyȱaccessȱdataȱthatȱ relateȱtoȱtheȱimplementation,ȱsuchȱasȱtheȱarrayȱorȱtheȱsupportȱfunctionȱ lookup_entry,ȱ becauseȱtheseȱitemsȱareȱdeclaredȱstatic. Download at http://www.pin5i.com/ 7.5 Recursion 179 Theȱ powerȱ ofȱ thisȱ typeȱ ofȱ implementationȱ isȱ thatȱ itȱ makesȱ theȱ variousȱ partsȱ ofȱ theȱ programȱ moreȱ independentȱ ofȱ oneȱ another.ȱ Forȱ example,ȱ asȱ theȱ addressȱ listȱ growsȱ larger,ȱtheȱsimpleȱsequentialȱsearchȱmayȱbecomeȱtooȱslow,ȱorȱtheȱtableȱmightȱbecomeȱ full.ȱAtȱthatȱtimeȱyouȱcanȱrewriteȱtheȱfindingȱfunctionȱtoȱbeȱmoreȱefficient,ȱperhapsȱbyȱ usingȱsomeȱformȱofȱhashedȱlookup,ȱorȱyouȱcouldȱevenȱscrapȱtheȱarrayȱaltogetherȱandȱ dynamicallyȱallocateȱtheȱspaceȱforȱtheȱentries.ȱButȱifȱtheȱclientȱprogramȱhadȱbeenȱableȱ toȱ accessȱ theȱ tableȱ directly,ȱ changingȱ theȱ organizationȱ ofȱ theȱ tableȱ wouldȱ causeȱ theȱ programȱtoȱfailȱinȱeachȱofȱtheseȱplaces.ȱ Theȱ blackȱ boxȱ conceptȱ removesȱ theȱ temptationȱ toȱ useȱ theȱ implementationȱ detailsȱbyȱmakingȱthoseȱdetailsȱunavailable.ȱThus,ȱtheȱonlyȱpossibleȱwayȱtoȱaccessȱtheȱ moduleȱisȱthroughȱitsȱdefinedȱinterface.ȱ ȱ ȱ ȱ 7.5 Recursion ȱ Cȱsupportsȱrecursiveȱfunctionsȱthroughȱitsȱruntimeȱstack. 31 ȱAȱrecursiveȱfunctionȱisȱoneȱ thatȱ callsȱ itself,ȱ eitherȱ directlyȱ orȱ indirectly.ȱ Computingȱ factorialsȱ andȱ Fibonacciȱ numbersȱareȱtwoȱapplicationsȱoftenȱusedȱinȱtextbooksȱtoȱillustrateȱrecursion,ȱwhichȱisȱ veryȱ unfortunate.ȱ Recursionȱ doesȱ notȱ offerȱ anyȱ advantageȱ forȱ theȱ first,ȱ andȱ itȱ isȱ horriblyȱinefficientȱforȱtheȱsecond.ȱ Hereȱisȱaȱsimpleȱprogramȱtoȱillustrateȱrecursion.ȱTheȱobjectiveȱisȱtoȱconvertȱanȱ integerȱfromȱbinaryȱtoȱprintableȱcharacters.ȱȱForȱexample,ȱfromȱtheȱvalueȱ4267ȱweȱwantȱ toȱ produceȱ theȱ charactersȱ '4',ȱ '2',ȱ '6',ȱ andȱ '7',ȱ inȱ thatȱ order.ȱ printfȱ performsȱ thisȱ typeȱofȱprocessingȱforȱtheȱ%dȱformatȱcode.ȱ Theȱ strategyȱ weȱ useȱ isȱ toȱ repeatedlyȱ divideȱ theȱ valueȱ byȱ 10ȱ andȱ printȱ theȱ remainders.ȱ Forȱ example,ȱ 4267ȱ modȱ 10ȱ givesȱ theȱ valueȱ 7.ȱ Weȱ cannotȱ justȱ printȱ thisȱ remainder,ȱ though;ȱ weȱ needȱ toȱ printȱ theȱ valueȱ thatȱ representsȱ theȱ digitȱ '7'ȱ inȱ theȱ machineȇsȱcharacterȱset.ȱȱInȱASCII,ȱtheȱcharacterȱ'7'ȱhasȱtheȱvalueȱ55,ȱsoȱweȱmightȱaddȱ 48ȱ toȱ theȱ remainderȱ toȱ getȱ theȱ properȱ character.ȱ However,ȱ usingȱ characterȱ constantsȱ ratherȱthanȱintegerȱconstantsȱenhancesȱportablility.ȱ Considerȱtheȱrelationshipsȱbelow:ȱ ȱ '0' + 0 = '0' '0' + 1 = '1' '0' + 2 = '2' etc.ȱ ȱ Fromȱtheseȱrelationshipsȱitȱisȱeasyȱtoȱseeȱthatȱaddingȱȇ0ȇȱtoȱtheȱremainderȱproducesȱtheȱ ȱInterestingly,ȱtheȱStandardȱdoesȱnotȱrequireȱaȱstack.ȱAȱstackȱprovidesȱtheȱmandatedȱbehavior,ȱthough,ȱandȱisȱusedȱinȱmanyȱ implementations.ȱ 31 Download at http://www.pin5i.com/ 180 Chapter 7 Functions codeȱforȱtheȱcorrespondingȱcharacter.ȱThenȱtheȱremainderȱisȱprinted. 32 ȱTheȱnextȱstepȱisȱ toȱgetȱtheȱquotient:ȱ4267/10ȱisȱ426.ȱTheȱprocessȱnowȱbeginsȱagainȱwithȱthisȱvalue.ȱ Theȱonlyȱproblemȱwithȱthisȱprocessȱisȱthatȱitȱgeneratesȱtheȱdigitsȱinȱtheȱwrongȱ order:ȱtheyȱareȱprintedȱbackwards.ȱProgramȱ7.6ȱusesȱrecursionȱtoȱcorrectȱthisȱproblem.ȱ Thisȱ functionȱ isȱ recursiveȱ becauseȱ itȱ containsȱ aȱ callȱ toȱ itself.ȱ Atȱ firstȱ glance,ȱ itȱ appearsȱthatȱtheȱfunctionȱwillȱneverȱstop.ȱWhenȱtheȱfunctionȱisȱcalled,ȱitȱwillȱcallȱitself;ȱ thisȱsecondȱexecutionȱwillȱcallȱitselfȱagain,ȱandȱsoȱforth,ȱforeverȱandȱever.ȱThisȱisȱnotȱ theȱcase,ȱthough.ȱ Theȱrecursionȱinȱthisȱprogramȱimplementsȱaȱkindȱofȱtwistedȱ whileȱloop.ȱJustȱasȱ aȱ whileȱ loopȱ mustȱ makeȱ someȱ progressȱ towardsȱ itsȱ terminationȱ criteriaȱ duringȱ eachȱ executionȱ ofȱ theȱ body,ȱ soȱ tooȱ mustȱ aȱ recursiveȱ functionȱ getȱ closerȱ toȱ aȱ limitingȱ caseȱ withȱeachȱrecursiveȱcall.ȱTheȱlimitingȱcaseȱisȱtheȱoneȱinȱwhichȱtheȱfunctionȱdoesȱnotȱcallȱ itself.ȱ Inȱ Programȱ 7.6,ȱ theȱ limitingȱ caseȱ occursȱ whenȱ theȱ quotientȱ isȱ zero.ȱ Weȱ divideȱ theȱvalueȱbyȱ10ȱbeforeȱeachȱrecursiveȱcall,ȱsoȱitȱgetsȱcloserȱandȱcloserȱtoȱzeroȱeachȱtimeȱ andȱeventuallyȱtheȱrecursionȱstops.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Take an integer value (unsigned), convert it to characters, and ** print it. Leading zeros are suppressed. */ #include <stdio.h> void binary_to_ascii( unsigned int value ) { unsigned int quotient; quotient = value / 10; if( quotient != 0 ) binary_to_ascii( quotient ); putchar( value % 10 + '0' ); } ȱ Programȱ7.6ȱȱConvertȱaȱbinaryȱintegerȱtoȱcharactersȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱȱȱbtoa.cȱ ȱTheseȱrelationshipsȱrequireȱthatȱtheȱdigitsȱbeȱassignedȱsequentialȱcodes.ȱThisȱcharacteristicȱisȱtrueȱofȱallȱcommonȱcharacterȱ sets.ȱ 32 Download at http://www.pin5i.com/ 7.5 Recursion 181 Howȱ doesȱ recursionȱ helpȱ getȱ theȱ digitsȱ toȱ printȱ inȱ theȱ properȱ order?ȱ ȱ Hereȱ isȱ howȱtoȱreadȱthisȱfunction,ȱ ȱ 1. Divideȱtheȱvalueȱbyȱ10.ȱ 2. Ifȱtheȱquotientȱisȱnonzero,ȱcallȱbinary_to_asciiȱtoȱprintȱthoseȱdigitsȱnow.ȱ 3. Thenȱprintȱtheȱremainderȱofȱtheȱdivisionȱinȱstepȱ1.ȱ ȱ Noteȱthatȱtheȱmiddleȱstep,ȱprintingȱtheȱdigitsȱofȱaȱnumber,ȱisȱexactlyȱtheȱsameȱproblemȱ weȱwereȱtryingȱtoȱsolveȱinȱtheȱfirstȱplaceȱexceptȱthatȱtheȱnumberȱisȱsmaller.ȱWeȱsolveȱ theȱproblemȱbyȱcallingȱtheȱfunctionȱthatȱweȱjustȱwrote,ȱtheȱoneȱthatȱconvertsȱintegersȱ toȱ digitsȱ andȱ printsȱ them.ȱ Becauseȱ theȱ numberȱ isȱ smaller,ȱ theȱ recursionȱ eventuallyȱ stops.ȱ Onceȱyouȱunderstandȱrecursion,ȱtheȱeasiestȱwayȱtoȱreadȱaȱrecursiveȱfunctionȱisȱ toȱnotȱgetȱhungȱupȱonȱtracingȱitsȱexecution.ȱJustȱtakeȱitȱonȱfaithȱthatȱtheȱrecursiveȱcallȱ willȱdoȱwhatȱitȱclaimsȱtoȱdo.ȱIfȱyouȱdoȱtheȱrightȱworkȱforȱeachȱstep,ȱyourȱlimitingȱcaseȱ isȱcorrect,ȱandȱyouȱgetȱcloserȱtoȱitȱeachȱtime,ȱthenȱtheȱfunctionȱwillȱworkȱcorrectly.ȱ ȱ ȱ ȱ 7.5.1 Tracing a Recursive Function ȱ Butȱ inȱorderȱ toȱunderstandȱhowȱ recursionȱworksȱinȱtheȱfirstȱplace,ȱyouȱneedȱtoȱ traceȱ theȱ executionȱ ofȱ theȱ recursiveȱ calls.ȱ Soȱ letȇsȱ doȱ thatȱ now.ȱ Theȱ keyȱ toȱ followingȱ theȱ executionȱ ofȱ aȱ recursiveȱ functionȱ isȱ understandingȱ howȱ theȱ variablesȱ declaredȱ innȱ aȱ functionȱareȱstored.ȱWhenȱaȱfunctionȱisȱcalled,ȱspaceȱforȱitsȱvariablesȱisȱcreatedȱonȱtheȱ runtimeȱstack.ȱTheȱvariablesȱbelongingȱtoȱtheȱpreviousȱfunctionsȱremainȱonȱtheȱstack,ȱ butȱtheyȱareȱcoveredȱupȱbyȱtheȱnewȱonesȱandȱareȱinaccessible.ȱ ȱ Whenȱ aȱ recursiveȱ functionȱ callsȱ itself,ȱ theȱ sameȱ thingȱ happens.ȱ Aȱ newȱ setȱ ofȱ variablesȱ isȱ createdȱ forȱ theȱ newȱ call,ȱ whichȱ coverȱ upȱ theȱ variablesȱ thatȱ belongȱ toȱ theȱ previousȱcall(s)ȱtoȱthisȱfunction.ȱWhenȱtracingȱtheȱexecutionȱofȱaȱrecursiveȱfunction,ȱweȱ mustȱ keepȱ theseȱ differentȱ setsȱ ofȱ variablesȱ separateȱ fromȱ oneȱ anotherȱ toȱ avoidȱ confusion.ȱ ȱ Theȱ functionȱ inȱ Programȱ 7.6ȱ hasȱ twoȱ variables:ȱ theȱ argumentȱ valueȱ andȱ theȱ localȱvariableȱ quotient.ȱTheȱfollowingȱdiagramsȱshowȱtheȱstateȱofȱtheȱstack,ȱwithȱtheȱ setȱ ofȱ variablesȱ currentlyȱ beingȱ accessedȱ onȱ theȱ topȱ ofȱ theȱ stack.ȱ Allȱ otherȱ setsȱ ofȱ variablesȱ areȱ shadedȱ inȱ gray,ȱ becauseȱ (heyȱ areȱ inaccessibleȱ toȱ theȱ functionȱ currentlyȱ executing.ȱ Download at http://www.pin5i.com/ 182 Chapter 7 Functions Supposeȱweȱcallȱtheȱfunctionȱwithȱtheȱvalueȱ4267.ȱȱHereȱisȱwhatȱtheȱstackȱlooksȱ likeȱasȱtheȱfunctionȱbeginsȱtoȱexecute.ȱ ȱ ȱ value 4267 quotient ȱ ȱ Variables from other function calls ȱ ȱ ȱ Afterȱtheȱdivisionȱoccurs,ȱtheȱstackȱlooksȱlikeȱthis.ȱ ȱ ȱ value 4267 quotient 426 ȱ ȱ Variables from other function calls ȱ ȱ ȱ Next,ȱtheȱ ifȱstatementȱdeterminesȱthatȱtheȱquotientȱisȱnotȱzeroȱandȱmakesȱaȱrecursiveȱ callȱtoȱtheȱfunction.ȱHereȱisȱwhatȱtheȱstackȱlooksȱlikeȱasȱtheȱsecondȱcallȱofȱtheȱfunctionȱ begins.ȱ ȱ ȱ value 426 quotient ȱ ȱ value 4267 quotient 426 ȱ ȱ Variables from other function calls ȱ ȱ ȱ ȱ Aȱ newȱ setȱ ofȱ variablesȱ hasȱ beenȱ createdȱ onȱ theȱ stack,ȱ hidingȱ theȱ previousȱ set,ȱ whichȱ willȱ remainȱ inaccessibleȱ untilȱ thisȱ recursiveȱ callȱ toȱ theȱ functionȱ returns.ȱ Afterȱ theȱ division,ȱtheȱstackȱlooksȱlikeȱthis.ȱ ȱ value 426 quotient 42 value 4267 quotient 426 Variables from other function calls Download at http://www.pin5i.com/ 7.5 Recursion 183 Theȱquotientȱhasȱtheȱvalueȱ42,ȱwhichȱisȱnonzero,ȱsoȱweȱgetȱanotherȱrecursiveȱcallȱwithȱ anotherȱsetȱofȱvariables.ȱAfterȱtheȱdivision,ȱtheȱstackȱlooksȱlikeȱthis:ȱ ȱ ȱ value 42 quotient 4 ȱ ȱ ȱ value 426 quotient 42 ȱ ȱ value 4267 quotient 426 ȱ ȱ ȱ Variables from other function calls ȱ ȱ ȱ Theȱquotientȱisȱstillȱnonzero,ȱsoȱanotherȱrecursiveȱcallȱisȱmade.ȱAfterȱtheȱdivision,ȱtheȱ stackȱlooksȱlikeȱthis:ȱ ȱ ȱ value 4 quotient 0 ȱ ȱ ȱ value 42 quotient 4 ȱ ȱ value 426 quotient 42 ȱ ȱ ȱ value 4267 quotient 426 ȱ ȱ Variables from other function calls ȱ ȱ ȱ ȱ Disregardingȱtheȱrecursiveȱcallȱitself,ȱtheȱ onlyȱstatementsȱthatȱ haveȱbeenȱexecutedȱ soȱ farȱareȱtheȱdivisionȱandȱtheȱtestȱofȱtheȱquotient.ȱBecauseȱtheȱrecursiveȱcallȱhasȱcausedȱ theseȱ statementsȱ toȱ beȱ repeated,ȱ theȱ effectȱ isȱ similarȱ toȱ thatȱ ofȱ aȱ loop;ȱ whileȱ theȱ quotientȱisȱnonzero,ȱ useȱitȱasȱtheȱinitialȱvalueȱ andȱstartȱ overȱagain.ȱButȱ theȱrecursionȱ savesȱ informationȱ thatȱ aȱ loopȱ wouldȱ not,ȱ theȱ stackedȱ valuesȱ ofȱ theȱ variables.ȱ Thisȱ informationȱisȱaboutȱtoȱbecomeȱimportant.ȱ Theȱquotientȱisȱzero,ȱsoȱtheȱfunctionȱdoesȱnotȱcallȱitselfȱagain.ȱInstead,ȱitȱbeginsȱ toȱ printȱ output.ȱ Theȱ functionȱ thenȱ returns,ȱ whichȱ beginsȱ toȱ removeȱ valuesȱ fromȱ theȱ stack.ȱ Download at http://www.pin5i.com/ 184 Chapter 7 Functions Eachȱcallȱtoȱ putcharȱgetsȱtheȱlastȱdigitȱofȱtheȱvalueȱbyȱtakingȱtheȱvalueȱmoduloȱ ten.ȱTheȱresultȱisȱanȱintegerȱinȱtheȱrangeȱzeroȱtoȱnine;ȱtheȱcharacterȱconstantȱforȱaȱzeroȱ isȱ addedȱ inȱ orderȱ toȱ getȱ theȱ ASCIIȱ characterȱ thatȱ correspondsȱ toȱ theȱ digit,ȱ whichȱ isȱ printed.ȱ ȱ 0 ȱ ȱ ȱ valueȱ 4 ȱ ȱ quotient ȱ ȱȱOutput:ȱ4ȱ ȱ ȱ value 42 quotient 4 ȱ ȱ value 426 quotient 42 ȱ ȱ ȱ value 4267 quotient 426 ȱ ȱ Variables from other function calls ȱ ȱ ȱ Theȱfunctionȱthenȱreturns,ȱandȱitsȱvariablesȱareȱdiscardedȱfromȱtheȱstack.ȱTheȱpreviousȱ invocationȱofȱtheȱfunctionȱthenȱcontinuesȱtoȱexecuteȱfromȱtheȱpointȱofȱtheȱrecursiveȱcallȱ usingȱitsȱownȱvariables,ȱwhichȱareȱnowȱonȱtheȱtopȱofȱtheȱstack.ȱBecauseȱitsȱvalueȱisȱ42,ȱ theȱcallȱtoȱputcharȱprintsȱtheȱdigitȱtwo.ȱ ȱ ȱ 4 ȱ ȱ ȱ ȱ valueȱ 42 ȱ ȱ quotient ȱ ȱȱOutput:ȱ42ȱ ȱ ȱ value 426 quotient 42 ȱ ȱ value 4267 quotient 426 ȱ ȱ ȱ Variables from other function calls ȱ ȱ ȱ Thisȱ invocationȱ ofȱ theȱ functionȱ thenȱ returns,ȱ whichȱ uncoversȱ theȱ variablesȱ forȱ theȱ previousȱ invocation.ȱ Executionȱ continuesȱ thereȱ fromȱ theȱ pointȱ ofȱ theȱ recursiveȱ call,ȱ andȱaȱsixȱisȱprinted.ȱJustȱbeforeȱtheȱfunctionȱreturnsȱagain,ȱtheȱstackȱlooksȱlikeȱthis:ȱ Download at http://www.pin5i.com/ 7.5 Recursion 185 ȱ value 426 quotient 42 ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱOutput:ȱ426ȱ ȱ ȱ value 4267 quotient 426 ȱ ȱ Variables from other function calls ȱ ȱ ȱ Weȱhaveȱnowȱunwoundȱtheȱrecursionȱandȱareȱbackȱtoȱtheȱoriginalȱcallȱtoȱtheȱfunction.ȱ Itȱprintsȱtheȱdigitȱseven,ȱwhichȱisȱtheȱremainderȱofȱitsȱvalueȱdividedȱbyȱten.ȱ ȱ ȱ 426ȱ ȱ ȱ ȱ valueȱ 4267ȱ ȱ quotient ȱ ȱȱOutput:ȱ4267ȱ ȱ Variables from other function calls ȱ ȱ ȱ Theȱfunctionȱthenȱreturnsȱtoȱwhateverȱotherȱfunctionȱcalledȱit.ȱ Ifȱ youȱ putȱ allȱ ofȱ theȱ charactersȱ thatȱ wereȱ printedȱ sideȱ byȱ sideȱ asȱ theyȱ wouldȱ appearȱonȱaȱprinterȱorȱscreen,ȱyouȱwillȱseeȱtheȱcorrectȱvalue:ȱ4267.ȱ ȱ ȱ ȱ 7.5.2 Recursion versus Iteration ȱ Recursionȱisȱaȱpowerfulȱtechnique,ȱbutȱlikeȱanyȱtechniqueȱitȱcanȱbeȱmisused.ȱHereȱisȱanȱ example.ȱTheȱdefinitionȱofȱaȱfactorialȱisȱoftenȱstatedȱrecursively,ȱlikeȱthis:ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱnȱǂȱ0:ȱȱ1ȱ ȱ factorial(n)ȱ=ȱȱ ȱ ȱ ȱ ȱȱȱȱȱnȱ>ȱ0:ȱȱnȱ×ȱfactorial(nȱ–ȱ1)ȱ ȱ Thisȱdefinitionȱhasȱbothȱofȱtheȱpropertiesȱweȱdiscussedȱearlierȱforȱrecursion:ȱthereȱisȱaȱ limitingȱcaseȱfromȱwhichȱnoȱrecursionȱisȱperformed,ȱandȱeachȱrecursiveȱcallȱgetsȱaȱlittleȱ closerȱtoȱtheȱlimitingȱcase.ȱ Definitionsȱ likeȱ thisȱ oneȱ oftenȱ leadȱ peopleȱ toȱ useȱ recursionȱ toȱ implementȱ aȱ factorialȱfunction,ȱsuchȱasȱtheȱoneȱshownȱinȱProgramȱ7.7a.ȱThisȱfunctionȱproducesȱtheȱ correctȱ answers,ȱ butȱ itȱ isȱ notȱ aȱ goodȱ useȱ ofȱ recursion.ȱ Why?ȱ Theȱ recursiveȱ functionȱ callsȱinvolveȱsomeȱruntimeȱoverhead—argumentsȱmustȱbeȱpushedȱonȱtheȱstack,ȱspaceȱ allocatedȱforȱlocalȱvariablesȱ(inȱgeneral,ȱthoughȱnotȱforȱthisȱspecificȱexample),ȱregistersȱ Download at http://www.pin5i.com/ 186 Chapter 7 Functions ȱ /* ** Compute the factorial of n, recursively */ long factorial( int n ) { if( n <= 0 ) return 1; else return n * factorial( n - 1 ); } ȱ Programȱ7.7aȱȱRecursiveȱfactorialsȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱfact_rec.cȱ ȱ ȱ ȱ ȱ ȱ mustȱbeȱsaved,ȱandȱsoȱforth.ȱWhenȱeachȱcallȱtoȱtheȱfunctionȱreturns,ȱallȱthisȱworkȱmustȱ beȱ undone.ȱ Forȱ allȱ ofȱ thisȱ overhead,ȱ however,ȱ recursionȱ doesȱ littleȱ toȱ simplifyȱ theȱ solutionȱtoȱthisȱproblem.ȱ Programȱ 7.7bȱ computesȱ theȱ sameȱ resultȱ withȱ aȱ loop.ȱ Althoughȱ thisȱ programȱ withȱitsȱsimpleȱloopȱdoesȱnotȱresembleȱtheȱmathematicalȱdefinitionȱofȱfactorialȱnearlyȱ asȱclosely,ȱitȱcomputesȱtheȱsameȱresultȱmoreȱefficiently.ȱIfȱyouȱlookȱmoreȱcloselyȱatȱtheȱ recursiveȱfunction,ȱyouȱwillȱseeȱthatȱtheȱrecursiveȱcallȱisȱtheȱlastȱthingȱtheȱfunctionȱ ȱ ȱ ȱ ȱ ȱ /* ** Compute the factorial of n, iteratively */ long factorial( int n ) { int result = 1; while( n > 1 ){ result *= n; n -= 1; } return result; } ȱ Programȱ7.7bȱȱIterativeȱfactorialsȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱfact_itr.cȱ Download at http://www.pin5i.com/ 7.5 Recursion 187 does.ȱ Thisȱ functionȱ isȱ anȱ exampleȱ ofȱ tailȱ recursion.ȱ Becauseȱ noȱ workȱ isȱ doneȱ inȱ theȱ functionȱ afterȱ theȱ recursiveȱ callȱ returns,ȱ tailȱ recursionȱ canȱ easilyȱ beȱ convertedȱ toȱ aȱ simpleȱloopȱthatȱaccomplishesȱtheȱsameȱtask.ȱ ȱ Manyȱ problemsȱ areȱ explainedȱ recursivelyȱ onlyȱ becauseȱ itȱ isȱ clearerȱ thanȱ aȱ nonȬ recursiveȱ explanation.ȱ However,ȱ anȱ iterativeȱ implementationȱ ofȱ theseȱ problemsȱ isȱ oftenȱmoreȱefficientȱthanȱaȱrecursiveȱimplementation,ȱevenȱthoughȱtheȱresultingȱcodeȱ isȱ lessȱ clear.ȱ Whenȱ aȱ problemȱ isȱ complexȱ enoughȱ thatȱ anȱ iterativeȱ implementationȱ isȱ difficultȱ forȱ someoneȱ elseȱ toȱ follow,ȱ thenȱ theȱ clarityȱ ofȱ theȱ recursiveȱ implementationȱ mayȱjustifyȱtheȱruntimeȱoverheadȱthatȱitȱwillȱincur.ȱ InȱProgramȱ7.7a,ȱrecursionȱaddedȱlittleȱtoȱtheȱsolutionȱofȱtheȱproblem.ȱProgramȱ 7.7bȱ withȱ itsȱ loopȱ wasȱ justȱ asȱ simple.ȱ Hereȱ isȱ aȱ moreȱ extremeȱ example.ȱ Fibonacciȱ numbersȱ areȱ aȱ sequenceȱ ofȱ numbersȱ inȱ whichȱ eachȱ valueȱ isȱ theȱ sumȱ ofȱ theȱ previousȱ twoȱvalues.ȱȱThisȱrelationshipȱisȱoftenȱdescribedȱrecursively:ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱnȱǂȱ1:ȱȱ1ȱ ȱ ȱ ȱ ȱȱȱȱȱȱ ȱ factorial(n)ȱ=ȱȱȱȱȱȱȱnȱ=ȱ2;ȱȱ1ȱ ȱ ȱ ȱ ȱȱȱȱȱnȱ>ȱ2:ȱȱȱFibonacci(nȱ–ȱ1)ȱ+ȱFibonacci(nȱ–ȱ2)ȱ ȱ Again,ȱ theȱ recursiveȱ definitionȱ suggestsȱ thatȱ theȱ solutionȱ shouldȱ beȱ implementedȱ usingȱ recursion,ȱ asȱ illustratedȱ inȱ Programȱ 7.8a.ȱ ȱ Hereȱ isȱ theȱ trap:ȱ theȱ recursiveȱstepȱcomputesȱFibonacci(nȱȬȱ1)ȱandȱFibonacci(nȱȬȱ2).ȱȱBut,ȱtheȱcomputationȱofȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Compute the value of the n'th Fibonacci number, recursively. */ long fibonacci( int n ) { if( n <= 2 ) return 1; return fibonacci( n - 1 ) + fibonacci( n - 2 ); } Programȱ7.8bȱȱȱRecursiveȱFibonacciȱnumbersȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱfib_rec.cȱ Download at http://www.pin5i.com/ 188 Chapter 7 Functions ȱFibonacci(nȱȬȱ1)ȱalsoȱcomputesȱFibonacci(nȱȬȱ2).ȱHowȱmuchȱcouldȱoneȱextraȱcomputationȱ cost?ȱ Theȱanswerȱisȱthatȱthereȱisȱfarȱmoreȱthanȱjustȱoneȱredundantȱcomputation:ȱeachȱ recursiveȱcallȱbeginsȱtwoȱmoreȱrecursiveȱcalls,ȱandȱeachȱofȱthoseȱcallsȱbeginsȱtwoȱmore,ȱ andȱ soȱ forth.ȱ Therefore,ȱ theȱ numberȱ ofȱ redundantȱ computationsȱ growsȱ veryȱ rapidly.ȱȱ Forȱ instance,ȱ inȱ computingȱ Fibonacci(l0),ȱ theȱ valueȱ ofȱ Fibonacci(3)ȱ isȱ computedȱ 21ȱ times.ȱ Butȱ toȱ computeȱ Fibonacci(30)ȱ recursively,ȱ Fibonacci(3)ȱ isȱ computedȱ 317,811ȱ times.ȱ Ofȱ course,ȱ everyȱ oneȱ ofȱ theseȱ 317,811ȱ calculationsȱ producedȱ exactlyȱ theȱ sameȱ result,ȱsoȱallȱbutȱoneȱwereȱwasted.ȱȱThisȱoverheadȱisȱhorrible!ȱ Considerȱ Programȱ 7.8b,ȱ whichȱ usesȱ aȱ simpleȱ loopȱ insteadȱ ofȱ recursion.ȱ Onceȱ again,ȱ theȱ loopȱ doesȱ notȱ resembleȱ theȱ abstractȱ definitionȱ asȱ closelyȱ asȱ theȱ recursiveȱ version,ȱbutȱitȱisȱhundredsȱofȱthousandsȱofȱtimesȱmoreȱefficient!ȱ Beforeȱimplementingȱaȱfunctionȱrecursively,ȱaskȱyourselfȱwhetherȱtheȱbenefitȱtoȱ beȱgainedȱbyȱusingȱrecursionȱoutweightsȱtheȱcosts.ȱAndȱbeȱcareful:ȱtheȱcostsȱmightȱbeȱ moreȱthanȱwhatȱtheyȱfirstȱappearȱtoȱbe.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Compute the value of the n'th Fibonacci number, iteratively. */ long fibonacci( int n ) { long result; long previous_result; long next_older_result; result = previous_result = 1; while( n > 2 ){ n -= 1; next_older_result = previous_result; previous_result = result; result = previous_result + next_older_result; } return result; } ȱ Programȱ7.8bȱȱIterativeȱFibonacciȱnumbersȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱfib_iter.cȱ Download at http://www.pin5i.com/ 7.6 Variable Argument Lists 189 7.6 Variable Argument Lists ȱ Aȱfunctionȱprototypeȱlistsȱtheȱargumentsȱthatȱtheȱfunctionȱexpects,ȱbutȱaȱprototypeȱcanȱ onlyȱ showȱ aȱ 6xedȱ numberȱ ofȱ arguments.ȱ Isȱ itȱ possibleȱ forȱ aȱ functionȱ toȱ acceptȱ aȱ differentȱnumberȱofȱargumentsȱatȱdifferentȱtimes?ȱȱYes,ȱbutȱthereȱareȱsomeȱrestrictions.ȱ Considerȱaȱfunctionȱthatȱcomputesȱtheȱaverageȱofȱaȱseriesȱofȱvalues.ȱThisȱtaskȱisȱtrivialȱ ifȱ theȱ valuesȱ areȱ storedȱ inȱ anȱ array,ȱ soȱ toȱ makeȱ theȱ problemȱ moreȱ interestingȱ letȇsȱ assumeȱthatȱtheyȱareȱnot.ȱProgramȱ7.9aȱattemptsȱtoȱdoȱtheȱjob.ȱ Thisȱ functionȱ hasȱ severalȱ problems.ȱ First,ȱ thereȱ isnȇtȱ aȱ testȱ forȱ tooȱ manyȱ arguments,ȱ butȱ oneȱ couldȱ easilyȱ beȱ added.ȱ Second,ȱ theȱ functionȱ cannotȱ handleȱ moreȱ thanȱfiveȱvalues.ȱThisȱproblemȱcanȱonlyȱbeȱrectifiedȱbyȱaddingȱevenȱmoreȱcopiesȱofȱtheȱ alreadyȱredundantȱcode.ȱ Butȱ thereȱ isȱ aȱ moreȱ seriousȱ problemȱ whichȱ occursȱ whenȱ youȱ tryȱ toȱ callȱ theȱ functionȱlikeȱthis:ȱ ȱ avg1 = average( 3, x, y, z ); ȱ Thereȱ areȱ onlyȱ fourȱ arguments,ȱ butȱ theȱ functionȱ hasȱ sixȱ formalȱ parameters.ȱ Theȱ Standardȱ coversȱ thisȱ situation:ȱ theȱ behaviorȱ isȱ undefined.ȱ Thus,ȱ theȱ firstȱ argumentȱ mightȱcorrespondȱtoȱtheȱn_valuesȱparameterȱorȱmaybeȱtoȱtheȱv2ȱparameter.ȱYouȱcanȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Compute the average of the specified number of values (bad). */ float average( int n_values, int v1, int v2, int v3, int v4, int v5 ) { float sum = v1; if( n_values sum += if( n_values sum += if( n_values sum += if( n_values sum += return sum / >= 2 ) v2; >= 3 ) v3; >= 4 ) v4; >= 5 ) v5; n_values; } ȱ Programȱ7.9aȱȱComputeȱtheȱaverageȱofȱscalarȱvalues:ȱbadȱversionȱ ȱ ȱ average1.cȱ Download at http://www.pin5i.com/ 190 Chapter 7 Functions certainlyȱtestȱyourȱimplementationȱtoȱseeȱwhatȱitȱdoes,ȱbutȱtheȱprogramȱisȱcertainlyȱnotȱ portable.ȱWhatȱisȱneedȱisȱaȱmechanismȱtoȱaccessȱanȱunboundedȱargumentȱlistȱinȱaȱwellȬ definedȱway.ȱ ȱ ȱ ȱ 7.6.1 The stdarg Macros ȱ Variableȱargumentȱlistȱareȱimplementedȱusingȱmacrosȱdefinedȱinȱtheȱ stdarg.hȱheader,ȱ whichȱ isȱ partȱ ofȱ theȱ standardȱ library.ȱ Theȱ headerȱ declaresȱ aȱ typeȱ va_listȱ andȱ threeȱ macrosȱ –ȱ va_start,ȱ va_arg,ȱ andȱ va_end. 33 ȱ Aȱ variableȱ ofȱ typeȱ va_listȱ isȱ declaredȱ andȱ usedȱwithȱtheȱmacrosȱtoȱaccessȱtheȱargumentȱvalues.ȱ Programȱ 7.9bȱ usesȱ theseȱ macrosȱ toȱ correctlyȱ accomplishȱ whatȱ programȱ 7.9aȱ triedȱ toȱ do.ȱ Noticeȱ theȱ ellipsisȱ inȱ theȱ argument,ȱ list:ȱ itȱ indicatesȱ thatȱ anȱ unspecifiedȱ numberȱ ofȱ argumentsȱ withȱ unspecifiedȱ typesȱ mayȱ beȱ passed.ȱ Theȱ sameȱ notationȱ isȱ usedȱwhenȱprototypingȱtheȱfunction.ȱ Theȱ functionȱ declaresȱ aȱ variableȱ calledȱ var_argȱ withȱ whichȱ toȱ accessȱ theȱ unspecifiedȱ portionȱ ofȱ theȱ argumentȱ list.ȱ Thisȱ variableȱ isȱ initializedȱ byȱ callingȱ va_start.ȱ Theȱ firstȱ parameterȱ isȱ theȱ nameȱ ofȱ theȱ va_listȱ variable,ȱ andȱ theȱ secondȱ parameterȱ isȱ theȱ lastȱ namedȱ argumentȱ beforeȱ theȱ ellipsis.ȱ Thisȱ initializationȱ setsȱ theȱ var_argȱvariableȱtoȱpointȱtoȱtheȱfirstȱofȱtheȱvariableȱarguments.ȱ Toȱ accessȱ anȱ argument,ȱ va_argȱ isȱ used.ȱ Thisȱ macroȱ takesȱ twoȱ parameters:ȱ theȱ va_listȱvariableȱandȱtheȱtypeȱofȱtheȱnextȱvalueȱinȱtheȱlist.ȱInȱthisȱexample,ȱtheȱvariableȱ argumentsȱareȱallȱintegers.ȱInȱsomeȱfunctions,ȱyouȱmayȱhaveȱtoȱdetermineȱtheȱtypeȱofȱ theȱnextȱargumentȱbyȱexaminingȱpreviouslyȱobtainedȱdata. 34 ȱ va_argȱreturnsȱtheȱvalueȱ ofȱthisȱargumentȱandȱadvancesȱvar_argȱtoȱpointȱtoȱtheȱnextȱvariableȱargument.ȱ Finally,ȱva_endȱisȱcalledȱafterȱtheȱlastȱaccessȱtoȱtheȱvariableȱarguments.ȱ ȱ ȱ ȱ 7.6.2 Limitations of Variable Arguments ȱ Noteȱthatȱtheȱvariableȱargumentsȱmustȱbeȱaccessedȱoneȱbyȱone,ȱinȱorder,ȱfromȱstartȱtoȱ finish.ȱȱYouȱcanȱstopȱearlyȱifȱyouȱwish,ȱbutȱthereȱisnȇtȱanyȱwayȱtoȱbeginȱaccessingȱinȱtheȱ middleȱofȱtheȱlist.ȱInȱaddition,ȱbecauseȱtheȱvariableȱportionȱofȱtheȱargumentȱlistȱisȱnotȱ prototyped,ȱ theȱ defaultȱ argumentȱ promotionsȱ areȱ performedȱ onȱ allȱ valuesȱ passedȱ asȱ variableȱarguments.ȱ ȱMacrosȱareȱimplementedȱbyȱtheȱpreprocessorȱandȱareȱdiscussedȱinȱChapterȱ14.ȱ ȱForȱexample, printfȱexaminesȱtheȱcharactersȱinȱtheȱformatȱstringȱtoȱdetermineȱtheȱtypesȱofȱtheȱargumentsȱitȱisȱsupposedȱ toȱprintȱ 33 34 Download at http://www.pin5i.com/ 7.6 Variable Argument Lists 191 ȱ /* ** Compute the average of the specified number of values. */ #include <stdarg.h> float average( int n_values, ... ) { va_list var_arg; int count; float sum = 0; /* ** Prepare to access the variable arguments. */ va_start( var_arg, n_values ); /* ** Add the values from the variable argument list. */ for( count = 0; count < n_values; count += 1 ){ sum += va_arg( var_arg, int ); } /* ** Done processing variable arguments. */ va_end( var_arg ); return sum / n_values; } ȱ Programȱ7.9bȱȱComputeȱtheȱaverageȱofȱscalarȱvalues:ȱgoodȱversionȱ ȱ ȱ average2.cȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Youȱ mayȱ alsoȱ haveȱ noticedȱ theȱ requirementȱ thatȱ thereȱ mustȱ beȱ atȱ leastȱ oneȱ namedȱ argumentȱ inȱ theȱ argumentȱ list;ȱ youȱ cannotȱ useȱ va_startȱ withoutȱ it.ȱ Thisȱ argumentȱprovidesȱaȱwayȱtoȱlocateȱtheȱvaryingȱportionȱofȱtheȱargumentȱlist.ȱ Thereȱ areȱ twoȱ fundamentalȱ limitationsȱ ofȱ theseȱ macros,ȱ bothȱ ofȱ whichȱ areȱ aȱ directȱ resultȱ ofȱ theȱ factȱ thatȱ theȱ typeȱ ofȱ aȱ valueȱ cannotȱ beȱ determinedȱ simplyȱ byȱ examiningȱit.ȱ Download at http://www.pin5i.com/ 192 Chapter 7 Functions 1. Theȱmacrosȱcannotȱdetermineȱhowȱmanyȱargumentsȱactuallyȱexist.ȱ CAUTION! 2. Theȱmacrosȱcannotȱdetermineȱtheȱtypeȱofȱeachȱargument.ȱ ȱ Theȱ namedȱ argument(s)ȱ mustȱ answerȱ bothȱ ofȱ theseȱ questions.ȱ Inȱ Programȱ 7.9b,ȱ theȱ namedȱargumentȱspecifiesȱhowȱmanyȱvaluesȱwereȱpassed,ȱbutȱtheirȱtypesȱareȱassumedȱ toȱ beȱ integers.ȱ Theȱ namedȱ argumentȱ inȱ printfȱ isȱ theȱ formatȱ string,ȱ whichȱ indicatesȱ bothȱtheȱnumberȱandȱtypesȱofȱtheȱarguments.ȱ ȱ Ifȱyouȱspecifyȱtheȱwrongȱtypeȱwithȱ va_argȱtheȱresultsȱareȱunpredictable.ȱThisȱerrorȱisȱ easyȱtoȱmakeȱbecauseȱva_argȱdoesnȇtȱcompensateȱforȱtheȱdefaultȱargumentȱpromotionsȱ thatȱareȱperformedȱonȱvariableȱarguments,ȱ char,ȱ short,ȱandȱ floatȱvaluesȱwillȱactuallyȱ beȱpassedȱasȱintȇsȱandȱdoubleȇs.ȱBeȱcarefulȱtoȱuseȱtheseȱlatterȱtypesȱwithȱva_arg.ȱ ȱ ȱ ȱ 7.7 Summary ȱ Aȱfunctionȱdefinitionȱspecifiesȱbothȱtheȱparameterȱlistȱandȱtheȱbodyȱofȱtheȱfunction,ȱtheȱ statementsȱ thatȱ areȱ executedȱ whenȱ theȱ functionȱ isȱ called.ȱ Thereȱ areȱ twoȱ acceptableȱ formsȱ forȱ writingȱ theȱ parameterȱ list.ȱ Theȱ K&Rȱ styleȱ declaresȱ theȱ typesȱ ofȱ theȱ parametersȱ inȱ aȱ separateȱ listȱ thatȱ occursȱ priorȱ toȱ theȱ openingȱ braceȱ ofȱ theȱ functionȇsȱ body.ȱ Theȱ newȱ style,ȱ whichȱ isȱ preferred,ȱ includesȱ theȱ typesȱ inȱ theȱ parameterȱ list.ȱ Aȱ functionȱwithȱnoȱstatementsȱinȱitsȱbody,ȱcalledȱaȱstub,ȱisȱusefulȱinȱtestingȱincompleteȱ programs.ȱ Aȱfunctionȱdeclarationȱgivesȱlimitedȱinformationȱaboutȱaȱfunction,ȱandȱisȱusedȱ whereȱtheȱfunctionȱisȱcalled.ȱThereȱareȱtwoȱacceptableȱformsȱforȱfunctionȱdeclarations.ȱ TheȱK&Rȱstyle,ȱwithȱnoȱparameterȱlist,ȱonlyȱdeclaresȱtheȱtypeȱofȱvalueȱreturnedȱbyȱtheȱ function.ȱTheȱnewȱstyle,ȱwhichȱisȱpreferred,ȱisȱcalledȱaȱfunctionȱprototype.ȱItȱincludesȱ declarationsȱofȱtheȱtypesȱofȱtheȱparametersȱasȱwell,ȱwhichȱallowsȱtheȱcompilerȱtoȱcheckȱ theȱ typesȱ andȱ numberȱ ofȱ argumentsȱ inȱ callsȱ toȱ theȱ function.ȱ Youȱ canȱ alsoȱ putȱ parameterȱnamesȱinȱaȱfunctionȱprototypeȱasȱwell.ȱWhileȱoptional,ȱthisȱpracticeȱmakesȱ theȱ prototypeȱ moreȱ usefulȱ forȱ otherȱ readersȱ becauseȱ itȱ conveysȱ moreȱ information.ȱȱ Prototypesȱ forȱ functionsȱ withoutȱ parametersȱ haveȱ justȱ theȱ keywordȱ voidȱ asȱ aȱ parameterȱlist.ȱȱTheȱpreferredȱwayȱtoȱuseȱfunctionȱprototypesȱisȱtoȱputȱtheȱprototypeȱinȱ aȱ separateȱ fileȱ whichȱ isȱ thenȱ #includeȇdȱ whereverȱ theȱ prototypeȱ isȱ needed.ȱ Thisȱ techniqueȱminimizesȱtheȱnumberȱofȱseparateȱcopiesȱofȱtheȱprototypeȱthatȱareȱneeded,ȱ whichȱsimplifiesȱmaintenance.ȱ Theȱ returnȱ statementȱ isȱ usedȱ toȱ specifyȱ theȱ valueȱ toȱ beȱ returnedȱ fromȱ aȱ function.ȱIfȱnoȱvalueȱisȱgivenȱinȱtheȱ returnȱstatement,ȱorȱifȱaȱfunctionȱdoesȱnotȱcontainȱ anyȱ returnȱ statements,ȱ noȱ valueȱ willȱ beȱ returned.ȱ Suchȱ functionsȱ areȱ calledȱ Download at http://www.pin5i.com/ 7.7 Summary 193 ȱinȱ manyȱ otherȱ languages.ȱ Inȱ ANSIȱ C,ȱ functionȱ thatȱ doȱ notȱ returnȱ aȱ valueȱ shouldȱ beȱ declaredȱasȱreturningȱtheȱtypeȱvoid.ȱ Ifȱ aȱ functionȱ itȱ isȱ calledȱ beforeȱ anyȱ declarationsȱ forȱ itȱ haveȱ beenȱ seen,ȱ theȱ compilerȱassumesȱthatȱtheȱfunctionȱreturnsȱanȱintegerȱvalue.ȱItȱisȱimportantȱtoȱdeclareȱ functionsȱthatȱreturnȱnonintegralȱtypesȱinȱorderȱtoȱavoidȱerrorsȱcausedȱbyȱunexpectedȱ typeȱ conversions.ȱ ȱ Argumentsȱ toȱ functionsȱ thatȱ areȱ notȱ prototypedȱ underȱ goȱ theȱ defaultȱ argumentȱ promotions:ȱ charȱ andȱ shortȱ argumentsȱ areȱ convertedȱ toȱ int,ȱ andȱ floatȱargumentsȱareȱconvertedȱtoȱdouble.ȱ Argumentsȱ toȱ functionsȱareȱpassedȱcallȱbyȱvalue,ȱwhichȱmakesȱ aȱ copyȱofȱeachȱ argument.ȱ Aȱ functionȱ canȱ thereforeȱ modifyȱ itsȱ parametersȱ (theȱ copies)ȱ withoutȱ affectingȱtheȱcallerȇsȱarguments.ȱArrayȱnamesȱareȱalsoȱpassedȱusingȱcallȱbyȱvalue,ȱbutȱ allȱthatȱisȱcopiedȱisȱaȱpointerȱtoȱtheȱcallerȇsȱarray.ȱWhenȱaȱsubscriptȱisȱusedȱonȱtheȱarrayȱ parameterȱ inȱ theȱ function,ȱ indirectionȱ causesȱ anȱ elementȱ inȱ theȱ callerȇsȱ arrayȱ toȱ beȱ accessed.ȱ Thus,ȱ modifyingȱ anȱ arrayȱ elementȱ inȱ theȱ functionȱ actuallyȱ modifiesȱ theȱ callerȇsȱarray.ȱThisȱbehaviorȱisȱnamedȱcallȱbyȱreference.ȱYouȱcanȱgetȱcallȱbyȱreferenceȱ semanticsȱ withȱ scalarȱ argumentsȱ byȱ passingȱ pointersȱ toȱ theȱ argumentsȱ andȱ usingȱ indirectionȱinȱtheȱfunctionȱtoȱaccessȱorȱmodifyȱtheȱvalues.ȱ Anȱ abstractȱ dataȱ type,ȱ orȱ blackȱ box,ȱ consistsȱ ofȱ anȱ interfaceȱ andȱ anȱ implementation.ȱ Theȱ interface,ȱ whichȱ isȱ public,ȱ specifiesȱ howȱ aȱ clientȱ usesȱ theȱ functionalityȱprovidedȱbyȱtheȱADT.ȱTheȱimplementation,ȱwhichȱisȱprivate,ȱisȱwhereȱtheȱ workȱ isȱ actuallyȱ done.ȱ Keepingȱ theȱ implementationȱ privateȱ preventsȱ clientsȱ fromȱ makingȱ theirȱ programsȱ dependentȱ onȱ detailsȱ ofȱ theȱ implementation.ȱ Theȱ implementationȱ canȱ thenȱ beȱ changedȱ whenȱ necessaryȱ withoutȱ affectingȱ theȱ clientsȇȱ code.ȱ Aȱ recursiveȱ functionȱ isȱ oneȱ thatȱ callsȱ itself,ȱ eitherȱ directlyȱ orȱ indirectly.ȱ Forȱ recursionȱtoȱwork,ȱeachȱinvocationȱofȱtheȱfunctionȱmustȱmakeȱsomeȱprogressȱtowardȱaȱ goal.ȱWhenȱtheȱgoalȱisȱreached,ȱnoȱmoreȱrecursiveȱcallsȱareȱmade.ȱToȱreadȱaȱrecursiveȱ function,ȱdoȱnotȱgetȱhungȱupȱonȱtracingȱeachȱrecursiveȱcall.ȱItȱisȱeasierȱtoȱunderstandȱ whatȱisȱhappeningȱifȱyouȱsimplyȱassumeȱthatȱtheȱrecursiveȱcallȱperformsȱtheȱworkȱthatȱ itȱclaimsȱtoȱdo.ȱ Someȱ functionsȱ thatȱ areȱ describedȱ recursively,ȱ suchȱ asȱ factorialȱ andȱ Fibonacciȱ numbers,ȱcanȱbeȱimplementedȱmoreȱefficientlyȱiteratively.ȱWhenȱaȱrecursiveȱcallȱisȱtheȱ lastȱthingȱthatȱisȱdoneȱinȱaȱfunction,ȱitȱisȱcalledȱtailȱrecursion.ȱȱTailȱrecursionȱcanȱeasilyȱ beȱconvertedȱtoȱaȱloop,ȱwhichȱisȱusuallyȱmoreȱefficient.ȱ Functionsȱ withȱ argumentȱ listsȱ containingȱ variableȱ numbersȱ andȱ typesȱ ofȱ argumentsȱcanȱbeȱimplementedȱusingȱtheȱmacrosȱdefinedȱinȱtheȱstdarg.hȱheader.ȱȱTheȱ varyingȱ portionȱ ofȱ theȱ parameterȱ list,ȱ whichȱ followsȱ oneȱ orȱ moreȱ ordinaryȱ (named)ȱ parameters,ȱ isȱ indicatedȱ withȱ anȱ elipsisȱ inȱ theȱ functionȱ prototype.ȱ Theȱ namedȱ parameter(s)ȱmustȱsomehowȱindicateȱtheȱnumberȱofȱargumentsȱpassedȱinȱtheȱvaryingȱ Download at http://www.pin5i.com/ 194 Chapter 7 Functions partȱand,ȱifȱnotȱknownȱinȱadvance,ȱtheirȱtypes.ȱTheȱargumentsȱinȱtheȱvaryingȱportionȱ ofȱtheȱlistȱundergoȱtheȱdefaultȱargumentȱpromotionsȱwhenȱtheyȱareȱpassed,ȱandȱtheyȱ canȱonlyȱbeȱaccessedȱinȱorderȱfromȱfirstȱtoȱlast.ȱ ȱ ȱ ȱ 7.8 Summary of Cautions ȱ 1. Writingȱfunctionȱprototypesȱwithinȱtheȱscopeȱofȱotherȱfunctionsȱ(pageȱ169).ȱ 2. Notȱprototypingȱfractionsȱthatȱreturnȱnonintegralȱvaluesȱ(pageȱ171).ȱ 3. MixingȱfunctionȱprototypesȱwithȱoldȬstyleȱfunctionȱdefinitionsȱ(pageȱ175).ȱ 4. Usingȱtheȱwrongȱargumentȱtypeȱinȱva_argȱgivesȱundefinedȱresultsȱ(pageȱ192).ȱ ȱ ȱ ȱ 7.9 Summary of Programming Tips ȱ 1. Puttingȱargumentȱnamesȱinȱfunctionȱprototypesȱmakesȱitȱeasierȱforȱtheȱclientȱtoȱuseȱ theȱfunctionȱ(pageȱ169).ȱ 2. Abstractȱ dataȱ typesȱ increaseȱ reliabilityȱ byȱ decreasingȱ theȱ programȇsȱ relianceȱ onȱ implementationȱdetailsȱ(pageȱ179).ȱ 3. Useȱrecursionȱasȱaȱnotationalȱtoolȱwhenȱtheȱbenefitȱjustifiesȱtheȱcostȱ(pageȱ187).ȱ ȱ ȱ ȱ 7.10 Questions ȱ 1. Aȱfunctionȱwithȱanȱemptyȱbodyȱisȱusefulȱasȱaȱstub.ȱHowȱmightȱsuchȱaȱfunctionȱbeȱ modifiedȱtoȱbeȱmoreȱuseful?ȱ 2. PrototypesȱforȱfunctionsȱareȱnotȱmandatoryȱinȱANSIȱC.ȱȱIsȱthisȱfactȱanȱadvantageȱorȱ aȱdisadvantage?ȱ 3. Whatȱ happensȱ ifȱ aȱ functionȱ thatȱ isȱ declaredȱ toȱ returnȱ aȱ specificȱ typeȱ includesȱ aȱ returnȱstatementȱwithȱanȱexpressionȱofȱaȱdifferentȱtype?ȱ 4. Whatȱhappensȱifȱaȱfunctionȱthatȱisȱdeclaredȱvoidȱcontainsȱaȱreturnȱstatementȱwithȱ anȱexpression?ȱ 5. Ifȱaȱfunctionȱisȱcalledȱbeforeȱtheȱcompilerȱhasȱseenȱaȱprototypeȱforȱit,ȱwhatȱhappensȱ ifȱtheȱfunctionȱreturnsȱsomeȱtypeȱotherȱthanȱinteger?ȱ 6. Ifȱaȱfunctionȱisȱcalledȱbeforeȱtheȱcompilerȱhasȱseenȱaȱprototypeȱforȱit,ȱwhatȱhappensȱ Download at http://www.pin5i.com/ 7.11 Programming Exercises 195 ifȱtheȱtypesȱofȱtheȱargumentsȱdoȱnotȱmatchȱthoseȱofȱtheȱformalȱparameters?ȱ 7. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱfunction?ȱ ȱ int find_max( int array[10] ) { int i; int max = array[0]; for( i = 1; i < 10; i += 1 ) if( array[i] > max ) max = array[i]; return max; } 8. Howȱisȱrecursionȱsimilarȱtoȱaȱwhileȱloop?ȱ 9. Explainȱtheȱadvantagesȱofȱputtingȱfunctionȱprototypesȱinȱ#includeȱfiles.ȱ 10. EnterȱtheȱrecursiveȱFibonacciȱfunctionȱonȱyourȱsystem,ȱandȱaddȱaȱstatementȱatȱtheȱ beginningȱ ofȱ theȱ functionȱ thatȱ incrementsȱ aȱ globalȱ integerȱ variable.ȱ Nowȱ writeȱ aȱ mainȱfunctionȱtoȱsetȱtheȱglobalȱvariableȱtoȱzeroȱandȱcomputeȱ fibonacci(1).ȱRepeatȱ forȱ fibonacci(2)ȱ throughȱ fibonacci(10).ȱ Howȱ manyȱ timesȱ wasȱ theȱ fibonacciȱ functionȱ calledȱ forȱ eachȱ ofȱ theseȱ computations?ȱ ȱ Isȱ thisȱ progressionȱ ofȱ valuesȱ relatedȱ inȱ anyȱ wayȱ toȱ theȱ Fibonacciȱ numbersȱ themselves?ȱ Basedȱ onȱ thisȱ information,ȱ canȱ youȱ calculateȱ theȱ numberȱ ofȱ callsȱ thatȱ wouldȱ beȱ neededȱ toȱ computeȱfibonacci(11)?ȱfibonacci(25)?ȱȱȱfibonacci(50)?ȱ ȱ ȱ ȱ 7.11 Programming Exercises ȱ 1. TheȱHermiteȱPolynomialsȱareȱdefinedȱasȱfollows:ȱ ȱ ȱ ȱ ȱȱȱȱȱnȱǂȱ0:ȱȱ1ȱ ȱ ȱ ȱ ȱȱȱȱȱȱ ȱ Hn(x)ȱ=ȱȱȱȱȱȱnȱ=ȱ1;ȱȱ2xȱ ȱ ȱ ȱȱȱȱȱnȱǃȱ2:ȱȱȱ2xHnȱ–ȱ1(x)ȱ–ȱ2(nȱ–ȱ1)Hnȱ–ȱ2(x)ȱ ȱ Forȱ example,ȱ theȱ valueȱ ofȱ H3(2)ȱ isȱ 40.ȱ Writeȱ aȱ recursiveȱ functionȱ toȱ computeȱ theȱ valueȱofȱHn(x).ȱYourȱfunctionȱshouldȱmatchȱthisȱprototype:ȱ ȱ ȱ int hermite( int n, int x ); Download at http://www.pin5i.com/ Chapter 7 Functions 196 2. Theȱ greatestȱ commonȱ divisorȱ ofȱ twoȱ integersȱ Mȱ andȱ Nȱ (whereȱ M,ȱ Nȱ >ȱ 0)ȱ canȱ beȱ computedȱasȱfollows:ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱMȱ%ȱNȱ=ȱ0:ȱ ȱ Nȱ ȱ gcd(M,ȱN)ȱ=ȱȱ ȱ ȱ ȱ ȱȱȱȱȱMȱ%ȱNȱ=ȱR,ȱRȱ>ȱ0:ȱȱ gcd(N,ȱR)ȱ ȱ Writeȱ aȱ functionȱ calledȱ gcdȱ thatȱ takesȱ twoȱ integerȱ argumentsȱ andȱ returnsȱ theȱ greatestȱcommonȱdivisorȱofȱthoseȱnumbers.ȱIfȱeitherȱofȱtheȱargumentsȱisȱnotȱgreaterȱ thanȱzero,ȱyourȱfunctionȱshouldȱreturnȱzero.ȱ 3. Writeȱtheȱfunctionȱforȱtheȱfollowingȱprototype:ȱ int ascii_to_integer( char *string ); Theȱ stringȱ argumentȱ mustȱ containȱ oneȱ orȱ moreȱ digits,ȱ andȱ theȱ functionȱ shouldȱ convertȱthoseȱdigitsȱtoȱanȱintegerȱandȱreturnȱtheȱresult.ȱIfȱanyȱnondigitȱcharactersȱ areȱfound,ȱreturnȱtheȱvalueȱzeroȱinstead.ȱDoȱnotȱworryȱaboutȱarithmeticȱoverflow.ȱ Hint:ȱTheȱtechniqueȱisȱsimple—forȱeachȱdigitȱyouȱfind,ȱmultiplyȱtheȱvalueȱyouȱhaveȱ soȱfarȱandȱthenȱaddȱtheȱvalueȱrepresentedȱbyȱtheȱnewȱdigitȱ 4. Writeȱ aȱ functionȱ calledȱ max_listȱ thatȱ examinesȱ anȱ arbitraryȱ numberȱ ofȱ integerȱ argumentsȱandȱreturnsȱtheȱlargestȱofȱthem.ȱȱTheȱargumentsȱwillȱbeȱterminatedȱbyȱaȱ valueȱthatȱisȱlessȱthanȱzero.ȱ 5. ImplementȱaȱbareȬbonesȱ printfȱfunctionȱthatȱisȱcapableȱofȱhandlingȱtheȱ %d,ȱ %f,ȱ %s,ȱ andȱ %cȱformatȱcodes.ȱTheȱbehaviorȱforȱotherȱformatȱcodes,ȱinȱtheȱtrueȱspiritȱofȱtheȱ ANSIȱ Standard,ȱ isȱ undefined.ȱ Youȱ mayȱ assumeȱ theȱ existenceȱ ofȱ theȱ functionsȱ print_integerȱandȱprint_floatȱtoȱprintȱvaluesȱofȱthoseȱtypes.ȱUseȱputcharȱtoȱprintȱ everythingȱelse.ȱ 6. Writeȱaȱfunctionȱ void written_amount( unsigned int amount, char *buffer ); thatȱ convertsȱ theȱ valueȱ inȱ amountȱ toȱ wordsȱ andȱ storesȱ themȱ inȱ theȱ buffer.ȱ Thisȱ functionȱ mightȱ beȱ usedȱ inȱ aȱ programȱ thatȱ printsȱ checks.ȱ Forȱ example,ȱ ifȱ valueȱ isȱ 16,312,ȱthenȱtheȱstringȱ SIXTEEN THOUSAND THRSE HUNDRED TWELVE shouldȱ beȱ storedȱ inȱ theȱ buffer.ȱ Itȱ isȱ theȱ callerȇsȱ responsibilityȱ toȱ makeȱ theȱ bufferȱ largeȱenough.ȱ Someȱvaluesȱcanȱbeȱprintedȱinȱtwoȱdifferentȱways.ȱForȱexample,ȱ1,200ȱcouldȱbeȱ eitherȱ ONE THOUSAND TWO HUNDRED OR TWELVE HUNDREDȱ Youȱ mayȱ convertȱ theseȱ valuesȱwhicheverȱwayȱyouȱwish.ȱ ȱ ȱ Download at http://www.pin5i.com/ 8 Arrays Youȇveȱ beenȱ usingȱ simple,ȱ oneȬdimensionalȱ arraysȱ sinceȱ Chapterȱ 2.ȱ Thisȱ chapterȱ explainsȱ moreȱ aboutȱ theseȱ arraysȱ andȱ exploresȱ moreȱ advancedȱ arrayȱ topicsȱ suchȱ asȱ multidimensionalȱarrays,ȱarraysȱandȱpointers,ȱandȱarrayȱinitialization.ȱ ȱ ȱ ȱ 8.1 One-Dimensional Arrays ȱ Beforeȱ weȱintroduceȱmultidimensionalȱarrays,ȱthereȱ isȱ aȱlotȱmoreȱtoȱ learnȱaboutȱ oneȬ dimensionalȱarrays.ȱLetȇsȱbeginȱwithȱaȱconceptȱthatȱmanyȱconsiderȱaȱflawȱinȱtheȱdesignȱ ofȱtheȱCȱlanguage,ȱbutȱthisȱconceptȱactuallyȱtiesȱsomeȱdisparateȱconceptsȱtogetherȱquiteȱ nicely.ȱ ȱ ȱ ȱ 8.1.1 Array Names ȱ Considerȱtheseȱdeclarations:ȱ ȱ ȱ int a; int b[10]; Weȱ callȱ theȱ variableȱ aȱ aȱ scalarȱ becauseȱ itȱ isȱ aȱ singleȱ value.ȱ Theȱ typeȱ ofȱ theȱ valueȱ isȱ integer.ȱȱWeȱcallȱtheȱvariableȱbȱanȱarrayȱbecauseȱitȱisȱaȱcollectionȱofȱvalues.ȱȱAȱsubscriptȱ isȱ usedȱ withȱ theȱ arrayȱ nameȱ toȱ identifyȱ oneȱ specificȱ valueȱ fromȱ thatȱ collection;ȱ forȱ example,ȱb[0]ȱidentifiesȱtheȱfirstȱvalueȱinȱtheȱbȱarray,ȱandȱb[4]ȱidentifiesȱtheȱfifth.ȱEachȱ specificȱ valueȱ isȱ aȱ scalarȱ andȱ mayȱ beȱ usedȱ inȱ anyȱ contextȱ inȱ whichȱ aȱ scalarȱ mayȱ beȱ used.ȱ Theȱtypeȱofȱ b[4]ȱisȱinteger,ȱbutȱwhatȱisȱtheȱtypeȱofȱ b?ȱToȱwhatȱdoesȱitȱrefer?ȱAȱ logicalȱanswerȱwouldȱbeȱthatȱitȱrefersȱtoȱtheȱwholeȱarray,ȱbutȱitȱdoesnȇt.ȱInȱC,ȱwhenȱtheȱ Download at http://www.pin5i.com/ 198ȱ Chapter 8 Arrays nameȱofȱanȱarrayȱisȱusedȱinȱalmostȱanyȱexpression,ȱtheȱvalueȱofȱtheȱnameȱisȱaȱpointerȱ constantȱ thatȱ isȱ theȱ addressȱ ofȱ theȱ firstȱ elementȱ ofȱ theȱ array.ȱ Itsȱ typeȱ dependsȱ onȱ theȱ typeȱ ofȱ theȱ arrayȱ elements:ȱ ifȱ theyȱ areȱ int,ȱ thenȱ theȱ valueȱ ofȱ theȱ arrayȱ nameȱ isȱ aȱ Ȉconstantȱpointerȱtoȱ int.ȈȱIfȱtheyȱareȱsomethingȱelse,ȱthenȱtheȱvalueȱofȱtheȱarrayȱnameȱ isȱaȱȈconstantȱpointerȱtoȱsomethingȱelse.Ȉȱ Doȱnotȱconcludeȱfromȱthisȱthatȱarraysȱandȱpointersȱareȱtheȱsame.ȱAnȱarrayȱhasȱ quiteȱ differentȱ characteristicsȱ thanȱ aȱ pointer,ȱ forȱ example,ȱ anȱ arrayȱ hasȱ aȱ certainȱ numberȱofȱelements,ȱwhileȱaȱpointerȱisȱaȱscalar.ȱTheȱcompilerȱusesȱtheȱarrayȱnameȱtoȱ keepȱtrackȱofȱtheseȱproperties.ȱItȱisȱonlyȱwhenȱtheȱarrayȱnameȱisȱusedȱinȱanȱexpressionȱ thatȱtheȱcompilerȱgeneratesȱtheȱpointerȱconstant.ȱ NoteȬthatȱthisȱvalueȱisȱaȱpointerȱconstantȱasȱopposedȱtoȱaȱpointerȱvariable;ȱyouȱ cannotȱchangeȱtheȱ valueȱ ofȱ aȱ constant.ȱ Onȱreflectionȱthisȱrestrictionȱmakesȱ sense;ȱtheȱ valueȱpointsȱtoȱwhereȱtheȱarrayȱbeginsȱinȱmemory,ȱsoȱtheȱonlyȱwayȱtoȱchangeȱitȱisȱtoȱ moveȱtheȱarrayȱsomewhereȱelseȱinȱmemory.ȱButȱmemoryȱforȱarraysȱisȱfixedȱwhenȱtheȱ programȱisȱlinked,ȱsoȱbyȱtheȱtimeȱtheȱprogramȱisȱrunning,ȱitȱisȱmuchȱtooȱlateȱtoȱmoveȱ anȱarray.ȱHence,ȱtheȱvaluesȱofȱarrayȱnamesȱareȱpointerȱconstants.ȱ Thereȱ areȱ onlyȱ twoȱ placesȱ whereȱ thisȱ pointerȱ substitutionȱ doesȱ notȱ occur— whenȱ anȱ arrayȱ nameȱ isȱ anȱ operandȱ ofȱ eitherȱ sizeofȱ orȱ theȱ unaryȱ operatorȱ &.ȱ sizeofȱ returnsȱ theȱ sizeȱ ofȱ theȱ entireȱ array,ȱ notȱ theȱ sizeȱ ofȱ aȱ pointerȱ toȱ theȱ array.ȱ Takingȱ theȱ addressȱofȱanȱarrayȱnameȱgivesȱaȱpointerȱtoȱtheȱfirstȱelementȱinȱtheȱarray,ȱnotȱaȱpointerȱ toȱsomeȱsubstitutedȱpointerȱconstantȱvalue.ȱ Nowȱconsiderȱthisȱexample:ȱ ȱ int a[10]; int b[10]; int *c; ... c = &a[0]; ȱ Theȱexpressionȱ &a[0]ȱisȱaȱpointerȱtoȱtheȱfirstȱelementȱofȱtheȱarray.ȱButȱthatȇsȱtheȱvalueȱ ofȱtheȱarrayȱnameȱitself,ȱsoȱtheȱfollowingȱassignmentȱperformsȱexactlyȱtheȱsameȱjobȱasȱ theȱoneȱabove:ȱ ȱ c = a; ȱ Thisȱassignmentȱshowsȱwhyȱitȱisȱimportantȱtoȱunderstandȱtheȱtrueȱmeaningȱofȱanȱarrayȱ nameȱinȱanȱexpression.ȱIfȱtheȱnameȱreferredȱtoȱtheȱentireȱarray,ȱthisȱstatementȱwouldȱ implyȱ thatȱtheȱ entireȱarrayȱisȱbeingȱcopiedȱ toȱ aȱnewȱarray.ȱButȱ thisȱ isȱ notȱ atȱallȱ whatȱ happens;ȱwhatȱisȱassignedȱisȱaȱcopyȱofȱaȱpointer,ȱmakingȱcȱpointȱtoȱtheȱfirstȱelementȱofȱ theȱarray.ȱThus,ȱassignmentsȱsuchȱasȱ Download at http://www.pin5i.com/ 8.1 One-Dimensional Arrays 199 b = a; ȱ areȱ illegal.ȱ Youȱ cannotȱ useȱ theȱ assignmentȱ operatorȱ toȱ copyȱ allȱ theȱ elementsȱ ofȱ oneȱ arrayȱtoȱanotherȱarray;ȱyouȱmustȱuseȱaȱloopȱandȱcopyȱoneȱelementȱatȱaȱtime.ȱ Considerȱthisȱstatement:ȱ ȱ a = c; ȱ Withȱ cȱ declaredȱ asȱ aȱ pointerȱ variable,ȱ thisȱ assignmentȱ looksȱ likeȱ itȱ oughtȱ toȱ performȱ anotherȱ pointerȱ assignment,ȱ copyingȱ theȱ valueȱ ofȱ cȱ intoȱ a.ȱ Butȱ thisȱ assignmentȱ isȱ illegal:ȱ rememberȱ thatȱ theȱ valueȱ ofȱ aȱ inȱ thisȱ expressionȱ isȱ aȱ constant,ȱ soȱ itȱ cannotȱ beȱ changed.ȱ ȱ ȱ ȱ 8.1.2 Subscripts ȱ Inȱtheȱcontextȱofȱtheȱpreviousȱdeclarations,ȱwhatȱisȱtheȱmeaningȱofȱthisȱexpression?ȱ ȱ *( b + 3 ) First,ȱtheȱvalueȱofȱ bȱisȱaȱpointerȱtoȱanȱinteger,ȱsoȱtheȱvalueȱthreeȱisȱscaledȱtoȱtheȱsizeȱofȱ anȱ integer.ȱ Theȱ additionȱ yieldsȱ aȱ pointerȱ toȱ theȱ integerȱ thatȱ isȱ locatedȱ threeȱ integersȱ beyondȱ theȱ firstȱ oneȱ inȱ theȱ array.ȱ Theȱ indirectionȱ thenȱ takesȱ usȱ toȱ thisȱ newȱ location,ȱ eitherȱtoȱgetȱtheȱvalueȱthereȱ(RȬvalue)ȱorȱtoȱstoreȱaȱnewȱoneȱ(LȬvalue).ȱ Ifȱ thisȱ processȱ soundsȱ familiar,ȱ itȱ isȱ becauseȱ aȱ subscriptȱ doesȱ exactlyȱ theȱ sameȱ thing.ȱȱWeȱcanȱnowȱexplainȱaȱstatementȱthatȱwasȱmentionedȱinȱChapterȱ5:ȱexceptȱforȱitsȱ precedence,ȱ aȱ subscriptȱ isȱ exactlyȱ theȱ sameȱ asȱ anȱ indirection.ȱ Forȱ example,ȱ theȱ followingȱexpressionsȱareȱequivalent:ȱ ȱ array[subscript] *( array + ( subscript ) ) ȱ Nowȱthatȱyouȱknowȱthatȱtheȱvalueȱofȱanȱarrayȱnameȱisȱjustȱaȱpointerȱconstant,ȱyouȱcanȱ verifyȱ thisȱ equivalence.ȱ Inȱ theȱ subscriptȱ expression,ȱ theȱ subscriptȱ isȱ evaluatedȱ first.ȱȱ Thenȱtheȱsubscriptȱvalueȱselectsȱaȱspecificȱarrayȱelement.ȱȱInȱtheȱsecondȱexpression,ȱtheȱ innerȱ parenthesesȱ guaranteeȱ thatȱ theȱ subscriptȱ isȱ evaluatedȱ first,ȱ asȱ before.ȱ Usingȱ pointerȱ arithmetic,ȱ theȱ additionȱ producesȱ aȱ pointerȱ toȱ theȱ desiredȱ element.ȱ Theȱ indirectionȱthenȱfollowsȱthatȱpointer,ȱandȱvoila—anȱarrayȱelement.ȱ Whereverȱ aȱ subscriptȱ isȱ used,ȱ theȱ equivalentȱ pointerȱ expressionȱ canȱ alsoȱ beȱ used;ȱ andȱ whereverȱ aȱ pointerȱ expressionȱ ofȱ theȱ formȱ shownȱ aboveȱ isȱ used,ȱ youȱ canȱ alsoȱuseȱaȱsubscript.ȱ Download at http://www.pin5i.com/ 200ȱ Chapter 8 Arrays Hereȱisȱaȱlittleȱexercisesȱtoȱillustrateȱthisȱequivalence.ȱ ȱ int int array[10]; *ap = array + 2; ȱ Rememberȱtheȱscalingȱthatȱisȱperformedȱonȱtheȱaddition:ȱtheȱresultȱisȱthatȱ apȱpointsȱatȱ array[2],ȱlikeȱthis:ȱ ȱ ȱ ȱ ȱ ȱ ȱ arrayȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Forȱ eachȱ ofȱ theȱ followingȱ expressionsȱ involvingȱ ap,ȱ seeȱ ifȱ youȱ canȱ thinkȱ ofȱ anȱ equivalentȱexpressionȱthatȱusesȱarray.ȱ ȱ ap Thisȱoneȱisȱeasy,ȱyouȱcanȱjustȱreadȱtheȱanswerȱfromȱtheȱinitialization:ȱ array + 2.ȱȱTheȱexpressionȱ&array[2]ȱisȱequivalent.ȱ *ap Anotherȱeasyȱone:ȱtheȱindirectionȱfollowsȱtheȱpointerȱtoȱtheȱlocationȱitȱ isȱpointingȱat,ȱwhichȱisȱarray[2].ȱȱYouȱcouldȱalsoȱwrite *(array + 2).ȱ ap[0] ȈYouȱ canȇtȱ doȱ that,ȱ apȱ isnȇtȱ anȱ array!Ȉȱ Ifȱ youȱ thoughtȱ somethingȱ likeȱ this,ȱyouȇreȱstuckȱinȱtheȱȈcanȇtȱdoȱitȱinȱotherȱlanguagesȈȱrut.ȱRemember,ȱ aȱ subscriptȱ inȱ Cȱ isȱ exactlyȱ likeȱ anȱ indirectionȱ expression,ȱ soȱ youȱ canȱ useȱoneȱanywhereȱyouȱcanȱuseȱindirection.ȱInȱthisȱcase,ȱtheȱequivalentȱ expressionȱisȱ *( ap + ( 0 ) )ȱwhich,ȱafterȱgettingȱridȱofȱtheȱzeroȱandȱ theȱ parentheses,ȱ endsȱ upȱ beingȱ identicalȱ toȱ theȱ previousȱ expression.ȱ Thereforeȱitȱhasȱtheȱsameȱanswer:ȱarray [2].ȱ ap + 6 Ifȱapȱpointsȱtoȱarray[2],ȱthisȱadditionȱgivesȱaȱpointerȱtoȱtheȱlocationȱsixȱ integersȱ laterȱ inȱ theȱ array,ȱ whichȱ isȱ equivalentȱ toȱ array + 8ȱ orȱ &array[8].ȱ *ap + 6 Beȱ careful,ȱ thereȱ areȱ twoȱ operatorsȱ here;ȱ whichȱ goesȱ first?ȱ Theȱ indirection.ȱ Theȱ resultȱ ofȱ theȱ indirectionȱ isȱ thenȱ addedȱ toȱ six,ȱ soȱ thisȱ expressionȱisȱtheȱsameȱasȱarray[2] * 6.ȱ *(ap + 6) Theȱparenthesesȱforceȱtheȱadditionȱtoȱgoȱfirst,ȱsoȱthisȱtimeȱweȱgetȱtheȱ valueȱofȱ array[8].ȱObserveȱthatȱtheȱindirectionȱusedȱhereȱisȱinȱexactlyȱ theȱsameȱformȱasȱtheȱindirectionȱofȱaȱsubscript.ȱ Download at http://www.pin5i.com/ 8.1 One-Dimensional Arrays 201 ap[6] Convertȱthisȱsubscriptȱtoȱitsȱindirectionȱform,ȱandȱyouȇllȱseeȱtheȱsameȱ expressionȱweȱjustȱdid,ȱsoȱitȱhasȱtheȱsameȱanswer.ȱ &ap Thisȱexpressionȱisȱperfectlyȱlegal,ȱbutȱthereȱisȱnoȱequivalentȱexpressionȱ involvingȱ arrayȱ becauseȱ youȱ cannotȱ predictȱ whereȱ theȱ compilerȱ willȱ locateȱapȱrelativeȱtoȱarray.ȱ ap[-1] Howȇsȱ thatȱ again,ȱ aȱ negativeȱ subscript?ȱ Aȱ subscriptȱ isȱ justȱ anȱ indirectionȱexpression;ȱconvertȱitȱtoȱthatȱformȱandȱthenȱevaluateȱitȱȱ apȱ pointsȱatȱtheȱthirdȱelementȱ(theȱoneȱwhoseȱsubscriptȱisȱtwo),ȱsoȱusingȱ anȱoffsetȱofȱȬ1ȱgetsȱusȱtheȱpreviousȱelement:ȱarray[1].ȱ ap[9] Thisȱ oneȱ looksȱ fineȱ butȱ isȱ actuallyȱ aȱ problem.ȱ Theȱ equivalentȱ expressionȱ isȱ array[11],ȱ butȱ theȱ problemȱ isȱ thatȱ thereȱ areȱ onlyȱ tenȱ elementsȱ inȱ theȱ array.ȱ Evaluatingȱ theȱ subscriptȱ producesȱ aȱ pointerȱ expressionȱthatȱrunsȱoffȱtheȱendȱofȱtheȱarray,ȱwhichȱmakesȱthisȱillegalȱ accordingȱ toȱ theȱ Standard.ȱ However,ȱ fewȱ compilersȱ detectȱ thisȱ error,ȱ soȱtheȱprogramȱgoesȱmerrilyȱonȱitsȱway.ȱȱButȱwhatȱdoesȱtheȱexpressionȱ do?ȱ Theȱ Standardȱ saysȱ thatȱ itsȱ behaviorȱ isȱ undefined,ȱ butȱ onȱ mostȱ machinesȱ itȱ accessesȱ whateverȱ valueȱ happensȱ toȱ beȱ storedȱ inȱ theȱ secondȱlocationȱbeyondȱtheȱendȱofȱtheȱarray.ȱYouȱcanȱsometimesȱfigureȱ outȱwhatȱthisȱvalueȱisȱbyȱaskingȱtheȱcompilerȱtoȱproduceȱanȱassemblyȱ languageȱversionȱofȱtheȱprogramȱandȱexaminingȱthatȱcode,ȱbutȱthereȱisȱ noȱuniversalȱwayȱtoȱpredictȱwhatȱvalueȱwillȱbeȱstoredȱthere.ȱȱThus,ȱthisȱ expressionȱwillȱaccessȱ(or,ȱifȱusedȱasȱanȱLȬvalue,ȱwillȱchange)ȱtheȱvalueȱ ofȱ someȱ randomȱ variable.ȱ Thisȱ resultȱ isȱ notȱ likelyȱ toȱ beȱ whatȱ youȱ wanted.ȱ ȱ Theȱ lastȱ twoȱ examplesȱ showȱ whyȱ subscriptȱ checkingȱ isȱ aȱ difficultȱ taskȱ inȱ C.ȱ Theȱ Standardȱdoesȱnotȱrequireȱthatȱitȱbeȱdoneȱatȱall;ȱtheȱearliestȱCȱcompilersȱdidnȇtȱcheckȱ subscripts,ȱandȱmostȱcurrentȱonesȱstillȱdonȇt.ȱTheȱfactȱthatȱsubscriptsȱcanȱbeȱappliedȱtoȱ arbitraryȱ pointers,ȱ notȱ justȱ arrayȱ names,ȱ makesȱ theȱ jobȱ difficult.ȱ Theȱ validityȱ ofȱ aȱ subscriptȱappliedȱtoȱaȱpointerȱvariableȱdependsȱonȱwhereȱitȱhappensȱtoȱbeȱpointingȱatȱ theȱtime,ȱasȱwellȱasȱtheȱvalueȱofȱtheȱsubscript.ȱ Consequently,ȱsubscriptȱcheckingȱinȱCȱinvolvesȱmoreȱoverheadȱthanȱyouȱmightȱ firstȱ think.ȱ Instructionsȱmustȱbeȱinsertedȱ intoȱtheȱprogramȱtoȱ verifyȱthatȱtheȱ resultȱofȱ theȱ subscriptȱ refersȱ toȱ anȱ elementȱ inȱ theȱ sameȱ arrayȱ asȱ theȱ pointer.ȱ Thisȱ comparisonȱ requiresȱinformationȱaboutȱtheȱlocationsȱandȱsizesȱofȱallȱarraysȱinȱtheȱprogram,ȱwhichȱ willȱ takeȱ someȱ space.ȱ Theȱ informationȱ mustȱ alsoȱ beȱ updatedȱ asȱ theȱ programȱ runsȱ toȱ reflectȱautomaticȱandȱdynamicallyȱallocatedȱarrays,ȱwhichȱwillȱtakeȱsomeȱtime.ȱThus,ȱ Download at http://www.pin5i.com/ 202ȱ Chapter 8 Arrays compilersȱthatȱofferȱsubscriptȱcheckingȱusuallyȱalsoȱofferȱaȱwayȱtoȱturnȱitȱoff.ȱ Hereȇsȱ anȱ interesting,ȱ thoughȱ admittedlyȱ arcane,ȱ tangent.ȱ Inȱ theȱ contextȱ ofȱ theȱ previousȱdeclarations,ȱwhatȱisȱtheȱmeaningȱofȱthisȱexpression?ȱ ȱ 2[array] ȱ Theȱ answerȱ mayȱ surpriseȱ you:ȱ itȱ isȱ legal.ȱ Convertȱ itȱ toȱ theȱ equivalentȱ indirectionȱ expressionȱandȱyouȱwillȱseeȱitsȱvalidity:ȱ ȱ *( 2 + ( array ) ) ȱ Theȱ innerȱ parenthesesȱ areȱ redundant,ȱ soȱ weȱ canȱ deleteȱ them.ȱ Also,ȱ additionȱ isȱ commutative,ȱsoȱthisȱexpressionȱhasȱexactlyȱtheȱsameȱmeaningȱasȱ ȱ *( array + 2 ) ȱ meaningȱthatȱtheȱoriginal,ȱfunnyȬlookingȱexpressionȱisȱidenticalȱtoȱarray[2].ȱ Thisȱ quirkȱ existsȱ becauseȱ ofȱ theȱ wayȱ thatȱ subscriptsȱ areȱ implementedȱ inȱ C.ȱ Eitherȱ formȱ isȱ fineȱ asȱ farȱ asȱ theȱ compilerȱ isȱ concerned.ȱ However,ȱ youȱ shouldȱ neverȱ writeȱ2[array]:ȱitȱonlyȱmakesȱtheȱprogramȱharderȱforȱothersȱtoȱread.ȱ ȱ ȱ ȱ 8.1.3 Pointers versus Subscripts ȱ Ifȱ youȱ canȱ useȱ indirectionȱ expressionsȱ andȱ subscriptsȱ interchangeably,ȱ whichȱ shouldȱ youȱuse?ȱAsȱusual,ȱthereȱisȱnoȱsimpleȱanswer.ȱSubscriptsȱareȱeasierȱforȱȈmostȱpeopleȱtoȱ understand,ȱespeciallyȱwithȱmultidimensionalȱarrays,ȱsoȱthereȱisȱsomeȱbenefitȱgainedȱ inȱ readabilityȱ byȱ usingȱ them.ȱ Onȱ theȱ otherȱ hand,ȱ thisȱ choiceȱ mayȱ affectȱ runtimeȱ efficiency.ȱ ȱ Assumingȱ thatȱ theyȱ areȱ bothȱ usedȱ correctly,ȱ subscriptsȱ areȱ neverȱ moreȱ efficientȱ thanȱ pointers,ȱbutȱpointersȱareȱsometimesȱmoreȱefficientȱthanȱsubscripts.ȱ ȱ Toȱ understandȱ thisȱ efficiencyȱ issueȱ letȇsȱ examineȱ twoȱ loopsȱ thatȱ performȱ theȱ sameȱwork.ȱȱFirst,ȱweȱclearȱtheȱelementsȱofȱanȱarrayȱusingȱsubscripts.ȱ ȱ int array[10], a; for( a = 0; a < 10; a += 1 ) array[a] = 0; ȱ Toȱevaluateȱthisȱsubscript,ȱtheȱcompilerȱinsertsȱinstructionsȱinȱtheȱprogramȱtoȱtakeȱtheȱ valueȱofȱaȱandȱmultiplyȱitȱbyȱtheȱsizeȱofȱanȱintegerȱ(say,ȱfour).ȱThisȱmultiplicationȱtakesȱ bothȱspaceȱandȱtime.ȱ Download at http://www.pin5i.com/ 8.1 One-Dimensional Arrays ȱ ȱ 203 Nowȱconsiderȱthisȱloop,ȱwhichȱdoesȱexactlyȱtheȱsameȱwork.ȱ ȱ int array[10], *ap; for( ap = array; ap < array + 10; ap++ ) *ap = 0; ȱ Theȱ multiplicationȱ isȱ stillȱ inȱ hereȱ somewhere,ȱ evenȱ thoughȱ thereȱ isȱ noȱ longerȱ anyȱ subscript.ȱLookȱcloselyȱnowȱandȱseeȱifȱyouȱcanȱfindȱit.ȱ Theȱ multiplicationȱ isȱ nowȱ performedȱ inȱ theȱ adjustmentȱ stepȱ ofȱ theȱ forȱ statement;ȱtheȱvalueȱoneȱmustȱbeȱscaledȱtoȱtheȱsizeȱofȱanȱintegerȱbeforeȱitȱisȱaddedȱtoȱ theȱ pointer.ȱ Butȱ thereȱ isȱ aȱ bigȱ differenceȱ here:ȱ theȱ sameȱ twoȱ valuesȱ (1ȱ ×ȱ 4)ȱ areȱ multipliedȱ eachȱ timeȱ throughȱ theȱ loop.ȱ Asȱ aȱ result,ȱ thisȱ multiplicationȱ isȱ performedȱ onceȱ atȱ compileȱ time—theȱ programȱ nowȱ containsȱ anȱ instructionȱ toȱ addȱ fourȱ toȱ theȱ pointer.ȱȱNoȱmultiplicationsȱareȱperformedȱatȱrunȱtime.ȱ Thisȱ exampleȱ illustratesȱ theȱ typeȱ ofȱ situationȱ inȱ whichȱ pointersȱ areȱ moreȱ efficientȱthanȱsubscriptsȱ–ȱwhenȱmovingȱthroughȱanȱarrayȱbyȱoneȱ(orȱanyȱotherȱfixedȱ amount).ȱ Theȱ multiplicationȱ isȱ performedȱ onȱ theȱ fixedȱ amountȱ atȱ compileȱ time,ȱ soȱ thereȱareȱfewerȱinstructionsȱtoȱexecuteȱatȱrunȱtime.ȱOnȱmostȱmachinesȱtheȱprogramȱisȱ smallerȱandȱfaster.ȱ Nowȱconsiderȱtheseȱtwoȱfragmentsȱofȱcode:ȱ ȱ a = get_value(); array[a] = 0; a = get_value(); *( array + a ) = 0; ȱ Thereȱisȱnoȱdifferenceȱinȱtheȱcodeȱgeneratedȱforȱtheseȱstatements.ȱaȱcouldȱbeȱanyȱ value,ȱ soȱ theȱ multiplicationȱ instructionȱ isȱ neededȱ inȱ bothȱ placesȱ toȱ scaleȱ it.ȱ Thisȱ exampleȱillustratesȱtheȱtypeȱofȱsituationȱinȱwhichȱpointersȱandȱsubscriptsȱareȱequallyȱ efficient.ȱ ȱ ȱ ȱ 8.1.4 Pointer Efficiency ȱ Iȱ statedȱ earlierȱ thatȱ pointersȱ areȱ sometimesȱ moreȱ efficientȱ thanȱ subscripts,ȱ assumingȱ thatȱ theyȱ areȱ usedȱ correctly.ȱ Asȱ theyȱ sayȱ onȱ TV,ȱ yourȱ resultsȱ mayȱ vary;ȱ itȱ dependsȱ onȱ yourȱ compilerȱ andȱ machine.ȱ However,ȱ theȱ efficiencyȱ ofȱ yourȱ programȱ dependsȱ primarilyȱonȱtheȱcodeȱyouȱwrite,ȱandȱitȱisȱjustȱasȱeasyȱtoȱwriteȱbadȱcodeȱwithȱpointersȱ asȱitȱisȱwithȱsubscripts.ȱȱInȱfact,ȱitȱisȱprobablyȱeasier.ȱ Toȱ illustrateȱ someȱ badȱ techniquesȱ asȱ wellȱ asȱ goodȱ ones,ȱ letȇsȱ lookȱ atȱ aȱ simpleȱ functionȱthatȱcopiesȱtheȱcontentsȱofȱoneȱarrayȱintoȱaȱsecondȱarrayȱusingȱsubscripts.ȱWeȱ willȱanalyzeȱtheȱassemblyȱcodeȱproducedȱforȱthisȱfunctionȱbyȱoneȱparticularȱcompilerȱ forȱ aȱ computerȱ usingȱ aȱ processorȱ fromȱ theȱ Motorolaȱ M68000ȱ family.ȱ Weȱ willȱ then Download at http://www.pin5i.com/ Chapter 8 Arrays 204ȱ ȱmodifyȱ theȱ functionȱ inȱ variousȱ waysȱ toȱ useȱ pointersȱ andȱ seeȱ whatȱ effectȱ eachȱ modificationȱȱhasȱonȱtheȱresultingȱobjectȱcode.ȱ Beforeȱ beginningȱ theȱ example,ȱ twoȱ cautionsȱ areȱ inȱ order.ȱ First,ȱ theȱ wayȱ youȱ writeȱyourȱprogramȱaffectsȱnotȱonlyȱitsȱruntimeȱefficiencyȱbutȱalsoȱitsȱreadability.ȱItȱisȱ importantȱ notȱ toȱ sacrificeȱ readabilityȱ forȱ negligibleȱ gainsȱ inȱ efficiency.ȱ Moreȱ willȱ beȱ saidȱaboutȱthisȱissueȱlater.ȱ Second,ȱtheȱassemblyȱlanguageȱshownȱisȱobviouslyȱspecificȱtoȱtheȱ68000ȱfamilyȱ ofȱ processors.ȱ Otherȱ machinesȱ (andȱ otherȱ compilers)ȱ mayȱ translateȱ theȱ programsȱ differently.ȱ Ifȱ youȱ needȱ theȱ utmostȱ efficiencyȱ forȱ yourȱ environment,ȱ youȱ canȱ experimentȱasȱIȇveȱdoneȱhereȱtoȱseeȱhowȱvariousȱsourceȱcodeȱidiomsȱareȱimplemented.ȱ First,ȱtheȱfollowingȱdeclarationsȱapplyȱtoȱallȱversionsȱofȱtheȱfunction.ȱ ȱ #define int int int int SIZE x[SIZE]; y[SIZE]; I; *p1, *p2; 50 ȱ Hereȱisȱtheȱsubscriptȱversionȱofȱtheȱfunction.ȱ ȱ void try1() { for( i = 0; i < SIZE; i++ ) x[i] = y[i]; } ȱ Thisȱversionȱisȱprettyȱstraightforward.ȱTheȱcompilerȱproducedȱtheȱfollowingȱassemblyȱ languageȱcode.ȱ ȱ ȱ 00000004 0000000a 0000000c 00000012 00000014 0000001a 00000020 00000022 00000028 0000002e 00000034 00000036 0000003c ȱ 42b90000 6028 20390000 e580 207c0000 22390000 e581 227c0000 23b00800 52b9G00C 7032 b0b90000 6ece 0000 _tryl: 0000 L20001: 0000 0000 0000 1800 0000 L20: 0000 clrl jra movl asll movl movl asll movl movl addql moveq cmpl jgt _i L20 _i,d0 #2,d0 #_y,a0 _i,d1 #2,d1 #_x,a1 a0@(0,d0:L),a1@(0,d1:L) #1,_i #50,d0 _i,d0 L20001 Download at http://www.pin5i.com/ 8.1 One-Dimensional Arrays 205 Letȇsȱ walkȱ throughȱ theseȱ instructions,ȱ oneȱ byȱ one.ȱ First,ȱ theȱ locationȱ containingȱ theȱ variableȱ iȱisȱcleared,ȱwhichȱimplementsȱtheȱassignmentȱtoȱzero.ȱThenȱexecutionȱjumpsȱ toȱtheȱinstructionȱlabeledȱ L20,ȱwhich,ȱwithȱtheȱfollowingȱinstruction,ȱtestsȱwhetherȱ iȱisȱ lessȱthanȱ50.ȱIfȱitȱis,ȱexecutionȱjumpsȱbackȱupȱtoȱtheȱinstructionȱlabeledȱL20001.ȱ Theȱ instructionȱ labeledȱ L20001ȱ beginsȱ theȱ bodyȱ ofȱ theȱ loop. iȱ isȱ copiedȱ toȱ registerȱd0ȱwhereȱitȱisȱshiftedȱleftȱbyȱtwoȱbits.ȱȱTheȱshiftȱisȱusedȱbecauseȱitȱproducesȱtheȱ sameȱresultȱasȱaȱmultiplicationȱbyȱfourȱbutȱisȱfaster.ȱȱTheȱaddressȱofȱtheȱarrayȱ yȱisȱthenȱ copiedȱtoȱaddressȱregisterȱa0.ȱ Nowȱ theȱ sameȱ calculationȱ thatȱ wasȱ previouslyȱ performedȱ onȱ iȱ isȱ doneȱ again,ȱ butȱthisȱtimeȱtheȱresultȱisȱputȱinȱregisterȱ d1.ȱThenȱtheȱaddressȱofȱtheȱarrayȱ xȱisȱputȱintoȱ addressȱregisterȱa1.ȱ Theȱ movlȱ instructionȱ withȱ theȱ complicatedȱ operandsȱ isȱ whatȱ reallyȱ doesȱ theȱ work:ȱtheȱvalueȱthatȱ a0 + d0ȱpointsȱatȱisȱcopiedȱtoȱtheȱlocationȱthatȱ a1 + d1ȱpointsȱat.ȱ Thenȱiȱisȱincremented,ȱandȱcomparedȱtoȱ50ȱtoȱseeȱifȱtheȱloopȱshouldȱrepeat.ȱ ȱ Doesȱitȱseemȱsillyȱthatȱtheȱcompilerȱevaluatesȱtheȱexpressionȱ i * 4ȱtwice,ȱwhenȱ iȱhasȱ notȱ changedȱ betweenȱ theȱ expressions?ȱ Well,ȱ thisȱ compilerȱ isȱ fairlyȱ old,ȱ andȱ itsȱ optimizerȱisnȇtȱveryȱsmart.ȱModernȱcompilersȱmayȱdoȱaȱbetterȱjob,ȱbutȱmaybeȱnot.ȱItȱisȱ betterȱtoȱwriteȱgoodȱsourceȱcodeȱinȱtheȱfirstȱplaceȱthanȱtoȱdependȱonȱtheȱcompilerȱtoȱ produceȱefficientȱobjectȱcodeȱfromȱbadȱsourceȱcode.ȱRemember,ȱthough,ȱthatȱefficiencyȱ isȱnotȱtheȱonlyȱfactor;ȱusuallyȱtheȱclarityȱofȱtheȱcodeȱisȱmoreȱimportant.ȱ ȱ ȱ ȱ Switching to Pointers ȱ Nowȱletȇsȱrewriteȱtheȱfunctionȱwithȱpointers.ȱ ȱ void try2() { for( p1 = x, p2 = y; p1 – x < SIZE; ) *p1++ = *p2++; } ȱ Iȇveȱ replacedȱ theȱ subscriptsȱ withȱ pointerȱ variables.ȱ Oneȱ ofȱ theȱ pointersȱ isȱ testedȱ toȱ determineȱwhenȱtoȱexitȱtheȱloop,ȱsoȱtheȱcounterȱisȱnoȱlongerȱneeded.ȱ ȱ 00000046 00000050 0000005a 23fc0000 0000 23fc0000 0000 601a 00000000 00000000 _try2: movl #_x,_p1 movl #_y,_p2 jra L25 Download at http://www.pin5i.com/ 206ȱ Chapter 8 Arrays 0000005c 00000062 00000068 0000006a 00000070 00000076 00000078 0000007a 00000080 00000086 00000088 0000008e 00000090 00000092 00000094 20790000 22790000 2290 58b90000 58b90000 7004 2f00 20390000 04800000 2f00 4eb90000 508f 7232 b280 6ec6 0000 0000 L20003: 0000 0000 L2 S: 0000 0000 0000 movl movl movl addql addql moveg movl movl subl movl jbsr addql moveq cmpl jgt _p2,a0 _p1,a1 a0@,a1@ #4,_p2 #4,_p1 #4,d0 d0,sp@_p1,d0 #_x,d0 d0,sp@ldiv #8,sp #50,d1 d0,d1 L20003 ȱ Theseȱchangesȱdoȱnotȱgiveȱmuchȱofȱanȱimprovementȱoverȱtheȱfirstȱversion.ȱTheȱcodeȱ neededȱ toȱ copyȱ anȱ integerȱ andȱ incrementȱ theȱ pointersȱ hasȱ decreased,ȱ butȱ theȱ initializationȱ codeȱ hasȱ increased.ȱ Theȱ shiftsȱ toȱ scaleȱ theȱ subscriptȱ areȱ gone,ȱ andȱ theȱ movlȱinstructionȱthatȱdoesȱtheȱrealȱworkȱnoȱlongerȱusesȱindexing.ȱButȱtheȱcodeȱtoȱcheckȱ forȱ theȱ endȱ ofȱ theȱ loopȱ hasȱ increasedȱ aȱ lot,ȱ becauseȱ theȱ subtractionȱ ofȱ twoȱ pointersȱ mustȱbeȱscaledȱ(inȱthisȱcase,ȱdividedȱbyȱ4).ȱTheȱdivisionȱisȱperformedȱbyȱpushingȱtheȱ valuesȱonȱtheȱstackȱandȱcallingȱaȱsubroutineȱnamedȱ ldiv.ȱȱIfȱthisȱmachineȱhadȱaȱ32Ȭbitȱ divideȱinstruction,ȱtheȱdivisionȱmightȱhaveȱbeenȱdoneȱmoreȱefficiently.ȱ ȱ ȱ ȱ Bringing Back the Counter ȱ Letȇsȱtryȱanotherȱapproachȱ ȱ void try3() { for( i = 0, p1 = x, p2 = y; i < SIZE; i++ ) *p1++ = *p2++; } ȱ Iȇveȱ usedȱ theȱ counterȱ againȱ toȱ controlȱ whenȱ theȱ loopȱ shouldȱ exitȱ toȱ getȱ ridȱ ofȱ theȱ pointerȱsubtractionȱandȱtheȱresultingȱlongȱsequenceȱofȱcode.ȱ ȱ 0000009e 000000a4 000000ae 000000b8 42b90000 0000 23fc0000 0000 00000000 23fc0000 00000000 0000 6020 _try3: clrl movl movl _i #_x,_p1 #_y,_p2 jra L30 Download at http://www.pin5i.com/ 8.1 One-Dimensional Arrays 000000ba 000000c0 000000c6 000000c8 000000ce 000000d4 000000da 000000dc 000000e2 20790000 22790000 2290 58b90000 58b90000 52b90000 7032 b0b90000 5ed6 0000 0000 L20005: 0000 0000 0000 L30: 0000 movl movl movl addql addql addql moveq cmpl jgt 207 _p2,a0 _p1,a1 a0@,a1@ #4,_p2 #4,_p1 #l,_i #50,d0 _i,d0 L20005 ȱ Thisȱversionȱhasȱtheȱshorterȱcodeȱtoȱcopyȱtheȱintegerȱandȱincrementȱtheȱpointers,ȱandȱ toȱ controlȱ whenȱ theȱ loopȱ breaks.ȱ Butȱ weȇreȱ stillȱ copyingȱ theȱ pointerȱ variablesȱ intoȱ addressȱregistersȱbeforeȱtheȱindirection.ȱ ȱ ȱ ȱ Register Pointer Variables ȱ Weȱ canȱ eliminateȱ copyingȱ theȱ pointerȱ valuesȱ byȱ usingȱ registerȱ variablesȱ forȱ theȱ pointers.ȱHowever,ȱtheyȱmustȱbeȱdeclaredȱasȱlocalȱvariables.ȱ ȱ void try4() { register int *p1, *p2; register int i; for( i = 0, p1 = x, p2 = y; i < SIZE; i++ ) *p1++ = *p2++; } ȱ Thisȱchangeȱimprovesȱmoreȱthanȱjustȱeliminatingȱtheȱcopyingȱofȱtheȱpointers.ȱ ȱ 000000f0 000000f2 000000f8 000000fe 00000100 00000102 00000104 00000106 00000108 7e00 2a7c0000 287c0000 6004 2adc 5287 7032 b087 6ef6 _try4: 0000 0000 L20007: L35: moveq movl movl jra movl addql moveq cmpl jgt #0,d7 #,x,a5 #_y,a4 L35 a4@+,a5@+ #1,37 #50,dO d7,d0 L200O7 ȱ Noteȱthatȱtheȱpointerȱvariableȱexistȱinȱregistersȱa4ȱandȱa5ȱfromȱtheȱstart.ȱWeȱcanȱ incrementȱthemȱdirectlyȱwithȱtheȱhardwareȇsȱautoincrementȱaddressingȱmodeȱ(whichȱ Download at http://www.pin5i.com/ 208ȱ Chapter 8 Arrays behavesȱ veryȱ muchȱ likeȱ theȱ Cȱ postfixȱ ++ȱ operator).ȱ Theȱ initializationȱ andȱ loopȱ terminationȱcodeȱis,ȱforȱtheȱmostȱpart,ȱunchanged.ȱThisȱcodeȱisȱlookingȱbetter.ȱ ȱ ȱ ȱ Eliminating the Counter ȱ Ifȱweȱcanȱfindȱaȱwayȱtoȱterminateȱtheȱloopȱwithoutȱusingȱtheȱpointerȱsubtractionȱthatȱ causedȱtroubleȱearlier,ȱweȱcanȱeliminateȱtheȱcounter.ȱ ȱ void try5() { register int *p1, *p2; for( p1 = x, p2 = y, p1 < &x[SIZE]; ) *p1++ = *p2++; } ȱ Insteadȱofȱtheȱsubtractionȱtoȱseeȱnowȱmanyȱelementsȱweȇveȱcopied,ȱthisȱloopȱchecksȱtoȱ seeȱwhetherȱtheȱpointerȱ p1ȱhasȱreachedȱtheȱendȱofȱtheȱsourceȱarray.ȱFunctionallyȱthisȱ testȱisȱjustȱasȱgood,ȱbutȱitȱshouldȱbeȱmoreȱefficientȱbecauseȱitȱdoesȱnotȱdoȱaȱsubtraction.ȱ Furthermore,ȱtheȱexpressionȱ &x[SIZE]ȱcanȱbeȱevaluatedȱatȱcompileȱtime,ȱbecauseȱ SIZEȱ isȱaȱliteralȱconstant.ȱHereȱisȱtheȱresult.ȱ ȱ 0000011c 00000122 00000128 0000012a 0000012c 00000132 2a7c0000 287c0000 6002 2adc bbfc0000 65f6 0000 0000 00c8 _try5: L20009: L40; movl movl jra movl cmpl jcs #_x,a5 #_y,a4 L40 a4@+,a5@+ #_x+200,a5 L20009 ȱ Thisȱ codeȱ isȱ compactȱ andȱ fastȱ andȱ rivalsȱ whatȱ anȱ assemblyȱ languageȱ programmerȱ wouldȱ haveȱ produced.ȱ Theȱ counterȱ andȱ itsȱ associatedȱ instructionsȱ areȱ gone.ȱ Theȱ comparisonȱ instructionȱ containsȱ theȱ expressionȱ _x+200,ȱ whichȱ isȱ theȱ expressionȱ &x[SIZE].ȱThisȱcomputationȱwasȱdoneȱatȱcompileȱtimeȱbecauseȱ SIZEȱisȱaȱconstant.ȱThisȱ codeȱisȱaboutȱasȱtightȱasȱweȱcanȱgetȱonȱthisȱmachine.ȱ ȱ ȱ ȱ Conclusions ȱ Whatȱcanȱweȱlearnȱfromȱtheseȱexperiments?ȱ 1. Pointerȱ variablesȱ canȱ resultȱ inȱ moreȱ efficientȱ codeȱ thanȱ subscriptsȱ whenȱ youȱ areȱ movingȱ throughȱ anȱ arrayȱ byȱ someȱ fixedȱ increment.ȱ Thisȱ pointȱ isȱ especiallyȱ true Download at http://www.pin5i.com/ 8.1 One-Dimensional Arrays 209 whenȱ ȱ theȱ incrementȱ isȱ oneȱ andȱ theȱ machineȱ hasȱ anȱ autoincrementȱ addressingȱ mode.ȱ 2. Pointersȱ declaredȱ asȱ registerȱ variablesȱ areȱ oftenȱ moreȱ efficientȱ thanȱ pointersȱ inȱ staticȱ memoryȱ orȱ onȱ theȱ stackȱ (theȱ amountȱ ofȱ improvementȱ dependsȱ onȱ theȱ particularȱmachineȱyouȇreȱworkingȱwith).ȱ 3. Ifȱ youȱ canȱ checkȱ forȱ loopȱ terminationȱ byȱ testingȱ somethingȱ thatȱ isȱ alreadyȱ beingȱ initializedȱandȱadjustedȱforȱtheȱloop,ȱthenȱyouȱdonȇtȱneedȱaȱseparateȱcounter.ȱ 4. Expressionsȱthatȱmustȱbeȱevaluatedȱatȱrunȱtimeȱareȱmoreȱexpensiveȱthanȱconstantȱ expressionsȱsuchȱasȱ&array[SIZE]ȱor array + SIZE.ȱ ȱ TIP Theȱ previousȱ examplesȱ mustȱ nowȱ beȱ putȱ intoȱ perspective.ȱ Isȱ itȱ worthȱ replacingȱ theȱ firstȱloop,ȱwhichȱisȱeasilyȱunderstood,ȱwithȱtheȱlastȱone,ȱwhichȱoneȱreaderȱcalledȱȈotterȱ gibberish,Ȉȱjustȱtoȱsaveȱaȱfewȱdozenȱmicrosecondsȱofȱexecutionȱtime?ȱOccasionallyȱyes,ȱ butȱinȱmostȱcasesȱtheȱanswerȱisȱdefinitelyȱnot!ȱTheȱcostȱofȱgainingȱruntimeȱefficiencyȱinȱ thisȱ wayȱ isȱ toȱ makeȱ theȱ programȱ moreȱ difficultȱ toȱ writeȱ inȱ theȱ firstȱ placeȱ andȱ moreȱ difficultȱ toȱ maintainȱ later.ȱ Ifȱ theȱ programȱ doesnȇtȱ workȱ orȱ cannotȱ beȱ maintained,ȱ itsȱ executionȱspeedȱisȱirrelevant.ȱ ItȱisȱeasyȱtoȱargueȱthatȱexperiencedȱCȱprogrammersȱwillȱhaveȱlittleȱtroubleȱwithȱ theȱ pointerȱ loop,ȱ butȱ thereȱ areȱ twoȱ fallaciesȱ toȱ thisȱ argument.ȱ First,ȱ Ȉlittleȱ troubleȈȱ actuallyȱ meansȱ Ȉsomeȱ trouble.Ȉȱ Usingȱ complexȱ idiomsȱ naturallyȱ involvesȱ moreȱ riskȱ thanȱusingȱsimpleȱones.ȱSecond,ȱtheȱmaintenanceȱprogrammersȱwhoȱworkȱonȱtheȱcodeȱ laterȱmayȱnotȱbeȱasȱexperiencedȱasȱyouȱare.ȱProgramȱmaintenanceȱisȱtheȱmajorȱcostȱofȱaȱ softwareȱ product,ȱ soȱ programmingȱ techniquesȱ thatȱ makeȱ maintenanceȱ moreȱ difficultȱ mustȱbeȱusedȱwithȱcare.ȱ Also,ȱ someȱ machinesȱ areȱ designedȱ withȱ specificȱ instructionsȱ toȱ performȱ arrayȱ subscripting,ȱwithȱtheȱintentȱofȱmakingȱthisȱcommonȱoperationȱveryȱfast.ȱAȱcompilerȱ forȱ suchȱ aȱ machineȱ willȱ implementȱ subscriptȱ expressionsȱ withȱ theseȱ specializedȱ instructionsȱ butȱ mayȱ notȱ useȱ themȱ toȱ implementȱ pointerȱ expressions,ȱ evenȱ thoughȱ itȱ should.ȱ Onȱ suchȱ aȱ machine,ȱ then,ȱ aȱ subscriptȱ mayȱ indeedȱ beȱ moreȱ efficientȱ thanȱ aȱ pointer.ȱ Thenȱwhatȱisȱtheȱpointȱofȱtheseȱexperimentsȱwithȱefficiency?ȱYouȱmayȱhaveȱtoȱ readȱsomeȱȇȈgibberishȈȱthatȱsomeoneȱelseȱwrote,ȱsoȱitȱisȱimportantȱthatȱyouȱunderstandȱ it.ȱ Butȱ thereȱ areȱ alsoȱ aȱ fewȱ placesȱ whereȱ peakȱ efficiencyȱ isȱ vital,ȱ suchȱ asȱ realȬtimeȱ programsȱthatȱmustȱrespondȱquicklyȱtoȱeventsȱasȱtheyȱoccur.ȱButȱanyȱprogramȱthatȱisȱ tooȱslowȱcanȱbenefitȱfromȱtheseȱtechniques.ȱTheȱkeyȱisȱtoȱidentifyȱtheȱsectionsȱofȱcodeȱ thatȱ areȱ takingȱ theȱ mostȱ timeȱ andȱ concentrateȱ yourȱ energiesȱ onȱ improvingȱ them,ȱ forȱ thatȱ isȱ howȱ youȱ achieveȱ theȱ biggestȱ gainsȱ forȱ yourȱ effort.ȱ Techniquesȱ forȱ identifyingȱ theseȱsectionsȱofȱcodeȱareȱdiscussedȱinȱChapterȱ18.ȱ Download at http://www.pin5i.com/ Chapter 8 Arrays 210ȱ 8.1.5 Arrays and Pointers ȱ Pointersȱ andȱ arraysȱ areȱ notȱ equivalent.ȱ Toȱ illustrateȱ thisȱ idea,ȱ considerȱ theseȱ declarations:ȱ ȱ ȱ ȱ int a[5]; int *b; ȱ Canȱ aȱ andȱ bȱ beȱ usedȱ interchangeably?ȱ Bothȱ haveȱ pointerȱ values,ȱ andȱ youȱ canȱ useȱ indirectionȱandȱsubscriptsȱonȱeitherȱone.ȱTheyȱare,ȱnevertheless,ȱquiteȱdifferent.ȱ Declaringȱ anȱ arrayȱ setsȱ asideȱ spaceȱ inȱ memoryȱ forȱ theȱ indicatedȱ numberȱ ofȱ elements,ȱandȱthenȱcreatesȱtheȱarrayȱnameȱwhoseȱvalueȱisȱaȱconstantȱthatȱpointsȱtoȱtheȱ beginningȱ ofȱ thisȱ space.ȱ Declaringȱ aȱ pointerȱ variableȱ reservesȱ spaceȱ forȱ theȱ pointerȱ itself,ȱbutȱthatȱisȱall.ȱSpaceȱisȱnotȱallocatedȱforȱanyȱintegers.ȱFurthermore,ȱtheȱpointerȱ variableȱisȱnotȱinitializedȱtoȱpointȱtoȱanyȱexistingȱspace.ȱȱIfȱitȱisȱanȱautomaticȱvariableȱitȱ isȱnotȱinitializedȱatȱall.ȱȱTheseȱtwoȱdeclarationsȱlookȱveryȱdifferentȱwhenȱdiagrammed.ȱ ȱ aȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ bȱ ȱ ȱ Thus,ȱ afterȱ theȱ declarationsȱ theȱ expressionȱ *aȱ isȱ perfectlyȱ legal,ȱ butȱ theȱ expressionȱ *bȱ isȱ not.ȱ *bȱ willȱ accessȱ someȱ indeterminateȱ locationȱ inȱ memoryȱ orȱ causeȱ theȱprogramȱtoȱterminate.ȱOnȱtheȱotherȱhand,ȱtheȱexpressionȱ b++ȱwillȱcompile,ȱbutȱ a++ȱ willȱnotȱbecauseȱtheȱvalueȱofȱaȱisȱaȱconstant.ȱ Itȱ isȱ importantȱ thatȱ youȱ understandȱ thisȱ distinctionȱ clearly,ȱ becauseȱ theȱ nextȱ topicȱmayȱmuddyȱtheȱwaters.ȱ ȱ ȱ ȱ 8.1.6 Array Names as Function Arguments ȱ Whatȱhappensȱwhenȱanȱarrayȱnameȱisȱpassedȱasȱanȱargumentȱtoȱaȱfunction?ȱYouȱnowȱ knowȱthatȱtheȱvalueȱofȱanȱarrayȱnameȱisȱaȱpointerȱtoȱtheȱfirstȱelementȱofȱtheȱarray,ȱsoȱitȱ makesȱ senseȱ thatȱ aȱ copyȱ ofȱ thisȱ pointerȱ valueȱ isȱ passedȱ toȱ theȱ function.ȱ Aȱ subscriptȱ usedȱ inȱ theȱ functionȱ willȱ performȱ indirectionȱ onȱ thisȱ pointer,ȱ andȱ itȱ isȱ throughȱ thisȱ indirectionȱthatȱtheȱfunctionȱcanȱaccessȱorȱmodifyȱtheȱelementsȱofȱtheȱcallingȱprogramȇsȱ array.ȱ Nowȱ Iȱ canȱ explainȱ theȱ apparentȱ contradictionȱ aboutȱ argumentȱ passingȱ inȱ C.ȱ Iȱ statedȱ earlierȱ thatȱ allȱ argumentsȱ toȱ functionsȱ areȱ passedȱ byȱ valueȱ butȱ thatȱ arrays Download at http://www.pin5i.com/ 8.1 One-Dimensional Arrays 211 behaveȱasȱthoughȱtheyȱwereȱpassedȱbyȱreference.ȱCallȱbyȱreferenceȱisȱimplementedȱbyȱ passingȱaȱpointerȱtoȱtheȱdesiredȱargumentȱandȱthenȱusingȱindirectionȱinȱtheȱfunctionȱtoȱ accessȱ theȱ dataȱ throughȱ theȱ pointer.ȱ Theȱ arrayȱ nameȱ isȱ aȱ pointer,ȱ andȱ subscriptsȱ performȱindirection.ȱ Soȱ whereȱ isȱ theȱ callȬbyȬvalueȱ behaviorȱ withȱ arrays?ȱ Theȱ functionȱ isȱ passedȱ aȱ copyȱ ofȱ theȱ argumentȱ (aȱ copyȱ ofȱ theȱ pointerȱ toȱ theȱ beginningȱ ofȱ theȱ array)ȱ soȱ theȱ functionȱ isȱ freeȱ toȱ manipulateȱ itsȱ pointerȱ parameterȱ withoutȱ fearȱ ofȱ modifyingȱ theȱ correspondingȱargumentȇsȱvalue.ȱ Soȱ thereȱ isȱ noȱ contradictionȱ afterȱ all:ȱ allȱ argumentsȱ areȱ passedȱ byȱ value.ȱ Ofȱ course,ȱwhenȱyouȱpassȱaȱpointerȱtoȱaȱvariableȱandȱtheȱfunctionȱusesȱindirectionȱonȱtheȱ pointer,ȱ theȱ functionȱ canȱ modifyȱ theȱ variable.ȱ Thoughȱ itȱ wasȱ notȱ obviousȱ atȱ firstȱ glance,ȱ thisȱ processȱ occursȱ withȱ arrayȱ nameȱ arguments.ȱ Theȱ argument,ȱ aȱ pointer,ȱ isȱ actuallyȱ passedȱ byȱ value,ȱ andȱ theȱ functionȱ getsȱ aȱ copyȱ ofȱ theȱ pointer,ȱ whichȱ canȱ beȱ modifiedȱwithoutȱfearȱofȱchangingȱtheȱcallerȇsȱargument.ȱ Programȱ8.1ȱisȱaȱsimpleȱfunctionȱthatȱillustratesȱtheseȱpoints.ȱItȱcopiesȱtheȱstringȱ containedȱ inȱ theȱ secondȱ argumentȱ toȱ theȱ bufferȱ toȱ whichȱ theȱ firstȱ argumentȱ points.ȱȱ Theȱ callerȇsȱ bufferȱ isȱ modifiedȱ becauseȱ ofȱ theȱ indirection,ȱ yetȱ theȱ argumentsȱ (theȱ pointers)ȱareȱmodifiedȱwithoutȱchangingȱtheȱcallerȇsȱpointerȱarguments.ȱ Noteȱtheȱexpressionȱ*string++ȱinȱtheȱwhileȱstatement.ȱItȱfetchesȱtheȱcharacterȱtoȱ whichȱ stringȱ pointsȱ and,ȱ asȱ aȱ sideȱ effect,ȱ modifiesȱ stringȱ toȱ pointȱ toȱ theȱ nextȱ character.ȱ Changingȱ theȱ parameterȱ inȱ thisȱ wayȱ doesȱ notȱ affectȱ theȱ argumentȱ inȱ theȱ callingȱprogram,ȱbecauseȱonlyȱtheȱfunctionȇsȱcopyȱisȱchanged.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Copy the string contained in the second argument to the ** buffer specified by the first argument. */ void strcpy( char *buffer, char const *string ) { /* ** Copy characters until a NUL byte is copied. */ while( (*buffer++ = *string++) != '\0' ) ; } ȱ Programȱ8.1ȱȱStringȱcopyȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱstrcpy.cȱ Download at http://www.pin5i.com/ 212ȱ TIP TIP Chapter 8 Arrays Thereȱ areȱ twoȱ otherȱ pointsȱ aboutȱ thisȱ functionȱ thatȱ areȱ worthȱ mentioningȱ (orȱ reiterating).ȱ First,ȱ theȱ parameterȱ isȱ declaredȱ asȱ aȱ pointerȱ toȱ constȱ characters.ȱ Whyȱ isȱ thisȱdeclarationȱimportantȱforȱaȱfunctionȱthatȱisȱnotȱgoingȱtoȱmodifyȱtheȱcharactersȱinȱ theȱ firstȱ place?ȱ Thereȱ areȱ atȱ leastȱ threeȱ reasons.ȱ First,ȱ itȱ isȱ goodȱ documentation.ȱ Someoneȱwishingȱtoȱuseȱthisȱfunctionȱcanȱseeȱfromȱtheȱprototypeȱthatȱtheȱdataȱwillȱnotȱ beȱ changed,ȱ withoutȱ readingȱ theȱ codeȱ (whichȱ mightȱ notȱ beȱ available).ȱ Second,ȱ theȱ compilerȱ willȱ beȱ ableȱ toȱ catchȱ anyȱ programmingȱ errorȱ thatȱ causesȱ accidentalȱ modification.ȱ Lastly,ȱ theȱ declarationȱ allowsȱ constȱ argumentsȱ toȱ beȱ passedȱ toȱ theȱ function.ȱ ȱ Theȱ secondȱ pointȱ toȱ beȱ madeȱ aboutȱ thisȱ functionȱ isȱ theȱ declarationȱ ofȱ theȱ argumentȱ andȱ theȱ localȱ variableȱ asȱ registerȱ variables.ȱ Onȱ manyȱ machinesȱ registerȱ variablesȱ willȱ resultȱ inȱ codeȱ thatȱ executesȱ fasterȱ thanȱ ifȱ theyȱ wereȱ inȱ staticȱ memoryȱ orȱ onȱ theȱ stack,ȱ asȱ illustratedȱ earlierȱ withȱ theȱ arrayȱ copyȱ functions.ȱ Runtimeȱ efficiencyȱ isȱ especiallyȱimportantȱwithȱaȱfunctionȱsuchȱasȱthisȱone,ȱwhichȱisȱlikelyȱtoȱbeȱcalledȱquiteȱ oftenȱbecauseȱitȱperformsȱsuchȱaȱusefulȱtask.ȱ However,ȱ itȱ dependsȱ onȱ yourȱ environmentȱ whetherȱ usingȱ registerȱ variablesȱ willȱresultȱinȱanȱimprovement.ȱManyȱcurrentȱcompilersȱcanȱdoȱaȱbetterȱjobȱofȱregisterȱ allocationȱ thanȱ theȱ programmer.ȱ ȱ Withȱ suchȱ aȱ compiler,ȱ usingȱ registerȱ declarationsȱ canȱactuallyȱcauseȱaȱdecreaseȱinȱefficiency.ȱCheckȱtheȱdocumentationȱthatȱcomesȱwithȱ yourȱcompilerȱtoȱseeȱifȱitȱperformsȱitsȱownȱregisterȱallocation.ȱ ȱ ȱ ȱ 8.1.7 Declaring Array Parameters ȱ Hereȱ isȱ anȱ interestingȱ question.ȱ Whatȱ isȱ theȱ correctȱ wayȱ toȱ declareȱ aȱ functionȱ parameterȱifȱyouȱintendȱtoȱpassȱitȱanȱarrayȱnameȱargument?ȱIsȱitȱdeclaredȱasȱaȱpointer,ȱ orȱasȱanȱarray?ȱ Asȱ youȱ haveȱ seen,ȱ aȱ pointerȱ isȱ actuallyȱ passed,ȱ soȱ theȱ functionȱ parameterȱ isȱ reallyȱ aȱ pointer.ȱ Butȱ toȱ makeȱ thingsȱ aȱ littleȱ easierȱ forȱ theȱ noviceȱ programmer,ȱ theȱ compilerȱ willȱ alsoȱ acceptȱ anȱ arrayȱ declarationȱ forȱ aȱ functionȱ parameter.ȱ Thus,ȱ theȱ followingȱfunctionȱprototypesȱareȱequivalent:ȱ ȱ int int strlen( char *string ); strlen( char string[] ); ȱ Thisȱ equivalenceȱ impliesȱ thatȱ aȱ pointerȱ andȱ anȱ arrayȱ nameȱ areȱ reallyȱ identicalȱ afterȱallȱbutȱdonȇtȱbeȱfooled—theseȱtwoȱdeclarationsȱareȱequivalentȱinȱthisȱcontextȱonly!ȱ Everywhereȱ elseȱ theyȱ areȱ quiteȱ different,ȱ asȱ discussedȱ earlier.ȱ Butȱ forȱ arrayȱ parameters,ȱyouȱmayȱuseȱeitherȱdeclaration.ȱ Download at http://www.pin5i.com/ 8.1 One-Dimensional Arrays 213 Youȱ canȱ useȱ eitherȱ declaration,ȱ butȱ whichȱ isȱ Ȉmoreȱ correct?Ȉȱ Theȱ pointer.ȱ Theȱ argumentȱ isȱ reallyȱ aȱ pointer,ȱ notȱ theȱ array.ȱ Also,ȱ theȱ expressionȱ sizeof stringȱ willȱ produceȱtheȱsizeȱofȱaȱpointerȱtoȱaȱcharacter,ȱnotȱtheȱsizeȱofȱtheȱarray.ȱ Itȱ shouldȱ nowȱ beȱ clearȱ whyȱ aȱ parameterȱ forȱ aȱ oneȬdimensionalȱ arrayȱ inȱ aȱ functionȱ prototypeȱ doesȱ notȱ needȱ aȱ dimension—spaceȱ isȱ notȱ beingȱ allocatedȱ forȱ theȱ arrayȱinȱtheȱfunction;ȱtheȱparameterȱisȱsimplyȱaȱpointerȱtoȱspaceȱthatȱwasȱ previouslyȱ allocatedȱ elsewhere.ȱ Thisȱ factȱ explainsȱ whyȱ anȱ arrayȱ parameterȱ isȱ compatibleȱ withȱ arraysȱ ofȱ anyȱ size—allȱ thatȱ isȱ passedȱ isȱ aȱ pointerȱ toȱ theȱ firstȱ element.ȱ Onȱ theȱ otherȱ hand,ȱthisȱimplementationȱmakesȱitȱimpossibleȱforȱtheȱfunctionȱtoȱdetermineȱtheȱsizeȱ ofȱtheȱarray.ȱȱIfȱtheȱarrayȱsizeȱisȱneededȱinȱtheȱfunction,ȱitȱmustȱbeȱpassedȱasȱanȱexplicitȱ argument.ȱ ȱ ȱ ȱ 8.1.8 Initialization ȱ Justȱ asȱ scalarȱ variablesȱ canȱ beȱ initializedȱ inȱ theirȱ declarations,ȱ soȱ tooȱ canȱ arrays.ȱ Theȱ onlyȱ differenceȱ isȱ thatȱ aȱ seriesȱ ofȱ valuesȱ isȱ neededȱ toȱ initializeȱ anȱ array.ȱ Aȱ seriesȱ isȱ easilyȱspecified:ȱtheȱvaluesȱareȱwrittenȱasȱaȱcommaȬseparatedȱlistȱenclosedȱinȱbraces,ȱasȱ inȱthisȱexample:ȱ ȱ int vector[5] = ( 10, 20, 30, 40, 50 ); ȱ Theȱvaluesȱgivenȱinȱtheȱinitializerȱlistȱareȱassignedȱtoȱtheȱelementsȱofȱtheȱarrayȱoneȱbyȱ one,ȱsoȱvector[0]ȱgetsȱtheȱvalueȱ10,ȱvector[1]ȱgetsȱtheȱvalueȱ20,ȱandȱsoȱforth.ȱ ȱ ȱ ȱ Static and Automatic Initialization ȱ Theȱ wayȱ arrayȱ initializationȱ takesȱ placeȱ isȱ analogousȱ toȱ theȱ wayȱ scalarsȱ areȱ initialized—itȱ dependsȱ uponȱ theirȱ storageȱ class.ȱ Arraysȱ storedȱ inȱ staticȱ memoryȱ areȱ initializedȱonce,ȱbeforeȱtheȱprogramȱbeginsȱtoȱexecute.ȱNoȱinstructionsȱareȱexecutedȱtoȱ putȱ theȱ valuesȱ inȱ theȱ properȱ places,ȱ theyȱ justȱ startȱ outȱ there.ȱ Thisȱ magicȱ isȱ accomplishedȱbyȱhavingȱtheȱlinkerȱinitializeȱtheȱarrayȱelementsȱtoȱtheirȱproperȱvaluesȱ inȱtheȱfileȱcontainingȱtheȱexecutableȱprogram.ȱIfȱtheȱarrayȱwasȱnotȱinitialized,ȱtheȱinitialȱ valuesȱwillȱbeȱzero.ȱWhenȱthisȱfileȱisȱloadedȱintoȱmemoryȱforȱexecution,ȱtheȱinitializedȱ arrayȱ valuesȱ areȱ loadedȱ inȱ exactlyȱ theȱ sameȱ wayȱ asȱ theȱ programȱ instructions.ȱ Thusȱ whenȱexecutionȱbegins,ȱstaticȱarraysȱareȱalreadyȱinitialized.ȱ Theȱ situationȱ isȱ notȱ asȱ rosyȱ withȱ automaticȱ variables,ȱ however.ȱ Becauseȱ theyȱ resideȱonȱtheȱruntimeȱstack,ȱautomaticȱvariablesȱmayȱuseȱdifferentȱmemoryȱlocationsȱ eachȱtimeȱtheȱblockȱinȱwhichȱtheyȱareȱdeclaredȱisȱentered.ȱȱThereȱisnȇtȱanyȱwayȱthatȱtheȱ Download at http://www.pin5i.com/ Chapter 8 Arrays 214ȱ compilerȱ canȱ initializeȱ theseȱ locationsȱ beforeȱ theȱ programȱ begins,ȱ soȱ automaticȱ variablesȱ areȱ uninitializedȱ byȱ default.ȱ Ifȱ initialȱ valuesȱ areȱ given,ȱ theȱ variablesȱ areȱ initializedȱwithȱimplicitȱassignmentȱstatementsȱeachȱtimeȱexecutionȱentersȱtheȱscopeȱinȱ whichȱtheyȱwereȱdeclared.ȱTheȱimplicitȱassignmentȱstatementȱtakeȱupȱspaceȱandȱtakeȱ timeȱ toȱ executeȬjustȱ asȱ ordinaryȱ assignmentsȱ would.ȱ Theȱ problemȱ forȱ arraysȱ isȱ thatȱ thereȱmayȱbeȱmanyȱvaluesȱinȱtheȱinitializerȱlist,ȱresultingȱinȱjustȱasȱmanyȱassignments.ȱ Forȱveryȱlargeȱarrays,ȱtheȱinitializationȱcouldȱtakeȱconsiderableȱtime.ȱ Hereȱisȱtheȱtradeoff,ȱthen.ȱWhenȱinitializingȱanȱarrayȱthatȱisȱlocalȱtoȱaȱfunctionȱ (orȱ aȱ block),ȱ thinkȱ carefullyȱ aboutȱ whetherȱ itȱ shouldȱ beȱ reinitializedȱ eachȱ timeȱ theȱ functionȱ(orȱblock)ȱisȱentered.ȱIfȱtheȱanswerȱisȱno,ȱthenȱdeclareȱtheȱarrayȱstaticȱsoȱthatȱ theȱinitializationȱcanȱbeȱperformedȱonceȱbeforeȱtheȱprogramȱbegins.ȱ ȱ ȱ ȱ 8.1.9 Incomplete Initialization ȱ Whatȱhappensȱwithȱtheseȱtwoȱdeclarations?ȱ ȱ int int vector[5] = { 1, 2, 3, 4, 5, 6 }; vector[5] = { 1, 2, 3, 4 }; ȱ Inȱbothȱcases,ȱtheȱnumberȱofȱinitializersȱdoesȱnotȱmatchȱtheȱsizeȱofȱtheȱarray.ȱTheȱfirstȱ declarationȱ isȱ anȱ error;ȱ thereȱ isȱ noȱ wayȱ toȱ packȱ sixȱ integerȱ valuesȱ intoȱ fiveȱ integerȱ variables.ȱTheȱsecond,ȱhowever,ȱisȱlegal.ȱȱItȱprovidesȱvaluesȱforȱtheȱfirstȱfourȱelementsȱ ofȱtheȱarray;ȱtheȱlastȱelementȱisȱinitializedȱtoȱzero.ȱ ȱ Canȱtheȱmiddleȱvaluesȱbeȱomittedȱfromȱtheȱlistȱasȱwell?ȱ ȱ int vector[5] = { 1, 5 }; ȱ Theȱcompilerȱcanȱonlyȱtellȱthatȱthereȱareȱnotȱenoughȱinitializers,ȱbutȱitȱhasȱnoȱwayȱtoȱ figureȱoutȱwhichȱonesȱareȱmissing.ȱȱTherefore,ȱonlyȱtrailingȱinitializersȱcanȱbeȱomitted.ȱ ȱ ȱ ȱ 8.1.10 Automatic Array Sizing ȱ Hereȱisȱanȱexampleȱofȱanotherȱusefulȱtechnique.ȱ int vector[] = { 1, 2, 3, 4, 5 }; ȱ Ifȱtheȱarrayȱsizeȱisȱmissing,ȱtheȱcompilerȱmakesȱtheȱarrayȱjustȱbigȱenoughȱtoȱholdȱtheȱ initializersȱthatȱwereȱgiven.ȱThisȱtechniqueȱisȱparticularlyȱhelpfulȱifȱtheȱinitializerȱlistȱisȱ frequentlyȱmodified.ȱ Download at http://www.pin5i.com/ 8.2 Multidimensional Arrays 8.1.11 215 Character Array Initialization ȱ Fromȱ whatȱ weȱ haveȱ saidȱ soȱ far,ȱ youȱ mightȱ thinkȱ thatȱ characterȱ arraysȱ areȱ initializedȱ likeȱthis:ȱ ȱ ȱ char message[] = { 'H', 'e', 'l', 'l', 'o', 0 }; ȱ Theȱ codeȱ works,ȱ butȱ itȱ isȱ cumbersomeȱ forȱ allȱ butȱ theȱ shortestȱ strings.ȱ Therefore,ȱ theȱ languageȱStandardȱprovidesȱaȱshorthandȱnotationȱforȱinitializingȱcharacterȱarrays:ȱ ȱ ȱ char message[] = "Hello"; ȱ Althoughȱthisȱlooksȱlikeȱaȱstringȱliteral,ȱitȱisȱnot.ȱItȱisȱsimplyȱanȱalternateȱwayȱofȱwritingȱ theȱinitializerȱlistȱinȱtheȱpreviousȱexample.ȱȱ Howȱ canȱ youȱ tellȱ theȱ differenceȱ betweenȱ stringȱ literalsȱ andȱ theseȱ shorthandȱ initializerȱlistsȱifȱtheyȱlookȱexactlyȱtheȱsame?ȱTheyȱareȱdistinguishedȱfromȱoneȱanotherȱ byȱ theȱ contextȱ inȱ whichȱ theyȇreȱ used.ȱ Whenȱ initializingȱ aȱ characterȱ array,ȱ itȱ isȱ anȱ initializerȱlist.ȱEverywhereȱelseȱitȱisȱaȱstringȱliteral.ȱ Hereȱisȱanȱexample:ȱ ȱ char char message1[] = "Hello"; *message2 = "Hello"; ȱ Theȱ initializersȱ lookȱ alike,ȱ butȱ theyȱ haveȱ differentȱ meanings.ȱ Theȱ firstȱ initializesȱ theȱ elementsȱ ofȱ aȱ characterȱ array,ȱ butȱ theȱ secondȱ isȱ aȱ trueȱ siringȱ literal.ȱ Theȱ pointerȱ variableȱisȱinitializedȱtoȱpointȱtoȱwhereverȱtheȱliteralȱisȱstored,ȱasȱillustratedȱbelow:ȱ ȱ message1ȱ ȱ ȇHȇȱ ȇeȇȱ ȇlȇȱ ȇlȇȱ ȇoȇ 0ȱ ȱ message2 ȱ ȱ ȱ ȱ ȱ ȱ ȇHȇȱ ȇeȇȱ ȇlȇȱ ȇlȇȱ ȇoȇ 0ȱ ȱ ȱ ȱ 8.2 Multidimensional Arrays ȱ Anȱarrayȱisȱcalledȱmultidimensionalȱifȱitȱhasȱmoreȱthanȱoneȱdimension.ȱForȱexample,ȱtheȱ declarationȱ ȱ ȱ int matrix[6][10]; ȱ createsȱ aȱ matrixȱ containingȱ 60ȱ elements.ȱ However,ȱ isȱ thisȱ sixȱ rowsȱ ofȱ tenȱ elementsȱ each,ȱorȱtenȱrowsȱofȱsixȱelementsȱeach?ȱ Toȱ answerȱ thisȱ question,ȱ youȱ needȱ toȱ lookȱ atȱ multidimensionalȱ arraysȱ fromȱ aȱ differentȱviewpoint.ȱConsiderȱthisȱprogressionȱofȱdeclarations:ȱ Download at http://www.pin5i.com/ 216ȱ Chapter 8 Arrays int int int int a; b[10]; c[6][10]; d[3][6][10]; ȱ aȱ isȱ aȱ singleȱ integer.ȱ Byȱ addingȱ theȱ dimensionȱ toȱ theȱ nextȱ declaration,ȱ bȱ isȱ aȱ vectorȱ containingȱtenȱintegerȱelements.ȱ Butȱallȱthatȱhasȱbeenȱdoneȱforȱ cȱisȱtoȱaddȱanotherȱdimension,ȱsoȱweȱcanȱviewȱ cȱ asȱaȱvectorȱcontainingȱsixȱelements,ȱexceptȱthatȱeachȱofȱthoseȱelementsȱhappensȱtoȱbeȱaȱ vectorȱofȱtenȱintegers.ȱInȱotherȱwords,ȱcȱisȱaȱoneȬdimensionalȱarrayȱofȱoneȬdimensionalȱ arrays.ȱȱTheȱsameȱcanȱbeȱsaidȱofȱ d:ȱitȱisȱanȱarrayȱofȱthreeȱelements,ȱeachȱofȱwhichȱisȱaȱ matrix.ȱWait,ȱȈmatrixȈȱisȱtheȱwrongȱviewpoint.ȱ dȱisȱanȱarrayȱofȱthreeȱelements,ȱeachȱofȱ whichȱisȱanȱarrayȱofȱsixȱelements,ȱandȱeachȱofȱthoseȱisȱanȱarrayȱofȱtenȱintegers.ȱMoreȱ concisely,ȱdȱisȱanȱarrayȱofȱthreeȱarraysȱofȱsixȱarraysȱofȱtenȱintegersȱeach.ȱ Itȱisȱimportantȱthatȱyouȱunderstandȱthisȱviewpoint,ȱbecauseȱitȱisȱtheȱbasisȱforȱCsȱ implementationȱofȱmultidimensionalȱarrays.ȱToȱreinforceȱthisȱidea,ȱletȇsȱtalkȱaboutȱtheȱ orderȱinȱwhichȱarrayȱelementsȱareȱstoredȱinȱmemory.ȱ ȱ ȱ ȱ 8.2.1 Storage Order ȱ Considerȱthisȱarray:ȱ ȱ int array[3]; ȱ Itȱcontainsȱthreeȱelements,ȱasȱshownȱinȱthisȱdiagram.ȱ ȱ ȱ ȱ arrayȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Butȱ nowȱ supposeȱ youȱ areȱ toldȱ thatȱ eachȱ ofȱ theseȱ elementsȱ isȱ inȱ factȱ anȱ arrayȱ ofȱ sixȱ elements?ȱHereȱisȱtheȱnewȱdeclaration:ȱ ȱ ȱ int array[3][6]; ȱ andȱhereȱisȱhowȱitȱlooks:ȱ ȱ ȱ arrayȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Theȱ solidȱ boxesȱ showȱ theȱ threeȱ elementsȱ ofȱ theȱ firstȱ dimension,ȱ andȱ theȱ dottedȱ divisionsȱ showȱ theȱ sixȱ elementsȱ ofȱ theȱ secondȱ dimension.ȱ Theȱ subscriptsȱ ofȱ theȱ elementsȱabove,ȱfromȱleftȱtoȱright,ȱare:ȱ Download at http://www.pin5i.com/ 8.2 Multidimensional Arrays 217 ȱ 0,0 1,3 0,1 1,4 0,2 1,5 0,3 2,0 0,4 2,1 0,5 2,2 1,0 2,3 1,1 2,4 1,2 2,5 ȱ Thisȱ exampleȱ illustratesȱ whatȱ isȱ calledȱ theȱ storageȱ orderȱ ofȱ arrayȱ elements.ȱ Inȱ C,ȱ elementsȱ ofȱ aȱ multidimensionalȱ arrayȱ areȱ storedȱ inȱ theȱ orderȱ givenȱ byȱ varyingȱ theirȱ rightmostȱ subscriptȱ mostȱ rapidly,ȱ calledȱ rowȱ majorȱ order.ȱ Knowingȱ theȱ storageȱ orderȱ helpsȱyouȱanswerȱsomeȱusefulȱquestions,ȱforȱexample,ȱtheȱorderȱinȱwhichȱtoȱwriteȱtheȱ valuesȱinȱanȱinitializerȱlist.ȱWhatȱvaluesȱdoesȱtheȱfollowingȱcodeȱprint?ȱ ȱ int matrix[6][10]; int *mp; ... mp = &matrix[3][8]; printf( "First value is %d\n", *mp ); printf( "Second value is %d\n", *++mp ); printf( "Third value is %d\n", *++mp ); ȱ Itȱisȱobviousȱthatȱtheȱfirstȱvalueȱprintedȱwillȱheȱtheȱcontentsȱofȱmatrix[3][8],ȱbutȱwhatȱ isȱprintedȱnext?ȱTheȱstorageȱorderȱdeterminesȱtheȱanswer—theȱnextȱelementȱisȱtheȱoneȱ whoseȱ rightmostȱ subscriptȱ hasȱ changed,ȱ namelyȱ matrix[3][9].ȱ Whatȱ aboutȱ theȱ nextȱ one?ȱ Columnȱ nineȱ isȱ theȱ lastȱ columnȱ inȱ theȱ row.ȱ Becauseȱ theȱ rowsȱ ofȱ theȱ matrixȱ areȱ storedȱoneȱafterȱanother,ȱtheȱnextȱelementȱprintedȱwillȱbeȱmatrix[4][0]. 35 ȱ Hereȱisȱaȱrelatedȱquestion.ȱȱDoesȱmatrixȱhaveȱthreeȱrowsȱofȱtenȱcolumnsȱeach,ȱorȱ tenȱ rowsȱ ofȱ threeȱ columnsȱ each?ȱ Theȱ answerȱ mayȱ surpriseȱ you—inȱ someȱ contexts,ȱ itȱ couldȱbeȱeitherȱway.ȱ ȱ Eitherȱway?ȱHowȱcouldȱitȱbeȱtwoȱdifferentȱthings?ȱEasy.ȱȱIfȱyouȱuseȱsubscriptsȱ toȱputȱdataȱintoȱtheȱarrayȱandȱyouȱlaterȱuseȱsubscriptsȱtoȱlookȱupȱvaluesȱinȱtheȱarray,ȱ thenȱ itȱ makesȱ noȱ differenceȱ whetherȱ youȱ interpretȱ theȱ firstȱ subscriptȱ asȱ theȱ rowȱ numberȱorȱtheȱcolumnȱnumber.ȱAsȱlongȱasȱyouȱdoȱitȱtheȱsameȱwayȱeachȱtime,ȱitȱwillȱworkȱ withȱeitherȱinterpretation.ȱ However,ȱinterpretingȱtheȱfirstȱsubscriptȱasȱaȱrowȱorȱasȱaȱcolumnȱcannotȱchangeȱ theȱstorageȱorderȱofȱtheȱarray.ȱIfȱyouȱuseȱtheȱfirstȱsubscriptȱasȱtheȱrowȱnumberȱandȱtheȱ secondȱasȱtheȱcolumnȱnumber,ȱthenȱaccessingȱtheȱelementsȱoneȱafterȱanotherȱinȱtheirȱ storageȱ orderȱ willȱ giveȱ youȱ theȱ dataȱ rowȱ byȱ row.ȱ ȱ Onȱ theȱ otherȱ hand,ȱ ifȱ youȱ useȱ theȱ firstȱsubscriptȱasȱtheȱcolumnȱnumber,ȱthenȱtheȱsameȱkindȱofȱaccessȱwillȱgiveȱyouȱyourȱ dataȱinȱorderȱcolumnȱbyȱcolumn.ȱYouȱcanȱchooseȱwhicheverȱinterpretationȱmakesȱtheȱ ȱThisȱexampleȱusedȱaȱpointerȱtoȱanȱintegerȱtoȱtraverseȱtheȱmemoryȱlocationsȱusedȱtoȱholdȱaȱtwoȬdimensionalȱarrayȱofȱ integers.ȱCalledȱȱflatteningȱtheȱarray,ȱthisȱtechniqueȱisȱactuallyȱillegal,ȱbecauseȱmovingȱfromȱoneȱrowȱtoȱtheȱnextȱinvolvesȱ leavingȱtheȱsubȬarrayȱthatȱcontainsȱtheȱfirstȱrow.ȱThoughȱitȱusuallyȱworks,ȱitȱshouldȱbeȱavoidedȱifȱpossible.ȱ ȱ 35 Download at http://www.pin5i.com/ 218ȱ Chapter 8 Arrays mostȱ senseȱ forȱ yourȱ application.ȱ Youȱ cannot,ȱ however,ȱ changeȱ theȱ wayȱ theȱ elementsȱ areȱactuallyȱstoredȱinȱmemory.ȱThatȱorderȱisȱdefinedȱbyȱtheȱStandard.ȱ ȱ ȱ ȱ 8.2.2 Array Names ȱ Theȱ valueȱ ofȱ theȱ nameȱ ofȱ aȱ oneȬdimensionalȱ arrayȱ isȱ aȱ pointerȱ constant,ȱ itsȱ typeȱ isȱ ȈpointerȱtoȱelementȬtypeȈȱandȱitȱpointsȱtoȱtheȱfirstȱelementȱofȱtheȱarray.ȱȱ Multidimensionalȱarraysȱareȱalmostȱasȱeasy.ȱȱTheȱonlyȱdifferenceȱisȱthatȱanȱelementȱinȱ theȱ firstȱ dimensionȱ ofȱ aȱ multidimensionalȱ arrayȱ isȱ anotherȱ array.ȱ Forȱ example,ȱ theȱ declaration:ȱ ȱ ȱ ȱ int matrix[3][10]; ȱ createsȱ matrix,ȱ aȱ oneȬdimensionalȱ arrayȱ containingȱ threeȱ elements.ȱ Eachȱ ofȱ theseȱ elementsȱhappensȱtoȱbeȱanȱartsyȱofȱtenȱintegers.ȱ Theȱvalueȱofȱtheȱnameȱ matrixȱisȱaȱpointerȱtoȱtheȱfirstȱelement,ȱsoȱ matrixȱpointsȱ toȱanȱarrayȱofȱtenȱintegers.ȱ K&R C TheȱideaȱofȱaȱpointerȱtoȱanȱarrayȱwasȱaȱfairlyȱlateȱadditionȱtoȱK&RȱC,ȱandȱsomeȱolderȱ compilersȱ doȱ notȱ fullyȱ implementȱ it.ȱ However,ȱ theȱ notionȱ ofȱ aȱ pointerȱ toȱ anȱ arrayȱ isȱ crucialȱtoȱtheȱunderstandingȱofȱsubscriptsȱwithȱmultidimensionalȱarrays.ȱ ȱ ȱ ȱ 8.2.3 Subscripts ȱ Toȱ identifyȱ aȱ singleȱ elementȱ fromȱ aȱ multidimensionalȱ array,ȱ oneȱ subscriptȱ mustȱ beȱ givenȱ forȱ eachȱ dimension,ȱ inȱ theȱ sameȱ orderȱ thatȱ theȱ dimensionsȱ wereȱ givenȱ inȱ theȱ declaration,ȱ andȱ eachȱ subscriptȱ isȱ enclosedȱ inȱ itsȱ ownȱ setȱ ofȱ brackets.ȱ Withȱ thisȱ declaration:ȱ ȱ ȱ int matrix[3][10]; ȱ theȱexpressionȱ ȱ ȱ ȱ matrix[1][5] ȱ accessesȱthisȱelement:ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Download at http://www.pin5i.com/ 8.2 Multidimensional Arrays 219 Butȱ subscriptsȱ ateȱ reallyȱ indirectionȱ expressionsȱ inȱ disguise,ȱ evenȱ withȱ multidimensionalȱarrays.ȱConsiderȱdieȱexpressionȱ ȱ matrix ȱ ȱ ItsȱtypeȱisȱȈpointerȱtoȱanȱarrayȱofȱtenȱintegersȈ,ȱandȱitsȱvalueȱis:ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Itȱpointsȱtoȱtheȱfirstȱarrayȱofȱtenȱintegers.ȱ ȱ Theȱexpressionȱ ȱ ȱ matrix ȱ isȱ alsoȱ aȱ Ȉpointerȱ toȱ anȱ arrayȱ ofȱ tenȱ integers,Ȉȱ butȱ itȱ pointsȱ toȱ aȱ differentȱ rowȱ ofȱ theȱ matrix:ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Why?ȱBecauseȱtheȱvalueȱoneȱisȱscaledȱbyȱtheȱsizeȱofȱanȱarrayȱofȱtenȱintegers.ȱApplyingȱ indirectionȱfollowsȱtheȱarrowȱandȱselectsȱthisȱarray:ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Soȱtheȱexpressionȱ ȱ ȱ *(ȱmatrix + 1 ) ȱ reallyȱ identifiesȱ aȱ particularȱ arrayȱ ofȱ tenȱ integers.ȱ Theȱ valueȱ ofȱ anȱ arrayȱ nameȱ isȱ aȱ constantȱ pointerȱ toȱ theȱ firstȱ elementȱ inȱ theȱ array,ȱ andȱ theȱ sameȱ isȱ trueȱ ofȱ thisȱ expression.ȱ Itsȱ typeȱ isȱ Ȉpointerȱ toȱ integer,Ȉȱ andȱ weȱ canȱ nowȱ showȱ itsȱ valueȱ inȱ theȱ contextȱofȱtheȱnextȱdimension:ȱ Download at http://www.pin5i.com/ Chapter 8 Arrays 220ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Nowȱholdȱonȱtoȱyourȱhat.ȱWhatȱisȱtheȱresultȱofȱthisȱexpression?ȱ ȱ *( matrix + 1 ) + 5 ȱ Theȱpreviousȱexpressionȱpointedȱtoȱanȱinteger,ȱsoȱvalueȱfiveȱisȱscaledȱbyȱtheȱsizeȱofȱanȱ integer.ȱȱTheȱresultȱpointsȱfiveȱintegersȱafterȱtheȱoriginalȱexpression:ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Applyingȱindirection,ȱ ȱ ȱ *( *( matrix + 1 ) + 5 ) ȱ takesȱ usȱ toȱ theȱ integerȱ inȱ question.ȱ Ifȱ usedȱ asȱ anȱ RȬvalue,ȱ youȱ wouldȱ getȱ theȱ valueȱ storedȱthere.ȱAsȱanȱLȬvalue,ȱtheȱlocationȱwouldȱreceiveȱaȱnewȱvalue.ȱ Thisȱ intimidatingȱ expressionȱ isȱ actuallyȱ ourȱ oldȱ friend,ȱ theȱ subscript.ȱ Weȱ canȱ rewriteȱ theȱ subexpressionȱ *( matrix + 1 )ȱ asȱ matrix[1].ȱ Substitutingȱ thisȱ subexpressionȱintoȱtheȱoriginalȱexpressionȱgivesȱus:ȱ ȱ *( matrix[1] + 5 ) ȱ Thisȱexpressionȱisȱperfectlyȱvalid,ȱmatrix[1]ȱselectsȱanȱarrayȱofȱtenȱintegers,ȱsoȱitsȱtypeȱ isȱaȱpointerȱtoȱanȱinteger.ȱToȱthisȱpointerȱweȱaddȱfive,ȱandȱthenȱapplyȱindirection.ȱ Butȱonceȱagain,ȱweȱhaveȱtheȱsubscriptȱformȱofȱindirection,ȱsoȱweȱcanȱsubstituteȱ andȱgetȱ ȱ matrix[1][5] Download at http://www.pin5i.com/ 8.2 Multidimensional Arrays CAUTION! 221 Thus,ȱ subscriptsȱ areȱ simplyȱ anotherȱ formȱ ofȱ indirectionȱ expressionȱ evenȱ forȱ multidimensionalȱarrays.ȱ Theȱ pointȱ ofȱ thisȱ exerciseȱ isȱ toȱ illustrateȱ howȱ subscriptsȱ workȱ forȱ multidimensionalȱarraysȱandȱhowȱtheyȱdependȱonȱtheȱnotionȱofȱaȱpointerȱtoȱanȱarray.ȱ Subscriptsȱ areȱ evaluatedȱ fromȱ leftȱ toȱ right.ȱ Theȱ arrayȱ nameȱ isȱ aȱ pointerȱ toȱ theȱ firstȱ elementȱofȱtheȱfirstȱdimension,ȱsoȱtheȱfirstȱsubscriptȱvalueȱisȱscaledȱbyȱtheȱsizeȱofȱthatȱ element.ȱ Theȱ resultȱ pointsȱ toȱ theȱ desiredȱ elementȱ inȱ thatȱ dimension.ȱ Theȱ indirectionȱ thenȱ selectsȱ thatȱ specificȱ element.ȱ Becauseȱ theȱ elementȱ isȱ anȱ array,ȱ theȱ typeȱ ofȱ thisȱ expressionȱisȱaȱpointerȱtoȱtheȱfirstȱelementȱofȱtheȱnextȱdimension.ȱȱTheȱnextȱsubscriptȱisȱ scaledȱ byȱ thatȱ size,ȱ andȱ theȱ processȱ isȱ repeatedȱ untilȱ allȱ ofȱ theȱ subscriptsȱ haveȱ beenȱ evaluated.ȱ ȱ Inȱmanyȱotherȱlanguages,ȱmultipleȱsubscriptsȱareȱwrittenȱasȱaȱcommaȬseparatedȱlistȱofȱ values.ȱSomeȱlanguagesȱallowȱbothȱforms.ȱNotȱsoȱinȱC:ȱwritingȱ ȱ matrix[4,3] ȱ looksȱ perfectlyȱ fine,ȱ butȱ almostȱ certainlyȱ doesȱ notȱ accomplishȱ whatȱ youȱ want.ȱ Rememberȱthatȱtheȱcommaȱoperatorȱevaluatesȱtheȱfirstȱexpressionȱbutȱthrowsȱawayȱitsȱ value.ȱTheȱresultȱisȱtheȱvalueȱofȱtheȱsecondȱexpression.ȱThus,ȱtheȱpreviousȱexpressionȱisȱ equivalentȱtoȱ ȱ matrix[3] ȱ Theȱ problemȱ isȱ thatȱ theȱ expressionȱ mayȱ compileȱ withoutȱ anyȱ errorȱ orȱ warning.ȱ Theȱ expressionȱisȱperfectlyȱlegitimate,ȱitȱjustȱdoesnȇtȱmeanȱwhatȱyouȱhadȱintended.ȱ ȱ ȱ ȱ 8.2.4 Pointers to Arrays ȱ Areȱtheseȱdeclarationsȱlegal?ȱ ȱ int int vector[10], *vp = vector; matrix[3] [10], *mp = matrix; ȱ Theȱfirstȱisȱlegal.ȱItȱallocatesȱaȱvectorȱofȱintegers,ȱandȱthenȱdeclaresȱvpȱtoȱbeȱaȱpointerȱtoȱ anȱ integerȱ andȱ initializesȱ theȱ pointerȱ toȱ pointȱ toȱ theȱ firstȱ elementȱ inȱ vector.ȱ Bothȱ vectorȱandȱvpȱhaveȱtheȱsameȱtype:ȱpointerȱtoȱinteger.ȱTheȱsecondȱdeclarationȱisȱillegal,ȱ however.ȱItȱcreatesȱtheȱmatrixȱcorrectlyȱandȱdeclaresȱ mpȱtoȱbeȱaȱpointerȱtoȱanȱinteger,ȱ butȱtheȱinitializationȱofȱmpȱisȱincorrectȱbecauseȱmatrixȱisȱnotȱaȱpointerȱtoȱanȱinteger,ȱitȱisȱ aȱ pointerȱ toȱ anȱ arrayȱ ofȱ integers.ȱ Howȱ wouldȱ weȱ declareȱ aȱ pointerȱ toȱ anȱ arrayȱ ofȱ integers?ȱ Download at http://www.pin5i.com/ 222ȱ Chapter 8 Arrays int (*p)[10]; ȱ ȱ Thisȱ declarationȱ isȱ moreȱ complexȱ thanȱ thoseȱ youȱ haveȱ seenȱ before,ȱ butȱ itȱ reallyȱ isnȇtȱ tooȱ difficult.ȱ Justȱ pretendȱ thatȱ itȱ isȱ anȱ expressionȱ andȱ evaluateȱ it.ȱ Subscriptsȱ haveȱ aȱ higherȱ precedenceȱ thanȱ indirection,ȱ butȱ theȱ parenthesesȱ surroundingȱ theȱ indirectionȱ forceȱitȱtoȱgoȱfirst.ȱSoȱpȱisȱaȱpointerȱtoȱsomething,ȱbutȱtoȱwhat?ȱ Theȱsubscriptȱisȱappliedȱnext,ȱsoȱpȱpointsȱtoȱsomeȱkindȱofȱarray.ȱThereȱarenȇtȱanyȱ moreȱ operatorsȱ inȱ theȱ declarationȱ expression,ȱ soȱ eachȱ elementȱ ofȱ theȱ arrayȱ isȱ anȱ integer.ȱ Theȱdeclarationȱdoesnȇtȱtellȱyouȱdirectlyȱwhatȱpȱis,ȱbutȱitȱisȱnotȱdifficultȱtoȱfigureȱ out—whenȱ weȱ appliedȱ indirectionȱ toȱ pȱ weȱ gotȱ anȱ array,ȱ andȱ puttingȱ aȱ subscriptȱ onȱ thatȱexpressionȱproducedȱanȱinteger.ȱSoȱpȱisȱaȱpointerȱtoȱanȱarrayȱofȱintegers.ȱ Addingȱinitializationȱtoȱtheȱdeclarationȱgivesȱus:ȱ ȱ int (*p)[10] = matrix; ȱ whichȱmakesȱpȱpointȱtoȱtheȱfirstȱrowȱofȱmatrix.ȱ pȱisȱaȱpointerȱtoȱanȱarrayȱofȱtenȱintegers.ȱȱAddingȱanȱintegerȱtoȱ pȱwillȱcauseȱtheȱ integerȱvalueȱtoȱbeȱscaledȱbyȱtheȱsizeȱofȱtenȱintegersȱbeforeȱtheȱadditionȱtakesȱplace.ȱSoȱ weȱcanȱuseȱthisȱpointerȱtoȱstepȱthroughȱtheȱmatrixȱrowȱbyȱrow.ȱ Whatȱ shouldȱ youȱ doȱ ifȱ youȱ wantȱ aȱ pointerȱ thatȱ willȱ goȱ throughȱ theȱ matrixȱ integerȱbyȱintegerȱratherȱthanȱrowȱbyȱrow?ȱBothȱofȱtheȱfollowingȱdeclarationsȱcreateȱaȱ simpleȱintegerȱpointer,ȱinitializedȱinȱtwoȱdifferentȱwaysȱtoȱpointȱtoȱtheȱfirstȱintegerȱinȱ theȱmatrix.ȱ ȱ int int *pi = &matrix[0][0]; *pi = matrix[0]; ȱ Incrementingȱthisȱpointerȱadvancesȱitȱtoȱtheȱnextȱinteger.ȱ CAUTION! Ifȱ youȱ intendȱ toȱ performȱ anyȱ arithmeticȱ withȱ theȱ pointer,ȱ avoidȱ thisȱ kindȱ ofȱ declaration:ȱ int (*p)[] = matrix pȱ isȱ stillȱ aȱ pointerȱ toȱ anȱ arrayȱ ofȱ integers,ȱ butȱ theȱ arrayȱ sizeȱ isȱ missing.ȱ Integersȱ involvedȱinȱpointerȱarithmeticȱwithȱthisȱvariableȱwillȱbeȱscaledȱbyȱtheȱsizeȱofȱanȱemptyȱ arrayȱ(thatȱis,ȱmultipliedȱbyȱzero),ȱwhichȱisȱprobablyȱnotȱwhatȱyouȱhadȱinȱmind.ȱSomeȱ compilersȱcatchȱthisȱerrorȱandȱsomeȱdonȇt.ȱ Download at http://www.pin5i.com/ 8.2 Multidimensional Arrays 223 8.2.5 Multidimensional Arrays as Function Arguments ȱ Aȱmultidimensionalȱarrayȱnameȱusedȱasȱanȱargumentȱtoȱaȱfunctionȱisȱpassedȱtheȱsameȱ asȱaȱoneȬdimensionalȱarrayȱname—aȱpointerȱtoȱtheȱfirstȱelementȱofȱtheȱarrayȱisȱpassed.ȱȱ However,ȱ theȱ differenceȱ betweenȱ themȱ isȱ thatȱ eachȱ elementȱ ofȱ theȱ multidimensionalȱ arrayȱ isȱ anotherȱ array,ȱ andȱ theȱ compilerȱ needsȱ toȱ knowȱ itsȱ dimensionsȱ inȱ orderȱ toȱ evaluateȱsubscriptsȱforȱtheȱarrayȱparameterȱinȱtheȱfunction.ȱHereȱareȱtwoȱexamplesȱtoȱ illustrateȱtheȱdifference:ȱ ȱ int vector[10]; ... func1( vector ); ȱ Theȱtypeȱofȱtheȱargumentȱvectorȱisȱaȱpointerȱtoȱanȱinteger,ȱsoȱfunc1ȱcanȱbeȱprototypedȱ inȱeitherȱofȱtheȱfollowingȱways:ȱ ȱ void func1( int *vec ); void func1( int vec[] ); ȱ Pointerȱarithmeticȱonȱvecȱinȱtheȱfunctionȱusesȱtheȱsizeȱofȱanȱintegerȱforȱitsȱscaleȱfactor.ȱ Nowȱletȇsȱlookȱatȱaȱmatrix.ȱ ȱ int matrix[3][10]; ... func2( matrix ); ȱ Hereȱ theȱ typeȱ ofȱ theȱ argumentȱ matrixȱ isȱ aȱ pointerȱ toȱ anȱ arrayȱ ofȱ tenȱ integers.ȱ Whatȱ shouldȱtheȱprototypeȱfor func2ȱlookȱlike?ȱEitherȱofȱtheȱfollowingȱformsȱcouldȱbeȱused:ȱ ȱ void func2( int (*mat)[10] ); void func2( int mat[][10] ); ȱ Inȱtheȱfunction,ȱtheȱfirstȱsubscriptȱusedȱwithȱ matȱisȱscaledȱbyȱtheȱsizeȱofȱanȱarrayȱofȱtenȱ integers;ȱtheȱsecondȱsubscriptȱisȱthenȱscaledȱbyȱtheȱsizeȱofȱanȱinteger,ȱjustȱasȱitȱwouldȱ beȱforȱtheȱoriginalȱmatrix.ȱ Theȱ keyȱ hereȱ isȱ thatȱ theȱ compilerȱ mustȱ knowȱ theȱ sizesȱ ofȱ theȱ secondȱ andȱ subsequentȱ dimensionsȱ inȱ orderȱ toȱ evaluateȱ subscripts,ȱ thusȱ theȱ prototypeȱ mustȱ declareȱtheseȱdimensions.ȱTheȱsizeȱofȱtheȱfirstȱdimensionȱisnȇtȱneededȱbecauseȱitȱisȱnotȱ usedȱinȱtheȱcalculationȱofȱsubscripts.ȱ YouȱcanȱwriteȱtheȱprototypeȱforȱaȱoneȬdimensionalȱarrayȱparameterȱeitherȱasȱanȱ arrayȱ orȱ asȱ aȱ pointer.ȱ Forȱ multidimensionalȱ arrays,ȱ youȱ onlyȱ haveȱ thisȱ choiceȱ forȱ theȱ firstȱdimension,ȱthough.ȱȱSpecifically,ȱitȱisȱincorrectȱtoȱprototypeȱfunc2ȱlikeȱthis:ȱ Download at http://www.pin5i.com/ 224ȱ Chapter 8 Arrays void func2( int **mat ); ȱ Thisȱexampleȱdeclaresȱ matȱtoȱbeȱaȱpointerȱtoȱaȱpointerȱtoȱanȱinteger,ȱwhichȱisȱnotȱatȱallȱ theȱsameȱthingȱasȱaȱpointerȱtoȱanȱarrayȱofȱtenȱintegers.ȱ ȱ ȱ ȱ 8.2.6 Initialization ȱ Theȱ storageȱ orderȱ ofȱ arrayȱ elementsȱ becomesȱ importantȱ whenȱ initializingȱ multidimensionalȱarrays.ȱȱThereȱareȱtwoȱwaysȱtoȱwriteȱtheȱinitializerȱlist.ȱTheȱfirstȱisȱtoȱ justȱgiveȱaȱlongȱlistȱofȱinitializers,ȱasȱinȱtheȱfollowingȱexample.ȱ ȱ int matrix[2][3] = { 100, 101, 102, 110, 111, 112 }; ȱ Theȱ storageȱ orderȱ hasȱ theȱ rightmostȱ subscriptȱ varyingȱ mostȱ rapidly,ȱ soȱ thisȱ initializationȱproducesȱtheȱsameȱresultȱasȱtheseȱassignments:ȱ ȱ matrix[0][0] matrix[0][1] matrix[0][2] matrix[1][0] matrix[1][1] matrix[1][2] = = = = = = 100; 101; 102; 110; 111; 112; ȱ Theȱ secondȱ wayȱ isȱ basedȱ onȱ theȱ ideaȱ thatȱ aȱ multidimensionalȱ arrayȱ isȱ reallyȱ aȱ oneȬ dimensionalȱ arrayȱ ofȱ complicatedȱ elements.ȱ Forȱ example,ȱ hereȇsȱ aȱ declarationȱ forȱ aȱ twoȬdimensionalȱarray:ȱ ȱ ȱ int two_dim[3][5]; ȱ Viewȱ two_dimȱ asȱ anȱ arrayȱ ofȱ threeȱ (complicated)ȱ elements.ȱ Toȱ initializeȱ anȱ arrayȱ ofȱ threeȱelements,ȱweȱuseȱaȱlistȱcontainingȱthreeȱinitializers:ȱ ȱ int two_dim[3][5] = { Ș, Ș, Ș }; ȱ ȱ Butȱeachȱofȱtheseȱelementsȱisȱactuallyȱanȱarrayȱofȱfiveȱintegers,ȱsoȱeachȱofȱtheȱȘȇsȱshouldȱ beȱaȱlistȱofȱfiveȱvaluesȱenclosedȱinȱbraces.ȱReplacingȱeachȱ Șȱwithȱsuchȱaȱlistȱresultsȱinȱ codeȱthatȱlooksȱlikeȱthis:ȱ ȱ ȱ int two_dim[3][5] = { { 00, 01, 02, 03, 04 }, { 10, 11, 12, 13, 14 }, { 20, 21, 22, 23, 24 } }; ȱ Ofȱcourse,ȱtheȱindentingȱandȱspacingȱweȱhaveȱusedȱareȱnotȱrequired,ȱalthoughȱtheyȱdoȱ makeȱtheȱlistȱeasierȱtoȱread.ȱ Download at http://www.pin5i.com/ 8.2 Multidimensional Arrays 225 Ifȱ youȱ eraseȱ allȱ butȱ theȱ outermostȱ bracesȱ fromȱ thisȱ example,ȱ youȱ willȱ seeȱ thatȱ whatȱisȱleftȱisȱaȱsimpleȱinitializerȱlistȱlikeȱtheȱfirstȱone.ȱTheȱbracesȱmerelyȱdelimitȱtheȱ initializerȱlistȱbyȱrow.ȱ Figuresȱ8.1ȱandȱ8.2ȱillustrateȱinitializingȱthreeȬȱandȱfourȬdimensionalȱarrays.ȱInȱ theseȱexamples,ȱtheȱdigitsȱofȱeachȱinitializerȱshowȱtheȱsubscriptȱvaluesȱofȱtheȱlocationȱ inȱwhichȱitȱisȱstored. 36 ȱ Whyȱ goȱ toȱ allȱ theȱ troubleȱ ofȱ puttingȱ inȱ theseȱ bracesȱ whenȱ theȱ initializationȱ worksȱ exactlyȱtheȱsameȱwayȱwithoutȱthem?ȱThereȱareȱtwoȱreasons.ȱTheȱfirstȱisȱorganization.ȱ Aȱ single,ȱ longȱ listȱ ofȱ numbersȱ makesȱ itȱ difficultȱ toȱ seeȱ whichȱ valueȱ belongsȱ toȱ eachȱ locationȱofȱtheȱarray,ȱthusȱtheȱbracesȱactȱasȱsignpostsȱandȱmakeȱitȱeasierȱtoȱverifyȱthatȱ theȱrightȱvaluesȱappearȱinȱtheȱrightȱplaces.ȱ Second,ȱ theȱ bracesȱ areȱ valuableȱ forȱ incompleteȱ initialization.ȱ Withoutȱ them,ȱ onlyȱ trailingȱ initializersȱ mayȱ beȱ omitted.ȱ Evenȱ ifȱ onlyȱ aȱ fewȱ elementsȱ ofȱ aȱ largeȱ multidimensionalȱarrayȱwereȱtoȱbeȱinitialized,ȱtheȱlistȱmightȱstillȱbeȱquiteȱlongȱbecauseȱ onlyȱ theȱ trailingȱ initializersȱ canȱ beȱ omitted.ȱ Withȱ theȱ braces,ȱ though,ȱ trailingȱ initializersȱmayȱbeȱomittedȱfromȱeachȱlist.ȱAlso,ȱtheȱinitializersȱforȱeachȱdimensionȱalsoȱ formȱaȱlist.ȱ Toȱ illustrateȱ thisȱ point,ȱ letȇsȱ revisitȱ theȱ fourȬdimensionalȱ arrayȱ initializationȱ inȱ Figureȱ8.2ȱandȱchangeȱourȱrequirementsȱaȱlittle.ȱSupposeȱweȱonlyȱneedȱtoȱinitializeȱtwoȱ elementsȱinȱtheȱarray.ȱElementȱ [0][0][0][0]ȱshouldȱbeȱ100ȱandȱelementȱ [1][0][0][0] shouldȱbeȱ200,ȱȱAllȱotherȱelementsȱshouldȱbeȱleftȱtoȱtheirȱdefaultȱ ȱ ȱ ȱ int three_dim[2][3][5] = { { { 000, 001, 002, { 010, Oil, 012, { 020, 021, 022, }, { 100, 101, 102, { 110, 111, 112, { 120, 121, 122, } 003, 004 }, 013, 014 }, 023, 024 } 103, 104 }, 113, 114 }, 123, 124 } }; ȱ Figureȱ8.1ȱInitializingȱaȱthreeȬdimensionalȱarrayȱ ȱIfȱtheseȱexamplesȱwereȱcompiled,ȱtheȱinitializersȱthatȱbeginȱwithȱzeroȱwouldȱactuallyȱbeȱinterpretedȱasȱoctalȱ numbers.ȱȱIgnoreȱthisȱpoint,ȱandȱlookȱonlyȱatȱtheȱindividualȱdigitsȱofȱeachȱinitializer.ȱ 36 Download at http://www.pin5i.com/ 226ȱ Chapter 8 Arrays int four_dim[2][2][3][5] = { { { { 0000, 0001, { 0010, 0011, { 0020, 0021, }, { { 0100, 0101, { 0110, 0111, { 0120, 0121, }, }, { { { 1000, 1001, { 1010, 1011, { 1020, 1021, }, { { 1100, 1101, { 1110, 1111, { 1120, 1121, }, } 0002, 0003, 0004 }, 0012, 0013, 0014 }, 0022, 0023, 0024 } 0102, 0103, 0104 }, 0112, 0113, 0114 }, 0122, 0123, 0124 } 1002, 1003, 1004 }, 1012, 1013, 1014 }, 1022, 1023, 1024 } 1102, 1103, 1104 }, 1112, 1113, 1114 }, 1122, 1123, 1124 } } ȱ Figureȱ8.2ȱInitializingȱaȱfourȬdimensionalȱarrayȱ ȱ ȱ ȱ ȱ ȱ ȱ values.ȱHereȱisȱhowȱweȱcanȱaccomplishȱthisȱtask:ȱ ȱ int four_dim[2][2][3][5] = { { { { 100 } } }, { { { 200 } } } } ȱ Withoutȱtheȱbraces,ȱyouȱwouldȱneedȱthisȱlongerȱinitializerȱlist:ȱ Download at http://www.pin5i.com/ 8.3 Arrays of Pointers 227 int four_dim[2][2][3][5] = { 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200 }; ȱ Thisȱlistȱisȱnotȱonlyȱharderȱtoȱreadȱbutȱalsoȱmoreȱdifficultȱtoȱgetȱrightȱinȱfirstȱplace.ȱ ȱ ȱ ȱ 8.2.7 Automatic Array Sizing ȱ Withȱmultidimensionalȱarrays,ȱonlyȱtheȱfirstȱdimensionalȱofȱtheȱarrayȱcanȱbeȱimpliedȱbyȱ theȱinitializerȱlist.ȱTheȱremainingȱonesȱareȱneededȱsoȱthatȱtheȱcompilerȱcanȱdetermineȱ theȱsizeȱofȱeachȱsubordinateȱdimension.ȱForȱexample:ȱ ȱ int two_dim[][5] = { { 00, 01, 02 }, { 10, 11 }, { 20, 21, 22, 23 } }; ȱ Theȱ leftmostȱ dimensionȱ isȱ determinedȱ toȱ beȱ threeȱ byȱ countingȱ theȱ numberȱ ofȱ initializersȱitȱcontains.ȱ Whyȱ canȇtȱ theȱ otherȱ dimensionȱ beȱ determinedȱ automaticallyȱ byȱ countingȱ theȱ valuesȱ inȱ itsȱ longestȱ initializerȱ list?ȱ Inȱ principle,ȱ theȱ compilerȱ couldȱ figureȱitȱ out,ȱ butȱ thenȱatȱleastȱoneȱofȱtheȱinitializersȱinȱeachȱlistȱwouldȱhaveȱtoȱbeȱfullȱsizeȱinȱorderȱforȱtheȱ dimensionȱtoȱbeȱdeterminedȱaccurately.ȱȱByȱrequiringȱthatȱallȱdimensionsȱafterȱtheȱfirstȱ oneȱbeȱgiven,ȱallȱofȱtheȱinitializerȱlistsȱcanȱbeȱincomplete.ȱ ȱ ȱ ȱ 8.3 Arrays of Pointers ȱ Asideȱfromȱitsȱtype,ȱaȱpointerȱvariableȱisȱlikeȱanyȱotherȱvariable.ȱJustȱasȱyouȱcanȱcreateȱ arraysȱofȱintegers,ȱyouȱcanȱalsoȱdeclareȱarraysȱofȱpointers.ȱHereȱisȱanȱexample:ȱ ȱ int *api[10]; ȱ Toȱfigureȱoutȱthisȱcomplexȱdeclaration,ȱpretendȱthatȱitȱisȱanȱexpressionȱandȱevaluateȱit.ȱ Subscriptsȱhaveȱaȱhigherȱprecedenceȱthanȱindirection,ȱsoȱinȱthisȱexpression,ȱtheȱ subscriptȱwouldȱbeȱappliedȱfirst.ȱTherefore,ȱ apiȱisȱanȱarrayȱofȱsomethingȱ(andȱoh,ȱbyȱ theȱway,ȱthereȱareȱtenȱofȱthem).ȱAfterȱgettingȱoneȱelementȱofȱtheȱarray,ȱtheȱindirectionȱ isȱappliedȱnext.ȱThereȱarenȇtȱanyȱmoreȱoperators,ȱsoȱtheȱresultȱofȱthisȱexpressionȱisȱanȱ integer.ȱ Download at http://www.pin5i.com/ 228ȱ Chapter 8 Arrays Soȱwhatȱisȱ api?ȱWeȱgotȱanȱintegerȱbyȱapplyingȱindirectionȱtoȱanȱelementȱofȱanȱ array,ȱsoȱapiȱmustȱbeȱanȱarrayȱofȱpointersȱtoȱintegers.ȱ Whereȱwouldȱyouȱeverȱuseȱanȱarrayȱofȱpointers?ȱHereȱisȱoneȱexample:ȱ ȱ char }; #define const *keyword[] = { "do", "for", "if", "register", "return", "switch", "while" N_KEYWORD ( sizeof( keyword ) / sizeof( keyword[0] ) ) ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Determine whether the argument matches any of the words in ** a list of keywords, and return the index to the one it matches. ** If no match is found, return the value -1. */ #include <string.h> int lookup_keyword( char const * const desired_word, char const *keyword_table[], int const size ) { char const **kwp; /* ** For each word in the table ... */ for( kwp = keyword_table; kwp < keyword_table + size; kwp++ ) /* ** If this word matches the one we're looking for, ** return its position in the table. */ if( strcmp( desired_word, *kwp ) == 0 ) return kwp - keyword_table; /* ** Not found. */ return -1; } ȱ Programȱ8.2ȱȱKeywordȱlookupȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ keyword.cȱ Download at http://www.pin5i.com/ 8.3 Arrays of Pointers 229 Noticeȱtheȱuseȱofȱ sizeofȱtoȱautomaticallyȱcountȱtheȱnumberȱofȱelementsȱinȱtheȱ array.ȱ sizeof( keyword )ȱgivesȱtheȱnumberȱofȱbytesȱinȱtheȱentireȱarray,ȱandȱ sizeof( keyword[0] )ȱisȱtheȱnumberȱofȱbytesȱinȱoneȱelement.ȱTheȱresultingȱdivisionȱgivesȱtheȱ numberȱofȱelements.ȱ ThisȱarrayȱwouldȱbeȱusefulȱinȱaȱprogramȱthatȱcountsȱkeywordsȱinȱCȱsourceȱfiles.ȱ Eachȱwordȱfromȱtheȱinputȱwouldȱbeȱcomparedȱtoȱtheȱstringsȱinȱtheȱlist,ȱandȱallȱmatchesȱ wouldȱbeȱcounted.ȱProgramȱ8.2ȱgoesȱthroughȱtheȱlistȱofȱkeywordsȱlookingȱforȱaȱmatchȱ withȱtheȱargumentȱstring.ȱWhenȱaȱmatchȱisȱfound,ȱtheȱ offsetȱintoȱtheȱlistȱisȱreturned.ȱ Theȱcallingȱprogramȱmustȱknowȱthatȱzeroȱmeansȱ do,ȱoneȱmeansȱ for,ȱandȱsoȱforth,ȱandȱ itȱ alsoȱ hasȱ toȱ knowȱ thatȱ Ȭ1ȱ isȱ returnedȱ forȱ aȱ nonkeyword.ȱ Thisȱ informationȱ wouldȱ probablyȱbeȱobtainedȱviaȱsymbolsȱdefinedȱinȱanȱincludedȱfile.ȱ Weȱcouldȱalsoȱstoreȱtheȱkeywordsȱinȱaȱmatrix,ȱlikeȱthis:ȱ ȱ char const keyword[][9] = { "do", "for", "if", "register", "return", "switch", "while" }; ȱ Whatȱ isȱ theȱ differenceȱ betweenȱ thisȱ declarationȱ andȱ theȱ precedingȱ one?ȱ Theȱ secondȱ declarationȱ createsȱ aȱ matrixȱ whoseȱ rowsȱ areȱ eachȱ longȱ enoughȱ toȱ holdȱ theȱ longestȱ keywordȱ(plusȱitsȱterminatingȱNULȱbyte).ȱTheȱmatrixȱlooksȱlikeȱthis:ȱ ȱ ȱ ȱ keywordȱ ȇdȇȱ ȇoȇȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ ȇfȇȱ ȇoȇȱ ȇrȇȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ ȇiȇȱ ȇfȇȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ ȇrȇȱ ȇeȇȱ ȇgȇȱ ȇiȇȱ ȇsȇȱ ȇtȇȱ ȇeȇȱ ȇrȇȱ 0ȱ ȇrȇȱ ȇeȇȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ 0ȱ ȇtȇȱ ȇuȇȱ ȇrȇȱ ȇnȇȱ ȇsȇȱ ȇwȇȱ ȇiȇȱ ȇtȇȱ ȇwȇȱ ȇhȇȱ ȇlȇȱ ȇeȇȱ ȇiȇȱ ȇcȇȱ ȇhȇȱ 0ȱ Download at http://www.pin5i.com/ Chapter 8 Arrays 230ȱ Theȱ firstȱ declarationȱ createsȱ anȱ arrayȱ ofȱ pointers,ȱ whichȱ areȱ initializedȱ toȱ pointȱ toȱ variousȱstringȱliterals,ȱasȱillustratedȱbelow.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇdȇȱ ȇoȇȱ 0ȱ ȱ ȇfȇȱ ȇoȇȱ ȇrȇȱ 0ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇrȇȱ ȇeȇȱ ȇtȇȱ ȇuȇȱ ȇrȇȱ ȇnȇȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇsȇȱ ȇwȇ ȇiȇȱ ȇtȇȱ ȇcȇȱ ȇhȇȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇwȇ ȇhȇȱ ȇiȇȱ ȇlȇȱ ȇeȇȱ ȇiȇȱ ȱ ȱ 0ȱ ȱ ȇfȇȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇrȇȱ ȇeȇȱ ȇgȇȱ ȇiȇȱ ȇsȇȱ ȇtȇȱ ȇeȇȱ ȇrȇȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ 0ȱ ȱ ȱ 0ȱ 0ȱ ȱ ȱ Noticeȱ theȱ differenceȱ inȱ theȱ amountȱ ofȱ memoryȱ used.ȱ Theȱ matrixȱ looksȱ inefficientȱbecauseȱeveryȱrowȱmustȱbeȱlongȱenoughȱtoȱstoreȱtheȱlongestȱkeyword.ȱȱButȱ itȱdoesȱnotȱneedȱanyȱpointers.ȱOnȱtheȱotherȱhand,ȱtheȱarrayȱofȱpointersȱtakesȱspace,ȱbutȱ eachȱofȱtheȱstringȱliteralsȱisȱonlyȱasȱlongȱasȱitȱneedsȱtoȱbe.ȱ WhatȱwouldȱweȱneedȱtoȱchangeȱinȱProgramȱ8.2ȱtoȱuseȱtheȱmatrixȱinsteadȱofȱtheȱ arrayȱofȱpointers?ȱItȱmayȱsurpriseȱyouȱtoȱlearnȱthatȱonlyȱtheȱdeclarationsȱforȱtheȱtableȱ parameterȱandȱtheȱlocalȱvariableȱwouldȱbeȱdifferent.ȱTheȱcodeȱwouldnȇtȱchangeȱatȱall.ȱȱ Becauseȱ theȱ valueȱ ofȱ anȱ arrayȱ nameȱ isȱ aȱ pointer,ȱ theȱ bodyȱ ofȱ theȱ functionȱ willȱ workȱ withȱeitherȱaȱpointerȱvariableȱorȱanȱarrayȱname.ȱ Whichȱisȱbetter?ȱItȱdependsȱonȱtheȱspecificȱwordsȱyouȱwishȱtoȱstore.ȱIfȱtheyȱareȱ allȱ nearlyȱ theȱ sameȱ length,ȱ theȱ matrixȱ isȱ moreȱ compactȱ becauseȱ thereȱ isȱ noȱ spaceȱ neededȱforȱpointers.ȱȱHowever,ȱifȱtheȱwordsȱareȱdifferentȱlengths,ȱorȱworseȱyet,ȱmostȱofȱ themȱ areȱ shortȱ butȱ aȱ fewȱ areȱ quiteȱ long,ȱ thenȱ theȱ arrayȱ ofȱ pointersȱ mayȱ beȱ moreȱ compact.ȱItȱ dependsȱ onȱwhetherȱ theȱspaceȱ consumedȱbyȱtheȱ pointersȱ isȱ lessȱthanȱ theȱ spaceȱwastedȱbyȱusingȱfixedȬlengthȱrowsȱforȱeachȱword.ȱ Inȱ practice,ȱ theseȱ differencesȱ areȱ soȱ slightȱ asȱ toȱ beȱ unimportantȱ forȱ allȱ butȱ theȱ largestȱofȱtables.ȱȱMoreȱoftenȱthanȱnot,ȱtheȱarrayȱofȱpointersȱisȱused,ȱbutȱwithȱaȱtwist:ȱ ȱ char const *keyword[] = { "do", "for", "if", "register", "return", "switch", ȱ 0ȱ Download at http://www.pin5i.com/ 8.4 Summary 231 "while", NULL }; ȱ Hereȱ weȱ addȱ aȱ NULLȱ pointerȱ toȱ theȱ endȱ ofȱ theȱ table.ȱ Theȱ NULLȱ letsȱ functionsȱ thatȱ searchȱ theȱtableȱ detectȱ theȱ endȱ ofȱ theȱ tableȱwithoutȱ knowingȱ itsȱ sizeȱ inȱ advance,ȱ likeȱ this:ȱ for( kwp = keyword_table; *kwp != NULL; kwp++ ) ȱ ȱ ȱ 8.4 Summary ȱ Theȱvalueȱofȱanȱarrayȱnameȱinȱmostȱexpressionsȱisȱaȱpointerȱtoȱtheȱfirstȱelementȱofȱtheȱ array.ȱȱThereȱareȱonlyȱtwoȱexceptionsȱtoȱthisȱrule,ȱȱ sizeofȱreturnsȱtheȱnumberȱofȱbytesȱ inȱ theȱ entireȱ arrayȱ ratherȱ thanȱ theȱ sizeȱ ofȱ aȱ pointer.ȱ Theȱ unaryȱ &ȱ operatorȱ returnsȱ aȱ pointerȱtoȱtheȱfirstȱelementȱofȱtheȱarray,ȱnotȱaȱpointerȱtoȱaȱpointerȱtoȱtheȱfirstȱelement.ȱ Exceptȱforȱtheirȱprecedence,ȱtheȱsubscriptȱexpressionȱ array[value]ȱisȱtheȱsameȱ asȱtheȱindirectionȱexpressionȱ *( array + ( value ) ).ȱThus,ȱsubscriptsȱmayȱbeȱusedȱ withȱpointerȱexpressionsȱasȱwellȱasȱwithȱarrayȱnames,ȱwhichȱmakesȱitȱdifficultȱforȱtheȱ compilerȱtoȱcheckȱtheȱvalidityȱofȱsubscripts.ȱPointerȱexpressionsȱmayȱbeȱmoreȱefficientȱ thanȱ subscripts,ȱ butȱ subscriptsȱ areȱ neverȱ moreȱ efficientȱ thanȱ pointerȱ expressions.ȱ However,ȱ reducingȱ program,ȱ maintainabilityȱ toȱ gainȱ runtimeȱ efficiencyȱ isȱ rarelyȱ aȱ goodȱidea.ȱ Pointersȱandȱarraysȱareȱnotȱequivalent.ȱTheȱpropertiesȱofȱanȱarrayȱandȱaȱpointerȱ variableȱ areȱ quiteȱ different.ȱ Declaringȱ anȱ arrayȱ createsȱ spaceȱ toȱ storeȱ theȱ arrayȱ elements,ȱwhileȱdeclaringȱaȱpointerȱvariableȱonlyȱcreatesȱspaceȱtoȱstoreȱtheȱpointer.ȱ Whenȱ anȱ arrayȱ nameȱ isȱ passedȱ asȱ aȱ functionȱ argument,ȱ aȱ pointerȱ toȱ theȱ firstȱ elementȱ isȱ passedȱ toȱ theȱ function.ȱ Thisȱ parameterȱ isȱ aȱ copy,ȱ soȱ theȱ functionȱ canȱ manipulateȱitȱwithoutȱaffectingȱtheȱactualȱargument.ȱHowever,ȱapplyingȱindirectionȱtoȱ theȱ pointerȱ parameterȱ allowsȱ theȱ functionȱ toȱ modifyȱ theȱ originalȱ arrayȱ elements.ȱȱ Arrayȱparametersȱmayȱbeȱdeclaredȱeitherȱasȱarrayȱnamesȱorȱpointers;ȱbothȱdeclarationȱ formsȱareȱequivalentȱforȱfunctionȱparametersȱonly.ȱ Anȱ arrayȱ mayȱ beȱ initializedȱ withȱ aȱ listȱ ofȱ valuesȱ enclosedȱ inȱ braces.ȱ Staticȱ variablesȱ (includingȱ arrays)ȱ receiveȱ theirȱ initialȱ valuesȱ whenȱ theȱ programȱ isȱ loadedȱ intoȱ memory.ȱ Automaticȱ variablesȱ (includingȱ arrays)ȱ mustȱ beȱ reinitializedȱ withȱ implicitȱassignmentȱstatementsȱeachȱtimeȱexecutionȱentersȱtheȱblockȱinȱwhichȱtheyȱareȱ declared.ȱ Ifȱ anȱ initializerȱ listȱ hasȱ fewerȱ valuesȱ thanȱ theȱ sizeȱ ofȱ theȱ array,ȱ theȱ lastȱ elementsȱ ofȱ theȱ arrayȱ areȱ initializedȱ withȱ theȱ defaultȱ value.ȱ Ifȱ theȱ dimensionȱ ofȱ anȱ initializedȱarrayȱisȱomitted,ȱtheȱcompilerȱwillȱmakeȱtheȱarrayȱjustȱlargeȱenoughȱtoȱholdȱ Download at http://www.pin5i.com/ 232ȱ Chapter 8 Arrays theȱ valuesȱ givenȱ inȱ theȱ initializerȱ list.ȱ Characterȱ arraysȱ mayȱ beȱ initializedȱ withȱ aȱ shorthandȱnotationȱthatȱresemblesȱaȱstringȱliteral.ȱ Multidimensionalȱ arraysȱ areȱ actuallyȱ oneȬdimensionalȱ arraysȱ whoseȱ elementsȱ areȱ eachȱ anȱ array.ȱ Theȱ valuesȱ inȱ multidimensionalȱ arraysȱ areȱ storedȱ inȱ rowȱ majorȱ order,ȱ withȱ theȱ rightmostȱ subscriptȱ varyingȱ mostȱ rapidly.ȱ Theȱ valueȱ ofȱ aȱ multidimensionalȱarrayȱnameȱisȱaȱpointerȱtoȱitsȱfirstȱelement,ȱwhichȱwillȱbeȱaȱpointerȱtoȱ anȱarray.ȱArithmeticȱwithȱthisȱpointerȱwillȱbeȱscaledȱbyȱtheȱsizeȱofȱtheȱarray.ȱSubscriptsȱ forȱ multidimensionalȱ arraysȱ areȱ alsoȱ pointerȱ expressions.ȱ Whenȱ theȱ nameȱ ofȱ aȱ multidimensionalȱ arrayȱ isȱ passedȱ asȱ anȱ argumentȱ toȱ aȱ function,ȱ theȱ correspondingȱ functionȱ parameterȱ mustȱ beȱ declaredȱ withȱ theȱ sizesȱ ofȱ theȱ secondȱ andȱ subsequentȱ dimensions.ȱ Becauseȱ aȱ multidimensionalȱ arrayȱ isȱ reallyȱ aȱ oneȬdimensionalȱ arrayȱ ofȱ complexȱ elements,ȱ theȱ initializerȱ listȱ forȱ aȱ multidimensionalȱ arrayȱ containsȱ aȱ listȱ ofȱ initializersȱforȱtheȱcomplexȱelements.ȱEachȱofȱtheseȱlistsȱmayȱalsoȱcontainȱnestedȱlists,ȱ asȱ neededȱ byȱ theȱ numberȱ ofȱ dimensionsȱ inȱ theȱ array.ȱ Theȱ interiorȱ bracesȱ mayȱ beȱ omittedȱ ifȱ theȱ initializerȱ listsȱ areȱ allȱ complete.ȱ Onlyȱ theȱ firstȱ dimensionȱ ofȱ aȱ multidimensionalȱarrayȱmayȱbeȱautomaticallyȱsizedȱfromȱtheȱinitializerȱlist.ȱ Itȱ isȱ possibleȱ toȱ createȱ arraysȱ ofȱ pointers.ȱ Listsȱ ofȱ stringsȱ mayȱ beȱ storedȱ inȱ aȱ matrix,ȱorȱasȱaȱlistȱofȱpointersȱtoȱvectorsȱorȱstringȱliterals.ȱInȱaȱmatrix,ȱeachȱrowȱmustȱbeȱ asȱlongȱasȱtheȱlongestȱstring,ȱhoweverȱnoȱpointersȱareȱstored.ȱTheȱlistȱofȱpointersȱtakesȱ space,ȱbutȱeachȱofȱtheȱstringsȱneedȱonlyȱbeȱasȱlongȱasȱnecessary.ȱ ȱ ȱ ȱ 8.5 Summary of Cautions ȱ 1. Usingȱ commasȱ toȱ separateȱ subscriptsȱ whenȱ accessingȱ aȱ multidimensionalȱ arrayȱ (pageȱ221).ȱ 2. Doingȱarithmeticȱwithȱaȱpointerȱtoȱanȱunsizedȱarrayȱ(pageȱ222).ȱ ȱ ȱ ȱ 8.6 Summary of Programming Tips ȱ 1. Writingȱgoodȱcodeȱinȱtheȱfirstȱplaceȱisȱbetterȱthanȱdependingȱonȱtheȱcompilerȱtoȱfixȱ upȱbadȱcodeȱ(pageȱ205).ȱ 2. Sourceȱ codeȱ readabilityȱ isȱ nearlyȱ alwaysȱ moreȱ importantȱ thanȱ runtimeȱ efficiencyȱ (pageȱ209).ȱ ȱ ȱ Download at http://www.pin5i.com/ 8.7 Questions 233 3. Pointerȱparametersȱtoȱfunctionsȱshouldȱbeȱdeclaredȱ constȱwheneverȱpossibleȱ(pageȱ 212).ȱ 4. Usingȱ registerȱ variablesȱ increasesȱ runtimeȱ efficiencyȱ inȱ someȱ environmentsȱ (pageȱ 212).ȱ 5. Usingȱbracesȱtoȱfullyȱencloseȱtheȱinitializersȱofȱaȱmultidimensionalȱarrayȱincreasesȱ readabilityȱ(pageȱ225).ȱ ȱ ȱ ȱ 8.7 Questions ȱ 1. Givenȱtheȱdeclarationsȱandȱdataȱshownȱbelow,ȱevaluateȱeachȱofȱtheȱexpressionsȱandȱ stateȱitsȱvalue.ȱEvaluateȱeachȱexpressionȱwithȱtheȱoriginalȱdataȱshownȱ(thatȱis,ȱtheȱ resultsȱ ofȱ oneȱ expressionȱ doȱ notȱ affectȱ theȱ followingȱ ones).ȱ Assumeȱ thatȱ theȱ intsȱ arrayȱbeginsȱatȱlocationȱ100ȱandȱthatȱintegersȱandȱpointersȱbothȱoccupyȱfourȱbytes.ȱ ȱ int ints[20] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200 }; (Otherȱdeclarations) int *ip = ints + 3; ȱ ȱ ȱ Expression ints ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ints + 4 ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. 4 *(ints + 4) ints[-2] &ints &ints[4] &ints + 4 &ints[-2] ȱ Expression ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ip ints[4] *ints + Value ip[4] ip + 4 ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. *ip + 4; ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. *(ip + 4) ip[-2] ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. &ip ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. &ip[4] &ip + 4 ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱ. &ip[-2] Value ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. Download at http://www.pin5i.com/ 234ȱ Chapter 8 Arrays 2. Areȱtheȱexpressions array[ i + j ]ȱand i + j[ array ]ȱequivalent?ȱ 3. Theȱfollowingȱdeclarationsȱareȱanȱattemptȱtoȱaccessȱtheȱarrayȱdataȱusingȱsubscriptsȱ thatȱstartȱatȱone.ȱWillȱitȱwork?ȱ ȱ int int actual_data[ 20 ]; *data = actual_data – 1; 4. Rewriteȱ theȱ followingȱ loop,ȱ whichȱ testsȱ whetherȱ aȱ stringȱ isȱ aȱ palindrome,ȱ toȱ useȱ pointerȱvariablesȱinsteadȱofȱsubscripts.ȱ char buffer[SIZE]; int front, rear; ... front = 0; rear = strlen( buffer ) – 1; while( front < rear ){ if( buffer[front] != buffer[rear] ) break; front += 1; rar -= 1; } if( front >= rear ){ printf( "It is a palindrome!\n" ); } 5. Theȱ potentialȱ efficiencyȱ ofȱ pointersȱ overȱ subscriptsȱ isȱ aȱ motivationȱ toȱ useȱ them.ȱ Whenȱisȱitȱreasonableȱtoȱuseȱsubscriptsȱdespiteȱtheȱpossibleȱlossȱofȱruntimeȱspeed?ȱ 6. Compileȱ theȱ functionsȱ try1ȱ throughȱ try5ȱ onȱ yourȱ machine,ȱ andȱ analyzeȱ theȱ resultingȱassemblyȱcode.ȱWhatȱisȱyourȱconclusion?ȱ 7. Testȱ yourȱ conclusionȱ forȱ theȱ previousȱ questionȱ byȱ runningȱ eachȱ ofȱ theȱ functionsȱ andȱ timingȱ theirȱ execution.ȱ Makingȱ theȱ arraysȱ severalȱ thousandȱ elementsȱ longȱ increasesȱtheȱaccuracyȱofȱtheȱexperimentȱbecauseȱtheȱcopyingȱtakesȱfarȱmoreȱtimeȱ thanȱtheȱirrelevantȱpartsȱofȱtheȱprogram.ȱAlso,ȱcallȱtheȱfunctionsȱfromȱwithinȱaȱloopȱ thatȱ iteratesȱ enoughȱ timesȱ soȱ thatȱ youȱ canȱ accuratelyȱ timeȱ theȱ entireȱ execution.ȱȱ Compileȱ theȱ programsȱ twiceȱ forȱ thisȱ experiment—onceȱ withoutȱ anyȱ optimizationȱ atȱ all,ȱ andȱ onceȱ withȱ optimization.ȱ Ifȱ yourȱ compilerȱ offersȱ aȱ choice,ȱ selectȱ optimizationȱforȱbestȱspeed.ȱ Download at http://www.pin5i.com/ 8.7 Questions 235 8. Theȱfollowingȱdeclarationsȱwereȱfoundȱinȱoneȱsourceȱfile:ȱ ȱ int int a[10]; *b = a; ȱ Butȱinȱaȱdifferentȱsourceȱfile,ȱthisȱcodeȱwasȱfound:ȱ ȱ ȱ extern extern int ... x = a[3]; y = b[3]; int *a; int b[]; x, y; Explainȱwhatȱhappensȱwhenȱtheȱtwoȱassignmentȱstatementsȱareȱexecuted.ȱ(Assumeȱ thatȱintegersȱandȱpointersȱbothȱoccupyȱfourȱbytes).ȱ 9. Writeȱaȱdeclarationȱthatȱwillȱinitializeȱanȱarrayȱofȱintegersȱcalledȱcoin_valuesȱtoȱtheȱ valuesȱofȱcurrentȱU.S.ȱcoins.ȱ 10. Givenȱtheȱdeclarationȱ int array[4][2]; ȱ giveȱtheȱvalueȱofȱeachȱofȱtheȱfollowingȱexpressions.ȱAssumeȱthatȱtheȱarrayȱbeginsȱatȱ locationȱ1000ȱandȱthatȱintegersȱoccupyȱtwoȱbytesȱofȱmemory.ȱ ȱ Expression Value array ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. array + 2 array[3] array[2] - 1 &array[1][2] &array[2][0] ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱ 11. Givenȱtheȱdeclarationȱ ȱ int array[4][2][3][6]; ȱ computeȱtheȱvalueȱofȱeachȱofȱtheȱfollowingȱexpressions.ȱAlso,ȱshowȱtheȱdeclarationȱ thatȱwouldȱbeȱneededȱforȱtheȱvariableȱ xȱinȱorderȱforȱtheȱexpressionȱtoȱbeȱassignedȱ toȱ xȱ withoutȱ usingȱ aȱ cast.ȱ Assumeȱ thatȱ theȱ arrayȱ beginsȱ atȱ locationȱ 1000ȱ andȱ thatȱ integersȱoccupyȱfourȱbytesȱofȱmemory.ȱ Download at http://www.pin5i.com/ 236ȱ Chapter 8 Arrays ȱ Expression array Value Type of x ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. array + 2 array[3] array[2] - 1 array[2][1] array[1][0] + 1 array[1][0][2] array[0][1][0] + 2 array[3][1][2][5] &array[3][1][2][5] ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱ 12. ArraysȱinȱCȱareȱstoredȱinȱrowȬmajorȱorder.ȱWhenȱisȱthisȱinformationȱrelevant?ȱ 13. Givenȱtheȱdeclaration:ȱ ȱ int array[4][5][3]; ȱ convertȱtheȱfollowingȱpointerȱexpressionȱtoȱuseȱsubscripts.ȱ ȱ Expression Type of x *array *( array + 2 ) *( array + 1 ) + 4 *( *( array + 1 ) + 4 ) *( *( *( array + 3 ) + 1 ) + 2 ) *( *( *array + 1 ) + 2 ) *{ **array + 2 ) **( *array + 1 ) ***array ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱ 14. Theȱ subscriptsȱ forȱ aȱ multidimensionalȱ arrayȱ mustȱ eachȱ beȱ givenȱ inȱ itsȱ ownȱ setȱ ofȱ brackets.ȱ Underȱ whatȱ conditionsȱ wouldȱ theȱ followingȱ codeȱ fragmentȱ compileȱ withoutȱproducingȱanyȱwarningsȱorȱerrors?ȱ ȱ int array[10][20]; ... i = array[3,4]; Download at http://www.pin5i.com/ 8.7 Questions 237 15. Givenȱtheȱdeclarations:ȱ ȱ unsigned int int which; array[ SIZE ]; ȱ whichȱofȱtheȱfollowingȱstatementsȱmakesȱmoreȱsense,ȱandȱwhy?ȱ ȱ ȱ ȱ if( array[ which ] == 5 && which < SIZE ) ... if( which < SIZE && array[ which ] == 5 ) ... ȱ 16. Whatȱ isȱ theȱ differenceȱ (ifȱ any)ȱ betweenȱ theȱ variablesȱ array1ȱ andȱ array2ȱ inȱ thisȱ program?ȱ ȱ void function( int array1[10] ){ int array2[10]; ... } ȱ 17. Explainȱ theȱ significantȱ differencesȱ betweenȱ theȱ followingȱ twoȱ usesȱ ofȱ theȱ constȱ keyword.ȱ ȱ void function( int const a, int const b[] )[ ȱ 18. Howȱ elseȱ couldȱ theȱ followingȱ functionȱ prototypeȱ beȱ writtenȱ toȱ achieveȱ theȱ sameȱ results?ȱ ȱ void function( int array[3][2][5] ); ȱ 19. Inȱ Programȱ 8.2,ȱ theȱ keywordȱ lookupȱ example,ȱ theȱ arrayȱ ofȱ pointersȱ toȱ charactersȱ wasȱmodifiedȱbyȱaddingȱaȱNULLȱpointerȱtoȱtheȱendȱofȱit,ȱthusȱeliminatingȱtheȱneedȱ toȱ knowȱ theȱ sizeȱ ofȱ theȱ table.ȱ Howȱ couldȱ theȱ matrixȱ ofȱ keywordsȱ beȱ modifiedȱ toȱ achieveȱtheȱsameȱresult?ȱShowȱtheȱ forȱstatementȱthatȱwouldȱbeȱusedȱtoȱaccessȱtheȱ modifiedȱmatrix.ȱ ȱ ȱ ȱ 8.8 Programming Exercises ȱ 1. Writeȱ aȱ declarationȱ forȱ anȱ arrayȱ thatȱ initializesȱ certainȱ locationsȱ ofȱ theȱ arrayȱ toȱ specificȱ values.ȱ Theȱ arrayȱ shouldȱ beȱ calledȱ char_valuesȱ andȱ containȱ 3ȱ ×ȱ 6ȱ ×ȱ 4ȱ ×ȱ 5ȱ unsignedȱ characters.ȱ Theȱ followingȱ locationsȱ shouldȱ beȱ staticallyȱ initializedȱ toȱ theseȱvalues:ȱ Download at http://www.pin5i.com/ 238ȱ Chapter 8 Arrays ȱ Loc 1,2,2,3ȱ 2,4,3,2ȱȱ 2,4,3,3ȱȱ 2,1,1,2ȱ Value 'A' '3' 3 0320 Loc 1,1,1,1ȱȱ 1,4,2,3ȱȱ 2,5,3,4ȱ 2,2,2,2ȱ Value ' ' '\n' 125 '\'' Loc 1,3,2,2ȱ 2,2,3,1ȱȱ 1,2,3,4ȱ 2,2,1,1ȱ Value 0xf3 '\121' 'x' '0' ȱ Locationsȱotherȱthanȱthoseȱmentionedȱaboveȱshouldȱbeȱinitializedȱtoȱbinaryȱ(notȱtheȱ character)ȱzero.ȱNote:ȱStaticȱinitializationȱisȱtoȱbeȱused;ȱthereȱcanȱbeȱnoȱexecutableȱ codeȱinȱyourȱsolution!ȱ Althoughȱitȱwillȱnotȱbeȱpartȱofȱtheȱsolution,ȱyouȱwillȱprobablyȱwantȱtoȱwriteȱaȱ programȱtoȱcheckȱyourȱinitializationȱbyȱprintingȱoutȱtheȱarray.ȱBecauseȱsomeȱofȱtheȱ valuesȱ areȱ notȱ printableȱ characters,ȱ printȱ theȱ valuesȱ asȱ integersȱ (octalȱ orȱ hexadecimalȱoutputȱwouldȱbeȱconvenient).ȱ Note:ȱSolvingȱthisȱproblemȱtwice,ȱonceȱusingȱnestedȱbracesȱinȱtheȱinitializerȱlistȱ andȱ onceȱ without,ȱ willȱ giveȱ youȱ aȱ greaterȱ appreciationȱ ofȱ theȱ usefulnessȱ ofȱ theȱ nestedȱbraces.ȱ 2. TheȱU.S.ȱfederalȱincomeȱtaxȱforȱ singleȱpeopleȱinȱ1995ȱwasȱcomputedȱaccordingȱ toȱ theȱfollowingȱrules:ȱ ȱ If Your Taxable of the Amount income Is Over But Not Over Your Tax is Over $0ȱ 23,350ȱ 56,550ȱ 117,950ȱ 256,500ȱ $23,350ȱ 56,550ȱ 117,950ȱ 256,500ȱ ––ȱȱ 15%ȱ $3,502.50ȱ+ȱ28%ȱ 12,798.50ȱ+ȱ31%ȱ 31,832.50ȱ+ȱ36%ȱ 81,710.50ȱ+ȱ39.8%ȱ $0ȱ 23,350ȱ 56,550ȱ 117,950ȱ 256,500ȱ ȱ Writeȱtheȱfunctionȱprototypedȱbelow:ȱ ȱ float single_tax( float income ); Theȱargumentȱisȱtaxableȱincome,ȱandȱtheȱfunctionȱreturnsȱtheȱappropriateȱamountȱ ofȱtax.ȱ 3. Anȱidentityȱmatrixȱisȱaȱsquareȱmatrixȱwhoseȱvaluesȱareȱallȱzeroȱexceptȱforȱthoseȱonȱ theȱmainȱdiagonal,ȱwhichȱareȱone.ȱForȱexample:ȱ ȱ 1 0 0 0 1 0 0 0 1 ȱ isȱaȱ3ȱ×ȱ3ȱidentityȱmatrix.ȱWriteȱaȱfunctionȱcalledȱ identity_matrixȱthatȱtakesȱaȱ10ȱ×ȱ 10ȱmatrixȱ ofȱintegersȱasȱitsȱonlyȱargumentȱandȱreturnsȱaȱbooleanȱvalueȱindicatingȱ whetherȱtheȱmatrixȱisȱanȱidentityȱmatrix.ȱ Download at http://www.pin5i.com/ 8.8 Programming Exercises 239 4. Modifyȱtheȱidentity_matrixȱfunctionȱfromȱtheȱpreviousȱproblemȱsoȱthatȱitȱcanȱtakeȱ matricesȱofȱanyȱsizeȱbyȱflatteningȱtheȱarray.ȱTheȱfirstȱargumentȱshouldȱbeȱaȱpointerȱ toȱ anȱ integer,ȱ andȱ youȱ willȱ needȱ aȱ secondȱ argumentȱ thatȱ specifiesȱ theȱ sizeȱ ofȱ theȱ matrix.ȱ 5. IfȱAȱisȱaȱmatrixȱofȱxȱrowsȱandȱyȱcolumnsȱandȱBȱisȱaȱmatrixȱofȱyȱrowsȱandȱzȱcolumns,ȱ thenȱAȱandȱ Bȱ canȱ beȱmultipliedȱ togetherȱandȱ theȱ resultȱwillȱ beȱ aȱ matrixȱ Cȱ withȱ xȱ rowsȱandȱzȱcolumns.ȱEachȱelementȱofȱthisȱmatrixȱisȱdeterminedȱwithȱtheȱfollowingȱ formula:ȱ ȱ y Ci , j ¦A i ,k u Bk , j ȱ ȱ Forȱexample:ȱ ȱ ª 2 6 º ª 50 14 44 52 º « 3 5 » u ª 4 2 4 5 º « 23 21 18 20 » » « » « 7 3 6 7 » « ¼ « «¬ 1 1»¼ ¬ 1 10 12 »¼ ¬ 11 ȱ ȱ ȱ Theȱvalueȱ14ȱinȱtheȱanswerȱwasȱtheȱresultȱofȱaddingȱ2ȱ×ȱ–2ȱȱandȱ–6ȱ×ȱ–3.ȱ Writeȱ aȱ functionȱ toȱ multiplyȱ twoȱ matrices.ȱ Theȱ functionȱ shouldȱ haveȱ thisȱ prototype:ȱ ȱ k 1 ȱ void matrix_multiply( int *m1, int *m2, int *r, int x, int y, int z ); m1ȱwillȱbeȱaȱmatrixȱwithȱxȱrowsȱandȱyȱcolumns;ȱm2ȱwillȱbeȱaȱmatrixȱwithȱyȱrowsȱandȱ zȱcolumns.ȱTheseȱmatricesȱshouldȱbeȱmultipliedȱtogether,ȱandȱtheȱresultsȱshouldȱbeȱ storedȱ inȱ r,ȱ whichȱ willȱ beȱ aȱ matrixȱ withȱ xȱ rowsȱ andȱ zȱ columns.ȱ ȱ Rememberȱ toȱ modifyȱtheȱformulaȱasȱnecessaryȱtoȱaccountȱforȱtheȱfactȱthatȱsubscriptsȱinȱCȱbeginȱ withȱzero,ȱnotȱone!ȱ 6. Asȱyouȱknow,ȱtheȱCȱcompilerȱallocatesȱarraysȱwithȱsubscriptsȱthatȱalwaysȱbeginȱatȱ zeroȱ andȱ doesȱ notȱ checkȱ subscriptsȱ whenȱ arrayȱ elementsȱ areȱ accessed.ȱ Inȱ thisȱ project,ȱ youȱ willȱ writeȱ aȱ functionȱ thatȱ allowsȱ theȱ userȱ toȱ accessȱ ȈpseudoȬarraysȈȱ whoseȱsubscriptsȱcanȱbeȱinȱanyȱranges,ȱwithȱcompleteȱerrorȱchecking.ȱ Hereȱisȱaȱprototypeȱforȱtheȱfunctionȱyouȱwillȱwrite:ȱ ȱ int array_offset( int arrayinfo[], ... ); ȱ Theȱ functionȱ takesȱ aȱ setȱ ofȱ informationȱ describingȱ theȱ dimensionsȱ ofȱ aȱ pseudoȬ arrayȱ andȱ aȱ setȱ ofȱ subscriptȱ values.ȱ Itȱ thenȱ usesȱ theȱ informationȱ toȱ translateȱ theȱ subscriptȱ valuesȱ intoȱ anȱ integerȱ thatȱ canȱ beȱ usedȱ asȱ aȱ subscriptȱ onȱ aȱ vector.ȱ Withȱ thisȱfunction,ȱtheȱuserȱcanȱallocateȱspaceȱeitherȱasȱaȱvectorȱorȱwithȱ malloc,ȱbutȱthenȱ accessȱthatȱspaceȱasȱaȱmultidimensionalȱarray.ȱȱTheȱarrayȱisȱcalledȱaȱȈpseudoȬȱ Download at http://www.pin5i.com/ 240ȱ Chapter 8 Arrays arrayȈȱ becauseȱ theȱ compilerȱ thinksȱ thatȱ itȱ isȱ aȱ vector,ȱ evenȱ thoughȱ thisȱ functionȱ allowsȱitȱtoȱbeȱaccessedȱasȱaȱmultidimensionalȱarray.ȱ Theȱfunctionȇsȱargumentsȱare:ȱ ȱ Argument Meaing arrayinfo AȱvariableȬlengthȱarrayȱofȱintegersȱthatȱcontainsȱinformationȱ aboutȱtheȱpseudoȬarray,ȱarrayinfo[0]ȱspecifiesȱhowȱmanyȱ dimensionsȱtheȱpseudoȬarrayȱhas,ȱwhichȱmustȱbeȱaȱvalueȱinȱtheȱ rangeȱ1Ȭ10,ȱinclusive.ȱarrayinfo[1]ȱandȱarrayinfo[2]ȱgiveȱtheȱ lowȱandȱhighȱlimitsȱforȱtheȱfirstȱdimension,ȱarrayinfo[3]ȱandȱ arrayinfo[4]ȱgiveȱtheȱlowȱandȱhighȱlimitsȱforȱtheȱsecondȱ dimension,ȱandȱsoȱforth.ȱ ... Theȱvariableȱportionȱofȱtheȱargumentȱlistȱmayȱcontainȱupȱtoȱtenȱ integers,ȱwhichȱareȱsubscriptȱvaluesȱthatȱidentifyȱaȱparticularȱ locationȱinȱtheȱpseudoȬarray.ȱYouȱmustȱuseȱva_ȱargumentȱmacrosȱ toȱaccessȱthem.ȱWhenȱtheȱfunctionȱisȱcalled,ȱarrayinfo[0]ȱ argumentsȱwillȱbeȱpassed.ȱ ȱ Theȱ formulaȱ toȱ useȱ forȱ computingȱ anȱ arrayȱ locationȱ fromȱ itsȱ subscriptsȱ isȱ givenȱ below.ȱ Theȱ variablesȱ s1,ȱ s2,ȱ etc.ȱ representȱ theȱ subscriptȱ argumentsȱ s1,ȱ s2,ȱ etc.ȱ Theȱ variablesȱ lo1ȱ andȱ hi1ȱ representȱ dieȱ lowȱ andȱ highȱ limitsȱ forȱ subscriptȱ s1,ȱ fromȱ theȱ arrayinfoȱ argument,ȱ andȱ soȱ forthȱ forȱ theȱ remainingȱ dimensions.ȱ Theȱ variableȱ locȱ representsȱ theȱ desiredȱ locationȱ inȱ theȱ pseudoȬarray,ȱ asȱ anȱ integerȱ offsetȱ fromȱ theȱ beginningȱofȱaȱvector.ȱForȱaȱoneȬdimensionalȱpseudoȬarray:ȱ ȱ ȱ ȱ loc s1 lo1 ȱ ȱ ForȱaȱtwoȬdimensionalȱpseudoȬarray:ȱ ȱ loc s1 lo1 u hi2 lo2 1 s2 lo2 ȱ ȱ ȱ ForȱaȱthreeȬdimensionalȱpseudoȬarray:ȱ ȱ loc ª¬ s1 lo1 u hi2 lo2 1 s2 lo2 º¼ u hi3 lo3 1 s3 lo3 ȱ ȱ ȱ ForȱaȱfourȬdimensionalȱpseudoȬarray:ȱ ȱ loc ¬ª s1 lo1 u hi2 lo2 1 s2 lo2 ¼º ^ u hi3 lo3 1 s3 lo3 ` u hi4 lo4 1 s4 lo4 ȱ ȱ ȱ andȱsoȱforthȱupȱtoȱtenȱdimensions.ȱ Download at http://www.pin5i.com/ 8.8 Programming Exercises 241 Youȱmayȱassumeȱthatȱ arrayinfoȱisȱaȱvalidȱpointerȱandȱthatȱtheȱcorrectȱnumberȱ ofȱ subscriptȱ argumentsȱ areȱ passedȱ toȱ array_offset.ȱ Everythingȱ elseȱ mustȱ beȱ checkedȱforȱerrors.ȱȱAȱfewȱofȱtheȱpossibleȱerrorsȱare:ȱnumberȱofȱdimensionsȱnotȱinȱ theȱrangeȱ1Ȭ10,ȱaȱsubscriptȱisȱlessȱthanȱitsȱlowȱvalue,ȱaȱlowȱvalueȱisȱgreaterȱthanȱtheȱ correspondingȱhighȱvalue,ȱetc.ȱIfȱtheseȱorȱanyȱotherȱerrorsȱareȱdetected,ȱtheȱvalueȱȬ1ȱ shouldȱbeȱreturned.ȱ Hint:ȱ Copyȱ theȱ subscriptȱ argumentsȱ intoȱ aȱ localȱ array.ȱ Youȱ canȱ thenȱ codeȱ theȱ calculationȱasȱaȱloopȱwithȱanȱiterationȱforȱeachȱdimension.ȱ Example:ȱ Assumeȱ thatȱ theȱ arrayinfoȱ arrayȱ containsȱ theȱ valuesȱ 3,ȱ 4,ȱ 6,ȱ 1,ȱ 5,ȱ Ȭ3,ȱ andȱ3.ȱTheseȱvaluesȱindicateȱthatȱweȱareȱworkingȱwithȱaȱthreeȬdimensionalȱpseudoȬ array.ȱ Theȱ firstȱ subscriptȱ isȱ aȱ valueȱ fromȱ 4ȱ throughȱ 6,ȱ theȱ secondȱ subscriptȱ isȱ aȱ valueȱfromȱ1ȱthroughȱ5,ȱandȱtheȱthirdȱsubscriptȱisȱaȱvalueȱfromȱȬ3ȱthroughȱ3.ȱȱInȱthisȱ example,ȱ array_offsetȱwillȱbeȱcalledȱwithȱthreeȱsubscriptȱarguments.ȱSeveralȱsetsȱ ofȱsubscriptsȱareȱshownȱbelowȱalongȱwithȱtheȱoffsetsȱthatȱtheyȱrepresentȱ ȱ Subscripts Offset Subscripts Offset Subscripts Offset 4,ȱ1,ȱȬ3ȱ 0ȱ 4,ȱ1,ȱ3ȱ 6ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ 5,ȱ1,ȱȬ3ȱȱ 35ȱ 4,ȱ1,ȱȬ2ȱ 1ȱ 4,ȱ2,ȱȬ3ȱ 7ȱȱȱȱȱȱȱȱȱȱ 6,ȱ3,ȱ1ȱ 88ȱ ȱ 7. Modifyȱtheȱarray_offsetȱfunctionȱfromȱProblemȱ6ȱsoȱthatȱitȱaccessesȱpseudoȬarraysȱ whoseȱ elementsȱ areȱ allocatedȱ inȱ columnȱ majorȱ order,ȱ thatȱ is,ȱ withȱ theȱ leftmostȱ subscriptȱ varyingȱ mostȱ rapidly.ȱ ȱ Thisȱ newȱ function,ȱ array_offset2,ȱ shouldȱ otherwiseȱworkȱtheȱsameȱasȱtheȱoriginalȱfunction.ȱ Theȱformulasȱforȱcalculatingȱsubscriptsȱforȱtheseȱarraysȱareȱgivenȱbelow.ȱ ForȱaȱoneȬdimensionalȱpseudoȬarray:ȱ ȱ loc s1 lo1 ȱ ȱ ForȱaȱtwoȬdimensionalȱpseudoȬarray:ȱ ȱ loc s2 lo2 u hi1 lo1 1 s1 lo1 ȱ ȱ ȱ ForȱaȱthreeȬdimensionalȱpseudoȬarray:ȱ ȱ ȱ loc ª¬ s3 lo3 u hi2 lo2 1 s2 lo2 º¼ u hi1 lo1 1 s1 lo1 ȱ ȱ ȱ ForȱaȱfourȬdimensionalȱpseudoȬarray:ȱ ȱ loc ª¬ s4 lo4 u hi3 lo3 1 s3 lo3 º¼ ^ u hi2 lo2 1 s2 lo2 ` u hi1 lo1 1 s1 lo1 ȱ ȱ ȱ andȱsoȱforthȱupȱtoȱtenȱdimensions.ȱ Download at http://www.pin5i.com/ Chapter 8 Arrays 242ȱ Example:ȱAssumeȱthatȱtheȱarrayinfoȱarrayȱcontainsȱtheȱvaluesȱ3,ȱ4,ȱ6,ȱ1,ȱ5,ȱȬ3,ȱandȱ3.ȱ TheseȱvaluesȱindicateȱthatȱweȱareȱworkingȱwithȱaȱthreeȬdimensionalȱpseudoȬarray.ȱ Theȱfirstȱsubscriptȱisȱaȱvalueȱfromȱ4ȱthroughȱ6,ȱtheȱsecondȱsubscriptȱisȱaȱvalueȱfromȱ 1ȱthroughȱ5,ȱandȱtheȱthirdȱsubscriptȱisȱaȱvalueȱfromȱȬ3ȱthroughȱ3.ȱInȱthisȱexample,ȱ array_offset2ȱ willȱ beȱ calledȱ withȱ threeȱ subscriptȱ arguments.ȱ Severalȱ setsȱ ofȱ subscriptsȱareȱshownȱbelowȱalongȱwithȱtheȱoffsetsȱthatȱtheyȱrepresent.ȱ ȱ ȱ Subscripts 4,ȱ1,ȱȬ3ȱ 5,ȱ1,ȱȬ3ȱ 6,ȱ1,ȱȬ3ȱ Offset_ 0ȱ 1ȱ 2ȱ Subscripts 4,ȱ2,ȱȬ3ȱ 4,ȱ3,ȱȬ3ȱ 4,ȱ1,ȱȬ2ȱ Offset 3ȱ 6ȱ 15ȱ Subscripts 4,ȱ1,ȱȬ1ȱ 5,ȱ3,ȱȬ1ȱ 6,ȱ5,ȱ3ȱ Offset 30ȱ 37ȱ 104ȱ ȱ 8. Theȱqueenȱisȱtheȱmostȱpowerfulȱpieceȱinȱtheȱgameȱofȱchess.ȱȱOnȱtheȱboardȱshownȱ below,ȱtheȱqueenȱcanȱcaptureȱanyȱpieceȱonȱanyȱsquareȱcoveredȱbyȱtheȱeightȱarrows.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȣ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Isȱitȱpossibleȱtoȱplaceȱeightȱqueensȱonȱaȱchessboardȱinȱsuchȱaȱwayȱthatȱnoneȱofȱthemȱ canȱ attackȱ anyȱ ofȱ theȱ others?ȱ Thisȱ questionȱ isȱ calledȱ Theȱ Eightȱ Queensȱ Problem.ȱ YourȱtaskȱisȱtoȱwriteȱaȱprogramȱtoȱfindȱallȱsolutionsȱtoȱtheȱEightȱQueensȱProblem.ȱ Howȱmanyȱsolutionsȱareȱthere?ȱ Hint:ȱ Theȱ programȱ isȱ easyȱ ifȱ youȱ useȱ aȱ techniqueȱ calledȱ backtracking.ȱ Writeȱ aȱ functionȱ thatȱ placesȱ aȱ queenȱ inȱ theȱ firstȱ columnȱ ofȱ oneȱ rowȱ andȱ thenȱ checksȱ toȱ makeȱsureȱthatȱthereȱareȱnoȱconflictsȱwithȱanyȱotherȱqueensȱonȱtheȱboard.ȱIfȱthereȱisȱ aȱconflict,ȱtheȱfunctionȱshouldȱmoveȱtheȱqueenȱtoȱtheȱnextȱcolumnȱofȱthatȱrowȱandȱ tryȱagain.ȱIfȱthereȱisȱaȱconflictȱinȱeveryȱcolumn,ȱtheȱfunctionȱshouldȱreturn.ȱ Ifȱ theȱ queenȱ canȱ beȱ placed,ȱ though,ȱ theȱ functionȱ shouldȱ thenȱ callȱ itselfȱ recursivelyȱtoȱplaceȱaȱqueenȱinȱtheȱnextȱrow.ȱȱWhenȱtheȱrecursiveȱcallȱreturns,ȱtheȱ functionȱ thenȱ movesȱ itsȱ queenȱ toȱ theȱ nextȱ column.ȱ Wheneverȱ aȱ queenȱ isȱ placedȱ successfullyȱinȱtheȱlastȱrow,ȱtheȱfunctionȱshouldȱprintȱtheȱchessboard,ȱshowingȱtheȱ locationsȱofȱtheȱeightȱqueens.ȱ Download at http://www.pin5i.com/ 9 Strings, Characters, and Bytes Stringsȱareȱanȱimportantȱtypeȱofȱdata,ȱyetȱCȱdoesȱnotȱhaveȱanȱexplicitȱstringȱdataȱtypeȱ becauseȱ stringsȱ areȱ storedȱ inȱ characterȱ arraysȱ orȱ asȱ stringȱ literals.ȱ Literalsȱ areȱ appropriateȱ forȱ stringsȱ thatȱ theȱ programȱ doesȱ notȱ needȱ toȱ modify.ȱ Allȱ otherȱ stringsȱ mustȱbeȱstoredȱinȱcharacterȱarraysȱorȱdynamicallyȱallocatedȱmemoryȱ(seeȱChapterȱ11).ȱȱ Thisȱchapterȱdescribesȱtheȱlibraryȱfunctionsȱthatȱdealȱwithȱstringsȱandȱcharactersȱandȱaȱ relatedȱ groupȱ ofȱ functionsȱ withȱ similarȱ capabilitiesȱ thatȱ dealȱ withȱ bothȱ stringȱ andȱ nonstringȱdata.ȱ ȱ ȱ ȱ 9.1 String Basics ȱ First,ȱletȇsȱreviewȱtheȱbasicsȱofȱstrings.ȱAȱstringȱisȱaȱsequenceȱofȱzeroȱorȱmoreȱcharactersȱ followedȱ byȱ aȱ NULȱ byte,ȱ whichȱ isȱ aȱ byteȱ whoseȱ bitsȱ areȱ allȱ zero.ȱ Therefore,ȱ itȱ isȱ notȱ possibleȱ forȱ aȱ stringȱ toȱ containȱ aȱ NULȱ asȱ oneȱ ofȱ itsȱ characters.ȱ Thisȱ restrictionȱ rarelyȱ causesȱproblemsȱbecauseȱthereȱisnȇtȱaȱprintableȱcharacterȱassociatedȱwithȱNUL,ȱwhichȱ isȱ whyȱ itȱ wasȱ chosenȱ asȱ aȱ terminator.ȱ Theȱ NULȱ terminatesȱ theȱ stringȱ butȱ isȱ notȱ consideredȱaȱpartȱofȱit,ȱsoȱtheȱlengthȱofȱaȱstringȱdoesȱnotȱincludeȱtheȱNUL.ȱ Theȱ headerȱ fileȱ string.hȱ containsȱ theȱ prototypesȱ andȱ declarationsȱ neededȱ toȱ useȱtheȱstringȱfunctions.ȱAlthoughȱitsȱuseȱisȱnotȱrequired,ȱitȱisȱaȱgoodȱideaȱtoȱincludeȱ thisȱheaderȱfileȱbecauseȱwithȱtheȱprototypesȱitȱcontainsȱtheȱcompilerȱcanȱdoȱaȱbetterȱjobȱ errorȱcheckingȱyourȱprogram. 37 ȱ Oldȱ Cȱ programsȱ oftenȱ didȱ notȱ includeȱ thisȱ file.ȱ Withoutȱ functionȱ prototypes,ȱ allȱ thatȱ couldȱ beȱ declaredȱ wasȱ theȱ typeȱ returnedȱbyȱeachȱfunction,ȱandȱtheȱvaluesȱreturnedȱbyȱmostȱofȱtheseȱfunctionsȱareȱignoredȱanyway.ȱ 37 Download at http://www.pin5i.com/ Chapter 9 Strings, Characters, and Bytes 244 9.2 String Length ȱ Theȱ lengthȱ ofȱ aȱ stringȱ isȱ theȱ numberȱ ofȱ charactersȱ itȱ contains.ȱ Theȱ lengthȱ isȱ easilyȱ computedȱ byȱ countingȱ theȱ characters,ȱ asȱ isȱ doneȱ inȱ Programȱ 9.1.ȱ Thisȱ implementationȱillustratesȱtheȱtypeȱofȱprocessingȱusedȱwhenȱdealingȱwithȱstrings,ȱbutȱ inȱ factȱ youȱ rarelyȱ needȱ toȱ writeȱ stringȱ functionsȱ becauseȱ theȱ onesȱ providedȱ inȱ theȱ standardȱ libraryȱ usuallyȱ willȱ doȱ theȱ job.ȱ Shouldȱ youȱ wishȱ toȱ writeȱ aȱ stringȱ function,ȱ though,ȱbeȱawareȱthatȱtheȱStandardȱreservesȱallȱfunctionȱnamesȱthatȱbeginȱwithȱstrȱforȱ futureȱexpansionȱofȱtheȱlibrary.ȱȱ Theȱprototypeȱforȱtheȱlibraryȱstrlenȱis:ȱ ȱ size_t CAUTION! strlen( char const *string ); ȱ Noteȱthatȱstrlenȱreturnsȱaȱvalueȱofȱtypeȱsize_t.ȱThisȱtypeȱisȱdefinedȱinȱtheȱincludeȱfileȱ stddef.hȱ andȱ isȱ anȱ unsignedȱ integerȱ type.ȱ Usingȱ unsignedȱ valuesȱ inȱ expressionsȱ canȱ leadȱ toȱ unexpectedȱ results.ȱ Forȱ example,ȱ theȱ followingȱ twoȱ statementsȱ appearȱ toȱ beȱ equivalent,ȱ ȱ if( strlen( x ) >= strlen( y ) ) ... if( strlen( x ) – strlen( y ) >= 0 ) ... ȱ butȱ theyȱ areȱ not.ȱ Theȱ firstȱ worksȱ asȱ youȱ wouldȱ expect,ȱ butȱ theȱ secondȱ oneȱ isȱ alwaysȱ true.ȱ Theȱ resultȱ ofȱ strlenȱ isȱ unsigned,ȱ soȱ theȱ expressionȱ onȱ theȱ leftȱ ofȱ theȱ >=ȱ isȱ unsigned,ȱandȱunsignedȱvaluesȱcanȱneverȱbeȱnegative.ȱ ȱ ȱ ȱ /* ** Compute the length of the string argument. */ #include <stddef.h> size_t strlen( char const *string ) { int length; for( length = 0; *string++ != '\0'; ) length += 1; return length; } ȱ Programȱ9.1ȱȱStringȱlengthȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱȱstrlen.cȱ Download at http://www.pin5i.com/ 9.3 Unrestricted String Functions CAUTION! 245 Expressionsȱ containingȱ bothȱ signedȱ andȱ unsignedȱ valuesȱ canȱ alsoȱ produceȱ strangeȱ results.ȱ Theȱ followingȱ statementsȱ areȱ notȱ equivalentȱ forȱ theȱ sameȱ reasonȱ asȱ theȱ previousȱpair.ȱ ȱ if( strlen( x ) >= 10 ) ... if( strlen( x ) - 10 >= 0 ) ... TIP ȱ Castingȱtheȱvalueȱreturnedȱbyȱstrlenȱtoȱanȱintȱeliminatesȱthisȱproblem.ȱ ȱ Itȱ isȱ temptingȱ toȱ writeȱ yourȱ ownȱ strlenȱ function,ȱ makingȱ judiciousȱ useȱ ofȱ registerȱ declarationsȱ andȱ cleverȱ tricksȱ toȱ makeȱ itȱ fasterȱ thanȱ theȱ libraryȱ function.ȱ Itȱ rarelyȱ works.ȱ Theȱ standardȱ libraryȱ functionsȱ areȱ sometimesȱ implementedȱ inȱ assemblyȱ languageȱ inȱ orderȱ toȱ exploitȱ theȱ speedȱ ofȱ specialȱ stringȱ manipulationȱ instructionsȱ providedȱbyȱcertainȱmachines.ȱȱEvenȱonȱmachinesȱwithoutȱsuchȱinstructions,ȱyourȱtimeȱ isȱ betterȱ spentȱ concentratingȱ onȱ theȱ algorithmsȱ forȱ otherȱ partsȱ ofȱ yourȱ program.ȱȱ Findingȱ aȱ betterȱ algorithmȱ isȱ moreȱ effectiveȱ thanȱ tuningȱ aȱ badȱ one,ȱ andȱ itȱ isȱ moreȱ efficientȱtoȱreuseȱexistingȱsoftwareȱthanȱtoȱreinventȱit.ȱ ȱ ȱ ȱ 9.3 Unrestricted String Functions ȱ Theȱ mostȱ commonlyȱ usedȱ stringȱ functionsȱ areȱ Ȉunrestricted,Ȉȱ meaningȱ thatȱ theyȱ determineȱ theȱ lengthȱ ofȱ theirȱ stringȱ argumentsȱ solelyȱ byȱ lookingȱ forȱ theȱ terminatingȱ NULȱbyte.ȱWhenȱusingȱtheseȱfunctions,ȱitȱisȱtheȱprogrammerȇsȱresponsibilityȱtoȱmakeȱ sureȱthatȱtheȱresultingȱstringȱdoesȱnotȱoverflowȱtheȱmemoryȱinȱwhichȱitȱisȱsupposedȱtoȱ fit.ȱThisȱproblemȱisȱdescribedȱinȱmoreȱdetailȱforȱeachȱofȱtheȱfunctionsȱdiscussedȱinȱthisȱ section.ȱ ȱ ȱ ȱ 9.3.1 Copying Strings ȱ Stringsȱareȱcopiedȱusingȱstrcpyȱwhoseȱprototypeȱisȱshownȱbelow.ȱ ȱ ȱ char *strcpy( char *dst, char const *src ); ȱ ThisȱfunctionȱcopiesȱtheȱstringȱfromȱtheȱsrcȱargumentȱintoȱtheȱdstȱargumentȱIfȱtheȱsrcȱ andȱ dstȱargumentsȱoverlap,ȱtheȱresultȱisȱundefined.ȱ Becauseȱitȱisȱmodified,ȱ dstȱmustȱ beȱ aȱ characterȱ arrayȱ orȱ aȱ pointerȱ toȱ anȱ arrayȱ orȱ toȱ dynamicallyȱ allocatedȱ memory.ȱ Aȱ stringȱ literalȱ mayȱ notȱ beȱ used.ȱ Theȱ functionȱ returnsȱ aȱ value,ȱ whichȱ isȱ describedȱ inȱ Sectionȱ9.3.3.ȱ Theȱpreviousȱcontentsȱofȱtheȱdestinationȱargumentȱareȱoverwrittenȱandȱareȱlost.ȱ Evenȱifȱtheȱnewȱstringȱisȱshorterȱthanȱtheȱoldȱcontentsȱofȱdst,ȱtheȱlastȱcharactersȱofȱtheȱȱ Download at http://www.pin5i.com/ 246 Chapter 9 Strings, Characters, and Bytes previousȱstringȱareȱeffectivelyȱerasedȱbecauseȱtheyȱappearȱafterȱtheȱterminatingȱNULȱ byteȱofȱtheȱnewȱstring.ȱ Considerȱthisȱexample:ȱ char message[] = "Original message"; ... if( ... ) strcpy( mesaage, "Different" ); Ifȱtheȱconditionȱisȱtrueȱandȱtheȱcopyȱisȱperformed,ȱtheȱarrayȱwillȱcontainȱtheȱfollowing:ȱ ȱ TheȱcharactersȱafterȱtheȱfirstȱNULȱbyteȱareȱneverȱaccessedȱbyȱtheȱstringȱfunctionsȱandȱ are,ȱforȱallȱpracticalȱpurposes,ȱlost.ȱ ȱ ȇDȇȱ ȇiȇȱ CAUTION! ȇfȇȱ ȇfȇȱ ȇeȇȱ ȇrȇȱ ȇeȇȱ ȇnȇȱ ȇtȇȱ 0ȱ ȇeȇȱ ȇsȇȱ ȇsȇȱ ȇaȇȱ ȇgȇȱ ȇeȇȱ 0ȱ ȱ Itȱisȱupȱtoȱtheȱprogrammerȱtoȱmakeȱsureȱthatȱtheȱdestinationȱarrayȱisȱlargeȱenoughȱtoȱ holdȱ theȱ string.ȱ Ifȱ theȱ stringȱ isȱ longerȱ thanȱ theȱ array,ȱ theȱ excessȱ charactersȱ willȱ beȱ copiedȱ anywayȱ andȱ willȱ overwriteȱ whateverȱ valuesȱ happenȱ toȱ beȱ afterȱ theȱ arrayȱ inȱ memory,ȱȱ strcpyȱisȱunableȱtoȱavoidȱthisȱproblemȱbecauseȱitȱcannotȱdetermineȱtheȱsizeȱ ofȱtheȱdestinationȱarray.ȱForȱexample:ȱ ȱ ȱ char message[] = "Original message"; ... strcpy( message, "A different message" ); ȱ Theȱsecondȱstringȱisȱtooȱlongȱtoȱfitȱinȱtheȱarray,ȱsoȱtheȱstrcpyȱwillȱrunȱoffȱtheȱendȱofȱtheȱ arrayȱandȱoverwriteȱwhateverȱvariablesȱhappenȱtoȱfollowȱitȱinȱmemory.ȱYouȱcanȱavoidȱ aȱ lotȱ ofȱ debuggingȱ byȱ makingȱ sureȱ thatȱ theȱ destinationȱ argumentȱ isȱ largeȱ enoughȱ beforeȱcallingȱstrcpy.ȱ ȱ ȱ ȱ 9.3.2 Concatenating Strings ȱ Toȱappendȱ(concatenate)ȱoneȱstringȱtoȱtheȱendȱofȱanother,ȱstrcatȱisȱusedȱprototypeȱis:ȱ ȱ ȱ char *strcat( char *dst, char const *src ); ȱ strcatȱrequiresȱthatȱ dstȱalreadyȱcontainȱaȱ(possiblyȱempty)ȱstring.ȱȱItȱfindsȱtheȱendȱofȱ thisȱstring,ȱandȱappendsȱtoȱitȱaȱcopyȱofȱtheȱstringȱfromȱ src.ȱIfȱtheȱ srcȱandȱ dstȱstringsȱ overlap,ȱtheȱresultȱisȱundefined.ȱ Download at http://www.pin5i.com/ 9.3 Unrestricted String Functions 247 Theȱfollowingȱexampleȱshowsȱaȱcommonȱuseȱofȱthisȱfunction.ȱ ȱ strcpy( message, "Hello " ); strcat( message, customer_name ); strcat( message, ", how are you?" ); ȱ Eachȱ ofȱ theȱ argumentsȱ toȱ strcatȱ areȱ appendedȱ toȱ theȱ stringȱ alreadyȱ inȱ message.ȱ Theȱ resultȱisȱaȱstringȱsuchȱasȱthisȱone:ȱ ȱ Hello Jim, how are you? ȱ Onceȱagain,ȱtheȱprogrammerȱmustȱensureȱthatȱthereȱisȱenoughȱspaceȱremainingȱinȱtheȱ destinationȱarrayȱtoȱholdȱtheȱentireȱsourceȱstring.ȱButȱthisȱtimeȱitȱisȱincorrectȱtoȱsimplyȱ compareȱ theȱ lengthȱ ofȱ theȱ sourceȱ stringȱ withȱ theȱ sizeȱ ofȱ theȱ array.ȱ ȱ Youȱ mustȱ alsoȱ accountȱforȱtheȱlengthȱofȱdieȱexistingȱstring.ȱ ȱ ȱ ȱ 9.3.3 Function Return Value ȱ Bothȱstrcpyȱandȱ strcatȱreturnȱaȱcopyȱofȱtheirȱfirstȱargument,ȱwhichȱisȱaȱpointerȱtoȱtheȱ destinationȱ array.ȱ Becauseȱ ofȱ thisȱ value,ȱ youȱ canȱ nestȱ callsȱ toȱ theseȱ functions,ȱ asȱ illustratedȱinȱtheȱfollowingȱexample.ȱ ȱ strcat( strcpy( dst, a ), b ); ȱ ȱ Theȱstrcpyȱisȱperformedȱfirst.ȱItȱcopiesȱtheȱstringȱfromȱaȱintoȱdetȱandȱreturnsȱtheȱvalueȱ dst.ȱ Theȱ returnedȱ valueȱ becomesȱ theȱ firstȱ argumentȱ toȱ strcat,ȱ whichȱ appendsȱ theȱ stringȱinȱbȱtoȱdst.ȱ Thisȱnestedȱstyleȱdoesȱnotȱhaveȱaȱfunctionalȱadvantageȱoverȱtheȱmoreȱreadableȱ ȱ strcpy( dst, a ); strcpy( dst, b ); ȱ Indeed,ȱtheȱvaluesȱreturnedȱbyȱtheȱvastȱmajorityȱofȱcallsȱtoȱtheseȱfunctionsȱareȱsimplyȱ ignored.ȱ ȱ ȱ ȱ 9.3.4 String Comparisons ȱ Comparingȱtwoȱstringsȱinvolvesȱcomparingȱtheȱcorrespondingȱcharactersȱinȱthem,ȱoneȱ byȱone,ȱuntilȱaȱmismatchȱisȱfound.ȱTheȱstringȱfromȱwhichȱtheȱȈlowerȈȱcharacterȱ(thatȱis,ȱ theȱcharacterȱnearerȱtheȱbeginningȱofȱtheȱcharacterȱ set)ȱcameȱisȱsaidȱtoȱ beȱ ȈlessȱthanȈȱ theȱ otherȱ string.ȱ Ifȱ oneȱ stringȱ isȱ aȱ prefixȱ ofȱ theȱ other,ȱ itȱ willȱ beȱ Ȉlessȱ thanȈȱ theȱ otherȱ stringȱbecauseȱitsȱterminatingȱNULȱisȱreachedȱfirst.ȱCalledȱaȱlexicographicȱcomparison,ȱ Download at http://www.pin5i.com/ 248 Chapter 9 Strings, Characters, and Bytes thisȱ processȱ givesȱ theȱ sameȱ resultȱ asȱ anȱ everydayȱ alphabeticȱ orderingȱ forȱ stringsȱ containingȱonlyȱuppercaseȱorȱonlyȱlowercaseȱcharacters.ȱ Theȱlibraryȱfunctionȱstrcmpȱcomparesȱtwoȱstringȱarguments,ȱȱitsȱprototypeȱis:ȱ ȱ int CAUTION! strcmp( char const *s1, char const *s2 ); ȱ strcmpȱreturnsȱaȱvalueȱlessȱthanȱzeroȱifȱs1ȱisȱlessȱthanȱs2;ȱaȱvalueȱgreaterȱthanȱzeroȱifȱs1ȱ isȱgreaterȱthanȱs2;ȱandȱzeroȱifȱtheȱtwoȱstringsȱareȱequal.ȱ ȱ Beginnersȱoftenȱwriteȱ ȱ if( strcmp( a, b ) ) CAUTION! CAUTION! ȱ andȱassumeȱthatȱtheȱresultȱreturnedȱwillȱbeȱtrueȱifȱtheȱstringsȱareȱequal.ȱTheȱresultȱisȱ justȱ theȱ oppositeȱ though,ȱ becauseȱ zeroȱ (false)ȱ isȱ returnedȱ inȱ thisȱ case.ȱ However,ȱ itȱ isȱ badȱstyleȱtoȱtestȱthisȱvalueȱasȱifȱitȱwereȱbooleanȱbecauseȱitȱhasȱthreeȱdistinctȱoutcomes:ȱ less,ȱequal,ȱandȱgreater.ȱComparingȱtheȱvalueȱtoȱzeroȱisȱthereforeȱpreferred.ȱ ȱ Noteȱ thatȱ theȱ Standardȱ doesȱ notȱ specifyȱ theȱ specificȱ valuesȱ usedȱ toȱ indicateȱ inequalities.ȱItȱonlyȱstatesȱthatȱtheȱvalueȱreturnedȱbeȱgreaterȱthanȱzeroȱifȱtheȱfirstȱstringȱ isȱ greaterȱ thanȱ theȱ secondȱ andȱ beȱ lessȱ thanȱ zeroȱ ifȱ theȱ firstȱ stringȱ isȱ lessȱ thanȱ theȱ second.ȱAȱcommonȱmistakeȱisȱtoȱassumeȱthatȱtheȱvaluesȱ1ȱandȱȬ1ȱwillȱbeȱreturned,ȱbutȱ thisȱassumptionȱisȱnotȱalwaysȱcorrect.ȱ ȱ Becauseȱ strcmpȱ doesȱ notȱ changeȱ eitherȱ ofȱ itsȱ arguments,ȱ thereȱ isnȇtȱ anyȱ dangerȱ ofȱ overflowingȱ anȱ array.ȱ However,ȱ asȱ withȱ theȱ otherȱ unrestrictedȱ stringȱ functions,ȱ theȱ stringȱ argumentsȱ mustȱ beȱ NULȱ terminated.ȱ Ifȱ theyȱ areȱ not,ȱ strcmpȱ willȱ continueȱ comparingȱbytesȱbeyondȱtheȱendȱofȱtheȱdata,ȱandȱtheȱresultȱwillȱhaveȱnoȱmeaning.ȱ ȱ ȱ ȱ 9.4 Length-Restricted String Functions ȱ Theȱ libraryȱ includesȱ severalȱ functionsȱ thatȱ dealȱ withȱ stringsȱ inȱ aȱ differentȱ way.ȱ Thisȱ groupȱofȱfunctionsȱtakesȱanȱexplicitȱlengthȱargumentȱthatȱlimitsȱhowȱmanyȱcharactersȱ canȱ beȱ copiedȱ orȱ compared.ȱ Theseȱ functionsȱ provideȱ anȱ easyȱ mechanismȱ toȱ preventȱ unexpectedlyȱlongȱstringsȱfromȱoverflowingȱtheirȱdestinations.ȱ Theȱ prototypesȱ forȱ theseȱ functionsȱ areȱ shownȱ onȱ theȱ nextȱ page.ȱ Likeȱ theirȱ unrestrictedȱcousins,ȱtheȱresultsȱfromȱ strncpyȱandȱ strncatȱareȱundefinedȱifȱtheȱsourceȱ andȱdestinationȱargumentsȱoverlap.ȱ ȱ Download at http://www.pin5i.com/ 9.4 Length-Restricted String Functions char char int CAUTION! CAUTION! 249 *strncpy( char *dst, char const *src, size_t len ); *strncat( char *dst, char const *src, size_t len ); strncmp( char const *s1, char const *s2, size_t len ); ȱ Likeȱ scrcpy,ȱ strncpyȱcopiesȱcharactersȱfromȱtheȱsourceȱstringȱtoȱtheȱdestinationȱarray.ȱ However,ȱitȱalwaysȱwritesȱexactlyȱ lenȱcharactersȱtoȱ dst.ȱIfȱ strlen( src )ȱisȱlessȱthanȱ len,ȱthenȱdstȱisȱpaddedȱtoȱaȱlengthȱofȱ lenȱwithȱadditionalȱNULȱcharacters.ȱȱIfȱ strlen( src )ȱisȱgreaterȱthanȱorȱequalȱtoȱ len,ȱthenȱonlyȱ lenȱcharactersȱwillȱbeȱwrittenȱtoȱ dst,ȱ andȱtheȱresultȱwillȱnotȱbeȱNULȬterminated!ȱ ȱ Theȱ resultȱ ofȱ aȱ callȱ toȱ strncpyȱ mightȱ notȱ beȱ aȱ string,ȱ becauseȱ stringsȱ mustȱ beȱ terminatedȱwithȱaȱNULȱbyte.ȱWhatȱhappensȱifȱanȱunterminatedȱsequenceȱofȱcharactersȱ isȱ usedȱ whereȱ aȱ stringȱ isȱ required,ȱ forȱ example,ȱ asȱ anȱ argumentȱ toȱ strlen?ȱ Theȱ functionȱ willȱ beȱ unableȱ toȱ tellȱ thatȱ theȱ NULȱ isȱ missing,ȱ soȱ itȱ willȱ continueȱ looking,ȱ characterȱ byȱ character,ȱ untilȱ itȱ findsȱ one.ȱ Itȱ mightȱ notȱ findȱ oneȱ untilȱ hundredsȱ ofȱ charactersȱ later,ȱ andȱ theȱ valueȱ returnedȱ byȱ strlenȱ willȱ essentiallyȱ beȱ aȱ randomȱ number.ȱ Or,ȱ theȱ programȱ mightȱ crashȱ tryingȱ toȱ accessȱ memoryȱ beyondȱ whatȱ wasȱ allocatedȱtoȱitȱ ȱ Thisȱproblemȱonlyȱoccursȱwhenȱyouȱcreateȱstringsȱwithȱtheȱstrncpyȱfunction,ȱandȱthenȱ eitherȱ useȱ themȱ withȱ theȱ str---ȱ functionsȱ orȱ printȱ themȱ withȱ theȱ %sȱ formatȱ codeȱ ofȱ printf.ȱBeforeȱusingȱtheȱunrestrictedȱfunctions,ȱyouȱmustȱfirstȱensureȱthatȱtheȱstringȱisȱ actuallyȱNULȬterminated.ȱForȱexample,ȱconsiderȱthisȱcodeȱfragment:ȱ ȱ char buffer[BSIZE]; ... strncpy( buffer, name, BSIZE ); buffer[BSIZE – 1] = '\0'; ȱ Ifȱtheȱcontentsȱofȱnameȱfitȱintoȱbuffer,ȱtheȱassignmentȱhasȱnoȱeffect.ȱIfȱnameȱisȱtooȱlong,ȱ though,ȱ theȱ assignmentȱ ensuresȱ thatȱ theȱ stringȱ inȱ bufferȱ isȱ properlyȱ terminated.ȱ Subsequentȱ callsȱ toȱ strlenȱ orȱ otherȱ unrestrictedȱ stringȱ functionsȱ onȱ thisȱ arrayȱ willȱ workȱproperly.ȱ Althoughȱ strncatȱisȱalsoȱaȱlengthȬrestrictedȱfunction,ȱitȱworksȱdifferentlyȱthanȱ strncpy.ȱ Itȱ appendsȱ upȱ toȱ lenȱ charactersȱ fromȱ srcȱ toȱ theȱ destinationȱ string.ȱ Butȱ strncatȱalwaysȱappendsȱaȱNULȱcharacterȱtoȱtheȱendȱofȱtheȱresult,ȱandȱitȱdoesȱnotȱpadȱ theȱ resultȱ withȱ NULsȱ likeȱ strncpy.ȱ Noteȱ thatȱ theȱ lengthȱ ofȱ theȱ existingȱ stringȱ inȱ theȱ destinationȱarrayȱisȱnotȱaccountedȱforȱbyȱstrncat.ȱItȱcanȱwriteȱupȱtoȱlenȱcharactersȱplusȱ aȱ terminatingȱ NULȱ byteȱ regardlessȱ ofȱ whetherȱ theȱ initialȱ contentsȱ ofȱ theȱ destinationȱ argumentȱleaveȱenoughȱroomȱforȱthem.ȱ Download at http://www.pin5i.com/ 250 Chapter 9 Strings, Characters, and Bytes Finally,ȱ strncmpȱcomparesȱupȱtoȱ lenȱcharactersȱofȱtwoȱstrings.ȱIfȱtheȱstringsȱareȱ unequalȱ beforeȱ orȱ atȱ theȱ lenȇthȱ character,ȱ theȱ comparisonȱ stopsȱ asȱ itȱ wouldȱ withȱ strcmp.ȱIfȱtheȱfirstȱlenȱcharactersȱofȱtheȱstringsȱareȱequal,ȱvalueȱzeroȱisȱreturned.ȱ ȱ ȱ ȱ 9.5 Basic String Searching ȱ Thereȱareȱmanyȱfunctionsȱinȱtheȱlibraryȱthatȱsearchȱstringsȱinȱvariousȱways.ȱThisȱwideȱ varietyȱofȱtoolsȱgivesȱtheȱCȱprogrammerȱgreatȱflexibility.ȱ ȱ ȱ ȱ 9.5.1 Finding a Character ȱ Theȱeasiestȱwayȱtoȱlocateȱaȱspecificȱcharacterȱinȱaȱstringȱisȱwithȱtheȱstrchrȱandȱstrrchrȱ functions,ȱwhoseȱprototypesȱare:ȱ ȱ char char *strchr( char const *str, int ch ); *strrchr( char const *str, int char ); ȱ Noteȱ thatȱ theȱ secondȱ argumentȱ isȱ anȱ integer.ȱ Itȱ containsȱ aȱ characterȱ value,ȱ however.ȱ strchrȱsearchesȱ theȱstringȱ strȱtoȱ findȱtheȱfirstȱoccurrenceȱ ofȱtheȱcharacterȱ ch.ȱ Thenȱ aȱ pointerȱtoȱthisȱpositionȱisȱreturned.ȱIfȱtheȱcharacterȱdoesȱnotȱappearȱatȱallȱinȱtheȱstring,ȱ aȱ NULLȱ pointerȱ isȱ returned.ȱ strrchrȱ worksȱ exactlyȱ theȱ sameȱ exceptȱ thatȱ itȱ returnsȱ aȱ pointerȱtoȱtheȱlastȱ(rightmost)ȱoccurrenceȱofȱtheȱcharacter.ȱ Hereȱisȱanȱexample;ȱ ȱ char char string[20] = "Hello there, honey."; *ans; ans = strchr( string, 'h' ); ȱ ansȱwillȱgetȱtheȱvalueȱ string + 7ȱbecauseȱtheȱfirstȱ 'h'ȱappearsȱinȱthisȱposition.ȱNoteȱ thatȱcaseȱisȱsignificant.ȱ ȱ ȱ ȱ 9.5.2 Finding Any of Several Characters ȱ Theȱstrpbrkȱfunctionȱisȱmoreȱgeneral.ȱInsteadȱofȱsearchingȱforȱoneȱspecificȱcharacter,ȱitȱ looksȱforȱtheȱfirstȱoccurrenceȱofȱanyȱofȱgroupȱofȱcharacters.ȱItsȱprototypeȱis:ȱ ȱ Download at http://www.pin5i.com/ 9.6 Advanced String Searching char 251 *strpbrk( char const *str, char const *group ); ȱ Thisȱ functionȱ returnsȱ aȱ pointerȱ toȱ theȱ firstȱ characterȱ inȱ strȱ thatȱ matchesȱ anyȱ ofȱ theȱ charactersȱinȱgroup,ȱorȱNULLȱifȱnoneȱmatched.ȱ Inȱtheȱfollowingȱcodeȱfragment,ȱ ȱ char char string[20] = "Hello there, honey."; *ans; ans = strpbrk( string, "aeiou" ); ȱ ansȱwillȱgetȱtheȱvalueȱ string + 1ȱbecauseȱthisȱpositionȱisȱtheȱfirstȱthatȱcontainsȱanyȱofȱ theȱcharactersȱinȱtheȱsecondȱargument.ȱȱOnceȱagain,ȱcaseȱisȱsignificant.ȱ ȱ ȱ ȱ 9.5.3 Finding a Substring ȱ Toȱlocateȱaȱsubstring,ȱstrstrȱisȱused.ȱItsȱprototypeȱis:ȱ ȱ ȱ char *strstr( char const *s1, char const *s2 ); ȱ Thisȱfunctionȱfindsȱtheȱfirstȱplaceȱinȱ s1ȱwhereȱtheȱentireȱstringȱ s2ȱbeginsȱandȱreturnsȱaȱ pointerȱ toȱ thisȱ location.ȱ Ifȱ s2ȱ doesȱ notȱ appearȱ inȱ itsȱ entiretyȱ anywhereȱ inȱ s1,ȱ thenȱ NULLȱisȱreturned.ȱIfȱtheȱsecondȱargumentȱisȱanȱemptyȱstring,ȱthenȱs1ȱisȱreturned.ȱ Theȱ standardȱ libraryȱ includesȱ neitherȱ aȱ strrstrȱ norȱ aȱ strrpbrkȱ function,ȱ butȱ theyȱ areȱ easyȱ toȱ implementȱ ifȱ youȱ needȱ them.ȱ Programȱ 9.2ȱ showsȱ oneȱ wayȱ ofȱ implementingȱstrrstr.ȱTheȱsameȱtechniqueȱcouldȱbeȱusedȱforȱstrrpbrk.ȱ ȱ ȱ ȱ 9.6 Advanced String Searching ȱ Theȱ nextȱ groupȱ ofȱ functionsȱ simplifyȱ theȱ locationȱ andȱ extractionȱ ofȱ individualȱ substringsȱfromȱaȱstring.ȱ ȱ ȱ ȱ 9.6.1 Finding String Prefixes ȱ Theȱ strspnȱandȱ strcspnȱfunctionsȱcountȱcharactersȱatȱtheȱbeginningȱofȱaȱstring.ȱTheirȱ prototypesȱareȱshownȱatȱtheȱtopȱofȱpageȱ253.ȱ Download at http://www.pin5i.com/ 252 Chapter 9 Strings, Characters, and Bytes ȱ /* ** Look in the string s1 for the rightmost occurrence of the string ** s2, and return a pointer to where it begins. */ #include <string.h> char * my_strrstr( char const *s1, char const *s2 ) { register char *last; register char *current; /* ** Initialize pointer for the last match we've found. */ last = NULL; /* ** Search only if the second string is not empty. If s2 is ** empty, return NULL. */ if( *s2 != '\0' ){ /* ** Find the first place where s2 appears in s1. */ current = strstr( s1, s2 ); /* ** Each time we find the string, save the pointer to ** where it begins. Then look after the string for ** another occurrence. */ while( current != NULL ){ last = current; current = strstr( last + 1, s2 ); } } /* ** Return pointer to the last occurrence we found. */ return last; } Programȱ9.2ȱȱFindȱrightmostȱoccurrenceȱofȱaȱsubstringȱȱ ȱ ȱ ȱ ȱ mstrrstr.cȱ Download at http://www.pin5i.com/ 9.6 Advanced String Searching 253 size_t strspn( char const *str, char const *group ); size_t strcspn( char const *str, char const *group ); ȱ Theȱ groupȱ stringȱ specifiesȱ oneȱ orȱ moreȱ characters.ȱ strspnȱ returnsȱ theȱ numberȱ ofȱ charactersȱatȱtheȱbeginningȱofȱ strȱthatȱmatchȱanyȱofȱtheseȱcharacters.ȱForȱexample,ȱifȱ groupȱcontainedȱtheȱwhitespaceȱcharactersȱspace,ȱtab,ȱandȱsoȱforth,ȱthisȱfunctionȱwouldȱ returnȱ theȱ numberȱ ofȱ whitespaceȱ charactersȱ foundȱ atȱ theȱ beginningȱ ofȱ str.ȱ Theȱ nextȱ characterȱofȱstrȱwouldȱbeȱtheȱfirstȱnonȬwhitespaceȱcharacter.ȱ Considerȱthisȱexample:ȱ ȱ int char len1, len2; buffer[] = "25,142,330,Smith,J,239-4123"; len1 = strspn( buffer, "0123456789" ); len2 = strspn( buffer, ",0123456789" ); ȱ Ofȱ course,ȱ theȱ bufferȱ wouldȱ notȱ normallyȱ beȱ initializedȱ inȱ thisȱ manner;ȱ itȱ wouldȱ containȱ dataȱ readȱ inȱ atȱ runȱ time.ȱ Butȱ withȱ thisȱ valueȱ inȱ theȱ buffer,ȱ theȱ variableȱ len1ȱ wouldȱbeȱsetȱtoȱtwo,ȱandȱtheȱvariableȱlen2ȱwouldȱbeȱsetȱtoȱ11.ȱTheȱfollowingȱcodeȱwillȱ computeȱaȱpointerȱtoȱtheȱfirstȱnonȬwhitespaceȱcharacterȱinȱaȱstring.ȱ ȱ ȱ ptr = buffer + strspn( buffer, " \n\r\f\t\v" ); ȱ strcspnȱ worksȱ similarlyȱ exceptȱ thatȱ onlyȱ charactersȱ thatȱ areȱ notȱ inȱ groupȱ areȱ counted.ȱTheȱ cȱinȱtheȱnameȱ strcspnȱcomesȱfromȱtheȱnotionȱthatȱtheȱcharacterȱgroupȱisȱ complemented,ȱthatȱis,ȱexchangedȱforȱallȱofȱtheȱcharactersȱitȱdidȱnotȱoriginallyȱcontain.ȱIfȱ youȱusedȱtheȱstringȱȈ \n\r\f\t\vȈȱforȱtheȱgroupȱargument,ȱthisȱfunctionȱwouldȱreturnȱ theȱnumberȱofȱnonȬwhitespaceȱcharactersȱfoundȱatȱtheȱbeginningȱofȱtheȱfirstȱargument.ȱ ȱ ȱ ȱ 9.6.2 Finding Tokens ȱ Aȱstringȱoftenȱcontainsȱseveralȱindividualȱpartsȱthatȱareȱsomehowȱseparatedȱfromȱeachȱ other.ȱToȱprocessȱtheseȱpartsȱoneȱatȱaȱtime,ȱyouȱmustȱfirstȱextractȱthemȱfromȱtheȱstring.ȱ ȱ Thisȱtaskȱisȱexactlyȱwhatȱtheȱstrtokȱfunctionȱaccomplishes.ȱItȱisolatesȱindividualȱ parts,ȱcalledȱtokens,ȱfromȱaȱstringȱandȱdiscardsȱtheȱseparators.ȱItsȱprototypeȱis:ȱ Download at http://www.pin5i.com/ 254 Chapter 9 Strings, Characters, and Bytes char *strtok( char *str, char const *sep ); ȱ CAUTION! Theȱ sepȱ argumentȱ isȱ aȱ stringȱ thatȱ definesȱ theȱ setȱ ofȱ charactersȱ thatȱ areȱ usedȱ asȱ separators.ȱ Theȱ firstȱ argumentȱ specifiesȱ aȱ stringȱ thatȱ isȱ assumedȱ toȱ containȱ zeroȱ orȱ moreȱ tokensȱ separatedȱ fromȱ oneȱ anotherȱ byȱ oneȱ orȱ moreȱ charactersȱ fromȱ theȱ sepȱ string. strtokȱfindsȱandȱNULȬterminatesȱtheȱnextȱtokenȱinȱ str,ȱandȱreturnsȱaȱpointerȱ toȱtheȱtoken.ȱ ȱ Whileȱitȱisȱdoingȱitsȱwork,ȱ strtokȱmodifiesȱtheȱstringȱthatȱitȱisȱprocessing.ȱIfȱtheȱstringȱ mustȱnotȱbeȱchanged,ȱcopyȱitȱandȱuseȱstrtokȱonȱtheȱcopy.ȱ Ifȱtheȱfirstȱargumentȱtoȱ strtokȱisȱnotȱNULL,ȱtheȱfunctionȱfindsȱtheȱfirstȱtokenȱinȱ theȱstring,ȱ strtokȱalsoȱsavesȱitsȱpositionȱinȱtheȱstring.ȱIfȱtheȱfirstȱargumentȱtoȱ strtokȱisȱ NULL,ȱtheȱfunctionȱusesȱtheȱsavedȱpositionȱtoȱfindȱtheȱnextȱtokenȱfromȱtheȱsameȱstringȱ asȱ before.ȱ strtokȱ returnsȱ aȱ NULLȱ pointerȱ whenȱ thereȱ arenȇtȱ anyȱ moreȱ tokensȱ inȱ theȱ string.ȱTypically,ȱaȱpointerȱtoȱaȱstringȱisȱpassedȱonȱtheȱfirstȱcallȱtoȱ strtok.ȱTheȱfunctionȱ isȱthenȱcalledȱrepeatedlyȱwithȱNULLȱfirstȱargumentȱuntilȱitȱreturnsȱNULL.ȱ Programȱ9.3ȱisȱaȱshortȱexample.ȱThisȱfunctionȱextractsȱtokensȱfromȱitsȱargumentȱ andȱ printsȱ themȱ oneȱ perȱ line.ȱ Theȱ tokensȱ areȱ separatedȱ byȱ whiteȱ space.ȱ Doȱ notȱ beȱ confusedȱ byȱ theȱ appearanceȱ ofȱ theȱ forȱ statement.ȱ Itȱ wasȱ brokenȱ ontoȱ threeȱ linesȱ becauseȱofȱitsȱlength.ȱ ȱ ȱ ȱ ȱ /* ** Extract whitespace-delimited tokens from a character array and ** print them one per line. */ #include <stdio.h> #include <string.h> void print_tokens( char *line ) { static char whitespace[] = " \t\f\r\v\n"; char *token; for( token = strtok( line, whitespace ); token != NULL; token = strtok( NULL, whitespace ) ) printf( "Next token is %s\n", token ); } ȱ Programȱ9.3ȱȱExtractȱtokensȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱtoken.c Download at http://www.pin5i.com/ 9.8 Character Operations CAUTION! 255 Ifȱ youȱ wish,ȱ youȱ mayȱ useȱ differentȱ separatorȱ setsȱ inȱ eachȱ callȱ toȱ strtok.ȱ Thisȱ techniqueȱisȱhandyȱwhenȱdifferentȱpartsȱofȱaȱstringȱareȱseparatedȱbyȱdifferentȱgroupsȱ ofȱcharacters.ȱ ȱ Becauseȱ strtokȱsavesȱlocalȱstateȱinformationȱaboutȱtheȱstringȱitȱisȱparsing,ȱyouȱcannotȱ useȱ itȱ toȱ parseȱ twoȱ stringsȱ concurrently.ȱ Thus,ȱ Programȱ 9.3ȱ wouldȱ failȱ ifȱ theȱ bodyȱ ofȱ theȱforȱloopȱcalledȱaȱfunctionȱthatȱalsoȱcalledȱstrtok.ȱ ȱ ȱ ȱ 9.7 Error Messages ȱ Whenȱ callsȱ areȱ madeȱ toȱ theȱ operatingȱ systemȱ toȱ performȱ functions,ȱ suchȱ asȱ openingȱ files,ȱerrorsȱthatȱoccurȱareȱreportedȱbyȱsettingȱanȱexternalȱintegerȱvariableȱcalledȱ errnoȱ toȱanȱerrorȱcode.ȱTheȱ strerrorȱfunctionȱtakesȱoneȱofȱtheseȱerrorȱcodesȱasȱanȱargumentȱ andȱreturnsȱaȱpointerȱtoȱaȱmessageȱdescribingȱtheȱerror.ȱTheȱprototypeȱofȱthisȱfunctionȱ is:ȱ ȱ ȱ char *strerror( in error_number ); ȱ Inȱfact,ȱtheȱreturnedȱvalueȱoughtȱtoȱbeȱdeclaredȱconst,ȱbecauseȱyouȱareȱnotȱsupposedȱtoȱ modifyȱit.ȱ ȱ ȱ ȱ 9.8 Character Operations ȱ Theȱ libraryȱ includesȱ twoȱ groupsȱ ofȱ functionsȱ thatȱ operateȱ onȱ individualȱ characters,ȱ prototypedȱinȱtheȱincludeȱfileȱctype.h.ȱTheȱfirstȱgroupȱisȱusedȱinȱclassifyingȱcharacters,ȱ andȱtheȱsecondȱgroupȱtransformsȱthem.ȱ ȱ ȱ ȱ 9.8.1 Character Classification ȱ Eachȱclassificationȱfunctionȱtakesȱanȱintegerȱargumentȱthatȱcontainsȱaȱcharacterȱvalue.ȱ Theȱfunctionȱtestsȱtheȱcharacterȱandȱreturnsȱanȱintegerȱtrueȱorȱfalseȱvalue. 38 ȱTableȱ9.1ȱ listsȱtheȱclassificationȱfunctionsȱandȱtheȱtestȱthatȱeachȱperforms.ȱ 38 ȱNoteȱthatȱtheȱStandardȱdoesȱnotȱspecifyȱanyȱparticularȱvalue,ȱsoȱanyȱnonzeroȱvalueȱmightȱbeȱreturned.ȱ Download at http://www.pin5i.com/ Chapter 9 Strings, Characters, and Bytes 256 ȱ Function iscntrl isspace isdigit isxdigit islower isupper isalpha isalnum ispunct isgraph isprint Returns True if its Argument is anyȱcontrolȱcharacterȱ aȱwhitespaceȱcharacter:ȱspaceȱ' ',ȱformȱfeedȱ'\f',ȱnewlineȱ'\n',ȱcarriageȱreturnȱlabȱ '\t',ȱorȱverticalȱtabȱ'\v'.ȱ aȱdecimalȱdigitȱ0ȱthroughȱ9.ȱ aȱhexadecimalȱdigit,ȱwhichȱincludesȱtheȱdecimalȱdigitsȱandȱtheȱlettersȱaȱthroughȱfȱandȱ AȱthroughȱF.ȱ aȱlowercaseȱletterȱaȱthroughȱz.ȱ anȱuppercaseȱletterȱAȱthroughȱZ.ȱ anȱalphabeticȱcharacterȱaȱthroughȱzȱorȱAȱthroughȱZ.ȱ anȱalphabeticȱorȱaȱnumericȱcharacterȱaȱthroughȱz,ȱAȱthroughȱZ,ȱorȱ0ȱthroughȱ9.ȱ punctuation:ȱanyȱcharacterȱwithȱaȱgraphicȱ(printableȱsymbol)ȱassociatedȱwithȱitȱthatȱisȱ notȱalphanumeric.ȱ anyȱcharacterȱwithȱaȱgraphicȱassociatedȱwithȱit.ȱ anyȱprintingȱcharacter,ȱwhichȱincludesȱtheȱgraphicȱcharactersȱandȱtheȱspaceȱcharacter. ȱ Tableȱ9.1ȱȱCharacterȱclassificationȱfunctionsȱ ȱ ȱ ȱ 9.8.2 Character Transformation ȱ Theȱ transformationȱ functionsȱ translateȱ uppercaseȱ charactersȱ toȱ lowercaseȱ andȱ viceȱ versa.ȱ ȱ ȱ int int tolower( int ch ); toupper( int ch ); toupperȱ returnsȱ theȱ uppercaseȱ equivalentȱ ofȱ itsȱ argument,ȱ andȱ tolowerȱ returnsȱ theȱ TIP lowercaseȱ equivalentȱ ofȱ itsȱ argument.ȱ Ifȱ theȱ argumentȱ toȱ eitherȱ functionȱ isȱ notȱ aȱ characterȱofȱtheȱappropriateȱcase,ȱthenȱitȱisȱreturnedȱunchanged.ȱ ȱ Testingȱ orȱ manipulatingȱ charactersȱ directlyȱ reducesȱ aȱ programȇsȱ portability.ȱ Forȱ example,ȱconsiderȱtheȱfollowingȱstatement,ȱwhichȱattemptsȱtoȱtestȱwhetherȱchȱcontainsȱ anȱuppercaseȱcharacter.ȱ ȱ if( ch >= 'A' && ch <= 'Z' ) ȱ ȱ ThisȱstatementȱworksȱonȱmachinesȱusingȱtheȱASCIIȱcharacterȱset,ȱbutȱfailsȱonȱmachinesȱ usingȱtheȱEBCDICȱcharacterȱset.ȱOnȱtheȱotherȱhand,ȱtheȱstatementȱ ȱ if( isupper( ch ) ) ȱ ȱ willȱworkȱcorrectlyȱwithȱanyȱcharacterȱset.ȱ Download at http://www.pin5i.com/ 9.9 Memory Operations 257 9.9 Memory Operations ȱ Byȱdefinition,ȱaȱstringȱisȱterminatedȱwithȱaȱNULȱbyte,ȱsoȱstringsȱmayȱnotȱcontainȱanyȱ NULs.ȱHowever,ȱitȱisȱnotȱuncommonȱforȱnonstringȱdataȱtoȱcontainȱzeros.ȱYouȱcannotȱ useȱtheȱstringȱfractionsȱtoȱprocessȱthisȱkindȱofȱdataȱbecauseȱtheyȱwouldȱstopȱworkingȱ whenȱtheyȱreachedȱtheȱfirstȱNUL.ȱ Thereȱisȱaȱrelatedȱsetȱofȱfunctionsȱwhoseȱoperationsȱareȱsimilarȱtoȱsomeȱofȱtheȱ stringȱ functions,ȱbutȱtheseȱfunctionsȱdealȱwithȱarbitraryȱsequencesȱofȱbytes.ȱ Hereȱ areȱ theirȱprototypes.ȱ ȱ void void void void void *memcpy( void *dst, void const *src, size_t length ); *memmove( void *dst, void const *src, size_t length ); *memcmp( void const *a, void const *b, size_t length ); *memchr( void const *a, int ch, size_t length ); *memset( void *a, int ch, size_t length ); ȱ Eachȱprototypeȱincludesȱanȱexplicitȱargumentȱtoȱindicateȱhowȱmanyȱbytesȱtoȱprocess,ȱ butȱunlikeȱtheȱstrn---ȱfunctions,ȱtheirȱoperationsȱdoȱnotȱstopȱifȱtheyȱencounterȱaȱNULȱ byte.ȱ memcpyȱcopiesȱlengthȱbytes,ȱbeginningȱatȱsrc,ȱintoȱtheȱmemoryȱbeginningȱatȱdst.ȱ Youȱcanȱcopyȱanyȱtypeȱofȱvalueȱinȱthisȱmanner,ȱsoȱlongȱasȱtheȱthirdȱargumentȱspecifiesȱ theȱlengthȱofȱtheȱvalueȱinȱbytes.ȱTheȱresultȱisȱundefinedȱifȱ srcȱandȱ dstȱoverlapȱinȱanyȱ way.ȱ Forȱexample:ȱ char temp[SIZE], values[SIZE]; ... memcpy( temp, values, SIZE ); ȱ copiesȱtheȱSIZEȱbytesȱfromȱtheȱarrayȱvaluesȱintoȱtheȱarrayȱtemp.ȱ Butȱwhatȱifȱbothȱwereȱarraysȱofȱintegers?ȱThenȱ(heȱfollowingȱstatementȱwouldȱ doȱtheȱjob:ȱ memcpy( temp, values, sizeof( values ) ); ȱ Noȱ castsȱ areȱ neededȱ onȱ theȱ firstȱ twoȱ argumentsȱ becauseȱ theȱ prototypeȱ callsȱ forȱ voidȱ pointers,ȱandȱanyȱtypeȱofȱpointerȱcanȱbeȱconvertedȱtoȱaȱvoid *.ȱ Ifȱonlyȱpartȱofȱtheȱarrayȱisȱtoȱbeȱcopied,ȱtheȱdesiredȱcountȱmayȱbeȱgivenȱforȱtheȱ thirdȱargument.ȱForȱdataȱthatȱisȱlargerȱthanȱoneȱbyte,ȱbeȱsureȱtoȱmultiplyȱtheȱcountȱbyȱ theȱsizeȱofȱeachȱdatum,ȱforȱexample:ȱ ȱ memcpy( saved_answers, answers, count * sizeof( answers[ 0 ] ) ); ȱ Youȱcanȱalsoȱcopyȱstructuresȱorȱarraysȱofȱstructuresȱwithȱthisȱtechnique.ȱ Download at http://www.pin5i.com/ 258 Chapter 9 Strings, Characters, and Bytes memmoveȱ behavesȱ exactlyȱ theȱ sameȱ asȱ memcpyȱ exceptȱ thatȱ itsȱ sourceȱ andȱ destinationȱoperandsȱmayȱoverlap.ȱThoughȱitȱneedȱnotȱbeȱimplementedȱthisȱway,ȱtheȱ resultȱofȱmemmoveȱisȱtheȱsameȱasȱtheȱresultȱobtainedȱbyȱcopyingȱtheȱsourceȱoperandȱtoȱaȱ temporaryȱlocationȱthatȱoverlapsȱneitherȱtheȱsourceȱnorȱtheȱdestination,ȱthenȱcopyingȱ fromȱ thisȱ temporaryȱ locationȱ toȱ theȱ destinationȱ operand.ȱ memmoveȱ usuallyȱ cannotȱ beȱ implementedȱ usingȱ theȱ specialȱ byteȬstringȱ handlingȱ instructionsȱ providedȱ onȱ someȱ machines,ȱ soȱ itȱ mayȱ beȱ slowerȱ thanȱ memcpy.ȱ However,ȱ memmoveȱ shouldȱ beȱ usedȱ whenȱ thereȱisȱaȱrealȱpossibilityȱofȱoverlappingȱarguments,ȱasȱinȱtheȱfollowingȱexample.ȱ ȱ /* ** Shift the values in the x array left one position */ memmove( x, x + 1, ( count – 1 ) * sizeof( x[ 0 ] ) ); ȱ memcmpȱ comparesȱ theȱ lengthȱ bytesȱ ofȱ memoryȱ beginningȱ atȱ aȱ toȱ theȱ bytesȱ beginningȱatȱ b.ȱTheȱvaluesȱareȱcomparedȱbyteȱbyȱbyteȱasȱunsignedȱcharacters,ȱandȱtheȱ functionȱreturnsȱtheȱsameȱtypeȱofȱvalueȱasȱ strcmpȱ–ȱaȱnegativeȱvalueȱifȱ aȱisȱlessȱthanȱ b,ȱ aȱpositiveȱvalueȱifȱaȱisȱgreaterȱthanȱb,ȱandȱzeroȱifȱtheyȱareȱequal.ȱBecauseȱtheȱvaluesȱareȱ comparedȱasȱsequencesȱofȱunsignedȱbytes,ȱ memcmpȱmayȱgiveȱunexpectedȱresultsȱifȱitȱisȱ usedȱtoȱcompareȱnonbyteȱdataȱsuchȱasȱintegersȱorȱfloats.ȱ memchrȱ searchesȱ theȱ lengthȱ bytesȱ beginningȱ atȱ aȱ forȱ theȱ firstȱ occurrenceȱ ofȱ theȱ characterȱ chȱ andȱ returnsȱ aȱ pointerȱ toȱ thatȱ location.ȱ Ifȱ theȱ characterȱ doesȱ notȱ occur,ȱ NULLȱisȱreturned.ȱ Finally,ȱ memsetȱ setsȱ eachȱ ofȱ theȱ lengthȱ bytesȱ beginningȱ atȱ aȱ toȱ theȱ characterȱ valueȱch.ȱForȱexample,ȱ ȱ memset( buffer, 0, SIZE ); ȱ initializesȱtheȱfirstȱSIZEȱbytesȱofȱtheȱbufferȱtoȱzero.ȱ ȱ ȱ ȱ 9.10 Summary ȱ Aȱ stringȱ isȱ aȱ sequenceȱ ofȱ zeroȱ orȱ moreȱ characters.ȱ Theȱ sequenceȱ isȱ terminatedȱ byȱ aȱ NULȱbyte.ȱTheȱlengthȱofȱaȱstringȱisȱtheȱnumberȱofȱcharactersȱitȱcontains.ȱTheȱstandardȱ libraryȱprovidesȱaȱhostȱofȱfunctionsȱthatȱprocessȱstrings;ȱtheirȱprototypesȱareȱinȱtheȱfileȱ string.h.ȱ ȱ Theȱ strlenȱfunctionȱcomputesȱtheȱlengthȱofȱaȱstring.ȱTheȱvalueȱthatȱisȱreturnedȱ isȱunsigned,ȱsoȱbeȱcarefulȱwhenȱusingȱitȱinȱexpressions. strcpyȱcopiesȱaȱstringȱfromȱ Download at http://www.pin5i.com/ 9.10 Summary 259 oneȱlocationȱtoȱanother,ȱandȱ strcatȱappendsȱaȱcopyȱofȱaȱstringȱtoȱtheȱendȱofȱanotherȱ string.ȱBothȱofȱtheseȱfunctionsȱassumeȱthatȱtheirȱargumentsȱareȱvalidȱstrings,ȱandȱtheȱ resultsȱ ofȱ bothȱ areȱ undefinedȱ ifȱ theȱ sourceȱ andȱ destinationȱ stringsȱ overlap. strcmpȱ performsȱaȱlexicographicȱcomparisonȱofȱtwoȱstrings.ȱItsȱreturnȱvalueȱindicatesȱwhetherȱ theȱfirstȱstringȱisȱlessȱthan,ȱequalȱto,ȱorȱgreaterȱthanȱtheȱsecondȱstring.ȱ ȱ Theȱ lengthȬrestrictedȱ functionsȱ strncpy, strncat,ȱ andȱ strncmpȱ areȱ similarȱ loȱ theirȱ unrestrictedȱ counterparts.ȱ Theȱ differenceȱ isȱ thatȱ theseȱ functionsȱ takeȱ aȱ lengthȱ argument.ȱWithȱ strncpy,ȱtheȱlengthȱspecifiesȱhowȱmanyȱcharactersȱwillȱbeȱwrittenȱtoȱ theȱdestinationȱarray.ȱIfȱtheȱsourceȱstringȱisȱlongerȱthanȱtheȱlength,ȱtheȱresultȱwillȱnotȱ beȱNULȱterminated.ȱTheȱlengthȱargumentȱtoȱ strncatȱindicatesȱtheȱmaximumȱnumberȱ ofȱcharactersȱthatȱwillȱbeȱcopiedȱfromȱtheȱsourceȱstring,ȱbutȱtheȱresultȱisȱalwaysȱNULȱ terminated.ȱ Theȱ lengthȱargumentȱtoȱ strncmpȱlimitsȱtheȱ numberȱofȱcharactersȱthatȱ areȱ compared.ȱIfȱtheȱstringsȱdoȱnotȱdifferȱwithinȱthisȱlength,ȱtheyȱareȱconsideredȱequal.ȱ ȱ Thereȱareȱseveralȱfunctionsȱthatȱsearchȱstrings. strchrȱsearchesȱaȱstringȱforȱtheȱ firstȱoccurrenceȱofȱaȱcharacter,ȱandȱ strrchrȱsearchesȱaȱstringȱforȱtheȱlastȱoccurrenceȱofȱ aȱ character.ȱ strpbrkȱ searchesȱ aȱ stringȱ forȱ theȱ firstȱ occurrenceȱ ofȱ anyȱ characterȱ inȱ aȱ specifiedȱset.ȱTheȱ strstrȱfunctionȱsearchesȱaȱstringȱforȱtheȱfirstȱoccurrenceȱofȱanotherȱ string.ȱ ȱ Moreȱ advancedȱ stringȱ searchesȱ areȱ alsoȱ provided.ȱ Theȱ strspnȱ functionȱ countsȱ theȱ numberȱ ofȱ charactersȱ atȱ theȱ beginningȱ ofȱ aȱ stringȱ thatȱ matchȱ anyȱ characterȱ inȱ aȱ specifiedȱset. strcspnȱcountsȱtheȱnumberȱofȱcharactersȱatȱtheȱbeginningȱofȱaȱstringȱthatȱ doȱ notȱ matchȱ anyȱ ofȱ theȱ charactersȱ inȱ aȱ specifiedȱ set.ȱ Theȱ strtokȱ functionȱ breaksȱ aȱ stringȱ intoȱ tokens.ȱ Eachȱ timeȱ itȱ isȱ called,ȱ itȱ returnsȱ aȱ pointerȱ toȱ theȱ nextȱ tokenȱ inȱ theȱ string.ȱTheȱtokensȱareȱseparatedȱbyȱoneȱorȱmoreȱcharactersȱfromȱaȱspecifiedȱset.ȱ ȱ Theȱstrerrorȱtakesȱanȱerrorȱcodeȱasȱanȱargument.ȱItȱreturnsȱaȱpointerȱtoȱaȱstringȱ thatȱdescribesȱtheȱerror.ȱ ȱ Aȱ varietyȱ ofȱ functionsȱ areȱ suppliedȱ forȱ testingȱ andȱ transformingȱ character.ȱ Programsȱthatȱuseȱtheseȱfunctionsȱareȱmoreȱportableȱthanȱthoseȱthatȱperformȱtheirȱownȱ testsȱ orȱ transformationsȱ ofȱ characters.ȱ Theȱ touperȱ functionȱ convertsȱ aȱ lowercaseȱ characterȱ toȱ uppercase,ȱandȱtheȱ tolowerȱfunctionȱ convertsȱaȱ characterȱtheȱ otherȱway.ȱȱ Theȱ iscntrlȱfunctionȱchecksȱwhetherȱitsȱargumentȱisȱaȱcontrolȱcharacter,ȱandȱ isspaceȱ testsȱ forȱ whiteȱ space,ȱ isdigitȱ checksȱ forȱ aȱ decimalȱ digit,ȱ andȱ isxdigitȱ checksȱ forȱ hexadecimalȱ digits. islowerȱ andȱ isupperȱ checkȱ forȱ lowercaseȱ andȱ uppercaseȱ characters,ȱ respectively,ȱ isalphaȱ looksȱ forȱ alphabeticȱ characters,ȱ isalnumȱ looksȱ forȱ alphanumericȱ characters,ȱ andȱ ispunctȱ looksȱ forȱ punctuationȱ characters.ȱ Finally,ȱ isgraphȱ checksȱ whetherȱ itsȱ argumentȱ hasȱ aȱ printableȱ graphicȱ associatedȱ withȱ it,ȱ andȱ isprintȱchecksȱforȱeitherȱaȱgraphicȱcharacterȱorȱaȱspace.ȱ Download at http://www.pin5i.com/ 260 Chapter 9 Strings, Characters, and Bytes Theȱ memxxxȱ functionsȱ provideȱ capabilitiesȱ similarȱ toȱ someȱ ofȱ theȱ stringȱ functions,ȱ butȱ processȱ arbitraryȱ byteȱ values,ȱ includingȱ NUL.ȱ Eachȱ ofȱ theȱ functionsȱ takesȱ aȱ lengthȱ argumentȱ memcpyȱ copiesȱ bytesȱ fromȱ aȱ sourceȱ toȱ aȱ destination,ȱ memmoveȱ performsȱ theȱ sameȱ function,ȱ butȱ itsȱ behaviorȱ isȱ wellȬdefinedȱ whenȱ theȱ sourceȱ andȱ destinationȱargumentsȱoverlap. memcmpȱcomparesȱtwoȱsequencesȱofȱbytes,ȱandȱ memchrȱ searchesȱ aȱ sequenceȱ ofȱ bytesȱ forȱ aȱ specificȱ value.ȱ Finally,ȱ memsetȱ storesȱ aȱ specifiedȱ valueȱinȱaȱsequence.ȱ ȱ ȱ ȱ 9.11 Summary of Cautions ȱ 1. Usingȱstrlenȱinȱexpressionsȱthatȱshouldȱbeȱsignedȱ(pageȱ244).ȱ 2. Mixingȱsignedȱandȱunsignedȱquantitiesȱinȱexpressionsȱ(pageȱ245).ȱ 3. Overflowingȱaȱshortȱarrayȱbyȱusingȱstrcpyȱtoȱcopyȱaȱlongȱstringȱintoȱitȱ(pageȱ246).ȱ 4. Overflowingȱ anȱ arrayȱ byȱ appendingȱ aȱ stringȱ thatȱ isȱ tooȱ longȱ usingȱ strcatȱ (pageȱ 247).ȱ 5. Testingȱtheȱresultȱreturnedȱbyȱstrcmpȱasȱaȱbooleanȱ(pageȱ248).ȱ 6. Comparingȱtheȱvalueȱreturnedȱbyȱstrcmpȱtoȱ1ȱorȱȬ1ȱ(pageȱ248).ȱ 7. UsingȱcharacterȱsequencesȱthatȱareȱnotȱNULȱterminatedȱ(pageȱ248).ȱ 8. Producingȱunterminatedȱstringsȱwithȱstrncpyȱ(pageȱ249).ȱ 9. Mixingȱstrncpyȱwithȱstrxxxȱ(pageȱ249).ȱ 10. Forgettingȱthatȱstrtokȱmodifiesȱtheȱstringȱthatȱitȱprocessesȱ(pageȱ254).ȱ 11. Theȱstrtokȱfunctionȱisȱnotȱreentrantȱ(pageȱ255).ȱ ȱ ȱ ȱ 9.12 Summary of Programming Tips ȱ 1. Donȇtȱtryȱtoȱbeatȱtheȱlibraryȱstringȱfunctionsȱbyȱwritingȱyourȱownȱ(pageȱ245).ȱ 2. Usingȱ theȱ libraryȱ characterȱ classificationȱ andȱ transformationȱ functionsȱ enhancesȱ portabilityȱ(pageȱ256).ȱ ȱ Download at http://www.pin5i.com/ 9.13 Questions 261 9.13 Questions ȱ 1. IsȱtheȱabsenceȱofȱanȱexplicitȱstringȱdataȱtypeȱinȱCȱanȱadvantageȱorȱaȱdisadvantage?ȱ ȱ 2. strlenȱ returnsȱ anȱ unsignedȱ (size_t)ȱ quantity.ȱ Whyȱ isȱ anȱ unsignedȱ valueȱ moreȱ appropriateȱthanȱaȱsignedȱvalue?ȱWhyȱisȱanȱunsignedȱvalueȱlessȱappropriate?ȱ ȱ 3. Wouldȱthereȱbeȱanyȱadvantageȱinȱhavingȱ strcatȱandȱ strcpyȱreturnȱaȱpointerȱtoȱtheȱ endȱofȱtheȱdestinationȱstringȱratherȱthanȱreturningȱaȱpointerȱtoȱitsȱbeginning?ȱ ȱ 4. Whatȱisȱtheȱsimplestȱwayȱtoȱcopyȱ50ȱbytesȱfromȱtheȱarrayȱxȱintoȱtheȱarrayȱy?ȱ ȱ 5. Supposeȱ youȱ haveȱ anȱ arrayȱ calledȱ bufferȱ thatȱ isȱ BSIZEȱ bytesȱ long,ȱ andȱ youȱ haveȱ copiedȱaȱstringȱintoȱthisȱarrayȱwithȱtheȱfollowingȱstatement:ȱ ȱ strncpy( buffer, some_other_string, BSIZE – 1 ); ȱ Isȱitȱguaranteedȱthatȱtheȱresultȱinȱbufferȱisȱaȱvalidȱstring?ȱ ȱ 6. Whatȱareȱtheȱadvantagesȱofȱusingȱ ȱ if( isalpha( ch ) ){ ȱ insteadȱofȱtheȱexplicitȱtestȱ ȱ if( ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z' ){ 7. Howȱcanȱtheȱfollwingȱcodeȱbeȱsimplified?ȱ for( p_str = message; *p_str != '\0'; p_str++ ){ if( islower( *p_str ) ) *p_str = toupper( *p_str ); } 8. Howȱdoȱtheȱexpressionsȱbelowȱdiffer?ȱ ȱ memchr( buffer, 0, SIZE ) – buffer strlen( buffer ) Download at http://www.pin5i.com/ Chapter 9 Strings, Characters, and Bytes 262 9.14 Programming Exercises ȱ 1. Writeȱaȱprogramȱthatȱreadsȱfromȱtheȱstandardȱinputȱandȱcomputesȱtheȱpercentageȱ ofȱcharactersȱitȱfindsȱinȱeachȱofȱtheȱfollowingȱcategories:ȱ ȱ ȱ controlȱcharactersȱ whitespaceȱcharactersȱ digitsȱ lowerȱcaseȱlettersȱ upperȱcaseȱlettersȱ punctuationȱcharactersȱ nonȬprintableȱcharactersȱ Useȱtheȱcharacterȱcategoriesȱthatȱareȱdefinedȱforȱtheȱctype.hȱfunctions.ȱ ȱ 2. Writeȱ aȱ functionȱ calledȱ my_strnlenȱ thatȱ isȱ similarȱ toȱ strlenȱ butȱ isȱ ableȱ toȱ handleȱ unterminatedȱstringsȱcreatedȱwithȱtheȱ strn---ȱfunctions.ȱYouȱwillȱhaveȱtoȱpassȱanȱ argumentȱcontainingȱtheȱsizeȱofȱtheȱarrayȱthatȱholdsȱtheȱstringȱtoȱbeȱtested.ȱ ȱ 3. Writeȱaȱfunctionȱcalledȱmy_strcpyȱthatȱisȱsimilarȱtoȱstrcpyȱbutȱwillȱnotȱoverflowȱtheȱ destinationȱarray.ȱTheȱresultȱofȱtheȱcopyȱmustȱbeȱaȱtrueȱstring.ȱ ȱ 4. Writeȱaȱfunctionȱcalledȱmy_strcatȱthatȱisȱsimilarȱtoȱstrcatȱbutȱwillȱnotȱoverflowȱtheȱ destinationȱarray.ȱTheȱresultȱmustȱbeȱaȱtrueȱstring.ȱ ȱ 5. Writeȱtheȱfunctionȱ ȱ ȱ void my_strncat( char *dest, char *src, int dest_len ); whichȱconcatenatesȱtheȱstringȱinȱ srcȱtoȱtheȱendȱofȱtheȱstringȱinȱ dest,ȱmakingȱsureȱ notȱtoȱoverflowȱtheȱ destȱarray,ȱwhichȱisȱ dest_lenȱbytesȱlong.ȱUnlikeȱ strncat,ȱthisȱ functionȱtakesȱintoȱaccountȱtheȱlengthȱofȱtheȱstringȱalreadyȱinȱdestȱtherebyȱinsuringȱ thatȱtheȱarrayȱboundsȱareȱnotȱexceeded.ȱ ȱ 6. Writeȱaȱ strcpyȱreplacementȱcalledȱ my_strcpy_endȱthatȱreturnsȱaȱpointerȱtoȱtheȱendȱ ofȱtheȱdestinationȱstringȱ(thatȱis,ȱaȱpointerȱtoȱtheȱNULȱbyte)ȱratherȱthanȱaȱpointerȱtoȱ theȱbeginningȱofȱtheȱdestinationȱstring.ȱ ȱ 7. Writeȱaȱfunctionȱcalledȱmy_strrchrȱwithȱthisȱprototype:ȱ ȱ ȱ char *my_strrchr( char const *str, int ch ); Theȱ functionȱ isȱ similarȱ toȱ strchrȱ exceptȱ thatȱ itȱ returnsȱ aȱ pointerȱ toȱ theȱ lastȱ (rightmost)ȱoccurrenceȱofȱtheȱcharacter.ȱ ȱ Download at http://www.pin5i.com/ 9.14 Programming Exercises 263 8. Writeȱaȱfunctionȱcalledȱmy_strnchrȱwithȱthisȱprototype:ȱ ȱ char *my_strnchr( char const *str, in ch, int which ); ȱ Theȱ functionȱ isȱ similarȱ toȱ strchrȱ exceptȱ thatȱ theȱ thirdȱ argumentȱ specifiesȱ whichȱ occurrenceȱofȱtheȱcharacterȱisȱdesired.ȱForȱexample,ȱifȱtheȱthirdȱargumentȱisȱone,ȱtheȱ functionȱ behavesȱ exactlyȱ likeȱ strchr.ȱ Ifȱ theȱ thirdȱ argumentȱ isȱ two,ȱ theȱ functionȱ returnsȱaȱpointerȱtoȱtheȱsecondȱoccurrenceȱofȱchȱinȱtheȱstringȱstr.ȱ ȱ 9. Writeȱaȱfunctionȱwithȱthisȱprototype:ȱ ȱ int count_chars( char const *str, char const *chars ); ȱ Theȱ functionȱ shouldȱ lookȱ throughȱ theȱ firstȱ argumentȱ andȱ returnȱ theȱ numberȱ ofȱ charactersȱthatȱmatchȱcharactersȱinȱtheȱsecondȱargument.ȱ ȱ 10. Writeȱthisȱfunction:ȱ ȱ int palindrome( char *string ); ȱ whichȱ returnsȱ aȱ trueȱ valueȱ ifȱ theȱ argumentȱ stringȱ isȱ aȱ palindromeȱ andȱ falseȱ otherwise.ȱAȱpalindromeȱisȱaȱstringȱthatȱreadsȱtheȱsameȱforwardsȱandȱbackwards. 39 ȱ Theȱ functionȱ shouldȱ ignoreȱ allȱ nonalphabeticȱ characters,ȱ andȱ characterȱ comparisonsȱshouldȱbeȱcaseȱindependent.ȱ ȱ 11. Writeȱaȱprogramȱthatȱscansȱtheȱstandardȱinputȱandȱcountsȱtheȱnumberȱofȱtimesȱtheȱ wordȱ ȈtheȈȱ appears.ȱ Theȱ comparisonȱ shouldȱ beȱ caseȱ independent,ȱ soȱ ȇTheȈȱ andȱ ȈTHEȈȱdonȇtȱcount.ȱYouȱmayȱassumeȱthatȱwordsȱwillȱbeȱseparatedȱfromȱeachȱotherȱ byȱoneȱorȱmoreȱwhiteȬspaceȱcharactersȱandȱthatȱtheȱinputȱlinesȱwillȱbeȱlessȱthanȱ100ȱ charactersȱinȱlength.ȱTheȱcountȱshouldȱbeȱwrittenȱtoȱtheȱstandardȱoutput.ȱ ȱ 12. Thereȱisȱaȱtechniqueȱforȱencryptingȱdataȱthatȱusesȱaȱwordȱasȱitsȱkey.ȱHereȱisȱhowȱitȱ works.ȱFirst,ȱaȱwordȱisȱchosenȱasȱtheȱkey,ȱforȱexample,ȱ TRAIL-BLAZERS.ȱIfȱtheȱwordȱ containsȱanyȱduplicateȱletters,ȱonlyȱtheȱfirstȱofȱeachȱisȱkept;ȱtheȱrestȱareȱdiscarded.ȱȱ Nowȱtheȱmodifiedȱwordȱisȱwrittenȱbeneathȱtheȱalphabet,ȱasȱshownȱhere:ȱ ȱ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z T R A I L B Z E S ȱWhenȱtheȱspacing,ȱpunctuation,ȱandȱcapitalizationȱareȱignored.ȱAnȱexampleȱisȱwhatȱAdamȱmightȱhaveȱsaidȱwhenȱheȱfirstȱ metȱEve:ȱȈMadam,ȱIȇmȱAdam.Ȉȱ 39 Download at http://www.pin5i.com/ 264 Chapter 9 Strings, Characters, and Bytes Finally,ȱ theȱ bottomȱ lineȱ isȱ completedȱ byȱ fillingȱ inȱ theȱ remainingȱ lettersȱ ofȱ theȱ alphabet:ȱ ȱ A B C D E P G H T J K L M N O P Q R S T U V W X Y Z T R A I L B Z E S C D F G H J K M N O P Q U V W X Y ȱ Toȱencryptȱaȱmessage,ȱeachȱletterȱinȱtheȱmessageȱisȱlocatedȱinȱtheȱtopȱrow,ȱandȱtheȱ correspondingȱ characterȱ fromȱ theȱ bottomȱ rowȱ isȱ usedȱ instead.ȱ Thus,ȱ ATTACT AT DAWNȱwouldȱbeȱencryptedȱusingȱthisȱkeyȱasȱTPPTAD TP ITVH.ȱ ȱ Inȱthisȱfirstȱofȱthreeȱprograms,ȱyouȱwillȱwriteȱtheȱfunctionȱ ȱ int prepare_key( char *key ); ȱ whichȱ acceptsȱ aȱ stringȱ containingȱ theȱ desiredȱ keyȱ wordȱ andȱ convertsȱ itȱ asȱ describedȱaboveȱtoȱtheȱarrayȱofȱencodedȱcharacters.ȱAssumeȱthatȱtheȱkeyȱargumentȱ isȱanȱarrayȱatȱleastȱ27ȱcharactersȱlong.ȱTheȱfunctionȱmustȱconvertȱallȱtheȱcharactersȱ inȱ theȱ keyȱ toȱ eitherȱ upperȬȱ orȱ lowercaseȱ (yourȱ choice),ȱ eliminateȱ anyȱ duplicateȱ lettersȱfromȱtheȱword,ȱandȱthenȱfillȱinȱtheȱrestȱofȱtheȱalphabetȱinȱtheȱsameȱcaseȱyouȱ choseȱ earlier.ȱ Ifȱ theȱ processingȱ succeeds,ȱ theȱ functionȱ returnsȱ aȱ trueȱ result.ȱ Ifȱ theȱ keyȱ argumentȱ isȱ emptyȱ orȱ containsȱ anyȱ nonalphabeticȱ characters,ȱ theȱ functionȱ shouldȱreturnȱaȱfalseȱresult.ȱ ȱ 13. Writeȱtheȱfunctionȱ ȱ void encrypt( char *data, char const *key ); ȱ whichȱ usesȱ aȱ keyȱ producedȱ byȱ prepare_keyȱ toȱ encryptȱ theȱ charactersȱ inȱ data.ȱ Nonalphabeticȱ charactersȱ inȱ dataȱ areȱ notȱ changed,ȱ butȱ alphabeticȱ charactersȱ areȱ encryptedȱ usingȱ theȱ keyȱ providedȱ byȱ replacingȱ theȱ originalȱ characterȱ withȱ theȱ codedȱcharacter.ȱTheȱcaseȱofȱalphabeticȱcharactersȱshouldȱbeȱpreserved.ȱ ȱ 14. Theȱfinalȱpartȱofȱthisȱproblemȱisȱtoȱwriteȱtheȱfunctionȱ ȱ void decrypt( char *data, char const *key ); ȱ whichȱtakesȱanȱencryptedȱstringȱandȱreconstructsȱtheȱoriginalȱmessage.ȱExceptȱforȱ decrypting,ȱthisȱfunctionȱshouldȱworkȱtheȱsameȱasȱencrypt.ȱ ȱ 15. Theȱ standardȱ I/Oȱ libraryȱ doesȱ notȱ provideȱ aȱ mechanismȱ forȱ puttingȱ commasȱ inȱ largeȱ integersȱ whenȱ theyȱ areȱ printed.ȱ Forȱ thisȱ exerciseȱ youȱ willȱ writeȱ aȱ programȱ thatȱprovidesȱthisȱcapabilityȱforȱdollarȱamounts.ȱTheȱfunctionȱwillȱconvertȱaȱstringȱ ofȱ digitsȱ (representingȱ anȱ amountȱ inȱ pennies)ȱ toȱ dollarsȱ asȱ illustratedȱ byȱ theȱ followingȱexamples.ȱ Download at http://www.pin5i.com/ 9.14 Programming Exercises ȱ Input Output (empty)ȱ $0.00ȱ 1ȱ $0.01ȱ 12ȱ $0.12ȱ 123ȱ $1.23ȱ 1234ȱ $12.34ȱ ȱ Hereȱisȱaȱprototypeȱforȱtheȱfunction:ȱ ȱ Input 12345ȱ 123456ȱ 1234567ȱ 12345678ȱ 123456789ȱ void dollars( char *dest, char const *src ); int format( char *format_string, char const *digit_string ); 265 Output $123.45ȱ $1,234.56ȱ $12,345.67ȱ $123,456.78ȱ $1,234,567.89ȱ ȱ srcȱwillȱpointȱtoȱtheȱcharactersȱtoȱbeȱformatted.ȱ(Youȱmayȱassumeȱthatȱtheseȱareȱallȱ digits.)ȱ Yourȱ functionȱ shouldȱ formatȱ theȱ charactersȱ asȱ shownȱ inȱ theȱ examples,ȱ leavingȱtheȱresultingȱstringȱinȱdest.ȱȱBeȱsureȱthatȱtheȱstringȱyouȱcreateȱisȱterminatedȱ withȱaȱNULȱbyte. srcȱshouldȱnotȱbeȱmodified.ȱUseȱpointersȱratherȱthanȱsubscripts.ȱ Hint:ȱFirstȱfindȱtheȱlengthȱofȱtheȱstringȱinȱtheȱsecondȱargument.ȱThisȱvalueȱwillȱ helpȱdetermineȱwhereȱtheȱcommasȱshouldȱbeȱinserted.ȱAlso,ȱtheȱdecimalȱpointȱandȱ lastȱtwoȱdigitsȱshouldȱbeȱtheȱonlyȱspecialȱcaseȱyouȱneedȱtoȱhandle.ȱ ȱ 16. Thisȱprogramȱisȱsimilarȱtoȱtheȱpreviousȱoneȱbutȱisȱmoreȱgeneral.ȱItȱformatsȱaȱstringȱ ofȱdigitsȱasȱspecifiedȱbyȱaȱformatȱstring,ȱsimilarȱtoȱtheȱȈprintȱusingȈȱstatementȱfoundȱ inȱmanyȱimplementationsȱofȱbasic.ȱTheȱfunctionȱshouldȱhaveȱthisȱprototype:ȱ ȱ ȱ Workingȱ fromȱ rightȱ toȱ left,ȱ theȱ digitsȱ inȱ digit_stringȱ areȱ copiedȱ intoȱ theȱ format_stringȱ accordingȱ toȱ theȱ charactersȱ initiallyȱ foundȱ inȱ format_string.ȱ Noteȱ thatȱ format_stringȱ isȱ modifiedȱ asȱ aȱ resultȱ ofȱ thisȱ process.ȱ Makeȱ sureȱ thatȱ theȱ format_scringȱisȱstillȱNULȬterminatedȱwhenȱyouȱareȱfinishedȱwithȱit.ȱTheȱreturnedȱ valueȱ isȱ eitherȱ trueȱ orȱ falseȱ dependingȱ onȱ whetherȱ anyȱ errorsȱ occurredȱ inȱ formatting.ȱ ȱ Theȱformatȱstringȱmayȱcontainȱtheȱfollowingȱcharacters:ȱ ȱ ȱ #ȱ Workingȱ fromȱ rightȱ toȱ leftȱ inȱ bothȱ strings,ȱ eachȱ poundȱ signȱ inȱ theȱ formatȱstringȱisȱreplacedȱbyȱtheȱnextȱdigitȱfromȱtheȱdigitȱstring.ȱIfȱtheȱ digitȱstringȱrunsȱout,ȱallȱremainingȱpoundȱsignsȱinȱtheȱformatȱstringȱ areȱreplacedȱwithȱblanksȱ(butȱseeȱtheȱdiscussionȱforȱperiodsȱbelow).ȱ ,ȱ Aȱcommaȱisȱnotȱchangedȱifȱthereȱwillȱbeȱatȱleastȱoneȱdigitȱtoȱitsȱleftȱinȱ theȱresult,ȱotherwiseȱitȱisȱreplacedȱwithȱaȱblank.ȱ ȱ ȱ ȱ Download at http://www.pin5i.com/ 266 Chapter 9 Strings, Characters, and Bytes .ȱ Aȱperiodȱisȱalwaysȱleftȱasȱaȱperiod.ȱIfȱthereȱisnȇtȱaȱdigitȱtoȱtheȱleftȱofȱ theȱ period,ȱ zerosȱ areȱ filledȱ inȱ fromȱ whereȱ theȱ digitsȱ endedȱ toȱ theȱ positionȱjustȱtoȱtheȱleftȱofȱtheȱperiod.ȱ ȱ Theȱ followingȱ examplesȱ illustrateȱ severalȱ callsȱ toȱ thisȱ function.ȱ Theȱ ¤ȱ symbolȱ isȱ usedȱtoȱindicateȱaȱblankȱspace.ȱ ȱ Format Digits Resulting Format ##### ##### ##,### ##,### ##,### #,###,###.## #,###,###.## #,###,###.## #,###,###.## #####.##### 12345 123 1234 123 1234567 123456789 1234567 123 1 1 12345 ¤¤123 ¤1,234 ¤¤¤123 34,567 1,234,567.89 ¤¤¤12,345.67 ¤¤¤¤¤¤¤¤1.23 ¤¤¤¤¤¤¤¤0.01 ¤¤¤¤0.0000l ȱ Toȱ simplifyȱ theȱ project,ȱ youȱ mayȱ assumeȱ thatȱ theȱ formatȱ stringȱ isȱ correctlyȱ formed.ȱThereȱwillȱalwaysȱbeȱatȱleastȱoneȱpoundȱsignȱtoȱtheȱleftȱandȱtoȱtheȱrightȱofȱaȱ periodȱandȱeveryȱcomma,ȱandȱcommasȱwillȱneverȱappearȱtoȱtheȱrightȱofȱaȱperiod.ȱȱ Theȱonlyȱerrorsȱyouȱneedȱtoȱcheckȱforȱare:ȱ ȱ a. moreȱ digitsȱ inȱ theȱ digitȱ stringȱ thanȱ thereȱ areȱ poundȱ signsȱ inȱ theȱ formatȱ stringȱ(asȱinȱtheȱbottomȱleftȱexampleȱabove),ȱandȱ b. anȱemptyȱdigitȱstring.ȱ ȱ Eitherȱ ofȱ theseȱ errorsȱ resultȱ inȱ theȱ functionȱ returningȱ FALSE,ȱ otherwiseȱ itȱ shouldȱ returnȱ TRUE.ȱ Ifȱ theȱ digitȱ stringȱ isȱ empty,ȱ theȱ formatȱ stringȱ shouldȱ beȱ returnedȱ unchanged.ȱYouȱwillȱlearnȱmoreȱifȱyouȱuseȱpointersȱratherȱthanȱsubscripts.ȱ Hint:ȱStartȱbyȱgettingȱpointersȱtoȱtheȱendȱofȱbothȱtheȱformatȱstringȱandȱtheȱdigitȱ string,ȱthenȱworkȱfromȱrightȱ toȱ left.ȱYouȱmustȱ retainȱtheȱpointerȱ valuesȱthatȱ wereȱ passedȱ asȱ argumentsȱ soȱ thatȱ youȱ canȱ determineȱ whenȱ youȱ haveȱ reachedȱ theȱ leftȱ endȱofȱtheseȱstrings.ȱ 17. Thisȱ programȱ isȱ similarȱ toȱ theȱ previousȱ twoȱ butȱ moreȱ generalȱ still.ȱ Itȱ allowsȱ theȱ callerȱtoȱputȱcommasȱinȱlargeȱnumbers,ȱsuppressȱleadingȱzeros,ȱprovideȱaȱfloatingȱ dollarȱsign,ȱandȱsoȱforth.ȱ TheȱfunctionȱisȱsimilarȱinȱoperationȱtoȱtheȱEditȱandȱMarkȱinstructionȱonȱtheȱIBMȱ 370ȱcomputer.ȱItȱhasȱthisȱprototype:ȱ ȱ char *edit( char *pattern, char const *digits ); ȱ Theȱbasicȱideaȱisȱsimple.ȱTheȱpatternȱisȱaȱpictureȱofȱwhatȱtheȱresultȱshouldȱlookȱlikeȱ Download at http://www.pin5i.com/ 9.14 Programming Exercises 267 Charactersȱ fromȱ theȱ digitȱ stringȱ areȱ copiedȱ intoȱ theȱ patternȱ stringȱ fromȱ theȱ leftȱ toȱ rightȱinȱaȱmannerȱdeterminedȱbyȱthisȱpicture.ȱ Theȱ firstȱ significantȱ digitȱ inȱ theȱ digitȱ stringȱ isȱ important.ȱ Allȱ charactersȱ inȱ theȱ resultȱ thatȱ areȱ toȱ theȱ leftȱ ofȱ theȱ firstȱ significantȱ digitȱ areȱ replacedȱ byȱ aȱ ȈfillȈȱ character,ȱandȱtheȱfunctionȱwillȱreturnȱaȱpointerȱtoȱtheȱplaceȱinȱtheȱresultȱwhereȱtheȱ firstȱsignificantȱdigitȱwasȱstored.ȱ(Theȱcallingȱprogramȱcanȱuseȱtheȱreturnedȱpointerȱ toȱ putȱ aȱ floatingȱ dollarȱ signȱ immediatelyȱ toȱ theȱ leftȱ ofȱ theȱ value.)ȱ Theȱ resultingȱ outputȱlooksȱ likeȱwhatȱyouȱmayȱhaveȱ seenȱprintedȱ onȱchecks—allȱ ofȱtheȱ spaceȱ toȱ theȱleftȱofȱtheȱvalueȱisȱfilledȱinȱwithȱstarsȱorȱsomeȱotherȱcharacter.ȱ Beforeȱtheȱdetailedȱworkingsȱofȱtheȱfunctionȱareȱdescribed,ȱitȱwillȱbeȱhelpfulȱtoȱ seeȱsomeȱexamplesȱofȱitsȱoperation.ȱForȱclarity,ȱtheȱ ¤ȱcharacterȱisȱusedȱtoȱrepresentȱ aȱ space.ȱ Theȱ underlineȱ inȱ theȱ resultȱ indicatesȱ theȱ characterȱ toȱ whichȱ theȱ returnedȱ valueȱpoints.ȱIfȱthereȱisnȇtȱanȱunderlinedȱcharacter,ȱtheȱreturnedȱvalueȱwasȱNULL.ȱ ȱ Format Digits Resulting Format *#,### *#,### *#,### *#,### *#,### *#,### *X#Y#Z ¤#,##!.## ¤#,##!.## $#,##!.## $#,##!.## $#,##!.## $#,##!.## $#,##!.## 1234 123456 12 0012 ¤¤12 ¤1¤¤ (empty) ¤23456 023456 ¤¤¤456 0¤¤¤¤6 0 1 Hi¤there *1,234 *1,234 *1,2 ****12 ****12 ***100 ** ¤¤¤234.56 ¤¤¤234.56 $$$$$4.56 $$$$$0.06 $$$ $1, $H,i0t.he ȱ Now,ȱtheȱdetails.ȱTheȱfirstȱargumentȱisȱtheȱpattern,ȱandȱtheȱfirstȱcharacterȱinȱtheȱ patternȱ isȱ theȱ Ȉfillȱ character.Ȉȱ Theȱ functionȱ usesȱ theȱ digitȱ stringȱ toȱ modifyȱ theȱ remainingȱ charactersȱ ofȱ theȱ patternȱ toȱ produceȱ theȱ outputȱ string.ȱ Theȱ patternȱ isȱ overwrittenȱ inȱ thisȱ process.ȱ Theȱ outputȱ stringȱ cannotȱ beȱ longerȱ thanȱ theȱ originalȱ pattern,ȱ soȱ thereȱ isȱ noȱ dangerȱ ofȱ (andȱ noȱ needȱ toȱ checkȱ for)ȱ overflowingȱ theȱ firstȱ argument.ȱ Theȱ patternȱ isȱ processedȱ characterȱ byȱ characterȱ fromȱ leftȱ toȱ right.ȱ Forȱ eachȱ characterȱafterȱtheȱfillȱcharacter,ȱoneȱofȱthreeȱthingsȱhappens:ȱ(a)ȱtheȱcharacterȱisȱleftȱ unchanged,ȱ(b)ȱitȱisȱreplacedȱbyȱaȱcharacterȱfromȱtheȱdigitȱstring,ȱorȱ(c)ȱitȱisȱreplacedȱ byȱtheȱfillȱcharacter.ȱ Theȱdigitȱstringȱisȱalsoȱprocessedȱfromȱleftȱtoȱright,ȱbutȱitȱisȱneverȱmodifiedȱinȱ anyȱway.ȱAlthoughȱitȱisȱcalledȱaȱȈdigitȱstring,Ȉȱitȱcanȱcontainȱanyȱcharacters,ȱasȱoneȱ ofȱtheȱaboveȱexamplesȱillustrates.ȱHowever,ȱeveryȱspaceȱinȱtheȱdigitȱstringȱshouldȱ Download at http://www.pin5i.com/ 268 Chapter 9 Strings, Characters, and Bytes beȱtreatedȱ(andȱproduceȱtheȱsameȱresults)ȱasȱifȱitȱwereȱtheȱdigitȱ0.ȱ ȱ Theȱ functionȱ mustȱ keepȱ aȱ ȈsignificanceȈȱ flag,ȱ whichȱ remembersȱ whetherȱ anyȱ significantȱdigitsȱhaveȱbeenȱcopiedȱfromȱtheȱdigitȱstring.ȱLeadingȱspacesȱandȱ0ȇsȱinȱ theȱdigitȱstringȱareȱnotȱsignificant;ȱallȱotherȱcharactersȱare.ȱ ItȱisȱanȱerrorȱforȱeitherȱtheȱpatternȱorȱdigitȱargumentsȱtoȱbeȱNULL.ȱInȱthisȱcase,ȱ theȱfunctionȱshouldȱimmediatelyȱreturnȱnull.ȱ Theȱ followingȱ tableȱ listsȱ allȱ processingȱ thatȱ isȱ required.ȱ Theȱ columnsȱ headedȱ signifȱreferȱtoȱtheȱsignificanceȱflag.ȱȈPatternȈȱandȱȈDigitȈȱreferȱtoȱtheȱnextȱcharacterȱ inȱtheȱpatternȱstringȱandȱdigitȱstring,ȱrespectively.ȱȱTheȱleftȱsideȱofȱtheȱtableȱlistsȱallȱ ofȱ theȱ differentȱ casesȱ thatȱ mightȱ occur.ȱ Theȱ rightȱ sideȱ describesȱ theȱ processingȱ neededȱ forȱ eachȱ case.ȱ Forȱ example,ȱ ifȱ theȱ nextȱ patternȱ characterȱ isȱ '#',ȱ theȱ significanceȱ indicatorȱ isȱ false,ȱ andȱ theȱ nextȱ characterȱ inȱ theȱ digitȱ stringȱ isȱ '0',ȱ replaceȱtheȱ '#'ȱinȱtheȱpatternȱwithȱaȱcopyȱofȱtheȱfillȱcharacterȱandȱdonȇtȱchangeȱtheȱ significanceȱindicator.ȱ ȱ If you find this… Then you do this… signif signif Pattern Digit Pattern Notes '\0' (doesnȇtȱmatter)ȱ (notȱused)ȱ (unchanged) (unchanged) Returnȱsavedȱpointerȱ '\0' '\0' (doesnȇtȱmatter)ȱ (unchanged) Returnȱsavedȱpointerȱ '\0'ȱorȱ' ' fillȱcharȱ (unchanged) ȱ '#' falseȱ anyȱotherȱ theȱdigitȱ trueȱ Saveȱpointerȱtoȱthisȱchar trueȱ anyȱ theȱdigitȱ (unchanged) ȱ '!' '\0' (doesnȇtȱmatter)ȱ '\0' (unchanged) Returnȱsavedȱpointerȱ falseȱ anyȱ theȱdigitȱ trueȱ Saveȱpointerȱtoȱthisȱchar trueȱ anyȱ theȱdigitȱ (unchanged) ȱ anythingȱ falseȱ (notȱused)ȱ fillȱcharȱ (unchanged) ȱ elseȱ trueȱ (notȱused)ȱ (unchanged) (unchanged) ȱ ȱ Download at http://www.pin5i.com/ 10 Structures and Unions Dataȱ frequentlyȱ existsȱ inȱ groups.ȱ Forȱ example,ȱ anȱ employerȱ mustȱ keepȱ trackȱ ofȱ theȱ name,ȱ age,ȱ andȱ salaryȱ ofȱ eachȱ employee.ȱ Accessingȱ theseȱ valuesȱ isȱ simplifiedȱ ifȱ theyȱ canȱ beȱ storedȱ together.ȱ However,ȱ ifȱ theȱ valuesȱ areȱ differentȱ types,ȱ asȱ theyȱ areȱ inȱ thisȱ example,ȱtheyȱcannotȱbeȱstoredȱtogetherȱinȱanȱarray.ȱInȱC,ȱvaluesȱwithȱdissimilarȱtypesȱ canȱbeȱstoredȱtogetherȱusingȱaȱstructure.ȱ ȱ ȱ ȱ 10.1 Structure Basics ȱ Anȱaggregateȱdataȱtypeȱisȱoneȱthatȱcanȱholdȱmoreȱthanȱoneȱindividualȱpieceȱofȱdataȱatȱaȱ time.ȱ Cȱ providesȱ twoȱ typesȱ ofȱ aggregateȱ data,ȱ arraysȱ andȱ structures.ȱ Arraysȱ areȱ collectionsȱofȱelementsȱofȱtheȱsameȱtype,ȱandȱindividualȱelementsȱareȱselectedȱthroughȱ aȱsubscriptȱorȱindirectionȱonȱaȱpointer.ȱ Aȱstructureȱ isȱ alsoȱ aȱcollectionȱofȱvalues,ȱ calledȱmembers,ȱbutȱtheȱmembersȱ ofȱ aȱ structureȱmayȱbeȱofȱdifferentȱtypes.ȱAȱstructureȱisȱquiteȱsimilarȱtoȱaȱrecordȱinȱPascalȱorȱ Modula.ȱ Arrayȱelementsȱcanȱbeȱaccessedȱviaȱaȱsubscriptȱonlyȱbecauseȱallȱofȱtheȱelementsȱ areȱ theȱ sameȱ size.ȱ Theȱ situationȱ isȱ differentȱ withȱ structures.ȱ Becauseȱ aȱ structureȇsȱ membersȱcanȱbeȱofȱdifferentȱsizes,ȱsubscriptsȱcannotȱbeȱusedȱtoȱaccessȱthem.ȱInstead,ȱ structureȱmembersȱareȱgivenȱnamesȱandȱareȱaccessedȱbyȱthoseȱnames.ȱ Thisȱdistinctionȱisȱimportant.ȱAȱstructureȱisȱnotȱanȱarrayȱofȱitsȱmembers.ȱUnlikeȱ anȱarrayȱname,ȱtheȱnameȱofȱaȱstructureȱvariableȱisȱnotȱreplacedȱwithȱaȱpointerȱwhenȱitȱ isȱ usedȱ inȱ anȱ expression.ȱ Subscriptsȱ cannotȱ beȱ usedȱ onȱ aȱ structureȱ variableȱ toȱ selectȱ specificȱmembers.ȱ Aȱ structureȱ variableȱ isȱ aȱ scalar,ȱ soȱ youȱ canȱ performȱ theȱ sameȱ kindsȱ ofȱ operationsȱ withȱ itȱ thatȱ youȱ canȱ withȱ otherȱ scalars.ȱ Structuresȱ mayȱ beȱ passedȱ asȱ argumentsȱtoȱfunctions,ȱtheyȱmayȱbeȱreturnedȱbyȱfunctions,ȱandȱstructuresȱofȱtheȱsameȱ Download at http://www.pin5i.com/ Chapter 10 Structures and Unions 270ȱ typeȱmayȱbeȱassignedȱtoȱoneȱanother.ȱYouȱcanȱdeclareȱpointersȱtoȱstructures,ȱtakeȱtheȱ addressȱ ofȱ structureȱ variables,ȱ andȱ declareȱ arraysȱ ofȱ structures.ȱ However,ȱ weȱ mustȱ firstȱcoverȱaȱfewȱmoreȱbasicsȱbeforeȱdiscussingȱtheseȱissues.ȱ ȱ ȱ ȱ 10.1.1 Structure Declarations ȱ Structuresȱareȱdeclaredȱbyȱlistingȱtheȱmembersȱthatȱtheyȱwillȱcontain.ȱThisȱlistȱincludesȱ theȱtypeȱandȱtheȱnameȱofȱeachȱmember.ȱ ȱ ȱ struct tag { member-list } variable-list ; ȱ Thisȱ structureȱ declarationȱ syntaxȱ requiresȱ someȱ explanation.ȱ Theȱ optionalȱ fieldsȱ cannotȱallȱbeȱomitted—atȱleastȱtwoȱofȱthemȱmustȱappear. 40 Hereȱareȱseveralȱexamples.ȱ ȱ struct { int char float c; a; b; } x; ȱ Thisȱdeclarationȱcreatesȱaȱsingleȱvariableȱnamedȱ x,ȱwhichȱcontainsȱthreeȱmembers:ȱanȱ integer,ȱaȱcharacterȱandȱaȱfloat.ȱ ȱ struct { int char float c; } y[20], *z; CAUTION! a; b; ȱ Thisȱdeclarationȱcreatesȱanȱarrayȱ yȱofȱtwentyȱstructuresȱandȱ z,ȱwhichȱisȱaȱpointerȱtoȱaȱ structureȱofȱthisȱtype.ȱ ȱ Theseȱ twoȱ declarationsȱ areȱ treatedȱ byȱ theȱ compilerȱ asȱ entirelyȱ differentȱ types,ȱ evenȱ thoughȱtheirȱmemberȱlistsȱareȱidentical.ȱThus,ȱtheȱvariablesȱyȱandȱzȱareȱaȱdifferentȱtypeȱ thanȱx,ȱsoȱtheȱstatementȱ ȱ z = &x; ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ 40 ȱAnȱexceptionȱtoȱthisȱruleȱisȱtheȱincompleteȱdeclarationȱofȱstructureȱtag,ȱdescribedȱlaterȱinȱthisȱchapter.ȱ Download at http://www.pin5i.com/ 10.1 Structure Basics 271 isȱillegal.ȱButȱdoesȱthisȱfactȱmeanȱthatȱailȱstructuresȱofȱaȱgivenȱtypeȱmustȱbeȱcreatedȱinȱaȱ singleȱdeclaration?ȱ Fortunately,ȱno.ȱTheȱtagȱfieldȱallowsȱaȱnameȱtoȱbeȱgivenȱtoȱtheȱmemberȱlistȱsoȱthatȱitȱ canȱbeȱreferencedȱinȱsubsequentȱdeclarations.ȱTheȱtagȱallowsȱmanyȱdeclarationsȱtoȱuseȱ theȱsameȱmemberȱlistȱandȱthusȱcreateȱstructuresȱofȱtheȱsameȱtype.ȱHereȱisȱanȱexample.ȱ ȱ struct SIMPLE int char float c; { a; b; }; ȱ Theȱ declarationȱ associatesȱ theȱ tagȱ SIMPLEȱ withȱ thisȱ memberȱ list.ȱ Theȱ declarationȱ doesnȇtȱhaveȱaȱvariableȱlist,ȱsoȱitȱdoesnȇtȱcreateȱanyȱvariables.ȱ Thisȱdeclarationȱisȱsimilarȱtoȱmakingȱaȱcookieȱcutter.ȱAȱcookieȱcutterȱdeterminesȱ theȱ shapeȱ ofȱ cookiesȱ yetȱ toȱ beȱ made,ȱ butȱ theȱ cookieȱ cutterȱ isȱ notȱ aȱ cookie.ȱ Theȱ tagȱ identifiesȱ aȱ patternȱ forȱ declaringȱ futureȱ variables,ȱ butȱ neitherȱ theȱ tagȱ norȱ theȱ patternȱ areȱvariables.ȱ ȱ struct struct SIMPLE SIMPLE x; y[20], *z; ȱ Theseȱdeclarationsȱuseȱtheȱtagȱtoȱcreateȱvariables.ȱTheyȱcreateȱtheȱsameȱvariablesȱasȱtheȱ firstȱ twoȱ examplesȱ butȱ withȱ oneȱ importantȱ difference—now x, y,ȱ and z areȱ allȱ theȱ sameȱkindȱofȱstructure.ȱ Anotherȱgoodȱtechniqueȱforȱdeclaringȱstructuresȱisȱtoȱcreateȱaȱnewȱtypeȱwithȱaȱ typedef,ȱasȱinȱtheȱfollowingȱexample.ȱ ȱ typedef struct int char float c; { a; b; } Simple; ȱ Thisȱtechniqueȱhasȱalmostȱtheȱsameȱeffectȱasȱdeclaringȱaȱstructureȱtag.ȱTheȱdifferenceȱisȱ thatȱ Simpleȱisȱnowȱtypeȱnameȱratherȱthanȱaȱstructureȱtag,ȱsoȱsubsequentȱdeclarationsȱ wouldȱlookȱlikeȱthisȱone.ȱ ȱ Simple Simple TIP x; y[20], *z; ȱ Ifȱyouȱwantȱtoȱuseȱaȱparticularȱstructureȱinȱmoreȱthanȱoneȱsourceȱfile,ȱyouȱshouldȱputȱ theȱtagȱdeclarationȱorȱ typedefȱinȱaȱheaderȱfile.ȱYouȱcanȱthenȱ #includeȱtheȱdeclarationȱ whereverȱitȱisȱneeded.ȱ Download at http://www.pin5i.com/ Chapter 10 Structures and Unions 272ȱ 10.1.2 Structure Members ȱ Inȱ theȱ examplesȱ soȱ far,ȱ Iȱ haveȱ usedȱ onlyȱ simpleȱ typesȱ forȱ members.ȱ Butȱ anyȱ kindȱ ofȱ variableȱ thatȱ canȱ beȱ declaredȱ outsideȱ ofȱ aȱ structureȱ mayȱ alsoȱ beȱ usedȱ asȱ aȱ structureȱ member.ȱ Specifically,ȱ structureȱ membersȱ canȱ beȱ scalars,ȱ arrays,ȱ pointers,ȱ andȱ evenȱ otherȱstructures.ȱ Hereȱisȱaȱmoreȱcomplexȱexample:ȱ ȱ struct COMPLEX float f; int long struct struct struct { a[20]; *lp; SIMPLE SIMPLE SIMPLE s; sa[10]; *sp; }; ȱ Theȱ membersȱ ofȱ aȱ structureȱ mayȱ haveȱ namesȱ thatȱ areȱ identicalȱ toȱ membersȱ ofȱ otherȱ structures,ȱsoȱtheȱmemberȱaȱofȱthisȱstructureȱdoesnȇtȱconflictȱwithȱtheȱmemberȱ aȱwhichȱ isȱaȱpartȱofȱtheȱ struct SIMPLEȱ s.ȱAsȱyouȱwillȱseeȱnext,ȱtheȱwayȱinȱwhichȱmembersȱareȱ accessedȱallowsȱeitherȱmemberȱtoȱbeȱspecifiedȱwithoutȱambiguity.ȱ ȱ ȱ ȱ 10.1.3 Direct Member Access ȱ Theȱ membersȱofȱaȱ structureȱ variableȱ areȱaccessedȱwithȱtheȱ dotȱoperator,ȱ whichȱtakesȱ twoȱ operands.ȱ Theȱ leftȱ operandȱ isȱ theȱ nameȱ ofȱ aȱ structureȱ variableȱ andȱ theȱ rightȱ operandȱ isȱ theȱ nameȱ ofȱ theȱ desiredȱ member.ȱ Theȱ resultȱ ofȱ thisȱ expressionȱ isȱ theȱ designatedȱmember.ȱForȱinstance,ȱconsiderȱtheȱdeclarationȱ ȱ struct COMPLEX comp; ȱ ȱ Theȱmemberȱnamedȱ aȱisȱanȱarray,ȱsoȱtheȱexpressionȱ comp.aȱselectsȱthatȱmember.ȱThisȱ expressionȱisȱanȱarrayȱname,ȱsoȱyouȱcanȱuseȱitȱinȱanyȱcontextȱinȱwhichȱanȱarrayȱnameȱ couldȱbeȱused.ȱSimilarly,ȱtheȱmemberȱ sȱisȱaȱstructure,ȱsoȱtheȱexpressionȱ comp.sȱisȱtheȱ nameȱ ofȱ aȱ structureȱ variableȱ andȱ mayȱ beȱ usedȱ inȱ anyȱ wayȱ thatȱ weȱ mightȱ useȱ anȱ ordinaryȱstructureȱvariable.ȱȱSpecifically,ȱweȱcanȱuseȱthisȱexpressionȱasȱtheȱleftȱoperandȱ ofȱ anotherȱ dotȱ operator,ȱ asȱ inȱ (comp.s).a,ȱ toȱ selectȱ theȱ memberȱ namedȱ aȱ ofȱ theȱ structureȱ s,ȱwhichȱisȱaȱmemberȱofȱtheȱstructureȱ comp.ȱTheȱdotȱoperatorȱassociatesȱfromȱ leftȱtoȱrightȱsoȱweȱdoȱnotȱneedȱtheȱparentheses;ȱtheȱexpressionȱcomp.s.aȱisȱequivalent.ȱ Hereȱisȱaȱ moreȱcomplexȱ example.ȱTheȱ memberȱ saȱisȱanȱarrayȱ ofȱstructures,ȱsoȱ comp.saȱisȱanȱarrayȱnameȱwhoseȱvalueȱisȱaȱpointerȱconstant.ȱ Download at http://www.pin5i.com/ 10.1 Structure Basics 273 Applyingȱaȱsubscriptȱtoȱthisȱexpression,ȱasȱinȱ (comp.sa)[4],ȱyieldsȱoneȱelementȱofȱtheȱ array.ȱButȱthisȱelementȱisȱaȱstructure,ȱsoȱweȱcanȱuseȱanotherȱdotȱoperatorȱtoȱgetȱoneȱofȱ itsȱmembers.ȱHereȱisȱtheȱexpression:ȱ ȱ ( (comp.sa)[4] ).c ȱ Theȱ subscriptȱ andȱ dotȱ operatorsȱ haveȱ theȱ sameȱ precedenceȱ andȱ allȱ associateȱ leftȱ toȱ right,ȱsoȱweȱdonȇtȱneedȱtheseȱparenthesesȱeither.ȱTheȱexpressionȱ ȱ comp.sa[4].c ȱ isȱequivalent.ȱ ȱ ȱ ȱ 10.1.4 Indirect Member Access ȱ Howȱdoȱyouȱaccessȱtheȱmembersȱofȱaȱstructureȱifȱallȱyouȱhaveȱisȱaȱpointerȱtoȱit?ȱTheȱ firstȱstepȱisȱtoȱapplyȱindirectionȱtoȱtheȱpointer,ȱwhichȱtakesȱyouȱtoȱtheȱstructure.ȱThenȱ youȱ useȱ theȱ dotȱ operatorȱ toȱ selectȱ aȱ member.ȱ However,ȱ theȱ dotȱ operatorȱ hasȱ higherȱ precedenceȱ thanȱ theȱ indirection,ȱ soȱ youȱ mustȱ useȱ parenthesesȱ toȱ ensureȱ thatȱ theȱ indirectionȱisȱevaluatedȱfirst.ȱAsȱanȱexample,ȱsupposeȱanȱargumentȱtoȱaȱfunctionȱisȱaȱ pointerȱtoȱaȱstructure,ȱasȱinȱthisȱprototype:ȱ ȱ void func( struct COMPLEX *cp ); ȱ Theȱ functionȱ canȱ accessȱ theȱ memberȱ fȱ ofȱ theȱ structureȱ toȱ whichȱ thisȱ variableȱ pointsȱ withȱthisȱexpression:ȱ ȱ (*cp).f ȱ Theȱindirectionȱfollowsȱtheȱpointerȱtoȱtheȱstructure;ȱonceȱthereȱtheȱdotȱoperatorȱselectsȱ aȱmember.ȱ Becauseȱ thisȱnotationȱ isȱaȱ nuisance,ȱCȱprovidesȱaȱ moreȱ convenientȱoperatorȱ toȱ doȱthisȱjob—theȬ>ȱorȱarrowȱoperator.ȱLikeȱtheȱdot,ȱtheȱarrowȱtakesȱtwoȱ operands,ȱbutȱ theȱ leftȱ operandȱ mustȱ beȱ aȱ pointerȱ toȱ aȱ structure!ȱ Theȱ arrowȱ operatorȱ appliesȱ indirectionȱ toȱ theȱ leftȱ operandȱ toȱ followȱ theȱ pointer,ȱ andȱ thenȱ selectsȱ theȱ memberȱ specifiedȱ byȱ theȱ rightȱ operandȱ exactlyȱ likeȱ theȱ dotȱ operator.ȱ Theȱ indirectionȱ isȱ builtȱ intoȱ theȱ arrowȱ operator,ȱ though,ȱ soȱ weȱ donȇtȱ needȱ anȱ explicitȱ indirectionȱ orȱ theȱ accompanyingȱparentheses.ȱHereȱareȱaȱfewȱexamplesȱusingȱtheȱsameȱpointerȱasȱbefore.ȱ ȱ cp->f cp->a cp->s Download at http://www.pin5i.com/ Chapter 10 Structures and Unions 274ȱ TheȱfirstȱexpressionȱaccessesȱtheȱfloatingȬpointȱmember.ȱTheȱsecondȱisȱanȱarrayȱname,ȱ andȱ theȱ thirdȱ isȱ aȱ structure.ȱ Shortlyȱ youȱ willȱ seeȱ numerousȱ additionalȱ examplesȱ toȱ clarifyȱaccessingȱstructureȱmembers.ȱ ȱ ȱ ȱ 10.1.5 Self-Referential Structures ȱ Isȱitȱ legalȱforȱaȱ structureȱ toȱ containȱ aȱ memberȱ thatȱisȱ theȱsameȱtypeȱasȱtheȱ structure?ȱȱ Hereȱisȱanȱexampleȱtoȱillustrateȱthisȱidea.ȱ ȱ struct SELF_REF1 int struct int { a; SELF_REF1 b; c; }; ȱ Thisȱ typeȱ ofȱ selfȱ referenceȱ isȱ notȱ legal,ȱ becauseȱ theȱ memberȱ bȱ isȱ anotherȱ completeȱ structureȱ thatȱ willȱ containȱ itsȱ ownȱ memberȱ b.ȱ Thisȱ secondȱ memberȱ isȱ yetȱ anotherȱ completeȱstructureȱandȱcontainsȱitsȱownȱmemberȱb,ȱandȱsoȱforth,ȱforever.ȱTheȱproblemȱ isȱ somewhatȱ likeȱ aȱ recursiveȱ programȱ thatȱ neverȱ stopsȱ recursing.ȱ Butȱ theȱ followingȱ declarationȱisȱlegal.ȱCanȱyouȱseeȱtheȱdifference?ȱ ȱ struct SELF_REF2 int struct int { a; SELF_REF2 *b; c; }; CAUTION! ȱ Theȱdifferenceȱbetweenȱthisȱdeclarationȱandȱtheȱpreviousȱoneȱisȱthatȱbȱisȱnowȱaȱpointerȱ ratherȱ thanȱ aȱ structure.ȱ Theȱcompilerȱ knowsȱ theȱ sizeȱ ofȱ aȱ pointerȱ toȱ aȱ structureȱ evenȱ beforeȱtheȱsizeȱofȱtheȱstructureȱhasȱbeenȱdetermined,ȱsoȱthisȱselfȱreferenceȱisȱlegal.ȱ Ifȱ theȱ ideaȱ ofȱ aȱ structureȱ containingȱ aȱ pointerȱ toȱ itselfȱ seemsȱ strange,ȱ keepȱ inȱ mindȱ thatȱ itȱ willȱ actuallyȱ beȱ pointingȱ toȱ aȱ differentȱ structureȱ ofȱ theȱ sameȱ type.ȱ Moreȱ advancedȱ dataȱ structures,ȱ suchȱ asȱ linkedȱ listsȱ andȱ trees,ȱ areȱ implementedȱ withȱ thisȱ technique.ȱȱEachȱstructureȱpointsȱtoȱtheȱnextȱelementȱonȱtheȱlistȱorȱdownȱthisȱbranchȱofȱ aȱtree.ȱ ȱ Watchȱoutȱforȱthisȱtrap:ȱ ȱ typedef struct { int a; SELF_REF3 *b; int c; } SELF_REF3; Download at http://www.pin5i.com/ 10.1 Structure Basics 275 Theȱ intentȱ ofȱ thisȱ declarationȱ isȱ toȱ createȱ SELF_REF3ȱ asȱ theȱ typeȱ nameȱ forȱ thisȱ structure.ȱ Itȱ fails,ȱ however.ȱ Theȱ typeȱ nameȱ SELFT_REF3ȱ onlyȱ becomesȱ definedȱ atȱ theȱ endȱofȱtheȱdeclaration,ȱsoȱitȱisȱundefinedȱinsideȱofȱtheȱdeclarationȱ Theȱsolutionȱisȱtoȱdefineȱaȱstructureȱtagȱtoȱuseȱinȱdeclaringȱb,ȱasȱshownȱnext.ȱ ȱ typedef struct int struct int } SELF_REF3; SELF_REF3_TAG { a; SELF_REF3_TAG c; *b; ȱ ȱ ȱ ȱ 10.1.6 Incomplete Declarations ȱ Occasionallyȱyouȱwillȱhaveȱtoȱdeclareȱstructuresȱthatȱareȱmutuallyȱdependent,ȱthatȱis,ȱ eachȱ containsȱ oneȱ orȱ moreȱ membersȱ ofȱ theȱ otherȱ type.ȱ Asȱ withȱ selfȱ referentialȱ structures,ȱatȱleastȱoneȱofȱtheȱstructuresȱmustȱreferȱtoȱtheȱotherȱonlyȱthroughȱpointers.ȱȱ Theȱproblemȱisȱinȱtheȱdeclaration:ȱifȱeachȱstructureȱrefersȱtoȱtheȱotherȇsȱstructureȱtag,ȱ whichȱoneȱisȱdeclaredȱfirst?ȱ Theȱ solutionȱ toȱ thisȱ problemȱ isȱ theȱ incompleteȱ declaration,ȱ whichȱ declaresȱ anȱ identifierȱtoȱbeȱaȱstructureȱtag.ȱȱWeȱcanȱthenȱuseȱtheȱtagȱinȱdeclarationsȱwhereȱtheȱsizeȱ ofȱ theȱ structureȱ isȱ notȱ needed,ȱ suchȱ asȱ declaringȱ pointersȱ toȱ it.ȱ Aȱ subsequentȱ declarationȱassociatesȱaȱmemberȱlistȱwithȱtheȱtag.ȱ Considerȱ thisȱ example,ȱ inȱ whichȱ twoȱ differentȱ structureȱ typesȱ eachȱ containȱ aȱ pointerȱtoȱtheȱother.ȱ ȱ struct B; struct A { struct B *partner; /* other declarations */ }; struct B; struct A *partner; /* other declarations */ }; ȱ Theȱincompleteȱdeclarationȱofȱtheȱtagȱ Bȱisȱneededȱinȱdieȱmemberȱlistȱofȱ A.ȱOnceȱ Aȱhasȱ beenȱdeclared,ȱtheȱmemberȱlistȱforȱBȱcanȱbeȱdeclared.ȱ Download at http://www.pin5i.com/ Chapter 10 Structures and Unions 276ȱ 10.1.7 Initializing Structures ȱ Structuresȱ canȱ beȱ initializedȱ inȱ muchȱ theȱ sameȱ wayȱ asȱ arrays.ȱ Aȱ commaȬseparatedȱ initializerȱ listȱ enclosedȱ inȱ bracesȱ isȱ usedȱ toȱ specifyȱ theȱ valuesȱ forȱ theȱ structureȱ members.ȱȱTheȱvaluesȱareȱwrittenȱinȱtheȱorderȱgivenȱinȱtheȱmemberȱlist.ȱMissingȱvaluesȱ causeȱtheȱremainingȱmembersȱtoȱgetȱdefaultȱinitialization.ȱ Structuresȱ containingȱ arrayȱ orȱ structureȱ membersȱ areȱ initializedȱ similarȱ toȱ multidimensionalȱarrays.ȱAȱcompleteȱinitializerȱlistȱforȱtheȱaggregateȱmemberȱisȱnestedȱ withinȱtheȱinitializerȱlistȱforȱtheȱstructure.ȱȱHereȱisȱanȱexample:ȱ ȱ struct INIT_EX { int a; short b[10]; Simple c; } x = { 10, { 1, 2, 3, 4, 5 }, { 25, 'x', 1.9 } }; ȱ ȱ ȱ 10.2 Structures, Pointers, and Members ȱ Theȱ operatorsȱ forȱ accessingȱ structuresȱ andȱ theirȱ membersȱ directlyȱ andȱ throughȱ pointersȱareȱquiteȱsimple,ȱbutȱtheyȱcanȱbecomeȱconfusingȱwhenȱappliedȱinȱcomplicatedȱ situations.ȱHereȱareȱsomeȱexamplesȱtoȱhelpȱyouȱbetterȱunderstandȱhowȱtheȱoperatorsȱ work.ȱTheȱexamplesȱuseȱtheȱfollowingȱdeclarations.ȱ ȱ typedef } Ex2; typedef } Ex; struct { int a; short b[2]; struct int char Ex2 struct EX { a; b[3]; c; EX *d; ȱ StructuresȱofȱtypeȱExȱwillȱbeȱpicturedȱlikeȱthis:ȱ ȱ c aȱ d bȱ a b Download at http://www.pin5i.com/ 10.2 Structures, Pointers, and Members 277 Theȱstructuresȱareȱpicturedȱthisȱwayȱtoȱmakeȱtheȱexamplesȱclearer.ȱInȱfact,ȱtheȱdiagramȱ isȱ notȱ completelyȱ accurate,ȱ becauseȱ theȱ compilerȱ avoidsȱ wastingȱ spaceȱ betweenȱ theȱ membersȱwheneverȱitȱcan.ȱ Theȱfirstȱexamplesȱwillȱuseȱtheseȱdeclarations:ȱ ȱ Ex Ex x = { 10, "Hi", {5, { -1, 25 } }, 0 }; *px = &x; ȱ whichȱproduceȱtheȱfollowingȱvariables:ȱ ȱ xȱ ȱ ȱ c pxȱ a dȱ b ȱ a b 0 10 ȇHȇȱȱȇiȇȱȱȱȱ0 ȱ Ȭ1ȱȱ25ȱ 5 ȱ ȱ ȱ Weȱ willȱ nowȱ examineȱ andȱ diagramȱ differentȱ expressionsȱ usingȱ theȱ notationȱ fromȱ Chapterȱ6.ȱ ȱ ȱ ȱ 10.2.1 Accessing the Pointer ȱ Letȇsȱbeginȱwithȱtheȱpointerȱvariable.ȱTheȱRȬvalueȱofȱtheȱexpressionȱpxȱis:ȱ ȱ xȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ pxȱ a 10 b ȇHȇȱȱȇiȇȱȱȱȱ0 c a 5 b Ȭ1ȱȱ25ȱ dȱ 0 pxȱ isȱ aȱ pointerȱ variableȱ butȱ thereȱ isnȇtȱ anyȱ indirectionȱ operator,ȱ soȱ theȱ valueȱ ofȱ theȱ expressionȱisȱtheȱcontentsȱofȱpx.ȱTheȱLȬvalueȱofȱthisȱexpressionȱis:ȱ ȱ xȱ ȱ ȱ c pxȱ a dȱ b ȱ a b 0 10 ȇHȇȱȱȇiȇȱȱȱȱ0 ȱ Ȭ1ȱȱ25ȱ 5 ȱ ȱ whichȱshowsȱthatȱtheȱoldȱvalueȱofȱpxȱisȱaboutȱtoȱbeȱreplacedȱbyȱaȱnewȱvalue.ȱ Download at http://www.pin5i.com/ Chapter 10 Structures and Unions 278ȱ Nowȱ considerȱ theȱ expressionȱ px + l.ȱ Thisȱ expressionȱ isȱ notȱ aȱ legalȱ LȬvalueȱ becauseȱitsȱvalueȱisȱnotȱstoredȱinȱanyȱidentifiableȱmemoryȱlocation.ȱȱTheȱexpressionȇsȱ RȬvalueȱ isȱ moreȱ interesting.ȱ Ifȱ pxȱ hadȱ beenȱ pointingȱ toȱ anȱ elementȱ ofȱ anȱ arrayȱ ofȱ structures,ȱthisȱexpressionȱwouldȱpointȱtoȱtheȱnextȱstructureȱinȱtheȱarray.ȱAsȱitȱis,ȱtheȱ expressionȱ isȱ illegalȱ becauseȱ thereȱ isȱ noȱ wayȱ ofȱ tellingȱ whetherȱ whatȱ comesȱ nextȱ inȱ memoryȱisȱoneȱofȱtheseȱstructuresȱorȱsomethingȱelse.ȱȱTheȱcompilerȱisȱnotȱableȱtoȱdetectȱ suchȱerrors,ȱsoȱitȱisȱupȱtoȱyouȱtoȱdetermineȱwhenȱpointerȱarithmeticȱisȱmeaningful.ȱ ȱ ȱ ȱ 10.2.2 Accessing the Structure ȱ Weȱ canȱ applyȱ indirectionȱ toȱ theȱ pointerȱ withȱ theȱ *ȱ operator.ȱ Theȱ RȬvalueȱ ofȱ theȱ expressionȱ*pxȱisȱtheȱentireȱstructureȱtoȱwhichȱpxȱpoints.ȱ ȱ xȱ ȱ ȱ c pxȱ a dȱ b ȱ a b 0 10 ȇHȇȱȱȇiȇȱȱȱȱ0 ȱ Ȭ1ȱȱ25ȱ 5 ȱ ȱ ȱ Theȱindirectionȱfallowsȱtheȱarrow,ȱwhichȱisȱshownȱasȱaȱsolidȱline,ȱandȱtheȱresultȱisȱtheȱ wholeȱstructure.ȱȱYouȱcanȱassignȱthisȱexpressionȱtoȱanotherȱstructureȱofȱtheȱsameȱtype,ȱ orȱ youȱ canȱ useȱ itȱ asȱ theȱ leftȱ operandȱ ofȱ theȱ dotȱ operatorȱ toȱ selectȱ aȱ specificȱ member.ȱȱ Youȱcanȱalsoȱpassȱitȱasȱanȱargumentȱtoȱaȱfunctionȱorȱreturnȱitȱasȱtheȱvalueȱofȱaȱfunctionȱ (thoughȱthereȱareȱsomeȱefficiencyȱconcernsȱaboutȱtheseȱlastȱtwoȱoperationsȱthatȱwillȱbeȱ discussedȱlater).ȱTheȱLȬvalueȱofȱtheȱexpressionȱ*pxȱis:ȱ ȱ xȱ ȱ ȱ c pxȱ a dȱ b ȱ a b ȱ ȱ ȱ ȱ Here,ȱtheȱstructureȱisȱaboutȱtoȱreceiveȱaȱnewȱvalue,ȱofȱmoreȱprecisely,ȱnewȱvaluesȱforȱ allȱ ofȱ itsȱ members.ȱ Asȱ anȱ LȬvalue,ȱ itȱ isȱ theȱ placeȱ thatȱ isȱ important,ȱ notȱ theȱ valuesȱ containedȱinȱtheȱplace.ȱ Theȱexpressionȱ *px + 1ȱisȱillegal,ȱbecauseȱtheȱresultȱofȱ *pxȱisȱaȱstructure.ȱAdditionȱisȱ notȱ definedȱ betweenȱ structuresȱ andȱ integers.ȱ Butȱ whatȱ aboutȱ theȱ expressionȱ Download at http://www.pin5i.com/ 10.2 Structures, Pointers, and Members 279 ȱ*( px + 1 )ȱ?ȱIfȱxȱhadȱbeenȱanȱelementȱofȱanȱarray,ȱthisȱexpressionȱwouldȱreferȱtoȱtheȱ structureȱthatȱfollowedȱit.ȱButȱxȱisȱaȱscalar,ȱsoȱthisȱexpressionȱisȱactuallyȱillegal.ȱ ȱ ȱ ȱ ȱ 10.2.3 Accessing Structure Members ȱ Nowȱletȇsȱlookȱatȱtheȱarrowȱoperator.ȱTheȱRȬvalueȱofȱtheȱexpressionȱpx->aȱisȱ ȱ xȱ ȱ ȱ c pxȱ a dȱ b ȱ a b 0 10 ȇHȇȱȱȇiȇȱȱȱȱ0 ȱ Ȭ1ȱȱ25ȱ 5 ȱ ȱ ȱ TheȱȬ>ȱoperatorȱappliesȱindirectionȱtoȱ pxȱ(indicatedȱbyȱtheȱsolidȱarrow)ȱinȱorderȱtoȱgetȱ theȱstructure,ȱandȱthenȱselectsȱtheȱaȱmember.ȱTheȱexpressionȱ px->aȱisȱusedȱwhenȱyouȱ haveȱaȱpointerȱtoȱaȱstructureȱbutȱdoȱnotȱknowȱitsȱname.ȱȱIfȱyouȱknewȱtheȱnameȱofȱthisȱ structure,ȱyouȱcouldȱuseȱtheȱequivalentȱexpressionȱx.aȱinstead.ȱ Letȇsȱ pauseȱ hereȱ andȱ compareȱ theȱ expressionsȱ *pxȱ andȱ px->aȱ toȱ eachȱ other.ȱ Inȱ bothȱcases,ȱtheȱaddressȱinȱ pxȱisȱusedȱtoȱfoldȱtheȱstructure.ȱButȱtheȱfirstȱmemberȱinȱtheȱ structureȱisȱ a,ȱsoȱtheȱaddressȱofȱ aȱisȱtheȱsameȱasȱtheȱaddressȱofȱtheȱstructure.ȱItȱwouldȱ seem,ȱthen,ȱthatȱpxȱpointsȱtoȱtheȱstructureȱandȱtoȱtheȱfirstȱmemberȱofȱtheȱstructure:ȱafterȱ all,ȱ theyȱ bothȱ haveȱ theȱ sameȱ address.ȱ Thisȱ analysisȱ isȱ onlyȱ halfȱ correct,ȱ though.ȱ Althoughȱbothȱaddressesȱhaveȱtheȱsameȱvalue,ȱtheyȱhaveȱdifferentȱtypes.ȱTheȱvariableȱ pxȱ wasȱ declaredȱ asȱ aȱ pointerȱ toȱ aȱ structure,ȱ soȱ theȱ resultȱ ofȱ theȱ expressionȱ *pxȱ isȱ theȱ wholeȱstructure,ȱnotȱitsȱfirstȱmember.ȱ Letȇsȱcreateȱaȱpointerȱtoȱanȱinteger.ȱ ȱ int *pi; ȱ Canȱweȱmakeȱ piȱpointȱtoȱtheȱintegerȱmemberȱ a?ȱIfȱ piȱhadȱtheȱsameȱvalueȱasȱ px,ȱthenȱ theȱresultȱofȱtheȱexpressionȱ*piȱwouldȱbeȱtheȱmemberȱa.ȱȱButȱtheȱassignmentȱ ȱ ȱ pi = px; ȱ illegalȱbecauseȱtheirȱtypesȱdoȱnotȱmatch.ȱUsingȱaȱcastȱworks,ȱ ȱ pi = (int *) px; ȱ ȱ butȱ isȱ dangerousȱ becauseȱ itȱ circumventsȱ theȱ compilerȇsȱ typeȱ checking.ȱ Theȱ correct Download at http://www.pin5i.com/ 280ȱ Chapter 10 Structures and Unions expressionȱisȱsimpler—toȱgetȱaȱpointerȱtoȱpx->a,ȱuseȱtheȱ&ȱoperator:ȱ ȱ ȱ pi = &px->a; ȱ Theȱ precedenceȱ ofȱ theȱ ->ȱ operatorȱ isȱ higherȱ thanȱ thatȱ ofȱ &,ȱ soȱ parenthesesȱ areȱ notȱ neededȱinȱthisȱexpression.ȱȱLetȇsȱexamineȱaȱdiagramȱofȱ&px->a:ȱ ȱ xȱ ȱ ȱ c a dȱ b ȱ a b 0 10 ȇHȇȱȱȇiȇȱȱȱȱ0 ȱ Ȭ1ȱȱ25ȱ 5 pxȱ ȱ ȱ ȱ Noteȱ howȱ theȱ valueȱ inȱ theȱ ovalȱ pointsȱ directlyȱ toȱ theȱ aȱ memberȱ ofȱ theȱ structure,ȱ asȱ opposedȱtoȱpx,ȱwhichȱpointsȱtoȱtheȱentireȱstructure.ȱAfterȱtheȱassignmentȱabove,ȱpiȱandȱ pxȱ willȱ haveȱ theȱ sameȱ value.ȱ Butȱ theirȱ typesȱ areȱ different,ȱ soȱ theȱ resultȱ ofȱ applyingȱ indirectionȱ toȱ themȱ willȱ alsoȱ beȱ different: *pxȱ isȱ theȱ wholeȱ structure,ȱ and *piȱ isȱ aȱ singleȱinteger.ȱ Hereȱ isȱ anotherȱ exampleȱ usingȱ theȱ arrowȱ operator.ȱ Theȱ valueȱ ofȱ px->bȱ isȱ aȱ pointerȱconstantȱbecauseȱbȱisȱanȱarray.ȱThisȱexpressionȱisȱnotȱaȱlegalȱLȬvalue.ȱHereȱisȱitsȱ RȬvalue.ȱ ȱ ȱ ȱ xȱ ȱ ȱ c pxȱ a dȱ b ȱ a b 0 10 ȇHȇȱȱȇiȇȱȱȱȱ0 ȱ Ȭ1ȱȱ25ȱ 5 ȱ ȱ ȱ Ifȱweȱaddȱindirectionȱtoȱthisȱexpression,ȱitȱselectsȱtheȱfirstȱelementȱofȱtheȱarray.ȱȱ Withȱaȱsubscriptȱorȱpointerȱarithmetic,ȱotherȱelementsȱofȱtheȱarrayȱcanȱbeȱobtainedȱasȱ well.ȱTheȱexpressionȱpx->b[1]ȱselectsȱtheȱsecondȱarrayȱelement,ȱlikeȱthis:ȱ ȱ xȱ ȱ ȱ c pxȱ a dȱ b ȱ a b 0 10 ȇHȇȱȱȇiȇȱȱȱȱ0 ȱ Ȭ1ȱȱ25ȱ 5 ȱ Download at http://www.pin5i.com/ 10.2 Structures, Pointers, and Members 10.2.4 281 Accessing a Nested Structure ȱ Toȱaccessȱtheȱmemberȱc,ȱwhichȱisȱaȱstructure,ȱuseȱtheȱexpressionȱ px->c.ȱItsȱRȬvalueȱisȱ theȱentireȱstructure.ȱ ȱ xȱ ȱ ȱ c pxȱ a dȱ b ȱ a b 0 10 ȇHȇȱȱȇiȇȱȱȱȱ0 ȱ Ȭ1ȱȱ25ȱ 5 ȱ ȱ ȱ Theȱdotȱoperatorȱcanȱbeȱaddedȱtoȱthisȱexpressionȱtoȱaccessȱspecificȱmembersȱofȱ c.ȱForȱ example,ȱtheȱexpressionȱpx->c.aȱhasȱtheȱfollowingȱRȬvalue:ȱ ȱ xȱ ȱ ȱ c pxȱ a dȱ b ȱ a b 0 10 ȇHȇȱȱȇiȇȱȱȱȱ0 ȱ Ȭ1ȱȱ25ȱ 5 ȱ ȱ ȱ Thisȱexpressionȱcontainsȱbothȱtheȱdotȱandȱarrowȱoperators.ȱTheȱarrowȱisȱusedȱbecauseȱ pxȱisȱnotȱaȱstructure,ȱitȱpointsȱtoȱaȱstructure.ȱThenȱtheȱdotȱoperatorȱisȱusedȱbecauseȱȱȱpx>cȱdoesȱnotȱpointȱtoȱaȱstructure,ȱitȱisȱaȱstructure.ȱ Hereȱisȱaȱmoreȱcomplexȱexpression:ȱ ȱ *px->c.b ȱ Examiningȱ thisȱ expressionȱ isȱ easyȱ ifȱ youȱ takeȱ oneȱ stepȱ atȱ aȱ time.ȱ Thereȱ areȱ threeȱ operators,ȱ andȱ theȱ arrowȱ goesȱ firstȱ px->cȱ givesȱ theȱ structureȱ c.ȱ Addingȱ .bȱ toȱ theȱ expressionȱ selectsȱ theȱ memberȱ bȱ fromȱ structureȱ c.ȱ bȱ isȱ anȱ array,ȱ soȱ px->c.b isȱ aȱ (constant)ȱpointerȱtoȱtheȱfirstȱelementȱofȱtheȱarray.ȱFinally,ȱtheȱindirectionȱisȱappliedȱtoȱ thisȱ pointer,ȱ soȱ theȱ resultȱ isȱ theȱ firstȱ elementȱ ofȱ theȱ array.ȱ Theȱ expressionȱ isȱ diagrammedȱbelow.ȱ ȱ xȱ ȱ ȱ c pxȱ a dȱ b ȱ a b 0 10 ȇHȇȱȱȇiȇȱȱȱȱ0 ȱ Ȭ1ȱȱ25ȱ 5 ȱ ȱ ȱ Download at http://www.pin5i.com/ Chapter 10 Structures and Unions 282ȱ 10.2.5 Accessing a Pointer Member ȱ Theȱexpressionȱpx->dȱgivesȱtheȱresultȱyouȱwouldȱexpect—itsȱRȬvalueȱisȱ0,ȱandȱitsȱȱȱȱȱȱLȬ valueȱisȱtheȱlocationȱitself.ȱTheȱexpressionȱ *px->dȱisȱmoreȱinteresting.ȱHereȱindirectionȱ isȱappliedȱtoȱtheȱpointerȱvalueȱfoundȱinȱtheȱmemberȱ d.ȱButȱdȱcontainsȱtheȱnullȱpointer,ȱ soȱ itȱ doesnȇtȱ pointȱ toȱ anything.ȱ Dereferencingȱ aȱ nullȱ pointerȱ isȱ anȱ error,ȱ butȱ asȱ discussedȱearlier,ȱsomeȱenvironmentsȱwillȱnotȱcatchȱitȱatȱrunȱtime.ȱOnȱtheseȱmachines,ȱ theȱ programȱ willȱ accessȱ whateverȱ isȱ atȱ locationȱ zeroȱ asȱ ifȱ itȱ wereȱ oneȱ ofȱ theseȱ structures,ȱ andȱ thenȱ continueȱ merrilyȱ onȱ asȱ ifȱ nothingȱ wereȱ wrong.ȱ Thisȱ exampleȱ illustratesȱ theȱ importanceȱ ofȱ checkingȱ toȱ seeȱ thatȱ pointersȱ reallyȱ pointȱ toȱ somethingȱ beforeȱdereferencingȱthem.ȱ Letȇsȱcreateȱanotherȱstructureȱandȱsetȱx.dȱtoȱpointȱtoȱitȱ ȱ Ex y; x.d = &y; ȱ Nowȱweȱcanȱevaluateȱ*px->d.ȱ ȱ xȱ ȱ ȱ c pxȱ a dȱ b ȱ a b 10 ȇHȇȱȱȇiȇȱȱȱȱ0 ȱ Ȭ1ȱȱ25ȱ 5 ȱ ȱ ȱ yȱ ȱ ȱ c a dȱ b ȱ a b ȱ ȱ ȱ ȱ Theȱ memberȱ dȱ pointsȱ toȱ aȱ structure,ȱ soȱ applyingȱ indirectionȱ toȱ itȱ yieldsȱ theȱ entireȱ structure.ȱTheȱnewȱstructureȱwasȱnotȱinitializedȱexplicitly,ȱsoȱnoȱvaluesȱareȱshownȱforȱ itsȱmembersȱinȱtheȱdiagram.ȱ Asȱ youȱ mayȱ expect,ȱ membersȱ ofȱ thisȱ newȱ structureȱ canȱ beȱ selectedȱ byȱ addingȱ moreȱ operatorsȱ toȱ theȱ expression.ȱ Weȱ useȱ theȱ arrowȱ becauseȱ dȱ pointsȱ toȱ aȱ structure.ȱȱ Whatȱdoȱtheseȱexpressionsȱaccomplish?ȱ ȱ px->d->a px->d->b px->d->c px->d->c.a px->d->c.b[1] Download at http://www.pin5i.com/ 10.3 Structure Storage Allocation HereȱisȱaȱdiagramȱofȱtheȱRȬvalueȱofȱtheȱlastȱexpression.ȱ ȱ xȱ ȱ ȱ c pxȱ a b ȱ a b 10 ȇHȇȱȱȇiȇȱȱȱȱ0 ȱ Ȭ1ȱȱ25ȱ 5 ȱ ȱ ȱ yȱ ȱ ȱ c a b ȱ a b ȱ ȱ ȱ ȱ ȱ ȱ 283 dȱ dȱ 10.3 Structure Storage Allocation ȱ Howȱ areȱ structuresȱ actuallyȱ storedȱ inȱ memory?ȱ Theȱ diagramsȱ inȱ theȱ previousȱ examplesȱ implyȱ thatȱ structuresȱ containȱ aȱ lotȱ ofȱ emptyȱ space.ȱ Thisȱ pictureȱ isȱ notȱ entirelyȱaccurate.ȱMemoryȱisȱallocatedȱforȱeachȱofȱtheȱmembers,ȱoneȱafterȱanother,ȱinȱ theȱorderȱgivenȱbyȱtheȱmemberȱlist.ȱExtraȱmemoryȱisȱusedȱonlyȱwhenȱneededȱtoȱgetȱtheȱ correctȱboundaryȱalignmentȱofȱaȱmember.ȱToȱillustrate,ȱconsiderȱthisȱstructure:ȱ Toȱillustrate,ȱconsiderȱthisȱstructure:ȱ ȱ struct ALIGN { char int char a; b; c; }; ȱ Onȱ aȱ machineȱ whoseȱ integersȱ occupyȱ fourȱ bytesȱ andȱ mustȱ beginȱ atȱ aȱ byteȱ whoseȱ addressȱisȱevenlyȱdivisibleȱbyȱfour,ȱthisȱstructureȱwouldȱappearȱlikeȱthisȱinȱmemory:ȱ ȱ aȱ ȱ ȱ ȱ b ȱ ȱ ȱ cȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Theȱcompilerȱisȱforbiddenȱtoȱskipȱbytesȱforȱboundaryȱalignmentȱatȱtheȱbeginningȱofȱaȱ structure,ȱsoȱallȱstructuresȱmustȱbeginȱonȱwhateverȱboundaryȱisȱrequiredȱforȱtheȱmostȱ stringentȱ dataȱ type.ȱ Thus,ȱ theȱ memberȱ a,ȱ shownȱ byȱ theȱ leftmostȱ box,ȱ beginsȱ atȱ anȱ addressȱ divisibleȱ byȱ four.ȱ Theȱ nextȱ memberȱ isȱ anȱ integer,ȱ soȱ threeȱ bytesȱ (shownȱ in Download at http://www.pin5i.com/ 284ȱ Chapter 10 Structures and Unions ȱgray)ȱmustȱbeȱskippedȱtoȱreachȱanȱappropriateȱboundary.ȱAfterȱtheȱintegerȱcomesȱtheȱ lastȱcharacter.ȱ Ifȱaȱsecondȱvariableȱofȱtheȱsameȱtypeȱwereȱdeclared,ȱitȱwouldȱhaveȱtoȱbeginȱonȱaȱ boundaryȱ ofȱ fourȱ asȱ well,ȱ soȱ threeȱ moreȱ bytesȱ wouldȱ beȱ skippedȱ atȱ dieȱ endȱ ofȱ theȱ structure.ȱThus,ȱeachȱstructureȱwouldȱrequireȱtwelveȱbytesȱofȱmemoryȱbutȱwouldȱonlyȱ useȱsixȱofȱthem,ȱwhichȱisȱnotȱveryȱgoodȱutilization.ȱ Youȱ canȱ minimizeȱ theȱ spaceȱ lostȱ toȱ boundaryȱ alignmentȱ inȱ structuresȱ byȱ rearrangingȱtheȱmemberȱlistȱinȱtheȱstructureȱdeclarationȱsoȱthatȱtheȱmembersȱwithȱtheȱ strictestȱboundaryȱrequirementsȱappearȱfirstȱandȱthoseȱwithȱtheȱweakestȱrequirementsȱ appearȱlast.ȱForȱexample,ȱthisȱstructureȱ ȱ struct ALIGN2 int char char { b; a; c; }; ȱ containsȱtheȱsameȱmembersȱasȱtheȱpreviousȱstructure,ȱbutȱrequiresȱonlyȱeightȱbytes,ȱaȱ savingsȱofȱ33%.ȱȱTheȱtwoȱcharactersȱcanȱbeȱstoredȱadjacentȱtoȱoneȱanother,ȱsoȱtheȱonlyȱ wastedȱspaceȱisȱtheȱtwoȱbytesȱskippedȱafterȱtheȱstructure.ȱ ȱ Thereȱ mayȱ beȱ goodȱ reasonsȱ whyȱ weȱ mightȱ notȱ wantȱ toȱ rearrangeȱ theȱ membersȱ ofȱ aȱ structureȱtoȱreduceȱtheȱmemoryȱlostȱtoȱalignment.ȱForȱexample,ȱweȱmayȱwantȱtoȱkeepȱ relatedȱ structureȱ membersȱ togetherȱ forȱ easierȱ maintenanceȱ andȱ readability.ȱ (Lackingȱ anyȱsuchȱreasons,ȱhowever,ȱtheȱmembersȱofȱaȱstructureȱshouldȱbeȱarrangedȱaccordingȱ toȱ theirȱ boundaryȱ needsȱ inȱ orderȱ toȱ minimizeȱ theȱ memoryȱ thatȱ willȱ beȱ lostȱ toȱ alignment.ȱ Whenȱtheȱprogramȱwillȱbeȱcreatingȱhundredsȱorȱthousandsȱofȱtheȱstructures,ȱtheȱ needȱtoȱreduceȱwastedȱmemoryȱcanȱbecomeȱmoreȱimportantȱthanȱreadabilityȱconcerns.ȱ Inȱthisȱtypeȱofȱsituation,ȱaddingȱcommentsȱtoȱtheȱdeclarationȱmayȱhelpȱregainȱmuchȱofȱ theȱlostȱreadability.ȱ sizeofȱ givesȱ theȱ totalȱ sizeȱ ofȱ aȱ structure,ȱ whichȱ includesȱ anyȱ bytesȱ thatȱ areȱ skippedȱ forȱ boundaryȱ alignment.ȱ Ifȱ youȱ mustȱ determineȱ theȱ actualȱ positionȱ ofȱ aȱ memberȱ inȱ aȱ structure,ȱ takingȱ intoȱ accountȱ boundaryȱ alignment,ȱ useȱ theȱ offsetofȱ macroȱ(whichȱisȱdefinedȱinȱstddef.h).ȱ ȱ offsetoff( type, member ) ȱ typeȱisȱtheȱtypeȱofȱtheȱstructure,ȱandȱ memberȱisȱtheȱnameȱofȱtheȱmemberȱyouȱwant.ȱTheȱ resultȱ isȱ aȱ size_tȱ valueȱ specifyingȱ theȱ numberȱ ofȱ bytesȱ fromȱ theȱ beginningȱ ofȱ theȱ structureȱ whereȱ theȱ specifiedȱ memberȱ begins.ȱ Forȱ example,ȱ withȱ theȱ declarationȱ above,ȱ ȱ offsetof( struct ALIGN, b ) ȱ returnsȱfour.ȱ Download at http://www.pin5i.com/ 10.4 Structures as Function Arguments 285 10.4 Structures as Function Arguments ȱ Aȱstructureȱvariableȱisȱaȱscalarȱandȱcanȱbeȱusedȱwhereverȱanyȱotherȱscalarȱcanȱbeȱused.ȱ Thusȱitȱisȱlegalȱtoȱpassȱaȱstructureȱasȱanȱargumentȱtoȱaȱfunction,ȱbutȱthisȱtechniqueȱisȱ oftenȱinappropriate.ȱ Theȱ followingȱ codeȱ fragmentsȱ areȱ fromȱ aȱ programȱ writtenȱ toȱ operateȱ anȱ electronicȱ cashȱ register.ȱ Hereȱ isȱ theȱ declarationȱ forȱ aȱ structureȱ thatȱ containsȱ informationȱaboutȱanȱindividualȱtransaction.ȱ ȱ typedef struct char int float float } Transaction; { product[PRODUCT_SIZE]; quantity; unit_price; total_amount; ȱ Whenȱaȱtransactionȱoccurs,ȱthereȱareȱmanyȱstepsȱinvolved,ȱoneȱofȱwhichȱisȱprintingȱtheȱ receipt.ȱLetȇsȱlookȱatȱsomeȱdifferentȱwaysȱtoȱperformȱthisȱtask.ȱ ȱ void print_receipt( Transaction trans ) { printf( "%s\n", trans.product ); printf( "%d @ %.2f total %.2f\n", trans.quantity, trans.unit_price, trans.total_amount ); } CAUTION! ȱ Ifȱcurrent_transȱisȱaȱTransactionȱstructure,ȱweȱcouldȱcallȱtheȱfunctionȱlikeȱthis:ȱ ȱ ȱ print_receipt( current_trans ); ȱ Thisȱapproachȱproducesȱtheȱcorrectȱresult,ȱbutȱitȱisȱinefficientȱbecauseȱtheȱcallȬbyȬvalueȱ argumentȱpassingȱofȱCȱrequiresȱthatȱaȱcopyȱofȱtheȱargumentȱbeȱgivenȱtoȱtheȱfunction.ȱȱ Ifȱ PRODUCT_SIZEȱisȱ20ȱandȱweȱareȱusingȱaȱmachineȱwithȱfourȬbyteȱintegersȱandȱfloats,ȱ thisȱparticularȱstructureȱoccupiesȱ32ȱbytes.ȱToȱpassȱitȱasȱanȱargument,ȱ32ȱbytesȱmustȱbeȱ copiedȱontoȱtheȱstackȱandȱthenȱdiscardedȱlater.ȱ Compareȱtheȱpreviousȱfunctionȱwithȱthisȱone:ȱ ȱ void print_receipt( Transaction *trans ) { printf( "%s\n", trans->product ); printf( "%d @ %.2f total %.2f\n", trans->quantity, trans->unit_price, trans->total_amount ); } Download at http://www.pin5i.com/ 286ȱ Chapter 10 Structures and Unions whichȱwouldȱbeȱcalledȱinȱthisȱmanner:ȱ ȱ ȱ print_receipt( &current_trans ); ȱ Here,ȱ aȱ pointerȱ toȱ theȱ structureȱ isȱ passed.ȱ Theȱ pointerȱ isȱ smallerȱ thanȱ theȱ entireȱ structureȱandȱthereforeȱmoreȱefficientȱtoȱpushȱonȱtheȱstack.ȱTheȱpriceȱpaidȱforȱpassingȱ aȱpointerȱisȱthatȱweȱmustȱuseȱindirectionȱinȱtheȱfunctionȱtoȱaccessȱtheȱmembersȱofȱtheȱ structure.ȱTheȱbiggerȱtheȱstructure,ȱtheȱmoreȱefficientȱitȱisȱtoȱpassȱaȱpointerȱtoȱit.ȱ Onȱ manyȱ machines,ȱ youȱ canȱ improveȱ theȱ efficiencyȱ ofȱ theȱ pointerȱ versionȱ byȱ declaringȱtheȱparameterȱtoȱbeȱaȱregisterȱvariable.ȱOnȱsomeȱmachines,ȱthisȱdeclarationȱ requiresȱ anȱ extraȱ instructionȱ atȱ theȱ beginningȱ ofȱ theȱ functionȱ toȱ copyȱ theȱ argumentȱ fromȱtheȱstackȱ(whereȱitȱwasȱpassed)ȱtoȱtheȱregisterȱinȱwhichȱitȱwillȱbeȱused.ȱButȱifȱtheȱ functionȱ performsȱ indirectionȱ onȱ theȱ pointerȱ moreȱ thanȱ twoȱ orȱ threeȱ times,ȱ thenȱ theȱ savingsȱ realizedȱ inȱ theȱ indirectionsȱ willȱ beȱ greaterȱ thanȱ theȱ costȱ ofȱ theȱ additionalȱ instruction.ȱ Aȱdrawbackȱofȱpassingȱaȱpointerȱisȱthatȱtheȱfunctionȱisȱnowȱableȱtoȱmodifyȱtheȱ valuesȱinȱtheȱcallingȱprogramȇsȱstructureȱvariable.ȱIfȱitȱisȱnotȱsupposedȱtoȱdoȱthisȱyouȱ canȱuseȱtheȱconstȱkeywordȱinȱtheȱfunctionȱtoȱpreventȱsuchȱmodifications.ȱHereȱisȱwhatȱ theȱfunctionȱprototypeȱlooksȱlikeȱwithȱtheseȱtwoȱchanges:ȱ ȱ void print_receipt( register Transaction const *trans ); ȱ Letȇsȱmoveȱonȱtoȱanotherȱstepȱinȱprocessingȱaȱtransaction;ȱcomputingȱtheȱtotalȱ amountȱdue.ȱYouȱwouldȱexpectȱthatȱtheȱfunctionȱcompute_total_amountȱwouldȱmodifyȱ theȱ total_amountȱ memberȱ ofȱ theȱ structure.ȱ Thereȱ areȱ threeȱ waysȱ toȱ accomplishȱ thisȱ task.ȱȱLetȇsȱlookȱatȱtheȱleastȱefficientȱwayȱfirst.ȱTheȱfollowingȱfunctionȱ ȱ Transaction compute_total_amount( Transaction trans ) { trans.total_amount = trans.quantity * trans.unit_price; return trans; } ȱ wouldȱbeȱcalledȱinȱthisȱmanner:ȱ ȱ current_trans = compute_total_amount( current_trans ); ȱ Aȱ copyȱofȱ theȱ structureȱisȱpassedȱasȱ anȱargumentȱ andȱ modified.ȱȱThenȱaȱ copyȱ ofȱ theȱ modifiedȱstructureȱisȱreturned,ȱsoȱtheȱstructureȱisȱcopiedȱtwice.ȱ Download at http://www.pin5i.com/ 10.4 Structures as Function Arguments 287 ȱ Aȱ slightlyȱ betterȱ methodȱ isȱ toȱ returnȱ onlyȱ theȱ modifiedȱ valueȱ ratherȱ thanȱ theȱ entireȱstructure.ȱThisȱapproachȱisȱusedȱbyȱtheȱsecondȱfunction.ȱ ȱ float compute_total_amount( Transaction trans ) { return trans.quantity * trans.unit_price; } ȱ However,ȱthisȱfunctionȱmustȱbeȱinvokedȱinȱthisȱmannerȱ ȱ current_trans.total_amount = compute_total_amount( current_trans ); ȱ Thisȱversionȱisȱbetterȱthanȱreturningȱtheȱentireȱstructure,ȱbutȱtheȱtechniqueȱonlyȱworksȱ whenȱ aȱ singleȱ valueȱ isȱ toȱ beȱ computed.ȱ Ifȱ weȱ wantedȱ theȱ functionȱ toȱ modifyȱ twoȱ orȱ moreȱmembersȱofȱtheȱstructure,ȱthisȱapproachȱfails.ȱBesides,ȱthereȱisȱstillȱtheȱoverheadȱ ofȱ passingȱ theȱ structureȱ asȱ anȱ argument.ȱ Worse,ȱ itȱ requiresȱ thatȱ theȱ callingȱ programȱ haveȱ knowledgeȱ ofȱ theȱ contentsȱ ofȱ theȱ structure,ȱ specifically,ȱ theȱ nameȱ ofȱ theȱ totalȱ field.ȱ Theȱthirdȱapproach,ȱpassingȱaȱpointer,ȱisȱbetter:ȱ ȱ void compute_total_amount( register Transaction *trans ) { trans->total_amount = trans->quantity * trans->unit_price; } ȱ Thisȱfunctionȱisȱcalledȱlikeȱthis:ȱ ȱ compute_total_amount( &current_trans ); ȱ Now,ȱ theȱ total_amountȱ fieldȱ inȱ theȱ callerȇsȱ structureȱ isȱ modifiedȱ directly;ȱ thereȱ isȱ noȱ needȱtoȱpassȱtheȱentireȱstructureȱintoȱtheȱfunctionȱorȱtoȱcopyȱtheȱmodifiedȱstructureȱasȱ theȱreturnȱvalue.ȱThisȱversionȱisȱmoreȱefficientȱthanȱeitherȱofȱtheȱotherȱtwoȱfunctions.ȱ Inȱaddition,ȱtheȱcallerȱnoȱlongerȱneedsȱtoȱknowȱaboutȱtheȱinternalsȱofȱtheȱstructure,ȱsoȱ modularityȱisȱalsoȱimproved.ȱ Whenȱ shouldȱ youȱ passȱ aȱ structure,ȱ ratherȱ thanȱ aȱ pointer,ȱ asȱ anȱ argumentȱ toȱ aȱ function?ȱ Rarely.ȱ Onlyȱ whenȱ aȱ structureȱ isȱ extremelyȱ smallȱ (theȱ sizeȱ ofȱ aȱ pointer,ȱ orȱ smaller)ȱisȱitȱasȱefficientȱtoȱ passȱtheȱstructureȱasȱitȱisȱtoȱpassȱaȱpointerȱtoȱit.ȱForȱmostȱ structures,ȱitȱisȱmoreȱefficientȱtoȱpassȱaȱpointer.ȱIfȱyouȱwantȱtheȱfunctionȱtoȱbeȱableȱtoȱ modifyȱanyȱofȱtheȱstructureȇsȱmembers,ȱaȱpointerȱisȱalsoȱpreferred.ȱ Download at http://www.pin5i.com/ 288ȱ K&R C Chapter 10 Structures and Unions Withȱ veryȱ earlyȱ K&Rȱ Cȱ compilers,ȱ youȱ couldnȇtȱ passȱ structuresȱ asȱ arguments—theȱ compilerȱsimplyȱdidȱnotȱallowȱit.ȱLaterȱK&Rȱcompilersȱdidȱallowȱstructureȱarguments.ȱȱ However,ȱ theseȱ compilersȱ didȱ notȱ supportȱ const,ȱ soȱ theȱ onlyȱ wayȱ toȱ preventȱ aȱ functionȱfromȱmodifyingȱaȱstructureȱargumentȱwasȱtoȱpassȱaȱcopyȱofȱtheȱstructure.ȱ ȱ ȱ ȱ 10.5 Bit Fields TIP TIP ȱ Oneȱ lastȱ thingȱ toȱ mentionȱ aboutȱ structuresȱ isȱ theirȱ capabilityȱ forȱ implementingȱ bitȱ fields.ȱAȱbitȱfieldȱisȱdeclaredȱexactlyȱlikeȱaȱstructureȱexceptȱthatȱitsȱmembersȱareȱfieldsȱ ofȱ oneȱ orȱ moreȱ bits.ȱ Theseȱ variableȱ lengthȱ fieldsȱ areȱ actuallyȱ storedȱ inȱ oneȱ orȱ moreȱ integerȱvariables.ȱ Theȱ declarationȱ ofȱ aȱ bitȱ fieldȱ isȱ theȱ sameȱ asȱ theȱ declarationȱ ofȱ anyȱ ordinaryȱ structureȱ memberȱ withȱ twoȱ exceptions.ȱ First,ȱ bitȱ fieldȱ membersȱ mustȱ beȱ declaredȱ asȱ int,ȱ signed int,ȱ orȱ unsigned int.ȱ Second,ȱ aȱ colonȱ andȱ anȱ integerȱ appearȱ afterȱ theȱ memberȱname,ȱandȱtheȱintegerȱvalueȱspecifiesȱtheȱnumberȱofȱbitsȱinȱthatȱfield.ȱ ȱ Itȱisȱaȱgoodȱideaȱtoȱexplicitlyȱdeclareȱbitȱfieldsȱasȱeitherȱ signedȱorȱ unsignedȱintegers.ȱItȱ isȱ implementationȱ dependentȱ whetherȱ bitȱ fieldsȱ declaredȱ asȱ intȱ areȱ interpretedȱ asȱ signedȱorȱunsignedȱvalues.ȱ ȱ Programsȱ thatȱ areȱ intendedȱ toȱ beȱ portableȱ shouldȱ avoidȱ bitȱ fields.ȱ Becauseȱ ofȱ theȱ followingȱ implementationȱ dependencies,ȱ bitȱ fieldsȱ mayȱ workȱ differentlyȱ onȱ variousȱ systems.ȱ ȱ 1. Whetherȱanȱintȱbitȱfieldȱisȱtreatedȱasȱsignedȱorȱunsigned.ȱ 2. Theȱmaximumȱnumberȱofȱbitsȱinȱaȱbitȱfield.ȱManyȱcompilersȱlimitȱbitȱfieldȱmembersȱ toȱtheȱsizeȱofȱanȱinteger,ȱsoȱaȱbitȱfieldȱdeclarationȱthatȱworksȱonȱaȱmachineȱwithȱ32Ȭ bitȱintegersȱmayȱnotȱworkȱonȱoneȱthatȱusesȱ16Ȭbitȱintegers.ȱ 3. Whetherȱtheȱmembersȱinȱaȱbitȱfieldȱareȱallocatedȱfromȱleftȱtoȱrightȱorȱfromȱrightȱtoȱ leftȱinȱmemory.ȱ 4. Whenȱaȱdeclarationȱspecifiesȱtwoȱbitȱfieldsȱandȱtheȱsecondȱisȱtooȱlargeȱtoȱfitȱinȱtheȱ bitsȱleftȱoverȱfromȱtheȱfirst,ȱtheȱcompilerȱmayȱeitherȱputȱtheȱsecondȱbitȱfieldȱinȱtheȱ nextȱ wordȱ ofȱ memoryȱ orȱ immediatelyȱ afterȱ theȱ firstȱ field,ȱ overlappingȱ theȱ boundaryȱbetweenȱmemoryȱlocations.ȱ ȱ Hereȱisȱanȱexampleȱofȱȱaȱbitȱfieldȱdeclaration:ȱ ȱ ȱ Download at http://www.pin5i.com/ 10.5 Bit Fields struct }; struct CHAR { unsigned ch unsigned font unsigned size CHAR 289 : 7; : 6; : 19; ch1; ȱ Thisȱdeclarationȱisȱfromȱaȱtextȱformattingȱprogramȱthatȱisȱcapableȱofȱmanipulatingȱupȱ toȱ128ȱdifferentȱcharacterȱvaluesȱ(forȱwhichȱsevenȱbitsȱareȱrequired),ȱupȱtoȱ64ȱdifferentȱ fontsȱ(whichȱtakesȱsixȱbits),ȱinȱsizesȱfromȱ0ȱtoȱ524,287ȱunits.ȱTheȱsizeȱfieldȱisȱtooȱlargeȱtoȱ beȱheldȱinȱaȱshortȱinteger,ȱbutȱtheȱotherȱfieldsȱareȱbothȱsmallerȱthanȱaȱcharacter.ȱTheȱbitȱ fieldȱ letsȱ theȱ programmerȱ useȱ theȱ bitsȱ leftȱ overȱ fromȱ chȱ andȱ fontȱ toȱ increaseȱ theȱ numberȱ ofȱ bitsȱ forȱ size,ȱ thusȱ avoidingȱ theȱ needȱ toȱ declareȱ aȱ wholeȱ integerȱ toȱ store size.ȱ Manyȱ compilersȱ forȱ machinesȱ withȱ 16Ȭbitȱ integersȱ willȱ flagȱ thisȱ declarationȱ asȱ illegalȱ becauseȱ theȱ lastȱ fieldȱ isȱ tooȱ large.ȱ Butȱ onȱ aȱ 32Ȭbitȱ machine,ȱ thisȱ declarationȱ wouldȱcreateȱch1ȱasȱoneȱofȱtheseȱtwoȱpossibilities.ȱ ȱ chȱ font size ȱ 6 19ȱ ȱ 7ȱ ȱ ȱ sizeȱ ch fontȱ ȱ 7 19 6ȱ ȱ ȱ Thisȱexampleȱillustratesȱaȱgoodȱreasonȱtoȱuseȱbitȱfields:ȱtheȱabilityȱtoȱpackȱoddȬ sizedȱdataȱtogetherȱtoȱsaveȱstorage.ȱThisȱsavingsȱbecomesȱparticularlyȱimportantȱwhenȱ thousandsȱofȱtheseȱstructuresȱareȱbeingȱused.ȱ Theȱotherȱreasonȱtoȱuseȱbitȱfieldsȱisȱbecauseȱtheyȱmakeȱitȱconvenientȱtoȱaccessȱ partsȱ ofȱ anȱ integer.ȱ Letȇsȱ examineȱ anȱ exampleȱ thatȱ mightȱ beȱ foundȱ inȱ anȱ operatingȱ system.ȱTheȱcodeȱtoȱoperateȱtheȱfloppyȱdiskȱmustȱcommunicateȱwithȱtheȱcontrollerȱforȱ theȱ disk.ȱ Oftenȱ theseȱ deviceȱ controllersȱ containȱ severalȱ registers,ȱ eachȱ ofȱ whichȱ containsȱ manyȱ differentȱ valuesȱ allȱ packedȱ togetherȱ intoȱ oneȱ integer.ȱ Aȱ bitȱ fieldȱ isȱ aȱ convenientȱwayȱtoȱaccessȱtheȱindividualȱvalues.ȱ Supposeȱoneȱofȱtheȱregistersȱforȱtheȱcontrollerȱwasȱdefinedȱas:ȱ Ready ErrorȱOccurred DiskȱSpinning HeadȱLoaded WriteȱProtected ErrorȱCode 1ȱȱ1ȱȱ1ȱȱ1ȱȱ1ȱ 8 Track Sectorȱ 9 5ȱ Command 5 Download at http://www.pin5i.com/ Chapter 10 Structures and Unions 290ȱ Theȱfirstȱfiveȱfieldsȱareȱoneȱbitȱeach,ȱandȱtheȱremainingȱfieldsȱareȱlarger.ȱOnȱaȱmachineȱ thatȱallocatedȱbitȱfieldsȱfromȱrightȱtoȱleft,ȱtheȱfollowingȱdeclarationȱwouldȱallowȱeasyȱ accessȱtoȱtheȱvariousȱfieldsȱinȱthisȱregister.ȱ ȱ struct DISK_REGISTER_FORMAT { unsigned command unsigned sector unsigned track unsigned error_code unsigned head_loaded unsigned write_protect unsigned disk_spinning unsigned error_occurred unsigned ready : : : : : : : : : 5; 5; 9; 8; 1; 1; 1; 1; 1; }; ȱ Ifȱ theȱ diskȱ registerȱ isȱaccessedȱ atȱ memoryȱ addressȱ 0xc0200142,ȱ weȱ wouldȱ declareȱ theȱ followingȱpointerȱconstant:ȱ ȱ #define DISK_REGISTER \ ((struct DISK_REGISTER_FORMAT *) 0xc0200142) ȱ Withȱthisȱpreparation,ȱtheȱcodeȱneededȱtoȱactuallyȱaccessȱtheȱdiskȱregisterȱisȱsimple,ȱasȱ shownȱinȱthisȱcodeȱfragment.ȱ ȱ ȱ ȱ /* ** Tell the controller which sector and track, ** and start the read operation. */ DISK_REGISTER->sector = new_sector; DISK_REGISTER->track = new_track; DISK_REGISTER->command = READ; /* ** Wait until the operation is done, ** indicated by ready becoming true. */ while( ! DISK_REGISTER->ready ) ; /* ** Check for errors. * / if( DISK_REGISTER->error_occurred ){ switch( DISK_REGISTER->error_code ){ ... ȱ ȱ Download at http://www.pin5i.com/ 10.6 Unions 291 Bitȱfieldsȱareȱaȱconvenience.ȱAnyȱtaskȱthatȱcanȱbeȱcompletedȱwithȱbitȱfieldsȱcanȱ alsoȱbeȱaccomplishedȱthroughȱshiftingȱandȱmasking.ȱForȱexample,ȱtheȱfollowingȱcodeȱ accomplishesȱexactlyȱtheȱsameȱthingȱasȱtheȱfirstȱassignmentȱinȱtheȱpreviousȱexample.ȱ ȱ #define DISK_REGISTER (unsigned int *) 0xc0200142 *DISK_REGISTER &= 0xfffffc1f; *DISK_REGISTER |= ( new_sector & 0x1f ) << 5; TIP ȱ TheȱfirstȱassignmentȱusesȱaȱbitwiseȱANDȱtoȱclearȱallȱofȱtheȱbitsȱinȱtheȱsectorȱfieldȱ toȱ zeroȱ withoutȱ affectingȱ theȱ otherȱ bits.ȱ Theȱ secondȱ takesȱ theȱ valueȱ ofȱ new_sector,ȱ ANDȇsȱitȱtoȱmakeȱsureȱthatȱtheȱvalueȱdoesȱnotȱexceedȱtheȱwidthȱofȱtheȱfield,ȱshiftsȱitȱleftȱ toȱtheȱproperȱposition,ȱandȱthenȱusesȱaȱbitwiseȱORȱtoȱsetȱtheȱfieldȱtoȱtheȱdesiredȱvalue.ȱ ȱ Theȱbitȱfieldȱexpressesȱthisȱprocessȱmoreȱsimplyȱinȱtheȱsourceȱcode,ȱbutȱthereȱisnȇtȱanyȱ differenceȱinȱtheȱobjectȱcode.ȱTheȱsameȱshiftingȱandȱmaskingȱoperationsȱareȱrequiredȱ whetherȱ orȱ notȱ theȱ bitȱ fieldȱ isȱ used.ȱ Theȱ onlyȱ advantageȱ providedȱ byȱ theȱ bitȱ fieldȱ isȱ simplifyingȱ theȱ sourceȱ code.ȱ Thisȱ advantageȱ mustȱ beȱ weighedȱ againstȱ theȱ bitȱ fieldȇsȱ lackȱofȱportability.ȱ ȱ ȱ ȱ 10.6 Unions ȱ Aȱ unionȱ isȱ aȱ differentȱ animalȱ altogether.ȱ Aȱ unionȱ isȱ declaredȱ likeȱ aȱ structureȱ butȱ doesnȇtȱworkȱlikeȱaȱstructure.ȱAllȱofȱtheȱmembersȱofȱaȱunionȱreferȱtoȱtheȱsameȱlocation(s)ȱ inȱ memory.ȱ Unionsȱ areȱ usedȱ whenȱ youȱ needȱ toȱ storeȱ differentȱ thingsȱ inȱ oneȱ placeȱ atȱ differentȱtimes.ȱ ȱ First,ȱletȇsȱlookȱatȱaȱsimpleȱexample.ȱ ȱ union { float f; int i; } fi; ȱ Onȱ aȱ machineȱ inȱ whichȱ floatsȱ andȱ integersȱ bothȱ occupyȱ 32ȱ bits,ȱ theȱ variableȱ fiȱ occupiesȱ onlyȱ oneȱ 32Ȭbitȱ wordȱ ofȱ memory.ȱ Ifȱ theȱ memberȱ fȱ isȱ used,ȱ theȱ wordȱ isȱ accessedȱasȱaȱfloatingȬpointȱvalue;ȱifȱtheȱmemberȱ iȱisȱused,ȱtheȱwordȱisȱaccessedȱasȱanȱ integer.ȱSoȱthisȱcodeȱ ȱ fi.f = 3.14159; printf( "%d\n", fi.i ); ȱ firstȱstoresȱtheȱfloatingȬpointȱrepresentationȱofȱΔȱintoȱfi,ȱandȱthenȱinterpretsȱthoseȱsameȱ bitsȱasȱifȱtheyȱwereȱanȱintegerȱandȱprintsȱoutȱthatȱvalue.ȱȱNoteȱthatȱbothȱmemberȱareȱ Download at http://www.pin5i.com/ 292ȱ Chapter 10 Structures and Unions referringȱ toȱ theȱ sameȱ bits;ȱ theȱ onlyȱ differenceȱ isȱ thatȱ theȱ typeȱ ofȱ eachȱ memberȱ determinesȱhowȱtheȱbitsȱareȱinterpreted.ȱ Whyȱ wouldȱ anyoneȱ everȱ wantȱ toȱ doȱ anythingȱ likeȱ thisȱ example?ȱ Itȱ wouldȱ beȱ helpfulȱ ifȱ youȱ wantedȱ toȱ seeȱ howȱ floatingȬpointȱ numbersȱ areȱ storedȱ onȱ aȱ particularȱ machineȱbutȱprobablyȱnotȱforȱanythingȱelse.ȱHereȱisȱaȱmoreȱrealisticȱexample.ȱOneȱtaskȱ ofȱaȱBASICȱinterpreterȱisȱtoȱkeepȱtrackȱofȱtheȱvaluesȱofȱvariablesȱusedȱin.ȱtheȱprogram.ȱ BASICȱprovidesȱseveralȱdifferentȱtypesȱofȱvariables,ȱsoȱtheȱtypeȱofȱeachȱvariableȱmustȱ beȱstoredȱalongȱwithȱitsȱvalue.ȱHereȱisȱaȱstructureȱthatȱsavesȱthisȱinformation,ȱbutȱitȱisȱ notȱtooȱefficient.ȱ ȱ struct VARIABLE enum { INT, FLOAT, STRING } int int_value; float float_value; char *string_value; type; }; ȱ WhenȱaȱvariableȱinȱtheȱBASICȱprogramȱisȱcreated,ȱtheȱinterpreterȱcreatesȱoneȱofȱtheseȱ structuresȱ andȱ recordsȱ theȱ typeȱ ofȱ theȱ variable.ȱ Then,ȱ basedȱ onȱ theȱ type,ȱ oneȱ ofȱ theȱ threeȱvalueȱfieldsȱisȱusedȱtoȱstoreȱtheȱvariableȇsȱvalue.ȱ Whatȱisȱinefficientȱaboutȱthisȱstructureȱisȱtheȱamountȱofȱmemoryȱused—ȱeveryȱ VARIABLEȱcontainsȱtwoȱvalueȱfieldsȱthatȱareȱnotȱused.ȱAȱunionȱcanȱreduceȱthisȱwasteȱbyȱ storingȱ eachȱ ofȱ theȱ threeȱ valueȱ fieldsȱ inȱ theȱ sameȱ memory.ȱ Theȱ threeȱ fieldsȱ willȱ notȱ conflictȱbecauseȱeachȱvariableȱcanȱonlyȱhaveȱoneȱtype,ȱthusȱonlyȱoneȱofȱtheȱfieldsȱinȱtheȱ unionȱwillȱeverȱbeȱneededȱatȱaȱtime.ȱ ȱ struct VARIABLE enum { INT, FLOAT, STRING } type; union { int i; float f; char *s; } value; }; ȱ Now,ȱ forȱ anȱ integerȱ variable,ȱ youȱ wouldȱ storeȱ INTȱ inȱ theȱ typeȱ fieldȱ andȱ theȱ integerȱ valueȱinȱtheȱvalue.iȱfield.ȱȱForȱaȱfloatingȬpointȱvalue,ȱyouȱwouldȱuseȱtheȱvalue.fȱfield.ȱ Whenȱ obtainingȱ theȱ valueȱ ofȱ thisȱ variableȱ later,ȱ theȱ typeȱ fieldȱ wouldȱ beȱ checkedȱ toȱ determineȱwhichȱvalueȱfieldȱtoȱuse.ȱThisȱchoiceȱdeterminesȱhowȱtheȱmemoryȱlocationȱ willȱbeȱaccessed,ȱsoȱoneȱlocationȱcanȱbeȱusedȱtoȱstoreȱanyȱofȱtheseȱthreeȱdifferentȱkindsȱ ofȱvalues.ȱNoteȱthatȱtheȱcompilerȱdoesnȇtȱcheckȱtheȱ typeȱfieldȱtoȱverifyȱthatȱtheȱproperȱ unionȱ memberȱ isȱ used.ȱ Itȱ isȱ upȱ toȱ theȱ programmerȱ toȱ maintainȱ theȱ typeȱ fieldȱ andȱ toȱ checkȱit.ȱ ȱ Ifȱ theȱ memberȱ ofȱ aȱ unionȱ areȱ differentȱ sizes,ȱ theȱ unionȱ willȱ beȱ asȱ largeȱ asȱ theȱ largestȱmember.ȱTheȱnextȱsectionȱdiscussesȱthisȱsituation.ȱ Download at http://www.pin5i.com/ 10.6 Unions 10.6.1 293 Variant Records ȱ Letȇsȱ examineȱ anȱ exampleȱ thatȱ implementsȱ whatȱ Pascalȱ andȱ Modulaȱ callȱ aȱ variantȱ record.ȱConceptually,ȱthisȱisȱtheȱsameȱsituationȱweȱjustȱdiscussed—aȱparticularȱareaȱinȱ memoryȱ willȱ storeȱ differentȱ typesȱ ofȱ valuesȱ atȱ differentȱ times.ȱ Inȱ thisȱ case,ȱ however,ȱ theȱvaluesȱareȱmoreȱcomplexȱthanȱsimpleȱintegersȱorȱfloats.ȱEachȱisȱanȱentireȱstructure.ȱ Iȱtookȱtheȱfollowingȱexampleȱfromȱanȱinventoryȱsystemȱthatȱkeepsȱtrackȱofȱtwoȱ differentȱ kindsȱ ofȱ entities:ȱ partsȱ andȱ subassemblies.ȱ Aȱ partȱ isȱ aȱ gadgetȱ thatȱ isȱ purchasedȱ fromȱ anotherȱ manufacturer.ȱ Itȱ hasȱ variousȱ characteristicsȱ suchȱ asȱwhoȱ weȱ buyȱ itȱ from,ȱ howȱ muchȱ itȱ costs,ȱ andȱ soȱ forth.ȱ Aȱ subassemblyȱ isȱ somethingȱ thatȱ weȱ make,ȱandȱisȱaȱcombinationȱofȱaȱbunchȱofȱpartsȱandȱotherȱsubassemblies.ȱ Theȱ firstȱ twoȱ structuresȱ specifyȱ whatȱ mustȱ beȱ storedȱ forȱ aȱ partȱ andȱ forȱ aȱ subassembly.ȱ ȱ struct PARTINFO { int cost; int supplier; ... }; struct SUBASSYINFO { int n_parts; struct { char partno[10]; short quan; } parts[MAXPARTS]; }; ȱ Theȱ inventoryȱ recordȱ containsȱ commonȱ informationȱ forȱ eachȱ entryȱ andȱ aȱ unionȱ toȱ storeȱeitherȱpartȱinformationȱorȱsubassemblyȱinformation.ȱ ȱ struct INVREC { char partno[10]; int quan; enum { PART, SUBASSY } union { struct PARTINFO struct SUBASSYINFO } info; type; part; subassy; }; ȱ HereȱareȱsomeȱstatementsȱthatȱmanipulateȱanȱINVRECȱstructureȱvariableȱcalledȱrec.ȱ Download at http://www.pin5i.com/ Chapter 10 Structures and Unions 294ȱ if( rec.type == PART ){ y = rec.info.part.cons; z = rec.info.part.supplier; } else { y = rec.info.subassy.nparts; z = rec.info.subassy.parts[0].quan; } ȱ Althoughȱnotȱveryȱrealistic,ȱthisȱcodeȱillustratesȱhowȱtoȱaccessȱeachȱofȱtheȱmembersȱofȱ theȱunion.ȱTheȱfirstȱpartȱofȱtheȱstatementȱgetsȱtheȱcostȱandȱtheȱsupplierȱforȱaȱpart,ȱandȱ theȱsecondȱpartȱofȱtheȱstatementȱgetsȱtheȱnumberȱofȱdifferentȱpartsȱinȱaȱsubassemblyȱ andȱtheȱquantityȱofȱtheȱfirstȱpart.ȱ Inȱaȱunionȱwhoseȱmembersȱareȱdifferentȱsizes,ȱtheȱamountȱofȱmemoryȱallocatedȱ forȱ theȱ unionȱ isȱ determinedȱ byȱ theȱ sizeȱ ofȱ itsȱ largestȱ member.ȱ Thus,ȱ aȱ unionȱ willȱ alwaysȱbeȱbigȱenoughȱtoȱstoreȱitsȱlargestȱmember.ȱIfȱtheȱmembersȱareȱwildlyȱdifferentȱ sizes,ȱthereȱwillȱbeȱaȱlotȱofȱwastedȱmemoryȱwhenȱstoringȱtheȱshorterȱmembers.ȱInȱthisȱ typeȱofȱsituation,ȱitȱmightȱbeȱpreferableȱforȱtheȱunionȱtoȱstoreȱpointersȱtoȱtheȱdifferentȱ membersȱratherȱthanȱtheȱmembersȱthemselves.ȱTheȱpointersȱwouldȱallȱbeȱtheȱsameȱsizeȱ thusȱ avoidingȱ theȱ problemȱ ofȱ wastedȱ memory.ȱ Whenȱ itȱ isȱ decidedȱ whichȱ memberȱ isȱ needed,ȱ theȱ rightȱ amountȱ ofȱ memoryȱ canȱ beȱ obtainedȱ toȱ storeȱ it.ȱ Chapterȱ 11,ȱ whichȱ dealsȱ withȱ dynamicȱ memoryȱ allocation,ȱ containsȱ anȱ exampleȱ illustratingȱ thisȱ technique.ȱ ȱ ȱ ȱ 10.6.2 Initializing Unions ȱ Aȱunionȱvariableȱcanȱbeȱinitialized,ȱbutȱtheȱvalueȱmustȱappropriateȱforȱtheȱtypeȱofȱtheȱ firstȱmemberȱofȱtheȱunion,ȱandȱitȱmustȱbeȱenclosedȱinȱbraces.ȱȱForȱexample,ȱ ȱ union { int a; float b; char c[4]; } x = { 5 }; ȱ initializesȱx.aȱtoȱhaveȱtheȱvalueȱfive.ȱ Itȱ isȱ notȱ possibleȱ toȱ initializeȱ thisȱ variableȱ toȱ aȱ floatingȬpointȱ orȱ aȱ characterȱ value.ȱ Ifȱ anȱ initializerȱ ofȱ anyȱ otherȱ typeȱ isȱ given,ȱ itȱ isȱ convertedȱ (ifȱ possible)ȱ toȱ anȱ integerȱandȱassignedȱtoȱx.a.ȱ ȱ Download at http://www.pin5i.com/ 10.7 Summary 295 ȱ 10.7 Summary ȱ Valuesȱ ofȱ differentȱ typesȱ canȱ beȱ storedȱ togetherȱ inȱ aȱ structure.ȱ Theȱ valuesȱ inȱ aȱ structure,ȱcalledȱmembers,ȱareȱaccessedȱbyȱname.ȱAȱstructureȱvariableȱisȱaȱscalar,ȱandȱ canȱappearȱwhereverȱanȱordinaryȱscalarȱvariableȱcanȱappear,ȱ Theȱdeclarationȱofȱaȱstructureȱlistsȱtheȱmembersȱthatȱtheȱstructureȱwillȱcontain.ȱȱ Differentȱ declarationsȱ areȱ consideredȱ toȱ beȱ differentȱ typesȱ evenȱ ifȱ theirȱ memberȱ listsȱ areȱ identical.ȱ Aȱ structureȱ tagȱ isȱ aȱ nameȱ associatedȱ withȱ aȱ memberȱ list.ȱ Youȱ canȱ useȱ differentȱ declarationsȱ toȱ declareȱ structuresȱ ofȱ theȱ sameȱ typeȱ byȱ usingȱ aȱ structureȱ tagȱ ratherȱthanȱrepeatingȱtheȱmemberȱlistȱinȱtheȱdeclarations.ȱAȱ typedefȱmayȱalsoȱbeȱusedȱ toȱaccomplishȱthisȱgoal.ȱ Structureȱ membersȱ mayȱ beȱ scalars,ȱ arrays,ȱ orȱ pointers.ȱ Aȱ structureȱ mayȱ alsoȱ containȱmembersȱwhichȱareȱstructures.ȱThereȱisȱnoȱconflictȱbetweenȱidenticallyȱnamedȱ membersȱofȱdifferentȱstructures.ȱYouȱuseȱtheȱdotȱoperatorȱtoȱaccessȱtheȱmembersȱofȱaȱ structureȱvariable.ȱIfȱyouȱhaveȱaȱpointerȱtoȱaȱstructure,ȱyouȱuseȱtheȱarrowȱoperatorȱtoȱ accessȱtheȱstructureȇsȱmembers.ȱ Aȱ structureȱ mayȱ notȱ containȱ aȱ memberȱ thatȱ isȱ theȱ sameȱ typeȱ ofȱ structure,ȱ butȱ mayȱcontainȱaȱmemberȱthatȱisȱaȱpointerȱtoȱtheȱsameȱtypeȱofȱstructure.ȱThisȱtechniqueȱisȱ oftenȱ usedȱ inȱ linkedȱ dataȱ structures.ȱ Toȱ declareȱ twoȱ structuresȱ thatȱ eachȱ containȱ aȱ pointerȱtoȱtheȱotherȱtype,ȱanȱincompleteȱdeclarationȱisȱneededȱtoȱdefineȱaȱstructureȱtagȱ name.ȱ Structureȱ variablesȱ mayȱ beȱ initializedȱ byȱ givingȱ aȱ listȱ ofȱ valuesȱ enclosedȱ inȱ braces.ȱȱTheȱtypeȱofȱeachȱvalueȱmustȱbeȱappropriateȱforȱtheȱmemberȱthatȱitȱinitializes.ȱ Theȱ compilerȱ allocatesȱ memoryȱ forȱ theȱ membersȱ ofȱ aȱ structureȱ variableȱ inȱ accordanceȱ withȱ theirȱ boundaryȱ alignmentȱ requirements.ȱ Memoryȱ mayȱ beȱwastedȱ inȱ theȱ structureȱ toȱ achieveȱ theȱ properȱ alignment.ȱ Listingȱ theȱ structureȱ membersȱ inȱ decreasingȱ orderȱ ofȱ theirȱ alignmentȱ requirementsȱ minimizesȱ theȱ amountȱ ofȱ wastedȱ memoryȱinȱtheȱstructure.ȱTheȱvalueȱreturnedȱbyȱ sizeofȱincludesȱanyȱwastedȱmemoryȱ inȱaȱstructure.ȱ Structuresȱ mayȱ beȱ passedȱ asȱ argumentsȱ toȱ functionsȱ andȱ returnedȱ fromȱ functions.ȱ However,ȱ itȱ isȱ usuallyȱ moreȱ efficientȱ toȱ passȱ aȱ pointerȱ toȱ theȱ structureȱ instead.ȱ Theȱ constȱ keywordȱ canȱ beȱ usedȱ inȱ theȱ declarationȱ ofȱ aȱ pointerȱ argumentȱ toȱ preventȱtheȱfunctionȱfromȱmodifyingȱtheȱstructure.ȱ Bitȱ fieldsȱ areȱ structureȱ membersȱ whoseȱ sizeȱ isȱ specifiedȱ inȱ bits.ȱ Bitȱ fieldȱ declarationsȱ areȱ inherentlyȱ nonportableȱ dueȱ toȱ theȱ manyȱ factorsȱ thatȱ areȱ implementationȱ dependent.ȱ However,ȱ bitȱ fieldsȱ allowȱ youȱ toȱ packȱ oddȱ sizedȱ valuesȱ togetherȱ toȱ conserveȱ space.ȱ Theyȱ alsoȱ simplifyȱ theȱ sourceȱ codeȱ neededȱ toȱ accessȱ arbitraryȱrunsȱofȱbitsȱfromȱwithinȱaȱvalue.ȱ Theȱmembersȱofȱaȱunionȱareȱallȱstoredȱinȱtheȱsameȱmemory.ȱȱByȱaccessingȱunionȱ membersȱ ofȱ differentȱ types,ȱ theȱ sameȱ bitsȱ inȱ memoryȱ canȱ beȱ interpretedȱ differently.ȱ Unionsȱ areȱ usefulȱ inȱ implementingȱ variantȱ records,ȱ thoughȱ theȱ programmerȱ isȱ responsibleȱforȱkeepingȱtrackȱofȱwhichȱvariantȱhasȱbeenȱstoredȱandȱforȱselectingȱtheȱȱ Download at http://www.pin5i.com/ 296ȱ Chapter 10 Structures and Unions properȱunionȱmemberȱtoȱaccessȱ theȱdata.ȱAȱunionȱvariableȱcanȱbeȱinitialized,ȱbutȱtheȱ valueȱmustȱmatchȱtheȱtypeȱofȱitsȱfirstȱmember.ȱ ȱ ȱ ȱ 10.8 Summary of Cautions ȱ 1. Structureȱ declarationsȱ withȱ identicalȱ memberȱ listsȱ produceȱ variablesȱ ofȱ differentȱ typesȱ(pageȱ270).ȱ 2. BeȱcarefulȱusingȱtypedefȱtoȱdefineȱaȱnameȱforȱaȱselfȬreferentialȱstructureȱ(pageȱ274).ȱ 3. Passingȱstructuresȱasȱargumentsȱisȱinefficientȱ(pageȱ285).ȱ ȱ ȱ ȱ 10.9 Summary of Programming Tips ȱ 1. Putȱ structureȱ tagȱ declarationsȱ andȱ typedefȇsȱ intoȱ headerȱ files,ȱ whichȱ canȱ beȱ #includeȇdȱwhereverȱneededȱ(pageȱ271).ȱ 2. Theȱ bestȱ arrangementȱ ofȱ structureȱ membersȱ mayȱ notȱ beȱ theȱ oneȱ thatȱ wastesȱ theȱ leastȱamountȱofȱspaceȱdueȱtoȱboundaryȱalignmentȱ(pageȱ284).ȱ 3. Explicitlyȱ declareȱ bitȱ fieldȱ membersȱ asȱ either signed intȱ orȱ unsigned intȱ (pageȱ 288).ȱ 4. Bitȱfieldsȱareȱnotȱportableȱ(pageȱ288).ȱ 5. Bitȱfieldsȱallowȱbitȱoperationsȱtoȱbeȱexpressedȱmoreȱclearlyȱinȱtheȱsourceȱcodeȱ(pageȱ 291).ȱ ȱ ȱ ȱ 10.10 Questions ȱ 1. Howȱareȱstructureȱmembersȱdifferentȱfromȱarrayȱelements?ȱ 2. Howȱisȱaȱstructureȱnameȱdifferentȱfromȱanȱarrayȱname?ȱ 3. Theȱsyntaxȱforȱstructureȱdeclarationsȱshowsȱsomeȱoptionalȱcomponents.ȱListȱallȱtheȱ legalȱformsȱofȱaȱstructureȱdeclaration,ȱandȱexplainȱwhatȱisȱaccomplishedȱbyȱeach.ȱ 4. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱprogramȱfragment?ȱ ȱ struct abc { int a; int b; int c;ȱ Download at http://www.pin5i.com/ 10.10 Questions 297 }; ... abc.a = 25; abc.b = 15; abc.c = -1 5. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱprogramȱfragment?ȱ ȱ typedef struct { int a; int b; int c; } abc; ... abc.a = 25; abc.b = 15; abc.c = -1 6. Completeȱtheȱfollowingȱdeclarationȱtoȱinitializeȱxȱsoȱthatȱtheȱmemberȱaȱisȱthree,ȱbȱisȱ theȱstringȱhello,ȱandȱcȱisȱzero.ȱYouȱmayȱassumeȱthatȱxȱisȱstoredȱinȱstaticȱmemory.ȱ ȱ struct { int a; char b[10]; float c; } x = 7. Considerȱtheȱfollowingȱdeclarationsȱandȱdata.ȱ ȱ struct NODE { int a; struct NODE *b; struct NODE *c; }; struct NODE { 5, { 15, { 22, { 12, { 18, }; nodes[5] = { nodes + 3, NULL }, nodes + 4, nodes + 3 }, NULL, nodes + 4 }, nodes + 1, nodes }, nodes + 2, nodes + 1 } (Otherȱdeclarations...)ȱ struct NODE *np struct NODE *npp = nodes + 2; = &nodes[1].b; Download at http://www.pin5i.com/ 298ȱ Chapter 10 Structures and Unions Evaluateȱ eachȱ ofȱ theȱ expressionsȱ belowȱ andȱ stateȱ itsȱ value.ȱ Also,ȱ stateȱ anyȱ sideȱ effectsȱ thatȱ occurȱ whenȱ theȱ expressionȱ isȱ evaluated.ȱ Youȱ shouldȱ evaluateȱ eachȱ expressionȱ withȱ theȱ originalȱ valuesȱ shownȱ (thatȱ is,ȱ donȇtȱ useȱ theȱ resultsȱ ofȱ oneȱ expressionȱtoȱevaluateȱtheȱnextȱone).ȱAssumeȱthatȱtheȱnodesȱarrayȱbeginsȱatȱlocationȱ 200ȱandȱthatȱintegersȱandȱpointersȱareȱfourȱbytesȱonȱthisȱmachine.ȱ ȱ Expression Value Expression Value nodes ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. &nodes[3].c->a nodes.a ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. nodes[3].a ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. nodes[3].c ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. nodes[31.c->a *nodes ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. {*nodes}.a np np->a ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. np->c->c->a ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. *nodes.a &nodes->a npp npp->a ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. *npp nodes->a ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. nodes[3].b->b *nodes[3].b->b &nodes ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. &nodes[3].c *npp->a ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. (*npp)->a ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. &nodes[3].a **npp &np &np->a ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. &np->c->c->a ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱ 8. Howȱmuchȱspaceȱisȱwastedȱinȱtheȱfollowingȱstructureȱdueȱtoȱboundaryȱalignmentȱ onȱaȱmachineȱwithȱ16Ȭbitȱintegers?ȱOnȱaȱmachineȱwithȱ32Ȭbitȱintegers?ȱ ȱ struct { char int char }; a; b; c; 9. Nameȱatȱleastȱtwoȱreasonsȱwhyȱbitȱfieldȱdeclarationsȱareȱnotȱportable.ȱ 10. Writeȱ aȱ declarationȱ thatȱ allowsȱ easyȱ accessȱ toȱ theȱ individualȱ partsȱ ofȱ aȱ floatingȬ pointȱinȱtheȱfollowingȱformat.ȱ ȱ Fractionȱ(24ȱbits) Exponentȱ(7ȱbits) Signȱ(1ȱbit) ȱ Download at http://www.pin5i.com/ 10.10 Questions 299 11. Howȱ wouldȱ youȱ accomplishȱ theȱ sameȱ resultȱ asȱ theȱ followingȱ codeȱ withoutȱ usingȱ bitȱfields?ȱAssumeȱthatȱyouȱhaveȱaȱ16Ȭbitȱmachineȱthatȱallocatesȱbitȱfieldsȱfromȱleftȱ toȱright.ȱ ȱ struct { int int int int } x; ... x.a = aaa; x.b = bbb; x.c = ccc; x.d = ddd; a:4; b:8; c:3; d:1; 12. Whatȱdoesȱtheȱfollowingȱcodeȱfragmentȱprint?ȱ ȱ struct { int a:2; } x; ... x.a = 1; x.a += 1; printf( "%d\n", x.a ); 13. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱcodeȱfragment?ȱ ȱ union { int float char } x; ... x.a = 25; x.b = 3.14; x.c = 'x'; printf( "%d a; b; c; %g %c\n", x.a, x.b, x.c ); 14. Supposeȱ someȱ informationȱ hasȱ beenȱ assignedȱ toȱ aȱ unionȱ variable.ȱ Howȱ canȱ thisȱ informationȱbeȱretrievedȱcorrectly?ȱ 15. TheȱfollowingȱstructureȱcouldȱbeȱusedȱbyȱaȱBASICȱinterpreterȱtoȱkeepȱtrackȱofȱtheȱ typeȱandȱvalueȱofȱvariables.ȱ ȱ struct VARIABLE { Download at http://www.pin5i.com/ 300ȱ Chapter 10 Structures and Unions enum { INT, FLOAT, STRING } union { int i; float f; char *s; } value; type; }; ȱ Whatȱwouldȱbeȱdifferentȱifȱtheȱstructureȱwereȱwrittenȱlikeȱthisȱinstead:ȱ ȱ struct VARIABLE { enum { INT, FLOAT, STRING } type; union { int i; float f; char s[MAX_STRING_LENGTH]; } value; }; ȱ ȱ ȱ 10.11 Programming Exercises ȱ 1. Theȱinformationȱsavedȱbyȱtheȱtelephoneȱcompanyȱwhenȱyouȱmakeȱaȱlongȱdistanceȱ phoneȱ callȱ includesȱ theȱ dateȱ andȱ timeȱ youȱ placedȱ theȱ call.ȱ Itȱ alsoȱ includesȱ threeȱ phoneȱnumbers:ȱtheȱoneȱyouȱcalled,ȱtheȱoneȱyouȱareȱcallingȱfrom,ȱandȱtheȱoneȱthatȱ willȱ beȱ billed.ȱ Eachȱ ofȱ theseȱ phoneȱ numbersȱ hasȱ threeȱ parts:ȱ theȱ areaȱ code,ȱ theȱ exchange,ȱ andȱ theȱ stationȱ number.ȱ Writeȱ aȱ structureȱ declarationȱ forȱ thisȱ billingȱ information.ȱ 2. Writeȱaȱdeclarationȱforȱanȱinformationȱsystemȱthatȱrecordsȱsalesȱatȱanȱautoȱdealer.ȱȱȱ Theȱ followingȱ dataȱ mustȱ beȱ savedȱ forȱ everyȱ sale.ȱ Theȱ maximumȱ lengthȱ ofȱ stringȱ valuesȱgivenȱdoesȱnotȱincludeȱspaceȱforȱtheȱterminatingȱNULȱbyte.ȱ ȱ customerȇsȱnameȱ customerȇsȱaddressȱ modelȱ ȱ ȱ stringȱ(20)ȱ stringȱ(40)ȱ stringȱ(20)ȱ ȱ Threeȱ differentȱ typesȱ ofȱ transactionsȱ areȱ possible:ȱ allȬcashȱ sales,ȱ salesȱ involvingȱ aȱ loan,ȱ andȱ leases.ȱ Forȱ allȬcashȱ sales,ȱ theȱ followingȱ additionalȱ informationȱ mustȱ beȱ saved:ȱ ȱ ȱ ȱ ȱ manufacturerȇsȱsuggestedȱretailȱpriceȱ ȱ ȱ actualȱsellingȱpriceȱ ȱ salesȱtaxȱ ȱ ȱ ȱ ȱ licensingȱfeeȱ ȱ ȱ ȱ ȱ floatȱ floatȱ floatȱ floatȱ Download at http://www.pin5i.com/ 10.11 Programming Exercises 301 Forȱleases,ȱtheȱfollowingȱadditionalȱinformationȱmustȱbeȱsaved:ȱ ȱ manufacturerȇsȱsuggestedȱretailȱpriceȱ ȱ ȱ actualȱsellingȱpriceȱ ȱ downȱpaymentȱ ȱ ȱ ȱ securityȱdepositȱ ȱ ȱ ȱ monthlyȱpaymentȱ ȱ ȱ ȱ leaseȱtermȱ ȱ ȱ ȱ ȱ floatȱ floatȱ floatȱ floatȱ floatȱ intȱ ȱ Forȱsalesȱinvolvingȱaȱloan,ȱtheȱfollowingȱadditionalȱinformationȱmustȱbeȱsaved:ȱ ȱ manufacturerȇsȱsuggestedȱretailȱpriceȱ ȱ ȱ actualȱsellingȱpriceȱ ȱ salesȱtaxȱ ȱ ȱ ȱ ȱ licensingȱfeeȱ ȱ ȱ ȱ ȱ downȱpaymentȱ ȱ ȱ ȱ loanȱdurationȱ ȱ ȱ ȱ ȱ interestȱrateȱ ȱ ȱ ȱ ȱ monthlyȱpaymentȱ ȱ ȱ ȱ ȱ ȱ ȱ nameȱofȱbankȱ ȱ floatȱ floatȱ floatȱ floatȱ floatȱ intȱ floatȱ floatȱ stringȱ(20)ȱ 3. Oneȱ ofȱ theȱ computerȇsȱ tasksȱ isȱ toȱ decodeȱ eachȱ instructionȱ inȱ theȱ programȱ thatȱ isȱ runningȱtoȱdetermineȱwhatȱoperationȱtoȱperform.ȱOnȱmanyȱmachines,ȱtheȱdecodingȱ processȱisȱcomplicatedȱbyȱtheȱfactȱthatȱdifferentȱinstructionsȱhaveȱdifferentȱformats.ȱ Onȱ oneȱ particularȱ machine,ȱ eachȱ instructionȱ isȱ 16ȱ bitsȱ long,ȱ andȱ theȱ followingȱ differentȱformatsȱareȱimplemented.ȱBitsȱareȱnumberedȱfromȱrightȱtoȱleft.ȱ ȱ Single Operand (sgl_op) Doubla Operand (dpl_op) Branch (branch) Bits Field Name Bits Field Name Bits Field Name 0-2 3-5 6-15 dst_reg dst_mode opcode ȱ ȱ Register Source (rag_src) Bits Field Name 0-2 3-5 6-8 9-15 dst_reg dst_mode src_reg opcode 0-2 3-5 6-8 9-11 12-15 dst_reg dst_mode src_reg src_mode opcode 0-7 8-15 offset opcode Miscellaneous (misc) Bits Field Name 0-15 opcode ȱ Yourȱ taskȱ isȱ toȱ writeȱ aȱ declarationȱ thatȱ willȱ allowȱ aȱ programȱ toȱ interpretȱ anȱ instructionȱinȱanyȱofȱtheseȱformats.ȱȱYourȱdeclarationȱmustȱalsoȱhaveȱanȱunsigned Download at http://www.pin5i.com/ 302ȱ Chapter 10 Structures and Unions shortȱfieldȱcalledȱaddrȱthatȱaccessesȱallȱ16ȱbits.ȱUseȱaȱtypedefȱinȱyourȱdeclarationȱtoȱ createȱaȱnewȱtypeȱcalledȱmachine_inst.ȱ Givenȱtheȱdeclaration:ȱ ȱ machine_inst x; ȱ theȱexpressionsȱbelowȱshouldȱaccessȱtheȱindicatedȱbits.ȱ ȱ Expression Bits x.addr x.misc.opcode x.branch.opcode x.sgl_op.dst_mode x.reg_src.src_reg x.dbl_op.opcode ȱ ȱ ȱ 0-15 0-15 8-15 3-5 6-8 12-15 Download at http://www.pin5i.com/ 11 Dynamic Memory Allocation Theȱelementsȱofȱanȱarrayȱareȱstoredȱinȱcontiguousȱlocationsȱinȱmemory.ȱWhenȱanȱarrayȱ isȱ declared,ȱ itsȱ memoryȱ isȱ allocatedȱ atȱ compileȱ time.ȱ However,ȱ youȱ canȱ alsoȱ allocateȱ theȱ memoryȱ atȱ runtimeȱ withȱ dynamicȱ memoryȱ allocation.ȱ Inȱ thisȱ chapter,ȱ weȱ willȱ examineȱ theȱ differencesȱ betweenȱ theseȱ techniquesȱ andȱ seeȱ whenȱ andȱ howȱ toȱ useȱ dynamicȱmemoryȱallocation.ȱ ȱ ȱ ȱ 11.1 Why Use Dynamic Allocation TIP ȱ Whenȱdeclaringȱarrays,ȱtheȱarrayȱsizeȱmustȱbeȱgivenȱasȱaȱcompileȬtimeȱconstant.ȱOften,ȱ theȱactualȱsizeȱneededȱforȱtheȱarrayȱisȱnotȱknownȱuntilȱrunȱtimeȱbecauseȱtheȱamountȱofȱ spaceȱ dependsȱ uponȱ theȱ inputȱ data.ȱ Forȱ example,ȱ aȱ programȱ thatȱ computesȱ studentȱ gradesȱ andȱ averagesȱ mightȱ needȱ toȱ storeȱ dataȱ forȱ allȱ ofȱ theȱ studentsȱ inȱ aȱ class,ȱ butȱ differentȱclassesȱwillȱhaveȱdifferentȱnumbersȱofȱstudents.ȱInȱtheseȱsituations,ȱtheȱusualȱ approachȱisȱtoȱdeclareȱanȱarrayȱthatȱisȱasȱbigȱasȱitȱeverȱwillȱneedȱtoȱbe.ȱ ȱ Thisȱ approachȱ hasȱ theȱ advantageȱ ofȱ beingȱ simple,ȱ butȱ itȱ hasȱ severalȱ disadvantages.ȱ First,ȱ suchȱ declarationsȱ buildȱ anȱ artificialȱ limitationȱ intoȱ theȱ program,ȱ makingȱ itȱ incapableȱ ofȱ handlingȱ problemsȱ largerȱ thanȱ theȱ sizeȱ usedȱ inȱ theȱ declaration.ȱ Theȱ obviousȱ solutionȱ isȱ toȱ makeȱ theȱ arrayȱ evenȱ bigger,ȱ butȱ theȱ secondȱ problemȱ thenȱ becomesȱevenȱworse.ȱNearlyȱallȱofȱtheȱmemoryȱusedȱforȱaȱhugeȱarrayȱisȱwastedȱwhenȱ theȱ numberȱ ofȱ elementsȱ actuallyȱ requiredȱ isȱ small.ȱ Aȱ thirdȱ disadvantageȱ isȱ thatȱ theȱ programȱmustȱrespondȱinȱaȱreasonableȱwayȱwhenȱthereȱisȱmoreȱinputȱthanȱtheȱarrayȱ canȱhold.ȱItȱshouldȱnotȱfailȱwithȱanȱexception,ȱandȱitȱmustȱnotȱprintȱanswersȱthatȱlookȱ validȱbutȱinȱfactȱareȱwrong.ȱTheȱrequiredȱlogicȱisȱsimpleȱenough,ȱbutȱtheȱassumptionȱ thatȱ Ȉtheȱ arrayȱ willȱ neverȱ overflowȈȱ makesȱ itȱ veryȱ temptingȱ toȱ notȱ botherȱ implementingȱit.ȱ Download at http://www.pin5i.com/ 304ȱ Chapter 11 Dynamic Memory Allocationȱ 11.2 Malloc and Free ȱ TheȱCȱlibraryȱprovidesȱtwoȱfunctions,ȱmallocȱandȱfree,ȱthatȱperformȱdynamicȱmemoryȱ allocationȱ andȱ deallocation.ȱ Theseȱ functionsȱ maintainȱ aȱ poolȱ ofȱ availableȱ memory.ȱ Whenȱaȱprogramȱneedsȱadditionalȱmemory,ȱitȱcallsȱmalloc,ȱwhichȱtakesȱanȱappropriateȱ pieceȱ ofȱmemoryȱ fromȱ theȱ poolȱandȱ returnsȱaȱpointerȱtoȱ thisȱblockȱofȱmemoryȱtoȱ theȱ program.ȱTheȱmemoryȱisȱnotȱinitializedȱinȱanyȱway.ȱIfȱitȱisȱimportantȱthatȱtheȱmemoryȱ beȱinitialized,ȱyouȱmustȱeitherȱdoȱitȱyourselfȱorȱuseȱtheȱ callocȱfunctionȱ(describedȱinȱ theȱnextȱsection).ȱWhenȱaȱpreviouslyȱallocatedȱpieceȱofȱmemoryȱisȱnoȱlongerȱneeded,ȱ freeȱisȱcalledȱtoȱreturnȱitȱtoȱtheȱpoolȱforȱlaterȱreuse.ȱ Theȱprototypesȱforȱtheseȱtwoȱfunctionsȱareȱshownȱbelow,ȱandȱareȱinȱstdlib.h.ȱ ȱ ȱ void void *malloc( size_t size ); free( void *pointer ); ȱ ȱ Theȱ argumentȱ toȱ mallocȱ isȱ theȱ numberȱ ofȱ bytesȱ (characters)ȱ ofȱ memoryȱ thatȱ areȱ needed. 41 ȱIfȱtheȱdesiredȱamountȱofȱmemoryȱisȱavailable,ȱmallocȱreturnsȱaȱpointerȱtoȱtheȱ beginningȱofȱtheȱallocatedȱblock.ȱ ȱ ȱ mallocȱ allocatesȱ contiguousȱ blocksȱ ofȱ memory.ȱ Forȱ example,ȱ aȱ requestȱ forȱ 100ȱ bytesȱ willȱ beȱ satisfiedȱ withȱ 100ȱ adjacentȱ bytes,ȱ neverȱ withȱ twoȱ orȱ moreȱ separateȱ chunksȱ ofȱ memory.ȱ Also,ȱ mallocȱ mayȱ actuallyȱ allocateȱ aȱ chunkȱ ofȱ memoryȱ slightlyȱ largerȱ thanȱ requested.ȱ However,ȱ thisȱ behaviorȱ isȱ implementationȱ dependent,ȱ soȱ youȱ shouldȱnotȱcountȱonȱgettingȱmoreȱmemoryȱthanȱyouȱrequested.ȱ ȱ Whatȱifȱtheȱpoolȱofȱmemoryȱisȱempty,ȱorȱitȱdoesȱnotȱcontainȱaȱbigȱenoughȱblock?ȱ Inȱ thisȱ case,ȱ mallocȱ callsȱ theȱ operatingȱ systemȱ toȱ obtainȱ moreȱ memoryȱ andȱ beginsȱ allocatingȱpiecesȱfromȱthisȱnewȱchunk.ȱIfȱtheȱoperatingȱsystemȱisȱunableȱtoȱgiveȱmoreȱ memoryȱ toȱ malloc,ȱ thenȱ aȱ NULLȱ pointerȱ isȱ returned.ȱ Thusȱ itȱ isȱ vitalȱ thatȱ theȱ pointerȱ returnedȱbyȱeveryȱcallȱtoȱmalloc beȱcheckedȱtoȱensureȱthatȱitȱisȱnotȱNULL.ȱ ȱ Theȱ argumentȱ toȱ freeȱ mustȱ eitherȱ beȱ NULLȱ orȱ aȱ valueȱ thatȱ wasȱ previouslyȱ returnedȱ fromȱ malloc,ȱ calloc,ȱ orȱ reallocȱ (describedȱ below).ȱ Passingȱ aȱ NULLȱ argumentȱtoȱfree hasȱnoȱeffect.ȱ ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ 41 ȱNoteȱthatȱtheȱtypeȱofȱthisȱargumentȱisȱsize_t,ȱwhichȱisȱanȱunsignedȱtype.ȱItȱisȱdefinedȱin stdlib.h.ȱ Download at http://www.pin5i.com/ 11.3 Calloc and Reallocȱ 305 Howȱ doesȱ mallocȱ knowȱ whetherȱ youȱ wantȱ toȱ storeȱ integers,ȱ floatingȬpointȱ values,ȱ structures,ȱ orȱ arraysȱ inȱ theȱ memoryȱ youȇveȱ requested?ȱ Itȱ doesnȇt—mallocȱ returnsȱ aȱ pointerȱ ofȱ typeȱ void *ȱ forȱ preciselyȱ thisȱ reason.ȱ Theȱ Standardȱ statesȱ thatȱ aȱ void *ȱ pointerȱ canȱ beȱ convertedȱ toȱ anyȱ otherȱ pointerȱ type.ȱ Someȱ compilerȱ though,ȱ especiallyȱolderȱones,ȱmayȱrequireȱyouȱtoȱuseȱaȱcastȱforȱtheȱconversion.ȱ Onȱmachinesȱwithȱboundaryȱalignmentȱrequirements,ȱtheȱmemoryȱreturnedȱbyȱ mallocȱwillȱalwaysȱbeginȱonȱaȱboundaryȱthatȱisȱsuitableȱforȱtheȱdataȱtypeȱwithȱtheȱmostȱ stringentȱalignmentȱrequirements.ȱ ȱ ȱ ȱ 11.3 Calloc and Realloc ȱ Thereȱ areȱ twoȱ additionalȱ memoryȱ allocationȱ functions,ȱ callocȱ andȱ realloc.ȱ Theirȱ prototypesȱareȱshownȱbelow.ȱ ȱ void void *calloc( size_t num_elementa, size_t element_size ); *realloc( void *ptr, size_t new_size ); ȱ callocȱalsoȱallocatesȱmemory.ȱTheȱmajorȱdifferenceȱbetweenȱmallocȱandȱcallocȱisȱthatȱ theȱ latterȱ initializesȱ theȱ memoryȱ toȱ zeroȱ beforeȱ returningȱ aȱ pointerȱ toȱ it.ȱ Thisȱ initializationȱisȱoftenȱconvenient,ȱbutȱisȱaȱwasteȱofȱtimeȱifȱtheȱfirstȱthingȱyourȱprogramȱ doesȱisȱtoȱstoreȱvaluesȱintoȱtheȱarray.ȱAȱminorȱdifferenceȱbetweenȱcallocȱandȱmallocȱisȱ theȱ wayȱ theȱ amountȱ ofȱ memoryȱ isȱ requested,ȱ callocȱ takesȱ theȱ numberȱ ofȱ elementsȱ desiredȱandȱtheȱnumberȱofȱbytesȱinȱeachȱelement.ȱFromȱtheseȱvaluesȱitȱcomputesȱtheȱ totalȱnumberȱofȱbytesȱneeded.ȱ Theȱ reallocȱfunctionȱisȱusedȱtoȱchangeȱtheȱsizeȱofȱaȱpreviouslyȱallocatedȱblockȱ ofȱ memory.ȱ Youȱ canȱ makeȱ aȱ blockȱ largerȱ orȱ smallerȱ withȱ thisȱ functionȱ Ifȱ aȱ blockȱ isȱ madeȱ larger,ȱ itsȱ oldȱ contentsȱ remainȱ unchangedȱ andȱ additionalȱ memoryȱ isȱ addedȱ toȱ theȱ endȱ ofȱ theȱ block.ȱ Theȱ newȱ memoryȱ isȱ notȱ initializedȱ inȱ anyȱ way.ȱ Ifȱ theȱ blockȱ isȱ madeȱ smaller,ȱ thenȱ memoryȱ isȱ takenȱ offȱ ofȱ theȱ end.ȱ Whatȱ remainsȱ ofȱ theȱ originalȱ contentsȱareȱunchanged.ȱ Ifȱtheȱoriginalȱblockȱcannotȱbeȱresized,ȱreallocȱwillȱallocateȱaȱdifferentȱblockȱofȱtheȱ rightȱsizeȱandȱcopyȱtheȱcontentsȱofȱtheȱoldȱblockȱtoȱtheȱnewȱone.ȱThus,ȱyouȱmustȱnotȱ useȱ theȱ oldȱ pointerȱ toȱ theȱ blockȱ afterȱ aȱ callȱ toȱ realloc.ȱ Useȱ theȱ newȱ pointerȱ thatȱ isȱ returnedȱinstead.ȱ Finally,ȱ ifȱ theȱ firstȱ argumentȱ toȱ reallocȱ isȱ NULL,ȱ thenȱ itȱ behavesȱ exactlyȱ like malloc.ȱ Download at http://www.pin5i.com/ Chapter 11 Dynamic Memory Allocationȱ 306ȱ 11.4 Using Dynamically Allocated Memory ȱ Hereȱisȱanȱexampleȱthatȱobtainsȱaȱchunkȱofȱmemoryȱfromȱmalloc.ȱ ȱ int *pi; ... pi = malloc( 100 ); if( pi == NULL ){ printf( "Out of memory!\n" ); exit( 1 ); } TIP ȱ TheȱsymbolȱNULLȱisȱdefinedȱinȱ stdio.hȱasȱtheȱliteralȱconstantȱzero.ȱItȱactsȱasȱaȱvisualȱ reminderȱthatȱtheȱvalueȱbeingȱtestedȱisȱaȱpointerȱtypeȱratherȱthanȱanȱinteger.ȱ Ifȱthereȱwasȱmemoryȱavailable,ȱweȱwillȱnowȱhaveȱaȱpointerȱtoȱ100ȱbytes.ȱOnȱaȱ machineȱ withȱ 4Ȭbyteȱ integers,ȱ theȱ memoryȱ willȱ beȱ treatedȱ asȱ anȱ arrayȱ ofȱ 25ȱ integersȱ becauseȱpiȱisȱaȱpointerȱtoȱanȱinteger.ȱ ȱ Ifȱ yourȱ goalȱ isȱ toȱ getȱ enoughȱ memoryȱ forȱ 25ȱ integers,ȱ though,ȱ hereȱ isȱ aȱ muchȱ betterȱ techniqueȱforȱobtainingȱit.ȱ ȱ ȱ pi = malloc( 25 * sizeof( int ) ); ȱ Thisȱapproachȱisȱbetterȱbecauseȱitȱisȱportable.ȱItȱworksȱproperlyȱevenȱonȱmachinesȱwithȱ differentȱsizeȱintegers.ȱ Nowȱthatȱyouȱhaveȱaȱpointer,ȱhowȱdoȱyouȱuseȱtheȱmemory?ȱOfȱcourseȱyouȱcanȱ useȱindirectionȱandȱpointerȱarithmeticȱtoȱaccessȱdifferentȱintegerȱlocationsȱinȱthisȱarray,ȱ asȱinȱthisȱloop,ȱwhichȱsetsȱeachȱelementȱofȱtheȱnewlyȱallocatedȱarrayȱtoȱzero:ȱ ȱ int *pi2, i; ... pi2 = pi; for( i = 0; i < 25; i += 1 ) *pi2++ = 0; ȱ Asȱ youȱ haveȱ seen,ȱ youȱ canȱ useȱ aȱ subscriptȱ onȱ theȱ pointerȱ asȱ well.ȱ Thisȱ secondȱ loopȱ performsȱtheȱsameȱworkȱasȱtheȱpreviousȱone.ȱ ȱ int i; ... for( i = 0; i < 25; i += 1 ) pi[i] = 0; ȱ Download at http://www.pin5i.com/ 11.5 Common Dynamic Memory Errorsȱ 307 11.5 Common Dynamic Memory Errors CAUTION! CAUTION! ȱ Thereȱ areȱ manyȱ errorsȱ thatȱ canȱ occurȱ inȱ programsȱ thatȱ useȱ dynamicȱ memoryȱ allocation.ȱ Theseȱ includeȱ dereferencingȱ NULLȱ pointers,ȱ goingȱ outsideȱ dieȱ boundsȱ ofȱ theȱ memoryȱ thatȱ wasȱ allocated,ȱ freeingȱ memoryȱ blocksȱ thatȱ wereȱ notȱ dynamicallyȱ allocated,ȱ attemptingȱ toȱ freeȱ aȱ portionȱ ofȱ aȱ dynamicȱ block,ȱ andȱ continuingȱ toȱ useȱ dynamicȱmemoryȱafterȱitȱhasȱbeenȱfreed.ȱ ȱ Theȱ mostȱ commonȱ errorȱ withȱ dynamicȱ memoryȱ allocationȱ isȱ forgettingȱ toȱ checkȱ whetherȱtheȱrequestedȱmemoryȱwasȱallocated.ȱProgramȱ11.1ȱpresentsȱaȱtechniqueȱthatȱ makesȱ thisȱ errorȱ checkingȱ almostȱ foolproofȱ Theȱ MALLOCȱ macroȱ cakesȱ theȱ numberȱ ofȱ elementsȱ andȱ typeȱ ofȱ eachȱelement,ȱcomputesȱtheȱtotalȱnumberȱofȱbytesȱneeded,ȱandȱ callsȱ allocȱ toȱ obtainȱ theȱ memory. 42 ȱ allocȱ callsȱ mallocȱ andȱ thenȱ checksȱ toȱ makeȱ sureȱ thatȱtheȱpointerȱreturnedȱwasȱnotȱNULL.ȱ Theȱ finalȱ pieceȱ ofȱ thisȱ puzzleȱ isȱ theȱ veryȱ firstȱ #define.ȱ Itȱ preventsȱ accidentalȱ callsȱ directlyȱ toȱ mallocȱ byȱ substitutingȱ junkȱ intoȱ theȱ program.ȱ Ifȱ anȱ accidentalȱ callȱ isȱ made,ȱ theȱ programȱ willȱ notȱ compileȱ dueȱ toȱ syntaxȱ errors.ȱ Theȱ #undefȱ isȱ neededȱ inȱ allocȱsoȱthatȱitȱcanȱcallȱmallocȱwithoutȱerror.ȱ ȱ Theȱ secondȱ biggestȱ sourceȱ ofȱ errorȱ withȱ dynamicallyȱ allocatedȱ memoryȱ isȱ goingȱ outsideȱ ofȱ theȱ boundsȱ ofȱ theȱ memoryȱ thatȱ wasȱ allocated.ȱ Forȱ example,ȱ ifȱ youȱ haveȱ obtainedȱanȱarrayȱofȱ25ȱintegers,ȱaccessingȱelementsȱwithȱsubscriptsȱlessȱthanȱzeroȱorȱ greaterȱthanȱ24ȱcanȱcauseȱtwoȱtypesȱofȱproblems.ȱ Theȱ firstȱ problemȱ isȱ obvious;ȱ theȱ memoryȱ beingȱ accessedȱ mightȱ beȱ holdingȱ someȱ otherȱ variable.ȱ Changingȱ itȱ hereȱ willȱ destroyȱ theȱ variable,ȱ andȱ changingȱ theȱ variableȱwillȱdestroyȱanyȱvalueȱyouȱstoreȱhere.ȱTheseȱkindsȱofȱbugsȱareȱveryȱdifficultȱtoȱ trackȱdown.ȱ Theȱ secondȱ problemȱ isȱ notȱ soȱ obvious.ȱ Someȱ implementationsȱ ofȱ mallocȱ andȱ freeȱkeepȱtheȱpoolȱofȱavailableȱstorageȱasȱaȱlinkedȱlist.ȱȱModifyingȱlocationȱoutsideȱtheȱ ȱ ȱ ȱ ȱ /* ** Definitions for a less error-prone memory allocator. */ #include <stdlib.h> #define #define extern malloc DON'T CALL malloc DIRECTLY! MALLOC(num,type) (type *)alloc( (num) * sizeof(type) ) void *alloc( size_t size ); Programȱ11.1aȱȱErrorȱcheckingȱallocator:ȱinterfaceȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ 42 ȱ#defineȱmacrosȱareȱdescribedȱinȱdetailȱinȱChapterȱ14.ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱȱȱalloc.hȱ Download at http://www.pin5i.com/ 308ȱ Chapter 11 Dynamic Memory Allocationȱ ȱ /* ** Implementation for a less error-prone memory allocator. */ #include <stdio.h> #include "alloc.h" #undef malloc void * alloc( size_t size ) { void *new_mem; /* ** Ask for the requested memory, and check that we really ** got it. */ new_mem = malloc( size ); if( new_mem == NULL ){ printf( "Out of memory!\en" ); exit( 1 ); } return new_mem; } ȱ Programȱ11.1bȱȱErrorȱcheckingȱallocator:ȱimplementationȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱȱalloc.cȱ ȱ ȱȱȱȱa_client.cȱ /* ** A program that uses the less error-prone memory allocator. */ #include "alloc.h" void function() { int *new_memory; /* ** Get space for a bunch of integers */ new_memory = MALLOC( 25, int ); /* ... */ } ȱ Programȱ11.1cȱȱUsingȱtheȱerrorȱcheckingȱallocatorȱ ȱ ȱ ȱ Download at http://www.pin5i.com/ 11.5 Common Dynamic Memory Errorsȱ 309 boundsȱ ofȱ allocatedȱ memoryȱ canȱ corruptȱ thisȱ list,ȱ whichȱ canȱ causeȱ exceptionsȱ thatȱ terminateȱtheȱprogram.ȱ Whenȱaȱprogramȱthatȱusesȱdynamicallyȱallocatedȱmemoryȱfails,ȱitȱisȱtemptingȱtoȱ blameȱ theȱ problemsȱ onȱ mallocȱ andȱ free.ȱ Theyȱ areȱ rarelyȱ theȱ culprit,ȱ though.ȱ Inȱ practice,ȱ theȱ problemȱ isȱ nearlyȱ alwaysȱ inȱ yourȱ programȱ andȱ isȱ frequentlyȱ causedȱ byȱ accessingȱdataȱoutsideȱofȱtheȱallocatedȱmemory.ȱ CAUTION! Differentȱ errorsȱ canȱ occurȱ whenȱ usingȱ free.ȱ Theȱ pointerȱ passedȱ toȱ freeȱ mustȱ beȱ aȱ pointerȱthatȱwasȱobtainedȱfromȱmalloc,ȱcalloc,ȱorȱrealloc.ȱCallingȱfreeȱwithȱaȱpointerȱ toȱ memoryȱ thatȱ wasȱ notȱ dynamicallyȱ allocatedȱ canȱ causeȱ theȱ programȱ toȱ terminateȱ eitherȱrightȱawayȱorȱatȱsomeȱlaterȱtime.ȱSimilarȱproblemsȱcanȱbeȱcausedȱbyȱattemptingȱ toȱfreeȱonlyȱaȱportionȱofȱaȱdynamicallyȱallocatedȱblock,ȱlikeȱthis:ȱ ȱ /* ** Get 10 integers */ pi = malloc( 10 * sizeof( int ) ); ... /* ** Free only the last 5 integers; keep the first 5 */ free( pi + 5 ); ȱ Freeingȱaȱportionȱofȱaȱblockȱisȱnotȱallowed;ȱtheȱwholeȱblockȱmustȱbeȱfreed.ȱHowever,ȱ theȱ reallocȱ functionȱ canȱ makeȱ aȱ dynamicallyȱ allocatedȱ chunkȱ ofȱ memoryȱ smaller,ȱ effectivelyȱfreeingȱtheȱendȱofȱit.ȱ CAUTION! Finally,ȱyouȱmustȱbeȱcarefulȱnotȱtoȱaccessȱmemoryȱthatȱhasȱbeenȱ freeȇd.ȱThisȱwarningȱ mayȱ seemȱ obvious,ȱ butȱ thereȱ isȱ aȱ subtleȱ problemȱ hereȱ afterȱ all.ȱ Supposeȱ copiesȱ areȱ madeȱofȱtheȱpointerȱtoȱaȱdynamicallyȱallocatedȱblock,ȱandȱtheseȱcopiesȱareȱsentȱoffȱtoȱ manyȱ differentȱ partsȱ ofȱ theȱ program.ȱ Itȱ isȱ difficultȱ toȱ makeȱ sureȱ thatȱ noneȱ ofȱ theseȱ otherȱareasȱinȱtheȱprogramȱuseȱtheirȱcopiesȱofȱtheȱpointerȱafterȱtheȱmemoryȱhasȱbeenȱ freed.ȱConversely,ȱyouȱmustȱbeȱsureȱthatȱallȱpartsȱofȱtheȱprogramȱareȱfinishedȱusingȱaȱ chunkȱofȱmemoryȱbeforeȱfreeingȱit.ȱ ȱ ȱ ȱ 11.5.1 Memory Leaks ȱ Dynamicallyȱallocatedȱmemoryȱshouldȱbeȱfreedȱwhenȱitȱisȱnoȱlongerȱneededȱsoȱthatȱitȱ canȱ beȱ reusedȱ laterȱ forȱ otherȱ purposes.ȱ Allocatingȱ memoryȱ butȱ notȱ freeingȱ itȱ laterȱ causesȱ aȱ memoryȱ leak.ȱ Withȱ operatingȱ systemsȱ thatȱ shareȱ aȱ commonȱ poolȱ ofȱ memoryȱ amongȱallȱ executingȱprograms,ȱmemoryȱleaksȱdribbleȱawayȱtheȱavailableȱmemoryȱsoȱ thatȱeventuallyȱthereȱisnȇtȱanyȱleft.ȱRebootingȱtheȱcomputerȱisȱtheȱonlyȱrecoveryȱforȱthisȱ situation.ȱ Download at http://www.pin5i.com/ 310ȱ Chapter 11 Dynamic Memory Allocationȱ Otherȱoperatingȱsystemsȱ keepȱtrackȱ ofȱ whichȱpiecesȱofȱ memoryȱeachȱ programȱ currentlyȱ has,ȱ soȱ thatȱ whenȱ aȱ programȱ terminatesȱ allȱ ofȱ theȱ memoryȱ thatȱ itȱ hadȱ allocatedȱ butȱ hadȱ notȱ freedȱ isȱ returnedȱ toȱ theȱ pool.ȱ Memoryȱ leaksȱ areȱ aȱ seriousȱ problemȱevenȱonȱtheseȱsystems,ȱbecauseȱaȱprogramȱthatȱcontinuallyȱallocatesȱmemoryȱ withoutȱeverȱfreeingȱanyȱwillȱeventuallyȱexhaustȱtheȱavailableȱmemory.ȱAtȱthisȱpoint,ȱ theȱdefectiveȱprogramȱwillȱnotȱbeȱableȱtoȱcontinueȱexecuting,ȱandȱitsȱfailureȱmayȱresultȱ inȱtheȱlossȱofȱtheȱworkȱcompletedȱsoȱfar.ȱ ȱ ȱ ȱ 11.6 Memory Allocation Examples ȱ Aȱ commonȱ useȱ forȱ dynamicȱ memoryȱ allocationȱ isȱ obtainingȱ spaceȱ forȱ arraysȱ whoseȱ sizesȱ areȱ notȱ knownȱ untilȱ runȱ time.ȱ Programȱ 11.2ȱ readsȱ aȱ listȱ ofȱ integers,ȱ sortsȱ themȱ intoȱascendingȱsequence,ȱandȱprintsȱtheȱlist.ȱ ȱ ȱ ȱ ȱ /* ** Read, sort, and print a list of integer values. */ #include <stdlib.h> #include <stdio.h> /* ** Function called by 'qsort' to compare integer values */ int compare_integers( void const *a, void const *b ) { register int const *pa = a; register int const *pb = b; return *pa > *pb ? 1 : *pa < *pb ? -1 : 0; } int main() { int int int *array; n_values; i; /* ** See how many numbers there will be. ȱ Programȱ11.2ȱȱSortȱaȱlistȱofȱintegersȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ continued…ȱ Download at http://www.pin5i.com/ 11.6 Memory Allocation Examplesȱ ȱ ȱ 311 */ printf( "How many values are there? " ); if( scanf( "%d", &n_values ) != 1 || n_values <= 0 ){ printf( "Illegal number of values.\n" ); exit( EXIT_FAILURE ); } /* ** Get memory to store them. */ array = malloc( n_values * sizeof( int ) ); if( array == NULL ){ printf( "Can't get memory for that many values.\n" ); exit( EXIT_FAILURE ); } /* ** Read the numbers. */ for( i = 0; i < n_values; i += 1 ){ printf( "? " ); if( scanf( "%d", array + i ) != 1 ){ printf( "Error reading value #%d\n", i ); exit( EXIT_FAILURE ); } } /* ** Sort the values. */ qsort( array, n_values, sizeof( int ), compare_integers ); /* ** Print them out. */ for( i = 0; i < n_values; i += 1 ) printf( "%d\n", array[i] ); /* ** Free the memory and exit. */ free( array ); return EXIT_SUCCESS; } ȱ Programȱ11.2ȱȱSortȱaȱlistȱofȱintegersȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ sort.cȱ Download at http://www.pin5i.com/ 312ȱ Chapter 11 Dynamic Memory Allocationȱ Memoryȱtoȱholdȱtheȱlistȱisȱdynamicallyȱallocatedȱsoȱthatȱwhenȱyouȱareȱwritingȱ theȱ programȱ youȱ donȇtȱ haveȱ toȱ guessȱ howȱ manyȱ valuesȱ theȱ userȱ mightȱ wishȱ toȱ sort.ȱ Theȱonlyȱlimitȱonȱ theȱ numberȱofȱvaluesȱthatȱcanȱbeȱsortedȱisȱtheȱamountȱofȱ dynamicȱ memoryȱavailableȱtoȱtheȱprogram.ȱWhenȱsmallȱlistsȱareȱsorted,ȱthough,ȱonlyȱasȱmuchȱ memoryȱasȱisȱactuallyȱneededȱisȱallocated,ȱsoȱmemoryȱisȱnotȱwasted.ȱ Nowȱconsiderȱaȱprogramȱthatȱreadsȱstrings.ȱIfȱyouȱdonȇtȱknowȱtheȱlengthȱofȱtheȱ longestȱ stringȱ inȱ advanceȱ youȱ cannotȱ useȱ anȱ ordinaryȱ arrayȱ asȱ aȱ buffer.ȱ Instead,ȱ useȱ dynamicallyȱallocatedȱmemory.ȱWhenȱyouȱfindȱanȱinputȱlineȱthatȱdoesnȇtȱfit,ȱreallocateȱ aȱlargerȱbufferȱandȱreadȱtheȱremainderȱofȱtheȱlineȱintoȱit.ȱTheȱimplementationȱofȱthisȱ techniqueȱisȱleftȱasȱaȱprogrammingȱexercise.ȱ ȱ ȱ ȱ ȱ ȱ /* ** Make a copy of a string in dynamically allocated memory. Note: ** caller is responsible for checking whether the memory was ** allocated! This allows the caller to respond to an error in ** any way they wish. */ #include <stdlib.h> #include <string.h> char * strdup( char const *string ) { char *new_string; /* ** Ask for enough memory to hold the string and its ** terminating NUL byte. */ new_string = malloc( strlen( string ) + 1 ); /* ** If we got the memory, copy the string. */ if( new_string != NULL ) strcpy( new_string, string ); return new_string; } ȱ Programȱ11.3ȱȱDuplicateȱaȱstringȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱstrdup.cȱ Download at http://www.pin5i.com/ 11.6 Memory Allocation Examplesȱ 313 Theȱinputȱisȱreadȱintoȱthisȱbuffer,ȱoneȱlineȱatȱaȱtime.ȱTheȱlengthȱofȱtheȱstringȱisȱ determined,ȱandȱthenȱmemoryȱisȱallocatedȱtoȱholdȱit.ȱFinally,ȱtheȱstringȱisȱcopiedȱintoȱ theȱnewȱmemoryȱsoȱtheȱbufferȱcanȱbeȱusedȱtoȱreadȱtheȱnextȱline.ȱ TheȱfunctionȱinȱProgramȱ11.3,ȱcalledȱstrdup,ȱreturnsȱaȱcopyȱofȱitsȱinputȱstringȱinȱ dynamicallyȱ allocatedȱ memory.ȱ Theȱ functionȱ firstȱ triesȱ toȱ obtainȱ enoughȱ memoryȱ toȱ holdȱtheȱcopy.ȱTheȱadditionalȱbyteȱbeyondȱtheȱstringȱlengthȱisȱneededȱtoȱholdȱtheȱNULȱ byteȱthatȱterminatesȱtheȱstring.ȱȱIfȱtheȱmemoryȱwasȱsuccessfullyȱallocated,ȱtheȱstringȱisȱ copiedȱ intoȱ theȱ newȱ memory.ȱ Finally,ȱ aȱ pointerȱ toȱ theȱ newȱ memoryȱ isȱ returned.ȱȱ Noticeȱ thatȱ new_stringȱ willȱ beȱ NULLȱ ifȱ theȱ allocationȱ failedȱ forȱ someȱ reason,ȱ soȱ aȱ NULLȱpointerȱwouldȱbeȱreturnedȱinȱthisȱcase.ȱ Thisȱ functionȱ isȱ veryȱ handy.ȱ Itȱ isȱ soȱ useful,ȱ inȱ fact,ȱ thatȱ manyȱ environmentsȱ includeȱitȱasȱpartȱofȱtheȱlibraryȱevenȱthoughȱtheȱStandardȱdoesȱnotȱmentionȱit.ȱ Ourȱ finalȱ exampleȱ illustratesȱ howȱ youȱ canȱ useȱ dynamicȱ memoryȱ allocationȱ toȱ eliminateȱwastedȱmemoryȱwithȱvariantȱrecords.ȱProgramȱ11.4ȱisȱaȱmodificationȱofȱtheȱ inventoryȱ systemȱ exampleȱ fromȱ Chapterȱ 10.ȱ Programȱ 11.4aȱ containsȱ theȱ declarationsȱ forȱtheȱinventoryȱrecords.ȱ Asȱ before,ȱ theȱ inventoryȱ systemȱ mustȱ handleȱ twoȱ typesȱ ofȱ records,ȱ thoseȱ forȱ partsȱandȱthoseȱforȱsubassemblies.ȱTheȱfirstȱstructureȱholdsȱtheȱinformationȱspecificȱtoȱ aȱ partȱ (onlyȱ aȱ portionȱ ofȱ thisȱ structureȱ isȱ shown),ȱ andȱ theȱ secondȱ holdsȱ informationȱ aboutȱsubassemblies.ȱTheȱlastȱdeclarationȱisȱforȱtheȱinventoryȱrecord.ȱItȱcontainsȱsomeȱ commonȱdataȱneededȱforȱbothȱsubassembliesȱandȱpartsȱandȱaȱvariantȱportion.ȱ Becauseȱ theȱ differentȱ fieldsȱ inȱ theȱ variantȱ partȱ areȱ differentȱ sizesȱ (inȱ fact,ȱ theȱ subassemblyȱ recordȱ isȱ variableȱ size),ȱ theȱ unionȱ containsȱ pointersȱ toȱ structuresȱ ratherȱ thanȱ theȱ structures.ȱ Dynamicȱ allocationȱ letsȱ theȱ programȱ createȱ anȱ inventoryȱ recordȱ thatȱisȱtheȱcorrectȱsizeȱforȱtheȱitemȱbeingȱstored,ȱsoȱthereȱisȱnoȱwastedȱmemory.ȱ Programȱ11.4bȱisȱaȱfunctionȱthatȱcreatesȱanȱinventoryȱrecordȱforȱaȱsubassembly.ȱ Thisȱtaskȱdependsȱonȱtheȱnumberȱofȱdifferentȱpartsȱtheȱsubassemblyȱcontains,ȱsoȱthisȱ valueȱisȱpassedȱasȱanȱargument.ȱ Thisȱ functionȱ allocatesȱ threeȱ things:ȱ theȱ inventoryȱ record,ȱ theȱ subassemblyȱ structure,ȱ andȱ theȱ arrayȱ ofȱ partsȱ inȱ theȱ subassemblyȱ structure.ȱ Ifȱ anyȱ ofȱ theseȱ allocationsȱfails,ȱanyȱmemoryȱthatȱwasȱalreadyȱobtainedȱisȱfreedȱandȱaȱNULLȱpointerȱisȱ returned.ȱOtherwise,ȱtheȱ typeȱandȱ info.subassy->n_partsȱfieldsȱareȱinitializedȱandȱaȱ pointerȱtoȱtheȱrecordȱisȱreturned.ȱ Obtainingȱmemoryȱforȱanȱinventoryȱrecordȱtoȱstoreȱaȱpartȱisȱaȱlittleȱeasierȱthanȱ forȱaȱsubassemblyȱbecauseȱonlyȱtwoȱallocationsȱareȱneeded.ȱThisȱfunctionȱisȱthereforeȱ notȱillustratedȱhere.ȱ Download at http://www.pin5i.com/ 314ȱ Chapter 11 Dynamic Memory Allocationȱ ȱ /* ** Declarations for the inventory record. ** ** Structure that contains information about a part. */ typedef struct { int cost; int supplier; /* etc. */ } Partinfo; /* ** Structure to hold information about a subassembly. */ typedef struct { int n_parts; struct SUBASSYPART { char partno[10]; short quan; } *part; } Subassyinfo; /* ** Structure for an inventory record, which is a variant record. */ typedef struct { char partno[10]; int quan; enum { PART, SUBASSY } type; union { Partinfo *part; Subassyinfo *subassy; } info; } Invrec; ȱ Programȱ11.4aȱȱInventoryȱsystemȱdeclarationsȱ ȱ ȱ ȱ ȱ ȱ ȱȱinventor.hȱ Download at http://www.pin5i.com/ 11.6 Memory Allocation Examplesȱ 315 ȱ /* ** Function to create a SUBASSEMBLY inventory record. */ #include <stdlib.h> #include <stdio.h> #include "inventor.h" Invrec * create_subassy_record( int n_parts ) { Invrec *new_rec; /* ** Try to get memory for the Invrec portion. */ new_rec = malloc( sizeof( Invrec ) ); if( new_rec != NULL ){ /* ** That worked; now get the SUBASSYINFO portion. */ new_rec->info.subassy = malloc( sizeof( Subassyinfo ) ); if( new_rec->info.subassy != NULL ){ /* ** Get an array big enough for the parts. */ new_rec->info.subassy->part = malloc( n_parts * sizeof( struct SUBASSYPART ) ); if( new_rec->info.subassy->part != NULL ){ /* ** Got the memory; fill in the fields ** whose values we know and return. */ new_rec->type = SUBASSY; new_rec->info.subassy->n_parts = n_parts; return new_rec; } /* ** Out of memory: free what we've got so far. */ free( new_rec->info.subassy ); } free( new_rec ); } return NULL; } ȱ Programȱ11.4bȱȱDynamicȱcreationȱofȱaȱvariantȱrecordȱ ȱ ȱ ȱ ȱ ȱȱȱȱinvcreat.cȱ Download at http://www.pin5i.com/ 316ȱ Chapter 11 Dynamic Memory Allocationȱ Programȱ 11.4cȱ containsȱ theȱ lastȱ partȱ ofȱ thisȱ example:ȱ aȱ functionȱ thatȱ destroysȱ inventoryȱ records.ȱ Thisȱ functionȱ worksȱ forȱ eitherȱ typeȱ ofȱ inventoryȱ record.ȱ Itȱ usesȱ aȱ switchȱ statementȱ toȱ determineȱ theȱ typeȱ ofȱ recordȱ itȱ wasȱ givenȱ andȱ thenȱ freesȱ allȱ dynamicallyȱallocatedȱfieldsȱinȱtheȱrecord.ȱFinally,ȱtheȱrecordȱisȱdeleted.ȱ Aȱcommonȱmistakeȱmadeȱinȱsituationsȱlikeȱthisȱoneȱisȱtoȱfreeȱtheȱrecordȱbeforeȱ freeingȱtheȱmemoryȱpointedȱtoȱbyȱfieldsȱinȱtheȱrecord.ȱAfterȱtheȱrecordȱhasȱbeenȱfreed,ȱ youȱmayȱnoȱlongerȱsafelyȱaccessȱanyȱofȱtheȱfieldsȱthatȱitȱcontains.ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Function to discard an inventory record. */ #include <stdlib.h> #include "inventor.h" void discard_inventory_record( Invrec *record ) { /* ** Delete the variant parts of the record */ switch( record->type ){ case SUBASSY: free( record->info.subassy->part ); free( record->info.subassy ); break; case PART: free( record->info.part ); break; } /* ** Delete the main part of the record */ free( record ); } ȱ Programȱ11.4cȱȱDestructionȱofȱaȱvariantȱrecordȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱinvdelet.cȱ Download at http://www.pin5i.com/ 11.7 Summaryȱ 317 Althoughȱ itȱ isȱ aȱ littleȱ lessȱ obvious,ȱ theȱ followingȱ codeȱ fragmentȱ isȱ aȱ slightlyȱ moreȱefficientȱimplementationȱofȱProgramȱ11.4c.ȱ ȱ if( record->typ == SUBASSY ) free( record->info.subassy->part ); free( record->info.part ); free( record ); ȱ Thisȱ codeȱ doesȱ notȱ distinguishȱ betweenȱ subassembliesȱ andȱ partsȱ whenȱ freeingȱ theȱ variantȱ partȱ ofȱ theȱ record.ȱ Eitherȱ memberȱ ofȱ theȱ unionȱ canȱ beȱ used,ȱ asȱ freeȱ doesȱ notȱ careȱwhichȱtypeȱofȱpointerȱitȱgets.ȱ ȱ ȱ ȱ 11.7 Summary ȱ Whenȱanȱarrayȱisȱdeclared,ȱitsȱsizeȱmustȱbeȱknownȱatȱcompileȱtime.ȱDynamicȱallocationȱ allowsȱaȱprogramȱtoȱcreateȱspaceȱforȱanȱarrayȱwhoseȱsizeȱisnȇtȱknownȱuntilȱruntime.ȱ Theȱ mallocȱandȱ callocȱfunctionsȱbothȱallocateȱmemoryȱandȱreturnȱaȱpointerȱtoȱ it.ȱ Theȱ argumentȱ toȱ mallocȱ isȱ theȱ numberȱ ofȱ bytesȱ ofȱ memoryȱ needed.ȱ Inȱ contrast,ȱ callocȱrequiresȱtheȱnumberȱofȱelementsȱyouȱwantȱandȱtheȱsizeȱofȱeachȱelement.ȱcallocȱ initializesȱ theȱ memoryȱ toȱ zeroȱ beforeȱ returning,ȱ whereasȱ mallocȱ leavesȱ theȱ memoryȱ uninitialized.ȱTheȱ reallocȱfunctionȱisȱcalledȱtoȱchangeȱtheȱsizeȱofȱanȱexistingȱblockȱofȱ dynamicallyȱallocatedȱmemory.ȱIncreasesȱinȱsizeȱmayȱbeȱaccomplishedȱbyȱcopyingȱtheȱ dataȱ fromȱ theȱ existingȱ blockȱ toȱ aȱ new,ȱ largerȱ block.ȱ Whenȱ aȱ dynamicallyȱ allocatedȱ blockȱisȱnoȱlongerȱneeded,ȱfreeȱisȱcalledȱtoȱreturnȱitȱtoȱtheȱpoolȱofȱavailableȱmemory.ȱ Memoryȱmustȱnotȱbeȱaccessedȱafterȱitȱhasȱbeenȱfreed.ȱ Theȱ pointerȱ returnedȱ byȱ malloc,ȱ calloc,ȱ andȱ reallocȱ willȱ beȱ NULLȱ ifȱ theȱ requestedȱ allocationȱ couldȱ notȱ beȱ performed.ȱ Erroneouslyȱ accessingȱ memoryȱ outsideȱ ofȱ anȱ allocatedȱ blockȱ mayȱ causeȱ theȱ sameȱ errorsȱ asȱ accessingȱ memoryȱ outsideȱ ofȱ anȱ array,ȱbutȱcanȱalsoȱcorruptȱtheȱpoolȱofȱavailableȱmemoryȱandȱleadȱtoȱaȱprogramȱfailure.ȱ Youȱmayȱnotȱpassȱaȱpointerȱtoȱfreeȱthatȱwasȱnotȱobtainedȱfromȱanȱearlierȱcallȱtoȱmalloc,ȱ calloc,ȱorȱrealloc.ȱNorȱmayȱyouȱfreeȱaȱportionȱofȱaȱblock.ȱ Aȱ memoryȱ leakȱ isȱ memoryȱ thatȱ hasȱ beenȱ dynamicallyȱ allocatedȱ butȱ hasȱ notȱ beenȱ freedȱ andȱ isȱ noȱ longerȱ inȱ use.ȱ ȱ Memoryȱ leaksȱ increaseȱ theȱ sizeȱ ofȱ theȱ program,ȱ andȱmayȱleadȱtoȱaȱcrashȱofȱtheȱprogramȱorȱtheȱsystem.ȱ Download at http://www.pin5i.com/ 318ȱ Chapter 11 Dynamic Memory Allocationȱ 11.8 Summary of Cautions ȱ 1. NotȱcheckingȱtheȱpointerȱreturnedȱfromȱmallocȱforȱNULLȱ(pageȱ307).ȱ 2. Accessingȱoutsideȱtheȱboundsȱofȱdynamicallyȱallocatedȱmemoryȱ(pageȱ307).ȱ 3. Passingȱaȱpointerȱtoȱfreeȱthatȱdidȱnotȱoriginallyȱcomeȱfromȱmallocȱ(pageȱ309).ȱ 4. Accessingȱdynamicȱmemoryȱafterȱitȱhasȱbeenȱfreedȱ(pageȱ309).ȱ ȱ ȱ ȱ 11.9 Summary of Programming Tips ȱ 1. DynamicȱallocationȱhelpsȱeliminateȱbuiltȬinȱlimitationsȱinȱtheȱprogramȱ(pageȱ303).ȱ 2. Usingȱsizeofȱtoȱcomputeȱtheȱsizeȱofȱdataȱtypesȱenhancesȱportabilityȱ(pageȱ306).ȱ ȱ ȱ ȱ 11.10 Questions ȱ 1. Whatȱ isȱ theȱ largestȱ staticȱ arrayȱ thatȱ youȱ canȱ declareȱ onȱ yourȱ system?ȱ Theȱ largestȱ dynamicallyȱallocatedȱpieceȱofȱmemory?ȱ 2. Whatȱ isȱ theȱ totalȱ amountȱ ofȱ memoryȱ thatȱ youȱ canȱ dynamicallyȱ allocateȱ onȱ yourȱ systemȱwhenȱyouȱaskȱforȱitȱ500ȱbytesȱatȱaȱtime?ȱWhenȱyouȱaskȱforȱitȱ5000ȱbytesȱatȱaȱ time?ȱIsȱthereȱaȱdifference?ȱIfȱso,ȱhowȱdoȱyouȱexplainȱit?ȱ 3. Inȱaȱprogramȱthatȱreadsȱstringsȱfromȱaȱfile,ȱisȱthereȱanyȱvalueȱthatȱcanȱlogicallyȱbeȱ usedȱforȱtheȱsizeȱofȱtheȱinputȱbuffer?ȱ 4. Someȱ Cȱ implementationsȱ provideȱ aȱ functionȱ calledȱ alloca,ȱ whichȱ differsȱ fromȱ mallocȱ inȱ thatȱ itȱ allocatesȱ memoryȱ onȱ theȱ stack.ȱ Whatȱ areȱ theȱ advantagesȱ andȱ disadvantagesȱofȱthisȱtypeȱofȱallocation?ȱ 5. Theȱ followingȱ program,ȱ whichȱ isȱ supposedȱ toȱ readȱ integersȱ inȱ theȱ rangeȱ oneȱ throughȱ sizeȱfromȱtheȱstandardȱinputȱandȱreturnȱcountsȱofȱhowȱmanyȱtimesȱeachȱ valueȱoccurs,ȱcontainsȱseveralȱerrors.ȱȱWhatȱareȱthey?ȱ ȱ #include <stdlib.h> int * frequency( int size ) { int *array; int i; Download at http://www.pin5i.com/ 11.11 Programming Exercisesȱ 319 /* ** Get enough memory to hold the counts. */ array = (int *)malloc( size * 2 ); /* ** Adjust the pointer back one integer so we ** can use subscripts in the range 1 – size. */ array -= 1; /* ** Clear the values to zero */ for( i = 0; i <= size; i += 1 ) array[i] = 0; /* ** Count how many times each value appears, ** then return the answers. */ while( scanf( "%d", &i ) == 1 ) array[ i ] += 1; free( array ); return array; } 6. Supposeȱ youȱ areȱ writingȱ aȱ programȱ andȱ wishȱ toȱ minimizeȱ theȱ amountȱ ofȱ stackȱ spaceȱitȱuses.ȱȱWillȱallocatingȱarraysȱdynamicallyȱhelp?ȱHowȱaboutȱscalars?ȱ 7. WhatȱwouldȱbeȱtheȱeffectȱofȱdeletingȱtheȱtwoȱcallsȱtoȱfreeȱinȱProgramȱ11.4b?ȱ ȱ ȱ ȱ 11.11 Programming Exercises ȱ 1. Writeȱyourȱownȱversionȱofȱtheȱcallocȱfunction,ȱusingȱmallocȱtoȱobtainȱmemory.ȱ 2. Writeȱ aȱ functionȱ thatȱ readsȱ aȱ listȱ ofȱ integersȱ fromȱ theȱ standardȱ inputȱ andȱ returnsȱ theȱvaluesȱinȱaȱdynamicallyȱallocatedȱarray.ȱTheȱendȱofȱtheȱinputȱlistȱisȱdeterminedȱ byȱwatchingȱforȱ EOF.ȱTheȱfirstȱnumberȱinȱtheȱarrayȱshouldȱbeȱaȱcountȱofȱhowȱmanyȱ valuesȱtheȱarrayȱcontains.ȱThisȱnumberȱisȱfollowedȱbyȱtheȱvalues.ȱ Download at http://www.pin5i.com/ Chapter 11 Dynamic Memory Allocationȱ 320ȱ 3. Writeȱaȱfunctionȱthatȱreadsȱaȱstringȱfromȱtheȱstandardȱinputȱandȱreturnsȱaȱcopyȱofȱ theȱ stringȱ inȱ dynamicallyȱ allocatedȱ memory.ȱ Theȱ functionȱ mayȱ notȱ imposeȱ anyȱ limitȱonȱtheȱsizeȱofȱtheȱstringȱbeingȱread!ȱ 4. Writeȱ aȱ programȱ toȱ createȱ theȱ dataȱ structureȱ inȱ theȱ followingȱ diagram.ȱ Theȱ lastȱ threeȱobjectsȱareȱstructuresȱwhichȱareȱdynamicallyȱallocated.ȱTheȱfirstȱobject,ȱwhichȱ mayȱ beȱ static,ȱ isȱ aȱ pointerȱ toȱ aȱ structure.ȱ Youȱ doȱ notȱ needȱ toȱ makeȱ thisȱ programȱ general—weȱwillȱdiscussȱthisȱdataȱstructureȱinȱtheȱnextȱchapter.ȱ ȱ headȱ ȱ 5ȱ ȱ 10ȱ ȱ 15ȱ ȱ ȱ ȱ ȱ ȱ ȱ 0ȱ ȱ Download at http://www.pin5i.com/ 12 Using Structures and Pointers Youȱcanȱcreateȱpowerfulȱdataȱstructuresȱbyȱcombiningȱstructuresȱandȱpointers.ȱInȱthisȱ chapterȱ weȱ takeȱ aȱ closerȱ lookȱ atȱ someȱ techniquesȱ forȱ usingȱ structuresȱ andȱ pointers.ȱȱ Weȱspendȱaȱlotȱofȱtimeȱwithȱaȱdataȱstructureȱcalledȱaȱlinkedȱlist,ȱnotȱonlyȱbecauseȱitȱisȱ veryȱ usefulȱ butȱ alsoȱ becauseȱ manyȱ ofȱ theȱ techniquesȱ usedȱ toȱ manipulateȱ linkedȱ listsȱ areȱapplicableȱtoȱotherȱdataȱstructures.ȱ ȱ ȱ ȱ 12.1 Linked Lists ȱ Forȱthoseȱofȱyouȱwhoȱareȱnotȱfamiliarȱwithȱlinkedȱlists,ȱhereȱisȱaȱbriefȱintroduction.ȱAȱ linkedȱlistȱisȱaȱcollectionȱofȱindependentȱstructuresȱ(oftenȱcalledȱnodes)ȱthatȱcontainȱdata.ȱ Theȱ individualȱ nodesȱ inȱ theȱ listȱ areȱ connectedȱ byȱ links,ȱ orȱ pointers.ȱ Aȱ programȱ accessesȱ theȱ nodesȱ inȱ theȱ listȱ byȱ followingȱ theȱ pointers.ȱ Usuallyȱ theȱ nodesȱ areȱ dynamicallyȱ allocated,ȱ thoughȱ occasionallyȱ youȱ willȱ findȱ linkedȱ listsȱ constructedȱ amongȱelementsȱofȱanȱarrayȱofȱnodes.ȱEvenȱinȱthisȱcase,ȱthough,ȱaȱprogramȱtraversesȱ theȱlistȱbyȱfollowingȱtheȱpointers.ȱ ȱ ȱ ȱ 12.2 Singly Linked Lists ȱ Inȱ aȱ singlyȱ linkedȱ list,ȱ eachȱ nodeȱ containsȱ aȱ pointerȱ toȱ theȱ nextȱ nodeȱ inȱ theȱ list.ȱ Theȱ pointerȱ fieldȱ ofȱ theȱ lastȱ nodeȱ inȱ theȱ listȱ containsȱ NULLȱ toȱ indicateȱ thatȱ thereȱ areȱ noȱ moreȱnodesȱinȱtheȱlist.ȱAfterȱyouȱhaveȱfoundȱtheȱfirstȱnodeȱonȱaȱlist,ȱtheȱpointersȱwillȱ leadȱyouȱtoȱtheȱremainingȱnodes.ȱToȱkeepȱtrackȱofȱwhereȱtheȱlistȱbegins,ȱaȱrootȱpointerȱ isȱ used.ȱ Theȱ rootȱ pointerȱ pointsȱ toȱ theȱ firstȱ nodeȱ onȱ theȱ list.ȱ Noticeȱ thatȱ theȱ rootȱ isȱ aȱ pointerȱandȱitȱdoesȱnotȱcontainȱanyȱdata.ȱȱ Hereȱisȱaȱdiagramȱofȱaȱsinglyȱlinkedȱlist.ȱ Download at http://www.pin5i.com/ Chapter 12 Using Structures and Pointersȱ 322ȱ rootȱ link link link 0 value value value 5 10 15 ȱ Theȱnodesȱinȱthisȱexampleȱareȱstructuresȱcreatedȱwithȱtheȱfollowingȱdeclaration.ȱ typedef struct struct int NODE NODE { *link; value; } Node; Theȱdataȱstoredȱinȱeachȱnodeȱisȱanȱinteger.ȱThisȱlistȱcontainsȱthreeȱnodes.ȱIfȱyouȱbeginȱ atȱtheȱrootȱandȱfollowȱtheȱpointerȱtoȱtheȱfirstȱnode,ȱyouȱcanȱaccessȱtheȱdataȱstoredȱinȱ thatȱnode.ȱFollowingȱtheȱpointerȱinȱtheȱfirstȱnodeȱtakesȱyouȱtoȱtheȱsecondȱnode,ȱwhereȱ youȱ canȱ getȱ itsȱ data.ȱ Finally,ȱ theȱ nextȱ pointerȱ bringsȱ youȱ toȱ theȱ lastȱ node.ȱ Theȱ valueȱ zeroȱisȱusedȱtoȱindicateȱaȱNULLȱpointer;ȱhereȱitȱmeansȱthatȱthereȱareȱnoȱmoreȱnodesȱinȱ theȱlist.ȱ Inȱtheȱdiagramȱtheȱnodesȱareȱshownȱasȱadjacentȱtoȱdisplayȱtheȱlogicalȱorderingȱ thatȱ theȱ linksȱ provide.ȱ Inȱ fact,ȱ theȱ nodesȱ mightȱ actuallyȱ beȱ scatteredȱ allȱ throughȱ memory.ȱItȱ doesnȇtȱ makeȱ anyȱdifferenceȱtoȱaȱprogramȱprocessingȱsuchȱaȱlistȱwhetherȱ theȱnodesȱareȱphysicallyȱadjacentȱorȱnot,ȱbecauseȱtheȱprogramȱalwaysȱusesȱtheȱlinksȱtoȱ getȱfromȱoneȱnodeȱtoȱtheȱnext.ȱ Aȱ singlyȱ linkedȱ listȱ canȱ beȱ traversedȱ fromȱ startȱ toȱ endȱ byȱ followingȱ theȱ links,ȱ butȱ theȱ listȱ cannotȱ beȱ traversedȱ backwards.ȱ Inȱ otherȱ words,ȱ onceȱ yourȱ programȱ hasȱ reachedȱtheȱlastȱnodeȱinȱtheȱlist,ȱtheȱonlyȱwayȱtoȱgetȱbackȱtoȱanyȱearlierȱnodeȱisȱtoȱstartȱ againȱfromȱtheȱrootȱpointer.ȱOfȱcourse,ȱtheȱprogramȱcouldȱsaveȱaȱpointerȱtoȱtheȱcurrentȱ nodeȱbeforeȱadvancingȱtoȱtheȱnextȱone,ȱorȱitȱcouldȱevenȱsaveȱpointersȱtoȱtheȱprecedingȱ fewȇȱnodes.ȱHowever,ȱtheseȱlinkedȱlistsȱareȱdynamicȱandȱcanȱgrowȱtoȱholdȱhundredsȱ orȱ thousandsȱ ofȱ nodes,ȱ soȱ itȱ isȱ notȱ feasibleȱ toȱ saveȱ pointersȱ toȱ allȱ ofȱ theȱ precedingȱ nodesȱinȱaȱlist.ȱ Theȱ nodesȱ inȱ thisȱ particularȱ listȱ areȱ linkedȱ soȱ thatȱ theȱ dataȱ valuesȱ areȱ inȱ ascendingȱorder.ȱThisȱorderingȱisȱimportantȱforȱsomeȱapplications,ȱsuchȱasȱorganizingȱ appointmentsȱ byȱ timeȱ ofȱ day.ȱ Itȱ isȱ alsoȱ possibleȱ toȱ createȱ anȱ unorderedȱ listȱ forȱ applicationsȱthatȱdoȱnotȱrequireȱanyȱordering.ȱ ȱ ȱ ȱ 12.2.1 Inserting into a Singly Linked List ȱ Howȱwouldȱweȱinsertȱaȱnewȱnodeȱintoȱanȱorderedȱsinglyȱlinkedȱlist?ȱSupposeȱweȱhadȱ aȱnewȱvalue,ȱsayȱ12,ȱtoȱinsertȱintoȱtheȱpreviousȱlist.ȱConceptuallyȱthisȱtaskȱisȱeasy:ȱstartȱ Download at http://www.pin5i.com/ 12.2 Singly Linked Lists 323 atȱ theȱ beginningȱ ofȱ theȱ list,ȱ followȱ theȱ pointersȱ untilȱ youȱ findȱ theȱ firstȱ nodeȱ whoseȱ valueȱisȱlargerȱthanȱ12,ȱandȱthenȱinsertȱtheȱnewȱvalueȱintoȱtheȱlistȱjustȱbeforeȱthatȱnode.ȱ Inȱpracticeȱtheȱalgorithmȱisȱmoreȱinteresting.ȱWeȱtraverseȱtheȱlistȱandȱstopȱwhenȱ weȱreachȱtheȱnodeȱcontainingȱ15,ȱtheȱfirstȱvalueȱgreaterȱthanȱ12.ȱWeȱknowȱthatȱtheȱnewȱ valueȱ shouldȱ beȱ addedȱ toȱ theȱ listȱ justȱ beforeȱ thisȱ node,ȱ butȱ theȱ pointerȱ fieldȱ ofȱ theȱ previousȱ nodeȱ mustȱ beȱ modifiedȱ toȱ accomplishȱ theȱ insertion.ȱ However,ȱ weȇveȱ passedȱ thisȱ node,ȱ andȱ weȱ cannotȱ goȱ back.ȱ Theȱ solutionȱ isȱ toȱ alwaysȱ saveȱ aȱ pointerȱ toȱ theȱ previousȱnodeȱinȱtheȱlist.ȱ Weȱwillȱnowȱdevelopȱaȱfunctionȱtoȱinsertȱaȱnodeȱintoȱanȱordered,ȱsinglyȱlinkedȱ list.ȱProgramȱ12.1ȱisȱourȱfirstȱattempt.ȱ ȱ ȱ ȱ ȱ ȱ /* ** Insert into an ordered, singly linked list. The arguments are ** a pointer to the first node in the list, and the value to ** insert. */ #include <stdlib.h> #include <stdio.h> #include "sll_node.h" #define #define FALSE 0 TRUE 1 int sll_insert( Node *current, int new_value ) { Node *previous; Node *new; /* ** Look for the right place by walking down the list ** until we reach a node whose value is greater than ** or equal to the new value. */ while( current->value < new_value ){ previous = current; current = current->link; } ȱ Programȱ12.1ȱȱInsertȱintoȱanȱordered,ȱsinglyȱlinkedȱlist:ȱfirstȱtryȱ ȱ ȱ continued…ȱ Download at http://www.pin5i.com/ Chapter 12 Using Structures and Pointersȱ 324ȱ ȱ /* ** Allocate a new node and store the new value into it. ** In this event, we return FALSE. */ new = (Node *)malloc( sizeof( Node ) ); if( new == NULL ) return FALSE; new->value = new_value; /* ** Insert the new node into the list, and return TRUE. */ new->link = current; previous->link = new; return TRUE; } ȱ Programȱ12.1ȱȱInsertȱintoȱanȱordered,ȱsinglyȱlinkedȱlist:ȱfirstȱtryȱ ȱ ȱ ȱȱȱȱȱȱinsert1.cȱ ȱ Weȱcallȱtheȱfunctionȱinȱthisȱmanner:ȱ ȱ result = sll_insert( root, 12 ); ȱ ȱ Letȇsȱ traceȱthisȱcodeȱandȱseeȱwhetherȱitȱ correctlyȱinsertsȱtheȱ newȱvalueȱ 12ȱ intoȱ theȱlist.ȱFirst,ȱtheȱfunctionȱisȱcalledȱwithȱtheȱvalueȱofȱtheȱrootȱvariable,ȱaȱpointerȱtoȱtheȱ firstȱnodeȱinȱtheȱlist.ȱHereȱisȱtheȱstateȱofȱtheȱlistȱwhenȱtheȱfunctionȱbegins:ȱ ȱ previousȱ current ?ȱ link link link 0 value value value 5 10 15 ȱ ȱ Thisȱdiagramȱdoesȱnotȱshowȱtheȱ rootȱvariableȱbecauseȱtheȱfunctionȱcannotȱaccessȱit.ȱAȱ copyȱ ofȱ itsȱ valueȱ cameȱ intoȱ theȱ functionȱ asȱ theȱ parameterȱ current,ȱ butȱ theȱ functionȱ cannotȱaccessȱ root.ȱNowȱ current->valueȱisȱ5,ȱwhichȱisȱlessȱthanȱ12,ȱsoȱtheȱbodyȱofȱtheȱ loopȱisȱexecutedȱonce.ȱWhenȱweȱgetȱbackȱtoȱtheȱtopȱofȱtheȱloop,ȱourȱpointersȱwillȱhaveȱ advanced.ȱ Download at http://www.pin5i.com/ 12.2 Singly Linked Lists previousȱ link 325 current link link 0 valueȱ value valueȱ 5ȱ 10 15 ȱ current->valueȱisȱnowȱ10,ȱsoȱtheȱbodyȱofȱtheȱloopȱexecutesȱagain,ȱwithȱthisȱresult:ȱ previous link link currentȱ link 0 valueȱ value valueȱ 5ȱ 10 15 ȱ Nowȱcurrent->valueȱisȱgreaterȱthanȱ12ȱsoȱtheȱloopȱbreaks.ȱ Atȱthisȱpointȱtheȱ previousȱpointerȱisȱtheȱimportantȱone,ȱbecauseȱitȱpointsȱtoȱtheȱ nodeȱ thatȱ mustȱ beȱ changedȱ toȱ insertȱ theȱ newȱ value.ȱ Butȱ first,ȱ aȱ newȱ nodeȱ mustȱ beȱ obtainedȱtoȱholdȱtheȱvalue.ȱTheȱnextȱdiagramȱshowsȱtheȱstateȱofȱtheȱlistȱafterȱtheȱvalueȱ isȱcopiedȱintoȱtheȱnewȱnode.ȱ previous link link currentȱ new link link 0 ? valueȱ value valueȱ value 5ȱ 10 15 12 ȱ Download at http://www.pin5i.com/ 326ȱ Chapter 12 Using Structures and Pointersȱ Linkingȱtheȱnewȱnodeȱintoȱtheȱlistȱrequiresȱtwoȱsteps.ȱFirst,ȱ ȱ new->link = current; ȱ makesȱ theȱ newȱ nodeȱ pointȱ toȱ whatȱ willȱ beȱ theȱ nextȱ nodeȱ inȱ theȱ list,ȱ theȱ firstȱ oneȱ weȱ foundȱwithȱaȱvalueȱlargerȱthanȱ12.ȱAfterȱthisȱstep,ȱtheȱlistȱlooksȱlikeȱthis:ȱ ȱ previous currentȱ new link link link link 0 valueȱ value valueȱ value 5ȱ 10 15 12 ȱ ȱ Theȱsecondȱstepȱisȱtoȱmakeȱtheȱ previousȱnode,ȱtheȱlastȱoneȱwhoseȱvalueȱwasȱsmallerȱ thanȱ12,ȱpointȱtoȱtheȱnewȱnode.ȱTheȱfollowingȱstatementȱperformsȱthisȱtask.ȱ ȱ previous->link = new; ȱ ȱ Theȱresultȱofȱthisȱstepȱis:ȱ ȱ previous link link currentȱ link new link 0 valueȱ value valueȱ value 5ȱ 10 15 12 ȱ ȱ Theȱfunctionȱthenȱreturns,ȱleavingȱtheȱlistȱlookingȱlikeȱthis:ȱ Download at http://www.pin5i.com/ 12.2 Singly Linked Lists 327 rootȱ link link link link 0 valueȱ value valueȱ value 5ȱ 10 15 12 ȱ Startingȱatȱtheȱrootȱpointerȱandȱfollowingȱtheȱlinksȱverifiesȱthatȱtheȱnewȱnodeȱhasȱbeenȱ correctlyȱinserted.ȱ ȱ ȱ ȱ Debugging the Insert Function CAUTION! Unfortunately,ȱ theȱ insertȱ functionȱ isȱ incorrect.ȱ Tryȱ insertingȱ theȱ valueȱ 20ȱ intoȱ theȱ listȱ andȱ youȱ willȱ seeȱ oneȱ problem:ȱ theȱ whileȱ loopȱ runsȱ offȱ theȱ endȱ ofȱ theȱ listȱ andȱ thenȱ appliesȱindirectionȱtoȱaȱNULLȱpointer.ȱToȱsolveȱthisȱproblem,ȱweȱmustȱtestȱ currentȱtoȱ makeȱsureȱthatȱitȱisȱnotȱNULLȱbeforeȱevaluatingȱcurrent->value:ȱ ȱ while( current != NULL && current->value < value ){ ȱ ȱ Theȱ nextȱ problemȱ isȱ tougher.ȱ Traceȱ theȱ functionȱ toȱ insertȱ theȱ valueȱ 3ȱ intoȱ theȱ list.ȱWhatȱhappens?ȱ Inȱorderȱtoȱaddȱaȱnodeȱtoȱtheȱbeginningȱofȱtheȱlist,ȱtheȱfunctionȱmustȱchangeȱtheȱ rootȱpointer.ȱTheȱfunction,ȱhowever,ȱcannotȱaccessȱtheȱvariableȱ root.ȱTheȱeasiestȱwayȱ toȱfixȱthisȱproblemȱisȱtoȱjustȱmakeȱ rootȱaȱglobalȱvariableȱsoȱthatȱtheȱinsertionȱfunctionȱ canȱ modifyȱ it.ȱ Unfortunately,ȱ thisȱ approachȱ isȱ alsoȱ theȱ worstȱ wayȱ toȱ fixȱ theȱ problem,ȱ becauseȱthenȱtheȱfunctionȱworksȱonlyȱforȱthatȱoneȱlist.ȱ Theȱ betterȱ solutionȱ isȱ toȱ passȱ aȱ pointerȱ toȱ rootȱ asȱ anȱ argument.ȱ Thenȱ theȱ functionȱ canȱ useȱ indirectionȱ bothȱ toȱ obtainȱ theȱ valueȱ ofȱ rootȱ (theȱ pointerȱ toȱ theȱ firstȱ nodeȱofȱtheȱlist),ȱandȱtoȱstoreȱaȱnewȱpointerȱintoȱit.ȱWhatȱisȱtheȱtypeȱofȱthisȱparameter?ȱ rootȱisȱaȱpointerȱtoȱaȱNode,ȱsoȱtheȱparameterȱisȱofȱtypeȱNode **:ȱaȱpointerȱtoȱaȱpointerȱtoȱ aȱ Node.ȱTheȱfunctionȱinȱProgramȱ12.2ȱcontainsȱtheseȱmodifications.ȱȱWeȱmustȱnowȱcallȱ theȱfunctionȱlikeȱthis:ȱ ȱ result = sll_insert( &root, 12 ); Download at http://www.pin5i.com/ 328ȱ Chapter 12 Using Structures and Pointersȱ ȱ /* ** Insert into an ordered, singly linked list. The arguments are ** a pointer to the root pointer for the list, and the value to ** insert. */ #include <stdlib.h> #include <stdio.h> #include "sll_node.h" #define #define int sll_insert( { Node Node Node FALSE 0 TRUE 1 Node **rootp, int new_value ) *current; *previous; *new; /* ** Get the pointer to the first node. */ current = *rootp; previous = NULL; /* ** Look for the right place by walking down the list ** until we reach a node whose value is greater than ** or equal to the new value. */ while( current != NULL && current->value < new_value ){ previous = current; current = current->link; } /* ** Allocate a new node and store the new value into it. ** In this event, we return FALSE. */ new = (Node *)malloc( sizeof( Node ) ); if( new == NULL ) return FALSE; new->value = new_value; /* ** Insert the new node into the list, and return TRUE. */ new->link = current; if( previous == NULL ) *rootp = new; else previous->link = new; return TRUE; } ȱ Programȱ12.2ȱȱInsertȱintoȱanȱordered,ȱsinglyȱlinkedȱlist:ȱsecondȱtryȱ ȱ ȱ ȱȱȱȱȱinsert2.cȱ Download at http://www.pin5i.com/ 12.2 Singly Linked Lists 329 Thisȱsecondȱversionȱcontainsȱsomeȱadditionalȱstatements.ȱ ȱ ȱ previous = NULL; ȱ isȱneededȱsoȱthatȱweȱcanȱcheckȱlaterȱwhetherȱtheȱnewȱvalueȱwillȱbeȱtheȱfirstȱnodeȱinȱtheȱ list.ȱ ȱ ȱ current = *rootp; ȱ usesȱindirectionȱonȱtheȱrootȱpointerȱargumentȱtoȱgetȱtheȱvalueȱofȱ root,ȱaȱpointerȱtoȱtheȱ firstȱnodeȱinȱdieȱlist.ȱFinallyȱ ȱ if( previous == NULL ) *rootp = new; else previous->link = new; ȱ wasȱ addedȱ toȱ theȱ endȱ ofȱ theȱ function.ȱ Itȱ checksȱ whetherȱ theȱ newȱ valueȱ shouldȱ beȱ addedȱtoȱtheȱbeginningȱofȱtheȱlist.ȱIfȱso,ȱweȱuseȱindirectionȱonȱtheȱrootȱpointerȱtoȱmakeȱ rootȱpointȱtoȱtheȱnewȱnode.ȱ ȱ Thisȱ functionȱ works,ȱ andȱ inȱ manyȱ languagesȱ itȱ isȱ asȱ goodȱ asȱ youȱ canȱ get.ȱ However,ȱweȱcanȱdoȱbetterȱbecauseȱCȱallowsȱyouȱtoȱgetȱtheȱaddressȱofȱ(aȱpointerȱto)ȱ existingȱobjects.ȱ ȱ ȱ ȱ Optimizing the Insert Function ȱ Itȱappearsȱthatȱinsertingȱaȱnodeȱatȱtheȱbeginningȱofȱtheȱlistȱmustȱbeȱaȱspecialȱcase.ȱAfterȱ all,ȱ theȱ pointerȱ thatȱ mustȱ beȱ adjustedȱ toȱ insertȱ theȱ firstȱ nodeȱ isȱ theȱ rootȱ pointer.ȱ Forȱ everyȱ otherȱ node,ȱ theȱ pointerȱ toȱ beȱ adjustedȱ isȱ theȱ linkȱ fieldȱ ofȱ theȱ previousȱ node.ȱ Theseȱseeminglyȱdifferentȱoperationsȱareȱreallyȱtheȱsame.ȱ ȱ Theȱ keyȱ toȱ eliminatingȱ theȱ specialȱ caseȱ isȱ toȱ realizeȱ thatȱ everyȱ nodeȱ inȱ theȱ listȱ hasȱaȱpointerȱsomewhereȱpointingȱtoȱit.ȱForȱtheȱfirstȱnode,ȱitȱisȱtheȱrootȱpointer,ȱandȱforȱ everyȱotherȱnodeȱitȱisȱtheȱlinkȱfieldȱofȱtheȱprecedingȱnode.ȱTheȱimportantȱpointȱisȱthatȱ thereȱisȱaȱ pointerȱsomewhereȱpointingȱtoȱ eachȱnode.ȱWhetherȱ theȱpointerȱ isȱorȱisȱnotȱ containedȱinȱaȱnodeȱisȱirrelevant.ȱ Download at http://www.pin5i.com/ 330ȱ Chapter 12 Using Structures and Pointersȱ Letȇsȱlookȱatȱtheȱlistȱonceȱmoreȱtoȱclarifyȱthisȱpoint.ȱHereȱisȱtheȱfirstȱnodeȱandȱitsȱ correspondingȱpointer.ȱ ȱ rootȱ link link link 0 value value value 5 10 15 ȱ ȱ Ifȱtheȱnewȱvalueȱisȱinsertedȱbeforeȱtheȱfirstȱnode,ȱthenȱthisȱpointerȱmustȱbeȱchanged.ȱ Hereȱisȱtheȱsecondȱnodeȱandȱitsȱpointer.ȱ ȱ rootȱ link link link 0 value value value 5 10 15 ȱ ȱ Ifȱtheȱnewȱvalueȱisȱinsertedȱbeforeȱtheȱsecondȱnode,ȱthenȱthisȱpointerȱmustȱbeȱchanged.ȱ Noteȱthatȱweȇreȱconcernedȱonlyȱwithȱtheȱpointer;ȱtheȱnodeȱthatȱcontainsȱitȱisȱirrelevant.ȱ Theȱsameȱpatternȱholdsȱforȱeveryȱnodeȱinȱtheȱlist.ȱ Nowȱletȇsȱtakeȱaȱlookȱatȱtheȱmodifiedȱfunctionȱasȱitȱbeginsȱtoȱexecute.ȱHereȱareȱ itsȱvariablesȱasȱtheyȱappearȱjustȱafterȱtheȱfirstȱassignmentȱstatement.ȱ ȱ ȱ rootpȱ current rootȱ link link link 0 value value value 5 10 15 ȱ Download at http://www.pin5i.com/ 12.2 Singly Linked Lists 331 Weȱ haveȱ aȱ pointerȱ toȱ theȱ currentȱ nodeȱ andȱ aȱ pointerȱ toȱ theȱ linkȱ thatȱ pointsȱ toȱ theȱ currentȱ node.ȱ Weȱ donȇtȱ needȱ anythingȱ else!ȱ Ifȱ theȱ valueȱ inȱ theȱ currentȱ nodeȱ isȱ largerȱ thanȱtheȱnewȱvalue,ȱtheȱrootpȱpointerȱtellsȱusȱwhichȱlinkȱfieldȱmustȱbeȱchangedȱtoȱlinkȱ theȱnewȱnodeȱintoȱtheȱlist.ȱIfȱinsertionsȱelsewhereȱinȱtheȱlistȱcanȱbeȱexpressedȱtheȱsameȱ way,ȱ theȱ specialȱ caseȱ disappears.ȱ Theȱ keyȱ isȱ theȱ pointer/nodeȱ relationshipȱ weȱ sawȱ earlier.ȱ Whenȱmovingȱtoȱtheȱnextȱnode,ȱsaveȱaȱpointerȱtoȱtheȱlinkȱthatȱpointsȱtoȱtheȱnextȱ nodeȱ insteadȱofȱkeepingȱ aȱpointerȱtoȱ theȱ previousȱnode.ȱItȱisȱeasyȱtoȱ diagramȱ whatȱ isȱ desired.ȱ ȱ rootp currentȱ rootȱ link link link 0 value value value 5 10 15 ȱ ȱ Noticeȱhereȱthatȱ rootpȱisȱnotȱpointingȱtoȱtheȱnode;ȱitȱpointsȱtoȱtheȱlinkȱfieldȱwithinȱtheȱ node.ȱThisȱfactȱisȱtheȱkeyȱtoȱsimplifyingȱtheȱinsertȱfunction,ȱbutȱitȱdependsȱuponȱourȱ beingȱableȱtoȱobtainȱtheȱaddressȱofȱtheȱlinkȱfieldȱofȱtheȱcurrentȱnode.ȱThisȱoperationȱisȱ easyȱ inȱ C.ȱ Theȱ expressionȱ &current->linkȱ doesȱ theȱ trick.ȱ Programȱ 12.3ȱ isȱ theȱ finalȱ versionȱofȱourȱinsertionȱfunction.ȱȱTheȱ rootpȱparameterȱisȱnowȱcalledȱ linkp,ȱbecauseȱitȱ pointsȱ toȱ manyȱ differentȱ linksȱ now,ȱ notȱ justȱ theȱ root.ȱ Weȱ donȇtȱ needȱ previousȱ anyȱ more,ȱ becauseȱ ourȱ linkȱ pointerȱ takesȱ careȱ ofȱ locatingȱ theȱ linkȱ thatȱ needsȱ toȱ beȱ modified.ȱTheȱspecialȱcaseȱatȱtheȱendȱofȱtheȱfunctionȱisȱgoneȱbecauseȱweȱalwaysȱhaveȱaȱ pointerȱ toȱ theȱ linkȱ fieldȱ thatȱ needsȱ toȱ beȱ changed—weȱ modifyȱ theȱ rootȱ variableȱ inȱ exactlyȱ theȱ sameȱ wayȱ asȱ theȱ linkȱ fieldȱ ofȱ aȱ node.ȱ Finally,ȱ registerȱ declarationsȱ haveȱ beenȱaddedȱtoȱtheȱpointerȱvariablesȱtoȱimproveȱtheȱefficiencyȱofȱtheȱresultingȱcode.ȱ Theȱ whileȱ loopȱ inȱ thisȱ finalȱ versionȱ isȱ trickierȱ becauseȱ ofȱ theȱ embeddedȱ assignmentȱtoȱcurrent.ȱHereȱisȱanȱequivalent,ȱthoughȱslightlyȱlongerȱloop.ȱ ȱ /* ** Look for the right place. */ current = *linkp; while( current != NULL && current->value < value ){ linkp = &current->link; current = *linkp; } Download at http://www.pin5i.com/ 332ȱ Chapter 12 Using Structures and Pointersȱ ȱ ȱ ȱ /* ** Insert into an ordered, singly linked list. The arguments are ** a pointer to the first node in the list, and the value to ** insert. */ #include <stdlib.h> #include <stdio.h> #include "sll_node.h" #define #define FALSE 0 TRUE 1 int sll_insert( register Node **linkp, int new_value ) { register Node *current; register Node *new; /* ** Look for the right place by ** until we reach a node whose ** or equal to the new value. */ while( ( current = *linkp ) != current->value < new_value linkp = &current->link; walking down the list value is greater than NULL && ) /* ** Allocate a new node and store the new value into it. ** In this event, we return FALSE. */ new = (Node *)malloc( sizeof( Node ) ); if( new == NULL ) return FALSE; new->value = new_value; /* ** Insert the new node into the list, and return TRUE. */ new->link = current; *linkp = new; return TRUE; } ȱ Programȱ12.3ȱȱInsertȱintoȱanȱordered,ȱsinglyȱlinkedȱlist:ȱfinalȱversionȱȱ ȱ ȱȱȱȱȱȱinsert3.cȱ Download at http://www.pin5i.com/ 12.2 Singly Linked Lists TIP CAUTION! 333 Toȱ begin,ȱ currentȱ isȱ setȱ toȱ pointȱ toȱ theȱ firstȱ nodeȱ inȱ theȱ list.ȱ Theȱ whileȱ testȱ checksȱ whetherȱweȇveȱreachedȱtheȱendȱofȱtheȱlist.ȱIfȱnot,ȱitȱthenȱchecksȱwhetherȱweȱareȱatȱtheȱ properȱplaceȱforȱtheȱinsertion.ȱIfȱnot,ȱtheȱbodyȱofȱtheȱloopȱexecutes,ȱwhichȱsetsȱlinkpȱtoȱ pointȱtoȱtheȱlinkȱfieldȱinȱtheȱcurrentȱnode,ȱandȱadvancesȱcurrentȱtoȱtheȱnextȱnode.ȱ Theȱfactȱthatȱtheȱlastȱstatementȱinȱtheȱloopȱbodyȱisȱidenticalȱtoȱtheȱstatementȱjustȱ priorȱtoȱtheȱloopȱleadsȱtoȱtheȱȈsimplificationȈȱofȱembeddingȱtheȱassignmentȱtoȱ currentȱ withinȱ theȱ whileȱ expression.ȱ Theȱ resultȱ isȱ aȱ moreȱ complexȱ butȱ moreȱ compactȱ loop,ȱ becauseȱweȱhaveȱeliminatedȱtheȱredundantȱassignmentȱtoȱcurrent.ȱ ȱ ȱ Eliminatingȱ theȱ specialȱ caseȱ madeȱ thisȱ functionȱ simpler.ȱ Thereȱ areȱ twoȱ factorsȱ thatȱ makeȱthisȱimprovementȱpossible.ȱTheȱfirstȱfactorȱisȱourȱabilityȱtoȱinterpretȱtheȱproblemȱ correctly.ȱUnlessȱyouȱcanȱidentifyȱtheȱcommonalityȱinȱseeminglyȱdifferentȱoperations,ȱ youȱwillȱbeȱstuckȱwritingȱextraȱcodeȱtoȱhandleȱspecialȱcases.ȱOftenȱthisȱknowledgeȱisȱ acquiredȱ onlyȱ afterȱ youȱ haveȱ workedȱ withȱ theȱ dataȱ structureȱ forȱ aȱ whileȱ andȱ understandȱitȱmoreȱclearly.ȱTheȱsecondȱfactorȱisȱthatȱtheȱCȱlanguageȱprovidesȱtheȱrightȱ toolsȱforȱyouȱtoȱexploitȱtheȱcommonality.ȱ TheȱimprovedȱfunctionȱdependsȱonȱCȇsȱabilityȱtoȱobtainȱtheȱaddressȱofȱexistingȱ objects.ȱLikeȱmanyȱCȱfeatures,ȱthisȱabilityȱisȱbothȱpowerfulȱandȱdangerous.ȱInȱModulaȱ andȱPascal,ȱforȱexample,ȱthereȱisnȇtȱanȱȈaddressȱofȈȱoperator,ȱsoȱtheȱonlyȱpointersȱthatȱ existȱareȱthoseȱproducedȱbyȱdynamicȱmemoryȱallocation.ȱItȱisȱnotȱpossibleȱtoȱobtainȱaȱ pointerȱtoȱanȱordinaryȱvariableȱorȱevenȱtoȱaȱfieldȱofȱaȱdynamicallyȱallocatedȱstructure.ȱ Pointerȱarithmeticȱisȱnotȱallowed,ȱandȱthereȱisnȇtȱanyȱmeansȱforȱcastingȱaȱpointerȱfromȱ oneȱ typeȱ toȱ another.ȱ Theseȱ restrictionsȱ areȱ advantageousȱ inȱ thatȱ theyȱ preventȱ theȱ programmerȱ fromȱ makingȱ mistakesȱ suchȱ asȱ subscriptingȱ offȱ theȱ endȱ ofȱ anȱ arrayȱ andȱ generatingȱpointersȱofȱoneȱtypeȱthatȱinȱfactȱpointȱtoȱobjectsȱofȱsomeȱotherȱtype.ȱ ȱ ȱ Thereȱ areȱ farȱ fewerȱ restrictionsȱ onȱ pointersȱ inȱ C,ȱ whichȱ isȱ whyȱ weȱ wereȱ ableȱ toȱ improveȱ theȱ insertionȱ function.ȱ Onȱ theȱ otherȱ hand,ȱ Cȱ programmersȱ mustȱ beȱ moreȱ carefulȱ whenȱ usingȱ pointersȱ toȱ avoidȱ mistakes.ȱ Theȱ Pascalȱ philosophyȱ toȱ pointersȱ isȱ sortȱ ofȱ likeȱ saying,ȱ ȈYouȱ mightȱ hurtȱ yourselfȱ withȱ aȱ hammer,ȱ soȱ weȱ wonȇtȱ giveȱ youȱ one.Ȉȱ Theȱ Cȱ philosophyȱ is,ȱ ȈHereȱ isȱ aȱ hammer.ȱ Inȱ fact,ȱ hereȱ areȱ severalȱ kindsȱ ofȱ hammers.ȱ Goodȱ luck.Ȉȱ Withȱ thisȱ power,ȱ Cȱ programmersȱ canȱ getȱ intoȱ moreȱ troubleȱ thanȱ Pascalȱ programmers,ȱ butȱ goodȱ Cȱ programmersȱ canȱ produceȱ smaller,ȱ moreȱ efficient,ȱandȱmoreȱmaintainableȱcodeȱthanȱtheirȱPascalȱorȱModulaȱcounterparts.ȱThisȱ isȱ oneȱ ofȱ theȱ reasonsȱ whyȱ Cȱ isȱ soȱ popularȱ inȱ industry,ȱ andȱ whyȱ experiencedȱ Cȱ programmersȱareȱinȱsuchȱdemand.ȱ Download at http://www.pin5i.com/ Chapter 12 Using Structures and Pointersȱ 334ȱ 12.2.2 Other List Operations ȱ Toȱmakeȱsinglyȱlinkedȱlistsȱreallyȱuseful,ȱweȱneedȱmoreȱoperationsȱsuchȱasȱsearchingȱ andȱ deletion.ȱ However,ȱ theȱ algorithmsȱ forȱ theseȱ operationsȱ areȱ straightforwardȱ andȱ easilyȱ implementedȱ usingȱ theȱ techniquesȱ illustratedȱ inȱ theȱ insertionȱ function.ȱ Theseȱ functionsȱareȱleftȱasȱexercises.ȱ ȱ ȱ ȱ 12.3 Doubly Linked Lists ȱ Anȱalternativeȱtoȱsinglyȱlinkedȱlistsȱisȱtheȱdoublyȱlinkedȱlist.ȱInȱaȱdoublyȱlinkedȱlist,ȱeachȱ nodeȱhasȱtwoȱpointers—oneȱtoȱtheȱnextȱnodeȱinȱtheȱlistȱandȱoneȱtoȱtheȱpreviousȱnode.ȱ Theȱbackȱpointerȱletsȱusȱtraverseȱdoublyȱlinkedȱlistsȱinȱeitherȱdirection.ȱWeȱcanȱevenȱgoȱ backȱandȱforth.ȱTheȱfollowingȱdiagramȱillustratesȱaȱdoublyȱlinkedȱlist.ȱ ȱ rootȱ fwd fwd fwd 0ȱ bwdȱ bwdȱ valueȱ bwdȱ 0 15ȱ value valueȱ 10 15ȱ ȱ ȱ Hereȱisȱtheȱdeclarationȱforȱtheȱnodeȱtype.ȱ ȱ typedef struct struct struct int NODE NODE NODE { *fwd; *bwd; value; } Node; ȱ Theȱ rootȱ isȱ nowȱ twoȱ pointers:ȱ oneȱ pointsȱ toȱ theȱ firstȱ nodeȱ inȱ theȱ list,ȱ andȱ theȱ otherȱ pointsȱtoȱtheȱlastȱnode.ȱTheseȱtwoȱpointersȱletȱusȱbeginȱaȱtraversalȱatȱeitherȱendȱofȱtheȱ listȱ Weȱ mightȱ declareȱ theȱ twoȱ rootȱ pointersȱ asȱ separateȱ variables,ȱ butȱ thenȱ weȱ wouldȱ haveȱ toȱ passȱ pointersȱ toȱ bothȱ ofȱ themȱ toȱ theȱ insertionȱ function.ȱ Itȱ isȱ moreȱ convenientȱ toȱ declareȱ anȱ entireȱ nodeȱ forȱ theȱ rootȱ pointers,ȱ oneȱ whoseȱ valueȱ fieldȱ isȱ neverȱused.ȱInȱourȱexample,ȱthisȱtechniqueȱonlyȱwastesȱtheȱmemoryȱforȱoneȱinteger.ȱȱ Download at http://www.pin5i.com/ 12.3 Doubly Linked Lists 335 Separateȱpointersȱmightȱbeȱbetterȱforȱlistsȱwhoseȱvalueȱfieldȱisȱlarge.ȱAlternatively,ȱweȱ mightȱuseȱtheȱvalueȱfieldȱofȱtheȱrootȱnodeȱtoȱstoreȱotherȱinformationȱaboutȱtheȱlist,ȱforȱ example,ȱtheȱnumberȱofȱnodesȱitȱcurrentlyȱcontains.ȱ Theȱ fwdȱ fieldȱ ofȱ theȱ footȱ nodeȱ pointsȱ toȱ theȱ firstȱ nodeȱ inȱ theȱ Use,ȱ andȱ theȱ bwdȱ fieldȱ ofȱ theȱ rootȱ nodeȱ pointsȱ toȱ theȱ lastȱ nodeȱ inȱ theȱ list.ȱ Bothȱ ofȱ theseȱ fieldsȱ willȱ beȱ NULLȱifȱtheȱlistȱisȱempty.ȱTheȱ bwdȱfieldȱofȱtheȱfirstȱnodeȱinȱtheȱlistȱandȱtheȱ fwdȱfieldȱofȱ theȱlastȱnodeȱwillȱbeȱNULL.ȱInȱanȱorderedȱlist,ȱnodesȱareȱstoredȱinȱincreasingȱorderȱofȱ theȱvalueȱfield.ȱ ȱ ȱ ȱ 12.3.1 Inserting into a Doubly Linked List ȱ Thisȱ time,ȱ weȱ developȱ aȱ functionȱ thatȱ insertsȱ aȱ valueȱ intoȱ anȱ ordered,ȱ doublyȱ linkedȱ list.ȱdll_insertȱtakesȱtwoȱarguments:ȱaȱpointerȱtoȱtheȱrootȱnodeȱandȱanȱintegerȱvalue.ȱ Theȱsinglyȱ linkedȱinsertionȱ functionȱ weȱwroteȱ earlierȱ addsȱ duplicateȱvaluesȱtoȱ theȱ list.ȱ Itȱ mayȱ beȱ moreȱ appropriateȱ forȱ someȱ applicationsȱ toȱ notȱ addȱ duplicates.ȱȱ dll_insertȱwillȱaddȱaȱnewȱvalueȱonlyȱifȱisȱnotȱalreadyȱinȱtheȱlist.ȱ Letȇsȱ takeȱ aȱ moreȱ disciplinedȱ approachȱ toȱ developingȱ thisȱ function.ȱ Thereȱ areȱ fourȱcasesȱthatȱcanȱoccurȱwhenȱinsertingȱaȱnodeȱintoȱaȱlinkedȱlist:ȱ 1. Theȱvalueȱmightȱhaveȱtoȱbeȱinsertedȱinȱtheȱmiddleȱofȱtheȱlist.ȱ 2. Theȱvalueȱmightȱhaveȱtoȱbeȱinsertedȱatȱtheȱbeginningȱofȱtheȱlist.ȱ 3. Theȱvalueȱmightȱhaveȱtoȱbeȱinsertedȱatȱtheȱendȱofȱtheȱlistȱ 4. Theȱ valueȱ mightȱ haveȱ toȱ beȱ insertedȱ atȱ bothȱ theȱ beginningȱ andȱ theȱ endȱ (thatȱ is,ȱ insertedȱintoȱanȱemptyȱlist).ȱ ȱ Inȱeachȱofȱtheseȱcases,ȱfourȱpointersȱmustȱbeȱmodified.ȱ ȱ x Inȱcasesȱ(1)ȱandȱ(2),ȱtheȱ fwdȱfieldȱofȱtheȱnewȱnodeȱmustȱbeȱsetȱtoȱpointȱtoȱtheȱnextȱ nodeȱinȱtheȱlist,ȱandȱtheȱ bwdȱfieldȱofȱtheȱnextȱnodeȱinȱtheȱlistȱmustȱbeȱsetȱtoȱpointȱtoȱ theȱ newȱ node.ȱ Inȱ casesȱ (3)ȱ andȱ (4),ȱ theȱ fwdȱ fieldȱ ofȱ theȱ newȱ nodeȱ mustȱ beȱ setȱ toȱ NULL,ȱandȱtheȱbwdȱfieldȱofȱtheȱrootȱnodeȱmustȱbeȱsetȱtoȱpointȱtoȱtheȱnewȱnode.ȱ x Inȱ casesȱ (1)ȱ andȱ (3),ȱ theȱ bwdȱ fieldȱ ofȱ theȱ newȱ nodeȱ mustȱ beȱ setȱ toȱ pointȱ toȱ theȱ previousȱ nodeȱ inȱ theȱ list,ȱ andȱ theȱ fwdȱ fieldȱ ofȱ theȱ previousȱ nodeȱ mustȱ beȱ setȱ toȱ pointȱtoȱtheȱnewȱnode.ȱInȱcasesȱ(2)ȱandȱ(4),ȱtheȱ bwdȱfieldȱofȱtheȱnewȱnodeȱmustȱbeȱ setȱ toȱ NULL,ȱ andȱ theȱ fwdȱ fieldȱ ofȱ theȱ rootȱ nodeȱ mustȱ beȱ setȱ toȱ pointȱ toȱ theȱ newȱ node.ȱ ȱ Ifȱthisȱdescriptionȱseemsȱunclear,ȱtheȱstraightforwardȱimplementationȱinȱProgramȱ12.4ȱ shouldȱhelp.ȱ Download at http://www.pin5i.com/ Chapter 12 Using Structures and Pointersȱ 336ȱ ȱ /* ** Insert a value into a doubly linked list. rootp is a pointer to ** the root node, and value is the new value to be inserted. ** Returns: 0 if the value is already in the list, -1 if there was ** no memory to create a new node, 1 if the value was added ** successfully. */ #include <stdlib.h> #include <stdio.h> #include "dll_node.h" int dll_insert( { Node Node Node Node *rootp, int value ) *this; *next; *newnode; /* ** See if value is already in the list; return if it is. ** Otherwise, allocate a new node for the value ("newnode" ** will point to it). "this" will point to the node that the ** new value should follow, and "next" will point to the one ** after it. */ for( this = rootp; (next = this->fwd) != NULL; this = next ){ if( next->value == value ) return 0; if( next->value > value ) break; } newnode = (Node *)malloc( sizeof( Node ) ); if( newnode == NULL ) return -1; newnode->value = value; /* ** Add the new node to the list. */ if( next != NULL ){ /* ** Case 1 or 2: not at end of the list */ if( this != rootp ){ /* Case 1: not at front */ newnode->fwd = next; ȱ Programȱ12.4ȱȱStraightforwardȱdoublyȱlinkedȱlistȱinsertȱfunctionȱ ȱ ȱ continued…ȱ Download at http://www.pin5i.com/ 12.3 Doubly Linked Lists 337 ȱ this->fwd = newnode; newnode->bwd = this; next->bwd = newnode; } else { /* Case 2: at front */ newnode->fwd = next; rootp->fwd = newnode; newnode->bwd = NULL; next->bwd = newnode; } } else { /* ** Case 3 or 4: at end of the list */ if( this != rootp ){ /* Case 3: not at front */ newnode->fwd = NULL; this->fwd = newnode; newnode->bwd = this; rootp->bwd = newnode; } else { /* Case 4: at front */ newnode->fwd = NULL; rootp->fwd = newnode; newnode->bwd = NULL; rootp->bwd = newnode; } } return 1; } ȱ Programȱ12.4ȱȱStraightforwardȱdoublyȱlinkedȱlistȱinsertȱfunctionȱ ȱ ȱ ȱȱȱȱdll_ins1.cȱ ȱ ȱ ȱ ȱ ȱ ȱ Theȱ functionȱ beginsȱ byȱ makingȱ thisȱ pointȱ toȱ theȱ rootȱ node.ȱ Theȱ nextȱ pointerȱ alwaysȱ pointsȱ toȱ theȱ nodeȱ afterȱ this;ȱ theȱ ideaȱ isȱ toȱ advanceȱ theseȱ pointersȱ togetherȱ untilȱtheȱnewȱnodeȱshouldȱbeȱinsertedȱbetweenȱthem.ȱTheȱforȱloopȱchecksȱtheȱvalueȱinȱ theȱnextȱnodeȱtoȱdetermineȱwhenȱthisȱpositionȱhasȱbeenȱreached.ȱ Ifȱtheȱnewȱvalueȱisȱfoundȱinȱtheȱlist,ȱtheȱfunctionȱsimplyȱreturns.ȱOtherwise,ȱtheȱ loopȱendsȱwhenȱtheȱendȱofȱtheȱlistȱisȱreachedȱorȱwhenȱtheȱproperȱpositionȱforȱinsertionȱ isȱreached.ȱInȱeitherȱcase,ȱtheȱnewȱnodeȱshouldȱbeȱinsertedȱafterȱtheȱ thisȱnode.ȱNoteȱ thatȱspaceȱforȱtheȱnewȱnodeȱisȱnotȱallocatedȱuntilȱafterȱweȱdetermineȱwhetherȱtheȱvalueȱ shouldȱactuallyȱbeȱaddedȱtoȱtheȱlist.ȱ Download at http://www.pin5i.com/ 338ȱ Chapter 12 Using Structures and Pointersȱ Allocatingȱ theȱ newȱ nodeȱ firstȱ wouldȱ causeȱ aȱ potentialȱ memoryȱ leakȱ forȱ duplicateȱ values.ȱ Theȱfourȱcasesȱhaveȱbeenȱimplementedȱseparately.ȱLetȇsȱtraceȱcaseȱ1ȱbyȱinsertingȱ theȱvalueȱ12ȱintoȱtheȱlist.ȱTheȱfollowingȱdiagramȱshowsȱtheȱstateȱofȱourȱvariablesȱjustȱ afterȱtheȱforȱloopȱbreaks.ȱ rootpȱ this nextȱ rootȱ fwd fwd fwd 0ȱ bwdȱ valueȱ bwdȱ bwdȱ 0 15ȱ value valueȱ 10 15ȱ ȱ Aȱnewȱnodeȱisȱthenȱallocated.ȱAfterȱexecutingȱtheȱstatementsȱ ȱ newnode->fwd = next; this->fwd = newnode; ȱ theȱlistȱlooksȱlikeȱthis:ȱ rootpȱ rootȱ fwd this fwd nextȱ fwd newnode fwd 0ȱ bwdȱ valueȱ bwdȱ bwdȱ bwdȱ 0 15ȱ ? 15 value valueȱ value 10 15ȱ 12 ȱ Download at http://www.pin5i.com/ 12.3 Doubly Linked Lists 339 Then,ȱtheȱstatementsȱ ȱ newnode->bwd = this; next->bwd = newnode; ȱ finishȱlinkingȱtheȱnewȱvalueȱintoȱtheȱlist:ȱ ȱ rootpȱ this rootȱ fwd fwd nextȱ fwd newnode fwd 0ȱ bwdȱ valueȱ bwdȱ bwdȱ bwdȱ 0 15ȱ 15 value valueȱ value 10 15ȱ 12 ȱ Studyȱ theȱ codeȱ toȱ determineȱ howȱ theȱ remainingȱ casesȱ work,ȱ andȱ convinceȱ yourselfȱ thatȱeachȱcaseȱisȱcompletedȱproperly.ȱ ȱ ȱ ȱ Simplifying the Insert Function TIP ȱ Theȱ observantȱ programmerȱ willȱ noticeȱ thatȱ thereȱ isȱ aȱ lotȱ ofȱ similarityȱ amongȱ theȱ groupsȱ ofȱ statementsȱ inȱ theȱ nestedȱ ifȱ statementsȱ inȱ theȱ function,ȱ andȱ theȱ goodȱ programmerȱwillȱbeȱbotheredȱbyȱallȱofȱtheȱduplication.ȱSoȱweȱwillȱnowȱeliminateȱtheȱ duplicationȱ usingȱ twoȱ techniques.ȱ Theȱ firstȱ isȱ statementȱ factoring,ȱ andȱ isȱ illustratedȱ inȱ theȱfollowingȱexample.ȱ ȱ if( x == 3 ){ i = 1; something; j = 2; } else { i = 1; something different; j = 2; } Download at http://www.pin5i.com/ 340ȱ Chapter 12 Using Structures and Pointersȱ Noticeȱthatȱtheȱstatementsȱi = 1;ȱandȱj = 2;ȱwillȱbeȱexecutedȱwhetherȱtheȱexpressionȱȱ x == 3ȱisȱtrueȱorȱfalse.ȱDoingȱi = 1;ȱbeforeȱtheȱifȱwillȱnotȱaffectȱtheȱresultȱofȱtheȱtestȱȱȱȱ x == 3,ȱsoȱbothȱpairsȱofȱassignmentsȱcanȱbeȱfactoredȱout,ȱleavingȱtheȱsimpler,ȱbutȱ completelyȱequivalent,ȱstatements:ȱ ȱ i = 1; if( x == 3 ) something; else something different; j = 2; CAUTION! ȱ ȱ Beȱcarefulȱnotȱtoȱfactorȱaȱstatementȱaboveȱtheȱifȱthatȱchangesȱtheȱresultȱofȱtheȱtest.ȱForȱ example,ȱinȱ ȱ if( x == 3 ){ x = 0; something; } else { x = 0; something different; } ȱ theȱ statementȱ x = 0;ȱ cannotȱ beȱ factoredȱ outȱ becauseȱ itȱ wouldȱ affectȱ theȱ resultȱ ofȱ theȱ comparison.ȱ Factoringȱ theȱ innermostȱ ofȱ theȱ nestedȱ ifȇsȱ inȱ Programȱ 12.4ȱ yieldsȱ theȱ codeȱ fragmentȱ inȱ Programȱ 12.5.ȱ Compareȱ thisȱ codeȱ toȱ theȱ previousȱ functionȱ andȱ convinceȱ yourselfȱthatȱitȱisȱequivalent.ȱ Theȱsecondȱsimplificationȱtechniqueȱisȱeasilyȱillustratedȱwithȱanȱexample:ȱ ȱ if( pointer != NULL ) field = pointer; else field = NULL; ȱ Theȱ intentȱ hereȱ isȱ toȱ setȱ aȱ variableȱ equalȱ toȱ pointer,ȱ orȱ toȱ NULLȱ ifȱ pointerȱ doesnȇtȱ pointȱtoȱanything.ȱButȱlookȱatȱthisȱstatement:ȱ ȱ field = pointer; ȱ Ifȱ pointerȱ isȱ notȱ NULL,ȱ fieldȱ getsȱ aȱ copyȱ ofȱ itsȱ value,ȱ asȱ before.ȱ ȱ Butȱ ifȱ pointerȱ is Download at http://www.pin5i.com/ 12.3 Doubly Linked Lists 341 ȱ /* ** Add the new node to the list. */ if( next != NULL ){ /* ** Case 1 or 2: not at end of */ newnode->fwd = next; if( this != rootp ){ /* this->fwd = newnode; newnode->bwd = this; } else { /* rootp->fwd = newnode; newnode->bwd = NULL; } next->bwd = newnode; } else { /* ** Case 3 or 4: at end of the */ newnode->fwd = NULL; if( this != rootp ){ /* this->fwd = newnode; newnode->bwd = this; } else { /* rootp->fwd = newnode; newnode->bwd = NULL; } rootp->bwd = newnode; } the list Case 1: not at front */ Case 2: at front */ list Case 3: not at front */ Case 4: at front */ ȱ Programȱ12.5ȱȱFactoredȱdoublyȱlinkedȱlistȱinsertionȱlogicȱ ȱ ȱ ȱ ȱȱȱȱdll_ins2.cȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ NULL,ȱ fieldȱ getsȱ aȱ copyȱ ofȱ theȱ NULLȱ fromȱ pointer,ȱ whichȱ hasȱ theȱ sameȱ effectȱ asȱ assigningȱ theȱ constantȱ NULL.ȱ Thisȱ statementȱ performsȱ theȱ sameȱ workȱ asȱ theȱ previousȱ oneȱandȱisȱobviouslyȱsimpler.ȱ Theȱ keyȱ toȱ applyingȱ thisȱ techniqueȱ toȱ theȱ codeȱ inȱ Programȱ 12.5ȱ isȱ toȱ identifyȱ theȱ statementsȱ thatȱ performȱ theȱ sameȱ workȱ evenȱ thoughȱ theyȱ lookȱ differentȱ andȱ rewriteȱ themȱsoȱthatȱtheyȱareȱidentical.ȱWeȱcanȱrewriteȱtheȱfirstȱstatementȱinȱcasesȱ3ȱandȱ4ȱasȱ ȱ newnode->fwd = next; Download at http://www.pin5i.com/ 342ȱ Chapter 12 Using Structures and Pointersȱ becauseȱ theȱ ifȱ statementȱ hasȱ justȱ determinedȱ thatȱ next == null.ȱ Thisȱ changeȱ makesȱ theȱfirstȱstatementȱonȱbothȱsidesȱofȱtheȱ ifȱstatementȱidentical,ȱsoȱweȱcanȱfactorȱitȱout.ȱ Writeȱdownȱthisȱchange,ȱandȱstudyȱwhatȱremains.ȱ Didȱyouȱseeȱit?ȱBothȱnestedȱ ifȇsȱareȱnowȱidentical,ȱsoȱtheyȱcanȱalsoȱbeȱfactored.ȱ TheȱresultȱofȱtheseȱchangesȱisȱshownȱinȱProgramȱ12.6.ȱ Weȱcanȱimproveȱthisȱcodeȱstillȱfurther.ȱTheȱfirstȱstatementȱinȱtheȱ elseȱclauseȱofȱ theȱfirstȱifȱcanȱbeȱrewrittenȱasȱ ȱ this->fwd = newnode; ȱ becauseȱ theȱ ifȱ statementȱ hasȱ alreadyȱ decidedȱ thatȱ this == rootp.ȱ Theȱ rewrittenȱ statementȱandȱitsȱmateȱcanȱnowȱbeȱfactoredȱout,ȱtoo.ȱ Programȱ 12.7ȱ isȱ theȱ entireȱ functionȱ afterȱ allȱ ofȱ theȱ changesȱ haveȱ beenȱ implemented.ȱ Itȱ doesȱ theȱ sameȱ workȱ asȱ theȱ originalȱ butȱ isȱ muchȱ smaller.ȱ Theȱ localȱ pointersȱ haveȱ beenȱ declaredȱ registerȱ variablesȱ toȱ improveȱ theȱ sizeȱ andȱ speedȱ ofȱ theȱ codeȱevenȱfurther.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Add the new node to the list. */ newnode->fwd = next; if( this != rootp ){ this->fwd = newnode; newnode->bwd = this; } else { rootp->fwd = newnode; newnode->bwd = NULL; } if( next != NULL ) next->bwd = newnode; else rootp->bwd = newnode; ȱ Programȱ12.6ȱȱFurtherȱfactoredȱdoublyȱlinkedȱlistȱinsertionȱlogicȱ ȱ ȱ ȱȱȱȱdll_ins3.cȱ Download at http://www.pin5i.com/ 12.3 Doubly Linked Lists 343 ȱ /* ** Insert a value into a doubly linked list. rootp is a pointer to ** the root node, and value is the new value to be inserted. ** Returns: 0 if the value is already in the list, -1 if there was ** no memory to create a new node, 1 if the value was added ** successfully. */ #include <stdlib.h> #include <stdio.h> #include "dll_node.h" int dll_insert( register Node *rootp, int value ) { register Node *this; register Node *next; register Node *newnode; /* ** See if value is already in the list; return if it is. ** Otherwise, allocate a new node for the value ("newnode" ** will point to it). "this" will point to the node that the ** new value should follow, and "next" will point to the one ** after it. */ for( this = rootp; (next = this->fwd) != NULL; this = next ){ if( next->value == value ) return 0; if( next->value > value ) break; } newnode = (Node *)malloc( sizeof( Node ) ); if( newnode == NULL ) return -1; newnode->value = value; /* ** Add the new node to the list. */ newnode->fwd = next; this->fwd = newnode; if( this != rootp ) newnode->bwd = this; else newnode->bwd = NULL; if( next != NULL ) next->bwd = newnode; else rootp->bwd = newnode; return 1; } ȱ Programȱ12.7ȱȱFullyȱsimplifiedȱdoublyȱlinkedȱlistȱinsertionȱfunctionȱȱȱ ȱ ȱȱȱȱdll_ins4.cȱ Download at http://www.pin5i.com/ 344ȱ Chapter 12 Using Structures and Pointersȱ Thisȱ functionȱ cannotȱ beȱ madeȱ significantlyȱ better,ȱ thoughȱ weȱ canȱ makeȱ theȱ sourceȱ codeȱsmaller.ȱTheȱpurposeȱofȱtheȱfirstȱ ifȱstatementȱisȱtoȱdetermineȱtheȱrightȱsideȱofȱanȱ assignment.ȱWeȱcanȱreplaceȱtheȱ ifȱwithȱaȱconditionalȱexpression.ȱWeȱcanȱalsoȱreplaceȱ theȱsecond ifȱwithȱaȱconditional,ȱthoughȱthisȱchangeȱisȱlessȱobvious.ȱ ȱ ȱ TheȱcodeȱinȱProgramȱ12.8ȱisȱcertainlyȱsmaller,ȱbutȱisȱitȱreallyȱbetter?ȱAlthoughȱthereȱareȱ fewerȱstatements,ȱtheȱnumberȱofȱcomparisonsȱandȱassignmentsȱthatȱmustȱbeȱmadeȱisȱ theȱsameȱasȱbefore,ȱsoȱthisȱcodeȱisnȇtȱanyȱfasterȱthanȱwhatȱweȱhadȱbefore.ȱThereȱareȱtwoȱ minorȱ differences:ȱ newnode->bwdȱ andȱ ->bwd = newnodeȱ areȱ bothȱ writtenȱ onceȱ ratherȱ thanȱtwice.ȱWillȱtheseȱdifferencesȱresultȱinȱsmallerȱcode?ȱPossibly,ȱdependingȱonȱhowȱ wellȱyourȱcompilerȱcanȱoptimize.ȱButȱtheȱdifferenceȱwillȱbeȱsmallȱatȱbest,ȱandȱthisȱcodeȱ isȱ lessȱ readableȱ thanȱ before,ȱ particularlyȱ forȱ anȱ inexperiencedȱ Cȱ programmer.ȱ Thus,ȱ Programȱ12.8ȱmayȱbeȱmoreȱtroubleȱtoȱmaintain.ȱ ȱ Ifȱtheȱprogramȱsizeȱorȱexecutionȱspeedȱwereȱreallyȱimportant,ȱtheȱonlyȱthingȱleftȱ toȱ tryȱ wouldȱ beȱ toȱ handȱ codeȱ theȱ functionȱ inȱ assemblyȱ language.ȱ Evenȱ thisȱ drasticȱ optionȱdoesȱnotȱguaranteeȱanyȱsignificantȱimprovement,ȱandȱtheȱdifficultyȱofȱwriting,ȱ reading,ȱ andȱ maintainingȱ assemblyȱ codeȱ suggestsȱ thatȱ thisȱ approachȱ shouldȱ beȱ usedȱ onlyȱasȱaȱlastȱresort.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Add the new node to the list. */ newnode->fwd = next; this->fwd = newnode; newnode->bwd = this != rootp ? this : NULL; ( next != NULL ? next : rootp )->bwd = newnode; ȱ Programȱ12.8ȱȱInsertȱfunctionȱusingȱconditionalȱexpressionsȱ ȱ ȱ ȱ ȱ ȱȱȱȱdll_ins5.cȱ Download at http://www.pin5i.com/ 12.4 Summary 345 ȱȱ 12.3.2 Other List Operations ȱ Asȱ withȱ singlyȱ linkedȱ lists,ȱ moreȱ operationsȱ areȱ neededȱ forȱ doublyȱ linkedȱ lists.ȱ Theȱ exercisesȱwillȱgiveȱyouȱpracticeȱinȱwritingȱthem.ȱ ȱ ȱ ȱ 12.4 Summary ȱ Aȱsinglyȱlinkedȱlistȱisȱaȱdataȱstructureȱthatȱstoresȱvaluesȱusingȱpointers.ȱEachȱnodeȱinȱ theȱ listȱ containsȱ aȱ fieldȱ whichȱ pointsȱ toȱ theȱ nextȱ node.ȱ Aȱ separateȱ pointer,ȱ calledȱ theȱ root,ȱpointsȱtoȱtheȱfirstȱnode.ȱWhenȱtheȱnodesȱareȱdynamicallyȱallocated,ȱtheyȱmayȱbeȱ scatteredȱ throughoutȱ memory.ȱ However,ȱ theȱ listȱ isȱ traversedȱ byȱ followingȱ theȱ pointers,ȱ soȱ theȱ physicalȱ arrangementȱ ofȱ theȱ nodesȱ isȱ irrelevant.ȱ ȱ Aȱ singlyȱ linkedȱ listȱ canȱonlyȱbeȱtraversedȱinȱoneȱdirection.ȱ Toȱinsertȱaȱnewȱvalueȱintoȱanȱordered,ȱsinglyȱlinkedȱlist,ȱyouȱmustȱfirstȱfindȱtheȱ properȱpositionȱinȱtheȱlist.ȱȱNewȱvaluesȱmayȱbeȱinsertedȱintoȱunorderedȱlistsȱanywhere.ȱȱ Thereȱ areȱ twoȱ stepsȱ toȱ linkȱ aȱ newȱ nodeȱ intoȱ theȱ list.ȱ First,ȱ theȱ newȱ nodeȇsȱ linkȱ fieldȱ mustȱbeȱsetȱtoȱpointȱtoȱwhatȱwillȱbeȱtheȱnextȱnode.ȱSecond,ȱtheȱpreviousȱlinkȱfieldȱmustȱ beȱchangedȱtoȱpointȱtoȱtheȱnewȱnode.ȱȱInȱmanyȱotherȱlanguages,ȱanȱinsertionȱfunctionȱ wouldȱ saveȱ aȱ pointerȱ toȱ theȱ previousȱ nodeȱ toȱ accomplishȱ theȱ secondȱ step.ȱ However,ȱ thisȱtechniqueȱmakesȱinsertingȱatȱtheȱbeginningȱofȱtheȱlistȱaȱspecialȱcase.ȱInȱC,ȱyouȱcanȱ eliminateȱ theȱ specialȱ caseȱ byȱ savingȱ aȱ pointerȱ toȱ theȱ linkȱ fieldȱ thatȱ mustȱ beȱ changedȱ insteadȱofȱaȱpointerȱtoȱtheȱpreviousȱnode.ȱ Eachȱnodeȱinȱaȱdoublyȱlinkedȱlistȱcontainsȱtwoȱlinkȱfields:ȱoneȱpointsȱtoȱtheȱnextȱ nodeȱinȱtheȱlist,ȱandȱtheȱotherȱpointsȱtoȱtheȱpreviousȱnode.ȱTwoȱrootȱpointersȱareȱusedȱ toȱpointȱtoȱtheȱfirstȱandȱtheȱlastȱnodesȱinȱtheȱlist.ȱThus,ȱtraversalsȱofȱdoublyȱlinkedȱlistsȱ mayȱbeginȱfromȱeitherȱendȱofȱtheȱlistȱandȱmayȱproceedȱinȱeitherȱdirection.ȱToȱinsertȱaȱ newȱ nodeȱ intoȱ aȱ doublyȱ linkedȱ list,ȱ fourȱ linksȱ mustȱ beȱ changed.ȱ Theȱ newȱ nodeȇsȱ forwardȱandȱbackwardȱlinksȱmustȱbeȱset,ȱandȱtheȱpreviousȱnodeȇsȱforwardȱpointerȱandȱ theȱnextȱnodeȇsȱbackwardȱpointerȱmustȱbothȱbeȱchangedȱtoȱpointȱtoȱtheȱnewȱnode.ȱ Statementȱ factoringȱ isȱ aȱ techniqueȱ thatȱ simplifiesȱ aȱ programȱ byȱ removingȱ redundantȱ statementsȱ fromȱ it.ȱ Ifȱ theȱ ȈthenȈȱ andȱ theȱ ȈelseȈȱ clausesȱ ofȱ anȱ ifȱ endȱ withȱ identicalȱ sequencesȱ ofȱ statements,ȱ theyȱ canȱ beȱ replacedȱ byȱ aȱ singleȱ copyȱ ofȱ theȱ sequenceȱafterȱtheȱ if.ȱȱIdenticalȱsequencesȱofȱstatementsȱcanȱalsoȱbeȱfactoredȱfromȱtheȱ beginningȱofȱanȱ ifȱstatementȱunlessȱtheirȱexecutionȱchangesȱtheȱtestȱperformedȱbyȱtheȱ if.ȱIfȱdifferentȱstatementsȱactuallyȱperformȱtheȱsameȱwork,ȱyouȱmayȱbeȱableȱtoȱrewriteȱ themȱ identically.ȱ Youȱ mayȱ thenȱ beȱ ableȱ toȱ applyȱ statementȱ factoringȱ toȱ simplifyȱ theȱ program.ȱ Download at http://www.pin5i.com/ 346ȱ Chapter 12 Using Structures and Pointersȱ 12.5 Summary of Cautions ȱ 1. Fallingȱoffȱtheȱendȱofȱaȱlinkedȱlistȱ(pageȱ327).ȱ 2. Beȱ especiallyȱ carefulȱ withȱ pointers,ȱ becauseȱ Cȱ doesȱ notȱ provideȱ aȱ safetyȱ netȱ forȱ theirȱuseȱ(pageȱ333).ȱ 3. Factoringȱaȱstatementȱoutȱofȱanȱifȱthatȱchangesȱtheȱresultȱofȱtheȱtestȱ(pageȱ340).ȱ ȱ ȱ ȱ 12.6 Summary of Programming Tips ȱ 1. Eliminatingȱspecialȱcasesȱmakesȱcodeȱeasierȱtoȱmaintainȱ(pageȱ333).ȱ 2. Eliminateȱduplicateȱstatementsȱfromȱifȱstatementsȱbyȱfactoringȱthemȱ(pageȱ339).ȱ 3. Doȱnotȱjudgeȱtheȱqualityȱofȱcodeȱsolelyȱbyȱitsȱsizeȱ(pageȱ344).ȱ ȱ ȱ ȱ 12.7 Questions ȱ 1. CanȱProgramȱ12.3ȱbeȱwrittenȱwithoutȱusingȱaȱ currentȱvariable?ȱIfȱso,ȱcompareȱtheȱ resultingȱfunctionȱtoȱtheȱoriginal.ȱ 2. Someȱ dataȱ structuresȱ textbooksȱ suggestȱ usingȱ aȱ Ȉheaderȱ nodeȈȱ inȱ aȱ singlyȱ linkedȱ list.ȱ Thisȱ dummyȱ nodeȱ isȱ alwaysȱ theȱ firstȱ elementȱ inȱ theȱ listȱ andȱ eliminatesȱ theȱ specialȱcaseȱcodeȱforȱinsertingȱatȱtheȱbeginningȱofȱtheȱlist.ȱDiscussȱtheȱprosȱandȱconsȱ ofȱthisȱtechnique.ȱ 3. Whereȱ wouldȱ theȱ insertionȱ functionȱ inȱ Programȱ 12.3ȱ putȱ aȱ nodeȱ withȱ aȱ duplicateȱ value?ȱWhatȱwouldȱbeȱtheȱeffectȱofȱchangingȱtheȱcomparisonȱfromȱ<ȱtoȱ<=?ȱ 4. Discussȱ techniquesȱ forȱ omittingȱ theȱ valueȱ fieldȱ fromȱ theȱ rootȱ nodeȱ ofȱ aȱ doublyȱ linkedȱlist.ȱ 5. Whatȱwouldȱbeȱtheȱresultȱifȱtheȱcallȱtoȱ mallocȱinȱProgramȱ12.7ȱwereȱperformedȱatȱ theȱbeginningȱofȱtheȱfunction?ȱ 6. Isȱitȱpossibleȱtoȱsortȱtheȱnodesȱinȱanȱunordered,ȱsinglyȱlinkedȱlist?ȱ 7. Aȱconcordanceȱlistȱisȱanȱalphabeticȱlistȱofȱtheȱwordsȱthatȱappearȱinȱaȱbookȱorȱarticle.ȱ Youȱcanȱimplementȱaȱconcordanceȱlistȱusingȱanȱordered,ȱsinglyȱlinkedȱlistȱofȱstringsȱ withȱ anȱ insertionȱ functionȱ thatȱ doesȱ notȱ addȱ duplicateȱ wordsȱ toȱ theȱ list.ȱ Theȱ problemȱ withȱ thisȱ implementationȱ isȱ thatȱ theȱ timeȱ itȱ takesȱ toȱ searchȱ theȱ listȱ increasesȱasȱtheȱlistȱgrowsȱinȱsize.ȱ ȱ Download at http://www.pin5i.com/ 12.8 Programming Exercises ȇaȇ 347 ȇbȇ listȱ 15 (etc.) (etc.) ȈaȈ ȈbagȈ ȈanȈ ȈbeȈ (etc.) ȱ ȱ Figureȱ12.1ȱȱAȱconcordanceȱlistȱ ȱ ȱ Figureȱ12.1ȱillustratesȱanȱalternativeȱdataȱstructureȱforȱstoringȱtheȱconcordanceȱ list.ȱ Theȱ ideaȱ isȱ toȱ breakȱ theȱ largeȱ listȱ intoȱ 26ȱ smallerȱ lists—oneȱ listȱ ofȱ wordsȱ forȱ eachȱ letterȱ ofȱ theȱ alphabet.ȱ Eachȱ ofȱ theȱ nodesȱ inȱ theȱ primaryȱ listȱ containsȱ aȱ letterȱ andȱpointsȱtoȱanȱordered,ȱsinglyȱlinkedȱlistȱofȱwordsȱ(storedȱasȱstrings)ȱthatȱbeginȱ withȱthisȱletter.ȱ Howȱ doesȱtheȱ timeȱ toȱsearchȱthisȱstructureȱforȱaȱ specificȱwordȱcompareȱtoȱ theȱ timeȱtoȱsearchȱanȱordered,ȱsinglyȱlinkedȱlistȱcontainingȱallȱofȱtheȱwords?ȱ ȱ ȱ ȱ 12.8 Programming Exercises ȱ 1. Writeȱaȱfunctionȱthatȱcountsȱtheȱnumber,ȱofȱnodesȱinȱaȱsinglyȱlinkedȱlist.ȱItȱshouldȱ takeȱ aȱ pointerȱ toȱ theȱ firstȱ nodeȱ inȱ theȱ listȱ asȱ itsȱ onlyȱ argument.ȱ Whatȱ mustȱ you Download at http://www.pin5i.com/ 348ȱ Chapter 12 Using Structures and Pointersȱ knowȱinȱorderȱtoȱwriteȱthisȱfunction?ȱWhatȱotherȱjobsȱcanȱthisȱfunctionȱperform?ȱ 2. Writeȱaȱfunctionȱtoȱlocateȱaȱparticularȱvalueȱinȱanȱunordered,ȱsinglyȱlinkedȱlist,ȱandȱ returnȱaȱpointerȱtoȱthatȱnode.ȱYouȱmayȱassumeȱthatȱtheȱnodeȱstructureȱisȱdefinedȱinȱ theȱfileȱsingly_linked_list_node.h.ȱ Areȱ anyȱ changesȱ neededȱ inȱ orderȱ toȱ makeȱ theȱ functionȱ workȱ onȱ anȱ ordered,ȱ singlyȱlinkedȱlist?ȱ 3. RewriteȱProgramȱ12.7,ȱ dll_insert,ȱsoȱthatȱtheȱheadȱandȱtailȱpointersȱareȱpassedȱinȱ asȱseparateȱpointersȱratherȱthanȱasȱpartȱofȱaȱrootȱnode.ȱWhatȱeffectȱdoesȱthisȱchangeȱ haveȱonȱtheȱlogicȱofȱtheȱfunction?ȱ 4. Writeȱ aȱ functionȱ thatȱ reversesȱ theȱ orderȱ ofȱ theȱ nodesȱ inȱ aȱ singlyȱ linkedȱ list.ȱ Theȱ functionȱshouldȱhaveȱtheȱfollowingȱprototype:ȱ ȱ struct NODE * sll_reverse( struct NODE *first ); ȱ Declareȱtheȱnodeȱstructureȱinȱtheȱfile singly_linked_list_node.h.ȱ Theȱargumentȱpointsȱtoȱtheȱfirstȱnodeȱinȱtheȱlist.ȱAfterȱtheȱlistȱisȱrearranged,ȱtheȱ functionȱreturnsȱaȱpointerȱtoȱtheȱnewȱheadȱofȱtheȱlist.ȱTheȱlinkȱfieldȱofȱtheȱlastȱnodeȱ inȱtheȱlistȱwillȱcontainȱNULL,ȱandȱinȱtheȱeventȱofȱanȱemptyȱlistȱ(first == NULL)ȱtheȱ functionȱshouldȱreturnȱNULL,ȱ 5. Writeȱaȱprogramȱ toȱ removeȱ aȱ nodeȱ fromȱ aȱsinglyȱlinkedȱlist.ȱ Theȱfunctionȱshouldȱ haveȱtheȱfollowingȱprototype:ȱ ȱ int sll_remove( struct NODE **rootp, struct NODE *node ); ȱ Youȱ mayȱ assumeȱ thatȱ theȱ nodeȱ structureȱ isȱ definedȱ inȱ theȱ fileȱ singly_Iinked_list_node.h.ȱ Theȱ firstȱ argumentȱ pointsȱ toȱ theȱ rootȱ pointerȱ ofȱ theȱ list,ȱandȱtheȱsecondȱpointsȱtoȱtheȱnodeȱthatȱisȱtoȱbeȱremoved.ȱTheȱfunctionȱreturnsȱ falseȱifȱtheȱlistȱdoesȱnotȱcontainȱtheȱindicatedȱnode,ȱotherwiseȱitȱremovesȱtheȱnodeȱ andȱreturnsȱtrue.ȱ Isȱthereȱanyȱadvantageȱinȱtakingȱaȱpointerȱtoȱtheȱnodeȱtoȱremoveȱasȱopposedȱtoȱ takingȱtheȱvalue?ȱ 6. Writeȱaȱprogramȱtoȱremoveȱaȱnodeȱfromȱaȱdoublyȱlinkedȱlist.ȱTheȱfunctionȱshouldȱ haveȱtheȱfollowingȱprototype:ȱ ȱ int dll_remove( struct NODE *rootp, struct NODE *node ); ȱ Youȱ mayȱ assumeȱ thatȱ theȱ nodeȱ structureȱ isȱ definedȱ inȱ theȱ fileȱ doubly_linked_list_node.h.ȱ Theȱ firstȱ argumentȱ pointsȱ toȱ aȱ nodeȱ containingȱ theȱ rootȱpointersȱforȱtheȱlistȱ(theȱsameȱasȱwithȱProgramȱ12.7),ȱandȱtheȱsecondȱpointsȱtoȱȱ Download at http://www.pin5i.com/ 12.8 Programming Exercises 349 ȱtheȱ nodeȱ thatȱ isȱ toȱ beȱ removed.ȱ Theȱ functionȱ returnsȱ falseȱ ifȱ theȱ listȱ doesȱ notȱ containȱtheȱindicatedȱnode,ȱotherwiseȱitȱremovesȱtheȱnodeȱandȱreturnsȱtrue.ȱ 7. Writeȱ aȱ functionȱ toȱ insertȱ aȱ newȱ wordȱ intoȱ theȱ concordanceȱ listȱ describedȱ inȱ Questionȱ7.ȱȱTheȱfunctionȱshouldȱtakeȱaȱpointerȱtoȱtheȱ listȱpointerȱandȱaȱstringȱasȱ itsȱarguments.ȱTheȱstringȱisȱassumedȱtoȱcontainȱaȱsingleȱword.ȱȱIfȱtheȱwordȱdoesȱnotȱ alreadyȱexistȱinȱtheȱlist,ȱitȱshouldȱbeȱcopiedȱintoȱdynamicallyȱallocatedȱmemoryȱandȱ thenȱinserted.ȱTheȱfunctionȱshouldȱreturnȱtrueȱifȱtheȱstringȱwasȱinserted;ȱandȱfalseȱifȱ theȱstringȱalreadyȱexistedȱinȱtheȱlist,ȱdidȱnotȱbeginȱwithȱaȱletter,ȱorȱifȱanythingȱelseȱ wentȱwrong.ȱ Theȱfunctionȱshouldȱmaintainȱtheȱprimaryȱlistȱinȱorderȱbyȱtheȱletterȱofȱtheȱnodeȱ andȱtheȱsecondaryȱlistsȱinȱorderȱbyȱtheȱwords.ȱ Download at http://www.pin5i.com/ 13 Advanced Pointers Topics Thisȱchapterȱisȱaȱcollectionȱofȱvariousȱtechniquesȱinvolvingȱpointers.ȱȱSomeȱofȱthemȱareȱ veryȱ useful,ȱ othersȱ areȱ ofȱ moreȱ academicȱ interest,ȱ andȱ aȱ fewȱ areȱ justȱ fun,ȱ butȱ allȱ areȱ goodȱillustrationsȱofȱvariousȱprinciplesȱinȱtheȱlanguage.ȱ ȱ ȱ ȱ 13.1 More Pointers to Pointers ȱ Weȱusedȱpointersȱtoȱpointersȱinȱtheȱlastȱchapterȱtoȱsimplifyȱtheȱfunctionȱthatȱinsertsȱaȱ newȱvalueȱintoȱaȱsinglyȱlinkedȱlist.ȱThereȱareȱmanyȱotherȱareasȱwhereȱhavingȱaȱpointerȱ toȱaȱpointerȱisȱalsoȱvaluable.ȱ Hereȱisȱaȱgeneralȱexample.ȱ ȱ int int int i; *pi; **ppi; ȱ Theseȱ declarationsȱ createȱ theȱ followingȱ variablesȱ inȱ memory.ȱ Ifȱ theseȱ areȱ automaticȱ variables,ȱweȱcannotȱmakeȱanyȱassumptionsȱaboutȱtheirȱinitialȱvalues.ȱ ȱ iȱ ȱ piȱ ȱ ppiȱ ?ȱ ȱ ?ȱ ȱ ?ȱ ȱ Givenȱthisȱinformation,ȱwhatȱisȱtheȱeffectȱofȱeachȱofȱtheseȱstatements?ȱ ȱ 1 printf( "%d\n", ppi ); 2 printf( "%d\n", &ppi ); 3 *ppi = 5; Download at http://www.pin5i.com/ 352ȱ Chapter 13 Advanced Pointer Topicsȱ 1 Ifȱppiȱisȱanȱautomaticȱvariable,ȱitȱisȱuninitializedȱandȱaȱrandomȱvalueȱisȱprinted.ȱIfȱitȱ isȱaȱstaticȱvariable,ȱzeroȱisȱprinted.ȱ 2 Thisȱstatementȱprints,ȱasȱaȱdecimalȱinteger,ȱtheȱaddressȱwhereȱ ppiȱisȱstored.ȱȱThisȱ valueȱisȱnotȱveryȱuseful.ȱ 3 Theȱresultȱofȱthisȱstatementȱisȱunpredictable.ȱIndirectionȱshouldȱnotȱbeȱperformedȱ onȱppiȱbecauseȱitȱisȱnotȱyetȱinitialized.ȱ ȱ Theȱnextȱtwoȱstatementsȱareȱmoreȱuseful.ȱ ȱ ppi = &pli; ȱ Thisȱ statementȱ initializesȱ ppiȱ toȱ pointȱ toȱ theȱ variableȱ pi.ȱ Weȱ canȱ nowȱ safelyȱ applyȱ indirectionȱtoȱppi.ȱ ȱ *ppi = &i; ȱ Thisȱ statementȱ initializesȱ piȱ (whichȱ isȱ accessedȱ indirectlyȱ throughȱ ppi)ȱ toȱ pointȱ toȱ i.ȱ Afterȱtheseȱlastȱtwoȱstatements,ȱtheȱvariablesȱlookȱlikeȱthis:ȱ ȱ iȱ ȱ piȱ ȱ ppiȱ ?ȱ ȱ ȱ ȱ ȱ ȱ Now,ȱeachȱofȱtheȱfollowingȱstatementsȱhasȱtheȱsameȱeffect:ȱ ȱ i = 'a'; *pi = 'a'; **ppi = 'a'; ȱ Whyȱ wouldȱ anyoneȱ everȱ useȱ theȱ moreȱ complicatedȱ versionsȱ withȱ indirectionȱ ifȱ aȱ simpleȱ assignmentȱ toȱ iȱ doesȱ theȱ job?ȱ Becauseȱ theȱ simpleȱ assignmentȱ isȱ notȱ alwaysȱ possible,ȱsuchȱasȱinȱtheȱlinkedȱlistȱinsertion.ȱWeȱcouldȱnotȱuseȱaȱsimpleȱassignmentȱinȱ thatȱ functionȱ becauseȱ theȱ variableȱ nameȱ wasȱ notȱ knownȱ withinȱ theȱ scopeȱ ofȱ theȱ function.ȱȱAllȱtheȱfunctionȱhadȱwasȱaȱpointerȱtoȱtheȱlocationȱthatȱneededȱtoȱbeȱchanged,ȱ soȱindirectionȱwasȱusedȱonȱtheȱpointerȱtoȱaccessȱtheȱdesiredȱvariable.ȱ Inȱtheȱpreviousȱexample,ȱtheȱvariableȱ iȱisȱanȱinteger,ȱandȱ piȱisȱaȱpointerȱtoȱanȱ integer.ȱButȱ ppiȱisȱpointingȱatȱ pi,ȱsoȱitȱisȱaȱpointerȱtoȱaȱpointerȱtoȱanȱinteger.ȱSupposeȱ weȱwantedȱanotherȱvariable,ȱoneȱthatȱwouldȱpointȱtoȱppi.ȱItsȱtype,ȱofȱcourse,ȱwouldȱbeȱ Ȉpointerȱtoȱaȱpointerȱtoȱaȱpointerȱtoȱanȱinteger,Ȉȱandȱitȱwouldȱbeȱdeclaredȱinȱthisȱway:ȱ ȱ int ***pppi; Download at http://www.pin5i.com/ 13.2 Advanced Declarations TIP 353 Theȱ moreȱlevelsȱ ofȱindirection,ȱtheȱlessȱoftenȱ youȱwillȱ needȱtoȱ useȱit.ȱ Butȱonceȱ youȱ trulyȱ understandȱ indirection,ȱ itȱ isȱ easyȱ toȱ applyȱ asȱ manyȱ levelsȱ ofȱ indirectionȱ asȱ youȱneedȱforȱanyȱsituation.ȱ ȱ Useȱonlyȱasȱmanyȱlevelsȱofȱindirectionȱasȱyouȱreallyȱneed.ȱOtherwise,ȱyourȱprogramsȱ willȱendȱupȱbeingȱlarger,ȱslower,ȱandȱharderȱtoȱmaintain.ȱ ȱ ȱ ȱ 13.2 Advanced Declarations ȱ Beforeȱusingȱmoreȱadvancedȱpointerȱtypes,ȱweȱmustȱseeȱhowȱtheyȱareȱdeclared.ȱEarlierȱ chaptersȱ introducedȱ theȱ ideaȱ ofȱ aȱ declarationȱ expressionȱ andȱ howȱ variablesȱ inȱ Cȱ areȱ declaredȱ byȱ inference.ȱ Weȱ sawȱ someȱ examplesȱ ofȱ declarationȱ byȱ inferenceȱ whenȱ weȱ declaredȱ pointersȱ toȱ arraysȱ inȱ Chapterȱ 8.ȱ Letȇsȱ exploreȱ thisȱ topicȱ byȱ lookingȱ atȱ aȱ sequenceȱofȱincreasinglyȱcomplexȱdeclarations.ȱ Weȇllȱstartȱwithȱsomeȱeasyȱones.ȱ ȱ int int f; *f; /* an integer */ /* a pointer to an integer */ ȱ Rememberȱhowȱtheȱsecondȱdeclarationȱworks,ȱthough;ȱitȱdeclaresȱtheȱexpressionȱ *fȱ toȱ beȱ anȱ integer.ȱ Fromȱ thisȱ factȱ youȱ mustȱ deduceȱ thatȱ fȱ isȱ aȱ pointerȱ toȱ anȱ integer.ȱ ThisȱinterpretationȱofȱCȱdeclarationsȱisȱvalidatedȱbyȱtheȱdeclarationȱ ȱ int* f, g; ȱ whichȱdoesȱnotȱdeclareȱtwoȱpointers.ȱDespiteȱtheȱspacing,ȱtheȱstarȱisȱassociatedȱwithȱf,ȱ andȱonlyȱfȱisȱaȱpointer,ȱgȱisȱanȱordinaryȱinteger.ȱ Hereȱisȱanotherȱoneȱyouȱhaveȱseenȱbefore:ȱ ȱ int f(); ȱ Itȱ declaresȱ fȱ toȱ beȱ aȱ functionȱ thatȱ returnsȱ anȱ integer.ȱ Theȱ oldȬstyleȱ declarationȱ saysȱ nothingȱaboutȱtheȱfunctionȇsȱparameters.ȱItȱonlyȱdeclaresȱtheȱtypeȱofȱvalueȱthatȱ fȱwillȱ return.ȱ Iȱ willȱ useȱ thisȱ styleȱ forȱ nowȱ toȱ keepȱ theȱ examplesȱ simplerȱ andȱ returnȱ toȱ fullȱ prototypesȱlater.ȱ Hereȇsȱaȱnewȱone:ȱ ȱ int *f(); ȱ Toȱfigureȱthisȱoneȱout,ȱyouȱmustȱdetermineȱhowȱtheȱexpressionȱ *f()ȱisȱevaluated.ȱTheȱ functionȱ callȱ operatorȱ ()ȱ goesȱ firstȱ becauseȱ itsȱ precedenceȱ isȱ higherȱ thanȱ thatȱ ofȱ indirection,ȱsoȱfȱisȱaȱfunctionȱthatȱreturnsȱaȱpointerȱtoȱanȱinteger.ȱ Download at http://www.pin5i.com/ 354ȱ Chapter 13 Advanced Pointer Topicsȱ Ifȱ Ȉdeclarationȱ byȱ inferenceȈȱ seemsȱ likeȱ aȱ nuisance,ȱ considerȱ thatȱ theȱ expressionsȱ usedȱ forȱ declaringȱ variablesȱ areȱ evaluatedȱ withȱ theȱ sameȱ rulesȱ usedȱ forȱ ordinaryȱexpressions.ȱYouȱdonȇtȱneedȱtoȱlearnȱaȱseparateȱsyntaxȱforȱdeclarations.ȱIfȱyouȱ canȱ evaluateȱ complexȱ expressions,ȱ youȱ canȱ alsoȱ figureȱ outȱ complexȱ declarationsȱ becauseȱtheyȱworkȱtheȱsameȱway.ȱ Theȱnextȱdeclarationȱisȱmoreȱinteresting.ȱ ȱ int (*f)(); ȱ Figuringȱ outȱ whatȱ theȱ parenthesesȱ meanȱ isȱ anȱ importantȱ stepȱ inȱ decipheringȱ thisȱ declaration.ȱThereȱareȱtwoȱsetsȱofȱparentheses,ȱandȱeachȱhasȱaȱdifferentȱmeaning.ȱTheȱ secondȱsetȱofȱparenthesesȱisȱtheȱfunctionȱcallȱoperator,ȱbutȱtheȱfirstȱsetȱisȱusedȱonlyȱforȱ grouping.ȱ Itȱ forcesȱ theȱ indirectionȱ toȱ beȱ appliedȱ beforeȱ theȱ functionȱ call,ȱ makingȱ fȱ aȱ pointerȱtoȱaȱfunctionȱthatȱreturnsȱanȱinteger.ȱ Aȱpointerȱtoȱaȱfunction?ȱYes,ȱeachȱfunctionȱinȱaȱprogramȱbeginsȱatȱsomeȱaddressȱ inȱ memory,ȱ soȱ itȱ isȱ possibleȱ forȱ aȱ variableȱ toȱ pointȱ toȱ thatȱ location.ȱ Theȱ initializationȱ andȱuseȱofȱpointersȱtoȱfunctionsȱisȱcoveredȱlaterȱinȱthisȱchapter.ȱ Theȱnextȱdeclarationȱshouldȱnowȱbeȱeasy:ȱ ȱ int *(*f)(); ȱ Itȱ isȱ theȱ sameȱ asȱ theȱ previousȱ exampleȱ exceptȱ thatȱ inȱ orderȱ toȱ getȱ anȱ integer,ȱ indirectionȱ isȱ appliedȱ toȱ theȱ valueȱ returnedȱ byȱ theȱ function.ȱ Hereȱ fȱ isȱ aȱ pointerȱ toȱ aȱ functionȱthatȱreturnsȱaȱpointerȱtoȱanȱinteger.ȱ Nowȱletȇsȱconsiderȱarrays,ȱtoo.ȱ ȱ int f[]; ȱ indicatesȱ thatȱ fȱ isȱ anȱ arrayȱ ofȱ integers.ȱ Theȱ sizeȱ hasȱ beenȱ omittedȱ forȱ nowȱ becauseȱ weȇreȱnotȱconcernedȱwithȱtheȱarrayȇsȱsize,ȱonlyȱitsȱtype. 43 Howȱaboutȱthisȱone?ȱ ȱ int *f[]; ȱ Again,ȱthereȱareȱtwoȱoperators.ȱTheȱsubscriptȱhasȱtheȱhigherȱprecedence,ȱsoȱ fȱisȱnowȱ anȱarrayȱofȱpointersȱtoȱintegers.ȱ Theȱnextȱexampleȱisȱaȱtrickȱquestion,ȱbutȱtryȱtoȱfigureȱitȱoutȱanyway.ȱ ȱ int f()[]; ȱ fȱ appearsȱ toȱ beȱ aȱ functionȱ thatȱ returnsȱ anȱ arrayȱ ofȱ integers.ȱ Theȱ trickȱ isȱ thatȱ itȱ isȱ illegal—functionsȱcanȱonlyȱreturnȱscalars,ȱnotȱarrays.ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ 43 ȱEvenȱwithoutȱaȱsize,ȱtheseȱdeclarationsȱareȱstillȱlegalȱifȱtheyȱareȱexternalȱorȱareȱfunction,ȱparameters.ȱ Download at http://www.pin5i.com/ 13.2 Advanced Declarations 355 Hereȱisȱanotherȱoneȱthatȱwillȱrequireȱsomeȱthought:ȱ ȱ int f[](); ȱ Nowȱfȱappearsȱtoȱbeȱanȱarrayȱofȱfunctionsȱthatȱreturnȱintegers.ȱThisȱdeclarationȱisȱalsoȱ illegalȱbecauseȱarrayȱelementsȱmustȱallȱbeȱtheȱsameȱsize,ȱbutȱitȱisȱquiteȱreasonableȱforȱ differentȱfunctionsȱcoȱbeȱdifferent,ȱsizes.ȱ Theȱnextȱdeclarationȱisȱlegal,ȱthough:ȱ ȱ int (*f[])(); ȱ Youȱmustȱfirstȱfindȱallȱofȱtheȱoperatorsȱandȱthenȱapplyȱthemȱinȱtheȱcorrectȱorder.ȱOnceȱ again,ȱ thereȱ areȱ twoȱ setsȱ ofȱ parenthesesȱ withȱ differentȱ meanings.ȱ Theȱ parenthesizedȱ expressionȱ *f[]ȱ isȱ evaluatedȱ first,ȱ soȱ fȱ isȱ anȱ arrayȱ ofȱ pointersȱ toȱ something.ȱ Theȱ trailingȱ ()ȱisȱtheȱfunctionȱcallȱoperator,ȱsoȱ fȱmustȱbeȱanȱarrayȱofȱpointersȱtoȱfunctionsȱ thatȱreturnȱintegers.ȱ Ifȱyouȱgotȱthatȱlastȱoneȱright,ȱthenȱthisȱoneȱshouldȱbeȱeasy:ȱ ȱ int *(*f[])(); ȱ Theȱonlyȱchangeȱisȱoneȱfinalȱindirection,ȱsoȱthisȱdeclarationȱcreatesȱanȱarrayȱofȱpointersȱ toȱfunctionsȱthatȱreturnȱpointersȱtoȱintegers.ȱ Upȱ toȱ now,ȱ Iȇveȱ usedȱ oldȬstyleȱ declarationsȱ toȱ keepȱ theȱ examplesȱ simple.ȱ Butȱ ANSIȱCȱletsȱusȱuseȱfullȱfunctionȱprototypesȱtoȱmakeȱtheȱdeclarationȱmoreȱspecific.ȱForȱ example:ȱ ȱ int int TIP (*f)( int, float ); *(*g[])( int, float ); ȱ declaresȱ fȱ toȱ beȱ aȱ pointerȱ toȱ aȱ functionȱ thatȱ takesȱ twoȱ arguments,ȱ anȱ integerȱ andȱ aȱ float,ȱ andȱ returnsȱ anȱ integer.ȱ ȱ gȱ isȱ anȱ arrayȱ ofȱ pointersȱ toȱ functionsȱ thatȱ takeȱ twoȱ arguments,ȱ anȱ integerȱ andȱ aȱ floatȱ andȱ returnȱ aȱ pointerȱ toȱ anȱ integer.ȱ Despiteȱ theȱ increasedȱ complexityȱ inȱ theȱ declaration,ȱ theȱ prototypeȱ formȱ isȱ greatlyȱ preferredȱ becauseȱofȱtheȱadditionalȱinformationȱitȱgivesȱtheȱcompiler.ȱ ȱ Ifȱ youȱ haveȱ aȱ UNIXȱ systemȱ andȱ haveȱ accessȱ toȱ theȱ Internet,ȱ youȱ canȱ getȱ cdec1,ȱ aȱ programȱthatȱconvertsȱbetweenȱCȱdeclarationsȱandȱEnglish.ȱItȱcanȱexplainȱanȱexistingȱ Cȱdeclaration:ȱ ȱ cdec1> explain int (*(*f)())[10]; declare f as pointer to function returning pointer to array 10 of int ȱ orȱgiveȱyouȱtheȱsyntaxȱforȱaȱdeclaration:ȱ Download at http://www.pin5i.com/ 356ȱ Chapter 13 Advanced Pointer Topicsȱ cdec1> declare x as pointer to array 10 of pointer to function returning int int (*(*x)[10])() ȱ Theȱ sourceȱ codeȱ forȱ cdec1ȱ canȱ beȱ foundȱ inȱ Volumeȱ 14ȱ ofȱ theȱ archivesȱ forȱ theȱ comp.sources.unixȱnewsgroup.ȱ ȱ ȱ ȱ 13.3 Pointers to Functions CAUTION! ȱ Youȱwillȱnotȱuseȱpointersȱtoȱfunctionsȱeveryȱday.ȱHowever,ȱtheyȱhaveȱtheirȱuses,ȱandȱ theȱtwoȱmostȱcommonȱareȱjumpȱtablesȱandȱpassingȱaȱfunctionȱpointerȱasȱanȱargumentȱ inȱaȱfunctionȱcall.ȱWeȇllȱexploreȱbothȱofȱtheseȱtechniquesȱthisȱsection.ȱFirst,ȱthough,ȱitȱisȱ importantȱtoȱpointȱoutȱaȱcommonȱerror.ȱ ȱ Simplyȱ declaringȱ aȱ pointerȱ toȱ aȱ functionȱ doesȱ notȱ makeȱ itȱ usable.ȱ Likeȱ anyȱ otherȱ pointer,ȱ aȱ pointerȱ toȱ aȱ functionȱ mustȱ beȱ initializedȱ toȱ pointȱ toȱ somethingȱ beforeȱ indirectionȱcanȱbeȱperformedȱonȱit.ȱTheȱfollowingȱcodeȱfragmentȱillustratesȱoneȱwayȱtoȱ initializeȱaȱpointerȱtoȱaȱfunction.ȱ ȱ int int f( int ); (*pf)( int ) = &f; ȱ Theȱsecondȱdeclarationȱcreatesȱ pf,ȱaȱpointerȱtoȱaȱfunction,ȱandȱinitializesȱitȱtoȱpointȱtoȱ theȱ functionȱ f.ȱ Theȱ initializationȱ canȱ alsoȱ beȱ accomplishedȱ withȱ anȱ assignmentȱ statement.ȱ Itȱ isȱ importantȱ toȱ haveȱ aȱ prototypeȱ forȱ fȱ priorȱ toȱ theȱ initialization,ȱ forȱ withoutȱitȱ theȱcompilerȱwouldȱbeȱunableȱtoȱcheckȱwhetherȱtheȱtypeȱofȱ fȱagreedȱwithȱ thatȱofȱpf.ȱ Theȱ ampersandȱ inȱ theȱ initializationȱ isȱ optional,ȱ becauseȱ theȱ compilerȱ alwaysȱ convertsȱ functionȱ namesȱ toȱ functionȱ pointersȱ whereverȱ theyȱ areȱ used.ȱ Theȱ ampersandȱ doesȱexplicitlyȱwhatȱtheȱcompilerȱwouldȱhaveȱdoneȱimplicitlyȱanyway.ȱ Afterȱtheȱpointerȱhasȱbeenȱdeclaredȱandȱinitialized,ȱthereȱareȱthreeȱwaysȱtoȱcallȱ theȱfunction:ȱ ȱ int ans; ans = f( 25 ); ans = (*pf)( 25 ); ans = pf( 25 ); ȱ Theȱ firstȱ statementȱ simplyȱ callsȱ theȱ functionȱ fȱ byȱ name,ȱ thoughȱ itsȱ evaluationȱ isȱ probablyȱnotȱwhatȱyouȱexpected.ȱTheȱfunctionȱnameȱfȱisȱfirstȱconvertedȱtoȱaȱpointerȱtoȱ theȱ function;ȱ theȱ pointerȱ specifiesȱ whereȱ theȱ functionȱ isȱ located.ȱ Theȱ functionȱ call Download at http://www.pin5i.com/ 13.3 Pointers to Functions 357 operatorȱthenȱinvokesȱtheȱfunctionȱbyȱexecutingȱtheȱcodeȱbeginningȱatȱthisȱaddress.ȱ Theȱ secondȱ statementȱ appliesȱ indirectionȱ toȱ pf,ȱ whichȱ convertsȱ theȱ functionȱ pointerȱ toȱ aȱ functionȱ name.ȱ Thisȱ conversionȱ isȱ notȱ reallyȱ necessary,ȱ becauseȱ theȱ compilerȱ convertsȱ itȱ backȱ toȱ aȱ pointerȱ beforeȱ applyingȱ theȱ functionȱ callȱ operator.ȱ Nevertheless,ȱthisȱstatementȱhasȱexactlyȱtheȱsameȱeffectȱasȱtheȱfirstȱone.ȱ Theȱ thirdȱ statementȱ hasȱ theȱ sameȱ effectȱ asȱ theȱ firstȱ two.ȱ Indirectionȱ isȱ notȱ needed,ȱ becauseȱ theȱ compilerȱ wantsȱ aȱ pointerȱ toȱ theȱ functionȱ anyway.ȱ Thisȱ exampleȱ showsȱhowȱfunctionȱpointersȱareȱusuallyȱused.ȱ Whenȱ wouldȱ anyoneȱ everȱ wantȱ toȱ useȱ aȱ pointerȱ toȱ aȱ function?ȱ Asȱ mentionedȱ earlier,ȱ theȱ twoȱ mostȱ commonȱ usesȱ ofȱ pointersȱ toȱ functionsȱ areȱ passingȱ aȱ functionȱ pointerȱasȱanȱargumentȱinȱaȱfunctionȱcallȱandȱjumpȱtables.ȱLetȇsȱlookȱatȱanȱapplicationȱ ofȱeach.ȱ ȱ ȱ ȱ 13.3.1 Callback Functions ȱ Hereȱisȱaȱsimpleȱfunctionȱthatȱlocatesȱaȱvalueȱinȱaȱsinglyȱlinkedȱlist.ȱItsȱargumentsȱareȱaȱ pointerȱtoȱtheȱfirstȱnodeȱinȱtheȱlistȱandȱtheȱvalueȱtoȱlocate.ȱ ȱ Node* search_list( Node *node, int const value ) { while( node != NULL ){ if( node->value == value ) break; node = node->link; } return node; } ȱ Thisȱ functionȱ looksȱ simpleȱ enough,ȱ butȱ itȱ worksȱ onlyȱ withȱ linkedȱ listsȱ whoseȱ valuesȱ areȱintegers.ȱIfȱyouȱalsoȱhadȱaȱlinkedȱlistȱofȱstrings,ȱyouȱwouldȱneedȱtoȱwriteȱaȱdifferentȱ function,ȱ identicalȱ inȱ everyȱ respectȱ toȱ thisȱ oneȱ exceptȱ forȱ theȱ typeȱ ofȱ theȱ parameterȱ valueȱandȱtheȱmannerȱinȱwhichȱtheȱnodeȱvaluesȱareȱcompared.ȱ ȱ Aȱ moreȱ generalȱ approachȱ isȱ toȱ makeȱ theȱ searchingȱ functionȱ typelessȱ soȱ thatȱ itȱ willȱworkȱonȱlistsȱwithȱvaluesȱofȱanyȱtype.ȱȱWeȱmustȱreviseȱtwoȱaspectsȱofȱtheȱfunctionȱ toȱ makeȱ itȱ typeless.ȱ First,ȱ weȱ mustȱ changeȱ howȱ theȱ comparisonȱ isȱ performedȱ soȱ thatȱ theȱfunctionȱcanȱcompareȱvaluesȱofȱanyȱtype.ȱThisȱgoalȱsoundsȱimpossible.ȱIfȱyouȱwriteȱ statementsȱ toȱ compareȱ integerȱ values,ȱ howȱ canȱ theyȱ possiblyȱ workȱ withȱ otherȱ typesȱ suchȱasȱstrings?ȱȱTheȱsolutionȱusesȱaȱpointerȱtoȱaȱfunction.ȱTheȱcallerȱwritesȱaȱfunctionȱ Download at http://www.pin5i.com/ 358ȱ TIP Chapter 13 Advanced Pointer Topicsȱ ȱtoȱ compareȱ twoȱ valuesȱ andȱ passesȱ aȱ pointerȱ toȱ itȱ asȱ anȱ argumentȱ toȱ theȱ searchȱ function.ȱTheȱsearchȱfunctionȱthenȱcallsȱtheȱcomparisonȱfunctionȱtoȱmakeȱcomparisons.ȱ Inȱthisȱway,ȱvaluesȱofȱanyȱtypeȱmayȱbeȱcompared.ȱ Theȱsecondȱaspectȱweȱmustȱchangeȱisȱtoȱpassȱaȱpointerȱtoȱtheȱvalueȱratherȱthanȱ theȱvalue.ȱTheȱfunctionȱwillȱreceiveȱthisȱargumentȱinȱaȱvoid*ȱparameter.ȱTheȱpointerȱtoȱ theȱ valueȱ isȱ thenȱ passedȱ toȱ theȱ comparisonȱ function.ȱ Thisȱ changeȱ alsoȱ enablesȱ stringȱ andȱ arrayȱ objectsȱ toȱ beȱ used.ȱ Stringȱ andȱ arraysȱ cannotȱ beȱ passedȱ asȱ arguments,ȱ butȱ pointersȱtoȱthemȱcan.ȱ Functionsȱ usedȱ inȱ thisȱ mannerȱ areȱ callbackȱ functionsȱ becauseȱ theȱ userȱ passesȱ aȱ pointerȱ toȱ aȱ functionȱ toȱ someȱ otherȱ routine,ȱ whichȱ thenȱ Ȉcallsȱ backȈȱ toȱ theȱ userȇsȱ function.ȱYouȱcanȱuseȱtheȱtechniqueȱanyȱtimeȱyouȱareȱwritingȱaȱfunctionȱthatȱmustȱbeȱ ableȱtoȱperformȱdifferentȱtypesȱofȱworkȱatȱaȱgivenȱpointȱorȱperformȱworkȱthatȱcanȱbeȱ definedȱonlyȱbyȱtheȱfunctionȇsȱcaller.ȱManyȱwindowingȱsystemsȱuseȱcallbackȱfunctionsȱ toȱ connectȱ actions,ȱ suchȱ asȱ draggingȱ theȱ mouseȱ andȱ clickingȱ buttons,ȱ toȱ specificȱ functionsȱinȱtheȱuserȇsȱprogram.ȱ Weȱcannotȱwriteȱanȱaccurateȱprototypeȱforȱtheȱcallbackȱfunctionȱinȱthisȱcontextȱ becauseȱweȱdonȇtȱknowȱwhatȱtypeȱofȱvaluesȱareȱbeingȱcompared.ȱIndeed,ȱweȱwantȱtheȱ searchȱ functionȱ toȱ workȱ withȱ anyȱ typeȱ ofȱ value.ȱ Theȱ solutionȱ toȱ thisȱ dilemmaȱ isȱ toȱ declareȱtheȱargumentsȱasȱvoid *,ȱwhichȱmeansȱȈaȱpointerȱtoȱsomethingȱwhoseȱtypeȱweȱ doȱnotȱknow.Ȉȱ ȱ Beforeȱusingȱtheȱpointersȱinȱtheȱcomparisonȱfunction,ȱtheyȱmustȱbeȱcastȱtoȱtheȱcorrectȱ type.ȱBecauseȱaȱcastȱcircumventsȱtheȱusualȱtypeȱchecking,ȱbeȱextremelyȱcarefulȱthatȱtheȱ functionȱisȱcalledȱwithȱtheȱproperȱtypeȱofȱarguments.ȱ Inȱ thisȱ case,ȱ theȱ callbackȱ functionȱ comparesȱ twoȱ values.ȱ Theȱ searchȱ functionȱ passesȱpointersȱtoȱ theȱtwoȱvaluesȱtoȱ beȱ comparedȱandȱchecksȱtheȱreturnedȱvalue;ȱ forȱ example,ȱzeroȱforȱequalȱvaluesȱandȱnonzeroȱforȱunequalȱvalues.ȱTheȱsearchȱfunctionȱisȱ nowȱtypelessȱbecauseȱitȱdoesnȇtȱperformȱtheȱactualȱcomparison.ȱItȱisȱtrueȱthatȱtheȱcallerȱ mustȱnowȱwriteȱtheȱnecessaryȱcomparisonȱfunction,ȱbutȱdoingȱsoȱisȱeasyȱbecauseȱtheȱ callerȱ knowsȱ whatȱ typeȱ ofȱ valuesȱ areȱ containedȱ inȱ theȱ list.ȱ Andȱ ifȱ severalȱ listsȱ withȱ differentȱ typesȱ ofȱ valuesȱ areȱ used,ȱ writingȱ oneȱ comparisonȱ functionȱ forȱ eachȱ typeȱ allowsȱaȱsingleȱsearchȱfunctionȱtoȱoperateȱonȱallȱofȱtheȱlists.ȱ Programȱ13.1ȱisȱanȱimplementationȱofȱaȱtypelessȱsearchȱfunction.ȱNoteȱthatȱtheȱ thirdȱparameterȱtoȱtheȱfunctionȱisȱaȱpointerȱtoȱaȱfunction.ȱTheȱfullȱprototypeȱisȱusedȱtoȱ declareȱ thisȱparameter.ȱ Noteȱalsoȱthatȱ theȱ parameterȱ nodeȱisȱ notȱdeclaredȱ constȱ evenȱ thoughȱtheȱfunctionȱneverȱmodifiesȱanyȱofȱtheȱnodesȱtoȱwhichȱitȱpoints.ȱIfȱ nodeȱwereȱ declaredȱ constȱtheȱfunctionȱwouldȱhaveȱtoȱreturnȱaȱ constȱresult,ȱwhichȱwouldȱrestrictȱ theȱcallerȱfromȱmodifyingȱtheȱnodeȱthatȱwasȱlocated.ȱ Download at http://www.pin5i.com/ 13.3 Pointers to Functions 359 ȱ /* ** Function to search a linked list for a specific value. Arguments ** are a pointer to the first node in the list, a pointer to the ** value we're looking for, and a pointer to a function that compares ** values of the type stored on the list. */ #include <stdio.h> #include "node.h" Node * search_list( Node *node, void const *value, int (*compare)( void const *, void const * ) ) { while( node != NULL ){ if( compare( &node->value, value ) == 0 ) break; node = node->link; } return node; } ȱ Programȱ13.1ȱȱTypelessȱlinkedȱlistȱsearchȱȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱsearch.cȱ ȱ ȱ ȱ ȱ ȱ ȱ Pointersȱtoȱtheȱvalueȱargumentȱandȱ &node->valueȱareȱpassedȱtoȱtheȱcomparisonȱ function.ȱ Theȱ latterȱ isȱ theȱ valueȱ inȱ theȱ nodeȱ weȱ areȱ currentlyȱ examining.ȱ Iȱ choseȱ theȱ counterȬintuitiveȱconventionȱofȱhavingȱtheȱcomparisonȱfunctionȱreturnȱzeroȱforȱequalȱ operandsȱ inȱ orderȱ toȱ beȱ compatibleȱ withȱ theȱ specificationȱ forȱ comparisonȱ functionsȱ usedȱ byȱ severalȱ functionsȱ inȱ theȱ standardȱ library.ȱ Inȱ thisȱ specification,ȱ unequalȱ operandsȱ areȱ reportedȱ moreȱ explicitly—aȱ negativeȱ valueȱ indicatesȱ thatȱ theȱ firstȱ argumentȱwasȱlessȱthanȱtheȱsecond,ȱandȱaȱpositiveȱvalueȱindicatesȱthatȱitȱwasȱgreater.ȱ Toȱ searchȱ aȱ particularȱ linkedȱ list,ȱ theȱ userȱ wouldȱ writeȱ theȱ appropriateȱ comparisonȱ functionȱ andȱ passȱ pointersȱ toȱ itȱ andȱ toȱ theȱ desiredȱ value.ȱ Forȱ example,ȱ hereȱisȱaȱcomparisonȱfunctionȱforȱsearchingȱaȱlistȱofȱintegers.ȱ ȱ int compare_ints( void const *a, void const *b ) { if( *(int *)a == *(int *)b ) return 0; else return 1; } Download at http://www.pin5i.com/ Chapter 13 Advanced Pointer Topicsȱ 360ȱ Theȱfunctionȱwouldȱbeȱusedȱlikeȱthis:ȱ ȱ desired_node = search_list( root, &desired_value, compare_ints ); ȱ Noteȱtheȱcasts:ȱTheȱargumentsȱtoȱtheȱcomparisonȱfunctionȱmustȱbeȱdeclaredȱ void *ȱtoȱ matchȱ theȱ prototypeȱ ofȱ theȱ searchȱ function;ȱ theyȱ areȱ thenȱ castȱ toȱ int *ȱ inȱ orderȱ toȱ compareȱtheȱvaluesȱasȱintegers.ȱ Ifȱyouȱwishȱtoȱsearchȱaȱlistȱofȱstrings,ȱthisȱcodeȱwillȱdoȱtheȱjob:ȱ ȱ #include <string.h> ... desired_node = search_list( root, "desired_value", strcmp ); ȱ Itȱ happensȱ thatȱ theȱ libraryȱ functionȱ strcmpȱ doesȱ exactlyȱ theȱ comparisonȱ weȱ need,ȱ thoughȱsomeȱcompilersȱwillȱissueȱwarningsȱbecauseȱitsȱargumentsȱareȱdeclaredȱchar *ȱ ratherȱthanȱvoid *.ȱ ȱ ȱ ȱ 13.3.2 Jump Tables ȱ Jumpȱtablesȱareȱbestȱexplainedȱwithȱanȱexample.ȱTheȱfollowingȱcodeȱfragmentȱisȱfromȱ aȱ programȱ thatȱ implementsȱ aȱ pocketȱ calculator.ȱ Otherȱ partsȱ ofȱ theȱ programȱ haveȱ alreadyȱreadȱinȱtwoȱnumbersȱ(op1ȱandȱ op2)ȱandȱanȱoperatorȱ(oper).ȱThisȱcodeȱtestsȱtheȱ operatorȱtoȱdetermineȱwhichȱfunctionȱtoȱinvoke.ȱ ȱ switch( oper ){ case ADD: result = add( op1, op2 ); break; case SUB: result = sub( op1, op2 ); break; case MUL: result = mul( op1, op2 ); break; case DIV: result = div( op1, op2 ); break; ... Download at http://www.pin5i.com/ 13.3 Pointers to Functions 361 Forȱ aȱ fancyȱ calculatorȱ withȱ aȱ hundredȱ orȱ soȱ operators,ȱ thisȱ switchȱ statementȱ willȱ becomeȱextremelyȱlarge.ȱ Whyȱareȱfunctionsȱbeingȱcalledȱtoȱperformȱtheseȱoperations?ȱItȱisȱgoodȱdesignȱtoȱ separateȱ theȱ operationsȱ fromȱ theȱ codeȱ thatȱ choosesȱ amongȱ them.ȱ Theȱ moreȱ complexȱ operationsȱ willȱ certainlyȱ beȱ implementedȱ asȱ separateȱ functionsȱ becauseȱ ofȱ theirȱ size,ȱ butȱevenȱtheȱsimpleȱoperationsȱmayȱhaveȱsideȱeffects,ȱsuchȱasȱsavingȱaȱconstantȱvalueȱ forȱlaterȱoperations.ȱ Inȱ orderȱ toȱ useȱ aȱ switch,ȱ theȱ codesȱ thatȱ representȱ theȱ operatorsȱ mustȱ beȱ integers.ȱIfȱtheyȱareȱconsecutiveȱintegersȱstartingȱwithȱzero,ȱweȱcanȱuseȱaȱjumpȱtableȱtoȱ accomplishȱtheȱsameȱthing.ȱAȱjumpȱtableȱisȱjustȱanȱarrayȱofȱpointersȱtoȱfunctions.ȱ Thereȱ areȱ twoȱ stepsȱ inȱ creatingȱ aȱ jumpȱ table.ȱ First,ȱ anȱ arrayȱ ofȱ pointersȱ toȱ functionsȱisȱdeclaredȱandȱinitialized.ȱTheȱonlyȱtrickȱisȱtoȱmakeȱsureȱthatȱtheȱprototypesȱ forȱtheȱfunctionsȱappearȱbeforeȱtheȱarrayȱdeclaration.ȱ ȱ double double double double ... double add( sub( mul( div( double, double, double, double, double double double double ); ); ); ); (*oper_func[])( double, double ) = { add, sub, mul, div, ... }; ȱ Theȱproperȱorderȱforȱtheȱfunctionsȇȱnamesȱinȱtheȱinitializerȱlistȱisȱdeterminedȱbyȱ theȱ integerȱ codesȱ usedȱ toȱ representȱ eachȱ operatorȱ inȱ theȱ program.ȱ Thisȱ exampleȱ assumesȱthatȱADDȱisȱzero,ȱSUBȱisȱone,ȱMULȱisȱtwo,ȱandȱsoȱforth.ȱ Theȱsecondȱstepȱisȱtoȱreplaceȱtheȱentireȱswitchȱstatementȱwithȱthisȱone!ȱ ȱ result = oper_func[ oper ]( op1, op2 ); CAUTION! ȱ operȱselectsȱtheȱcorrectȱpointerȱfromȱtheȱarray,ȱandȱtheȱfunctionȱcallȱoperatorȱexecutesȱ it.ȱ ȱ AnȱoutȬofȬboundsȱsubscriptȱisȱjustȱasȱillegalȱonȱaȱjumpȱtableȱasȱitȱisȱonȱanyȱotherȱarray,ȱ butȱ itȱ isȱ muchȱ moreȱ difficultȱ toȱ diagnose.ȱ Thereȱ areȱ threeȱ placesȱ whereȱ theȱ programȱ mightȱterminateȱwhenȱthisȱerrorȱoccurs.ȱFirst,ȱifȱtheȱsubscriptȱvalueȱisȱfarȱenoughȱoutȱ ofȱbounds,ȱtheȱlocationȱthatȱitȱidentifiesȱmightȱbeȱoutsideȱofȱdieȱmemoryȱallocatedȱtoȱ theȱ program.ȱ Someȱ operatingȱ systemsȱ detectȱ thisȱ errorȱ andȱ abortȱ theȱ program,ȱ butȱ othersȱ doȱ not.ȱ Ifȱ theȱ programȱ isȱ terminated,ȱ theȱ faultȱ willȱ beȱ reportedȱ nearȱ theȱ jumpȱ tableȱstatement,ȱmakingȱtheȱproblemȱfairlyȱeasyȱtoȱdiagnosis.ȱ Ifȱ theȱ programȱ doesȱ notȱ abort,ȱ theȱ valueȱ identifiedȱ byȱ theȱ illegalȱ subscriptȱ isȱ fetched,ȱ andȱ theȱ processorȱ jumpsȱ toȱ thatȱ location.ȱ Thisȱ unpredictableȱ valueȱ mayȱ or Download at http://www.pin5i.com/ 362ȱ TIP Chapter 13 Advanced Pointer Topicsȱ ȱmayȱ notȱ representȱ aȱ validȱ addressȱ forȱ theȱ program.ȱ Ifȱ itȱ doesȱ notȱ theȱ programȱ mayȱ alsoȱ abort,ȱ butȱ theȱ addressȱ reportedȱ forȱ theȱ faultȱ isȱ essentiallyȱ aȱ randomȱ number,ȱ makingȱdebuggingȱmoreȱdifficult.ȱ Ifȱtheȱprogramȱhasnȇtȱfailedȱyet,ȱtheȱmachineȱwillȱbeginȱtoȱexecuteȱinstructionsȱ atȱ theȱ bogusȱ addressȱ obtainedȱ withȱ theȱ illegalȱ subscript,ȱ andȱ debuggingȱ theȱ errorȱ becomesȱ muchȱ harder.ȱ Ifȱ theȱ randomȱ addressȱ isȱ inȱ anȱ areaȱ inȱ memoryȱ thatȱ containsȱ data,ȱtheȱprogramȱusuallyȱabortsȱveryȱquicklyȱdueȱtoȱanȱillegalȱinstructionȱorȱanȱillegalȱ operandȱ addressȱ (althoughȱ dataȱ valuesȱ sometimesȱ representȱ validȱ instructions,ȱ theyȱ doȱnotȱoftenȱmakeȱanyȱsense).ȱTheȱonlyȱclueȱtoȱhowȱtheȱcomputerȱgotȱwhereȱitȱdidȱisȱ theȱreturnȱaddressȱstoredȱonȱtheȱstackȱbyȱtheȱfunctionȱcallȱmadeȱinȱtheȱjumpȱtable.ȱIfȱ anyȱofȱtheȱrandomȱinstructionsȱmodifiedȱtheȱstackȱorȱchangedȱtheȱstackȱpointerȱwhenȱ theyȱwereȱexecuted,ȱthisȱclueȱisȱlost.ȱ Worseȱstillȱisȱifȱtheȱrandomȱaddressȱhappensȱtoȱbeȱinȱtheȱmiddleȱofȱaȱfunction.ȱ Thenȱtheȱfunctionȱexecutesȱmerrilyȱalong,ȱchangingȱwhoȱknowsȱwhatȱdata,ȱuntilȱitȱisȱ finished.ȱButȱtheȱreturnȱaddressȱisnȇtȱwhereȱtheȱfunctionȱexpectsȱitȱtoȱbeȱonȱtheȱstack,ȱ soȱanotherȱrandomȱvalueȱisȱusedȱinstead.ȱThisȱvalueȱbecomesȱtheȱaddressȱofȱtheȱnextȱ instructionȱ toȱ execute,ȱ andȱ theȱ computerȱ goesȱ toȱ aȱ differentȱ randomȱ locationȱ andȱ continuesȱtoȱexecuteȱwhateverȱitȱfindsȱthere.ȱ Theȱ problemȱ isȱ thatȱ theȱ instructionsȱ destroyȱ theȱ lastȱ clueȱ asȱ toȱ howȱ theȱ computerȱgotȱtoȱwhereȱtheȱfaultȱfinallyȱoccurs.ȱWithoutȱthisȱinformation,ȱitȱisȱdifficultȱ toȱpinpointȱtheȱsourceȱofȱtheȱproblem.ȱIfȱyouȱareȱsuspiciousȱofȱaȱjumpȱtable,ȱthenȱprintȱ aȱ messageȱ beforeȱ andȱ afterȱ itsȱ functionȱ call.ȱ Itȱ willȱ thenȱ beȱ obviousȱ ifȱ theȱ calledȱ functionȱ neverȱ returns.ȱ Theȱ trickȱ isȱ toȱ realizeȱ thatȱ aȱ faultȱ inȱ oneȱ partȱ ofȱ theȱ programȱ mightȱ beȱ causedȱ byȱ anȱ errorȱ inȱ aȱ jumpȱ tableȱ inȱ someȱ distant,ȱ unrelatedȱ partȱ ofȱ theȱ program.ȱ ȱ Itȱisȱmuchȱeasierȱtoȱmakeȱsureȱthatȱtheȱsubscriptȱusedȱinȱaȱjumpȱtableȱisȱwithinȱrangeȱinȱ theȱ firstȱ place.ȱ Inȱ theȱ calculatorȱ example,ȱ theȱ functionȱ thatȱ readsȱ inȱ theȱ operatorȱ andȱ convertsȱitȱtoȱitsȱcorrespondingȱintegerȱshouldȱverifyȱthatȱtheȱoperatorȱisȱvalid.ȱ ȱ ȱ ȱ 13.4 Command Line Arguments ȱ Processingȱ commandȱ lineȱ argumentsȱ isȱ anotherȱ applicationȱ ofȱ pointersȱ toȱ pointers.ȱȱ Someȱoperatingȱsystems,ȱincludingȱUNIXȱandȱMSȬDOS,ȱletȱtheȱuserȱwriteȱargumentsȱ onȱtheȱcommandȱthatȱinitiatesȱtheȱexecutionȱofȱaȱprogram.ȱTheseȱargumentsȱareȱpassedȱ toȱtheȱprogram,ȱwhichȱcanȱprocessȱthemȱinȱanyȱwayȱitȱseesȱfit.ȱ ȱ Download at http://www.pin5i.com/ 13.4 Command Line Arguments 363 ȱ 13.4.1 Passing Command Line Arguments ȱ Howȱareȱtheseȱargumentsȱpassedȱtoȱtheȱprogram?ȱTheȱ mainȱfunctionȱofȱaȱCȱprogramȱ hasȱ twoȱ parameters. 44 ȱ Theȱ first,ȱ oftenȱ calledȱ argc,ȱ isȱ aȱ countȱ ofȱ theȱ numberȱ ofȱ argumentsȱinȱtheȱcommandȱline.ȱTheȱsecond,ȱoftenȱcalledȱ argv,ȱpointsȱtoȱtheȱvaluesȱofȱ theȱarguments.ȱBecauseȱthereȱisnȇtȱanȱinherentȱlimitȱonȱtheȱnumberȱofȱarguments,ȱ argvȱ pointsȱtoȱtheȱfirstȱelementȱofȱwhatȱisȱessentiallyȱanȱarray.ȱEachȱofȱtheseȱelementsȱisȱaȱ pointerȱtoȱtheȱtextȱofȱoneȱargument.ȱIfȱtheȱprogramȱneedsȱtoȱaccessȱtheȱcommandȱlineȱ arguments,ȱtheȱmainȱfunctionȱisȱdeclaredȱwithȱtheseȱparameters:ȱ ȱ int main( int argc, char **argv ) ȱ Noteȱthatȱtheȱnamesȱargcȱandȱargvȱareȱfrequentlyȱusedȱbutȱareȱnotȱmagicalȱinȱanyȱway.ȱ TheyȱcouldȱbeȱcalledȱȈfredȈȱandȱȈgingerȈȱifȱyouȱsoȱdesired,ȱthoughȱtheȱprogramȱwouldȱ beȱharderȱtoȱread.ȱ Figureȱ13.1ȱshowsȱhowȱtheȱargumentsȱinȱthisȱcommandȱlineȱwouldȱbeȱpassed:ȱ ȱ $cc –c –O main.c insert.c –o test ȱ Noteȱtheȱarrayȱofȱpointers:ȱEachȱelementȱofȱthisȱarrayȱisȱaȱpointerȱtoȱaȱcharacter,ȱ andȱtheȱarrayȱisȱterminatedȱbyȱaȱNULLȱpointer.ȱTheȱvalueȱinȱargcȱandȱthisȱNULLȱmayȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇcȇȱ ȇcȇȱ 0ȱ ȱ ȇȬȇȱ ȇcȇȱ 0ȱ ȱ ȱ ȱ argcȱ 7ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ argvȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇmȇ ȇaȇȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇnȇȱ ȇsȇȱ ȇeȇȱ ȇrȇȱ ȇtȇȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ 0ȱ ȱ ȱ ȱ ȇtȇȱ ȇeȇȱ ȇsȇȱ ȱ ȱ ȱ ȱ ȇȬȇȱ ȇOȇ ȇiȇȱ ȱ ȇȬȇȱ ȇoȇȱ ȱ 0ȱ ȱ ȱ ȱ ȱ ȱ ȇiȇȱ ȱ ȇnȇȱ ȱ ȱ ȱ ȱ ȱ ȇ.ȇȱ ȱ ȱ 0ȱ ȱ ȱ ȱ ȇcȇȱ ȱ ȱ 0ȱ ȱ ȇ.ȇȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇcȇȱ 0ȱ ȱ ȱ ȱ ȱ ȇtȇȱ 0ȱ ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱ Actually,ȱ someȱ operatingȱ systemsȱ alsoȱ passȱ aȱ thirdȱ parameterȱ toȱ theȱ mainȱ function,ȱ aȱ pointerȱ toȱ aȱ listȱ ofȱ environmentȱ variablesȱandȱtheirȱvalues.ȱConsultȱyourȱcompilerȇsȱorȱoperatingȱsystemȇsȱdocumentationȱforȱdetails.ȱ 44 Download at http://www.pin5i.com/ 364ȱ Chapter 13 Advanced Pointer Topicsȱ ȱbothȱbeȱusedȱtoȱdetermineȱhowȱmanyȱargumentsȱwereȱpassed,ȱ argvȱpointsȱtoȱtheȱfirstȱ elementȱ ofȱ thisȱ array,ȱ whichȱ isȱ whyȱ itȱ isȱ declaredȱ asȱ aȱ pointerȱ toȱ aȱ pointerȱ toȱ aȱ character.ȱ Oneȱ lastȱ thingȱ toȱ observeȱ isȱ thatȱ theȱ veryȱ firstȱ argumentȱ isȱ theȱ nameȱ ofȱ theȱ program.ȱWhatȱ isȱ theȱ purposeȱofȱpassingȱ theȱprogramȱnameȱ asȱanȱ argument?ȱSurelyȱ theȱprogramȱknowsȱwhatȱitȱis.ȱUsuallyȱthisȱargumentȱisȱignored,ȱbutȱitȱcanȱbeȱusefulȱ forȱprogramsȱthatȱareȱcommonlyȱinvokedȱwithȱdifferentȱsetsȱofȱoptions.ȱTheȱUNIXȱ lsȱ command,ȱ whichȱ listsȱ theȱ filesȱ inȱ aȱ directory,ȱ isȱ suchȱ aȱ program.ȱ Onȱ manyȱ UNIXȱ systems,ȱtheȱcommandȱhasȱseveralȱdifferentȱnames.ȱWhenȱinvokedȱwithȱtheȱnameȱ ls,ȱ itȱ producesȱ aȱ briefȱ listingȱ ofȱ files.ȱ Whenȱ invokedȱ withȱ theȱ nameȱ l,ȱ itȱ producesȱ aȱ multicolumnȱ briefȱ listing,ȱ andȱ theȱ nameȱ l1ȱ producesȱ aȱ detailedȱ listing.ȱ Theȱ programȱ examinesȱ theȱ firstȱ argumentȱ toȱ determineȱ whichȱ nameȱ wasȱ usedȱ toȱ invokeȱ itȱ andȱ selectsȱoptionsȱbasedȱonȱtheȱname.ȱ Onȱsomeȱsystems,ȱtheȱargumentȱstringsȱareȱstoredȱoneȱrightȱafterȱtheȱother,ȱsoȱ advancingȱaȱpointerȱtoȱtheȱfirstȱargumentȱpastȱtheȱendȱofȱtheȱstringȱwillȱtakeȱyouȱtoȱtheȱ beginningȱofȱtheȱnextȱone.ȱThisȱarrangementȱisȱimplementationȱdependent,ȱthough,ȱsoȱ youȱ mustȱ notȱ dependȱ uponȱ it.ȱ Toȱ findȱ theȱ beginningȱ ofȱ anȱ argument,ȱ useȱ theȱ appropriateȱpointerȱfromȱtheȱarray.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** A program to print its command line arguments. */ #include <stdio.h> #include <stdlib.h> int main( int argc, char **argv ) { /* ** Print arguments until a NULL pointer is reached (argc is ** not used). The program name is skipped. */ while( *++argv != NULL ) printf( "%s\n", *argv ); return EXIT_SUCCESS; } ȱ Porgramȱ13.2ȱȱPrintȱcommandȱlineȱargumentsȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱȱȱȱecho.cȱ Download at http://www.pin5i.com/ 13.4 Command Line Arguments 365 Howȱ doesȱ aȱ programȱ accessȱ theseȱ arguments?ȱ Programȱ 13.2ȱ isȱ aȱ veryȱ simpleȱ example—itȱ simplyȱ printsȱ outȱ allȱ ofȱ itsȱ argumentsȱ (exceptȱ forȱ theȱ programȱ name)ȱ muchȱlikeȱtheȱUNIXȱechoȱcommand.ȱ Theȱ whileȱloopȱincrementsȱ argvȱandȱthenȱchecksȱ *argvȱtoȱseeȱifȱtheȱendȱofȱtheȱ argumentȱlistȱhasȱbeenȱreached.ȱItȱisȱlookingȱforȱtheȱNULLȱthatȱterminatesȱtheȱlist.ȱIfȱ thereȱ isȱ anotherȱ argument,ȱ theȱ bodyȱ ofȱ theȱ loopȱ isȱ executedȱ andȱ printsȱ it.ȱ Byȱ incrementingȱargvȱfirstȱinȱtheȱloop,ȱtheȱprogramȱnameȱisȱautomaticallyȱskipped.ȱ Theȱ %sȱcodeȱusedȱinȱtheȱformatȱstringȱofȱ printfȱrequiresȱanȱargumentȱthatȱisȱaȱ pointerȱtoȱcharacter.ȱ printfȱassumesȱthatȱthisȱcharacterȱisȱtheȱfirstȱofȱNULȬterminatedȱ string.ȱApplyingȱindirectionȱonȱ argvȱyieldsȱtheȱvalueȱtoȱwhichȱitȱpoints,ȱaȱpointerȱtoȱaȱ characterȱ–ȱjustȱwhatȱtheȱformatȱrequires.ȱ ȱ ȱ ȱ 13.4.2 Processing Command Line Arguments ȱ Letȇsȱwriteȱaȱprogramȱthatȱprocessesȱcommandȱlineȱargumentsȱmoreȱrealistically.ȱThisȱ programȱ willȱ handleȱ aȱ veryȱ commonȱ paradigm—optionȱ argumentsȱ followedȱ byȱ fileȱ nameȱ arguments.ȱ Afterȱ theȱ programȱ name,ȱ thereȱ mayȱ beȱ zeroȱ orȱ moreȱ options,ȱ followedȱbyȱzeroȱorȱmoreȱfileȱnames,ȱlikeȱthis:ȱ ȱ prog –a –b –c name1 name2 name3 ȱ Eachȱ optionȱ argumentȱ isȱ aȱ dashȱ followedȱ byȱ aȱ singleȱ letterȱ thatȱ identifiesȱ whichȱ ofȱ severalȱpossibleȱoptionsȱisȱdesired.ȱEachȱfileȱnameȱargumentȱisȱprocessedȱinȱsomeȱway.ȱȱ Ifȱthereȱareȱnoȱfileȱnames,ȱtheȱstandardȱinputȱisȱprocessedȱinstead.ȱ Toȱ makeȱ theseȱ examplesȱ generic,ȱ ourȱ programȱ setsȱ variablesȱ toȱ rememberȱ whichȱ optionsȱ wereȱ found.ȱ Otherȱ partsȱ ofȱ aȱ realȱ programȱ mightȱ thenȱ testȱ theseȱ variablesȱ toȱ determineȱ whatȱ processingȱ wasȱ requested.ȱ Inȱ aȱ realȱ program,ȱ theȱ processingȱrequiredȱforȱanȱoptionȱmightȱalsoȱbeȱdoneȱwhenȱtheȱoptionȱisȱdiscoveredȱinȱ theȱarguments.ȱ Download at http://www.pin5i.com/ 366ȱ Chapter 13 Advanced Pointer Topicsȱ ȱ /* ** Process command-line arguments */ #include <stdio.h> #define TRUE 1 /* ** */ void void /* ** */ int Prototypes for functions that do the real work. process_standard_input( void ); process_file( char *file_name ); Option flags, default initialization is FALSE. option_a, option_b /* etc. */ ; void main( int argc, char **argv ) { /* ** Process option arguments: skip to next argument, and ** check that it begins with a dash. */ while( *++argv != NULL && **argv == '-' ){ /* ** Check the letter after the dash. */ switch( *++*argv ){ case 'a': option_a = TRUE; break; case 'b': option_b = TRUE; break; /* etc. */ } } /* ** Process file name arguments */ if( *argv == NULL ) process_standard_input(); else { do { process_file( *argv ); } while( *++argv != NULL ); } } ȱ Programȱ13.3ȱȱProcessingȱcommandȱlineȱargumentsȱȱ ȱ ȱ ȱ ȱ ȱcmd_line.cȱ Download at http://www.pin5i.com/ 13.4 Command Line Arguments 367 ȱ Programȱ 13.3ȱ resemblesȱ Programȱ 13.2ȱ becauseȱ itȱ containsȱ aȱ loopȱ thatȱ goesȱ throughȱ allȱ ofȱ theȱ arguments.ȱ Theȱ mainȱ differenceȱ isȱ thatȱ weȱ mustȱ nowȱ distinguishȱ betweenȱoptionȱargumentsȱandȱtileȱnameȱarguments.ȱTheȱloopȱstopsȱwhenȱitȱreachesȱ anȱargumentȱthatȱdoesȱnotȱbeginȱwithȱaȱdash.ȱAȱsecondȱloopȱprocessesȱtheȱfileȱnames.ȱ NoticeȱtheȱtestȱthatȱwasȱaddedȱtoȱtheȱwhileȱloopȱinȱProgramȱ13.3:ȱ ȱ **argv == '-' ȱ Theȱ doubleȱ indirectionȱ accessesȱ theȱ firstȱ characterȱ ofȱ theȱ argument,ȱ asȱ illustratedȱ inȱ Figureȱ13.2.ȱIfȱthisȱcharacterȱisȱnotȱaȱdashȱthenȱthereȱarenȇtȱanyȱmoreȱoptionsȱandȱtheȱ loopȱbreaks.ȱNoteȱthatȱitȱisȱimportantȱtoȱtestȱ *argvȱbeforeȱtestingȱ **argv.ȱIfȱ *argvȱwereȱ NULL,ȱtheȱsecondȱindirectionȱinȱ**argvȱwouldȱbeȱillegal.ȱ Theȱ *++*argvȱ expressionȱ inȱ theȱ switchȱ statementȱ isȱ oneȱ youȱ haveȱ seenȱ before.ȱȱ Theȱfirstȱindirectionȱgoesȱtoȱwhereȱ argvȱpoints,ȱandȱthisȱlocationȱisȱincremented.ȱTheȱ lastȱ indirectionȱ followsȱ theȱ incrementedȱ pointer,ȱ asȱ diagrammedȱ inȱ Figureȱ 13.3.ȱ Theȱ switchȱstatementȱsetsȱaȱvariableȱdependingȱonȱwhichȱoptionȱletterȱwasȱfound,ȱandȱtheȱ ++ȱinȱtileȱ whileȱloopȱadvancesȱ argvȱtoȱtheȱnextȱargumentȱforȱtheȱnextȱiterationȱofȱtheȱ loop.ȱ Whenȱ thereȱ arenȇtȱ anyȱ moreȱ options,ȱ theȱ fileȱ namesȱ areȱ handled.ȱ Ifȱ argvȱ isȱ pointingȱtoȱtheȱnull,ȱthereȱarenȇtȱanyȱandȱtheȱstandardȱinputȱisȱprocessed.ȱOtherwise,ȱ eachȱnameȱisȱprocessedȱoneȱbyȱone.ȱTheȱfunctionȱcallsȱinȱthisȱprogramȱareȱgenericȱsoȱ theyȱdonȇtȱshowȱanyȱofȱtheȱworkȱthatȱaȱrealȱprogramȱmightȱperform.ȱNevertheless,ȱthisȱ designȱ isȱ good.ȱ Theȱ mainȱ programȱ dealsȱ withȱ theȱ argumentsȱ soȱ thatȱ theȱ functionsȱ doingȱ theȱ processingȱ donȇtȱ haveȱ toȱ worryȱ aboutȱ parsingȱ optionsȱ orȱ loopingȱ throughȱ fileȱnames.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇpȇȱ ȇrȇȱ ȇoȇȱ ȇgȇȱ 0ȱ ȱ ȱ ȇȬȇȱ ȇaȇȱ 0ȱ argcȱ 7ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ argvȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇnȇȱ ȇaȇȱ ȇmȇ ȇeȇȱ ȇ1ȇȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇnȇȱ ȇaȇȱ ȇmȇ ȇeȇȱ ȇ2ȇȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ 0ȱ ȱ ȱ ȇnȇȱ ȇaȇȱ ȇmȇ ȱ ȱ Figureȱ13.2ȱȱAccessingȱtheȱargumentȱ ȱ ȱ ȇȬȇȱ ȱ ȇbȇȱ ȱ ȱ ȱ 0ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇȬȇȱ ȇcȇȱ ȱ ȱ ȱ ȱ ȱ ȇeȇȱ ȇ3ȇȱ ȱ ȱ 0ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ 0ȱ 0ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ 0ȱ ȱ ȱ ȱ Download at http://www.pin5i.com/ Chapter 13 Advanced Pointer Topicsȱ 368ȱ ȱ argcȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇpȇȱ ȇrȇȱ ȇoȇȱ ȇgȇȱ 7ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ argvȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇnȇȱ ȇaȇȱ ȇmȇ ȇeȇȱ ȇ1ȇȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȇnȇȱ ȇaȇȱ ȇmȇ ȇeȇȱ ȇ2ȇȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ 0ȱ ȱ ȱ ȇnȇȱ ȇaȇȱ ȇmȇ ȱ ȇȬȇȱ ȇbȇȱ ȱ ȱ ȱ 0ȱ ȱ ȱ ȱ 0ȱ ȱ ȱ ȱ ȱ ȱ ȇȬȇȱ ȇcȇȱ ȱ ȱ ȱ ȱ ȱ ȇeȇȱ ȇ3ȇȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ 0ȱ 0ȱ ȱ ȱ 0ȱ ȱ ȇaȇȱ 0ȱ 0ȱ ȱ ȱ ȇȬȇȱ ȱ ȱ Figureȱ13.3ȱȱAccessingȱtheȱnextȱcharacterȱinȱtheȱargumentȱ ȱ ȱ ȱ Someȱprogramsȱallowȱtheȱuserȱtoȱputȱmultipleȱoptionȱlettersȱinȱoneȱargument,ȱ likeȱthis:ȱ ȱ prog –abc name1 name2 name3 ȱ Atȱ firstȱ youȱ mightȱ thinkȱ thatȱ thisȱ changeȱ willȱ complicateȱ ourȱ program,ȱ butȱ itȱ turnsȱ outȱ toȱ beȱ fairlyȱ easyȱ toȱ process.ȱ Eachȱ argumentȱ mayȱ nowȱ containȱ multipleȱ options,ȱsoȱweȱ useȱ anotherȱ loopȱ toȱ processȱthem.ȱ Theȱloopȱshouldȱterminateȱ whenȱitȱ encountersȱtheȱtrailingȱNULȱbyteȱatȱtheȱendȱofȱtheȱargument.ȱ Theȱ switchȱ statementȱ inȱ Programȱ 13.3ȱ isȱ replacedȱ byȱ theȱ followingȱ codeȱ fragment:ȱ ȱ while( ( opt = *++*argv ) != '\0' ){ switch( opt ){ case 'a': option_a = TRUE; break; /* etc. */ } } ȱ Theȱtestȱinȱtheȱloopȱadvancesȱtheȱargumentȱpointerȱbeyondȱtheȱdashȱandȱmakesȱaȱcopyȱ ofȱ theȱ characterȱ foundȱ there.ȱ Ifȱ thisȱ characterȱ isȱ notȱ dieȱ NULȱ byte,ȱ thenȱ theȱ switchȱ statementȱ isȱ usedȱ asȱ beforeȱ toȱ setȱ theȱ appropriateȱ variable.ȱ Noteȱ thatȱ theȱ optionȱ characterȱ isȱ savedȱ inȱ aȱ localȱ variableȱ optȱ toȱ avoidȱ havingȱ toȱ evaluateȱ **argvȱ inȱ theȱ switchȱstatement.ȱ Download at http://www.pin5i.com/ 13.5 String Literals TIP 369 Beȱ awareȱ thatȱ theȱ commandȱ lineȱ argumentsȱ mayȱ onlyȱ beȱ processedȱ onceȱ inȱ thisȱ mannerȱbecauseȱtheȱpointersȱtoȱtheȱargumentsȱareȱdestroyedȱbyȱtheȱinnerȱloop.ȱIfȱtheȱ argumentsȱmustȱbeȱprocessedȱmoreȱthanȱonce,ȱmakeȱaȱcopyȱofȱeachȱpointerȱthatȱyouȱ mustȱincrementȱasȱyouȱgoȱthroughȱtheȱlist.ȱ Thereȱ areȱ otherȱ possibilitiesȱ forȱ processingȱ options.ȱ Forȱ example,ȱ theȱ optionsȱ mightȱ beȱ wordsȱ ratherȱ thanȱ singleȱ letters,ȱ orȱ thereȱ mightȱ beȱ valuesȱ associatedȱ withȱ someȱoptions,ȱasȱinȱthisȱexample:ȱ ȱ cc –o prog prog.c ȱ Oneȱofȱtheȱchapterȱproblemsȱexpandsȱonȱthisȱidea.ȱ ȱ ȱ ȱ 13.5 String Literals ȱ Itȱisȱtimeȱtoȱtakeȱaȱcloserȱlookȱatȱaȱtopicȱmentionedȱearlier:ȱstringȱliterals.ȱWhenȱaȱstringȱ literalȱappearsȱinȱanȱexpression,ȱitsȱvalueȱisȱaȱpointerȱconstant.ȱTheȱcompilerȱstoresȱaȱ copyȱofȱtheȱspecifiedȱcharactersȱsomewhereȱinȱmemory,ȱandȱtheȱpointerȱpointsȱtoȱtheȱ firstȱ ofȱ theseȱ characters.ȱ Butȱ whenȱ arrayȱ namesȱ areȱ usedȱ inȱ expressions,ȱ theirȱ valuesȱ areȱ alsoȱ pointerȱ constants.ȱ Weȱ canȱ performȱ subscripting,ȱ indirection,ȱ andȱ pointerȱ arithmeticȱonȱthem.ȱAreȱtheseȱoperationsȱmeaningfulȱonȱstringȱliterals,ȱtoo?ȱLetȇsȱlookȱ atȱsome.ȱ Whatȱisȱtheȱmeaningȱofȱthisȱexpression?ȱ ȱ "xyz" + 1 ȱ Toȱmostȱprogrammers,ȱitȱlooksȱlikeȱgibberish.ȱItȱappearsȱtoȱbeȱtryingȱtoȱperformȱsomeȱ kindȱofȱadditionȱonȱaȱstring.ȱButȱwhenȱyouȱrememberȱthatȱtheȱstringȱliteralȱisȱaȱpointer,ȱ theȱ meaningȱ becomesȱ clear.ȱ Thisȱ expressionȱ computesȱ theȱ sumȱ ofȱ theȱ pointerȱ valueȱ plusȱone.ȱTheȱresultȱisȱaȱpointerȱtoȱtheȱsecondȱcharacterȱinȱtheȱliteral:ȱy.ȱ Howȱaboutȱthisȱexpression?ȱ ȱ *"xyz" ȱ Whenȱindirectionȱisȱappliedȱtoȱaȱpointer,ȱtheȱresultȱisȱtheȱthingȱtoȱwhichȱitȱpoints.ȱTheȱ typeȱ ofȱ aȱ stringȱ literalȱ isȱ Ȉpointerȱ toȱ character,Ȉȱ soȱ theȱ resultȱ ofȱ theȱ indirectionȱ isȱ theȱ characterȱtoȱwhichȱitȱpoints:ȱ x.ȱNoteȱthatȱtheȱresultȱisȱnotȱtheȱentireȱstring,ȱjustȱtheȱfirstȱ character.ȱ Thisȱnextȱexampleȱalsoȱlooksȱstrange,ȱbutȱbyȱnowȱyouȱshouldȱbeȱableȱtoȱfigureȱ outȱthatȱtheȱvalueȱofȱthisȱexpressionȱisȱtheȱcharacterȱz.ȱ ȱ "xyz"[2] Download at http://www.pin5i.com/ 370ȱ Chapter 13 Advanced Pointer Topicsȱ Theȱ lastȱ exampleȱ containsȱ anȱ error.ȱ Theȱ offsetȱ ofȱ fourȱ goesȱ offȱ theȱ endȱ ofȱ theȱ string,ȱsoȱtheȱresultȱisȱanȱunpredictableȱcharacter.ȱ ȱ *( "xyz" + 4 ) ȱ Whenȱ wouldȱ anyoneȱ everȱ wantȱ toȱ useȱ expressionsȱ likeȱ these?ȱ Theȱ functionȱ inȱ Programȱ 13.4ȱ isȱ oneȱ usefulȱ example.ȱ Canȱ youȱ figureȱ outȱ whatȱ thisȱ mysteryȱ functionȱ does?ȱ Hereȱ isȱ aȱ hint:ȱ Traceȱ theȱ functionȱ withȱ severalȱ differentȱ inputȱ valuesȱ andȱ seeȱ whatȱisȱprinted.ȱTheȱanswerȱisȱgivenȱatȱtheȱendȱofȱtheȱchapter.ȱ Inȱ theȱ meantime,ȱ letȇsȱ lookȱ atȱ anotherȱ example.ȱ Programȱ 13.5ȱ containsȱ aȱ functionȱthatȱconvertsȱbinaryȱvaluesȱtoȱcharactersȱandȱprintsȱthem.ȱYouȱfirstȱsawȱthisȱ functionȱ asȱ Programȱ 7.6.ȱ Forȱ thisȱ example,ȱ weȇllȱ modifyȱ itȱ toȱ printȱ valuesȱ inȱ hexadecimal.ȱ Theȱ firstȱ changeȱ isȱ easy:ȱ justȱ divideȱ byȱ 16ȱ insteadȱ ofȱ 10.ȱ Butȱ nowȱ theȱ remainderȱ mightȱ beȱ anyȱ valueȱ fromȱ 0ȱ toȱ 15,ȱ andȱ theȱ valuesȱ fromȱ 10ȱ toȱ 15ȱ shouldȱ beȱ printedȱ asȱ theȱ lettersȱ Aȱ toȱ F.ȱ Theȱ followingȱ codeȱ isȱ aȱ typicalȱ approachȱ toȱ thisȱ newȱ problem.ȱ ȱ remainder = value % 16; if( remainder < 10 ) putchar( remainder + '0' ); else putchar( remainder – 10 + 'A' ); ȱ Iȇveȱusedȱaȱlocalȱvariableȱtoȱsaveȱtheȱremainderȱratherȱthanȱcomputingȱitȱthreeȱseparateȱ times.ȱForȱremaindersȱinȱtheȱrangeȱ0ȱthroughȱ9,ȱaȱdigitȱisȱprintedȱtheȱsameȱasȱbefore.ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Mystery function ** ** The argument is a value in the range 0 through 100. */ #include <stdio.h> void mystery( int n ) { n += 5; n /= 10; printf( "%s\n", "**********" + 10 - n ); } ȱ Programȱ13.4ȱȱȱMysteryȱfunctionȱȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱmystery.cȱ Download at http://www.pin5i.com/ 13.5 String Literals 371 ȱ /* ** Take an integer value (unsigned), convert it to characters, and ** print it. Leading zeros are suppressed. */ #include <stdio.h> void binary_to_ascii( unsigned int value ) { unsigned int quotient; quotient = value / 10; if( quotient != 0 ) binary_to_ascii( quotient ); putchar( value % 10 + '0' ); } ȱ Programȱ13.5ȱȱȱConvertȱaȱbinaryȱintegerȱtoȱcharactersȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱȱȱȱȱbtoa.cȱ ȱ ȱ ȱ ȱ ȱ ȱ ButȱtheȱotherȱremaindersȱareȱprintedȱasȱlettersȬȱTheȱtestȱisȱneededȱbecauseȱtheȱlettersȱAȱ throughȱFȱdoȱnotȱimmediatelyȱfollowȱtheȱdigitsȱinȱanyȱcommonȱcharacterȱset.ȱ Theȱfollowingȱcodeȱsolvesȱtheȱproblemȱinȱaȱdifferentȱway.ȱ ȱ putchar( "0123456789ABCDEF"[ value % 16 ] ); TIP ȱ Onceȱagainȱtheȱremainderȱwillȱbeȱaȱvalueȱinȱtheȱrangeȱofȱ0ȱthroughȱ15,ȱbutȱthisȱtimeȱitȱ isȱusedȱasȱaȱsubscriptȱtoȱselectȱoneȱofȱtheȱcharactersȱfromȱtheȱstringȱliteralȱtoȱprint.ȱTheȱ previousȱ codeȱ isȱ complicatedȱ becauseȱ theȱ lettersȱ andȱ digitsȱ areȱ notȱ adjacentȱ inȱ theȱ characterȱset.ȱThisȱsolutionȱavoidsȱtheȱcomplicationȱbyȱdefiningȱaȱstringȱinȱwhichȱtheyȱ areȱadjacent.ȱTheȱremainderȱselectsȱtheȱrightȱdigitȱfromȱthisȱstring.ȱ Thisȱ secondȱ approachȱ isȱ fasterȱ thanȱ theȱ traditionalȱ one,ȱ becauseȱ fewerȱ operationsȱ areȱ needed.ȱ Theȱ codeȱ mayȱ orȱ mayȱ notȱ beȱ smallerȱ thanȱ theȱ original,ȱ however.ȱ Theȱ decreaseȱ inȱ instructionsȱ isȱ offsetȱ byȱ theȱ additionȱ ofȱ theȱ 17Ȭbyteȱ stringȱ literal.ȱ ȱ However,ȱaȱlargeȱreductionȱinȱreadabilityȱisȱaȱbigȱpriceȱtoȱpayȱforȱaȱsmallȱimprovementȱ inȱexecutionȱspeed.ȱWhenȱyouȱuseȱanȱunusualȱtechniqueȱorȱstatement,ȱbeȱsureȱthatȱyouȱ includeȱaȱcommentȱdescribingȱhowȱitȱworks.ȱOnceȱthisȱexampleȱhasȱbeenȱexplained,ȱitȱ isȱactuallyȱeasierȱtoȱfollowȱthanȱtheȱtraditionalȱcodeȱbecauseȱitȱisȱshorter.ȱ Download at http://www.pin5i.com/ 372ȱ Chapter 13 Advanced Pointer Topicsȱ Nowȱbackȱtoȱtheȱmysteryȱfunction.ȱDidȱyouȱfigureȱitȱout?ȱItȱprintsȱaȱnumberȱofȱ starsȱproportionalȱtoȱtheȱvalueȱofȱtheȱargument.ȱItȱprintsȱ0ȱstarsȱifȱtheȱargumentȱwasȱ0,ȱ 10ȱstarsȱifȱtheȱargumentȱwasȱ100,ȱandȱanȱintermediateȱnumberȱofȱstarsȱforȱintermediateȱ values.ȱInȱotherȱwords,ȱthisȱfunctionȱprintsȱoneȱbarȱofȱaȱhistogram,ȱandȱitȱdoesȱitȱmuchȱ moreȱeasilyȱandȱefficientlyȱthanȱtheȱmoreȱtraditionalȱloop.ȱ ȱ ȱ ȱ 13.6 Summary ȱ Ifȱdeclaredȱproperly,ȱaȱpointerȱvariableȱmayȱpointȱtoȱanotherȱpointerȱvariable.ȱLikeȱanyȱ otherȱpointerȱvariable,ȱaȱpointerȱtoȱaȱpointerȱmustȱbeȱinitializedȱbeforeȱitȱcanȱbeȱused.ȱ Twoȱ indirectionȱ operationsȱ areȱ neededȱ onȱ aȱ pointerȱ toȱ aȱ pointerȱ toȱ obtainȱ theȱ targetȱ object.ȱMoreȱlevelsȱofȱindirectionȱareȱallowedȱ(forȱexample,ȱaȱpointerȱtoȱaȱpointerȱtoȱaȱ pointerȱ toȱ an int),ȱ butȱ areȱ neededȱ lessȱ oftenȱ thanȱ simplerȱ pointers.ȱ Youȱ mayȱ alsoȱ createȱ pointerȱ variablesȱ thatȱ pointȱ toȱ functionsȱ andȱ arrays,ȱ andȱ createȱ arraysȱ ofȱ suchȱ pointers.ȱ DeclarationsȱinȱCȱareȱbyȱinference.ȱTheȱdeclarationȱ ȱ int *a; ȱ declaresȱtheȱexpressionȱ*aȱtoȱbeȱanȱinteger.ȱYouȱmustȱthenȱinferȱthatȱaȱisȱaȱpointerȱtoȱanȱ integer.ȱWithȱdeclarationȱbyȱinference,ȱtheȱrulesȱforȱreadingȱdeclarationsȱareȱȱtheȱsameȱ asȱthoseȱforȱreadingȱexpressions.ȱ Youȱcanȱuseȱpointersȱtoȱfunctionsȱtoȱimplementȱcallbackȱfunctions.ȱAȱpointerȱtoȱ yourȱcallbackȱfunctionȱisȱpassedȱasȱanȱargumentȱtoȱanotherȱfunction,ȱwhichȱcallsȱyourȱ functionȱusingȱtheȱpointer.ȱWithȱthisȱtechnique,ȱyouȱcanȱcreateȱgenericȱfunctionsȱthatȱ performȱcommonȱoperationsȱsuchȱasȱsearchingȱaȱlinkedȱlist.ȱAnyȱworkȱthatȱisȱspecificȱ toȱoneȱinstanceȱofȱtheȱproblem,ȱsuchȱasȱcomparingȱvaluesȱinȱtheȱlist,ȱisȱperformedȱinȱaȱ callbackȱfunctionȱsuppliedȱbyȱtheȱclient.ȱ Jumpȱ tablesȱ alsoȱ useȱ pointersȱ toȱ functions.ȱ Aȱ jumpȱ tableȱ performsȱ aȱ selectionȱ muchȱ likeȱ aȱ switchȱ statement.ȱ Theȱ tableȱ consistsȱ ofȱ anȱ arrayȱ ofȱ pointersȱ toȱ functionsȱ (whichȱmustȱhaveȱidenticalȱprototypes).ȱOneȱpointerȱisȱselectedȱwithȱaȱsubscript,ȱandȱ theȱ correspondingȱ functionȱ isȱ called.ȱ Alwaysȱ verifyȱ thatȱ theȱ subscriptȱ valueȱ isȱ inȱ theȱ properȱrange,ȱbecauseȱdebuggingȱerrorsȱinȱjumpȱtablesȱisȱdifficult.ȱ Ifȱ anȱ executionȱ environmentȱ implementsȱ commandȱ lineȱ arguments,ȱ theȱ argumentsȱareȱpassedȱtoȱtheȱmainȱfunctionȱviaȱtwoȱparameters,ȱoftenȱcalledȱ argcȱandȱ argv. argcȱisȱanȱintegerȱandȱcontainsȱaȱcountȱofȱtheȱnumberȱofȱarguments. argvȱisȱaȱ pointerȱtoȱaȱsequenceȱofȱpointersȱtoȱcharacters.ȱEachȱpointerȱinȱtheȱsequenceȱpointsȱtoȱaȱ commandȱlineȱargument.ȱTheȱsequenceȱisȱterminatedȱwithȱaȱNULLȱpointer.ȱTheȱfirstȱ ȱ Download at http://www.pin5i.com/ 13.9 Questions 373 argumentȱ isȱ theȱ nameȱ ofȱ theȱ program.ȱ Aȱ programȱ canȱ accessȱ itsȱ commandȱ lineȱ argumentsȱbyȱusingȱindirectionȱonȱargv.ȱ Theȱvalueȱofȱaȱstringȱliteralȱthatȱappearsȱinȱanȱexpressionȱisȱaȱconstantȱpointerȱtoȱ theȱfirstȱcharacterȱinȱtheȱliteral.ȱLikeȱarrayȱnames,ȱyouȱcanȱuseȱstringȱliteralsȱinȱpointerȱ expressionsȱandȱwithȱsubscripts.ȱ ȱ ȱ ȱ 13.7 Summary of Cautions ȱ 1. Applyingȱindirectionȱtoȱanȱuninitializedȱpointerȱ(pageȱ356).ȱ 2. UsingȱanȱoutȬofȬboundsȱsubscriptȱinȱaȱjumpȱtableȱ(pageȱ361).ȱ ȱ ȱ ȱ 13.8 Summary of Programming Tips ȱ 1. Avoidȱusingȱmoreȱlevelsȱofȱindirectionȱthanȱnecessaryȱ(pageȱ353).ȱ 2. Theȱcdec1ȱprogramȱisȱhelpfulȱforȱdecipheringȱcomplicatedȱdeclarationsȱ(pageȱ355).ȱ 3. Beȱcarefulȱwhenȱcastingȱfromȱvoid *ȱtoȱotherȱpointerȱtypesȱ(pageȱ358).ȱ 4. Alwaysȱvalidateȱtheȱsubscriptȱusedȱinȱaȱjumpȱtableȱ(pageȱ362).ȱ 5. Destructivelyȱ processingȱ commandȱ lineȱ argumentsȱ preventsȱ themȱ fromȱ beingȱ processedȱagainȱlaterȱ(pageȱ369).ȱ 6. Unusualȱ codeȱ shouldȱ alwaysȱ beȱ accompaniedȱ byȱ aȱ commentȱ describingȱ whatȱ itȱ doesȱandȱhowȱitȱworksȱ(pageȱ371).ȱ ȱ ȱ ȱ 13.9 Questions ȱ 1. Aȱlistȱofȱdeclarationsȱisȱshownȱbelow.ȱ a. int abc();ȱ b. int abc[3];ȱ c. int **abc();ȱ d. int (*abc)();ȱ e. int (*abc)[6];ȱ Download at http://www.pin5i.com/ 374ȱ Chapter 13 Advanced Pointer Topicsȱ f. int *abc();ȱ g. int **(*abc[5])();ȱ h. int *abc[6];ȱ i. int *(*abc)[6];ȱ j. *(*abc())();ȱ int k. int (**(*abc)())();ȱ l. int (*(*abc)())[6];ȱ m. int *(*(*(*abc)())[6])();ȱ Matchȱeachȱofȱtheȱdeclarationsȱwithȱtheȱbestȱdescriptionȱfromȱthisȱlist.ȱ I. Pointerȱtoȱanȱint.ȱ II. Pointerȱtoȱaȱpointerȱtoȱanȱint.ȱ III. Arrayȱofȱint.ȱ IV. Pointerȱtoȱarrayȱofȱint.ȱ V. Arrayȱofȱpointerȱtoȱint.ȱ VI. Pointerȱtoȱarrayȱofȱpointerȱtoȱint.ȱ VII. Arrayȱofȱpointerȱtoȱpointerȱtoȱint.ȱ VIII. Functionȱreturningȱint.ȱ IX. Functionȱreturningȱpointerȱtoȱint.ȱ X. Functionȱreturningȱpointerȱtoȱpointerȱtoȱint.ȱ XI. Pointerȱtoȱfunctionȱreturningȱint.ȱ XII. Pointerȱtoȱfunctionȱreturningȱpointerȱtoȱint.ȱ XIII. Pointerȱtoȱfunctionȱreturningȱpointerȱtoȱpointerȱtoȱint.ȱ XIV. Arrayȱofȱpointerȱtoȱfunctionȱreturningȱint.ȱ XV. Arrayȱofȱpointerȱtoȱfunctionȱreturningȱpointerȱtoȱint.ȱ XVI. Arrayȱofȱpointerȱtoȱfunctionȱreturningȱpointerȱtoȱpointerȱtoȱint.ȱ XVII. Functionȱreturningȱpointerȱtoȱfunctionȱreturningȱint.ȱ XVIII. Functionȱreturningȱpointerȱtoȱpointerȱtoȱfunctionȱreturningȱint.ȱ XIX. Functionȱreturningȱpointerȱtoȱfunctionȱreturningȱpointerȱtoȱint.ȱ XX. Pointerȱtoȱfunctionȱreturningȱpointerȱtoȱfunctionȱreturningȱint.ȱ XXI. Pointerȱ toȱ functionȱ returningȱ pointerȱ toȱ pointerȱ toȱ functionȱ returningȱ int.ȱ Download at http://www.pin5i.com/ 13.9 Questions 375 XXII. Pointerȱ toȱ functionȱ returningȱ pointerȱ toȱ functionȱ returningȱ pointerȱ toȱ int.ȱ XXIII. Pointerȱtoȱfunctionȱreturningȱpointerȱtoȱarrayȱofȱint.ȱ XXIV. Pointerȱtoȱfunctionȱreturningȱpointerȱtoȱarrayȱofȱpointerȱtoȱint.ȱ XXV. Pointerȱ toȱ functionȱ returningȱ pointerȱ toȱ arrayȱ ofȱ pointerȱ toȱ functionȱ returningȱpointerȱtoȱint.ȱ XXVI. Illegalȱ 2. Givenȱtheȱfollowingȱdeclarations:ȱ ȱ char char *array[10]; **ptr = array; ȱ whatȱisȱtheȱeffectȱofȱaddingȱoneȱtoȱtheȱvariableȱptr?ȱ 3. Supposeȱyouȱareȱwritingȱaȱfunctionȱthatȱbeginsȱlikeȱthis:ȱ ȱ void func( int ***arg ){ ȱ Whatȱ isȱ theȱ typeȱ ofȱ theȱ argument?ȱ Drawȱ aȱ diagramȱ thatȱ showsȱ howȱ thisȱ variableȱ wouldȱbeȱcorrectlyȱused.ȱWhatȱexpressionȱwouldȱyouȱuseȱtoȱgetȱtheȱintegerȱthatȱtheȱ argumentȱisȱreferringȱto?ȱ 4. Howȱcanȱtheȱfollowingȱcodeȱfragmentȱbeȱimproved?ȱ Transaction *trans; trans->product->orders += 1; trans->product->quantity_on_hand -= trans->quantity; trans->product->supplier->reorder_quantity += trans->quantity; if( trans->product->export_restricted ){ ... } 5. Givenȱtheȱfollowingȱdeclarations:ȱ ȱ typedef int int } Point; struct { x; y; Point p; Point *a = &p; Point **b = &a; ȱ determineȱtheȱvalueȱofȱeachȱofȱtheȱfollowingȱexpressions.ȱ Download at http://www.pin5i.com/ 376ȱ Chapter 13 Advanced Pointer Topicsȱ a. aȱ b. *aȱ c. a->xȱ d. bȱ e. b->aȱ f. b->xȱ g. *bȱ h. *b->aȱ i. *b->xȱ j. b->a->xȱ k. (*b)->aȱ l. (*b)->xȱ m. **bȱ ȱ 6. Givenȱtheȱfollowingȱdeclarations:ȱ ȱ typedeef int int } Point; struct { x; y; Point x, y; Point *a = &x, *b = &y; ȱ explainȱtheȱmeaningȱofȱeachȱofȱtheseȱstatements.ȱ ȱ a. x = y;ȱ b. a = y;ȱ c. a = b;ȱ d. a = *b;ȱ e. *a = *b;ȱ ȱ 7. ManyȱimplementationsȱofȱANSIȱCȱincludeȱaȱfunctionȱcalledȱ getopt.ȱThisȱfunctionȱ helpsȱprocessȱcommandȱlineȱarguments.ȱHowever,ȱ getoptȱisȱnotȱmentionedȱinȱtheȱ Standard.ȱWhatȱareȱtheȱadvantagesȱandȱdisadvantagesȱofȱhavingȱsuchȱaȱfunction?ȱ Download at http://www.pin5i.com/ 13.10 Programming Exercises 377 8. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱthisȱcodeȱfragment,ȱandȱhowȱwouldȱyouȱfixȱit?ȱ ȱ char *pathname = " /usr/temp/XXXXXXXXXXXXXXX"; ... /* ** Insert the filename into the pathname. */ strcpy( pathname + 10, "abcde" ); 9. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱcodeȱfragment,ȱandȱhowȱwouldȱyouȱ fixȱit?ȱ ȱ char pathname[] = "/usr/temp/"; ... /* ** Append the filename to the pathname. */ strcat( pathname, "abcde" ); 10. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱcodeȱfragment,ȱandȱhowȱwouldȱyouȱ fixȱit?ȱ ȱ char pathname[20] = "/usr/temp/"; ... /* ** Append the filename to the pathname. */ strcat( pathname, filename ); 11. Theȱ Standardȱ slatesȱ thatȱ theȱ effectsȱ ofȱ modifyingȱ aȱ stringȱ literalȱ areȱ undefined.ȱ Whatȱproblemsȱmightȱbeȱcausedȱifȱyouȱdidȱmodifyȱstringȱliterals?ȱ ȱ ȱ ȱ 13.10 Programming Exercises ȱ 1. Writeȱaȱprogramȱthatȱreadsȱfromȱtheȱstandardȱinputȱandȱcomputesȱtheȱpercentageȱ ofȱcharactersȱitȱfindsȱinȱeachȱofȱtheȱfollowingȱcategories:ȱ ȱ controlȱcharactersȱ whitespaceȱcharactersȱ digitsȱ lowerȱcaseȱlettersȱ upperȱcaseȱlettersȱ punctuationȱcharactersȱ nonȬprintableȱcharactersȱ Download at http://www.pin5i.com/ 378ȱ Chapter 13 Advanced Pointer Topicsȱ Theȱcharacterȱcategoriesȱareȱtoȱbeȱasȱtheyȱareȱdefinedȱforȱtheȱctype.hȱfunctions.ȱDoȱ notȱuseȱaȱseriesȱofȱifȱstatements.ȱ 2. WriteȱaȱgeneralȬpurposeȱfunctionȱtoȱtraverseȱaȱsinglyȱlinkedȱlist.ȱItȱshouldȱtakeȱtwoȱ parameters:ȱ aȱ pointerȱ toȱ theȱ firstȱ nodeȱ inȱ theȱ listȱ andȱ aȱ pointerȱ toȱ aȱ callbackȱ function.ȱ Theȱ callbackȱ functionȱ shouldȱ takeȱ aȱ singleȱ argument,ȱ aȱ pointerȱ toȱ aȱ listȱ node,ȱandȱshouldȱbeȱinvokedȱonceȱforȱeachȱnodeȱinȱtheȱlist.ȱWhatȱdoesȱtheȱfunctionȱ needȱtoȱknowȱaboutȱtheȱnodesȱinȱtheȱlist?ȱ 3. Convertȱ theȱ followingȱ codeȱ fragmentȱ soȱ thatȱ itȱ usesȱ aȱ jumpȱ tableȱ insteadȱ ofȱ aȱ switchȱstatement.ȱ ȱ Node *list; Node *current; Transaction *transaction; typedef enum { NEW, DELETE, FORWARD, BACKWARD, SEARCH, EDIT } Trans_type; ... case NEW: add_new_trans( list, transaction ); break; case DELETE: current = delete_trans( list, current ); break; case FORWARD: current = current->next; break; case BACKWARD: current = current->prev; break; case SEARCH: current = search( list, transaction ); break; case EDIT: edit( current, transaction ); break; default: printf( "Illegal transaction type!\n" ); break; } Download at http://www.pin5i.com/ 13.10 Programming Exercises 379 4. Writeȱaȱfunctionȱcalledȱ sortȱthatȱwillȱsortȱanȱarrayȱofȱanyȱkindȱofȱvalue.ȱToȱmakeȱ theȱ functionȱ generic,ȱ oneȱ ofȱ itsȱ argumentsȱ mustȱ beȱ aȱ pointerȱ toȱ aȱ callbackȱ comparisonȱfunctionȱthatȱtheȱcallerȱwillȱsupply.ȱTheȱcomparisonȱfunctionȱwillȱtakeȱ twoȱarguments,ȱwhichȱareȱpointersȱtoȱtheȱvaluesȱbeingȱcompared,ȱȱitȱwillȱreturnȱanȱ integerȱthatȱisȱzeroȱifȱtheȱtwoȱvaluesȱareȱequal,ȱlessȱthanȱzeroȱifȱtheȱfirstȱvalueȱisȱlessȱ thanȱtheȱsecond,ȱandȱgreaterȱthanȱzeroȱifȱtheȱfirstȱvalueȱisȱgreaterȱthanȱtheȱsecond.ȱ Theȱargumentsȱtoȱsortȱwillȱbe:ȱ 1. aȱpointerȱtoȱtheȱfirstȱvalueȱinȱtheȱarrayȱtoȱbeȱsorted,ȱ 2. theȱnumberȱofȱvaluesȱinȱtheȱarray,ȱ 3. theȱsizeȱofȱeachȱarrayȱelement,ȱandȱ 4. aȱpointerȱtoȱtheȱcomparisonȱcallbackȱfunction.ȱ ȱ Theȱsortȱfunctionȱdoesȱnotȱreturnȱaȱvalue.ȱ Youȱwillȱnotȱbeȱableȱtoȱdeclareȱtheȱarrayȱargumentȱwithȱitsȱrealȱtypeȱbecauseȱtheȱ functionȱcanȱbeȱcalledȱtoȱsortȱdifferentȱtypesȱofȱarray.ȱIfȱyouȱtreatȱtheȱdataȱasȱifȱitȱ wereȱ anȱ arrayȱ ofȱ characters,ȱ youȱ canȱ useȱ theȱ thirdȱ argumentȱ bothȱ toȱ locateȱ theȱ beginningȱ ofȱ eachȱ elementȱ ofȱ theȱ actualȱ arrayȱ andȱ toȱ interchangeȱ twoȱ arrayȱ elementsȱoneȱbyteȱatȱaȱtime.ȱ Youȱ mayȱ useȱ theȱ followingȱ algorithmȱ forȱ aȱ simpleȱ exchangeȱ sort,ȱ orȱ youȱ mayȱ feelȱfreeȱtoȱuseȱanyȱbetterȱalgorithmȱyouȱknow.ȱ ȱ forȱiȱ=ȱ1ȱtoȱnumberȬofȬrecordsȱ–ȱ1ȱdoȱ ȱ forȱjȱ=ȱiȱ+ȱ1ȱtoȱnumberȬofȬrecordsȱdoȱ ȱ ȱ ifȱrecordȱiȱ>ȱrecordȱjȱthenȱ ȱ ȱ ȱ interchangeȱrecordsȱiȱandȱjȱ 5. Writingȱ theȱ codeȱ toȱ processȱ commandȱ lineȱ argumentsȱ isȱ tedious,ȱ whichȱ suggestsȱ thatȱthereȱoughtȱtoȱbeȱaȱstandardȱfunctionȱtoȱdoȱit.ȱDifferentȱprogramsȱhandleȱtheirȱ argumentsȱinȱdifferentȱways,ȱhowever,ȱsoȱtheȱfunctionȱmustȱbeȱflexibleȱinȱorderȱforȱ itȱ toȱ beȱ usefulȱ inȱ moreȱ thanȱ justȱ aȱ coupleȱ ofȱ programs.ȱ Forȱ thisȱ project,ȱ youȱ willȱ writeȱ suchȱ aȱ function.ȱ Yourȱ routineȱ willȱ provideȱ flexibilityȱ byȱ locatingȱ andȱ extractingȱtheȱarguments.ȱCallbackȱfunctionsȱprovidedȱbyȱtheȱuserȱwillȱperformȱtheȱ actualȱprocessing.ȱ Hereȱisȱaȱprototypeȱforȱyourȱfunction.ȱȱNoteȱthatȱtheȱfourthȱandȱfifthȱargumentsȱ prototypeȱcallbackȱfunctions.ȱ ȱ char ** do_args( int argc, char **argv, char *control, void (*do_arg)( int ch, char * value ), void (*illegal_arg)( int ch ) ); Download at http://www.pin5i.com/ 380ȱ Chapter 13 Advanced Pointer Topicsȱ Theȱfirstȱtwoȱparametersȱareȱthoseȱreceivedȱbyȱtheȱmainȱfunction,ȱwhichȱareȱpassedȱ unchangedȱ toȱ do_args.ȱ Theȱ thirdȱ isȱ aȱ stringȱ thatȱ identifiesȱ whatȱ commandȱ lineȱ argumentsȱ areȱ expected.ȱ Theȱ lastȱ twoȱ parametersȱ areȱ pointersȱ toȱ functionsȱ providedȱbyȱtheȱuser.ȱ do_argsȱprocessesȱcommandȱlineȱargumentsȱlikeȱthis:ȱ ȱ Skipȱpastȱtheȱprogramȱnameȱargumentȱ Whileȱtheȱnextȱargumentȱbeginsȱwithȱaȱdashȱ Forȱeachȱcharacterȱinȱtheȱargumentȱafterȱtheȱdashȱ Processȱtheȱcharacterȱ Returnȱaȱpointerȱtoȱtheȱnextȱargumentȱpointer.ȱ ȱ ToȱȈprocessȱtheȱcharacter,Ȉȱyouȱmustȱfirstȱseeȱwhetherȱtheȱcharacterȱisȱinȱtheȱcontrolȱ string.ȱIfȱitȱisȱnotȱthere,ȱcallȱtheȱfunctionȱtoȱwhichȱ illegal_argȱpoints,ȱpassingȱtheȱ characterȱ asȱ anȱ argument.ȱ Ifȱ itȱ isȱ thereȱ butȱ isȱ notȱ followedȱ byȱ aȱ plus,ȱ callȱ theȱ functionȱ toȱ whichȱ do_argȱ points,ȱ passingȱ theȱ characterȱ andȱ aȱ NULLȱ pointerȱ asȱ arguments.ȱ Ifȱtheȱcharacterȱisȱinȱ controlȱandȱisȱfollowedȱbyȱaȱplus,ȱthenȱthereȱshouldȱbeȱaȱ valueȱassociatedȱwithȱtheȱcharacter.ȱIfȱthereȱareȱanyȱmoreȱcharactersȱinȱtheȱcurrentȱ argument,ȱ theyȱ areȱ theȱ desiredȱ value.ȱ Otherwise,ȱ theȱ nextȱ argumentȱ isȱ theȱ value.ȱȱ Inȱ eitherȱ case,ȱ youȱ shouldȱ callȱ theȱ functionȱ toȱ whichȱ do_argȱ points,ȱ passingȱ asȱ argumentsȱ theȱ characterȱ andȱ aȱ pointerȱ toȱ theȱ value.ȱ Ifȱ thereȱ wasnȇtȱ aȱ valueȱ (noȱ additionalȱcharactersȱandȱnoȱnextȱargument),ȱthenȱyonȱshouldȱcallȱtheȱ illegal_argȱ functionȱ instead.ȱ Note:ȱ Beȱ sureȱ thatȱ theȱ charactersȱ inȱ theȱ valueȱ areȱ notȱ processedȱ asȱ argumentsȱlater!ȱ Whenȱ allȱ theȱ argumentsȱ thatȱ beginȱ withȱ aȱ dashȱ haveȱ beenȱ processed,ȱ youȱ shouldȱreturnȱaȱpointerȱtoȱtheȱpointerȱtoȱtheȱnextȱcommandȱlineȱargumentȱ(thatȱis,ȱaȱ valueȱsuchȱasȱ &argv[4]ȱorȱ argv + 4).ȱIfȱallȱofȱtheȱcommandȱlineȱargumentsȱbeganȱ withȱdashes,ȱyouȱwillȱreturnȱaȱpointerȱtoȱtheȱNULLȱthatȱterminatesȱtheȱcommandȱ lineȱargumentȱlist.ȱ Theȱ functionȱ mustȱ notȱ modifyȱ eitherȱ theȱ commandȱ lineȱ argumentȱ pointersȱ orȱ theȱarguments.ȱToȱillustrate,ȱsupposeȱthatȱtheȱprogramȱprogȱcallsȱthisȱfunction:ȱtheȱ followingȱexamplesȱshowȱtheȱresultsȱwithȱseveralȱdifferentȱsetsȱofȱarguments.ȱ ȱ $ prog –x –y z Commandȱline: "x" control: (*do_arg)( 'x', 0 ) do_argsȱcalls: andȱreturns: Commandȱline: control: do_argsȱcalls: (*illegal_arg)( 'y' ) &argv[3] $ prog –x –y –z "x+y+z+" (*do_arg)( 'x', "-y" ) (*illegal_arg)( 'z' ) Download at http://www.pin5i.com/ 13.10 Programming Exercises andȱreturns: Commandȱline: control: do_argsȱcalls: andȱreturns: Commandȱline: control: do_argsȱcalls: andȱreturns: &argv[4] $ prog –abcd –ef ghi jkl "ab+cdef+g" (*do_arg)( (*do_arg)( (*do_arg)( (*do_arg)( &argv[4] 'a', 'b', 'e', 'f', 0 ) "cd" ) 0 ) "ghi" ) $ prog –a b –c –d –e –f "abcdef" (*do_arg)( 'a', 0 ) &argv[2] 381 Download at http://www.pin5i.com/ Download at http://www.pin5i.com/ ȱȱ Download at http://www.pin5i.com/ 14 The Preprocessor Thereȱ areȱ manyȱ stepsȱ involvedȱ inȱ compilingȱ aȱ Cȱ program.ȱ Theȱ firstȱ stepȱ isȱ calledȱ preprocessing.ȱ Theȱ Cȱ preprocessorȱ performsȱ textualȱ manipulationsȱ onȱ theȱ sourceȱ codeȱ beforeȱ itȱ isȱ compiled.ȱ Theȱ majorȱ tasksȱ includeȱ deletingȱ comments,ȱ insertingȱ theȱ contentsȱ ofȱ #includeȇdȱ filesȱ intoȱ theȱ code,ȱ definingȱ andȱ substitutingȱ #defineȇdȱ symbols,ȱ andȱ decidingȱ whetherȱ orȱ notȱ certainȱ partsȱ ofȱ theȱ codeȱ shouldȱ beȱ compiledȱ basedȱonȱconditionalȱcompilationȱdirectives.ȱ ȱ ȱ ȱ 14.1 Predefined Symbols ȱ Tableȱ 14.1ȱ summarizesȱ theȱ symbolsȱ definedȱ byȱ theȱ preprocessor.ȱ Theȱ valuesȱ areȱ allȱ eitherȱ stringȱ literalsȱ orȱ decimalȱ constants.ȱ __FILE__ȱ andȱ __LINE__ȱ areȱ usefulȱ inȱ identifyingȱtheȱsourceȱofȱdebuggingȱoutput.ȱ __DATE__ȱandȱ __TIME__ȱareȱoftenȱusedȱtoȱ encodeȱ versionȱ informationȱ intoȱ theȱ compiledȱ program.ȱ __STDC__ȱ isȱ usedȱ inȱ conjunctionȱwithȱconditionalȱcompilationȱ(describedȱlaterȱinȱthisȱchapter)ȱforȱprogramsȱ thatȱmustȱbeȱcompiledȱinȱbothȱANSIȱandȱnonȬANSIȱenvironments.ȱ ȱ Symbol Sample Value Meaning __FILE__ "name.c" Nameȱofȱtheȱsourceȱfileȱbeingȱcompiledȱ __LINE__ 25 Lineȱnumberȱofȱtheȱcurrentȱlineȱinȱtheȱfile.ȱ __DATE__ "Jan 31 1997" Dateȱthatȱtheȱfileȱwasȱcompiled.ȱ __TIME__ "18:04:30" Timeȱthatȱtheȱfileȱwasȱcompiled.ȱ __STDC__ 1ȱifȱtheȱcompilerȱconformsȱtoȱANSIȱC,ȱelseȱundefined.ȱ ȱ Tableȱ14.1ȱȱPreprocessorȱsymbolsȱ Download at http://www.pin5i.com/ 384ȱ Chapter 14 The Preprocessorȱ 14.2 #define K&R C ȱ Youȱhaveȱalreadyȱseenȱsimpleȱusesȱofȱtheȱ #defineȱdirectiveȱthatȱgiveȱsymbolicȱnamesȱ toȱ numericȱ values.ȱ Inȱ thisȱ section,ȱ Iȇllȱ introduceȱ moreȱ usesȱ ofȱ #define.ȱ Letȇsȱ startȱ byȱ lookingȱatȱaȱmoreȱformalȱdescriptionȱofȱit.ȱ ȱ ȱ #define name stuff ȱ Wheneverȱ theȱ symbolȱ nameȱ appearsȱ afterȱ thisȱ directive,ȱ theȱ preprocessorȱ replacesȱ itȱ withȱstuff.ȱ ȱ Earlyȱ Cȱ compilersȱ requiredȱ thatȱ theȱ #ȱ appearȱ atȱ theȱ beginningȱ ofȱ aȱ line,ȱ althoughȱ itȱ couldȱbeȱfollowedȱbyȱwhiteȱspace.ȱInȱANSIȱC,ȱthisȱrestrictionȱisȱremoved.ȱ Theȱreplacementȱtextȱneedȱnotȱbeȱlimitedȱtoȱnumericȱliteralȱconstants.ȱAnyȱtextȱ canȱbeȱsubstitutedȱintoȱtheȱprogramȱwithȱaȱ#define.ȱHereȱareȱaȱfewȱexamples:ȱ ȱ #define reg #define do_forever #define CASE register for(;;) break;case ȱ Theȱfirstȱdefinitionȱmerelyȱcreatesȱaȱshortȱaliasȱforȱtheȱ registerȱkeyword.ȱThisȱshorterȱ nameȱ makesȱ itȱ easierȱ toȱ lineȱ upȱ declarationsȱ withȱ tabs.ȱ Theȱ secondȱ isȱ aȱ moreȱ descriptiveȱ synonymȱ forȱtheȱvariantȱofȱtheȱ forȱstatementȱthatȱ implementsȱ anȱinfiniteȱ loop.ȱ Finally,ȱ theȱ lastȱ oneȱ isȱ aȱ shorthandȱ notationȱ forȱ useȱ withȱ switchȱ statements.ȱ ȱ Itȱ automaticallyȱputsȱaȱ breakȱbeforeȱeachȱ caseȱthusȱmakingȱtheȱ switchȱstatementȱappearȱ toȱbeȱmoreȱlikeȱcaseȱstatementsȱinȱotherȱlanguages.ȱ ȱ Ifȱtheȱstuffȱinȱtheȱdefinitionȱisȱlong,ȱitȱcanȱbeȱsplitȱoverȱmultipleȱlinesȱbyȱendingȱ eachȱlineȱofȱtheȱdefinition,ȱexceptȱtheȱlastȱone,ȱwithȱaȱbackslash,ȱasȱinȱthisȱexample:ȱ ȱ #define DEBUG_PRINT printf( "File %s line %d:" \ " x=%d, y=%d, z=%d", \ __FILE__, __LINE__, \ x, y, z ) ȱ Iȇmȱtakingȱadvantageȱofȱtheȱfactȱthatȱadjacentȱstringȱliteralsȱareȱconcatenatedȱinȱtoȱoneȱ string.ȱ Thisȱ typeȱ ofȱ declarationȱ isȱ usefulȱ whenȱ debuggingȱ aȱ programȱ withȱ manyȱ differentȱ computationsȱ involvingȱ aȱ setȱ ofȱ variables.ȱ Itȱ makesȱ insertingȱ aȱ debuggingȱ statementȱtoȱprintȱtheirȱcurrentȱvaluesȱeasier.ȱ ȱ ȱ Download at http://www.pin5i.com/ 14.2 #defineȱ 385 x * = 2; y += x; z = x * y; DEBUG_PRINT; CAUTION! ȱ Theȱstatementȱinvokingȱ debug_printȱendsȱwithȱaȱsemicolon,ȱsoȱyouȱshouldnȇtȱhaveȱaȱ semicolonȱ atȱ theȱ endȱ ofȱ theȱ macroȱ definition.ȱ Ifȱ youȱ do,ȱ theȱ resultȱ willȱ beȱ twoȱ statements—aȱ printfȱ followedȱ byȱ anȱ emptyȱ statement.ȱ Havingȱ twoȱ statementsȱ willȱ causeȱproblemsȱinȱcontextsȱwhereȱonlyȱoneȱstatementȱisȱallowed,ȱforȱexample:ȱ ȱ if( ... ) DEBUG_PRINT; else ... ȱ Youȱcanȱalsoȱuseȱaȱ #defineȱtoȱinsertȱaȱsequenceȱofȱstatementsȱintoȱtheȱprogram.ȱ Hereȱisȱaȱdeclarationȱforȱanȱentireȱloop:ȱ ȱ #define PROCESS_LOOP \ for( i = 0; i < 10; i += 1 ){ \ sum += i; \ if( i > 0 ) \ prod *= i; \ } TIP ȱ Donȇtȱ misuseȱ thisȱ technique.ȱ Ifȱ theȱ sameȱ codeȱ isȱ neededȱ inȱ severalȱ areasȱ ofȱ theȱ program,ȱ itȱ isȱ usuallyȱ betterȱ toȱ implementȱ itȱ asȱ aȱ function.ȱ Iȇllȱ discussȱ theȱ tradeoffsȱ betweenȱ#defineȇsȱandȱfunctionsȱinȱdetailȱlaterȱinȱtheȱchapter.ȱ ȱ ȱ ȱ 14.2.1 Macros ȱ Theȱ #defineȱ mechanismȱ includesȱ aȱ provisionȱ toȱ substituteȱ argumentsȱ intoȱ theȱ text,ȱ implementingȱwhatȱareȱoftenȱcalledȱmacrosȱorȱdefinedȱmacros.ȱHereȱisȱhowȱmacrosȱareȱ declared:ȱ ȱ #define name(parameter-list) stuff ȱ Theȱ parameter-listȱ isȱ aȱ commaȬseparatedȱ listȱ ofȱ symbolsȱ thatȱ mayȱ appearȱ inȱ theȱ stuff.ȱTheȱopeningȱparenthesisȱofȱtheȱparameterȱlistȱmustȱbeȱadjacentȱtoȱtheȱname.ȱIfȱ thereȱisȱanyȱwhiteȱspaceȱbetweenȱthem,ȱtheȱparameterȱlistȱwillȱbeȱinterpretedȱasȱpartȱofȱ stuff.ȱ Download at http://www.pin5i.com/ 386ȱ Chapter 14 The Preprocessorȱ Whenȱtheȱmacroȱisȱinvoked,ȱtheȱnameȱisȱfollowedȱbyȱaȱcommaȬseparatedȱlistȱofȱ values,ȱ oneȱ forȱ eachȱ parameter,ȱ enclosedȱ inȱ parentheses.ȱ Theȱ actualȱ valueȱ givenȱ forȱ eachȱparameterȱisȱsubstitutedȱintoȱtheȱstuffȱwheneverȱtheȱparameterȱappears.ȱ Hereȱisȱaȱmacroȱthatȱtakesȱoneȱparameter:ȱ ȱ #define SQUARE(x) x * x ȱ Ifȱyouȱputȱ ȱ SQUARE( 5 ) ȱ inȱtheȱprogramȱafterȱthisȱdeclaration:ȱtheȱpreprocessorȱsubstitutesȱ ȱ 5 * 5 CAUTION! ȱ inȱitsȱplace.ȱ Thereȱisȱaȱproblemȱwithȱthisȱmacro,ȱhowever.ȱLookȱatȱthisȱfragmentȱofȱcode;ȱ ȱ a = 5; printf( "%d\n", SQUARE( a + 1 ) ); ȱ Atȱfirstȱglance,ȱyouȱwouldȱexpectȱthatȱthisȱcodeȱwouldȱprintȱ36.ȱInȱfact,ȱitȱprintsȱ 11.ȱToȱ seeȱwhy,ȱ lookȱatȱtheȱ macroȱ textȱ thatȱisȱ substituted.ȱ Theȱparameterȱ xȱisȱreplacedȱwithȱ theȱtextȱa + 1,ȱsoȱtheȱstatementȱisȱactuallyȱ ȱ printf( "%d\n", a + 1 * a + 1 ); ȱ Theȱproblemȱisȱnowȱclear:ȱtheȱexpressionȱresultingȱfromȱtheȱsubstitutionȱisȱnotȱbeingȱ evaluatedȱinȱtheȱintendedȱorder.ȱ Thisȱerrorȱisȱeasyȱtoȱcorrectȱbyȱaddingȱparenthesesȱtoȱtheȱmacroȱdefinition:ȱ ȱ #define SQUARE(x) (x) * (x) ȱ Theȱpreprocessorȱnowȱsubstitutesȱthisȱstatement,ȱwhichȱhasȱtheȱexpectedȱresult,ȱinȱtheȱ previousȱexample,ȱ ȱ printf( "%d\n", ( a + 1 ) * ( a + 1 ) ); ȱ Hereȱisȱanotherȱmacroȱdefinition.ȱ ȱ #define DOUBLE(x) (x) + (x) ȱ Theȱparenthesesȱareȱinȱplaceȱtoȱavoidȱtheȱearlierȱproblem,ȱbutȱaȱdifferentȱerrorȱ canȱoccurȱwithȱthisȱmacro.ȱWhatȱvalueȱisȱprintedȱbyȱtheȱfollowingȱcode?ȱ Download at http://www.pin5i.com/ 14.2 #defineȱ 387 a = 5; printf( "%d\n", 10 * DOUBLE( a ) ); ȱ Itȱlooksȱlikeȱitȱshouldȱprintȱ100,ȱbutȱinȱfactȱitȱprintsȱ55.ȱAgain,ȱtheȱtextȱresultingȱfromȱ theȱmacroȱsubstitutionȱrevealsȱtheȱproblem:ȱ ȱ printf( "%d\n", 10 * ( a ) + ( a ) ); ȱ Theȱ multiplicationȱ isȱ performedȱ beforeȱ theȱ additionȱ definedȱ inȱ theȱ macroȱ isȱ completed.ȱ Thisȱ errorȱ isȱ alsoȱ easyȱ toȱ fix:ȱ surroundȱ theȱ entireȱ expressionȱ withȱ parenthesesȱwhenȱtheȱmacroȱisȱdefined.ȱ ȱ #define DOUBLE(x) TIP ( (x) + (x) ) ȱ Allȱmacroȱdefinitionȱthatȱevaluateȱnumericȱexpressionsȱshouldȱbeȱparenthesizedȱinȱthisȱ mannerȱ toȱ avoidȱ unexpectedȱ interactionsȱ withȱ operatorsȱ inȱ theȱ argumentsȱ orȱ withȱ operatorsȱadjacentȱtoȱwhereȱtheȱmacroȱisȱused.ȱ Hereȱisȱanȱinterestingȱpairȱofȱmacros:ȱ ȱ #define repeat #define until( x ) do while( ! (x) ) ȱ Theseȱ createȱ aȱ ȈnewȈȱ loop,ȱ whichȱ worksȱ theȱ sameȱ asȱ theȱ repeat/untilȱ loopȱ inȱ otherȱlanguages.ȱItȱisȱusedȱlikeȱthis:ȱ ȱ repeat { statements } until( i >= 10 ); ȱ Theȱpreprocessorȱsubstitutesȱtheȱfollowingȱcode.ȱ ȱ do { statements } while( ! ( i >= 10 ) ); TIP ȱ Theȱ parenthesesȱ aroundȱ theȱ expressionȱ makeȱ sureȱ thatȱ itȱ isȱ completelyȱ evaluatedȱ beforeȱtheȱ!ȱoperatorȱcomplementsȱitsȱvalue.ȱ ȱ Itȱisȱpossibleȱtoȱcreateȱsuitesȱofȱ #defineȱmacrosȱinȱorderȱtoȱwriteȱCȱprogramsȱthatȱlookȱ likeȱ otherȱ languages.ȱ Inȱ mostȱ cases,ȱ youȱ shouldȱ avoidȱ thisȱ temptationȱ becauseȱ theȱ resultingȱ programsȱ areȱ difficultȱ forȱ otherȱ Cȱ programmersȱ toȱ understand.ȱ Theyȱ mustȱ constantlyȱ lookȱ upȱ theȱ definitionsȱ toȱ seeȱ whatȱ isȱ reallyȱ happening.ȱ Evenȱ ifȱ everyoneȱ workingȱonȱtheȱprojectȱnowȱandȱforȱtheȱrestȱofȱtheȱprojectȇsȱlifeȱisȱfamiliarȱwithȱtheȱotherȱ language,ȱthisȱtechniqueȱmayȱcauseȱconfusionȱbecauseȱofȱaspectsȱofȱtheȱotherȱlanguageȱ cannotȱbeȱmimickedȱexactly.ȱ Download at http://www.pin5i.com/ Chapter 14 The Preprocessorȱ 388ȱ 14.2.2 #define Substitution ȱ Thereȱ areȱ severalȱ stepsȱ involvedȱ inȱ expandingȱ #defineȇdȱ symbolsȱ andȱ macrosȱ inȱ theȱ program.ȱ ȱ 1. Forȱmacroȱinvocations,ȱtheȱargumentsȱareȱfirstȱexaminedȱtoȱseeȱifȱtheyȱcontainȱanyȱ #defineȇdȱsymbols.ȱȱIfȱso,ȱtheyȱareȱreplacedȱfirst.ȱ 2. Theȱsubstitutionȱtextȱisȱthenȱinsertedȱintoȱtheȱprogramȱinȱplaceȱofȱtheȱoriginalȱtext.ȱ Forȱmacros,ȱtheȱargumentȱnamesȱareȱreplacedȱbyȱtheirȱvalues.ȱ 3. Finally,ȱ theȱ resultingȱ textȱ isȱ scannedȱ againȱ toȱ seeȱ ifȱ itȱ containsȱ anyȱ #defineȇdȱ symbols;ȱifȱso,ȱtheȱprocessȱisȱrepeated.ȱ ȱ Thus,ȱmacroȱargumentsȱandȱ#defineȱdefinitionsȱmayȱcontainȱotherȱ#defineȇdȱsymbols.ȱ Macrosȱmayȱnotȱbeȱrecursive,ȱhowever.ȱ Stringȱ literalsȱ areȱ notȱ examinedȱ whenȱ theȱ preprocessorȱ isȱ searchingȱ forȱ #defineȇdȱ symbols.ȱ Thereȱ areȱ twoȱ techniquesȱ thatȱ areȱ usefulȱ inȱ injectingȱ macroȱ argumentȱvaluesȱintoȱstringȱliterals.ȱFirst,ȱtheȱconcatenationȱofȱadjacentȱstringsȱmakesȱ itȱeasyȱtoȱbreakȱaȱstringȱintoȱpieces,ȱoneȱofȱwhichȱisȱactuallyȱaȱmacroȱargument.ȱHereȱisȱ anȱexampleȱofȱthisȱtechnique:ȱ ȱ #define PRINT(FORMAT,VALUE) \ printf( "The value is " FORMAT "\n", VALUE ) ... PRINT( "%d", x + 3 ); ȱ Thisȱtechniqueȱonlyȱworksȱifȱaȱstringȱliteralȱisȱgivenȱasȱtheȱmacroȱargument.ȱ Theȱsecondȱtechniqueȱusesȱtheȱpreprocessorȱtoȱconvertȱaȱmacroȱargumentȱtoȱaȱ string.ȱTheȱconstructȱ #argumentȱisȱtranslatedȱbyȱtheȱpreprocessorȱintoȱȈargumentȈ.ȱThisȱ translationȱletsȱyouȱwriteȱcodeȱlikeȱthis:ȱ ȱ #define PRINT(FORMAT,VALUE) printf( "The value of " #VALUE " is " FORMAT "\n", VALUE ) ... PRINT( "%d", x + 3 ); \ \ ȱ whichȱproducesȱthisȱoutput:ȱ ȱ The value of x + 3 is 25 ȱ Theȱ ##ȱ constructȱ performsȱ aȱ differentȱ task.ȱ Itȱ causesȱ theȱ twoȱ tokensȱ onȱ eitherȱ sideȱ ofȱ itȱ toȱ beȱ concatenated.ȱ Amongȱ otherȱ uses,ȱ thisȱ capabilityȱ allowsȱ macroȱ definitionsȱtoȱconstructȱidentifiersȱfromȱseparateȱpiecesȱofȱtext.ȱTheȱfollowingȱexampleȱ usesȱconcatenationȱtoȱaddȱaȱvalueȱtoȱoneȱofȱseveralȱvariables:ȱ Download at http://www.pin5i.com/ 14.2 #defineȱ #define ADD_TO_SUM( sum_number, value ) sum ## sum_number += value ... ADD_TO_SUM( 5, 25 ); 389 \ ȱ Theȱlastȱstatementȱaddsȱtheȱvalueȱ25ȱtoȱtheȱvariableȱ sum5.ȱNoteȱthatȱtheȱconcatenationȱ mustȱresultȱinȱaȱlegalȱconstruct,ȱotherwiseȱtheȱresultȱisȱundefined.ȱ ȱ ȱ ȱ 14.2.3 Macros versus Functions ȱ Macrosȱareȱfrequentlyȱusedȱtoȱperformȱsimpleȱcomputations,ȱsuchȱasȱfindingȱtheȱlargerȱ (orȱsmaller)ȱofȱtwoȱexpressions:ȱ ȱ #define MAX( a, b ) ( (a) > (b) ? (a) : (b) ) ȱ Whyȱnotȱuseȱaȱfunctionȱtoȱaccomplishȱthisȱtask?ȱThereȱareȱtwoȱreasons.ȱȱFirst,ȱtheȱcodeȱ neededȱ toȱ callȱ andȱ returnȱ fromȱ aȱ functionȱ isȱ likelyȱ toȱ beȱ largerȱ thanȱ theȱ codeȱ thatȱ actuallyȱ performsȱ thisȱ smallȱ amountȱ ofȱ work,ȱ soȱ theȱ macroȱ makesȱ theȱ programȱ bothȱ smallerȱandȱfasterȱthanȱusingȱaȱfunction.ȱ Moreȱ important,ȱ though,ȱ isȱ theȱ factȱ thatȱ aȱ functionȇsȱ parametersȱ mustȱ beȱ declaredȱtoȱbeȱaȱspecificȱtype,ȱsoȱitȱcanȱonlyȱbeȱcalledȱwithȱexpressionsȱofȱtheȱproperȱ type.ȱOnȱtheȱotherȱhand,ȱthisȱparticularȱmacroȱcanȱbeȱusedȱforȱintegers,ȱlongs,ȱfloats,ȱ doubles,ȱ andȱ anyȱ otherȱ typeȱ whoseȱ valuesȱ mayȱ beȱ comparedȱ withȱ theȱ >ȱ operator.ȱ Inȱ otherȱwords,ȱmacrosȱareȱtypeless.ȱ Theȱdisadvantageȱtoȱusingȱmacrosȱasȱopposedȱtoȱfunctionsȱisȱthatȱaȱcopyȱofȱtheȱ codeȱ isȱ insertedȱ intoȱ theȱ programȱ eachȱ timeȱ theȱ macroȱ isȱ used.ȱ Unlessȱ theȱ macroȱ isȱ veryȱshort,ȱusingȱmacrosȱcanȱgreatlyȱincreaseȱtheȱsizeȱofȱtheȱprogram.ȱ Thereȱ areȱ someȱ tasksȱ thatȱ functionsȱ simplyȱ cannotȱ accomplish.ȱ Letȇsȱ takeȱ aȱ closerȱlookȱatȱtheȱmacroȱdefinedȱinȱProgramȱ11.1ȱa.ȱȱTheȱsecondȱargumentȱtoȱtheȱmacroȱ isȱaȱtype,ȱwhichȱcannotȱbeȱpassedȱasȱaȱfunctionȱargument.ȱ ȱ #define MALLOC(n, type) \ ( (type *)malloc( (n) * sizeof( type ) ) ) ȱ Youȱ canȱ nowȱ seeȱexactlyȱ howȱ thisȱ macroȱworks.ȱ Theȱ firstȱ statementȱ inȱ theȱ followingȱ exampleȱisȱconvertedȱbyȱtheȱpreprocessorȱtoȱtheȱsecondȱstatement.ȱ ȱ pi = MALLOC( 25, int ); pi = ( ( int * )malloc( ( 25 ) * sizeof( int ) ) ); ȱ Again,ȱ noticeȱ thatȱ theȱ definitionȱ ofȱ theȱ macroȱ doesȱ notȱ endȱ withȱ aȱ semicolon.ȱ Theȱ semicolonȱappearsȱonȱtheȱstatementȱthatȱinvokesȱtheȱmacro.ȱ Download at http://www.pin5i.com/ Chapter 14 The Preprocessorȱ 390ȱ 14.2.4 Macro Arguments with Side Effects ȱ Whenȱmacroȱparametersȱappearȱmoreȱthanȱonceȱinȱtheȱdefinition,ȱthereȱisȱtheȱdangerȱ ofȱunexpectedȱresultsȱwhenȱtheȱmacroȱisȱusedȱwithȱargumentsȱthatȱhaveȱsideȱeffects.ȱAȱ sideȱeffectȱisȱaȱpermanentȱeffectȱcausedȱbyȱevaluatingȱtheȱexpression.ȱForȱexample,ȱtheȱ expressionȱ ȱ x + 1 ȱ canȱ beȱ evaluatedȱ hundredsȱ ofȱ timesȱ andȱ theȱ sameȱ resultȱ willȱ beȱ obtainedȱ eachȱ rime.ȱ Thisȱexpressionȱdoesnȇtȱhaveȱanyȱsideȱeffects.ȱButȱ ȱ x++ ȱ hasȱ aȱ sideȱ effect:ȱ itȱ incrementsȱ x.ȱ Theȱ nextȱ timeȱ thisȱ expressionȱ isȱ evaluated,ȱ itȱ willȱ produceȱ aȱ differentȱ result.ȱ Theȱ MAXȱ macroȱ demonstratesȱ theȱ problemsȱ causedȱ byȱ argumentsȱwithȱsideȱeffects.ȱTraceȱtheȱfollowingȱcode.ȱWhatȱdoȱyouȱthinkȱitȱwillȱprintȱ out?ȱ ȱ #define MAX( a, b ) ( (a) > (b) ? (a) : (b) ) ... x = 5; y = 8; z = MAX( x++, y++ ); printf( "x=%d, y=%d, z=%d\n", x, y, z ); ȱ Thisȱ problemȱ isȱ notȱ easy.ȱ Keepȱ inȱ mindȱ thatȱ theȱ firstȱ expressionȱ inȱ theȱ conditionalȱ determinesȱ whichȱ oneȱ ofȱ theȱ otherȱ twoȱ expressionsȱ willȱ beȱ evaluated.ȱ Theȱ otherȱ expressionȱisȱnotȱevaluatedȱatȱall.ȱTheȱresultȱisȱx=6,ȱy=10,ȱz=9.ȱ Asȱ usual,ȱ theȱ strangeȱ resultȱ becomesȱ clearerȱ byȱ examiningȱ theȱ codeȱ thatȱ isȱ substitutedȱforȱtheȱmacro:ȱ ȱ z = ( ( x++ ) > ( y++ ) ? ( x++ ) : ( y++ ) ); ȱ Althoughȱ theȱ smallerȱ valueȱ isȱ incrementedȱ once,ȱ theȱ largerȱ valueȱ isȱ incrementedȱ twice—onceȱ duringȱ theȱ comparisonȱ andȱ againȱ whenȱ theȱ expressionȱ afterȱ theȱ ?ȱ isȱ evaluated.ȱ Sideȱ effectsȱ areȱ notȱ limitedȱ onlyȱ toȱ changingȱ theȱ valuesȱ ofȱ variables.ȱ Theȱ expressionȱ ȱ getchar() ȱ hasȱ aȱ sideȱ effect.ȱ Callingȱ theȱ functionȱ consumesȱ aȱ characterȱ ofȱ input,ȱ soȱ subsequentȱ callsȱ retrieveȱ differentȱ characters.ȱ Theȱ expressionȱ mustȱ notȱ beȱ evaluatedȱ repeatedlyȱ unlessȱtheȱintentȱisȱtoȱconsumeȱinputȱcharacters.ȱ Download at http://www.pin5i.com/ 14.2 #defineȱ 391 Considerȱtheȱfollowingȱmacro.ȱ ȱ #define EVENPARITY( ch ) ( ( count_one_bits( ch ) & 1 ) ? ( ch ) | PARITYBIT : ( ch ) ) \ \ ȱ Itȱusesȱtheȱ count_one_bitsȱfunctionȱfromȱProgramȱ5.1ȱthatȱreturnsȱtheȱnumberȱofȱoneȬ bitsȱ inȱ itsȱ argument.ȱ Theȱ purposeȱ ofȱ theȱ macroȱ isȱ toȱ generateȱ aȱ characterȱ withȱ evenȱ parity. 45 ȱItȱfirstȱcountsȱtheȱnumberȱofȱonesȱinȱtheȱcharacter,ȱandȱifȱtheȱresultȱisȱanȱoddȱ numberȱtheȱ PARITYBITȱvalueȱ(aȱoneȬbit)ȱisȱORȇedȱinȱwithȱtheȱcharacter;ȱotherwiseȱtheȱ characterȱ isȱ usedȱ unchanged.ȱ Butȱ imagineȱ whatȱ happensȱ whenȱ theȱ macroȱ isȱ usedȱ inȱ thisȱmanner:ȱ ȱ ch = EVENPARITY( getchar() ); ȱ Theȱstatementȱlooksȱreasonable:ȱreadȱaȱcharacterȱandȱcomputeȱitsȱparity.ȱHowever,ȱitȱ failsȱbecauseȱitȱactuallyȱreadsȱtwoȱcharacters!ȱ ȱ ȱ ȱ 14.2.5 Naming Conventions ȱ #defineȇdȱ macrosȱ behaveȱ differentlyȱ thanȱ trueȱ functionsȱ inȱ aȱ numberȱ ofȱ ways,ȱ asȱ TIP summarizedȱ inȱ Tableȱ 14.2.ȱ Becauseȱ ofȱ theseȱ differences,ȱ itȱ isȱ veryȱ importantȱ thatȱ theȱ programmerȱknowsȱwhetherȱanȱidentifierȱisȱaȱmacroȱorȱaȱfunction.ȱUnfortunately,ȱtheȱ syntaxȱforȱusingȱmacrosȱisȱidenticalȱtoȱtheȱsyntaxȱforȱfunctions,ȱsoȱtheȱlanguageȱdoesnȇtȱ helpȱhighlightȱtheȱdifference.ȱ ȱ Thisȱconfusionȱisȱoneȱreasonȱitȱisȱimportantȱtoȱadoptȱaȱnamingȱconventionȱforȱmacrosȱ (andȱ forȱ mostȱ otherȱ #defineȇdȱ symbolsȱ asȱ well).ȱ Aȱ commonȱ conventionȱ isȱ toȱ makeȱ macroȱnamesȱallȱuppercaseȱletters.ȱInȱtheȱstatementȱ ȱ value = max( a, b ); ȱ itȱisȱnotȱapparentȱwhetherȱmaxȱisȱaȱfunctionȱorȱaȱmacro.ȱYouȱhaveȱtoȱprobeȱtheȱsourceȱ fileȱandȱanyȱheaderȱfilesȱitȱincludedȱtoȱfindȱoutȱforȱsure.ȱOnȱtheȱotherȱhand,ȱinȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱ Parityȱ isȱ anȱ errorȱ detectionȱ mechanism.ȱ Beforeȱ dataȱ isȱ scoredȱ orȱ transmittedȱ overȱ aȱ communicationsȱ line,ȱ aȱ parityȱ bitȱ isȱ computedȱwithȱaȱvalueȱthatȱmakesȱtheȱtotalȱnumberȱofȱoneȬbitsȱanȱevenȱnumber.ȱLater,ȱtheȱdataȱcanȱbeȱverifiedȱbyȱcountingȱ theȱnumberȱofȱoneȬbits;ȱifȱtheȱresultȱisȱodd,ȱanȱerrorȱhasȱoccurred.ȱThisȱtechniqueȱisȱcalledȱevenȱparity.ȱOddȱparityȱworksȱtheȱ sameȱway,ȱexceptȱthatȱtheȱparityȱbitȱisȱcomputedȱsoȱthatȱtheȱtotalȱnumberȱofȱoneȬbitsȱisȱanȱoddȱnumber.ȱ ȱ 45 Download at http://www.pin5i.com/ Chapter 14 The Preprocessorȱ 392ȱ ȱ Property #define Macro Function Codeȱsizeȱ Macroȱ codeȱ isȱ insertedȱ intoȱ theȱ programȱ eachȱ timeȱ theȱ macroȱ isȱ used.ȱProgramȱendsȱupȱbeingȱlargerȱ forȱallȱbutȱtheȱsmallestȱmacros.ȱ Functionȱcodeȱappearsȱonlyȱonce;ȱcallsȱtoȱtheȱ functionȱ appearȱ eachȱ timeȱ theȱ functionȱ isȱ used.ȱ Executionȱ speedȱ Faster.ȱ Extraȱoverheadȱofȱfunctionȱcall/return.ȱ Operatorȱ precedenceȱ Macroȱ argumentsȱ areȱ evaluatedȱ inȱ theȱ contextȱ ofȱ anyȱ surroundingȱ expression;ȱ unlessȱ parenthesized,ȱ theȱprecedenceȱofȱadjacentȱoperatorsȱ canȱyieldȱunexpectedȱresults.ȱ Functionȱ argumentsȱ areȱ evaluatedȱ onceȱ whenȱ theȱ functionȱ isȱ called;ȱ theȱ resultingȱ valueȱ isȱ passedȱ toȱ theȱ function.ȱ Expressionȱ evaluationȱisȱmoreȱpredictable.ȱ Argumentȱ evaluationȱ Argumentsȱ evaluatedȱ everyȱ timeȱ theyȱ areȱ usedȱ inȱ theȱ macroȱ definition;ȱ argumentsȱ withȱ sideȱ effectsȱ canȱ produceȱ unexpectedȱ resultsȱdueȱtoȱmultipleȱevaluations.ȱ ArgumentsȱevaluatedȱonlyȱonceȱbeforeȱfuncȬ tionȱ isȱ called;ȱ multipleȱ usesȱ ofȱ argumentsȱ inȱ theȱ functionȱ doȱ notȱ causeȱ multipleȱ evaluaȬ tions.ȱ Sideȱ effectsȱ inȱ argumentsȱ doȱ notȱ poseȱ anyȱspecialȱproblems.ȱ Argumentȱ typesȱ Macrosȱareȱtypeless;ȱworkȱwithȱanyȱ argumentȱ typeȱ forȱ whichȱ theȱ operationsȱperformedȱareȱlegal.ȱ Functionȱargumentsȱareȱtyped;ȱseparateȱfuncȬ tionsȱareȱneededȱforȱdifferentȱargumentȱtypesȱ evenȱifȱtheȱworkȱperformedȱisȱidentical.ȱ ȱ Tableȱ14.2ȱȱDifferencesȱbetweenȱmacrosȱandȱfunctionsȱ ȱ ȱ ȱ ȱ ȱ ȱ value = MAX( a, b ); ȱ thenȱnamingȱconventionȱmakesȱitȱobvious.ȱThisȱconventionȱisȱespeciallyȱimportantȱinȱ macrosȱthatȱmightȱbeȱusedȱwithȱargumentsȱthatȱhaveȱsideȱeffects,ȱbecauseȱitȱalertsȱtheȱ programmerȱ toȱ theȱ needȱ toȱ evaluateȱ theȱ argumentȱ intoȱ aȱ temporaryȱ variableȱ beforeȱ usingȱitȱinȱtheȱmacro.ȱ ȱ ȱ ȱ 14.2.6 #undef ȱ ThisȱdirectiveȱunȬ#defineȇsȱaȱnameȱbyȱremovingȱitsȱdefinition.ȱ ȱ #undef name ȱ Ifȱ anȱ existingȱ nameȱ isȱ toȱ beȱ redefined,ȱ theȱ oldȱ definitionȱ mustȱ firstȱ beȱ removedȱ withȱ #undef.ȱ Download at http://www.pin5i.com/ 14.2 #defineȱ 14.2.7 393 Command Line Definitions ȱ Manyȱ Cȱ compilersȱ provideȱ theȱ abilityȱ toȱ defineȱ symbolsȱ onȱ theȱ commandȱ lineȱ thatȱ initiatesȱtheȱcompilation.ȱThisȱfeatureȱisȱusefulȱwhenȱcompilingȱdifferentȱversionsȱofȱaȱ programȱ fromȱ theȱ sameȱ sourceȱ file.ȱ Forȱ example,ȱ supposeȱ aȱ particularȱ programȱ declaresȱanȱarrayȱofȱaȱcertainȱsize.ȱOnȱmachinesȱwithȱlimitedȱmemoryȱtheȱarrayȱmustȱ beȱsmall,ȱbutȱonȱmachinesȱwithȱlotsȱofȱmemoryȱyouȇdȱpreferȱtoȱmakeȱtheȱarrayȱlarger.ȱ Ifȱtheȱarrayȱisȱdeclaredȱusingȱaȱsymbolȱlikeȱthis.ȱ ȱ int array[ARRAY_SIZE]; ȱ thenȱtheȱvalueȱforȱ ARRAY_SIZEȱcanȱbeȱgivenȱonȱtheȱcommandȱlineȱwhenȱtheȱprogramȱisȱ compiled.ȱ OnȱUNKȱcompilers,ȱtheȱ -Dȱoptionȱdoesȱthisȱjob.ȱThereȱareȱtwoȱwaysȱtoȱuseȱthisȱ option.ȱ ȱ -Dname -Dname=stuff ȱ Theȱfirstȱformȱdefinesȱtheȱsymbolȱ nameȱtoȱhaveȱtheȱvalueȱone.ȱTheȱsecondȱformȱdefinesȱ theȱ symbolȇsȱ valueȱ toȱ beȱ theȱ stuffȱ afterȱ theȱ equalȱ sign.ȱ Theȱ Borlandȱ Cȱ compilersȱ forȱ MSȬDOSȱ provideȱ theȱ sameȱ capabilityȱ withȱ theȱ sameȱ syntax.ȱ Consultȱ yourȱ compilerȇsȱ documentationȱforȱinformationȱaboutȱyourȱsystem.ȱ Toȱ returnȱ toȱ ourȱ example,ȱ theȱ commandȱ lineȱ toȱ compileȱ thisȱ programȱ onȱ aȱ UNIXȱsystemȱmightȱlookȱlikeȱthis:ȱ ȱ cc –DARRAY_SIZE=100 prog.c ȱ Thisȱ exampleȱ illustratesȱ anotherȱ benefitȱ thatȱ youȱ getȱ byȱ parameterizingȱ quantitiesȱsuchȱasȱarrayȱsizesȱinȱtheȱprogram.ȱIfȱtheȱarrayȱsizeȱwereȱgivenȱasȱaȱliteralȱ constantȱinȱtheȱdeclaration,ȱorȱifȱtheȱarrayȱwereȱeverȱaccessedȱwithinȱaȱloopȱthatȱusedȱaȱ literalȱconstantȱasȱaȱlimit,ȱtheȱtechniqueȱwouldȱnotȱwork.ȱTheȱsymbolicȱconstantȱmustȱ beȱusedȱwhereverȱyouȱneedȱtoȱreferenceȱtheȱsizeȱofȱtheȱarrays.ȱ Compilersȱ thatȱ offerȱ commandȬlineȱ definitionȱ ofȱ symbolsȱ usuallyȱ offerȱ commandȬlineȱunȬdefinitionȱofȱsymbols.ȱOnȱUNIXȱcompilers,ȱtheȱ -Uȱoptionȱperformsȱ this.ȱ Specifyingȱ -Unameȱ causesȱ theȱ initialȱ definitionȱ ofȱ nameȱ inȱ theȱ programȱ toȱ beȱ ignored.ȱThisȱfeatureȱisȱusefulȱinȱconjunctionȱwithȱconditionalȱcompilation.ȱ Download at http://www.pin5i.com/ 394ȱ Chapter 14 The Preprocessorȱ 14.3 Conditional Compilation ȱ ȱ Itȱ isȱ oftenȱ handyȱ toȱ beȱ ableȱ toȱ selectȱ whetherȱ certainȱ statementsȱ orȱ groupsȱ ofȱ statementsȱ shouldȱ beȱ translatedȱ orȱ ignoredȱ whenȱ compilingȱ aȱ program.ȱ Statementsȱ usedȱsolelyȱinȱtheȱdebuggingȱofȱaȱprogramȱareȱanȱobviousȱexample.ȱTheyȱshouldȱnotȱ appearȱ inȱ productionȱ versionsȱ ofȱ theȱ program,ȱ yetȱ youȱ wouldȱ ratherȱ notȱ physicallyȱ removeȱthemȱfromȱtheȱsourceȱcodeȱasȱtheyȱmightȱbeȱneededȱforȱdebuggingȱagainȱafterȱ theȱprogramȱhasȱundergoneȱsomeȱmaintenanceȱmodifications.ȱ ȱ Conditionalȱcompilationȱisȱperfectȱforȱthisȱpurpose.ȱWithȱconditionalȱcompilation,ȱ selectedȱpartsȱofȱtheȱcodeȱcanȱbeȱeitherȱcompiledȱnormallyȱorȱcompletelyȱignored.ȱTheȱ basicȱ constructȱ toȱ supportȱ conditionalȱ compilationȱ isȱ theȱ #ifȱ directiveȱ withȱ itsȱ matchingȱ#endif.ȱTheȱsyntaxȱforȱitsȱsimplestȱformȱisȱshownȱbelow.ȱ ȱ #if constant-expression statements #endif ȱ Theȱ constant-expressionȱ isȱ evaluatedȱ byȱ theȱ preprocessor.ȱ Ifȱ itsȱ valueȱ isȱ nonzeroȱ (true),ȱ thenȱ the statementsȱ areȱ compiledȱ normally;ȱ otherwiseȱ theȱ preprocessorȱ silentlyȱdeletesȱthem.ȱ ȱ Aȱconstantȱexpressionȱisȱonȱwhoseȱtermsȱareȱeitherȱliteralȱconstantsȱorȱ #defineȇdȱ symbols.ȱVariablesȱthatȱdoȱnotȱattainȱtheirȱvaluesȱuntilȱexecutionȱtimeȱareȱnotȱlegalȱinȱ constantȱexpressionsȱbecauseȱtheirȱvaluesȱcannotȱbeȱpredictedȱatȱcompileȱtime.ȱ Forȱexample,ȱbracketingȱallȱyourȱdebuggingȱcodeȱlikeȱthis:ȱ ȱ #if DEBUG printf( "x=%d, y=%d\n", x, y ); #endif ȱ makesȱitȱeasyȱtoȱeitherȱcompileȱorȱignoreȱtheȱcode.ȱToȱcompileȱit,ȱ ȱ #define DEBUG 1 ȱ wouldȱ beȱ used.ȱ Toȱ ignoreȱ it,ȱ thisȱ symbolȱ wouldȱ beȱ definedȱ asȱ 0ȱ instead.ȱ Theȱ codeȱ remainsȱinȱtheȱsourcesȱfileȱinȱeitherȱcase.ȱ ȱ Anotherȱ useȱ ofȱ conditionalȱ compilationȱ isȱ toȱ selectȱ betweenȱ differentȱ alternativesȱwhenȱcompiling.ȱToȱsupportȱthisȱcapability,ȱtheȱ #ifȱdirectiveȱhasȱoptionalȱ #elifȱandȱ#elseȱclauses.ȱTheȱcompleteȱsyntaxȱlooksȱlikeȱthis:ȱ ȱ ȱ Download at http://www.pin5i.com/ 14.3 Conditional Compilationȱ 395 #if constant-expression statements #elif constant-expression other statements ... #else other statements #endif K&R C ȱ Thereȱ mayȱ beȱ anyȱ numberȱ ofȱ #elifȱ clauses.ȱ Theȱ constant-expressionȱ inȱ eachȱ isȱ evaluatedȱ onlyȱ ifȱ noneȱ ofȱ theȱ previousȱ onesȱ areȱ true.ȱ Theȱ statementsȱ inȱ theȱ #elseȱ clauseȱ areȱ compiledȱ onlyȱ whenȱ allȱ ofȱ theȱ expressionsȱ areȱ false,ȱ otherwiseȱ theyȱ areȱ ignored.ȱ ȱ Theȱ originalȱ K&Rȱ Cȱ didȱ notȱ haveȱ anȱ #elifȱ directive.ȱ However,ȱ directivesȱ canȱ beȱ nestedȱtoȱachieveȱtheȱsameȱresultȱwithȱsuchȱcompilers.ȱ Theȱ followingȱ exampleȱ isȱ fromȱ aȱ programȱ thatȱ isȱ soldȱ inȱ severalȱ differentȱ versions.ȱEachȱversionȱhasȱaȱdifferentȱsetȱofȱoptionalȱfeatures.ȱTheȱchallengeȱinȱwritingȱ thisȱcodeȱwasȱfiguringȱoutȱhowȱtoȱproduceȱtheȱvariousȱversions.ȱYouȱmustȱavoidȱatȱallȱ costsȱwritingȱaȱdifferentȱsetȱofȱsourceȱfilesȱforȱeachȱversion!ȱMostȱofȱtheȱcodeȱinȱeachȱsetȱ wouldȱbeȱidenticalȱandȱmaintainingȱtheȱprogramȱwouldȱbeȱaȱnightmare.ȱFortunately,ȱ conditionalȱcompilationȱdoesȱtheȱjob.ȱ ȱ if( feature_selected == FEATURE1 ) #if FEATURE1_ENABLED_FULLY feature1_function( arguments ); #elif FEATURE1_ENABLED_PARTIALLY feature1_partial_function( arguments ); #else printf( "To use this feature, send $39.95;" " allow ten weeks for delivery. \n" ); #endif ȱ Thereȱisȱonlyȱoneȱsingleȱsetȱofȱsourceȱfiles.ȱWhenȱtheyȱareȱcompiled,ȱsymbolsȱforȱeachȱ ofȱtheȱdesiredȱfeaturesȱ(orȱfeatureȱlevels)ȱareȱdefinedȱasȱone,ȱandȱtheȱremainingȱsymbolȱ areȱdefinedȱasȱzero.ȱ ȱ ȱ ȱ 14.3.1 If Defined ȱ Itȱ isȱ alsoȱ possibleȱ toȱ testȱ whetherȱ orȱ notȱ aȱ symbolȱ isȱ defined.ȱ Thisȱ taskȱ isȱ oftenȱ moreȱ convenientȱforȱconditionalȱcompilationȱbecauseȱtheȱsymbolȱcontrollingȱtheȱcompilationȱ needȱ notȱ beȱ definedȱ atȱ allȱ unlessȱ theȱ featureȱ itȱ controlsȱ isȱ wanted.ȱ Thisȱ testȱ canȱ beȱ madeȱinȱanyȱofȱtheȱfollowingȱways:ȱ Download at http://www.pin5i.com/ Chapter 14 The Preprocessorȱ 396ȱ ȱ #if #ifdef defined(symbol) symbol #if #ifndef !defined(symbol) symbol ȱ Theȱ membersȱofȱeachȱofȱtheseȱpairsȱareȱ equivalentȱtoȱ eachȱother,ȱ butȱ theȱ #ifȱformȱ isȱ moreȱversatileȱbecauseȱtheȱconstantȱexpressionȱmayȱcontainȱadditionalȱterms,ȱasȱin:ȱ ȱ #if X > 0 || defined( ABC ) && defined( BCD ) K&R C ȱ Dependingȱuponȱhowȱoldȱtheyȱare,ȱsomeȱK&RȱCȱcompilersȱmayȱnotȱincludeȱallȱofȱthisȱ capability.ȱ ȱ ȱ ȱ ȱ 14.3.2 Nested Directives ȱ Theseȱdirectivesȱmayȱbeȱnestedȱwithinȱoneȱanother,ȱasȱinȱtheȱfollowingȱcodeȱfragment:ȱ ȱ #if defined( OS_UNIX ) #ifdef OPTION1 unix_version_of_option1(); #endif #ifdef OPTION2 unix_version_of_option2(); #endif #elif defined( OS_MSDOS ) #ifdef OPTION2 msdos_version_of_option2(); #endif #endif ȱ Inȱ thisȱ example,ȱ theȱ choiceȱ ofȱ operatingȱ systemsȱ determinesȱ whichȱ alternativesȱ areȱ availableȱ forȱ theȱ differentȱ options.ȱ Theȱ exampleȱ alsoȱ illustratesȱ thatȱ preprocessorȱ directivesȱmayȱbeȱindentedȱforȱreadabilityȱbyȱprecedingȱthemȱwithȱwhiteȱspace.ȱ ȱ Toȱhelpȱ theȱreaderȱkeepȱtrackȱ ofȱcomplicatedȱ nestedȱ directives,ȱitȱ isȱhelpfulȱtoȱ labelȱeachȱ #endifȱwithȱtheȱexpressionȱfromȱtheȱ #ifȱtoȱwhichȱitȱapplies.ȱThisȱpracticeȱisȱ particularlyȱusefulȱwhenȱtheȱenclosedȱstatementsȱareȱlengthy.ȱForȱexample:ȱ Download at http://www.pin5i.com/ 14.4 File Inclusionȱ #ifdef 397 OPTION1 lengthy code for option1; #else #endif lengthy code for alternative; /* OPTION1 */ ȱ Someȱcompilersȱallowȱaȱsymbolȱtoȱappearȱonȱanȱ #endifȱdirective,ȱevenȱthoughȱitȱhasȱ noȱeffect.ȱTheȱStandardȱdoesnȇtȱmentionȱtheȱlegalityȱofȱthisȱpractice,ȱsoȱitȱisȱsaferȱtoȱuseȱ aȱcomment.ȱ ȱ ȱ ȱ 14.4 File Inclusion TIP TIP TIP ȱ Asȱyouȱhaveȱalreadyȱseen,ȱtheȱ #includeȱdirectiveȱcausesȱtheȱcontentsȱofȱanotherȱfileȱtoȱ beȱcompiledȱasȱifȱ theyȱactuallyȱ appearedȱ inȱplaceȱofȱtheȱ #includeȱdirective.ȱTheȱwayȱ thisȱ substitutionȱ isȱ performedȱ isȱ simple:ȱ theȱ preprocessorȱ removesȱ theȱ directiveȱ andȱ substitutesȱtheȱcontentsȱofȱtheȱnamedȱfile.ȱThus,ȱaȱheaderȱfileȱthatȱisȱincludedȱintoȱtenȱ otherȱsourceȱfilesȱisȱactuallyȱcompiledȱtenȱtimes.ȱ ȱ Thisȱfactȱsuggestsȱthatȱusingȱ #includeȱfilesȱinvolvesȱsomeȱoverhead,ȱbutȱthereȱareȱtwoȱ veryȱgoodȱreasonsȱwhyȱyouȱshouldȱnotȱworryȱaboutȱit.ȱFirst,ȱthereȱisȱactuallyȱnotȱmuchȱ extraȱoverhead.ȱIfȱaȱsetȱofȱdeclarationsȱisȱneededȱinȱtwoȱsourceȱfiles,ȱitȱwillȱtakeȱnearlyȱ theȱ sameȱ amountȱ ofȱ timeȱ toȱ compileȱ thoseȱ sourceȱ filesȱ ifȱ theȱ declarationsȱ areȱ duplicatedȱ asȱ itȱ wouldȱ ifȱ theȱ declarationsȱ wereȱ #includeȇdȱ inȱ theȱ files.ȱ Also,ȱ theȱ overheadȱ occursȱ onlyȱ whenȱ theȱ programȱ isȱ beingȱ compiled,ȱ soȱ runtimeȱ efficiencyȱ isȱ notȱaffected.ȱMoreȱimportantly,ȱthough,ȱtheȱadvantagesȱofȱhavingȱtheȱdeclarationsȱinȱaȱ headerȱfileȱareȱsignificant.ȱTheyȱdoȱnotȱhaveȱtoȱbeȱreplicatedȱinȱeveryȱfileȱinȱwhichȱtheyȱ areȱneeded,ȱsoȱmaintainingȱthemȱisȱeasier.ȱ ȱ Theȱ factȱ thatȱ everythingȱ inȱ theȱ headerȱ fileȱ isȱ compiledȱ eachȱ timeȱ itȱ isȱ #includeȇdȱ suggestsȱthatȱeachȱheaderȱfileȱshouldȱonlyȱcontainȱdeclarationsȱforȱoneȱsetȱofȱfunctionsȱ orȱ data.ȱ Itȱ isȱ betterȱ toȱ useȱ severalȱ headerȱ files,ȱ eachȱ containingȱ theȱ declarationsȱ appropriateȱforȱaȱparticularȱfunctionȱorȱmodule,ȱthanȱtoȱputȱallȱofȱtheȱdeclarationsȱforȱaȱ programȱinȱoneȱgiantȱheaderȱfile.ȱ ȱ Theȱprinciplesȱofȱprogramȱdesignȱandȱmodularityȱsupportȱthisȱapproachȱasȱwell.ȱItȱisȱ betterȱtoȱincludeȱintoȱaȱfileȱonlyȱtheȱnecessaryȱdeclarationsȱsoȱthatȱtheȱstatementsȱinȱtheȱ fileȱcannotȱaccidentallyȱaccessȱfunctionsȱorȱvariablesȱthatȱshouldȱbeȱprivate.ȱAlso,ȱitȱisȱ easierȱtoȱmaintainȱaȱsetȱofȱdeclarationsȱifȱyouȱdonȇtȱhaveȱtoȱwadeȱthroughȱhundredsȱofȱ linesȱofȱunrelatedȱcodeȱtoȱfindȱthem.ȱ Download at http://www.pin5i.com/ Chapter 14 The Preprocessorȱ 398ȱ 14.4.1 Library Includes ȱ Theȱcompilerȱsupportsȱtwoȱdifferentȱtypesȱofȱ#includeȇs:ȱlibraryȱfilesȱandȱlocalȱfiles.ȱInȱ fact,ȱthereȱisȱlittleȱdifferenceȱbetweenȱthem.ȱ Libraryȱheaderȱfilesȱareȱincludedȱusingȱtheȱfollowingȱsyntax.ȱ ȱ #include <filename> ȱ Thereȱarenȇtȱanyȱrestrictionsȱonȱtheȱfilename,ȱalthoughȱbyȱconventionȱtheȱnamesȱofȱtheȱ standardȱlibraryȱheaderȱfilesȱendȱwithȱaȱ.hȱsuffix. 46 Theȱ compilerȱ searchesȱ forȱ libraryȱ headerȱ filesȱ byȱ lookingȱ aȱ Ȉseriesȱ ofȱ standardȱ locationsȈȱ definedȱ byȱ theȱ implementation.ȱ Theȱ documentationȱ forȱ yourȱ particularȱ compilerȱ shouldȱ indicateȱ whatȱ theȱ standardȱ locationsȱ areȱ andȱ howȱ youȱ canȱ changeȱ themȱ orȱ addȱ otherȱ locationsȱ toȱ theȱ list.ȱ Forȱ example,ȱ Cȱ compilersȱ onȱ UNIXȱ systemsȱ typicallyȱlookȱforȱlibraryȱheaderȱfilesȱinȱaȱdirectoryȱcalledȱ /usr/include.ȱAȱcommandȱ lineȱ optionȱ toȱ theȱcompilerȱ letsȱyouȱaddȱadditionalȱdirectoriesȱ toȱ thisȱlistȱsoȱthatȱ youȱ canȱ createȱ yourȱ ownȱ librariesȱ ofȱ headerȱ files.ȱ Again,ȱ consultȱ yourȱ compilerȇsȱ documentationȱtoȱseeȱhowȱyourȱsystemȱbehaves.ȱ ȱ ȱ ȱ 14.4.2 Local Includes ȱ Hereȱisȱtheȱotherȱformȱofȱtheȱ#includeȱdirective.ȱ ȱ #include "filename" ȱ Theȱ Standardȱ letsȱ eachȱ implementationȱ decideȱ whetherȱ toȱ treatȱ theȱ localȱ formȱ ofȱ #includeȱ differentlyȱ thanȱ theȱ libraryȱ form.ȱ Ifȱ anyȱ specialȱ processingȱ thatȱ isȱ providedȱ forȱ theȱ localȱ formȱ failsȱ forȱ aȱ givenȱ file,ȱ thenȱ theȱ compilerȱ searchesȱ forȱ theȱ fileȱ asȱ ifȱ aȱ libraryȱ #includeȱhadȱbeenȱused.ȱAȱcommonȱstrategyȱforȱprocessingȱlocalȱincludesȱisȱtoȱ lookȱ inȱ theȱ currentȱ directoryȱ forȱ theȱ file.ȱ ȱ Ifȱ theȱ fileȱ isȱ notȱ found,ȱ thenȱ theȱ standardȱ locationsȱareȱsearchedȱasȱusual.ȱ Youȱcanȱwriteȱallȱofȱyourȱ#includeȱstatementsȱwithȱquotationȱmarksȱinsteadȱofȱ angleȱbrackets.ȱHowever,ȱsomeȱcompilersȱwouldȱwasteȱaȱsmallȱamountȱofȱtimeȱwhenȱ tryingȱtoȱlocateȱlibraryȱincludeȱfiles.ȱAȱbetterȱreasonȱtoȱuseȱtheȱangleȱbracketȱformȱforȱ libraryȱ filesȱ isȱ theȱ informationȱ thatȱ itȱ givesȱ theȱ reader.ȱ Theȱ angleȱ bracketsȱ makeȱ itȱ obviousȱthatȱ ȱ #include <erno.h>ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ 46 ȱTechnically,ȱlibraryȱheaderȱfilesȱneedȱnotȱbeȱstoredȱasȱfilesȱatȱall,ȱthoughȱthisȱwonȇtȱbeȱapparentȱtoȱtheȱprogrammerȱ Download at http://www.pin5i.com/ 14.4 File Inclusionȱ 399 referencesȱaȱlibraryȱfile.ȱWithȱtheȱalternateȱformȱ ȱ #include "errno.h" ȱ itȱisȱnotȱclearȱwhetherȱtheȱlibraryȱheaderȱorȱaȱlocalȱfileȱofȱtheȱsameȱnameȱisȱbeingȱused.ȱȱ Theȱonlyȱwayȱtoȱfindȱoutȱforȱsureȱisȱtoȱexamineȱtheȱdirectoryȱinȱwhichȱtheȱcompilationȱ isȱperformed.ȱ Aȱ variantȱ supportedȱ onȱ Unixȱ systemsȱ andȱ theȱ Borlandȱ Cȱ compilersȱ isȱ theȱ absoluteȱ pathname,ȱ whichȱ identifiesȱ notȱ onlyȱ theȱ nameȱ ofȱ aȱ fileȱ butȱ itsȱ location.ȱ Anȱ absoluteȱpathnameȱonȱaȱUNIXȱsystemȱbeginsȱwithȱaȱslash,ȱlikeȱthis:ȱ ȱ /home/fred/C/my_proj/declaration2.h ȱ OnȱMSȬDOSȱsystems,ȱbackslashesȱareȱusedȱinsteadȱofȱslashes.ȱIfȱanȱabsoluteȱpathnameȱ isȱ usedȱ inȱ eitherȱ formȱ ofȱ #include,ȱ thenȱ theȱ usualȱ directoryȱ searchingȱ isȱ skippedȱ becauseȱtheȱpathnameȱspecifiesȱtheȱlocationȱofȱtheȱfile.ȱ ȱ ȱ ȱ 14.4.3 Nested File Inclusion ȱ Itȱ isȱ possibleȱ toȱ putȱ #includeȱ directivesȱ inȱ filesȱ thatȱ areȱ included.ȱ Forȱ example,ȱ considerȱ aȱ collectionȱ ofȱ functionsȱ thatȱ readȱ inputȱ andȱ thenȱ performȱ variousȱ inputȱ validationȱtasks.ȱTheȱvalidatedȱdataȱisȱthenȱreturned.ȱWhenȱendȱofȱfileȱisȱreached,ȱtheȱ constantȱEOFȱisȱreturnedȱinstead.ȱ Prototypesȱ forȱ theseȱ functionsȱ wouldȱ beȱ putȱ inȱ aȱ headerȱ fileȱ andȱ #includeȇedȱ intoȱ eachȱ sourceȱ fileȱ thatȱ usesȱ theȱ functions.ȱ However,ȱ everyȱ fileȱ thatȱ usesȱ theseȱ functionsȱ mustȱ alsoȱ includeȱ stdio.hȱ toȱ getȱ theȱ declarationȱ forȱ EOF.ȱ Therefore,ȱ theȱ headerȱfileȱcontainingȱtheȱprototypesȱmayȱalsoȱcontain:ȱ ȱ #include <stdio.h> TIP ȱ soȱthatȱincludingȱtheȱheaderȱfileȱautomaticallyȱbringsȱinȱtheȱstandardȱI/Oȱdeclarationsȱ asȱwell.ȱ TheȱStandardȱrequiresȱthatȱnestedȱ #includeȱfilesȱbeȱsupportedȱtoȱaȱdepthȱofȱatȱ leastȱeight,ȱbutȱitȱdoesnȇtȱimposeȱaȱmaximumȱlimitȱonȱnestingȱdepth.ȱInȱpractice,ȱthereȱ isȱlittleȱreasonȱtoȱnestȱ#includeȇsȱtoȱdepthsȱgreaterȱthanȱoneȱorȱtwo.ȱ ȱ Aȱdisadvantageȱofȱnestedȱ #includeȱfilesȱisȱthatȱtheyȱmakeȱitȱdifficultȱtoȱdetermineȱtheȱ trueȱ dependenciesȱ ofȱ sourceȱ filesȱ onȱ oneȱ another.ȱ Someȱ programs,ȱ suchȱ asȱ theȱ UNIXȱ makeȱutility,ȱmustȱknowȱtheseȱdependenciesȱinȱorderȱtoȱdetermineȱwhichȱfilesȱneedȱtoȱ beȱcompiledȱafterȱsomeȱfilesȱareȱmodified.ȱ Download at http://www.pin5i.com/ 400ȱ Chapter 14 The Preprocessorȱ Anotherȱdisadvantageȱofȱnestedȱ #includeȇsȱisȱtheȱpossibilityȱofȱoneȱheaderȱfileȱ beingȱincludedȱmultipleȱtimes.ȱToȱillustrateȱthisȱerror,ȱconsiderȱthisȱcode:ȱ ȱ #include "x.h" #include "x.h" ȱ Itȱ isȱ obviousȱ hereȱ thatȱ theȱ fileȱ x.hȱ isȱ beingȱ includedȱ twice.ȱ Noȱ oneȱ wouldȱ everȱ writeȱ thisȱcodeȱintentionally.ȱButȱthisȱcodeȱ ȱ #include "a.h" #include "b.h" ȱ seemsȱfine.ȱIfȱbothȱa.hȱandȱb.hȱcontainȱaȱnestedȱ#includeȱofȱx.h,ȱthenȱx.hȱisȱonceȱagainȱ beingȱincludedȱtwice,ȱonlyȱthisȱtimeȱitȱisȱnotȱasȱobvious.ȱ Multipleȱ inclusionȱ occursȱ mostȱ oftenȱ inȱ largerȱ programsȱ withȱ aȱ multitudeȱ ofȱ headerȱfiles,ȱthusȱitȱisȱnotȱeasyȱtoȱfind.ȱAȱsimpleȱsolutionȱtoȱtheȱproblemȱisȱprovidedȱbyȱ theȱconditionalȱcompilationȱfeature.ȱIfȱallȱheaderȱfilesȱareȱwrittenȱas:ȱ ȱ #ifndef _HEADERNAME_H #define _HEADERNAME_H 1 /* ** All the stuff that you want in the header file */ #endif ȱ thenȱ theȱ risksȱ ofȱ multipleȱ inclusionȱ areȱ eliminated.ȱ Theȱ firstȱ timeȱ theȱ headerȱ fileȱ isȱ included,ȱitȱisȱprocessedȱnormallyȱandȱtheȱsymbolȱ _HEADERNAME_Hȱisȱdefinedȱtoȱbeȱone.ȱ Ifȱ theȱ headerȱ isȱ includedȱ again,ȱ itsȱ entireȱ contentsȱ areȱ ignoredȱ byȱ theȱ conditionalȱ compilationȱdirectives.ȱ Theȱsymbolȱ _HEADERNAME_Hȱisȱnamedȱafterȱtheȱfilenameȱofȱ theȱ includeȱfileȱinȱorderȱtoȱavoidȱconflictsȱwithȱsimilarȱsymbolsȱinȱotherȱheaderȱfiles.ȱ Noteȱthatȱtheȱdefinitionȱinȱtheȱpreviousȱexampleȱcanȱalsoȱbeȱwrittenȱ ȱ #define _HEADERNAME_H ȱ withȱexactlyȱtheȱsameȱeffect.ȱEvenȱthoughȱitsȱvalueȱisȱnowȱtheȱemptyȱstringȱratherȱthanȱ Ȉ1Ȉ,ȱtheȱsymbolȱisȱstillȱdefined.ȱ Keepȱ inȱ mind,ȱ though,ȱ thatȱ theȱ preprocessorȱ mustȱ stillȱ readȱ theȱ entireȱ headerȱ file,ȱevenȱifȱtheȱwholeȱfileȱisȱignored.ȱBecauseȱthisȱprocessingȱslowsȱdownȱcompilation,ȱ multipleȱ inclusion,ȱ whetherȱ byȱ nestedȱ #includeȇsȱ orȱ not,ȱ shouldȱ beȱ avoidedȱ whenȱ possible.ȱ Download at http://www.pin5i.com/ 14.5 Other Directivesȱ 401 14.5 Other Directives ȱ Thereȱareȱaȱfewȱadditionalȱdirectivesȱsupportedȱbyȱtheȱpreprocessor.ȱFirst,ȱtheȱ #errorȱ directiveȱletsȱyouȱgenerateȱerrorȱmessagesȱwhenȱtheȱprogramȱisȱcompiled.ȱHereȱisȱitsȱ syntax:ȱ ȱ #error text of error message ȱ Theȱfollowingȱcodeȱfragmentȱshowsȱhowȱyouȱmightȱuseȱthisȱdirective.ȱ ȱ #if defined( OPTION_A ) stuff needed for option Aȱ #elif defined( OPTION_B ) stuff needed for option B #elif defined( OPTION_C ) stuff needed for option C #else #error No option selected! #endif ȱ Somewhatȱlessȱusefulȱisȱtheȱ#lineȱdirective,ȱwhichȱhasȱthisȱform:ȱ ȱ #line number "string" ȱ Itȱinformsȱtheȱpreprocessorȱthatȱnumberȱisȱtheȱlineȱnumberȱofȱtheȱnextȱlineȱofȱinput.ȱIfȱ theȱoptionalȱ"string"ȱisȱgiven,ȱtheȱpreprocessorȱtakesȱitȱasȱtheȱnameȱofȱtheȱcurrentȱfile.ȱȱ Specifically,ȱthisȱdirectiveȱmodifiesȱtheȱvalueȱofȱtheȱ __LINE__ȱsymbolȱand,ȱoptionally,ȱ theȱ__FILE__ȱsymbolȱasȱwell.ȱ Thisȱdirectiveȱisȱmostȱoftenȱusedȱinȱprogramsȱthatȱtranslateȱotherȱlanguagesȱtoȱ Cȱ code.ȱErrorȱ messagesȱproducedȱbyȱtheȱCȱ compilerȱ canȱ referenceȱ theȱfileȱ nameȱ andȱ lineȱ numbersȱ ofȱ theȱ originalȱ sourceȱ fileȱ insteadȱ ofȱ theȱ intermediateȱ Cȱ sourceȱ fileȱ producedȱbyȱtheȱtranslatingȱprogram.ȱ Theȱ #pragmaȱdirectiveȱisȱaȱmechanismȱthatȱsupportsȱimplementationȬdependentȱ directives.ȱ Itsȱ syntaxȱ isȱ implementationȱ dependent.ȱ Anȱ environmentȱ mayȱ provideȱ #pragmaȇsȱ toȱ allowȱ optionsȱ orȱ otherȱ processingȱ notȱ availableȱ anyȱ otherȱ way.ȱ Forȱ example,ȱsomeȱcompilersȱuseȱ#pragmaȇsȱtoȱturnȱlistingsȱonȱorȱoffȱduringȱcompilationȱorȱ toȱ insertȱ assemblyȱ codeȱ intoȱ Cȱ programs.ȱ Pragmasȱ areȱ inherentlyȱ notȱ portable.ȱ Unrecognizedȱ #pragmaȱ directivesȱ areȱ ignoredȱ byȱ theȱ preprocessor,ȱ andȱ twoȱ differentȱ compilersȱmightȱinterpretȱtheȱsameȱ#pragmaȱinȱdifferentȱways.ȱ Finally,ȱ theȱ nullȱ directiveȱ isȱ aȱ lineȱ thatȱ beginsȱ withȱ aȱ poundȱ signȱ butȱ containsȱ nothingȱ else.ȱ Theseȱ directivesȱ areȱ simplyȱ deletedȱ byȱ theȱ preprocessor.ȱ Theȱ nullȱ directivesȱinȱtheȱfollowingȱexampleȱemphasizeȱtheȱ#includeȱdirectiveȱbyȱseparatingȱitȱ Download at http://www.pin5i.com/ 402ȱ Chapter 14 The Preprocessorȱ fromȱtheȱsurroundingȱcode.ȱ ȱ # #include <stido.h> # ȱ Theȱsameȱeffectȱcanȱbeȱachievedȱwithȱblankȱlines.ȱ ȱ ȱ ȱ 14.6 Summary ȱ TheȱfirstȱstepȱinȱcompilingȱaȱCȱprogramȱisȱtoȱpreproeessȱit.ȱTheȱpreprocessorȱmaintainsȱ fiveȱsymbols,ȱwhichȱareȱdescribedȱinȱTableȱ14.1.ȱ Theȱ #defineȱ directiveȱ attachesȱ aȱ symbolicȱ nameȱ toȱ anȱ arbitraryȱ sequenceȱ ofȱ characters.ȱ Forȱ example,ȱ theseȱ charactersȱ mayȱ beȱ literalȱ constants,ȱ expressions,ȱ orȱ programȱ statements.ȱ Theȱ sequenceȱ isȱ terminatedȱ byȱ theȱ endȱ ofȱ theȱ line.ȱ Longȱ sequencesȱofȱcharactersȱmayȱbeȱsplitȱoverȱmultipleȱlinesȱbyȱendingȱeachȱlineȱexceptȱtheȱ lastȱoneȱwithȱaȱbackslash.ȱMacrosȱareȱdefinedȱsequencesȱintoȱwhichȱargumentȱvaluesȱ areȱsubstituted.ȱWhenȱaȱmacroȱisȱinvoked,ȱvaluesȱareȱgivenȱforȱeachȱofȱitsȱarguments.ȱ Toȱ preventȱ errorsȱ withȱ macrosȱ thatȱ mayȱ appearȱ inȱ egressions,ȱ surroundȱ theȱ entireȱ definitionȱofȱtheȱmacroȱwithȱparentheses.ȱAlso,ȱsurroundȱeachȱoccurrenceȱofȱtheȱmacroȱ parametersȱinȱtheȱdefinitionȱwithȱparentheses.ȱ #defineȱmayȱbeȱusedȱtoȱȈrewriteȈȱtheȱCȱ languageȱsoȱthatȱitȱresemblesȱanotherȱlanguage.ȱ Theȱ #argumentȱconstructȱisȱconvertedȱbyȱtheȱpreprocessorȱintoȱtheȱstringȱliteralȱ ȈargumentȈ.ȱȱTheȱ##ȱoperatorȱconcatenatesȱtheȱtextȱappearingȱonȱeachȱsideȱofȱit.ȱ Someȱ tasksȱ canȱ beȱ implementedȱ withȱ bothȱ macrosȱ andȱ functions.ȱ However,ȱ macrosȱareȱtypeless,ȱwhichȱcanȱbeȱanȱadvantage.ȱMacrosȱexecuteȱfasterȱthanȱfunctionsȱ becauseȱ thereȱ isȱ noȱ overheadȱ usedȱ callingȱ orȱ returningȱ fromȱ theȱ function,ȱ howeverȱ usingȱ macrosȱ ratherȱ thanȱ functionsȱ usuallyȱ increasesȱ theȱ sizeȱ ofȱ theȱ program.ȱ Also,ȱ argumentsȱwithȱsideȱeffectsȱcanȱcauseȱunexpectedȱresultsȱwithȱmacros.ȱTheȱbehaviorȱofȱ theseȱargumentsȱwithȱfunctionsȱisȱmoreȱpredictable.ȱBecauseȱofȱtheseȱdifferences,ȱitȱisȱ importantȱtoȱuseȱaȱnamingȱconventionȱthatȱletsȱtheȱprogrammerȱdetermineȱwhetherȱanȱ identifierȱisȱaȱfunctionȱorȱaȱmacro.ȱ Withȱ manyȱ compilers,ȱ symbolsȱ canȱ beȱ definedȱ fromȱ theȱ commandȱ line.ȱ Theȱ #undefȱdirectiveȱcausesȱtheȱinitialȱdefinitionȱforȱaȱnameȱtoȱbeȱignored.ȱ Youȱcanȱcreateȱdifferentȱversionsȱofȱaȱprogramȱfromȱaȱsingleȱsetȱofȱsourceȱfilesȱ byȱ usingȱ conditionalȱ compilation.ȱ Theȱ #ifȱ directiveȱ eitherȱ includesȱ orȱ ignoresȱ aȱ sequenceȱ ofȱ codeȱ accordingȱ toȱ theȱ resultȱ ofȱ aȱ compileȬtimeȱ test.ȱ Whenȱ theȱ #elifȱ andȱ #elseȱ directivesȱ areȱ alsoȱ used,ȱ youȱ canȱ selectȱ oneȱ ofȱ severalȱ sequencesȱ ofȱ codeȱ to Download at http://www.pin5i.com/ 14.8 Summary of Programming Tipsȱ 403 compile.ȱInȱadditionȱtoȱtestingȱconstantȱexpressions,ȱtheseȱdirectivesȱcanȱtestȱwhetherȱ orȱnotȱsymbolsȱareȱdefined.ȱTheȱ#ifdefȱandȱ#ifndefȱdirectivesȱalsoȱperformȱthisȱtask.ȱ Theȱ #includeȱdirectiveȱperformsȱfileȱinclusion.ȱItȱhasȱtwoȱforms.ȱIfȱtheȱfilenameȱ isȱenclosedȱinȱangleȱbrackets,ȱtheȱcompilerȱsearchesȱforȱtheȱfileȱinȱanȱimplementationȬ definedȱstandardȱplace.ȱThisȱformȱisȱusuallyȱusedȱwhenȱincludingȱlibraryȱheaders.ȱInȱ theȱotherȱform,ȱtheȱfilenameȱisȱenclosedȱinȱquotationȱmarks.ȱEachȱimplementationȱmayȱ processȱthisȱformȱdifferently.ȱHowever,ȱifȱanyȱspecialȱprocessingȱforȱthisȱformȱfailsȱtoȱ locateȱtheȱ file,ȱthenȱ theȱstandardȱplaceȱisȱsearchedȱinstead.ȱ Thisȱformȱisȱusuallyȱusedȱ forȱincludingȱfilesȱthatȱyouȱhaveȱwritten.ȱFileȱinclusionȱmayȱbeȱnested,ȱthoughȱthereȱisȱ usuallyȱ littleȱ needȱ forȱ nestingȱ thatȱ isȱ moreȱ thanȱ oneȱ orȱ twoȱ levelsȱ deep.ȱ Nestedȱ includesȱ increaseȱ theȱ riskȱ ofȱ includingȱ aȱ fileȱ moreȱ thanȱ once,ȱ andȱ makeȱ itȱ harderȱ toȱ determineȱwhichȱincludeȱfilesȱaȱgivenȱsourceȱfileȱdependsȱon.ȱ Theȱ#errorȱdirectiveȱgeneratesȱanȱerrorȱmessageȱatȱcompileȱtimeȱcontainingȱtextȱ ofȱyourȱchoice.ȱTheȱ #lineȱdirectiveȱallowsȱyouȱtoȱtellȱtheȱcompilerȱtheȱlineȱnumberȱofȱ theȱ nextȱ lineȱ ofȱ inputȱ and,ȱ optionally,ȱ theȱ nameȱ ofȱ theȱ fileȱ itȱ cameȱ from.ȱ Theȱ implementationȬdependentȱ #pragmaȱ directiveȱ allowsȱ compilersȱ toȱ provideȱ nonstandardȱprocessingȱsuchȱasȱinsertingȱinlineȱassemblyȱcodeȱintoȱaȱfunction.ȱ ȱ ȱ ȱ 14.7 Summary of Cautions ȱ 1. Doȱ notȱ putȱ aȱ semicolonȱ atȱ theȱ endȱ ofȱ aȱ macroȱ definitionȱ thatȱ formsȱ anȱ entireȱ statementȱ(pageȱ385).ȱ 2. Usingȱ macroȱ argumentsȱ inȱ theȱ definitionȱ withoutȱ surroundingȱ themȱ withȱ parenthesesȱ(pageȱ386).ȱ 3. Notȱsurroundingȱtheȱentireȱmacroȱdefinitionȱwithȱparenthesesȱ(pageȱ387).ȱ ȱ ȱ ȱ 14.8 Summary of Programming Tips ȱ 1. Avoidȱ usingȱ aȱ #defineȱ forȱ longȱ sequencesȱ ofȱ codeȱ thatȱ canȱ beȱ implementedȱ asȱ aȱ functionȱ(pageȱ385).ȱ 2. Inȱ macrosȱ thatȱ evaluateȱ expressions,ȱ parenthesizeȱ allȱ occurrencesȱ ofȱ theȱ macroȱ arguments,ȱandȱsurroundȱtheȱentireȱdefinitionȱwithȱparenthesesȱ(pageȱ387).ȱ 3. Avoidȱusingȱ#defineȱmacrosȱtoȱcreateȱaȱnewȱlanguageȱ(pageȱ387).ȱ Download at http://www.pin5i.com/ 404ȱ Chapter 14 The Preprocessorȱ 4. Adoptȱaȱnamingȱconventionȱthatȱmakesȱitȱobviousȱwhenȱaȱ #defineȱmacroȱisȱbeingȱ usedȱ(pageȱ391).ȱ 5. Useȱ fileȱ inclusionȱ whereverȱ itȱ isȱ appropriate;ȱ doȱ notȱ worryȱ aboutȱ overheadȱ (pageȱ 397).ȱ 6. Aȱheaderȱfileȱshouldȱonlyȱcontainȱdeclarationsȱforȱoneȱsetȱofȱfunctionsȱand/orȱdataȱ (pageȱ397).ȱ 7. Separateȱheaderȱfilesȱforȱdifferentȱsetsȱofȱdeclarationsȱimprovesȱinformationȱhidingȱ (pageȱ397).ȱ 8. Nestingȱ #includeȱ filesȱ makesȱ itȱ moreȱ difficultȱ toȱ determineȱ theȱ dependenciesȱ amongȱsourceȱfilesȱ(pageȱ399).ȱ ȱ ȱ ȱ 14.9 Questions ȱ 1. Theȱ preprocessorȱ definesȱ fiveȱ symbolsȱ thatȱ giveȱ theȱ nameȱ ofȱ theȱ fileȱ beingȱ compiled,ȱ theȱ currentȱ lineȱ numberȱ inȱ thatȱ file,ȱ theȱ currentȱ dateȱ andȱ time,ȱ andȱ whetherȱtheȱcompilerȱisȱanȱANSIȱcompiler.ȱNameȱoneȱwayȱinȱwhichȱeachȱofȱtheseȱ symbolsȱmightȱbeȱuseful.ȱ 2. Nameȱtwoȱadvantagesȱofȱusingȱ#defineȇdȱnamesȱinȱplaceȱofȱliteralȱconstants.ȱ 3. Writeȱ aȱ macroȱ forȱ debuggingȱ thatȱ willȱ printȱ arbitraryȱ expressions.ȱ Itȱ shouldȱ beȱ calledȱwithȱtwoȱarguments.ȱTheȱfirstȱisȱaȱ printfȱformatȱcode,ȱandȱtheȱsecondȱisȱtheȱ expressionȱtoȱbeȱprinted.ȱ 4. Whatȱwillȱtheȱfollowingȱprogramȱprint?ȱBeȱsureȱtoȱexpandȱtheȱ#defineȇsȱcarefully!ȱ ȱ #define MAX(a,b) #define SQUARE(x) #define DOUBLE(x) main() { int (a)>(b)?(a):(b) x*x x+x x, y, z; y = 2; z = 3; x = MAX(y,z); /* a */ printf( "%d %d %d\n", x, y, z ); y = 2; z = 3; x = MAX(++y,++z); ȱ Download at http://www.pin5i.com/ 14.9 Questionsȱ 405 /* b */ printf( "%d %d %d\n", x, y, z ); x y z /* c */ = 2; = SQUARE(x); = SQUARE(x+6); printf( "%d %d %d\n", x, y, z ); x y z /* d */ } = 2; = 3; = MAX(5*DOUBLE(x),++y); printf( "%d %d %d\n", x, y, z ); 5. Theȱ putcharȱfunctionȱisȱdefinedȱinȱtheȱfileȱ stdio.hȱasȱaȱmacro,ȱdespiteȱtheȱfactȱthatȱ itȱisȱfairlyȱlong.ȱWhyȱdoȱyouȱthinkȱitȱwasȱdefinedȱthisȱway?ȱ 6. What,ȱifȱanything,ȱisȱwrongȱwithȱtheȱfollowingȱprogramȱfragment?ȱ ȱ /* ** Process all the values in the array. */ result = 0; i = 0; while( i < SIZE ){ result += process( value[ i++ ] ); } 7. What,ȱifȱanything,ȱisȱwrongȱwithȱtheȱfollowingȱprogramȱfragment?ȱ ȱ #define SUM( value ) ( ( value ) + ( value ) ) int array[SIZE]; ... /* ** Sum all the values in the array. */ sum = 0; i = 0; while( i < SIZE ) sum += SUM( array[ i++ ] ); 8. What,ȱifȱanything,ȱisȱwrongȱwithȱtheȱfollowingȱcodeȱfragments?ȱ ȱ Inȱfileȱheader1.h:ȱ #ifndef #define #include ȱ _HEADER1_H _HEADER1_H "header2.h" otherȱdeclarationsȱ #endif Download at http://www.pin5i.com/ 406ȱ Chapter 14 The Preprocessorȱ ȱ Inȱfileȱheader2.h:ȱ #ifndef #define #include ȱ _HEADER2_H _HEADER2_H "header1.h" otherȱdeclarationsȱ #endif 9. Inȱ anȱ attemptȱ toȱ improveȱ portability,ȱ oneȱ programmerȱ wroteȱ theȱ followingȱ declarations.ȱ ȱ #if sizeof( int ) == 2 typedef long int32; #else typedef int int32; #endif ȱ What,ȱifȱanything,ȱisȱwrongȱwithȱthem?ȱ ȱ ȱ ȱ 14.10 Programming Exercises ȱ 1. Theȱ companyȱ youȱ areȱ workingȱ forȱ marketsȱ aȱ programȱ thatȱ handlesȱ financialȱ transactionsȱ andȱ printsȱ reportsȱ aboutȱ them.ȱ Toȱ broadenȱ theȱ potentialȱ market,ȱ theȱ programȱ isȱ soldȱ inȱ severalȱ editions,ȱ eachȱ withȱ variousȱ combinationsȱ ofȱ options— theȱ moreȱ options,ȱ theȱ higherȱ theȱ price.ȱ Yourȱ taskȱ isȱ toȱ implementȱ theȱ codeȱ forȱ aȱ certainȱprintingȱfunctionȱsoȱthatȱitȱcanȱbeȱeasilyȱcompiledȱtoȱproduceȱtheȱdifferentȱ versionsȱofȱtheȱprogram.ȱ Yourȱfunctionȱwillȱbeȱnamedȱ print_ledger.ȱItȱtakesȱaȱsingleȱ intȱargument,ȱandȱ doesȱ notȱ returnȱ anyȱ value.ȱ Itȱ shouldȱ callȱ oneȱ orȱ moreȱ ofȱ theȱ followingȱ functionsȱ dependingȱonȱwhichȱ(ifȱany)ȱsymbolsȱareȱdefinedȱwhenȱtheȱfunctionȱisȱcompiled.ȱ ȱ If this symbol is defined… Then you call this function. OPTION_LONG OPTION_DETAILED (neither)ȱ print_ledger_long print_ledger_detailed print_ledger_default ȱ Eachȱ ofȱ theseȱ functionsȱ alsoȱ takesȱ aȱ singleȱ intȱ argument.ȱ Passȱ theȱ valueȱ youȱ receivedȱtoȱwhicheverȱfunction(s)ȱyouȱcall.ȱ 2. Writeȱaȱfunctionȱthatȱreturnsȱaȱvalueȱindicatingȱtheȱtypeȱofȱcomputerȱonȱwhichȱitȱisȱ running.ȱ Theȱ functionȱ willȱ heȱ usedȱ inȱ aȱ programȱ thatȱ runsȱ onȱ aȱ wideȱ varietyȱ ofȱ computers.ȱ Download at http://www.pin5i.com/ 14.10 Programming Exercisesȱ 407 Weȱ willȱ useȱ conditionalȱ compilationȱ toȱ accomplishȱ thisȱ magic.ȱ Yourȱ functionȱ shouldȱ beȱ calledȱ cpu_type,ȱ andȱ shouldȱ notȱ takeȱ anyȱ arguments.ȱ Whenȱ yourȱ functionȱisȱcompiled,ȱoneȱofȱtheȱsymbolsȱinȱtheȱȈDefinedȈȱcolumnȱofȱtheȱtableȱbelowȱ mayȱ beȱ defined.ȱ Yourȱ functionȱ shouldȱ returnȱ theȱ correspondingȱ symbolȱ fromȱ theȱ ȈReturnedȈȱ column.ȱ Ifȱ noneȱ ofȱ theȱ symbolsȱ inȱ theȱ leftȱ columnȱ wereȱ defined,ȱ thenȱ theȱ valueȱ CPU_UNKHOWNȱ shouldȱ beȱ returned.ȱ Ifȱ moreȱ thanȱ oneȱ ofȱ theȱ symbolsȱ wasȱ defined,ȱtheȱresultȱisȱundefined.ȱ ȱ Defined Returned VAX M68000 K68020 I80386 X6809 X6502 U3B2 CPU_VAX CPU_68000 CPU_68020 CPU_80386 CPU_6809 CPU_6502 CPU_3B2 CPU_UNKNOWN (none)ȱ ȱ Theȱ symbolsȱ inȱ theȱ ȈReturnedȈȱ columnȱ willȱ beȱ #defineȇdȱ asȱ variousȱ integerȱ valuesȱinȱanȱincludeȱtileȱcalledȱcpu_types.hȱ.ȱ Download at http://www.pin5i.com/ Download at http://www.pin5i.com/ 15 Input/Output Functions Oneȱ ofȱ theȱ biggestȱ advantagesȱ ofȱ ANSIȱ Cȱ overȱ earlierȱ implementationsȱ isȱ thatȱ theȱ libraryȱ isȱ includedȱ inȱ theȱ specification.ȱ Everyȱ ANSIȱ implementationȱ willȱ haveȱ theȱ mandatedȱsetȱofȱfunctions,ȱandȱtheyȱwillȱhaveȱtheȱrequiredȱinterfaceȱandȱworkȱinȱtheȱ prescribedȱ manner.ȱ Thisȱ situationȱ isȱ aȱ greatȱ improvementȱ overȱ theȱ earlyȱ daysȱ ofȱ Cȱ whenȱ differentȱ implementationsȱ ȈimprovedȈȱ theȱ commonȱ libraryȱ functionsȱ byȱ modifyingȱ orȱ extendingȱ theirȱ functionality.ȱ Theseȱ changesȱ mayȱ haveȱ beenȱ usefulȱ onȱ theȱparticularȱsystemȱforȱwhichȱtheyȱwereȱmade,ȱbutȱtheyȱinhibitedȱportabilityȱbecauseȱ codeȱ thatȱ dependedȱ onȱtheȱ changesȱ wouldȱfailȱonȱotherȱimplementationsȱthatȱlackedȱ themȱ(orȱhadȱdifferentȱchanges).ȱ ANSIȱ implementationsȱ arenȇtȱ prohibitedȱ fromȱ havingȱ additionalȱ functionsȱ inȱ theirȱ libraries.ȱ However,ȱ theȱ standardȱ functionsȱ mustȱ operateȱ asȱ definedȱ byȱ theȱ Standard.ȱ Ifȱ youȱ areȱ concernedȱ withȱ portability,ȱ simplyȱ avoidȱ anyȱ nonstandardȱ functions.ȱ Thisȱ chapterȱ coversȱ ANSIȱ Cȱ inputȱ andȱ outputȱ (I/O).ȱ However,ȱ weȱ beginȱ withȱ twoȱveryȱusefulȱfunctionsȱtoȱreportȱandȱreactȱtoȱerrors.ȱ ȱ ȱ ȱ 15.1 Error Reporting ȱ Theȱ perrorȱfunctionȱreportsȱerrorsȱinȱaȱsimple,ȱuniformȱway.ȱManyȱofȱtheȱfunctionsȱinȱ theȱANSIȱCȱlibraryȱcallȱtheȱoperatingȱsystemȱtoȱperformȱsomeȱwork,ȱespeciallyȱtheȱI/Oȱ functions.ȱAnyȱtimeȱtheȱoperatingȱsystemȱisȱaskedȱtoȱdoȱsomething,ȱthereȱisȱtheȱchanceȱ thatȱitȱmightȱfail.ȱȱForȱinstance,ȱifȱaȱprogramȱattemptsȱtoȱreadȱfromȱaȱdiskȱfileȱthatȱdoesȱ notȱexist,ȱthereȱisȱnotȱmuchȱtheȱoperatingȱsystemȱcanȱdoȱexceptȱindicateȱthatȱsomethingȱ wentȱ wrong.ȱ Theȱ libraryȱ functionsȱ passȱ thisȱ indicationȱ toȱ theȱ userȇsȱ programȱ afterȱ savingȱ aȱ codeȱ inȱ theȱ externalȱ integerȱ variableȱ errnoȱ (definedȱ inȱ errno.h)ȱ toȱ indicateȱ exactlyȱwhyȱtheȱoperationȱfailed.ȱ Download at http://www.pin5i.com/ 410ȱ Chapter 15 Input/Output Functionsȱ Theȱ perrorȱfunctionȱsimplifiesȱreportingȱtheseȱspecificȱerrorsȱtoȱtheȱuser.ȱItsȱprototypeȱ fromȱstdio.hȱisȱshownȱbelow.ȱ ȱ void perror( char const *message ); TIP ȱ Ifȱ messageȱisȱ notȱ NULLȱ andȱ pointsȱ toȱ aȱ nonemptyȱ string,ȱ theȱ stringȱ isȱ printedȱ andȱ isȱ followedȱ byȱ aȱ colonȱ andȱ aȱ space.ȱ Aȱ messageȱ explainingȱ theȱ errorȱ codeȱ currentlyȱ inȱ errnoȱisȱthenȱprinted.ȱ ȱ perrnoȇsȱ bestȱ featureȱ isȱ itsȱ easeȱ ofȱ use.ȱ Goodȱ programmingȱ practiceȱ dictatesȱ thatȱ anyȱ operationȱ thatȱ mightȱ resultȱ inȱ anȱ errorȱ shouldȱ beȱ checkedȱ afterwardsȱ toȱ determineȱ whetherȱ orȱ notȱ itȱ succeeded.ȱ Evenȱ operationsȱ thatȱ areȱ supposedlyȱ ȈguaranteedȈȱ toȱ workȱ shouldȱ beȱ checked,ȱ becauseȱ soonerȱ orȱ laterȱ theyȱ willȱ fail.ȱ Theȱ smallȱ amountȱ ofȱ extraȱworkȱneededȱtoȱdoȱthisȱcheckingȱwillȱbeȱrepaidȱtoȱyouȱmanyȱtimesȱoverȱinȱsavedȱ debuggingȱtime.ȱperrorȱisȱillustratedȱinȱexamplesȱthroughoutȱthisȱchapter.ȱ Noteȱthatȱerrnoȱisȱsetȱonlyȱwhenȱaȱlibraryȱfunctionȱfails.ȱWhenȱtheȱfunctionsȱareȱ successful,ȱ errnoȱ isȱ notȱ modifiedȱ atȱ all.ȱ Thisȱ behaviorȱ meansȱ thatȱ errnoȱ cannotȱ beȱ testedȱ toȱ determineȱ whetherȱ anȱ errorȱ occurred.ȱ Instead,ȱ checkȱ errnoȱ onlyȱ whenȱ theȱ functionȱthatȱwasȱcalledȱindicatesȱthatȱitȱfailed.ȱ ȱ ȱ ȱ 15.2 Terminating Execution ȱ Anotherȱ usefulȱ functionȱ isȱ exit,ȱ whichȱ isȱ usedȱ toȱ terminateȱ theȱ executionȱ ofȱ aȱ program.ȱItsȱprototype,ȱfoundȱinȱstdlib.h,ȱisȱshownȱbelow.ȱ ȱ void exit( int status ); ȱ Theȱ statusȱ argumentȱ isȱ returnedȱ toȱ theȱ operatingȱ systemȱ andȱ isȱ anȱ indicationȱ ofȱ whetherȱorȱnotȱtheȱprogramȱcompletedȱnormally.ȱThisȱvalueȱisȱtheȱsameȱasȱtheȱintegerȱ statusȱ returnedȱ byȱ theȱ mainȱ function.ȱ Theȱ predefinedȱ symbolsȱ EXIT_SUCCESSȱ andȱ EXIT_FAILUREȱ indicateȱ successfulȱ andȱ unsuccessfulȱ termination,ȱ respectively.ȱ Otherȱ valuesȱmayȱbeȱused,ȱbutȱtheirȱmeaningsȱareȱimplementationȱdependent.ȱ Thisȱ functionȱ isȱ particularlyȱ usefulȱ whenȱ errorȱ conditionsȱ thatȱ preventȱ theȱ programȱ fromȱ continuingȱ toȱ executeȱ areȱ discovered.ȱ Youȱ willȱ oftenȱ followȱ callsȱ toȱ perrorȱwithȱaȱcallȱtoȱ exit.ȱAlthoughȱterminatingȱtheȱprogramȱisȱnotȱtheȱrightȱwayȱtoȱ handleȱallȱerrors,ȱitȱisȱbetterȱthanȱlettingȱaȱdoomedȱprogramȱcontinueȱtoȱexecuteȱandȱ abortȱlater.ȱ Noteȱthatȱthisȱfunctionȱ neverȱreturns.ȱWhenȱ exitȱ isȱ finished,ȱtheȱprogramȱ hasȱ disappeared,ȱsoȱthereȱisȱnothingȱtoȱreturnȱto.ȱ Download at http://www.pin5i.com/ 15.4 ANSI I/O Conceptsȱ 411 15.3 The Standard I/O Library ȱ Theȱ earliestȱ implementationsȱ ofȱ K&Rȱ Cȱ hadȱ littleȱ inȱ theȱ wayȱ ofȱ libraryȱ functionsȱ toȱ supportȱ inputȱ andȱ output.ȱ Asȱ aȱ result,ȱ everyȱ programmerȱ whoȱ wantedȱ moreȱ sophisticatedȱI/Oȱfunctionalityȱthanȱthatȱprovidedȱhadȱtoȱimplementȱtheirȱown.ȱ ThisȱsituationȱwasȱgreatlyȱimprovedȱbyȱtheȱStandardȱI/OȱLibrary,ȱaȱcollectionȱofȱ I/Oȱ functionsȱ thatȱ implementedȱ muchȱ ofȱ theȱ addedȱ functionalityȱ thatȱ programmersȱ hadȱ beenȱ implementingȱ onȱ theirȱ own.ȱ Thisȱ libraryȱ expandedȱ onȱ existingȱ functions,ȱ suchȱasȱprintf,ȱcreatingȱdifferentȱversionsȱthatȱcouldȱbeȱusedȱinȱaȱvarietyȱofȱsituations.ȱ TheȱlibraryȱalsoȱintroducedȱtheȱnotionȱofȱbufferedȱI/O,ȱwhichȱincreasesȱtheȱefficiencyȱ ofȱmostȱprograms.ȱ Thereȱ wereȱtwoȱmajorȱdrawbacksȱ toȱthisȱlibrary.ȱ First,ȱ itȱwasȱ implementedȱ onȱ oneȱ specificȱ typeȱ ofȱ machineȱ withoutȱ muchȱ considerationȱ ofȱ otherȱ machinesȱ withȱ differentȱcharacteristics.ȱThisȱfactȱledȱtoȱsituationsȱwhereȱcodeȱthatȱworkedȱfineȱonȱoneȱ machineȱ couldȱ notȱ heȱ madeȱ toȱ workȱ onȱ anotherȱ solelyȱ becauseȱ ofȱ architecturalȱ differencesȱbetweenȱtheȱmachines.ȱTheȱsecondȱdrawbackȱisȱdirectlyȱrelatedȱtoȱtheȱfirst.ȱ Whenȱ implementorsȱ discoveredȱ theseȱ deficiencies,ȱ theyȱ attemptedȱ toȱ fixȱ themȱ byȱ modifyingȱ theȱ libraryȱ functions.ȱ Asȱ soonȱ asȱ theyȱ didȱ so,ȱ though,ȱ theȱ libraryȱ wasȱ noȱ longerȱȈstandard,Ȉȱandȱprogramȱportabilityȱwasȱreduced.ȱ TheȱI/0ȱfunctionsȱinȱtheȱANSIȱCȱlibraryȱareȱdirectȱdescendentsȱofȱthoseȱfromȱtheȱ oldȱ Standardȱ I/Oȱ Libraryȱ exceptȱ thatȱ theȱ ANSIȱ functionsȱ haveȱ beenȱ improved.ȱ Portabilityȱ andȱ completenessȱ wereȱ keyȱ considerationsȱ inȱ theȱ designȱ ofȱ theȱ ANSIȱ library.ȱ However,ȱ backwardȱ compatibilityȱ withȱ existingȱ programsȱ wasȱ anotherȱ consideration.ȱ Mostȱ ofȱ theȱ differencesȱ betweenȱ ANSIȱ functionsȱ andȱ theirȱ olderȱ counterpartsȱareȱtheȱadditionsȱthatȱenhanceȱportabilityȱorȱfunctionality.ȱ Oneȱlastȱcommentȱonȱportability:ȱTheseȱfunctionsȱareȱtheȱresultȱofȱconsiderableȱ evolution,ȱ butȱ thereȱ areȱ probablyȱ additionalȱ revisionsȱ thatȱ couldȱ makeȱ themȱ evenȱ better.ȱ Aȱ majorȱ advantageȱ toȱ ANSIȱ Cȱ isȱ thatȱ anyȱ suchȱ changesȱ willȱ haveȱ toȱ beȱ implementedȱasȱdifferentȱfunctionsȱratherȱthanȱmodificationsȱtoȱtheȱexistingȱfunctions.ȱ Therefore,ȱprogramȱportabilityȱwillȱnotȱsufferȱasȱitȱhasȱinȱtheȱpast.ȱ ȱ ȱ ȱ 15.4 ANSI I/O Concepts ȱ Theȱincludeȱfileȱ stdio.hȱcontainsȱdeclarationsȱrelevantȱtoȱtheȱI/OȱportionȱofȱtheȱANSIȱ library.ȱ Itsȱ nameȱ comesȱ fromȱ theȱ oldȱ Standardȱ I/Oȱ Library.ȱ Althoughȱ aȱ fewȱ I/Oȱ functionsȱmayȱbeȱusedȱwithoutȱincludingȱthisȱfile,ȱmostȱfunctionsȱwillȱrequireȱit.ȱ Download at http://www.pin5i.com/ Chapter 15 Input/Output Functionsȱ 412ȱ 15.4.1 Streams ȱ ComputersȱtodayȱhaveȱaȱlargeȱvarietyȱofȱdevicesȱonȱwhichȱI/Oȱmayȱbeȱperformed.ȱCDȬ ROMȱ drives,ȱ hardȱ andȱ floppyȱ diskȱ drives,ȱ networkȱ connections,ȱ communicationsȱ ports,ȱ andȱ videoȱ adaptersȱ areȱ aȱ fewȱ ofȱ theȱ moreȱ commonȱ devices.ȱ Eachȱ deviceȱ hasȱ differentȱ characteristicsȱ andȱ operatingȱ protocols.ȱ Theȱ operatingȱ systemȱ takesȱ careȱ ofȱ theȱ detailsȱ ofȱ communicatingȱ withȱ theseȱ differentȱ devicesȱ andȱ providesȱ aȱ simpler,ȱ moreȱuniformȱI/Oȱinterfaceȱtoȱtheȱprogrammer.ȱ ANSIȱ Cȱ abstractsȱ theȱ notionȱ ofȱ I/Oȱ evenȱ further.ȱ Asȱ farȱ asȱ Cȱ programsȱ areȱ concerned,ȱallȱI/Oȱisȱsimplyȱaȱmatterȱofȱmovingȱbytesȱintoȱorȱoutȱofȱtheȱprogram.ȱThisȱ streamȱ ofȱ bytes,ȱ notȱ surprisingly,ȱ isȱ calledȱ aȱ stream.ȱ Theȱ programȱ isȱ onlyȱ concernedȱ withȱ creatingȱ theȱ correctȱ bytesȱ ofȱ dataȱ forȱ outputȱ andȱ interpretingȱ theȱ bytesȱ ofȱ dataȱ thatȱ comeȱ inȱ asȱ input.ȱ Detailsȱ ofȱ theȱ specificȱ I/Oȱ deviceȱ areȱ hiddenȱ fromȱ theȱ programmer.ȱ Mostȱ streamsȱ areȱ fullyȱ buffered,ȱ whichȱ meansȱ thatȱ ȈreadingȈȱ andȱ ȈwritingȈȱ actuallyȱcopyȱdataȱoutȱofȱandȱintoȱanȱareaȱinȱmemoryȱcalledȱtheȱbuffer.ȱCopyingȱtoȱandȱ fromȱ memoryȱ isȱ veryȱ fast.ȱ Theȱ bufferȱ forȱ anȱ outputȱ streamȱ isȱ flushedȱ (physicallyȱ written)ȱtoȱtheȱdeviceȱorȱfileȱonlyȱwhenȱ itȱ becomesȱfull.ȱWritingȱaȱfullȱbufferȱisȱmoreȱ efficientȱ thanȱ writingȱ theȱ dataȱ inȱ littleȱ bitsȱ andȱ piecesȱ asȱ theȱ programȱ producesȱ it.ȱȱ Similarly,ȱinputȱbuffersȱareȱrefilledȱwhenȱtheyȱbecomeȱemptyȱbyȱreadingȱtheȱnextȱlargeȱ chunkȱofȱinputȱfromȱtheȱdeviceȱorȱfileȱintoȱtheȱbuffer.ȱ CAUTION! Thisȱ bufferingȱ couldȱ causeȱ confusionȱ withȱ theȱ standardȱ inputȱ andȱ standardȱ output,ȱsoȱtheyȱareȱfullyȱbufferedȱonlyȱifȱtheȱoperatingȱsystemȱcanȱdetermineȱthatȱtheyȱ areȱ notȱ associatedȱ withȱ interactiveȱ devices.ȱ Otherwise,ȱ theirȱ bufferingȱ stateȱ isȱ implementationȱ dependent.ȱ Aȱ commonȱ (butȱ notȱ universal)ȱ strategyȱ isȱ toȱ tieȱ theȱ standardȱoutputȱtoȱtheȱstandardȱinputȱinȱsuchȱaȱwayȱthatȱtheȱoutputȱbufferȱisȱflushedȱ whenȱinputȱisȱrequested.ȱȱThen,ȱanyȱpromptsȱorȱotherȱoutputȱpreviouslyȱwrittenȱtoȱtheȱ outputȱbufferȱwillȱappearȱonȱtheȱscreenȱbeforeȱtheȱuserȱmustȱenterȱtheȱinput.ȱ ȱ ȱ Althoughȱ thisȱ bufferingȱ isȱ usuallyȱ desirable,ȱ itȱ canȱ causeȱ confusionȱ whenȱ youȱ areȱ debuggingȱyourȱprogram.ȱAȱcommonȱdebuggingȱstrategyȱisȱtoȱsprinkleȱcallsȱtoȱ printfȱ throughoutȱtheȱprogramȱtoȱdetermineȱtheȱspecificȱareaȱinȱwhichȱanȱerrorȱisȱoccurring.ȱ However,ȱtheȱoutputȱfromȱtheseȱcallsȱisȱbufferedȱandȱdoesȱnotȱimmediatelyȱshowȱupȱ onȱtheȱscreen.ȱȱInȱfactȱifȱtheȱprogramȱaborts,ȱtheȱbufferedȱoutputȱmayȱnotȱbeȱwrittenȱatȱ all,ȱ whichȱ leadsȱ theȱ programmerȱ toȱ incorrectȱ conclusionsȱ aboutȱ whereȱ theȱ errorȱ occurred.ȱTheȱsolutionȱtoȱthisȱproblemȱisȱtoȱalwaysȱfollowȱdebuggingȱ printfȇsȱwithȱaȱ callȱtoȱfflush,ȱlikeȱthis:ȱ Download at http://www.pin5i.com/ 15.4 ANSI I/O Conceptsȱ 413 printf( "something or other" ); fflush( stdout ); ȱ fflushȱ (describedȱ inȱ moreȱ detailȱ laterȱ inȱ theȱ chapter)ȱ forcesȱ theȱ bufferȱ toȱ writtenȱ immediatelyȱwhetherȱorȱnotȱitȱisȱfull.ȱ ȱ ȱ Text Streams TIP ȱ Thereȱ areȱ twoȱ typesȱ ofȱ streams,ȱ textȱ andȱ binary.ȱ Textȱ streamsȱ haveȱ certainȱ characteristicsȱ thatȱ mayȱ varyȱ fromȱ systemȱ toȱ system.ȱ Oneȱ ofȱ theseȱ isȱ theȱ maximumȱ lengthȱ ofȱ aȱ textȱ line.ȱ Theȱ Standardȱ requiresȱ thatȱ thisȱ limitȱ beȱ atȱ leastȱ 254ȱ characters.ȱȱ Anotherȱisȱtheȱmannerȱinȱwhichȱtextȱlinesȱareȱterminated.ȱForȱexample,ȱtheȱconventionȱ forȱtextȱfilesȱonȱMSȬDOSȱsystemsȱisȱthatȱeachȱlineȱisȱterminatedȱwithȱaȱcarriageȱreturnȱ characterȱandȱaȱnewlineȱ(alsoȱcalledȱaȱlinefeed)ȱcharacter.ȱHowever,ȱUNIXȱsystemsȱuseȱ onlyȱaȱnewline.ȱ ȱ Theȱ Standardȱ definesȱ aȱ textȱ lineȱ toȱ beȱ zeroȱ orȱ moreȱ charactersȱ followedȱ byȱ aȱ terminatingȱnewlineȱcharacter.ȱOnȱsystemsȱwhereȱtheȱexternalȱrepresentationȱofȱaȱtextȱ lineȱdiffersȱfromȱthisȱdefinition,ȱtheȱlibraryȱfunctionsȱtakeȱcareȱofȱtranslatingȱbetweenȱ theȱ externalȱ andȱ internalȱ forms.ȱ Onȱ MSȬDOSȱ systems,ȱ forȱ example,ȱ aȱ newlineȱ isȱ writtenȱasȱtheȱcarriageȱreturn/newlineȱpair.ȱOnȱinput,ȱtheȱcarriageȱreturnȱcharacterȱisȱ discarded.ȱ Theȱ abilityȱ toȱ manipulateȱ textȱ withoutȱ regardȱ toȱ itsȱ externalȱ appearanceȱ simplifiesȱtheȱcreationȱofȱportableȱprograms.ȱ ȱ ȱ Binary Streams ȱ Theȱbytesȱinȱaȱbinaryȱstream,ȱonȱtheȱotherȱhand,ȱareȱwrittenȱtoȱtheȱfileȱorȱdeviceȱexactlyȱ asȱtheȱprogramȱwroteȱthemȱandȱareȱdeliveredȱtoȱtheȱprogramȱexactlyȱasȱtheyȱwereȱreadȱ fromȱ theȱ fileȱ orȱ device.ȱ Theyȱ areȱ notȱ changedȱ inȱ anyȱ manner.ȱ Thisȱ typeȱ ofȱ streamȱ isȱ appropriateȱ forȱ nontextualȱ data,ȱ butȱ binaryȱ streamsȱ mayȱ alsoȱ beȱusedȱ forȱ textȱ filesȱ ifȱ youȱdoȱnotȱwantȱtheȱI/OȱfunctionsȱtoȱmodifyȱtheȱendȬofȬlineȱcharacters.ȱ ȱ ȱ ȱ 15.4.2 FILEs ȱ Oneȱ ofȱ theȱ declarationsȱ containedȱ inȱ stdio.hȱ isȱ forȱ theȱ fileȱ structure.ȱ Notȱ toȱ beȱ confusedȱwithȱaȱdataȱfileȱstoredȱonȱaȱdisk,ȱaȱ FILEȱisȱaȱdataȱstructureȱusedȱtoȱaccessȱaȱ stream.ȱ Ifȱyouȱhaveȱseveralȱdifferentȱstreamsȱ activeȱ atȱaȱtime,ȱ eachȱwillȱhaveȱ itsȱ ownȱ FILEȱ associatedȱ withȱ it.ȱ Toȱ performȱ someȱ operationȱ onȱ aȱ stream,ȱ youȱ callȱ theȱ appropriateȱfunctionȱandȱpassȱitȱtheȱFILEȱassociatedȱwithȱthatȱstream.ȱ Download at http://www.pin5i.com/ Chapter 15 Input/Output Functionsȱ 414ȱ Theȱ runtimeȱ environmentȱ mustȱ provideȱ atȱ leastȱ threeȱ streamsȱ toȱ everyȱ ANSIȱ Cȱ program—theȱstandardȱinput,ȱtheȱstandardȱoutput,ȱandȱtheȱstandardȱerror.ȱTheȱnamesȱofȱ theseȱstreamsȱareȱstdin,ȱstdout,ȱandȱstderr,ȱrespectively,ȱandȱtheyȱareȱsimplyȱpointersȱ toȱ FILEȱstructures.ȱTheȱstandardȱinputȱisȱwhereȱinputȱcomesȱfromȱbyȱdefault,ȱandȱtheȱ standardȱ outputȱ isȱ theȱ defaultȱ outputȱ device.ȱ Theȱ defaultsȱ dependȱ onȱ theȱ implementation;ȱ oftenȱ theȱ standardȱ inputȱ isȱ aȱ keyboardȱ deviceȱ andȱ theȱ standardȱ outputȱisȱaȱterminalȱorȱscreen.ȱ Manyȱ operatingȱ systemsȱ letȱ theȱ userȱ changeȱ theȱ standardȱ inputȱ andȱ outputȱ fromȱ theirȱ defaultȱ devicesȱ whenȱ aȱ programȱ isȱ executed.ȱ Forȱ example,ȱ MSȬDOSȱ andȱ UNIXȱsystemsȱbothȱsupportȱinput/outputȱredirectionȱusingȱthisȱnotation:ȱ ȱ $program < data > answer ȱ Whenȱthisȱprogramȱexecutes,ȱitȱwillȱreadȱitsȱstandardȱinputȱfromȱtheȱfileȱ dataȱinsteadȱ ofȱtheȱkeyboard,ȱandȱitȱwillȱwriteȱitsȱstandardȱoutputȱtoȱtheȱfileȱ answerȱinsteadȱofȱtheȱ screen.ȱ Referȱ toȱ yourȱ systemȇsȱ documentationȱ forȱ detailsȱ onȱ howȱ (orȱ whether)ȱ I/Oȱ redirectionȱisȱperformed.ȱ Theȱstandardȱerrorȱisȱtheȱplaceȱwhereȱerrorȱmessagesȱareȱwritten.ȱ perrorȱwritesȱ itsȱoutputȱhere.ȱOnȱmanyȱsystemsȱtheȱstandardȱerrorȱandȱtheȱstandardȱoutputȱdefaultȱ toȱtheȱsameȱlocation,ȱbutȱhavingȱaȱseparateȱstreamȱforȱerrorȱmessagesȱmeansȱthatȱtheyȱ willȱ stillȱ appearȱ onȱ theȱ screenȱ orȱ otherȱ defaultȱ outputȱ deviceȱ evenȱ ifȱ theȱ standardȱ outputȱhasȱbeenȱredirectedȱsomewhereȱelse.ȱ ȱ ȱ ȱ 15.4.3 Standard I/O Constants ȱ Thereȱ areȱ numerousȱ constantsȱ definedȱ inȱ stdio.hȱ thatȱ areȱ relatedȱ inȱ someȱ wayȱ toȱ inputȱ andȱ output.ȱ EOF,ȱ whichȱ youȱ haveȱ alreadyȱ seen,ȱ isȱ theȱ valueȱ returnedȱ byȱ manyȱ functionsȱtoȱindicateȱthatȱendȱofȱfileȱhasȱbeenȱreached.ȱTheȱactualȱvalueȱchosenȱforȱ EOFȱ usesȱ moreȱ bitsȱ thanȱ aȱ characterȱ inȱ orderȱ toȱ preventȱ binaryȱ characterȱ valuesȱ fromȱ mistakenlyȱbeingȱinterpretedȱasȱEOF.ȱ Howȱ manyȱ filesȱ canȱ aȱ programȱ naveȱ openȱ atȱ once?ȱ Itȱ dependsȱ onȱ theȱ implementation,ȱbutȱyouȱareȱguaranteedȱofȱbeingȱableȱtoȱsimultaneouslyȱopenȱatȱleastȱ FOPEN_MAXȱfiles.ȱThisȱconstant,ȱwhichȱincludesȱtheȱthreeȱstandardȱstreams,ȱmustȱbeȱatȱ leastȱeight.ȱ Theȱ constantȱ FILENAME_MAXȱ isȱ anȱ integerȱ thatȱ indicatesȱ howȱ largeȱ aȱ characterȱ arrayȱshouldȱbeȱtoȱholdȱtheȱlongestȱlegalȱfileȱnameȱthatȱtheȱimplementationȱsupports.ȱ Ifȱ thereȱ isnȇtȱ aȱ practicalȱ limitȱ toȱ theȱ lengthȱ ofȱ aȱ fileȱ name,ȱ thenȱ thisȱ valueȱ isȱ theȱ recommendedȱsizeȱforȱsuchȱstrings.ȱTheȱremainingȱconstantsȱareȱdescribedȱlaterȱinȱthisȱ chapterȱalongȱwithȱtheȱfunctionsȱwithȱwhichȱtheyȱareȱused.ȱ ȱ Download at http://www.pin5i.com/ 15.5 Overview of Stream I/Oȱ 415 15.5 Overview of Stream I/O ȱ Theȱ standardȱ libraryȱ functionsȱ makeȱ itȱ veryȱ convenientȱ toȱ performȱ I/Oȱ toȱ andȱ fromȱ filesȱinȱCȱprograms.ȱHereȱisȱaȱgeneralȱoverviewȱofȱfileȱI/O.ȱ 1. Theȱprogramȱdeclaresȱaȱpointerȱvariableȱofȱtypeȱ FILE *ȱforȱeachȱfileȱthatȱmustȱbeȱ simultaneouslyȱactive.ȱThisȱvariableȱwillȱpointȱtoȱtheȱ FILEȱstructureȱusedȱbyȱtheȱ streamȱwhileȱitȱisȱactive.ȱ 2. Theȱ streamȱ isȱ openedȱ byȱ callingȱ theȱ fopenȱ function.ȱ Toȱ openȱ aȱ stream,ȱ youȱ mustȱ specifyȱ whichȱ fileȱ orȱ deviceȱ isȱ toȱ beȱ accessedȱ andȱ howȱ itȱ isȱ toȱ beȱ accessedȱ (forȱ example,ȱ reading,ȱ writing,ȱ orȱ both).ȱ fopenȱ andȱ theȱ operatingȱ systemȱ verifyȱ thatȱ theȱ fileȱ orȱ deviceȱ existsȱ (and,ȱ onȱ someȱ operatingȱ systems,ȱ thatȱ youȱ haveȱ permissionȱ toȱ accessȱ itȱ inȱ theȱ mannerȱ youȱ specify)ȱ andȱ initializesȱ theȱ FILEȱ structure.ȱ 3. Theȱfileȱisȱthenȱreadȱand/orȱwrittenȱasȱdesired.ȱ 4. Finally,ȱ theȱ streamȱisȱclosedȱwithȱ theȱ fcloseȱfunction.ȱ Closingȱaȱ streamȱpreventsȱ theȱassociatedȱfileȱfromȱbeingȱaccessedȱagain,ȱguaranteesȱthatȱanyȱdataȱstoredȱinȱ theȱstreamȱbufferȱisȱcorrectlyȱwrittenȱtoȱtheȱfile,ȱandȱreleasesȱtheȱFILEȱstructureȱsoȱ thatȱitȱcanȱbeȱusedȱagainȱwithȱanotherȱfile.ȱ ȱ I/Oȱ onȱ theȱ standardȱ streamsȱ isȱ simplerȱ becauseȱ theyȱ doȱ notȱ haveȱ toȱ beȱ openedȱ orȱ closed.ȱ TheȱI/Oȱfunctionsȱdealȱwithȱdataȱinȱthreeȱbasicȱforms:ȱindividualȱcharacters,ȱtextȱ lines,ȱandȱbinaryȱdata.ȱAȱdifferentȱsetȱofȱfunctionsȱisȱusedȱtoȱprocessȱeachȱform.ȱTableȱ 15.1ȱlistsȱtheȱfunctionȱorȱfunctionȱfamilyȱusedȱforȱeachȱformȱofȱI/O.ȱFunctionȱfamilies,ȱ listedȱ inȱ theȱ tableȱ inȱitalic,ȱ areȱ groupsȱ ofȱfunctionsȱwhoseȱmembersȱeachȱperformȱtheȱ sameȱbasicȱworkȱinȱaȱslightlyȱdifferentȱway.ȱTheȱfunctionsȱdifferȱinȱwhereȱtheȱinputȱisȱ obtainedȱorȱwhereȱtheȱoutputȱgoes.ȱTheȱvariantsȱareȱtoȱperformȱtheȱwork:ȱ ȱ ȱ ȱ ȱ ȱ Function or Family Name Description Type of Data Input Output Characterȱ getcharȱ putcharȱ Readȱ(write)ȱaȱsingleȱcharacterȱ Lineȱ getsȱ putsȱ Unformattedȱinputȱ(output)ȱofȱaȱlineȱ scanfȱ printfȱ Formattedȱinputȱ(output)ȱ fread fwrite Readȱ(write)ȱbinaryȱdataȱ Binaryȱ ȱ Tableȱ15.1ȱȱFunctionsȱtoȱperformȱcharacter,ȱline,ȱandȱbinaryȱI/Oȱ Download at http://www.pin5i.com/ 416ȱ Chapter 15 Input/Output Functionsȱ ȱ Family Name Purpose To Any Stream Only stdin and stdout String in Memory fgetc, getc getchar Characterȱinputȱ 1 getcharȱ fputc, putc putchar Characterȱoutputȱ 1 putcharȱ fgets gets Lineȱinputȱ 2 getsȱ fputs puts Lineȱoutputȱ 2 putsȱ fscanf scanf sscanf Formattedȱinputȱ scanfȱ printf sprintf Formattedȱoutputȱ fprintf printfȱ ȱ 1 Useȱ aȱ subscriptȱ orȱ indirectionȱ onȱ aȱ pointerȱ toȱ get/putȱ singleȱ charactersȱ to/fromȱ memory,ȱ 2 Use strcpyȱtoȱget/putȱlinesȱto/fromȱmemory.ȱ ȱ Tableȱ15.2ȱȱInput/outputȱfunctionȱfamiliesȱ ȱ ȱ ȱ ȱ 1. onlyȱwithȱstdinȱorȱstdout,ȱ 2. withȱaȱstreamȱgivenȱasȱanȱargument,ȱ 3. usingȱcharacterȱstringsȱinȱmemoryȱratherȱthanȱstreams.ȱ ȱ Theȱ functionsȱ thatȱ requireȱ aȱ streamȱ argumentȱ willȱ acceptȱ stdinȱ orȱ stdoutȱ asȱ arguments.ȱSomeȱfamiliesȱdoȱnotȱhaveȱfunctionsȱforȱtheȱstringȱvariants,ȱbecauseȱitȱisȱsoȱ easyȱtoȱaccomplishȱtheȱsameȱresultȱwithȱotherȱstatementsȱorȱfunctions.ȱTableȱ15.2ȱlistsȱ theȱ functionsȱ inȱ eachȱ family.ȱ Theȱ individualȱ functionsȱ areȱ describedȱ laterȱ inȱ thisȱ chapter.ȱ ȱ ȱ ȱ 15.6 Opening Streams ȱ Theȱ fopenȱ functionȱ opensȱ aȱ specificȱ fileȱ andȱ associatesȱ aȱ streamȱ withȱ theȱ file.ȱ Itsȱ prototypeȱisȱshownȱbelow.ȱ ȱ FILE *fopen( char const *name, char const *mode ); ȱ Theȱargumentsȱareȱbothȱstrings.ȱ nameȱisȱtheȱnameȱofȱtheȱfileȱorȱdeviceȱthatȱyouȱwishȱtoȱ open.ȱTheȱrulesȱforȱconstructingȱfilenamesȱvaryȱfromȱsystemȱtoȱsystem,ȱwhichȱisȱwhyȱ fopenȱ takesȱ theȱ filenameȱ inȱ oneȱ stringȱ ratherȱ thanȱ inȱ separateȱ argumentsȱ forȱ pathȱ name,ȱ driveȱ letter,ȱ fileȱ extension,ȱ andȱ soȱ forth.ȱ Thisȱ argumentȱ specifiesȱ theȱ fileȱ toȱ open—theȱ nameȱ ofȱ theȱ FILE *ȱ variableȱ thatȱ theȱ programȱ usesȱ toȱ saveȱ theȱ valueȱ returnedȱbyȱfopenȱdoesȱnotȱinfluenceȱwhichȱfileȱisȱopened.ȱ Download at http://www.pin5i.com/ 15.6 Opening Streamsȱ CAUTION! 417 Theȱmodeȱargumentȱindicatesȱwhetherȱtheȱstreamȱwillȱbeȱusedȱforȱinput,ȱoutput,ȱ orȱ bothȱ andȱ whetherȱ theȱ streamȱ willȱ beȱ textȱ orȱ binary.ȱ Theȱ modesȱ usedȱ mostȱ frequentlyȱareȱshownȱinȱtheȱfollowingȱtable.ȱ ȱ ȱ Read Write Append "r" "w" "a" Textȱ "rb" "wb" "ab" Binaryȱ ȱ ȱ Theȱmodesȱbeginȱwithȱr,ȱw,ȱorȱaȱtoȱindicateȱthatȱtheȱstreamȱisȱtoȱbeȱopenedȱforȱreading,ȱ writing,ȱ orȱ appending,ȱ respectively.ȱ Aȱ fileȱ openedȱ forȱ readingȱ mustȱ alreadyȱ exist,ȱ whereasȱaȱfileȱopenedȱforȱwritingȱisȱtruncatedȱifȱitȱalreadyȱexistsȱandȱcreatedȱifȱitȱdoesȱ not.ȱIfȱaȱfileȱopenedȱforȱappendingȱdoesȱnotȱexist,ȱitȱwillȱbeȱcreated;ȱifȱitȱalreadyȱexists,ȱ itȱisȱnotȱtruncated.ȱInȱeitherȱcase,ȱdataȱcanȱonlyȱbeȱwrittenȱtoȱtheȱendȱofȱtheȱfile.ȱ Adding a + toȱ theȱ modeȱ opensȱ theȱ fileȱ forȱ update,ȱ andȱ bothȱ readingȱ andȱ writingȱareȱallowedȱonȱ theȱstream.ȱHowever,ȱ ifȱyouȱ haveȱbeenȱreadingȱ fromȱ theȱfile,ȱ youȱmustȱcallȱoneȱofȱtheȱfileȱpositioningȱfunctionsȱ(fseek,ȱ fsetpos,ȱandȱ rewind,ȱwhichȱ areȱdescribedȱlaterȱinȱthisȱchapter)ȱbeforeȱyouȱmayȱbeginȱwritingȱtoȱit.ȱAfterȱwritingȱtoȱ theȱfile,ȱyouȱmustȱcallȱeitherȱ fflushȱorȱoneȱofȱtheȱfileȱpositioningȱfunctionsȱbeforeȱyouȱ mayȱbeginȱreadingȱfromȱit.ȱ Ifȱ itȱ isȱ successful,ȱ fopenȱ returnsȱ aȱ pointerȱ toȱ theȱ FILEȱ structureȱ forȱ theȱ newlyȱ createdȱ stream.ȱ Otherwiseȱ aȱ NULLȱ pointerȱ isȱ returnedȱ andȱ errnoȱ willȱ indicateȱ theȱ natureȱofȱtheȱproblem.ȱ ȱ Alwaysȱ checkȱ theȱ valueȱ returnedȱ byȱ fopen!ȱ Ifȱ theȱ functionȱ fails,ȱ aȱ NULLȱ valueȱ isȱ returned.ȱIfȱtheȱprogramȱdoesȱnotȱcheckȱforȱerrors,ȱtheȱNULLȱpointerȱwillȱbeȱgivenȱtoȱ subsequentȱI/Oȱfunctions.ȱTheyȱwillȱperformȱindirectionȱonȱitȱandȱfail.ȱ Theȱfollowingȱexampleȱillustratesȱtheȱuseȱofȱfopen.ȱ ȱ FILE *input; input = fopen( "data3", "r" ); if( input == NULL ){ perror( "data3" ); exit( EXIT_FAILURE ); } ȱ First,ȱtheȱ fopenȱfunctionȱisȱcalled;ȱtheȱfileȱtoȱbeȱopenedȱisȱnamedȱ data3ȱandȱitȱisȱtoȱbeȱ openedȱforȱreading.ȱThisȱstepȱisȱfollowedȱbyȱtheȱallȬimportantȱcheckȱtoȱseeȱwhetherȱtheȱ openȱ succeeded.ȱ Ifȱ itȱ didȱ not,ȱ theȱ errorȱ isȱ reportedȱ toȱ theȱ userȱ andȱ theȱ programȱ terminates.ȱTheȱexactȱoutputȱproducedȱbyȱthisȱcallȱtoȱ perrorȱwillȱvaryȱdependingȱonȱ theȱoperatingȱsystemȱinȱuse,ȱbutȱitȱmightȱlookȱsomethingȱlikeȱthis:ȱ Download at http://www.pin5i.com/ 418ȱ Chapter 15 Input/Output Functionsȱ data3: No such file or directory ȱ Thisȱtypeȱofȱmessageȱclearlyȱindicatesȱtoȱtheȱuserȱthatȱsomethingȱhasȱgoneȱwrongȱandȱ givesȱ theȱ userȱ aȱ goodȱ indicationȱ ofȱ whatȱ theȱ problemȱ is.ȱ Itȱ isȱ especiallyȱ importantȱ toȱ reportȱtheseȱerrorsȱinȱprogramsȱwhichȱreadȱfilenamesȱorȱtakeȱthemȱfromȱtheȱcommandȱ line.ȱWheneverȱtheȱuserȱentersȱaȱfilename,ȱthereȱisȱtheȱpossibilityȱthatȱtheyȱmayȱmakeȱaȱ mistake.ȱClear,ȱdescriptiveȱerrorȱmessagesȱhelpȱtheȱuserȱdetermineȱwhatȱwentȱwrongȱ andȱbowȱtoȱfixȱit.ȱ Theȱ freopenȱfunctionȱisȱusedȱtoȱopenȱ(orȱreopen)ȱaȱspecificȱstreamȱonȱaȱfile.ȱȱItsȱ prototypeȱis:ȱ ȱ FILE *freopen( char const *filename, char const *mode, FILE *stream ); ȱ Theȱlastȱargumentȱisȱtheȱstreamȱtoȱbeȱopened.ȱȱItȱmayȱbeȱaȱstreamȱthatȱwasȱpreviouslyȱ returnedȱbyȱfopen,ȱorȱitȱmaybeȱoneȱofȱtheȱstandardȱstreamȱstdin,ȱstdout,ȱorȱstderr.ȱ Theȱfunctionȱfirstȱattemptsȱtoȱcloseȱtheȱstream.ȱItȱthenȱopensȱtheȱstreamȱwithȱtheȱ givenȱfileȱnameȱandȱmode.ȱIfȱtheȱopenȱfails,ȱtheȱvalueȱ NULLȱisȱreturned,ȱotherwiseȱtheȱ thirdȱargumentȱvalueȱisȱreturned.ȱ ȱ ȱ ȱ 15.7 Closing Streams ȱ Streamsȱareȱclosedȱwithȱtheȱfcloseȱfunction,ȱwhichȱhasȱthisȱprototype:ȱ ȱ int fclose( FILE *f ); ȱ Forȱ outputȱ streams,ȱ fcloseȱ flushesȱ theȱ bufferȱ beforeȱ theȱ fileȱ isȱ closed.ȱ fcloseȱ returnȱ zeroȱifȱitȱsuccessfulȱandȱEOFȱotherwise.ȱ Programȱ 15.1ȱ interpretsȱ itsȱ commandȱ lineȱ argumentsȱ asȱ aȱ listȱ ofȱ filenames.ȱ Itȱ opensȱeachȱfileȱandȱprocessesȱthem,ȱoneȱbyȱone.ȱIfȱanyȱfileȱcannotȱbeȱopened,ȱanȱerrorȱ messageȱthatȱincludesȱtheȱnameȱofȱtheȱfileȱisȱprinted,ȱandȱtheȱprogramȱcontinuesȱtoȱtheȱ nextȱnameȱinȱtheȱlist.ȱTheȱexitȱstatusȱisȱbasedȱonȱwhetherȱanyȱerrorsȱoccurred.ȱ Iȱ saidȱ earlierȱ thatȱ anyȱ operationȱ thatȱ mightȱ failȱ shouldȱ beȱ checkedȱ toȱ seeȱ whetherȱorȱnotȱitȱsucceeded.ȱInȱthisȱprogram,ȱtheȱvalueȱreturnedȱbyȱ fcloseȱisȱcheckedȱ toȱ seeȱ ifȱ anythingȱ wentȱ wrong.ȱ Manyȱ programmersȱ doȱ notȱ botherȱ withȱ thisȱ test,ȱ arguingȱ thatȱ thereȱ isȱ noȱ reasonȱ whyȱ theȱ closeȱ willȱ failȱ toȱ work.ȱ Furthermore,ȱ theyȇreȱ finishedȱwithȱtheȱfile,ȱsoȱitȱdoesnȇtȱmatterȱevenȱifȱitȱdidȱfail.ȱHowever,ȱthisȱanalysisȱisȱ notȱentirelyȱcorrect.ȱ ȱ Download at http://www.pin5i.com/ 15.7 Closing Streamsȱ 419 ȱ /* ** Process each of the files whose names appear on the command line. */ #include <stdlib.h> #include <stdio.h> int main( int ac, char **av ) { int exit_status = EXIT_SUCCESS; FILE *input; /* ** While there are more names ... */ while( *++av != NULL ){ /* ** Try opening the file. */ input = fopen( *av, "r" ); if( input == NULL ){ perror( *av ); exit_status = EXIT_FAILURE; continue; } /* ** Process the file here ... */ /* ** Close the file (don't expect any errors here). */ if( fclose( input ) != 0 ){ perror( "fclose" ); exit( EXIT_FAILURE ); } } return exit_status; } ȱ Programȱ15.1ȱȱOpeningȱandȱclosingȱfilesȱȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱopen_cls.cȱ Download at http://www.pin5i.com/ 420ȱ Chapter 15 Input/Output Functionsȱ Theȱ inputȱvariableȱmightȱhaveȱchangedȱbecauseȱofȱaȱprogramȱbugȱbetweenȱtheȱ fopenȱ andȱ theȱ fclose.ȱ Thisȱ bugȱ wouldȱ certainlyȱ causeȱ aȱ failure.ȱ Inȱ programsȱ thatȱ doȱ notȱcheckȱtheȱresultȱofȱanȱfopen,ȱinputȱmightȱevenȱbeȱNULL.ȱEitherȱofȱtheseȱconditionsȱ willȱ causeȱ theȱ fcloseȱ toȱ fail.ȱ Butȱ ifȱ eitherȱ ofȱ theseȱ conditionsȱ existed,ȱ theȱ I/Oȱ wouldȱ haveȱ failedȱ asȱ well,ȱ andȱ theȱ programȱ probablyȱ wouldȱ haveȱ terminatedȱ longȱ beforeȱ fcloseȱwasȱcalled.ȱ Soȱshouldȱyouȱcheckȱ fcloseȱ(orȱanyȱotherȱoperation,ȱforȱthatȱmatter)ȱforȱerrorsȱ orȱnot?ȱWhenȱmakingȱthisȱdecision,ȱaskȱyourselfȱtwoȱquestions.ȱ ȱ 1. Whatȱshouldȱbeȱdoneȱifȱtheȱoperationȱsucceeded?ȱ 2. Whatȱshouldȱbeȱdoneȱifȱtheȱoperationȱfailed?ȱ ȱ Ifȱtheȱanswersȱtoȱtheseȱquestionsȱareȱdifferent,ȱthenȱyouȱshouldȱcheckȱforȱtheȱerror.ȱItȱisȱ reasonableȱ toȱ skipȱ theȱ errorȱ checkingȱ onlyȱ inȱ casesȱ whereȱ bothȱ questionsȱ haveȱ theȱ sameȱanswer.ȱ ȱ ȱ ȱ 15.8 Character I/O ȱ Afterȱ aȱ streamȱ isȱ open,ȱ itȱ canȱ beȱ usedȱ forȱ inputȱ andȱ output.ȱ Theȱ simplestȱ formȱ isȱ characterȱI/O.ȱCharacterȱinputȱisȱperformedȱbyȱtheȱgetcharȱfamilyȱofȱfunctions,ȱwhoseȱ prototypesȱareȱshownȱbelow.ȱ ȱ int fgetc( FILE *stream ); int getc( FILE *stream ); int getchar( void ); ȱ Theȱ desiredȱ streamȱ isȱ givenȱ asȱ theȱ argumentȱ toȱ getcȱ andȱ fgetc,ȱ butȱ getcharȱ alwaysȱ readsȱfromȱtheȱstandardȱinput.ȱȱEachȱfunctionȱreadsȱtheȱnextȱcharacterȱfromȱtheȱstreamȱ andȱreturnsȱitȱasȱtheȱvalueȱofȱtheȱfunction.ȱIfȱthereȱarenȇtȱanyȱmoreȱcharactersȱonȱtheȱ stream,ȱtheȱconstantȱEOFȱisȱreturnedȱinstead.ȱ Theseȱ functionsȱ areȱ supposedȱ toȱ readȱ characters,ȱ yetȱ theyȱ allȱ returnȱ anȱ intȱ ratherȱthanȱaȱchar.ȱAlthoughȱcodesȱthatȱrepresentȱcharactersȱareȱjustȱsmallȱintegers,ȱtheȱ realȱreasonȱforȱreturningȱanȱ intȱisȱtoȱallowȱtheȱfunctionsȱtoȱreportȱendȱofȱfile.ȱIfȱaȱ charȱ wereȱ returned,ȱ thenȱ oneȱ ofȱ theȱ 256ȱ characterȱ valuesȱ wouldȱ haveȱ toȱ beȱ chosenȱ toȱ designateȱendȱofȱfile.ȱIfȱthisȱcharacterȱappearedȱinȱaȱfile,ȱitȱwouldȱbeȱimpossibleȱtoȱreadȱ beyondȱitsȱpositionȱbecauseȱtheȱcharacterȱwouldȱseemȱtoȱsignalȱtheȱendȱofȱtheȱfile.ȱ Havingȱ theȱ functionsȱ returnȱ anȱ intȱ solvesȱ theȱ problem.ȱ EOFȱ isȱ definedȱ asȱ anȱ integerȱwhoseȱvalueȱisȱoutsideȱofȱtheȱrangeȱofȱpossibleȱcharacterȱvalues.ȱThisȱsolutionȱ letsȱusȱuseȱtheseȱfunctionsȱtoȱreadȱbinaryȱfiles,ȱwhereȱallȱcharactersȱmayȱoccur,ȱasȱwellȱ asȱtextȱfiles.ȱ Download at http://www.pin5i.com/ 15.8 Character I/Oȱ 421 Toȱ writeȱ individualȱ charactersȱ toȱ aȱ stream,ȱ functionsȱ inȱ theȱ putcharȱ familyȱ areȱ used.ȱTheirȱprototypesȱare:ȱ ȱ int fputc( int character, FILE *stream ); int putc( int character, FILE *stream ); int putchar( int character ); ȱ Theȱ firstȱ argumentȱ isȱ theȱ characterȱ toȱ beȱ printed.ȱ Theȱ functionsȱ truncateȱ theȱ integerȱargumentȱtoȱanȱunsignedȱcharacterȱbeforeȱprinting,ȱsoȱ ȱ putchar( 'abc' ); ȱ onlyȱprintsȱoneȱcharacterȱ(whichȱoneȱisȱimplementationȱdependent).ȱ ȱTheseȱfunctionsȱreturnȱtheȱvalueȱ EOFȱifȱtheyȱfailȱforȱanyȱreason,ȱsuchȱasȱwritingȱ toȱaȱstreamȱthatȱhasȱbeenȱclosed.ȱ ȱ ȱ ȱ 15.8.1 Character I/O Macros ȱ fgetcȱandȱfputcȱareȱtrueȱfunctions,ȱbutȱgetc,ȱputc,ȱgetchar,ȱandȱputcharȱareȱ#defineȇdȱ macros.ȱ Theȱ macrosȱ areȱ slightlyȱ moreȱ efficientȱ inȱ termsȱ ofȱ executionȱ time,ȱ andȱ theȱ functionsȱwillȱbeȱmoreȱefficientȱinȱtermsȱofȱprogramȱsize.ȱHavingȱbothȱtypesȱavailableȱ allowsȱ youȱ toȱ chooseȱ theȱ rightȱ oneȱ dependingȱ onȱ whetherȱ sizeȱ orȱ speedȱ isȱ moreȱ important.ȱThisȱdistinctionȱisȱrarelyȱaȱmatterȱofȱgreatȱconcern,ȱbecauseȱtheȱdifferencesȱ observedȱinȱactualȱprogramsȱusingȱoneȱorȱtheȱotherȱareȱusuallyȱnotȱsignificant.ȱ ȱ ȱ ȱ 15.8.2 Undoing Character I/O ȱ Youȱcannotȱtellȱwhatȱtheȱnextȱcharacterȱonȱaȱstreamȱwillȱbeȱuntilȱyouȇveȱreadȱit.ȱThus,ȱ youȱ willȱ occasionallyȱ readȱ oneȱ characterȱ beyondȱ whatȱ youȱ wanted.ȱ Forȱ example,ȱ supposeȱ youȱ mustȱ readȱ aȱ sequenceȱ ofȱ digitsȱ fromȱ aȱ streamȱ oneȱ byȱ one.ȱ Becauseȱ youȱ cannotȱseeȱwhatȱtheȱnextȱcharacterȱwillȱbeȱwithoutȱreadingȱit,ȱyouȱmustȱkeepȱreadingȱ untilȱyouȱgetȱaȱnondigit.ȱButȱwhatȱdoȱyouȱdoȱwithȱtheȱextraȱcharacterȱtoȱavoidȱlosingȱ it?ȱ The ungetc functionȱsolvesȱthisȱtypeȱofȱproblem.ȱHereȱisȱitsȱprototype.ȱ ȱ int ungetc( int character, FILE *stream ); ȱ ungetcȱ returnȱ aȱ characterȱ previouslyȱ readȱ backȱ toȱ theȱ streamȱ soȱ thatȱ itȱ canȱ beȱ readȱ againȱlater.ȱProgramȱ15.2ȱillustratesȱungetc.ȱItȱreadsȱcharactersȱfromȱtheȱstandardȱinputȱ andȱconvertsȱthemȱtoȱanȱinteger.ȱWithoutȱanȱungetcȱcapability,ȱthisȱfunctionȱwouldȱ Download at http://www.pin5i.com/ Chapter 15 Input/Output Functionsȱ 422ȱ ȱ /* ** Convert a series of digits from the standard input to an integer. */ #include <stdio.h> #include <ctype.h> int read_int() { int int value; ch; value = 0; /* ** Convert digits from the standard input; stop when we get a ** character that is not a digit. */ while( ( ch = getchar() ) != EOF && isdigit( ch ) ){ value *= 10; value += ch - '0'; } /* ** Push back the nondigit so we don't lose it. */ ungetc( ch, stdin ); return value; } ȱ Programȱ15.2ȱȱConvertingȱcharactersȱtoȱanȱintegerȱ ȱ ȱ ȱ ȱ ȱȱȱȱchar_int.cȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ haveȱ toȱ returnȱ theȱ excessȱ characterȱ toȱ theȱ caller,ȱ whoȱ wouldȱ thenȱ beȱ responsibleȱ forȱ sendingȱitȱtoȱwhateverȱpartȱofȱtheȱprogramȱreadsȱtheȱnextȱcharacter.ȱTheȱspecialȱcasesȱ andȱ extraȱ logicȱ involvedȱ inȱ handlingȱ theȱ extraȱ characterȱ makeȱ theȱ programȱ significantlyȱmoreȱcomplex.ȱ Eachȱstreamȱallowsȱatȱleastȱoneȱcharacterȱtoȱbeȱpushedȱbackȱ(ungotten).ȱIfȱmoreȱ charactersȱareȱpushedȱbackȱonȱaȱstreamȱthatȱallowsȱit,ȱtheyȱwillȱbeȱreadȱinȱtheȱoppositeȱ orderȱthatȱtheyȱwereȱpushed.ȱNoteȱthatȱpushingȱcharactersȱbackȱtoȱaȱstreamȱisȱnotȱtheȱ sameȱ asȱ writingȱ toȱ theȱ stream.ȱ Theȱ externalȱ storageȱ associatedȱ withȱ aȱ streamȱ isȱ notȱ affectedȱbyȱanȱungetc.ȱ ȱ Download at http://www.pin5i.com/ 15.9 Unformatted Line I/Oȱ CAUTION! 423 ȈUngottenȈȱ charactersȱ areȱ associatedȱ withȱ theȱ currentȱ positionȱ inȱ theȱ stream,ȱ soȱ changingȱ theȱstreamȇsȱpositionȱ withȱ fseek,ȱ fsetpos,ȱorȱ rewindȱ discardsȱanyȱungottenȱ characters.ȱ ȱ ȱ ȱ 15.9 Unformatted Line I/O ȱ Lineȱ orientedȱ I/Oȱ canȱ beȱ performedȱ inȱ oneȱ ofȱ twoȱ ways—unformattedȱ orȱ formatted.ȱȱ Bothȱformsȱmanipulateȱcharacterȱstrings.ȱTheȱdifferenceȱisȱthatȱunformattedȱI/Oȱsimplyȱ readsȱorȱwritesȱstrings,ȱwhereasȱformattedȱI/Oȱperformsȱconversionsȱbetweenȱinternalȱ andȱexternalȱrepresentationsȱofȱnumericȱandȱotherȱvariables.ȱInȱthisȱsection,ȱweȇllȱlookȱ atȱunformattedȱlineȱI/O.ȱ Theȱ getsȱ andȱ putsȱ familiesȱ operateȱ onȱ characterȱ stringsȱ ratherȱ thanȱ individualȱ characters.ȱ Thisȱ characteristicȱ makesȱ themȱ usefulȱ inȱ programsȱ thatȱ dealȱ withȱ textualȱ inputȱonȱaȱlineȬbyȬlineȱbasis.ȱTheȱprototypesȱforȱtheseȱfunctionsȱareȱshownȱbelow.ȱ ȱ char *fgets( char *buffer, int buffer_size, FILE *stream ); char *gets( char *buffer ); int fputs( char const *buffer, FILE *stream ); int puts( char const *buffer ); ȱ fgetsȱ readsȱ charactersȱ fromȱ theȱ specifiedȱ streamȱ andȱ copiesȱ themȱ intoȱ theȱ buffer.ȱ Readingȱstopsȱafterȱaȱnewlineȱcharacterȱhasȱbeenȱreadȱandȱstoredȱinȱtheȱbuffer.ȱItȱalsoȱ stopsȱafterȱ buffer_size – 1ȱcharactersȱhaveȱbeenȱstoredȱinȱtheȱbuffer.ȱDataȱisȱnotȱlostȱ inȱthisȱcase,ȱbecauseȱtheȱnextȱcallȱtoȱ fgetsȱwillȱgetȱtheȱnextȱcharactersȱfromȱtheȱstream.ȱ Inȱeitherȱcase,ȱaȱ NULȱbyteȱisȱappendedȱtoȱtheȱendȱofȱwhateverȱwasȱstoredȱinȱtheȱbuffer,ȱ thusȱmakingȱitȱaȱstring.ȱ Ifȱ endȱ ofȱ fileȱ isȱ reachedȱ beforeȱ anyȱ charactersȱ haveȱ beenȱ read,ȱ theȱ bufferȱ isȱ unchangedȱ andȱ fgetsȱ returnsȱ aȱ NULLȱ pointer.ȱ Otherȱ wise,ȱ fgestsȱ returnsȱ itsȱ firstȱ argumentȱ(theȱpointerȱtoȱtheȱbuffer).ȱTheȱreturnedȱvalueȱisȱusuallyȱusedȱonlyȱtoȱcheckȱ forȱendȱofȱfile.ȱ Theȱ bufferȱ passedȱ loȱ fputsȱ mustȱ containȱ aȱ string;ȱ itsȱ charactersȱ areȱ writtenȱ toȱ theȱ stream.ȱ Theȱ stringȱ isȱ expectedȱ toȱ beȱ NULȬterminated,ȱ whichȱ isȱ whyȱ thereȱ isnȇtȱ aȱ bufferȱsizeȱargument.ȱTheȱstringȱisȱwrittenȱverbatim:ȱifȱitȱdoesȱnotȱcontainȱaȱnewline,ȱ noneȱ isȱ written;ȱ ifȱ itȱ containsȱ severalȱ newlines,ȱ theyȱ areȱ allȱ written.ȱ Thus,ȱ whereasȱ fgetsȱ triesȱ toȱ readȱ oneȱ wholeȱ line,ȱ fputsȱ canȱ writeȱ aȱ partȱ ofȱ aȱ line,ȱ aȱ wholeȱ line,ȱ orȱ severalȱ lines.ȱ Ifȱ anȱ errorȱ occurredȱ whileȱ writing,ȱ fputsȱ returnsȱ theȱ constantsȱ EOF;ȱ otherwiseȱitȱreturnsȱaȱnonȬnegativeȱvalue.ȱ Download at http://www.pin5i.com/ 424ȱ CAUTION! CAUTION! Chapter 15 Input/Output Functionsȱ Programȱ 15.3ȱ isȱ aȱ functionȱ thatȱ readsȱ linesȱ ofȱ inputȱ fromȱ oneȱ fileȱ andȱ writesȱ themȱunchangedȱtoȱanotherȱfile.ȱTheȱconstantȱ MAX_LINE_LENGTHȱdeterminesȱtheȱsizeȱofȱ theȱbuffer,ȱandȱthereforeȱtheȱsizeȱofȱtheȱlongestȱlineȱthatȱwillȱbeȱread.ȱInȱthisȱfunctionȱ theȱvalueȱhasȱlittleȱsignificanceȱbecauseȱtheȱresultingȱfileȱwillȱbeȱtheȱsameȱwhetherȱlongȱ linesȱareȱwrittenȱailȱatȱonceȱorȱpieceȱbyȱpiece.ȱOnȱtheȱotherȱhand,ȱifȱtheȱfunctionȱwereȱ toȱ countȱ theȱ numberȱ ofȱ linesȱ thatȱ areȱ copied,ȱ aȱ tooȱ smallȱ bufferȱ wouldȱ produceȱ anȱ incorrectȱcountȱbecauseȱlongȱlinesȱwouldȱbeȱreadȱinȱtwoȱorȱmoreȱchunks.ȱWeȱcouldȱfixȱ thisȱproblemȱbyȱaddingȱcodeȱtoȱseeȱifȱeachȱchunkȱendedȱwithȱaȱnewline.ȱ Theȱ correctȱ valueȱ forȱ theȱ bufferȱsizeȱ isȱ usuallyȱ aȱ compromiseȱ thatȱ dependsȱ onȱ theȱ natureȱ ofȱ theȱ processingȱ required.ȱ However,ȱ fgetsȱ willȱ neverȱ causeȱ errorsȱ byȱ overflowingȱitsȱbuffer.ȱ ȱ Noteȱ thatȱ fgetsȱ cannotȱ readȱ intoȱ aȱ bufferȱ whoseȱ sizeȱ isȱ lessȱ thanȱ two,ȱ becauseȱ oneȱ spaceȱinȱtheȱbufferȱisȱreservedȱforȱtheȱNULȱbyteȱthatȱwillȱbeȱadded.ȱ Theȱ getsȱ andȱ putsȱ functionsȱ areȱ almostȱ identicalȱ toȱ fgetsȱ andȱ fputs.ȱ Theȱ differencesȱ allowȱ backwardȱ compatibility.ȱ Theȱ majorȱ functionalȱ differenceȱ isȱ thatȱ whenȱ getsȱreadsȱaȱlineȱofȱinput,ȱitȱdoesȱnotȱstoreȱtheȱterminatingȱnewȬlineȱinȱtheȱbuffer.ȱ Whenȱputsȱwritesȱaȱstring,ȱitȱaddsȱaȱnewlineȱtoȱtheȱoutputȱafterȱtheȱstringȱisȱwritten.ȱ ȱ Anotherȱdifferenceȱpertainsȱonlyȱtoȱ getsȱandȱisȱobviousȱfromȱtheȱfunctionȱprototypes:ȱ thereȱisȱnoȱbufferȱsizeȱargument.ȱThusȱ getsȱcannotȱdetermineȱtheȱlengthȱofȱtheȱbuffer.ȱ Ifȱ aȱ longȱ inputȱ lineȱ isȱ readȱ intoȱ aȱ shortȱ buffer,ȱ theȱ excessȱ charactersȱ areȱ writtenȱ inȱ whateverȱmemoryȱlocationsȱfollowȱtheȱbuffer,ȱthusȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Copy the standard input to the standard output, line by line. */ #include <stdio.h> #define MAX_LINE_LENGTH 1024 /* longest line I can copy */ void copylines( FILE *input, FILE *output ) { char buffer[MAX_LINE_LENGTH]; while( fgets( buffer, MAX_LINE_LENGTH, input ) != NULL ) fputs( buffer, output ); } ȱ Programȱ15.3ȱȱCopyȱlinesȱfromȱoneȱfileȱtoȱanotherȱ ȱ ȱ ȱ ȱ ȱȱȱcopyline.c Download at http://www.pin5i.com/ 15.10 Formatted Line I/Oȱ 425 destroyingȱ theȱ valuesȱ ofȱ oneȱ orȱ moreȱ unrelatedȱ variables.ȱ Thisȱ characteristicȱ makesȱ getsȱ suitableȱ forȱ onlyȱ theȱ mostȱ trivialȱ ofȱ programs,ȱ becauseȱ theȱ onlyȱ wayȱ toȱ guardȱ againstȱoverflowingȱtheȱinputȱbufferȱisȱtoȱdeclareȱaȱhugeȱone.ȱButȱnoȱmatterȱhowȱlargeȱ itȱis,ȱthereȱisȱalwaysȱtheȱpossibilityȱthatȱtheȱnextȱlineȱofȱinputȱwillȱbeȱlarger,ȱespeciallyȱ whenȱtheȱstandardȱinputȱhasȱbeenȱredirectedȱtoȱaȱfile.ȱ ȱ ȱ ȱ 15.10 Formatted Line I/O ȱ Theȱ nameȱ Ȉformattedȱ lineȱ I/OȈȱ isȱ somethingȱ ofȱ aȱ misnomer,ȱ becauseȱ theȱ functionsȱ inȱ theȱ scanfȱ andȱ printfȱ familiesȱ areȱ notȱ limitedȱ toȱ singleȱ lines.ȱ Theyȱ canȱ performȱ I/Oȱ onȱ partialȱlinesȱandȱmultipleȱlinesȱasȱwell.ȱ ȱ ȱ ȱ 15.10.1 The scanf Family ȱ Theȱ prototypesȱ forȱ theȱ scanfȱ familyȱ areȱ shownȱ below.ȱ Theȱ ellipsisȱ inȱ eachȱ prototypeȱ representsȱaȱvariableȬlengthȱ listȱofȱ pointers.ȱ Theȱvaluesȱ convertedȱ fromȱtheȱ inputȱ areȱ storedȱoneȱbyȱoneȱintoȱtheȱlocationsȱtoȱwhichȱtheseȱargumentsȱpoint.ȱ ȱ int fscanf( FILE *stream, char const *format, ... ); int scanf( char const *format, ... ); int sscanf( char const *string, char const *format, ... ); CAUTION! ȱ Theseȱfunctionsȱallȱreadȱcharactersȱfromȱanȱinputȱsourceȱandȱconvertȱthemȱaccordingȱ toȱtheȱcodesȱgivenȱinȱtheȱformatȱstring.ȱTheȱinputȱsourceȱforȱfscanfȱisȱtheȱstreamȱgivenȱ asȱ anȱ argument,ȱ scanfȱ readsȱ fromȱ theȱ standardȱ input,ȱ andȱ sscanfȱ takesȱ inputȱ charactersȱfromȱtheȱcharacterȱstringȱgivenȱasȱtheȱfirstȱargument.ȱȱ Inputȱ stopsȱ whenȱ theȱ endȱ ofȱ theȱ formatȱ stringȱ isȱ reachedȱ orȱ inputȱ isȱreadȱ thatȱ doesȱ notȱ matchȱ whatȱ theȱ formatȱ suingȱ specifies.ȱ Inȱ eitherȱ case,ȱ theȱ numberȱ ofȱ inputȱ valuesȱ thatȱ wereȱ convertedȱ isȱ returnedȱ asȱ theȱ functionȱ value.ȱ Ifȱ endȱ ofȱ fileȱ isȱ encounteredȱ beforeȱ anyȱ inputȱ valuesȱ haveȱ beenȱ converted,ȱ theȱ functionȱ returnsȱ theȱ constantȱEOF.ȱ ȱ Forȱtheseȱfunctionsȱtoȱworkȱproperly,ȱtheȱpointerȱargumentsȱmustȱbeȱtheȱrightȱtypeȱforȱ theȱ correspondingȱ formatȱ codes.ȱ Theȱ functionsȱ cannotȱ verifyȱ whetherȱ theirȱ pointerȱ argumentsȱareȱ theȱ correctȱtypes,ȱ soȱtheyȱassumeȱ thatȱ theyȱ areȱandȱgoȱ aheadȱ andȱ useȱ chem.ȱ Ifȱ theȱ pointerȱ typesȱ areȱ incorrect,ȱ theȱ resultingȱ valuesȱ willȱ beȱ garbage,ȱ andȱ adjacentȱvariablesȱmayȱbeȱoverwrittenȱinȱtheȱprocess.ȱ Download at http://www.pin5i.com/ 426ȱ Chapter 15 Input/Output Functionsȱ Byȱ nowȱ theȱ purposeȱ ofȱ theȱ ampersandsȱ beforeȱ theȱ argumentsȱ toȱ theȱ scanfȱ functionsȱ shouldȱ beȱ clear.ȱ Becauseȱ ofȱ Cȇsȱ callȬbyȬvalueȱ argumentȱ passingȱ mechanism,ȱ theȱ onlyȱ wayȱ toȱ identifyȱ aȱ locationȱ asȱ aȱ functionȱ argumentȱ isȱ toȱ passȱ aȱ pointerȱ toȱ it.ȱ Aȱ veryȱ commonȱ errorȱ isȱ toȱ forgetȱ theȱ ampersand.ȱ Thisȱ omissionȱ causesȱ theȱ valueȱ ofȱ theȱ variableȱ toȱ beȱ passedȱ asȱ theȱ argument,ȱ whichȱ scanfȱ (orȱ eitherȱ ofȱ theȱ otherȱ two)ȱ interpretsȱasȱifȱitȱwereȱaȱpointer.ȱWhenȱitȱisȱdeȬreferenced,ȱeitherȱtheȱprogramȱabortsȱorȱ dataȱinȱanȱunexpectedȱlocationȱisȱoverwritten.ȱ ȱ ȱ ȱ 15.10.2 scanf Format Codes ȱ Theȱformatȱstringȱmayȱcontainȱanyȱofȱtheȱfollowing:ȱ x Whitespaceȱ characters—theseȱ matchȱ zeroȱ orȱ moreȱ whitespaceȱ charactersȱ inȱ theȱ input,ȱwhichȱareȱignored.ȱ x Formatȱ codes—theseȱ specifyȱ howȱ theȱ functionȱ shouldȱ interpretȱ theȱ nextȱ inputȱ characters.ȱ x Otherȱcharacters—eachȱtimeȱanyȱotherȱcharacterȱappearsȱinȱtheȱformatȱstring,ȱthenȱ theȱnextȱinputȱcharacterȱmustȱmatchȱit.ȱIfȱitȱdoes,ȱtheȱinputȱcharacterȱisȱdiscarded;ȱifȱ itȱdoesȱnot,ȱtheȱfunctionȱreturns.ȱ ȱ Theȱformatȱcodesȱforȱtheȱscanfȱfunctionsȱallȱbeginȱwithȱaȱpercentȱsign,ȱfollowedȱbyȱ(1)ȱ anȱoptionalȱasterisk,ȱ(2)ȱanȱoptionalȱwidth,ȱ(3)ȱanȱoptionalȱqualifier,ȱandȱ(4)ȱtheȱformatȱ code.ȱTheȱasteriskȱcausesȱtheȱconvertedȱvalueȱtoȱbeȱdiscardedȱratherȱthanȱstored.ȱThisȱ techniqueȱ isȱ oneȱ wayȱ toȱ skipȱ pastȱ unneededȱ input.ȱ Theȱ widthȱ isȱ givenȱ asȱ aȱ nonȬ negativeȱinteger.ȱItȱlimitsȱtheȱnumberȱofȱinputȱcharactersȱthatȱwillȱbeȱreadȱinȱorderȱtoȱ convertȱthisȱvalue.ȱIfȱaȱwidthȱisnȇtȱgiven,ȱcharactersȱareȱreadȱuntilȱtheȱnextȱwhitespaceȱ characterȱisȱfoundȱinȱtheȱinput.ȱTheȱqualifiersȱmodifyȱtheȱmeaningsȱofȱcertainȱformatȱ codes,ȱandȱareȱlistedȱinȱTableȱ15.3.ȱ ȱ ȱ ȱ ȱ Result when used with qualifier ȱ Format code h l L d, I, n o, u, x e, f, g short unsigned short long unsigned long double long double ȱ Tableȱ15.3ȱȱscanfȱqualifiersȱ Download at http://www.pin5i.com/ 15.10 Formatted Line I/Oȱ 427 Theȱ purposeȱ ofȱ theȱ qualifierȱ isȱ toȱ specifyȱ theȱ sizeȱ ofȱ theȱ argument.ȱ Omittingȱ theȱ qualifierȱ whenȱ anȱ integerȱ argumentȱ isȱ shorterȱ orȱ longerȱ thanȱ theȱ defaultȱ integerȱ isȱ aȱ commonȱ mistake.ȱ Theȱ sameȱ isȱ trueȱ withȱ theȱ floatingȬpointȱ types.ȱ Dependingȱ onȱ theȱ relativeȱsizesȱofȱtheseȱtypes,ȱomittingȱtheȱqualifierȱmayȱresultȱinȱlongȱvariablesȱthatȱareȱ onlyȱhalfȱinitializedȱorȱvariablesȱadjacentȱtoȱshortȱonesȱbeingȱoverwritten.ȱ ȱ Onȱaȱmachineȱwhoseȱdefaultȱintegerȱisȱtheȱsameȱsizeȱasȱaȱ short,ȱtheȱ hȱqualifierȱisȱnotȱ neededȱ whenȱ convertingȱ aȱ short.ȱ However,ȱ theȱ qualifierȱ isȱ neededȱ onȱ aȱ machineȱ whoseȱdefaultȱ integerȱ sizeȱ isȱlongerȱ thanȱ aȱ short.ȱThus,ȱ yourȱprogramsȱ willȱbeȱ moreȱ portableȱ ifȱ youȱ useȱ theȱ appropriateȱ qualifierȱ whenȱ convertingȱ allȱ shortȱ andȱ longȱ integers,ȱandȱallȱlong doubleȱvariables.ȱȱ Theȱformatȱcodeȱisȱaȱsingleȱcharacterȱthatȱspecifiesȱhowȱtheȱinputȱcharactersȱareȱ toȱbeȱinterpreted.ȱTableȱ15.4ȱdescribesȱtheȱcodes.ȱ Letȇsȱ lookȱ atȱ someȱ examplesȱ thatȱ useȱ theȱ scanfȱ functions.ȱ Onceȱ again,ȱ onlyȱ theȱ partsȱ relevantȱ toȱ theseȱ functionsȱ areȱ shown.ȱ Ourȱ firstȱ exampleȱ isȱ straightforward.ȱ Itȱ readsȱ pairsȱ ofȱ numbersȱ fromȱ anȱ inputȱ streamȱ andȱ doesȱ someȱ processingȱ onȱ them.ȱȱ Whenȱendȱofȱtileȱisȱreached,ȱtheȱloopȱbreaks.ȱ ȱ int a, b; while( fscanf( input, "%d %d", &a, &b ) == 2 ){ /* ** Process the values a and b. */ } ȱ Thisȱcodeȱisȱratherȱunsophisticatedȱbecauseȱanyȱillegalȱcharactersȱinȱtheȱinputȱstreamȱ alsoȱ breakȱ theȱ loop.ȱ Also,ȱ becauseȱ fscanfȱ skipsȱ overȱ whiteȱ space,ȱ thereȱ isȱ noȱ wayȱ toȱ verifyȱwhetherȱtheȱtwoȱvaluesȱwereȱbothȱonȱtheȱsameȱlineȱorȱonȱdifferentȱinputȱlines.ȱȱ Aȱtechniqueȱtoȱsolveȱthisȱproblemȱisȱshownȱinȱaȱlaterȱexample.ȱ Theȱnextȱexampleȱusesȱaȱfieldȱwidth.ȱ ȱ nfields = fscanf( input, "%4d %4d %4d", &a, &b, &c ) ȱ Theȱwidthsȱrestrictȱeachȱofȱtheȱintegerȱvaluesȱtoȱbeȱfourȱorȱfewerȱdigitsȱlong.ȱWithȱthisȱ input,ȱ ȱ 1 2 ȱ aȱwouldȱbecomeȱoneȱandȱ bȱwouldȱbecomeȱtwo.ȱ cȱwouldȱbeȱunchanged,ȱandȱ nfieldsȱ wouldȱbeȱtwo.ȱButȱwithȱthisȱinput,ȱ ȱ 12345 67890 Download at http://www.pin5i.com/ 428ȱ Chapter 15 Input/Output Functionsȱ ȱ Code Argument Meaning c char * Aȱsingleȱcharacterȱisȱreadȱandȱstored.ȱLeadingȱwhitespaceȱisȱnotȱskipped.ȱIfȱaȱ widthȱisȱgiven,ȱthatȱnumberȱofȱcharactersȱareȱreadȱandȱstored;ȱnoȱNULȱbyteȱisȱ appended;ȱtheȱargumentȱmustȱpointȱtoȱaȱcharacterȱarrayȱthatȱisȱlargeȱenough.ȱ i d int * Anȱoptionallyȱsignedȱintegerȱisȱconverted.ȱ dȱinterpretsȱtheȱinputȱasȱdecimal;ȱ iȱ determinesȱ theȱ baseȱ ofȱ theȱ valueȱ byȱ itsȱ firstȱ charactersȱ asȱ isȱ doneȱ withȱ integerȱliteralȱconstants.ȱ u o x unsigned * Anȱ optionallyȱ signedȱ integerȱ isȱ converted,ȱ butȱ isȱ storedȱ asȱ unsigned.ȱ Theȱ valueȱisȱinterpretedȱasȱdecimalȱwithȱu,ȱoctalȱwithȱo,ȱandȱhexadecimalȱwithȱx.ȱ TheȱcodeȱXȱisȱaȱsynonymȱforȱx.ȱ e f g float * Aȱ floatingȬpointȱ valueȱ isȱ expected.ȱ Itȱ mustȱ lookȱ likeȱ aȱ floatingȬpointȱ literalȱ constantȱexceptȱthatȱaȱdecimalȱpointȱisȱnotȱrequired.ȱ Eȱandȱ Gȱareȱsynonymsȱ forȱeȱandȱg.ȱ s char * Aȱsequenceȱofȱnonwhitespaceȱcharactersȱisȱread.ȱTheȱargumentȱmustȱpointȱ toȱ aȱ characterȱ arrayȱ thatȱ isȱ largeȱ enough.ȱ Inputȱ stopsȱ whenȱ whitespaceȱ isȱ found;ȱtheȱstringȱisȱthenȱNULȬterminated.ȱ [xxx] char * Aȱ sequenceȱ ofȱ charactersȱ fromȱ theȱ givenȱ setȱ isȱ read.ȱ Theȱ argumentȱ mustȱ pointȱ toȱ aȱ characterȱ arrayȱ thatȱ isȱ largeȱ enough,ȱ inputȱ stopsȱ whenȱ theȱ firstȱ characterȱ thatȱ isȱ notȱ inȱ theȱ setȱ isȱ encountered.ȱ Theȱ stringȱ isȱ thenȱ NULȬ terminated.ȱ Theȱ codeȱ %[abc]ȱ specifiesȱ theȱ setȱ includingȱ a,ȱ b,ȱ andȱ c.ȱ Beginningȱ theȱ listȱ withȱ ^ȱ complementsȱ theȱ set,ȱ soȱ %[^abc]ȱ meansȱ allȱ charactersȱexceptȱa,ȱb,ȱandȱc.ȱAȱrightȱbracketȱmayȱbeȱincludedȱinȱtheȱlistȱonlyȱ ifȱ itȱ isȱ firstȱ itȱ isȱ implementationȱ dependentȱ whetherȱ aȱ dashȱ (forȱ example,ȱ %[a-z])ȱspecifiesȱaȱrangeȱofȱcharacters.ȱ p void * Theȱinputȱisȱexpectedȱtoȱbeȱaȱsequenceȱofȱcharactersȱsuchȱasȱthoseȱproducedȱ byȱtheȱ %pȱformatȱcodeȱofȱ printfȱ(seeȱbelow).ȱTheȱconversionȱisȱperformedȱ inȱanȱimplementationȬdependentȱmanner,ȱbutȱtheȱresultȱwillȱcompareȱequalȱ toȱtheȱvalueȱthatȱproducedȱtheȱcharactersȱwhenȱprintedȱasȱdescribedȱabove.ȱ n int * Theȱnumberȱofȱcharactersȱreadȱfromȱtheȱinputȱsoȱfarȱbyȱthisȱcallȱtoȱ scanfȱisȱ returned.ȱ%nȱconversionȱareȱnotȱcountedȱinȱtheȱvalueȱreturnedȱby scanf.ȱNoȱ inputȱisȱconsumed.ȱ % (none) Thisȱcodeȱmatchesȱaȱsingleȱ%ȱinȱtheȱinput,ȱwhichȱisȱdiscarded.ȱ ȱ Tableȱ15.4ȱȱscanfȱformatȱcodesȱ ȱ ȱ aȱwouldȱbeȱ1234,ȱ bȱwouldȱbeȱfive,ȱ cȱwouldȱbeȱ6789,ȱandȱ nfieldsȱwouldȱbeȱthree.ȱTheȱ finalȱzeroȱwouldȱremainȱunreadȱinȱtheȱinputȱ Itȱ isȱ difficultȱ toȱ maintainȱ synchronizationȱ withȱ lineȱ boundariesȱ inȱ theȱ inputȱ whenȱ usingȱ fscanf,ȱ becauseȱ itȱ skipsȱ newlinesȱ asȱ whiteȱ space.ȱ Forȱ example,ȱ supposeȱ thatȱ aȱ programȱ readsȱ inputȱ thatȱ consistsȱ ofȱ groupsȱ ofȱ fourȱ values.ȱ Theseȱ valuesȱ areȱ thenȱprocessedȱinȱsomeȱway,ȱandȱtheȱnextȱfourȱvaluesȱareȱread.ȱTheȱsimplestȱwayȱto Download at http://www.pin5i.com/ 15.10 Formatted Line I/Oȱ 429 prepareȱ inputȱ forȱ suchȱ aȱ programȱ isȱ toȱ putȱ eachȱ setȱ ofȱ fourȱ valuesȱ onȱ itsȱ ownȱ inputȱ line,ȱmakingȱitȱeasyȱtoȱseeȱwhichȱvaluesȱformȱaȱset.ȱButȱifȱoneȱofȱtheȱlinesȱcontainsȱtooȱ manyȱ orȱ tooȱ fewȱ values,ȱ theȱ programȱ becomesȱ confused.ȱ Forȱ example,ȱ considerȱ thisȱ input,ȱwhichȱcontainsȱanȱerrorȱinȱitsȱsecondȱline:ȱ ȱ 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 2 3 4 5 ȱ Ifȱweȱusedȱ fscanfȱtoȱreadȱtheȱvaluesȱfourȱatȱaȱtime,ȱtheȱfirstȱandȱsecondȱsetsȱofȱvaluesȱ wouldȱ beȱ correct,ȱ butȱ theȱ thirdȱ setȱ ofȱ valuesȱ wouldȱ beȱ readȱ asȱ 2,ȱ 3,ȱ 3,ȱ 3.ȱ ȱ Eachȱ subsequentȱsetȱwouldȱalsoȱbeȱincorrect.ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Line-oriented input processing with sscanf */ #include <stdio.h> #define BUFFER_SIZE 100 /* Longest line we'll handle */ void function( FILE *input ) { int a, b, c, d, e; char buffer[ BUFFER_SIZE ]; while( fgets( buffer, BUFFER_SIZE, input ) != NULL ){ if( sscanf( buffer, "%d %d %d %d %d", &a, &b, &c, &d, &e ) != 4 ){ fprintf( stderr, "Bad input skipped: %s", buffer ); continue; } /* ** Process this set of input. */ } } ȱ Programȱ15.4ȱȱProcessingȱlineȬorientedȱinputȱwithȱsscanfȱȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱscanf1.cȱ Download at http://www.pin5i.com/ 430ȱ Chapter 15 Input/Output Functionsȱ Programȱ15.4ȱusesȱaȱmoreȱreliableȱapproachȱforȱreadingȱthisȱtypeȱofȱinput.ȱTheȱ advantageȱ ofȱ thisȱ methodȱ isȱ thatȱ theȱ inputȱ isȱ nowȱ processedȱ lineȱ byȱ line.ȱ Itȱ isȱ impossibleȱ toȱ readȱ aȱ setȱ ofȱ valuesȱ thatȱ beginsȱ onȱ oneȱ lineȱ andȱ endsȱ onȱ theȱ next.ȱ Furthermore,ȱbyȱtryingȱ toȱ convertȱfiveȱvalues,ȱ inputȱ linesȱ thatȱhaveȱtooȱ manyȱ valuesȱ areȱdetectedȱasȱwellȱasȱthoseȱwithȱtooȱfew.ȱ Aȱ relatedȱ techniqueȱ isȱ usedȱ toȱ readȱ lineȬorientedȱ inputȱ thatȱ mayȱ beȱ inȱ severalȱ differentȱ formats.ȱ Aȱ lineȱ isȱ readȱ withȱ fgetsȱ andȱ thenȱ scannedȱ withȱ severalȱ sscanfȇs,ȱ eachȱ usingȱ aȱ differentȱ format.ȱ Theȱ formatȱ ofȱ theȱ inputȱ lineȱ isȱ determinedȱ byȱ theȱ firstȱ sscanfȱ thatȱ convertsȱ theȱ expectedȱ numberȱ ofȱ values.ȱ Forȱ instance,ȱ Programȱ 15.5ȱ examinesȱtheȱcontentsȱofȱaȱbufferȱthatȱwasȱreadȱearlier.ȱItȱextractsȱeitherȱone,ȱtwo,ȱorȱ threeȱvaluesȱfromȱaȱlineȱofȱinputȱandȱassignsȱdefaultȱvaluesȱtoȱvariablesȱforȱwhichȱanȱ inputȱvalueȱwasȱnotȱgiven.ȱ ȱ ȱ ȱ 15.10.3 The printf Family ȱ Functionsȱ inȱ theȱ printfȱ familyȱ areȱ usedȱ toȱ createȱ formattedȱ output.ȱ Thereȱ areȱ threeȱ functionsȱ inȱ thisȱ family:ȱ fprintf,ȱ printf,ȱ andȱ sprintf.ȱ ȱ Theirȱ prototypesȱ areȱ shownȱ below.ȱ ȱ int fprintf( FILE *stream, char const *format, ... ); int printf( char const *format, ... ); int sprintf( char *buffer, char const *format, ... ); CAUTION! ȱ AsȱyouȱsawȱinȱChapterȱ1,ȱ printfȱformatsȱtheȱvaluesȱinȱitsȱargumentȱlistȱaccordingȱtoȱ theȱformatȱcodesȱandȱotherȱcharactersȱinȱtheȱ formatȱargument.ȱTheȱotherȱmembersȱofȱ thisȱfamilyȱworkȱtheȱsameȱway.ȱȱWithȱprintf,ȱtheȱresultingȱoutputȱgoesȱtoȱtheȱstandardȱ output.ȱWithȱfprintf,ȱanyȱoutputȱstreamȱcanȱbeȱused,ȱandȱsprintfȱwritesȱitsȱresultsȱasȱ aȱNULȬterminatedȱstringȱinȱtheȱspecifiedȱbufferȱratherȱthanȱtoȱaȱstream.ȱ ȱ sprintfȱisȱaȱpotentialȱsourceȱofȱerror.ȱTheȱbufferȱsizeȱisȱnotȱanȱargumentȱtoȱsprintf,ȱsoȱ outputȱthatȱisȱunexpectedlyȱlongȱ canȱspillȱoutȱofȱtheȱendȱofȱtheȱbufferȱandȱoverwriteȱ whateverȱhappensȱtoȱfollowȱtheȱbufferȱinȱmemory.ȱThereȱareȱtwoȱstrategiesȱforȱmakingȱ sureȱ thatȱ thisȱ problemȱ neverȱ happens.ȱ Theȱ firstȱ isȱ toȱ declareȱ aȱ veryȱ largeȱ buffer.ȱ Butȱ thisȱ solutionȱ wastesȱ memory,ȱ andȱ althoughȱ aȱ largeȱ bufferȱ reducesȱ theȱ chanceȱ ofȱ overflow,ȱitȱdoesȱnotȱeliminateȱit.ȱTheȱsecondȱapproachȱisȱtoȱanalyzeȱtheȱformatȱtoȱseeȱ howȱ longȱ theȱ resultingȱ outputȱ wouldȱ beȱ whenȱ theȱ largestȱ possibleȱ valuesȱ areȱ converted.ȱ Forȱ example,ȱ theȱ largestȱ integerȱ onȱ aȱ machineȱ withȱ 4Ȭbyteȱ integersȱ isȱ 11ȱ charactersȱ includingȱ aȱ sign,ȱ soȱ theȱ bufferȱ shouldȱ alwaysȱ beȱ atȱ leastȱ 12ȱ charactersȱ inȱ orderȱtoȱholdȱtheȱvalueȱandȱtheȱterminatingȱNULȱbyte.ȱThereȱisnȇtȱaȱlimitȱonȱtheȱlengthȱȱ Download at http://www.pin5i.com/ 15.10 Formatted Line I/Oȱ 431 ȱ ȱ /* ** Variable format input processing with sscanf */ #include <stdio.h> #include <stdlib.h> #define #define DEFAULT_A DEFAULT_B 1 2 /* or whatever ... */ /* or whatever ... */ void function( char *buffer ) { int a, b, c; /* ** See if all three values are given. */ if( sscanf( buffer, "%d %d %d", &a, &b, &c ) != 3 ){ /* ** No, use default value for a, see if other two ** values are both given. */ a = DEFAULT_A; if( sscanf( buffer, "%d %d", &b, &c ) != 2 ){ /* ** Use default value for b too, look for ** remaining value. */ b = DEFAULT_B; if( sscanf( buffer, "%d", &c ) != 1 ){ fprintf( stderr, "Bad input: %s", buffer ); exit( EXIT_FAILURE ); } } } /* ** Process the values a, b, and c. */ } ȱ ȱ ȱ ȱȱȱȱȱȱȱscanf2.cȱ Programȱ15.5ȱȱProcessingȱvariableȱformatȱinputȱwithȱsscanfȱ ȱ ȱ ȱ ȱ ȱ ȱ ofȱstrings,ȱbutȱtheȱnumberȱofȱcharactersȱprintedȱforȱaȱstringȱcanȱbeȱrestrictedȱwithȱanȱ optionalȱfieldȱinȱtheȱformatȱcode.ȱ Download at http://www.pin5i.com/ 432ȱ Chapter 15 Input/Output Functionsȱ Theȱformatȱcodesȱusedȱwithȱtheȱprintfȱfamilyȱworkȱdifferentlyȱthanȱthoseȱusedȱwithȱtheȱ scanfȱ functions,ȱ soȱ youȱ mustȱ beȱ carefulȱ notȱ toȱ intermixȱ them.ȱ Thisȱ problemȱ isȱ madeȱ moreȱ difficultȱ byȱ theȱ factȱ thatȱ someȱ ofȱ theȱ formatȱ codesȱ lookȱ identicalȱ withoutȱ theirȱ optionalȱfields.ȱUnfortunately,ȱmanyȱofȱtheȱcommonlyȱusedȱcodes,ȱsuchȱasȱ %d,ȱfallȱintoȱ thisȱcategory.ȱ ȱ Anotherȱ sourceȱ ofȱ errorȱ isȱ havingȱ argumentsȱ whoseȱ typesȱ doȱ notȱ matchȱ theȱ CAUTION! correspondingȱformatȱcodes.ȱUsuallyȱtheȱresultȱofȱthisȱerrorȱisȱgarbageȱinȱtheȱoutput,ȱ butȱ itȱ isȱ possibleȱ forȱ suchȱ aȱ mismatchȱ toȱ causeȱ theȱ programȱ toȱ abort.ȱ Asȱ inȱ theȱ scanfȱ family,ȱ theseȱ functionsȱ cannotȱ verifyȱ thatȱ aȱ valueȱ hasȱ theȱ properȱ typeȱ forȱ aȱ formatȱ code,ȱsoȱitȱisȱupȱtoȱyouȱtoȱmakeȱsureȱtheyȱmatchȱproperly.ȱ ȱ ȱ ȱ ȱ Code Argument Meaning CAUTION! c int Theȱargumentȱisȱtruncatedȱtoȱunsigned charȱandȱprintedȱasȱaȱcharacter.ȱ d i int Theȱargumentȱisȱprintedȱasȱaȱdecimalȱinteger.ȱIfȱaȱprecisionȱisȱgivenȱandȱtheȱ valueȱhasȱfewerȱdigits,ȱzerosȱareȱaddedȱatȱtheȱfront.ȱ u o x,X unsigned int Theȱ argumentȱ isȱ printedȱ asȱ anȱ unsignedȱ valueȱ inȱ decimalȱ (u),ȱ octalȱ (o),ȱ orȱ hexadecimalȱ(xȱorȱX).ȱxȱandȱXȱareȱidenticalȱexceptȱthatȱabcdefȱareȱusedȱforȱxȱ conversions,ȱandȱABCDEFȱareȱusedȱwithȱX.ȱ e E double Theȱ argumentȱ isȱ printedȱ inȱ exponentȱ form;ȱ forȱ example,ȱ 6.023000e23ȱ forȱ theȱ eȱ code,ȱ andȱ 6.023000E23ȱ forȱ theȱ Eȱ code.ȱ Theȱ numberȱ ofȱ digitsȱ behindȱ theȱ decimalȱ pointȱ isȱ determinedȱ byȱ theȱ precisionȱ field;ȱ theȱ defaultȱ isȱ sixȱ digits.ȱ f double Theȱargumentȱisȱprintedȱinȱconventionalȱnotation.ȱTheȱprecisionȱdeterminesȱ theȱnumberȱofȱdigitsȱbehindȱtheȱdecimalȱpoint;ȱtheȱdefaultȱisȱsix.ȱ g G double Theȱ argumentȱ isȱ printedȱ inȱ eitherȱ %fȱ orȱ %eȱ (orȱ %E,ȱ ifȱ Gȱ isȱ given)ȱ notation,ȱ dependingȱonȱitsȱvalue.ȱTheȱ %fȱformȱisȱusedȱifȱtheȱexponentȱisȱgreaterȱthanȱ orȱequalȱtoȱ –4ȱȱbutȱlessȱthanȱtheȱprecision.ȱOtherwiseȱtheȱexponentȱformȱisȱ used.ȱ s char * Aȱstringȱisȱprinted.ȱ p void * Theȱ valueȱ ofȱ theȱ pointerȱ isȱ convertedȱ toȱ anȱ implementationȬdependentȱ sequenceȱofȱprintableȱcharacters.ȱThisȱcodeȱisȱusedȱprimarilyȱinȱconjunctionȱ withȱtheȱ%pȱcodeȱinȱscanf.ȱ n int * Thisȱ codeȱ isȱ uniqueȱ inȱ thatȱ itȱ doesȱ notȱ produceȱ anyȱ output.ȱ Instead,ȱ theȱ numberȱ ofȱ charactersȱ ofȱ outputȱ producedȱ soȱ farȱ isȱ storedȱ inȱ theȱ correspondingȱargument.ȱ % (none) Aȱsingleȱ%ȱisȱproducedȱinȱtheȱoutput.ȱ ȱ Tableȱ15.5ȱȱprintfȱformatȱcodesȱ Download at http://www.pin5i.com/ 15.10 Formatted Line I/Oȱ 433 15.10.4 printf Format Codes ȱ Theȱformatȱstringȱmayȱcontainȱformattingȱcodes,ȱwhichȱcauseȱtheȱnextȱvalueȱfromȱtheȱ argumentȱlistȱtoȱbeȱformattedȱinȱtheȱspecifiedȱmanner,ȱandȱotherȱcharacters,ȱwhichȱareȱ printedȱverbatim.ȱFormatȱcodesȱconsistȱofȱaȱpercentȱsignȱfollowedȱbyȱ(1)ȱzeroȱorȱmoreȱ flagȱ charactersȱ thatȱ modifyȱ howȱ someȱ conversionsȱ areȱ performed,ȱ (2)ȱ anȱ optionalȱ minimumȱ fieldȱ width.ȱ (3)ȱ anȱ optionalȱ precision,ȱ (4)ȱ anȱ optionalȱ modifier,ȱ andȱ (5)ȱ theȱ conversionȱtype.ȱ Theȱpreciseȱmeaningsȱofȱtheȱflagsȱandȱotherȱfieldsȱdependȱonȱwhichȱconversionȱ isȱ used.ȱ Tableȱ 15.5ȱ describesȱ theȱ conversionȱ typeȱ codes,ȱ andȱ Tableȱ 15.6ȱ describesȱ theȱ flagȱcharactersȱandȱtheirȱmeanings.ȱ Theȱ fieldȱ widthȱ isȱ aȱ decimalȱ integerȱ specifyingȱ theȱ minimumȱ numberȱ ofȱ charactersȱthatȱwillȱappearȱinȱtheȱresult.ȱIfȱaȱvalueȱhasȱfewerȱcharactersȱthanȱtheȱfieldȱ width,ȱpaddingȱoccursȱtoȱincreaseȱitsȱlength.ȱTheȱflagsȱdetermineȱwhetherȱpaddingȱisȱ doneȱ withȱ spacesȱ orȱ zerosȱ andȱ whetherȱ itȱ occursȱ onȱ theȱ leftȱ orȱ fileȱ rightȱ endȱ ofȱ theȱ value.ȱ Forȱd,ȱi,ȱ u,ȱ o,ȱ x,ȱandȱ Xȱconversions,ȱtheȱprecisionȱspecifiesȱtheȱminimumȱnumberȱ ofȱ digitsȱ thatȱ willȱ appearȱ inȱ theȱ resultȱ andȱ overridesȱ theȱ zeroȱ flag.ȱ Ifȱ theȱ convertedȱ valueȱhasȱfewerȱdigits,ȱleadingȱzerosȱareȱinserted.ȱDigitsȱareȱnotȱproducedȱifȱtheȱvalueȱ zeroȱ isȱ convertedȱ withȱ aȱ precisionȱ ofȱ zero.ȱ Forȱ e,ȱ E,ȱ andȱ fȱ conversions,ȱ theȱ precisionȱ determinesȱtheȱnumberȱofȱdigitsȱthatȱwillȱappearȱafterȱtheȱdecimalȱpoint.ȱForȱ gȱandȱ Gȱ conversions,ȱ itȱ specifiesȱ theȱ maximumȱ numberȱ ofȱ significantȱ digitsȱ thatȱ willȱ appear.ȱ Whenȱusedȱwithȱsȱconversions,ȱtheȱprecisionȱspecifiesȱtheȱmaximumȱnumberȱofȱȱ ȱ ȱ ȱ Flag Meaning - Leftȱjustifyȱtheȱvalueȱinȱitsȱfield.ȱTheȱdefaultȱisȱtoȱrightȱjustify.ȱ 0 Whenȱrightȱjustifyingȱnumericȱvalues,ȱtheȱdefaultȱisȱtoȱuseȱspacesȱtoȱfillȱunusedȱcolumnsȱtoȱ theȱleftȱofȱtheȱvalue.ȱThisȱflagȱcausesȱzerosȱtoȱbeȱusedȱinstead,ȱandȱitȱappliesȱtoȱtheȱd,ȱi,ȱu,ȱo,ȱ x,ȱ X,ȱ e,ȱ E,ȱ f,ȱ g,ȱandȱ Gȱcodes.ȱWithȱtheȱ d,ȱ i,ȱ u,ȱ o,ȱ x,ȱandȱ Xȱcodes,ȱtheȱzeroȱflagȱisȱignoredȱifȱaȱ precisionȱisȱgiven.ȱTheȱzeroȱflagȱhasȱnoȱeffectȱifȱtheȱminusȱflagȱisȱalsoȱgiven.ȱ + Whenȱusedȱwithȱaȱcodeȱthatȱformatsȱaȱsignedȱvalue,ȱthisȱforcesȱaȱplusȱsignȱtoȱappearȱwhenȱ theȱ valueȱ isȱ notȱ negative.ȱ Ifȱ theȱ valueȱ isȱ negative,ȱ aȱ minusȱ signȱ isȱ shownȱ asȱ usual.ȱ Byȱ default,ȱplusȱsignsȱareȱnotȱshown.ȱ spaceȱ Usefulȱonlyȱforȱcodesȱthatȱconvertȱsignedȱvalues,ȱthisȱflagȱcausesȱaȱspaceȱtoȱbeȱaddedȱtoȱtheȱ beginningȱ ofȱ theȱ resultȱ whenȱ theȱ valueȱ isȱ notȱ negative.ȱ Noteȱ thatȱ thisȱ flagȱ andȱ +ȱ areȱ mutuallyȱexclusive;ȱifȱbothȱareȱgivenȱtheȱspaceȱflagȱisȱignored.ȱ # Selectsȱanȱalternateȱformȱofȱconversionȱforȱsomeȱcodes.ȱTheseȱareȱdescribedȱinȱTableȱ15.8.ȱ ȱ Tableȱ15.6ȱȱprintfȱformatȱflagsȱ Download at http://www.pin5i.com/ Chapter 15 Input/Output Functionsȱ 434ȱ ȱ Modifier Used With … h d, I, u, o, x, X h n l d, I, u, o, x, X l n L e, E, f, g, G Means the Arguments is … aȱ(possiblyȱunsigned)ȱshortȱinteger aȱpointerȱtoȱaȱshortȱintegerȱ aȱ(possiblyȱunsigned)ȱlongȱintegerȱ aȱpointerȱtoȱaȱlongȱintegerȱ aȱlong doubleȱ ȱ Tableȱ15.7ȱȱprintfȱformatȱcodeȱmodifiersȱ ȱ ȱ charactersȱ thatȱ willȱ beȱ converted.ȱ Theȱ precisionȱ isȱ givenȱ asȱ aȱ periodȱ followedȱ byȱ anȱ optionalȱdecimalȱinteger.ȱIfȱtheȱintegerȱisȱmissingȱȱaȱprecisionȱofȱzeroȱisȱused.ȱ Ifȱ anȱ asteriskȱ isȱ givenȱ inȱ placeȱ ofȱ aȱ decimalȱ integerȱ forȱ theȱ fieldȱ widthȱ and/orȱ precision,ȱ thenȱ theȱ nextȱ argumentȱ toȱ printfȱ (whichȱ mustȱ beȱ anȱ integer)ȱ suppliesȱ theȱ widthȱ and/orȱ precision.ȱ Thus,ȱ eitherȱ ofȱ theseȱ valuesȱ mayȱ beȱ computedȱ ratherȱ thanȱ specifiedȱinȱadvance.ȱ Whenȱcharacterȱorȱshortȱintegerȱvaluesȱareȱgivenȱasȱargumentsȱtoȱ printf,ȱtheyȱ areȱconvertedȱtoȱintegersȱbeforeȱbeingȱpassed.ȱSometimesȱtheȱconversionȱcanȱaffectȱtheȱ outputȱ thatȱ isȱ produced.ȱ Also,ȱ whenȱ passingȱ aȱ longȱ integerȱ asȱ anȱ argumentȱ inȱ anȱ environmentȱwhereȱlongȱintegersȱoccupyȱmoreȱmemoryȱthanȱordinaryȱintegers,ȱprintfȱ mustȱ beȱ toldȱ thatȱ theȱ argumentȱ isȱ aȱ long.ȱ Theȱ modifiers,ȱ shownȱ inȱ Tableȱ 15.7,ȱ solveȱ theseȱproblemsȱbyȱindicatingȱtheȱexactȱsizeȱofȱintegerȱandȱfloatingȬpointȱarguments.ȱ Onȱ implementationsȱ inȱ whichȱ intsȱ andȱ shortȱ intsȱ areȱ theȱ sameȱ length,ȱ theȱ hȱ modifierȱhasȱnoȱeffect.ȱOtherwise,ȱtheȱvalueȱtoȱbeȱconvertedȱwillȱhaveȱbeenȱpromotedȱ toȱanȱ(unsigned)ȱintegerȱwhenȱitȱwasȱpassedȱasȱanȱargument;ȱthisȱmodifierȱcausesȱitȱtoȱ beȱ truncatedȱ backȱ toȱ itsȱ shortȱ formȱ beforeȱ theȱ conversionȱ takesȱ place.ȱ Withȱ decimalȱ conversions,ȱ theȱ truncationȱ isȱ generallyȱ notȱ needed.ȱ Butȱ withȱ someȱ octalȱ orȱ hexadecimalȱconversions,ȱtheȱ hȱmodifierȱwillȱensureȱthatȱtheȱproperȱnumberȱofȱdigitsȱ isȱprinted.ȱ ȱ ȱ ȱ Used With … The # Flag … o guaranteesȱthatȱtheȱvalueȱproducedȱbeginsȱwithȱaȱzero.ȱ x, X prefixesȱaȱnonzeroȱvalueȱwithȱ0xȱ(0Xȱforȱtheȱ%Xȱcode).ȱ e, E, f ensuresȱtheȱresultȱalwaysȱcontainsȱaȱdecimalȱpoint,ȱevenȱifȱnoȱ digitsȱfollowȱit.ȱ g, G doesȱtheȱsameȱasȱforȱtheȱe,ȱE,ȱandȱfȱcodesȱabove;ȱinȱaddition,ȱ trailingȱzerosȱareȱnotȱremovedȱfromȱtheȱfraction.ȱ ȱ Tableȱ15.8ȱȱAlternativeȱformsȱofȱprintfȱconversionsȱ Download at http://www.pin5i.com/ 15.10 Formatted Line I/Oȱ 435 ȱ CAUTION! TIP Format Code String Converted A ABC ABCDEFGH %s A ABC ABCDEFGH %5s ¤¤¤¤A ¤¤ABC ABCDEFGH %.5s A ABC ABCDE %5.5s ¤¤¤¤A ¤¤ABC ABCDE %-5s A¤¤¤¤ ABC¤¤ ABCDEFGH ȱ Figureȱ15.1ȱȱFormattingȱstringsȱwithȱprintfȱ ȱ ȱ Onȱimplementationsȱinȱwhichȱ intsȱandȱ long intsȱareȱtheȱsameȱlength,ȱtheȱ lȱmodifierȱ hasȱ noȱ effect.ȱ Onȱ allȱ otherȱ implementations,ȱ theȱ lȱ modifierȱ isȱ required,ȱ becauseȱ longȱ integersȱonȱsuchȱmachinesȱareȱpassedȱinȱtwoȱpartsȱonȱtheȱruntimeȱstack.ȱIfȱtheȱmodifierȱ isȱ notȱ given,ȱ onlyȱ theȱ firstȱ partȱ isȱ retrievedȱ forȱ theȱ conversion.ȱ Notȱ onlyȱ willȱ thisȱ conversionȱ produceȱ incorrectȱ results,ȱ butȱ theȱ secondȱ partȱ ofȱ theȱ valueȱ isȱ thenȱ interpretedȱ asȱ aȱ separateȱ argument,ȱ disruptingȱ theȱ correspondenceȱ betweenȱ theȱ subsequentȱargumentsȱandȱtheirȱformatȱcodes.ȱ Whenȱusedȱwithȱseveralȱofȱtheȱprintfȱformatȱcodes,ȱtheȱ#ȱflagȱselectsȱanȱalternateȱ formȱofȱconversion.ȱTheȱdetailsȱofȱtheseȱformsȱareȱlistedȱinȱTableȱ15.8.ȱ ȱ Becauseȱ someȱ implementationsȱ requireȱ theȱ lȱ modifierȱ whenȱ printingȱ longȱ integerȱ valuesȱandȱothersȱdoȱnot,ȱitȱisȱbetterȱtoȱuseȱitȱwheneverȱprintingȱlongs.ȱThenȱyouȱcanȱ portȱtheȱprogramȱtoȱeitherȱtypeȱofȱimplementationȱwithȱfewerȱmodifications.ȱ ȱ ȱ ȱ ȱ ȱ Format Number Converted Code 1 -12 12345 123456789 %d 1 -12 12345ȱ 123456789 %6d ¤¤¤¤¤1 ¤¤¤-12 ¤12345ȱ 123456789 %.4d 0001 -0012 12345ȱ 123456789 %6.4d ¤¤0001 ¤-0012 ¤12345ȱ 123456789 %-4d 1¤¤¤ -12¤ 12345ȱ 123456789 %04d 0001 -012 12345ȱ 123456789 %+d +1 -12 +12345ȱ +123456789 ȱ Figureȱ15.2ȱȱformattingȱintegersȱwithȱprintfȱ Download at http://www.pin5i.com/ Chapter 15 Input/Output Functionsȱ 436ȱ ȱ Format Code Number Converted 1 .01 .00012345 12345.6789 %f 1.000000 0.010000 0.000123 12345.678900 %10.2f ¤¤¤¤¤¤1.00 ¤¤¤¤¤¤0.01 ¤¤¤¤¤¤0.00 ¤¤12345.68 %e 1.000000e+00 1.000000e-02 1.234500e-04 1.234568e+04 %.4e 1.0000e+00 1.0000e-02 1.2345e-04 1.2346e+04 %g 1 0.01 0.00012345 12345.7 ȱ Figureȱ15.3ȱȱFormattingȱfloatingȬpointȱvaluesȱwithȱprintfȱ ȱ Theȱ abundanceȱ ofȱ codes,ȱ modifiers,ȱ qualifiers,ȱ alternateȱ forms,ȱ andȱ optionalȱ fieldsȱ thatȱ canȱ beȱ usedȱ withȱ printfȱ canȱ beȱ overwhelming,ȱ burȱ theyȱ provideȱ greatȱ flexibilityȱ inȱ formattingȱ yourȱ output.ȱ Beȱ patient,ȱ itȱ takesȱ timeȱ toȱ learnȱ themȱ all!ȱ Hereȱ areȱsomeȱexamplesȱtoȱgetȱyouȱstarted.ȱ Figureȱ15.1ȱshowsȱsomeȱofȱtheȱpossibleȱvariationsȱinȱformattingȱofȱstrings.ȱOnlyȱ theȱcharactersȱshownȱareȱprinted.ȱToȱavoidȱambiguity,ȱtheȱsymbolȱ¤ȱisȱusedȱtoȱdenoteȱaȱ blankȱ space.ȱ Figureȱ 15.2ȱ showsȱ theȱ resultsȱ ofȱ formattingȱ severalȱ integerȱ valuesȱ withȱ variousȱintegerȱformats.ȱȱFigureȱ15.3ȱshowsȱsomeȱofȱtheȱwaysȱthatȱfloatingȬpointȱvaluesȱ canȱ beȱ formatted.ȱ Finally,ȱ Figureȱ 15.4ȱ showsȱ theȱ resultsȱ ofȱ formattingȱ aȱ muchȱ largerȱ floatingȬpointȱ numberȱ withȱ theȱ sameȱ formatȱ codesȱ asȱ theȱ previousȱ figure.ȱ Theȱ apparentȱerrorȱinȱtheȱfirstȱtwoȱoutputsȱoccursȱbecauseȱmoreȱsignificantȱdigitsȱareȱbeingȱ printedȱthanȱcanȱbeȱstoredȱinȱmemory.ȱ ȱ ȱ ȱ 15.11 Binary I/O ȱ Theȱmostȱefficientȱwayȱofȱwritingȱdataȱtoȱaȱfileȱisȱtoȱwriteȱitȱinȱbinary.ȱBinaryȱoutputȱ avoidsȱtheȱoverheadȱandȱlossȱofȱprecisionȱinvolvedȱwithȱconvertingȱnumericȱvaluesȱtoȱ characterȱstrings.ȱButȱbinaryȱdataȱisȱnotȱreadableȱbyȱhumanȱbeings,ȱsoȱthisȱtechniqueȱisȱȱ ȱ ȱ Format Number Converted Code 6.023e23 %f 602299999999999975882752.000000 %10.2f 602299999999999975882752.00 %e 6.023000e+23 %.4e 6.0230e+23 %g 6.023e+23 ȱ Figureȱ15.4ȱȱFormattingȱlargeȱfloatingȬpointȱvaluesȱwithȱprintfȱ Download at http://www.pin5i.com/ 15.11 Binary I/Oȱ 437 usefulȱonlyȱforȱdataȱthatȱwillȱbeȱsubsequentlyȱreadȱbyȱanotherȱprogram.ȱ Theȱ freadȱfunctionȱisȱusedȱtoȱreadȱbinaryȱdata;ȱ fwriteȱisȱusedȱtoȱwriteȱit.ȱTheirȱ prototypesȱlookȱlikeȱthis:ȱ ȱ size_t fread( void *buffer, size_t size, size_t count, FILE *stream ); size_t fwrite( void *buffer, size_t size, size_t count, FILE *stream ); ȱ bufferȱisȱaȱpointerȱtoȱtheȱareaȱthatȱholdsȱtheȱdata.ȱ sizeȱisȱtheȱnumberȱofȱbytesȱinȱeachȱ elementȱ ofȱ theȱ buffer,ȱ countȱ isȱ theȱ numberȱ ofȱ elementsȱ toȱ beȱ readȱ orȱ written,ȱ andȱ ofȱ courseȱstreamȱisȱtheȱstreamȱwithȱwhichȱtoȱreadȱorȱwriteȱtheȱdata.ȱ Theȱbufferȱisȱinterpretedȱasȱanȱarrayȱofȱoneȱorȱmoreȱvalues.ȱTheȱcountȱargumentȱ specifiesȱhowȱmanyȱvaluesȱareȱinȱtheȱarray,ȱsoȱtoȱreadȱorȱwriteȱaȱscalar,ȱuseȱaȱcountȱofȱ one.ȱTheȱfunctionsȱreturnȱtheȱnumberȱofȱelementsȱ(notȱbytes)ȱactuallyȱreadȱorȱwritten.ȱȱ Thisȱnumberȱmayȱbeȱsmallerȱthanȱtheȱrequestedȱnumberȱofȱelementsȱifȱendȱofȱfileȱwasȱ reachedȱonȱinputȱorȱanȱerrorȱoccurredȱonȱoutput.ȱ Letȇsȱlookȱatȱaȱcodeȱfragmentȱthatȱusesȱtheseȱfunctions.ȱ ȱ struct VALUE { long a; float b; char c[SIZE]; } values[ARRAY_SIZE]; ... n_values = fread( values, sizeof( struct VALUE ), ARRAY_SIZE, input_stream ); (processȱtheȱdataȱinȱtheȱarray)ȱ fwrite( values, sizeof( struct VALUE ), n_values, output_stream ); ȱ Thisȱprogramȱreadsȱbinaryȱdataȱfromȱanȱinputȱfile,ȱperformsȱsomeȱtypeȱofȱprocessingȱ onȱit,ȱandȱwritesȱtheȱresultȱtoȱanȱoutputȱfile.ȱAsȱmentioned,ȱthisȱtypeȱofȱI/Oȱisȱefficientȱ becauseȱtheȱbitsȱinȱeachȱvalueȱareȱwrittenȱ(orȱread)ȱtoȱ(orȱfrom)ȱtheȱstreamȱwithoutȱanyȱ conversions.ȱForȱexample,ȱsupposeȱoneȱofȱtheȱlongȱintegerȱvaluesȱinȱtheȱarrayȱhadȱtheȱ valueȱ4,023,817.ȱTheȱbitsȱthatȱrepresentȱthisȱvalueȱareȱ0x003d6609—theseȱbitsȱwouldȱbeȱ writtenȱtoȱtheȱstream.ȱBinaryȱinformationȱisȱnotȱreadableȱbyȱhumanȱbeingsȱbecauseȱtheȱ bitsȱ doȱ notȱ correspondȱ toȱ anyȱ reasonableȱ characters.ȱ Ifȱ interpretedȱ asȱ characters,ȱ thisȱ valueȱisȱ \0=f\t,ȱwhichȱcertainlyȱdoesȱnotȱconveyȱtheȱvalueȱofȱtheȱnumberȱveryȱwellȱtoȱ us.ȱ Download at http://www.pin5i.com/ 438ȱ Chapter 15 Input/Output Functionsȱ 15.12 Flushing and Seeking Functions ȱ Thereȱ areȱ aȱ fewȱ additionalȱ functionsȱ thatȱ areȱ usefulȱ whenȱ dealingȱ withȱ streams.ȱ Theȱ firstȱ isȱ fflush,ȱ whichȱ forcesȱ theȱ bufferȱ forȱ anȱ outputȱ streamȱ toȱ beȱ physicallyȱ writtenȱ evenȱifȱitȱisȱnotȱyetȱfull.ȱItsȱprototypeȱis:ȱ ȱ int fflush( FILE *stream ); ȱ Thisȱ functionȱ shouldȱ beȱ calledȱ wheneverȱ itȱ isȱ importantȱ forȱ bufferedȱ outputȱ toȱ beȱ physicallyȱ writtenȱ immediately.ȱ Forȱ example,ȱ callingȱ fflushȱ guaranteesȱ thatȱ debuggingȱinformationȱisȱphysicallyȱprintedȱinsteadȱofȱheldȱinȱtheȱbufferȱuntilȱaȱlaterȱ time.ȱ Normally,ȱ dataȱ isȱ writtenȱ toȱ aȱ fileȱ sequentially,ȱ whichȱ meansȱ thatȱ dataȱ writtenȱ laterȱappearsȱinȱtheȱfileȱafterȱanyȱdataȱwrittenȱearlier.ȱCȱalsoȱsupportsȱrandomȱaccessȱI/Oȱ inȱwhichȱdifferentȱlocationsȱofȱtheȱfileȱcanȱbeȱaccessedȱinȱanyȱorder.ȱRandomȱaccessȱisȱ accomplishedȱ byȱ seekingȱ toȱ theȱ desiredȱ positionȱ inȱ theȱ fileȱ beforeȱ readingȱ orȱ writing.ȱȱ Thereȱareȱtwoȱfunctionsȱthatȱperformȱthisȱoperation,ȱandȱtheirȱprototypesȱare:ȱ ȱ long ftell( FILE *stream ); int fseek( FILE *stream, long offset, int from ); ȱ Theȱ ftellȱfunctionȱreturnsȱtheȱcurrentȱpositionȱinȱtheȱstream,ȱthatȱis,ȱtheȱoffsetȱ fromȱ theȱ beginningȱ ofȱ theȱ fileȱ atȱ whichȱ theȱ nextȱ readȱ orȱ writeȱ wouldȱ begin.ȱ Thisȱ functionȱ letsȱ youȱ saveȱ theȱ currentȱ positionȱ inȱ aȱ fileȱ soȱ thatȱ youȱ canȱ returnȱ toȱ itȱ later.ȱȱ Onȱbinaryȱstreamsȱtheȱvalueȱwillȱbeȱtheȱnumberȱofȱbytesȱtheȱcurrentȱpositionȱisȱfromȱ theȱbeginningȱofȱtheȱfile.ȱȱ Onȱ textȱ streams,ȱ theȱ valueȱ representȱ aȱ position,ȱ butȱ itȱ mayȱ notȱ accuratelyȱ representȱtheȱnumberȱofȱcharactersȱfromȱtheȱbeginningȱofȱtheȱfileȱbecauseȱofȱtheȱendȬ ofȬlineȱ characterȱ translationsȱ performedȱ onȱ textȱ streamsȱ byȱ someȱ systems.ȱ However,ȱ theȱvalueȱreturnedȱbyȱftellȱmayȱalwaysȱbeȱusedȱasȱanȱoffsetȱfromȱtheȱbeginningȱofȱtheȱ fileȱwithȱfseek.ȱȱ fseekȱ allowsȱ youȱ toȱ seekȱ onȱ aȱ stream.ȱ Thisȱ operationȱ changesȱ theȱ positionȱ atȱ whichȱ theȱ nextȱ readȱ orȱ writeȱ willȱ occur.ȱ Theȱ firstȱ argumentȱ isȱ theȱ streamȱ toȱ change.ȱ Theȱ secondȱ andȱ thirdȱ argumentsȱ identifyȱ theȱ desiredȱ locationȱ inȱ theȱ file.ȱ Tableȱ 15.9ȱ describesȱthreeȱwaysȱthatȱtheȱsecondȱandȱthirdȱargumentsȱcanȱbeȱused.ȱ Itȱisȱanȱerrorȱtoȱattemptȱtoȱseekȱbeforeȱtheȱbeginningȱofȱaȱfile.ȱSeekingȱbeyondȱ theȱendȱofȱtheȱfileȱandȱwritingȱextendsȱtheȱfile.ȱSeekingȱbeyondȱtheȱendȱreadingȱcausesȱ anȱendȬofȬfileȱindicationȱtoȱbeȱreturned.ȱOnȱbinary,ȱstreams,ȱseeksȱfromȱ SEEK_ENDȱmayȱ notȱbeȱsupportedȱandȱshouldȱthereforeȱbeȱavoided.ȱOnȱtextȱstreams,ȱtheȱoffsetȱmustȱbeȱ ȱ Download at http://www.pin5i.com/ 15.12 Flushing and Seeking Functionsȱ 439 If from is… Then you will seek to… SEEK_SET offsetȱbytesȱfromȱtheȱbeginningȱofȱtheȱstream;ȱ offsetȱmustȱbeȱ nonȬnegative.ȱ SEEK_CUR offsetȱ bytesȱ fromȱ theȱ currentȱ locationȱ inȱ theȱ stream;ȱ offsetȱ mayȱbeȱpositiveȱorȱnegative.ȱ SEEK_END offsetȱbytesȱfromȱtheȱendȱofȱtheȱfile;ȱ offsetȱmayȱbeȱpositiveȱorȱ negative,ȱpositiveȱvaluesȱseekȱbeyondȱtheȱendȱofȱtheȱfile.ȱ ȱ Tableȱ15.9ȱȱfseekȱargumentsȱ ȱ ȱ ȱ ȱ zeroȱ ifȱ fromȱ isȱ eitherȱ SEEK_CURȱ orȱ SEEK_END.ȱ Theȱ offsetȱ mustȱ beȱ aȱ valueȱ previouslyȱ returnedȱfromȱaȱcallȱtoȱftellȱonȱtheȱsameȱstreamȱifȱfromȱisȱSEEK_SET.ȱ Partȱ ofȱ theȱ reasonȱ forȱ theseȱ restrictionsȱ isȱ theȱ endȬofȬlineȱ characterȱ mappingȱ performedȱonȱtextȱstreams.ȱBecauseȱofȱtheȱmapping,ȱtheȱnumberȱofȱbytesȱinȱtheȱtextȱfileȱ mayȱ beȱ differentȱ thanȱ theȱ numberȱ ofȱ bytesȱ theȱ programȱ wrote.ȱ Thus,ȱ aȱ portableȱ programȱcannotȱseekȱtoȱaȱpositionȱinȱaȱtextȱstreamȱusingȱtheȱresultȱofȱaȱcomputationȱ basedȱonȱtheȱnumberȱofȱcharactersȱwritten.ȱ Thereȱareȱthreeȱsideȱeffectsȱofȱchangingȱaȱstreamȇsȱpositionȱwithȱfseek.ȱFirst,ȱtheȱ endȬofȬfileȱindicatorȱisȱcleared.ȱSecond,ȱifȱaȱcharacterȱhadȱbeenȱreturnedȱtoȱtheȱstreamȱ withȱ ungetcȱ priorȱ toȱ anȱ fseek,ȱ theȱ ungottenȱ characterȱ isȱ forgottenȱ becauseȱ afterȱ theȱ seekȱitȱisȱnoȱlongerȱtheȱnextȱcharacter.ȱFinally,ȱseekingȱletsȱyouȱswitchȱfromȱreadingȱtoȱ writingȱandȱbackȱonȱstreamsȱopenedȱforȱupdate.ȱ Programȱ 15.6ȱ usesȱ fseekȱ toȱ accessȱ aȱ fileȱ ofȱ studentȱ information.ȱ Theȱ recordȱ numberȱargumentȱisȱaȱ size_tȱbecauseȱitȱdoesnȇtȱmakeȱsenseȱforȱitȱtoȱbeȱnegative.ȱTheȱ desiredȱlocationȱinȱtheȱfileȱisȱcomputedȱbyȱmultiplyingȱtheȱrecordȱnumberȱandȱrecordȱ size.ȱ Thisȱ calculationȱ worksȱ onlyȱ whenȱ allȱ recordsȱ inȱ theȱ fileȱ areȱ theȱ sameȱ length.ȱȱ Finally,ȱ theȱ resultȱ ofȱ freadȱ isȱ returnedȱ soȱ theȱ callerȱ canȱ determineȱ whetherȱ theȱ operationȱwasȱsuccessful.ȱ Thereȱ areȱ threeȱ additionalȱ functionsȱ thatȱ performȱ theseȱ sameȱ tasksȱ inȱ moreȱ limitedȱways.ȱTheirȱprototypesȱfollow,ȱ ȱ void rewind( FILE *stream ); int fgetpos( FILE *stream, fpos_t *position ); int fsetpos( FILE *stream, fpos_t const *position ); ȱ Theȱ rewindȱfunctionȱsetsȱtheȱread/writeȱpointerȱbackȱtoȱtheȱbeginningȱonȱtheȱindicatedȱ stream.ȱ Itȱ alsoȱ clearsȱ theȱ errorȱ indicatorȱ forȱ theȱ stream.ȱ Theȱ fgetposȱ andȱ fsetposȱ functionsȱareȱalternativesȱtoȱftellȱandȱfseek,ȱrespectively.ȱ Download at http://www.pin5i.com/ Chapter 15 Input/Output Functionsȱ 440ȱ ȱ /* ** Reads a specific record from a file. The arguments are the stream ** from which to read, the desired record number, and a pointer to ** the buffer into which the data should be placed. */ #include <stdio.h> #include "studinfo.h" int read_random_record( FILE *f, size_t rec_number, StudentInfo *buffer ) { fseek( f, (long)rec_number * sizeof( StudentInfo ), SEEK_SET ); return fread( buffer, sizeof( StudentInfo ), 1, f ); } ȱ Programȱ15.6ȱȱRandomȱfileȱaccessȱȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱrd_rand.cȱ ȱ ȱ ȱ ȱ ȱ Theȱprimaryȱdifferenceȱisȱthatȱthisȱpairȱofȱfunctionsȱtakesȱaȱpointerȱtoȱaȱ fpos_tȱasȱanȱ argument.ȱ fgetposȱstoresȱtheȱcurrentȱfileȱpositionȱinȱthisȱlocationȱandȱ fsetposȱsetsȱtheȱ fileȱpositionȱtoȱtheȱvalue.ȱ Theȱ wayȱ aȱ fileȱ positionȱ isȱ representedȱ byȱ anȱ fpos_tȱ isȱ notȱ definedȱ byȱ theȱ standard.ȱȱItȱmayȱbeȱaȱbyteȱoffsetȱinȱtheȱfile,ȱorȱitȱmayȱnot.ȱTherefore,ȱtheȱonlyȱsafeȱwayȱ toȱuseȱanȱfpos_tȱobtainedȱfromȱfgetposȱisȱasȱanȱargumentȱtoȱaȱsubsequentȱfsetpos.ȱ ȱ ȱ ȱ 15.13 Changing the Buffering ȱ Theȱbufferingȱperformedȱonȱstreamsȱisȱsometimesȱinappropriate,ȱsoȱtheȱfollowingȱtwoȱ functionsȱ areȱ providedȱ toȱ modifyȱ it.ȱ Bothȱ functionsȱ mayȱ beȱ calledȱ onlyȱ afterȱ theȱ specifiedȱ streamȱ hasȱ beenȱ openedȱ butȱ beforeȱ anyȱ otherȱ operationsȱ haveȱ beenȱ performedȱonȱit.ȱ ȱ void setbuf( FILE *stream, char *buf ); int setvbuf( FILE *stream, char *buf, int mode, size_t size ); ȱ setbufȱinstallsȱanȱalternateȱarrayȱtoȱbeȱusedȱforȱbufferingȱtheȱstream.ȱTheȱarrayȱ mustȱ beȱ BUFSIZȱ (whichȱ isȱ definedȱ inȱ stdio.h)ȱ charactersȱ long.ȱ Assigningȱ yourȱ ownȱ bufferȱtoȱaȱstreamȱpreventsȱtheȱI/Oȱlibraryȱfromȱdynamicallyȱallocatingȱaȱbufferȱforȱit.ȱ IfȱcalledȱwithȱaȱNULLȱargument,ȱsetbufȱturnsȱoffȱallȱbufferingȱforȱtheȱstream.ȱCharactersȱ ȱ Download at http://www.pin5i.com/ 15.14 Stream Error Functionsȱ CAUTION! 441 areȱwrittenȱtoȱandȱreadȱfromȱtheȱfileȱexactlyȱasȱdirectedȱbyȱtheȱprogram. 47 ȱ Itȱ isȱ dangerousȱ toȱ useȱ anȱ automaticȱ arrayȱ forȱ aȱ streamȱ buffer.ȱ Ifȱ executionȱ leavesȱ theȱ blockȱ inȱ whichȱ theȱ arrayȱ wasȱ declaredȱ beforeȱ theȱ streamȱ isȱ closed,ȱ theȱ streamȱ willȱ continueȱ toȱ useȱ theȱ memoryȱ even,ȱ afterȱ itȱ hasȱ beenȱ allocatedȱ toȱ otherȱ functionsȱ forȱ otherȱpurposes.ȱ Theȱ setvbufȱfunctionȱisȱmoreȱgeneral.ȱTheȱmodeȱargumentȱindicatesȱwhatȱtypeȱ ofȱ bufferingȱ isȱ desired. _IOFBFȱ indicatesȱ aȱ fullyȱ bufferedȱ stream,ȱ _IONBFȱ indicatesȱ anȱ unbufferedȱstream,ȱandȱ_IOLBFȱindicatesȱaȱlineȱbufferedȱstream.ȱAnȱoutputȱstreamȱthatȱ isȱlineȱbufferedȱisȱflushedȱeachȱtimeȱaȱnewlineȱisȱwrittenȱtoȱtheȱbuffer.ȱ Theȱ bufȱ andȱ sizeȱ argumentsȱ areȱ usedȱ toȱ specifyȱ theȱ bufferȱ toȱ use;ȱ ifȱ bufȱ isȱ NULL,ȱthenȱzeroȱmustȱbeȱgivenȱforȱsize.ȱȱGenerally,ȱitȱisȱbestȱtoȱuseȱanȱarrayȱofȱBUFSIZȱ charactersȱforȱaȱbuffer.ȱAlthoughȱusingȱaȱveryȱlargeȱbufferȱmayȱincreaseȱtheȱefficiencyȱ ofȱ theȱ programȱ slightly,ȱ itȱ mayȱ alsoȱ decreaseȱ theȱ efficiency.ȱ Forȱ example,ȱ mostȱ operatingȱ systemsȱ bufferȱ input/outputȱ operationsȱ toȱ diskȱ internally.ȱ Specifyingȱ aȱ bufferȱ thatȱ isȱ notȱ aȱ multipleȱ ofȱ theȱ operatingȱ systemȇsȱ bufferȱ sizeȱ mayȱ resultȱ inȱ extraȱ diskȱoperationsȱtoȱreadȱorȱwriteȱaȱfractionȱofȱaȱblock.ȱIfȱaȱlargerȱbufferȱisȱneeded,ȱyouȱ shouldȱ useȱ aȱ multipleȱ ofȱ BUFSIZ.ȱ Onȱ MSȬDOSȱ machines,ȱ aȱ bufferȱ thatȱ matchesȱ theȱ clusterȱsizeȱusedȱforȱyourȱdiskȱmayȱprovideȱsomeȱimprovement.ȱ ȱ ȱ ȱ 15.14 Stream Error Functions ȱ Theȱfollowingȱfunctionsȱareȱusedȱtoȱdetermineȱtheȱstateȱofȱaȱstream.ȱ ȱ int feof( FILE *stream ); int ferror( FILE *stream ); void clearer( FILE *stream ); ȱ feofȱreturnsȱtrueȱifȱtheȱstreamȱisȱcurrentlyȱatȱendȱofȱfile.ȱThisȱconditionȱcanȱbeȱclearedȱ byȱ performingȱ fseek,ȱ rewind,ȱ orȱ fsetposȱ onȱ theȱ stream.ȱ ferrorȱ reportsȱ onȱ theȱ errorȱ stateȱ ofȱ theȱ streamȱ andȱ returnsȱ trueȱ ifȱ anyȱ read/writeȱ errorsȱ haveȱ occurred.ȱ Finally,ȱ clearerrȱresetsȱtheȱerrorȱindicationȱforȱtheȱgivenȱstream.ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱInȱhostedȱruntimeȱenvironments,ȱtheȱoperatingȱsystemȱmayȱperformȱitsȱownȱbuffering,ȱindependentȱofȱtheȱstream.ȱThus,ȱ merelyȱcallingȱsetbufȱwillȱnotȱallowȱaȱprogramȱtoȱreadȱcharactersȱfromȱaȱkeyboardȱasȱtheyȱareȱtyped,ȱbecauseȱtheȱoperatingȱ systemȱusuallyȱbuffersȱtheseȱcharactersȱinȱorderȱtoȱimplementȱbackspaceȱediting.ȱ 47 Download at http://www.pin5i.com/ 442ȱ Chapter 15 Input/Output Functionsȱ 15.15 Temporary Files ȱ Occasionally,ȱitȱisȱconvenientȱtoȱuseȱaȱfileȱtoȱholdȱdataȱtemporarily.ȱWhenȱtheȱprogramȱ isȱ finished,ȱ theȱ fileȱ isȱ deletedȱ becauseȱ theȱ dataȱ itȱ containsȱ isȱ noȱ longerȱ useful.ȱ Theȱ tmpfileȱfunctionȱservesȱforȱthisȱpurpose.ȱ ȱ FILE *tmpfile( void ); ȱ Thisȱfunctionȱcreatesȱaȱfileȱthatȱisȱremovedȱautomaticallyȱwhenȱtheȱfileȱisȱclosedȱorȱtheȱ programȱterminates.ȱTheȱfileȱisȱopenedȱwithȱmodeȱ wb+,ȱmakingȱitȱsuitableȱforȱuseȱwithȱ binaryȱorȱtextȱdataȱ tmpfileȱ isȱ notȱ appropriateȱ forȱ aȱ temporaryȱ fileȱ thatȱ mustȱ beȱ openedȱ withȱ aȱ differentȱ modeȱ orȱ createdȱ byȱ oneȱ programȱ andȱ readȱ byȱ another.ȱ Inȱ theseȱ circumstances,ȱ fopenȱ mustȱ beȱ used,ȱ andȱ theȱ resultingȱ fileȱ mustȱ beȱ explicitlyȱ deletedȱ usingȱremoveȱ(seeȱbelow)ȱwhenȱitȱisȱnoȱlongerȱneeded.ȱ Temporaryȱfileȱnamesȱcanȱbeȱconstructedȱwithȱtheȱ tmpnamȱfunction,ȱwhichȱ hasȱ thisȱprototype:ȱ ȱ char *tmpnam( char * name ); ȱ Ifȱ calledȱ withȱ aȱ NULLȱ argument,ȱ theȱ functionȱ returnsȱ aȱ pointerȱ toȱ aȱ staticȱ arrayȱ containingȱtheȱconstructedȱfileȱname.ȱOtherwise,ȱtheȱargumentȱisȱassumedȱtoȱpointȱtoȱ anȱarrayȱthatȱisȱatȱleastȱ L_tmpnamȱcharactersȱlong.ȱInȱthisȱcase,ȱtheȱnameȱisȱconstructedȱ inȱtheȱarrayȱandȱtheȱargumentȱisȱreturned.ȱ Eitherȱway,ȱtheȱnameȱthatȱisȱconstructedȱisȱguaranteedȱnotȱtoȱbeȱtheȱnameȱofȱanȱ existingȱfile. 48 ȱtmpnamȱgeneratesȱaȱnewȱuniqueȱnameȱeachȱtimeȱitȱisȱcalledȱupȱtoȱTMP_MAXȱ times.ȱ ȱ ȱ ȱ 15.16 File Manipulation Functions ȱ Thereȱ areȱ twoȱ functionsȱ thatȱ manipulateȱ filesȱ withoutȱ performingȱ anyȱ input/output.ȱȱ Theirȱ prototypesȱ areȱ shownȱ below.ȱ Bothȱ functionsȱ returnȱ zeroȱ ifȱ theyȱ succeedȱ andȱ aȱ nonzeroȱvalueȱifȱtheyȱfail.ȱ ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱ Beware:ȱ Theȱ schemeȱ usedȱ toȱ guaranteeȱ uniquenessȱ mayȱ failȱ onȱ multiprogrammingȱ systemsȱ orȱ systemsȱ thatȱ shareȱ aȱ networkȱ fileȱ server.ȱ Theȱ causeȱ ofȱ theȱ problemȱ isȱ theȱ delayȱ betweenȱ whenȱ theȱ nameȱ isȱ constructedȱ andȱ whenȱ aȱ fileȱ ofȱ thatȱ nameȱisȱcreated.ȱIfȱseveralȱprogramsȱhappenȱtoȱconstructȱtheȱsameȱnameȱandȱtestȱforȱtheȱexistenceȱofȱaȱfileȱbeforeȱanyȱhaveȱ actuallyȱcreatedȱit,ȱeachȱprogramȱwillȱthinkȱthatȱitȱhasȱaȱuniqueȱname.ȱCreatingȱtheȱfileȱasȱsoonȱasȱtheȱtemporaryȱnameȱhasȱ beenȱconstructedȱreducesȱ(butȱdoesȱnotȱeliminate)ȱtheȱpotentialȱconflict.ȱ 48 Download at http://www.pin5i.com/ 15.17 Summaryȱ 443 int remove( char const *filename ); int rename( char const *oldname, char const *newname ); ȱ removeȱdeletesȱtheȱspecifiedȱfile.ȱIfȱtheȱfileȱisȱopenȱwhenȱ removeȱisȱcalled,ȱtheȱbehaviorȱ isȱimplementationȱdependent.ȱ Theȱ renameȱ functionȱ isȱ usedȱ toȱ changeȱ theȱ nameȱ ofȱ aȱ fileȱ fromȱ oldnameȱ toȱ newname.ȱ Ifȱ aȱ fileȱ alreadyȱ existsȱ withȱ theȱ newȱ name,ȱ theȱ behaviorȱ isȱ implementationȱ dependent.ȱIfȱthisȱfunctionȱfails,ȱtheȱfileȱwillȱstillȱbeȱaccessibleȱwithȱitsȱoriginalȱname.ȱ ȱ ȱ ȱ 15.17 Summary ȱ Theȱ Standardȱ dictatesȱ theȱ interfaceȱ andȱ operationȱ ofȱ theȱ functionsȱ inȱ theȱ standardȱ library,ȱ whichȱ enhancesȱ programȱ portability.ȱ Anȱ implementationȱ mayȱ provideȱ additionalȱfunctionsȱinȱitsȱlibrary,ȱbutȱmayȱnotȱchangeȱtheȱrequiredȱfunctions.ȱ perrorȱprovidesȱaȱsimpleȱmethodȱofȱreportingȱerrorsȱtoȱtheȱuser.ȱWhenȱaȱfatalȱ errorȱisȱdetected,ȱyouȱcanȱuseȱexitȱtoȱterminateȱtheȱprogram.ȱ Theȱ stdio.hȱ headerȱ containsȱ declarationsȱ necessaryȱ forȱ usingȱ theȱ I/Oȱ libraryȱ functions.ȱȱAllȱI/Oȱisȱaȱmatterȱofȱmovingȱbytesȱintoȱorȱoutȱofȱtheȱprogram.ȱTheȱinterfaceȱ providedȱbyȱtheȱ libraryȱ forȱI/Oȱ isȱcalledȱaȱstream.ȱByȱdefault,ȱstreamȱ I/Oȱ isȱ buffered.ȱ Binaryȱstreamsȱareȱusedȱprimarilyȱforȱbinaryȱdata.ȱBytesȱareȱwrittenȱtoȱorȱreadȱfromȱaȱ binaryȱ streamȱ withoutȱ modification.ȱ Textȱ streams,ȱ onȱ theȱ otherȱ hand,ȱ areȱ usedȱ forȱ characters.ȱ Theȱ longestȱ lineȱ allowedȱ inȱ aȱ textȱ streamȱ isȱ implementationȬdefined,ȱ butȱ mustȱ beȱ atȱ leastȱ 254ȱ charactersȱ long.ȱ Byȱ definition,ȱ aȱ lineȱ isȱ terminatedȱ byȱ aȱ newlineȱ character.ȱ Ifȱ theȱ hostȱ operatingȱ systemȱ usesȱ aȱ differentȱ conventionȱ forȱ terminatingȱ lines,ȱtheȱI/Oȱfunctionsȱmustȱtranslateȱbetweenȱthatȱformȱandȱtheȱinternalȱform.ȱ Aȱ FILEȱisȱaȱdataȱstructureȱthatȱmanagesȱtheȱbufferȱandȱstoresȱtheȱI/Oȱstateȱforȱaȱ stream.ȱ Theȱ runtimeȱ environmentȱ providesȱ threeȱ streamsȱ toȱ eachȱ program—theȱ standardȱ input,ȱ standardȱ output,ȱ andȱ standardȱ error.ȱ Itȱ isȱ commonȱ forȱ theȱ standardȱ inputȱtoȱdefaultȱtoȱaȱkeyboardȱandȱtheȱotherȱtwoȱstreamsȱtoȱdefaultȱtoȱaȱdisplayȱscreen.ȱȱ Aȱseparateȱstreamȱisȱprovidedȱforȱerrorȱmessagesȱsoȱthatȱtheyȱwillȱbeȱdisplayedȱinȱtheȱ defaultȱ locationȱ evenȱ ifȱ theȱ standardȱ outputȱ hasȱ beenȱ redirectedȱ toȱ anotherȱ location.ȱ FOPEN_MAXȱisȱtheȱimplementationȬdefinedȱlimitȱofȱtheȱnumberȱofȱ FILEsȱyouȱmayȱhaveȱ openȱ simultaneously.ȱ Theȱ valueȱ mustȱ beȱ atȱ leastȱ eight.ȱ FILENAME_MAXȱ isȱ eitherȱ theȱ maximumȱlengthȱor,ȱifȱthereȱisnȇtȱaȱmaximumȱlength,ȱtheȱrecommendedȱsizeȱtoȱuseȱforȱ characterȱarraysȱinȱwhichȱfilenamesȱareȱstored.ȱ Download at http://www.pin5i.com/ 444ȱ Chapter 15 Input/Output Functionsȱ ToȱperformȱstreamȱI/Oȱ onȱaȱfile,ȱ itȱisȱ firstȱ openedȱ withȱ fopen,ȱ whichȱ returnsȱ aȱ pointerȱtoȱtheȱ FILEȱstructureȱassignedȱtoȱ theȱstream.ȱThisȱpointerȱmustȱbeȱsavedȱinȱaȱ FILE *ȱvariable.ȱTheȱfileȱmayȱthenȱbeȱreadȱfromȱand/orȱwrittenȱto.ȱAfterwards,ȱtheȱfileȱ isȱ closed.ȱ Manyȱ ofȱ theȱ I/Oȱ functionsȱ belongȱ toȱ familiesȱ whoseȱ membersȱ performȱ essentiallyȱ theȱ sameȱ workȱ withȱ minorȱ differencesȱ asȱ toȱ whereȱ inputȱ isȱ obtainedȱ orȱ outputȱisȱwritten.ȱTheȱusualȱvariantsȱincludeȱaȱfunctionȱthatȱtakesȱaȱstreamȱargument,ȱ aȱfunctionȱthatȱworksȱonlyȱwithȱoneȱofȱtheȱstandardȱstreams,ȱandȱaȱfunctionȱthatȱworksȱ withȱaȱbufferȱinȱmemoryȱratherȱthanȱaȱstream.ȱ Streamsȱareȱopenedȱwithȱ fopen.ȱItsȱargumentsȱareȱtheȱnameȱofȱtheȱfileȱtoȱopenȱ andȱ theȱ desiredȱ modeȱ ofȱ theȱ stream.ȱ Theȱ modeȱ specifiesȱ reading,ȱ writing,ȱ orȱ appending,ȱ andȱ alsoȱ specifiesȱ whetherȱ theȱ streamȱ willȱ beȱ textȱ orȱ binary.ȱ freopenȱ performsȱtheȱsameȱtask,ȱexceptȱthatȱyouȱcanȱspecifyȱtheȱstreamȱtoȱuse.ȱThisȱfunctionȱisȱ mostȱ oftenȱ usedȱ toȱ reopenȱ oneȱ ofȱ theȱ standardȱ streams.ȱ Alwaysȱ checkȱ theȱ valueȱ returnedȱfromȱfopenȱorȱfreopenȱforȱerrors.ȱȱAfterȱyouȱhaveȱfinishedȱwithȱaȱstream,ȱyouȱ shouldȱcloseȱitȱwithȱfclose.ȱ CharacterȬbyȬcharacterȱ I/Oȱ isȱ performedȱ byȱ theȱ getcharȱ andȱ putcharȱ familiesȱ ofȱ functions.ȱ Theȱ inputȱ functionsȱ fgetcȱ andȱ getcȱ bothȱ takeȱ aȱ streamȱ argument,ȱ andȱ getcharȱ readsȱ onlyȱ fromȱ theȱ standardȱ input.ȱ Theȱ firstȱ isȱ implementedȱ asȱ aȱ functionȱ andȱtheȱotherȱtwoȱareȱimplementedȱasȱmacros.ȱAllȱthreeȱreturnȱaȱsingleȱcharacterȱasȱanȱ integerȱ value.ȱ Exceptȱ forȱ performingȱ outputȱ insteadȱ ofȱ input,ȱ theȱ fputc,ȱ putc,ȱ andȱ putcharȱfunctionsȱshareȱtheȱpropertiesȱofȱtheȱcorrespondingȱinputȱfunctions.ȱ ungetcȱisȱ usedȱ toȱ pushȱ anȱ unwantedȱ characterȱ backȱ toȱ aȱ stream.ȱ Theȱ pushedȱ characterȱ willȱ beȱ theȱ firstȱ oneȱ returnedȱ byȱ theȱ nextȱ inputȱ operation.ȱ Changingȱ theȱ streamȇsȱ positionȱ (seeking)ȱcausesȱungottenȱcharactersȱtoȱbeȱforgotten.ȱ Lineȱ I/Oȱ canȱ beȱ eitherȱ formattedȱ orȱ unformatted.ȱ Theȱ getsȱ andȱ putsȱ familiesȱ performȱunformattedȱlineȱI/O.ȱfgetsȱandȱgetsȱbothȱreadȱaȱlineȱofȱinputȱintoȱaȱspecifiedȱ buffer.ȱ Theȱ formerȱ takesȱ aȱ streamȱ argumentȱ andȱ theȱ latterȱ worksȱ withȱ theȱ standardȱ input.ȱ fgetsȱ isȱ safer.ȱ Itȱ takesȱ theȱ bufferȱ sizeȱ asȱ anȱ argumentȱ andȱ thereforeȱ canȱ guaranteeȱthatȱaȱlongȱinputȱlineȱwillȱnotȱoverflowȱtheȱbuffer.ȱDataȱisȱnotȱlost—theȱnextȱ partȱ ofȱ aȱ longȱ inputȱ lineȱ willȱ beȱ readȱ byȱ theȱ nextȱ callȱ toȱ fgets.ȱ Theȱ fputsȱ andȱ putsȱ functionsȱ writeȱ textȱ toȱ aȱ stream.ȱ Theirȱ interfacesȱ areȱ analogousȱ toȱ theȱ correspondingȱ inputȱfunctions.ȱȱForȱbackwardȱcompatibility,ȱ getsȱremovesȱtheȱnewlineȱfromȱtheȱlineȱ itȱread,ȱandȱputsȱwritesȱaȱnewlineȱafterȱtheȱtextȱfromȱtheȱbuffer.ȱ Theȱ scanfȱ andȱ printfȱ familiesȱ performȱ formattedȱ I/O.ȱ Thereȱ areȱ threeȱ inputȱ functions.ȱ fscanfȱtakesȱaȱstreamȱargument,ȱ scanfȱreadsȱfromȱtheȱstandardȱinput,ȱandȱ sscanfȱ takesȱ charactersȱ fromȱ aȱ bufferȱ inȱ memory.ȱ Theȱ printfȱ famiJyȱ alsoȱ hasȱ threeȱ functionsȱwithȱsimilarȱproperties.ȱTheȱscanfȱfunctionsȱconvertȱcharactersȱaccordingȱtoȱaȱ formatȱstring.ȱAȱlistȱofȱpointerȱargumentsȱindicatesȱwhereȱtheȱresultingȱvaluesȱareȱ Download at http://www.pin5i.com/ 15.17 Summaryȱ 445 ȱ stored.ȱTheȱfunctionȱreturnsȱtheȱnumberȱofȱvaluesȱthatȱwereȱconverted,ȱorȱEOFȱifȱendȱofȱ fileȱ wasȱ reachedȱ beforeȱ theȱ firstȱ conversion.ȱ Theȱ printfȱ functionsȱ convertȱ valuesȱ toȱ characterȱformȱaccordingȱtoȱaȱformatȱstring.ȱTheȱvaluesȱareȱpassedȱasȱarguments.ȱ ȱ Itȱ isȱ moreȱ efficientȱ toȱ writeȱ binaryȱ data,ȱ suchȱ asȱ integersȱ andȱ floatingȬpointȱ values,ȱwithȱbinaryȱI/OȱthanȱwithȱcharacterȱI/O.ȱBinaryȱI/Oȱreadsȱandȱwritesȱtheȱbitsȱinȱ theȱ valueȱ directly,ȱ withoutȱ convertingȱ theȱ valueȱ toȱ characters.ȱ Theȱ resultȱ ofȱ binaryȱ output,ȱhowever,ȱisȱnotȱhumanȬreadable.ȱ freadȱandȱ fwriteȱperformȱbinaryȱI/O.ȱEachȱ takesȱfourȱarguments:ȱaȱpointerȱtoȱaȱbuffer,ȱtheȱsizeȱofȱoneȱelementȱinȱtheȱbuffer,ȱtheȱ desiredȱnumberȱofȱelementsȱtoȱreadȱorȱwrite,ȱandȱaȱstream.ȱ ȱ Byȱ default,ȱ streamsȱ areȱ sequential.ȱ However,ȱ youȱ canȱ performȱ randomȱ I/Oȱ byȱ seekingȱtoȱaȱdifferentȱpositionȱinȱtheȱfileȱbeforeȱreadingȱorȱwriting.ȱTheȱ fseekȱfunctionȱ letsȱ youȱ specifyȱ aȱ positionȱ inȱ theȱ fileȱ asȱ anȱ offsetȱ fromȱ theȱ beginningȱ ofȱ theȱ file,ȱ theȱ currentȱfileȱposition,ȱorȱtheȱendȱofȱtheȱfile.ȱ ftellȱreturnsȱtheȱcurrentȱfileȱposition.ȱTheȱ fsetpos andȱ fgetposȱ functionsȱ areȱ alternativesȱ toȱ theȱ previousȱ twoȱ functions.ȱȱ However,ȱ theȱ onlyȱ legalȱ argumentȱ toȱ fsetposȱ isȱ aȱ valueȱ previouslyȱ returnedȱ byȱ fgetposȱonȱtheȱsameȱstream.ȱFinally,ȱtheȱ rewindȱfunctionȱreturnsȱtoȱtheȱbeginningȱofȱaȱ file.ȱ ȱ Theȱ bufferȱusedȱforȱaȱstreamȱcanȱ beȱ changedȱbyȱcallingȱ setbufȱbeforeȱ anyȱ I/Oȱ hasȱoccurredȱonȱtheȱstream.ȱAssigningȱaȱbufferȱinȱthisȱmannerȱpreventsȱoneȱfromȱbeingȱ dynamicallyȱ allocated.ȱ Passingȱ aȱ NULLȱ pointerȱ asȱ theȱ bufferȱ argumentȱ disablesȱ bufferingȱaltogether.ȱTheȱ setvbufȱfunctionȱisȱmoreȱgeneral.ȱȱWithȱit,ȱyouȱcanȱspecifyȱaȱ bufferȱwithȱaȱnonstandardȱsize.ȱYouȱmayȱalsoȱchooseȱtheȱtypeȱofȱbufferingȱyouȱdesire:ȱ fullyȱbuffered,ȱlineȱbuffered,ȱorȱunbuffered.ȱ ȱ Theȱ ferrorȱandȱ clearerrȱfunctionsȱrelateȱtoȱtheȱerrorȱstateȱofȱaȱstream,ȱthatȱis,ȱ whetherȱanyȱread/writeȱerrorsȱhaveȱoccurred.ȱTheȱfirstȱfunctionȱreturnsȱtheȱerrorȱstate,ȱ andȱ theȱ secondȱ functionȱ resetsȱ it.ȱ Theȱ feofȱ functionȱ returnsȱ trueȱ ifȱ theȱ streamȱ isȱ currentlyȱatȱendȱofȱfile.ȱ ȱ Theȱ tmpfileȱfunctionȱreturnsȱaȱstreamȱthatȱisȱassociatedȱwithȱaȱtemporaryȱfile.ȱȱ Theȱ fileȱ isȱ automaticallyȱ deletedȱ afterȱ theȱ streamȱ isȱ closed.ȱ Theȱ tmpnameȱ functionȱ createsȱaȱfilenameȱsuitableȱforȱuseȱasȱaȱtemporaryȱfile.ȱTheȱnameȱdoesȱnotȱconflictȱwithȱ theȱnamesȱofȱanyȱexistingȱfiles.ȱAȱfileȱcanȱbeȱdeletedȱbyȱpassingȱitsȱnameȱtoȱtheȱ removeȱ function.ȱTheȱ renameȱfunctionȱchangesȱtheȱnameȱofȱaȱfile.ȱItȱtakesȱtwoȱarguments,ȱtheȱ currentȱnameȱofȱtheȱfileȱandȱtheȱnewȱname.ȱ Download at http://www.pin5i.com/ 446ȱ Chapter 15 Input/Output Functionsȱ 15.18 Summary of Cautions ȱ 1. Forgettingȱtoȱfollowȱdebuggingȱprintfȇsȱwithȱaȱcallȱtoȱfȱflushȱ(pageȱ412).ȱ 2. Notȱcheckingȱtheȱvalueȱreturnedȱbyȱfopenȱ(pageȱ417).ȱ 3. Changingȱtheȱfileȱpositionȱdiscardsȱanyȱungottenȱcharactersȱ(pageȱ423).ȱ 4. Specifyingȱtooȱsmallȱaȱbufferȱwithȱfgetsȱ(pageȱ424).ȱ 5. Inputȱfromȱgetsȱoverflowingȱtheȱbufferȱundetectedȱ(pageȱ424).ȱ 6. Mismatchedȱ formatȱ codesȱ andȱ argumentȱ pointerȱ typesȱ withȱ anyȱ ofȱ theȱ scanfȱ functionsȱ(pageȱ425).ȱ 7. Forgettingȱtoȱputȱanȱampersandȱbeforeȱeachȱnonarray,ȱnonpointerȱargumentȱtoȱanyȱ ofȱtheȱscanfȱfunctionsȱ(pageȱ426).ȱ 8. Beȱ sureȱ toȱ specifyȱ theȱ properȱ qualifierȱ inȱ scanfȱ formatȱ codesȱ toȱ convertȱ doubles,ȱ longȱdoubles,ȱandȱshortȱandȱlongȱintegersȱ(pageȱ427).ȱ 9. Outputȱfromȱsprintfȱoverflowingȱtheȱbufferȱundetectedȱ(pageȱ430).ȱ 10. Interchangingȱprintfȱandȱscanfȱformatȱcodesȱ(pageȱ432).ȱ 11. Mismatchedȱ formatȱ codesȱ andȱ argumentȱ typesȱ withȱ anyȱ ofȱ theȱ printfȱ functionsȱ (pageȱ432).ȱ 12. Onȱimplementationsȱinȱwhichȱlongȱintegersȱareȱlongerȱthanȱintegers,ȱnotȱspecifyingȱ theȱlȱmodifierȱwhenȱprintingȱlongȱintegerȱvaluesȱ(pageȱ435).ȱ 13. Beȱcarefulȱwhenȱusingȱanȱautomaticȱarrayȱasȱaȱstreamȱbufferȱ(pageȱ441).ȱ ȱ ȱ ȱ 15.19 Summary of Programming Tips ȱ 1. Checkȱforȱandȱreportȱerrorsȱwheneverȱtheyȱmayȱoccurȱ(pageȱ410).ȱ 2. Theȱabilityȱtoȱmanipulateȱtextȱlinesȱwithoutȱregardȱforȱtheirȱexternalȱrepresentationȱ improvesȱprogramȱportabilityȱ(pageȱ413).ȱ 3. Usingȱscanfȱqualifiersȱenhancesȱportabilityȱ(pageȱ427).ȱ 4. Portabilityȱisȱenhancedȱifȱyouȱuseȱtheȱ lȱmodifierȱwhenȱprintingȱlongȱintegersȱevenȱ ifȱyourȱimplementationȱdoesnȇtȱrequireȱitȱ(pageȱ435).ȱ ȱ ȱ ȱ 15.20 Questions ȱ 1. Whatȱhappensȱifȱtheȱvalueȱreturnedȱfromȱfopenȱisȱnotȱcheckedȱforȱerrors?ȱ Download at http://www.pin5i.com/ 15.20 Questionsȱ 447 2. WhatȱwillȱhappenȱifȱI/Oȱisȱattemptedȱonȱaȱstreamȱthatȱhasȱneverȱbeenȱopened?ȱ 3. Whatȱ willȱ happenȱ ifȱ aȱ callȱ toȱ fcloseȱ fails,ȱ butȱ theȱ programȱ doesȱ notȱ checkȱ theȱ returnedȱvalueȱforȱerrors?ȱ 4. Ifȱaȱprogramȱisȱexecutedȱwithȱitsȱstandardȱinputȱredirectedȱtoȱcomeȱfromȱaȱfile,ȱhowȱ doesȱtheȱprogramȱdetectȱthisȱfact?ȱ 5. Whatȱhappensȱifȱfgetsȱisȱcalledȱwithȱaȱbufferȱsizeȱofȱone?ȱȱOfȱtwo?ȱ 6. Howȱlongȱmustȱtheȱbufferȱbeȱtoȱensureȱthatȱtheȱstringȱproducedȱbyȱsprintf willȱnotȱ overflowȱit?ȱȱAssumeȱthatȱyourȱmachineȱusesȱ2Ȭbyteȱintegers.ȱ sprintf( buffer, "%d %c %x", a, b, c ); 7. Howȱlongȱmustȱtheȱbufferȱbeȱtoȱensureȱthatȱtheȱstringȱproducedȱbyȱsprintfȱwillȱnotȱ overflowȱit?ȱ sprintf( buffer, "%s", a ); 8. Isȱtheȱlastȱdigitȱprintedȱbyȱtheȱ %fȱformalȱcodeȱroundedȱorȱareȱtheȱunprintedȱdigitsȱ simplyȱtruncated?ȱ 9. Howȱcanȱyouȱobtainȱaȱlistȱofȱallȱofȱtheȱerrorȱmessagesȱthatȱperrorȱcanȱprint?ȱ 10. Whyȱdoȱ fprintf,ȱ fscanf,ȱ fputs,ȱandȱ fcloseȱallȱtakeȱaȱpointerȱtoȱaȱ FILEȱratherȱthanȱ dieȱFILEȱstructure?ȱ 11. Whatȱmodeȱwouldȱyouȱuseȱtoȱopenȱaȱfileȱthatȱyouȱwantedȱtoȱwriteȱto,ȱassumingȱ(1)ȱ youȱdoȱnotȱwantȱtoȱloseȱtheȱformerȱcontentsȱofȱtheȱfile,ȱandȱ(2)ȱyouȱwantȱtoȱbeȱableȱ toȱwriteȱanywhereȱinȱtheȱfile?ȱ 12. Whyȱisȱtheȱfrepoenȱfunctionȱnecessary?ȱ 13. Forȱ mostȱ programs,ȱ doȱ youȱ thinkȱ itȱ isȱ worthȱ theȱ effortȱ toȱ thinkȱ aboutȱ whetherȱ fgetc( stdin )ȱorȱgetchar()ȱwouldȱbeȱbetter?ȱ 14. Whatȱdoesȱtheȱfollowingȱstatementȱprintȱonȱyourȱsystem?ȱ printf( "%d\n", 3.14 ); 15. Explainȱhowȱstringsȱwillȱbeȱprintedȱwithȱtheȱ%-6.10sȱformatȱcode.ȱ 16. Whenȱ aȱ particularȱ valueȱ isȱ printedȱ withȱ theȱ formatȱ codeȱ %.3f,ȱ theȱ resultȱ isȱ 1.405,ȱ butȱ whenȱ theȱ sameȱ valueȱ isȱ printedȱ withȱ theȱ formatȱ codeȱ %.2f,ȱ theȱ resultȱ isȱ 1.40.ȱȱ Explainȱthisȱapparentȱerror.ȱ Download at http://www.pin5i.com/ 448ȱ Chapter 15 Input/Output Functionsȱ 15.21 Programming Exercises ȱ 1. Writeȱ aȱ programȱ thatȱ copiesȱ theȱ standardȱ inputȱ toȱ theȱ standardȱ outputȱ oneȱ characterȱatȱaȱtime.ȱ 2. Changeȱ yourȱ solutionȱ toȱ Exerciseȱ 1ȱ soȱ thatȱ itȱ readsȱ andȱ writesȱ anȱ entireȱ lineȱ atȱ aȱ time.ȱYouȱmayȱassumeȱthatȱeachȱlineȱinȱtheȱfileȱwillȱcontainȱ80ȱorȱfewerȱcharactersȱ (notȱcountingȱtheȱterminatingȱnewline).ȱ 3. Changeȱ yourȱ solutionȱ toȱ Exerciseȱ 2ȱ toȱ removeȱ theȱ 80ȱ characterȱ lineȱ lengthȱ restriction.ȱYouȱshouldȱstillȱprocessȱtheȱfileȱaȱlineȱatȱaȱtime,ȱbutȱlinesȱlongerȱthanȱ80ȱ charactersȱmayȱbeȱprocessedȱaȱpieceȱatȱaȱtime.ȱ 4. ChangeȱyourȱsolutionȱtoȱExerciseȱ3ȱtoȱpromptȱforȱandȱreadȱtwoȱfilenamesȱfromȱtheȱ standardȱ input.ȱ Theȱ firstȱ willȱ beȱ theȱ inputȱ file,ȱ andȱ theȱ secondȱ willȱ beȱ theȱ outputȱ file.ȱTheȱrevisedȱprogramȱshouldȱopenȱbothȱfilesȱandȱcopyȱfromȱtheȱinputȱfileȱtoȱtheȱ outputȱfileȱasȱbefore.ȱ 5. Changeȱ yourȱ solutionȱ toȱ Exerciseȱ 4ȱ soȱ thatȱ itȱ looksȱ forȱ linesȱ beginningȱ withȱ anȱ integer.ȱȱTheseȱintegerȱvaluesȱshouldȱbeȱsummedȱandȱtheȱtotalȱshouldȱbeȱwrittenȱatȱ theȱendȱofȱtheȱoutputȱfile.ȱOtherȱthanȱthisȱoneȱchange,ȱtheȱrevisedȱprogramȱshouldȱ performȱasȱbefore.ȱ 6. Inȱ Chapterȱ 9ȱ youȱ wroteȱ aȱ functionȱ calledȱ palindromeȱ thatȱ wouldȱ determineȱ whetherȱorȱnotȱaȱstringȱcontainedȱaȱpalindrome.ȱForȱthisȱproblem,ȱyouȱareȱtoȱwriteȱ aȱfunctionȱthatȱwillȱdetermineȱwhetherȱorȱnotȱtheȱvalueȱofȱanȱintegerȱvariableȱisȱaȱ palindrome.ȱ Forȱ example,ȱ theȱ valueȱ 245ȱ isȱ notȱ aȱ palindromeȱ butȱ 14741ȱ is.ȱ Theȱ functionȱshouldȱhaveȱthisȱprototype:ȱ ȱ int numeric_palindrome( int value ); ȱ Itȱshouldȱreturnȱtrueȱifȱtheȱvalueȱisȱaȱpalindrome,ȱotherwiseȱfalse.ȱ 7. Aȱcertainȱdataȱfileȱcontainsȱtheȱagesȱofȱfamilyȱmembers.ȱTheȱagesȱofȱtheȱmembersȱofȱ oneȱfamilyȱareȱallȱonȱtheȱsameȱline,ȱandȱareȱseparatedȱbyȱwhiteȱspace.ȱForȱexample,ȱ thisȱdataȱ ȱ 45 42 22 36 35 7 3 1 22 20 ȱ describesȱthreeȱfamiliesȱhavingȱthree,ȱfive,ȱandȱtwoȱmembers,ȱrespectively.ȱ Writeȱaȱprogramȱthatȱcomputesȱtheȱaverageȱageȱofȱeachȱfamilyȱrepresentedȱinȱaȱ fileȱofȱthisȱsort.ȱItȱshouldȱprintȱtheȱaverageȱageȱusingȱtheȱ%5.2fȱformat,ȱfollowedȱbyȱ aȱcolonȱandȱtheȱinputȱdata.ȱYouȱmayȱassumeȱthatȱnoȱfamilyȱcontainsȱmoreȱthanȱ10ȱ members.ȱ 8. Writeȱaȱprogramȱtoȱproduceȱaȱhexȱdumpȱofȱaȱfile.ȱȱItȱshouldȱtakeȱaȱsingleȱargumentȱ ȱ Download at http://www.pin5i.com/ 15.21 Programming Exercisesȱ 449 fromȱtheȱcommandȱline,ȱwhichȱisȱtheȱnameȱofȱtheȱfileȱtoȱdump.ȱIfȱthisȱargumentȱisȱ missing,ȱtheȱprogramȱshouldȱdumpȱtheȱstandardȱinputȱinstead.ȱ Eachȱlineȱofȱtheȱdumpȱshouldȱhaveȱtheȱfollowingȱformat.ȱ ȱ Columns Contents 1–6ȱȱ Theȱcurrentȱoffsetȱinȱtheȱfile,ȱinȱhexadecimal,ȱwithȱleadingȱzeros.ȱ 9–43ȱ Theȱ hexadecimalȱ representationȱ ofȱ theȱ nextȱ 16ȱ bytesȱ inȱ theȱ file.ȱ Theseȱ areȱ printedȱ inȱ fourȱ groupsȱ ofȱ 8ȱ hexȱ digits,ȱ withȱ oneȱ spaceȱ betweenȱeachȱgroup.ȱ 46ȱ Anȱasterisk.ȱ 47–62ȱ Theȱ characterȱ representationȱ ofȱ theȱ sameȱ 16ȱ bytesȱ inȱ theȱ file.ȱ Ifȱ aȱ byteȱ isȱ notȱ aȱ printableȱ characterȱ orȱ aȱ space,ȱ aȱ periodȱ isȱ printedȱ instead.ȱ 63ȱ Anȱasterisk.ȱ ȱ AllȱhexadecimalȱnumbersȱshouldȱuseȱuppercaseȱAȬFȱratherȱthanȱlowercaseȱletters.ȱ Hereȱareȱsomeȱsampleȱlinesȱillustratingȱthisȱformat.ȱ ȱ 000200 000210 000220 D4O5C000 82102004 91D02000 9010207F 82102001 91D02000 0001C000 2F757372 2F6C6962 2F6C642E 736F002F 6465762F *...... ... ... .* *.. ... ...../usr* */lib/ld.so./dev/* 9. TheȱUNIXȱfgrepȱprogramȱtakesȱaȱstringȱandȱaȱseriesȱofȱfilenamesȱasȱcommandȱlineȱ arguments.ȱ Itȱ thenȱ looksȱ throughȱ theȱ filesȱ oneȱ byȱ one.ȱ Forȱ eachȱ lineȱ thatȱ containsȱ theȱgivenȱstring,ȱtheȱnameȱofȱtheȱfile,ȱaȱcolon,ȱandȱtheȱlineȱcontainingȱtheȱstringȱareȱ printed.ȱ Writeȱ thisȱ program.ȱ Theȱ stringȱ argumentȱ comesȱ first,ȱ andȱ itȱ mayȱ notȱ containȱ anyȱ newlineȱ characters.ȱ Theȱ filenameȱ argumentsȱ comeȱ next.ȱ Ifȱ thereȱ arenȇtȱ anyȱ filenamesȱgiven,ȱtheȱprogramȱshouldȱreadȱtheȱstandardȱinput.ȱInȱthisȱcase,ȱtheȱlinesȱ printedȱbyȱtheȱprogramȱareȱnotȱprefixedȱwithȱaȱfilenameȱorȱcolon.ȱYouȱmayȱassumeȱ thatȱtheȱlinesȱofȱtextȱinȱtheȱfilesȱwillȱbeȱnoȱlongerȱthanȱ510ȱcharacters.ȱ 10. Writeȱ aȱ programȱ toȱ computeȱ checksumsȱ forȱ files.ȱ Theȱ programȱ isȱ invokedȱ asȱ follows:ȱ ȱ $sum [-f] [file...] ȱ Theȱ-fȱoptionȱisȱoptional.ȱIȇllȱdescribeȱitsȱmeaningȱlater.ȱ Nextȱ comesȱ anȱ optionalȱ listȱ ofȱ fileȱ names.ȱ Ifȱ thereȱ arenȇtȱ anyȱ namesȱ given,ȱ theȱ programȱprocessesȱtheȱstandardȱinput.ȱOtherwise,ȱtheȱprogramȱprocessesȱeachȱfileȱ inȱ theȱ orderȱ inȱ whichȱ theyȱ areȱ namedȱ onȱ theȱ commandȱ line.ȱ ȈProcessingȱ aȱ fileȈȱ meansȱtoȱcomputeȱandȱprintȱtheȱchecksumȱforȱtheȱfile.ȱ Theȱalgorithmȱforȱcomputingȱtheȱchecksumȱisȱsimple.ȱEachȱcharacterȱinȱtheȱfileȱ isȱaddedȱtoȱaȱ16Ȭbit,ȱunsignedȱinteger,ȱandȱtheȱresultȱisȱtheȱchecksumȱvalue.ȱ Download at http://www.pin5i.com/ 450ȱ Chapter 15 Input/Output Functionsȱ Althoughȱ simpleȱ toȱ implement,ȱ thisȱ algorithmȱ isȱ notȱ aȱ greatȱ errorȱ detectionȱ method.ȱInterchangingȱtwoȱcharactersȱinȱtheȱfileȱwouldȱnotȱbeȱdetectedȱasȱanȱerror.ȱ Ordinarily,ȱ theȱ checksumȱ isȱ writtenȱ toȱ theȱ standardȱ outputȱ whenȱ theȱ endȱ ofȱ eachȱfileȱisȱfound.ȱIfȱtheȱ -fȱoptionȱisȱgiven,ȱtheȱchecksumȱisȱwrittenȱtoȱaȱfileȱinsteadȱ ofȱtheȱstandardȱoutput.ȱTheȱnameȱofȱtheȱfileȱshouldȱbeȱ file.cksȱwhereȱ fileȱisȱtheȱ inputȱ fileȱ name.ȱ Thisȱ optionȱ isȱ illegalȱ whenȱ readingȱ fromȱ theȱ standardȱ inputȱ becauseȱthereȱisnȇtȱanȱinputȱfileȱname.ȱ Belowȱ areȱ aȱ fewȱ sampleȱ runsȱ ofȱ theȱ program.ȱ Theyȱ areȱ validȱ forȱ systemsȱ thatȱ useȱ ASCIIȱ characters.ȱ Theȱ fileȱ hwȱ containsȱ theȱ lineȱ ȈHelloȱ World!Ȉȱ followedȱ byȱ aȱ newline.ȱ Theȱ fileȱ hw2ȱ containsȱ twoȱ suchȱ lines.ȱ Noneȱ ofȱ theȱ inputȱ containsȱ anyȱ trailingȱblanksȱorȱtabs.ȱ ȱ $sum hi ^D 219 %sum hw 1095 $sum –f -f illegal when reading standard input $sum –f hw2 $ ȱ (fileȱhw2.cksȱnowȱcontainsȱ2190)ȱ ȱ 11. Writeȱaȱprogramȱtoȱkeepȱtrackȱofȱanȱinventoryȱofȱpartsȱandȱtheirȱvalue.ȱEachȱpartȱ hasȱaȱdescriptionȱthatȱmayȱbeȱfromȱ1ȱtoȱ20ȱcharactersȱinȱlength.ȱWhenȱaȱnewȱpartȱisȱ addedȱtoȱtheȱinventory,ȱitȱisȱassignedȱtheȱnextȱavailableȱpartȱnumber.ȱTheȱfirstȱpartȱ numberȱisȱ1.ȱTheȱprogramȱshouldȱstoreȱtheȱquantityȱonȱhandȱandȱtheȱtotalȱvalueȱforȱ eachȱpart.ȱ Theȱprogramȱshouldȱtakeȱaȱsingleȱargumentȱfromȱtheȱcommandȱline,ȱwhichȱisȱ theȱnameȱofȱtheȱinventoryȱtile.ȱIfȱtheȱfileȱdoesȱnotȱexist,ȱanȱemptyȱinventoryȱfileȱisȱ created.ȱ Theȱ programȱ thenȱ promptsȱ forȱ transactionsȱ andȱ processesȱ themȱ oneȱ byȱ one.ȱ Theȱfollowingȱtransactionsȱareȱallowed.ȱ ȱ new description, quantity, cost-each ȱ Theȱ newȱ transactionȱ entersȱ aȱ newȱ partȱ intoȱ theȱ system.ȱ descriptionȱ isȱ theȱ descriptionȱofȱtheȱpart,ȱwhichȱmayȱnotȱbeȱlongerȱthanȱ20ȱcharacters.ȱquantityȱisȱtheȱ numberȱofȱpartsȱinitiallyȱplacedȱintoȱinventory;ȱitȱmayȱnotȱbeȱnegative.ȱcost-eachȱisȱ theȱcostȱofȱeachȱpart.ȱItȱisȱnotȱanȱerrorȱforȱaȱnewȱpartȱtoȱhaveȱtheȱsameȱdescriptionȱ Download at http://www.pin5i.com/ 15.21 Programming Exercisesȱ 451 asȱ anȱ existingȱ part.ȱ Theȱ programȱ mustȱ computeȱ andȱ saveȱ theȱ totalȱ valueȱ ofȱ theseȱ parts.ȱTheȱnextȱavailableȱpartȱnumberȱisȱassignedȱtoȱeachȱnewȱpart.ȱPartȱnumbersȱ startȱatȱ1ȱandȱincreaseȱsequentially.ȱTheȱnumbersȱofȱdeletedȱpartsȱarcȱreusedȱwhenȱ newȱpartsȱareȱentered.ȱ ȱ buy part-number,quantity,cost-each ȱ Theȱ buyȱ transactionȱ addsȱ additionalȱ unitsȱ toȱ anȱ existingȱ partȱ inȱ inventory.ȱ partnumberȱisȱtheȱnumberȱofȱtheȱpart,ȱ quantityȱisȱtheȱnumberȱofȱpartsȱobtainedȱ(whichȱ mayȱnotȱbeȱnegative),ȱandȱ cost-eachȱisȱtheȱcostȱofȱeachȱofȱtheȱparts.ȱTheȱprogramȱ shouldȱ addȱ theȱ quantityȱ andȱ theȱ totalȱ valueȱ ofȱ theȱ newȱ partsȱ toȱ theȱ existingȱ inventory.ȱ ȱ sell part-number,quantity,price-each ȱ Theȱsellȱtransactionȱremovesȱunitsȱfromȱanȱexistingȱpartȱinȱinventory.ȱpart-numberȱ isȱtheȱnumberȱofȱtheȱpart,ȱ quantityȱisȱtheȱnumberȱofȱpartsȱsoldȱ(whichȱmayȱnotȱbeȱ negativeȱorȱlargerȱthanȱtheȱquantityȱonȱhand),ȱandȱprice-eachȱisȱtheȱpriceȱobtainedȱ forȱ eachȱ ofȱ theȱ partsȱ sold.ȱ Theȱ programȱ shouldȱ subtractȱ thisȱ quantityȱ fromȱ theȱ inventoryȱ andȱ reduceȱ theȱ totalȱ valueȱ forȱ thisȱ partȱ byȱ theȱ numberȱ sold.ȱ ȱ Itȱ shouldȱ thenȱ computeȱ theȱ profitȱ forȱ theȱ saleȱ asȱ theȱ differenceȱ betweenȱ theȱ priceȱ obtainedȱ andȱtheȱinventoryȱvalueȱforȱtheȱpartsȱsold.ȱ ȱ delete part-number ȱ Thisȱtransactionȱdeletesȱtheȱspecifiedȱpartȱfromȱtheȱinventoryȱfile.ȱ ȱ print part-number ȱ Thisȱtransactionȱprintsȱinformationȱforȱtheȱspecifiedȱpartȱincludingȱtheȱdescription,ȱ quantityȱonȱhand,ȱandȱtotalȱvalueȱofȱthoseȱparts.ȱ ȱ print all ȱ Thisȱtransactionȱprintsȱinformationȱforȱallȱpartsȱinȱinventoryȱinȱaȱtabularȱform.ȱ ȱ total ȱ Thisȱtransactionȱcomputesȱandȱprintsȱtheȱtotalȱvalueȱofȱallȱpartsȱinȱinventory.ȱ ȱ end ȱ Thisȱtransactionȱterminatesȱexecutionȱofȱtheȱprogram.ȱ Computingȱtheȱtrueȱvalueȱofȱanȱinventoryȱwhenȱpartsȱareȱobtainedȱatȱdifferentȱ costsȱisȱcomplexȱandȱdependsȱonȱwhetherȱtheȱcheapestȱorȱmostȱexpensiveȱpartsȱareȱ usedȱfirst.ȱTheȱmethodȱusedȱbyȱthisȱprogramȱisȱsimple:ȱOnlyȱtheȱtotalȱvalueȱofȱeachȱ typeȱofȱ partȱisȱkept,ȱandȱallȱunitsȱ ofȱoneȱ particularȱpartȱ areȱ consideredȱ equal.ȱ Forȱ example,ȱ supposeȱ 10ȱ paperȱ clipsȱ areȱ initiallyȱ purchasedȱ forȱ $1.00ȱ each.ȱ Theȱ totalȱ valueȱofȱthisȱinventoryȱisȱ$10.00.ȱLater,ȱ10ȱmoreȱpaperȱclipsȱareȱpurchasedȱforȱ$1.25ȱ Download at http://www.pin5i.com/ Chapter 15 Input/Output Functionsȱ 452ȱ each,ȱbringingȱtheȱtotalȱvalueȱofȱtheȱinventoryȱtoȱ$22.50.ȱAtȱthisȱpoint,ȱeachȱpaperȱ clipȱ isȱ valuedȱ atȱ $1.125.ȱ Noȱ recordȱ isȱ keptȱ ofȱ theȱ individualȱ batchesȱ evenȱ thoughȱ theyȱ wereȱ purchasedȱ atȱ differentȱ prices.ȱ Whenȱ paperȱ clipsȱ areȱ sold,ȱ theȱ profitȱ isȱ computedȱbasedȱonȱtheirȱcurrentȱvalueȱasȱcalculatedȱabove.ȱ Hereȱ areȱ someȱ hintsȱ onȱ designingȱ theȱ program.ȱ First,ȱ useȱ theȱ partȱ numberȱ toȱ determineȱwhereȱinȱtheȱinventoryȱfileȱaȱpartȱisȱwritten.ȱTheȱfirstȱpanȱnumberȱisȱ1,ȱsoȱ theȱ locationȱ inȱ theȱ inventoryȱ fileȱ whereȱ partȱ numberȱ 0ȱ wouldȱ goȱ canȱ beȱ usedȱ toȱ storeȱ otherȱ information.ȱ Second,ȱ youȱ canȱ detectȱ deletedȱ partsȱ byȱ settingȱ theirȱ descriptionȱtoȱtheȱemptyȱstring.ȱ ȱ Download at http://www.pin5i.com/ 16 Standard Library TheȱStandardȱLibraryȱisȱaȱtoolkitȱthatȱgreatlyȱexpandsȱtheȱpowerȱofȱtheȱCȱprogrammer.ȱ Beforeȱ youȱ canȱ useȱ thisȱ power,ȱ however,ȱ youȱ mustȱ becomeȱ familiarȱ withȱ theȱ libraryȱ functions.ȱ Neglectingȱ theȱ libraryȱ isȱ likeȱ onlyȱ learningȱ howȱ toȱ useȱ theȱ gasȱ pedal,ȱ steeringȱ wheel,ȱ andȱ brakeȱ inȱ yourȱ carȱ butȱ notȱ botheringȱ toȱ learnȱ aboutȱ theȱ cruiseȱ control,ȱradio,ȱandȱairȱconditioning.ȱȱYouȱmayȱbeȱableȱtoȱgetȱwhereȱyouȱwantȱtoȱgo,ȱbutȱ itȱwillȱbeȱharderȱandȱwonȇtȱbeȱasȱmuchȱfun.ȱ Thisȱ chapterȱ describesȱ theȱ libraryȱ functionsȱ thatȱ haveȱ notȱ beenȱ coveredȱ inȱ previousȱchapters.ȱTheȱsectionȱtitlesȱincludeȱtheȱfileȱnameȱthatȱyouȱneedȱtoȱ#includeȱtoȱ obtainȱtheȱfunctionȱprototypes.ȱ ȱ ȱ ȱ 16.1 Integer Functions ȱ Thisȱ groupȱ ofȱ functionsȱ returnȱ integerȱ values.ȱ Theȱ functionsȱ fallȱ intoȱ threeȱ families:ȱ arithmetic,ȱrandomȱnumbers,ȱandȱstringȱconversion.ȱ ȱ ȱ 16.1.1 Arithmetic <stdlib.h> ȱ Theȱlibraryȱincludesȱfourȱintegerȱarithmeticȱfunctions.]ȱ ȱ int abs( int value ); long int labs( long int value ); div_t div( int numerator, int denominator ); ldiv_t ldiv( long int numer, long int denom ); ȱ Theȱ absȱ functionȱ returnsȱ theȱ absoluteȱ valueȱ ofȱ itsȱ argument.ȱ Ifȱ theȱ resultȱ cannotȱ beȱ representedȱasȱanȱinteger,ȱtheȱbehaviorȱisȱundefined.ȱlabsȱdoesȱtheȱsameȱworkȱforȱlongȱ integerȱvalues.ȱ Download at http://www.pin5i.com/ Chapter 16 Standard Libraryȱ 454ȱ Theȱ divȱ functionȱ dividesȱ theȱ firstȱ argumentȱ (theȱ numerator)ȱ byȱ theȱ secondȱ argumentȱ (theȱ denominator)ȱ andȱ producesȱ aȱ quotientȱ andȱ aȱ remainderȱ thatȱ areȱ returnedȱinȱaȱdiv_tȱstructure.ȱȱThisȱstructureȱcontainsȱtheȱfieldsȱ ȱ int quot; int rem; ȱ thoughȱnotȱnecessarilyȱinȱthisȱorder.ȱIfȱtheȱdivisionȱisȱnotȱeven,ȱtheȱquotientȱwillȱbeȱtheȱ integerȱ ofȱ smallerȱ magnitudeȱ thatȱ isȱ nearestȱ toȱ theȱ algebraicȱ quotient.ȱ Noteȱ thatȱ theȱ resultsȱofȱdivisionȱwithȱtheȱ /ȱoperatorȱareȱnotȱasȱpreciselyȱdefined.ȱWhenȱeitherȱofȱtheȱ operandsȱ ofȱ /ȱ areȱ negativeȱ andȱ theȱ resultȱ isȱ notȱ exact,ȱ itȱ isȱ implementationȱ definedȱ whetherȱtheȱquotientȱisȱtheȱlargestȱintegerȱlessȱthanȱorȱequalȱtoȱtheȱalgebraicȱquotientȱ orȱ theȱ smallestȱ integerȱ greaterȱ thanȱ orȱ equalȱ toȱ theȱ algebraicȱ quotient.ȱ ldivȱ doesȱ theȱ sameȱworkȱforȱlongȱintegerȱvaluesȱandȱreturnsȱanȱldiv_tȱstructure.ȱ ȱ ȱ ȱ 16.1.2 Random Numbers <stdlib.h> ȱ Randomȱ numbersȱ areȱ usefulȱ inȱ programsȱ thatȱ shouldȱ notȱ produceȱ theȱ sameȱ resultsȱ everyȱtimeȱtheyȱareȱexecuted,ȱsuchȱasȱgamesȱandȱsimulations.ȱTogether,ȱtheȱfollowingȱ twoȱ functionsȱ produceȱ pseudoȬrandomȱ numbers,ȱ soȱ calledȱ becauseȱ theyȱ areȱ computedȱ andȱthereforeȱrepeatable,ȱandȱthusȱnotȱtrulyȱrandom.ȱ ȱ int rand( void ); void srand( unsigned int seed ); ȱ randȱreturnsȱaȱpseudoȬrandomȱnumberȱinȱtheȱrangeȱzeroȱtoȱ RAND_MAXȱ(whichȱmustȱbeȱ atȱ leastȱ 32,767).ȱ Whenȱ calledȱ repeatedly,ȱ theȱ functionȱ returnsȱ otherȱ numbersȱ inȱ thisȱ range.ȱȱToȱobtainȱnumbersȱfromȱaȱsmallerȱrange,ȱfirstȱtakeȱtheȱrandomȱnumberȱmoduloȱ theȱsizeȱofȱtheȱdesiredȱrange,ȱthenȱscaleȱitȱbyȱaddingȱorȱsubtractingȱanȱoffsetȱasȱneeded.ȱ Toȱ preventȱ theȱ randomȱ numberȱsequenceȱ fromȱ beingȱ theȱ sameȱeveryȱ timeȱ theȱ programȱ isȱ run,ȱ theȱ srandȱ functionȱ mayȱ beȱ called.ȱ Itȱ initializesȱ theȱ randomȱ numberȱ generatorȱ withȱ theȱ valueȱ passedȱ asȱ itsȱ argument.ȱ Aȱ commonȱ techniqueȱ isȱ toȱ useȱ theȱ timeȱofȱdayȱtoȱseedȱtheȱrandomȱnumberȱgenerator,ȱasȱinȱthisȱexample:ȱ ȱ srand( (unsigned int)time( 0 ) ); ȱ Theȱtimeȱfunctionȱisȱdescribedȱlaterȱinȱthisȱchapter.ȱ TheȱfunctionȱinȱProgramȱ16.1ȱusesȱintegersȱtoȱrepresentȱplayingȱcardsȱandȱusesȱ randomȱnumbersȱtoȱȈshuffleȈȱtheȱspecifiedȱnumberȱofȱcardsȱinȱtheȱȈdeck.Ȉȱ Download at http://www.pin5i.com/ 16.1 Integer Functionsȱ 455 ȱ /* ** Use random numbers to shuffle the "cards" in the deck. The second ** argument indicates the number of cards. The first time this ** function is called, srand is called to initialize the random ** number generator. */ #include <stdlib.h> #include <time.h> #define TRUE 1 #define FALSE 0 void shuffle( int *deck, int n_cards ) { int i; static int first_time = TRUE; /* ** Seed the random number generator with the current time ** of day if we haven't done so yet. */ if( first_time ){ first_time = FALSE; srand( (unsigned int)time( NULL ) ); } /* ** "Shuffle" by interchanging random pairs of cards. */ for( i = n_cards - 1; i > 0; i -= 1 ){ int where; int temp; where = rand() % i; temp = deck[ where ]; deck[ where ] = deck[ i ]; deck[ i ] = temp; } } ȱ Programȱ16.1ȱȱShufflingȱplayingȱcardsȱwithȱrandomȱnumbersȱȱ ȱ ȱ ȱ ȱ ȱ ȱ 16.1.3 ȱ ȱ ȱȱȱȱȱȱshuffle.cȱ String Conversion <stdlib.h> ȱ Theȱ stringȱ conversionȱ functionsȱ convertȱ characterȱ stringsȱ toȱ numericȱ values.ȱ Theȱ simplestȱones,ȱatoiȱandȱatol,ȱperformȱbaseȱ10ȱconversions.ȱstrtolȱandȱstrtoulȱallowȱ Download at http://www.pin5i.com/ 456ȱ Chapter 16 Standard Libraryȱ youȱ toȱ specifyȱ theȱ baseȱ forȱ theȱ conversion,ȱ andȱ theyȱ alsoȱ giveȱ youȱ accessȱ toȱ theȱ remainingȱpartȱofȱtheȱstring.ȱ ȱ int atoi( char const *string ); long int atol( char const *string ); long int strtol( char const *string, char **unused, int base ); unsigned long int strtoul( char const *string, char **unused, int base ); ȱ Ifȱtheȱfirstȱargumentȱtoȱanyȱofȱtheseȱfunctionsȱcontainsȱleadingȱwhiteȱspaceȱcharacters,ȱ theyȱareȱskipped.ȱTheȱfunctionsȱthenȱconvertȱlegalȱcharactersȱtoȱtheȱindicatedȱtypeȱofȱ value.ȱIfȱthereȱareȱanyȱtrailingȱillegalȱcharacters,ȱtheyȱareȱignored.ȱ atoiȱ andȱ atolȱ convertȱ charactersȱ toȱ integerȱ andȱ longȱ integerȱ values,ȱ respectively.ȱ strtolȱ convertsȱ theȱ argumentȱ stringȱ toȱ aȱ longȱ inȱ theȱ sameȱ mannerȱ asȱ atol.ȱ However,ȱ strtolȱ savesȱ aȱ pointerȱ toȱ theȱ firstȱ characterȱ inȱ theȱ stringȱ afterȱ theȱ convertedȱ value.ȱ Ifȱ theȱ secondȱ argumentȱ toȱ theȱ functionȱ isȱ notȱ NULL,ȱ theȱ savedȱ pointerȱisȱstoredȱinȱtheȱlocationȱpointedȱtoȱbyȱtheȱsecondȱargument.ȱTheȱpointerȱallowsȱ theȱ remainderȱ ofȱ theȱ stringȱ toȱ beȱ processedȱ withoutȱ havingȱ toȱ guessȱ whereȱ theȱ conversionȱstopped.ȱȱ strtoulȱbehavesȱinȱtheȱsameȱmannerȱbutȱproducesȱanȱunsignedȱ longȱinstead.ȱ Theȱ thirdȱ argumentȱ toȱ bothȱ ofȱ theseȱ functionsȱ isȱ theȱ baseȱ withȱ whichȱ theȱ conversionȱ isȱ performed.ȱ Ifȱ theȱ baseȱ isȱ 0,ȱ anyȱ ofȱ theȱ formsȱ usedȱ forȱ writingȱ integerȱ literalsȱ inȱ aȱ programȱ areȱ accepted,ȱ includingȱ theȱ formsȱ thatȱ specifyȱ theȱ baseȱ ofȱ theȱ number,ȱsuchȱasȱ 0x2af4ȱandȱ 0377.ȱOtherwise,ȱtheȱbaseȱmayȱbeȱaȱvalueȱinȱtheȱrangeȱ2ȱ throughȱ 36—theȱ conversionȱ isȱ thenȱ performedȱ withȱ theȱ givenȱ base.ȱ Forȱ basesȱ 11ȱ throughȱ 36,ȱ theȱ charactersȱ Aȱ throughȱ Zȱ areȱ interpretedȱ asȱ digitsȱ withȱ valuesȱ 10ȱ throughȱ35,ȱrespectively.ȱȱLowercaseȱcharactersȱaȱthroughȱzȱareȱinterpretedȱtheȱsameȱasȱ uppercaseȱcharactersȱinȱthisȱcontext.ȱThus,ȱ ȱ x = strtol( " 590bear", next, 12 ); ȱ wouldȱreturnȱtheȱvalueȱ9947ȱandȱstoreȱaȱpointerȱtoȱtheȱletterȱeȱinȱtheȱvariableȱthatȱnextȱ pointsȱ to.ȱ Theȱ conversionȱ stopsȱ withȱ bȱ becauseȱ eȱ isȱ notȱ aȱ validȱ digitȱ forȱ aȱ baseȱ 12ȱ number.ȱ Ifȱtheȱstringȱargumentȱtoȱanyȱofȱtheseȱfunctionsȱdoesȱnotȱcontainȱaȱlegalȱnumericȱ value,ȱ thenȱ 0ȱ isȱ returned.ȱ Ifȱ theȱ convertedȱ valueȱ cannotȱ beȱ represented,ȱ theȱ valueȱ ERANGEȱisȱstoredȱinȱerrno,ȱandȱoneȱofȱtheȱvaluesȱinȱTableȱ16.1ȱisȱreturned.ȱ Download at http://www.pin5i.com/ 16.2 Floating-Point Functionsȱ 457 Function Returns strol LONG_MINȱifȱtheȱvalueȱisȱtooȱlargeȱandȱnegative,ȱorȱLONG_MAXȱifȱtheȱ strtoul valueȱisȱtooȱlargeȱandȱpositive.ȱ ULONG_MAXȱifȱtheȱvalueȱisȱtooȱlarge.ȱ ȱ Tableȱ16.1ȱErrorȱvaluesȱreturnedȱbyȱstrtolȱandȱstrtoulȱ ȱ ȱ ȱ 16.2 Floating-Point Functions CAUTION! ȱ Theȱheaderȱfileȱ math.hȱcontainsȱdeclarationsȱforȱtheȱremainingȱmathematicalȱfunctionsȱ inȱtheȱlibrary.ȱTheȱreturnȱvaluesȱfromȱtheseȱfunctionsȱandȱmostȱofȱtheirȱargumentsȱareȱ double.ȱ ȱ Aȱcommonȱsourceȱofȱerrorȱisȱtoȱomitȱtheȱheaderȱfileȱwhenȱusingȱtheseȱfunctions,ȱlikeȱ this:ȱ ȱ double x; x = sqrt( 5.5 ); ȱ Theȱ compiler,ȱ neverȱ havingȱ seenȱ aȱ prototypeȱ forȱ sqrt,ȱ mistakenlyȱ assumesȱ thatȱ itȱ returnsȱanȱintegerȱandȱerroneouslyȱconvertsȱtheȱvalueȱtoȱdouble.ȱTheȱresultingȱvalueȱisȱ meaningless.ȱ Aȱ domainȱ errorȱ occursȱ ifȱ theȱ argumentȱ toȱ aȱ functionȱ isȱ notȱ withinȱ theȱ domainȱ definedȱforȱthatȱfunction.ȱForȱexample,ȱ ȱ sqrt( -5.0 ); ȱ isȱ aȱ domainȱ errorȱ becauseȱ squareȱ rootȱ isȱ undefinedȱ forȱ negativeȱ numbers.ȱ Whenȱ aȱ domainȱ errorȱ occurs,ȱ theȱ functionȱ returnsȱ anȱ errorȱ valueȱ definedȱ byȱ theȱ implementation,ȱandȱtheȱvalueȱ EDOMȱisȱstoredȱinȱerrno.ȱAȱrangeȱerrorȱoccursȱifȱtheȱresultȱ ofȱaȱfunctionȱisȱtooȱlargeȱorȱtooȱsmallȱtoȱbeȱrepresentedȱinȱaȱdouble.ȱForȱexample,ȱ ȱ exp( DBL_MAX ) ȱ willȱproduceȱaȱrangeȱerrorȱbecauseȱitsȱresultȱisȱtooȱlarge.ȱInȱthisȱcase,ȱtheȱfunctionȱwillȱ returnȱ HUGE_VAL,ȱaȱ doubleȱvalueȱthatȱisȱdefinedȱinȱ math.h.ȱȱIfȱtheȱresultȱofȱaȱfunctionȱisȱ tooȱsmallȱtoȱbeȱrepresentedȱinȱaȱdouble,ȱthenȱtheȱfunctionȱwillȱreturnȱzeroȱinstead.ȱThisȱ caseȱisȱalsoȱaȱrangeȱerror,ȱbutȱitȱisȱimplementationȱdependentȱwhetherȱ errnoȱisȱsetȱtoȱ ERANGEȱinȱthisȱcase.ȱ Download at http://www.pin5i.com/ Chapter 16 Standard Libraryȱ 458ȱ 16.2.1 Trigonometry <math.h> ȱ Theȱusualȱtrigonometryȱfunctionsȱareȱprovided.ȱ ȱ double double double double double double double sin( double angle ); cos( double angle ); tan( double angle ); asin( double value ); acos( double value ); atan( double value ); atan2( double x, double y ); ȱ Theȱargumentȱtoȱ sin,ȱ cos,ȱandȱtanȱisȱanȱangleȱinȱradians;ȱtheȱfunctionsȱreturnȱtheȱsine,ȱ cosine,ȱandȱtangentȱofȱtheȱangle,ȱrespectively.ȱ Theȱ asin,ȱ acos,ȱ andȱ atanȱ functionsȱ returnȱ theȱ arcȱ sine,ȱ arcȱ cosine,ȱ andȱ arcȱ tangentȱofȱtheirȱargument,ȱrespectively.ȱAȱdomainȱerrorȱwillȱoccurȱifȱtheȱargumentȱtoȱ asinȱorȱ acosȱisȱnotȱinȱtheȱrangeȱȬ1ȱtoȱ1.ȱȱ asinȱandȱ atanȱreturnȱaȱvalueȱinȱtheȱrangeȱȬΔ/2ȱ toȱΔ/2ȱradians,ȱandȱacosȱreturnsȱaȱvalueȱinȱtheȱrangeȱ0ȱtoȱΔȱradians.ȱ Theȱ atan2ȱ functionȱ returnsȱ theȱ arcȱ tangentȱ ofȱ theȱ expressionȱ y/xȱ butȱ usesȱ theȱ signsȱofȱbothȱargumentsȱtoȱdetermineȱwhichȱquadrantȱtheȱresultȱliesȱwithin.ȱItȱreturnsȱ aȱresultȱinȱtheȱrangeȱȬȱΔȱtoȱΔȱradians.ȱ ȱ ȱ ȱ 16.2.2 Hyperbolic <math.h> ȱ double sinh( double angle ); double cosh( double angle ); double tanh( double angle ); ȱ Theseȱfunctionsȱreturnȱtheȱhyperbolicȱsine,ȱhyperbolicȱcosine,ȱandȱhyperbolicȱtangentȱ ofȱtheirȱargument,ȱrespectively.ȱTheȱargumentȱtoȱeachȱisȱanȱangleȱinȱradians.ȱ ȱ ȱ ȱ 16.2.3 Logarithm and Exponent <math.h> ȱ Thereȱareȱthreeȱfunctionsȱthatȱdealȱdirectlyȱwithȱlogarithmsȱandȱexponents.ȱ ȱ double exp( double x ); double log( double x ); double log10( double x ); Download at http://www.pin5i.com/ 16.2 Floating-Point Functionsȱ 459 ex Theȱexpȱfunctionȱreturnsȱtheȱvalueȱeȱraisedȱtoȱtheȱpowerȱgivenȱbyȱtheȱargument,ȱorȱȱȱȱ.ȱ Theȱlogȱfunctionȱreturnsȱtheȱbaseȱeȱlogarithmȱofȱitsȱargument,ȱalsoȱknownȱasȱtheȱ naturalȱ logarithm.ȱ Theȱ logl0ȱ functionȱ returnsȱ theȱ baseȱ 10ȱ logarithmȱ ofȱ itsȱ argument.ȱ Noteȱthatȱtheȱlogȱofȱaȱnumberȱxȱtoȱanȱarbitraryȱbaseȱbȱmayȱbeȱcomputedȱlikeȱthis:ȱ ȱ log e x log b x log e b ȱ ȱ Aȱdomainȱerrorȱoccursȱforȱbothȱlogȱfunctionsȱifȱtheȱargumentȱisȱnegative.ȱ ȱ ȱ ȱ 16.2.4 Floating-point Representation <math.h> ȱ Theseȱ threeȱ functionsȱ provideȱ aȱ wayȱ toȱ storeȱ floatingȬpointȱ valuesȱ inȱ anȱ implementationȬindependentȱformat.ȱ ȱ double frexp( double value, int *exponent ); double ldexp( double fraction, int exponent ); double modf( double value, double *ipart ); ȱ Theȱ frexpȱ functionȱ computesȱ anȱ exponentȱ andȱ aȱ fractionȱ suchȱ thatȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ fraction u 2 exponent value , whereȱ 0.5 d fraction 1 andȱ exponentȱ isȱ anȱ integer.ȱ Theȱ exponentȱisȱstoredȱinȱtheȱlocationȱpointedȱtoȱbyȱtheȱsecondȱargumentȱandȱtheȱfunctionȱ returnsȱ theȱ fraction.ȱ Theȱ relatedȱ functionȱ ldexpȱ returnsȱ theȱ valueȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ fractionu 2 exponent ,whichȱisȱtheȱoriginalȱvalue.ȱTheseȱfunctionsȱareȱveryȱusefulȱwhenȱyouȱ mustȱ passȱ floatingȬpointȱ numbersȱ amongȱ machinesȱ withȱ incompatibleȱ floatingȬpointȱ formats.ȱ TheȱmodfȱfunctionȱbreaksȱaȱfloatingȬpointȱvalueȱintoȱintegerȱandȱfractionalȱparts,ȱ eachȱhavingȱtheȱsameȱsignȱasȱtheȱoriginalȱvalue.ȱTheȱintegerȱpartȱisȱstoredȱasȱaȱ doubleȱ inȱtheȱlocationȱpointedȱtoȱbyȱtheȱsecondȱargument,ȱandȱtheȱfractionalȱpartȱisȱreturnedȱ asȱtheȱfunctionȱvalue.ȱ ȱ ȱ ȱ 16.2.5 Power <math.h> ȱ Thereȱareȱtwoȱfunctionsȱinȱthisȱfamily.ȱ ȱ double pow( double x, double y ); double sqrt( double x ); Download at http://www.pin5i.com/ Chapter 16 Standard Libraryȱ 460ȱ Theȱ powȱfunctionȱreturnsȱtheȱvalueȱxy.ȱBecauseȱlogarithmsȱmayȱbeȱusedȱinȱcomputingȱ thisȱvalue,ȱaȱdomainȱerrorȱoccursȱifȱxȱisȱnegativeȱandȱyȱisȱnotȱanȱintegralȱvalue.ȱȱ Theȱ sqrtȱ functionȱ returnsȱ theȱ squareȱ rootȱ ofȱ itsȱ argument.ȱ Aȱ domainȱ errorȱ occursȱifȱtheȱargumentȱisȱnegative.ȱ ȱ ȱ ȱ 16.2.6 Floor, Ceiling, Absolute Value, and Remainder <math.h> ȱ Theȱprototypesȱforȱtheseȱfunctionsȱareȱshownȱbelow.ȱ ȱ double double double double floor( double x ); ceil( double x ); fabs( double x ); fmod( double x, double y ); ȱ Theȱ floorȱ functionȱ returnsȱ theȱ largestȱ integralȱ valueȱ thatȱ isȱ notȱ greaterȱ thanȱ itsȱ argument.ȱ Thisȱ valueȱ isȱ returnedȱ asȱ aȱ doubleȱ dueȱ toȱ theȱ greatlyȱ increasedȱ rangeȱ ofȱ doublesȱoverȱintegers.ȱTheȱ ceilȱfunctionȱreturnsȱtheȱsmallestȱintegralȱvalueȱthatȱisȱnotȱ lessȱthanȱitsȱargument.ȱ fabsȱreturnsȱ theȱabsoluteȱvalueȱofȱitsȱargument.ȱ Theȱ fmodȱfunctionȱreturnsȱ theȱ remainderȱ thatȱ resultsȱ whenȱ xȱ isȱ dividedȱ byȱ y,ȱ andȱ theȱ quotientȱ isȱ restrictedȱ toȱ anȱ integralȱvalue.ȱ ȱ ȱ ȱ 16.2.7 String Conversion <stdlib.h> ȱ Theseȱfunctionsȱareȱsimilarȱtoȱtheȱintegerȱstringȱconversionȱfunctionsȱexceptȱthatȱtheyȱ returnȱfloatingȬpointȱvalues.ȱ ȱ double atof( char const *string ); double strtod( char const *string, char **unused ); ȱ Ifȱ theȱ argumentȱ toȱ eitherȱ ofȱ theseȱ functionsȱ containsȱ leadingȱ whiteȱ spaceȱ characters,ȱ theyȱareȱskipped.ȱTheȱfunctionsȱthenȱconvertȱlegalȱcharactersȱtoȱaȱdouble,ȱignoringȱanyȱ trailingȱ illegalȱ characters.ȱ Bothȱ functionsȱ acceptȱ allȱ ofȱ theȱ formsȱ usedȱ forȱ writingȱ floatingȬpointȱliteralsȱinȱaȱprogram.ȱ strtodȱ convertsȱ theȱ argumentȱ stringȱ toȱ aȱ doubleȱ inȱ theȱ sameȱ mannerȱ asȱ atof.ȱȱ However,ȱstrtodȱsavesȱaȱpointerȱtoȱtheȱfirstȱcharacterȱinȱtheȱstringȱafterȱtheȱconvertedȱ Download at http://www.pin5i.com/ 16.3 Date and Time Functionsȱ 461 value.ȱIfȱtheȱsecondȱargumentȱtoȱtheȱfunctionȱisȱnotȱNULL,ȱtheȱsavedȱpointerȱisȱstoredȱ inȱtheȱlocationȱpointedȱtoȱbyȱtheȱsecondȱargument.ȱTheȱpointerȱallowsȱtheȱremainderȱ ofȱtheȱstringȱtoȱbeȱprocessedȱwithoutȱhavingȱtoȱguessȱwhereȱtheȱconversionȱstopped.ȱ Ifȱ theȱ stringȱ argumentȱ toȱ eitherȱ ofȱ theseȱ functionsȱ doesȱ notȱ containȱ aȱ legalȱ numericȱvalue,ȱthenȱzeroȱisȱreturned.ȱIfȱtheȱconvertedȱvalueȱisȱtooȱlargeȱorȱsmallȱtoȱbeȱ represented,ȱtheȱvalueȱERANGEȱisȱstoredȱinȱerrno.ȱHUGE_VALȱisȱreturnedȱifȱtheȱvalueȱisȱtooȱ largeȱ(eitherȱpositiveȱorȱnegative),ȱandȱzeroȱisȱreturnedȱifȱitȱisȱtooȱsmall.ȱ ȱ ȱ ȱ 16.3 Date and Time Functions ȱ Theȱlibraryȱoffersȱaȱlargeȱcollectionȱofȱfunctionsȱthatȱsimplifyȱdealingȱwithȱdatesȱandȱ times.ȱTheirȱprototypesȱareȱfoundȱinȱtime.h.ȱ ȱ ȱ ȱ 16.3.1 Processor Time <time.h. ȱ Theȱ clockȱfunctionȱreturnsȱtheȱamountȱofȱprocessorȱtimeȱusedȱbyȱtheȱprogramȱsinceȱitȱ beganȱexecuting.ȱ ȱ clock_t clock( void ); ȱ Noteȱthatȱthisȱvalueȱmayȱbeȱanȱapproximation.ȱIfȱaȱmoreȱpreciseȱvalueȱisȱrequired,ȱcallȱ clockȱ atȱ theȱ veryȱ beginningȱ ofȱ yourȱ mainȱ functionȱ andȱ subtractȱ theȱ valueȱ obtainedȱ thereȱfromȱanyȱfutureȱvalueȱreturnedȱbyȱ clock.ȱIfȱtheȱimplementationȱcannotȱprovideȱ theȱprocessorȱtime,ȱorȱifȱtheȱtimeȱisȱtooȱlargeȱtoȱbeȱrepresentedȱinȱaȱ clock_tȱvariable,ȱ theȱvalueȱ-1ȱisȱreturned,ȱ clockȱreturnsȱaȱnumberȱthatȱisȱimplementationȱdefined;ȱusuallyȱitȱisȱtheȱnumberȱ CAUTION! ofȱtimesȱtheȱprocessorȇsȱclockȱhasȱticked.ȱToȱconvertȱtheȱvalueȱtoȱseconds,ȱdivideȱitȱbyȱ theȱconstantȱCLOCKS_PER_SEC.ȱ ȱ Onȱ someȱ implementations,ȱ thisȱ functionȱ mayȱ onlyȱ returnȱ anȱ approximationȱ ofȱ theȱ processorȱ timeȱ used.ȱ Ifȱ theȱ hostȱ operatingȱ systemȱ isȱ incapableȱ ofȱ trackingȱ processorȱ time,ȱ itȱ mayȱ returnȱ theȱ amountȱ ofȱ realȱ timeȱ thatȱ hasȱ elapsedȱ instead.ȱ Thisȱ behaviorȱ mayȱalsoȱoccurȱwithȱsimpleȱoperatingȱsystemsȱthatȱcannotȱrunȱmoreȱthanȱoneȱprogramȱ atȱ aȱ time.ȱ Oneȱ ofȱ theȱ chapterȱ exercisesȱ exploresȱ howȱ toȱ findȱ outȱ whichȱ wayȱ yourȱ systemȱbehaves.ȱ Download at http://www.pin5i.com/ Chapter 16 Standard Libraryȱ 462ȱ 16.3.2 Time of Day <time.h> ȱ Theȱtimeȱfunctionȱreturnsȱtheȱcurrentȱdateȱandȱtimeȱofȱday.ȱ ȱ time_t time( time_t *returned_value ); CAUTION! ȱ Ifȱ theȱ argumentȱ isȱ aȱ nonȬNULLȱ pointer,ȱ theȱ timeȱ valueȱ isȱ alsoȱ storedȱ throughȱ thisȱ pointer.ȱIfȱtheȱimplementationȱcannotȱprovideȱtheȱcurrentȱdateȱandȱtimeȱorȱifȱtheȱtimeȱ isȱtooȱlargeȱtoȱbeȱrepresentedȱinȱaȱtime_tȱvariable,ȱtheȱvalueȱ-1ȱisȱreturned.ȱ Theȱ mannerȱ inȱ whichȱ theȱ timeȱ isȱ encodedȱ isȱ notȱ specifiedȱ byȱ theȱ Standard,ȱ soȱ youȱ shouldȱ notȱ useȱ literalȱ constantsȱ becauseȱ theyȱ mayȱ haveȱ differentȱ meaningsȱ onȱ differentȱ implementations.ȱ Aȱ commonȱ representationȱ isȱ toȱ returnȱ theȱ numberȱ ofȱ secondsȱ thatȱ haveȱ elapsedȱ sinceȱ anȱ arbitrarilyȱ chosenȱ epoch.ȱ Onȱ MSȬDOSȱ andȱ UNIXȱ systems,ȱtheȱepochȱisȱ00:00:00ȱJanuaryȱ1,ȱ1970. 49 ȱ Itȱisȱtemptingȱtoȱcallȱ timeȱtwiceȱandȱsubtractȱtheȱvaluesȱobtainedȱtoȱdetermineȱelapsedȱ time,ȱ butȱthisȱ techniqueȱisȱdangerousȱbecauseȱtheȱStandardȱdoesȱnotȱ requireȱ thatȱtheȱ resultingȱvalueȱrepresentȱseconds.ȱ difftimeȱ(describedȱinȱtheȱnextȱsection)ȱshouldȱbeȱ usedȱforȱthisȱpurpose.ȱ ȱ ȱ ȱ Date and Time Conversions <time.h> ȱ Theȱfollowingȱfunctionsȱmanipulateȱtime_tȱvalues.ȱ ȱ char *ctime( time_t const *time_value ); double difftime( time_t time1, time_t time2 ); ȱ ctimeȱtakesȱaȱpointerȱtoȱaȱtimeȱvalueȱandȱreturnsȱaȱpointerȱtoȱaȱstringȱofȱtheȱformȱ ȱ Sun Jul 4 04:02:48 1976\n\0 ȱ Theȱ spacingȱ inȱ thisȱ stringȱ isȱ fixed.ȱ Theȱ dayȱ ofȱ theȱ monthȱ alwaysȱ takesȱ twoȱ positionsȱ evenȱifȱtheȱfirstȱisȱaȱspace,ȱandȱtwoȱdigitsȱalwaysȱappearȱforȱeachȱofȱtheȱtimeȱvalues.ȱȱ Theȱ Standardȱdoesnȇtȱmentionȱtheȱ storageȱclassȱofȱtheȱmemoryȱ containingȱ theȱ string,ȱ andȱmanyȱimplementationsȱuseȱaȱstaticȱarrayȱforȱthisȱpurpose.ȱȱThus,ȱtheȱstringȱwillȱbeȱ overwrittenȱbyȱtheȱnextȱcallȱtoȱ ctime,ȱsoȱyouȱshouldȱmakeȱaȱcopyȱofȱitȱifȱyouȱneedȱtoȱ saveȱit.ȱȱNoteȱthatȱctimeȱmayȱactuallyȱbeȱimplementedȱasȱ ȱ asctime( localtime( time_value ) ); ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱOnȱmanyȱimplementations,ȱtime_tȱisȱdefinedȱasȱaȱsigned,ȱ32Ȭbitȱquantity.ȱTheȱyearȱ2038ȱshouldȱbeȱinteresting:ȱinȱthatȱ yearȱtheȱnumberȱofȱsecondsȱsinceȱ1970ȱwillȱoverflowȱaȱtime_tȱvariable.ȱ 49 Download at http://www.pin5i.com/ 16.3 Date and Time Functionsȱ 463 Theȱdifftimeȱfunctionȱcomputesȱtheȱdifferenceȱtimel - time2ȱandȱconvertsȱtheȱ resultȱtoȱseconds;ȱnoteȱthatȱitȱreturnsȱaȱdouble.ȱ Theȱnextȱtwoȱfunctionsȱconvertȱaȱ time_tȱvalueȱintoȱaȱ struct tm,ȱwhichȱallowsȱ easierȱaccessȱtoȱtheȱcomponentsȱofȱtheȱdateȱandȱtime.ȱ ȱ struct tm *gmtime( time_t const *time_value ); struct tm *locatime( time_t const *time_value ); ȱ CAUTION! Theȱ gmtimeȱfunctionȱconvertsȱtheȱtimeȱvalueȱintoȱCoordinatedȱUniversalȱTimeȱ(UTC).ȱ UTCȱwasȱformerlyȱcalledȱGreenwichȱMeanȱTime,ȱhenceȱtheȱnameȱgmtime.ȱAsȱtheȱnameȱ implies,ȱlocaltimeȱconvertsȱaȱtimeȱvalueȱintoȱlocalȱtime.ȱTheȱStandardȱincludesȱbothȱofȱ theseȱ functionsȱ butȱ doesȱ notȱ describeȱ howȱ theȱ relationshipȱ betweenȱ UTCȱ andȱ localȱ timeȱisȱtoȱbeȱimplemented.ȱ Aȱ struct tmȱ containsȱ theȱ fieldsȱ listedȱ inȱ Tableȱ 16.2,ȱ thoughȱ notȱ necessarilyȱ inȱ theȱorderȱinȱwhichȱtheyȱareȱlisted.ȱ ȱ Theȱ mostȱ commonȱ errorȱ madeȱ whenȱ usingȱ theseȱ valuesȱ isȱ toȱ interpretȱ theȱ monthȱ incorrectly.ȱ Theseȱ valuesȱ areȱ theȱ numberȱ ofȱ monthsȱ sinceȱ January,ȱ soȱ 0ȱ representsȱ Januaryȱ andȱ 11ȱ representsȱ December.ȱ Althoughȱ notȱ intuitiveȱ atȱ first,ȱ thisȱ numberingȱ turnsȱoutȱtoȱbeȱaȱusefulȱencodingȱforȱtheȱmonthsȱbecauseȱitȱletsȱyouȱuseȱtheȱvaluesȱasȱ subscriptsȱtoȱanȱarrayȱcontainingȱtheȱmonthȱnames.ȱ ȱ ȱ ȱ ȱ Type & name Range Meaning int tm_set; 0ȱȬȱ61ȱ Secondsȱafterȱtheȱminute† int tm_min; 0ȱȬȱ59ȱ Minutesȱafterȱtheȱhourȱ int tm_hour; 0ȱȬȱ23ȱ Hoursȱafterȱmidnightȱ int tm_mday; 0ȱȬȱ31ȱ Dayȱofȱtheȱmonthȱ int tm_mon; 0ȱȬȱ11ȱ MonthsȱafterȱJanuaryȱ int tm_year; 0ȱȬȱ??ȱ Yearsȱafterȱ1900ȱ int tm_wday; 0ȱȬȱ6ȱ DaysȱafterȱSundayȱ int tm_yday; 0ȱȬȱ365ȱ DaysȱafterȱJanuaryȱ1ȱ int tm_isdst; ȱ DaylightȱSavingsȱTimeȱflagȱ ȱ † Oneȱ mustȱ admireȱ theȱ thoroughnessȱ ofȱ theȱ ANSIȱ Standardsȱ committeeȱ thatȱ formulatedȱ theȱ C++ȱstandardȱforȱmakingȱallowanceȱforȱtheȱȈleapȱsecondsȈȱthatȱareȱoccasionallyȱaddedȱtoȱtheȱ lastȱminuteȱofȱtheȱyearȱtoȱadjustȱourȱtimeȱstandardsȱtoȱtheȱEarthȇsȱslowingȱrotation.ȱ ȱ Tableȱ16.2ȱȱFieldsȱinȱaȱstruct tmȱ Download at http://www.pin5i.com/ 464ȱ CAUTION! Chapter 16 Standard Libraryȱ Theȱnextȱmostȱcommonȱerrorȱisȱtoȱforgetȱthatȱtheȱ tm_yearȱvalueȱisȱonlyȱtheȱyearsȱsinceȱ 1900.ȱȱToȱcomputeȱtheȱactualȱyear,ȱ1900ȱmustȱbeȱaddedȱtoȱtheȱvalue.ȱ Afterȱyouȱhaveȱaȱ struct tm,ȱyouȱmayȱeitherȱuseȱitsȱvaluesȱdirectly,ȱorȱyouȱmayȱ passȱitȱtoȱeitherȱofȱtheseȱfunctions.ȱ ȱ char *asctime( struct tm const*tm_ptr ); size_t strftime( char *string, size_t maxsize, char const *format, struct tm const *tm_ptr ); ȱ Theȱ asctimeȱfunctionȱconvertsȱtheȱtimeȱrepresentedȱinȱtheȱargumentȱtoȱaȱstringȱ ofȱtheȱfollowingȱform:ȱ ȱ Sun Jul 4 04:02:48 1976\n\0 ȱ Thisȱformȱisȱtheȱsameȱoneȱusedȱbyȱtheȱ ctimeȱfunction,ȱwhichȱinȱfactȱmayȱcallȱ asctimeȱ toȱperformȱitsȱwork.ȱ Theȱ strftimeȱfunctionȱconvertsȱaȱ struct tmȱintoȱaȱstringȱaccordingȱtoȱaȱformatȱ string.ȱȱThisȱfunctionȱprovidesȱtremendousȱflexibilityȱinȱformattingȱdates.ȱIfȱtheȱstringȱ resultingȱ fromȱ theȱ conversionȱ isȱ lessȱ thanȱ theȱ maxsizeȱ argument,ȱ thenȱ theȱ stringȱ isȱ copiedȱintoȱtheȱarrayȱthatȱtheȱfirstȱargumentȱpointsȱtoȱandȱ strftimeȱreturnsȱtheȱlengthȱ ofȱtheȱstring.ȱȱOtherwiseȱ0ȱisȱreturnedȱandȱtheȱarrayȱcontentsȱareȱundefined.ȱ Theȱ formatȱ stringȱ containsȱ ordinaryȱ charactersȱ andȱ formatȱ codes.ȱ Ordinaryȱ charactersȱareȱcopiedȱwhereȱtheyȱappear.ȱFormatȱcodesȱareȱreplacedȱbyȱaȱdareȱorȱtimeȱ value.ȱ Formatȱ codesȱ consistȱ ofȱ aȱ %ȱ characterȱ followedȱ byȱ aȱ characterȱ thatȱ indicatesȱ valueȱdesired.ȱTableȱ16.3ȱlistsȱtheȱformatȱcodesȱthatȱareȱimplemented.ȱAȱ %ȱfollowedȱbyȱ anyȱ otherȱ characterȱ isȱ undefined,ȱ whichȱ leavesȱ individualȱ implementationsȱ freeȱ toȱ defineȱadditionalȱformatȱcodes.ȱYouȱshouldȱavoidȱusingȱthemȱunlessȱyouȱareȱwillingȱtoȱ sacrificeȱportability.ȱTheȱlocaleȬspecificȱvaluesȱareȱdeterminedȱbyȱtheȱcurrentȱlocale,ȱasȱ discussedȱlaterȱinȱthisȱchapter.ȱTheȱ%Uȱandȱ%Wȱcodesȱareȱidenticalȱexceptȱthatȱtheȱformerȱ countsȱ theȱ firstȱ Sundayȱ ofȱ theȱ yearȱ asȱ theȱ beginningȱ ofȱ theȱ firstȱ weekȱ andȱ theȱ latterȱ countsȱtheȱfirstȱMondayȱofȱtheȱyearȱasȱtheȱbeginningȱofȱtheȱfirstȱweek.ȱIfȱtheȱtimeȱzoneȱ cannotȱbeȱdetermined,ȱtheȱ%zȱcodeȱisȱreplacedȱbyȱanȱemptyȱstring.ȱ Finally,ȱtheȱmktimeȱfunctionȱisȱusedȱtoȱconvertȱaȱstruct tmȱtoȱaȱtime_tȱvalue,ȱ ȱ time_t mktime( struct tm *tm_ptr ); ȱ Theȱvaluesȱofȱ tm_wdayȱandȱ tm_ydayȱinȱtheȱ struct tmȱareȱignored,ȱandȱtheȱvalueȱinȱtheȱ otherȱfieldsȱneedȱnotȱbeȱwithinȱtheirȱusualȱranges.ȱAfterȱtheȱconversion,ȱtheȱ struct tmȱ isȱthenȱnormalized,ȱsoȱthatȱtm_wdayȱandȱtm_yday areȱcorrectȱandȱtheȱremainingȱfieldsȱ Download at http://www.pin5i.com/ 16.4 Nonlocal Jumps <setjmp.h>ȱ Code %% %a %A %b %B %c %d %H %I %j %m %M %p %S %U %w %W %x %X %y %Y %Z 465 is Replaced By aȱ%ȱ theȱdayȱofȱweek,ȱusingȱtheȱlocaleȇsȱabbreviatedȱweekdayȱnamesȱ theȱdayȱofȱweek,ȱusingȱtheȱlocaleȇsȱfullȱweekdayȱnamesȱ theȱmonth,ȱusingȱtheȱlocaleȇsȱabbreviatedȱmonthȱnamesȱ theȱmonth,ȱusingȱtheȱlocaleȇsȱfullȱmonthȱnamesȱ theȱdateȱandȱtime,ȱusingȱ%x %Xȱ theȱdayȱofȱmonthȱ(01Ȭ31)ȱ theȱhour,ȱinȱ24Ȭhourȱclockȱformatȱ(00Ȭ23)ȱ theȱhour,ȱinȱ12Ȭhourȱclockȱformatȱ(01Ȭ12)ȱ theȱdayȱnumberȱofȱtheȱyearȱ(001Ȭ366)ȱ theȱmonthȱnumberȱ(01Ȭ12)ȱ theȱminuteȱ(00Ȭ59)ȱ theȱlocaleȇsȱequivalentȱofȱAMȱorȱPM,ȱwhicheverȱisȱappropriateȱ theȱsecondsȱ(00Ȭ61)ȱ theȱweekȱnumberȱofȱtheȱyearȱ(00Ȭ53),ȱstartingȱwithȱSundayȱ theȱdayȱofȱtheȱweek;ȱSundayȱisȱdayȱ0ȱ theȱweekȱnumberȱofȱtheȱyearȱ(00Ȭ53),ȱstartingȱwithȱMondayȱ theȱdate,ȱusingȱtheȱlocaleȇsȱdateȱformatȱ theȱtime,ȱusingȱtheȱlocaleȇsȱtimeȱformatȱ theȱyearȱwithinȱtheȱcenturyȱ(00Ȭ99)ȱ theȱyear,ȱincludingȱcenturyȱ(forȱexample,ȱ1984)ȱ theȱtimeȱzoneȱabbreviationȱ ȱ Tableȱ16.3ȱȱstrftimeȱformatȱcodesȱ ȱ ȱ areȱ allȱ withinȱ theirȱ usualȱ ranges.ȱ Thisȱ techniqueȱ isȱ aȱ simpleȱ wayȱ ofȱ determiningȱ theȱ dayȱofȱtheȱweekȱforȱaȱparticularȱdate.ȱ ȱ ȱ ȱ 16.4 Nonlocal Jumps <setjmp.h> ȱ Theȱ setjmpȱandȱ longjmpȱfunctionsȱprovideȱaȱmechanismȱsimilarȱtoȱtheȱ gotoȱstatementȱ exceptȱ thatȱ itȱ isȱ notȱ limitedȱ inȱ scopeȱ toȱ oneȱ function.ȱ Theseȱ functionsȱ areȱ commonlyȱ usedȱwithȱdeeplyȱnestedȱchainsȱofȱfunctionȱcalls.ȱIfȱanȱerrorȱisȱdetectedȱinȱaȱlowerȬlevelȱ function,ȱ youȱ canȱ returnȱ immediatelyȱ toȱ theȱ topȬlevelȱ functionȱ withoutȱ havingȱ toȱ returnȱanȱerrorȱflagȱtoȱeachȱintermediateȱfunctionȱinȱtheȱchain.ȱ Toȱ useȱ theseȱ functions,ȱ youȱ mustȱ includeȱ theȱ headerȱ fileȱ setjmp.h;ȱ theirȱ prototypesȱareȱshownȱbelow.ȱ Download at http://www.pin5i.com/ Chapter 16 Standard Libraryȱ 466ȱ int setjmp( jmp_buf state ); void longjmp( jump_buf state, int value ); ȱ Youȱ declareȱ aȱ jmp_bufȱ variableȱ andȱ initializeȱ itȱ byȱ callingȱ setjmp,ȱ whichȱ returnsȱ theȱ valueȱ zero.ȱ setjmpȱ savesȱ programȱ stateȱ informationȱ (forȱ example,ȱ theȱ currentȱ stackȱ pointerȱ andȱ programȱ counter)ȱ inȱ theȱ jumpȱ buffer. 50 ȱ Theȱ functionȱ inȱ whichȱ youȱ callȱ setjmpȱbecomesȱyourȱȈtopȬlevelȈȱfunction.ȱ Later,ȱ aȱ callȱ toȱ longjmpȱ fromȱ anywhereȱ withinȱ theȱ topȬlevelȱ functionȱ orȱ anyȱ otherȱ functionȱ thatȱ itȱ calls,ȱ eitherȱ directlyȱ orȱ indirectly,ȱ causesȱ theȱ savedȱ stateȱ toȱ beȱ restored.ȱTheȱeffectȱofȱlongjmpȱisȱthatȱexecutionȱimmediatelyȱgoesȱbackȱtoȱtheȱtopȬlevelȱ functionȱbyȱreturningȱagainȱfromȱtheȱsetjmpȱfunction.ȱ Howȱ canȱ youȱ distinguishȱ betweenȱ theseȱ twoȱ differentȱ returnsȱ formȱ setjmp?ȱ Whenȱitȱisȱinitiallyȱcalled,ȱsetjmpȱreturnsȱtheȱvalueȱzero.ȱWhenȱsetjmpȱreturnsȱagainȱasȱ theȱresultȱofȱaȱ longjmp,ȱtheȱvalueȱthatȱitȱreturnsȱisȱtheȱsecondȱargumentȱtoȱtheȱ longjmpȱ call,ȱwhichȱmustȱbeȱnonzero.ȱByȱcheckingȱtheȱreturnȱvalue,ȱtheȱprogramȱcanȱdetermineȱ whetherȱ(and,ȱinȱtheȱcaseȱofȱmultipleȱcalls,ȱwhich)ȱlongjmpȱwasȱcalled.ȱ ȱ ȱ ȱ 16.4.1 Example ȱ Programȱ 16.2ȱ usesȱ setjmpȱ toȱ handleȱ errorsȱ detectedȱ inȱ functionsȱ thatȱ itȱ callsȱ withoutȱ theȱ usualȱ logicȱ ofȱ returningȱ andȱ checkingȱ forȱ errorȱ codes.ȱ Theȱ initialȱ callȱ toȱ setjmpȱ establishesȱtheȱpointȱatȱwhichȱexecutionȱwillȱresumeȱafterȱaȱcallȱtoȱ longjmp.ȱȱIfȱreturnsȱ theȱ valueȱ zero,ȱ soȱ theȱ programȱ entersȱ theȱ transactionȱ processingȱ loop.ȱ Ifȱ get_trans,ȱ process_trans,ȱ orȱ anyȱ functionsȱ calledȱ byȱ theseȱ functionsȱ detectsȱ anȱ error,ȱ itȱ callsȱ longjmpȱlikeȱthis:ȱ ȱ longjmp( restart, 1 ); ȱ Executionȱimmediatelyȱresumesȱatȱtheȱrestartȱpoint,ȱandȱsetjmpȱreturnsȱwithȱtheȱvalueȱ one.ȱ Inȱ thisȱ example,ȱ twoȱ differentȱ typesȱ ofȱ errorsȱ areȱ handled:ȱ fatalȱ errorsȱ thatȱ preventȱ theȱ programȱ fromȱ continuing,ȱ andȱ minorȱ errorsȱ thatȱ onlyȱ disruptȱ theȱ transactionȱ thatȱ wasȱ beingȱ processed.ȱ Thisȱ callȱ toȱ longjmpȱ isȱ theȱ latter.ȱ Whenȱ setjmpȱ returnsȱone,ȱanȱerrorȱmessageȱisȱprintedȱandȱtheȱtransactionȱloopȱisȱenteredȱonceȱagain.ȱ Toȱreportȱaȱfatalȱerror,ȱ longjmpȱisȱcalledȱwithȱanyȱotherȱvalue,ȱandȱtheȱprogramȱsavesȱ itsȱdataȱandȱexits.ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ 50 ȱTheȱaddressȱofȱtheȱinstructionȱcurrentlyȱbeingȱexecutedȱinȱtheȱprogram.ȱ Download at http://www.pin5i.com/ 16.4 Nonlocal Jumps <setjmp.h>ȱ 467 ȱ /* ** A program to demonstrate the use of setjmp */ #include "trans.h" #include <stdio.h> #include <stdlib.h> #include <setjmp.h> /* ** The variable that stores setjmp's state information. */ jmp_buf restart; int main() { int value; Trans *transaction; /* ** Establish the point at which we want to resume execution ** after a call to longjmp. */ value = setjmp( restart ); /* ** Figure out what to do after a return from setjmp. */ switch( value ){ default: /* ** longjmp was called -- fatal error */ fputs( "Fatal error.\n", stderr ); break; case 1: /* ** longjmp was called -- minor error */ fputs( "Invalid transaction.\n", stderr ); /* FALL THROUGH and continue processing */ case 0: /* ** Original return from setjmp: perform normal ** processing. */ while( (transaction = get_trans()) != NULL ) process_trans( transaction ); } ȱ Programȱ16.2ȱȱsetjmpȱandȱlongjmpȱexampleȱ ȱ ȱ ȱ ȱ ȱ continued...ȱ Download at http://www.pin5i.com/ Chapter 16 Standard Libraryȱ 468ȱ ȱ /* ** Save data and exit the program */ write_data_to_file(); return value == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }ȱ ȱ Programȱ16.2ȱȱsetjmpȱandȱlongjmpȱexampleȱ ȱ ȱ ȱ ȱ ȱ ȱ 16.4.2 ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱsetjmp.cȱ When to Use Nonlocal Jumps ȱ setjmpȱandȱ longjmpȱareȱnotȱabsolutelyȱnecessary,ȱbecauseȱyouȱcanȱalwaysȱachieveȱtheȱ CAUTION! TIP sameȱ resultȱ byȱ returningȱ anȱ errorȱ codeȱ andȱ checkingȱ forȱ itȱ inȱ theȱ callingȱ function.ȱ Returningȱ inȱ thisȱ mannerȱ isȱ sometimesȱ inconvenient,ȱ especiallyȱ ifȱ theȱ functionsȱ areȱ alreadyȱ returningȱ someȱ value.ȱ Ifȱ thereȱ isȱ aȱ longȱ chainȱ ofȱ functionȱ callingȱ functionȱ callingȱ function,ȱ thenȱ eachȱ functionȱ inȱ theȱ chainȱ mustȱ checkȱ forȱ andȱ returnȱ theȱ errorȱ codeȱevenȱifȱtheȱlastȱfunctionȱcalledȱisȱtheȱonlyȱoneȱthatȱeverȱdetectsȱanyȱerrors.ȱUsingȱ setjmpȱandȱlongjmpȱinȱthisȱsituationȱsimplifiesȱtheȱintermediateȱfunctionsȱbyȱremovingȱ theȱerrorȱcodeȱlogicȱfromȱthem.ȱ ȱ WhenȱtheȱtopȬlevelȱfunctionȱ(theȱoneȱthatȱcalledȱ setjmp)ȱreturns,ȱtheȱstateȱinformationȱ inȱ theȱ jumpȱ bufferȱ becomesȱ invalid.ȱ Callsȱ toȱ longjmpȱ afterȱ thisȱ timeȱ areȱ likelyȱ toȱ fail,ȱ andȱ theȱ symptomsȱ willȱ beȱ difficultȱ toȱ debug.ȱ Thisȱ factȱ isȱ whyȱ longjmpȱ canȱ beȱ calledȱ onlyȱbyȱtheȱtopȬlevelȱfunction,ȱorȱbyȱfunctionsȱcalledȱfromȱtheȱtopȬlevelȱfunction.ȱOnlyȱ thenȱisȱtheȱstateȱinformationȱsavedȱinȱtheȱjumpȱbufferȱvalid.ȱ ȱ Becauseȱsetȱ jmpȱandȱ longjmpȱimplementȱwhatȱisȱeffectivelyȱaȱ goto,ȱyouȱmustȱexerciseȱ someȱ disciplineȱ inȱ theirȱ use.ȱ Inȱ situationsȱ likeȱ theȱ exampleȱ inȱ Programȱ 16.2,ȱ theseȱ functionsȱ canȱ contributeȱ toȱ cleaner,ȱ lessȱ complicatedȱ code.ȱ However,ȱ ifȱ setjmpȱ andȱ longjmpȱareȱusedȱtoȱsimulateȱaȱ gotoȱwithinȱoneȱfunctionȱorȱifȱthereȱareȱdozensȱofȱjumpȱ buffersȱ toȱ whichȱ executionȱ canȱ return,ȱ theȱ logicȱ willȱ becomeȱ moreȱ difficultȱ toȱ understandȱ andȱ theȱ programȱ willȱ beȱ harderȱ toȱ debugȱ andȱ maintain,ȱ inȱ additionȱ toȱ beingȱ moreȱ likelyȱ toȱ fail.ȱ Youȱ canȱ useȱ setjmpȱ andȱ longjmp,ȱ butȱ youȱ shouldȱ useȱ themȱ wisely.ȱ ȱ Download at http://www.pin5i.com/ 16.5 Signalsȱ 469 16.5 Signals ȱ Mostȱofȱtheȱactionsȱthatȱhappenȱinȱaȱprogramȱareȱcausedȱbyȱtheȱprogram,ȱforȱexample,ȱ executingȱvariousȱstatementsȱorȱrequestingȱinput.ȱHowever,ȱthereȱareȱsomeȱeventsȱthatȱ theȱprogramȱmustȱreachȱtoȱthatȱareȱnotȱcausedȱbyȱtheȱprogram.ȱAȱcommonȱexampleȱisȱ whenȱ theȱ riserȱ interruptsȱ aȱ program.ȱ Ifȱ partiallyȱ computedȱ resultsȱ mustȱ beȱ savedȱ inȱ orderȱtoȱavoidȱlossȱofȱdata,ȱtheȱprogramȱmustȱbeȱpreparedȱtoȱreactȱtoȱthisȱeventȱevenȱ thoughȱthereȱisȱnoȱwayȱtoȱpredictȱwhenȱitȱwillȱoccur.ȱ Signalsȱ areȱ usedȱ forȱ thisȱ purpose.ȱ Aȱ signalȱ representsȱ anȱ eventȱ thatȱ canȱ occurȱ asynchronously,ȱthatȱis,ȱnotȱsynchronizedȱwithȱanythingȱinȱtheȱprogramȇsȱexecution.ȱIfȱ theȱ programȱ hasȱ notȱ arrangedȱ toȱ handleȱ aȱ particularȱ signal,ȱ aȱ defaultȱ actionȱ isȱ takenȱ whenȱ theȱ signalȱoccurs.ȱTheȱStandardȱdoesȱnotȱ defineȱwhatȱtheȱdefaultȱ actionȱ is,ȱbutȱ mostȱ implementationsȱ abortȱ theȱ program.ȱ Alternatively,ȱ theȱ programȱ canȱ callȱ theȱ signalȱfunctionȱtoȱeitherȱignoreȱtheȱsignalȱorȱtoȱinstallȱaȱsignalȱhandler,ȱaȱfunctionȱinȱtheȱ programȱtoȱbeȱcalledȱwhenȱaȱsignalȱoccurs.ȱ ȱ ȱ ȱ ȱ 16.5.1 Signal Names <signal.h> ȱ Tableȱ 16.4ȱ listsȱ theȱ signalsȱ definedȱ byȱ theȱ Standard,ȱ thoughȱ anȱ implementationȱ needȱ notȱgenerateȱallȱofȱtheseȱsignalsȱandȱitȱcanȱdefineȱadditionalȱonesȱifȱappropriate.ȱ SIGABRTȱ isȱ theȱ signalȱ raisedȱ byȱ theȱ abortȱ functionȱ toȱ abortȱ theȱ program.ȱ Theȱ specificȱ errorsȱ thatȱ willȱ raiseȱ aȱ SIGFPEȱ signalȱ areȱ implementationȱ dependent.ȱ Someȱ commonȱonesȱareȱarithmeticȱoverflowȱorȱunderflowȱandȱdivideȱbyȱzeroȱerrors.ȱSomeȱȱ ȱ ȱ ȱ ȱ Signal Meaning SIGABRT Theȱprogramȱhasȱrequestedȱabnormalȱtermination.ȱ SIGFPE Anȱarithmeticȱerrorȱoccurred.ȱ SIGILL Anȱillegalȱinstructionȱwasȱdetected.ȱ SIGSEGV Anȱinvalidȱaccessȱtoȱmemoryȱwasȱdetected.ȱ SIGINT Anȱinteractiveȱattentionȱsignalȱwasȱreceived.ȱ SIGTERM Aȱrequestȱtoȱterminateȱtheȱprogramȱwasȱreceived.ȱ ȱ Tableȱ16.4ȱȱSignalsȱ Download at http://www.pin5i.com/ Chapter 16 Standard Libraryȱ 470ȱ implementationsȱextendȱthisȱsignalȱtoȱprovideȱspecificȱinformationȱaboutȱtheȱoperationȱ thatȱcausedȱtheȱsignal.ȱUsingȱthisȱinformationȱmayȱletȱtheȱprogramȱreactȱtoȱtheȱsignalȱ moreȱintelligently,ȱbutȱreducesȱitsȱportability.ȱ Theȱ SIGILLȱsignalȱindicatesȱthatȱtheȱCPUȱtriedȱtoȱexecuteȱanȱillegalȱinstruction.ȱ Thisȱ errorȱ mayȱ beȱ causedȱ byȱ incorrectȱ compilerȱ settings;ȱ forȱ example,ȱ compilingȱ aȱ programȱwithȱIntelȱ80386ȱinstructionsȱbutȱrunningȱitȱonȱanȱ80286ȱcomputer.ȱAnotherȱ possibleȱ causeȱ isȱ anȱerrorȱ inȱ theȱ executionȱ ofȱtheȱprogram,ȱ suchȱ asȱcallingȱ aȱ functionȱ usingȱanȱuninitializedȱfunctionȱpointerȱthatȱhasȱcausedȱtheȱCPUȱtoȱattemptȱtoȱexecuteȱ whatȱisȱactuallyȱdata.ȱ SIGSEGVȱindicatesȱanȱattemptȱbyȱtheȱprogramȱtoȱaccessȱmemoryȱ illegally.ȱ Theȱ twoȱmostȱcommonȱcausesȱofȱthisȱsignalȱ areȱattemptsȱ toȱ accessȱmemoryȱ thatȱisȱnotȱinstalledȱonȱtheȱmachineȱorȱnotȱallocatedȱtoȱyourȱprogramȱbyȱtheȱoperatingȱ systemȱ andȱ violatingȱ boundaryȱ requirements.ȱ Theȱ latterȱ occursȱ onȱ machinesȱ thatȱ enforceȱboundaryȱalignmentȱonȱdata.ȱForȱexample,ȱifȱintegersȱareȱrequiredȱtoȱbeȱonȱanȱ evenȱboundaryȱ(beginȱatȱanȱevenȱnumberedȱaddress),ȱanȱinstructionȱthatȱspecifiesȱanȱ oddȱ addressȱ toȱ accessȱ anȱ integerȱ willȱ causeȱ aȱ boundaryȱ violation.ȱ Uninitializedȱ pointersȱareȱoftenȱtheȱcauseȱofȱthisȱerror.ȱ Theȱprecedingȱsignalsȱareȱsynchronousȱbecauseȱtheyȱareȱallȱcausedȱfromȱwithinȱ theȱprogram.ȱAlthoughȱyouȱmayȱnotȱbeȱableȱtoȱpredictȱwhenȱanȱarithmeticȱerrorȱmayȱ occur,ȱ ifȱ youȱ runȱ theȱ programȱ overȱ andȱ overȱ withȱ theȱ sameȱ dataȱ theȱ sameȱ errorȱ willȱ occurȱ atȱ theȱ sameȱ placeȱ everyȱ time.ȱ Theȱ lastȱ twoȱ signals,ȱ SIGINTȱ andȱ SIGTERM,ȱ areȱ asynchronous.ȱ Theyȱ originateȱ fromȱ outsideȱ theȱ program,ȱ usuallyȱ byȱ theȱ programȇsȱ user,ȱandȱindicateȱthatȱtheȱuserȱisȱtryingȱtoȱtellȱtheȱprogramȱsomething.ȱ SIGINTȱ isȱ theȱ signalȱ thatȱ mostȱ implementationsȱ raiseȱ whenȱ theȱ userȱ triesȱ toȱ interruptȱ theȱ program.ȱ SIGTERMȱ isȱ anȱ alternativeȱ signalȱ thatȱ anȱ implementationȱ mayȱ useȱ toȱ requestȱ thatȱ theȱ programȱ beȱ terminated.ȱ Inȱ systemsȱ thatȱ implementȱ bothȱ ofȱ theseȱ signals,ȱ aȱ commonȱ strategyȱ isȱ toȱ defineȱ aȱ signalȱ handlerȱ forȱ SIGINTȱ inȱ orderȱ toȱ performȱ housekeepingȱ andȱ saveȱ dataȱ beforeȱ exitingȱ theȱ program,ȱ butȱ toȱ notȱ installȱ aȱ signalȱhandlerȱforȱ SIGTERMȱsoȱthatȱtheȱprogramȱcanȱbeȱterminatedȱwithoutȱdoingȱthisȱ housekeeping.ȱ ȱ ȱ ȱ 16.5.2 Processing Signals <signal.h> ȱ Usuallyȱ weȱ areȱ concernedȱ withȱ handlingȱ signalsȱ thatȱ occurȱ onȱ theirȱ own,ȱ thatȱ is,ȱ unplannedȱsignals.ȱTheȱraiseȱfunctionȱisȱprovidedȱtoȱraiseȱaȱsignalȱexplicitly.ȱ ȱ int raise( int sig ); Download at http://www.pin5i.com/ 16.5 Signalsȱ 471 ȱ Callingȱthisȱfunctionȱraisesȱtheȱindicatedȱsignal.ȱȱTheȱprogramȱrespondsȱtoȱtheȱsignalȱ exactlyȱ asȱ ifȱ itȱ hadȱ occurredȱ onȱ itsȱ own.ȱ Youȱ canȱ callȱ thisȱ functionȱ toȱ testȱ signalȱ handlers,ȱ butȱ itȱ canȱ alsoȱ beȱ misusedȱ toȱ effectȱ aȱ nonlocalȱ goto.ȱ Avoidȱ usingȱ itȱ inȱ thisȱ way.ȱ Thereȱareȱthreeȱwaysȱthatȱaȱprogramȱcanȱreactȱwhenȱaȱsignalȱoccurs.ȱTheȱdefaultȱ actionȱisȱdefinedȱbyȱtheȱimplementation,ȱoftenȱtheȱdefaultȱisȱtoȱabortȱtheȱprogram.ȱȱTheȱ programȱcanȱspecifyȱotherȱbehaviorsȱforȱrespondingȱtoȱsignals:ȱaȱsignalȱcanȱbeȱignored,ȱ orȱtheȱprogramȱcanȱinstallȱaȱsignalȱhandlerȱthatȱisȱcalledȱwhenȱtheȱsignalȱoccurs.ȱTheȱ signalȱfunctionȱisȱusedȱtoȱspecifyȱtheȱdesiredȱaction.ȱ ȱ void ( *signal( int si, void ( *handler )( int ) ) )( int ); ȱ Thisȱprototypeȱisȱdaunting,ȱsoȱnowȱweȱwillȱunravelȱit.ȱFirst,ȱIȇllȱomitȱtheȱreturnȱtypeȱsoȱ weȱcanȱexamineȱtheȱarguments:ȱ ȱ signal( int sig, void ( *handler )( int ) ) ȱ TheȱfirstȱargumentȱisȱaȱsignalȱfromȱTableȱ16.4,ȱandȱtheȱsecondȱargumentȱisȱtheȱhandlerȱ youȱwantȱtoȱinstallȱforȱthatȱsignal.ȱTheȱhandlerȱisȱaȱpointerȱtoȱaȱfunctionȱthatȱtakesȱaȱ singleȱintegerȱargumentȱandȱdoesnȇtȱreturnȱaȱresult.ȱWhenȱtheȱsignalȱoccurs,ȱtheȱcodeȱ forȱ theȱ signalȱ isȱ passedȱ asȱ anȱ argumentȱ toȱ theȱ handler.ȱ Thisȱ argumentȱ allowsȱ oneȱ handlerȱtoȱprocessȱseveralȱdifferentȱsignals.ȱ Nowȱ Iȇllȱ omitȱ theȱ argumentsȱ fromȱ theȱ prototypeȱ toȱ makeȱ theȱ returnȱ valueȱ apparent:ȱ ȱ void ( *signal() )( int ); ȱ signalȱ isȱ aȱ functionȱ thatȱ returnsȱ aȱ pointerȱ toȱ anotherȱ function,ȱ whichȱ takesȱ aȱ singleȱ integerȱ argumentȱ andȱ doesnȇtȱ returnȱ aȱ result.ȱ Inȱ fact,ȱ signalȱ returnsȱ aȱ pointerȱ toȱ theȱ previousȱ handlerȱ forȱ theȱ signal.ȱ Byȱ savingȱ thisȱ valueȱ youȱ canȱ installȱ aȱ handlerȱ forȱ aȱ signalȱandȱthenȱlaterȱreturnȱtoȱtheȱpreviousȱsignalȱhandler.ȱIfȱtheȱcallȱtoȱsignalȱfails,ȱforȱ exampleȱbecauseȱofȱanȱillegalȱsignalȱcode,ȱtheȱvalueȱSIG_ERRȱisȱreturned.ȱThisȱvalueȱisȱaȱ macroȱthatȱisȱdefinedȱinȱtheȱheaderȱfile.ȱ Thereȱareȱtwoȱadditionalȱmacros,ȱSIG_DFLȱandȱSIG_IGN,ȱthatȱmayȱbeȱgivenȱasȱtheȱ secondȱ argumentȱ toȱ signal.ȱ SIG_DFȱ reinstatesȱ theȱ defaultȱ actionȱ forȱ theȱ signal,ȱ andȱ SIG_IGNȱcausesȱtheȱsignalȱtoȱbeȱignored.ȱ Download at http://www.pin5i.com/ Chapter 16 Standard Libraryȱ 472ȱ 16.5.3 Signal Handlers ȱ Whenȱaȱsignalȱoccursȱforȱwhichȱaȱhandlerȱhasȱbeenȱinstalled,ȱtheȱsystemȱfirstȱreinstatesȱ theȱ defaultȱ actionȱ forȱ theȱ signal. 51 ȱ Thisȱ changeȱ preventsȱ anȱ infiniteȱ loopȱ ifȱ theȱ signalȱ recursȱwithinȱtheȱhandler.ȱNextȱtheȱhandlerȱisȱcalled,ȱandȱtheȱsignalȱcodeȱisȱpassedȱasȱ anȱargument.ȱ Theȱ typeȱ ofȱ workȱ theȱ handlerȱ canȱ performȱ isȱ limited.ȱ Ifȱ theȱ signalȱ isȱ asynchronous,ȱ thatȱ is,ȱ itȱ isȱ notȱ causedȱ byȱ callingȱ theȱ abortȱ orȱ raiseȱ functions,ȱ theȱ handlerȱshouldȱnotȱcallȱanyȱlibraryȱfunctionȱotherȱthanȱsignalȱbecauseȱtheirȱresultsȱareȱ undefinedȱ inȱ thisȱ context.ȱ Furthermore,ȱ theȱ handlerȱ mayȱ notȱ accessȱ anyȱ staticȱ dataȱ exceptȱtoȱassignȱaȱvalueȱtoȱaȱstaticȱvariableȱofȱtypeȱ volatile sig_atomic_t.ȱ(volatileȱ isȱdescribedȱinȱtheȱnextȱsection.)ȱToȱbeȱtrulyȱsafe,ȱaboutȱallȱthatȱaȱsignalȱhandlerȱcanȱdoȱ isȱsetȱoneȱofȱtheseȱvariablesȱandȱthenȱreturn.ȱTheȱrestȱofȱtheȱprogramȱmustȱperiodicallyȱ examineȱtheȱvariableȱtoȱseeȱifȱaȱsignalȱhasȱoccurred.ȱ Theseȱ harshȱ restrictionsȱ ariseȱ fromȱ theȱ natureȱ ofȱ signalȱ handling.ȱ Theȱ signalȱ usuallyȱ indicatesȱ thatȱ somethingȱ wentȱ wrong.ȱ Theȱ behaviorȱ ofȱ theȱ CPUȱ isȱ preciselyȱ definedȱinȱsuchȱcircumstances,ȱbutȱtheȱprogramȱaddsȱaȱlotȱofȱcontextȱsurroundingȱtheȱ errorȱthatȱmayȱnotȱbeȱsoȱwellȱdefined.ȱForȱexample,ȱaȱsignalȱthatȱoccurredȱwhileȱstrcpyȱ wasȱexecutingȱmightȱleaveȱtheȱdestinationȱstringȱtemporarilyȱunterminated,ȱorȱaȱsignalȱ occurringȱ whileȱ aȱ functionȱ wasȱ beingȱ calledȱ mightȱ leaveȱ theȱ stackȱ inȱ anȱ incompleteȱ state.ȱ Ifȱ libraryȱ functionsȱ thatȱ dependȱ onȱ thisȱ contextȱ wereȱ called,ȱ theyȱ mayȱ failȱ inȱ unexpectedȱways,ȱpossiblyȱcausingȱanotherȱsignalȱcoȱoccur.ȱ CAUTION! Theȱ accessȱ restrictionsȱ defineȱ theȱ minimalȱ functionalityȱ thatȱ isȱ guaranteedȱ toȱ workȱinȱtheȱsignalȱhandler.ȱTheȱtype sig_atomic_tȱdefinesȱaȱdataȱtypeȱthatȱtheȱCPUȱ canȱaccessȱatomically,ȱthatȱis,ȱasȱaȱsingleȱunit.ȱForȱexample,ȱaȱ16Ȭbitȱmachineȱcanȱaccessȱ aȱ 16Ȭbitȱ integerȱ atomicallyȱ butȱ mayȱ needȱ twoȱ operationsȱ toȱ accessȱ aȱ 32Ȭbitȱ integer.ȱȱ Restrictingȱdataȱaccessȱinȱtheȱsignalȱhandlerȱtoȱatomicȱunitsȱeliminatesȱtheȱpossibilityȱ ofȱinconsistentȱresultsȱifȱanotherȱsignalȱoccursȱinȱtheȱmiddleȱofȱtheȱstepsȱthatȱaccessȱaȱ nonatomicȱvariable.ȱ ȱ TheȱStandardȱstatesȱthatȱaȱsignalȱhandlerȱmayȱterminateȱtheȱprogramȱbyȱcallingȱ exit.ȱȱ Aȱhandlerȱforȱanyȱsignal,ȱexceptȱ SIGABRT,ȱmayȱalsoȱterminateȱtheȱprogramȱbyȱcallingȱ abort.ȱ Howeverȱ bothȱ ofȱ theseȱ areȱ libraryȱ functions,ȱ soȱ theyȱ mayȱ notȱ workȱ properlyȱ whenȱ calledȱ fromȱ handlersȱ ofȱ asynchronousȱ signals.ȱ Ifȱ youȱ mustȱ terminateȱ theȱ programȱ inȱ thisȱ way,ȱ beȱ awareȱ thatȱ thereȱ isȱ aȱ remoteȱ chanceȱ thatȱ ifȱ mayȱ fail.ȱ Ifȱ itȱ occurs,ȱaȱfailureȱmayȱdestroyȱdataȱorȱexhibitȱbizarreȱsymptoms,ȱbutȱtheȱprogramȱwillȱ eventuallyȱterminate.ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱAnȱimplementationȱmayȱchooseȱtoȱȈblockȈȱtheȱsignalȱwhileȱtheȱhandlerȱisȱbeingȱexecutedȱinsteadȱofȱreinstatingȱtheȱdefaultȱ action.ȱConsultȱyourȱsystemȇsȱdocumentation.ȱ 51 Download at http://www.pin5i.com/ 16.5 Signalsȱ 473 Volatile Data ȱ Aȱ signalȱ mayȱ occurȱ atȱ anyȱ time,ȱ soȱ theȱ valuesȱ ofȱ variablesȱ thatȱ areȱ modifiedȱ byȱ theȱ signalȱ handlerȱ mayȱ changeȱ atȱ anyȱ time.ȱ Becauseȱ ofȱ this,ȱ youȱ cannotȱ countȱ onȱ theseȱ variablesȱ havingȱ theȱ sameȱ valuesȱ fromȱ oneȱ programȱ statementȱ toȱ theȱ next.ȱ Theȱ volatileȱ keywordȱ informsȱ theȱ compilerȱ ofȱ thisȱ fact,ȱ whichȱ preventsȱ itȱ fromȱ ȈoptimizingȈȱ theȱ programȱ inȱ aȱ wayȱ thatȱ mayȱ changeȱ itsȱ meaning.ȱ Considerȱ thisȱ programȱfragment:ȱ ȱ if( value ){ printf( } else { printf( } if( value ){ printf( } else { printf( } "True\n" ); "False\n" ); "True\n" ); "False\n" ); ȱ Ordinarily,ȱyouȱwouldȱexpectȱtheȱsecondȱtestȱtoȱhaveȱtheȱsameȱresultȱasȱtheȱfirst.ȱIfȱaȱ signalȱhandlerȱchangesȱthisȱvariable,ȱthenȱtheȱsecondȱtestȱmayȱbeȱdifferent.ȱUnlessȱtheȱ variableȱ wereȱ declaredȱ volatile,ȱ theȱ compilerȱ mightȱ ȈoptimizeȈȱ theȱ programȱ byȱ substitutingȱtheȱfollowingȱcode,ȱwhichȱisȱordinarilyȱequivalent:ȱ ȱ if( value ){ printf( printf( } else { printf( printf( } "True\n" ); "True\n" ); "False\n" ); "False\n" ); ȱ ȱ ȱ Returning From a Handler ȱ Returningȱfromȱaȱsignalȱhandlerȱcausesȱtheȱexecutionȱofȱtheȱprogramȱtoȱresumeȱfromȱ theȱpointȱ whereȱtheȱ signalȱoccurred.ȱ Anȱ exceptionȱ toȱ thisȱ ruleȱ isȱ SIGFPE.ȱBecauseȱ theȱ computationȱcannotȱbeȱcompleted,ȱtheȱeffectȱofȱreturningȱfromȱthisȱsignalȱisȱundefined.ȱ Download at http://www.pin5i.com/ Chapter 16 Standard Libraryȱ 474ȱ CAUTION! TIP Ifȱyouȱwishȱtoȱcatchȱfutureȱsignalsȱofȱtheȱtypeȱthatȱoccurred,ȱbeȱsureȱtoȱcallȱ signalȱtoȱ reinstallȱtheȱhandlerȱbeforeȱreturningȱfromȱtheȱhandler.ȱOtherwise,ȱonlyȱtheȱfirstȱsignalȱ willȱbeȱcaught.ȱTheȱnextȱsignalȱwillȱbeȱprocessedȱwithȱtheȱdefaultȱaction.ȱ ȱ Becauseȱofȱtheȱdifferencesȱinȱhowȱvariousȱcomputersȱreactȱtoȱunanticipatedȱerrors,ȱtheȱ specificationȱ ofȱ theȱ signalȱ mechanismȱ isȱ somewhatȱ loose.ȱ Forȱ example,ȱ implementationsȱneedȱnotȱuseȱanyȱorȱallȱofȱtheȱsignalsȱdefined,ȱandȱtheȱdefaultȱactionȱ forȱaȱsignalȱmayȱorȱmayȱnotȱbeȱreinstatedȱbeforeȱcallingȱitsȱhandler.ȱOnȱtheȱotherȱhand,ȱ theȱsevereȱlimitationsȱimposedȱonȱsignalȱhandlingȱfunctionsȱreflectsȱtheȱintersectionȱofȱ theȱrestrictionsȱimposedȱbyȱdifferentȱhardwareȱandȱsoftwareȱenvironments.ȱ Theȱ resultȱ ofȱ theseȱ restrictionsȱ andȱ implementationȱ dependenciesȱ isȱ thatȱ programsȱ thatȱ handleȱ signalsȱ areȱ lessȱ portableȱ thanȱ thoseȱ thatȱ doȱ not.ȱ Usingȱ signalsȱ onlyȱ whereȱ necessaryȱ andȱ notȱ violatingȱ theȱ rulesȱ inȱ signalȱ handlingȱ functionsȱ (evenȱ thoughȱ itȱ mayȱ appearȱ toȱ workȱ onȱ oneȱ machine)ȱ helpȱ minimizeȱ theȱ portabilityȱ problemsȱinherentȱinȱthisȱtypeȱofȱprogram.ȱ ȱ ȱ ȱ 16.6 Printing Variable Argument Lists <stdarg.h> ȱ Theȱ functionsȱ inȱ thisȱ groupȱ areȱ usedȱ whenȱ variableȱ argumentȱ listsȱ mustȱ beȱ printed.ȱȱ Note:ȱTheyȱrequireȱinclusionȱofȱbothȱtheȱstdio.hȱandȱstdarg.hȱheaderȱfiles.ȱ ȱ int vprintf( char const *format, va_list arg ); int vfprintf( FILE *stream, char const *format, va_list arg ); int vsprintf( char *buffer, char const *format, va_list arg ); ȱ Theseȱ functionsȱ areȱ equivalentȱ toȱ theirȱ standardȱ counterpartsȱ exceptȱ thatȱ aȱ variableȱ argumentȱlistȱisȱusedȱ(seeȱChapterȱ7ȱforȱdetailsȱonȱvariableȱargumentȱlists).ȱargȱmustȱbeȱ initializedȱusingȱ va_startȱbeforeȱtheȱfunctionsȱareȱcalled,ȱandȱnoneȱofȱtheseȱfunctionsȱ callȱva_end.ȱ ȱ ȱ ȱ 16.7 Execution Environment ȱ Theseȱfunctionsȱcommunicateȱwithȱorȱaffectȱtheȱprogramȇsȱexecutionȱenvironment.ȱ ȱ ȱ ȱ 16.7.1 ȱ Terminating Execution <stdlib.h> Download at http://www.pin5i.com/ 16.7 Execution Environment 475 ȱ Theseȱthreeȱfunctionsȱrelateȱtoȱnormalȱandȱabnormalȱprogramȱtermination.ȱ ȱ void abort( void ) void atexit( void (func)( void ) ); void exit( int status ); ȱ abortȱ isȱ calledȱ toȱ terminateȱ theȱ executionȱ ofȱ aȱ programȱ abnormally.ȱ Becauseȱ theȱ functionȱraisesȱtheȱ SIGABRTȱsignalȱtoȱaccomplishȱthisȱresult,ȱtheȱprogramȱcanȱinstallȱaȱ signalȱhandlerȱtoȱperformȱanyȱdesiredȱactionȱpriorȱtoȱ(orȱinsteadȱof)ȱaborting.ȱ atexitȱ registersȱ functionsȱ asȱ exitȱ functions.ȱ Exitȱ functionsȱ areȱ calledȱ whenȱ theȱ programȱisȱaboutȱtoȱterminateȱnormally,ȱeitherȱbecauseȱexitȱwasȱcalledȱorȱbecauseȱtheȱ mainȱfunctionȱhasȱreturned.ȱAnȱexitȱfunctionȱmayȱnotȱtakeȱanyȱarguments.ȱ exit,ȱ whichȱ wasȱ describedȱ inȱ Chapterȱ 15,ȱ isȱ calledȱ toȱ terminateȱ theȱ programȱ normally.ȱIfȱtheȱinitialȱinvocationȱofȱtheȱ mainȱfunctionȱreturnsȱaȱvalue,ȱtheȱeffectȱisȱtheȱ sameȱasȱifȱexitȱhadȱbeenȱcalledȱwithȱthatȱvalueȱasȱitsȱargument.ȱ CAUTION! Whenȱexitȱisȱcalled,ȱallȱofȱtheȱexitȱfunctionsȱregisteredȱwithȱ atexitȱareȱcalledȱinȱ theȱ reverseȱ orderȱ thatȱ theyȱ wereȱ registered.ȱ Then,ȱ theȱ buffersȱ areȱ flushedȱ forȱ allȱ streamsȱ thatȱ needȱ it,ȱ andȱ allȱ openȱ filesȱ areȱ closed.ȱ Filesȱ createdȱ withȱ tmpfileȱ areȱ removed.ȱ Theȱ exitȱ statusȱ isȱ thenȱ returnedȱ toȱ theȱ hostȱ environmentȱ andȱ theȱ programȱ ceasesȱtoȱexecute.ȱ ȱ Becauseȱexecutionȱceases,ȱtheȱexitȱfunctionȱneverȱreturnsȱtoȱitsȱcaller.ȱHowever,ȱifȱoneȱ ofȱ theȱ functionsȱ registeredȱ withȱ atexitȱ makesȱ anotherȱ callȱ toȱ exit,ȱ theȱ effectȱ isȱ undefined.ȱThisȱerrorȱmayȱresultȱinȱanȱinfiniteȱloop,ȱpossiblyȱstoppingȱwhenȱthereȱisnȇtȱ anyȱmoreȱmemoryȱforȱtheȱstack.ȱ ȱ ȱ ȱ 16.7.2 Assertions <assert.h> ȱ Anȱassertionȱisȱaȱdeclarationȱofȱsomethingȱthatȱshouldȱbeȱtrue.ȱANSIȱCȱimplementsȱanȱ aessertȱ macroȱ thatȱ isȱ usefulȱ whenȱ debuggingȱ programs.ȱ Itsȱ prototypeȱ isȱ shownȱ below. 52 ȱ void assert( int expression ); ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱBecauseȱitȱisȱaȱmacroȱratherȱthanȱaȱfunction,ȱassert doesnȇtȱactuallyȱhaveȱaȱprototype.ȱȱHowever,ȱtheȱprototypeȱshownȱ illustratesȱhowȱassertȱisȱused.ȱ 52 Download at http://www.pin5i.com/ 476ȱ Chapter 16 Standard Libraryȱ Whenȱ executed,ȱ theȱ macroȱ testsȱ theȱ expressionȱ argument.ȱ Ifȱ itȱ isȱ falseȱ (zero),ȱ thenȱ aȱ diagnosticȱmessageȱisȱprintedȱtoȱtheȱstandardȱerrorȱandȱtheȱprogramȱterminates.ȱTheȱ formatȱ ofȱ thisȱ messageȱ isȱ implementationȱ defined,ȱ butȱ itȱ willȱ includeȱ theȱ expressionȱ andȱtheȱnameȱofȱtheȱsourceȱfileȱandȱtheȱlineȱnumberȱofȱtheȱassertion.ȱIfȱtheȱexpressionȱ isȱtrueȱ(nonzero),ȱnothingȱisȱprinted.ȱ Thisȱmacroȱprovidesȱaȱconvenientȱwayȱtoȱcheckȱforȱthingsȱthatȱoughtȱtoȱbeȱtrue.ȱȱ Forȱexample,ȱaȱfunctionȱthatȱisȱcalledȱwithȱaȱpointerȱargumentȱthatȱmustȱnotȱbeȱNULLȱ couldȱverifyȱtheȱvalueȱwithȱanȱassertion:ȱ ȱ assert( value != NULL ); ȱ IfȱtheȱfunctionȱisȱmistakenlyȱcalledȱwithȱaȱNULLȱargument,ȱtheȱprogramȱwillȱprintȱaȱ messageȱthatȱlooksȱsomethingȱlikeȱthis:ȱ ȱ Assertion failed: value != NULL, file list.c, line 274 TIP ȱ ȱ Usingȱ assertionsȱ inȱ thisȱ wayȱ makesȱ debuggingȱ easierȱ becauseȱ theȱ programȱ stopsȱ asȱ soonȱ asȱ anȱ errorȱ isȱ detected.ȱ Furthermore,ȱ theȱ messageȱ indicatesȱ exactlyȱ whereȱ theȱ symptomȱ appeared.ȱWithoutȱanȱassertion,ȱtheȱprogramȱmayȱcontinueȱtoȱ runȱ andȱfailȱ later,ȱmakingȱitȱharderȱtoȱdebug.ȱ Noteȱthatȱassertȱisȱonlyȱappropriateȱforȱverifyingȱexpressionsȱthatȱmustȱbeȱtrue.ȱ Youȱ cannotȱ useȱ itȱ toȱ checkȱ forȱ conditionsȱ thatȱ youȱ areȱ tryingȱ toȱ handle,ȱ suchȱ asȱ detectingȱillegalȱinputȱandȱaskingȱtheȱuserȱforȱanotherȱvalue,ȱbecauseȱitȱterminatesȱtheȱ program.ȱ Whenȱ theȱ programȱ isȱ thoroughlyȱ tested,ȱ youȱ canȱ eliminateȱ theȱ assertionsȱ byȱ definingȱ theȱ nameȱ NDEBUGȱ whenȱ compilingȱ theȱ program. 53 ȱ Youȱ canȱ useȱ theȱ –DNDEBUGȱ compilerȱcommandȱlineȱoptionȱorȱaddȱ ȱ #define NDEBUG ȱ toȱ theȱ sourceȱ fileȱ priorȱ toȱ whereȱ assert.hȱ isȱ included.ȱ Withȱ NDEBUGȱ defined,ȱ theȱ preprocessorȱdiscardsȱtheȱassertions,ȱthusȱeliminatingȱtheirȱoverheadȱwithoutȱhavingȱ toȱphysicallyȱdeleteȱthemȱfromȱtheȱsourceȱcode.ȱ ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ 53 ȱAnyȱvalueȱmayȱbeȱused;ȱallȱthatȱmattersȱisȱwhetherȱNDEBUGȱisȱdefinedȱorȱnot.ȱ Download at http://www.pin5i.com/ 16.8 Sorting and Searching <stdlib.h> 16.7.3 477 The Environment <stdlib.h> ȱ TheȱenvironmentȱisȱanȱimplementationȬdefinedȱlistȱofȱname/valueȱpairsȱmaintainedȱbyȱ theȱoperatingȱsystem.ȱTheȱ getenvȱfunctionȱsearchesȱthisȱlistȱforȱaȱspecificȱnameȱand,ȱifȱ found,ȱ returnsȱ aȱ pointerȱ toȱ itsȱ value.ȱ Theȱ programȱ mustȱ notȱ modifyȱ theȱ returnedȱ string.ȱIfȱtheȱnameȱisȱnotȱfound,ȱaȱNULLȱpointerȱisȱreturnedȱinstead.ȱ ȱ char *getenv( char const *name ); ȱ Noteȱthatȱtheȱstandardȱdoesȱnotȱdefineȱaȱcorrespondingȱ putenvȱfunction.ȱSomeȱ implementationsȱprovideȱ oneȱanyway,ȱbutȱ youȱshouldȱavoidȱ usingȱitȱifȱ portabilityȱ isȱ anȱissue.ȱ ȱ ȱ ȱ 16.7.4 Executing System Commands <stdlib.h> ȱ Theȱ systemȱfunctionȱpassesȱitsȱstringȱargumentȱtoȱtheȱhostȱenvironmentȱsoȱthatȱitȱcanȱ beȱexecutedȱasȱaȱcommandȱbyȱtheȱsystemȇsȱcommandȱprocessor.ȱ ȱ void system( char const *command ); ȱ Theȱexactȱmannerȱinȱwhichȱthisȱtaskȱisȱperformedȱisȱimplementationȱdependent,ȱ asȱ isȱ theȱ valueȱ returnedȱ byȱ system.ȱ However,ȱ systemȱ mayȱ beȱ calledȱ withȱ aȱ NULLȱ argumentȱtoȱinquireȱwhetherȱaȱcommandȱprocessorȱactuallyȱexists.ȱȱInȱthisȱcase,ȱsystemȱ returnsȱaȱnonzeroȱvalueȱifȱaȱcommandȱprocessorȱisȱavailable,ȱotherwiseȱitȱreturnsȱzero.ȱ ȱ ȱ ȱ 16.8 Sorting and Searching <stdlib.h> ȱ Theȱ qsortȱfunctionȱsortsȱdataȱinȱanȱarrayȱintoȱascendingȱorder.ȱBecauseȱitȱisȱtypeless,ȱ youȱ canȱ useȱ qsortȱ toȱ sortȱ anyȱ typeȱ ofȱ data,ȱ asȱ longȱ asȱ theȱ elementsȱ ofȱ theȱ arrayȱ areȱ fixedȱsize.ȱ ȱ void qsort( void *base, size_t n_elements, size_t el_size, int (*compare)( void const *, void const * ) ); ȱ Theȱ firstȱ argumentȱ pointsȱ toȱ theȱ arrayȱ toȱ beȱ sorted,ȱ theȱ secondȱ indicatesȱ howȱ manyȱ elementsȱareȱinȱtheȱarray,ȱandȱtheȱthirdȱisȱtheȱsizeȱfinȱcharacters)ȱofȱeachȱelement.ȱTheȱ fourthȱ argumentȱ isȱ aȱ pointerȱ toȱ aȱ functionȱ thatȱ comparesȱ elementsȱ ofȱ theȱ typeȱ beingȱ sorted.ȱȱȱqsortȱcallsȱthisȱfunctionȱtoȱcompareȱtheȱdataȱinȱtheȱarrayȱwhenȱsortingȱit.ȱByȱȱ Download at http://www.pin5i.com/ Chapter 16 Standard Libraryȱ 478ȱ ȱ ȱ /* ** Demonstrates sorting an array of structures with qsort */ #include <stdlib.h> #include <string.h> typedef char int } Record; struct { key[ 10 ]; /* the sort key for the array */ other_data; /* data associated with the key */ /* ** Comparison function: compares only the key value. */ int r_compare( void const *a, void const *b ){ return strcmp( ((Record *)a)->key, ((Record *)b)->key ); } int main() { Record array[ 50 ]; /* ** Code that fills the array with 50 elements. */ qsort( array, 50, sizeof( Record ), r_compare ); /* ** Array is now sorted by the key field of the structures. */ return EXIT_SUCCESS; } ȱ Programȱ16.3ȱȱSortingȱanȱarrayȱwithȱqsortȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱȱȱqsort.cȱ ȱ ȱ ȱ ȱ ȱ passingȱaȱpointerȱtoȱanȱappropriateȱcomparisonȱfunction,ȱyouȱcanȱuseȱ qsortȱtoȱsonȱanȱ arrayȱofȱanyȱtypeȱofȱvalues.ȱ Theȱ comparisonȱ functionȱ takesȱ twoȱ arguments,ȱ whichȱ areȱ pointersȱ toȱ twoȱ valuesȱ toȱ beȱ compared.ȱ Theȱ functionȱ shouldȱ returnȱ anȱ integerȱ lessȱ than,ȱ equalȱ to,ȱ orȱ greaterȱthanȱzeroȱaccordingȱtoȱwhetherȱtheȱfirstȱvalueȱisȱlessȱthan,ȱequalȱto,ȱorȱgreaterȱ thanȱtheȱsecond,ȱrespectively.ȱ Download at http://www.pin5i.com/ 16.8 Sorting and Searching <stdlib.h> 479 Becauseȱ ofȱ theȱ typelessȱ natureȱ ofȱ thisȱ function,ȱ theȱ argumentsȱ areȱ declaredȱ asȱ void *.ȱCastsȱmustȱbeȱusedȱinȱtheȱcomparisonȱfunctionȱtoȱconvertȱthemȱtoȱpointersȱofȱ theȱproperȱtype.ȱProgramȱ16.3ȱillustratesȱhowȱanȱarrayȱofȱstructuresȱcontainingȱaȱkeyȱ valueȱandȱsomeȱadditionalȱdataȱwouldȱbeȱsorted.ȱ Theȱ bsearchȱfunctionȱperformsȱaȱbinaryȱsearchȱtoȱlocateȱaȱspecificȱelementȱinȱaȱ sortedȱarray.ȱTheȱresultȱisȱundefinedȱifȱtheȱarrayȱisȱnotȱsorted.ȱ ȱ void *bsearch( void const *key, void const *base, size_t n_elements, size_t el_size, int (*compare)( void const *, void const * ) ); ȱ Theȱfirstȱargumentȱpointsȱtoȱtheȱvalueȱyouȱwantȱtoȱfind,ȱtheȱsecondȱpointsȱtoȱtheȱ arrayȱtoȱbeȱsearched,ȱtheȱthirdȱindicatesȱtheȱnumberȱofȱelementsȱinȱtheȱarray,ȱandȱtheȱ fourthȱisȱtheȱsizeȱ(inȱcharacters)ȱofȱeachȱelement.ȱȱTheȱfinalȱargumentȱisȱaȱpointerȱtoȱaȱ comparisonȱ functionȱ asȱ weȱ describedȱ forȱ qsort.ȱ bsearchȱ returnsȱ aȱ pointerȱ toȱ theȱ desiredȱarrayȱelement.ȱȱIfȱtheȱdesiredȱvalueȱdoesȱnotȱexist,ȱNULLȱisȱreturned.ȱ Noteȱ thatȱ theȱ keyȱ argumentȱ mustȱ beȱ theȱ sameȱ typeȱ ofȱ valueȱ asȱ theȱ arrayȱ elements.ȱ Ifȱ theȱ arrayȱ containsȱ structuresȱ thatȱ haveȱ aȱ keyȱ fieldȱ andȱ someȱ otherȱ data,ȱ youȱmustȱcreateȱanȱentireȱstructureȱandȱfillȱinȱtheȱkeyȱfield.ȱTheȱotherȱfieldsȱcanȱbeȱleftȱ empty,ȱ becauseȱtheȱ comparisonȱfunctionȱwillȱexamineȱ onlyȱ theȱ keyȱ field.ȱ Thisȱ useȱofȱ bsearchȱisȱillustratedȱinȱProgramȱ16.4.ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** Demonstrates searching an array of structures with bsearch */ #include <stdlib.h> #include <string.h> typedef char int } Record; struct { key[ 10 ]; /* the sort key for the array */ other_data; /* data associated with the key */ /* ** Comparison function: compares only the key value. */ int r_compare( void const *a, void const *b ){ return strcmp( ((Record *)a)->key, ((Record *)b)->key ); } ȱ Programȱ16.4ȱȱSearchingȱanȱarrayȱwithȱbsearchȱȱ ȱ ȱ ȱ ȱ ȱȱȱcontinue...ȱ Download at http://www.pin5i.com/ 480ȱ Chapter 16 Standard Libraryȱ ȱ int main() { Record Record Record array[ 50 ]; key; *ans; /* ** Code that fills the array with 50 elements and sorts it */ /* ** Create a key record (only the key field filled in with the ** value we want to locate) and search the array. */ strcpy( key.key, "value" ); ans = bsearch( &key, array, 50, sizeof( Record ), r_compare ); /* ** ans now points to the array element whose key field ** matches the value, or NULL if none matched. */ return EXIT_SUCCESS; } ȱ Programȱ16.4ȱȱSearchingȱanȱarrayȱwithȱbsearchȱȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱbsearch.cȱ 16.9 Locales ȱ InȱanȱeffortȱtoȱmakeȱCȱmoreȱusefulȱworldwide,ȱtheȱStandardȱdefinesȱaȱlocale,ȱwhichȱisȱaȱ particularȱsetȱofȱparametersȱforȱthingsȱthatȱvaryȱfromȱcountryȱtoȱcountry.ȱTheȱdefaultȱ isȱ theȱ ȈCȈȱ locale,ȱ andȱ otherȱ localesȱ mayȱ beȱ definedȱ byȱ theȱ implementation.ȱ Changingȱ theȱ localeȱ mayȱ affectȱ howȱ otherȱ libraryȱ functionsȱ work.ȱ Theȱ effectsȱ ofȱ changingȱ theȱ localeȱareȱdescribedȱatȱtheȱendȱofȱthisȱsection.ȱ Theȱ setlocaleȱ function,ȱ whoseȱ prototypeȱ isȱ shownȱ below,ȱ isȱ usedȱ toȱ changeȱ eitherȱtheȱentireȱlocaleȱorȱaȱportionȱofȱit.ȱ ȱ char *setlocale( int category, char const *locale ); ȱ Theȱ categoryȱ argumentȱ specifiesȱ whichȱ portionȱ ofȱ theȱ localeȱ toȱ change.ȱ Theȱ permissibleȱvaluesȱareȱlistedȱinȱTableȱ16.5.ȱ Download at http://www.pin5i.com/ 16.9 Locales 481 Ifȱ theȱ secondȱ argumentȱ toȱ setlocaleȱ isȱ NULL,ȱ theȱ functionȱ returnsȱ aȱ pointerȱ toȱ theȱ nameȱ ofȱ theȱ currentȱ localeȱ forȱ theȱ givenȱ category.ȱ Thisȱ valueȱ mayȱ beȱ savedȱ andȱ usedȱ inȱ aȱ subsequentȱ callȱ toȱ setȱ localeȱ toȱ restoreȱ aȱ previousȱ locale.ȱ Ifȱ theȱ secondȱ argumentȱ isȱ notȱ NULL,ȱ itȱ specifiesȱ theȱ nameȱ ofȱ theȱ newȱ localeȱ toȱ use.ȱ Ifȱ theȱ callȱ isȱ successful,ȱtheȱfunctionȱreturnsȱtheȱnameȱofȱtheȱnewȱlocale,ȱotherwiseȱNULLȱisȱreturnedȱ andȱtheȱlocaleȱisȱnotȱaffected.ȱ ȱ ȱ ȱ 16.9.1 Numeric and Monetary Formatting <locale.h> ȱ Theȱrulesȱforȱformattingȱnumericȱandȱmonetaryȱvaluesȱdifferȱfromȱplaceȱtoȱplaceȱinȱtheȱ world.ȱ Forȱ example,ȱ aȱ numberȱ thatȱ wouldȱ beȱ writtenȱ 1,234.56ȱ inȱ theȱ Unitedȱ Statesȱ wouldȱ beȱ writtenȱ 1.234,56ȱ inȱ manyȱ Europeanȱ countries.ȱ Theȱ localeconvȱ functionȱ obtainsȱ theȱ informationȱ neededȱ toȱ properlyȱ formatȱ bothȱ nonmonetaryȱ andȱ monetaryȱ valuesȱ accordingȱ toȱ theȱ currentȱ locale.ȱ Noteȱ thatȱ thisȱ functionȱ doesȱ notȱ actuallyȱ performȱtheȱformatting;ȱitȱsimplyȱprovidesȱinformationȱaboutȱhowȱitȱshouldȱbeȱdone.ȱ ȱ struct lconv *localeconv( void ); ȱ Theȱ lconvȱ structureȱ containsȱ twoȱ typesȱ ofȱ parameters:ȱ charactersȱ andȱ characterȱ pointers.ȱȱTheȱcharacterȱparametersȱhaveȱnonnegativeȱvalues.ȱȱIfȱaȱcharacterȱparameterȱ isȱ CHAR_MAX,ȱ thenȱ thatȱ valueȱ isȱ notȱ availableȱ (orȱ notȱ used)ȱ inȱ theȱ currentȱ locale.ȱ Aȱ pointerȱ toȱ anȱ emptyȱ stringȱ indicatesȱ theȱ sameȱ thingȱ forȱ theȱ characterȱ pointerȱ parameters.ȱ ȱ ȱ ȱ Value Changes LC_ALL Theȱentireȱlocale.ȱ LC_COLLATE Theȱcollatingȱsequence,ȱwhichȱaffectsȱtheȱbehaviorȱofȱtheȱ strcollȱandȱ strxfrm functionsȱ(seeȱbelow).ȱ LC_CTYPE Theȱ characterȱ typeȱ classificationsȱ usedȱ byȱ theȱ functionsȱ definedȱ inȱ ctype.h.ȱ LC_MONETARY Theȱcharactersȱtoȱbeȱusedȱwhenȱformattingȱmonetaryȱvalues.ȱ LC_NUMERIC Theȱ charactersȱ toȱ beȱ usedȱ whenȱ formattingȱ nonmonetaryȱ values.ȱ Alsoȱ changesȱ theȱ decimalȱ pointȱ characterȱ usedȱ byȱ theȱ formattedȱ input/outputȱfunctionsȱandȱstringȱconversionȱfunctions.ȱ LC_TIME Theȱbehaviorȱofȱtheȱstrftimeȱfunction.ȱ ȱ Tableȱ16.5ȱȱsetlocaleȱcategoriesȱ Download at http://www.pin5i.com/ 482ȱ Chapter 16 Standard Libraryȱ ȱ Field and Type Meaning char *decimal_point: Theȱcharacterȱtoȱuseȱasȱaȱdecimalȱpoint.ȱThisȱvalueȱwillȱ neverȱbeȱanȱemptyȱstring.ȱ char *thousands_sep Theȱcharacterȱusedȱtoȱseparateȱgroupsȱofȱdigitsȱthatȱ appearȱtoȱtheȱleftȱofȱtheȱdecimalȱpoint.ȱ char *grouping Specifiesȱhowȱmanyȱdigitsȱareȱinȱeachȱdigitȱgroupȱtoȱtheȱ leftȱofȱtheȱdecimalȱpoint.ȱ ȱ Tableȱ16.6ȱȱParametersȱforȱformattingȱnonmonetaryȱnumericȱvaluesȱ ȱ ȱ ȱ Numeric Formatting ȱ TheȱparametersȱlistedȱinȱTableȱ16.6ȱareȱusedȱwhenȱformattingȱnumericȱquantitiesȱthatȱ areȱnotȱmonetary.ȱTheȱ groupingȱstringȱisȱinterpretedȱasȱfollows.ȱTheȱfirstȱvalueȱinȱtheȱ stringȱ specifiesȱ howȱ manyȱ digitsȱ appearȱ inȱ theȱ firstȱ groupȱ toȱ theȱ leftȱ ofȱ theȱ decimalȱ point.ȱ Theȱ nextȱ valueȱ inȱ theȱ stringȱ correspondsȱ toȱ theȱ nextȱ groupȱ toȱ theȱ left,ȱ andȱ soȱ forth.ȱ Twoȱ valuesȱ haveȱ specialȱ significance:ȱ CHAR_MAXȱ indicatesȱ thatȱ theȱ remainingȱ digitsȱareȱnotȱbrokenȱintoȱgroups,ȱandȱ0ȱindicatesȱthatȱtheȱprecedingȱvalueȱappliesȱtoȱ allȱremainingȱgroupsȱinȱtheȱnumber.ȱ TypicalȱNorthȱAmericanȱformattingȱisȱindicatedȱwithȱtheȱparametersȱ ȱ decimal_point="." thousands_sep="," grouping="\3" ȱ Theȱgroupingȱstringȱcontainsȱaȱthreeȱfollowedȱbyȱaȱzeroȱ(theȱterminatingȱNULȱbyte). 54 ȱ Theseȱ valuesȱ meanȱ thatȱ theȱ firstȱ groupȱ toȱ theȱ leftȱ ofȱ theȱ decimalȱ pointȱ willȱ containȱ threeȱ digits,ȱ andȱ allȱ theȱ remainingȱ groupsȱ willȱ alsoȱ containȱ threeȱ digits.ȱ Theȱ valueȱ 1234567.89ȱ wouldȱ appearȱ asȱ 1,234,567.89ȱ whenȱ formattedȱ accordingȱ toȱ theseȱ parameters.ȱ Hereȱisȱanotherȱexample.ȱ ȱ grouping="\4\3" thousands_sep="-" ȱ Theseȱ valuesȱ expressȱ theȱ rulesȱ forȱ formattingȱ telephoneȱ numbersȱ inȱ Northȱ America.ȱ Theȱ valueȱ 2125551234ȱ wouldȱ beȱ formattedȱ asȱ 212-555-1234ȱ accordingȱ toȱ theseȱ parameters.ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ 54 ȱNoteȱthatȱthisȱnumberȱisȱaȱbinaryȱthree,ȱnotȱtheȱcharacterȱthree!ȱ Download at http://www.pin5i.com/ 16.9 Locales 483 Monetary Formatting ȱ Theȱ rulesȱ forȱ formattingȱ monetaryȱ valuesȱ areȱ muchȱ moreȱ complexȱ dueȱ toȱ theȱ manyȱ differentȱ waysȱ ofȱ indicatingȱ positiveȱ andȱ negativeȱ values,ȱ positioningȱ theȱ currencyȱ symbolȱ relativeȱ toȱ theȱ value,ȱ andȱ soȱ forth.ȱ Inȱ addition,ȱ theȱ rulesȱ changeȱ whenȱ formattingȱ aȱ monetaryȱ valueȱ forȱ internationalȱ publication.ȱ Weȱ beginȱ withȱ theȱ parametersȱusedȱwhenȱformattingȱlocalȱ(notȱinternational)ȱmonetaryȱquantities,ȱshownȱ inȱTableȱ16.7.ȱ Whenȱ formattingȱ monetaryȱ valuesȱ forȱ internationalȱ use,ȱ theȱ stringȱ int_curr_symbolȱ isȱ usedȱ insteadȱ ofȱ currency_symbol,ȱ andȱ theȱ characterȱ int_frac_digitsȱisȱusedȱinsteadȱofȱfrac_digits.ȱȱInternationalȱcurrencyȱsymbolsȱareȱ ȱ ȱ ȱ ȱ Field and Type Meaning char *currency_symbol Theȱlocalȱcurrencyȱsymbol.ȱ char *mon_decimal_point Theȱdecimalȱpointȱcharacter.ȱ char *mon_thousands_sep Theȱcharacterȱusedȱtoȱseparateȱdigitȱgroupsȱthatȱappearȱtoȱtheȱleftȱofȱ theȱdecimalȱpoint.ȱ char *mon_grouping Specifiesȱtheȱnumberȱofȱdigitsȱinȱeachȱgroupȱappearingȱtoȱtheȱleftȱofȱtheȱ decimalȱpointȱ char *positive_sign Theȱstringȱusedȱtoȱindicateȱaȱnonnegativeȱamount.ȱ char *negative_sign Theȱstringȱusedȱtoȱindicateȱaȱnegativeȱamount.ȱ char frac_digits Theȱnumberȱofȱdigitsȱappearingȱtoȱtheȱrightȱofȱtheȱdecimalȱpoint.ȱ char p_cs_precedes 1ȱifȱtheȱcurrency_symbolȱprecedesȱaȱnonnegativeȱvalue;ȱ0ȱIfȱitȱfollows. char n_cs_precedes 1ȱifȱtheȱcurrency_symbolȱprecedesȱaȱnegativeȱvalue;ȱ0ȱifȱitȱfollows.ȱ char p_sep_by_space 1ȱifȱtheȱcurrency_symbolȱisȱseparatedȱbyȱaȱspaceȱfromȱaȱnonnegativeȱ value;ȱelseȱ0.ȱ char n_sep_by_space 1ȱifȱtheȱcurrency_symbolȱisȱseparatedȱbyȱaȱspaceȱfromȱaȱnegativeȱ value;ȱelseȱ0.ȱ char p_sign_posn Indicatesȱwhereȱtheȱpositive_signȱappearsȱinȱaȱnonnegativeȱvalue.ȱ Theȱfollowingȱvaluesȱareȱallowed:ȱ 0ȱȱȱȱȱȱParenthesesȱsurroundȱtheȱcurrencyȱsymbolȱandȱvalue.ȱ 1ȱȱȱȱȱȱTheȱsignȱprecedesȱtheȱcurrencyȱsymbolȱandȱvalue.ȱ 2ȱȱȱȱȱȱTheȱsignȱfollowsȱtheȱcurrencyȱsymbolȱandȱvalue.ȱ 3ȱȱȱȱȱȱTheȱsignȱImmediatelyȱprecedesȱtheȱcurrencyȱsymbol.ȱ 4ȱȱȱȱȱȱTheȱsignȱimmediatelyȱfollowsȱtheȱcurrencyȱsymbol.ȱ char n_sign_posn Indicatesȱwhereȱtheȱnegative_signȱappearsȱinȱaȱnegativeȱvalue.ȱTheȱ valuesȱusedȱforȱp_sign_posnȱareȱalsoȱusedȱhere.ȱ ȱ Tableȱ16.7ȱȱParametersȱforȱformattingȱlocalȱmonetaryȱvaluesȱ Download at http://www.pin5i.com/ Chapter 16 Standard Libraryȱ 484ȱ formedȱ inȱ accordanceȱ withȱ theȱ ISOȱ 4217:1987ȱ standard.ȱ Theȱ firstȱ threeȱ charactersȱ ofȱ thisȱstringȱareȱtheȱalphabeticȱinternationalȱcurrencyȱsymbol,ȱandȱtheȱfourthȱcharacterȱisȱ usedȱtoȱseparateȱtheȱsymbolȱfromȱtheȱvalue.ȱ Theȱ followingȱ valuesȱ willȱ formatȱ monetaryȱ valuesȱ inȱ aȱ styleȱ acceptableȱ inȱ theȱ UnitedȱStates.ȱ ȱ currency_symbol="$" mon_decimal_point="." mon_thousands_sep="," mon_grouping="\3" positive_sign="" negative_sign="CR" frac_digits='\2' p_cs_precedes='\1' n_cs_precedes='\1' p_sep_by_space='\0' n_sep_by_space='\0' p_sign_posn='\1' n_sign_posn='\2' ȱ Usingȱ theseȱ parameters,ȱ theȱ valuesȱ 1234567890ȱ andȱ Ȭ1234567890ȱ wouldȱ appearȱ asȱ $1,234,567,890.00ȱandȱ$1,234,567,890,00CRȱrespectively.ȱ Settingȱ n_sign_posn='\0'ȱ causesȱ theȱ negativeȱ valueȱ aboveȱ toȱ appearȱ asȱ ($1,234,567,890.00).ȱ ȱ ȱ ȱ 16.9.2 Strings and Locales <string.h> ȱ Theȱ collatingȱsequenceȱofȱaȱmachineȇsȱ characterȱsetȱ isȱ fixed,ȱyetȱtheȱlocaleȱprovidesȱaȱ wayȱtoȱspecifyȱalternateȱsequences.ȱWhenȱaȱcollatingȱsequenceȱotherȱthanȱtheȱdefaultȱ mustȱbeȱused,ȱtheȱfollowingȱtwoȱfunctionsȱareȱprovided.ȱ ȱ int strcoll( char const *s1, char const *s2 ); size_t strxfrm( char *s1, char const *s2, size_t size ); ȱ Theȱ strcollȱ functionȱ comparesȱ theȱ twoȱ stringsȱ asȱ specifiedȱ byȱ theȱ LC_COLLATEȱ categoryȱofȱtheȱcurrentȱlocale.ȱItȱreturnsȱaȱvalueȱlessȱthan,ȱequalȱto,ȱorȱgreaterȱthanȱzeroȱ accordingȱtoȱwhetherȱtheȱfirstȱstringȱisȱlessȱthan,ȱequalȱto,ȱorȱgreaterȱthanȱtheȱsecondȱ string.ȱ Noteȱ thatȱ thisȱ comparisonȱ mayȱ requireȱ considerablyȱ moreȱ computationȱ thanȱ strcmpȱ becauseȱ ofȱ theȱ needȱ toȱ obeyȱ aȱ collatingȱ sequenceȱ thatȱ isȱ notȱ nativeȱ toȱ theȱ machine.ȱ strxfrmȱisȱprovidedȱtoȱreduceȱtheȱcomputationȱrequiredȱwhenȱstringsȱmustȱ beȱcomparedȱrepeatedlyȱinȱthisȱmanner.ȱItȱconvertsȱitsȱsecondȱargument,ȱinterpretedȱinȱ theȱcurrentȱlocale,ȱintoȱanotherȱstringȱthatȱisȱnotȱdependentȱonȱtheȱlocale.ȱAlthoughȱtheȱ contentsȱ ofȱ theȱ convertedȱ stringȱ areȱ indeterminate,ȱ strcmpȱ givesȱ theȱ sameȱ resultȱ comparingȱ twoȱ stringsȱ convertedȱ inȱ thisȱ mannerȱ asȱ strcollȱproducesȱcomparingȱtheȱ originalȱstrings.ȱ Download at http://www.pin5i.com/ 16.10 Summary 16.9.3 485 Effects of Changing the Locale ȱ Changingȱtheȱlocaleȱhasȱsomeȱeffectsȱinȱadditionȱtoȱthoseȱpreviouslyȱdescribed.ȱ 1. Aȱ locateȱ mayȱ addȱ charactersȱ toȱ (butȱ mayȱ notȱ changeȱ theȱ meaningsȱ ofȱ existingȱ charactersȱof)ȱtheȱcharacterȱsetȱusedȱwhenȱtheȱprogramȱisȱexecuting.ȱForȱexample,ȱ manyȱ Europeanȱ languagesȱ makeȱ useȱ ofȱ extendedȱ characterȱ setsȱ thatȱ includeȱ accents,ȱcurrencyȱsymbols,ȱandȱotherȱspecialȱcharacters.ȱ 2. Theȱ directionȱ ofȱ printingȱ mayȱ change.ȱ Specifically,ȱ theȱ localeȱ determinesȱ whereȱ aȱ characterȱshouldȱbeȱprintedȱinȱrelationȱtoȱtheȱpreviousȱcharacterȱthatȱwasȱprinted.ȱ 3. Theȱprintfȱandȱscanfȱfamiliesȱofȱfunctionsȱuseȱtheȱdecimalȱpointȱcharacterȱdefinedȱbyȱ theȱcurrentȱlocale.ȱ 4. Theȱisalpha,ȱislower,ȱisspace,ȱandȱisupperȱfunctionsȱmayȱincludeȱmoreȱcharactersȱ thanȱpreviouslyȱdescribedȱifȱtheȱlocaleȱextendsȱtheȱexecutionȱcharacterȱset.ȱ 5. Theȱ collatingȱ sequenceȱ ofȱ theȱ executionȱ characterȱ setȱ mayȱ change.ȱ Thisȱ isȱ theȱ sequenceȱusedȱbyȱstrcollȱtoȱcompareȱstringsȱtoȱeachȱother.ȱ 6. Manyȱaspectsȱofȱtheȱdateȱandȱtimeȱformatȱproducedȱbyȱstrftimeȱareȱspecificȱtoȱtheȱ locale,ȱasȱpreviouslyȱdescribed.ȱ ȱ ȱ ȱ 16.10 Summary ȱ Theȱ standardȱ libraryȱ includesȱ manyȱ usefulȱ functions.ȱ Theȱ firstȱ groupȱ ofȱ functionsȱ returnȱintegerȱresults.ȱ absȱandȱ labsȱreturnȱtheȱabsoluteȱvalueȱofȱtheirȱarguments.ȱTheȱ divȱ andȱ ldivȱ functionsȱ performȱ integerȱ division.ȱ Unlikeȱ theȱ /ȱ operator,ȱ theȱ valueȱ ofȱ theȱquotientȱisȱwellȱdefinedȱwhenȱoneȱofȱtheȱargumentsȱisȱnegative.ȱTheȱ randȱfunctionȱ returnsȱaȱpseudoȬrandomȱnumber.ȱCallingȱsrandȱallowsȱyouȱtoȱstartȱatȱarbitraryȱpointsȱ inȱ theȱ sequenceȱ ofȱ pseudoȬrandomȱ values.ȱ Theȱ atoiȱ andȱ atolȱ functionsȱ convertȱ aȱ stringȱ toȱ anȱ integerȱ value.ȱ Theȱ strtolȱ andȱ strtoulȱ functionsȱ performȱ theȱ sameȱ conversion,ȱbutȱgiveȱyouȱmoreȱcontrol.ȱ ȱ Mostȱ ofȱtheȱ nextȱgroupȱofȱfunctionsȱ takeȱ doubleȱargumentsȱandȱreturnȱ doubleȱ results.ȱ Theȱ usualȱ trigonometryȱ functions,ȱ sin,ȱ cos,ȱ tan,ȱ asin,ȱ acos,ȱ atan,ȱ andȱ atan2,ȱ areȱ provided.ȱ Theȱ firstȱ threeȱ takeȱ aȱ singleȱ argument,ȱ anȱ angleȱ inȱ radians,ȱ andȱ returnȱ theȱsine,ȱcosine,ȱandȱtangentȱofȱtheȱangle,ȱrespectively.ȱTheȱsecondȱthreeȱreturnȱtheȱarcȱ sine,ȱ arcȱ cosine,ȱ andȱ arcȱ tangentȱ ofȱ theirȱ argument,ȱ respectively.ȱ Theȱ lastȱ functionȱ computesȱarcȱtangentȱfromȱanȱxȱandȱyȱvalue.ȱTheȱhyperbolicȱsine,ȱcosine,ȱandȱtangentȱ areȱcomputedȱbyȱsinh,ȱcoshȱandȱtanh,ȱrespectively.ȱȱTheȱexpȱfunctionȱreturnsȱtheȱvalueȱ Download at http://www.pin5i.com/ 486ȱ Chapter 16 Standard Libraryȱ eȱraisedȱtoȱtheȱpowerȱofȱtheȱargumentȱTheȱ logȱfunctionȱreturnsȱtheȱnaturalȱlogarithmȱ ofȱitsȱargument,ȱandȱlogl0ȱreturnsȱtheȱbaseȱ10ȱlogarithm.ȱ TheȱfrexpȱandȱldexpȱfunctionsȱareȱusefulȱforȱconstructingȱmachineȬindependentȱ representationsȱofȱfloatingȱpointȱnumbers.ȱfrexpȱcomputesȱaȱrepresentationȱforȱaȱgivenȱ value,ȱ andȱ ldexpȱ interpretsȱ aȱ representationȱ toȱ recoverȱ theȱ originalȱ value.ȱ Theȱ modfȱ functionȱ breaksȱ aȱ floatingȬpointȱ valueȱ intoȱ integerȱ andȱ fractionalȱ parts.ȱ Theȱ powȱ functionȱraisesȱitsȱfirstȱargumentȱtoȱtheȱpowerȱspecifiedȱbyȱitsȱsecondȱargument.ȱ sqrtȱ returnsȱ theȱ squareȱ rootȱ ofȱ itsȱ argument.ȱ floorȱ returnsȱ theȱ largestȱ integerȱ notȱ greaterȱ thanȱ itsȱ argument,ȱ andȱ ceilȱ returnsȱ theȱ smallestȱ integerȱ notȱ lessȱ thanȱ itsȱ argument.ȱ fabsȱreturnsȱtheȱabsoluteȱvalueȱofȱitsȱargument.ȱfmodȱtakesȱtwoȱarguments,ȱandȱreturnsȱ theȱ remainderȱ thatȱ resultsȱ fromȱ anȱ integerȱ divisionȱ ofȱ theȱ secondȱ argumentȱ intoȱ theȱ first.ȱ ȱFinally,ȱ theȱ atofȱandȱ strtodȱconvertȱ stringsȱtoȱfloatingȬpointȱ values.ȱ Theȱ latterȱ functionȱprovidesȱmoreȱcontrolȱoverȱtheȱconversion.ȱ Theȱ nextȱ groupȱ ofȱ functionsȱ dealȱ withȱ datesȱ andȱ times.ȱ clockȱ returnsȱ theȱ amountȱ ofȱ processorȱ timeȱ usedȱ byȱ aȱ programȱ sinceȱ itȱ beganȱ executing.ȱ Theȱ timeȱ functionȱreturnsȱtheȱcurrentȱdateȱandȱtimeȱofȱdayȱasȱaȱtime_tȱvalue.ȱTheȱctimeȱfunctionȱ convertsȱ aȱ time_tȱ valueȱ intoȱ aȱ humanȬreadableȱ representationȱ ofȱ theȱ dateȱ andȱ time.ȱ difftimeȱcomputesȱtheȱdifferenceȱinȱsecondsȱbetweenȱtwoȱ time_tȱvalues.ȱ gmtimeȱandȱ localtimeȱconvertȱaȱ time_tȱvalueȱtoȱaȱ struct tmȱcontainingȱallȱofȱtheȱcomponentsȱofȱ theȱdateȱandȱtime.ȱTheȱformerȱfunctionȱusesȱUniversalȱCoordinatedȱTimeȱandȱtheȱlatterȱ usesȱlocalȱtime.ȱTheȱ asctimeȱandȱ strftimeȱfunctionsȱconvertȱaȱ struct tmȱtoȱaȱhumanȬ readableȱrepresentationȱofȱtheȱdateȱandȱtime.ȱTheȱlatterȱfunctionȱprovidesȱgreatȱcontrolȱ overȱtheȱformatȱofȱtheȱresult.ȱFinally,ȱ mktimeȱnormalizesȱtheȱvaluesȱinȱaȱstruct tmȱandȱ convertsȱthemȱtoȱaȱtime_tȱvalue.ȱ Nonlocalȱjumpsȱareȱprovidedȱbyȱ setjmpȱandȱ longjmp.ȱȱ setjmpȱisȱcalledȱtoȱsaveȱ processorȱstateȱ informationȱ inȱ aȱ jmp_bufȱvariable.ȱ Then,ȱaȱ subsequentȱcallȱtoȱ longjmpȱ restoresȱ theȱ savedȱ processorȱ state.ȱ longjmpȱ mayȱ notȱ beȱ calledȱ alterȱ theȱ functionȱ thatȱ calledȱsetjmpȱreturns.ȱ Signalsȱ representȱ unexpectedȱ eventsȱ thatȱ mayȱ occurȱ duringȱ theȱ executionȱ ofȱ aȱ program,ȱ suchȱ asȱ aȱ userȱ interruptȱ orȱ anȱ arithmeticȱ error.ȱ Theȱ defaultȱ actionȱ whenȱ aȱ signalȱoccursȱisȱimplementationȱdefined,ȱthoughȱterminatingȱtheȱprogramȱisȱcommon.ȱȱ Youȱmayȱchangeȱtheȱdefaultȱactionȱbyȱdefiningȱaȱsignalȱhandlerȱandȱinstallingȱitȱwithȱ theȱ signalȱ function.ȱ Theȱ typeȱ ofȱ workȱ thatȱ youȱ mayȱ performȱ inȱ aȱ signalȱ handlerȱ isȱ severelyȱrestrictedȱbecauseȱtheȱprogramȱmayȱbeȱinȱanȱinconsistentȱstateȱafterȱtheȱsignalȱ occurs.ȱ Volatileȱ dataȱ mayȱ changeȱ itsȱ value,ȱ apparentlyȱ allȱ byȱ itself.ȱ Forȱ example,ȱ aȱ variableȱ thatȱ isȱ changedȱ inȱ aȱ signalȱ handlerȱ shouldȱ beȱ declaredȱ volatile.ȱ Theȱ raiseȱ functionȱcausesȱtheȱsignalȱindicatedȱbyȱitsȱargumentȱtoȱoccur.ȱ ȱ Download at http://www.pin5i.com/ 16.11 Summary of Cautions 487 Theȱ vprintf,ȱ vfprintf,ȱ andȱ vsprintfȱ functionsȱ performȱ theȱ sameȱ workȱ asȱ theȱ printfȱfamilyȱofȱfunctions,ȱexceptȱthatȱtheȱvaluesȱtoȱbeȱprintedȱareȱpassedȱasȱaȱvariableȱ argumentȱ list.ȱ Theȱ abortȱ functionȱ abortsȱ theȱ programȱ byȱ raisingȱ theȱ SIGABRTȱ signal.ȱ Theȱatexitȱfunctionȱregistersȱexitȱfunctions,ȱwhichȱareȱcalledȱbeforeȱtheȱprogramȱexits.ȱȱ Theȱassertȱmacroȱisȱusedȱtoȱterminateȱtheȱprogramȱwhenȱanȱexpressionȱthatȱshouldȱbeȱ trueȱ isȱ actuallyȱ false.ȱ Whenȱ debuggingȱ isȱ completed,ȱ definingȱ theȱ NDEBUGȱ symbolȱ eliminatesȱtheȱassertionsȱwithoutȱdeletingȱthemȱfromȱtheȱsourceȱcode.ȱgetenvȱretrievesȱ valuesȱfromȱtheȱoperatingȱsystemȱenvironment.ȱ systemȱtakesȱaȱstringȱasȱanȱargument,ȱ andȱusesȱtheȱlocalȱcommandȱprocessorȱtoȱexecuteȱtheȱstringȱasȱaȱcommand.ȱ Theȱ qsortȱ functionȱ sortsȱ anȱ arrayȱ ofȱ valuesȱ intoȱ ascendingȱ order,ȱ andȱ theȱ bsearchȱfunctionȱperformsȱaȱbinaryȱsearchȱtoȱlocateȱaȱvalueȱinȱaȱsortedȱarray.ȱBothȱofȱ theseȱfunctionsȱareȱtypeless—theyȱworkȱonȱarraysȱofȱanyȱtypeȱofȱdata.ȱ Aȱ localeȱ isȱ aȱ setȱ ofȱ parametersȱ thatȱ tailorȱ theȱ behaviorȱ ofȱ Cȱ programsȱ toȱ countriesȱaroundȱtheȱworld.ȱTheȱsetlocaleȱfunctionȱisȱusedȱtoȱchangeȱtheȱentireȱlocaleȱ orȱ partsȱ ofȱ it.ȱ Theȱ localeȱ includesȱ parametersȱ thatȱ defineȱ howȱ numericȱ formattingȱ shouldȱ beȱ performed.ȱ Theȱ typesȱ ofȱ valuesȱ describedȱ includeȱ nonmonetary,ȱ localȱ monetary,ȱ andȱ internationalȱ monetaryȱ values.ȱ Theȱ localeȱ doesȱ notȱ performȱ anyȱ formatting,ȱ itȱ simplyȱ providesȱ theȱ specificationsȱ forȱ theȱ formatting.ȱ Aȱ localeȱ canȱ specifyȱaȱcollatingȱsequenceȱthatȱisȱdifferentȱfromȱtheȱmachineȇsȱdefaultȱsequence.ȱȱInȱ thisȱ case,ȱ strxcollȱ isȱ usedȱ toȱ compareȱ stringsȱ accordingȱ toȱ theȱ currentȱ collatingȱ sequence.ȱ Theȱ valueȱ thatȱ itȱ returnsȱ isȱ analogousȱ toȱ thatȱ returnedȱ byȱ strcmp.ȱ Theȱ strxfrmȱfunctionȱconvertsȱaȱstringȱinȱtheȱcurrentȱcollatingȱsequenceȱtoȱaȱstringȱinȱtheȱ defaultȱ collatingȱ sequence.ȱ Stringsȱ convertedȱ inȱ thisȱ mannerȱ canȱ beȱ comparedȱ withȱ strcmp;ȱ theȱ resultȱ ofȱ theȱ comparisonȱ willȱ beȱ theȱ sameȱ asȱ theȱ resultȱ ofȱ comparingȱ theȱ originalȱstringsȱwithȱstrxcoll.ȱ ȱ ȱ ȱ ȱ 16.11 Summary of Cautions ȱ 1. Notȱ includingȱ theȱ math.hȱ headerȱ fileȱ canȱ makeȱ theȱ mathȱ functionsȱ produceȱ incorrectȱresultsȱ(pageȱ457).ȱ 2. Theȱclockȱfunctionȱmayȱonlyȱbeȱanȱapproximationȱofȱprocessorȱtimeȱ(pageȱ461).ȱ 3. Theȱvalueȱreturnedȱbyȱtimeȱisȱnotȱnecessarilyȱsecondsȱ(pageȱ462).ȱ 4. Theȱmonthȱinȱaȱstruct tmȱisȱnotȱaȱnumberȱinȱtheȱrangeȱ1Ȭ12ȱ(pageȱ463).ȱ Download at http://www.pin5i.com/ 488ȱ Chapter 16 Standard Libraryȱ 5. Theȱyearȱinȱaȱstruct tmȱisȱtheȱnumberȱofȱyearsȱsinceȱ1900ȱ(pageȱ464).ȱ 6. longjmpȱmayȱnotȱbeȱusedȱtoȱreturnȱtoȱaȱfunctionȱthatȱisȱnoȱlongerȱactiveȱ(pageȱ468).ȱ 7. Callingȱ exitȱorȱ abortȱfromȱtheȱhandlerȱofȱanȱasynchronousȱsignalȱisȱnotȱsafeȱ(pageȱ 472).ȱ 8. Youȱmustȱreinstallȱaȱsignalȱhandlerȱeachȱtimeȱtheȱsignalȱoccursȱ(pageȱ474).ȱ 9. Avoidȱmultipleȱcallsȱtoȱexitȱ(pageȱ475).ȱ ȱ ȱ ȱ 16.12 Summary of Programming Tips ȱ 1. Misusingȱsetjmpȱandȱlongjmpȱleadsȱtoȱspaghettiȱcodeȱ(pageȱ468).ȱ 2. Handlingȱsignalsȱmakesȱprogramsȱlessȱportableȱ(pageȱ474).ȱ 3. Usingȱassertionsȱsimplifiesȱdebuggingȱ(pageȱ476),ȱ ȱ ȱ ȱ 16.13 Questions ȱ 1. Whatȱdoesȱtheȱfollowingȱfunctionȱcallȱreturn?ȱ ȱ strtol( "12345", NULL, -5 ); 2. IfȱtheȱȇȇrandomȈȱnumbersȱproducedȱbyȱtheȱ randȱfunctionȱareȱnotȱtrulyȱrandom,ȱareȱ theyȱreallyȱanyȱgood?ȱ 3. Whatȱisȱtheȱresultȱofȱtheȱfollowingȱprogramȱonȱyourȱsystem?ȱ ȱ #include <stdlib.h> int main() { int i; for( i = 0; i < 100; i += 1 ) printf( "%d\n", rand() % 2 ); } 4. Howȱwouldȱyouȱwriteȱaȱprogramȱtoȱdetermineȱwhetherȱtheȱclockȱfunctionȱonȱyourȱ systemȱmeasuresȱtheȱcpuȱtimeȱusedȱorȱelapsedȱtime?ȱ 5. Theȱfollowingȱcodeȱfragmentȱattemptsȱtoȱprintȱtheȱcurrentȱtimeȱinȱmilitaryȱformat.ȱȱ Whatȱisȱwrongȱwithȱit?ȱ Download at http://www.pin5i.com/ 16.13 Questions 489 #include <time.h> struct tm *tm; time_t now; ... now = time(); tm = locatime( now ); printf( "%d:%02d:%02d %d/%02d/%02d\n" tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_mon, tm->tm_mday, tm->tm_year ); 6. Whatȱisȱwrongȱwithȱtheȱfollowingȱprogram?ȱWhatȱhappensȱwhenȱitȱisȱexecutedȱonȱ yourȱsystem?ȱ ȱ #include <stdlib.h> #include <setjmp.h> jmp_buf jbuf; void set_buffer() { setjmp( jbuf ); } int main( int ac, char **av ) { int a = atoi( av[ 1 ] ); int b = atoi( av[ 2 ] ); set_buffer(); printf( "%d plus %d equals %d\n", a, b, a + b ); longjmp( jbuf, 1 ); printf( "After longjmp\n" ); return EXIT_SUCCESS; } 7. Writeȱ aȱ programȱ thatȱ willȱ determineȱ whetherȱ anȱ integerȱ divisionȱ byȱ zeroȱ orȱ aȱ floatingȬpointȱdivisionȱbyȱzeroȱresultsȱinȱaȱ SIGFPEȱsignal.ȱHowȱdoȱyouȱexplainȱtheȱ results?ȱ 8. Theȱcomparisonȱfunctionȱusedȱbyȱ qsortȱshouldȱreturnȱaȱnegativeȱvalueȱifȱtheȱfirstȱ argumentȱ isȱ lessȱ thanȱ theȱ second,ȱ andȱ aȱ positiveȱ valueȱ ifȱ theȱ firstȱ argumentȱ isȱ greaterȱ thanȱ theȱ second.ȱ Wouldȱ itȱ makeȱ anyȱ differenceȱ inȱ qsortȇsȱ behaviorȱ ifȱ theȱ comparisonȱfunctionȱreturnedȱtheȱoppositeȱvaluesȱinstead?ȱ Download at http://www.pin5i.com/ Chapter 16 Standard Libraryȱ 490ȱ 16.14 Programming Exercises ȱ 1. Aȱpopularȱjokeȱamongȱcomputerȱpeopleȱisȱtoȱsay,ȱȈMyȱageȱisȱ29,ȱbutȱIȇmȱnotȱtellingȱ youȱ theȱ baseȱ ofȱ thatȱ number!Ȉȱ Ifȱ theȱ baseȱ isȱ 16,ȱ theȱ personȱ isȱ reallyȱ 41ȱ yearsȱ old.ȱ Writeȱaȱprogramȱthatȱtakesȱanȱageȱasȱaȱcommandȱlineȱargumentȱandȱcomputesȱtheȱ smallestȱ radixȱ (base)ȱ inȱ theȱ rangeȱ 2ȱ throughȱ 36ȱ forȱ whichȱ theȱ ageȱ appearsȱ toȱ beȱ aȱ numberȱ lessȱ thanȱ orȱ equalȱ toȱ 29.ȱ Forȱ example,ȱ ifȱ theȱ userȱ entersȱ 41,ȱ theȱ programȱ shouldȱsayȱtoȱuseȱbaseȱ16ȱbecauseȱdecimalȱ41ȱisȱ29ȱinȱbaseȱ16.ȱ 2. Writeȱ aȱ functionȱ thatȱ simulatesȱ theȱ throwingȱ ofȱ aȱ sixȬsidedȱ dieȱ byȱ returningȱ aȱ randomȱintegerȱinȱtheȱrangeȱ1ȱthroughȱ6.ȱBeȱsureȱthatȱeachȱofȱtheȱvaluesȱisȱequallyȱ likelyȱ toȱ appear.ȱ Theȱ firstȱ timeȱ theȱ functionȱ isȱ called,ȱ itȱ shouldȱ seedȱ theȱ randomȱ numberȱgeneratorȱwithȱtheȱtimeȱofȱday.ȱ 3. WriteȱaȱprogramȱthatȱtellsȱtheȱcurrentȱtimeȱofȱdayȱasȱaȱthreeȬyearȬoldȱchildȱwouldȱ (forȱexample,ȱtheȱbigȱhandȱisȱonȱtheȱ6ȱandȱtheȱlittleȱhandȱisȱonȱtheȱ12).ȱ 4. Writeȱ aȱ programȱ thatȱ takesȱ threeȱ integersȱ asȱ commandȱ lineȱ argumentsȱ andȱ interpretsȱ themȱ asȱ aȱ monthȱ (1Ȭ12),ȱ aȱ dayȱ (1Ȭ31),ȱ andȱ a.ȱ yearȱ (0Ȭ?).ȱ Itȱ shouldȱ thenȱ printȱ theȱ dayȱ ofȱ theȱ weekȱ onȱ whichȱ theȱ specifiedȱ dateȱ fellȱ (orȱ willȱ fall).ȱ Forȱ whatȱ rangeȱofȱyearsȱisȱitȱaccurate?ȱ 5. Winterȱ weatherȱ reportsȱ oftenȱ giveȱ theȱ Ȉwindȱ chill,Ȉȱ whichȱ measuresȱ howȱ coldȱ aȱ particularȱ temperatureȱ andȱ windȱ speedȱ feel.ȱ Forȱ example,ȱ ifȱ itȱ isȱ Ȭ5°ȱ Celsiusȱ (23°ȱ Fahrenheit)ȱ withȱ aȱ windȱ ofȱ 10ȱ metersȱ perȱ secondȱ (22.37ȱ mph),ȱ theȱ windȱ chillȱ temperatureȱisȱȬ22.3°ȱCelsiusȱ(Ȭ8.2°ȱFahrenheit).ȱ Writeȱaȱfunctionȱwithȱtheȱfollowingȱprototypeȱtoȱcomputeȱtheȱwindȱchill.ȱ ȱ double wind_chill( double temp, double velocity ); ȱ tempȱisȱtheȱairȱtemperatureȱinȱdegreesȱCelsius,ȱandȱ velocityȱisȱtheȱwindȱspeedȱinȱ metersȱperȱsecond.ȱTheȱfunctionȱreturnsȱtheȱwindȱchillȱtemperature,ȱwhichȱisȱalsoȱ inȱdegreesȱCelsius.ȱ Windȱchillȱisȱcomputedȱusingȱthisȱformula:ȱ ȱ A B V CV 't Windchil A B X CX ȱ ȱ Forȱ aȱ givenȱ airȱ temperatureȱ andȱ windȱ velocity,ȱ itȱ givesȱ theȱ temperatureȱ thatȱ producesȱtheȱsameȱcoolingȱeffectȱwithȱaȱ4ȱmphȱwindȱ(theȱwindȱchillȱstandard).ȱVȱisȱ theȱ windȱ velocityȱ inȱ metersȱ perȱ second.ȱ Atȱ isȱ 33ȱ Ȭȱ temp,ȱ theȱ differenceȱ betweenȱ neutralȱskinȱtemperatureȱofȱ33°ȱCelsiusȱandȱtheȱairȱtemperature.ȱTheȱconstantsȱareȱ A=10.45,ȱ B=10,ȱ C=-1,ȱ andȱ X=1.78816,ȱ whichȱ isȱ 4ȱ mphȱ convertedȱ toȱ metersȱ perȱ second.ȱȱ ȱ Download at http://www.pin5i.com/ 16.14 Programming Exercises 491 6. Theȱformulaȱforȱdeterminingȱtheȱmonthlyȱpaymentȱforȱaȱmortgageȱisȱ ȱ AI P N 1 1 I ȱ ȱ whereȱAȱisȱtheȱamountȱofȱtheȱloan,ȱIȱisȱtheȱinterestȱrateȱperȱperiodȱ(asȱaȱdecimal,ȱnotȱ aȱpercentage),ȱandȱNȱisȱtheȱnumberȱofȱperiodsȱoverȱwhichȱtheȱloanȱwillȱbeȱrepaid.ȱ Forȱ example,ȱ aȱ $100,000ȱ loanȱ repaidȱ overȱ 20ȱ yearsȱ alȱ 8%ȱ interestȱ hasȱ aȱ monthlyȱ paymentȱofȱ$836.44ȱ(20ȱyearsȱisȱ240ȱpaymentȱperiods,ȱandȱtheȱinterestȱperȱpaymentȱ periodȱisȱ0.66667).ȱ Writeȱtheȱfunction,ȱprototypedȱbelow,ȱtoȱcomputeȱtheȱloanȱpayment.ȱ ȱ double payment( double amount, double interest, int year ); ȱ yearsȱ specifiesȱ theȱ durationȱ ofȱ theȱ loan,ȱ amountȱ isȱ theȱ amountȱ ofȱ theȱ loan,ȱ andȱ interestȱisȱtheȱannualȱinterestȱrateȱexpressedȱasȱaȱpercentageȱ(forȱexample,ȱ12%).ȱ Theȱ functionȱ shouldȱ computeȱ andȱ returnȱ theȱ monthlyȱ paymentȱ forȱ theȱ loan,ȱ roundedȱtoȱtheȱnearestȱpenny.ȱ ȱ 7. WellȬdesignedȱrandomȱnumberȱgeneratorsȱreturnȱvaluesȱthatȱappearȱtoȱbeȱrandom,ȱ yetȱoverȱtimeȱareȱuniform.ȱNumbersȱderivedȱfromȱtheȱrandomȱvaluesȱshouldȱalsoȱ haveȱtheseȱ properties.ȱForȱexample,ȱaȱpoorlyȱdesignedȱrandomȱnumberȱgeneratorȱ mightȱ returnȱ valuesȱ thatȱ appearȱ randomȱ butȱ inȱ factȱ alternateȱ betweenȱ evenȱ andȱ oddȱnumbers.ȱIfȱtheseȱseeminglyȱrandomȱvaluesȱareȱtakenȱmoduloȱtwoȱ(toȱsimulateȱ theȱresultsȱofȱflippingȱaȱcoin,ȱforȱinstance),ȱtheȱresultȱisȱanȱalternatingȱsequenceȱofȱ zerosȱ andȱ ones.ȱ Aȱ differentȱ flawȱ wouldȱ beȱ aȱ generatorȱ thatȱ returnedȱ onlyȱ oddȱ values.ȱȱTakingȱtheseȱvaluesȱmoduloȱtwoȱwouldȱresultȱinȱaȱcontinuousȱsequenceȱofȱ ones.ȱȱNeitherȱofȱtheseȱsequencesȱcanȱbeȱusedȱbecauseȱtheyȱareȱnotȱrandomȱenough.ȱ Writeȱ aȱ programȱ toȱ testȱ theȱ randomȱ numberȱ generatorȱ onȱ yourȱ system.ȱ Youȱ shouldȱgenerateȱ10,000ȱrandomȱnumbersȱandȱperformȱtwoȱtypesȱofȱtests.ȱTheȱfirstȱ isȱaȱfrequencyȱtest.ȱTakeȱeachȱrandomȱnumberȱmoduloȱtwo,ȱandȱcountȱhowȱmanyȱ timesȱtheȱresultȱisȱzeroȱandȱone.ȱȱDoȱtheȱsameȱforȱmoduloȱthreeȱthroughȱten.ȱTheȱ resultsȱ willȱ notȱ beȱ preciselyȱ uniform,ȱ butȱ thereȱ shouldȱ notȱ beȱ anyȱ largeȱ peaksȱ orȱ valleysȱinȱtheȱfrequencies.ȱ Theȱsecondȱtestȱchecksȱforȱcyclicȱfrequency.ȱȱTakeȱeachȱrandomȱnumberȱandȱtheȱ precedingȱ oneȱ moduloȱ two.ȱ Useȱ theseȱ remaindersȱ asȱ theȱ subscriptsȱ ofȱ aȱ twoȬ dimensionalȱ arrayȱ andȱ incrementȱ theȱ specifiedȱ location.ȱ Repeatȱ forȱ moduloȱ threeȱ throughȱ ten.ȱ Onceȱ again,ȱ theȱ resultsȱ willȱ notȱ beȱ exactlyȱ even,ȱ butȱ theyȱ shouldȱ beȱ approximatelyȱuniform.ȱ Modifyȱ yourȱ programȱ soȱ thatȱ youȱ canȱ provideȱ differentȱ valuesȱ toȱ seedȱ theȱ randomȱnumberȱgenerator,ȱandȱrunȱtestsȱwithȱseveralȱdifferentȱseeds.ȱȱHowȱgoodȱisȱ yourȱrandomȱnumberȱgenerator?ȱ Download at http://www.pin5i.com/ 492ȱ Chapter 16 Standard Libraryȱ 8. Aȱcertainȱdataȱfileȱcontainsȱtheȱagesȱofȱfamilyȱmembers.ȱTheȱagesȱofȱtheȱmembersȱofȱ oneȱ familyȱ areȱ allȱ onȱ theȱ sameȱ line,ȱ separatedȱ byȱ whiteȱ space.ȱ Forȱ example,ȱ thisȱ dataȱ ȱ 45 42 22 36 35 7 3 1 22 20 ȱ describesȱthreeȱfamiliesȱhavingȱthree,ȱfive,ȱandȱtwoȱmembers,ȱrespectively.ȱ Writeȱaȱprogramȱthatȱcomputesȱtheȱaverageȱageȱofȱeachȱfamilyȱrepresentedȱinȱaȱ fileȱofȱthisȱsort.ȱȱItȱshouldȱprintȱtheȱaverageȱageȱusingȱtheȱ%5.2fȱformat,ȱfollowedȱbyȱ aȱ colonȱ andȱ theȱ inputȱ data.ȱ Thisȱ problemȱ isȱ identicalȱ toȱ oneȱ fromȱ theȱ previousȱ chapterȱbutȱwithoutȱtheȱlimitationȱonȱhowȱmanyȱmembersȱaȱfamilyȱcanȱhave!ȱYouȱ may,ȱhowever,ȱassumeȱthatȱtheȱinputȱlinesȱwillȱnotȱexceedȱ512ȱcharactersȱeach.ȱ 9. Whatȱareȱ theȱ oddsȱ ofȱ2ȱstudentsȱ inȱaȱclassȱofȱ30ȱ sharingȱtheȱ sameȱbirthday?ȱ Howȱ bigȱ wouldȱ aȱ groupȱ ofȱ peopleȱ haveȱ toȱ beȱ forȱ theȱ oddsȱ ofȱ anyȱ 2ȱ ofȱ themȱ sharingȱ aȱ birthdayȱtoȱbeȱ50%?ȱ Writeȱaȱprogramȱtoȱdetermineȱtheseȱanswers.ȱGetȱ30ȱrandomȱnumbersȱandȱtakeȱ themȱmoduloȱ365ȱtoȱrepresentȱdaysȱofȱtheȱyearȱ(ignoreȱleapȱyears).ȱThenȱcheckȱtoȱ seeȱifȱanyȱofȱtheȱnumbersȱmatch.ȱRepeatȱthisȱtestȱ10,000ȱtimesȱtoȱgetȱanȱestimateȱforȱ theȱodds.ȱ Toȱ answerȱ theȱ secondȱ question,ȱ modifyȱ theȱ programȱ soȱ thatȱ itȱ willȱ acceptȱ theȱ groupȱsizeȱasȱaȱcommandȱlineȱargument.ȱSeedȱtheȱrandomȱnumberȱgeneratorȱwithȱ theȱtimeȱofȱday,ȱandȱrunȱtheȱprogramȱseveralȱtimesȱtoȱgetȱanȱideaȱofȱhowȱaccurateȱ theȱoddsȱestimateȱis.ȱ 10. Anȱ insertionȱ sortȱ isȱ performedȱ byȱ addingȱ valuesȱ toȱ anȱ arrayȱ oneȱ byȱ one.ȱ Theȱ firstȱ valueȱ isȱ simplyȱ storedȱ atȱ theȱ beginningȱ ofȱ theȱ array.ȱ Eachȱ subsequentȱ valueȱ isȱ addedȱbyȱfindingȱitsȱproperȱpositionȱinȱtheȱarray,ȱmovingȱexistingȱvaluesȱasȱneededȱ toȱmakeȱroomȱforȱit,ȱandȱthenȱinsertingȱit.ȱ Writeȱ aȱ functionȱ calledȱ insertion_sortȱ thatȱ performsȱ thisȱ task.ȱ Itsȱ prototypeȱ shouldȱ beȱ theȱ sameȱ asȱ qsort.ȱ Hint:ȱ Considerȱ theȱ arrayȱ thatȱ youȱ getȱ asȱ havingȱ aȱ sortedȱ partȱ onȱ theȱ leftȱ andȱ anȱ unsortedȱ partȱ onȱ theȱ right.ȱ Initiallyȱ theȱ sortedȱ partȱ willȱ beȱ empty.ȱ Asȱ yourȱ functionȱ insertsȱ eachȱ value,ȱ theȱ boundaryȱ betweenȱ theȱ sortedȱandȱunsortedȱpartsȱmovesȱtoȱaccommodateȱtheȱinsertion.ȱWhenȱallȱelementsȱ haveȱbeenȱinserted,ȱtheȱunsortedȱpartȱisȱnowȱemptyȱandȱtheȱarrayȱisȱsorted.ȱ Download at http://www.pin5i.com/ 17 Classic Abstract Data Types Thereȱ areȱ severalȱ abstractȱ dataȱ typesȱ (ADTs)ȱ whoseȱ propertiesȱ makeȱ themȱ soȱ usefulȱ thatȱ theyȱ areȱ indispensableȱ componentsȱ ofȱ aȱ Cȱ programmerȇsȱ toolkit:ȱ theȱ list,ȱ stack,ȱ queue,ȱ andȱ tree.ȱ Linkedȱ listsȱ wereȱ discussedȱ inȱ Chapterȱ 12;ȱ thisȱ chapterȱ coversȱ theȱ remainingȱADTs.ȱ Theȱfirstȱpartȱofȱtheȱchapterȱdescribesȱtheȱpropertiesȱandȱbasicȱimplementationsȱ ofȱ theseȱ structures.ȱ Theȱ chapterȱ endsȱ byȱ discussingȱ howȱ toȱ improveȱ theȱ flexibilityȱ ofȱ theirȱimplementationsȱandȱtheȱresultingȱsafetyȱcompromises.ȱ ȱ ȱ ȱ 17.1 Memory Allocation ȱ ThereȱisȱoneȱdecisionȱthatȱmustȱbeȱmadeȱforȱallȱADTs—howȱtoȱobtainȱtheȱmemoryȱthatȱ storesȱtheȱvalues.ȱThereȱareȱthreeȱchoices:ȱaȱstaticȱarray,ȱaȱdynamicallyȱallocatedȱarray,ȱ andȱaȱdynamicallyȱallocatedȱlinkedȱstructure.ȱ Theȱstaticȱarrayȱimposesȱaȱfixedȱsizeȱonȱtheȱstructure.ȱMoreover,ȱthisȱsizeȱmustȱ beȱdeterminedȱatȱcompileȱtime.ȱHowever,ȱitȱisȱtheȱsimplestȱtechniqueȱandȱleastȱproneȱ toȱerror.ȱ Usingȱaȱdynamicȱarrayȱletsȱyouȱwaitȱuntilȱruntimeȱtoȱdecideȱhowȱbigȱtoȱmakeȱ theȱ array.ȱ Itȱ alsoȱ letsȱ youȱ dynamicallyȱ resizeȱ theȱ arrayȱ whenȱ neededȱ byȱ allocatingȱ aȱ new,ȱlargerȱarray,ȱcopyingȱtheȱvaluesȱfromȱtheȱoriginalȱarrayȱtoȱtheȱnewȱone,ȱandȱthenȱ deletingȱ theȱ originalȱ array.ȱ Inȱ decidingȱ whetherȱ orȱ notȱ toȱ useȱ aȱ dynamicȱ array,ȱ youȱ mustȱweighȱtheȱincreasedȱcomplexityȱagainstȱtheȱflexibilityȱofȱanȱADTȱwithoutȱaȱfixed,ȱ predeterminedȱsizeȱlimit.ȱ Finally,ȱ linkedȱ structuresȱ offerȱ theȱ greatestȱ flexibility.ȱ Eachȱ elementȱ isȱ individuallyȱallocatedȱwhenȱneeded,ȱsoȱthereȱisnȇtȱanyȱmaximumȱsizeȱrestrictionȱotherȱ thanȱ theȱ memoryȱ availableȱ onȱ theȱ machine.ȱ However,ȱ aȱ linkedȱ structureȱ consumesȱ extraȱ memoryȱ forȱ theȱ links,ȱ andȱ traversingȱ aȱ linkedȱ structureȱ toȱ accessȱ aȱ specificȱ elementȱisȱnotȱasȱefficientȱasȱaccessingȱaȱvalueȱinȱanȱarray.ȱ Download at http://www.pin5i.com/ Chapter 17 Classic Abstract Data Typesȱ 494ȱ ȱ 17.2 Stacks ȱ Theȱ stackȱ isȱ aȱ dataȱ structureȱ characterizedȱ byȱ itsȱ LastȬInȱ FirstȬOutȱ orȱ LIFOȱ behavior.ȱ Partygoersȱareȱwellȱacquaintedȱwithȱstacks;ȱtheȱhostȇsȱdrivewayȱisȱaȱstackȱofȱcars.ȱTheȱ lastȱcarȱparkedȱisȱtheȱfirstȱoneȱthatȱmustȱbeȱremoved,ȱandȱtheȱfirstȱcarȱthatȱwasȱparkedȱ cannotȱbeȱmovedȱuntilȱallȱtheȱothersȱareȱgone.ȱ ȱ ȱ ȱ 17.2.1 Stack Interface ȱ Theȱbasicȱstackȱoperationsȱareȱusuallyȱcalledȱpushȱandȱpop.ȱPushȱaddsȱaȱnewȱvalueȱtoȱ theȱ topȱ ofȱ theȱ stack,ȱ andȱ popȱ removesȱ theȱ topmostȱ valueȱ andȱ returnsȱ it.ȱ Accessȱ isȱ providedȱonlyȱtoȱtheȱtopȱvalueȱonȱtheȱstack.ȱ Inȱ theȱ traditionalȱ stackȱ interface,ȱ theȱ onlyȱ wayȱ toȱ accessȱ theȱ topȱ elementȱ isȱ toȱ removeȱ it.ȱAnȱ alternativeȱinterfaceȱ forȱ theȱstackȱ hasȱ threeȱbasicȱ operations:ȱpush,ȱ pop,ȱ andȱtop.ȱȱPushȱoperatesȱasȱdescribedȱabove,ȱbutȱpopȱsimplyȱremovesȱtheȱtopȱelement— itsȱvalueȱisȱnotȱreturned.ȱTopȱreturnsȱtheȱvalueȱofȱtheȱtopȱelementȱwithoutȱremovingȱitȱ fromȱtheȱstack.ȱ TIP Theȱtraditionalȱ popȱfunctionȱhasȱaȱsideȱeffect:ȱitȱchangesȱtheȱstateȱofȱtheȱstack.ȱItȱisȱalsoȱ theȱ onlyȱ wayȱ toȱ accessȱ theȱ topȱ elementȱ ofȱ theȱ stack.ȱ Havingȱ aȱ topȱ functionȱ letsȱ youȱ repeatedlyȱaccessȱtheȱvalueȱonȱtheȱtopȱofȱtheȱstackȱwithoutȱhavingȱtoȱsaveȱitȱinȱaȱlocalȱ variable.ȱ Thisȱ capabilityȱ isȱ anotherȱ exampleȱ ofȱ theȱ benefitsȱ ofȱ designingȱ functionsȱ withoutȱsideȱeffects.ȱ Weȱ needȱ twoȱ additionalȱ functionsȱ toȱ useȱ theȱ stack.ȱ Anȱ emptyȱ stackȱ cannotȱ beȱ popped,ȱ soȱ weȱ needȱ aȱ functionȱ toȱ tellȱ usȱ ifȱ theȱ stackȱ isȱ empty.ȱ Aȱ stackȱ implementedȱ withȱaȱmaximumȱsizeȱlimitȱshouldȱhaveȱaȱfunctionȱthatȱtellsȱusȱwhetherȱtheȱstackȱisȱfullȱ ȱ ȱ ȱ 17.2.2 Implementing a Stack ȱ TheȱstackȱisȱoneȱofȱtheȱeasiestȱADTsȱtoȱimplement.ȱTheȱbasicȱapproachȱisȱtoȱstoreȱsheȱ valuesȱintoȱsuccessiveȱlocationsȱinȱanȱarrayȱasȱtheyȱareȱpushed.ȱYouȱmustȱkeepȱtrackȱofȱ theȱsubscriptȱofȱtheȱvalueȱthatȱwasȱmostȱrecentlyȱpushed.ȱToȱpopȱtheȱstackȱyouȱsimplyȱ decrementȱ thisȱ value.ȱ Theȱ headerȱ fileȱ inȱ Programȱ 17.1ȱ describesȱ theȱ nontraditionalȱ interfaceȱforȱaȱstackȱmodule.ȱ TIP Noteȱ thatȱ theȱ interfaceȱ containsȱ onlyȱ theȱ informationȱ thatȱ aȱ clientȱ needsȱ toȱ useȱ theȱ stack;ȱ specifically,ȱ itȱ doesȱ notȱ revealȱ howȱ dieȱ stackȱ isȱ implemented.ȱ Inȱ fact,ȱ withȱ aȱ minorȱ modificationȱ thatȱ weȱ discussȱ later,ȱ thisȱ sameȱ headerȱ fileȱ canȱ beȱ usedȱ withȱ allȱ threeȱ implementationȱ techniques.ȱ Definingȱ theȱ interfaceȱ inȱ thisȱ mannerȱ isȱ goodȱ practiceȱ becauseȱ itȱ preventsȱ theȱ clientȱ fromȱ makingȱ assumptionsȱ thatȱ dependȱ onȱ aȱ particularȱimplementation.ȱ Download at http://www.pin5i.com/ 17.2 Stacksȱ 495 ȱ ȱ ȱ /* ** Interface for a stack module */ #define STACK_TYPE int /* Type of value on the stack */ /* ** push ** Pushes a new value on the stack. ** to be pushed. */ void push( STACK_TYPE value ); The argument is the value /* ** pop ** Pops a value off of the stack, discarding it. */ void pop( void ); /* ** top ** Returns the topmost value on the stack without changing the ** stack. */ STACK_TYPE top( void ); /* ** is_empty ** Returns TRUE if the stack is empty, else FALSE. */ int is_empty( void ); /* ** is_full ** Returns TRUE if the stack is full, else FALSE. */ int is_full( void ); ȱ Programȱ17.1ȱȱStackȱinterfaceȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱȱȱstack.hȱ ȱ ȱ ȱ ȱ ȱ Anȱ interestingȱ featureȱ ofȱ thisȱ interfaceȱ isȱ itsȱ declarationȱ ofȱ theȱ typeȱ ofȱ valueȱ toȱ beȱ TIP storedȱonȱtheȱstack.ȱTheȱclientȱwouldȱmodifyȱthisȱdeclarationȱtoȱsuitȱhisȱneedsȱbeforeȱ compilingȱtheȱstackȱmodule.ȱ Download at http://www.pin5i.com/ 496ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ An Arrayed Stack TIP ȱ Ourȱfirstȱimplementation,ȱinȱProgramȱ17.2,ȱusesȱaȱstaticȱarray.ȱTheȱsizeȱofȱtheȱstackȱisȱ givenȱ inȱ aȱ #define,ȱ whichȱ mustȱ beȱ setȱ byȱ theȱ clientȱ beforeȱ theȱ moduleȱ isȱ compiled.ȱȱ Thisȱrestrictionȱisȱrelaxedȱinȱtheȱstackȱimplementationsȱdiscussedȱlater.ȱ ȱ Everythingȱthatȱisȱnotȱpartȱofȱtheȱexternalȱinterfaceȱisȱdeclaredȱ staticȱtoȱpreventȱtheȱ clientȱfromȱaccessingȱtheȱvaluesȱinȱanyȱwayȱotherȱthanȱthroughȱtheȱdefinedȱinterface.ȱ ȱ ȱ ȱ ȱ ȱ /* ** A stack implemented with a static array. The array size can ** be adjusted only by changing the #define and recompiling ** the module. */ #include "stack.h" #include <assert.h> #define STACK_SIZE 100 /* Max # of values on the stack */ /* ** The array that holds the values on the stack, and a pointer ** to the topmost value on the stack. */ static STACK_TYPE stack[ STACK_SIZE ]; static int top_element = -1; /* ** push */ void push( STACK_TYPE value ) { assert( !is_full() ); top_element += 1; stack[ top_element ] = value; } /* ** */ pop ȱ Programȱ17.2ȱȱStackȱimplementedȱwithȱaȱstaticȱarrayȱ ȱ ȱ ȱ ȱ continuedȱ...ȱ Download at http://www.pin5i.com/ 17.2 Stacksȱ 497 ȱ ȱ void pop( void ) { assert( !is_empty() ); top_element -= 1; } /* ** top */ STACK_TYPE top( void ) { assert( !is_empty() ); return stack[ top_element ]; } /* ** is_empty */ int is_empty( void ) { return top_element == -1; } /* ** is_full */ int is_full( void ) { return top_element == STACK_SIZE - 1; } ȱ Programȱ17.2ȱȱStackȱimplementedȱwithȱaȱstaticȱarrayȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱa_stack.cȱ ȱ ȱ ȱ ȱ ȱ Theȱvariableȱtop_elementȱholdsȱtheȱsubscriptȱofȱtheȱvalueȱatȱtheȱtopȱofȱtheȱstack.ȱ Itȱisȱinitializedȱtoȱ-1ȱtoȱindicateȱthatȱtheȱstackȱisȱempty.ȱByȱincrementingȱthisȱvariableȱ inȱpushȱbeforeȱstoringȱtheȱnewȱvalue,ȱ top_elementȱalwaysȱcontainsȱtheȱsubscriptȱofȱtheȱ topmostȱ value.ȱ Ifȱ itȱ wereȱ initializedȱ toȱ 0,ȱ top_elementȱ wouldȱ beȱ keepingȱ trackȱ ofȱ theȱ nextȱ availableȱ spaceȱ inȱ theȱ array.ȱ Thisȱ approachȱ worksȱ butȱ isȱ slightlyȱ lessȱ efficientȱ becauseȱaȱsubtractionȱisȱrequiredȱinȱorderȱtoȱaccessȱtheȱtopȱelement.ȱ Download at http://www.pin5i.com/ 498ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ ȱ Aȱtraditionalȱ popȱfunction,ȱwrittenȱwithȱstraightforwardȱcode,ȱwouldȱlookȱlikeȱ this:ȱ ȱ STACK_TYPE pop( void ) { STACK_TYPE temp; assert( !is_empty() ); temp = stack[ top_element ]; top_element -= 1; return temp; } ȱ Theȱ orderingȱ ofȱ theseȱ operationsȱ isȱ important.ȱ top_elementȱ isȱ decrementedȱ afterȱ theȱ valueȱ isȱ copiedȱ fromȱ theȱ array,ȱ inȱ contrastȱ toȱ push,ȱ whereȱ itȱ isȱ incrementedȱ beforeȱ copyingȱ theȱ valueȱ intoȱ theȱ array.ȱ Weȱ canȱ makeȱ theȱ popȱ functionȱ moreȱ efficientȱ byȱ eliminatingȱtheȱtemporaryȱvariableȱandȱtheȱcopyingȱthatȱgoesȱwithȱit:ȱ ȱ assert( !is_empty() ); return stack[ top_element-- ]; ȱ popȱneedȱnotȱeraseȱvaluesȱfromȱtheȱstack—simplyȱdecrementingȱtheȱtopȱpointerȱ TIP isȱenoughȱbecauseȱtheȱoldȱvalueȱcanȱnoȱlongerȱbeȱaccessedȱbyȱtheȱclient.ȱ ȱ Aȱnoteworthyȱfeatureȱofȱthisȱstackȱmoduleȱisȱitsȱuseȱofȱ assertȱtoȱguardȱagainstȱillegalȱ operations,ȱsuchȱasȱpoppingȱaȱstackȱthatȱisȱalreadyȱemptyȱorȱpushingȱanotherȱvalueȱonȱ aȱstackȱthatȱisȱfull.ȱTheȱassertionsȱcallȱtheȱ is_fullȱandȱ is_emptyȱfunctionsȱratherȱthanȱ testingȱ top_elementȱ themselves.ȱ Thisȱ approachȱ makesȱ itȱ easierȱ toȱ changeȱ theȱ implementationȱshouldȱyouȱdecideȱlaterȱtoȱdetectȱemptyȱandȱfullȱdifferently.ȱ Assertionsȱareȱappropriateȱforȱerrorsȱthatȱtheȱclientȱcannotȱrecoverȱfrom.ȱButȱifȱ theȱ clientȱ wantsȱ toȱ beȱ sureȱ thatȱ theȱ programȱ doesnȇtȱ abort,ȱ theȱ programȱ mustȱ checkȱ whetherȱthereȱisȱspaceȱonȱtheȱstackȱbeforeȱattemptingȱtoȱpushȱaȱnewȱvalue.ȱThereforeȱ theȱassertionsȱmustȱonlyȱcheckȱthingsȱthatȱtheȱclientȱcanȱalsoȱcheck.ȱ ȱ ȱ ȱ A Dynamically Arrayed Stack ȱ Theȱ nextȱ implementationȱ usesȱ aȱ dynamicȱ array,ȱ butȱ firstȱ weȱ needȱ toȱ addȱ twoȱ newȱ functionsȱinȱtheȱinterface:ȱ Download at http://www.pin5i.com/ 17.2 Stacksȱ 499 ȱ ȱ ȱ /* ** create_stack ** Create the stack. The argument specifies ** how many elements the stack can hold. ** NOTE; this does not apply to the static ** array version of the stack. */ void create_stack( size_t size ); /* ** destroy_stack ** Destroy the stack. This frees the memory ** used by the stack. NOTE: this does not ** apply to the static array stack either. */ void destroy_stack( void );ȱ ȱ Theȱfirstȱfunctionȱcreatesȱtheȱstackȱwithȱwhateverȱsizeȱtheȱuserȱpassesȱasȱanȱargument.ȱȱ Theȱsecondȱdeletesȱtheȱstack,ȱandȱisȱneededȱtoȱavoidȱmemoryȱleaks.ȱ TIP Theseȱ declarationsȱ mayȱ beȱ addedȱ toȱ stack.hȱ evenȱ thoughȱ theȱ previousȱ stackȱ implementationȱdoesȱnotȱdefineȱeitherȱfunction.ȱNoteȱthatȱthereȱisȱnoȱdangerȱofȱaȱclientȱ mistakenlyȱcallingȱeitherȱofȱtheseȱfunctionsȱforȱaȱstaticallyȱarrayedȱstackȱbecauseȱtheyȱ doȱnotȱexistȱinȱthatȱmodule.ȱ ȱ Aȱ betterȱ approachȱ isȱ toȱ implementȱ theȱ unneededȱ functionsȱ inȱ theȱ arrayȱ moduleȱ asȱ stubsȱ thatȱ doȱ nothing.ȱ Theȱ interfacesȱ forȱ theȱ twoȱ implementationsȱ willȱ thenȱ beȱ identical,ȱthusȱmakingȱitȱeasierȱtoȱswitchȱfromȱoneȱimplementationȱtoȱanother.ȱ Interestingly,ȱ usingȱ aȱ dynamicallyȱ allocatedȱ arrayȱ doesȱ notȱ changeȱ theȱ implementationȱ muchȱ (seeȱ Programȱ 17.3).ȱ Theȱ arrayȱ hasȱ beenȱ replacedȱ byȱ aȱ pointer,ȱ andȱ theȱ stack_sizeȱ variableȱ hasȱ beenȱ introducedȱ toȱ rememberȱ theȱ sizeȱ ofȱ theȱ stack.ȱ Theȱdefaultȱinitializationȱwillȱmakeȱbothȱofȱtheseȱzero.ȱ Theȱcreate_stackȱfunctionȱfirstȱchecksȱthatȱtheȱstackȱwasȱnotȱalreadyȱcreated.ȱItȱ thenȱ allocatesȱ theȱ requestedȱ amountȱ ofȱ memoryȱ andȱ verifiesȱ thatȱ theȱ allocationȱ wasȱ successful.ȱAfterȱdestroy_stackȱfreesȱtheȱmemory,ȱitȱsetsȱtheȱsizeȱandȱpointerȱvariablesȱ backȱtoȱzeroȱsoȱthatȱanotherȱstackȱcanȱbeȱcreatedȱlater.ȱ Theȱ onlyȱ changesȱ toȱ theȱ restȱ ofȱ theȱ moduleȱ areȱ theȱ comparisonȱ toȱ theȱ stack_sizeȱvariableȱ ratherȱ thanȱ theȱ STACK_SIZEȱconstantȱinȱ is_fullȱandȱtheȱadditionȱ ofȱanȱassertionȱtoȱbothȱ is_fullȱandȱ is_empty.ȱTheȱassertionȱpreventsȱanyȱofȱtheȱstackȱ functionsȱ fromȱ beingȱ calledȱ beforeȱ theȱ stackȱ hasȱ beenȱ created.ȱ Theȱ otherȱ stackȱ functionsȱdonȇtȱneedȱtheȱnewȱassertionȱbecauseȱtheyȱallȱcallȱoneȱofȱtheseȱtwoȱfunctions.ȱ Download at http://www.pin5i.com/ 500ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ ȱ ȱ /* ** A stack implemented with a dynamically allocated array. ** The array size is given when create is called, which must ** happen before any other stack operations are attempted. */ #include "stack.h" #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <assert.h> /* ** The array that holds the values on the stack, and a pointer ** to the topmost value on the stack. */ static STACK_TYPE *stack; static size_t stack_size; static int top_element = -1; /* ** create_stack */ void create_stack( size_t size ) { assert( stack_size == 0 ); stack_size = size; stack = malloc( stack_size * sizeof( STACK_TYPE ) ); assert( stack != NULL ); } /* ** destroy_stack */ void destroy_stack( void ) { assert( stack_size > 0 ); stack_size = 0; free( stack ); stack = NULL; } /* ** */ push ȱ ȱ Programȱ17.3ȱȱStackȱimplementedȱwithȱaȱdynamicȱarrayȱ ȱ ȱ ȱ continuedȱ...ȱ Download at http://www.pin5i.com/ 17.2 Stacksȱ 501 ȱ ȱ void push( STACK_TYPE value ) { assert( !is_full() ); top_element += 1; stack[ top_element ] = value; } /* ** pop */ void pop( void ) { assert( !is_empty() ); top_element -= 1; } /* ** top */ STACK_TYPE top( void ) { assert( !is_empty() ); return stack[ top_element ]; } /* ** is_empty */ int is_empty( void ) { assert( stack_size > 0 ); return top_element == -1; } /* ** is_full */ int is_full( void ) { assert( stack_size > 0 ); return top_element == stack_size - 1; } ȱ ȱ Programȱ17.3ȱȱStackȱimplementedȱwithȱaȱdynamicȱarrayȱ ȱ ȱ ȱ ȱȱȱȱȱd_stack.cȱ Download at http://www.pin5i.com/ 502ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ ȱ Usingȱ assertȱ toȱ checkȱ theȱ successȱ ofȱ aȱ memoryȱ allocationȱ canȱ leadȱ toȱ unexpectedȱ programȱ abortsȱ inȱ environmentsȱ whereȱ memoryȱ isȱ limited.ȱ Anȱ alternativeȱ strategyȱ wouldȱ beȱ toȱ returnȱ aȱ valueȱ fromȱ create_stackȱ indicatingȱ whetherȱ orȱ notȱ itȱ wasȱ successful.ȱInȱtheȱeventȱofȱaȱfailure,ȱtheȱclientȱprogramȱcouldȱtryȱagainȱwithȱaȱsmallerȱ size.ȱ ȱ ȱ ȱ A Linked Stack ȱ Becauseȱonlyȱtheȱtopȱelementȱonȱaȱstackȱisȱaccessible,ȱaȱsinglyȱlinkedȱlistȱworksȱwellȱforȱ aȱlinkedȱstack.ȱPushingȱaȱvalueȱonȱtheȱstackȱisȱaccomplishedȱbyȱaddingȱtheȱnewȱvalueȱ atȱtheȱstartȱofȱtheȱlist.ȱPoppingȱtheȱstackȱremovesȱtheȱfirstȱvalueȱfromȱtheȱlist.ȱTheȱvalueȱ atȱtheȱheadȱofȱtheȱlistȱisȱalwaysȱeasilyȱaccessible.ȱ Inȱ theȱ implementationȱ shownȱ inȱ Programȱ 17.4,ȱ thereȱ isnȇtȱ anyȱ needȱ forȱ aȱ create_stackȱ function,ȱ butȱ destroy_stackȱ canȱ beȱ implementedȱ toȱ emptyȱ theȱ stack.ȱ Becauseȱ theȱ memoryȱ toȱ holdȱ theȱ valuesȱ isȱ dynamicallyȱ allocated,ȱ itȱ mustȱ beȱ freedȱ toȱ avoidȱmemoryȱleaks.ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** A stack implemented with a linked list. ** limit. */ #include "stack.h" #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <assert.h> #define This stack has no size FALSE 0 ȱ ȱ Programȱ17.4ȱȱStackȱimplementedȱwithȱaȱlinkedȱlistȱ ȱ ȱ ȱ ȱ continuedȱ...ȱ Download at http://www.pin5i.com/ 17.2 Stacksȱ 503 ȱ ȱ /* ** Define a structure to hold one value. ** point to the next value on the stack. */ typedef struct STACK_NODE { STACK_TYPE value; struct STACK_NODE *next; } StackNode; The link field will /* ** A pointer to the topmost node on the stack. */ static StackNode *stack; /* ** create_stack */ void create_stack( size_t size ) { } /* ** destroy_stack */ void destroy_stack( void ) { while( !is_empty() ) pop(); } /* ** push */ void push( STACK_TYPE value ) { StackNode *new_node; new_node = malloc( sizeof( StackNode ) ); assert( new_node != NULL ); new_node->value = value; new_node->next = stack; stack = new_node; } ȱ ȱ Programȱ17.4ȱȱStackȱimplementedȱwithȱaȱlinkedȱlistȱ ȱ ȱ ȱ ȱ continuedȱ...ȱ Download at http://www.pin5i.com/ 504ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ ȱ /* ** pop */ void pop( void ) { StackNode *first_node; assert( !is_empty() ); first_node = stack; stack = first_node->next; free( first_node ); } /* ** top */ STACK_TYPE top( void ) { assert( !is_empty() ); return stack->value; } /* ** is_empty */ int is_empty( void ) { return stack == NULL; } /* ** is_full */ int is_full( void ) { return FALSE; } ȱ ȱ Programȱ17.4ȱȱStackȱimplementedȱwithȱaȱlinkedȱlistȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱl_stack.c Download at http://www.pin5i.com/ 17.3 Queuesȱ 505 ȱ ȱ TIP Theȱstructureȱisȱneededȱtoȱbundleȱaȱvalueȱandȱaȱpointerȱtogether,ȱandȱtheȱstackȱ variableȱ isȱ nowȱ aȱ pointerȱ toȱ oneȱ ofȱ theseȱ structures.ȱ Theȱ stackȱ isȱ emptyȱ whenȱ thisȱ pointerȱisȱNULL,ȱasȱitȱisȱinitially.ȱ ȱ Theȱ destroy_stackȱ functionȱ popsȱ valuesȱ untilȱ theȱ slackȱ isȱ empty.ȱ Again,ȱ noticeȱ thatȱ existingȱis_emptyȱandȱpopȱfunctionsȱareȱcalledȱratherȱthanȱrepeatingȱtheȱneededȱcode.ȱ create_stackȱ isȱ anȱ emptyȱ function,ȱ andȱ becauseȱ thisȱ stackȱ cannotȱ fillȱ up,ȱ is_fullȱalwaysȱreturnsȱfalse.ȱ ȱ ȱ ȱ 17.3 Queues ȱ Aȱ queueȱ hasȱ aȱ differentȱ orderingȱ thanȱ aȱ stack:ȱ queuesȱ areȱ FirstȬIn,ȱ FirstȬOutȱ orȱ FIFOȱ structures.ȱWaitingȱlinesȱareȱusuallyȱqueues.ȱTheȱpersonȱthatȱarrivedȱfirstȱisȱatȱtheȱheadȱ ofȱtheȱline,ȱandȱnewȱarrivalsȱjoinȱtheȱlineȱatȱitsȱend.ȱ ȱ ȱ ȱ 17.3.1 Queue Interface ȱ Unlikeȱ stacks,ȱ thereȱ arenȇtȱ generallyȱ acceptedȱ namesȱ forȱ theȱ queueȱ functionsȱ thatȱ performȱinsertionȱandȱremovalȱofȱvalues,ȱsoȱweȱwillȱuseȱinsertȱandȱdelete.ȱAlso,ȱthereȱ isȱnotȱcompleteȱagreementȱonȱwhetherȱinsertionsȱoccurȱatȱtheȱfrontȱofȱtheȱqueueȱorȱatȱ theȱrear.ȱInȱprincipleȱitȱdoesnȇtȱmakeȱanyȱdifferenceȱwhatȱyouȱcallȱtheȱendȱofȱtheȱlineȱ whereȱ insertionsȱ occur,ȱ butȱ insertingȱ atȱ theȱ rearȱ andȱ removingȱ fromȱ theȱ frontȱ ofȱ theȱ queueȱmayȱbeȱeasierȱtoȱrememberȱbecauseȱthisȱmethodȱmoreȱaccuratelyȱdescribesȱourȱ humanȱexperiencesȱwithȱwaitingȱlines.ȱ ȱ ȱ ȱ ȱ ȱ /* ** Interface for a queue module */ #include <stdlib.h> #define QUEUE_TYPE int ȱ Programȱ17.5ȱȱQueueȱinterfaceȱ /* Type of value in the queue */ ȱ ȱ ȱ ȱ ȱ ȱ ȱ continued...ȱ Download at http://www.pin5i.com/ Chapter 17 Classic Abstract Data Typesȱ 506ȱ ȱ ȱ /* ** create_queue ** Creates a queue. The argument indicates the maximum number ** of values that the queue will hold. NOTE: this applies only ** to the dynamically allocated array implementation. */ void create_queue( size_t size ); /* ** destroy_queue ** Destroys a queue. NOTE: this applies only to the linked and ** dynamically allocated array implementations. */ void destroy_queue( void ); /* ** insert ** Adds a new value on the queue. ** to be inserted. */ void insert( QUEUE_TYPE value ); The argument is the value /* ** delete ** Removes a value from the queue, discarding it. */ void delete( void ); /* ** first ** Returns the first value on the queue without changing the ** queue itself. */ QUEUE_TYPE first( void ); /* ** is_empty ** Returns TRUE if the queue is empty, else FALSE */ int is_empty( void ); /* ** is_full ** Returns TRUE if the queue is full, else FALSE */ int is_full( void ); ȱ Programȱ17.5ȱȱQueueȱinterfaceȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱqueue.hȱ Download at http://www.pin5i.com/ 17.3 Queuesȱ 507 ȱ Inȱ theȱ traditionalȱ interface,ȱ deleteȱ removesȱ theȱ valueȱ fromȱ theȱ frontȱ ofȱ theȱ queueȱandȱreturnsȱit.ȱInȱtheȱalternateȱinterface,ȱdeleteȱtakesȱtheȱvalueȱoutȱofȱtheȱqueueȱ butȱdoesȱnotȱreturnȱit;ȱtheȱ firstȱfunctionȱreturnsȱtheȱfirstȱvalueȱinȱtheȱqueueȱwithoutȱ removingȱit.ȱ Theȱ headerȱ fileȱ inȱ Programȱ 17.5ȱ definesȱ theȱ alternateȱ interface.ȱ Itȱ includesȱ prototypesȱ forȱ theȱ create_queueȱ andȱ destroy_queueȱ functionsȱ neededȱ byȱ theȱ linkedȱ andȱdynamicȱimplementations.ȱ ȱ ȱ ȱ 17.3.2 Implementing a Queue ȱ Queuesȱareȱmoreȱdifficultȱloȱimplementȱthanȱstacks.ȱTwoȱpointersȱaxeȱneeded—oneȱforȱ theȱfrontȱofȱtheȱlineȱandȱoneȱforȱtheȱrear.ȱAlso,ȱarraysȱareȱnotȱasȱwellȱsuitedȱtoȱqueuesȱ asȱtheyȱareȱtoȱstacksȱbecauseȱofȱtheȱwayȱqueuesȱuseȱmemory.ȱ Aȱ stackȱ isȱ alwaysȱ rootedȱ atȱ oneȱ endȱ ofȱ theȱ array.ȱ Aȱ queue,ȱ however,ȱ usesȱ differentȱelementsȱofȱtheȱarrayȱasȱvaluesȱareȱinsertedȱandȱremoved.ȱConsiderȱaȱqueueȱ implementedȱasȱanȱarrayȱofȱfiveȱvalues.ȱHereȱisȱhowȱitȱwillȱlookȱafterȱtheȱvaluesȱ10,ȱ20,ȱ 30,ȱ40,ȱandȱ50ȱhaveȱbeenȱinserted.ȱ ȱ subscriptȱ 0ȱ 1ȱ 2ȱ 3ȱ 4ȱ ȱ 10ȱ 20ȱ 30ȱ 40ȱ 50ȱ ȱ ȱ ȱ front 0ȱ rearȱ 4ȱ ȱ ȱ ȱ Afterȱthreeȱremovals,ȱitȱlooksȱlikeȱthis:ȱ ȱ subscriptȱ 0ȱ 1ȱ 2ȱ 3ȱ 4ȱ ȱ ȱ ȱ ȱ 40ȱ 50ȱ ȱ ȱ ȱ front 3ȱ rearȱ 4ȱ ȱ ȱ Theȱarrayȱisȱnotȱfull,ȱbutȱthereȱisnȇtȱanyȱroomȱatȱitsȱendȱtoȱinsertȱnewȱvalues.ȱ Oneȱ solutionȱ toȱ thisȱ problemȱ isȱ toȱ moveȱ theȱ remainingȱ elementsȱ backȱ towardȱ theȱbeginningȱofȱtheȱarrayȱwhenȱaȱvalueȱisȱremoved.ȱTheȱcopyingȱoverheadȱmakesȱthisȱ approachȱimpractical,ȱespeciallyȱforȱlargeȱqueues.ȱ AȱbetterȱalternativeȱisȱtoȱhaveȱtheȱrearȱofȱtheȱqueueȱȈwrapȱaroundȈȱtoȱtheȱfrontȱ ofȱ theȱ arrayȱ soȱ thatȱ newȱ valuesȱ canȱ beȱ storedȱ inȱ theȱ spaceȱ madeȱ availableȱ byȱ earlierȱ removals.ȱThisȱmethodȱisȱoftenȱcalledȱaȱcircularȱarray.ȱTheȱfollowingȱdiagramȱillustratesȱ thisȱconceptȱ Download at http://www.pin5i.com/ 508ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ subscript 1 0 frontȱ 3 2 rearȱ 4 4 50 40 3 Insertingȱanotherȱvalueȱgivesȱthisȱresult:ȱ subscript ȱ 1 0 frontȱ 60 3 2 rearȱ 0 4 50 40 3 ȱ Theȱcircularȱarrayȱisȱeasyȱtoȱimplement—whenȱtheȱrearȱsubscriptȱmovesȱoffȱtheȱ endȱofȱtheȱarray,ȱsetȱitȱbackȱtoȱzero,ȱasȱisȱdoneȱinȱtheȱfollowingȱcode.ȱ ȱ rear += 1; if( rear >= QUEUE_SIZE ) rear = 0; ȱ Theȱfollowingȱapproachȱhasȱtheȱsameȱresult.ȱ ȱ rear = ( rear + 1 ) % QUEUE_SIZE; ȱ Theȱsameȱtechniqueȱmustȱbeȱappliedȱwhenȱincrementingȱfront.ȱ Theȱcircularȱarrayȱintroducesȱaȱproblemȱofȱitsȱown,ȱthough.ȱItȱisȱmoreȱcomplexȱ toȱdetermineȱwhetherȱaȱcircularȱarrayȱisȱfullȱorȱempty.ȱSupposeȱtheȱqueueȱwereȱfull,ȱasȱ thisȱoneȱis:ȱ subscript 70 0 frontȱ 1 60 3ȱ 80 2 rearȱ 2 4 50 40 3 ȱ Download at http://www.pin5i.com/ 17.3 Queuesȱ 509 ȱ Noteȱ theȱ valuesȱ ofȱ frontȱ andȱ rear;ȱ threeȱ andȱ two,ȱ respectively.ȱ Ifȱ fourȱ valuesȱ areȱ removedȱ fromȱ theȱ queue,ȱ frontȱ willȱ beȱ incrementedȱ fourȱ times,ȱ givingȱ thisȱ configuration:ȱ subscript 1 0 frontȱ 2 80 2 rearȱ 2 4 3 Whenȱtheȱlastȱvalueȱisȱremoved,ȱtheȱqueueȱlooksȱlikeȱthis:ȱ subscript ȱ 1 0 frontȱ 3 2 rearȱ 2 4 3 ȱ Theȱproblemȱisȱthatȱtheȱvaluesȱofȱfrontȱandȱrearȱareȱnowȱtheȱsameȱasȱtheyȱwereȱwhenȱ theȱqueueȱwasȱfull.ȱAnyȱcomparisonȱofȱthemȱthatȱisȱtrueȱwhenȱtheȱqueueȱisȱemptyȱwillȱ alsoȱbeȱtrueȱwhenȱitȱisȱfull,ȱsoȱweȱcannotȱtestȱforȱanȱemptyȱqueueȱbyȱcomparingȱ frontȱ andȱrear.ȱ Thereȱ areȱ twoȱ waysȱ toȱ solveȱ thisȱ problem.ȱ Theȱ firstȱ isȱ toȱ introduceȱ aȱ newȱ variableȱ thatȱ countsȱ howȱ manyȱ valuesȱ areȱ inȱ theȱ queue.ȱ Itȱ isȱ incrementedȱ withȱ eachȱ insertionȱ andȱ decrementedȱ withȱ eachȱ removal.ȱ Testingȱ thisȱ variableȱ toȱ determineȱ whetherȱtheȱqueueȱisȱemptyȱorȱfullȱisȱeasy.ȱ Theȱ secondȱ approachȱ isȱ toȱ redefineȱ theȱ meaningȱ ofȱ full.ȱ Ifȱ oneȱ elementȱ inȱ theȱ arrayȱisȱalwaysȱleftȱunused,ȱthenȱwhenȱtheȱqueueȱisȱȈfullȈȱtheȱfrontȱandȱrearȱvaluesȱwillȱ beȱ differentȱ thanȱ whenȱ theȱ queueȱ isȱ empty.ȱ Byȱ notȱ allowingȱ theȱ arrayȱ toȱ becomeȱ completelyȱfull,ȱtheȱproblemȱisȱavoided.ȱ Oneȱ minorȱ questionȱ remains:ȱ Whatȱ valuesȱ shouldȱ frontȱ andȱ rearȱ haveȱ whenȱ theȱqueueȱisȱempty?ȱWhenȱtheȱqueueȱhasȱoneȱvalueȱinȱit,ȱweȱwantȱ frontȱandȱ rearȱtoȱ bothȱpointȱtoȱtheȱvalue.ȱAnȱinsertionȱincrementsȱ rear,ȱsoȱinȱorderȱforȱ rearȱtoȱpointȱtoȱ theȱvalueȱafterȱtheȱfirstȱinsertion,ȱ rearȱmustȱbeȱoneȱlessȱthanȱ frontȱwhenȱtheȱqueueȱisȱ empty.ȱ Fortunately,ȱ thisȱ stateȱ isȱ alsoȱ theȱ resultȱ ofȱ removingȱ theȱ lastȱ valueȱ fromȱ theȱ queue,ȱsoȱremovingȱtheȱlastȱvalueȱisȱnotȱaȱspecialȱcase.ȱ Download at http://www.pin5i.com/ 510ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ Theȱqueueȱisȱemptyȱwhenȱ ȱ ( rear + 1 ) % QUEUE_SIZE == front ȱ Becauseȱ weȱ mustȱ stopȱ insertingȱ valuesȱ justȱ beforeȱ frontȱ andȱ rearȱ reachȱ thisȱ relationship,ȱtheȱqueueȱmustȱbeȱcalledȱȈfullȈȱwhenȱ ȱ ( rear + 2 ) % QUEUE_SIZE == front ȱ ȱ ȱ An Arrayed Queue ȱ Programȱ17.6ȱimplementsȱaȱqueueȱwithȱaȱstaticȱarray.ȱItȱusesȱtheȱȈdonȇtȱcompletelyȱfillȱ theȱarrayȈȱtechniqueȱofȱdistinguishingȱbetweenȱanȱemptyȱandȱaȱfullȱqueue.ȱ ȱ ȱ ȱ ȱ ȱ ȱ /* ** A queue implemented with a static array. The array size can ** be adjusted only by changing the #define and recompiling ** the module. */ #include "queue.h" #include <stdio.h> #include <assert.h> #define #define QUEUE_SIZE ARRAY_SIZE 100 /* Max # of values on the queue */ ( QUEUE_SIZE + 1 ) /* Size of array */ /* ** The array that holds the values on the queue, and pointers ** to the front and rear of the queue. */ static QUEUE_TYPE queue[ ARRAY_SIZE ]; static size_t front = 1; static size_t rear = 0; ȱ Programȱ17.6ȱȱQueueȱimplementedȱwithȱaȱstaticȱarrayȱȱ ȱ ȱ ȱ continued...ȱ Download at http://www.pin5i.com/ 17.3 Queuesȱ 511 ȱ ȱ /* ** insert */ void insert( QUEUE_TYPE value ) { assert( !is_full() ); rear = ( rear + 1 ) % ARRAY_SIZE; queue[ rear ] = value; } /* ** delete */ void delete( void ) { assert( !is_empty() ); front = ( front + 1 ) % ARRAY_SIZE; } /* ** first */ QUEUE_TYPE first( void ) { assert( !is_empty() ); return queue[ front ]; } /* ** is_empty */ int is_empty( void ) { return ( rear + 1 ) % ARRAY_SIZE == front; } /* ** is_full */ int is_full( void ) { return ( rear + 2 ) % ARRAY_SIZE == front; } ȱ Programȱ17.6ȱȱQueueȱimplementedȱwithȱaȱstaticȱarrayȱȱ ȱ ȱ ȱ ȱȱȱa_queue.cȱ Download at http://www.pin5i.com/ 512ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ TheȱQUEUE_SIZEȱconstantȱisȱsetȱtoȱtheȱmaximumȱnumberȱofȱvaluesȱthatȱtheȱclientȱ wantsȱonȱtheȱqueue.ȱBecauseȱthisȱimplementationȱneverȱfillsȱtheȱqueue,ȱ ARRAY_SIZEȱisȱ definedȱ asȱ oneȱ moreȱ thanȱ QUEUE_SIZE.ȱ Theȱ functionsȱ areȱ straightforwardȱ implementationsȱofȱtheȱtechniquesȱweȱdiscussed.ȱ Weȱcouldȱhaveȱusedȱanyȱ valuesȱtoȱ initializeȱ frontȱandȱ rearȱasȱlongȱ asȱ rearȱ isȱ oneȱlessȱthanȱfront.ȱTheseȱparticularȱvaluesȱleaveȱtheȱfirstȱelementȱofȱtheȱarrayȱunusedȱ untilȱtheȱfirstȱtimeȱrearȱwrapsȱaround,ȱbutȱsoȱwhat?ȱ ȱ ȱ ȱ Dynamically Arrayed and Linked Queues ȱ Theȱmodificationsȱneededȱtoȱdynamicallyȱallocateȱtheȱarrayȱforȱaȱqueueȱareȱanalogousȱ toȱthoseȱneededȱforȱaȱstack.ȱConsequently,ȱitsȱimplementationȱisȱleftȱtoȱtheȱexercises.ȱ Theȱlinkedȱqueueȱisȱsimplerȱinȱsomeȱrespectsȱthanȱitsȱarrayedȱcousins.ȱItȱdoesnȇtȱ useȱ anȱ array,ȱ soȱ theȱ problemsȱ ofȱ theȱ circularȱ arrayȱ disappear.ȱ Testingȱ forȱ emptyȱ isȱ simplyȱaȱmatterȱofȱseeingȱifȱtheȱlistȱisȱempty.ȱTheȱtestȱforȱfullȱalwaysȱreturnsȱfalse.ȱThisȱ implementationȱisȱalsoȱleftȱasȱanȱexercise.ȱ ȱ ȱ ȱ 17.4 Trees ȱ Aȱ completeȱ descriptionȱ ofȱ allȱ theȱ varietiesȱ ofȱ treesȱ isȱ beyondȱ theȱ scopeȱ ofȱ thisȱ book.ȱȱ However,ȱ theȱ techniquesȱ forȱ implementingȱ treesȱ areȱ illustratedȱ quiteȱ nicelyȱ byȱ describingȱoneȱveryȱusefulȱvariety;ȱtheȱbinaryȱsearchȱtree.ȱ Aȱtreeȱisȱaȱstructureȱthatȱisȱeitherȱemptyȱorȱhasȱaȱvalueȱandȱzeroȱorȱmoreȱchildren,ȱ eachȱofȱwhichȱisȱalsoȱaȱtree.ȱThisȱrecursiveȱdefinitionȱimpliesȱcorrectlyȱthatȱthereȱisnȇtȱ anȱ inherentȱ limitȱ toȱ theȱ heightȱ ofȱ aȱ tree.ȱ Aȱ binaryȱ treeȱ isȱ aȱ specializedȱ formȱ ofȱ treeȱ inȱ whichȱeachȱnodeȱhasȱatȱmostȱtwoȱchildren,ȱnamedȱleftȱandȱright.ȱAȱbinaryȱsearchȱtreeȱhasȱ oneȱadditionalȱproperty:ȱTheȱvalueȱinȱeachȱnodeȱisȱgreaterȱthanȱallȱofȱtheȱvaluesȱinȱitsȱ leftȱsubtreeȱandȱlessȱthanȱallȱofȱtheȱvaluesȱinȱitsȱrightȱsubtree.ȱNoteȱthatȱthisȱdefinitionȱ precludesȱ havingȱ duplicateȱ valuesȱ inȱ theȱ tree.ȱ Theseȱ propertiesȱ makeȱ binaryȱ searchȱ treesȱanȱexcellentȱtoolȱforȱquicklyȱlocatingȱdataȱusingȱaȱkey.ȱFigureȱ17.1ȱisȱanȱexampleȱ ofȱaȱbinaryȱsearchȱtree.ȱEachȱnodeȱinȱtheȱtreeȱhasȱexactlyȱoneȱparentȱ(theȱnodeȱaboveȱ it),ȱandȱzero,ȱone,ȱorȱtwoȱchildrenȱ(theȱnodesȱdirectlyȱbeneathȱit).ȱTheȱonlyȱexceptionȱisȱ theȱtopmostȱnode,ȱcalledȱtheȱrootȱofȱtheȱtree,ȱwhichȱdoesnȇtȱhaveȱaȱparent.ȱTheȱnodesȱ withoutȱchildrenȱareȱcalledȱleafȱnodesȱorȱleaves.ȱTreesȱareȱdrawnȱwithȱtheȱrootȱatȱtheȱtopȱ andȱtheȱleavesȱatȱtheȱbottom. 55 ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ 55 ȱNoteȱthatȱtreesȱinȱnature,ȱwithȱtheirȱrootsȱatȱtheȱbottomȱandȱtheirȱleavesȱonȱtop,ȱareȱactuaryȱupsideȱdown.ȱ Download at http://www.pin5i.com/ 17.4 Treesȱ 513 ȱ 20 12ȱ ȱ5ȱ 25 16ȱ ȱ9ȱ 28ȱ 17 26ȱ 29 ȱ ȱ Figureȱ17.1ȱȱBinaryȱsearchȱtreeȱ ȱ ȱ ȱ 17.4.1 Insertions into a Binary Search Tree ȱ Whenȱaȱnewȱvalueȱisȱtoȱbeȱaddedȱtoȱaȱbinaryȱsearchȱtree,ȱitȱmustȱbeȱputȱinȱtheȱproperȱ positionȱsoȱthatȱtheȱsearchȱtreeȱpropertyȱisȱmaintained.ȱFortunately,ȱthisȱtaskȱisȱsimple.ȱȱ Theȱbasicȱalgorithmȱworksȱlikeȱthis:ȱ ȱ Ifȱtheȱtreeȱisȱempty;ȱ Insertȱtheȱnewȱvalueȱasȱtheȱrootȱnodeȱ Otherwise:ȱ Ifȱtheȱnewȱvalueȱisȱlessȱthanȱtheȱcurrentȱnodeȇsȱvalue:ȱ Insertȱtheȱnewȱvalueȱinȱtheȱleftȱsubtreeȱofȱtheȱcurrentȱnodeȱ Otherwise:ȱ Insertȱtheȱnewȱvalueȱinȱtheȱrightȱsubtreeȱofȱtheȱcurrentȱnode.ȱ TIP ȱ Theȱ recursiveȱ expressionȱ ofȱ thisȱ algorithmȱ isȱ aȱ directȱ consequenceȱ ofȱ theȱ recursiveȱ definitionȱofȱtheȱtree.ȱ Toȱ insertȱ 15ȱ intoȱ theȱ treeȱ inȱ Figureȱ 17.1,ȱ compareȱ 15ȱ withȱ 20.ȱ Itȱ isȱ lessȱ soȱ theȱ valueȱ isȱ insertedȱ intoȱ theȱ leftȱ subtree.ȱ Thisȱ subtreeȇsȱ rootȱ isȱ 12,ȱ soȱ theȱ processȱ isȱ repeatedȱwithȱthisȱnode:ȱcompareȱ15ȱwithȱ12.ȱThisȱtimeȱ15ȱisȱgreater,ȱsoȱweȱinsertȱ15ȱ intoȱ12ȇsȱrightȱsubtree.ȱWeȱnowȱcompareȱ15ȱwithȱ16.ȱItȱisȱless,ȱsoȱweȱinsertȱ15ȱintoȱtheȱ leftȱsubtreeȱofȱnodeȱ16.ȱButȱthisȱsubtreeȱisȱempty,ȱsoȱtheȱnodeȱcontainingȱ15ȱbecomesȱ theȱrootȱofȱtheȱnewȱleftȱsubtreeȱofȱnodeȱ16.ȱ ȱ Becauseȱ theȱ recursionȱ occursȱ atȱ theȱ endȱ ofȱ theȱ algorithmȱ (tailȱ recursion),ȱ itȱ isȱ moreȱ efficientȱtoȱimplementȱtheȱalgorithmȱiteratively.ȱ Download at http://www.pin5i.com/ Chapter 17 Classic Abstract Data Typesȱ 514ȱ ȱ 17.4.2 Deletions from a Binary Search Tree ȱ Removingȱaȱvalueȱfromȱaȱtreeȱisȱmoreȱdifficultȱthanȱremovingȱaȱvalueȱfromȱaȱstackȱorȱaȱ queue.ȱDeletingȱaȱnodeȱfromȱtheȱmiddleȱofȱaȱtreeȱdisconnectsȱitsȱsubtreesȱfromȱtheȱrestȱ ofȱtheȱtree—weȱmustȱreconnectȱthemȱorȱtheyȱwillȱbeȱlost.ȱ Thereȱ areȱ threeȱ casesȱ thatȱ weȱ mustȱ handle:ȱ deletingȱ nodesȱ withȱ noȱ children,ȱ withȱoneȱchild,ȱandȱwithȱtwoȱchildren.ȱTheȱfirstȱsituationȱisȱeasy.ȱDeletingȱaȱleafȱnodeȱ doesnȇtȱdisconnectȱanyȱsubtrees,ȱsoȱthereȱisȱnothingȱtoȱreconnect.ȱDeletingȱaȱnodeȱwithȱ onlyȱoneȱchildȱisȱalmostȱasȱeasy:ȱtheȱparentȱofȱtheȱdeletedȱnodeȱinheritsȱtheȱchild.ȱThisȱ solutionȱpreventsȱthatȱsubtreeȱfromȱbeingȱdisconnected,ȱyetȱpreservesȱtheȱorderingȱofȱ theȱbinaryȱsearchȱtree.ȱ Theȱ lastȱ caseȱ isȱ moreȱ difficult.ȱ Ifȱ aȱ nodeȱ hasȱ twoȱ children,ȱ itsȱ parentȱ cannotȱ inheritȱbothȱofȱthem.ȱOneȱstrategyȱisȱtoȱnotȱdeleteȱtheȱnodeȱatȱall.ȱInstead,ȱtheȱlargestȱ valueȱ inȱ theȱ nodeȇsȱ leftȱ subtreeȱ isȱ deletedȱ andȱ thatȱ valueȱ replacesȱ theȱ oneȱ thatȱ wasȱ originallyȱtoȱhaveȱbeenȱdeleted.ȱTheȱdeletionȱfunctionsȱareȱimplementedȱasȱexercises.ȱ ȱ ȱ ȱ 17.4.3 Searching a Binary Search Tree ȱ Becauseȱ ofȱ dieȱ orderingȱ imposedȱ onȱ aȱ binaryȱ searchȱ tree,ȱ searchingȱ theȱ treeȱ forȱ aȱ particularȱvalueȱisȱeasy.ȱHereȱisȱtheȱalgorithm:ȱ ȱ Ifȱtheȱtreeȱisȱempty:ȱ Theȱvalueȱisȱnotȱinȱtheȱtreeȱ Otherwise:ȱ Ifȱtheȱrootȱcontainsȱtheȱvalue:ȱ Theȱvalueȱisȱfoundȱ Otherwise:ȱ Ifȱtheȱvalueȱisȱlessȱthanȱtheȱroot:ȱ Searchȱtheȱleftȱsubtreeȱ Otherwise:ȱ Searchȱtheȱrightȱsubtreeȱ ȱ Theȱrecursionȱinȱthisȱalgorithmȱisȱalsoȱtailȱrecursion,ȱsoȱanȱiterativeȱimplementationȱisȱ preferred.ȱ Whatȱ doȱ youȱ doȱ whenȱ theȱ valueȱ isȱ found?ȱ Itȱ dependsȱ onȱ theȱ clientȇsȱ needs.ȱȱ Sometimes,ȱ allȱ thatȱ isȱ requiredȱ isȱ toȱ checkȱ forȱ membership.ȱ Inȱ thisȱ case,ȱ returningȱ aȱ true/falseȱstatusȱisȱadequate.ȱIfȱtheȱdataȱisȱaȱstructureȱthatȱisȱidentifiedȱbyȱaȱkeyȱfield,ȱ theȱclientȱwillȱwantȱtoȱaccessȱtheȱnonȬkeyȱmembersȱofȱtheȱstructureȱthatȱwasȱlocated,ȱ whichȱrequiresȱreturningȱaȱpointerȱtoȱtheȱstructure.ȱ Download at http://www.pin5i.com/ 17.4 Treesȱ 515 ȱ 17.4.4 Tree Traversals ȱ Treesȱdoȱnotȱlimitȱyouȱtoȱaccessingȱonlyȱoneȱvalueȱasȱdoȱstacksȱandȱqueues.ȱThusȱtreesȱ haveȱanotherȱbasicȱoperation—theȱtraversal.ȱWhenȱyouȱexamineȱallȱofȱtheȱnodesȱinȱaȱ tree,ȱyouȱareȱtraversingȱtheȱtree.ȱThereȱareȱseveralȱdifferentȱordersȱinȱwhichȱtheȱnodesȱ mayȱ beȱ traversed,ȱ theȱ mostȱ commonȱ beingȱ preȬorder,ȱ inȬorder,ȱ postȬorder,ȱ andȱ breadthȬ first.ȱ Allȱ traversalsȱ startȱ atȱ theȱ rootȱ ofȱ theȱ treeȱ orȱ atȱ theȱ nodeȱ whichȱ isȱ theȱ rootȱ ofȱ whateverȱsubtreeȱyouȱwishȱtoȱtraverse.ȱ Aȱ preȬorderȱ traversalȱ examinesȱ theȱ valueȱ inȱ theȱ nodeȱ andȱ thenȱ recursivelyȱ traversesȱtheȱleftȱandȱrightȱsubtrees.ȱForȱexample,ȱaȱpreȬorderȱtraversalȱofȱtheȱtreeȱ ȱ 20 12ȱ 5ȱ 25ȱ 16 ȱ ȱ wouldȱbeginȱbyȱprocessingȱtheȱvalueȱ20.ȱWeȱthenȱtraverseȱtheȱleftȱsubtree:ȱ ȱ 12ȱ ȱ5ȱ 16 ȱ ȱ Afterȱprocessingȱtheȱvalueȱ12,ȱweȱwouldȱtraverseȱitsȱleftȱsubtreeȱ ȱ ȱ5ȱ ȱ ȱ andȱ processȱ theȱ valueȱ 5.ȱ Itsȱ leftȱ andȱ rightȱ subtreesȱ areȱ empty,ȱ soȱ weȱ haveȱ nowȱ completedȱthisȱsubtree.ȱ Havingȱfinishedȱtheȱleftȱsubtreeȱofȱnodeȱ12,ȱweȱcontinueȱwithȱitsȱrightȱsubtreeȱ ȱ 16ȱ ȱ Download at http://www.pin5i.com/ Chapter 17 Classic Abstract Data Typesȱ 516ȱ ȱ andȱ processȱ theȱ valueȱ 16.ȱ Bothȱ ofȱ itsȱ subtreesȱ areȱ alsoȱ empty,ȱ whichȱ meansȱ weȱ haveȱ completedȱtheȱsubtreeȱwhoseȱrootȱisȱ16ȱandȱtheȱsubtreeȱwhoseȱrootȱisȱ12.ȱ Havingȱ finishedȱ theȱ leftȱ subtreeȱ ofȱ 20,ȱ theȱ nextȱ stepȱ isȱ toȱ processȱ itsȱ rightȱ subtree:ȱ ȱ 25ȱ ȱ ȱ Processingȱtheȱvalueȱ25ȱcompletesȱtheȱtraversal.ȱ Forȱ aȱ largerȱ example,ȱ considerȱ theȱ binaryȱ searchȱ treeȱ inȱ Figureȱ 17.1ȱ Ifȱ eachȱ nodeȇsȱ valueȱ isȱ printedȱ whenȱ theȱ nodeȱ wasȱ examined,ȱ theȱ outputȱ ofȱ aȱ preȬorderȱ traversalȱwouldȱbe:ȱ20,ȱ12,ȱ5,ȱ9,ȱ16,ȱ17,ȱ25,ȱ28,ȱ26,ȱ29.ȱ AnȱinȬorderȱtraversalȱfirstȱtraversesȱtheȱleftȱsubtree,ȱthenȱexaminesȱtheȱvalueȱinȱ theȱ node,ȱ andȱ traversesȱ theȱ rightȱ subtreeȱ last.ȱ Anȱ inȬorderȱ traversalȱ ofȱ theȱ treeȱ inȱ Figureȱ17.1ȱwouldȱexamineȱtheȱnodesȱinȱthisȱorderȱ5,ȱ9,ȱ12,ȱ16,ȱ17,ȱ20,ȱ25,ȱ26,ȱ28,ȱ29.ȱ Aȱ postȬorderȱ traversalȱ traversesȱ theȱ leftȱ andȱ rightȱ subtreesȱ firstȱ andȱ examinesȱ theȱnodeȇsȱvalueȱlast.ȱAȱpostȬorderȱtraversalȱofȱtheȱsameȱtreeȱwouldȱexamineȱtheȱnodesȱ inȱthisȱorder:ȱ9,ȱ5,ȱ17,ȱ16,ȱ12,ȱ26,ȱ29,ȱ28,ȱ25,ȱ20.ȱ Finally,ȱ aȱ breadthȬfirstȱ traversalȱ examinesȱ theȱ nodesȱ ofȱ theȱ treeȱ levelȱ byȱ level.ȱȱ Firstȱtheȱrootȱisȱprocessed,ȱthenȱitsȱchildren,ȱthenȱallȱofȱitsȱgrandchildren,ȱandȱsoȱforth.ȱȱ Traversingȱtheȱsampleȱtreeȱinȱthisȱmannerȱwouldȱexamineȱtheȱnodesȱinȱthisȱorder:ȱ20,ȱ 12,ȱ25,ȱ5,ȱ16,ȱ28,ȱ9,ȱ17,ȱ26,ȱ29.ȱAlthoughȱtheȱfirstȱthreeȱtraversalsȱareȱeasilyȱimplementedȱ asȱrecursiveȱ functions,ȱtheȱbreadthȬfirstȱ traversalȱ isȱanȱ iterativeȱ algorithmȱ thatȱusesȱaȱ queue.ȱTheȱexercisesȱdescribeȱitȱinȱmoreȱdetail.ȱ ȱ ȱ ȱ 17.4.5 Binary Search Tree Interface ȱ TheȱinterfaceȱinȱProgramȱ17.7ȱprototypesȱtheȱfunctionȱforȱinsertingȱvaluesȱintoȱaȱbinaryȱ searchȱtree.ȱItȱalsoȱincludesȱaȱ findȱfunctionȱtoȱfindȱaȱspecificȱvalueȱinȱtheȱtree,ȱwhichȱ returnsȱaȱpointerȱtoȱtheȱvalueȱthatȱwasȱfound.ȱOnlyȱoneȱtraversalȱfunctionȱisȱdefined,ȱ becauseȱtheȱinterfacesȱforȱtheȱremainingȱonesȱdifferȱinȱnameȱonly.ȱ ȱ ȱ ȱ 17.4.6 Implementing a Binary Search Tree ȱ Althoughȱ linkedȱ treeȱ implementationsȱ areȱ byȱ farȱ theȱ mostȱ common,ȱ itȱ isȱ possibleȱ toȱ storeȱaȱbinaryȱsearchȱtreeȱinȱanȱarray.ȱOfȱcourse,ȱtheȱfixedȱlengthȱofȱtheȱarrayȱlimitsȱtheȱ numberȱofȱelementsȱthatȱcanȱbeȱaddedȱtoȱtheȱtree,ȱbutȱifȱyouȱuseȱdynamicȱallocationȱ Download at http://www.pin5i.com/ 17.4 Treesȱ 517 ȱ ȱ /* ** Interface for a binary search tree module */ #define TREE_TYPE int /* Type of value in the tree */ /* ** insert ** Add a new value to the tree. The argument is the value ** to be added and must not already exist in the tree. */ void insert( TREE_TYPE value ); /* ** find ** Searches for a specific value, which is passed as the first ** argument. */ TREE_TYPE *find( TREE_TYPE value ); /* ** pre_order_traverse ** Does a pre-order traversal of the tree. The argument is a ** pointer to a callback function that will be called for ** each node in the tree, with the value passed as an argument. */ void pre_order_traverse( void (*callback)( TREE_TYPE value ) ); ȱ Programȱ17.7ȱȱBinaryȱsearchȱtreeȱinterfaceȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱȱȱȱȱtree.hȱ ȱ ȱ ȱ ȱ youȱ canȱ createȱ aȱ largerȱ spaceȱ andȱ copyȱ theȱ valuesȱ intoȱ itȱ whenȱ theȱ originalȱ arrayȱ overflows.ȱ ȱ ȱ ȱ An Arrayed, Binary Search Tree ȱ Theȱ keyȱ toȱ representingȱ aȱ treeȱ inȱ anȱ arrayȱ isȱ coȱ useȱ subscriptsȱ toȱ locateȱ parentsȱ andȱ childrenȱofȱaȱparticularȱvalue.ȱTheȱrulesȱareȱeasy:ȱ ȱ TheȱparentȱofȱnodeȱNȱisȱnodeȱN/2.ȱ ȱTheȱleftȱchildȱofȱnodeȱNȱisȱnodeȱ2N.ȱ TheȱrightȱchildȱofȱnodeȱNȱisȱnodeȱ2Nȱ+ȱ1.ȱ ȱ Theȱformulaȱforȱtheȱparentȱworksȱbecauseȱtheȱintegerȱdivisionȱoperatorȱtruncatesȱanyȱ fractionalȱpart.ȱ Download at http://www.pin5i.com/ Chapter 17 Classic Abstract Data Typesȱ 518ȱ ȱ CAUTION! ȱ Alas,ȱ thereȱ isȱ aȱ minorȱ problem.ȱ Theseȱ rulesȱ assumeȱ thatȱ theȱ rootȱ ofȱ theȱ treeȱ isȱ nodeȱ one,ȱbutȱCȱarraysȱbeginȱwithȱsubscriptȱzero.ȱTheȱeasiestȱsolutionȱisȱtoȱsimplyȱignoreȱtheȱ firstȱelementȱofȱtheȱarray.ȱIfȱtheȱelementsȱareȱsoȱlargeȱthatȱthisȱapproachȱwouldȱwasteȱ tooȱmuchȱspace,ȱthenȱyouȱcanȱuseȱtheseȱalternateȱrulesȱforȱzeroȬbasedȱarrayȱsubscriptsȱ instead:ȱ ȱ TheȱparentȱofȱnodeȱNȱisȱnodeȱ(Nȱ+ȱ1)/2ȱȬȱ1.ȱ TheȱleftȱchildȱofȱnodeȱNȱisȱnodeȱ2Nȱ+ȱ1.ȱ TheȱrightȱchildȱofȱnodeȱNȱisȱnodeȱ2Nȱ+ȱ2.ȱ ȱ Programȱ17.8ȱisȱaȱbinaryȱsearchȱtreeȱimplementedȱwithȱaȱstaticȱarray.ȱThereȱareȱ severalȱ pointsȱ ofȱ interestȱ inȱ thisȱ implementation.ȱ Itȱ usesȱ theȱ simplerȱ rulesȱ forȱ determiningȱchildrenȱsoȱtheȱarrayȱisȱdeclaredȱoneȱlargerȱthanȱtheȱadvertisedȱsizeȱandȱ itsȱ firstȱ elementȱ isȱ ignored.ȱ Functionsȱ areȱ definedȱ toȱ computeȱ theȱ leftȱ andȱ rightȱ childrenȱofȱaȱnode.ȱEvenȱthoughȱtheȱcomputationȱisȱsimple,ȱtheȱfunctionȱnamesȱmakeȱ theȱ codeȱ thatȱ useȱ themȱ muchȱ clearer.ȱ Theseȱ functionsȱ alsoȱ simplifyȱ theȱ taskȱ ofȱ modifyingȱtheȱmoduleȱtoȱuseȱtheȱalternateȱsetȱofȱrules.ȱ Thisȱ implementationȱ usesȱ theȱ valueȱ zeroȱ toȱ indicateȱ aȱ nodeȱ thatȱ isȱ notȱ beingȱ used.ȱIfȱzeroȱisȱaȱlegitimateȱdataȱvalue,ȱaȱdifferentȱvalueȱmustȱbeȱchosenȱandȱtheȱarrayȱ elementsȱmustȱbeȱinitializedȱdynamically.ȱAnotherȱtechniqueȱisȱtoȱhaveȱaȱcompanionȱ arrayȱofȱbooleanȱvaluesȱtoȱindicateȱwhichȱnodesȱareȱinȱuse.ȱ Aȱproblemȱwithȱanȱarrayedȱtreeȱisȱthatȱtheȱspaceȱinȱtheȱarrayȱisȱoftenȱnotȱusedȱ effectively.ȱSpaceȱisȱwastedȱbecauseȱnewȱvaluesȱmustȱbeȱinsertedȱatȱspecificȱplacesȱinȱ theȱtreeȱandȱcannotȱjustȱbeȱputȱwhereverȱthereȱhappensȱtoȱbeȱspace.ȱ Toȱ illustrate,ȱ supposeȱ anȱ arrayȱ ofȱ 100ȱ elementsȱ isȱ usedȱ toȱ holdȱ aȱ tree.ȱ Ifȱ theȱ valuesȱ1,ȱ2,ȱ3,ȱ4,ȱ5,ȱ6,ȱandȱ7ȱareȱinsertedȱinȱthatȱorder,ȱtheyȱwillȱbeȱstoredȱinȱlocationsȱ1,ȱ 2,ȱ4,ȱ8,ȱ16,ȱ32,ȱandȱ64,ȱrespectively.ȱButȱnowȱtheȱvalueȱ8ȱcannotȱbeȱinsertedȱbecauseȱtheȱ rightȱ childȱ ofȱ 7ȱ wouldȱ beȱ storedȱ inȱ locationȱ 128,ȱ andȱ theȱ arrayȱ isȱ notȱ thatȱ large.ȱ Whetherȱorȱnotȱthisȱproblemȱactuallyȱhappensȱdependsȱentirelyȱonȱtheȱorderȱinȱwhichȱ theȱ valuesȱareȱinserted.ȱIfȱ theȱ sameȱvaluesȱwereȱ insertedȱinȱthisȱ order,ȱ4,ȱ 2,ȱ1,ȱ 3,ȱ6,ȱ 5,ȱ andȱ7,ȱtheyȱwouldȱoccupyȱlocationsȱ1ȱthroughȱ7ȱofȱtheȱarray,ȱandȱtheȱvalueȱ8ȱcouldȱbeȱ insertedȱwithoutȱdifficulty.ȱ Withȱ aȱ dynamicallyȱ allocatedȱ array,ȱ weȱ canȱ reallocateȱ theȱ arrayȱ whenȱ moreȱ spaceȱ isȱ needed.ȱ Thisȱ techniqueȱ isȱ notȱ aȱ veryȱ goodȱ solutionȱ toȱ theȱ problemȱ ofȱ anȱ unbalancedȱ tree,ȱ though,ȱ becauseȱ eachȱ newȱ insertionȱ requiresȱ theȱ arrayȱ sizeȱ toȱ beȱ doubled,ȱ andȱ theȱ spaceȱ availableȱ forȱ dynamicȱ memoryȱ allocationȱ willȱ soonȱ beȱ exhausted.ȱAȱbetterȱsolutionȱisȱtoȱuseȱaȱlinkedȱbinaryȱtreeȱratherȱthanȱanȱarray.ȱ Download at http://www.pin5i.com/ 17.4 Treesȱ 519 ȱ ȱ /* ** A binary search tree implemented with a static array. The ** array size can be adjusted only by changing the #define and ** recompiling the module. */ #include "tree.h" #include <assert.h> #include <stdio.h> #define #define TREE_SIZE ARRAY_SIZE 100 /* Max # of values in the tree */ ( TREE_SIZE + 1 ) /* ** The array that holds the values in the tree. */ static TREE_TYPE tree[ ARRAY_SIZE ]; /* ** left_child ** Compute the subscript of the left child of a node. */ static int left_child( int current ) { return current * 2; } /* ** right_child ** Compute the subscript of the right child of a node. */ static int right_child( int current ) { return current * 2 + 1; } /* ** insert */ void insert( TREE_TYPE value ) { int current; ȱ Programȱ17.8ȱȱBinaryȱsearchȱtreeȱimplementedȱwithȱaȱstaticȱarrayȱ ȱ ȱ continued...ȱ Download at http://www.pin5i.com/ 520ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ ȱ /* ** Ensure the value is nonzero, because zero indicates an ** unused node. */ assert( value != 0 ); /* ** Start with the root node. */ current = 1; /* ** Go to the proper subtree until we reach a leaf. */ while( tree[ current ] != 0 ){ /* ** Go to the left or right subtree, as appropriate. ** (And make sure we don't have a duplicate value!) */ if( value < tree[ current ] ) current = left_child( current ); else { assert( value != tree[ current ] ); current = right_child( current ); } assert( current < ARRAY_SIZE ); } tree[ current ] = value; } /* ** find */ TREE_TYPE * find( TREE_TYPE value ) { int current; /* ** Start with the root node. ** go to the proper subtree. */ current = 1; Until we find the value, ȱ Programȱ17.8ȱȱBinaryȱsearchȱtreeȱimplementedȱwithȱaȱstaticȱarrayȱ ȱ ȱ ȱ continued...ȱ Download at http://www.pin5i.com/ 17.4 Treesȱ 521 ȱ ȱ while( current < ARRAY_SIZE && tree[ current ] != value ){ /* ** Go to the left or right subtree, as appropriate. */ if( value < tree[ current ] ) current = left_child( current ); else current = right_child( current ); } if( current < ARRAY_SIZE ) return tree + current; else return 0; } /* ** do_pre_order_traverse ** Do one level of a pre-order traverse. This helper function ** is needed to save the information of which node we're ** currently processing; this is not a part of the client's ** interface. */ static void do_pre_order_traverse( int current, void (*callback)( TREE_TYPE value ) ) { if( current < ARRAY_SIZE && tree[ current ] != 0 ){ callback( tree[ current ] ); do_pre_order_traverse( left_child( current ), callback ); do_pre_order_traverse( right_child( current ), callback ); } } /* ** pre_order_traverse */ void pre_order_traverse( void (*callback)( TREE_TYPE value ) ) { do_pre_order_traverse( 1, callback ); } ȱ Programȱ17.8ȱȱBinaryȱsearchȱtreeȱimplementedȱwithȱaȱstaticȱarrayȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱa_tree.cȱ Download at http://www.pin5i.com/ 522ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ A Linked Binary Search Tree ȱ Theȱ linkedȱ implementationȱ eliminatesȱ theȱ problemȱ ofȱ unusedȱ arrayȱ spaceȱ byȱ dynamicallyȱ allocatingȱ memoryȱ toȱ holdȱ eachȱ newȱ valueȱ andȱ linkingȱ theseȱ structuresȱ togetherȱintoȱaȱtree.ȱThus,ȱthereȱisnȇtȱanyȱunusedȱmemory.ȱ Programȱ 17.9ȱ isȱ theȱ linkedȱ implementation.ȱ Compareȱ itȱ withȱ theȱ arrayedȱ treeȱ implementationȱ inȱ Programȱ 17.8.ȱ Becauseȱeachȱ nodeȱ inȱ theȱ treeȱ mustȱ pointȱ toȱ itsȱ leftȱ andȱ rightȱ children,ȱ aȱ structureȱ isȱ usedȱ toȱ holdȱ theȱ valueȱ andȱ theȱ twoȱ pointers.ȱ Theȱ arrayȱ isȱ replacedȱ byȱ aȱ pointerȱ toȱ theȱ rootȱ ofȱ theȱ tree.ȱ Thisȱ pointerȱ isȱ initiallyȱ NULL,ȱ indicatingȱthatȱtheȱtreeȱisȱempty.ȱ Theȱ insertȱfunctionȱusesȱtwoȱpointers. 56 ȱTheȱfirstȱisȱusedȱtoȱexamineȱnodesȱinȱ theȱ treeȱ toȱ findȱ theȱ properȱ placeȱ toȱ insertȱ theȱ newȱ value.ȱ Theȱ secondȱ isȱ aȱ pointerȱ toȱ whateverȱ linkȱ pointsȱ toȱ theȱ nodeȱ currentlyȱ beingȱ examined.ȱ Whenȱ aȱ leafȱ isȱ reached,ȱ thisȱ pointerȱ isȱ theȱ oneȱ thatȱ mustȱ beȱ changedȱ toȱ insertȱ theȱ newȱ node.ȱ Theȱ functionȱ walksȱ downȱ theȱ tree,ȱ goingȱ leftȱ orȱ rightȱ accordingȱ toȱ howȱ theȱ newȱ valueȱ comparesȱ withȱtheȱcurrentȱnodeȇsȱvalue,ȱuntilȱaȱleafȱisȱreached.ȱThenȱaȱnewȱnodeȱisȱcreatedȱandȱ linkedȱintoȱtheȱtree.ȱThisȱiterativeȱalgorithmȱinsertsȱtheȱfirstȱnodeȱinȱtheȱtreeȱproperlyȱ withoutȱaȱspecialȱcase.ȱ ȱ ȱ ȱ Variations on the Tree Interface ȱ Asȱ itȱ isȱ shown,ȱ theȱ findȱ functionȱ reallyȱ onlyȱ checksȱ forȱ membership.ȱ Returningȱ aȱ pointerȱtoȱtheȱvalueȱthatȱwasȱfoundȱisnȇtȱtooȱusefulȱbecauseȱtheȱcallerȱalreadyȱknowsȱ theȱvalue:ȱitȱwasȱpassedȱasȱanȱargument!ȱ Supposeȱtheȱvaluesȱcontainedȱinȱtheȱtreeȱareȱinȱfactȱstructuresȱthatȱcontainȱaȱkeyȱ valueȱandȱsomeȱdata.ȱNowȱweȱcanȱmodifyȇȱtheȱ findȱfunctionȱtoȱbeȱmuchȱmoreȱuseful.ȱ Locatingȱ aȱ particularȱ nodeȱ byȱ itsȱ keyȱ andȱ thenȱ returningȱ aȱ pointerȱ toȱ theȱ structureȱ givesȱtheȱclientȱsomethingȱheȱdidnȇtȱpreviouslyȱhave—ȱtheȱdataȱthatȱisȱassociatedȱwithȱ theȱ key.ȱ However,ȱ toȱ achieveȱ thisȱ resultȱ findȱ mustȱ somehowȱ compareȱ onlyȱ theȱ keyȱ portionȱofȱtheȱvalueȱinȱeachȱnode.ȱTheȱsolutionȱisȱtoȱwriteȱaȱfunctionȱthatȱmakesȱthisȱ comparisonȱandȱpassȱfindȱaȱpointerȱtoȱtheȱfunctionȱlikeȱweȱdidȱwithȱqsort.ȱ Sometimesȱ theȱ clientȱ mayȱ wantȱ toȱ traverseȱ theȱ treeȱ himself,ȱ forȱ example,ȱ toȱ countȱtheȱnumberȱofȱchildrenȱbelongingȱtoȱeachȱnode.ȱBothȱtheȱTreeNodeȱstructureȱandȱ theȱpointerȱtoȱtheȱrootȱnodeȱofȱtheȱtreeȱmustȱbeȱmadeȱpublicȱforȱtheȱclientȱtoȱtraverseȱ theȱ tree.ȱ Theȱ safestȱ wayȱ ofȱ providingȱ theȱ rootȱ pointerȱ isȱ throughȱ aȱ function,ȱ thusȱ preventingȱtheȱclientȱfromȱchangingȱtheȱrootȱpointerȱhimselfȱandȱlosingȱtheȱtree.ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱWeȱusedȱtheȱsameȱtechniqueȱinȱChapterȱ12ȱinȱtheȱfunctionȱthatȱinsertedȱvaluesȱintoȱanȱordered,ȱsinglyȱlinkedȱlist.ȱ!fȱyouȱ lookȱ atȱ theȱ pathȱ thatȱ isȱ followedȱ fromȱ theȱ rootȱ ofȱ theȱ treeȱ toȱ theȱ leafȱ whereȱ theȱ insertionȱ willȱ occur,ȱ youȱ willȱ seeȱ thatȱ itȱ isȱ essentiallyȱaȱsinglyȱlinkedȱlist.ȱ 56 Download at http://www.pin5i.com/ 17.4 Treesȱ 523 ȱ ȱ /* ** A binary search tree implemented by linking dynamically allocated ** structures. */ #include "tree.h" #include <assert.h> #include <stdio.h> #include <malloc.h> /* ** The TreeNode structure holds the value and pointers for one ** tree node. */ typedef struct TREE_NODE { TREE_TYPE value; struct TREE_NODE *left; struct TREE_NODE *right; } TreeNode; /* ** The pointer to the root node in the tree. */ static TreeNode *tree; /* ** insert */ void insert( TREE_TYPE value ) { TreeNode *current; TreeNode **link; /* ** Start with the root node. */ link = &tree; /* ** As long as we keep finding values, go to the proper ** subtree. */ while( (current = *link) != NULL ){ /* ** Go to the left or right subtree, as appropriate. ȱ Programȱ17.9ȱȱLinkedȱbinaryȱsearchȱtreeȱȱ ȱ ȱ ȱ ȱ ȱ continued...ȱ Download at http://www.pin5i.com/ 524ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ ȱ ** (And make sure we don't have a duplicate value!) */ if( value < current->value ) link = &current->left; else { assert( value != current->value ); link = &current->right; } } /* ** Allocate a new node; make the proper link field point ** to it. */ current = malloc( sizeof( TreeNode ) ); assert( current != NULL ); current->value = value; current->left = NULL; current->right = NULL; *link = current; } /* ** find */ TREE_TYPE * find( TREE_TYPE value ) { TreeNode *current; /* ** Start with the root node. ** go to the proper subtree. */ current = tree; Until we find the value, while( current != NULL && current->value != value ){ /* ** Go to the left or right subtree, as appropriate. */ if( value < current->value ) current = current->left; else current = current->right; } ȱ Programȱ17.9ȱȱLinkedȱbinaryȱsearchȱtreeȱȱ ȱ ȱ ȱ ȱ ȱ ȱ continued...ȱ Download at http://www.pin5i.com/ 17.4 Treesȱ 525 ȱ ȱ if( current != NULL ) return &current->value; else return NULL; } /* ** do_pre_order_traverse ** Do one level of a pre-order traverse. This helper function ** is needed to save the information of which node we're ** currently processing; this is not a part of the ** client's interface. */ static void do_pre_order_traverse( TreeNode *current, void (*callback)( TREE_TYPE value ) ) { if( current != NULL ){ callback( current->value ); do_pre_order_traverse( current->left, callback ); do_pre_order_traverse( current->right, callback ); } } /* ** pre_order_traverse */ void pre_order_traverse( void (*callback)( TREE_TYPE value ) ) { do_pre_order_traverse( tree, callback ); } ȱ Programȱ17.9ȱȱLinkedȱbinaryȱsearchȱtreeȱȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱȱl_tree.cȱ ȱ ȱ ȱ ȱ ȱ Itȱ isȱ oftenȱ helpfulȱ forȱ eachȱ treeȱ nodeȱ toȱ haveȱ aȱ pointerȱ toȱ itsȱ parentȱ node.ȱ Theȱ clientȱ canȱ useȱ theȱ parentȱ pointerȱ toȱ moveȱ bothȱ upȱ andȱ downȱ inȱ theȱ tree.ȱ Theȱ findȱ functionȱ inȱ thisȱ moreȱ publicȱ treeȱ couldȱ thenȱ returnȱ aȱ pointerȱ toȱ theȱ treeȱ nodeȱ ratherȱ thanȱ theȱ value,ȱ whichȱ wouldȱ allowȱ theȱ clientȱ toȱ useȱ thatȱ pointerȱ asȱ theȱ beginningȱ ofȱ otherȱtraversals.ȱ Oneȱ finalȱ improvementȱ isȱ aȱ destroy_treeȱ functionȱ toȱ freeȱ allȱ ofȱ theȱ memoryȱ thatȱ wasȱ allocatedȱ forȱ theȱ tree.ȱ Theȱ implementationȱ ofȱ thisȱ functionȱ isȱ leftȱ asȱ anȱ exercise.ȱ Download at http://www.pin5i.com/ Chapter 17 Classic Abstract Data Typesȱ 526ȱ ȱ 17.5 Improvements in Implementation ȱ TheȱimplementationsȱinȱthisȱchapterȱillustrateȱhowȱtheȱdifferentȱADTsȱwork,ȱbutȱtheyȱ areȱinadequateȱinȱseveralȱrespectsȱforȱuseȱinȱrealȱprograms.ȱThisȱsectionȱidentifiesȱtheseȱ problemsȱ andȱ suggestsȱ howȱ toȱ solveȱ them.ȱ Weȱ useȱ theȱ arrayedȱ stackȱ asȱ anȱ example,ȱ butȱtheȱtechniquesȱdescribedȱapplyȱtoȱtheȱotherȱADTsȱasȱwell.ȱ ȱ ȱ ȱ 17.5.1 CAUTION! Having More Than One Stack ȱ Theȱ mainȱ problemȱ withȱ theȱ implementationsȱ soȱ farȱ isȱ that,ȱ theyȱ encapsulateȱ theȱ memoryȱusedȱtoȱholdȱtheȱstructureȱasȱwellȱasȱtheȱfunctionsȱthatȱmanipulateȱit.ȱThusȱaȱ programȱcannotȱhaveȱmoreȱthanȱoneȱstack!ȱ Thisȱ limitationȱ isȱ easilyȱ solvedȱ byȱ removingȱ theȱ declarationsȱ ofȱ theȱ arrayȱ andȱ top_elementȱ fromȱ theȱ stackȱ implementationȱ moduleȱ andȱ puttingȱ themȱ inȱ theȱ clientȇsȱ codeȱinstead.ȱTheyȱareȱthenȱaccessedȱbyȱtheȱstackȱfunctionsȱthroughȱarguments,ȱsoȱtheȱ functionsȱareȱnoȱlongerȱtiedȱtoȱoneȱarray.ȱTheȱclientȱcanȱcreateȱanyȱnumberȱofȱarraysȱ andȱmanipulateȱthemȱasȱstacksȱbyȱcallingȱtheȱstackȱfunctions.ȱ ȱ Theȱdangerȱwithȱthisȱapproachȱisȱtheȱlossȱofȱencapsulation.ȱIfȱtheȱclientȱhasȱtheȱdata,ȱheȱ canȱaccessȱitȱdirectly.ȱIllegalȱaccesses,ȱforȱexampleȱaddingȱaȱnewȱvalueȱtoȱtheȱarrayȱinȱ theȱwrongȱplaceȱorȱaddingȱaȱvalueȱwithoutȱadjustingȱtop_element,ȱcanȱresultȱinȱlostȱorȱ illegalȱdataȱorȱmayȱcauseȱtheȱstackȱfunctionsȱtoȱfail.ȱ Aȱ relatedȱ problemȱ isȱ ensuringȱ thatȱ theȱ clientȱ passesȱ theȱ correctȱ stackȱ andȱ top_elementȱ argumentsȱ toȱ eachȱ stackȱ functionȱ thatȱ isȱ called.ȱ Ifȱ theseȱ argumentsȱ areȱ mixedȱ up,ȱ theȱ resultȱ isȱ garbage.ȱ Weȱ canȱ reduceȱ theȱ likelihoodȱ ofȱ thisȱ happeningȱ byȱ bundlingȱtheȱstackȱarrayȱandȱitsȱtop_elementȱvalueȱtogetherȱinȱaȱstructure.ȱ Thereȱ wasnȇtȱ anyȱ dangerȱ ofȱ eitherȱ problemȱ occurringȱ whenȱ theȱ stackȱ moduleȱ containedȱ theȱ data.ȱ Theȱ exercisesȱ describeȱ aȱ modificationȱ thatȱ letsȱ theȱ stackȱ moduleȱ manageȱmoreȱthanȱoneȱstack.ȱ ȱ ȱ ȱ 17.5.2 Having More Than One Type ȱ Evenȱifȱtheȱpreviousȱproblemȱisȱsolvedȱtheȱtypeȱofȱvaluesȱstoredȱonȱtheȱstackȱisȱfixedȱatȱ compileȱtimeȱbyȱtheȱtypeȱinȱtheȱstack.hȱheaderȱfile.ȱIfȱyouȱneedȱaȱstackȱofȱintegersȱandȱ aȱstackȱofȱfloats,ȱyouȇreȱoutȱofȱluck.ȱ ȱ Download at http://www.pin5i.com/ 17.5 Improvements in Implementationȱ 527 ȱ CAUTION! Theȱ simplisticȱ wayȱ ofȱ solvingȱ thisȱ problemȱ isȱ toȱ writeȱ aȱ separateȱ copyȱ ofȱ theȱ stackȱfunctionsȱtoȱ dealȱwithȱeachȱdifferentȱdataȱtype.ȱ Thisȱ approachȱdoesȱtheȱjobȱbutȱ involvesȱaȱlotȱofȱduplicatedȱcode,ȱwhichȱmakesȱmaintenanceȱmoreȱdifficult.ȱ Aȱmoreȱelegantȱapproachȱisȱtoȱimplementȱtheȱentireȱstackȱmoduleȱasȱaȱ #defineȱ thatȱ takesȱ theȱ desiredȱ typeȱ asȱ aȱ parameter.ȱ Thisȱ definitionȱ isȱ thenȱ usedȱ toȱ createȱ theȱ routinesȱforȱeachȱtypeȱthatȱisȱrequired.ȱForȱthisȱsolutionȱtoȱwork,ȱthough,ȱweȱmustȱfindȱ aȱwayȱtoȱmakeȱtheȱnamesȱofȱtheȱfunctionsȱgeneratedȱforȱdifferentȱtypesȱuniqueȱsoȱthatȱ theyȱdonȇtȱconflictȱwithȱeachȱother.ȱYouȱmustȱalsoȱbeȱcarefulȱtoȱcreateȱonlyȱoneȱsetȱofȱ routinesȱforȱeachȱtypeȱnoȱmatterȱhowȱmanyȱstacksȱofȱthatȱtypeȱyouȱneed.ȱAnȱexampleȱ ofȱthisȱapproachȱisȱpresentedȱinȱSectionȱ17.5.4.ȱ Aȱthirdȱapproachȱisȱtoȱmakeȱtheȱstackȱtypelessȱbyȱhavingȱitȱstoreȱ void *ȱvalues.ȱ Toȱstoreȱintegersȱandȱotherȱdataȱthatȱtakesȱtheȱsameȱamountȱofȱspaceȱasȱaȱpointer,ȱcastsȱ areȱusedȱtoȱconvertȱtheȱdesiredȱtypeȱtoȱ void *ȱinȱtheȱargumentȱtoȱ pushȱandȱtoȱconvertȱ theȱvalueȱreturnedȱbyȱ topȱbackȱtoȱtheȱdesiredȱtype.ȱToȱworkȱwithȱlargerȱdata,ȱsuchȱasȱ structures,ȱpointersȱtoȱtheȱdataȱareȱstoredȱonȱtheȱstack.ȱ ȱ Theȱproblemȱwithȱthisȱapproachȱisȱtheȱlossȱofȱtypeȱchecking.ȱThereȱisȱnoȱwayȱtoȱverifyȱ thatȱtheȱvalueȱpassedȱtoȱpushȱisȱtheȱcorrectȱtypeȱforȱtheȱstackȱbeingȱused.ȱIfȱanȱintegerȱisȱ accidentallyȱ pushedȱ onȱ aȱ stackȱ thatȱ containsȱ pointers,ȱ theȱ resultȱ isȱ almostȱ sureȱ toȱ beȱ disaster.ȱ Makingȱ theȱ treeȱ moduleȱ typelessȱ isȱ aȱ littleȱ moreȱ difficultȱ becauseȱ theȱ treeȱ functionsȱmustȱcompareȱvaluesȱinȱtheȱtreeȱnodes.ȱHowever,ȱweȱcanȱpassȱaȱpointerȱtoȱaȱ comparisonȱfunctionȱwrittenȱbyȱtheȱclientȱasȱanȱargumentȱtoȱeachȱtreeȱfunction.ȱAgain,ȱ theȱresultȱofȱpassingȱtheȱwrongȱpointerȱisȱdisaster.ȱ ȱ ȱ ȱ 17.5.3 Name Clashes ȱ Bothȱtheȱstackȱandȱqueueȱmodulesȱhaveȱ is_fullȱandȱ is_emptyȱfunctions,ȱandȱbothȱtheȱ queueȱ andȱ treeȱ modulesȱ haveȱ anȱ insertȱ function.ȱ Ifȱ youȱ wantedȱ toȱ addȱ aȱ deleteȱ functionȱ toȱ theȱ treeȱ module,ȱ itȱ wouldȱ conflictȱ withȱ theȱ oneȱ alreadyȱ inȱ theȱ queueȱ module.ȱ Toȱcoexistȱinȱoneȱprogram,ȱtheȱnamesȱofȱallȱofȱtheseȱfunctionsȱmustȱbeȱunique.ȱ However,ȱ thereȱ isȱ strongȱ motivationȱ toȱ retainȱ theȱ ȈstandardȈȱ namesȱ associatedȱ withȱ eachȱ dataȱ structureȱ wheneverȱ possible.ȱ Theȱ solutionȱ isȱ toȱ compromise:ȱ chooseȱ aȱ namingȱ conventionȱ thatȱ isȱ tolerableȱ andȱ stickȱ withȱ it.ȱ Forȱ example,ȱ is_queue_emptyȱ andȱ is_atack_emptyȱ solveȱ theȱ problem.ȱ Theirȱ disadvantageȱ isȱ thatȱ theȱ longerȱ namesȱ areȱnotȱasȱconvenientȱtoȱuse,ȱyetȱtheyȱdoȱnotȱconveyȱanyȱadditionalȱinformation.ȱ Download at http://www.pin5i.com/ Chapter 17 Classic Abstract Data Typesȱ 528ȱ ȱ 17.5.4 Standard Libraries of ADTs ȱ Computerȱscienceȱisȱnotȱanȱoldȱdiscipline,ȱbutȱweȱhaveȱcertainlyȱbeenȱatȱitȱlongȱenoughȱ toȱ learnȱ everythingȱ thereȱ isȱ toȱ knowȱ aboutȱ theȱ behaviorȱ ofȱ stacksȱ andȱ queues.ȱ Thenȱ whyȱ doesȱ everyoneȱ writeȱ theirȱ ownȱ stackȱ andȱ queueȱ functions?ȱ Whyȱ arenȇtȱ theseȱ ADTsȱpanȱofȱtheȱstandardȱlibrary?ȱ Itȱisȱbecauseȱofȱtheȱthreeȱproblemsȱjustȱdiscussed.ȱTheȱnameȱclashesȱareȱsolvedȱ easilyȱenough,ȱbutȱtheȱlackȱofȱtypeȱsafetyȱandȱtheȱdangersȱthatȱcomeȱfromȱgivingȱtheȱ clientȱ directȱ accessȱ toȱ theȱ dataȱ makeȱ itȱ infeasibleȱ toȱ writeȱ aȱ libraryȱ ofȱ functionsȱ thatȱ implementȱaȱstackȱinȱaȱgeneral,ȱyetȱsafeȱway.ȱ Solvingȱthisȱproblemȱrequiresȱgenericity,ȱtheȱabilityȱtoȱwriteȱaȱsetȱofȱfunctionsȱinȱ whichȱ theȱ typesȱ ofȱ theȱ dataȱ haveȱ notȱ yetȱ beenȱ decided.ȱ Thisȱ setȱ ofȱ functionsȱ isȱ thenȱ instantiated,ȱorȱcreated,ȱwithȱeachȱdifferentȱtypeȱthatȱisȱneeded.ȱCȱdoesȱnotȱprovideȱthisȱ capability,ȱbutȱweȱcanȱuseȱtheȱ#defineȱmechanismȱtoȱapproximateȱit.ȱ Programȱ17.10aȱcontainsȱaȱ #defineȱwhoseȱbodyȱisȱtheȱentireȱimplementationȱofȱ anȱ arrayedȱ stack.ȱ Theȱ argumentsȱ toȱ theȱ #defineȱ areȱ theȱ typeȱ ofȱ valueȱ toȱ beȱ stored,ȱ aȱ suffix,ȱandȱtheȱarrayȱsizeȱtoȱuse.ȱTheȱsuffixȱisȱappendedȱtoȱeachȱofȱtheȱnamesȱdefinedȱ byȱtheȱimplementationȱtoȱavoidȱnameȱclashes.ȱ Programȱ17.10bȱusesȱtheȱdeclarationȱinȱProgramȱ17.10aȱtoȱcreateȱtwoȱstacks,ȱoneȱ thatȱ holdsȱ upȱ toȱ tenȱ integersȱ andȱ anotherȱ thatȱ holdsȱ upȱ toȱ fiveȱ floats.ȱ Whenȱ eachȱ #defineȱisȱexpanded,ȱ aȱnewȱsetȱofȱstackȱroutinesȱ isȱ createdȱtoȱ manipulateȱ theȱproperȱ typeȱ ofȱ data.ȱ However,ȱ ifȱ twoȱ stacksȱ ofȱ integersȱ wereȱ needed,ȱ twoȱ setsȱ ofȱ identicalȱ functionsȱwouldȱbeȱcreated.ȱ Weȱ solveȱ thisȱ problemȱ byȱ rewritingȱ Programȱ 17.10aȱ asȱ threeȱ separateȱ macros:ȱ oneȱtoȱdeclareȱtheȱinterface,ȱoneȱtoȱcreateȱtheȱfunctionsȱthatȱmanipulateȱtheȱdata,ȱandȱ oneȱtoȱcreateȱtheȱdata.ȱWhenȱtheȱfirstȱstackȱofȱintegersȱisȱneeded,ȱallȱthreeȱmacrosȱareȱ used.ȱAdditionalȱstacksȱofȱintegersȱareȱcreatedȱbyȱrepeatedlyȱinvokingȱtheȱlastȱmacro.ȱȱ Theȱinterfaceȱtoȱtheȱstackȱmustȱalsoȱbeȱchanged.ȱTheȱfunctionsȱmustȱtakeȱanȱadditionalȱ argumentȱthatȱspecifiesȱtheȱstackȱtoȱmanipulate.ȱTheseȱmodificationsȱareȱtheȱsubjectȱofȱ aȱprogrammingȱexercise.ȱ Thisȱ techniqueȱ makesȱ itȱ possibleȱ toȱ createȱ aȱ libraryȱ ofȱ genericȱ abstractȱ dataȱ types.ȱ However,ȱ theȱ addedȱ flexiblityȱ comesȱ withȱ aȱ price.ȱ Theȱ userȱ hasȱ severalȱ newȱ responsibilities.ȱHeȱorȱsheȱmustȱnow:ȱ ȱ 1. decideȱ onȱ aȱ namingȱ conventionȱ toȱ avoidȱ nameȱ clashesȱ amongȱ stacksȱ ofȱ differentȱ types,ȱ 2. beȱsureȱtoȱcreateȱexactlyȱoneȱsetȱofȱstackȱroutinesȱforȱeachȱdifferentȱtype,ȱ 3. beȱ sureȱ toȱ useȱ theȱ properȱ nameȱ (forȱ example,ȱ push_intȱ versusȱ push_float)ȱ whenȱ accessingȱaȱstack.ȱ Download at http://www.pin5i.com/ 17.5 Improvements in Implementationȱ 529 ȱ ȱ /* ** GENERIC implementation of a stack with a static array. The array ** size is given as one of the arguments when the stack is ** instantiated. */ #include <assert.h> #define GENERIC_STACK( STACK_TYPE, SUFFIX, STACK_SIZE ) static static STACK_TYPE int stack##SUFFIX[ STACK_SIZE ]; top_element##SUFFIX = -1; int is_empty##SUFFIX( void ) { return top_element##SUFFIX == -1; } int is_full##SUFFIX( void ) { return top_element##SUFFIX == STACK_SIZE - 1; } void push##SUFFIX( STACK_TYPE value ) { assert( !is_full##SUFFIX() ); top_element##SUFFIX += 1; stack##SUFFIX[ top_element##SUFFIX ] = value; } void pop##SUFFIX( void ) { assert( !is_empty##SUFFIX() ); top_element##SUFFIX -= 1; } STACK_TYPE top##SUFFIX( void ) { assert( !is_empty##SUFFIX() ); return stack##SUFFIX[ top_element##SUFFIX ]; } ȱ Programȱ17.10aȱȱGenericȱarrayedȱstackȱ ȱ ȱ ȱ ȱ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ȱ ȱ ȱȱȱȱg_stack.hȱ Download at http://www.pin5i.com/ 530ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ ȱ /* ** A client that uses the generic stack module to create two stacks ** holding different types of data. */ #include <stdlib.h> #include <stdio.h> #include "g_stack.h" /* ** Create two stacks, one of integers and one of floats. */ GENERIC_STACK( int, _int, 10 ) GENERIC_STACK( float, _float, 5 ) int main() { /* ** Push several values on each stack. */ push_int( 5 ); push_int( 22 ); push_int( 15 ); push_float( 25.3 ); push_float( -40.5 ); /* ** Empty the integer stack and print the values. */ while( !is_empty_int() ){ printf( "Popping %d\n", top_int() ); pop_int(); } /* ** Empty the float stack and print the values. */ while( !is_empty_float() ){ printf( "Popping %f\n", top_float() ); pop_float(); } return EXIT_SUCCESS; } ȱ Programȱ17.10bȱȱUsingȱtheȱgenericȱarrayedȱstackȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱg_client.cȱ Download at http://www.pin5i.com/ 17.6 Summaryȱ 531 ȱ 4. beȱsureȱtoȱpassȱtheȱproperȱstackȱdataȱstructureȱtoȱtheȱfunctions.ȱ ȱ ItȱisȱnotȱsurprisingȱthatȱgenericityȱisȱhardȱtoȱimplementȱinȱC,ȱbecauseȱtheȱlanguageȱwasȱ designedȱ longȱ beforeȱ theȱ notionȱ wasȱ described.ȱ Genericityȱ isȱ oneȱ ofȱ theȱ problemsȱ addressedȱmoreȱcompletelyȱbyȱObjectȬOrientedȱlanguages.ȱ ȱ ȱ ȱ 17.6 Summary ȱ Thereȱ areȱ threeȱ techniquesȱ forȱ obtainingȱ memoryȱ forȱ ADTs;ȱ aȱ staticȱ array,ȱ aȱ dynamicallyȱ allocatedȱ array,ȱ andȱ aȱ dynamicallyȱ allocatedȱ linkedȱ structure.ȱ Theȱ staticȱ arrayȱ imposesȱ aȱ predetermined,ȱ fixedȱ sizeȱ onȱ theȱ structure.ȱ Theȱ sizeȱ ofȱ aȱ dynamicȱ arrayȱ canȱ beȱ computedȱ atȱ runȱ time,ȱ andȱ theȱ arrayȱ canȱ beȱ reallocatedȱ ifȱ needed.ȱ Aȱ linkedȱstructureȱdoesnȇtȱimposeȱanyȱlimitȱonȱtheȱmaximumȱnumberȱofȱvalues.ȱ AȱstackȱisȱaȱlastȬin,ȱfirstȬoutȱstructure.ȱItsȱinterfaceȱprovidesȱfunctionsȱtoȱpushȱaȱ newȱ valueȱ onȱ theȱ stackȱ andȱ popȱ aȱ valueȱ offȱ theȱ stack.ȱ Anȱ alternateȱ interfaceȱ addsȱ aȱ thirdȱfunctionȱwhichȱreturnsȱtheȱlopȱvalueȱonȱtheȱstackȱwithoutȱpoppingȱit.ȱAȱstackȱisȱ easilyȱ implementedȱ withȱ anȱ arrayȱ byȱ usingȱ aȱ variable,ȱ initializedȱ toȱ Ȭ1,ȱ toȱ rememberȱ theȱ subscriptȱ ofȱ theȱ topȱ element.ȱ Toȱ pushȱ aȱ newȱ valueȱ onȱ theȱ stack,ȱ theȱ variableȱ isȱ incrementedȱ andȱ theȱ valueȱ isȱ thenȱ storedȱ inȱ theȱ array.ȱ Whenȱ poppingȱ aȱ value,ȱ theȱ variableȱ isȱ decrementedȱ afterȱ accessingȱ theȱ valueȱ inȱ theȱ array.ȱ Twoȱ additionalȱ functionsȱareȱrequiredȱtoȱuseȱaȱdynamicallyȱallocatedȱstack.ȱOneȱcreatesȱtheȱstackȱtoȱaȱ specifiedȱ size,ȱ andȱ theȱ otherȱ destroysȱ it.ȱ Aȱ singlyȱ linkedȱ listȱ alsoȱ worksȱ wellȱ forȱ implementingȱaȱstack.ȱValuesȱareȱpushedȱbyȱinsertingȱthemȱatȱtheȱbeginningȱofȱtheȱlist,ȱ andȱtheȱstackȱisȱpoppedȱbyȱremovingȱtheȱfirstȱclement.ȱ AȱqueueȱisȱaȱfirstȬin,ȱfirstȬoutȱstructure.ȱItsȱinterfaceȱprovidesȱfunctionsȱtoȱinsertȱ aȱnewȱvalueȱandȱtoȱdeleteȱanȱexistingȱvalue.ȱBecauseȱofȱtheȱorderingȱaȱqueueȱimposesȱ onȱ itsȱ elements,ȱ aȱ circularȱ arrayȱ isȱ aȱ moreȱ appropriateȱ implementationȱ thanȱ anȱ ordinaryȱarray.ȱȱWhenȱaȱvariableȱusedȱasȱaȱsubscriptȱforȱaȱcircularȱarrayȱisȱincrementedȱ pastȱtheȱendȱofȱtheȱarray,ȱitsȱvalueȱwrapsȱaroundȱtoȱzero.ȱToȱdetermineȱwhenȱtheȱarrayȱ isȱfull,ȱyouȱmayȱuseȱaȱvariableȱthatȱcountsȱ theȱnumberȱofȱinsertedȱvalues.ȱToȱuseȱtheȱ frontȱandȱrearȱpointersȱofȱtheȱqueueȱtoȱdetectȱthisȱcondition,ȱthereȱmustȱalwaysȱbeȱatȱ leastȱoneȱemptyȱelementȱinȱtheȱarray.ȱ Aȱbinaryȱsearchȱtreeȱ(BST)ȱisȱaȱstructureȱthatȱisȱeitherȱemptyȱorȱhasȱaȱvalueȱandȱ upȱtoȱtwoȱchildren,ȱcalledȱleftȱandȱright,ȱwhichȱareȱalsoȱBSTs.ȱTheȱvalueȱinȱaȱnodeȱofȱaȱ BSTȱ isȱ greaterȱ thanȱ allȱ theȱ valuesȱ containedȱ inȱ itsȱ leftȱ subtree,ȱ andȱ lessȱ thanȱ allȱ theȱ valuesȱinȱitsȱrightȱsubtree.ȱBecauseȱofȱthisȱordering,ȱitȱisȱveryȱefficientȱtoȱsearchȱforȱaȱ valueȱ inȱ aȱ BST—ifȱ aȱ nodeȱ doesȱ notȱ containȱ theȱ desiredȱ value,ȱ youȱ canȱ alwaysȱ tellȱ whichȱofȱitsȱsubtreesȱtoȱexamine.ȱToȱinsertȱaȱvalueȱintoȱaȱBST,ȱyouȱfirstȱsearchȱforȱit.ȱIfȱ Download at http://www.pin5i.com/ 532ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ theȱvalueȱisȱnotȱfound,ȱinsertȱitȱatȱtheȱlocationȱwhereȱtheȱsearchȱfailed.ȱWhenȱremovingȱ aȱvalueȱfromȱaȱBST,ȱcareȱmustȱbeȱtakenȱnotȱtoȱdisconnectȱitsȱsubtreesȱfromȱtheȱtree.ȱAȱ treeȱisȱtraversedȱbyȱprocessingȱallȱofȱitsȱnodesȱinȱsomeȱorder.ȱThereȱareȱfourȱcommonȱ orderings.ȱ Aȱ preȬorderȱ traversalȱ processesȱ theȱ node,ȱ andȱ thenȱ traversesȱ itsȱ leftȱ andȱ rightȱsubtrees.ȱAnȱinȬorderȱtraversalȱtraversesȱtheȱleftȱsubtree,ȱprocessesȱtheȱnode,ȱandȱ thenȱ traversesȱ theȱ rightȱ subtree.ȱ Aȱ postȬorderȱ traversalȱ traversesȱ theȱ leftȱ andȱ rightȱ subtrees,ȱ andȱ thenȱ processesȱ theȱ node.ȱ Aȱ breadthȬfirstȱ traversalȱ processesȱ theȱ nodesȱ leftȱ toȱ rightȱ onȱeachȱlevelȱfromȱtheȱ rootȱdownȱtoȱ theȱleaves.ȱAnȱarrayȱcanȱbeȱ usedȱ toȱ implementȱ aȱ BST,ȱ butȱ willȱ wasteȱ aȱ lotȱ ofȱ memoryȱ ifȱ theȱ treeȱ isȱ unbalanced.ȱ Aȱ linkedȱ BSTȱavoidsȱthisȱwaste.ȱ Thereȱ areȱ threeȱ problemsȱ associatedȱ withȱ straightforwardȱ implementationsȱ ofȱ theseȱADTs.ȱFirst,ȱtheyȱonlyȱallowȱyouȱ10ȱhaveȱoneȱstack,ȱqueue,ȱorȱtree.ȱThisȱproblemȱ isȱ solvedȱ byȱ separatingȱ theȱ allocationȱ ofȱ theȱ structureȱ fromȱ theȱ functionsȱ thatȱ manipulateȱ it,ȱ howeverȱ theȱ resultingȱ lossȱ ofȱ encapsulationȱ increasesȱ theȱ chancesȱ ofȱ errors.ȱ Theȱ secondȱ problemȱ isȱ theȱ inabilityȱ toȱ declareȱ stacks,ȱ queues,ȱ orȱ treesȱ ofȱ differentȱ types.ȱ Creatingȱ aȱ separateȱ copyȱ ofȱ theȱ ADTȱ functionsȱ forȱ eachȱ typeȱ makesȱ maintainingȱtheȱcodeȱmoreȱdifficult.ȱAȱbetterȱapproachȱisȱtoȱimplementȱtheȱcodeȱwithȱaȱ #defineȱwhichȱisȱthenȱexpandedȱwithȱeachȱrequiredȱtype,ȱthoughȱyouȱmustȱchooseȱaȱ namingȱ conventionȱ carefully.ȱ Anotherȱ approachȱ isȱ toȱ makeȱ theȱ ADTȱ typelessȱ byȱ castingȱ theȱ valuesȱ toȱ beȱ storedȱ toȱ void *.ȱ ȱ Aȱ drawbackȱ ofȱ thisȱ strategyȱ isȱ theȱ lossȱ ofȱ typeȱchecking.ȱTheȱthirdȱproblemȱisȱavoidingȱnameȱclashesȱamongȱtheȱdifferentȱADTsȱ andȱamongȱtheȱversionsȱ ofȱ aȱsingleȱADTȱthatȱhandleȱ differentȱ typesȱ ofȱdata.ȱ Genericȱ implementationsȱ ofȱ theȱ ADTsȱ canȱ beȱ created,ȱ thoughȱ theyȱ requireȱ theȱ userȱ toȱ acceptȱ moreȱresponsibilityȱforȱtheirȱcorrectȱuse.ȱ ȱ ȱ ȱ 17.7 Summary of Cautions ȱ 1. Usingȱassertionsȱtoȱcheckȱforȱmemoryȱallocationsȱisȱdangerousȱ(pageȱ502).ȱ 2. Theȱcalculationsȱforȱanȱarrayedȱbinaryȱtreeȱassumeȱthatȱtheȱarrayȱsubscriptsȱbeginȱ atȱoneȱ(pageȱ518).ȱ 3. Encapsulatingȱ theȱ dataȱ inȱ theȱ moduleȱ thatȱ servicesȱ itȱ preventsȱ theȱ clientȱ fromȱ accessingȱtheȱdataȱincorrectlyȱ(pageȱ526).ȱ 4. Thereȱisȱnoȱtypeȱcheckingȱwithȱtypelessȱfunctions,ȱsoȱbeȱcarefulȱtoȱpassȱtheȱcorrectȱ typeȱofȱdataȱ(pageȱ527).ȱ ȱ Download at http://www.pin5i.com/ 17.9 Questionsȱ 533 ȱ 17.8 Summary of Programming Tips ȱ 1. Avoidingȱfunctionsȱwithȱsideȱeffectsȱmakesȱtheȱprogramȱeasierȱtoȱunderstandȱ(pageȱ 494).ȱ 2. Theȱinterfaceȱforȱaȱmoduleȱshouldȱnotȱdivulgeȱdetailsȱofȱtheȱimplementationȱ(pageȱ 494).ȱ 3. Parameterizingȱtheȱdataȱtypeȱmakesȱitȱeasierȱtoȱchangeȱ(pageȱ495).ȱ 4. Onlyȱtheȱadvertisedȱinterfaceȱforȱaȱmoduleȱshouldȱbeȱpublicȱ(pageȱ496).ȱ 5. Useȱassertionsȱtoȱguardȱagainstȱillegalȱoperationsȱ(pageȱ498).ȱ 6. Makingȱ differentȱ implementationsȱ adhereȱ toȱ aȱ commonȱ interfaceȱ makesȱ modulesȱ moreȱinterchangeableȱ(pageȱ499).ȱ 7. Reuseȱexistingȱcodeȱratherȱthanȱrewritingȱitȱ(pageȱ505).ȱ 8. Iterationȱisȱmoreȱefficientȱthanȱtailȱrecursionȱ(pageȱ513).ȱ ȱ ȱ ȱ 17.9 Questions ȱ 1. Supposeȱyouȱhaveȱaȱprogramȱthatȱreadsȱaȱseriesȱofȱnamesȱbutȱmustȱprintȱthemȱinȱ theȱoppositeȱorder.ȱWhatȱADTȱisȱmostȱappropriateȱforȱthisȱtask?ȱ 2. WhichȱADTȱwouldȱheȱmostȱappropriateȱforȱorganizingȱtheȱmilkȱonȱaȱsupermarketȱ shelf?ȱ Considerȱ whatȱ happensȱ bothȱ whenȱ customersȱ buyȱ milkȱ andȱ whenȱ theȱ supermarketȱgetsȱaȱnewȱshipmentȱofȱmilk.ȱ 3. Inȱ theȱ traditionalȱ interfaceȱ forȱ aȱ stack,ȱ theȱ popȱ functionȱ returnsȱ theȱ valueȱ thatȱ itȱ removedȱ fromȱ theȱ stack.ȱ Wouldȱ itȱ beȱ possibleȱ toȱ provideȱ bothȱ interfacesȱ inȱ oneȱ module?ȱ 4. Wouldȱtheȱstackȱmoduleȱbeȱsignificantlyȱmoreȱpowerfulȱifȱitȱhadȱanȱ emptyȱfunctionȱ thatȱremovedȱallȱvaluesȱfromȱtheȱstack?ȱ 5. Theȱ variableȱ top_elementȱ isȱ incrementedȱ beforeȱ storingȱ theȱ valueȱ inȱ pushȱ butȱ isȱ decrementedȱafterȱreturningȱtheȱvalueȱinȱpop.ȱWhatȱwouldȱhappenȱifȱtheȱorderȱofȱ theseȱoperationsȱwasȱreversed?ȱ 6. Whatȱwouldȱhappenȱ ifȱallȱofȱtheȱ assertionsȱ wereȱ removedȱ fromȱ theȱ stackȱ moduleȱ thatȱusesȱaȱstaticȱarray?ȱ 7. Inȱtheȱlinkedȱimplementationȱofȱaȱstack,ȱwhyȱdoesȱtheȱ destroy_stackȱfunctionȱpopȱ eachȱofȱtheȱvaluesȱonȱtheȱstackȱoneȱbyȱone?ȱ 8. Theȱpopȱfunctionȱinȱtheȱlinkedȱstackȱimplementationȱdeclaresȱaȱlocalȱvariableȱcalledȱ first_node.ȱȱCanȱthisȱvariableȱbeȱomitted?ȱ Download at http://www.pin5i.com/ 534ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ 9. Whenȱaȱcircularȱarrayȱisȱfull,ȱtheȱ frontȱandȱ rearȱvaluesȱhaveȱtheȱsameȱrelationshipȱ toȱoneȱanotherȱasȱtheyȱdoȱwhenȱtheȱarrayȱisȱempty.ȱHowever,ȱfullȱandȱemptyȱareȱ differentȱstates.ȱȱConceptually,ȱhowȱcanȱthisȱsituationȱhappen?ȱ 10. Whichȱsolutionȱisȱbetterȱforȱsolvingȱtheȱproblemȱofȱdetectingȱaȱfullȱcircularȱarray:ȱ (1)ȱalwaysȱleavingȱoneȱarrayȱelementȱunused,ȱorȱ(2)ȱaȱseparateȱvariableȱtoȱcountȱtheȱ numberȱofȱvaluesȱinȱtheȱarray?ȱ 11. Writeȱ theȱ statementsȱ thatȱ computeȱ theȱ numberȱ ofȱ valuesȱ onȱ aȱ queueȱ fromȱ theȱ valuesȱofȱfrontȱandȱrear.ȱ 12. Whichȱ isȱ betterȱ suitedȱ forȱ theȱ storageȱ ofȱ aȱ queue,ȱ aȱ singlyȱ linkedȱ listȱ orȱ aȱ doublyȱ linkedȱlist?ȱ 13. Drawȱtheȱtreeȱthatȱwouldȱresultȱfromȱinsertingȱtheȱfollowingȱvalues,ȱinȱthisȱorder,ȱ intoȱaȱbinaryȱsearchȱtree:ȱ20,ȱ15,ȱ18,ȱ32,ȱ5,ȱ91,ȱȬ4,ȱ76,ȱ33,ȱ41,ȱ34,ȱ21,ȱ90.ȱ 14. Insertingȱvaluesȱintoȱaȱbinaryȱsearchȱtreeȱinȱeitherȱascendingȱorȱdescendingȱorderȱ producesȱaȱtreeȱthatȱisȱunbalanced.ȱWhatȱisȱtheȱefficiencyȱofȱsearchingȱsuchȱaȱtreeȱ forȱaȱvalue?ȱ 15. InȱwhatȱorderȱwouldȱtheȱnodesȱofȱtheȱfollowingȱtreeȱbeȱprocessedȱusingȱaȱpreȬorderȱ traversal?ȱAnȱinȬorderȱtraversal?ȱAȱpostȬorderȱtraversal?ȱAȱbreadthȬfirstȱtraversal?ȱ 54 36 72ȱ 22ȱ 16ȱ 41 25ȱ 25 80 61ȱ 51 73 ȱ 16. Rewriteȱtheȱdo_pre_order_traversalȱfunctionȱtoȱperformȱanȱinȬorderȱtreeȱtraversalȱ 17. Rewriteȱtheȱdo_pre_order_traversalȱfunctionȱtoȱperformȱaȱpostȬorderȱtreeȱ traversal.ȱ 18. Whichȱ traversalȱ ofȱ aȱ binaryȱ searchȱ treeȱ willȱ visitȱ theȱ nodesȱ inȱ ascendingȱ orderȱ ofȱ theirȱvalues?ȱWhichȱwillȱvisitȱtheȱnodesȱinȱdescendingȱorder?ȱ 19. Theȱdestroy_treeȱfunctionȱdeletesȱaȱtreeȱbyȱfreeingȱallȱofȱtheȱmemoryȱallocatedȱforȱ ȱ Download at http://www.pin5i.com/ 17.10 Programming Exercisesȱ 535 ȱ theȱnodesȱinȱtheȱtree,ȱwhichȱmeansȱthatȱallȱofȱtheȱtreeȱnodesȱmustȱbeȱprocessedȱinȱaȱ particularȱorder.ȱWhatȱtypeȱofȱtraversalȱwouldȱbeȱmostȱappropriateȱforȱthisȱtask?ȱ ȱ ȱ ȱ 17.10 Programming Exercises ȱ 1. Addȱ aȱ resize_stackȱ functionȱ toȱ theȱ dynamicallyȱ allocatedȱ stackȱ module.ȱ Theȱ functionȱtakesȱoneȱargument:ȱtheȱnewȱsizeȱforȱtheȱstack.ȱ 2. Convertȱ theȱ queueȱ moduleȱ toȱ useȱ dynamicȱ arrayȱ allocationȱ andȱ addȱ aȱ resize_queueȱfunctionȱ(similarȱtoȱtheȱoneȱdescribedȱinȱProgrammingȱExerciseȱ1)ȱtoȱ it.ȱ 3. Convertȱtheȱqueueȱmoduleȱtoȱuseȱlinkedȱlistȱallocation.ȱ 4. Theȱ stack,ȱ queue,ȱ andȱ treeȱ modulesȱ wouldȱ beȱ moreȱ usefulȱ ifȱ theyȱ couldȱ handleȱ moreȱthanȱoneȱstack,ȱqueue,ȱorȱtree.ȱChangeȱtheȱdynamicallyȱarrayedȱstackȱmoduleȱ soȱ thatȱ itȱ canȱ manageȱ upȱ toȱ tenȱ separateȱ stacks.ȱ Youȱ willȱ haveȱ toȱ changeȱ theȱ interfacesȱ toȱ theȱ stackȱ functionsȱ toȱ acceptȱ anotherȱ argument—theȱ indexȱ ofȱ theȱ desiredȱstack.ȱ 5. Writeȱaȱfunctionȱtoȱcountȱtheȱnumberȱofȱnodesȱinȱaȱbinaryȱsearchȱtree.ȱYouȱmayȱuseȱ whicheverȱimplementationȱyouȱprefer.ȱ 6. Writeȱ aȱ functionȱ toȱ doȱ aȱ breadthȬfirstȱ traversalȱ ofȱ theȱ arrayedȱ binaryȱ searchȱ tree.ȱ Useȱtheȱfollowingȱalgorithm:ȱ ȱ Addȱtheȱrootȱnodeȱtoȱaȱqueue.ȱ Whileȱtheȱqueueȱisȱnotȱempty:ȱ Removeȱtheȱfirstȱnodeȱfromȱtheȱqueueȱandȱprocessȱit.ȱ Addȱallȱofȱtheȱnodeȇsȱchildrenȱtoȱtheȱqueue.ȱ 7. Writeȱaȱfunctionȱtoȱcheckȱwhetherȱaȱbinaryȱtreeȱisȱinȱfactȱaȱbinaryȱsearchȱtree.ȱYouȱ mayȱuseȱwhicheverȱimplementationȱyouȱprefer.ȱ 8. Writeȱaȱfunctionȱforȱtheȱarrayedȱtreeȱmoduleȱthatȱdeletesȱaȱvalueȱfromȱtheȱtree.ȱIfȱ theȱ valueȱ toȱ beȱ deletedȱ isȱ notȱ foundȱ inȱ theȱ tree,ȱ theȱ functionȱ mayȱ abortȱ theȱ program.ȱ 9. Writeȱaȱ destroy_treeȱfunctionȱforȱtheȱlinkedȱimplementationȱofȱtheȱbinaryȱsearchȱ tree.ȱTheȱfunctionȱshouldȱfreeȱallȱofȱtheȱmemoryȱusedȱinȱtheȱtree.ȱ 10. Writeȱaȱfunctionȱforȱtheȱlinkedȱtreeȱmoduleȱthatȱdeletesȱaȱvalueȱfromȱtheȱtree.ȱIfȱtheȱ valueȱtoȱbeȱdeletedȱisȱnotȱfoundȱinȱtheȱtree,ȱtheȱfunctionȱmayȱabortȱtheȱprogram.ȱ Download at http://www.pin5i.com/ 536ȱ ȱ Chapter 17 Classic Abstract Data Typesȱ 11. Rewriteȱtheȱ#defineȱinȱProgramȱ17.10aȱasȱthreeȱseparateȱ#defines.ȱ a. oneȱtoȱdeclareȱtheȱstackȱinterfaceȱ b. oneȱtoȱcreateȱtheȱimplementationȱ c. oneȱtoȱcreateȱtheȱdataȱforȱaȱstackȱ Youȱ mustȱ changeȱ theȱ interfaceȱ forȱ theȱ stackȱ toȱ passȱ theȱ stackȱ dataȱ asȱ anȱ explicitȱ argument.ȱ(Itȱwillȱbeȱmoreȱconvenientȱtoȱpackageȱtheȱstackȱdataȱintoȱaȱstructure.)ȱ Theseȱmodificationsȱwillȱletȱaȱsingleȱsetȱofȱstackȱfunctionsȱmanipulateȱanyȱstackȱofȱ theȱcorrespondingȱtype.ȱ Download at http://www.pin5i.com/ 18 Runtime Environment Inȱthisȱchapter,ȱweȱwillȱexamineȱtheȱassemblyȱlanguageȱcodeȱproducedȱbyȱoneȱspecificȱ compilerȱ forȱ oneȱ specificȱ computerȱ inȱ orderȱ toȱ learnȱ severalȱ interestingȱ thingsȱ aboutȱ theȱ runtimeȱ environmentȱ forȱ thisȱ implementation.ȱ Amongȱ theȱ questionsȱ thatȱ willȱ beȱ answeredȱare,ȱȈWhatȱareȱtheȱlimitsȱofȱmyȱruntimeȱenvironment?ȈȱandȱȈHowȱdoȱIȱgetȱCȱ andȱassemblyȱlanguageȱprogramsȱtoȱworkȱtogether?Ȉȱ ȱ ȱ ȱ 18.1 Determining the Runtime Environment ȱ Yourȱcompilerȱorȱenvironmentȱisȱsureȱtoȱbeȱdifferentȱthanȱtheȱoneȱweȱlookȱatȱhere,ȱsoȱ youȱ willȱ needȱ toȱ performȱ experimentsȱ likeȱ theseȱ yourselfȱ inȱ orderȱ toȱ findȱ outȱ howȱ thingsȱworkȱonȱyourȱmachine.ȱ Theȱfirstȱstepȱisȱobtainingȱanȱassemblyȱlanguageȱlistingȱfromȱyourȱcompiler.ȱOnȱ UNIXȱ systems,ȱ theȱ -sȱ compilerȱ optionȱ causesȱ theȱ compilerȱ toȱ writeȱ theȱ assemblyȱ languageȱ forȱ eachȱ sourceȱ fileȱ inȱ aȱ fileȱ whoseȱ nameȱ hasȱ theȱ .sȱ suffix.ȱ Theȱ Borlandȱ compilersȱ alsoȱ supportȱ thisȱ option,ȱ thoughȱ theyȱ useȱ theȱ .asmȱ suffix.ȱ Consultȱ theȱ documentationȱforȱspecificȱdetailsȱofȱotherȱsystems.ȱ Youȱwillȱalsoȱneedȱtoȱreadȱtheȱassemblyȱlanguageȱcodeȱforȱyourȱmachine.ȱItȱisȱ notȱ necessaryȱ toȱ beȱ aȱ skillfulȱ assemblyȱ languageȱ programmer,ȱ butȱ youȱ willȱ needȱ aȱ basicȱunderstandingȱofȱwhatȱeachȱinstructionȱisȱdoingȱandȱhowȱtoȱinterpretȱaddressingȱ modes.ȱAȱmanualȱdescribingȱyourȱcomputerȇsȱinstructionȱsetȱisȱanȱexcellentȱreferenceȱ forȱthisȱtask.ȱ Assemblyȱlanguageȱisȱnotȱtaughtȱinȱthisȱchapterȱbecauseȱthatȱisȱnotȱtheȱpointȱofȱ thisȱ book.ȱ Yourȱ assemblyȱ languageȱ isȱ likelyȱ toȱ differȱ fromȱ thisȱ oneȱ anyway.ȱ Nevertheless,ȱ ifȱ youȱ compileȱ theȱ testȱ program,ȱ theȱ explanationsȱ ofȱ myȱ machineȇsȱ assemblyȱ languageȱ mayȱ helpȱ youȱ decipherȱ yours,ȱ becauseȱ bothȱ assemblyȱ programsȱ implementȱtheȱsameȱsourceȱcode.ȱ Download at http://www.pin5i.com/ 538ȱ ȱ Chapter 18 Runtime Environmentȱ ȱ /* ** Program to determine the C runtime environment. */ /* ** Static initialization */ int static_variable = 5; void f() { register int register char extern double int double char /* ** */ i1 i6 c1 c3 c5 c7 c9 i1, i2, i3, i4, i5, i6, i7, i8, i9, i10; *c1, *c2, *c3, *c4, *c5, *c6, *c7, *c8, *c9, *c10; a_very_long_name_to_see_how_long_they_can_be; int dbl; func_ret_int(); func_ret_double(); *func_ret_char_ptr(); Maximum number of register variables. = = = = = = = 1; i2 6; i7 (char (char (char (char (char = 2; i3 = 3; i4 = 4; i5 = 5; = 7; i8 = 8; i9 = 9; i10 = 10; *)110; c2 = (char *)120; *)130; c4 = (char *)140; *)150; c6 = (char *)160; *)170; c8 = (char *)180; *)190; c10 = (char *)200; /* ** External names */ a_very_long_name_to_see_how_long_they_can_be = 1; /* ** Function calling/returning protocol, stack frame */ i2 = func_ret_int( 10, i1, i10 ); dbl = func_ret_double(); c1 = func_ret_char_ptr( c1 ); } ȱ Programȱ18.1ȱȱTestȱprogramȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ continued...ȱ Download at http://www.pin5i.com/ 18.1 Determining the Runtime Environmentȱ 539 ȱ ȱ int func_ret_int( int a, int b, register int c ) { int d; d = b - 6; return a + b + c; } double func_ret_double() { return 3.14; } char * func_ret_char_ptr( char *cp ) { return cp + 1; } ȱ Programȱ18.1ȱȱTestȱprogramȱ ȱ ȱ ȱ ȱ ȱ ȱ 18.1.1 ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱruntime.cȱ Test Program ȱ Soȱ letȇsȱ lookȱ atȱ Programȱ 18.1,ȱ theȱ testȱ program.ȱ Itȱ containsȱ variousȱ piecesȱ ofȱ codeȱ whoseȱ implementationsȱ areȱ ofȱ interest.ȱ Theȱ programȱ doesnȇtȱ accomplishȱ anythingȱ useful,ȱbutȱitȱdoesnȇtȱhaveȱto—allȱthatȱweȱwantȱtoȱdoȱisȱtoȱlookȱatȱtheȱassemblyȱcodeȱ theȱ compilerȱ producesȱ forȱ it.ȱ Ifȱ thereȱ areȱ otherȱ aspectsȱ ofȱ yourȱ runtimeȱ environmentȱ youȱwishȱtoȱinvestigate,ȱmodifyȱtheȱprogramȱtoȱincludeȱexamplesȱofȱthem.ȱ Theȱ assemblyȱ codeȱ inȱ Programȱ 18.2ȱ wasȱ producedȱ forȱ aȱ computerȱ usingȱ aȱ microprocessorȱ fromȱ theȱ Motorolaȱ 68000ȱ family.ȱ Iȱ haveȱ editedȱ thisȱ codeȱ toȱ makeȱ itȱ moreȱclearȱandȱtoȱremoveȱirrelevantȱdeclarations.ȱ Thisȱisȱaȱlongȱprogram.ȱLikeȱmostȱcompilerȱoutput,ȱitȱcontainsȱnoȱcommentsȱtoȱ helpȱtheȱreader.ȱButȱdonȇtȱletȱitȱintimidateȱyou!ȱIȇllȱexplainȱmostȱofȱitȱlineȱbyȱlineȱinȱaȱ seriesȱ ofȱ examplesȱ thatȱ showȱ aȱ fragmentȱ ofȱ Cȱ codeȱ followedȱ byȱ theȱ assemblyȱ codeȱ producedȱfromȱit.ȱTheȱcompleteȱlistingȱisȱgivenȱonlyȱasȱaȱreferenceȱsoȱyouȱcanȱseeȱhowȱ allȱofȱtheȱlittleȱpiecesȱinȱtheȱexamplesȱfitȱtogether.ȱ Download at http://www.pin5i.com/ 540ȱ ȱ Chapter 18 Runtime Environmentȱ ȱ .data .even .globl _static_variable _static_variable: .long 5 .text _f: .globl link moveml moveq moveq moveq moveq moveq moveq movl movl movl movl movl movl movl movl movl movl movl movl movl movl movl movl movl pea jbsr lea movl jbsr movl movl pea jbsr addqw movl moveml unlk rts _f a6,#-88 #0x3cfc,sp@ #1,d7 #2,d6 #3,d5 #4,d4 #5,d3 #6,d2 #7,a6@(-4) #8,a6@(-8) #9,a6@(-12) #10,a6@(-16) #110,a5 #120,a4 #130,a3 #140,a2 #150,a6@(-20) #160,a6@(-24) #170,a6@(-28) #180,a6@(-32) #190,a6@(-36) #200,a6@(-40) #1,_a_very_long_name_to_see_how_long_they_can_be a6@(-16),sp@d7,sp@10 _func_ret_int sp@(12),sp d0,d6 _func_ret_double d0,a6@(-48) d1,a6@(-44) a5@ _func_ret_char_ptr #4,sp d0,a5 a6@(-88),#0x3cfc a6 ȱ Programȱ18.2ȱȱAssemblyȱlanguageȱcodeȱforȱtestȱprogramȱ ȱ ȱ ȱ continued...ȱ Download at http://www.pin5i.com/ 18.1 Determining the Runtime Environmentȱ 541 ȱ ȱ .globl _func_ret_int: link moveml movl movl subql movl movl addl addl moveml unlk rts _func_ret_int .globl _func_ret_double: link moveml movl movl unlk rts L2000000: _func_ret_double a6,#-8 #0x80,sp@ a6@(16),d7 a6@(12),d0 #6,d0 d0,a6@(-4) a6@(8),d0 a6@(12),d0 d7,d0 a6@(-8),#0x80 a6 a6,#0 #0,sp@ L2000000,d0 L2000000+4,d1 a6 .long 0x40091eb8,0x51eb851f .globl _func_ret_char_ptr _func_ret_char_ptr: link a6,#0 moveml #0,sp@ movl a6@(8),d0 addql #1,d0 unlk a6 rts ȱ Programȱ18.2ȱȱAssemblyȱlanguageȱcodeȱforȱtestȱprogramȱ ȱ ȱ ȱ ȱ ȱ ȱ 18.1.2 ȱ ȱ ȱ ȱȱȱȱruntime.sȱ Static Variables and Initialization ȱ Theȱ firstȱ thingȱ theȱ testȱ programȱ didȱ wasȱ toȱ declareȱ andȱ initializeȱ aȱ variableȱ inȱ staticȱ memory.ȱ Download at http://www.pin5i.com/ Chapter 18 Runtime Environmentȱ 542ȱ ȱ ȱ /* ** Static initialization */ int static_variable = 5; .data .even .globl _static_variable _static_variable: .long 5 ȱ Theȱassemblyȱcodeȱbeginsȱwithȱdirectivesȱtoȱenterȱtheȱdataȱsectionȱofȱtheȱprogramȱandȱ makeȱ sureȱ thatȱ theȱ variableȱ beginsȱ atȱ anȱ evenȱ address.ȱ Theȱ boundaryȱ alignmentȱ isȱ aȱ requirementȱ ofȱ theȱ 68000.ȱ Thenȱ theȱ variableȱ nameȱ isȱ declaredȱ global.ȱ Noticeȱ thatȱ theȱ nameȱ beginsȱ withȱ anȱ underscore.ȱ Manyȱ (butȱ notȱ all)ȱ Cȱ implementationsȱ addȱ anȱ underscoreȱtoȱtheȱbeginningȱofȱexternalȱnamesȱdeclaredȱinȱtheȱCȱcodeȱtoȱpreventȱtheseȱ namesȱfromȱconflictingȱwithȱnamesȱusedȱinȱvariousȱlibraryȱroutines.ȱFinally,ȱspaceȱisȱ createdȱforȱtheȱvariable,ȱandȱitȱisȱinitializedȱwithȱtheȱproperȱvalue.ȱ ȱ ȱ ȱ 18.1.3 The Stack Frame ȱ Theȱfunctionȱ fȱbeginsȱnext.ȱThereȱareȱthreeȱpartsȱtoȱaȱfunction:ȱtheȱprologue,ȱtheȱbody,ȱ andȱ theȱ epilogue.ȱ Theȱ prologueȱ ofȱ aȱ functionȱ doesȱ theȱ workȱ neededȱ toȱ startȱ upȱ aȱ function,ȱsuchȱasȱreservingȱmemoryȱonȱtheȱstackȱforȱlocalȱvariables.ȱTheȱepilogueȱtakesȱ careȱofȱcleaningȱupȱtheȱstackȱjustȱbeforeȱtheȱfunctionȱreturns.ȱTheȱbodyȱofȱtheȱfunction,ȱ ofȱcourse,ȱisȱwhereȱtheȱusefulȱworkȱisȱperformed.ȱ ȱ void f() { register int register char extern double int double char i1, i2, i3, i4, i5, i6, i7, i8, i9, i10; *c1, *c2, *c3, *c4, *c5, *c6, *c7, *c8, *c9, *c10; a_very_long_name_to_see_how_long_they_can_be; int dbl; func_ret_int(); func_ret_double(); *func_ret_char_ptr(); .text _f: .globl link moveml _f a6,#-88 #0x3cfc,sp@ Download at http://www.pin5i.com/ 18.1 Determining the Runtime Environmentȱ 543 ȱ Theseȱinstructionsȱbeginȱwithȱaȱdirectiveȱtoȱenterȱtheȱcodeȱ(text)ȱsegmentȱofȱtheȱ program,ȱfollowedȱbyȱaȱglobalȱdeclarationȱforȱtheȱfunctionȱname.ȱNoteȱonceȱagainȱtheȱ underscoreȱaddedȱtoȱ theȱ frontȱ ofȱtheȱname.ȱ Theȱfirstȱexecutableȱinstructionȱ beginsȱ toȱ constructȱtheȱstackȱframeȱforȱthisȱfunction.ȱTheȱstackȱframeȱisȱtheȱareaȱonȱtheȱstackȱthatȱ theȱ functionȱ willȱ useȱ forȱ storageȱ ofȱ variablesȱ andȱ otherȱ values.ȱ Theȱ linkȱ instructionȱ willȱbeȱexplainedȱinȱdetailȱlater;ȱallȱthatȱisȱimportantȱnowȱisȱthatȱitȱreservesȱ88ȱbytesȱofȱ spaceȱonȱtheȱstackȱforȱstorageȱofȱlocalȱvariablesȱandȱotherȱvalues.ȱ Theȱ lastȱ instructionȱ inȱ thisȱ sequenceȱ writesȱ copiesȱ ofȱ theȱ valuesȱ inȱ selectedȱ registersȱ toȱ theȱ stack.ȱ Theȱ 68000ȱ hasȱ eightȱ registersȱ forȱ manipulatingȱ data,ȱ calledȱ d0ȱ throughȱd7,ȱandȱeightȱmoreȱregistersȱforȱmanipulatingȱaddresses,ȱcalledȱa0ȱthroughȱa7.ȱȱ Theȱ valueȱ 0x3cfcȱ indicatesȱ thatȱ registersȱ d2ȱ throughȱ d7ȱ andȱ a2ȱ throughȱ a5ȱ areȱ toȱ beȱ stored;ȱtheseȱareȱtheȱȈotherȱvaluesȈȱmentionedȱearlier.ȱȱItȱwillȱbecomeȱclearȱshortlyȱwhyȱ theseȱparticularȱregistersȱwereȱsaved.ȱ Theȱ localȱ variableȱ declarationsȱ andȱ functionȱ prototypesȱ donȇtȱ produceȱ anyȱ assemblyȱcode.ȱHadȱanyȱlocalȱvariablesȱbeenȱinitializedȱinȱitsȱdeclaration,ȱinstructionsȱ wouldȱappearȱhereȱtoȱperformȱtheȱassignment.ȱ ȱ ȱ ȱ 18.1.4 Register Variables ȱ Theȱbodyȱofȱtheȱfunctionȱcomesȱnext.ȱTheȱpurposeȱofȱthisȱpartȱofȱtheȱtestȱprogramȱisȱtoȱ determineȱ howȱ manyȱ variablesȱ canȱ beȱ storedȱ inȱ registers.ȱ Itȱ declaresȱ aȱ lotȱ ofȱ registerȱ variablesȱ andȱ initializesȱ eachȱ ofȱ themȱ withȱ aȱ differentȱ value.ȱ Theȱ assemblyȱ codeȱ answersȱtheȱquestionȱbyȱshowingȱwhereȱeachȱvalueȱwasȱstored.ȱ ȱ /* ** */ i1 i6 c1 c3 c5 c7 c9 Maximum number of register variables. = = = = = = = 1; i2 6; i7 (char (char (char (char (char moveq moveq moveq moveq = 2; i3 = 3; i4 = 4; i5 = 5; = 7; i8 = 8; i9 = 9; i10 = 10; *)110; c2 = (char *)120; *)130; c4 = (char *)140; *)150; c6 = (char *)160; *)170; c8 = (char *)180; *)190; c10 = (char *)200; #1,d7 #2,d6 #3,d5 #4,d4 Download at http://www.pin5i.com/ Chapter 18 Runtime Environmentȱ 544ȱ ȱ moveq moveq movl movl movl movl movl movl movl movl movl movl movl movl movl movl #5,d3 #6,d2 #7,a6@(-4) #8,a6@(-8) #9,a6@(-12) #10,a6@(-16) #110,a5 #120,a4 #130,a3 #140,a2 #150,a6@(-20) #160,a6@(-24) #170,a6@(-28) #180,a6@(-32) #190,a6@(-36) #200,a6@(-40) ȱ Theȱintegerȱvariablesȱareȱinitializedȱfirst.ȱNoticeȱthatȱtheȱvaluesȱ1ȱthroughȱ6ȱareȱ putȱinȱdamȱregisters,ȱbutȱ7ȱthroughȱ10ȱareȱputȱsomewhereȱelse.ȱThisȱcodeȱshowsȱthatȱ upȱtoȱ6ȱintegerȱvaluesȱmayȱbeȱkeptȱinȱtheȱdataȱregisters.ȱWhatȱaboutȱdataȱtypesȱotherȱ thanȱinteger?ȱSomeȱimplementationsȱwillȱnotȱputȱ charȱvariablesȱinȱregisters.ȱOnȱsomeȱ machinesȱ doublesȱ areȱ tooȱ longȱ toȱ fitȱ inȱ aȱ register,ȱ andȱ otherȱ machinesȱ haveȱ specialȱ registersȱthatȱareȱusedȱforȱfloatingȬpointȱvalues.ȱItȱisȱeasyȱtoȱmodifyȱtheȱtestȱprogramȱtoȱ discoverȱtheseȱdetails.ȱ Theȱ nextȱ severalȱ instructionsȱ initializeȱ theȱ pointerȱ variables.ȱ Theȱ firstȱ 4ȱ valuesȱ goȱ toȱ registers,ȱ andȱ theȱ remainingȱ onesȱ areȱ putȱ somewhereȱ else.ȱ Thus,ȱ thisȱ compilerȱ allowsȱupȱtoȱ4ȱpointerȱvariablesȱtoȱbeȱinȱregisters.ȱWhatȱaboutȱotherȱtypesȱofȱpointers?ȱȱ Again,ȱ furtherȱ experimentationȱ isȱ needed.ȱ Onȱ manyȱ machines,ȱ though,ȱ theȱ sizeȱ ofȱ aȱ pointerȱisȱtheȱsameȱnoȱmatterȱwhatȱitȱisȱpointingȱat,ȱsoȱyouȱmayȱfindȱthatȱanyȱtypeȱofȱ pointerȱcanȱbeȱstoredȱinȱaȱregister.ȱ Whereȱ areȱ theȱ otherȱ variablesȱ put?ȱ Theȱ addressingȱ modeȱ usedȱ performsȱ indirectionȱandȱindexing.ȱThisȱcombinationȱworksȱmuchȱlikeȱaȱsubscriptȱonȱanȱarray.ȱȱ Registerȱ a6ȱ isȱ calledȱ theȱ frameȱ pointerȱ andȱ pointsȱ toȱ aȱ ȈreferenceȈȱ locationȱ withinȱ theȱ stackȱ frame.ȱ Allȱ valuesȱ inȱ theȱ stackȱ frameȱ areȱ accessedȱ byȱ meansȱ ofȱ offsetsȱ fromȱ thisȱ referenceȱlocation;ȱa6@(-28)ȱspecifiesȱanȱoffsetȱofȱȬ28.ȱNoticeȱthatȱtheȱoffsetsȱbeginȱwithȱ Ȭ4ȱandȱgrowȱbyȱfourȱeachȱtime.ȱIntegersȱandȱpointersȱonȱthisȱmachineȱoccupyȱ4ȱbytesȱ ofȱmemoryȱeach.ȱWithȱtheseȱoffsets,ȱyouȱcanȱmakeȱaȱmapȱshowingȱexactlyȱwhereȱeachȱ variableȱappearsȱonȱtheȱstackȱrelativeȱtoȱtheȱframeȱpointer,ȱa6.ȱ Havingȱ seenȱ thatȱ registersȱ d2-d7ȱ andȱ a2-a5ȱ areȱ beingȱ usedȱ toȱ holdȱ registerȱ variables,ȱ itȱ nowȱ becomesȱ clearȱ whyȱ thoseȱ registersȱ wereȱ savedȱ inȱ theȱ functionȱ prologue.ȱ ȱ Aȱ functionȱ mustȱ saveȱ theȱ valuesȱ inȱ anyȱ registerȱ thatȱ itȱ intendsȱ toȱ useȱ forȱ registerȱvariablesȱsoȱthatȱtheȱoriginalȱvaluesȱcanȱbeȱrestoredȱbeforeȱreturningȱtoȱtheȱ Download at http://www.pin5i.com/ 18.1 Determining the Runtime Environmentȱ 545 ȱ ȱcallingȱfunction,ȱthusȱpreservingȱitsȱregisterȱvariables.ȱ Oneȱ lastȱ thingȱ aboutȱ registerȱ variables:ȱ Whyȱ wereȱ registersȱ d0-d1,ȱ a0-a1,ȱ andȱ a6-a7ȱnotȱusedȱforȱregisterȱvariables?ȱOnȱthisȱmachine,ȱ a6ȱisȱusedȱasȱtheȱframeȱpointerȱ andȱ a7ȱ isȱ theȱ stackȱ pointer.ȱ (Thisȱ assemblyȱ languageȱ givesȱ itȱ theȱ aliasȱ sp.)ȱ Aȱ laterȱ exampleȱwillȱshowȱthatȱ d0ȱandȱ d1ȱareȱusedȱinȱreturningȱvaluesȱfromȱfunctions,ȱsoȱtheyȱ canȇtȱbeȱusedȱforȱregisterȱvariables.ȱ Butȱthereȱisȱnoȱapparentȱuseȱofȱ a0ȱorȱ a1ȱinȱthisȱcode.ȱTheȱobviousȱconclusionȱisȱ thatȱ theyȱ haveȱ someȱ purpose,ȱ butȱ theȱ testȱ programȱ didȱ notȱ containȱ anyȱ codeȱ ofȱ thatȱ type.ȱFurtherȱexperimentationȱisȱneededȱtoȱanswerȱthisȱquestion.ȱ ȱ ȱ ȱ 18.1.5 Length of External Identifiers ȱ Theȱnextȱtestȱtriesȱtoȱdetermineȱtheȱmaximumȱallowableȱlengthȱofȱexternalȱidentifiers.ȱ Thisȱ testȱ seemsȱ easyȱ enough:ȱ declareȱ andȱ useȱ aȱ variableȱ withȱ aȱ longȱ nameȱ andȱ seeȱ whatȱhappens.ȱ ȱ /* ** External names */ a_very_long_name_to_see_how_long_they_can_be = 1; movl CAUTION! #1,_a_very_long_name_to_see_how_long_they_can_be ȱ Itȱappearsȱfromȱthisȱcodeȱthatȱthereȱisnȇtȱaȱlimitȱonȱtheȱlengthȱofȱnames.ȱMoreȱprecisely,ȱ thisȱ nameȱisȱwithinȱwhateverȱlimitȱ thereȱ is.ȱToȱ findȱ theȱlimit,ȱ keepȱ makingȱ theȱ nameȱ longerȱandȱlongerȱuntilȱitȱisȱtruncatedȱinȱtheȱassemblyȱprogram.ȱ ȱ Inȱfact,ȱthisȱtestȱisȱnotȱadequate.ȱ Theȱfinalȱ limitȱ onȱ externalȱnamesȱ isȱimposedȱbyȱ theȱ linker,ȱ whichȱ mayȱ happilyȱ readȱ longȱ namesȱ butȱ ignoreȱ allȱ butȱ theȱ firstȱ severalȱ characters.ȱTheȱStandardȱrequiresȱexternalȱnamesȱtoȱbeȱsignificantȱinȱatȱleastȱtheirȱfirstȱ sixȱcharactersȱ(thoughȱdifferencesȱinȱtheȱcaseȱofȱlettersȱmightȱbeȱlost).ȱToȱtestȱwhatȱtheȱ linkerȱdoes,ȱsimplyȱlinkȱtheȱprogramȱandȱexamineȱtheȱresultingȱloadȱmapȱorȱnameȱlist.ȱ ȱ ȱ ȱ 18.1.6 Determining the Stack Frame Layout ȱ Theȱruntimeȱstackȱholdsȱdataȱneededȱforȱeachȱfunctionȱtoȱrun,ȱincludingȱitsȱautomaticȱ variablesȱandȱreturnȱaddresses.ȱTheȱnextȱfewȱtestsȱwillȱdetermineȱtwoȱrelatedȱthings:ȱȱ Download at http://www.pin5i.com/ 546ȱ ȱ Chapter 18 Runtime Environmentȱ theȱ organizationȱ ofȱ theȱ stackȱ frameȱ andȱ theȱ protocolȱ forȱ callingȱ andȱ returningȱ fromȱ functions.ȱȱTheȱresultsȱshowȱhowȱtoȱinterfaceȱCȱandȱassemblyȱlanguageȱprograms.ȱ ȱ ȱ ȱ Passing Function Arguments ȱ Thisȱexampleȱbeginsȱtheȱcallȱtoȱaȱfunction.ȱ ȱ /* ** Function calling/returning protocol, stack frame */ i2 = func_ret_int( 10, i1, i10 ); movl movl pea jbsr a6@(-16),sp@d7,sp@10 _func_ret_int ȱ Theȱfirstȱthreeȱinstructionsȱpushȱtheȱargumentsȱtoȱtheȱfunctionȱonȱtheȱstack.ȱTheȱfirstȱ argumentȱ thatȱ isȱ pushedȱ isȱ theȱ oneȱ storedȱ atȱ a6@(-16):ȱ theȱ offsetsȱ examinedȱ earlierȱ showȱthatȱthisȱvalueȱisȱtheȱvariableȱ i10.ȱ d7ȱisȱpushedȱnext;ȱitȱcontainsȱtheȱvariableȱ i1.ȱ Theȱ lastȱ argumentȱ isȱ pushedȱ differentlyȱ thanȱ theȱ others.ȱ Theȱ peaȱ instructionȱ simplyȱ pushesȱ itsȱ operandȱ onȱ theȱ stack,ȱ whichȱ isȱ anȱ efficientȱ wayȱ toȱ pushȱ aȱ literalȱ constant.ȱȱ Whyȱ areȱ theȱ argumentsȱ beingȱ pushedȱ onȱ theȱ stackȱ inȱ theȱ oppositeȱ orderȱ fromȱ howȱ theyȱappearedȱinȱtheȱargumentȱlist?ȱTheȱanswerȱwillȱbecomeȱclearȱshortly.ȱ Theseȱinstructionsȱbeginȱtoȱcreateȱtheȱstackȱframeȱbelongingȱtoȱtheȱfunctionȱthatȱ isȱaboutȱtoȱbeȱcalled.ȱByȱtracingȱtheȱinstructionsȱandȱkeepingȱtrackȱofȱtheirȱeffects,ȱweȱ canȱconstructȱaȱcompleteȱpictureȱofȱtheȱstackȱframe.ȱThisȱpictureȱprovidesȱinformationȱȱ ȱ ȱ ȱ Lowerȱ Memoryȱ Addressesȱ Argumentȱ#1 CurrentȱSPȱ Argumentȱ#2 Argumentȱ#3 Higherȱ Memoryȱ Addressesȱ ? OriginalȱSPȱValueȱ ȱ Figureȱ18.1ȱȱStackȱframeȱafterȱpushingȱtheȱargumentsȱ ȱ Download at http://www.pin5i.com/ 18.1 Determining the Runtime Environmentȱ 547 ȱ thatȱ isȱ helpfulȱ ifȱ youȱ needȱ toȱ traceȱ theȱ executionȱ ofȱ aȱ Cȱ programȱ atȱ theȱ assemblyȱ languageȱ level.ȱ Figureȱ 18.1ȱ showsȱ whatȱ hasȱ beenȱ builtȱ soȱ far.ȱ Theȱ diagramȱ showsȱ lowerȱmemoryȱaddressesȱatȱtheȱtopȱandȱhigherȱmemoryȱaddressesȱatȱtheȱbottom.ȱTheȱ stackȱ growsȱ towardȱ lowerȱ memoryȱ addressesȱ (upward)ȱ asȱ valuesȱ areȱ pushedȱ onȱ it.ȱȱ Theȱstackȱcontentsȱbelowȱtheȱoriginalȱstackȱpointerȱareȱunknown,ȱsoȱitȱisȱshownȱasȱaȱ questionȱmark.ȱ TheȱnextȱinstructionȱisȱaȱȈjumpȱsubroutine:Ȉȱitȱpushesȱtheȱreturnȱaddressȱonȱtheȱ stackȱandȱbranchesȱtoȱtheȱbeginningȱofȱ _func_ret_int.ȱTheȱreturnȱaddressȱisȱusedȱbyȱ theȱcalledȱfunctionȱwhenȱitȱisȱfinishedȱtoȱgoȱbackȱtoȱwhereȱitȱwasȱcalled.ȱTheȱstackȱnowȱ looksȱlikeȱFigureȱ18.2.ȱ ȱ ȱ ȱ Function Prologue ȱ Executionȱcontinuesȱwithȱtheȱprologueȱofȱtheȱcalledȱfunction:ȱ ȱ int func_ret_int( int a, int b, register int c ) { int d; .globl _func_ret_int: link moveml movl _func_ret_int a6,#-8 #0x80,sp@ a6@(16),d7 ȱ ȱ ȱ ȱ ReturnȱAddrȱ CurrentȱSP Argumentȱ#1ȱ Argumentȱ#2ȱ Argumentȱ#3ȱ ?ȱ OriginalȱSPȱValue ȱ ȱ Figureȱ18.2ȱȱStackȱframeȱafterȱtheȱjumpȱsubroutineȱinstructionȱ Download at http://www.pin5i.com/ 548ȱ ȱ Chapter 18 Runtime Environmentȱ Theȱprologueȱisȱsimilarȱtoȱtheȱoneȱexaminedȱearlier;ȱtheȱinstructionsȱmustȱbeȱexaminedȱ inȱmoreȱdetailȱtoȱcompleteȱtheȱmapȱofȱtheȱstackȱframe.ȱTheȱlinkȱinstructionȱhasȱseveralȱ steps.ȱFirst,ȱtheȱcontentsȱofȱa6ȱareȱpushedȱonȱtheȱstack.ȱSecond,ȱtheȱcurrentȱvalueȱinȱtheȱ stackȱpointerȱisȱcopiedȱintoȱa6.ȱFigureȱ18.3ȱillustratesȱthisȱresult.ȱ Finally,ȱ theȱ linkȱ instructionȱ subtractsȱ 8ȱ fromȱ theȱ stackȱ pointer.ȱ Asȱ before,ȱ thisȱ createsȱtheȱspaceȱthatȱwillȱholdȱtheȱlocalȱvariablesȱandȱsavedȱregisterȱvalues.ȱTheȱnextȱ instructionȱ savesȱ aȱ singleȱ registerȱ intoȱ theȱ stackȱ frame;ȱ theȱ operandȱ 0x80ȱ designatesȱ registerȱ d7.ȱTheȱregisterȱisȱstoredȱatȱ theȱtopȱofȱ theȱstack,ȱ whichȱ indicatesȱthatȱ theȱ topȱ portionȱofȱtheȱstackȱframeȱisȱwhereȱregisterȱvaluesȱareȱsaved;ȱtheȱremainingȱpartȱofȱtheȱ stackȱframeȱmustȱbeȱwhereȱlocalȱvariablesȱareȱstored.ȱFigureȱ18.4ȱshowsȱwhatȱweȱknowȱ soȱfarȱaboutȱtheȱstackȱframe.ȱ Theȱ lastȱ taskȱ theȱ prologueȱ performsȱ isȱ toȱ copyȱ aȱ valueȱ fromȱ theȱ stackȱ intoȱ d7.ȱ Theȱ functionȱ declaresȱ theȱ thirdȱ argumentȱ toȱ beȱ aȱ registerȱ variable,ȱ andȱ theȱ thirdȱ argumentȱ isȱ 16ȱ bytesȱ downȱ fromȱ theȱ frameȱ pointer.ȱ Onȱ thisȱ machine,ȱ registerȱ argumentsȱareȱpassedȱonȱtheȱstackȱnormallyȱandȱcopiedȱintoȱaȱregisterȱinȱtheȱfunctionȱ prologue.ȱThisȱadditionalȱinstructionȱisȱoverhead—ifȱthereȱarenȇtȱenoughȱinstructionsȱ inȱtheȱfunctionȱthatȱuseȱtheȱargument,ȱthereȱwonȇtȱbeȱenoughȱsavingsȱinȱspeedȱorȱspaceȱ toȱoffsetȱtheȱoverheadȱofȱcopyingȱtheȱargumentȱintoȱaȱregister.ȱ ȱ ȱ ȱ ȱ Oldȱa6ȱValueȱ CurrentȱSPȱandȱa6 ReturnȱAddrȱ Argumentȱ#1ȱ Argumentȱ#2ȱ Argumentȱ#3ȱ ?ȱ OriginalȱSPȱValue ȱ ȱ Figureȱ18.3ȱȱStackȱframeȱduringȱtheȱlinkȱinstructionȱ Download at http://www.pin5i.com/ 18.1 Determining the Runtime Environmentȱ 549 ȱ Argument Ordering on the Stack ȱ Weȱcanȱnowȱdeduceȱwhyȱtheȱargumentsȱareȱpushedȱonȱtheȱstackȱinȱreverseȱorder.ȱTheȱ calledȱfunctionȱaccessesȱtheȱargumentsȱusingȱoffsetsȱfromȱtheȱframeȱpointer.ȱWhenȱtheȱ argumentsȱareȱpushedȱinȱreverseȱorder,ȱtheȱfirstȱargumentȱisȱonȱtopȱofȱtheȱpileȱandȱitsȱ offsetȱfromȱtheȱframeȱpointerȱisȱaȱconstant.ȱInȱfact,ȱtheȱoffsetȱfromȱtheȱframeȱpointerȱtoȱ anyȱ argumentȱ willȱ beȱ aȱ constantȱ valueȱ thatȱ isȱ independentȱ ofȱ howȱ manyȱ argumentsȱ wereȱpushed.ȱ Whatȱwouldȱhappenȱifȱtheȱargumentsȱwereȱpushedȱinȱtheȱoppositeȱorder?ȱThenȱ theȱ offsetȱ toȱ theȱ firstȱ argumentȱ wouldȱ dependȱ onȱ howȱ manyȱ wereȱ pushed.ȱ Theȱ compilerȱ couldȱ computeȱ thisȱ valueȱ exceptȱ forȱ oneȱ problem—theȱ actualȱ numberȱ ofȱ argumentsȱpassedȱmightȱbeȱdifferentȱfromȱtheȱnumberȱofȱparametersȱthatȱtheȱfunctionȱ expects.ȱInȱthisȱsituation,ȱtheȱoffsetsȱwouldȱbeȱincorrect,ȱandȱwhenȱtheȱfunctionȱtriedȱtoȱ accessȱanȱargumentȱitȱwouldȱnotȱgetȱtheȱoneȱitȱwanted.ȱ HowȱareȱextraȱargumentsȱhandledȱinȱtheȱreverseȬorderȱscheme?ȱTheȱdiagramȱofȱ theȱstackȱframeȱshowsȱthatȱanyȱextraȱargumentsȱthatȱwereȱpassedȱwouldȱappearȱbelowȱ theȱ firstȱ ones;ȱ theȱ distanceȱ fromȱ theȱ frameȱ pointerȱ toȱ theȱ firstȱ argumentȱ wouldȱ beȱ unchanged.ȱ Therefore,ȱ theȱ functionȱ wouldȱ accessȱ theȱ firstȱ threeȱ argumentsȱ properlyȱ andȱsimplyȱignoreȱtheȱextras.ȱ ȱ ȱ ȱ ȱ CurrentȱSP SavedȱRegisterȱValues LocalȱVariables Oldȱa6ȱValue Currentȱa6 ReturnȱAddr Argumentȱ#1 Argumentȱ#2 Argument #3 ? OriginalȱSPȱValue ȱ ȱ Figureȱ18.4ȱȱStackȱframeȱafterȱtheȱlinkȱinstructionȱ Download at http://www.pin5i.com/ Chapter 18 Runtime Environmentȱ 550ȱ ȱ TIP Ifȱ theȱ functionȱ somehowȱ knewȱ thatȱ thereȱ wereȱ extraȱ arguments,ȱ onȱ thisȱ machineȱ itȱ couldȱaccessȱtheirȱvaluesȱbyȱtakingȱtheȱaddressȱofȱtheȱlastȱargumentȱandȱincrementingȱ thisȱ pointer.ȱ Butȱ itȱ isȱ betterȱ toȱ useȱ theȱ stdarg.hȱ macros,ȱ whichȱ provideȱ aȱ portableȱ interfaceȱforȱaccessingȱvariableȱarguments.ȱ ȱ ȱ ȱ Final Stack Frame Layout ȱ Theȱmapȱofȱtheȱstackȱframeȱforȱthisȱcompilerȱisȱnowȱcomplete,ȱandȱisȱshownȱinȱFigureȱ 18.5.ȱ Letȇsȱcontinueȱlookingȱatȱtheȱfunction:ȱ ȱ d = b - 6; return a + b + c; } movl subql movl movl a6@(12),d0 #6,d0 d0,a6@(-4) a6@(8),d0 ȱ ȱ ȱ SavedȱRegisterȱ Valuesȱ StackȱPointer Localȱ Variablesȱ OldȱFrameȱPtrȱ FrameȱPointer Argumentsȱ Pushedȱinȱ ReverseȱOrderȱ TopȱofȱPreviousȱStackȱFrame ȱ Figureȱ18.5ȱȱStackȱframeȱlayoutȱ ȱ Download at http://www.pin5i.com/ 18.1 Determining the Runtime Environmentȱ 551 ȱ addl addl moveml unlk rts a6@(12),d0 d7,d0 a6@(-8),#0x80 a6 ȱ Theȱstackȱframeȱmapȱmakesȱitȱeasyȱtoȱdetermineȱthatȱtheȱfirstȱ movlȱinstructionȱcopiesȱ theȱsecondȱargumentȱintoȱ d0.ȱTheȱnextȱinstructionȱsubtractsȱ6ȱfromȱthisȱvalue,ȱandȱtheȱ thirdȱstoresȱtheȱresultȱinȱtheȱlocalȱvariableȱ d.ȱ d0ȱisȱusedȱasȱaȱȈscratchpadȈȱorȱtemporaryȱ locationȱforȱcomputations;ȱthisȱisȱoneȱofȱtheȱreasonsȱitȱcannotȱbeȱusedȱtoȱholdȱregisterȱ variables.ȱ Theȱ nextȱ threeȱ instructionsȱ evaluateȱ theȱ expressionȱ inȱ theȱ returnȱ statement.ȱ Thisȱvalueȱisȱtheȱoneȱweȱwantȱtoȱreturnȱtoȱtheȱcallingȱfunction.ȱButȱtheȱresultȱisȱjustȱleftȱ inȱd0;ȱrememberȱthisȱdetailȱforȱlater.ȱ ȱ ȱ ȱ Function Epilogue ȱ Thisȱ functionȇsȱ epilogueȱ beginsȱ withȱ theȱ movemlȱ instruction,ȱ whichȱ restoresȱ theȱ previouslyȱsavedȱregisterȱvalue(s).ȱThenȱtheȱ unlkȱ(unlink)ȱinstructionȱcopiesȱtheȱvalueȱ inȱ a6ȱintoȱtheȱstackȱpointerȱandȱloadsȱ a6ȱwithȱitsȱformerȱvalue,ȱwhichȱisȱpoppedȱoffȱofȱ theȱ stackȱ inȱ theȱ process.ȱ Theȱ effectȱ ofȱ thisȱ actionȱ isȱ toȱ deleteȱ theȱ portionȱ ofȱ theȱ stackȱ frameȱaboveȱtheȱreturnȱaddress.ȱFinally,ȱtheȱ rtsȱinstructionȱreturnsȱfromȱtheȱfunctionȱ byȱpoppingȱtheȱreturnȱaddressȱoffȱtheȱstackȱintoȱtheȱprogramȱcounter.ȱ Executionȱ nowȱ resumesȱ inȱ theȱ callingȱ program.ȱ Noticeȱ thatȱ theȱ stackȱ isȱ notȱ entirelyȱcleanedȱupȱyet.ȱ ȱ i2 = func_ret_int( 10, i1, i10 ); lea movl sp@(12),sp d0,d6 ȱ Theȱ firstȱ instructionȱ executedȱ afterȱ weȇveȱ returnedȱ toȱ theȱ callingȱ programȱ addsȱ 12ȱ toȱ theȱstackȱpointer.ȱ Theȱadditionȱeffectivelyȱ popsȱtheȱargumentȱ valuesȱ offȱ ofȱtheȱ stack,ȱ whichȱisȱnowȱinȱexactlyȱtheȱsameȱstateȱthatȱitȱwasȱinȱbeforeȱtheȱfunctionȱcallȱbegan.ȱ Itȱ isȱ interestingȱ thatȱ theȱ calledȱ functionȱ doesȱ notȱ removeȱ itsȱ entireȱ stackȱ frameȱ fromȱtheȱstack:ȱtheȱargumentsȱareȱleftȱforȱtheȱcallingȱprogramȱtoȱremove.ȱTheȱreason,ȱ onceȱ again,ȱ hasȱ toȱ doȱ withȱ variableȱ argumentȱ lists.ȱ Theȱ callingȱ functionȱ pushesȱ theȱ argumentsȱonȱtheȱstack,ȱsoȱitȱisȱtheȱonlyȱoneȱwhoȱknowsȱforȱsureȱhowȱmanyȱargumentsȱ thereȱare.ȱHence,ȱonlyȱtheȱcallingȱfunctionȱcanȱsafelyȱremoveȱthem.ȱ Download at http://www.pin5i.com/ Chapter 18 Runtime Environmentȱ 552ȱ ȱ Return Values ȱ Theȱepilogueȱdidȱnotȱtouch d0,ȱsoȱitȱstillȱcontainsȱtheȱvalueȱreturnedȱbyȱtheȱfunction.ȱ Theȱ secondȱ instructionȱ executedȱ afterȱ returningȱ fromȱ theȱ functionȱ copiesȱ d0ȱ intoȱ d6,ȱ whichȱisȱtheȱvariableȱ(i2)ȱtoȱwhichȱtheȱresultȱisȱassigned.ȱ Withȱ thisȱ compiler,ȱ then,ȱ aȱ functionȱ returnsȱ aȱ valueȱ byȱ leavingȱ itȱ inȱ d0,ȱ theȱ callingȱfunctionȱgetsȱtheȱvalueȱfromȱd0ȱafterȱtheȱfunctionȱhasȱreturned.ȱThisȱprotocolȱisȱ theȱotherȱreasonȱthatȱd0ȱisȱnotȱusedȱtoȱholdȱregisterȱvariables.ȱ Theȱnextȱfunctionȱcalledȱreturnsȱaȱdouble.ȱ ȱ dbl = func_ret_double(); c1 = func_ret_char_ptr( c1 ); jbsr movl movl _func_ret_double d0,a6@(-48) d1,a6@(-44) pea jbsr addqw movl a5@ _func_ret_char_ptr #4,sp d0,a5 ȱ Thisȱfunctionȱdoesnȇtȱhaveȱanyȱarguments,ȱsoȱnothingȱisȱpushedȱonȱtheȱstack.ȱAfterȱitȱ returns,ȱbothȱ d0ȱandȱ d1ȱareȱstored.ȱOnȱthisȱmachine,ȱdoublesȱareȱ8ȱbytesȱlong,ȱtooȱbigȱ toȱ fitȱ inȱ oneȱ register.ȱ Therefore,ȱ bothȱ d0ȱ andȱ d1ȱ areȱ neededȱ toȱ returnȱ oneȱ ofȱ theseȱ values.ȱ Theȱlastȱfunctionȱcallȱillustratesȱhowȱpointerȱvaluesȱareȱreturnedȱfromȱfunctions:ȱ theyȱareȱalsoȱpassedȱbackȱthroughȱ d0.ȱAȱdifferentȱcompilerȱmightȱpassȱpointerȱvaluesȱ backȱthroughȱa0ȱorȱsomeȱotherȱregister.ȱTheȱremainingȱinstructionsȱinȱtheȱprogramȱareȱ theȱprologueȱforȱthisȱfunction.ȱ ȱ ȱ ȱ 18.1.7 Expression Side Effects ȱ InȱChapterȱ4ȱIȱmentionedȱthatȱifȱanȱexpressionȱsuchȱasȱ ȱ ȱ y + 3; ȱ appearedȱ inȱ aȱ program,ȱ itȱ wouldȱ beȱ evaluatedȱ butȱ wouldȱ notȱ affectȱ theȱ programȱ becauseȱitsȱresultȱwasȱnotȱsaved.ȱAȱfootnoteȱthenȱexplainedȱthatȱitȱactuallyȱcouldȱaffectȱ theȱexecutionȱofȱtheȱprogramȱinȱaȱsubtleȱway.ȱ Considerȱ Programȱ 18.3,ȱ whichȱ isȱ supposedȱ loȱ returnȱ theȱ valueȱ ofȱ a + b.ȱ Theȱ functionȱ computesȱ aȱ resultȱ butȱ doesnȇtȱ returnȱ anythingȱ becauseȱ theȱ expressionȱ wasȱ erroneouslyȱ omittedȱ fromȱ theȱ returnȱ statement.ȱ Butȱ withȱ thisȱ compiler,ȱ theȱ functionȱ actuallyȱworks!ȱȱd0ȱisȱusedȱtoȱcomputeȱx,ȱandȱbecauseȱthisȱexpressionȱisȱtheȱlastȱoneȱȱ Download at http://www.pin5i.com/ 18.1 Determining the Runtime Environmentȱ 553 ȱ ȱ /* ** A function that works on some machines despite a major error. */ int erroneous( int a, int b ) { int x; /* ** Compute the answer, and return it */ x = a + b; return; } ȱ Programȱ18.3ȱȱAȱfunctionȱthatȱaccidentallyȱreturnsȱtheȱproperȱvalueȱȱ ȱ ȱȱȱȱȱȱȱȱnoȬret.cȱ ȱ ȱ ȱ ȱ ȱ evaluated,ȱ d0ȱ stillȱ containsȱ theȱ resultȱ whenȱ theȱ functionȱ hasȱ finished.ȱ Quiteȱ accidentally,ȱtheȱfunctionȱreturnsȱtheȱproperȱvalueȱtoȱtheȱcallingȱprogram.ȱ Nowȱsupposeȱweȱinsertedȱtheȱexpressionȱ ȱ a + 3; ȱ beforeȱtheȱreturnȱstatement.ȱThisȱnewȱcomputationȱwouldȱchangeȱd0.ȱEvenȱthoughȱtheȱ resultȱofȱtheȱexpressionȱisȱnotȱstoredȱinȱanyȱvariable,ȱitȱhasȱaffectedȱtheȱexecutionȱofȱtheȱ programȱbyȱchangingȱtheȱvalueȱthatȱisȱreturnedȱbyȱthisȱfunction.ȱ Aȱ similarȱ problemȱ canȱ beȱ causedȱ byȱ debuggingȱ statements.ȱ Ifȱ youȱ addȱ theȱ statementȱ ȱ printf( "Function returns the value %d\n", x ); ȱ beforeȱtheȱ returnȱstatement,ȱtheȱfunctionȱnoȱlongerȱreturnsȱtheȱcorrectȱvalue.ȱRemoveȱ theȱdebuggingȱstatementȱandȱitȱstartsȱworkingȱagain.ȱItȱisȱextremelyȱfrustratingȱwhenȱ yourȱdebuggingȱstatementsȱchangeȱtheȱbehaviorȱofȱtheȱprogram!ȱ Theseȱ effectsȱ areȱ allȱ madeȱ possibleȱ byȱ theȱ originalȱ error—theȱ omissionȱ ofȱ theȱ expressionȱ fromȱ theȱ returnȱ statement.ȱ Thisȱ scenarioȱ mayȱ soundȱ unlikely,ȱ butȱ itȱ occurredȱ surprisinglyȱ oftenȱ withȱ oldȱ Cȱ compilersȱ becauseȱ theyȱ wouldȱ notȱ warnȱ theȱ programmerȱofȱaȱfunctionȱthatȱwasȱsupposedȱtoȱreturnȱaȱvalueȱbutȱdidȱnot.ȱ Download at http://www.pin5i.com/ 554ȱ ȱ Chapter 18 Runtime Environmentȱ 18.2 Interfacing With Assembly Language ȱ Thisȱexperimentȱhasȱshownȱeverythingȱneededȱtoȱwriteȱassemblyȱlanguageȱprogramsȱ thatȱcanȱcallȱorȱbeȱcalledȱbyȱCȱprograms.ȱTheȱrelevantȱresultsȱforȱthisȱenvironmentȱareȱ summarizedȱbelow—yourȱenvironmentȱsurelyȱdiffersȱinȱoneȱorȱmoreȱways!ȱ First,ȱ theȱ nameȱ ofȱ theȱ assemblyȱ programȱ mustȱ followȱ theȱ rulesȱ forȱ externalȱ identifiers.ȱOnȱthisȱsystem,ȱitȱmustȱbeginȱwithȱanȱunderscore.ȱ Second,ȱ theȱ assemblyȱ programȱ mustȱ followȱ theȱ properȱ protocolȱ forȱ functionȱ callsȱandȱreturns.ȱThereȱareȱtwoȱcases:ȱcallingȱaȱCȱfunctionȱfromȱanȱassemblyȱlanguageȱ programȱandȱcallingȱanȱassemblyȱlanguageȱfunctionȱfromȱaȱCȱprogram.ȱToȱcallȱCȱfromȱ assemblyȱlanguage:ȱ ȱ 1. Ifȱregistersȱd0,ȱd1,ȱa0,ȱorȱa1ȱcontainȱimportantȱvalues,ȱtheyȱmustȱbeȱsavedȱbeforeȱ callingȱtheȱCȱfunction,ȱbecauseȱtheȱCȱfunctionȱwillȱnotȱpreserveȱthem.ȱ 2. Anyȱargumentsȱtoȱtheȱfunctionȱmustȱbeȱpushedȱonȱtheȱstackȱinȱreverseȱorder.ȱ 3. Theȱ functionȱ mustȱ beȱ calledȱ withȱ aȱ Ȉjumpȱ subroutineȈȱ typeȱ ofȱ instructionȱ thatȱ pushesȱtheȱreturnȱaddressȱonȱtheȱstack.ȱ 4. Whenȱ theȱ Cȱ functionȱ returns,ȱ theȱ assemblyȱ programȱ mustȱ removeȱ anyȱ argumentsȱfromȱtheȱstack.ȱ 5. Ifȱaȱreturnȱvalueȱwasȱexpected,ȱitȱwillȱbeȱinȱd0ȱ(ifȱtheȱvalueȱisȱaȱdouble,ȱtheȱotherȱ halfȱofȱitȱwillȱbeȱinȱd1).ȱ 6. Anyȱregistersȱthatȱwereȱsavedȱbeforeȱtheȱcallȱmayȱnowȱbeȱrestored.ȱ ȱ ToȱwriteȱanȱassemblyȱprogramȱthatȱisȱcalledȱfromȱC:ȱ ȱ 1. Saveȱanyȱregistersȱ(otherȱthanȱd0,ȱd1,ȱa0,ȱandȱa1)ȱthatȱyouȱwishȱtoȱmodify.ȱ 2. Argumentȱ valuesȱ areȱ obtainedȱ fromȱ theȱ stackȱ whereȱ theȱ callingȱ Cȱ functionȱ pushedȱthem.ȱ 3. Ifȱtheȱfunctionȱshouldȱreturnȱaȱvalue,ȱitȱisȱleftȱinȱd0ȱ(inȱwhichȱcaseȱd0ȱmustȱnotȱbeȱ savedȱandȱrestored).ȱ 4. Beforeȱreturning,ȱtheȱfunctionȱmustȱremoveȱanythingȱitȱputȱonȱtheȱstack.ȱ ȱ ItȱisȱnotȱnecessaryȱtoȱbuildȱaȱcompleteȱCȬstyleȱstackȱframeȱinȱyourȱassemblyȱprogram.ȱ AllȱyouȱneedȱtoȱdoȱtoȱcallȱaȱCȱfunctionȱisȱtoȱpushȱtheȱargumentsȱinȱtheȱrightȱmannerȱ andȱcleanȱthemȱupȱwhenȱtheȱfunctionȱreturns.ȱInȱanȱassemblyȱprogramȱcalledȱbyȱaȱCȱ function,ȱyouȱmustȱaccessȱtheȱargumentsȱfromȱwhereȱtheȱCȱfunctionȱputȱthem.ȱ Download at http://www.pin5i.com/ 18.3 Runtime Efficiencyȱ 555 ȱ Beforeȱ youȱ canȱ actuallyȱ writeȱ assemblyȱ functions,ȱ youȱ willȱ needȱ toȱ knowȱ theȱ assemblyȱlanguageȱforȱyourȱmachine.ȱTheȱcursoryȱknowledgeȱthatȱallowedȱusȱtoȱfigureȱ outȱwhatȱanȱexistingȱassemblyȱprogramȱdoesȱisȱnotȱenoughȱforȱwritingȱnewȱprograms.ȱ Programsȱ 18.4ȱ andȱ 18.5ȱ areȱ twoȱ examplesȱ thatȱ callȱ assemblyȱ functionsȱ fromȱ Cȱ functionsȱandȱviceȱversa.ȱTheyȱareȱusefulȱillustrationsȱevenȱthoughȱtheyȱareȱspecificȱtoȱ thisȱenvironment.ȱTheȱfirstȱexampleȱisȱanȱassemblyȱlanguageȱprogramȱthatȱreturnsȱtheȱ sumȱ ofȱ threeȱ integerȱ arguments.ȱ Theȱ functionȱ doesȱ notȱ botherȱ completingȱ theȱ stackȱ frame;ȱ itȱ justȱ computesȱ theȱ sumȱ andȱ returns.ȱ Weȱ wouldȱ callȱ thisȱ functionȱ fromȱ aȱ Cȱ functionȱinȱthisȱmanner:ȱ ȱ sum = sum_three_values( 25, 14, -6 ); ȱ Theȱ nextȱ exampleȱ showsȱ aȱ fragmentȱ ofȱ anȱ assemblyȱ languageȱ programȱ whichȱ hasȱthreeȱvaluesȱtoȱprint.ȱItȱcallsȱprintfȱtoȱdoȱtheȱjob.ȱ ȱ ȱ ȱ 18.3 Runtime Efficiency ȱ Whenȱ isȱ aȱ programȱ Ȉtooȱ big?Ȉȱ Onȱ olderȱ computers,ȱ whenȱ theȱ programȱ grewȱ largerȱ thanȱtheȱamountȱofȱmainȱmemory,ȱitȱsimplyȱwouldȱnotȱrun,ȱthusȱitȱwasȱȈtooȱbig.ȈȱEvenȱ onȱmodernȱmachines,ȱaȱprogramȱthatȱmustȱbeȱstoredȱinȱROMȱmustȱbeȱsmallȱenoughȱtoȱ fitȱintoȱtheȱavailableȱmemory. 57 ȱ ȱ ȱ ȱ | | Sum three integer arguments and return the | total. | .text .globl _sum_three_values _sum_three_values: movl sp@(4),d0 |Get 1st arg, addl sp@(8),d0 |add 2nd arg, addl sp@(12),d0 |add last arg. rts |Return. ȱ Programȱ18.4ȱȱAssemblyȱlanguageȱprogramȱthatȱsumsȱthreeȱintegersȱ ȱ ȱȱȱȱȱȱȱȱȱȱȱsum.sȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱReadȱOnlyȱMemoryȱ(ROM)ȱisȱmemoryȱthatȱcannotȱbeȱchanged.ȱItȱisȱoftenȱusedȱtoȱholdȱprogramsȱinȱcomputersȱdedicatedȱtoȱ controllingȱsomeȱdevice.ȱ 57 Download at http://www.pin5i.com/ Chapter 18 Runtime Environmentȱ 556ȱ ȱ ȱ | | Need to print the three values x, y, and z. | movl z,sp@| Push args on the movl y,sp@| stack in reverse movl x,sp@| order: format, x, movl #format,sp@| y, and z. jbsr _printf | Now call printf addl #16,sp | Clean up stack \&... .data format: .ascii "x = %d, y = %d, and z = %d" .byte 012, 0 | Newline and null .even x: .long 25 y: .long 45 z: .long 50 ȱ Programȱ18.5ȱȱAssemblyȱlanguageȱprogramȱthatȱcallsȱprintfȱȱ ȱ ȱ ȱȱȱȱȱȱȱȱprintf.sȱ ȱ ȱ ȱ ȱ ȱ Butȱ manyȱ modernȱ computerȱ systemsȱ makeȱ thisȱ boundaryȱ lessȱ obviousȱ thanȱ itȱ onceȱ wasȱ byȱ providingȱ virtualȱ memory.ȱ Virtualȱ memoryȱ isȱ implementedȱ byȱ theȱ operatingȱ system,ȱ whichȱ bringsȱ theȱ activeȱ partsȱ ofȱ theȱ programȱ intoȱ memoryȱ whenȱ neededȱ andȱ copiesȱ inactiveȱ partsȱ toȱ disk,ȱ thusȱ allowingȱ theȱ systemȱ toȱ runȱ largerȱ programs.ȱ Butȱ theȱ largerȱ theȱ programȱ theȱ moreȱ copyingȱ isȱ required.ȱ Soȱ ratherȱ thanȱ beingȱunableȱtoȱrunȱtheȱprogramȱatȱall,ȱweȱgetȱaȱgradualȱreductionȱinȱperformanceȱasȱ theȱprogramȱgrowsȱlarger.ȱȱSoȱwhenȱisȱtheȱprogramȱtooȱbig?ȱWhenȱitȱrunsȱtooȱslowly.ȱ Theȱ issueȱ ofȱ executionȱ speedȱ isȱ obviouslyȱ relatedȱ toȱ itsȱ size.ȱ Theȱ slowerȱ theȱ programȱexecutes,ȱtheȱmoreȱuncomfortableȱitȱwillȱbeȱtoȱuseȱit.ȱItȱisȱhardȱtoȱidentifyȱtheȱ pointȱ atȱ whichȱ aȱ programȱ isȱ suddenlyȱ Ȉtooȱ slowȈȱ unlessȱ itȱ mustȱ respondȱ toȱ someȱ physicalȱeventsȱoverȱwhichȱitȱhasȱnoȱcontrol.ȱForȱexample,ȱaȱprogramȱtoȱoperateȱaȱCDȱ playerȱisȱclearlyȱtooȱslowȱifȱitȱcannotȱprocessȱtheȱdataȱasȱfastȱasȱitȱcomesȱoffȱofȱtheȱCD.ȱ ȱ ȱ ȱ 18.3.1 Improving Efficiency ȱ Modemȱ optimizingȱ compilersȱ doȱ aȱ veryȱ goodȱ jobȱ ofȱ producingȱ efficientȱ objectȱ codeȱ fromȱaȱCȱprogram.ȱTherefore,ȱspendingȱtimeȱtryingȱtoȱmakeȱyourȱcodeȱmoteȱefficientȱ byȱmakingȱsmallȱchangesȱtoȱitȱisȱusuallyȱnotȱveryȱproductive.ȱ Download at http://www.pin5i.com/ 18.3 Runtime Efficiencyȱ 557 ȱ TIP ȱ Ifȱ aȱ programȱ isȱ tooȱ largeȱ orȱ tooȱ slow,ȱ selectingȱ aȱ moreȱ efficientȱ algorithmȱ orȱ dataȱ structureȱisȱaȱmuchȱmoreȱeffectiveȱwayȱtoȱimproveȱtheȱperformanceȱthanȱplayingȱwithȱ individualȱvariablesȱtoȱseeȱifȱdeclaringȱthemȱ registerȱhelpsȱorȱnot.ȱThisȱfactȱdoesȱnotȱ giveȱ youȱ licenseȱ toȱ beȱ sloppyȱ inȱ yourȱ coding,ȱ however,ȱ becauseȱ poorȱ codeȱ alwaysȱ makesȱthingsȱworse.ȱ Ifȱaȱprogramȱisȱtooȱlarge,ȱitȱisȱeasyȱtoȱimagineȱwhereȱyouȱmightȱlookȱforȱwaysȱtoȱ makeȱitȱsmaller;ȱtheȱlargestȱfunctionsȱandȱdataȱstructures.ȱButȱifȱaȱprogramȱisȱtooȱslow,ȱ whereȱ doȱ youȱ evenȱ startȱ toȱ lookȱ toȱ improveȱ itsȱ speed?ȱ Theȱ answerȱ isȱ toȱ profileȱ theȱ program,ȱwhichȱsimplyȱmeansȱtoȱmeasureȱhowȱmuchȱtimeȱisȱspentȱexecutingȱeachȱofȱ itsȱparts.ȱTheȱportionsȱofȱtheȱprogramȱthatȱtakeȱtheȱlongestȱareȱobviousȱcandidatesȱforȱ optimization.ȱMakingȱtheȱmostȱheavilyȱusedȱpartsȱofȱtheȱprogramȱfasterȱisȱanȱeffectiveȱ useȱofȱyourȱtime.ȱ MostȱUNIXȱsystemsȱcomeȱwithȱprofilingȱtools,ȱandȱsuchȱtoolsȱareȱavailableȱforȱ manyȱotherȱsystemsȱasȱwell.ȱFigureȱ18.6ȱisȱaȱportionȱofȱtheȱoutputȱfromȱoneȱsuchȱtool.ȱȱȱ Itȱshowsȱtheȱnumberȱofȱtimesȱeachȱfunctionȱwasȱcalledȱandȱtheȱnumberȱofȱsecondsȱthatȱ wereȱ spentȱ inȱ thatȱ functionȱ duringȱ oneȱ executionȱ ofȱ aȱ particularȱ program.ȱ Theȱ totalȱ executionȱtimeȱwasȱ32.95ȱseconds.ȱThereȱareȱthreeȱinterestingȱpointsȱweȱcanȱlearnȱfromȱ thisȱlist.ȱ ȱ 1. Someȱ ofȱ theȱ mostȱ oftenȱ usedȱ functionsȱ areȱ libraryȱ functions.ȱ Inȱ thisȱ example,ȱ mallocȱandȱ freeȱheadȱtheȱ list.ȱYouȱcannotȱchangeȱhowȱ theyȱ areȱ implemented,ȱ butȱ ifȱ theȱ programȱ wasȱ redesignedȱ soȱ thatȱ itȱ didȱ notȱ dynamicallyȱ allocateȱ memoryȱorȱdidȱsoȱlessȱoften,ȱitsȱspeedȱcouldȱbeȱimprovedȱbyȱupȱtoȱ25%.ȱ 2. Someȱfunctionsȱusedȱaȱlotȱofȱtimeȱbecauseȱtheyȱwereȱcalledȱaȱlot.ȱEvenȱthoughȱ eachȱindividualȱcallȱwasȱquick,ȱthereȱwereȱaȱlotȱofȱthem.ȱ_nextch_from_chrlstȱisȱ anȱ example.ȱ Eachȱ callȱ toȱ thisȱ functionȱ usedȱ onlyȱ aboutȱ 4.3ȱ microseconds.ȱȱ Becauseȱ itȱ isȱ soȱ short,ȱ itȱ isȱ unlikelyȱ thatȱ youȱ couldȱ improveȱ thisȱ functionȱ veryȱ much.ȱ Butȱ itȱ isȱ worthȱ lookingȱ atȱ simplyȱ becauseȱ itȱ isȱ calledȱ soȱ often.ȱ Aȱ fewȱ judiciousȱregisterȱdeclarationsȱmightȱmakeȱaȱsignificantȱdifference.ȱ 3. Someȱ functionsȱ wereȱ notȱ calledȱ often,ȱ butȱ eachȱ callȱ tookȱ aȱ longȱ time.ȱ Forȱ example,ȱtheȱfunctionȱ _lookup_macroȱaveragedȱoverȱ265ȱmicrosecondsȱperȱcall.ȱ Findingȱaȱfasterȱalgorithmȱtoȱperformȱthisȱtaskȱcouldȱmakeȱtheȱprogramȱupȱtoȱ 7¾%ȱȱfaster. 58 ȱ ȱ Asȱaȱlastȱresort,ȱyouȱcouldȱrecodeȱindividualȱfunctionsȱinȱassemblyȱlanguage.ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱActuallyȱthereȱisȱaȱfourthȱpointȱtoȱbeȱlearned,ȱȱmallocȱwasȱcalledȱ20,833ȱtimesȱmoreȱoftenȱthanȱfree,ȱsoȱsomeȱmemoryȱhasȱ leaked!ȱ 58 Download at http://www.pin5i.com/ Chapter 18 Runtime Environmentȱ 558ȱ ȱ ȱ Seconds ------4.94 3.21 2.85 2.82 2.69 2.57 1.35 1.23 1.10 1.09 0.91 0.90 0.82 0.79 0.77 0.65 0.57 0.51 0.46 0.41 0.37 0.35 0.34 0.32 0.31 0.31 0.31 # Calls ------293426 272593 658973 272593 791303 9664 372915 254501 302714 285031 197235 272419 285031 7620 63946 292822 272594 34374 151006 6473 8843 23774 203535 10984 133032 604 52627 Function Name ----------------------malloc free _nextch_from_chrlst _insert _check_traverse _lookup_macro _append_to_chrlst _interpolate _next_input_char _input_fliter demote putfreehdr _nextchar _lookup_number_register _new_character allocate _getfreehdr _next_text_char _duplicate_char _expression _sub_expression _skip_white_space _copy_interpolate _copy_function _duplicate_ascii_char _process_filled_text _next_ascii_char ȱ Figureȱ18.5ȱȱSampleȱprofilingȱinformationȱ ȱ ȱ ȱ ȱ ȱ ȱ Theȱ smallerȱ theȱ function,ȱ theȱ easierȱ itȱ isȱ toȱ recode.ȱ Theȱ benefitȱ mayȱ alsoȱ beȱ greater,ȱ becauseȱ theȱ fixedȱ overheadȱ ofȱ theȱ Cȱ prologueȱ andȱ epilogueȱ consumeȱ aȱ greaterȱ percentageȱ ofȱ theȱ executionȱ timeȱ ofȱ smallȱ functions.ȱ Recedingȱ largerȱ functionsȱ inȱ assemblyȱlanguageȱisȱmoreȱdifficultȱandȱisȱthereforeȱaȱlessȱproductiveȱuseȱofȱyourȱtime.ȱ ȱ Oftenȱ theȱ profileȱ willȱ notȱ tellȱ youȱ anythingȱ thatȱ youȱ donȇtȱ alreadyȱ know,ȱ butȱ sometimesȱtheȱresultsȱcanȱbeȱquiteȱunexpected.ȱTheȱadvantageȱofȱprofilingȱisȱthatȱyouȱ canȱbeȱsureȱyouȱareȱspendingȱyourȱtimeȱonȱtheȱareasȱinȱtheȱprogramȱthatȱcanȱbenefitȱ mostȱfromȱimprovement.ȱ ȱ Download at http://www.pin5i.com/ 18.5 Summary of Cautionsȱ 559 ȱ 18.4 Summary CAUTION! TIP ȱ Someȱofȱtheȱtasksȱweȇveȱexaminedȱonȱthisȱmachineȱareȱaccomplishedȱinȱtheȱsameȱwayȱ inȱmanyȱotherȱenvironmentsȱasȱwell.ȱForȱexample,ȱmostȱenvironmentsȱconstructȱsomeȱ kindȱofȱstackȱframeȱinȱwhichȱfunctionsȱstoreȱtheirȱdata.ȱTheȱdetailsȱofȱtheȱframeȱmightȱ vary,ȱbutȱtheȱbasicȱideaȱisȱquiteȱcommon.ȱ ȱ Otherȱ tasksȱ areȱ likelyȱ toȱ beȱ differentȱ fromȱ oneȱ environmentȱ toȱ theȱ next.ȱ Someȱ computersȱhaveȱspecificȱhardwareȱtoȱkeepȱtrackȱofȱfunctionȱarguments,ȱsoȱtheyȱmayȱbeȱ handledȱ differentlyȱ thanȱ weȱ haveȱ seen.ȱ Otherȱ machinesȱ mightȱ passȱ functionȱ valuesȱ backȱdifferently.ȱ ȱ Inȱ fact,ȱ differentȱ compilersȱ canȱ produceȱ veryȱ differentȱ codeȱ forȱ theȱ sameȱ machine.ȱȱ Anotherȱcompilerȱforȱourȱtestȱmachineȱwasȱableȱtoȱuseȱanywhereȱfromȱ9ȱtoȱ14ȱregisterȱ variables,ȱdependingȱ onȱ otherȱ circumstances.ȱ Differentȱ compilersȱ mayȱ haveȱ differentȱ stackȱframeȱconventionsȱorȱuseȱincompatibleȱtechniquesȱforȱcallingȱandȱreturningȱfromȱ functions.ȱ Thereforeȱ youȱ cannot,ȱ inȱ general,ȱ useȱ differentȱ compilersȱ toȱ compileȱ differentȱpiecesȱofȱoneȱprogram.ȱ Theȱ bestȱ wayȱ toȱ improveȱ theȱ efficiencyȱ ofȱ aȱ programȱ isȱ toȱ selectȱ betterȱ algorithmsȱ forȱ it.ȱ Theȱ nextȱ bestȱ wayȱ toȱ improveȱ theȱ executionȱ speedȱ isȱ toȱ profileȱ theȱ programȱtoȱseeȱwhereȱitȱisȱspendingȱmostȱofȱitsȱtime.ȱConcentratingȱyourȱoptimizationȱ effortsȱonȱtheseȱportionsȱofȱtheȱprogramȱwillȱgiveȱyouȱtheȱbestȱresults.ȱ ȱ Learningȱaboutȱyourȱmachineȇsȱruntimeȱenvironmentȱisȱbothȱusefulȱandȱdangerous— usefulȱbecauseȱtheȱknowledgeȱyonȱgainȱletsȱyouȱdoȱthingsȱyouȱwouldȱnotȱotherwiseȱbeȱ ableȱ toȱ do;ȱ dangerousȱ becauseȱ anythingȱ thatȱ dependsȱ onȱ thisȱ knowledgeȱ isȱ likelyȱ toȱ impairȱ theȱ portabilityȱ ofȱ yourȱ program.ȱ Theseȱ days,ȱ withȱ computersȱ becomingȱ obsoleteȱ beforeȱ theyȱ reachȱ theȱ storeȱ shelves,ȱ theȱ possibilityȱ ofȱ movingȱ fromȱ oneȱ machineȱtoȱanotherȱisȱveryȱreal,ȱwhichȱisȱaȱstrongȱmotivationȱtoȱproduceȱportableȱcode.ȱ ȱ ȱ ȱ 18.5 Summary of Cautions ȱ 1. Theȱ linker,ȱ notȱ theȱ compiler,ȱ determinesȱ theȱ maximumȱ lengthȱ ofȱ externalȱ identifiersȱ(pageȱ545).ȱ 2. Youȱcannotȱlinkȱprogramsȱproducedȱbyȱdifferentȱcompilersȱ(pageȱ559).ȱ Download at http://www.pin5i.com/ 560ȱ ȱ Chapter 18 Runtime Environmentȱ 18.6 Summary of Programming Tips ȱ 1. Useȱstdargȱtoȱimplementȱvariableȱargumentȱlistsȱ(pageȱ550).ȱ 2. Improvingȱtheȱalgorithmȱisȱmoreȱeffectiveȱthanȱoptimizingȱtheȱcodeȱ(pageȱ557).ȱ 3. Usingȱ techniquesȱ specificȱ toȱ oneȱ environmentȱ makesȱ theȱ programȱ nonportableȱ (pageȱ559).ȱ ȱ ȱ ȱ 18.7 Questions ȱ 1. Whatȱdoesȱtheȱstackȱframeȱlookȱlikeȱforȱyourȱenvironment?ȱ 2. Whatȱisȱtheȱlongestȱexternalȱidentifierȱthatȱisȱsignificantȱonȱyourȱsystem?ȱ 3. Howȱ manyȱ variablesȱ willȱ yourȱ environmentȱ storeȱ inȱ registers?ȱ Doesȱ itȱ makeȱ anyȱ distinctionȱbetweenȱpointerȱandȱnonpointerȱvalues?ȱ 4. Howȱ areȱ argumentsȱ passedȱ toȱ functionsȱ inȱ yourȱ environment?ȱ Howȱ areȱ valuesȱ returnedȱfromȱfunctions?ȱ 5. Ifȱaȱfunctionȱdeclaresȱoneȱorȱmoreȱofȱitsȱargumentsȱtoȱbeȱregisterȱvariablesȱonȱtheȱ machineȱexaminedȱinȱthisȱchapter,ȱtheȱargumentsȱtoȱtheȱfunctionȱareȱpushedȱonȱtheȱ stackȱasȱusualȱandȱthenȱcopiedȱintoȱtheȱrightȱregistersȱinȱtheȱfunctionȱprologue.ȱItȱ wouldȱ beȱ moreȱ efficientȱ toȱ passȱ thoseȱ argumentsȱ throughȱ theȱ registersȱ directly.ȱȱ Couldȱthisȱargumentȱpassingȱtechniqueȱbeȱimplemented,ȱandȱifȱso,ȱhowȱcouldȱitȱbeȱ done?ȱ 6. Inȱtheȱenvironmentȱdiscussed,ȱtheȱcallingȱfunctionȱisȱresponsibleȱforȱremovingȱtheȱ argumentsȱ thatȱ itȱ pushedȱ onȱ theȱ stack.ȱ Isȱ itȱ possibleȱ forȱ theȱ calledȱ functionȱ toȱ performȱthisȱtaskȱinstead?ȱIfȱnot,ȱwhatȱisȱrequiredȱtoȱmakeȱitȱpossible?ȱ 7. IfȱassemblyȱlanguageȱprogramsȱareȱmoreȱefficientȱthanȱCȱprograms,ȱwhyȱnotȱwriteȱ everythingȱinȱassemblyȱlanguage?ȱ ȱ ȱ ȱ 18.8 Programming Exercises ȱ 1. Writeȱ anȱ assemblyȱ languageȱ functionȱ forȱ yourȱ systemȱ thatȱ takesȱ threeȱ integerȱ argumentsȱandȱreturnsȱtheirȱsum.ȱ 2. Writeȱ anȱ assemblyȱ languageȱ programȱ thatȱ createsȱ threeȱ integerȱ valuesȱ andȱ callsȱ printfȱtoȱprintȱthemȱout.ȱ 3. Supposeȱtheȱstdarg.hȱfileȱw