Kenneth Reek - Pointers on C
January 20, 2017 | Author: Huanye Liu | Category: N/A
Short Description
Download Kenneth Reek - Pointers on C ...
Description
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 #inc1ude #include #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 #include #include #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 main(t,_,a) char *a; {return!0 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] ){ 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 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;
ȱ ȱ 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ȱ
[] . -> ++ -! ~ + ++ -*
/ % + >
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ȱ
>=
<
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 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 c || ++a > b
jj.
a > c && ++a > b
kk.
! ~ b++
ll.
b++ & a >= 3 > 0
oo.
a = '0' ) && ( a 0 )
h.
( ( a = 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 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 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 #include 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 = 'A' && ch = 'a' && ch ȱ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( ¤t_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( ¤t_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 ) 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 #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 #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 #include /* ** 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 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 #include #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 #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 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 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 #include #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ȱ ¤t->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 = ¤t->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 #include #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 = ¤t->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 #include #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 #include #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ȱ 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 #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 ... 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 #include 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 #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 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 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
ȱ 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 ȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ 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
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 #
ȱ 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 #include 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 #include 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 #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 #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 #include #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 #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
ȱ 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
ȱ 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 #include #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
ȱ 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
ȱ 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
ȱ 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
ȱ 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
ȱ 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
ȱ 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
ȱ 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
ȱ 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 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 #include #include #include #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 #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 #include #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 #include #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 #include #include /* ** 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 = ¤t->left; else { assert( value != current->value ); link = ¤t->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 ¤t->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 #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 #include #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ȱwasȱaccidentallyȱdeletedȱfromȱyourȱsystem.ȱWriteȱaȱsetȱofȱ stdargȱmacrosȱasȱdescribedȱinȱChapterȱ7.ȱ
Download at http://www.pin5i.com/
APPENDIX Selected Problem Solutions
Thisȱappendixȱgivesȱsolutionsȱforȱselectedȱquestionsȱandȱprogrammingȱexercisesȱfromȱ theȱ chapters.ȱ Inȱ theȱ caseȱ ofȱ programmingȱ exercises,ȱ thereȱ areȱ oftenȱ manyȱ correctȱ solutionsȱinȱadditionȱtoȱtheȱonesȱgivenȱhere.ȱ ȱ ȱ ȱ
Chapter 1 ȱ 1.2
1.5 1.8
Questions
Theȱdeclarationȱneedsȱtoȱbeȱwrittenȱonlyȱonce,ȱwhichȱmakesȱitȱeasierȱtoȱmaintainȱ ifȱmodificationsȱareȱneededȱlater.ȱȱAlso,ȱwritingȱitȱonlyȱonceȱeliminatesȱtheȱchanceȱ thatȱadditionalȱcopiesȱareȱwrittenȱdifferentlyȱfromȱeachȱother.ȱ scanf( "%d %d %s", &quantity, &price, department );
Whenȱ anȱ arrayȱ isȱ passedȱ asȱ aȱ functionȱ argument,ȱ theȱ functionȱ hasȱ noȱ wayȱ ofȱ knowingȱ itsȱ size.ȱ Therefore,ȱ getsȱ hasȱ noȱ wayȱ toȱ preventȱ aȱ veryȱ longȱ inputȱ lineȱ fromȱ overflowingȱ theȱ inputȱ array.ȱ Theȱ fgetsȱ function,ȱ whichȱ requiresȱ thatȱ theȱ arrayȱsizeȱbeȱpassedȱasȱanȱargument,ȱdoesȱnotȱhaveȱthisȱproblem.ȱ
ȱ ȱ ȱ
Chapter 1 ȱ 1.2
Programming Exercises Byȱ readingȱ theȱ inputȱ characterȱ byȱ characterȱ ratherȱ thanȱ lineȱ byȱ line,ȱ theȱ lineȱ lengthȱ limitȱ isȱ avoided.ȱ Theȱ solutionȱ wouldȱ beȱ moreȱ readableȱ ifȱ itȱ definedȱ symbolsȱTRUEȱandȱFALSe,ȱbutȱthisȱtechniqueȱhasȱnotȱyetȱbeenȱdiscussed.ȱ
Download at http://www.pin5i.com/
Appendix Selected Problem Solutionsȱ
562ȱ ȱ ȱ
/* ** Copy the standard input to the standard output, and number the ** output lines. */ #include #include int main() { int int int
ch; line; at_beginning;
line = 0; at_beginning = 1; /* ** Read characters and process them one by one. */ while( (ch = getchar()) != EOF ){ /* ** If we're at the beginning of a line, print the ** line number. */ if( at_beginning == 1 ){ at_beginning = 0; line += 1; printf( "%d ", line ); } /* ** Print the character, and check for end of line. */ putchar( ch ); if( ch == '\n' ) at_beginning = 1; } return EXIT_SUCCESS; }
ȱ Solutionȱ1.2ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱnumber.cȱ ȱ ȱ ȱ 1.5 Weȱcanȱstillȱbreakȱtheȱloopȱwhenȱtheȱoutputȱlineȱisȱfull,ȱbutȱotherwiseȱtheȱloopȱ mustȱ continue.ȱ Weȱ mustȱ alsoȱ checkȱ howȱ manyȱ charactersȱ areȱ copiedȱ inȱ eachȱ rangeȱtoȱpreventȱaȱ NULȱbyteȱfromȱbeingȱcopiedȱintoȱtheȱoutputȱbufferȱtooȱearly.ȱ Hereȱisȱaȱmodificationȱthatȱdoesȱtheȱjob.ȱ
Download at http://www.pin5i.com/
Chapter 1 Programming Exercisesȱ
563
ȱ ȱ /* ** Process a line of input by concatenating the characters from ** the indicated columns. The output line is then NUL terminated. */ void rearrange( char *output, char const *input, int const n_columns, int const columns[] ) { int col; /* subscript for columns array */ int output_col; /* output column counter */ int len; /* 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, skip the range. */ if( columns[col] >= len ) continue; /* ** If the output array is full, we're done. */ if( 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; /* ** See how many characters the input line has in this ** range. If it is less than nchars, adjust nchars. */ if( columns[col] + nchars - 1 >= len ) nchars = len - columns[col]; /* ** Copy the relevant data. */ strncpy( output + output_col, input + columns[col], nchars ); output_col += nchars; }
ȱ Solutionȱ1.5ȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
Appendix Selected Problem Solutionsȱ
564ȱ ȱ ȱ
output[output_col] = '\0'; }
ȱ Solutionȱ1.5ȱ ȱ ȱ ȱ ȱ
Chapter 2 ȱ 2.4
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱrearran2.cȱ
Questions TheȱcharacterȱequivalencesȱgivenȱassumeȱthatȱtheȱimplementationȱusesȱASCII.ȱ \40ȱȱȱ=ȱ32ȱ=ȱtheȱspaceȱcharacter.ȱ \100ȱ=ȱ64ȱ=ȱȇ@ȇȱ \x40ȱ=ȱ64ȱ=ȱȇ@ȇȱ \x100ȱ isȱtwelveȱbitsȱ(thoughȱtheȱfirstȱthreeȱareȱzeros).ȱȱOnȱmostȱmachinesȱthisȱ numberȱ isȱ tooȱ bigȱ toȱ beȱ storedȱ inȱ aȱ character,ȱ soȱ theȱ resultȱ isȱ implementationȱdependent.ȱ \0123ȱ consistsȱ ofȱ twoȱ characters:ȱ ȇ\012ȇȱ andȱ ȇ3ȇ.ȱ Theȱ resultingȱ valueȱ isȱ implementationȱdependent.ȱ \x0123ȱ isȱtooȱbigȱtoȱfitȱintoȱaȱcharacter.ȱTheȱresultingȱvalueȱisȱimplementationȱ dependentȱ
2.7
Both.ȱTrue:ȱTheȱlanguageȱdoesnȇtȱimposeȱanyȱrulesȱregardingȱwhatȱaȱprogramȱ oughtȱ toȱ lookȱ like,ȱ exceptȱ forȱ preprocessorȱ directives.ȱ False:ȱ Programsȱ writtenȱ withoutȱstyleȱareȱdifficultȱorȱimpossibleȱtoȱmaintain,ȱsoȱhowȱtheȱprogramȱlooksȱ isȱextremelyȱimportantȱforȱallȱbutȱtheȱmostȱtrivialȱofȱprograms.ȱ
2.8
Bothȱ programsȱ areȱ missingȱ theȱ closingȱ braceȱ toȱ theȱ whileȱ loop,ȱ however,ȱ itȱ isȱ easierȱtoȱseeȱinȱtheȱsecondȱprogramȱthanȱinȱtheȱfirst.ȱThisȱexampleȱillustratesȱtheȱ valueȱofȱindentingȱtheȱstatementsȱinȱaȱfunction.ȱ
2.11
Whenȱaȱheaderȱisȱchanged,ȱeveryȱfileȱthatȱincludesȱitȱmustȱbeȱrecompiled.ȱ ȱ If This File is Changed These Must Be Recompiled list.c list.h table.h
list.c list.c, table.c, main.c table.c, main.c
ȱ TheȱBorlandȱC/C++ȱcompilerȇsȱWindowsȱIntegratedȱDevelopmentȱEnvironmentȱ looksȱ forȱ theseȱ relationshipsȱ amongȱ theȱ filesȱ andȱ automaticallyȱ compilesȱ onlyȱ thoseȱthatȱareȱneeded.ȱ ȱ
Download at http://www.pin5i.com/
Chapter 2 Programming Exercisesȱ
565
ȱ UNIXȱsystemsȱhaveȱaȱtoolȱcalledȱmakeȱthatȱperformsȱtheȱsameȱjob,ȱthoughȱwithȱ thisȱtoolȱyouȱmustȱconstructȱaȱȈmakefileȈȱthatȱdescribesȱtheȱrelationshipsȱamongȱ theȱfiles.ȱ ȱ ȱ ȱ
Chapter 2 ȱ 2.2
Programming Exercises Theȱprogramȱisȱeasyȱtoȱimplementȱwithȱaȱcounter.ȱHowever,ȱitȱisȱnotȱasȱtrivialȱ asȱitȱfirstȱseems.ȱTryȱtestingȱyourȱsolutionȱwithȱthisȱinput:ȱ}{ȱ
ȱ ȱ ȱ ȱ /* ** Check the pairing of braces in a C program. */ #include #include int main() { int int
ch; braces;
braces = 0; /* ** Read the program character by character. */ while( (ch = getchar()) != EOF ){ /* ** Opening braces are always legal. */ if( ch == '{' ) braces += 1; /* ** A closing brace is legal only if matched to an ** opening brace. */ if( ch == '}' ) if( braces == 0 ) printf( "Extra closing brace!\n" ); else braces -= 1; }
ȱ Solutionȱ2.2ȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continuedȱ...ȱ
Download at http://www.pin5i.com/
Appendix Selected Problem Solutionsȱ
566ȱ ȱ ȱ
/* ** No more input: make sure there aren't any opening braces ** that were not matched. */ if( braces > 0 ) printf( "%d unmatched opening brace(s)!\n", braces ); return EXIT_SUCCESS; }
ȱ Solutionȱ2.2ȱ ȱ ȱ ȱ ȱ
Chapter 3 ȱ 3.3
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱbraces.cȱ
Questions Declareȱ integerȱ variablesȱ thatȱ mustȱ beȱ aȱ particularȱ sizeȱ withȱ namesȱ likeȱ int8,ȱ int16,ȱ int32.ȱForȱintegersȱthatȱyouȱwantȱtoȱbeȱtheȱdefaultȱsize,ȱuseȱnamesȱlikeȱ defint8,ȱ defintl6,ȱ andȱ defint32ȱ dependingȱ onȱ theȱ largestȱ valueȱ theyȱ mustȱ hold.ȱ Thenȱ createȱ aȱ fileȱ calledȱ int_sizes.hȱ forȱ eachȱ machineȱ containingȱ typedefȇsȱthatȱselectȱtheȱbestȱintegerȱsizeȱforȱeachȱofȱyourȱnames.ȱȱOnȱaȱtypicalȱ 32Ȭbitȱmachineȱthisȱfileȱwouldȱcontain:ȱ ȱ typedef typedef typedef typedef typedef typedef
signed char short int int int int int
int8; int16; int32; defint8; defint16; defint32;
ȱ Onȱaȱtypicalȱmachineȱwithȱ16Ȭbitȱintegers,ȱtheȱfileȱwouldȱcontain:ȱ ȱ typedef typedef typedef typedef typedef typedef
signed char int long int int int long int
int8; int16; int32; defint8; defint16; defint32;
ȱ #defineȇsȱcouldȱalsoȱbeȱused.ȱ
3.7
Theȱ variableȱ jarȱ isȱ anȱ enumeratedȱ type,ȱ butȱ itsȱ valueȱ isȱ actuallyȱ anȱ integer.ȱ However,ȱ theȱ printf formatȱ codeȱ %sȱ isȱ usedȱ toȱ printȱ strings,ȱ notȱ integers.ȱ Consequently,ȱtheȱoutputȱcannotȱbeȱdetermined.ȱ Hadȱtheȱformatȱcodeȱbeenȱ%d,ȱthenȱtheȱoutputȱwouldȱhaveȱbeen:ȱ
ȱ
Download at http://www.pin5i.com/
Chapter 4 Questionsȱ
567
ȱ 32 48
3.10
No.ȱInȱanyȱgivenȱnumberȱofȱbitsȱn,ȱthereȱareȱonlyȱ2nȱdistinctȱcombinationsȱofȱtheȱ bitȱvalues.ȱTheȱonlyȱthingȱthatȱchangesȱbetweenȱaȱsignedȱandȱanȱunsignedȱvalueȱ isȱ howȱ halfȱ ofȱ thoseȱ valuesȱ areȱ interpreted.ȱ Inȱ aȱ signedȱ number,ȱ theyȱ areȱ negative;ȱinȱanȱunsignedȱnumber,ȱtheyȱareȱtheȱlargerȱpositiveȱvalues.ȱ
3.11
Theȱ floatȱ hasȱ aȱ greaterȱ rangeȱ thanȱ theȱ int,ȱ butȱ itȱ cannotȱ haveȱ moreȱ distinctȱ valuesȱ withoutȱ usingȱ moreȱ bits.ȱ Theȱ logicȱ inȱ theȱ previousȱ answerȱ impliesȱ thatȱ theyȱ holdȱ theȱ sameȱ numberȱ ofȱ distinctȱ values,ȱ butȱ forȱ mostȱ floatingȬpointȱ systemsȱthisȱanswerȱisȱwrong.ȱThereȱareȱusuallyȱlotsȱofȱrepresentationsȱforȱzero,ȱ andȱbyȱusingȱunnormalizedȱfractions,ȱlotsȱofȱrepresentationsȱforȱotherȱvaluesȱasȱ well.ȱThusȱtheȱnumberȱofȱdistinctȱvaluesȱisȱlessȱthanȱthatȱofȱanȱint.ȱ
3.21
Yes,ȱitȱisȱpossible,ȱbutȱyouȱshouldȱnotȱcountȱonȱit.ȱItȱisȱalsoȱquiteȱpossibleȱthatȱ theyȱ willȱ not,ȱ evenȱ ifȱ thereȱ wereȱ noȱ interveningȱ functionȱ calls.ȱ Onȱ someȱ architectures,ȱaȱhardwareȱinterruptȱwillȱpushȱmachineȱstateȱinformationȱonȱtheȱ stack,ȱwhichȱcouldȱdestroyȱtheȱvariables.ȱ
ȱ ȱ ȱ
Chapter 4 ȱ 4.1
4.4
Questions Itȱ isȱ legal,ȱ butȱ itȱ doesnȇtȱ affectȱ theȱ programȇsȱ state.ȱ Noneȱ ofȱ theȱ operatorsȱ involvedȱhaveȱanyȱsideȱeffectsȱandȱtheȱresultȱthatȱisȱcomputedȱisȱnotȱassignedȱtoȱ anyȱvariable.ȱ Useȱtheȱemptyȱstatement.ȱ ȱ if( condition ) ; else { statements }
ȱ Equivalently,ȱyouȱcanȱinvertȱtheȱconditionȱtoȱomitȱtheȱemptyȱthenȱclause.ȱ ȱ if( ! ( condition ) ){ statements }
4.9
Thereȱ areȱ noȱ breakȱ statements,ȱ soȱ bothȱ messagesȱ areȱ printedȱ forȱ eachȱ evenȱ number.ȱ ȱ odd
Download at http://www.pin5i.com/
Appendix Selected Problem Solutionsȱ
568ȱ ȱ
ȱ
4.10
even odd odd even odd
Itȱ isȱ easierȱ toȱ startȱ withȱ theȱ mostȱ specialȱ caseȱ andȱ workȱ yourȱ wayȱ backȱ toȱ theȱ moreȱgeneralȱcases.ȱ ȱ if( year % 400 == 0 ) leap_year = 1; else if( year % 100 == 0 ) leap_year = 0; else if( year % 4 == 0 ) leap_year = 1; else leap_year = 0;
ȱ ȱ ȱ
Chapter 4 ȱ 4.1
Programming Exercises FloatingȬpointȱ variablesȱ mustȱ beȱ used,ȱ andȱ theȱ programȱ shouldȱ checkȱ forȱ negativeȱinputs.ȱ
ȱ ȱ ȱ ȱ /* ** Compute the square root of a number. */ #include #include int main() { float new_guess; float last_guess; float number; /* ** Prompt for and read the data, then check it. */ printf( "Enter a number: " ); scanf( "%f", &number ); if( number < 0 ){ printf( "Cannot compute the square root of a " "negative number!\n" );
ȱ Solutionȱ4.1ȱ ȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continuedȱ...ȱ
Download at http://www.pin5i.com/
Chapter 4 Programming Exercisesȱ
569
ȱ return EXIT_FAILURE; } /* ** Compute approximations to the square root until they ** don't change any more. */ new_guess = 1; do { last_guess = new_guess; new_guess = ( last_guess + number / last_guess ) / 2; printf( "%.15e\n", new_guess ); } while( new_guess != last_guess ); /* ** Print results. */ printf( "Square root of %g is %g\n", number, new_guess ); return EXIT_SUCCESS; }
ȱ Solutionȱ4.1ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ sqrt.cȱ ȱ ȱ ȱ 4.4 Theȱassignmentȱofȱsrcȱtoȱdstȱcouldȱbeȱembeddedȱwithinȱtheȱifȱstatement.ȱ ȱ ȱ ȱ ȱ /* ** Copy exactly N characters from the string in src to the dst ** array (padding with NULs if needed). */ void copy_n( char dst[], char src[], int n ) { int dst_index, src_index; src_index = 0; for( dst_index = 0; dst_index < n; dst_index += 1 ){ dst[dst_index] = src[src_index]; if( src[src_index] != 0 ) src_index += 1; } }
ȱ Solutionȱ4.4ȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱcopy_n.cȱ
Download at http://www.pin5i.com/
Appendix Selected Problem Solutionsȱ
570ȱ ȱ
Chapter 5 ȱ 5.2
Questions Trickȱ question.ȱ Theȱ obviousȱ answerȱ isȱ -10(2 - 3 * 4),ȱ butȱ inȱ factȱ itȱ isȱ implementationȱ dependent.ȱ Theȱ multiplicationȱ mustȱ beȱ completedȱ beforeȱ theȱ addition,ȱbutȱthereȱisnȇtȱaȱruleȱmatȱdeterminesȱtheȱorderȱinȱwhichȱtheȱfunctionȱ callsȱareȱdone.ȱThus,ȱtheȱanswerȱcouldȱbeȱanyȱofȱtheȱfollowing:ȱ ȱ -10 ( 2 – 3 * 4 ) or ( 2 – 4 * 3 ) -5 ( 3 – 2 * 4 ) or ( 3 – 4 * 2 ) -2 ( 4 – 2 * 3 ) or ( 4 – 3 * 2 )
5.4
Notȱ theyȱ eachȱ doȱ preciselyȱ theȱ sameȱ work.ȱ Ifȱ youȱ wantȱ toȱ getȱ picky,ȱ theȱ ifȱ versionȱmightȱpossiblyȱbeȱaȱtadȱlongerȱbecauseȱitȱhasȱtwoȱinstructionsȱtoȱstoreȱ intoȱi.ȱHowever,ȱonlyȱoneȱofȱthemȱwillȱbeȱexecuted,ȱsoȱthereȱisnȇtȱanyȱdifferenceȱ inȱspeed.ȱ
5.6
Theȱ ()ȱ operatorȱ doesnȇtȱ haveȱ anyȱ sideȱ effects,ȱ butȱ theȱ functionȱ beingȱ calledȱ might.ȱ ȱ Operator Side Effect ++, --
Inȱ bothȱ prefixȱ andȱ postfixȱ forms,ȱ theseȱ operatorsȱ modifyȱ theȱ LȬvalueȱonȱwhichȱtheyȱoperate.ȱ
=
Andȱallȱofȱtheȱotherȱassignmentȱoperators:ȱtheyȱallȱmodifyȱtheȱ LȬvalueȱgivenȱasȱtheȱleftȱoperand.ȱ
ȱ ȱ ȱ
Chapter 5 ȱ 5.1
Programming Exercises Theȱpreferredȱwayȱofȱconvertingȱcaseȱisȱwithȱtheȱ tolowerȱlibraryȱfunction,ȱlikeȱ this:ȱ
ȱ ȱ ȱ /* ** Copy the standard input to the standard output, converting ** all uppercase characters to lowercase. Note: This depends ** on the fact that tolower returns its argument unchanged if ** the argument is not an uppercase letter. */ #include #include
ȱ Solutionȱ5.1aȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
Chapter 5 Programming Exercisesȱ
571
ȱ ȱ int main( void ) { int ch; while( (ch = getchar()) != EOF ) putchar( tolower( ch ) ); }
ȱ Solutionȱ5.1aȱȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ Butȱweȱhavenȇtȱdiscussedȱthisȱfunctionȱyet,ȱsoȱhereȱisȱanotherȱapproach:ȱ ȱ ȱ ȱ
ȱȱȱȱȱȱȱȱȱuc_lc.cȱ
/* ** Copy the standard input to the standard output, converting ** all uppercase characters to lowercase. */ #include int main( void ) { int ch; while( (ch = getchar()) != EOF ){ if( ch >= 'A' && ch = 3 ){ int i; for( i = len - 2; i > 0; ){ *dst++ = *src++; if( --i > 0 && i % 3 == 0 ) *dst++ = ','; } } else *dst++ = '0'; /* ** Store the decimal point, and then store the remaining ** digits from 'src'. If 'src' had fewer than two digits, ** force in '0's instead. Then NUL terminate 'dst'. */ *dst++ = '.'; *dst++ = len < 2 ? '0' : *src++; *dst++ = len < 1 ? '0' : *src; *dst = 0; }
ȱ Solutionȱ9.15ȱȱ ȱ ȱ ȱ
Chapter 10 ȱ 10.2
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱdollars.cȱ
Questions
Aȱ structureȱ isȱ aȱ scalar.ȱ Likeȱ anyȱ otherȱ scalar,ȱ whenȱ theȱ nameȱ ofȱ aȱ structureȱ isȱ usedȱ asȱ anȱ RȬvalueȱ inȱ anȱ expressionȱ itȱ refersȱ toȱ theȱ valuesȱ storedȱ inȱ theȱ structure.ȱWhenȱusedȱasȱanȱLȬvalue,ȱtheȱnameȱrefersȱtoȱtheȱplaceȱinȱwhichȱ dieȱ structureȱisȱstored.ȱȱWhenȱanȱarrayȱnameȱisȱusedȱasȱanȱRȬvalueȱinȱanȱexpression,ȱ
Download at http://www.pin5i.com/
584ȱ ȱ
Appendix Selected Problem Solutionsȱ
10.7
however,ȱitsȱvalueȱisȱaȱpointerȱtoȱtheȱfirstȱelementȱinȱtheȱarray.ȱBecauseȱitsȱvalueȱ isȱaȱconstantȱpointer,ȱanȱarrayȱnameȱcannotȱbeȱusedȱasȱanȱLȬvalue.ȱ ȱ Oneȱanswerȱcannotȱbeȱdeterminedȱbecauseȱweȱdonȇtȱknowȱwhereȱtheȱcompilerȱ choseȱtoȱstoreȱnp.ȱ ȱ Expression Value nodes 200ȱ nodes.a illegalȱ nodes[3].a 12ȱ nodes[3].c 200ȱ nodes[3].c->a 5ȱ *nodes *nodes.a
{5, nodes+3, NULL}
(*nodes).a nodes->a nodes[3].b->b *nodes[3].b->b &nodes &nodes[3].a &nodes[3].c &nodes[3].c->a &nodes->a np np->a np->c->c->a npp npp->a *npp **npp *npp->a
illegalȱ 5ȱ 5ȱ 248ȱ {18, nodes+12, nodes+1 }
200ȱ 236ȱ 244ȱ 200ȱ 200ȱ 224ȱ 22ȱ 15ȱ 216ȱ illegalȱ 248ȱ {18, nodes+2, nodes+1 }
(*npp)->a &np &np->a &np->c->c->a
illegalȱ 18ȱ donȇtȱknowȱ 224ȱ 212ȱ
ȱ 10.11 xȱ shouldȱ beȱ declaredȱ anȱ integerȱ (orȱ anȱ unsignedȱ integer),ȱ andȱ maskingȱ andȱ shiftingȱ areȱ usedȱ toȱ storeȱ theȱ properȱ values.ȱ Translatingȱ eachȱ statementȱ individuallyȱgivesȱthisȱcode:ȱ x x x x
&= |= &= |=
0x0fff; ( aaa & 0xf ) quantity; if( the_product->export_restricted ){ ... }
ȱ Thisȱexpressionȱisȱusedȱoverȱandȱoverȱandȱneedȱnotȱbeȱrecomputedȱeachȱtime.ȱ Someȱ compilersȱ willȱ doȱ bothȱ ofȱ theseȱ thingsȱ forȱ youȱ automaticallyȱ butȱ someȱ wonȇtȱ
Download at http://www.pin5i.com/
592ȱ ȱ
Appendix Selected Problem Solutionsȱ 13.7
Theȱ soleȱ advantageȱ isȱ soȱ obviousȱ thatȱ itȱmayȱ beȱ hardȱ toȱ thinkȱ of,ȱ andȱ itȱ isȱ theȱ reasonȱtheȱfunctionȱwasȱwrittenȱinȱtheȱfirstȱplace—thisȱfunctionȱmakesȱitȱeasierȱ toȱprocessȱtheȱcommandȱlineȱarguments.ȱEverythingȱelseȱaboutȱthisȱfunctionȱisȱaȱ disadvantage.ȱYouȱcanȱonlyȱprocessȱtheȱargumentsȱinȱtheȱmannerȱsupportedȱbyȱ theȱ function.ȱ Becauseȱ itȱ isȱ notȱ partȱ ofȱ theȱ Standard,ȱ usingȱ getoptȱ reducesȱ theȱ portabilityȱofȱyourȱprogram.ȱ
ȱ 13.11 First,ȱ someȱ implementationsȱ putȱ stringȱ literalsȱ intoȱ memoryȱ thatȱ cannotȱ beȱ modified.ȱ Attemptingȱ toȱ overwriteȱ suchȱ aȱ literalȱ willȱ terminateȱ theȱ program.ȱ Second,ȱ someȱ implementationsȱ willȱ onlyȱ storeȱ oneȱ copyȱ ofȱ stringȱ literalsȱ thatȱ areȱ usedȱ moreȱ thanȱ onceȱ inȱ aȱ program.ȱ Modifyingȱ oneȱ ofȱ theseȱ literalsȱ willȱ changeȱ theȱ valueȱ ofȱ allȱ ofȱ them,ȱ makingȱ debuggingȱ difficult.ȱ Forȱ example,ȱ theȱ statementȱ ȱ printf( "Hello\n" );
ȱ willȱactuallyȱprintȱBye!ȱifȱtheȱstatementȱ ȱ strcpy( "Hello\n", "Bye!\n" );
ȱ wereȱexecutedȱfirst.ȱ ȱ ȱ ȱ
Chapter 13 ȱ 13.1
Programming Exercises
Thisȱ problemȱ wasȱ givenȱ inȱ Chapterȱ 9ȱ butȱ withoutȱ theȱ restrictionȱ aboutȱ ifȱ statements.ȱTheȱintentȱofȱtheȱrestrictionȱisȱtoȱgetȱyouȱtoȱthinkȱaboutȱalternativeȱ implementations.ȱ Theȱ functionȱ is_not_print,ȱ whichȱ negatesȱ theȱ resultȱ ofȱ isprint,ȱ avoidsȱ theȱ needȱ forȱ aȱ specialȱ caseȱ inȱ theȱ mainȱ loop.ȱ Toȱ improveȱ thisȱ program,ȱ rewriteȱ itȱ withȱ anȱ arrayȱ ofȱ structures,ȱ whereȱ eachȱ elementȱ holdsȱ theȱ functionȱpointer,ȱlabel,ȱandȱcountȱforȱoneȱcategory.ȱ
ȱ ȱ ȱ /* ** Compute the percentage of characters read from the standard ** input that are in each of several character categories. */ #include #include #include
ȱ Solutionȱ13.1ȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
Chapter 13 Programming Exercisesȱ
593
ȱ ȱ /* ** Define a function to compute whether a character is not ** printable; this eliminates a special case for this ** category in the code below. */ int is_not_print( int ch ) { return !isprint( ch ); } /* ** Jump table of classification functions for each category. */ static int (*test_func[])( int ) = { iscntrl, isspace, isdigit, islower, isupper, ispunct, is_not_print }; #define N_CATEGORIES \ ( sizeof( test_func ) / sizeof( test_func[ 0 ] ) ) /* ** */ char
The name of each of the character categories. *label[] = { "control", "whitespace", "digit", "lower case", "upper case", "punctuation", "non-printable"
}; /* ** ** */ int int
Number of characters seen in each category so far, and total # of characters. count[ N_CATEGORIES ]; total;
main() { int int
ch; category;
ȱ Solutionȱ13.1ȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
594ȱ ȱ
Appendix Selected Problem Solutionsȱ ȱ /* ** Read and process each character */ while( (ch = getchar()) != EOF ){ total += 1; /* ** Call each of the test functions with this ** character; if true, increment the associated ** counter. */ for( category = 0; category < N_CATEGORIES; category += 1 ){ if( test_func[ category ]( ch ) ) count[ category ] += 1; } } /* ** Print the results. */ if( total == 0 ){ printf( "No characters in the input!\n" ); } else { for( category = 0; category < N_CATEGORIES; category += 1 ){ printf( "%3.0f%% %s characters\n", count[ category ] * 100.0 / total, label[ category ] ); } } return EXIT_SUCCESS;
}
ȱ Solutionȱ13.1ȱȱ ȱ ȱ ȱ
Chapter 14 ȱ 14.1
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱchar_cat.cȱ
Questions
Theȱfileȱnameȱandȱcurrentȱlineȱmightȱbeȱhandyȱwhenȱprintedȱinȱerrorȱmessages,ȱ particularlyȱ inȱ theȱ earlyȱ stagesȱ ofȱ debugging.ȱ Inȱ fact,ȱ theȱ assertȱ macroȱ usesȱ themȱforȱthisȱpurpose.ȱ__DATE__ȱandȱ__TIME__ȱmightȱbeȱusedȱtoȱcompileȱversionȱ informationȱintoȱaȱprogram.ȱȱFinally,ȱ __STDC__ȱmightȱbeȱusedȱwithȱconditionalȱ compilationȱ toȱ selectȱ betweenȱ ANSIȱ andȱ preȬANSIȱ constructsȱ inȱ sourceȱ codeȱ thatȱmustȱbeȱprocessedȱbyȱbothȱtypesȱofȱcompilers.ȱ ȱ ȱ
Download at http://www.pin5i.com/
Chapter 14 Programming Exercisesȱ
595
ȱ 14.6
ȱ 14.7
Itȱ isȱ impossibleȱ toȱ determineȱ fromȱ theȱ codeȱ thatȱ wasȱ given.ȱ Ifȱ processȱ isȱ implementedȱ asȱ aȱ macroȱ andȱ evaluatesȱ itsȱ argumentȱ moreȱ thanȱ once,ȱ theȱ sideȱ effectȱofȱincrementingȱtheȱsubscriptȱwillȱlikelyȱcauseȱtheȱresultȱtoȱbeȱincorrect.ȱ Thereȱareȱseveralȱthingsȱwrongȱwithȱthisȱcode,ȱsomeȱofȱwhichȱareȱratherȱsubtle.ȱ Theȱ majorȱ problemȱ isȱ thatȱ theȱ macroȱ dependsȱ onȱ itsȱ argumentȱ havingȱ theȱ sideȱ effectȱofȱincrementingȱtheȱarrayȱsubscript.ȱThisȱdependencyȱisȱveryȱdangerous,ȱ andȱisȱmadeȱworseȱbyȱtheȱfactȱthatȱtheȱnameȱofȱtheȱmacroȱdoesnȇtȱindicateȱwhatȱ itȱ isȱ reallyȱ doingȱ (whichȱ isȱ theȱ secondȱ problem).ȱ Supposeȱ theȱ loopȱ isȱ laterȱ rewrittenȱlikeȱthis:ȱ ȱ for( i = 0; i < SIZE; i += 1 ) sum += SUM( array[ i ] );
ȱ Thoughȱitȱlooksȱequivalent,ȱtheȱprogramȱnowȱfails.ȱTheȱfinalȱproblem:ȱBecauseȱ theȱmacroȱalwaysȱaccessesȱtwoȱelementsȱinȱtheȱarray,ȱtheȱprogramȱfailsȱifȱSIZEȱisȱ anȱoddȱvalue.ȱ ȱ ȱ ȱ
Chapter 14 ȱ 14.1
Programming Exercises
Theȱ onlyȱ trickyȱ thingȱ aboutȱ thisȱ problemȱ isȱ theȱ factȱ thatȱ bothȱ optionsȱ mayȱ beȱ selected.ȱThisȱpossibilityȱrulesȱoutȱtheȱuseȱofȱ #elifȱtoȱhelpȱdetermineȱifȱneitherȱ oneȱwasȱdefined.ȱ
ȱ ȱ ȱ /* ** Print the indicated ledger in whichever style(s) is ** indicated by the symbols that are defined. */ void print_ledger( int x ) { #ifdef OPTION_LONG # define OK 1 print_ledger_long( x ); #endif #ifdef OPTION_DETAILED # define OK 1 print_ledger_detailed( x ); #endif
ȱ Solutionȱ14.1ȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
596ȱ ȱ
Appendix Selected Problem Solutionsȱ
ȱ #ifndef OK print_ledger_default( x ); #endif }
ȱ Solutionȱ14.1ȱȱ ȱ ȱ ȱ
Chapter 15 ȱ 15.1
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱprt_ldgr.cȱ
Questions
Ifȱtheȱopenȱfailedȱforȱanyȱreason,ȱtheȱvalueȱreturnedȱwillȱbeȱNULL.ȱWhenȱthisȱ valueȱ isȱ passedȱ toȱ anyȱ subsequentȱ I/Oȱ function,ȱ thatȱ functionȱ willȱ fail.ȱ Itȱ dependsȱ onȱ theȱ implementationȱ whetherȱ orȱ notȱ theȱ programȱ willȱ abort.ȱ Ifȱ itȱ doesnȇt,ȱ thenȱ theȱ I/Oȱ operationȱ mayȱ haveȱ modifiedȱ theȱ contentsȱ ofȱ someȱ unpredictableȱlocationsȱinȱmemory.ȱ
15.2
Itȱ willȱ failȱ becauseȱ theȱ FILEȱ structureȱ youȱ areȱ tryingȱ toȱ useȱ hasȱ neverȱ beenȱ initializedȱ properly.ȱ Theȱ contentsȱ ofȱ unpredictableȱ memoryȱ locationsȱ mayȱ beȱ changedȱinȱtheȱattempt.ȱ
15.4
Differentȱoperatingȱsystemsȱprovideȱvariousȱmechanismsȱtoȱdetectȱredirection,ȱ butȱ usuallyȱ theȱ programȱ doesȱ notȱ needȱ toȱ knowȱ whetherȱ itsȱ inputȱ isȱ comingȱ fromȱ aȱ fileȱ orȱ fromȱ aȱ keyboard.ȱ Theȱ operatingȱ systemȱ takesȱ careȱ ofȱ handlingȱ mostȱofȱtheȱdeviceȬindependentȱaspectsȱofȱinputȱoperations,ȱandȱtheȱlibraryȱI/Oȱ functionsȱtakeȱcareȱofȱtheȱrest.ȱForȱmostȱapplications,ȱtheȱprogramȱcanȱreadȱtheȱ standardȱinputȱinȱtheȱsameȱwayȱnoȱmatterȱwhereȱtheȱinputȱisȱactuallyȱcomingȱ from.ȱ
15.16 Ifȱtheȱvalueȱisȱ1.4049,ȱtheȱ%.3fȱcodeȱwillȱcauseȱtheȱtrailingȱ4ȱtoȱbeȱroundedȱtoȱaȱ5,ȱ butȱ withȱ theȱ %.2fȱ codeȱ theȱ trailingȱ 0ȱ isȱ notȱ roundedȱ upȱ becauseȱ theȱ firstȱ digitȱ thatȱisȱtruncatedȱisȱaȱ4.ȱ ȱ ȱ ȱ
Chapter 15 ȱ 15.2
ȱ
Programming Exercises
Theȱ assumptionȱ thatȱ theȱ inputȱ linesȱ areȱ restrictedȱ inȱ lengthȱ simplifiesȱ mattersȱ greatly.ȱIfȱgetsȱisȱused,ȱtheȱbufferȱmustȱbeȱatȱleastȱ81ȱbytesȱtoȱholdȱ80ȱcharactersȱ ofȱ dataȱ plusȱ theȱ terminatingȱ null.ȱ Ifȱ fgetsȱ isȱ used,ȱ itȱ mustȱ beȱ atȱ leastȱ 82ȱ bytesȱ longȱbecauseȱtheȱnewlineȱisȱalsoȱstored.ȱ
Download at http://www.pin5i.com/
Chapter 15 Programming Exercisesȱ
597
ȱ ȱ /* ** Copy standard input to standard output, one line ** at a time. Lines must be 80 data bytes or shorter. */ #include #define
BUFSIZE
81
main() { char
buf[BUFSIZE];
/* 80 data bytes + the null byte */
while( gets( buf ) != NULL ) puts( buf ); return EXIT_SUCCESS; }
ȱ Solutionȱ15.2ȱȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱȱȱprog2.cȱ ȱ ȱ ȱ 15.9 Theȱrestrictionȱthatȱtheȱstringȱcannotȱcontainȱnewlinesȱmeansȱthatȱtheȱprogramȱ canȱ readȱ dataȱ fromȱ theȱ fileȱ aȱ lineȱ atȱ aȱ time.ȱ Thereȱ isȱ noȱ needȱ toȱ tryȱ toȱ matchȱ stringsȱ thatȱ crossȱ lineȱ boundaries.ȱ Thisȱ restrictionȱ meansȱ thatȱ strstrȱ canȱ beȱ usedȱ forȱ searchingȱ theȱ lines.ȱ Theȱ restrictionȱ onȱ theȱ lengthȱ ofȱ theȱ inputȱ linesȱ simplifiesȱtheȱsolution.ȱTheȱlengthȱlimitationȱcouldȱbeȱremovedȱwithȱaȱdynamiȬ callyȱallocatedȱbufferȱthatȱisȱlengthenedȱwhenȱanȱinputȱlineȱisȱfoundȱthatȱdoesȱ notȱcompletelyȱfit.ȱTheȱmajorityȱofȱtheȱprogramȱdealsȱwithȱgettingȱtheȱfilenamesȱ andȱopeningȱfiles.ȱ ȱ ȱ ȱ /* ** Find and print all of the lines in the named files that ** contain the given string. ** ** Usage: ** fgrep string file [ file ... ] */ #include #include #include #define
BUFFER_SIZE 512
ȱ Solutionȱ15.9ȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
598ȱ ȱ
Appendix Selected Problem Solutionsȱ
ȱ void search( char *filename, FILE *stream, char *string ) { char buffer[ BUFFER_SIZE ]; while( fgets( buffer, BUFFER_SIZE, stream ) != NULL ){ if( strstr( buffer, string ) != NULL ){ if( filename != NULL ) printf( "%s:", filename ); fputs( buffer, stdout ); } } } int main( int ac, char **av ) { char *string; if( ac 1 ) srand( atoi( av[ 1 ] ) ); last_x = rand(); /* ** Run the tests. */ for( i = 0; i < 10000; i += 1 ){ x = rand(); CHECK( 2, frequency2, cycle2 ); CHECK( 3, frequency3, cycle3 ); CHECK( 4, frequency4, cycle4 ); CHECK( 5, frequency5, cycle5 ); CHECK( 6, frequency6, cycle6 ); CHECK( 7, frequency7, cycle7 ); CHECK( 8, frequency8, cycle8 ); CHECK( 9, frequency9, cycle9 ); CHECK( 10, frequency10, cycle10 ); last_x = x; } /* ** Print */ PRINT_F( PRINT_F( PRINT_F( PRINT_F( PRINT_F( PRINT_F(
ȱ Solutionȱ16.7ȱȱ ȱ ȱ
the results. 2, 3, 4, 5, 6, 7,
frequency2 frequency3 frequency4 frequency5 frequency6 frequency7
ȱ
ȱ
); ); ); ); ); );
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continuedȱ...ȱ
Download at http://www.pin5i.com/
Chapter 17 Questionsȱ
603
ȱ ȱ PRINT_F( 8, frequency8 ); PRINT_F( 9, frequency9 ); PRINT_F( 10, frequency10 ); PRINT_C( PRINT_C( PRINT_C( PRINT_C( PRINT_C( PRINT_C( PRINT_C( PRINT_C( PRINT_C(
2, cycle2 ); 3, cycle3 ); 4, cycle4 ); 5, cycle5 ); 6, cycle6 ); 7, cycle7 ); 8, cycle8 ); 9, cycle9 ); 10, cycle10 );
return EXIT_SUCCESS; }
ȱ Solutionȱ16.7ȱȱ ȱ ȱ ȱ ȱ
Chapter 17 ȱ 17.3
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱtestrand.cȱ
Questions
Theȱ traditionalȱ andȱ theȱ alternateȱ interfaceȱ canȱ easilyȱ coexist.ȱ topȱ returnsȱ theȱ valueȱ onȱ theȱ topȱ ofȱ theȱ stackȱ withoutȱ removingȱ it,ȱ andȱ popȱ removesȱ theȱ valueȱ andȱ returnsȱ it.ȱ Theȱ clientȱ whoȱ wantsȱ theȱ traditionalȱ behaviorȱ usesȱ popȱ inȱ theȱ traditionalȱ manner.ȱ Theȱ alternateȱ interfaceȱ isȱ obtainedȱ byȱ callingȱ topȱ andȱ ignoringȱtheȱvalueȱthatȱpopȱreturns.ȱ
17.7
Becauseȱ eachȱ wasȱ allocatedȱ individuallyȱ usingȱ malloc,ȱ poppingȱ themȱ oneȱ byȱ oneȱ ensuresȱ thatȱ eachȱ isȱ freed.ȱ Theȱ codeȱ toȱ freeȱ themȱ alreadyȱ existsȱ inȱ pop,ȱ soȱ callingȱitȱisȱbetterȱthanȱduplicatingȱtheȱcode.ȱ
17.9
Considerȱthatȱanȱarrayȱofȱfiveȱelementsȱcanȱbeȱinȱsixȱdistinctȱstates:ȱitȱmayȱbeȱ empty,ȱorȱitȱmayȱcontainȱone,ȱtwo,ȱthree,ȱfour,ȱorȱfiveȱvalues.ȱButȱfrontȱandȱ rearȱmustȱalwaysȱreferȱtoȱoneȱofȱtheȱfiveȱelementsȱinȱtheȱarray.ȱSoȱforȱanyȱgivenȱ valueȱofȱfront,ȱthereȱareȱonlyȱfiveȱdistinctȱstatesȱforȱrear;ȱitȱcanȱbeȱequalȱtoȱ front,ȱfront + 1,ȱfront + 2,ȱfront + 3,ȱorȱfront + 4ȱ(rememberȱthatȱȱȱȱȱȱȱȱȱ front + 5ȱisȱreallyȱfrontȱbecauseȱofȱtheȱwraparound).ȱItȱisȱnotȱpossibleȱtoȱ representȱsixȱdistinctȱstatesȱwithȱvariablesȱthatȱcanȱonlyȱattainȱfiveȱdistinctȱ states.ȱ
Download at http://www.pin5i.com/
Appendix Selected Problem Solutionsȱ
604ȱ ȱ
17.12 Assumingȱyouȱhadȱaȱpointerȱtoȱtheȱrearȱofȱtheȱlist,ȱaȱsinglyȱlinkedȱlistȱwouldȱbeȱ fine.ȱ Theȱ queueȱ isȱ neverȱ traversedȱ backwards,ȱ soȱ theȱ extraȱ linkȱ ofȱ aȱ doublyȱ linkedȱlistȱhasȱnoȱadvantage.ȱ ȱ 17.18 Anȱ inȬorderȱ traversalȱ doesȱ ascendingȱ order.ȱ Thereȱ isnȇtȱ aȱ predefinedȱ traversalȱ thatȱ givesȱ descendingȱ order,ȱ thoughȱ modifyingȱ theȱ inȬorderȱ traversalȱ toȱ visitȱ theȱrightȱsubtreeȱbeforeȱtheȱleftȱsubtreeȱwouldȱdoȱtheȱjob.ȱ ȱ ȱ ȱ
Chapter 17 ȱ 17.3
Programming Exercises
Thisȱ conversionȱ isȱ similarȱ toȱ theȱ linkedȱ stack,ȱ butȱ whenȱ theȱ lastȱ valueȱ isȱ removed,ȱtheȱrearȱpointerȱmustȱalsoȱbeȱsetȱNULL.ȱ
ȱ ȱ ȱ /* ** A queue implemented with a linked list. ** limit. */ #include "queue.h" #include #include
This queue has no size
/* ** Define a structure to hold one value. ** point to the next value on the queue. */ typedef struct QUEUE_NODE { QUEUE_TYPE value; struct QUEUE_NODE *next; } QueueNode;
The link field will
/* ** Pointers to the first and the last nodes on the queue. */ static QueueNode *front; static QueueNode *rear; /* ** destroy_queue */ void destroy_queue( void ) {
ȱ Solutionȱ17.3ȱȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
Chapter 17 Programming Exercisesȱ
605
ȱ ȱ while( !is_empty() ) delete(); } /* ** insert */ void insert( QUEUE_TYPE value ) { QueueNode *new_node; /* ** Allocate a new node, and fill in its fields. */ new_node = (QueueNode *)malloc( sizeof( QueueNode ) ); assert( new_node != NULL ); new_node->value = value; new_node->next = NULL; /* ** Insert it at the end of the queue. */ if( rear == NULL ){ front = new_node; } else { rear->next = new_node; } rear = new_node; } /* ** delete */ void delete( void ) { QueueNode
*next_node;
/* ** Remove a node from the front of the queue. ** last node, set rear to NULL too. */ assert( !is_empty() ); next_node = front->next; free( front ); front = next_node; if( front == NULL ) rear = NULL;
If this is the
}
ȱ Solutionȱ17.3ȱȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
Appendix Selected Problem Solutionsȱ
606ȱ ȱ ȱ
/* ** first */ QUEUE_TYPE first( void ) { assert( !is_empty() ); return front->value; } /* ** is_empty */ int is_empty( void ) { return front == NULL; } /* ** is_full */ int is_full( void ) { return 0; }
ȱ Solutionȱ17.3ȱȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱȱȱȱl_queue.cȱ ȱ ȱ ȱ 17.6 Ifȱtheȱqueueȱmoduleȱisȱused,ȱtheȱnameȱclashesȱwillȱhaveȱtoȱbeȱresolved.ȱ ȱ ȱ ȱ /* ** Do a breadth_first_traversal of an arrayed binary search tree. */ void breadth_first_traversal( void (*callback)( TREE_TYPE value ) ) { int current; int child; /* ** Insert the root node into the queue. */ queue_insert( 1 );
ȱ Solutionȱ17.6ȱȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continuedȱ...ȱ
Download at http://www.pin5i.com/
Chapter 18 Programming Exercisesȱ
607
ȱ ȱ /* ** While the queue is not empty... */ while( !is_queue_empty() ){ /* ** Take the first value off the queue and process it */ current = queue_first(); queue_delete(); callback( tree[ current ] ); /* ** Add the children of the node to the queue. */ child = left_child( current ); if( child < ARRAY_SIZE && tree[ child ] != 0 ) queue_insert( child ); child = left_child( current ); if( child < ARRAY_SIZE && tree[ child ] != 0 ) queue_insert( child ); } }
ȱ Solutionȱ17.6ȱȱ ȱ ȱ ȱ
Chapter 18 ȱ 18.5
18.6
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱbreadth.cȱ
Questions
Thisȱideaȱsoundsȱgreat,ȱbutȱitȱcannotȱbeȱimplemented.ȱTheȱregisterȱkeywordȱisȱ optionalȱinȱtheȱfunctionȇsȱprototype,ȱsoȱthereȱisnȇtȱaȱreliableȱwayȱthatȱtheȱcallingȱ functionȱcanȱtellȱwhichȱ(ifȱany)ȱargumentsȱareȱsoȱdeclared.ȱ ȱ No,ȱ itȱ isȱ notȱ possible;ȱ onlyȱ theȱ callingȱ functionȱ knowsȱ howȱ manyȱ argumentsȱ wereȱ actuallyȱ pushedȱ onȱ theȱ stack.ȱ Ifȱ anȱ argumentȱ countȱ wereȱ pushed,ȱ however,ȱ thenȱ theȱ calledȱ functionȱ couldȱ removeȱ theȱ arguments.ȱ Itȱ wouldȱ firstȱ haveȱpopȱtheȱreturnȱaddressȱandȱsaveȱit,ȱthough.ȱ
ȱ ȱ ȱ
Chapter 18 ȱ 18.7
Programming Exercises
Theȱanswerȱactuallyȱdependsȱonȱtheȱspecificȱenvironment,ȱbutȱhereȱisȱaȱsolutionȱ forȱtheȱenvironmentȱthatȱwasȱdiscussedȱinȱthisȱchapter.ȱTheȱuserȱmustȱprovideȱ theȱ actualȱ typeȱ ofȱ theȱ argumentȱ afterȱ itȱ undergoesȱ theȱ standardȱ typeȱ conversions,ȱjustȱasȱwithȱtheȱrealȱstdarg.hȱmacros.ȱ
Download at http://www.pin5i.com/
Appendix Selected Problem Solutionsȱ
608ȱ ȱ ȱ
/* ** Replacement for the library stdarg.h macros. */ /* ** va_list ** Define the type for a variable that will hold a pointer to ** the variable portion of the argument list. char * is used ** because arithmetic on them is not scaled. */ typedef char *va_list; /* ** va_start ** A macro to initialize a va_list variable to point to the ** first of the variable arguments on the stack. */ #define va_start(arg_ptr,arg) arg_ptr = (char *)&arg + sizeof( arg ) /* ** va_arg ** A macro that returns the value of the next variable argument ** on the stack; it also increments arg_ptr to the next ** argument. */ #define va_arg(arg_ptr,type) *((type *)arg_ptr)++ /* ** va_end ** Called after the last access to variable arguments; nothing ** needs to be done in this environment. */ #define va_end(arg_ptr)
ȱ Solutionȱ18.3ȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
mystdarg.hȱ
View more...
Comments