Uploaded by tojes70645

kupdf.net kenneth-reek-pointers-on-c-

advertisement
orced version 1.0, by vivisimo, and posted in http://library.nu
last modified: 2011.06.05
1
A Quick Start
1.1 Introduction
Itȱisȱalwaysȱdifficultȱtoȱstartȱdescribingȱaȱprogrammingȱlanguageȱbecauseȱlittleȱ
detailsȱ doȱ notȱ makeȱ muchȱ senseȱ untilȱ oneȱ knowsȱ enoughȱ toȱ understandȱ theȱ Ȉbigȱ
picture.ȈȱInȱthisȱchapter,ȱIȱtryȱtoȱgiveȱyouȱaȱglimpseȱofȱtheȱbigȱpictureȱbyȱlookingȱatȱaȱ
sampleȱ programȱ andȱ explainingȱ itsȱ workingsȱ lineȱ byȱ line.ȱ Thisȱ sampleȱ programȱ alsoȱ
showsȱyouȱhowȱfamiliarȱproceduresȱareȱaccomplishedȱinȱC.ȱThisȱinformationȱplusȱtheȱ
otherȱtopicsȱdiscussedȱinȱtheȱchapterȱintroduceȱyouȱtoȱtheȱbasicsȱofȱtheȱCȱlanguageȱsoȱ
thatȱyouȱcanȱbeginȱwritingȱusefulȱprograms.ȱ
ȱ
Theȱ programȱ weȱ dissectȱ readsȱ textȱ fromȱ theȱ standardȱ input,ȱ modifiesȱ it,ȱ andȱ
writesȱitȱtoȱtheȱstandardȱoutput.ȱProgramȱl.lȱfirstȱreadsȱaȱlistȱofȱcolumnȱnumbers.ȱTheseȱ
numbersȱ areȱ pairsȱ andȱ indicateȱ rangesȱ ofȱ columnsȱ inȱ theȱ inputȱ line.ȱ Theȱ listȱ isȱ
terminatedȱ withȱaȱnegativeȱnumber.ȱTheȱremainingȱinputȱlinesȱareȱreadȱandȱprinted,ȱ
thenȱtheȱselectedȱcolumnsȱfromȱtheȱinputȱlinesȱareȱextractedȱandȱprimed.ȱNoteȱthatȱtheȱ
firstȱcolumnȱinȱaȱlineȱisȱnumberȱzero.ȱForȱexample,ȱifȱtheȱinputȱisȱ
ȱ
4 9 12 20 -1
abcdefghijklmnopqrstuvwxyz
Hello there, how are you?
I am fine, thanks.
See you!
Bye
ȱ
thenȱtheȱprogramȱwouldȱproduce:ȱ
ȱ
Original input : abcdefghijklmnopqxstuvwxyz
Rearranged line: efghijmnopqrstu
Download at http://www.pin5i.com/
2ȱ Chapter 1 A Quick Start
Original input :
Rearranged line:
Original input :
Rearranged line:
Original input :
Rearranged line:
Original input :
Rearranged line:
Hello there, how are you?
o ther how are
I am fine, thanks.
fine, thanks.
See you!
you!
Bye
ȱ
Theȱ importantȱ pointȱ aboutȱ thisȱ programȱ isȱ thatȱ itȱ illustratesȱ mostȱ ofȱ theȱ basicȱ
techniquesȱyouȱneedȱtoȱknowȱtoȱbeginȱwritingȱCȱprograms.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
**
**
**
**
**
**
**
**
**
*/
This program reads input lines from standard input and prints
each input line, followed by just some portions of the line, to
the standard output.
The first input is a lint of column numbers, which ends with a
negative number. The column numbers are paired and specify
ranges of columns from the input line that are to be printed.
For example, 0 3 10 12 -1 indicates that only columns 0 through 3
and columns 10 through 12 will be printed.
#include <stdio.h>
#inc1ude <stdlib.h>
#include <string.h>
#define MAX_COLS
#define MAX_INPUT
int
void
20
1000
/* max # of columns to process */
/* max len of input & output lines */
read_column_numbers( int columns[], int max );
rearrange( char *output, char const *input,
int n_columns, int const columns[] );
int
main( void )
{
int
n_columns;
int
columns[MAX_COLS];
char input[MAX_INPUT];
char output[MAX_INPUT];
/* # of columns to process */
/* the columns to process */
/*array for input line */
/*array for output line */
ȱ
Programȱ1.1ȱ Rearrangeȱcharactersȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continue‫ܥ‬ȱ
Download at http://www.pin5i.com/
1.1 Introduction
ȱ
/*
** Read the list of column numbers
*/
n_columns = read_column_numbers( columns, MAX_COLS );
/*
** Read, process and print the remaining lines of input
*/
while( gets(input ) != NULL ){
printf( "Original input : %s\n", input );
rearrange( output, input, n_columns, columns );
printf( "Rearranged line: %s\n", output );
}
return EXIT_SUCCESS;
}
/*
** Read the list of column numbers, ignoring any beyond the specified
** maximum.
*/
int
read_column_numbers( int columns[], int max )
{
int
num = 0;
int
ch;
/*
** Get the numbers, stopping at eof or when a number is < 0.
*/
while( num < max && scanf( "%d", &columns[num] ) == 1
&&columns[num] >= 0 )
num +=1;
/*
** Make sure we have an even number of inputs, as they are
** supposed to be paired.
*/
if( num % 2 != 0 ){
puts( "Last column number is not paired." );
exit( EXIT_FAILURE );
}
/*
** Discard the rest of the line that contained the final
ȱ
Programȱ1.1ȱ Rearrangeȱcharactersȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continue‫ܥ‬ȱ
3
Download at http://www.pin5i.com/
4ȱ Chapter 1 A Quick Start
** number.
*/
while( (ch = getchar()) != EOF && ch != '\n' )
;
return num;
}
/*
** Process a line of input by
** the indicated columns. The
*/
void
rearrange( char *output, char
in n_columns, int const
{
int
col;
int
output_col;
int
len;
concatenating the characters from
output line is the NUL terminated,
const *input,
columns[] )
/* subscript for columns array */
/* output column counter */
/* length of input line */
len = strlen( input );
output_col = 0;
/*
** Process each pair of column numbers.
*/
for( col = 0; col < n_columns; col += 2 ){
int
nchars = columns[col + 1] – columns[col] + 1;
/*
** If the input line isn't this long or the output
** array is full, we're done
*/
if( columns[col] >= len ||
output_col == MAX_INPUT – 1 )
break;
/*
** If there isn't room in the output array, only copy
** what will fit.
*/
if( output_col + nchars > MAX_INPUT – 1)
nchars = MAX_INPUT – output_col – 1;
/*
ȱ
Programȱ1.1ȱ Rearrangeȱcharactersȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continue‫ܥ‬ȱ
Download at http://www.pin5i.com/
1.1 Introduction
5
** Copy the relevant data.
*/
strncpy( output + output_col, input + columns[col],
nchars );
output_col += nchars;
}
output[output_col] = '\0';
}
Programȱ1.1ȱ Rearrangeȱcharactersȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
rearrang.cȱ
1.1.1 Spacing and Comments
ȱ
Now,ȱlet’sȱtakeȱaȱcloserȱlookȱatȱthisȱprogram.ȱTheȱfirstȱpointȱtoȱnoticeȱisȱtheȱspacingȱofȱ
theȱprogram:ȱtheȱblankȱlinesȱthatȱseparateȱdifferentȱpartsȱfromȱoneȱanother,ȱtheȱuseȱofȱ
tabsȱ toȱ indentȱ statementsȱ toȱ displayȱ theȱ programȱ structure,ȱ andȱ soȱ forth.ȱ Cȱ isȱ aȱ freeȬ
formȱlanguage,ȱsoȱthereȱareȱnoȱrulesȱasȱtoȱhowȱyouȱmustȱwriteȱstatements.ȱHowever,ȱaȱ
littleȱ disciplineȱ whenȱ writingȱ theȱ programȱ paysȱ offȱ laterȱ byȱ makingȱ itȱ easierȱ toȱ readȱ
andȱmodify.ȱMoreȱonȱthisȱissueȱinȱaȱbit.ȱ
Whileȱitȱisȱimportantȱtoȱdisplayȱtheȱstructureȱofȱtheȱprogramȱclearly,ȱitȱisȱevenȱ
moreȱ importantȱ toȱ tellȱ theȱ readerȱ whatȱ theȱ programȱ doesȱ andȱ howȱ itȱ works.ȱ
Commentsȱfulfillȱthisȱroleȱ
ȱ
ȱ
/*
**
**
**
**
**
**
**
**
**
*/
This program reads input lines from the standard input and prints
each input line, followed by just: some portions of the lines, to
the standard output .
The first input; is a list of column numbers, which ends with a
negative number . The column numbers are paired and specify
ranges of columns from the input line that are to be printed.
For example, 0 3 l0 12 —l indicates that only columns 0 through 3
and columns 10 through 12 will be printed
ȱ
ȱ
Thisȱ blockȱ ofȱ textȱ isȱ aȱ comment.ȱ Commentsȱ beginȱ withȱ theȱ /*ȱ charactersȱ andȱ
endȱwithȱtheȱ*/ȱcharacters.ȱTheyȱmayȱappearȱanywhereȱinȱaȱCȱprogramȱinȱwhichȱwhiteȱ
spaceȱ mayȱ appear.ȱ However,ȱ commentsȱ cannotȱ containȱ otherȱ comments,ȱ thatȱ is,ȱ theȱ
Firstȱ*/ȱterminatesȱtheȱcommentȱnoȱmatterȱhowȱmanyȱ/*ȇsȱhaveȱappearedȱearlier.ȱ
Download at http://www.pin5i.com/
6ȱ Chapter 1 A Quick Start
CommentsȱareȱsometimesȱusedȱinȱotherȱlanguagesȱtoȱȈcommentȱoutȈȱcode,ȱthusȱ
removingȱ theȱ codeȱ fromȱ theȱ programȱ withoutȱ physicallyȱ deletingȱ itȱ fromȱ theȱ sourceȱ
file.ȱThisȱpracticeȱisȱaȱbadȱideaȱinȱC,ȱbecauseȱitȱwon’tȱworkȱifȱtheȱcodeȱyou‘reȱtryingȱtoȱ
getȱridȱofȱhasȱanyȱcommentsȱinȱit.ȱAȱbetterȱwayȱtoȱlogicallyȱdeleteȱcodeȱinȱaȱCȱprogramȱ
isȱtheȱ#ifȱdirective.ȱWhenȱusedȱlikeȱthis:ȱ
ȱ
#if 0
ȱ
statementsȱ
#endif
theȱprogramȱstatementsȱbetweenȱtheȱ #ifȱandȱtheȱ #endifȱareȱeffectivelyȱremovedȱfromȱ
theȱprogram.ȱCommentsȱcontainedȱinȱtheȱstatementsȱhaveȱnoȱeffectȱonȱthisȱconstruct,ȱ
thusȱitȱisȱaȱmuchȱsaferȱwayȱtoȱaccomplishȱtheȱobjective.ȱThereȱisȱmuchȱmoreȱthatȱyouȱ
canȱdoȱwithȱthisȱdirective,ȱwhichȱIȱexplainȱfullyȱinȱChapterȱ14.ȱ
ȱ
ȱ
ȱ
1.1.2 Preprocessor Directives
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_COLS
#define MAX_INPUT
TIP
20
1000
/* max # of columns to process */
/* max len of input & output lines */
Theseȱfiveȱlinesȱareȱcalledȱpreprocessorȱdirectives,ȱorȱjustȱdirectives,ȱbecauseȱtheyȱ
areȱinterpretedȱbyȱtheȱpreprocessorȱTheȱpreprocessorȱreadsȱtheȱsourceȱcode,ȱmodifiesȱ
itȱ asȱ indicatedȱ byȱ anyȱ preprocessorȱ directives,ȱ andȱ thenȱ passesȱ theȱ modifiedȱ codeȱ toȱ
theȱcompiler.ȱ
Inȱourȱsampleȱprogram,ȱtheȱpreprocessorȱreplacesȱtheȱfirstȱ #includeȱstatementȱ
withȱtheȱcontentsȱofȱtheȱlibraryȱheaderȱnamedȱ stdio.h;ȱtheȱresultȱisȱtheȱsameȱasȱifȱtheȱ
contentsȱ ofȱ stdio.hȱ hadȱ beenȱ writtenȱ verbatimȱ atȱ thisȱ pointȱ inȱ theȱ sourceȱ file.ȱ Theȱ
secondȱandȱthirdȱdirectivesȱdoȱtheȱsameȱwith stdlib.hȱandȱstring.h.ȱ
Theȱ stdio.hȱheaderȱgivesȱusȱaccessȱtoȱfunctionsȱfromȱtheȱStandardȱI/OȱLibrary,ȱaȱ
collectionȱ ofȱ functionsȱ thatȱ performȱ inputȱ andȱ output,ȱ stdlib.hȱ definesȱ theȱ
EXIT_SUCCESSȱ andȱ EXIT_FAILUREȱ symbols.ȱ Weȱ needȱ string.hȱ toȱ useȱ theȱ stringȱ
manipulationȱfunctions.ȱ
ȱ
Thisȱtechniqueȱisȱalsoȱaȱhandyȱwayȱtoȱmanageȱyourȱdeclarationsȱifȱtheyȱareȱneededȱinȱ
severalȱdifferentȱsourceȱfiles—youȱwriteȱtheȱdeclarationsȱinȱaȱseparateȱfileȱandȱthenȱuseȱ
#includeȱtoȱreadȱthemȱintoȱeachȱrelevantȱsourceȱtile.ȱThusȱthereȱisȱonlyȱoneȱcopyȱofȱtheȱ
declarations;ȱtheyȱareȱnotȱduplicatedȱinȱmanyȱdifferentȱplaces,ȱwhichȱwouldȱbeȱmoreȱ
errorȱproneȱtoȱmaintain.ȱ
Download at http://www.pin5i.com/
1.1 Introduction
TIP
int
void
TIP
7
Theȱ otherȱ directiveȱ isȱ #define,ȱ whichȱ definesȱ theȱ nameȱ MAX_COLSȱ toȱ beȱ theȱ valueȱ 20,ȱ
andȱ MAX_INPUTȱtoȱbeȱtheȱvalueȱ1000.ȱWhereverȱeitherȱnameȱappearsȱlaterȱinȱtheȱsourceȱ
tile,ȱ itȱ isȱ replacedȱ byȱ theȱ appropriateȱ value.ȱ Becauseȱ theyȱ areȱ definedȱ asȱ literalȱ
constants,ȱtheseȱnamesȱcannotȱbeȱusedȱinȱsomeȱplacesȱwhereȱordinaryȱvariablesȱcanȱbeȱ
usedȱ(forȱexample,ȱonȱtheȱleftȱsideȱofȱanȱassignment).ȱMakingȱtheirȱnamesȱuppercaseȱ
servesȱasȱaȱreminderȱthatȱtheyȱareȱnotȱordinaryȱvariables.ȱ #defineȱdirectivesȱareȱusedȱ
forȱtheȱsameȱkindsȱofȱthingsȱasȱsymbolicȱconstantsȱinȱotherȱlanguagesȱandȱforȱtheȱsameȱ
reasons.ȱIfȱweȱlaterȱdecideȱthatȱ20ȱcolumnsȱareȱnotȱenough,ȱweȱcanȱsimplyȱchangeȱtheȱ
definitionȱofȱ MAX_COLS.ȱThereȱisȱnoȱneedȱtoȱhuntȱthroughȱtheȱprogramȱlookingȱforȱ20’sȱ
toȱchangeȱandȱpossiblyȱmissingȱoneȱorȱchangingȱaȱ20ȱthatȱhadȱnothingȱtoȱdoȱwithȱtheȱ
maximumȱnumberȱofȱcolumns.ȱȱ
ȱ
ȱ
read_column_numbers( int columns[], int max );
rearrange( char *output, char const *input,
int n_columns, int const columns[] );
Theseȱ declarationsȱ areȱ calledȱ functionȱ prototypes.ȱ Theyȱ tellȱ theȱ compilerȱ aboutȱ
theȱ characteristicsȱ ofȱ functionsȱ thatȱ areȱ definedȱ laterȱ inȱ theȱ sourceȱ tile.ȱ Theȱ compilerȱ
canȱthenȱcheckȱcallsȱtoȱtheseȱfunctionsȱforȱaccuracy.ȱEachȱprototypeȱbeginsȱwithȱaȱtypeȱ
nameȱthatȱdescribesȱtheȱvalueȱthatȱisȱreturned.ȱTheȱtypeȱnameȱisȱfollowedȱbyȱtheȱnameȱ
ofȱ theȱ function.ȱ Theȱ argumentsȱ expectedȱ byȱ theȱ functionȱ areȱ next,ȱ soȱ
read_column_numbers returnsȱ anȱ integerȱ andȱ takesȱ twoȱ arguments,ȱ anȱ arrayȱ ofȱ
integersȱandȱanȱintegerȱscalar.ȱTheȱargumentȱnamesȱareȱnotȱrequired;ȱIȱgiveȱthemȱhereȱ
toȱserveȱasȱaȱreminderȱofȱwhatȱeachȱargumentȱisȱsupposedȱtoȱbe.ȱ
Theȱ rearrangeȱfunctionȱtakesȱfourȱarguments.ȱTheȱfirstȱandȱsecondȱareȱpointers.ȱ
Aȱ pointerȱ specifiesȱ whereȱ aȱ valueȱ residesȱ inȱ theȱ computer’sȱ memory,ȱ muchȱ likeȱ aȱ
houseȱnumberȱspecifiesȱwhereȱaȱparticularȱfamilyȱresidesȱonȱaȱstreet.ȱPointersȱareȱwhatȱ
giveȱ theȱ Cȱ languageȱ itsȱ powerȱ andȱ areȱ coveredȱ inȱ greatȱ detailȱ startingȱ inȱ Chapterȱ 6.ȱ
Theȱsecondȱandȱfourthȱargumentsȱareȱdeclaredȱ const,ȱwhichȱmeansȱthatȱtheȱfunctionȱ
promisesȱ notȱ toȱ modifyȱ theȱ callerȇsȱ arguments.ȱ Theȱ keywordȱ voidȱ indicatesȱ thatȱ theȱ
functionȱdoesȱnotȱreturnȱanyȱvalueȱatȱall;ȱsuchȱaȱfunctionȱwouldȱbeȱcalledȱaȱprocedureȱinȱ
otherȱlanguages.ȱ
ȱ
Ifȱ theȱ sourceȱ codeȱ forȱ thisȱ programȱ wasȱ containedȱ inȱ severalȱ sourceȱ tiles,ȱ functionȱ
prototypesȱ wouldȱ haveȱ toȱ beȱ writtenȱ inȱ eachȱ tileȱ usingȱ theȱ function.ȱ Puttingȱ theȱ
prototypesȱ inȱ headerȱ filesȱ andȱ usingȱ a #includeȱ toȱ accessȱ themȱ avoidsȱ theȱ
maintenanceȱproblemȱcausedȱbyȱhavingȱmultipleȱcopiesȱofȱtheȱsameȱdeclarations.ȱ
Download at http://www.pin5i.com/
8ȱ Chapter 1 A Quick Start
1.1.3 The Main Function
int
main( void )
{
ȱ
ȱ
Theseȱ linesȱ beginȱ theȱ definitionȱ ofȱ aȱ functionȱ calledȱ main.ȱ Everyȱ Cȱ programȱ
mustȱhaveȱaȱmainȱfunction,ȱbecauseȱthisȱisȱwhereȱexecutionȱbegins.ȱTheȱkeywordȱ intȱ
indicatesȱthatȱtheȱfunctionȱreturnsȱanȱintegerȱvalue;ȱtheȱkeywordȱ voidȱindicatesȱthatȱitȱ
expectsȱ noȱ arguments.ȱ Theȱ bodyȱ ofȱ theȱ functionȱ includesȱ everythingȱ betweenȱ thisȱ
openingȱbraceȱandȱitsȱmatchingȱclosingȱbrace.ȱ
Observeȱhowȱtheȱindentationȱclearlyȱshowsȱwhatȱisȱincludedȱinȱtheȱfunction.ȱ
ȱ
int
int
char
char
n_columns;
columns[MAX_COLS];
input[MAX_INPUT];
output[MAX_INPUT];
/* # of columns to process */
/* the columns to process */
/*array for input line */
/*array for output line */
Theseȱ linesȱ declareȱ fourȱ variables:ȱ anȱ integerȱ scalar,ȱ anȱ arrayȱ ofȱ integers,ȱ andȱ
twoȱarraysȱofȱcharacters.ȱAllȱfourȱofȱtheseȱvariablesȱareȱlocalȱtoȱtheȱmainȱfunction,ȱsoȱ
theyȱ cannotȱ beȱ accessedȱ byȱ nameȱ fromȱ anyȱ otherȱ functions.ȱ Theyȱ can,ȱ ofȱ course,ȱ beȱ
passedȱasȱargumentsȱtoȱotherȱfunctions.ȱ
ȱ
/*
** Read the list of column numbers
*/
n_columns = read_column_numbers( columns, MAX_COLS );
ȱ
Thisȱ statementȱ callsȱ theȱ functionȱ read_column_numbers.ȱ Theȱ arrayȱ columnsȱ andȱ theȱ
constantȱ representedȱ by MAX_COLS (20)ȱ areȱ passedȱ asȱ arguments.ȱ Inȱ C,ȱ arrayȱ
argumentsȱ behaveȱ asȱ thoughȱ theyȱ areȱ passedȱ byȱ reference,ȱ andȱ scalarȱ variablesȱ andȱ
constantsȱareȱpassedȱbyȱvalueȱ(likeȱvarȱparametersȱandȱvalueȱparameters,ȱrespectively,ȱ
inȱPascalȱorȱModula).ȱThus,ȱanyȱchangesȱmadeȱbyȱaȱfunctionȱtoȱaȱscalarȱargumentȱareȱ
lostȱ whenȱ theȱ functionȱ returns;ȱ theȱ functionȱ cannotȱ changeȱ theȱ valueȱ ofȱ theȱ callingȱ
programȇsȱargumentȱinȱthisȱmanner.ȱWhenȱaȱfunctionȱchangesȱtheȱvalueȱofȱanȱelementȱ
ofȱanȱarrayȱargument,ȱhowever,ȱtheȱarrayȱinȱtheȱcallingȱprogramȱisȱactuallyȱmodified.ȱ
ȱ
TheȱruleȱaboutȱhowȱparametersȱareȱpassedȱtoȱCȱfunctionsȱactuallyȱstates:ȱ
ȱ
Allȱargumentsȱtoȱfunctionsȱareȱpassedȱbyȱvalue.ȱ
ȱ
Nevertheless,ȱanȱarrayȱnameȱasȱanȱargumentȱproducesȱtheȱcallȬbyȬreferenceȱbehavior
Download at http://www.pin5i.com/
1.1 Introduction
9
describedȱabove.ȱTheȱreasonȱforȱthisȱapparentȱcontradictionȱbetweenȱtheȱruleȱandȱtheȱ
actualȱbehaviorȱisȱexplainedȱinȱChapterȱ8.ȱ
ȱ
/*
** Read, process and print the remaining lines of input
*/
while( gets(input ) != NULL ){
printf( "Original input : %s\n", input );
rearrange( output, input, n_columns, columns );
printf( "Rearranged line: %s\n", output );
}
return EXIT_SUCCESS;
}
ȱ
ȱ
Theȱcommentȱdescribingȱthisȱpieceȱofȱcodeȱmightȱseemȱunnecessary.ȱHowever,ȱ
theȱ majorȱ expenseȱ ofȱ softwareȱ todayȱ isȱ notȱ writingȱ itȱ butȱ maintainingȱ it.ȱ Theȱ firstȱ
problemȱinȱmodifyingȱaȱpieceȱofȱcodeȱisȱfiguringȱoutȱwhatȱitȱdoes,ȱsoȱanythingȱyouȱcanȱ
putȱinȱourȱcodeȱthatȱmakesȱitȱeasierȱforȱsomeoneȱ(ȱperhapsȱyou!)ȱtoȱunderstandȱitȱlaterȱ
isȱ worthȱ doing.ȱ Beȱ sureȱ toȱ writeȱ accurateȱ commentȱ whenȱ youȱ changeȱ theȱ code.ȱ
Inaccurateȱcommentsȱareȱworseȱthanȱnoneȱatȱall!ȱ
Thisȱpieceȱofȱcodeȱconsistsȱofȱaȱwhileȱloop.ȱInȱC,ȱwhileȱloopsȱoperateȱtheȱsameȱasȱ
theyȱdoȱinȱotherȱlanguages.ȱTheȱexpressionȱisȱtested.ȱIfȱitȱisȱfalse,ȱtheȱbodyȱofȱtheȱloopȱ
isȱ skipped.ȱ Ifȱ theȱ expressionȱ isȱ true,ȱ theȱ bodyȱ ofȱ theȱ loopȱ isȱ executedȱ andȱ theȱ wholeȱ
processȱbeginsȱagain.ȱȱ
Thisȱloopȱrepresentsȱtheȱmainȱlogicȱofȱtheȱprogram.ȱInȱbrief,ȱitȱmeans:ȱ
ȱ
whileȱweȱwereȱableȱtoȱreadȱanotherȱlineȱofȱinputȱ
printȱtheȱinputȱ
rearrangeȱtheȱinput,ȱstoringȱitȱinȱoutputȱ
printȱtheȱoutputȱ
ȱ
Theȱ getsȱ functionȱ readsȱ oneȱ lineȱ ofȱ textȱ fromȱ theȱ standardȱ inputȱ andȱ storesȱ itȱ inȱ theȱ
arrayȱ passedȱ asȱ anȱ argument.ȱ Aȱ lineȱ isȱ aȱ sequenceȱ ofȱ charactersȱ terminatedȱ byȱ aȱ
newlineȱ character;ȱ getsȱ discardsȱ theȱ newlineȱ andȱ storesȱ aȱ NULȱ byteȱ atȱ theȱ endȱ ofȱ theȱ
line 1 .ȱ(Aȱ NULȱbyteȱisȱoneȱwhoseȱbitsȱareȱallȱ 0,ȱwrittenȱasȱaȱcharacterȱconstantȱlikeȱthis:ȱ
'\0'.)ȱ getsȱ thenȱ returnsȱ aȱ valueȱ thatȱ isȱ not NULLȱ toȱ indicateȱ thatȱ aȱ lineȱ was
ȱNULȱisȱtheȱnameȱgivenȱinȱtheȱASCIIȱcharacterȱsetȱtoȱtheȱcharacterȱ'\0',ȱwhoseȱbitsȱareȱallȱzero.ȱNULLȱrefersȱtoȱaȱpointerȱ
whoseȱvalueȱisȱzero.ȱBothȱareȱintegersȱandȱhaveȱtheȱsameȱvalue,ȱsoȱtheyȱcouldȱbeȱusedȱinterchangeably.ȱHowever,ȱitȱisȱworthȱ
usingȱtheȱappropriateȱconstantȱbecauseȱthisȱtellsȱaȱpersonȱreadingȱtheȱprogramȱnotȱonlyȱthatȱyouȱareȱusingȱtheȱvalueȱzero,ȱ
butȱwhatȱyouȱareȱusingȱitȱfor.ȱ
1
Download at http://www.pin5i.com/
10ȱ Chapter 1 A Quick Start
ȱ
successfullyȱread 2 .ȱWhenȱ getsȱisȱ calledȱbutȱthereȱisȱ noȱ moreȱinput,ȱ itȱ returnsȱ NULLȱ toȱ
indicateȱthatȱitȱhasȱreachedȱtheȱendȱofȱtheȱinputȱ(endȱofȱtile).ȱ
DealingȱwithȱcharacterȱstringsȱisȱaȱcommonȱtaskȱinȱCȱprograms.ȱAlthoughȱthereȱ
isȱ noȱ ȈstringȈȱ dataȱ type,ȱ thereȱ isȱ aȱ conventionȱ forȱ characterȱ stringsȱ thatȱ isȱ observedȱ
throughoutȱtheȱlanguage:ȱaȱstringȱisȱaȱsequenceȱofȱcharactersȱterminatedȱbyȱa NULȱbyte.ȱ
Theȱ NULȱisȱconsideredȱaȱterminatorȱandȱisȱnotȱcountedȱasȱaȱpartȱofȱtheȱstring.ȱAȱstringȱ
literalȱisȱaȱsequenceȱofȱcharactersȱenclosedȱinȱquotationȱmarksȱinȱtheȱsourceȱprogram 3 .ȱ
Forȱexample,ȱtheȱstringȱliteralȱ
ȱ
"Hello"
ȱ
ȱ
ȱ
occupiesȱsixȱbytesȱinȱmemory,ȱwhichȱcontainȱ(inȱorder)ȱH,e,l,l,o,ȱandȱNUL.ȱ
ȱ
Theȱ printfȱfunctionȱperformsȱformattedȱoutput.ȱModulaȱandȱPascalȱusersȱwillȱ
beȱ delightedȱ withȱ theȱ simplicityȱ ofȱ formattedȱ outputȱ inȱ C.ȱ printfȱ takesȱ multipleȱ
arguments;ȱ theȱ firstȱ isȱ aȱ characterȱ stringȱ thatȱ describesȱ theȱ formatȱ ofȱ theȱ output,ȱ andȱ
theȱrestȱareȱtheȱvaluesȱtoȱbeȱprinted.ȱTheȱformatȱisȱoftenȱgivenȱasȱaȱstringȱliteral.ȱ
Theȱ formatȱ stringȱ containsȱ formatȱ designatorsȱ interspersedȱ withȱ ordinaryȱ
characters.ȱ Theȱ ordinaryȱ charactersȱ areȱ printedȱ verbatim,ȱ butȱeachȱ formatȱ designatorȱ
causesȱtheȱnextȱargumentȱvalueȱtoȱbeȱprintedȱusingȱtheȱindicatedȱformat.ȱAȱfewȱofȱtheȱ
moreȱusefulȱformatȱdesignatorsȱareȱgivenȱinȱTableȱl.l.ȱIfȱ
ȱ
ȱ
ȱ
Format
Meaning
%d
Printȱanȱintegerȱvalueȱinȱdecimal.ȱ
%o
Printȱanȱintegerȱvalueȱinȱoctal.ȱ
%x
Printȱanȱintegerȱvalueȱinȱhexadecimal.ȱ
%g
PrintȱaȱfloatingȬpointȱvalue.ȱ
%c
Printȱaȱcharacter.ȱ
%s
Printȱaȱcharacterȱstring.ȱ
\n
Printȱaȱnewline.ȱ
ȱ
Tableȱ1.1ȱCommonȱprintfȱformatȱcodesȱ
ȱTheȱsymbolȱNULLȱisȱdefinedȱinȱtheȱheader stdio.h.ȱOnȱtheȱotherȱhand,ȱthereȱisȱnoȱpredefinedȱsymbolȱNUL,ȱsoȱifȱyouȱwishȱ
toȱuseȱitȱinsteadȱofȱtheȱcharacterȱconstantȱ'\0'ȱyouȱmustȱdefineȱitȱyourselfȱ
3ȱ Thisȱ symbolȱisȱ aȱ quotationȱmark:ȱ ",ȱ andȱ thisȱ symbolȱ isȱ anȱ apostrophe:ȱ'.ȱ Theȱ penchantȱ ofȱ computerȱ peopleȱ toȱcallȱthemȱ
Ȉsingleȱ quoteȈȱ andȱ Ȉdoubleȱ quoteȈȱ whenȱ theirȱ existingȱ namesȱ areȱ perfectlyȱ goodȱ seemsȱ unnecessary,ȱ soȱ Iȱ willȱ useȱ theirȱ
everydayȱnames.ȱ
2
Download at http://www.pin5i.com/
1.1 Introduction 11
theȱarrayȱinputȱcontainsȱtheȱstringȱHi friends!,ȱthenȱtheȱstatementȱ
ȱ
printf( "Original input : %s\n", input );
ȱ
willȱproduceȱ
ȱ
Original input : Hi friends!
terminatedȱwithȱaȱnewline.ȱ
Theȱnextȱstatementȱinȱtheȱsampleȱprogramȱcallsȱtheȱrearrangeȱfunction.ȱTheȱlastȱ
threeȱargumentsȱareȱvaluesȱthatȱareȱpassedȱtoȱtheȱfunction,ȱandȱtheȱfirstȱisȱtheȱanswerȱ
thatȱtheȱfunctionȱwillȱconstructȱandȱpassȱbackȱtoȱtheȱmainȱfunction.ȱRememberȱthatȱitȱ
isȱonlyȱpossibleȱtoȱpassȱtheȱanswerȱbackȱthroughȱthisȱargumentȱbecauseȱitȱisȱanȱarray.ȱ
Theȱlastȱcallȱtoȱprintfȱdisplaysȱtheȱresultȱofȱrearrangingȱtheȱline.ȱ
Finally,ȱ whenȱ theȱ loopȱ hasȱ completed,ȱ theȱ mainȱ functionȱ returnsȱ theȱ valueȱ
EXIT_SUCCESS.ȱ Thisȱ valueȱ indicatesȱ toȱ theȱ operatingȱ systemȱ thatȱ theȱ programȱ wasȱ
successful.ȱTheȱclosingȱbraceȱmarksȱtheȱendȱofȱtheȱbodyȱofȱtheȱmainȱfunction.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
1.1.4 The read_column_numbers Function
/*
** Read the list of column numbers, ignoring any beyond the specified
** maximum.
*/
int
read_column_numbers( int columns[], int max )
{
Theseȱlinesȱbeginȱtheȱdefinitionȱofȱtheȱ read_column_numbersȱfunction.ȱNoteȱthatȱ
thisȱdeclarationȱandȱtheȱfunctionȱprototypeȱthatȱappearedȱearlierȱinȱtheȱprogramȱmatchȱ
inȱtheȱnumberȱandȱtypesȱofȱargumentsȱandȱinȱtheȱtypeȱreturnedȱbyȱtheȱfunction.ȱItȱisȱ
anȱerrorȱifȱtheyȱdisagree.ȱ
Thereȱisȱnoȱindicationȱofȱtheȱarrayȱsizeȱinȱtheȱarrayȱparameterȱdeclarationȱtoȱtheȱ
function.ȱThisȱformatȱisȱcorrect,ȱbecauseȱtheȱfunctionȱwillȱgetȱwhateverȱsizeȱarrayȱtheȱ
callingȱ programȱ passedȱ asȱ anȱ argument.ȱ Thisȱ isȱ aȱ greatȱ feature,ȱ asȱ itȱ allowsȱ aȱ singleȱ
functionȱ toȱ manipulateȱ one—dimensiona1ȱ arraysȱ ofȱ anyȱ size.ȱ Theȱ downȱ sideȱ ofȱ thisȱ
featureȱisȱthatȱthereȱisȱnoȱwayȱforȱtheȱfunctionȱtoȱdetermineȱtheȱsizeȱofȱtheȱarray.ȱIfȱthisȱ
informationȱisȱneeded,ȱtheȱvalueȱmustȱbeȱpassedȱasȱaȱseparateȱargument.ȱ
Download at http://www.pin5i.com/
12ȱ Chapter 1 A Quick Start
Whenȱ theȱ read_column_numbersȱ functionȱ isȱ called,ȱ theȱ nameȱ ofȱ oneȱ ofȱ theȱ
argumentsȱ thatȱ isȱ passedȱ happensȱ toȱ matchȱ theȱ nameȱ ofȱ theȱ formalȱ parameterȱ givenȱ
above.ȱ However,ȱ theȱ nameȱ ofȱ theȱ otherȱ argumentȱ doesȱ notȱ matchȱ itsȱ correspondingȱ
parameter.ȱ Asȱ inȱ mostȱ otherȱ languages,ȱ theȱ formalȱ parameterȱ nameȱ andȱ theȱ actualȱ
argumentȱnameȱhaveȱnoȱrelationshipȱtoȱoneȱanother;ȱyouȱcanȱmakeȱthemȱtheȱsameȱifȱ
youȱwish,ȱbutȱitȱisȱnotȱrequired.ȱ
ȱ
int
int
num = 0;
ch;
Twoȱ variablesȱ areȱ declared;ȱ theyȱ willȱ beȱ localȱ toȱ thisȱ function.ȱ Theȱ firstȱ oneȱ isȱ
initializedȱ toȱ zeroȱ inȱ theȱ declaration,ȱ butȱ theȱ secondȱ oneȱ isȱ notȱ initialized.ȱ Moreȱ
precisely,ȱ itsȱ initialȱ valueȱ willȱ beȱ someȱ unpredictableȱ value,ȱ whichȱ isȱ probablyȱ
garbage.ȱTheȱlackȱofȱanȱinitialȱvalueȱisȱnotȱaȱproblemȱinȱthisȱfunctionȱbecauseȱtheȱfirstȱ
thingȱdoneȱwithȱtheȱvariableȱisȱtoȱassignȱitȱaȱvalue.ȱ
ȱ
ȱ
** Get the numbers, stopping at eof or when a number is < 0.
*/
while( num < max && scanf( "%d", &columns[num] ) == 1
&&columns[num] >= 0 )
num +=1;
CAUTION!
4
ȱ
ȱ
Thisȱ secondȱ loopȱ readsȱ inȱ theȱ columnȱ numbers.ȱ Theȱ scanfȱ functionȱ readsȱ
charactersȱfromȱtheȱstandardȱinputȱandȱconvertsȱthemȱaccordingȱtoȱaȱformatȱstring—
sortȱ ofȱ theȱ reverseȱ ofȱ whatȱ printfȱ does.ȱ scanfȱ takesȱ severalȱ arguments,ȱ theȱ firstȱ ofȱ
whichȱ isȱ aȱ formatȱ suingȱ thatȱ describesȱ theȱ typeȱ ofȱ inputȱ thatȱ isȱ expected.ȱ Theȱ
remainingȱargumentsȱareȱvariablesȱintoȱwhichȱtheȱinputȱisȱstored.ȱTheȱvalueȱretunedȱ
byȱ scanfȱisȱtheȱnumberȱofȱvaluesȱthatȱwereȱsuccessfullyȱconvertedȱandȱstoredȱintoȱtheȱ
arguments.ȱ
ȱ
ȱ
Youȱmustȱbeȱcarefulȱwithȱthisȱfunctionȱforȱtwoȱreasons.ȱFirst,ȱbecauseȱofȱtheȱwayȱscanfȱ
isȱimplemented,ȱallȱofȱitsȱscalarȱargumentsȱmustȱhaveȱanȱampersandȱinȱfrontȱofȱthem.ȱ
Forȱ reasonsȱ thatȱ Iȱ makeȱ clearȱ inȱ Chapterȱ 8,ȱ arrayȱ argumentsȱ doȱ notȱ requireȱ anȱ
ampersand 4 .ȱHowever,ȱifȱaȱsubscriptȱisȱusedȱtoȱidentifyȱaȱspecificȱarrayȱelement,ȱthenȱ
anȱ ampersandȱ isȱ required.ȱ Iȱ explainȱ theȱ needȱ forȱ theȱ ampersandsȱ onȱ theȱ scalar
ȱThereȱisȱnoȱharmȱinȱputtingȱanȱampersandȱinȱfrontȱofȱanȱarrayȱnameȱhere,ȱhowever,ȱsoȱyouȱmayȱuseȱoneȱifȱyouȱwish.ȱ
Download at http://www.pin5i.com/
1.1 Introduction 13
CAUTION!
argumentsȱinȱChapterȱ15.ȱForȱnow,ȱjustȱbeȱsureȱtoȱputȱthemȱin.ȱbecauseȱtheȱprogramȱ
willȱsurelyȱfailȱwithoutȱthem.ȱ
ȱ
Theȱsecondȱpitfallȱisȱtheȱformatȱcodes,ȱwhichȱareȱnotȱidenticalȱtoȱthoseȱin printfȱbutȱ
similarȱ enoughȱ toȱ beȱ confusing.ȱ Tableȱ 1.2ȱ informallyȱ describesȱ aȱ fewȱ ofȱ theȱ formatȱ
designatorsȱthatȱyouȱmayȱuseȱwithȱscanf.ȱNoteȱthatȱtheȱfirstȱfiveȱvalues,ȱsoȱtheȱvariableȱ
givenȱasȱtheȱargumentȱmustȱbeȱprecededȱwithȱanȱampersand.ȱWithȱallȱofȱtheseȱformatȱ
codesȱ(exceptȱ %c),ȱwhiteȱspaceȱ(spaces,ȱtabs,ȱnewlines,ȱetc.)ȱinȱtheȱinputȱisȱskippedȱtheȱ
valueȱ isȱ encountered,ȱ andȱ subsequentȱ whiteȱ spaceȱ terminatesȱ theȱ value.ȱ Therefore,ȱ aȱ
characterȱstringȱreadȱwithȱ%sȱcannotȱcontainȱwhiteȱspace.ȱThereȱareȱmanyȱotherȱformatȱ
designators,ȱbutȱtheseȱwillȱbeȱenoughȱforȱourȱcurrentȱneeds.ȱ
Weȱcanȱnowȱexplainȱtheȱexpressionȱ
ȱ
scanf( "%d", &columns[num] )
ȱ
ȱ
Theȱformatȱcodeȱ%dȱindicatesȱthatȱanȱintegerȱvalueȱisȱdesired.ȱCharactersȱareȱreadȱfromȱ
theȱ standardȱ input,ȱ anyȱ leadingȱ whiteȱ spaceȱ foundȱ isȱ skipped.ȱ Thenȱ digitsȱ areȱ
convertedȱ intoȱ anȱ integer,ȱ andȱ theȱ resultȱ isȱ storedȱ inȱ theȱ specifiedȱ arrayȱ element.ȱ Anȱ
ampersandȱisȱrequiredȱinȱfrontȱofȱtheȱargumentȱbecauseȱtheȱsubscriptȱselectsȱaȱsingleȱ
arrayȱelement,ȱwhichȱisȱaȱscalar.ȱ
Theȱtestȱinȱtheȱwhileȱloopȱconsistsȱofȱthreeȱparts.ȱ
ȱ
num < max
ȱ
makesȱ sureȱ thatȱ weȱ doȱ notȱ getȱ tooȱ manyȱ numbersȱ andȱ overflowȱ theȱ array.ȱ scanf
retumsȱtheȱvalueȱoneȱifȱitȱconvertedȱanȱinteger.ȱFinally,ȱ
ȱ
columns[num] >= 0
ȱ
checksȱ thatȱ theȱ valueȱ enteredȱ wasȱ positive.ȱ lfȱ anyȱ ofȱ theseȱ testsȱ areȱ false.ȱ Theȱ loopȱ
stops.ȱ
ȱ
ȱ
Format
Meaning
Type of Variable
%d
int
Readȱanȱintegerȱvalue.ȱ
%ld
long
Readȱaȱlongȱintegerȱvalue.ȱ
float
%f
Readȱaȱrealȱvalue.ȱ
double
%lf
Readȱaȱdoubleȱprecisionȱrealȱvalue.ȱ
char
%c
Readȱaȱcharacter.ȱ
array of char
%s
Readȱaȱcharacterȱstringȱfromȱtheȱinput.ȱ
ȱ
Tableȱ1.2ȱCommonȱscanfȱformatȱcodesȱ
Download at http://www.pin5i.com/
14ȱ Chapter 1 A Quick Start
TIP
TheȱStandardȱdoesȱnotȱrequireȱthatȱCȱcompilersȱcheckȱtheȱvalidityȱofȱarrayȱsubscripts,ȱ
andȱtheȱvastȱmajorityȱofȱcompilersȱdon’t.ȱThus,ȱifȱyouȱneedȱsubscriptȱvalidityȱchecking,ȱ
youȱ mustȱ writeȱ itȱ yourself.ȱ ifȱ theȱ testȱ forȱ num < maxȱ wereȱ notȱ hereȱ andȱ theȱ programȱ
readȱ aȱ fileȱ containingȱ moreȱ thanȱ 20ȱ columnȱ numbers,ȱ theȱ excessȱ valuesȱ wouldȱ beȱ
storedȱ inȱ theȱ memoryȱ locationsȱ thatȱ followȱ theȱ array,ȱ thusȱ destroyingȱ whateverȱ dataȱ
wasȱ formerlyȱ inȱ thoseȱ locations,ȱ whichȱ mightȱ beȱ otherȱ variablesȱ orȱ theȱ functionȇsȱ
returnȱaddress.ȱThereȱareȱotherȱpossibilitiesȱtoo,ȱbutȱtheȱresultȱisȱthatȱtheȱprogramȱwillȱ
probablyȱnotȱperformȱasȱyouȱhadȱintended.ȱ
Theȱ &&ȱ isȱ theȱ Ȉlogicalȱ andȈȱ operator.ȱ Forȱ thisȱ expressionȱ toȱ beȱ true,ȱ theȱ
expressionsȱonȱbothȱsidesȱofȱtheȱ &&ȱmustȱevaluateȱtoȱtrue.ȱHowever,ȱifȱtheȱleftȱsideȱisȱ
false,ȱtheȱrightȱsideȱisȱnotȱevaluatedȱatȱall,ȱbecauseȱtheȱresultȱcanȱonlyȱbeȱfalse.ȱInȱthisȱ
case,ȱ ifȱ weȱ findȱ thatȱ numȱ hasȱ reachedȱ theȱ maximumȱ value,ȱ theȱ loopȱ breaksȱ andȱ theȱ
expressionȱ
ȱ
columns[num]
CAUTION!
CAUTION!
ȱ
isȱneverȱevaluated 5 .ȱ
ȱ
Beȱcarefulȱnotȱtoȱuseȱtheȱ&ȱoperatorȱwhenȱyouȱreallyȱwantȱ&&;ȱtheȱformerȱdoesȱaȱbitwiseȱ
AND,ȱ whichȱ sometimesȱ givesȱ theȱ sameȱ resultȱ thatȱ &&ȱ wouldȱ giveȱ butȱ inȱ otherȱ casesȱ
doesȱnot.ȱIȱdescribeȱtheseȱoperatorsȱinȱChapterȱ5.ȱ
Eachȱ callȱ toȱ scanfȱ roadsȱ aȱ decimalȱ integerȱ fromȱ theȱ standardȱ input.ȱ Ifȱ theȱ
conversionȱ fails,ȱ eitherȱ becauseȱ endȱ ofȱ meȱ wasȱ reachedȱ orȱ becauseȱ theȱ nextȱ inputȱ
charactersȱ wereȱ notȱ validȱ inputȱ forȱ anȱ integer,ȱ theȱ valueȱ 0ȱ isȱ returned,ȱ whichȱ breaksȱ
theȱ loop.ȱ Ifȱ theȱ charactersȱ areȱ legalȱ inputȱ forȱ anȱ integer,ȱ theȱ valueȱ isȱ convertedȱ toȱ
binaryȱandȱstoredȱinȱtheȱarrayȱelementȱcolumns[num]. scanfȱthanȱreturnsȱtheȱvalueȱ1.ȱ
ȱ
Beware:ȱTheȱoperatorȱthatȱtestsȱtwoȱexpressionsȱforȱequalityȱisȱ ==.ȱUsingȱtheȱ =ȱoperatorȱ
insteadȱresultsȱinȱaȱlegalȱexpressionȱthatȱalmostȱcertainlyȱwillȱnotȱdoȱwhatȱyouȱwantȱitȱ
toȱdo:ȱitȱdoesȱanȱassignmentȱratherȱthanȱaȱcomparison!ȱItȱisȱaȱlegalȱexpression,ȱthough,ȱ
soȱtheȱcompilerȱwon’tȱcatchȱthisȱerrorȱforȱyou 6 .ȱBeȱextremelyȱcarefulȱtoȱuseȱtheȱdoubleȱ
equalȱsignȱoperatorȱforȱcomparisons.ȱIfȱyourȱprogramȱisȱnotȱworking,ȱcheckȱallȱofȱyourȱ
comparisonsȱforȱthisȱerror.ȱBelieveȱme,ȱyouȱwillȱmakeȱthisȱmistake,ȱprobablyȱmoreȱthanȱ
once,ȱasȱIȱhave.ȱ
5ȱȱTheȱphraseȱȈtheȱloopȱbreaksȈȱmeansȱthatȱitȱterminates,ȱnotȱthatȱitȱisȱhasȱsuddenlyȱbecomeȱdefective.ȱThisȱphraseȱcomesȱ
fromȱtheȱbreakȱstatement,ȱwhichȱisȱdiscussedȱinȱChapterȱ4.ȱ
6ȱȱSomeȱnewerȱcompilersȱwillȱprintȱaȱwarningȱaboutȱassignmentsȱin ifȱand whileȱstatementsȱonȱtheȱtheoryȱthatȱitȱisȱmuchȱ
moreȱlikelyȱthatȱyouȱwantedȱaȱcomparisonȱthanȱanȱassignmentȱinȱthisȱcontext.ȱ
Download at http://www.pin5i.com/
1.1 Introduction 15
Theȱ nextȱ &&ȱ makesȱ sureȱ thatȱ theȱ numberȱ isȱ testedȱ forȱ aȱ negativeȱ valueȱ onlyȱ ifȱ
scanfȱwasȱsuccessfulȱinȱreadingȱit.ȱTheȱstatementȱ
ȱ
num += 1;
ȱ
addsȱ1ȱtoȱtheȱvariableȱnum.ȱItȱisȱequivalentȱtoȱtheȱstatementȱ
ȱ
num = num + 1;
ȱ
IȱdiscussȱlaterȱwhyȱCȱprovidesȱtwoȱdifferentȱwaysȱtoȱincrementȱaȱvariable 7 .ȱ
ȱ
ȱ
/*
** Make sure we have an even number of inputs, as they are
** supposed to be paired.
*/
if( num % 2 != 0 ){
puts( "Last column number is not paired." );
exit( EXIT_FAILURE );
}
Thisȱ testȱ checksȱ thatȱ anȱ evenȱ numberȱ ofȱ integersȱ wereȱ entered,ȱ whichȱ isȱ requiredȱ
becauseȱtheȱnumbersȱareȱsupposedȱtoȱbeȱinȱpairs.ȱTheȱ % operatorȱperformsȱanȱintegerȱ
division,ȱ butȱ itȱ givesȱ theȱ remainderȱ ratherȱ thanȱ theȱ quotient.ȱ Ifȱ numȱ isȱ notȱ anȱ evenȱ
number,ȱtheȱremainderȱofȱdividingȱitȱbyȱtwoȱwillȱbeȱnonzero.ȱ
Theȱ putsȱfunctionȱisȱtheȱoutputȱversionȱofȱ gets;ȱitȱwritesȱtheȱspecifiedȱstringȱtoȱ
theȱstandardȱoutputȱandȱappendsȱaȱnewlineȱcharacterȱtoȱit.ȱTheȱprogramȱthenȱcallsȱtheȱ
exit;ȱfunction,ȱwhichȱterminatesȱitsȱexecution.ȱTheȱvalueȱ EXIT_FAILUREȱisȱpassedȱbackȱ
toȱtheȱoperatingȱsystemȱtoȱindicateȱthatȱsomethingȱwasȱwrong.ȱ
ȱ
/*
** Discard the rest of the line that contained the final
** number.
*/
while( (ch = getchar()) != EOF && ch != '\n' )
;
ȱ
ȱ
scanfȱonlyȱreadsȱasȱfarȱasȱitȱhasȱtoȱwhenȱconvertingȱinputȱvalues.ȱTherefore,ȱtheȱ
remainderȱ ofȱ theȱ Lineȱ thatȱ containedȱ theȱ lastȱ valueȱ willȱ stillȱ beȱ outȱ there,ȱ waitingȱ to
7
ȱWithȱtheȱprefixȱandȱpostfixȱ++ȱoperators,ȱthereȱareȱactuallyȱfourȱwaysȱtoȱincrementȱaȱvariableȱ
Download at http://www.pin5i.com/
16ȱ Chapter 1 A Quick Start
beȱread.ȱItȱmayȱcontainȱjustȱtheȱterminatingȱnewline,ȱorȱitȱmayȱcontainȱotherȱcharactersȱ
too.ȱRegardless,ȱthisȱwhileȱloopȱreadsȱandȱdiscardsȱtheȱremainingȱcharactersȱtoȱpreventȱ
themȱfromȱbeingȱinterpretedȱasȱtheȱfirstȱlineȱofȱdata.ȱ
Theȱexpressionȱ
ȱ
(ch = getchar()) != EOF && ch != '\n'
ȱ
meritsȱ someȱ discussion.ȱ First,ȱ theȱ functionȱ getcharȱ readsȱ aȱ singleȱ characterȱ fromȱ theȱ
standardȱinputȱandȱreturnsȱitsȱvalue.ȱIfȱthereȱareȱnoȱmoreȱcharactersȱinȱtheȱinput,ȱtheȱ
constantȱEOFȱ(whichȱisȱdefinedȱinȱstdio.h)ȱisȱrammedȱinsteadȱtoȱsignalȱendȬofȬline.ȱ
Theȱ valueȱ returnedȱ byȱ getcharȱ isȱ assignedȱ toȱ theȱ variableȱ ch,ȱ whichȱ isȱ thenȱ
comparedȱ toȱ EOF.ȱ Theȱ parenthesesȱ enclosingȱ theȱ assignmentȱ ensureȱ thatȱ itȱ isȱ doneȱ
beforeȱtheȱcomparison.ȱIfȱ chȱisȱequalȱtoȱ EOF,ȱtheȱexpressionȱisȱfalseȱandȱtheȱloopȱstops.ȱ
Otherwise,ȱ chȱisȱcomparedȱtoȱaȱnewline;ȱagain,ȱtheȱloopȱstopsȱifȱtheyȱareȱfoundȱtoȱbeȱ
equal.ȱThus,ȱtheȱexpressionȱisȱtrueȱ{causingȱtheȱloopȱtoȱrunȱagain)ȱonlyȱifȱendȱofȱlineȱ
wasȱnotȱreachedȱandȱtheȱcharacterȱreadȱwasȱnotȱaȱnewline.ȱThus,ȱtheȱloopȱdiscardsȱtheȱ
remainingȱcharactersȱonȱtheȱcurrentȱinputȱline.ȱ
Nowȱlet’sȱmoveȱonȱtoȱtheȱinterestingȱpart.ȱInȱmostȱotherȱlanguages,ȱweȱwouldȱ
haveȱwrittenȱtheȱloopȱlikeȱthis:ȱ
ȱ
ch = getchar();
while( ch != EOF && ch != '\n' )
ch = getchar();
TIP
ȱ
Getȱaȱ character,ȱ thereȱ ifȱweȇveȱnotȱ yetȱ reachedȱendȱ ofȱ tileȱ orȱ gottenȱaȱ newline,ȱ
getȱanotherȱcharacter.ȱNoteȱthatȱthereȱareȱtwoȱcopiesȱofȱtheȱstatement.ȱȱ
ȱ
ȱ
ch = getchar();
ȱ
Theȱabilityȱtoȱembedȱtheȱassignmentȱinȱtheȱ whileȱstatementȱallowsȱtheȱCȱprogrammerȱ
toȱeliminateȱthisȱredundantȱstatement.ȱ
ȱ
Theȱloopȱinȱtheȱsampleȱprogramȱhasȱtheȱsameȱfunctionalityȱasȱtheȱoneȱshownȱabove,ȱ
butȱ itȱ containsȱ oneȱ fewerȱ statement.ȱ Itȱ isȱ admittedlyȱ harderȱ toȱ road,ȱ andȱ oneȱ couldȱ
makeȱaȱconvincingȱargumentȱthatȱthisȱcodingȱtechniqueȱshouldȱbeȱavoidedȱforȱjustȱthatȱ
reason.ȱ However,ȱ most,ȱ ofȱ theȱ difficultyȱ inȱ readingȱ isȱ dueȱ coȱ inexperienceȱ withȱ theȱ
languageȱ andȱ itsȱ idioms;ȱ experiencedȱ Cȱ programmersȱ haveȱ noȱ troubleȱ readingȱ (andȱ
writing)ȱ statementsȱ suchȱ asȱ thisȱ one.ȱ Youȱ shouldȱ avoidȱ makingȱ codeȱ harderȱ toȱ readȱ
whenȱthereȱisȱnoȱtangibleȱbenefitȱtoȱbeȱgainedȱfromȱit,ȱbutȱtheȱmaintenanceȱadvantageȱ
inȱnotȱhavingȱmultipleȱcopiesȱofȱcodeȱmoreȱthanȱjustifiesȱthisȱcommonȱcodingȱidiom.ȱ
Download at http://www.pin5i.com/
1.1 Introduction 17
TIP
Aȱ questionȱ frequentlyȱ askedȱ isȱ whyȱ chȱ isȱ declaredȱ asȱ anȱ integerȱ whenȱ weȱ areȱ
usingȱ itȱ toȱ readȱ characters?ȱ Theȱ answerȱ isȱ thatȱ EOFȱ isȱ anȱ integerȱ valueȱ thatȱ requiresȱ
moreȱbitsȱthanȱareȱavailableȱinȱaȱcharacterȱvariable;ȱthisȱfactȱpreventsȱaȱcharacterȱinȱtheȱ
inputȱ fromȱ accidentallyȱ beingȱ interpretedȱ asȱ EOF.ȱ Butȱ itȱ alsoȱ meansȱ thatȱ ch,ȱ whichȱ isȱ
receivingȱ theȱ characters,ȱ mustȱ beȱ largeȱ enoughȱ toȱ holdȱ EOFȱ 100,ȱ whichȱ isȱ whyȱ anȱ
integerȱisȱused.ȱAsȱdiscussedȱinȱChapterȱ3,ȱcharactersȱareȱjustȱtinyȱintegersȱanyway,ȱsoȱ
usingȱanȱintegerȱvariableȱtoȱholdȱcharacterȱvaluesȱcausesȱnoȱproblems.ȱ
ȱ
Oneȱ finalȱ commentȱ onȱ thisȱ fragmentȱ ofȱ theȱ program:ȱ thereȱ areȱ noȱ statementsȱ inȱ theȱ
bodyȱ ofȱ theȱ whileȱ statement.ȱ Itȱ turnsȱ outȱ thatȱ theȱ workȱ doneȱ toȱ evaluateȱ theȱ whileȱ
expressionȱisȱallȱthatȱisȱneeded,ȱsoȱthereȱisȱnothingȱleft forȱtheȱbodyȱofȱtheȱloopȱtoȱdo.ȱ
Youȱ willȱ encounterȱ suchȱ loopsȱ occasionally,ȱ andȱ handlingȱ themȱ isȱ noȱ problem.ȱ Theȱ
solitaryȱsemicolonȱafterȱtheȱwhileȱstatementȱisȱcalledȱtheȱemptyȱstatement,ȱandȱitȱisȱusedȱ
inȱsituationsȱlikeȱthisȱoneȱwhereȱtheȱsyntaxȱrequiresȱaȱstatementȱbutȱthereȱisȱnoȱworkȱtoȱ
beȱ done.ȱ Theȱ semicolonȱ isȱ onȱ aȱ lineȱ byȱ itselfȱ inȱ orderȱ toȱ preventȱ theȱ readerȱ fromȱ
mistakenlyȱassumingȱthatȱtheȱnextȱstatementȱisȱmeȱbodyȱofȱtheȱloop.ȱ
ȱ
return num;
}
ȱ
ȱ
Theȱ returnȱstatementȱisȱhowȱaȱfunctionȱreturnsȱaȱvalueȱtoȱtheȱexpressionȱfromȱ
whichȱitȱwasȱcalled.ȱInȱthisȱcase,ȱtheȱvalueȱofȱtheȱvariableȱ numȱisȱreturnedȱtoȱtheȱcallingȱ
program,ȱwhereȱitȱisȱassignedȱtoȱtheȱmainȱprogramȇsȱvariableȱn_columns.ȱ
ȱ
ȱ
ȱ
ȱ
1.1.5 The rearrange Function
/*
** Process a line of input by
** the indicated columns. The
*/
void
rearrange( char *output, char
in n_columns, int const
{
int
col;
int
output_col;
int
len;
concatenating the characters from
output line is the NUL terminated,
const *input,
columns[] )
/* subscript for columns array */
/* output column counter */
/* length of input line */
Download at http://www.pin5i.com/
18ȱ Chapter 1 A Quick Start
Theseȱstatementsȱdefineȱtheȱrearrangeȱfunctionȱandȱdeclareȱsomeȱlocalȱvariablesȱ
forȱit.ȱTheȱmostȱinterestingȱpointȱhereȱisȱthatȱtheȱfirstȱtwoȱparametersȱareȱdeclaredȱasȱ
pointersȱbutȱarrayȱnamesȱareȱpassedȱasȱargumentsȱwhenȱtheȱfunctionȱisȱcalled.ȱWhenȱ
anȱarrayȱnameȱisȱusedȱasȱanȱargument,ȱwhatȱisȱpassedȱtoȱtheȱfunctionȱisȱaȱpointerȱtoȱ
theȱ beginningȱ ofȱ theȱ array,ȱ whichȱ isȱ actuallyȱ theȱ addressȱ whereȱ theȱ arrayȱ residesȱ inȱ
memory.ȱTheȱfactȱthatȱaȱpointerȱisȱpassedȱratherȱthanȱatȱcopyȱofȱtheȱarrayȱisȱwhatȱgivesȱ
arraysȱtheirȱcallȱbyȱreferenceȱsemantics.ȱTheȱfunctionȱcanȱmanipulateȱtheȱargumentȱasȱ
aȱpointer,ȱorȱitȱcanȱuseȱaȱsubscriptȱwithȱtheȱargumentȱjustȱasȱwithȱanȱarrayȱname.ȱTheseȱ
techniquesȱareȱdescribedȱinȱmoreȱdetailȱinȱChapterȱ8.ȱ
ȱ
Becauseȱ ofȱ theȱ callȱ byȱ referenceȱ semantics,ȱ though,ȱ ifȱ theȱ functionȱ modifiesȱ
elementsȱofȱtheȱparameterȱarray,ȱitȱactuallyȱmodifiesȱtheȱcorrespondingȱelementsȱofȱtheȱ
argumentȱ array.ȱ Thus,ȱ declaringȱ columnsȱ toȱ beȱ constȱ isȱ usefulȱ inȱ twoȱ ways.ȱ First,ȱ itȱ
statesȱ thatȱ theȱ intentionȱ ofȱ theȱ functionȇsȱ authorȱ isȱ thatȱ thisȱ parameterȱ isȱ notȱ toȱ beȱ
modified.ȱ Second,ȱ itȱ causesȱ theȱ compilerȱ toȱ verifyȱ thatȱ thisȱ intentionȱ isȱ notȱ violated.ȱ
Thus,ȱ callersȱ ofȱ thisȱ functionȱ needȱ notȱ worryȱ aboutȱ theȱ possibilityȱ ofȱ elementsȱ ofȱ meȱ
arrayȱpassedȱasȱtheȱfourthȱargumentȱbeingȱchanged.ȱ
ȱ
ȱ
len = strlen( input );
output_col = 0;
/*
** Process each pair of column numbers.
*/
for( col = 0; col < n_columns; col += 2 ){
ȱ
ȱ
Theȱrealȱworkȱofȱtheȱfunctionȱbeginsȱhere.ȱWeȱfirstȱgetȱtheȱlengthȱofȱtheȱinputȱ
string,ȱsoȱweȱcanȱskipȱcolumnȱnumbersȱthatȱareȱbeyondȱtheȱendȱofȱtheȱinput.ȱTheȱ forȱ
statementȱinȱCȱisȱnotȱquiteȱlikeȱotherȱlanguages;ȱitȱisȱmoreȱofȱatȱshorthandȱnotationȱforȱ
aȱ commonlyȱ usedȱ styleȱ ofȱ whileȱ statement.ȱ Theȱ forȱ statementȱ containsȱ threeȱ
expressionsȱ (allȱ ofȱ whichȱ areȱ optional,ȱ byȱ theȱ way).ȱ Theȱ firstȱ expressionȱ isȱ theȱ
initializationȱandȱisȱevaluatedȱonceȱbeforeȱtheȱloopȱbegins.ȱTheȱsecondȱisȱtheȱtestȱandȱisȱ
evaluatedȱbeforeȱeachȱiterationȱofȱtheȱloop;ȱifȱtheȱresultȱisȱfalseȱtheȱloopȱterminates.ȱTheȱ
thirdȱexpression,ȱisȱtheȱadjustmentȱwhichȱisȱevaluatedȱatȱtheȱendȱofȱeachȱiterationȱjustȱ
beforeȱ theȱ testȱ isȱ evaluated.ȱ Toȱ illustrate,ȱ theȱ forȱ loopȱ thatȱ beginsȱ aboveȱ couldȱ beȱ
rewrittenȱasȱaȱwhileȱloop:ȱ
ȱ
col = 0;
Download at http://www.pin5i.com/
1.1 Introduction 19
ȱ
ȱ
while( col < n_columns ){
bodyȱofȱtheȱloopȱ
col += 2;
}
int
nchars = columns[col + 1] – columns[col] + 1;
/*
** If the input line isn't this long or the output
** array is full, we're done
*/
if( columns[col] >= len ||
output_col == MAX_INPUT – 1 )
break;
/*
** If there isn't room in the output array, only copy
** what will fit.
*/
if( output_col + nchars > MAX_INPUT – 1)
nchars = MAX_INPUT – output_col – 1;
/*
** Copy the relevant data.
*/
strncpy( output + output_col, input + columns[col],
nchars );
output_col += nchars;
TIP
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Hereȱ isȱ theȱ bodyȱ ofȱ theȱ forȱ loop,ȱ whichȱ beginsȱ byȱ computingȱ theȱ numberȱ ofȱ
charactersȱinȱthisȱrangeȱofȱcolumns.ȱThenȱitȱchecksȱwhetherȱtoȱcontinueȱwithȱtheȱloop.ȱ
Ifȱtheȱinputȱlineȱisȱshorterȱthanȱthisȱstartingȱcolumn,ȱorȱifȱtheȱoutputȱlineȱisȱalreadyȱfull,ȱ
thereȱisȱnoȱmoreȱworkȱtoȱbeȱdoneȱandȱtheȱbreakȱstatementȱexitsȱtheȱloopȱimmediately.ȱ
ȱTheȱ nextȱ testȱ checksȱ whetherȱ allȱ ofȱ theȱ charactersȱ fromȱ thisȱ rangeȱ ofȱ columnsȱ
willȱfitȱinȱtheȱoutputȱline.ȱIfȱnot,ȱncharsȱisȱadjustedȱtoȱtheȱnumberȱthatȱwillȱfit.ȱ
ȱ
ItȱisȱcommonȱinȱȈthrowawayȈȱprogramsȱthatȱareȱusedȱonlyȱonceȱtoȱnotȱbotherȱcheckingȱ
thingsȱsuchȱasȱarrayȱboundsȱandȱtoȱsimplyȱmakeȱtheȱarrayȱȈbigȱenoughȈȱsoȱthatȱitȱwillȱ
neverȱ overflow.ȱ Unfortunately,ȱ thisȱ practiceȱ isȱ sometimesȱ usedȱ inȱ productionȱ code,ȱ
too.ȱ There,ȱ mostȱ ofȱ theȱ extraȱ spaceȱ isȱ wasted, butȱ itȱ isȱ stillȱ possibleȱ toȱ overflowȱ theȱ
Download at http://www.pin5i.com/
20ȱ Chapter 1 A Quick Start
array,ȱleadingȱtoȱaȱprogramȱfailure 8 .ȱ
ȱ
Finally,ȱtheȱ strncpyȱfunctionȱcopiesȱtheȱselectedȱcharactersȱfromȱtheȱinputȱlineȱ
toȱtheȱnextȱavailableȱpositionȱinȱtheȱoutputȱline.ȱTheȱfirstȱtwoȱargumentsȱtoȱstrncpyȱareȱ
theȱdestinationȱandȱsource,ȱrespectively,ȱofȱaȱstringȱtoȱcopy.ȱTheȱdestinationȱinȱthisȱcallȱ
isȱtheȱpositionȱ output_colȱcolumnsȱpastȱtheȱbeginningȱofȱtheȱoutputȱarray.ȱTheȱsourceȱ
isȱtheȱpositionȱcolumns[col]ȱpastȱtheȱbeginningȱofȱtheȱinputȱarray.ȱTheȱthirdȱargumentȱ
specifiesȱ theȱ numberȱ ofȱ charactersȱ toȱ beȱ copied 9 .ȱ Theȱ outputȱ columnȱ counterȱ isȱ thenȱ
advancedȱncharsȱpositions.ȱ
ȱ
}
output[output_col] = '\0';
}
ȱ
Afterȱtheȱ loopȱends,ȱtheȱoutputȱstringȱisȱ terminatedȱ withȱaȱ NULȱcharacter;ȱnoteȱ
thatȱtheȱbodyȱofȱtheȱloopȱtakesȱcareȱtoȱensureȱthatȱthereȱisȱspaceȱinȱtheȱarrayȱtoȱholdȱit.ȱ
Thenȱexecutionȱreachesȱtheȱbottomȱofȱtheȱfunction,ȱsoȱanȱimplicitȱ returnȱisȱexecuted.ȱ
Withȱnoȱexplicitȱ returnȱstatement,ȱnoȱvalueȱcanȱbeȱpassedȱbackȱtoȱtheȱexpressionȱfromȱ
whichȱtheȱfunctionȱwasȱcalled.ȱTheȱmissingȱreturnȱvalueȱisȱnotȱaȱproblemȱhereȱbecauseȱ
theȱfunctionȱwasȱdeclaredȱvoidȱ(thatȱis,ȱreturningȱnoȱvalue)ȱandȱthereȱisȱnoȱassignmentȱ
orȱtestingȱofȱtheȱfunction‘sȱreturnȱvalueȱwhereȱitȱisȱcalled.ȱ
ȱ
ȱ
ȱ
ȱ
1.2 Other Capabilities
Theȱ sampleȱ programȱ illustratedȱ manyȱ ofȱ theȱ Cȱ basics,ȱ butȱ thereȱ isȱ aȱ littleȱ moreȱ youȱ
shouldȱ knowȱ beforeȱ youȱ beginȱ writingȱ yourȱ ownȱ programs.ȱ Firstȱ isȱ theȱ putcharȱ
function,ȱ whichȱ isȱ theȱ companionȱ toȱ getchar.ȱ Itȱ takesȱ aȱ singleȱ integerȱ argumentȱ andȱ
printsȱthatȱcharacterȱonȱtheȱstandardȱoutput.ȱȱ
Also,ȱthereȱareȱmanyȱmoreȱlibraryȱfunctionsȱforȱmanipulatingȱstrings.ȱI’llȱbrieflyȱ
introduceȱaȱfewȱofȱtheȱmostȱusefulȱonesȱhere.ȱUnlessȱotherwiseȱnoted,ȱeachȱargumentȱ
toȱtheseȱfunctionsȱmayȱbeȱaȱstringȱliteral,ȱtheȱnameȱofȱaȱcharacterȱarray,ȱorȱaȱpointerȱtoȱ
aȱcharacter.ȱ
8ȱTheȱastuteȱreaderȱwillȱhaveȱnoticedȱthatȱthereȱisȱnothingȱtoȱpreventȱgetsȱfromȱoverflowingȱtheȱinputȱarrayȱifȱanȱextremelyȱ
longȱinputȱlineȱisȱencountered.ȱThisȱloopholeȱisȱreallyȱaȱshortcomingȱofȱgets,ȱwhichȱisȱoneȱreasonȱwhyȱfgetsȱ(describedȱinȱ
chapterȱ15)ȱshouldȱbeȱusedȱinstead.ȱ
9
lf the source of the copy contains fewer characters than indicated by the third argument, the destination is padded to the proper length
with NUL. bytes.
Download at http://www.pin5i.com/
1.4 Summary 21
strcpyȱisȱsimilarȱtoȱstrncpyȱexceptȱthatȱthereȱisȱnoȱspecifiedȱlimitȱtoȱtheȱȱnumberȱ
ofȱ charactersȱ thatȱ areȱ copied.ȱ Itȱ takesȱ twoȱ arguments:ȱ theȱ stringȱ inȱ theȱ secondȱ
argumentȱisȱcopiedȱintoȱtheȱfirst,ȱoverwritingȱanyȱstringȱthatȱtheȱfirstȱargumentȱmightȱ
alreadyȱcontain,ȱstrcatȱalsoȱtakesȱtwoȱarguments,ȱbutȱthisȱfunctionȱappendsȱtheȱstringȱ
inȱtheȱsecondȱargumentȱtoȱtheȱendȱofȱtheȱstringȱalreadyȱcontainedȱinȱtheȱfirst.ȱAȱstringȱ
literalȱmayȱnotȱbeȱusedȱasȱtheȱfirstȱargumentȱtoȱeitherȱofȱtheseȱlastȱtwoȱfunctions.ȱItȱisȱ
theȱ programmersȱ responsibilityȱ withȱ bothȱ functionsȱ toȱ ensureȱ thatȱ theȱ destinationȱ
arrayȱisȱlargeȱenoughȱtoȱholdȱtheȱresult.ȱ
Forȱsearchingȱinȱstrings,ȱthereȱisȱstrchr,ȱwhichȱtakesȱtwoȱargumentsȱȬȱtheȱfirstȱisȱ
aȱstring,ȱandȱtheȱsecondȱisȱaȱcharacter.ȱItȱsearchesȱtheȱstringȱforȱtheȱfirstȱoccurrenceȱofȱ
theȱ characterȱ andȱ returnsȱ aȱ pointerȱ toȱ theȱ positionȱ whereȱ itȱ wasȱ found.ȱ Ifȱ theȱ firstȱ
argumentȱ doesȱ notȱ containȱ theȱ character,ȱ aȱ NULLȱ pointerȱ isȱ returnedȱ instead.ȱ Theȱ
strstrȱfunctionȱisȱsimilar.ȱItsȱsecondȱargumentȱisȱaȱstring,ȱandȱitȱsearchesȱforȱtheȱfirstȱ
occurrenceȱofȱthisȱstringȱinȱtheȱfirstȱargument.ȱ
ȱ
ȱ
ȱ
ȱ
1.3 Compiling
ȱ
Theȱ wayȱ youȱ compileȱ andȱ runȱ Cȱ programsȱ dependsȱ onȱ theȱ kindȱ ofȱ systemȱ you’reȱ
using.ȱToȱcompileȱaȱprogramȱstoredȱinȱtheȱfileȱtesting.cȱonȱaȱUNIXȱmachine,ȱtryȱtheseȱ
commands:ȱ
cc testing.c
a.out
ȱ
OnȱPC’s,ȱyouȱneedȱtoȱknowȱwhichȱcompilerȱyouȱareȱusing.ȱForȱBorlandȱC++,ȱtryȱthisȱ
commandȱinȱaȱMSȬDOSȱwindow:ȱ
bcc testing.c
testing
ȱ
ȱ
ȱ
ȱ
1.4 Summary
ȱ
TheȱgoalȱofȱthisȱchapterȱwasȱtoȱdescribeȱenoughȱofȱCȱtoȱgiveȱyouȱanȱoverviewȱofȱtheȱ
language.ȱ Withȱ thisȱ context,ȱ itȱ willȱ beȱ easierȱ toȱ understandȱ theȱ topicsȱ inȱ theȱ nextȱ
chapters.ȱ
Theȱ sampleȱ programȱ illustratedȱ numerousȱ points.ȱ Commentsȱ beginȱ withȱ / *ȱ
andȱ endȱ withȱ */,ȱ andȱ areȱ usedȱ toȱ includeȱ descriptionsȱ inȱ theȱ program.ȱ Theȱ
preprocessorȱ directiveȱ #includeȱ causesȱ theȱ contentsȱ ofȱ aȱ libraryȱ headerȱ toȱ beȱ
Download at http://www.pin5i.com/
22ȱ Chapter 1 A Quick Start
processedȱ byȱ theȱ compiler,ȱ andȱ theȱ #defineȱ directiveȱ allowsȱ youȱ toȱ giveȱ symbolicȱ
namesȱtoȱliteralȱconstants.ȱ
Allȱ Cȱ programsȱ mustȱ haveȱ aȱ functionȱ calledȱ mainȱ inȱ whichȱ executionȱ begins.ȱ
Scalarȱargumentsȱtoȱfunctionsȱareȱpassedȱbyȱvalue,ȱandȱarrayȱargumentsȱhaveȱcallȱbyȱ
referenceȱ semantics.ȱ Stringsȱ areȱ sequencesȱ ofȱ charactersȱ terminatedȱ withȱ aȱ NULȱ byte,ȱ
andȱ thereȱisȱ aȱ libraryȱofȱ functionsȱtoȱ manipulateȱstringsȱinȱvariousȱways.ȱTheȱ printf
functionȱ performsȱ formattedȱ output,ȱ andȱ theȱ scanfȱ functionȱ isȱ usedȱ forȱ formattedȱ
input;ȱ getcharȱ andȱ putcharȱ performȱ unformattedȱ characterȱ inputȱ andȱ output,ȱ
respectively.ȱ ifȱ andȱ whileȱ statementsȱ workȱ muchȱ theȱ sameȱ inȱ Cȱ asȱ theyȱ doȱ inȱ otherȱ
languages.ȱ
Havingȱseenȱhowȱtheȱsampleȱprogramȱworks,ȱyouȱmayȱnowȱwishȱtoȱtryȱwritingȱ
someȱCȱprogramsȱofȱyourȱown.ȱIfȱitȱseemsȱlikeȱthereȱoughtȱtoȱbeȱmoreȱtoȱtheȱlanguage,ȱ
youȱ areȱ right,ȱ thereȱ isȱ muchȱ more,ȱ butȱ thisȱ samplingȱ shouldȱ beȱ enoughȱ toȱ getȱ youȱ
started.ȱ
ȱ
ȱ
ȱ
ȱ
1.5 Summary of Cautions
1.
2.
3.
4.
Notȱputtingȱampersandsȱinȱfrontȱofȱscalarȱargumentsȱtoȱscanfȱ(pageȱ12).ȱ
Usingȱprintfȱformatȱcodesȱin scanfȱ(pageȱ13).ȱ
Usingȱ&ȱforȱaȱlogicalȱANDȱinsteadȱofȱ&&ȱ(pageȱ14).ȱ
Using = toȱcompareȱforȱequalityȱinsteadȱof == (pageȱ14).ȱ
ȱ
ȱ
ȱ
ȱ
1.6 Summary of Programming Tips
1.
2.
3.
4.
5.
6.
7.
Usingȱ#includeȱfilesȱforȱdeclarationsȱ(pageȱ6).ȱ
Usingȱ#defineȱtoȱgiveȱnamesȱtoȱconstantȱvaluesȱ(pageȱ7).ȱ
Puttingȱfunctionȱprototypesȱinȱ#includeȱfilesȱ(pageȱ7).ȱ
Checkingȱsubscriptȱvaluesȱbeforeȱusingȱthemȱ(pageȱ14).ȱ
Nestingȱassignmentsȱinȱaȱwhileȱorȱifȱexpressionȱ(pageȱ16).ȱ
Howȱtoȱwriteȱaȱloopȱwithȱanȱemptyȱbodyȱ(pageȱ17).ȱ
Alwaysȱcheckȱtoȱbeȱsureȱthatȱyouȱdon’tȇȱgoȱoutȱofȱtheȱboundsȱofȱanȱarrayȱ(pageȱ19).ȱ
Download at http://www.pin5i.com/
1.8 Programming Exercises 23
1.7 Questions
1. Cȱ isȱ aȱ freeȬformȱ language,ȱ whichȱ meansȱ thatȱ thereȱ areȱ noȱ rulesȱ regardingȱ howȱ
programsȱ mustȱ look 10 .ȱ Yetȱ theȱ sampleȱ programȱ followedȱ specificȱ spacingȱ rules.ȱ
Whyȱdoȱyouȱthinkȱthisȱis?ȱ
2. Whatȱ isȱ theȱ advantageȱ ofȱ puttingȱ declarations,ȱ suchȱ asȱ functionȱ prototypes,ȱ inȱ
headerȱfilesȱandȱthenȱusing #include toȱbringȱtheȱdeclarationsȱintoȱtheȱsourceȱfilesȱ
whereȱtheyȱareȱneeded?ȱ
3. Whatȱisȱtheȱadvantageȱofȱusing #define toȱgiveȱnamesȱtoȱliteralȱconstants?ȱ
4. Whatȱformatȱstringȱwouldȱyouȱuseȱwithȱ printfȱinȱorderȱtoȱprintȱaȱdecimalȱinteger,ȱ
aȱ string,ȱ andȱ aȱ floatingȬpointȱ value,ȱ inȱ thatȱ order?ȱ Separateȱ theȱ valuesȱ fromȱ oneȱ
anotherȱwithȱaȱspace,ȱandȱendȱtheȱoutputȱwithȱaȱnewlineȱcharacter.ȱ
5. Writeȱtheȱ scanfȱstatementȱneededȱtoȱreadȱtwoȱintegers,ȱcalledȱ quantityȱandȱ price,ȱ
followedȱbyȱaȱstring,ȱwhichȱshouldȱbeȱstoredȱinȱaȱcharacterȱarrayȱcalledȱdepartment.ȱ
6. ThereȱareȱnoȱchecksȱmadeȱonȱtheȱvalidityȱofȱanȱarrayȱsubscriptȱinȱC.ȱWhyȱdoȱyouȱ
thinkȱthisȱobviousȱsafetyȱmeasureȱwasȱomittedȱfromȱtheȱlanguage?ȱ
7. Theȱrearrangeȱprogramȱdescribedȱinȱtheȱchapterȱcontainsȱtheȱstatementȱ
ȱ
strncpy( output + output_col,
input + columns[col], nchars );
Theȱ strcpyȱ functionȱ takesȱ onlyȱ twoȱ arguments,ȱ soȱ theȱ numberȱ ofȱ charactersȱ itȱ
copiesȱisȱdeterminedȱbyȱtheȱstringȱspecifiedȱbyȱtheȱsecondȱargument.ȱWhatȱwouldȱ
beȱ theȱ effectȱ ofȱ replacingȱ theȱ strncpyȱ functionȱ callȱ withȱ aȱ callȱ toȱ strcpyȱ inȱ thisȱ
program?ȱ
8. Theȱrearrangeȱprogramȱcontainsȱtheȱstatementȱ
while( gets( input ) != NULL ){
ȱ
ȱ
ȱ
ȱ
ȱ
Whatȱmightȱgoȱwrongȱwithȱthisȱcode?ȱ
ȱ
1.8 Programming Exercises
ȱ
1. TheȱȈHelloȱworld!ȈȱprogramȱisȱoftenȱtheȱfirstȱCȱprogramȱthatȱaȱstudentȱofȱCȱwrites.ȱ
Itȱprintsȱ Hello world!ȱfollowedȱbyȱaȱnewlineȱonȱtheȱstandardȱoutput.ȱThisȱtrivialȱ
programȱisȱaȱgoodȱoneȱtoȱuseȱwhenȱfiguringȱoutȱhowȱtoȱrun theȱCȱcompilerȱonȱyourȱ
particularȱsystem.ȱ
10
ȱOtherȱthanȱforȱtheȱpreprocessorȱdirectives.ȱ
Download at http://www.pin5i.com/
24ȱ Chapter 1 A Quick Start
2. Writeȱaȱprogramȱthatȱreadsȱlinesȱfromȱtheȱstandardȱinput.ȱEachȱlineȱisȱprintedȱonȱ
theȱstandardȱoutputȱprecededȱbyȱitsȱlineȱnumber.ȱTryȱtoȱwriteȱtheȱprogramȱsoȱthatȱ
itȱhasȱnoȱbuiltȬinȱlimitȱonȱhowȱlongȱaȱlineȱitȱcanȱhandle.ȱ
3. Writeȱaȱprogramȱthatȱreadsȱcharactersȱfromȱtheȱstandardȱinputȱandȱwritesȱthemȱtoȱ
theȱ standardȱ output.ȱ Itȱ shouldȱ alsoȱ computeȱ aȱ checksumȱ andȱ writeȱ itȱ outȱ afterȱ theȱ
characters.ȱȱ
Theȱchecksumȱisȱcomputedȱinȱaȱsigned charȱvariableȱthatȱisȱinitializedȱtoȱ—1.ȱAsȱ
eachȱ characterȱ isȱ readȱ fromȱ theȱ standardȱ input,ȱ itȱ isȱ addedȱ toȱ theȱ checksum.ȱ Anyȱ
overflowȱ fromȱ theȱ checksumȱ variableȱ isȱ ignored.ȱ Whenȱ allȱ ofȱ theȱ charactersȱ haveȱ
beenȱ written,ȱ theȱ checksumȱ isȱ thenȱ writtenȱ asȱ aȱ decimalȱ integer,ȱ whichȱ mayȱ beȱ
negative.ȱBeȱsureȱtoȱfollowȱtheȱchecksumȱwithȱaȱnewȬline.ȱ
Onȱ computersȱ thatȱ useȱ ASCII,ȱ runningȱ yourȱ programȱ onȱ aȱ fileȱ containingȱ theȱ
wordsȱȈHelloȱworld!Ȉȱfollowedȱbyȱaȱnewlineȱshouldȱproduceȱtheȱfollowingȱoutput:ȱ
Hello world!
102
4. Writeȱ aȱ programȱ thatȱ readsȱ inputȱ linesȱ oneȱ byȱ oneȱ untilȱ endȱ ofȱ fileȱ isȱ reached,ȱ
determinesȱtheȱlengthȱofȱeachȱinputȱline,ȱandȱthenȱprintsȱoutȱonlyȱtheȱlongestȱlineȱ
thatȱ wasȱ found.ȱ Toȱ simplifyȱ matters,ȱ youȱ mayȱ assumeȱ thatȱ noȱ inputȱ lineȱ willȱ beȱ
longerȱthanȱ1000ȱcharacters.ȱ
5. Theȱstatementȱ
if( columns[col] >= len … )
break;
inȱtheȱrearrangeȱprogramȱstopsȱcopyingȱrangesȱofȱcharactersȱasȱsoonȱasȱaȱrangeȱisȱ
encounteredȱthatȱisȱpastȱtheȱendȱofȱtheȱinputȱline.ȱThisȱstatementȱisȱcorrectȱonlyȱifȱ
theȱrangesȱareȱenteredȱinȱincreasingȱorder,ȱwhichȱmayȱnotȱbeȱtheȱcase.ȱModifyȱtheȱ
rearrangeȱfunctionȱsoȱthatȱitȱwillȱworkȱcorrectlyȱevenȱifȱtheȱrangesȱareȱnotȱenteredȱ
inȱorder.ȱ
6. Modifyȱ theȱ rearrangeȱ programȱ toȱ removeȱ theȱ restrictionȱ thatȱ anȱ evenȱ numberȱ ofȱ
columnȱvaluesȱmustȱbeȱreadȱinitially.ȱIfȱanȱoddȱnumberȱofȱvaluesȱareȱread,ȱtheȱlastȱ
valuedȱindicatesȱtheȱstartȱofȱtheȱfinalȱrangeȱofȱcharacters.ȱCharactersȱfromȱhereȱtoȱ
theȱendȱofȱtheȱinputȱstringȱareȱcopiedȱtoȱtheȱoutputȱstring.ȱ
ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
2
Basic Concepts
Thereȱisȱnoȱdoubtȱthatȱlearningȱtheȱfundamentalsȱofȱaȱprogrammingȱlanguageȱisȱnotȱasȱ
muchȱ funȱ asȱ writingȱ programs.ȱ However,ȱ notȱ knowingȱ theȱ fundamentalsȱ makesȱ
writingȱprogramsȱaȱlotȱlessȱfun.ȱ
ȱ
ȱ
ȱ
2.1 Environments
ȱ
Inȱanyȱ particularȱ implementationȱofȱ ANSIȱC,ȱthereȱ areȱ twoȱ distinctȱenvironmentsȱ thatȱ
areȱ ofȱ interest:ȱ theȱ translationȱ environment,ȱ inȱ whichȱ sourceȱ codeȱ isȱ convertedȱ inȱ toȱ
executableȱ machineȱ instructions;ȱ andȱ theȱ executionȱ environment,ȱ inȱ whichȱ theȱ codeȱ
actuallyȱruns.ȱTheȱStandardȱmakesȱitȱclearȱthatȱtheseȱenvironmentsȱneedȱnotȱbeȱonȱtheȱ
sameȱ machine.ȱ Forȱ example,ȱ crossȬcompilersȱ runȱ onȱ oneȱ machineȱ butȱ produceȱ
executableȱ codeȱ thatȱ willȱ beȱ runȱ onȱ aȱ differentȱ typeȱ ofȱ machine.ȱ Norȱ isȱ anȱ operatingȱ
systemȱ aȱ requirement:ȱ theȱ Standardȱ alsoȱ discussesȱ freestandingȱ environmentsȱ inȱ whichȱ
thereȱ isȱ noȱ operatingȱ system.ȱ Youȱ mightȱ encounterȱ thisȱ typeȱ ofȱ environmentȱ inȱ anȱ
embeddedȱsystemȱsuchȱasȱtheȱcontrollerȱforȱaȱmicrowaveȱoven.ȱ
ȱ
ȱ
ȱ
2.1.1 Translation
Theȱ translationȱ phaseȱ consistsȱ ofȱ severalȱ steps.ȱ First,ȱ eachȱ ofȱ theȱ (potentiallyȱ many)ȱ
sourceȱtilesȱthatȱmakeȱupȱaȱprogramȱareȱindividuallyȱconvertedȱtoȱobjectȱcodeȱviaȱtheȱ
compilationȱ process.ȱ Then,ȱ theȱ variousȱ objectȱ filesȱ areȱ tiedȱ togetherȱ byȱ theȱ linkerȱ toȱ
formȱ aȱ single,ȱ completeȱ executableȱ program.ȱ Theȱ linkerȱ alsoȱ bringsȱ inȱ anyȱ functionsȱ
fromȱ theȱ standardȱ Cȱ librariesȱ thatȱ wereȱ usedȱ inȱ theȱ program,ȱ andȱ itȱ canȱ alsoȱ searchȱ
personalȱprogramȱlibrariesȱasȱwell.ȱFigureȱ2.lȱillustratesȱthisȱprocess.ȱ
Download at http://www.pin5i.com/
26ȱ Chapter 2 Basic Concepts
Source code
Compiler
Object code
Source code
Compiler
Object code
Source code
Compiler
Object code
Libraries
Linker
Executable
ȱ
ȱ
Figureȱ2.1ȱTheȱcompilationȱprocessȱ
ȱ
ȱ
Theȱcompilationȱprocessȱitselfȱconsistsȱofȱseveralȱphases,ȱwithȱtheȱfirstȱbeingȱtheȱ
preprocessor.ȱ Thisȱ phaseȱ performsȱ textualȱ manipulationsȱ onȱ theȱ sourceȱ code,ȱ forȱ
example,ȱsubstitutingȱtheȱtextȱofȱidentifiersȱthatȱhaveȱbeenȱ #define’dȱandȱreadingȱtheȱ
textȱofȱtilesȱthatȱwereȱ#includeȇd.ȱ
Theȱsourceȱcodeȱisȱthenȱparsedȱtoȱdetermineȱtheȱmeaningsȱofȱitsȱstatements.ȱThisȱ
secondȱstageȱisȱwhereȱmostȱerrorȱandȱwarningȱmessagesȱareȱproduced.ȱObjectȱcodeȱisȱ
thenȱ generated.ȱ Objectȱ codeȱ isȱ aȱ preliminaryȱ formȱ ofȱ theȱ machineȱ instructionsȱ thatȱ
implementȱ theȱ statementsȱ ofȱ theȱ programsȱ calledȱ forȱ byȱ aȱ commandȬlineȱ option,ȱ anȱ
optimizerȱprocessesȱtheȱobjectȱcodeȱinȱorderȱtoȱmakeȱitȱmoreȱefficient.ȱThisȱoptimizationȱ
takesȱextraȱtime,ȱsoȱitȱisȱusuallyȱnotȱdoneȱuntilȱtheȱprogramȱhasȱbeenȱdebuggedȱandȱisȱ
readyȱtoȱgoȱintoȱproduction.ȱWhetherȱtheȱobjectȱcodeȱisȱproducedȱdirectlyȱorȱisȱinȱtheȱ
formȱ ofȱ assemblyȱ languageȱ statementsȱ thatȱ mustȱ thenȱ beȱ assembledȱ inȱ aȱ separateȱ
phaseȱtoȱformȱtheȱobjectȱfileȱisȱnotȱimportantȱtoȱus.ȱ
ȱ
ȱ
ȱ
Filename Conventions
ȱ
Althoughȱ theȱ Standardȱ doesȱ notȱ haveȱ anyȱ rulesȱ governingȱ theȱ namesȱ usedȱ forȱ tiles,ȱ
mostȱenvironmentsȱhaveȱfilenameȱconventionsȱthatȱyouȱmustȱfollow.ȱCȱsourceȱcodeȱisȱ
usuallyȱputȱinȱfilesȱwhoseȱnamesȱendȱwithȱtheȱ .cȱextension.ȱFilesȱthatȱareȱ #includeȇdȱ
intoȱotherȱCȱsourceȱcodeȱareȱcalledȱheaderȱfilesȱandȱusuallyȱhaveȱnamesȱendingȱinȱ.h.ȱ
Differentȱ environmentsȱ mayȱ haveȱ differentȱ conventionsȱ regardingȱ objectȱ fileȱ
names.ȱ Forȱ example,ȱ theyȱ endȱ withȱ .oȱ onȱ UNIXȱ systemsȱ butȱ withȱ .objȱ onȱ MSȬDOSȱ
systems.ȱ
Download at http://www.pin5i.com/
2.1 Environments 27
Compiling and Linking
ȱ
Theȱ specificȱ commandsȱ usedȱ toȱ compileȱ andȱ linkȱ Cȱ programsȱ varyȱ fromȱ system,ȱ butȱ
manyȱ workȱ theȱ sameȱ asȱ theȱ twoȱ systemsȱ describedȱ here.ȱ Theȱ Cȱ compilerȱ onȱ mostȱ
UNIXȱsystemsȱisȱcalledȱcc,ȱandȱitȱcanȱbeȱinvokedȱinȱaȱvarietyȱofȱways.ȱ
ȱ
ȱ
ȱ
1. ToȱcompileȱandȱlinkȱaȱCȱprogramȱthatȱisȱcontainedȱentirelyȱinȱoneȱsourceȱfile:ȱ
cc program.c
Thisȱcommandȱproducesȱanȱexecutableȱprogramȱcalled a.out.ȱAnȱobjectȱfileȱcalledȱ
program.oȱisȱproduced,ȱbutȱitȱisȱdeletedȱafterȱtheȱlinkingȱisȱcomplete.ȱ
ȱ
2. ToȱcompileȱandȱlinkȱseveralȱCȱsourceȱfiles:ȱ
cc main.c sort.c lookup.c
Theȱ objectȱ filesȱ areȱ notȱ deletedȱ whenȱ moreȱ thanȱ oneȱ sourceȱ fileȱ isȱ compiled.ȱ Thisȱ
factȱ allowsȱ youȱ toȱ recompileȱ onlyȱ theȱ file(s)ȱ thatȱ changedȱ afterȱ makingȱ
modifications,ȱasȱshownȱinȱtheȱnextȱcommand.ȱ
ȱ
3. ToȱcompileȱoneȱCȱsourceȱfileȱandȱlinkȱitȱwhitȱexistingȱobjectȱfiles:ȱ
cc main.o lookup.o sort.c
4. Toȱ compileȱ aȱ singleȱ Cȱ sourceȱ fileȱ andȱ produceȱ anȱ objectȱ fileȱ (inȱ thisȱ case,ȱ calledȱ
program.o)ȱforȱlaterȱlinking:ȱ
cc –c program.c
5. ToȱcompileȱseveralȱCȱsourceȱfilesȱandȱproduceȱanȱobjectȱfileȱforȱeach:ȱ
cc –c main.c sort.c lookup.c
6. Toȱlinkȱseveralȱobjectȱfiles:ȱ
cc main.o sort.o lookup.o
ȱ
ȱ
ȱ
Theȱ –o name optionȱ mayȱ beȱ addedȱ toȱ anyȱ ofȱ theȱ commandsȱ aboveȱ thatȱ produceȱ anȱ
executableȱprogram;ȱitȱcausesȱtheȱlinkerȱtoȱstoreȱtheȱexecutableȱprogramȱinȱaȱfileȱcalledȱ
name ratherȱthanȱ a.out.ȱByȱdefault,ȱtheȱlinkerȱsearchesȱtheȱstandardȱCȱlibrary.ȱTheȱȱȱȱȬ
lnameȱ flagȱ tellsȱ theȱ linkerȱ toȱ alsoȱ searchȱ theȱ libraryȱ calledȱ name;ȱ thisȱ optionȱ shouldȱ
appearȱlastȱonȱtheȱcommandȱline.ȱThereȱareȱotherȱoptionsȱasȱwell;ȱconsultȱyourȱsystemȇȱ
documentation.ȱ
Download at http://www.pin5i.com/
28ȱ Chapter 2 Basic Concepts
Borlandȱ C/C++ȱ 5.0ȱ forȱ MSȬDOS/Windowsȱ hasȱ twoȱ interfacesȱ thatȱ youȱ canȱ use.ȱ
Theȱ Windowsȱ Integratedȱ Developmentȱ Environmentȱ isȱ aȱ completeȱ selfȬcontainedȱ
programmingȱ toolȱ thatȱ containsȱ aȱ sourceȬcodeȱ editor,ȱ debuggers,ȱ andȱ compilers.ȱ Itsȱ
useȱ isȱ beyondȱ theȱ scopeȱ ofȱ thisȱ book.ȱ Theȱ MSȬDOSȱ commandȱ lineȱ interface,ȱ though,ȱ
worksȱmuchȱtheȱsameȱasȱtheȱUNIXȱcompilers,ȱwithȱtheȱfollowingȱexceptions:ȱ
ȱ
1. itsȱnameȱisȱbcc;ȱ
ȱ
2. theȱobjectȱfilesȱareȱnamedȱfile.obj;ȱ
ȱ
3. theȱ compilerȱ doesȱ notȱ deleteȱ theȱ objectȱ fileȱ whenȱ onlyȱ aȱ singleȱ sourceȱ fileȱ isȱ
compiledȱandȱlinked;ȱandȱ
ȱ
4. byȱdefault,ȱtheȱexecutableȱfileȱnamedȱafterȱtheȱfirstȱsourceȱorȱobjectȱfileȱnamedȱonȱ
theȱ commandȱ line,ȱ thoughȱ theȱ –enameȱ optionȱ mayȱ beȱ usedȱ toȱ putȱ theȱ executableȱ
programȱinȱname.exe.ȱ
ȱ
ȱ
ȱ
ȱ
2.1.2 Execution
ȱ
Theȱexecutionȱofȱaȱprogramȱalsoȱgoesȱthroughȱseveralȱphases.ȱFirst,ȱtheȱprogramȱmustȱ
beȱloadedȱintoȱmemory.ȱInȱhostedȱenvironmentsȱ(thoseȱwithȱanȱoperatingȱsystem),ȱthisȱ
taskȱisȱhandledȱbyȱtheȱoperatingȱsystem.ȱItȱisȱatȱthisȱpointȱthatȱpreȬinitializedȱvariablesȱ
thatȱarcȱnotȱstoredȱonȱtheȱstackȱareȱgivenȱtheirȱinitialȱvalues.ȱProgramȱloadingȱmustȱbeȱ
arrangedȱ manuallyȱ inȱ freestandingȱ environments,ȱ perhapsȱ byȱ placingȱ theȱ executableȱ
codeȱinȱreadȬonlyȬmemoryȱ(ROM).ȱȱ
Executionȱofȱtheȱprogramȱnowȱbegins.ȱInȱhostedȱenvironments,ȱaȱsmallȱstartupȱ
routineȱisȱusuallyȱlinkedȱwithȱtheȱprogram.ȱItȱperformsȱvariousȱhousekeepingȱchores,ȱ
suchȱasȱgatheringȱtheȱcommandȱlineȱargumentsȱsoȱthatȱtheȱprogramȱcanȱaccessȱthem.ȱ
Theȱmainȱfunctionȱisȱthanȱcalled.ȱ
Yourȱ codeȱ isȱ nowȱ executed.ȱ Onȱ mostȱ machines,ȱ yourȱ programȱ willȱ useȱ aȱ
runtimeȱ stack,ȱ whereȱ variablesȱ localȱ toȱ functionsȱ andȱ functionȱ returnȱ addressesȱ areȱ
stored.ȱ Theȱ programȱ canȱ alsoȱ useȱ staticȱ memory;ȱ variablesȱ storedȱ inȱ staticȱ memoryȱ
retainȱtheirȱvaluesȱthroughoutȱtheȱprogram’sȱexecution.ȱ
Theȱfinalȱphaseȱisȱtheȱterminationȱofȱtheȱprogram,ȱwhichȱcanȱresultȱfromȱseveralȱ
differentȱ causes.ȱ ȈNormalȈȱ terminationȱ isȱ whenȱ theȱ mainȱ functionȱ returns. 11 ȱ Someȱ
executionȱ environmentsȱ allowȱ theȱ programȱ toȱ returnȱ aȱ codeȱ thatȱ indicatesȱ whyȱ theȱ
programȱ stoppedȱ executing.ȱ Inȱ hostedȱ environments,ȱ theȱ startupȱ routineȱ receivesȱ
11
ȱOrȱwhenȱsomeȱfunctionȱcalls exit,ȱdescribedȱinȱChapterȱ16.ȱ
Download at http://www.pin5i.com/
2.2 Lexical Rules 29
ȱ
controlȱagainȱandȱmayȱperformȱvariousȱhousekeepingȱtasks,ȱsuchȱasȱclosingȱanyȱfilesȱ
thatȱtheȱprogramȱmayȱhaveȱusedȱbutȱdidȱnotȱexplicitlyȱclose.ȱTheȱprogramȱmightȱalsoȱ
haveȱbeenȱinterrupted,ȱperhapsȱdueȱtoȱtheȱuserȱpressingȱtheȱbreakȱkeyȱorȱhangingȱupȱaȱ
telephoneȱconnection,ȱorȱitȱmightȱhaveȱinterruptedȱitselfȱdueȱtoȱanȱerrorȱthatȱoccurredȱ
duringȱexecution.ȱ
ȱ
ȱ
ȱ
2.2 Lexical Rules
ȱ
Theȱ lexicalȱ rules,ȱ likeȱ spellingȱ rulesȱ inȱ English,ȱ governȱ howȱ youȱ formȱ theȱ individualȱ
pieces,ȱcalledȱtokens,ȱofȱaȱsourceȱprogram.ȱ
AnȱANSIȱCȱprogramȱconsistsȱofȱdeclarationsȱandȱfunctions.ȱTheȱfunctionsȱdefineȱ
theȱworkȱtoȱbeȱperformed,ȱwhereasȱtheȱdeclarationsȱdescribeȱtheȱfunctionsȱand/orȱtheȱ
kindȱofȱdataȱ(andȱsometimesȱtheȱdataȱvaluesȱthemselves)ȱonȱwhichȱtheȱfunctionsȱwillȱ
operate.ȱCommentsȱmayȱbeȱinterspersedȱthroughoutȱtheȱsourceȱcode.ȱ
ȱ
ȱ
ȱ
2.2.1 Characters
ȱ
Theȱ Standardȱ doesȱ notȱ requireȱ thatȱ anyȱ specificȱ characterȱ setȱ beȱ usedȱ inȱ aȱ Cȱ
environment,ȱbutȱitȱdoesȱspecifyȱthatȱtheȱcharacterȱsetȱmustȱhaveȱtheȱEnglishȱalphabetȱ
inȱ bothȱ upperȱ andȱ lowercase,ȱ theȱ digitsȱ 0ȱ throughȱ 9,ȱ andȱ theȱ followingȱ specialȱ
characters.ȱ
ȱ
! " # % ' ( ) * + , - . / :
; < > = ? [ ] \ ^ _ { } | ~
Theȱ newlineȱ characterȱ isȱ whatȱ marksȱ theȱ endȱ ofȱ eachȱ lineȱ ofȱ sourceȱ codeȱ and,ȱ whenȱ
characterȱ inputȱ isȱ readȱ byȱ theȱ executingȱ program,ȱ theȱ endȱ ofȱ eachȱ lineȱ ofȱ input.ȱ Ifȱ
neededȱbyȱtheȱruntimeȱenvironment,ȱtheȱȈnewlineȈȱcanȱbeȱaȱsequenceȱofȱcharacters,ȱbutȱ
theyȱareȱallȱtreatedȱasȱifȱtheyȱwereȱaȱsingleȱcharacter.ȱTheȱspace,ȱtab,ȱverticalȱtab,ȱandȱ
formȱ feedȱ charactersȱ areȱ alsoȱ required.ȱ Theseȱ charactersȱ andȱ theȱ newlineȱ areȱ oftenȱ
referredȱ toȱ collectivelyȱ asȱ whiteȱ spaceȱ character,ȱ becauseȱ theyȱ causeȱ spaceȱ toȱ appearȱ
ratherȱthanȱmakingȱmarksȱonȱtheȱpageȱwhenȱtheyȱareȱprinted.ȱ
TheȱStandardȱdefinesȱseveralȱtrigraphsȱ–ȱaȱtrigraphȱisȱaȱsequenceȱofȱcharactersȱ
thatȱrepresentsȱanotherȱcharacter.ȱTrigraphsȱareȱprovidedȱsoȱthatȱCȱenvironmentsȱcanȱ
beȱimplementedȱwithȱcharacterȱsetsȱthatȱlackȱsomeȱofȱtheȱrequiredȱcharacters.ȱHereȱareȱ
theȱtrigraphsȱandȱtheȱcharactersȱthatȱtheyȱrepresent.ȱ
Download at http://www.pin5i.com/
30ȱ Chapter 2 Basic Concepts
??(
??)
??!
[
]
|
??<
??>
??'
{
}
^
??=
??/
??-
#
\
~
ȱ
Thereȱ isȱ noȱ specialȱ significanceȱ toȱ aȱ pairȱ ofȱ questionȱ marksȱ followedȱ byȱ anyȱ otherȱ
character.ȱ
ȱ
ȱ
CAUTION!
Althoughȱ trigraphsȱ areȱ vitalȱ inȱ aȱ fewȱ environments,ȱ theyȱ areȱ aȱ minorȱ nuisanceȱ forȱ
nearlyȱ everyoneȱ else.ȱ Theȱ sequenceȱ ??ȱ wasȱ chosenȱ toȱ beginȱ eachȱ trigrahpȱ becauseȱ itȱ
doesȱ notȱ oftenȱ occurȱ naturally,ȱ butȱ thereinȱ liesȱ theȱ danger.ȱ Youȱ neverȱ thinkȱ aboutȱ
trigraphsȱbecauseȱtheyȱareȱusuallyȱnotȱaȱproblem,ȱsoȱwhenȱoneȱisȱwrittenȱaccidentally,ȱ
asȱinȱ
ȱ
ȱ
printf( "Delete file (are you really sure??): " );
theȱresultingȱ]ȱinȱtheȱoutputȱisȱsureȱtoȱsurpriseȱyou.ȱ
ThereȱareȱaȱfewȱcontextsȱinȱwritingȱCȱsourceȱcodeȱwhereȱyouȱwouldȱlikeȱtoȱuseȱaȱ
particularȱ characterȱ butȱ cannotȱ becauseȱ thatȱ characterȱ hasȱ aȱ specialȱ meaningȱ inȱ thatȱ
context.ȱForȱexample,ȱtheȱquotationȱmarkȱ "ȱisȱusedȱtoȱdelimitȱstringȱliterals.ȱHowȱdoesȱ
oneȱ includeȱ aȱ quotationȱ markȱ withinȱ aȱ stringȱ literal?ȱ K&Rȱ Cȱ definedȱ severalȱ escapeȱ
sequencesȱorȱcharacterȱescapesȱtoȱovercomeȱthisȱdifficulty,ȱandȱANSIȱCȱhasȱaddedȱaȱfewȱ
newȱonesȱtoȱtheȱlist.ȱEscapeȱsequencesȱconsistȱofȱaȱbackslashȱfollowedȱbyȱoneȱorȱmoreȱ
otherȱ characters.ȱ Eachȱ ofȱ theȱ escapeȱ sequencesȱ inȱ theȱ listȱ belowȱ representsȱ theȱ
characterȱthatȱfollowsȱtheȱbackslashȱbutȱwithoutȱtheȱspecialȱmeaningȱusuallyȱattachedȱ
toȱtheȱcharacter.ȱ
ȱ
\?
Usedȱ whenȱ writingȱ multipleȱquestionȱ marksȱ toȱ preventȱ themȱfromȱbeingȱ
interpretedȱasȱtrigraphs.ȱ
\* Usedȱtoȱgetȱquotationȱmarksȱinsideȱofȱstringȱliterals.ȱ
\' Usedȱtoȱwriteȱaȱcharacterȱliteralȱforȱtheȱcharacterȱ'.ȱ
\\ Usedȱ whenȱ aȱ backslashȱ isȱ neededȱ toȱ preventȱ itsȱ beingȱ interpretedȱ asȱ aȱ
characterȱescape.ȱ
ȱ
K&R C
Thereȱareȱmanyȱcharactersȱthatȱareȱnotȱusedȱtoȱexpressȱsourceȱcodeȱbutȱareȱveryȱ
usefulȱ inȱ formattingȱ programȱ outputȱ orȱ manipulatingȱ aȱ terminalȱ displayȱ screen.ȱ
Characterȱescapesȱareȱalsoȱprovidedȱtoȱsimplifyȱtheirȱinclusionȱinȱyourȱprogram.ȱTheseȱ
characterȱescapesȱwereȱchosenȱforȱtheirȱmnemonicȱvalue.ȱ
ȱ
ȱ
Theȱcharacterȱescapesȱmarkedȱwithȱ†ȱareȱnewȱtoȱANSIȱCȱandȱareȱnotȱimplementedȱinȱ
K&RȱC.ȱ
Download at http://www.pin5i.com/
2.2 Lexical Rules 31
ȱ
\a
† Alertȱ character.ȱ Thisȱ ringsȱ theȱ terminalȱ bellȱ orȱ producesȱ someȱ otherȱ
audibleȱorȱvisualȱsignal.ȱ
\b
Backspaceȱcharacter.ȱ
\f
Formfeedȱcharacter.ȱ
\n
Newlineȱcharacter.ȱ
\r
Carriageȱreturnȱcharacter.ȱ
\t
Horizontalȱtabȱcharacter.ȱ
\v
† Verticalȱtabȱcharacter.ȱ
\ddd
dddȱrepresentsȱfromȱoneȱtoȱthreeȱoctalȱdigits.ȱThisȱescapeȱrepresentsȱtheȱ
characterȱwhoseȱrepresentationȱhasȱtheȱgivenȱoctalȱvalue.ȱ
\xddd † Likeȱtheȱabove,ȱexceptȱthatȱtheȱvalueȱisȱspecifiedȱinȱhexadecimal.ȱ
ȱ
Noteȱ thatȱ anyȱ numberȱ ofȱ hexadecimalȱ digitsȱ mayȱ beȱ includedȱ inȱ aȱ \xdddȱ
sequence,ȱbutȱtheȱresultȱisȱundefinedȱifȱtheȱresultingȱvaluedȱisȱlargerȱthanȱwhatȱwillȱfitȱ
inȱaȱcharacter.ȱ
ȱ
ȱ
ȱ
2.2.2 Comments
ȱ
CAUTION!
Cȱcommentsȱbeginȱwithȱtheȱcharactersȱ/*,ȱendȱwithȱtheȱcharactersȱ*/,ȱandȱmayȱcontainȱ
anythingȱ exceptȱ */ȱ inȱ between.ȱ Whereasȱ commentsȱ mayȱ spanȱ multipleȱ linesȱ inȱ theȱ
sourceȱ code,ȱ theyȱ mayȱ notȱ beȱ nestedȱ withinȱ oneȱ another.ȱ Noteȱ thatȱ theseȱ characterȱ
sequencesȱdoȱnotȱbeginȱorȱendȱcommentsȱwhenȱtheyȱappearȱinȱstringȱliterals.ȱ
Eachȱ commentȱ isȱ strippedȱ fromȱ theȱ sourceȱ codeȱ byȱ theȱ preprocessorȱ andȱ
replacedȱ byȱ aȱ singleȱ space.ȱ Commentsȱ mayȱ thereforeȱ appearȱ anywhereȱ thatȱ whiteȱ
spaceȱcharactersȱmayȱappear.ȱ
ȱ
A.ȱcommentȱbeginsȱwhereȱitȱbeginsȱandȱendsȱwhereȱitȱends,ȱandȱitȱincludesȱeverythingȱ
onȱ allȱ theȱ linesȱ inȱ between.ȱ Thisȱ statementȱ mayȱ seemȱ obvious,ȱ butȱ itȱ wasnȇtȱ toȱ theȱ
studentȱwhoȱwroteȱthisȱinnocentȱlookingȱfragmentȱofȱcode.ȱ
Canȱyouȱseeȱwhyȱonlyȱtheȱfirstȱvariableȱisȱinitialized?ȱ
ȱ
x1
x2
x3
x4
CAUTION!
=
=
=
=
0;
0;
0;
0
/***********************
** Initialize the
**
** counter variables. **
***********************/
ȱ
Takeȱcareȱtoȱterminateȱcommentsȱwithȱ*/ȱratherȱthanȱ*?.ȱTheȱlatterȱcanȱoccurȱifȱyouȱareȱ
typingȱrapidlyȱorȱholdȱtheȱshiftȱkeyȱdownȱtooȱlong.ȱThisȱmistakeȱlooksȱobviousȱwhenȱ
pointedȱout,ȱbutȱitȱisȱdeceptivelyȱhardȱtoȱfindȱinȱrealȱprograms.ȱ
ȱ
Download at http://www.pin5i.com/
32ȱ Chapter 2 Basic Concepts
2.2.3 Free Form Source Code
Cȱisȱaȱfreeȱformȱlanguage,ȱmeaningȱthatȱthereȱareȱnoȱrulesȱgoverningȱwhereȱstatementsȱ
canȱbeȱwritten,ȱhowȱmanyȱstatementsȱmayȱappearȱonȱaȱline,ȱwhereȱspacesȱshouldȱbeȱ
put,ȱ orȱ howȱ manyȱ spacesȱ canȱ occur. 12 ȱ Theȱ onlyȱ ruleȱ isȱ thatȱ oneȱ orȱ moreȱ whiteȱ spaceȱ
charactersȱ(orȱaȱcomment)ȱmustȱappearȱbetweenȱtokensȱthatȱwouldȱbeȱinterpretedȱasȱaȱ
singleȱlongȱtokenȱifȱtheyȱwereȱadjacent.ȱThus,ȱtheȱfollowingȱstatementsȱareȱequivalent:ȱ
ȱ
y=x+1;
y = x + 1 ;
y = x
+
1;
Ofȱtheȱnextȱgroupȱofȱstatements,ȱtheȱfirstȱthreeȱareȱequivalent,ȱbutȱtheȱlastȱisȱillegal.ȱ
ȱ
int
x;
int
x;
int/*comment*/x;
intx;
ȱ
Thisȱfreedomȱisȱaȱmixedȱblessing;ȱyouȱwillȱhearȱsomeȱsoapboxȱphilosophyȱaboutȱthisȱ
issueȱshortly.ȱ
ȱ
ȱ
ȱ
2.2.4 Identifiers
ȱ
Identifiersȱ areȱ theȱ namesȱ usedȱ forȱ variables,ȱ functions,ȱ types,ȱ andȱ soȱ forth.ȱ Theyȱ areȱ
composedȱ ofȱ upperȱ andȱ lowercaseȱ letters,ȱ digits,ȱ andȱ theȱ underscoreȱ character,ȱ butȱ
theyȱmayȱnotȱbeginȱwithȱaȱdigit.ȱCȱisȱaȱcaseȱsensitiveȱlanguage,ȱsoȱabc,ȱAbc,ȱabC,ȱandȱABCȱ
areȱfourȱdifferentȱidentifiers.ȱIdentifiersȱmaybeȱanyȱlength,ȱthoughȱtheȱStandardȱallowsȱ
theȱcompilerȱtoȱignoreȱcharactersȱafterȱtheȱfirstȱ31.ȱItȱalsoȱallowsȱanȱimplementationȱtoȱ
restrictȱidentifiersȱforȱexternalȱnamesȱ(thatȱis,ȱthoseȱthatȱtheȱlinkerȱmanipulates)ȱtoȱsixȱ
monocaseȱcharacters.ȱ
12
ȱExceptȱforȱpreprocessorȱdirectives,ȱdescribedȱinȱChapterȱ14,ȱwhichȱareȱlineȱoriented.ȱ
Download at http://www.pin5i.com/
2.3 Program Style 33
TheȱfollowingȱCȱkeywordsȱareȱreserved,ȱmeaningȱthatȱtheyȱcannotȱalsoȱbeȱusedȱ
asȱidentifiers.ȱ
ȱ
auto
break
case
char
const
continue
default
do
double
else
enum
extern
float
for
goto
if
int
long
register
return
short
signed
sizeof
static
struct
switch
typedef
union
unsigned
void
volatile
while
ȱ
ȱ
ȱ
2.2.5 Form of a Program
ȱ
AȱCȱprogramȱmayȱbeȱstoredȱinȱoneȱorȱmoreȱsourceȱtiles.ȱAlthoughȱoneȱsourceȱfileȱmayȱ
containȱ moreȱ thanȱ oneȱ function,ȱ everyȱ functionȱ mustȱ beȱ completelyȱ containedȱ inȱ aȱ
singleȱ sourceȱ file. 13 ȱ Thereȱ areȱ noȱ rulesȱ inȱ theȱ Standardȱ governingȱ thisȱ issue,ȱ butȱ aȱ
reasonableȱ organizationȱ ofȱ aȱ Cȱ programȱ isȱ forȱ eachȱ sourceȱ fileȱ toȱ containȱ aȱ groupȱ ofȱ
relatedȱ functions.ȱ Thisȱ techniqueȱ hasȱ theȱ sideȱ benefitȱ ofȱ makingȱ itȱ possibleȱ toȱ
implementȱabstractȱdataȱtypes.ȱ
ȱ
ȱ
ȱ
2.3 Program Style
ȱ
Aȱ fewȱ commentsȱ onȱ programȱ styleȱ areȱ inȱ order.ȱ Freeformȱ languageȱ suchȱ asȱ Cȱ willȱ
acceptȱ sloppyȱ programs,ȱ whichȱ areȱ quickȱ andȱ easyȱ toȱ writeȱ butȱ difficultȱ toȱ readȱ andȱ
understandȱlater.ȱWeȱhumansȱrespondȱtoȱvisualȱcluesȱsoȱputtingȱthemȱinȱyourȱsourceȱ
codeȱ willȱ aidȱ whoeverȱ mustȱ readȱ itȱ later.ȱ (Thisȱ mightȱ beȱ you!)ȱ Programȱ 2.1ȱ isȱ anȱ
exampleȱthat,ȱalthoughȱadmittedlyȱextreme,ȱillustratesȱtheȱproblem.ȱThisȱisȱaȱworkingȱ
programȱ thatȱ performsȱ aȱ marginallyȱ usefulȱ function.ȱ Theȱ questionȱ is,ȱ whatȱ doesȱ itȱ
do? 14 ȱWorseȱyet,ȱsupposeȱyouȱhadȱtoȱmakeȱaȱmodificationȱtoȱthisȱprogram!ȱAlthoughȱ
experiencedȱCȱprogrammersȱcouldȱfigureȱitȱoutȱgivenȱenoughȱtime,ȱfewȱwouldȱbother.ȱ
Itȱ wouldȱ beȱ quickerȱ andȱ easierȱ toȱ justȱ tossȱ itȱ outȱ andȱ writeȱ aȱ newȱ programȱ fromȱ
scratch.ȱ
ȱTechnically,ȱaȱfunctionȱcouldȱbeginȱinȱoneȱsourceȱfileȱandȱcontinueȱinȱanotherȱifȱtheȱsecondȱwereȱ#includeȇdȱintoȱtheȱfirst.ȱ
However,ȱthisȱprocedureȱisȱnotȱaȱgoodȱuseȱofȱtheȱ#includeȱdirective.ȱ
13
ȱBelieveȱitȱorȱnot,ȱitȱprintsȱtheȱlyricsȱtoȱtheȱsongȱTheȱtwelveȱDaysȱofȱChristmas.ȱTheȱprogramȱisȱaȱminorȱmodificationȱofȱoneȱ
writtenȱbyȱIanȱPhillippsȱofȱCambridgeȱConsultantsȱLtd.ȱforȱtheȱInternationalȱObfuscatedȱCȱCodeȱContestȱ(seeȱ
http://reality.sgi.com/csp/ioccc).ȱReprintedȱbyȱpermission.ȱCopyrightȱ©ȱ1988,ȱLandonȱCurtȱNollȱ&ȱLarryȱBassel.ȱAllȱRightsȱ
Reserved.ȱPermissionȱforȱpersonal,ȱeducationalȱorȱnonȬprofitȱuseȱisȱgrantedȱprovidedȱthisȱcopyrightȱandȱnoticeȱisȱincludedȱinȱ
itsȱentiretyȱandȱremainsȱunaltered.ȱAllȱotherȱusersȱmustȱreceiveȱpriorȱpermissionȱinȱwritingȱformȱbothȱLandonȱCurtȱNollȱandȱ
LarryȱBassel.ȱ
14
Download at http://www.pin5i.com/
34ȱ Chapter 2 Basic Concepts
#include <stdio.h>
main(t,_,a)
char *a;
{return!0<t?t<3?main(-79,-13,a+main(-87,1-_,
main(-86, 0, a+1 )+a)):1,t<_?main(t+1, _, a ):3,main ( -94, -27+t, a
)&&t == 2 ?_<13 ?main ( 2, _+1, "%s %d %d\n" ):9:16:t<0?t<-72?main(_,
t,"@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+,/#{l,+,/n{n+\
,/+#n+,/#;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K w'K:'+}e#';dq#'l q#'+d'K#!/\
+k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/+#n';d}rw' i;# ){n\
l]!/n{n#'; r{#w'r nc{nl]'/#{l,+'K {rw' iK{;[{nl]'/w#q#\
n'wk nw' iwk{KK{nl]!/w{%'l##w#' i; :{nl]'/*{q#'ld;r'}{nlwb!/*de}'c \
;;{nl'-{}rw]'/+,}##'*}#nc,',#nw]'/+kd'+e}+;\
#'rdq#w! nr'/ ') }+}{rl#'{n' ')# }'+}##(!!/")
:t<-50?_==*a ?putchar(a[31]):main(-65,_,a+1):main((*a == '/')+t,_,a\
+1 ):0<t?main ( 2, 2 , "%s"):*a=='/'||main(0,main(-61,*a, "!ek;dc \
i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"),a+1);}
ȱ
Programȱ2.1ȱ Mysteryȱprogramȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
mystery.cȱ
ȱ
ȱ
ȱ
Poorȱ styleȱ andȱ poorȱ documentationȱ areȱ twoȱ ofȱ theȱ reasonsȱ whyȱ softwareȱ isȱ soȱ
TIP
expensiveȱ toȱ createȱ andȱ maintain.ȱ Goodȱ programmingȱ styleȱ goesȱ aȱ longȱ wayȱ towardȱ
makingȱ yourȱ programsȱ easierȱ toȱ read.ȱ Theȱ directȱ resultȱ ofȱ goodȱ styleȱ isȱ thatȱ theȱ
programsȱ areȱ easierȱ toȱ getȱ working.ȱ Theȱ indirectȱ resultȱ isȱ thatȱ theyȱ areȱ easierȱ toȱ
maintain,ȱwhichȱtranslatesȱtoȱbigȱcostȱsavings.ȱ
Theȱexamplesȱinȱthisȱbookȱuseȱaȱstyleȱthatȱemphasizesȱtheȱstructureȱofȱtheȱprogramȱ
throughȱjudiciousȱuseȱofȱwhiteȱspace.ȱHereȱareȱsomeȱofȱtheȱcharacteristicsȱofȱthisȱstyle,ȱ
andȱwhyȱ]ȱchoseȱthemȱ
ȱ
1. Aȱblankȱlineȱseparatesȱstatementsȱintoȱlogicalȱgroupsȱbasedȱonȱtheirȱfunctionality.ȱ
Theȱreaderȱcanȱeasilyȱskipȱanȱentireȱgroupȱwithoutȱhavingȱtoȱreadȱeachȱlineȱofȱcodeȱ
toȱseeȱwhereȱtheȱgroupȱlogicallyȱendsȱ
2. Theȱparenthesesȱinȱifȱandȱrelatedȱstatementsȱareȱpartȱofȱtheȱstatement,ȱnotȱpartȱofȱ
theȱexpressionȱbeingȱtested.ȱThusȱIȱuseȱspacesȱtoȱseparateȱtheȱparenthesesȱfromȱtheȱ
expressionȱ soȱ thatȱ theȱ expressionȱ standsȱ outȱ moreȱ clearly.ȱ Theȱ sameȱ isȱ trueȱ ofȱ
functionȱprototypes.ȱ
3. Spacesȱ areȱ usedȱ aroundȱ mostȱ operatorsȱ inȱ orderȱ toȱ makeȱ expressionsȱ moreȱ
readable.ȱSometimesȱIȱomitȱspacesȱinȱcomplexȱexpressionsȱtoȱshowȱtheȱgroupingȱofȱ
theȱsubexpressions.ȱ
4. Statementsȱ thatȱ areȱ nestedȱ withinȱ otherȱ statementsȱ areȱ indentedȱ toȱ showȱ thisȱ
relationship.ȱItȱisȱeasierȱtoȱlineȱupȱrelatedȱstatementsȱbyȱusingȱtabsȱtoȱindentȱratherȱ
thanȱ spaces.ȱ Itȱ isȱ importantȱ toȱ useȱ aȱ largeȱ enoughȱ indentȱ toȱ beȱ ableȱ toȱ visuallyȱ
Download at http://www.pin5i.com/
2.4 Summary 35
beȱableȱtoȱvisuallyȱlocateȱmatchingȱpartsȱofȱtheȱprogramȱoverȱaȱpageȱofȱcode.ȱTwoȱ
orȱthreeȱspacesȱareȱnotȱenough.ȱ
Someȱpeopleȱavoidȱtabsȱbecauseȱtheyȱthinkȱtabsȱindentȱstatementsȱtooȱmuch.ȱInȱ
complexȱfunctionsȱwithȱdeeplyȱnestedȱstatements,ȱtheȱlargeȱtabȱindentȱmeansȱthatȱ
thereȱisȱlittleȱspaceȱleftȱonȱtheȱlineȱtoȱwriteȱtheȱstatements.ȱHoweverȱifȱtheȱfunctionȱ
isȱ thatȱ complex,ȱ itȱ wouldȱ probablyȱ benefitȱ fromȱ beingȱ brokenȱ intoȱ smallerȱ
functions,ȱ oneȱ ofȱ whichȱ containsȱ theȱ statementsȱ thatȱ wereȱ formerlyȱ nestedȱ soȱ
deeply.ȱ
5. Mostȱcommentsȱareȱwrittenȱinȱblocks,ȱwhichȱmakesȱthemȱstandȱoutȱvisuallyȱformȱ
theȱcode.ȱTheyȱareȱeasierȱforȱtheȱreaderȱtoȱfind,ȱandȱeasierȱtoȱskip.ȱ
6. Inȱtheȱdefinitionȱofȱaȱfunction,ȱtheȱreturnȱtypeȱappearsȱonȱaȱseparateȱlineȱbeforeȱtheȱ
functionȱ name,ȱ whichȱ appearsȱ atȱ theȱ beginningȱ ofȱ theȱ nextȱ line.ȱ Toȱ locateȱ theȱ
definitionȱofȱaȱfunction,ȱsearchȱforȱtheȱfunctionȱnameȱatȱtheȱbeginningȱofȱaȱline.ȱ
Thereȱareȱmanyȱotherȱcharacteristicȱthatȱyouȱwillȱseeȱasȱyouȱstudyȱtheȱcodeȱexamples.ȱ
Otherȱ programmersȱ haveȱ otherȱ personalȱ stylesȱ thatȱ theyȱ prefer.ȱ Whetherȱ youȱ adoptȱ
thisȱ styleȱ orȱ aȱ differentȱ oneȱ isȱ notȱ nearlyȱ asȱ importantȱ asȱ consistentlyȱ usingȱ someȱ
reasonableȱstyle.ȱIfȱyouȱareȱconsistent,ȱanyȱcompetentȱreaderȱwillȱbeȱableȱtoȱfigureȱoutȱ
yourȱcodeȱeasilyȱenough.ȱ
ȱ
ȱ
ȱ
ȱ
2.4 Summary
ȱ
TheȱsourceȱcodeȱofȱaȱCȱprogramȱisȱstoredȱinȱoneȱorȱmoreȱfiles,ȱwithȱeachȱfunctionȱbeingȱ
completelyȱ containedȱ inȱ oneȱ file.ȱ Placingȱ relatedȱ functionsȱ inȱ theȱ sameȱ fileȱ isȱ aȱ goodȱ
strategy.ȱEachȱsourceȱfileȱisȱindividuallyȱcompiledȱtoȱproduceȱanȱobjectȱfile.ȱTheȱobjectȱ
filesȱareȱthenȱlinkedȱtoȱformȱtheȱexecutableȱprogram.ȱThisȱmayȱorȱmayȱnotȱbeȱdoneȱonȱ
theȱsameȱmachineȱthatȱwillȱeventuallyȱrunȱtheȱprogram.ȱ
Theȱprogramȱmustȱbeȱloadedȱintoȱmemoryȱbeforeȱitȱcanȱbeȱexecuted.ȱInȱhostedȱ
environments,ȱ thisȱ taskȱ isȱ performedȱ byȱ theȱ operatingȱ system;ȱ inȱ freestandingȱ
environments,ȱtheȱprogramȱisȱoftenȱstoredȱpermanentlyȱinȱROM.ȱStaticȱvariablesȱthatȱ
haveȱbeenȱinitializedȱareȱgivenȱtheirȱvaluesȱbeforeȱexecutionȱbegins.ȱExecutionȱofȱyourȱ
codeȱ beginsȱ inȱ theȱ mainȱ function.ȱ Mostȱ environmentsȱ useȱ aȱ stackȱ toȱ storeȱ localȱ
variablesȱandȱotherȱdata.ȱ
TheȱcharacterȱsetȱusedȱbyȱaȱCȱimplementationȱmustȱincludeȱcertainȱcharacters.ȱ
Trigraphsȱ allowȱ youȱ toȱ writeȱ charactersȱ thatȱ areȱ missingȱ fromȱ someȱ characterȱ sets.ȱ
Escapeȱ sequencesȱ allowȱ charactersȱ withȱ noȱ printableȱ representation,ȱ suchȱ asȱ whiteȱ
spaceȱcharacters,ȱtoȱbeȱincludedȱinȱaȱprogram.ȱ
Download at http://www.pin5i.com/
36ȱ Chapter 2 Basic Concepts
Commentsȱbeginȱwithȱ/*ȱandȱendȱwithȱ*/,ȱandȱmayȱnotȱbeȱnested.ȱCommentsȱareȱ
removedȱ byȱ theȱ preprocessor.ȱ Identifiersȱ areȱ composedȱ ofȱ letters,ȱ digits,ȱ andȱ theȱ
underscoreȱ character,ȱ andȱ mayȱ notȱ beginȱ withȱ aȱ digit.ȱ Uppercaseȱ andȱ lowercaseȱ
charactersȱareȱdistinctȱfromȱoneȱanotherȱinȱidentifiers.ȱKeywordsȱareȱreservedȱandȱmayȱ
notȱbeȱusedȱasȱidentifiers.ȱCȱisȱaȱfreeȱformȱlanguage;ȱhowever,ȱwritingȱprogramsȱwithȱaȱ
clearȱstyleȱmakesȱthemȱeasierȱtoȱreadȱandȱmaintain.ȱ
ȱ
ȱ
ȱ
2.5 Summary of Cautions
ȱ
1. Charactersȱinȱstringȱliteralsȱbeingȱmistakenlyȱinterpretedȱasȱtrigraphsȱ(pageȱ30).ȱ
2. Badlyȱwrittenȱcommentsȱcanȱunexpectedlyȱencloseȱstatementsȱ(pageȱ31).ȱ
3. Improperȱterminationȱofȱcommentsȱ(pageȱ31).ȱ
ȱ
ȱ
ȱ
2.6 Summary of Programming Tips
ȱ
1. Goodȱ styleȱ andȱ documentationȱ resultȱ inȱ programsȱ thatȱ areȱ easierȱ toȱ readȱ andȱ
maintainȱ(pageȱ34).ȱ
ȱ
ȱ
ȱ
2.7 Questions
ȱ
1. Commentsȱ inȱ Cȱ doȱ notȱ nest.ȱ Whatȱ wouldȱ beȱ theȱ resultȱ ofȱ Ȉcommentingȱ outȈȱ theȱ
codeȱinȱtheȱexampleȱshownȱbelow?ȱ
ȱ
void
squares( int limit )
{
/* Comment out this entire function
int
i;
/* loop counter */
/*
** Print table of squares
*/
for( i = 0; i < limit; i += 1 )
printf( "%d %d0, i, i * i );
End of commented-out code */
}
Download at http://www.pin5i.com/
2.7 Questions 37
2. Whatȱareȱtheȱadvantagesȱofȱputtingȱaȱlargeȱprogramȱintoȱaȱsingleȱsourceȱfile?ȱ
Whatȱareȱtheȱdisadvantages?ȱ
3. Showȱ theȱ stringȱ literalȱ thatȱ youȱ wouldȱ useȱ withȱ printfȱ inȱ orderȱ toȱ printȱ theȱ
followingȱtext,ȱincludingȱtheȱquotationȱmarks:ȱ
"Blunder??!??"
4. Whatȱisȱtheȱvalueȱofȱ\40?ȱOfȱ\100?ȱOfȱ\x40?ȱOfȱ\x100?ȱOfȱ\0123?ȱOfȱ\x0123?ȱ
5. Whatȱisȱtheȱresultȱofȱthisȱstatement?ȱ
int
x/*blah blah*/y;
6. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱdeclaration?ȱ
int
Case, If, While, Stop, stop;
7. Trueȱ orȱ False:ȱ Becauseȱ Cȱ (excludingȱ theȱ preprocessorȱ directives)ȱ isȱ aȱ freeȬformȱ
language,ȱ theȱ onlyȱ rulesȱ thatȱ governȱ howȱ programsȱ areȱ writtenȱ areȱ theȱ syntaxȱ
rules,ȱsoȱitȱdoesnȇtȱmatterȱhowȱtheȱprogramȱactuallyȱlooks.ȱ
8. Isȱtheȱloopȱinȱtheȱfollowingȱprogramȱcorrect?ȱ
ȱ
#include < stdio.h>
int
main( void )
{
int
x, y;
x = 0;
while( x < 10 ){
y = x * x;
printf( "%d\t%d\n", x, y );
x += 1;
}
ȱ
Isȱtheȱloopȱinȱthisȱprogramȱcorrect?ȱ
ȱ
#include <stdio.h>
int
main( void )
{
int
x, y;
Download at http://www.pin5i.com/
38ȱ Chapter 2 Basic Concepts
x = 0;
while( x < 10 ){
y = x * x;
printf( "%d\t%d\n", x, y );
x += 1;
}
Whichȱprogramȱwasȱeasierȱtoȱcheck?ȱ
9. SupposeȱyouȱhaveȱaȱCȱprogramȱwhoseȱmainȱfunctionȱisȱinȱtheȱfileȱ main.cȱandȱhasȱ
otherȱfunctionsȱinȱtheȱfilesȱ list.cȱandȱ report.c.ȱWhatȱcommand(s)ȱwouldȱyouȱuseȱ
onȱyourȱsystemȱtoȱcompileȱandȱlinkȱthisȱprogram?ȱ
10. Howȱwouldȱyouȱmodifyȱtheȱcommandȱforȱtheȱpreviousȱquestionȱinȱorderȱtoȱlinkȱaȱ
libraryȱcalledȱparseȱwithȱtheȱprogram?ȱ
11. Supposeȱ youȱ haveȱ aȱ Cȱ programȱ composedȱ ofȱ severalȱ separateȱ files,ȱ andȱ theyȱ
includeȱoneȱanotherȱasȱshownȱbelow.ȱ
ȱ
File
Includes Files
main.c
list.c
symbol.c
table.c
table.h
stdio.h, table.h
list.h
symbol.h
table.h
symbol.h, list.h
ȱ
Whichȱ filesȱ wouldȱ haveȱ toȱ beȱ recompiledȱ afterȱ youȱ makeȱ aȱ changeȱ toȱ list.c?ȱ Toȱ
list.h?ȱToȱtable.h?ȱ
ȱ
ȱ
ȱ
2.8 Programming Exercises
ȱ
1. Writeȱ aȱ programȱ withȱ threeȱ functionsȱ inȱ threeȱ separateȱ sourceȱ files.ȱ Theȱ functionȱ
incrementȱ shouldȱ takeȱ aȱ singleȱ integerȱ argumentȱ andȱ returnȱ theȱ valueȱ ofȱ thatȱ
argumentȱplusȱone.ȱThisȱfunctionȱshouldȱbeȱinȱtheȱfile increment.cȱ
Theȱ secondȱ functionȱ isȱ calledȱ negate.ȱ Itȱ alsoȱ takesȱ aȱ singleȱ integerȱ argumentȱ andȱ
returnȱtheȱnegatedȱvalueȱofȱthatȱargumentȱ(forȱexample,ȱifȱtheȱargumentȱisȱ25,ȱtheȱ
functionȱshouldȱreturnȱȬ25;ȱifȱtheȱargumentȱisȱȬ612,ȱtheȱfunctionȱshouldȱreturnȱ612).ȱ
Theȱ finalȱ functionȱ isȱ main,ȱ inȱ theȱ fileȱ main.c,ȱ andȱ itȱ shouldȱ callȱ eachȱ ofȱ theȱ otherȱ
functionsȱwithȱtheȱvaluesȱ10,ȱ0,ȱandȱȬ10ȱandȱprintȱtheȱresults.ȱ
2. WriteȱaȱprogramȱthatȱwillȱreadȱCȱsourceȱcodeȱfromȱtheȱstandardȱinputȱandȱensureȱ
thatȱ theȱ bracesȱ areȱ pairedȱ correctly.ȱ Note:ȱ youȱ needȱ notȱ worryȱ aboutȱ bracesȱ thatȱ
appearȱwithinȱcomments,ȱstringȱliterals,ȱorȱcharacterȱconstants.ȱ
Download at http://www.pin5i.com/
3
Data
Programsȱ operateȱ onȱ data,ȱ andȱ thisȱ chapterȱ describesȱ data:ȱ itsȱ variousȱ types,ȱ itsȱ
characteristics,ȱ andȱ howȱ toȱ declareȱ it.ȱ Threeȱ propertiesȱ ofȱ variablesȱ –ȱ theirȱ scope,ȱ
linkage,ȱ andȱ storageȱ classȱ –ȱ areȱ alsoȱ described.ȱ Theseȱ threeȱ propertiesȱ determineȱ theȱ
ȈvisibilityȈȱofȱaȱvariableȱ(thatȱis,ȱwhereȱitȱcanȱbeȱused)ȱandȱitsȱȈlifetimeȈȱ(howȱlongȱitsȱ
valueȱlasts).ȱ
ȱ
ȱ
ȱ
3.1 Basic Data Types
ȱ
Thereȱ areȱ onlyȱ fourȱ basicȱ dataȱ typesȱ inȱ Cȱ –ȱ integers,ȱ floatingȬpointȱ values,ȱ pointers,ȱ
andȱ aggregateȱ typesȱ suchȱ asȱ arraysȱ andȱ structures.ȱ Allȱ otherȱ typesȱ areȱ derivedȱ fromȱ
someȱcombinationȱofȱtheseȱfour.ȱLetȇsȱbeginȱbyȱintroducingȱtheȱintegersȱandȱfloatingȬ
pointȱtypes.ȱ
ȱ
ȱ
ȱ
3.1.1 The Integer Family
ȱ
Theȱintegerȱfamilyȱcontainsȱcharacters,ȱshortȱintegers,ȱintegers,ȱandȱlongȱintegers.ȱAllȱhaveȱ
bothȱsignedȱandȱunsignedȱversions.ȱ
ItȱsoundsȱasȱthoughȱaȱȈlongȱintegerȈȱoughtȱtoȱbeȱableȱtoȱholdȱlargerȱvaluesȱthanȱ
aȱ Ȉshortȱ integer,Ȉȱ butȱ thisȱ assumptionȱ isȱ notȱ necessarilyȱ true.ȱ Theȱ ruleȱ regardingȱ theȱ
relativeȱsizesȱofȱintegersȱisȱsimple:ȱ
ȱ
Longȱintegersȱareȱasȱleastȱasȱlargeȱasȱintegers,ȱwhichȱthemselvesȱareȱatȱleastȱasȱlargeȱasȱ
shortȱintegers.ȱ
Download at http://www.pin5i.com/
40 Chapter 3 Data
ȱ
Type
char
signed char
unsigned char
short int
unsigned short int
int
unsigned int
long int
unsigned long int
K&R C
Minimum Range
0ȱtoȱ127ȱ
Ȭ127ȱtoȱ127ȱ
0ȱtoȱ255ȱ
Ȭ32767ȱtoȱ32767ȱ
0ȱtoȱ65535ȱ
Ȭ32767ȱtoȱ32767ȱ
0ȱtoȱ65535ȱ
Ȭ2147483647ȱtoȱ2147483647ȱ
0ȱtoȱ4294967295ȱ
ȱ
Tableȱ3.1ȱMinimumȱvariableȱrangesȱ
ȱ
Noteȱ thatȱ thereȱ isȱ noȱ requirementȱ thatȱ aȱ longȱ integerȱ actuallyȱ beȱ longerȱ thanȱ aȱ shortȱ
integer,ȱ itȱ simplyȱ cannotȱ beȱ anyȱ shorter.ȱ Theȱ ANSIȱ Standardȱ addsȱ aȱ specificationȱ forȱ
theȱ minimumȱ allowableȱ rangeȱ ofȱ valuesȱ thatȱ eachȱ differentȱ typeȱ mayȱ represent,ȱ asȱ
shownȱ inȱ Tableȱ 3.1.ȱ Thisȱ specificationȱ isȱ aȱ bigȱ improvementȱ overȱ K&Rȱ Cȱ whenȱ
portabilityȱ amongȱ environmentsȱ isȱ important,ȱ especiallyȱ whenȱ theȱ environmentsȱ areȱ
onȱmachinesȱwithȱwildlyȱdifferentȱarchitectures.ȱ
Aȱ short intȱmustȱbeȱatȱleastȱ16ȱbits,ȱandȱaȱ long intȱatȱleastȱ32ȱbits. Itȱisȱupȱtoȱ
theȱimplementorȱtoȱdecideȱwhetherȱtoȱmakeȱtheȱdefaultȱintȱ16ȱorȱ32ȱbits,ȱorȱsomethingȱ
else.ȱ Usuallyȱ theȱ defaultȱ isȱ chosenȱ toȱ beȱ whateverȱ isȱ mostȱ naturalȱ (efficient)ȱ forȱ theȱ
machine.ȱ Noteȱ thatȱ thereȱ isȱ stillȱ noȱ requirementȱ thatȱ theȱ threeȱ sizesȱ actuallyȱ beȱ
different.ȱAnȱenvironmentȱforȱaȱmachineȱwithȱ32Ȭbilȱwordsȱandȱnoȱinstructionsȱtoȱdealȱ
effectivelyȱwithȱshorterȱintegralȱvaluesȱcouldȱimplementȱthemȱallȱasȱ32Ȭbitȱintegers.ȱ
Theȱ includeȱ file limits.h specifiesȱ theȱ characteristicsȱ ofȱ theȱ variousȱ integerȱ
types.ȱ Itȱ definesȱ theȱ namesȱ shownȱ inȱ Tableȱ 3.2. limits.h alsoȱ definesȱ theȱ followingȱ
names.ȱ CHAR_BITȱ isȱ theȱ numberȱ ofȱ bitsȱ inȱ aȱ characterȱ (atȱ leastȱ eight).ȱ CHAR_MINȱ andȱ
CHAR_MAXȱdefineȱtheȱrangeȱforȱtheȱdefaultȱ
ȱ
ȱ
Signed
Unsigned
Type
Minimum Value
Maximum Value
Maximum Value
SCHAR_MIN
SCHAR_MAX
UCHAR_MAX
Characterȱ
SHRT_MIN
SHRT_MAX
USHRT_MAX
Shortȱintegerȱ
INT_MIN
INT_MAX
UINT_MAX
Integerȱ
LONG_MIN
LONG_MAX
ULONG_MAX
Longȱintegerȱ
ȱ
Talbeȱ3.2ȱLimitsȱofȱvariableȱrangesȱ
Download at http://www.pin5i.com/
3.1 Basic Data Types 41
characterȱtype;ȱtheseȱwillȱbeȱtheȱsameȱasȱeitherȱ SCHAR_MINȱandȱ SCHAR_MAXȱorȱzeroȱandȱ
UCHAR_MAX.ȱ Finally,ȱ MB_LEN_MAXȱ specifiesȱ theȱ maximumȱ numberȱ ofȱ charactersȱ inȱ aȱ
multibyteȱcharacter.ȱ
Althoughȱ theȱ intentionȱ behindȱ charȱ variablesȱ isȱ forȱ themȱ toȱ holdȱ characters,ȱ
charactersȱareȱactuallyȱtinyȱintegerȱvalues.ȱTheȱdefaultȱcharȱisȱalwaysȱeitherȱaȱ signed
charȱorȱan unsigned char,ȱbutȱwhatȱyouȱgetȱdependsȱonȱtheȱcompiler.ȱThisȱfactȱmeansȱ
thatȱaȱ charȱonȱdifferentȱmachinesȱmightȱholdȱdifferentȱrangesȱofȱvalues,ȱsoȱprogramsȱ
thatȱuseȱ charȱvariablesȱareȱportableȱonlyȱifȱtheyȱrestrictȱtheseȱvariablesȱtoȱvaluesȱinȱtheȱ
intersectionȱ ofȱ theȱ signedȱ andȱ unsignedȱ ranges,ȱ forȱ example,ȱ theȱ charactersȱ inȱ theȱ
ASCIIȱcharacterȱsetȱallȱfallȱwithinȱthisȱrange.ȱ
Theȱ portabilityȱ ofȱ programsȱ thatȱ useȱ charactersȱ asȱ littleȱ integersȱ canȱ beȱ
improvedȱ byȱ explicitlyȱ declaringȱ theseȱ variablesȱ asȱ eitherȱ signedȱ orȱ unsigned.ȱ Thisȱ
practiceȱensuresȱthatȱtheirȱsigned—nessȱisȱconsistentȱfromȱmachineȱtoȱmachine.ȱOnȱtheȱ
otherȱhand,ȱdealingȱwithȱsignedȱcharactersȱonȱaȱmachineȱthatȱisȱmoreȱcomfortableȱwithȱ
unsignedȱ charactersȱ willȱ beȱ lessȱ efficient,ȱ soȱ declaringȱ allȱ charȱ variablesȱ asȱ eitherȱ
signedȱorȱ unsignedȱisȱprobablyȱnotȱaȱgoodȱidea.ȱAlso,ȱmanyȱlibraryȱfunctionsȱdealingȱ
withȱ charactersȱ declareȱ theirȱ argumentsȱ asȱ char,ȱ whichȱ mayȱ causeȱ aȱ compatibilityȱ
problemȱwithȱargumentsȱthatȱareȱexplicitlyȱdeclaredȱsignedȱorȱunsigned.ȱ
TIP
Whenȱportabilityȱisȱanȱissue,ȱtheȱsignedȬnessȱofȱcharactersȱposesȱaȱdilemma.ȱTheȱbestȱ
compromiseȱ isȱ toȱ limitȱ theȱ valuesȱ storedȱ inȱ charȱ variablesȱ toȱ theȱ intersectionȱ ofȱ theȱ
signedȱ andȱ unsignedȱ ranges,ȱ whichȱ maximizesȱ portabilityȱ withoutȱ sacrificingȱ
efficiency,ȱandȱperformȱarithmeticȱonlyȱon charȱvariablesȱthatȱareȱexplicitlyȱsignedȱorȱ
unsigned.ȱ
ȱ
ȱ
ȱ
Integer Literals
ȱ
Theȱ termȱ literalȱ isȱ anȱ abbreviationȱ forȱ literalȱ constant—anȱ entityȱ thatȱ specifiesȱ itsȱ ownȱ
value,ȱ andȱ whoseȱ valueȱ cannotȱ beȱ changed.ȱ Thisȱ distinctionȱ isȱ importantȱ becauseȱ
ANSIȱCȱallowsȱtheȱcreationȱofȱnamedȱconstantsȱ(variablesȱdeclaredȱtoȱbeȱ const),ȱwhichȱ
areȱveryȱmuchȱlikeȱordinaryȱvariablesȱexceptȱthat,ȱonceȱinitialized,ȱtheirȱvaluesȱcannotȱ
beȱchanged.ȱȱ
Whenȱ anȱ integerȱ literalȱ isȱ writtenȱ inȱ aȱ program,ȱ whichȱ ofȱ theȱ nineȱ differentȱ
typesȱ ofȱ theȱ integerȱ familyȱ doesȱ itȱ have?ȱ Theȱ answerȱ dependsȱ onȱ howȱ theȱ literalȱ isȱ
written,ȱbutȱtheȱdefaultȱrulesȱcanȱbeȱoverriddenȱforȱsomeȱliteralsȱbyȱappendingȱaȱsuffixȱ
toȱtheȱendȱofȱtheȱvalue.ȱTheȱcharactersȱ Lȱand lȱ(that’sȱanȱel,ȱnotȱtheȱdigitȱone)ȱcauseȱaȱ
literalȱtoȱbeȱinterpretedȱasȱaȱlongȱintegerȱvalue,ȱandȱtheȱcharactersȱ Uȱandȱ uȱspecifyȱanȱ
unsignedȱvalue.ȱAȱliteralȱmayȱbeȱdesignatedȱ unsigned longȱbyȱappendingȱoneȱofȱeachȱ
toȱit.ȱ
Download at http://www.pin5i.com/
42 Chapter 3 Data
Thereȱ areȱ manyȱ differentȱ waysȱ toȱ specifyȱ integerȱ literalsȱ inȱ sourceȱ code.ȱ Theȱ
mostȱnaturalȱareȱdecimalȱintegerȱvalues,ȱsuchȱasȱthese:ȱ
ȱ
123
65535
-275
15
Decimalȱ literalsȱ areȱ eitherȱ int,ȱ long,ȱ orȱ unsigned long.ȱ Theȱ shortestȱ typeȱ thatȱ willȱ
containȱtheȱvalueȱisȱwhatȱisȱusedȱbyȱdefault.ȱ
Integersȱcanȱbeȱgivenȱinȱoctalȱbyȱstartingȱwithȱtheȱdigitȱzero,ȱorȱinȱhexadecimalȱ
byȱstartingȱwithȱ0x,ȱasȱinȱ
ȱ
0173
0x7b
0177777
0xFFFF
000060
0xabcdef00
ȱ
Theȱdigitsȱ8ȱandȱ9ȱareȱillegalȱinȱoctalȱliterals;ȱtheȱcharactersȱABCDEFȱorȱabcdefȱmayȱallȱbeȱ
usedȱasȱdigitsȱinȱhexadecimalȱliterals.ȱOctalȱandȱhexadecimalȱliteralsȱareȱ int,ȱ unsigned
int, longȱ,ȱorȱ unsigned long;ȱtheȱshortestȱoneȱthatȱisȱbigȱenoughȱtoȱholdȱtheȱvaluedȱisȱ
whatȱisȱusedȱbyȱdefault.ȱ
Andȱ thenȱ thereȱ areȱ characterȱ literals.ȱ Theseȱ alwaysȱ haveȱ typeȱ int;ȱ youȱ cannotȱ
useȱtheȱunsignedȱorȱlongȱsuffixesȱonȱthem.ȱAȱcharacterȱliteralȱisȱaȱsingleȱcharacterȱ(orȱ
characterȱescapeȱorȱtrigraph)ȱenclosedȱinȱapostrophies,ȱasȱinȱ
ȱ
'M'
'\n'
\'??('
'\3777'
ȱ
Multibyeȱ characterȱ literalsȱ suchȱ asȱ ȇabcȇȱ areȱ allowedȱ byȱ theȱ Standard,ȱ butȱ theirȱ
implementationȱ mayȱ varyȱ fromȱ oneȱ environmentȱ toȱ theȱ nextȱ soȱ theirȱ useȱ isȱ
discouraged.ȱ
Finally,ȱ wideȱ characterȱ literalsȱ areȱ writtenȱ asȱ anȱ Lȱ followedȱ byȱ aȱ multibyteȱ
characterȱliteral,ȱasȱin:ȱ
ȱ
L'X'
TIP
L'e^'
ȱ
Theseȱareȱusedȱwhenȱtheȱruntimeȱenvironmentȱsupportsȱaȱlargeȱcharacterȱset.ȱ
ȱ
Whenȱ youȱ needȱ anȱ integerȱ literal,ȱ theȱ compilerȱ doesnȇtȱ careȱ whichȱ formȱ youȱ write,ȱ
althoughȱitȱmakesȱaȱbigȱdifferenceȱtoȱaȱhumanȱreader.ȱWhichȱformȱyouȱchoose,ȱthen,ȱ
shouldȱ beȱ determinedȱ byȱ theȱ contextȱ inȱ whichȱ theȱ literalȱ isȱ used.ȱ Mostȱ literalsȱ areȱ
writtenȱ inȱ decimalȱ formȱ becauseȱ itȱ theȱ mostȱ naturalȱ forȱ peopleȱ toȱ read.ȱ Hereȱ areȱ aȱ
coupleȱofȱexamplesȱwhereȱotherȱtypesȱofȱintegerȱliteralsȱareȱmoreȱappropriate.ȱ
ȱ Technically,ȱ -275ȱ isȱ notȱ aȱ literalȱ constantȱ butȱ aȱ constantȱ expression.ȱ Theȱ minusȱ signȱ isȱ interpretedȱ asȱ aȱ unaryȱ operatorȱ
insteadȱofȱbeingȱpartȱofȱtheȱnumber.ȱThisȱambiguityȱhasȱlittleȱpracticalȱconsequence,ȱthough,ȱasȱtheȱexpressionȱisȱevaluatedȱ
byȱtheȱcompilerȱandȱhasȱtheȱdesireȱeffectȱ
15
Download at http://www.pin5i.com/
3.1 Basic Data Types 43
Aȱ literalȱ thatȱ identifiesȱ certainȱ bitȱ positionsȱ withinȱ aȱ wordȱ wouldȱ beȱ betterȱ
writtenȱasȱaȱhexadecimalȱorȱoctalȱvalue,ȱbecauseȱtheseȱformsȱdisplayȱmoreȱclearlyȱtheȱ
specialȱnatureȱofȱtheȱvalue.ȱForȱexample,ȱtheȱvalueȱ 983040ȱhasȱaȱ1Ȭbitȱinȱpositionsȱl6—
l9,ȱ butȱ youȱ wouldȱ neverȱ guessȱ itȱ fromȱ lookingȱ atȱ itsȱ decimalȱ value.ȱ Writtenȱ inȱ
hexadecimal,ȱthough,ȱtheȱvalueȱisȱ 0xF0000,ȱwhichȱclearlyȱshowsȱthoseȱbitsȱasȱlȱandȱtheȱ
remainingȱbitsȱ0.ȱIfȱthisȱvalueȱisȱbeingȱusedȱinȱaȱcontextȱinȱwhichȱtheseȱspecificȱbitsȱareȱ
important,ȱ forȱ exampleȱ asȱ aȱ maskȱ toȱ extractȱ theȱ correspondingȱ bitsȱ fromȱ aȱ variable,ȱ
thenȱ writingȱ theȱ literalȱ inȱ hexadecimalȱ makesȱ theȱ meaningȱ ofȱ theȱ operationȱ muchȱ
clearerȱtoȱaȱhumanȱreader.ȱȱ
lfȱaȱvalueȱisȱgoingȱtoȱbeȱusedȱasȱaȱcharacter,ȱexpressingȱtheȱvalueȱasȱaȱcharacterȱ
literalȱ makesȱ clearerȱ theȱ meaningȱ thatȱ isȱ intendedȱ forȱ theȱ value.ȱ Forȱ example,ȱ theȱ
statementsȱ
ȱ
value = value – 48;
value = value – \60;
ȱ
areȱentirelyȱequivalentȱinȱoperationȱtoȱ
ȱ
value = value – '0' ;
ȱ
butȱ itȱ isȱ muchȱ easierȱ toȱ seeȱ fromȱ theȱ latterȱ thatȱ theȱ digitȱ storedȱ inȱ valueȱ isȱ beingȱ
convertedȱfromȱaȱcharacterȱtoȱaȱbinaryȱvalue.ȱMoreȱimportantly,ȱtheȱcharacterȱconstantȱ
yieldsȱ theȱ correctȱ valueȱ noȱ matterȱ whichȱ characterȱ setȱ isȱ used.ȱ soȱ itȱ improvesȱ
portability.ȱ
ȱ
ȱ
ȱ
Enumerated Type
ȱ
Anȱ enumeratedȱ typeȱ isȱ oneȱ whoseȱ valuesȱ areȱ symbolicȱ constantsȱ ratherȱ thanȱ literal.ȱ
Theseȱareȱdeclaredȱinȱthisȱfashion:ȱ
ȱ
enum Jar_Type { CUP, PINT, QUART,
HALF_GALLON, GALLON };
ȱ
whichȱdeclaresȱaȱtypeȱcalledȱJar_Type.ȱVariablesȱofȱthisȱtypeȱareȱdeclaredȱlikeȱthis:ȱ
ȱ
enum Jar_Type milk_jug, gas_can, medicine_bottle;
ȱ
Ifȱ thereȱ isȱ onlyȱ oneȱ declarationȱ ofȱ variablesȱ ofȱ aȱ particularȱ enumeratedȱ type,ȱ bothȱ
statementsȱmayȱbeȱcombinedȱlikeȱthis:ȱ
ȱ
enum { CUP, PINT, QUART, HALF_GALLON, GALLON }
ȱ
ȱ
milk_jug,ȱgas_can,ȱmedicine_bottle;ȱ
Download at http://www.pin5i.com/
44 Chapter 3 Data
Theȱ variablesȱ areȱ inȱ factȱ storedȱ asȱ integers,ȱ andȱ theȱ valuesȱ usedȱ internallyȱ toȱ
representȱtheȱsymbolicȱnamesȱareȱtheȱintegerȱvaluesȱ0ȱforȱCUP,ȱ1ȱforȱPINT,ȱetc.ȱWhereȱ
appropriate,ȱspecificȱintegerȱvaluesȱmayȱbeȱspecifiedȱforȱtheȱsymbolicȱnamesȱlikeȱthis:ȱ
ȱ
enum Jar_Type { CUP=8, PINT=16, QUART=32,
HALF_GALLON=64, GALLON=128 };
TIP
ȱ
Itȱisȱlegalȱforȱonlyȱsomeȱofȱtheȱsymbolsȱtoȱbeȱgivenȱvaluesȱthisȱway.ȱAnyȱsymbolȱnotȱ
givenȱanȱexplicitȱvalueȱgetsȱaȱvalueȱoneȱgreaterȱthanȱtheȱsymbolȱbeforeȱit.ȱ
ȱ
Theȱ symbolicȱ namesȱ areȱ treatedȱ asȱ integerȱ constants,ȱ andȱ variablesȱ declaredȱ withȱ anȱ
enumeratedȱtypeȱareȱactuallyȱintegers.ȱThisȱfactȱmeansȱthatȱyouȱcanȱsassingȱtheȱliteralȱȬ
623ȱ toȱ aȱ variableȱ ofȱ typeȱ Jar_Type,ȱ andȱ youȱ canȱ assignȱ theȱ valueȱ HALF_GALLONȱ toȱ anyȱ
integerȱ variable.ȱ Avoidȱ usingȱ enumerationsȱ inȱ thisȱ manner,ȱ however,ȱ becauseȱ theirȱ
valueȱisȱweakenedȱbyȱmixingȱthemȱindiscriminatelyȱwithȱintegers.ȱ
ȱ
ȱ
ȱ
3.1.2 Floating-Pint Types
ȱ
Numbersȱsuchȱasȱ3.14159ȱandȱ6.023×1023ȱcannotȱbeȱstoredȱasȱintegers.ȱTheȱfirstȱisȱnotȱaȱ
wholeȱ number,ȱ andȱ theȱ secondȱ isȱ farȱ tooȱ large.ȱ Theyȱ can,ȱ however,ȱ beȱ storedȱ asȱ
floatingȬpointȱ values.ȱ Theseȱ areȱ usuallyȱ storedȱ asȱ aȱ fractionȱ andȱ anȱ exponentȱ ofȱ someȱ
assumedȱbase,ȱsuchȱasȱ
ȱ
ȱ
.3243F×161ȱ ȱ
.11001001000111111×22
ȱ
bothȱ ofȱ whichȱ representȱ theȱ valueȱ 3.14159.ȱ Thereȱ areȱ manyȱ differentȱ methodsȱ ofȱ
representingȱfloatingȬpointȱvalues;ȱtheȱStandardȱdoesȱnotȱdictateȱanyȱspecificȱformat.ȱȱ
TheȱfloatingȬpointȱfamilyȱincludes float, double, and long double types.ȱTheseȱ
typesȱ usuallyȱ provideȱ singleȱ precision,ȱ doubleȱ precision,ȱ andȱ onȱ machinesȱ thatȱ
supportȱ it,ȱ extendedȱ precisionȱ valuesȱ respectively.ȱ Theȱ ANSIȱ Standardȱ requiresȱ onlyȱ
thatȱlongȱdoublesȱbeȱatȱleastȱasȱlongȱasȱ doubles,ȱwhichȱthemselvesȱmustȱbeȱatȱleastȱasȱ
bigȱ asȱ floats. Itȱ alsoȱ imposesȱ aȱ minimumȱ range;ȱ allȱ floatingȬpointȱ typesȱ mustȱ beȱ
capableȱofȱstoringȱvaluesȱinȱtheȱrangeȱȬ1037ȱthroughȱ1037.ȱ
Anȱincludeȱfileȱcalledȱ float.hȱdefinesȱtheȱnamesȱ FLT_MAX,ȱ DBL_MAX,ȱ LDBL_MAXȱtoȱ
theȱ maximumȱ valuesȱ thatȱ canȱ beȱ storedȱ inȱ aȱ float,ȱ double,ȱ andȱ longȱ double,ȱ
respectively;ȱminimumȱvaluesȱareȱgivenȱbyȱFLT_MIN.ȱ
Download at http://www.pin5i.com/
3.1 Basic Data Types 45
DBL_MIN,ȱ andȱ LDBL_MIN.ȱ Additionalȱ namesȱ thatȱ specifyȱ certainȱ characteristicsȱ ofȱ theȱ
floatingȬpointȱ implementation,ȱ suchȱ asȱ theȱ radixȱ beingȱ usedȱ andȱ theȱ numberȱ ofȱ
significantȱdigitsȱtheȱdifferentȱlengthsȱhave,ȱareȱalsoȱdefinedȱhere.ȱ
Floatingȱpointȱliteralsȱareȱalwaysȱwrittenȱinȱdecimalȱandȱmustȱcontainȱeitherȱaȱ
decimalȱpoint,ȱanȱexponent,ȱorȱboth.ȱHereȱareȱsomeȱexamples:ȱ
ȱ
3.14159
1E10
25.
.5
6.023e23
ȱ
Floatingȱ pointȱ literalsȱ areȱ doubleȱ valuesȱ unlessȱ theyȱ areȱ followedȱ byȱ aȱ suffix:ȱ Lȱ orȱ 1ȱ
specifyȱlong double,ȱandȱFȱorȱfȱspecify float.ȱ
ȱ
ȱ
ȱ
3.1.3 Pointers
ȱ
PointersȱareȱaȱmajorȱreasonȱwhyȱtheȱCȱlanguageȱisȱpopular.ȱPointersȱallowȱtheȱefficientȱ
implementationȱofȱadvancedȱdataȱstructuresȱsuchȱasȱtreesȱandȱlists.ȱOtherȱlanguages,ȱ
suchȱ asȱ Pascalȱ andȱ ModulaȬ2,ȱ implementȱ pointersȱ butȱ doȱ notȱ allowȱ arithmeticȱ orȱ
comparisonsȱtoȱbeȱperformedȱonȱthem.ȱNorȱdoȱtheyȱallowȱanyȱwayȱofȱcreatingȱpointersȱ
toȱexistingȱdataȱobjects.ȱTheȱlackȱofȱsuchȱrestrictionsȱisȱwhatȱallowsȱtheȱCȱprogrammerȱ
toȱ produceȱ programsȱ matȱ areȱ moreȱ efficientȱ andȱ compactȱ thanȱ programsȱ inȱ otherȱ
languages.ȱAtȱtheȱsameȱtime,ȱtheȱunrestrictedȱuseȱofȱpointersȱinȱCȱisȱtheȱcauseȱofȱmuchȱ
weepingȱandȱgnashingȱofȱteethȱbyȱbothȱbeginningȱandȱexperiencedȱCȱprogrammers.ȱ
Theȱ valuesȱ ofȱ variablesȱ areȱ storedȱ inȱ theȱ computerȇsȱ memory,ȱ eachȱ atȱ aȱ
particularȱlocation.ȱEachȱmemoryȱlocationȱisȱidentifiedȱandȱreferencedȱwithȱanȱaddress,ȱ
justȱ asȱ theȱ housesȱ onȱ aȱ streetȱ canȱ beȱ locatedȱ byȱ theirȱ address.ȱ Pointerȱ isȱ justȱ anotherȱ
nameȱforȱanȱaddress;ȱatȱpointerȱvariableȱisȱaȱvariableȱwhoseȱvalueȱisȱtheȱaddressȱofȱsomeȱ
otherȱmemoryȱlocation.ȱThereȱareȱoperatorsȱthatȱallowȱyouȱtoȱobtainȱtheȱaddressȱofȱaȱ
variableȱ andȱ toȱ followȱ aȱ pointerȱ variableȱ toȱ theȱ valueȱ orȱ dataȱ structureȱ toȱ whichȱ itȱ
points,ȱbutȱweȱwillȱdiscussȱthoseȱinȱChapterȱ5.ȱ
Theȱ ideaȱ ofȱ accessingȱ dataȱ byȱ itsȱ addressȱ insteadȱ ofȱ byȱ itsȱ nameȱ frequentlyȱ
causesȱconfusion.ȱItȱshouldnȇt,ȱbecauseȱyouȱhaveȱbeenȱdoingȱthisȱallȱyourȱlife.ȱLocatingȱ
housesȱonȱaȱstreetȱbyȱtheirȱaddressȱisȱexactlyȱtheȱsameȱthing.ȱNoȱoneȱeverȱconfusesȱtheȱ
addressȱofȱaȱhouseȱwithȱitsȱcontents;ȱnoȱoneȱeverȱmistakenlyȱwritesȱaȱletterȱtoȱȈMr.ȱ428ȱ
ElmhurstȱSt.ȈȱlivingȱatȱȈRobertȱSmith.Ȉȱ
Aȱpointerȱisȱexactlyȱtheȱsame.ȱImagineȱtheȱcomputerȇsȱmemoryȱasȱhousesȱalongȱ
aȱveryȱlongȱstreet,ȱeachȱidentifiedȱbyȱitsȱownȱuniqueȱnumber.ȱEachȱlocationȱcontainsȱaȱ
value,ȱwhichȱisȱseparateȱandȱdistinctȱfromȱitsȱaddress,ȱevenȱthoughȱbothȱaxeȱnumbers.ȱ
Download at http://www.pin5i.com/
46 Chapter 3 Data
Pointer Constants
ȱ
Pointerȱconstantsȱareȱfundamentallyȱdifferentȱfromȱnonpointerȱconstants.ȱBecauseȱtheȱ
compilerȱtakesȱcareȱofȱassigningȱvariablesȱtoȱlocationsȱinȱtheȱcomputer’sȱmemory,ȱtheȱ
programmerȱ usuallyȱ hasȱ noȱ wayȱ ofȱ knowingȱ inȱ advanceȱ whereȱ someȱ particularȱ
variableȱ willȱ reside.ȱ Therefore,ȱ youȱ obtainȱ theȱ addressȱ ofȱ aȱ variableȱ byȱ usingȱ anȱ
operatorȱratherȱthanȱwritingȱitsȱaddressȱasȱaȱliteralȱconstant.ȱForȱexample,ȱifȱweȱwantȱ
theȱaddressȱofȱtheȱvariableȱ xyz,ȱweȱcannotȱ writeȱaȱliteralȱsuchȱasȱ 0xff2044ecȱbecauseȱ
weȱhaveȱnoȱwayȱofȱknowingȱwhetherȱthatȱisȱwhereȱtheȱcompilerȱwillȱactuallyȱputȱtheȱ
variable.ȱIndeed,ȱanȱautomaticȱvariableȱmayȱbeȱallocatedȱatȱdifferentȱplacesȱeachȱtimeȱaȱ
functionȱ isȱ called.ȱ Thus,ȱ thereȱ isȱ littleȱ useȱ forȱ pointerȱ constantsȱ expressedȱ asȱ literalȱ
numericȱvalues,ȱsoȱthereȱisȱnoȱnotationȱbuiltȱintoȱCȱspecificallyȱforȱthem. 16
ȱ
ȱ
ȱ
String Literals
ȱ
Manyȱ peopleȱ findȱ itȱ strangeȱ thatȱ thereȱ isȱ noȱ stringȱ typeȱ inȱ C,ȱ yetȱ theȱ languageȱ hasȱ aȱ
stringȱliteral.ȱThereȱisȱinȱfactȱaȱnotionȱofȱaȱstring,ȱaȱsequenceȱofȱzeroȱorȱmoreȱcharactersȱ
terminatedȱ byȱ NULȱ byte.ȱ Stringsȱ areȱ usuallyȱ storedȱ inȱ characterȱ arrays,ȱ whichȱ isȱ whyȱ
thereȱ isȱ noȱ explicitȱ stringȱ type.ȱ Becauseȱ theȱ NULȱ isȱ usedȱ toȱ terminateȱ strings,ȱ itȱ isȱ notȱ
possibleȱforȱaȱstringȱtoȱcontainȱ NULs.ȱThisȱrestrictionȱisȱusuallyȱnotȱaȱproblem,ȱthough;ȱ
NULȱwasȱchosenȱasȱterminatorȱbecauseȱitȱhasȱnoȱprintableȱgraphicȱassociatedȱwithȱit.ȱ
Stringȱ literalsȱ areȱ writtenȱ asȱ aȱ sequenceȱ ofȱ charactersȱ enclosedȱ inȱ quotationȱ
marks,ȱlikeȱthese:ȱ
ȱ
"Hello"
K&R C
16
"\aWarning!\a"
"Line 1\nLine2"
""
ȱ
Theȱ lastȱ exampleȱ illustratesȱ thatȱ aȱ stringȱ literalȱ (unlikeȱ aȱ characterȱ literal)ȱ mayȱ beȱ
empty;ȱtheȱterminatingȱNULȱbyteȱwillȱalwaysȱbeȱthere,ȱthough.ȱ
ȱ
Stringȱ literalsȱ causeȱ theȱ specifiedȱ charactersȱ andȱ aȱ terminatingȱ NULȱ byteȱ toȱ beȱ storedȱ
somewhereȱinȱtheȱprogram.ȱK&RȱCȱmadeȱnoȱmentionȱasȱtoȱwhetherȱtheȱcharactersȱinȱaȱ
stringȱ literalȱ couldȱ beȱ modifiedȱ byȱ theȱ program,ȱ butȱ itȱ explicitlyȱ statedȱ thatȱ stringȱ
literalsȱwithȱidenticalȱvaluesȱwereȱstoredȱseparately.ȱManyȱimplementations,ȱtherefore,ȱ
allowedȱliteralsȱtoȱbeȱmodifiedȱbyȱtheȱprogram.ȱ
ANSIȱ Cȱ statesȱ thatȱ theȱ effectȱ ofȱ modifyingȱ aȱ stringȱ literalȱ isȱ undefined.ȱ Itȱ alsoȱ
allowsȱtheȱcompilerȱtoȱstoreȱaȱstringȱliteralȱonceȱevenȱifȱitȱappearsȱmanyȱtimesȱinȱtheȱ
sourceȱ code.ȱ Thisȱ factȱ makesȱ modifyingȱ stringȱ literalsȱ extremelyȱ risky,ȱ becauseȱ aȱ
changeȱ madeȱ toȱ oneȱ literalȱ mayȱ changeȱ theȱ valueȱ ofȱ otherȱ stringȱ literalsȱ inȱ theȱ
ȱThereȱisȱoneȱexception:ȱtheȱNULLȱpointer,ȱwhichȱcanȱbeȱexpressedȱasȱtheȱvalueȱzero.ȱSeeȱChapterȱ6ȱforȱmoreȱinformation.ȱ
Download at http://www.pin5i.com/
3.2 Basic Declarations 47
program.ȱ Therefore,ȱ manyȱ ANSIȱ compilersȱ doȱ notȱ letȱ youȱ modifyȱ stringȱ literals,ȱ orȱ
provideȱcompileȬtimeȱoptionsȱtoȱletȱyouȱchooseȱwhetherȱorȱnotȱyouȱwantȱmodificationȱ
ofȱliteralsȱtoȱbeȱallowed.ȱAvoidȱthisȱpractice:ȱifȱyouȱneedȱtoȱmodifyȱaȱstring,ȱstoreȱitȱinȱ
enȱarrayȱinstead.ȱ
Iȱ discussȱ stringȱ literalsȱ alongȱ withȱ pointersȱ becauseȱ usingȱ aȱ stringȱ literalȱ inȱ atȱ
programȱ generatesȱ aȱ Ȉconstantȱ pointerȱ toȱ character.Ȉȱ Whenȱ aȱ stringȱ literalȱ appearsȱ inȱ
anȱexpression,ȱtheȱvalueȱusedȱinȱtheȱexpressionȱisȱtheȱaddressȱwhereȱitsȱcharactersȱwereȱ
stored,ȱnotȱtheȱcharactersȱthemselves.ȱThus,ȱyouȱcanȱassignȱaȱstringȱliteralȱtoȱaȱvariableȱ
ofȱtypeȱȈpointerȱtoȱcharacter,Ȉȱwhichȱmakesȱtheȱvariableȱpointȱtoȱwhereȱtheȱcharactersȱ
areȱstored.ȱYouȱcannotȱassignȱaȱstringȱliteralȱtoȱaȱcharacterȱarray,ȱthough,ȱbecauseȱtheȱ
immediateȱvalueȱofȱtheȱliteralȱisȱaȱpointer,ȱnotȱtheȱcharactersȱthemselves.ȱ
lfȱ notȱ beingȱ ableȱ toȱ assignȱ orȱ copyȱ stringsȱ soundsȱ inconvenient,ȱ youȱ shouldȱ
knowȱ thatȱ theȱ standardȱ Cȱ libraryȱ includesȱ aȱ suiteȱ ofȱ functionsȱ whoseȱ purposeȱ isȱ toȱ
manipulateȱ strings.ȱ Theȱ suiteȱ includesȱ functionsȱ toȱ copy,ȱ concatenate,ȱ compare,ȱ andȱ
computeȱtheȱlengthȱofȱstringsȱandȱtoȱsearchȱstringsȱforȱspecificȱcharacters.ȱ
ȱ
ȱ
ȱ
3.2 Basic Declarations
ȱ
Knowingȱtheȱbasicȱdataȱtypesȱisȱofȱlittleȱuseȱunlessȱyouȱcanȱdeclareȱvariables.ȱTheȱbasicȱ
formȱofȱaȱdeclarationȱisȱ
ȱ
ȱ
specifier(s)ȱdeclaration_expression_listȱ
ȱ
Forȱsimpleȱtypes,ȱtheȱdeclaration_expression_listȱisȱjustȱaȱlistȱofȱtheȱidentifiersȱbeingȱ
declared.ȱ Forȱ moreȱ involvedȱ types,ȱ eachȱ ofȱ theȱ itemsȱ inȱ theȱ listȱ isȱ actuallyȱ anȱ
expressionȱthatȱshowsȱhowȱtheȱnameȱbeingȱdeclaredȱmightȱbeȱused.ȱlfȱthisȱideaȱseemsȱ
obscureȱnow,ȱdon‘tȱworry,ȱweȱexploreȱitȱinȱmoreȱdetailȱshortly.ȱ
Theȱ specifier(s)ȱ includesȱ keywordsȱ thatȱ describeȱ theȱ baseȱ typeȱ ofȱ theȱ
identifiersȱbeingȱdeclared.ȱSpecifiersȱmayȱalsoȱbeȱgivenȱtoȱchangeȱtheȱdefaultȱstorageȱ
classȱandȱscopeȱofȱtheȱidentifier.ȱWeȱdiscussȱtheseȱtopicsȱshortly.ȱȱ
YouȱsawȱsomeȱbasicȱdeclarationsȱinȱtheȱsampleȱprogramȱinȱChapterȱ1.ȱHereȱareȱ
aȱcoupleȱmore.ȱ
ȱ
int
char
i;
j, k, l;
ȱ
Theȱfirstȱdeclarationȱindicatesȱthatȱtheȱvariableȱiȱisȱanȱinteger.ȱTheȱsecondȱdeclaresȱj,ȱk,ȱ
andȱlȱtoȱbeȱcharacterȱvariables.ȱ
Download at http://www.pin5i.com/
48 Chapter 3 Data
Theȱspecifiersȱmayȱincludeȱkeywordsȱtoȱmodifyȱtheȱlengthȱand/orȱsignednessȱofȱ
theȱidentifier.ȱTheseȱincludeȱ
ȱ
short
long
signed
unsigned
ȱ
Also,ȱtheȱkeywordȱintȱmayȱbeȱomittedȱfromȱtheȱdeclarationȱofȱanyȱintegralȱtypeȱ
ifȱ atȱ leastȱ oneȱ otherȱ specifierȱ isȱ givenȱ inȱ theȱ declaration.ȱ Thus,ȱ theȱ followingȱ twoȱ
declarationsȱareȱequivalent:ȱ
ȱ
unsigned short int
unsigned short
a;
a;
ȱ
Tableȱ 3.3ȱ showsȱ allȱ ofȱ theȱ variationsȱ onȱ theseȱ declarations.ȱ Theȱ declarationsȱ withinȱ
eachȱboxȱareȱequivalent.ȱTheȱsignedȱkeywordȱisȱordinarilyȱusedȱonlyȱforȱcharsȱbecauseȱ
theȱotherȱintegerȱtypesȱareȱsignedȱbyȱdefault.ȱItȱisȱimplementationȱdependentȱwhetherȱ
charȱ isȱ signedȱ orȱ unsigned,ȱ soȱ charȱ isȱ equivalentȱ toȱ eitherȱ signedȱ charȱ orȱ unsigned
char.ȱTableȱ3.3ȱdoesȱnotȱincludeȱthisȱequivalence.ȱ
Theȱ situationȱ isȱ simplerȱ withȱ theȱ floatingȬpointȱ types,ȱ becauseȱ noneȱ ofȱ theȱ
specifiersȱareȱapplicableȱexceptȱfor long double.ȱ
ȱ
ȱ
ȱ
3.2.1 Initialization
ȱ
Aȱ declarationȱ mayȱ specifyȱ anȱ initialȱ valueȱ forȱ aȱ scalarȱ variableȱ byȱ followingȱ theȱ
variableȱnameȱwithȱanȱequalȱsignȱandȱtheȱdesiredȱvalue.ȱForȱexample,ȱ
ȱ
int
j = 15;
ȱ
declares jȱtoȱbeȱanȱintegerȱvariableȱandȱassignsȱitȱtheȱvalueȱ15.ȱWeȱreturnȱtoȱtheȱtopicȱ
ofȱinitializationȱagainȱlaterȱinȱthisȱchapter.ȱ
ȱ
ȱ
short
short int
int
long
long int
signed
signed
signed
signed
signed
singed
short
short int
int
long
long int
ȱ
Tableȱ3.3ȱEquivalentȱintegerȱdeclarationsȱ
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
short
short int
int
long
long int
Download at http://www.pin5i.com/
3.2 Basic Declarations 49
3.2.2 Declaring Simple Arrays
ȱ
Toȱ declareȱ aȱ oneȬdimensionalȱ array,ȱ theȱ arrayȱ nameȱ isȱ followedȱ byȱ aȱ subscriptȱ thatȱ
specifiesȱ theȱ numberȱ ofȱ elementsȱ inȱ theȱ array.ȱ Thisȱ isȱ theȱ firstȱ exampleȱ ofȱ theȱ
declaration_expression mentionedȱearlier.ȱForȱexample,ȱconsiderȱtheȱdeclaration:ȱ
ȱ
int
values[20];
ȱ
Theȱ obviousȱ interpretationȱ ofȱ thisȱ declarationȱ isȱ thatȱ weȱ areȱ declaringȱ anȱ arrayȱ ofȱ 20ȱ
integers.ȱThisȱinterpretationȱisȱcorrect,ȱbutȱthereȱisȱaȱbetterȱwayȱtoȱreadȱtheȱdeclaration.ȱ
Theȱnameȱ values,ȱwhenȱfollowedȱbyȱaȱsubscript,ȱyieldsȱanȱvalueȱofȱtypeȱ intȱ(andȱbyȱ
theȱway,ȱthereȱareȱ20ȱofȱthem).ȱTheȱȈdeclarationȱexpressionȈȱshowsȱtheȱidentifierȱusedȱ
inȱanȱexpressionȱthatȱresultsȱinȱaȱvalueȱofȱtheȱbaseȱtype,ȱintegerȱinȱthisȱcase.ȱ
Theȱsubscriptsȱofȱarraysȱalwaysȱbeginȱatȱzeroȱandȱextendȱthroughȱoneȱlessȱthanȱ
theȱ declaredȱ sizeȱ ofȱ theȱ array.ȱ Thereȱ isȱ noȱ wayȱ toȱ changeȱ thisȱ property,ȱ butȱ ifȱ youȱ
absolutelyȱmustȱhaveȱanȱarrayȱwhoseȱsubscriptsȱbeginȱatȱten,ȱitȱisȱnotȱdifficultȱtoȱjustȱ
subtractȱtenȱinȱeachȱofȱyourȱsubscripts.ȱȱ
AnotherȱaspectȱofȱarraysȱinȱCȱisȱthatȱtheȱcompilerȱdoesȱnotȱcheckȱtheȱsubscriptsȱ
toȱseeȱwhetherȱtheyȱareȱinȱtheȱproperȱrange. 17 ȱTheȱlackȱofȱcheckingȱisȱbothȱgoodȱandȱ
bad.ȱItȱisȱgoodȱbecauseȱthereȱisȱnoȱtimeȱlostȱcheckingȱarrayȱsubscriptsȱthatȱareȱknownȱ
toȱbeȱcorrect,ȱandȱitȱisȱbadȱbecauseȱinvalidȱsubscriptsȱareȱnotȱdetected.ȱAȱgoodȱruleȱofȱ
thumbȱtoȱuseȱis:ȱ
ȱ
Ifȱaȱsubscriptȱwasȱcomputedȱfromȱvaluesȱthatȱareȱalreadyȱknownȱtoȱbeȱcorrect,ȱthenȱthereȱ
isȱnoȱneedȱtoȱcheckȱitsȱvalue.ȱAnyȱvalueȱthatȱisȱderivedȱinȱanyȱwayȱfromȱdataȱthatȱtheȱ
userȱhasȱenteredȱmustȱbeȱcheckedȱbeforeȱbeingȱusedȱasȱaȱsubscriptȱtoȱensureȱthatȱitȱisȱinȱ
theȱproperȱrange.ȱ
ȱ
WeȱcoverȱtheȱinitializationȱofȱarraysȱinȱChapterȱ8.ȱ
ȱ
ȱ
ȱ
3.2.3 Declaring Pointers
ȱ
Declarationȱ expressionsȱ areȱ alsoȱ usedȱ toȱ declareȱ pointers.ȱ Inȱ Pascalȱ andȱ Modula,ȱ aȱ
declarationȱ givesȱ aȱ listȱ ofȱ identifiersȱ followedȱ byȱ theirȱ type.ȱ Inȱ C,ȱ theȱ baseȱ typeȱ isȱ
given,ȱfollowedȱbyȱaȱlistȱofȱidentifiersȱusedȱinȱtheȱexpressionsȱneededȱtoȱproduceȱthatȱ
baseȱtype.ȱForȱexample,ȱ
ȱ Itȱ isȱ technicallyȱ possibleȱ forȱ aȱ compilerȱ toȱ accuratelyȱ checkȱ subscriptȱ valuesȱ butȱ doingȱ soȱ involvesȱ aȱ lotȱ ofȱ additionalȱ
overhead.ȱ Someȱ laterȱ compilers,ȱ suchȱ asȱ Borlandȱ C++ȱ 5.0,ȱ implementȱ subscriptȱ checkingȱ asȱ aȱ debuggingȱ toolȱ thatȱ canȱ beȱ
turnedȱonȱorȱoff.ȱ
17
Download at http://www.pin5i.com/
50 Chapter 3 Data
int
CAUTION!
*a;
ȱ
statesȱ thatȱ theȱ expressionȱ *aȱ resultsȱ inȱ theȱ typeȱ int.ȱ Knowingȱ thatȱ theȱ *ȱ operatorȱ
performsȱindirection,ȱweȱcanȱinferȱthatȱaȱmustȱbeȱaȱpointerȱtoȱanȱinteger. 18
ȱ
Theȱ freeȱ formȱ natureȱ ofȱ Cȱ makesȱ itȱ temptingȱ toȱ writeȱ theȱ asteriskȱ nearȱ theȱ type,ȱ likeȱ
this:ȱ
int*
a;
ȱ
Thisȱdeclarationȱhasȱtheȱsameȱmeaningȱasȱtheȱpreviousȱone,ȱandȱitȱnowȱseemsȱtoȱmoreȱ
clearlyȱdeclareȱthatȱaȱisȱofȱtype int *.ȱThisȱtechniqueȱisȱnotȱgood,ȱandȱhereȱisȱwhy.ȱ
ȱ
ȱ
int* b, c, d;
ȱ
Peopleȱ naturallyȱ readȱ thisȱ statementȱ asȱ declaringȱ allȱ threeȱ variablesȱ toȱ beȱ pointersȱ toȱ
integersȱbutȱitȱdoesnȇt.ȱWeȱareȱfooledȱbyȱhowȱitȱlooks.ȱTheȱasteriskȱisȱreallyȱpartȱofȱtheȱ
expressionȱ *bȱ andȱ appliesȱ onlyȱ toȱ thatȱ oneȱ identifier,ȱ bȱ isȱ aȱ pointer,ȱ theȱ otherȱ twoȱ
variablesȱareȱordinaryȱintegers.ȱHereȱisȱtheȱcorrectȱdeclarationȱforȱthreeȱpointers.ȱ
ȱ
int
*b, *c, *d;
ȱ
ȱ
Declarationsȱ ofȱ pointerȱ variablesȱ mayȱ alsoȱ specifyȱ initialȱ valuesȱ forȱ theȱ
variables.ȱHereȱisȱanȱexampleȱinȱwhichȱaȱpointerȱisȱdeclaredȱandȱinitializedȱtoȱaȱstringȱ
literal.ȱ
ȱ
char
CAUTION!
*message = "Hello world!";
ȱ
Thisȱ statementȱ declaresȱ messageȱ toȱ beȱ aȱ pointerȱ toȱ aȱ characterȱ andȱ initializesȱ theȱ
pointerȱtoȱtheȱaddressȱofȱtheȱfirstȱcharacterȱinȱtheȱstringȱliteral.ȱ
ȱ
Oneȱdangerȱwithȱthisȱtypeȱofȱinitializationȱisȱthatȱitȱisȱeasyȱtoȱmisinterpretȱitsȱmeaning.ȱ
Inȱ theȱ previousȱ declaration,ȱ itȱ appearsȱ thatȱ theȱ initialȱ valueȱ isȱ assignedȱ toȱ theȱ
expressionȱ *messageȱ whenȱ inȱ factȱ theȱ valueȱ isȱ assignedȱ toȱ messageȱ itself.ȱ Inȱ otherȱ
words,ȱtheȱpreviousȱdeclarationȱisȱequivalentȱto:ȱ
ȱ
char
message
*message;
= "Hello world!";
ȱIndirectionȱisȱonlyȱlegalȱonȱaȱpointerȱvalue.ȱTheȱpointerȱpointsȱtoȱtheȱresult,ȱandȱtheȱindirectionȱȈfollowsȈȱtheȱpointerȱtoȱ
obtainȱtheȱresult.ȱSeeȱChapterȱ6ȱforȱȱmoreȱdetails.ȱ
18
Download at http://www.pin5i.com/
3.3 Typedef 51
3.2.4 Implicit Declarations
ȱ
Thereȱ areȱ aȱ fewȱ declarationsȱ inȱ whichȱ typeȱ namesȱ mayȱ beȱ omittedȱ altogether.ȱ
Functions,ȱ forȱ example,ȱ areȱ assumedȱ toȱ returnȱ integersȱ unlessȱ declaredȱ otherwise.ȱ
Whenȱdeclaringȱformalȱparametersȱtoȱfunctionsȱinȱtheȱoldȱstyle,ȱanyȱparametersȱwhoseȱ
declarationsȱ areȱ omittedȱ areȱ assumedȱ toȱ beȱ integers.ȱ Finally,ȱ ifȱ theȱ compilerȱ canȱ seeȱ
enoughȱ toȱ determineȱ thatȱ aȱ statementȱ isȱ inȱ factȱ aȱ declaration,ȱ anȱ omittedȱ typeȱ isȱ
assumedȱtoȱbeȱinteger.ȱ
Considerȱthisȱprogram:ȱ
ȱ
int
a[10];
int
c;
b[10];
d;
f( x )
{
return x + 1;
}
ȱ
Theȱ firstȱ andȱ secondȱ linesȱ areȱ notȱ unusual,ȱ howeverȱ theȱ thirdȱ andȱ fourthȱ linesȱ areȱ
illegalȱ inȱ ANSIȱ C.ȱ Theȱ thirdȱ lineȱ omitsȱ theȱ type,ȱ butȱ thereȱ isȱ enoughȱ informationȱ leftȱ
thatȱ someȱ K&Rȱ compilersȱ canȱ stillȱ figureȱ outȱ thatȱ theȱ statementȱ isȱ aȱ declaration.ȱ
Amazingly,ȱaȱfewȱK&Rȱcompilersȱcorrectlyȱprocessȱtheȱfourthȱlineȱasȱaȱdeclarationȱtoo.ȱ
Theȱfunctionȱ fȱisȱassumedȱtoȱreturnȱanȱinteger,ȱandȱitsȱargumentȱisȱassumedȱtoȱbeȱanȱ
integer.ȱ
ȱ
Dependingȱ onȱ implicitȱ declarationsȱ isȱ aȱ badȱ idea.ȱ Anȱ implicitȱ declarationȱ alwaysȱ
leavesȱaȱquestionȱinȱtheȱreadersȱmind:ȱWasȱtheȱomissionȱofȱtheȱtypeȱintended,ȱorȱdidȱ
theȱprogrammerȱsimplyȱforgetȱtheȱproperȱdeclaration?ȱExplicitȱdeclarationsȱmakeȱyourȱ
intentȱclear.ȱ
ȱ
ȱ
ȱ
3.3 Typedef
ȱ
Cȱ supportsȱ aȱ mechanismȱ calledȱ typedef,ȱ whichȱ allowsȱ youȱ toȱ defineȱ newȱ namesȱ forȱ
variousȱ dataȱ types.ȱ Typedefsȱ areȱ writtenȱ exactlyȱ theȱ sameȱ asȱ ordinaryȱ declarationsȱ
exceptȱ thatȱ theȱ keywordȱ typedefȱ appearsȱ atȱ theȱ beginning.ȱ Forȱ example,ȱ theȱ
declarationȱ
ȱ
char
*ptr_to_char;
ȱ
declaresȱtheȱvariableȱ ptr_to_charȱtoȱbeȱaȱpointerȱtoȱaȱcharacter.ȱButȱaddȱtheȱkeywordȱ
typedefȱandȱyouȱget.ȱ
Download at http://www.pin5i.com/
52 Chapter 3 Data
typedef char
*ptr_to_char;
ȱ
whichȱ declaresȱ theȱ identifierȱ ptr_to_charȱ toȱ beȱ aȱ newȱ nameȱ forȱ theȱ typeȱ pointerȱ toȱ
character.ȱ Youȱ canȱ useȱ theȱ newȱ nameȱ inȱ subsequentȱ declarationsȱ justȱ likeȱ anyȱ ofȱ theȱ
predefinedȱnames.ȱForȱexample,ȱȱ
ȱ
ȱ
ptr_to_char a;
ȱ
declaresȱaȱtoȱbeȱaȱpointerȱtoȱaȱcharacter.ȱȱ
Usingȱ aȱ typedefȱ toȱ declareȱ types,ȱ particularlyȱ complexȱ ones,ȱ reducesȱ theȱ chancesȱ ofȱ
messingȱupȱaȱdeclaration. 19 ȱFurthermore,ȱifȱyouȱshouldȱdecideȱlaterȱtoȱchangeȱtheȱtypeȱ
ofȱsomeȱkindȱofȱdataȱbeingȱusedȱinȱyourȱprogram,ȱchangingȱoneȱ typedefȱisȱeasierȱthanȱ
changingȱallȱdeclarationȱofȱallȱvariablesȱ(andȱfunctions)ȱinȱtheȱprogramȱthatȱdealȱwithȱ
thatȱdata.ȱ
ȱ
Useȱ typedef ratherȱ thanȱ #defineȱ forȱ creatingȱ newȱ typeȱ names,ȱ becauseȱ theȱ latterȱ isȱ
unableȱtoȱproperlyȱhandleȱpointerȱtypes.ȱForȱexample,ȱ
ȱ
#define d_ptr_to_char
char *
d_ptr_to_char
a, b;
ȱ
declaresȱ aȱ properlyȱ butȱ declaresȱ bȱ toȱ beȱ aȱ character.ȱ Definitionsȱ ofȱ namesȱ forȱ moreȱ
complexȱ types,ȱ suchȱ asȱ pointersȱ toȱ functionsȱ orȱ arrays,ȱ areȱ alsoȱ handledȱ betterȱ withȱ
typedef.ȱ
ȱ
ȱ
ȱ
3.4 Constants
ȱ
ANSIȱ Cȱ allowsȱ youȱ toȱ declareȱ constants,ȱ whichȱ areȱ exactlyȱ likeȱ variablesȱ exceptȱ thatȱ
theirȱ valuesȱ cannotȱ beȱ changed.ȱ Youȱ useȱ theȱ constȱ keywordȱ toȱ declareȱ constants,ȱ asȱ
shownȱinȱtheȱfollowingȱexamples.ȱ
ȱ
int
const a;
const int
a;
ȱ
Bothȱ ofȱ theseȱ statementsȱ declareȱ aȱ toȱ beȱ anȱ integerȱ whoseȱ valueȱ cannotȱ beȱ changed.ȱ
Pickȱwhicheverȱformȱofȱdeclarationȱyouȱfindȱeasiestȱtoȱunderstandȱandȱstickȱwithȱit.ȱ
Ofȱ course,ȱ ifȱ aȇsȱ valueȱ cannotȱ beȱ changed,ȱ youȱ canȇtȱ assignȱ anythingȱ toȱ it,ȱ soȱ
howȱ doȱ youȱ giveȱ itȱ aȱ valueȱ inȱ theȱ firstȱ place?ȱ Thereȱ areȱ twoȱ ways.ȱ First,ȱ youȱ canȱ
initializeȱitȱinȱtheȱdeclaration,ȱlikeȱthis:ȱ
19
ȱtypedefȱisȱparticularlyȱusefulȱwithȱstructures;ȱseeȱChapterȱ10ȱforȱsomeȱexamples.ȱ
Download at http://www.pin5i.com/
3.4 Constants 53
int
const a = 15;
ȱ
Second,ȱ constȱ formalȱ parametersȱ ofȱ aȱ functionȱ areȱ givenȱ theȱ valuesȱ ofȱ theȱ actualȱ
argumentsȱwhenȱaȱfunctionȱcallȱisȱperformed.ȱȱ
Theȱ situationȱ becomesȱ moreȱ interestingȱ withȱ pointerȱ variables,ȱ becauseȱ thereȱ
areȱtwoȱthingsȱthatȱmightȱbeȱconstant—theȱpointerȱvariableȱandȱtheȱentityȱtoȱwhichȱitȱ
points.ȱHereȱareȱsomeȱsampleȱdeclarations:ȱ
ȱ
int
*pi;
ȱ
piȱisȱanȱordinaryȱpointerȱtoȱanȱinteger.ȱTheȱvariableȱ
ȱ
int
const *pci;
ȱ
pciȱisȱaȱpointerȱtoȱaȱconstantȱinteger.ȱYouȱcanȱchangeȱtheȱpointer’sȱvalueȱbutȱnotȱtheȱ
valueȱtoȱwhichȱitȱpoints.ȱContrastȱthisȱexampleȱwithȱcpi:ȱ
ȱ
int
* const cpi;
ȱ
whichȱ isȱ aȱ constantȱ pointerȱ toȱ anȱ integer.ȱ Hereȱ theȱ pointerȱ isȱ theȱ constant;ȱ itsȱ valueȱ
cannotȱchange,ȱbutȱyouȱareȱfreeȱtoȱmodifyȱtheȱintegerȱtoȱwhichȱitȱpoints.ȱ
ȱ
int
TIP
const * const
cpci
ȱ
Finally,ȱthereȱisȱ cpci;ȱinȱthisȱexampleȱbothȱtheȱpointerȱandȱtheȱvalueȱtoȱwhichȱitȱpointsȱ
areȱconstant;ȱ
ȱ
Useȱtheȱ constȱkeywordȱwhenȱdeclaringȱvariablesȱwhoseȱvaluesȱwillȱnotȱchange.ȱThisȱ
practiceȱ notȱ onlyȱmakesȱyourȱ intentȱmoreȱ clearȱ toȱ othersȱ readingȱ theȱ program,ȱ butȱitȱ
alsoȱletsȱtheȱcompilerȱcatchȱplacesȱwhereȱsuchȱaȱvalueȱisȱaccidentallyȱmodified.ȱ
Theȱ #defineȱdirectiveȱisȱanotherȱmechanismȱforȱcreatingȱnamedȱconstant. 20 ȱForȱ
example,ȱbothȱofȱtheȱfollowingȱstatementsȱcreateȱaȱnamedȱconstantȱforȱtheȱvalueȱ50.ȱ
ȱ
#define
int
MAX_ELEMENTS
50
const max_elements = 50;
ȱ
Theȱ #defineȱ formȱ isȱ moreȱ usefulȱ thanȱ theȱ constȱ variableȱ becauseȱ youȱ canȱ useȱ theȱ
formerȱwhereverȱaȱliteralȱconstantȱisȱallowed,ȱsuchȱasȱinȱdeclaringȱtheȱsizeȱofȱarrays.ȱ
Theȱconstantȱvariableȱcanȱonlyȱbeȱusedȱwhereȱvariableȱareȱallowed.ȱ
20
ȱSeeȱChapterȱ14ȱforȱaȱcompleteȱdescription.ȱ
Download at http://www.pin5i.com/
54 Chapter 3 Data
TIP
Namedȱ constantsȱ areȱ valuableȱ becauseȱ theyȱ giveȱ symbolicȱ namesȱ toȱ quantitiesȱ thatȱ
wouldȱ otherwiseȱ beȱ writtenȱ asȱ literals.ȱ Definingȱ sizesȱ ofȱ arraysȱ orȱ limitsȱ onȱ loopȱ
countersȱ withȱ namedȱ constantsȱ ratherȱ thanȱ literalȱ constantsȱ improvesȱ theȱ
maintainabilityȱofȱtheȱ program—shouldȱaȱvalueȱhaveȱtoȱchange,ȱonlyȱtheȱdeclarationȱ
needȱ beȱ touched.ȱ Itȱ isȱ muchȱ easierȱ toȱ changeȱ oneȱ declarationȱ thanȱ toȱ searchȱ throughȱ
theȱ entireȱ programȱ changingȱ allȱ instancesȱ ofȱ aȱ literalȱ constant,ȱ especiallyȱ whenȱ theȱ
same,ȱliteralȱvalueȱisȱusedȱforȱtwoȱorȱmoreȱdifferentȱpurposes.ȱ
ȱ
ȱ
ȱ
3.5 Scope
ȱ
Whenȱ aȱ variableȱ isȱ declaredȱ inȱ oneȱ partȱ ofȱ aȱ program,ȱ itȱ canȱ beȱ accessedȱ onlyȱ inȱ aȱ
certainȱ areaȱ ofȱ theȱ program.ȱ Theȱ extentȱ ofȱ thisȱ areaȱ isȱ determinedȱ byȱ theȱ identifier’sȱ
scope.ȱTheȱscopeȱofȱanȱidentifierȱisȱtheȱareaȱinȱtheȱprogramȱinȱwhichȱthatȱidentifierȱmayȱ
beȱused.ȱForȱexample,ȱtheȱscopeȱofȱaȱfunctionȇsȱlocalȱvariablesȱisȱlimitedȱtoȱtheȱbodyȱofȱ
theȱ function.ȱ Thisȱ ruleȱ meansȱ twoȱ things.ȱ First,ȱ noȱ otherȱ functionȱ mayȱ accessȱ theseȱ
variablesȱ byȱ theirȱ names,ȱ becauseȱ theȱ namesȱ areȱ notȱ validȱ outsideȱ ofȱ theirȱ scope.ȱ
Second,ȱ itȱisȱlegalȱtoȱ declareȱ differentȱvariablesȱwithȱtheȱsameȱnamesȱ soȱ longȱasȱ theyȱ
areȱnotȱdeclaredȱinȱtheȱsameȱscope.ȱ
Theȱcompilerȱrecognizeȱfourȱdifferentȱtypesȱofȱscopeȱ–ȱfileȱscope,ȱfunctionȱscope,ȱblockȱ
scope,ȱandȱprototypeȱscope.ȱTheȱlocationȱwhereȱanȱidentifierȱisȱdeclaredȱdeterminesȱitsȱ
scope.ȱTheȱprogramȱskeletonȱinȱFigureȱ3.1ȱillustratesȱallȱtheȱpossibleȱlocations.ȱ
ȱ
ȱ
ȱ
3.5.1 Block Scope
ȱ
Aȱlistȱofȱstatementsȱenclosedȱinȱbracesȱisȱcalledȱaȱblock.ȱAnyȱidentifiersȱdeclaredȱatȱtheȱ
beginningȱ ofȱ aȱ blockȱ haveȱ blockȱ scope,ȱ whichȱ meansȱ thatȱ theyȱ areȱ accessibleȱ toȱ allȱ
statementsȱinȱtheȱblock.ȱTheȱvariablesȱinȱFigureȱ3.1ȱlabeledȱsix,ȱseven,ȱnineȱandȱtenȱallȱ
haveȱblockȱscope.ȱTheȱformalȱparametersȱofȱaȱfunctionȱdefinitionȱ(declarationȱfive)ȱalsoȱ
haveȱblockȱscopeȱinȱtheȱfunctionȇsȱbody.ȱȱ
Whenȱ blocksȱ areȱ nested,ȱ theȱ scopeȱ ofȱ identifiersȱ declaredȱ inȱ theȱ nestedȱ blocksȱ
extendsȱonlyȱtoȱtheȱendȱofȱthatȱblock.ȱHowever,ȱifȱanȱidentifierȱinȱaȱnestedȱblockȱhasȱ
theȱ sameȱ nameȱ asȱ oneȱ inȱ anyȱ outerȱ block,ȱ thenȱ theȱ innerȱ definitionȱ hidesȱ theȱ outerȱ
one—theȱ variableȱ inȱ theȱ outerȱ blockȱ cannotȱ beȱ referencedȱ byȱ nameȱ fromȱ withinȱ theȱ
innerȱblock.ȱTheȱ f inȱdeclarationȱnineȱisȱaȱdifferentȱvariableȱthanȱtheȱ fȱinȱdeclarationȱ
six,ȱandȱtheȱlatterȱisȱnotȱaccessibleȱbyȱnameȱfromȱwithinȱtheȱinnerȱblock.ȱ
Download at http://www.pin5i.com/
3.5 Scope 55
ȱ
3
1
int a;
2
int b ( int c );
4
int d ( int e )
5
{
8
6
int f;
7
int g ( int h );
…
{
9
int f, g, i;
…
}
{
10
int i;
…
}
}
TIP
K&R C
ȱ
Figureȱ3.1ȱIdentifierȱscopeȱexampleȱ
ȱ
ȱ
Duplicateȱvariableȱnamesȱinȱnestedȱblocksȱshouldȱbeȱavoided.ȱThereȱisȱnoȱgoodȱreasonȱ
forȱ usingȱ them,ȱ andȱ theyȱ causeȱ confusionȱ duringȱ debuggingȱ orȱ maintenanceȱ ofȱ theȱ
programȱȱ
Blocksȱ thatȱ areȱ notȱ nestedȱ withinȱ oneȱ anotherȱ areȱ aȱ littleȱ different.ȱ Variablesȱ
declaredȱinȱeachȱblockȱareȱinaccessibleȱfromȱotherȱblocksȱbecauseȱtheirȱscopesȱdoȱnotȱ
overlap.ȱBecauseȱitȱisȱimpossibleȱforȱvariablesȱinȱbothȱblocksȱtoȱexistȱatȱtheȱsameȱtime,ȱ
theȱ compilerȱ isȱ freeȱ toȱ storeȱ themȱ inȱ theȱ sameȱ memoryȱ locations.ȱ Forȱ example,ȱ iȱ inȱ
declarationȱ tenȱ couldȱ shareȱ theȱ sameȱ memoryȱ locationȱ asȱ anyȱ ofȱ theȱ variablesȱ inȱ
declarationȱ nine.ȱ Thereȱ isȱ noȱ dangerȱ inȱ thisȱ sharing,ȱ becauseȱ onlyȱ oneȱ ofȱ theȱ non—
nestedȱblocksȱcanȱbeȱactiveȱatȱanyȱtime.ȱȱ
ȱ
InȱK&RȱC,ȱtheȱscopeȱofȱformalȱparametersȱtoȱaȱfunctionȱbeganȱatȱtheȱdeclarationsȱofȱtheȱ
parameters,ȱ whichȱ wasȱ outsideȱ ofȱ theȱ bodyȱ ofȱ theȱ function.ȱ Ifȱ thereȱ wereȱ localȱ
variablesȱdeclaredȱinȱtheȱfunctionȱwithȱtheȱsameȱnamesȱasȱtheȱparameters,ȱtheyȱhidȱtheȱ
parameters,ȱwhichȱwereȱthenȱinaccessibleȱanywhereȱinȱtheȱfunction.ȱInȱotherȱwords,ȱif
Download at http://www.pin5i.com/
56 Chapter 3 Data
declarationȱsixȱhadȱincludedȱanȱ e,ȱthenȱtheȱbodyȱofȱtheȱfunctionȱcouldȱonlyȱaccessȱtheȱ
localȱvariable;ȱ theȱparameterȱ eȱwouldȱbeȱinaccessible.ȱ Ofȱcourse,ȱnoȱ oneȱeverȱ hidesȱ aȱ
parameterȱ intentionallyȱ becauseȱ thereȱ isȱ noȱ pointȱ inȱ passingȱ anȱ argumentȱ ifȱ youȱ areȱ
notȱgoingȱtoȱuseȱitsȱvalueȱinȱtheȱfunction.ȱANSIȱCȱpreventsȱthisȱerrorȱfromȱhappeningȱ
byȱgivingȱtheȱformalȱparametersȱblockȱscopeȱinȱtheȱfunctionȇsȱoutermostȱblock.ȱLocalȱ
variablesȱ declaredȱ inȱ theȱ outermostȱ blockȱ cannotȱ haveȱ theȱ sameȱ nameȱ asȱ anyȱ ofȱ theȱ
parameters,ȱbecauseȱtheyȱareȱallȱdeclaredȱinȱtheȱsameȱscope.ȱȱ
ȱ
ȱ
3.5.2 File Scope
ȱ
Anyȱidentifierȱdeclaredȱoutsideȱofȱallȱblocksȱhasȱfileȱscope,ȱmeaningȱthatȱtheȱidentifierȱ
mayȱbeȱaccessedȱanywhereȱfromȱitsȱdeclarationȱtoȱtheȱendȱofȱtheȱsourceȱfileȱinȱwhichȱitȱ
wasȱdeclared.ȱDeclarationsȱoneȱandȱtwoȱinȱFigureȱ3.1ȱareȱinȱthisȱcategory.ȱTheȱnamesȱ
ofȱtheȱfunctionsȱdefinedȱinȱaȱfileȱhaveȱfileȱscope,ȱbecauseȱtheȱnameȱitselfȱisȱitselfȱIȱnotȱ
withinȱanyȱblocksȱ(asȱinȱdeclarationȱfour).ȱIȱshouldȱpointȱoutȱthatȱdeclarationsȱwrittenȱ
inȱ aȱ headerȱ tileȱ thatȱ isȱ thenȱ #includeȇdȱ intoȱ anotherȱ fileȱ areȱ treatedȱ asȱ ifȱ theyȱ wereȱ
writtenȱdirectlyȱinȱtheȱincludingȱfile;ȱtheirȱscopeȱisȱnotȱlimitedȱbyȱtheȱendȱofȱtheȱheaderȱ
file.ȱȱ
ȱ
ȱ
ȱ
3.5.3 Prototype Scope
ȱ
Prototypeȱscopeȱappliesȱonlyȱtoȱargumentȱnamesȱdeclaredȱinȱfunctionȱprototypes,ȱasȱinȱ
declarationsȱthreeȱandȱeightȱinȱFigureȱ3.1.ȱInȱaȱprototypeȱ(asȱopposedȱtoȱtheȱfunctionȱ
definition)ȱtheȱargumentȱnamesȱneedȱnotȱappear.ȱIfȱtheyȱareȱgiven,ȱhowever,ȱyouȱmayȱ
chooseȱanyȱnamesȱyouȱwish;ȱtheyȱneedȱnotȱmatchȱeitherȱtheȱformalȱparameterȱnamesȱ
givenȱinȱtheȱfunctionȱdefinitionȱorȱtheȱnamesȱofȱtheȱactualȱargumentsȱusedȱwhenȱtheȱ
functionȱ isȱ called.ȱ Prototypeȱ scopeȱ preventsȱ theseȱ namesȱ fromȱ conflictingȱ withȱ anyȱ
otherȱnamesȱinȱtheȱprogram.ȱIndeed,ȱtheȱonlyȱpossibleȱconflictȱisȱusingȱtheȱsameȱnameȱ
moreȱthanȱonceȱinȱtheȱsameȱprototype.ȱ
ȱ
ȱ
ȱ
3.5.4 Function Scope
ȱ
Theȱfinalȱtypeȱofȱscopeȱisȱfunctionȱscope.ȱItȱappliesȱonlyȱtoȱstatementȱlabels,ȱwhichȱareȱ
usedȱwith goto statements.ȱBasically,ȱfunctionȱscopeȱboilsȱdownȱtoȱaȱsimpleȱruleȱ–ȱallȱ
statementȱ labesȱ inȱ aȱ functionȱ mustȱ beȱ unique.ȱ Iȱ hopeȱ thatȱ youȱ neverȱ useȱ thisȱ
knowledge.ȱ
Download at http://www.pin5i.com/
3.6 Linkage 57
3.6 Linkage
ȱ
Afterȱ theȱ individualȱ sourceȱ filesȱ comprisingȱ aȱ programȱ areȱ compiled,ȱ theȱ objectȱ filesȱ
areȱ linkedȱ togetherȱ withȱ functionsȱ fromȱ oneȱ orȱ moreȱ librariesȱ toȱ formȱ theȱ executableȱ
program.ȱHowever,ȱwhenȱtheȱsameȱidentifierȱappearsȱinȱmoreȱthanȱoneȱsourceȱfile,ȱdoȱ
theyȱ referȱ toȱ theȱ sameȱ entity,ȱ asȱ inȱ Pascal,ȱ orȱ toȱ differentȱ entities?ȱ Theȱ linkageȱ ofȱ anȱ
identifierȱdeterminesȱhowȱmultipleȱoccurrencesȱofȱtheȱidentifierȱareȱtreated.ȱTheȱscopeȱ
ofȱanȱidentifierȱisȱrelatedȱtoȱitsȱlinkage,ȱbutȱtheȱtwoȱpropertiesȱareȱnotȱtheȱsame.ȱȱ
Thereȱ areȱ threeȱ typesȱ ofȱ linkage—external,ȱ internalȱ andȱ none.ȱ Identifiersȱ thatȱ
haveȱnoȱlinkageȱareȱalwaysȱindividuals,ȱthatȱis,ȱmultipleȱdeclarationsȱofȱtheȱidentifierȱ
areȱ alwaysȱ treatedȱ asȱ separateȱ andȱ distinctȱ entities.ȱ Internalȱ linkageȱ meansȱ thatȱ allȱ
declarationsȱ ofȱ theȱ identifierȱ withinȱ oneȱ sourceȱ fileȱ referȱ toȱ aȱ singleȱ entity,ȱ butȱ
declarationsȱ ofȱ theȱ sameȱ identifierȱ inȱ otherȱ sourceȱ filesȱ referȱ toȱ differentȱ entities.ȱ
Finally,ȱallȱreferencesȱtoȱanȱidentifierȱwithȱexternalȱlinkageȱreferȱtoȱtheȱsameȱentity.ȱȱ
Theȱ programȱ skeletonȱ inȱ Figureȱ 3.2ȱ illustratesȱ linkageȱ byȱ showingȱ allȱ ofȱ theȱ
differentȱ waysȱ thatȱ namesȱ canȱbeȱ declared.ȱByȱ default,ȱ theȱ linkageȱ ofȱ identifiersȱ b,ȱ c,ȱ
andȱ fȱisȱexternal;ȱandȱtheȱremainingȱidentifiersȱhaveȱnoȱlinkage.ȱThus,ȱanotherȱsourceȱ
fileȱ thatȱ containsȱ aȱ similarȱ declarationȱ forȱ bȱ andȱ callsȱ theȱ functionȱ cȱ willȱ accessȱ theȱ
entitiesȱdefinedȱinȱthisȱsourceȱtile,ȱ fȱhasȱexternalȱlinkageȱbecauseȱitȱisȱaȱfunctionȱname.ȱ
Callsȱtoȱtheȱfunctionȱfȱinȱthisȱsourceȱfileȱwillȱbeȱlinkedȱwithȱtheȱfunctionȱdefinitionȱthatȱ
appearsȱinȱsomeȱotherȱsourceȱfile,ȱorȱperhapsȱtheȱfunctionȱdefinitionȱmightȱcomeȱfromȱ
aȱlibrary.ȱ
Theȱkeywordsȱexternȱandȱstaticȱareȱusedȱinȱdeclarationsȱtoȱmodifyȱtheȱlinkageȱ
ofȱtheȱidentifiersȱbeingȱdeclared.ȱWhenȱusedȱonȱaȱdeclarationȱofȱ
ȱ
ȱ
ȱ
1
typedef char *a;
2
int b;
3
int c ( int d )
4
{
5
int e;
6
int f ( int g );
…
}
ȱ
Figureȱ3.2ȱLinkageȱexampleȱ
7
Download at http://www.pin5i.com/
58 Chapter 3 Data
somethingȱ thatȱ normallyȱ hasȱ externalȱ linkage,ȱ theȱ keywordȱ staticȱ givesȱ itȱ internalȱ
linkageȱinstead.ȱForȱexample,ȱifȱdeclarationȱtwoȱwereȱwrittenȱ
ȱ
static int
b;
ȱ
thenȱtheȱvariableȱbȱwouldȱremainȱprivateȱtoȱthisȱsourceȱfile;ȱreferencesȱtoȱtheȱvariableȱbȱ
inȱ otherȱ sourceȱ filesȱ wouldȱ beȱ linkedȱ toȱ aȱ differentȱ variable.ȱ Similarly,ȱ definingȱ aȱ
functionȱtoȱbeȱstatic,ȱforȱexample,ȱ
ȱ
static int c( int d )
TIP
ȱ
preventsȱitȱfromȱbeingȱcalledȱfromȱotherȱsourceȱfiles.ȱ
staticȱ onlyȱ hasȱ thisȱ effectȱ inȱ declarationsȱ whoseȱ defaultȱ linkageȱ isȱ external.ȱ
Althoughȱ itȱ isȱ legalȱ toȱ addȱ staticȱ toȱ declarationȱ five,ȱ forȱ exampleȱ itȱ hasȱ anȱ entirelyȱ
differentȱeffectȱbecauseȱeȱdoesȱnotȱdefaultȱtoȱexternalȱlinkage.ȱ
Theȱrulesȱforȱtheȱ externȱkeywordȱareȱmoreȱcomplicated.ȱInȱgeneral,ȱitȱspecifiesȱ
externalȱlinkageȱforȱanȱidentifierȱandȱisȱusedȱtoȱgetȱaccessȱtoȱanȱentityȱthatȱisȱdefinedȱ
elsewhere.ȱ Considerȱ theȱ exampleȱ inȱ Figureȱ 3.3.ȱ Declarationȱ threeȱ specifiesȱ externalȱ
linkageȱ forȱ k,ȱ whichȱ givesȱ thisȱ functionȱ accessȱ toȱ anȱ externalȱ variableȱ declaredȱ inȱ
anotherȱsourceȱfile.ȱ
ȱ
Technically,ȱ theȱ keywordȱ isȱ onlyȱ requiredȱ inȱ declarations,ȱ suchȱ asȱ numberȱ threeȱ inȱ
Figureȱ3.3,ȱwhoseȱdefaultȱlinkageȱisȱnotȱexternal.ȱItsȱuseȱisȱoptionalȱinȱdeclarationsȱthatȱ
haveȱfileȱscope.ȱHowever,ȱitȱisȱeasierȱforȱaȱreaderȱtoȱunderstandȱyourȱintentionsȱifȱyouȱ
defineȱtheȱvariableȱonceȱandȱuseȱexternȱinȱeveryȱotherȱdeclarationȱthatȱrefersȱtoȱit.ȱ
Whenȱexternȱisȱusedȱonȱtheȱfirstȱdeclarationȱinȱtheȱsourceȱfileȱforȱanȱidentifier,ȱ
ȱ
ȱ
1
static int i;
int func()
{
2
int j;
3
4
extern int k;
extern int i;
...
}
ȱ
Figureȱ3.3ȱUsingȱexternȱ
Download at http://www.pin5i.com/
3.7 Storage Class 59
itȱ specifiesȱ thatȱ theȱ identifierȱ hasȱ externalȱ linkage.ȱ Whenȱ usedȱ onȱ theȱ secondȱ orȱ
subsequentȱ declarationsȱ ofȱ anȱ identifier,ȱ however,ȱ theȱ keywordȱ doesȱ notȱ changeȱ theȱ
linkageȱ specifiedȱ byȱ theȱ firstȱ declaration.ȱ Forȱ example,ȱ declarationȱ fourȱ inȱ Figureȱ 3.3ȱ
doesȱnotȱchangeȱtheȱlinkageȱofȱiȱestablishedȱbyȱdeclarationȱone.ȱ
ȱ
ȱ
ȱ
3.7 Storage Class
ȱ
Theȱ storageȱ classȱ ofȱ aȱ variableȱ refersȱ toȱ theȱ typeȱ ofȱ memoryȱ inȱ whichȱ theȱ variable’sȱ
valueȱ isȱ stored.ȱ Theȱ storageȱ classȱ ofȱ aȱ variableȱ determinesȱ whenȱ itȱ isȱ createdȱ andȱ
destroyedȱandȱhowȱlongȱitȱwillȱretainȱitsȱvalue.ȱThereȱareȱthreeȱpossibleȱplacesȱtoȱstoreȱ
variables:ȱ inȱ ordinaryȱ memory,ȱ onȱ theȱ runtimeȱ stack,ȱ andȱ inȱ hardwareȱ registers.ȱ
Variablesȱstoredȱinȱtheseȱthreeȱplacesȱwillȱhaveȱdifferentȱcharacteristics.ȱ
Theȱ defaultȱ storageȱ classȱ forȱ aȱ variableȱ dependsȱ onȱ whereȱ itȱ isȱ declared.ȱ
Variablesȱdeclaredȱoutsideȱofȱanyȱblocksȱareȱalwaysȱstoredȱinȱstaticȱmemory,ȱthatȱis,ȱinȱ
memoryȱthatȱisȱnotȱpartȱofȱtheȱstack.ȱThereȱisȱnoȱwayȱtoȱspecifyȱanyȱotherȱstorageȱclassȱ
forȱtheseȱvariables.ȱStaticȱvariablesȱareȱcreatedȱbeforeȱtheȱprogramȱbeginsȱtoȱrunȱandȱ
existȱthroughoutȱitsȱentireȱexecution.ȱTheyȱ retainȱwhateverȱvalueȱtheyȱwereȱassignedȱ
untilȱaȱdifferentȱvalueȱisȱassignedȱorȱuntilȱtheȱprogramȱcompletes.ȱ
Theȱdefaultȱstorageȱclassȱforȱvariablesȱdeclaredȱwithinȱaȱblockȱisȱautomatic,ȱthatȱ
is,ȱonȱtheȱstack.ȱThereȱisȱaȱkeywordȱauto,ȱbutȱitȱisȱrarelyȱusedȱbecauseȱitȱdoesn’tȱchangeȱ
theȱdefault.ȱAutomaticȱvariablesȱareȱcreatedȱjustȱbeforeȱtheȱprogramȱexecutionȱentersȱ
theȱblockȱinȱwhichȱtheyȱwereȱdeclared,ȱandȱtheyȱareȱdiscardedȱjustȱasȱexecutionȱleavesȱ
thatȱ block.ȱ Ifȱ theȱ blockȱ isȱ executedȱ severalȱ times,ȱ asȱ inȱ theȱ caseȱ ofȱ aȱ functionȱ thatȱ isȱ
calledȱrepeatedly,ȱnewȱcopiesȱofȱtheȱautomaticȱvariablesȱareȱcreatedȱeachȱtime.ȱTheseȱ
newȱvariablesȱmayȱorȱmayȱnotȱoccupyȱtheȱsameȱmemoryȱlocationsȱonȱtheȱstackȱasȱtheȱ
previousȱinstancesȱofȱtheȱsameȱvariables,ȱandȱevenȱifȱtheyȱdoȱthereȱisȱnoȱguaranteeȱthatȱ
theȱmemoryȱwasȱnotȱusedȱforȱsomeȱotherȱpurposeȱinȱtheȱmeantime.ȱWeȱthereforeȱsayȱ
thatȱautomaticȱvariablesȱdisappearȱatȱtheȱendȱofȱaȱblock;ȱtheyȱgenerallyȱwillȱnotȱhaveȱ
theirȱpreviousȱvaluesȱtheȱnextȱtimeȱtheȱblockȱisȱentered.ȱ
Onȱvariablesȱdeclaredȱwithinȱaȱblock,ȱtheȱkeywordȱ staticȱchangesȱtheȱstorageȱ
classȱ fromȱ automaticȱ toȱ static.ȱ Variablesȱ withȱ staticȱ storageȱ classȱ existȱ forȱ theȱ entireȱ
durationȱ ofȱ theȱ program,ȱ ratherȱ thanȱ justȱ theȱ durationȱ ofȱ theȱ blockȱ inȱ whichȱ itȱ isȱ
declared.ȱNoteȱthatȱchangingȱtheȱstorageȱclassȱofȱaȱvariableȱdoesȱnotȱchangeȱitsȱscope;ȱ
itȱ isȱ stillȱ accessibleȱ byȱ nameȱ onlyȱ fromȱ withinȱ theȱ block.ȱ Theȱ formalȱ parametersȱ toȱ aȱ
functionȱcannotȱbeȱdeclaredȱstatic,ȱbecauseȱargumentsȱareȱalwaysȱpassedȱonȱtheȱstackȱ
toȱsupportȱrecursion.ȱ
Download at http://www.pin5i.com/
60 Chapter 3 Data
Finally,ȱ theȱ registerȱ keywordȱ mayȱ beȱ usedȱ onȱ declarationsȱ ofȱ automaticȱ
variablesȱ toȱ indicateȱ thatȱ theyȱ shouldȱ beȱ storedȱ inȱ theȱ machine’sȱ hardwareȱ registersȱ
ratherȱthanȱinȱmemory.ȱUsually,ȱsuchȱvariablesȱcanȱbeȱaccessedȱmoreȱefficientlyȱthanȱ
thoseȱ storedȱ inȱ memory.ȱ However,ȱ theȱ compilerȱ isȱ freeȱ toȱ ignoreȱ theȱ registerȱ
keyword.ȱ lfȱ tooȱ manyȱ variablesȱ areȱ designatedȱ asȱ register,ȱ onlyȱ theȱ firstȱ onesȱ willȱ
actuallyȱbeȱstoredȱinȱtheȱregisters,ȱandȱtheȱrestȱwillȱbeȱautomatic.ȱAȱcompilerȱthatȱdoesȱ
itsȱownȱregisterȱoptimizationȱmayȱignoreȱ registerȱaltogetherȱonȱtheȱgroundsȱthatȱtheȱ
compilerȱ canȱ doȱ aȱ betterȱ jobȱ decidingȱ whichȱ valuesȱ shouldȱ beȱ inȱ registersȱ thanȱ aȱ
human.ȱ
Typically,ȱ youȱ wantȱ toȱ declareȱ theȱ variablesȱ thatȱ areȱ usedȱ mostȱ heavilyȱ asȱ
registerȱ variables.ȱ Onȱ someȱ computers,ȱ theȱ programȱ canȱ benefitȱ ifȱ weȱ declareȱ
pointersȱasȱregisterȱvariables,ȱparticularlyȱthoseȱpointersȱonȱwhichȱtheȱmostȱindirectionȱ
isȱ performed.ȱ Youȱ mayȱ declareȱ theȱ formalȱ parametersȱ ofȱ aȱ functionȱ asȱ registerȱ
variables,ȱandȱtheȱcompilerȱwillȱgenerateȱinstructionsȱatȱtheȱbeginningȱofȱtheȱfunctionȱ
toȱcopyȱtheȱvaluesȱfromȱtheȱstackȱtoȱtheȱregisters.ȱItȱisȱentirelyȱpossible,ȱhowever,ȱthatȱ
theȱ spaceȱ andȱ timeȱ savingsȱ inȱ subsequentȱ accessesȱ toȱ theȱ parametersȱ mayȱ notȱ beȱ
enoughȱtoȱoffsetȱtheȱoverheadȱofȱthisȱcopying.ȱ
Registerȱ variablesȱ areȱ createdȱ andȱ destroyedȱ atȱ theȱ sameȱ timeȱ asȱ automaticȱ
variables,ȱbutȱ thereȱ isȱ someȱ additionalȱ workȱ needed.ȱ Beforeȱ aȱ functionȱ thatȱ hasȱ usedȱ
registerȱ variablesȱ returns,ȱ theȱ previousȱ contentsȱ ofȱ theȱ registersȱ mustȱ beȱ restoredȱ inȱ
orderȱ toȱ ensureȱ thatȱ theȱ caller’sȱ registerȱ variablesȱ areȱ notȱ destroyed.ȱ Manyȱ machinesȱ
useȱtheȱruntimeȱstackȱtoȱaccomplishȱthisȱtask.ȱWhenȱaȱfunctionȱbegins,ȱcontentsȱofȱanyȱ
registersȱthatȱitȱwillȱuseȱareȱsavedȱonȱtheȱstack.ȱTheseȱvaluesȉa1ȉeȱthenȱcopiedȱbatikȱtoȱ
theȱregistersȱjustȱbeforeȱtheȱfunctionȱreturns.ȱ
Manyȱhardwareȱimplementationsȱdoȱnotȱassignȱaddressesȱtoȱtheȱregisters.ȱAlso,ȱ
becauseȱ ofȱ theȱ savingȱ andȱ restoringȱ ofȱ registerȱ values,ȱ atȱ particularȱ registerȱ mayȱ
containȱ manyȱ differentȱ valuesȱ atȱ differentȱ times.ȱ Forȱ theseȱ reasons,ȱ youȱ areȱ notȱ
allowedȱtoȱtakeȱtheȱaddressȱofȱaȱregisterȱvariable.ȱ
ȱ
ȱ
ȱ
3.7.1 Initialization
ȱ
Weȱnowȱreturnȱtoȱtheȱtopicȱofȱinitializationȱofȱvariablesȱinȱtheirȱdeclarations.ȱThereȱisȱ
anȱ importantȱ differenceȱ inȱ howȱ initializationȱ worksȱ onȱ automaticȱ variablesȱ versusȱ
staticȱvariables.ȱInitializationȱofȱvariablesȱwithȱstaticȱstorageȱclassȱisȱaccomplishedȱbyȱ
placingȱ theȱ desiredȱ valueȱ inȱ theȱ executableȱ programȱ fileȱ inȱ theȱ locationȱ thatȱ willȱ beȱ
usedȱ byȱ theȱ variableȱ whenȱ theȱ programȱ isȱ executing.ȱ Whenȱ thisȱ executableȱ fileȱ isȱ
loadedȱ intoȱ memory,ȱ theȱ locationȱ assignedȱ toȱ theȱ variableȱ startsȱ outȱ withȱ theȱ correctȱ
valueȱ alreadyȱ inȱ it.ȱ Noȱ extraȱ timeȱ isȱ takenȱ toȱ accomplishȱ thisȱ task,ȱ norȱ areȱ anyȱ
instructionsȱexecutedȱinȱtheȱprogramȱtoȱdoȱit.ȱTheȱvariableȱjustȱstartsȱoutȱwithȱtheȱrightȱȱ
Download at http://www.pin5i.com/
3.8 The Static Keyword 61
value.ȱ Staticȱ variablesȱ areȱ initializedȱ toȱ zeroȱ unlessȱ anȱ explicitȱ initializationȱ specifiesȱ
someȱotherȱvalueȱ
Initializationȱ ofȱ automaticȱ variablesȱ takesȱ moreȱ overheadȱ becauseȱ theȱ locationȱ
usedȱtoȱstoreȱtheȱvariableȱcannotȱbeȱdeterminedȱwhenȱtheȱprogramȱisȱlinked.ȱIndeed,ȱ
localȱ variablesȱ inȱ aȱfunctionȱmayȱoccupyȱdifferentȱlocationsȱeachȱ timeȱtheȱfunctionȱisȱ
called.ȱ Forȱ thisȱ reason,ȱ thereȱ isȱ noȱ defaultȱ initializationȱ ofȱ automaticȱ variables,ȱ andȱ
explicitȱinitializationȱisȱperformedȱwithȱanȱinvisibleȱassignmentȱstatementȱinsertedȱinȱ
theȱbeginningȱofȱtheȱblock.ȱ
Thisȱtechniqueȱhasȱfourȱconsequences.ȱFirst,ȱinitializationȱofȱautomaticȱvariablesȱ
isȱ noȱ moreȱ efficientȱ thanȱ anȱ assignmentȱ statement.ȱ Exceptȱ forȱ variablesȱ declaredȱ asȱ
const,ȱ initializingȱ theȱ variableȱ inȱ itsȱ declarationȱ orȱ usingȱ assignmentȱ statementsȱ isȱ
solelyȱ aȱ matterȱ ofȱ style.ȱ Second,ȱ theȱ implicitȱ assignmentȱ statementȱ causesȱ automaticȱ
variablesȱ toȱ beȱ reinitializedȱ eachȱ timeȱ theȱ functionȱ (orȱ block)ȱ inȱ whichȱ theyȱ wereȱ
declaredȱ isȱ entered.ȱ Thisȱ behaviorȱ isȱ quiteȱ differentȱ fromȱ staticȱ variables,ȱ whichȱ areȱ
initializedȱ onlyȱ onceȱ beforeȱ theȱ programȱ beginsȱ toȱ execute.ȱ Theȱ thirdȱ consequenceȱ isȱ
anȱ advantage.ȱ Becauseȱ initializationȱ isȱ performedȱ atȱ runȱ time,ȱ youȱ mayȱ useȱ anyȱ
expressionȱasȱanȱinitializer,ȱforȱexample.ȱ
ȱ
int
func( int a )
{
int
b = a + 3;
ȱ
Finally,ȱunlessȱyouȱinitializeȱthemȱexplicitly,ȱautomaticȱvariablesȱwillȱcontainȱgarbageȱ
whenȱtheyȱareȱcreated.ȱ
ȱ
ȱ
ȱ
3.8 The Static Keyword
ȱ
Itȱisȱindeedȱunfortunateȱthatȱtheȱstaticȱkeywordȱhasȱdifferentȱmeaningsȱwhenȱusedȱinȱ
differentȱcontexts,ȱbecauseȱitȱalwaysȱcausesȱconfusionȱ forȱ beginningȱCȱ programmers.ȱ
Thisȱsummaryȱandȱtheȱfollowingȱexampleȱshouldȱhelpȱclarifyȱtheȱissueȱforȱyou.ȱȱ
Whenȱ usedȱ onȱ functionȱ definitions,ȱ orȱ declarationsȱ ofȱ variablesȱ thatȱ appearȱ
outsideȱofȱblocks,ȱtheȱkeywordȱ staticȱchangesȱtheȱlinkageȱfromȱexternalȱtoȱinternal—
theȱ storageȱ classȱ andȱscopeȱ areȱnotȱ affected.ȱ Functionsȱ andȱ variablesȱ declaredȱ inȱ thisȱ
wayȱareȱaccessibleȱonlyȱfromȱwithinȱtheȱsourceȱfileȱinȱwhichȱtheyȱwereȱdeclared.ȱ
Whenȱusedȱonȱvariableȱdeclarationsȱthatȱappearȱinsideȱofȱaȱblock,ȱtheȱkeywordȱ
staticȱ changesȱ theȱ storageȱ classȱ fromȱ automaticȱ toȱ static—theȱ linkageȱ andȱ scopeȱ areȱ
notȱaffected.ȱVariablesȱdeclaredȱinȱthisȱmannerȱareȱcreatedȱwhenȱtheȱprogramȱbeginsȱ
Download at http://www.pin5i.com/
62 Chapter 3 Data
toȱ executeȱ andȱ continueȱ toȱ existȱ forȱ itsȱ entireȱ duration,ȱ insteadȱ ofȱ beingȱ createdȱ andȱ
destroyedȱeveryȱtimeȱexecutionȱentersȱandȱleavesȱtheȱblock.ȱ
ȱ
ȱ
ȱ
3.9 Scope, Linkage, and Storage Class Example
ȱ
Figureȱ 3.4ȱ containsȱ anȱ exampleȱ whichȱ illustratesȱ scope,ȱ linkage,ȱ andȱ storageȱ class.ȱ
Declarationsȱwithȱtileȱscopeȱdefaultȱtoȱexternalȱlinkage,ȱsoȱaȱinȱlineȱ1ȱisȱ
ȱ
1
2
3
int
extern
static
a = 5;
int
b;
int
c;
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int d( int e )
{
int
register
static
extern
...
{
25
26
27
28
static int i()
{
...
}
29
...
int
int
int
f = 15;
b;
g = 20;
a;
int
int
extern int
...
e;
a;
h;
}
...
{
int
int
...
x;
e;
}
...
}
ȱ
Figureȱ3.4ȱScope,ȱlinkage,ȱandȱstorageȱclassȱexampleȱ
Download at http://www.pin5i.com/
3.9 Scope, Linkage, and Storage Class Example 63
external.ȱ Theȱ externȱ keywordȱ inȱ lineȱ 2ȱ isȱ technicallyȱ notȱ neededȱ butȱ sty1isticallyȱ
desiredȱifȱ bȱisȱdefinedȱelsewhere.ȱTheȱ staticȱkeywordȱinȱlineȱ3ȱoverridesȱtheȱdefaultȱ
linkageȱforȱc,ȱgivingȱitȱinternalȱlinkageȱinstead.ȱOtherȱsourceȱfilesȱthatȱdeclareȱvariablesȱ
namedȱ aȱ orȱ bȱ withȱ externalȱ linkageȱ willȱ accessȱ theȱ sameȱ variablesȱ declaredȱ here.ȱ
However,ȱ cȱ canȱ onlyȱ beȱ accessedȱ fromȱ withinȱ thisȱ sourceȱ fileȱ dueȱ toȱ itsȱ internalȱ
linkage.ȱ
Theȱstorageȱclassȱof a, b,ȱand cȱisȱstatic,ȱ meaningȱthatȱtheyȱareȱnotȱstoredȱonȱ
theȱ stack.ȱ Thus,ȱ theseȱ variablesȱ areȱ createdȱ whenȱ theȱ programȱ beginsȱ executing,ȱ andȱ
theyȱretainȱtheirȱvaluesȱuntilȱitȱfinishes.ȱ aȱwillȱbeȱinitializedȱtoȱfiveȱwhenȱtheȱprogramȱ
begins.ȱȱ
Theȱ scopeȱ ofȱ theseȱ variablesȱ extendsȱ throughȱ theȱ restȱ ofȱ thisȱ sourceȱ file,ȱ butȱ
localȱ declarationsȱ ofȱ variablesȱ namedȱ aȱ andȱ bȱ inȱ linesȱ 7ȱ andȱ i3ȱ hideȱ theseȱ variablesȱ
fromȱthoseȱportionsȱofȱtheȱprogram.ȱThus,ȱtheȱscopesȱofȱtheseȱfirstȱthreeȱvariablesȱare,ȱ
ȱ
aȱ
linesȱ1Ȭ12,ȱ17Ȭ29ȱ
bȱ
linesȱ2Ȭ6,ȱ25Ȭ29ȱ
cȱ
linesȱ3Ȭ29ȱ
ȱ
Lineȱ4ȱdeclaresȱtwoȱidentifiers.ȱTheȱscopeȱofȱ dȱextendsȱfromȱlineȱ4ȱthroughȱtheȱ
enȱofȱthisȱfile;ȱtheȱdefinitionȱofȱfunctionȱdȱservesȱasȱitsȱprototypeȱforȱanyȱfunctionsȱlaterȱ
inȱthisȱsourceȱfileȱthatȱwishȱtoȱcallȱ d.ȱAsȱaȱfunctionȱname,ȱ dȱdefaultȱtoȱexternalȱlinkage,ȱ
soȱ functionsȱ inȱ otherȱ sourceȱ filesȱ canȱ callȱ dȱ asȱ longȱ asȱ theyȱ haveȱ aȱ prototype. 21 ȱ Weȱ
couldȱ changeȱ theȱ linkageȱ toȱ internalȱ byȱ declaringȱ theȱ function static,ȱ butȱ doingȱ soȱ
wouldȱ makeȱ itȱ inaccessibleȱ fromȱ otherȱ sourceȱ files.ȱ Storageȱ classȱ isȱ notȱ anȱ issueȱ forȱ
functionsȱbecauseȱcodeȱisȱalwaysȱstoredȱinȱstaticȱmemory.ȱ
Theȱargumentȱ eȱhasȱnoȱlinkage,ȱsoȱweȱcanȱaccessȱitȱbyȱnameȱonlyȱfromȱwithinȱ
thisȱ function.ȱ Itȱ hasȱ automaticȱ storageȱ class,ȱ soȱ itȱ comesȱ intoȱ existenceȱ whenȱ theȱ
functionȱ isȱ calledȱ andȱ disappearsȱ whenȱ theȱ functionȱ returns.ȱ Itsȱ scopeȱ isȱ limitedȱ toȱ
linesȱ6Ȭ11,ȱ17Ȭ19,ȱandȱ23Ȭ24ȱdueȱtoȱconflictingȱlocalȱdeclarations.ȱ
Linesȱ 6Ȭ8ȱ declareȱ localȱ variables,ȱ thusȱ theirȱ scopeȱ endsȱ atȱ theȱ endȱ ofȱ theȱ
function.ȱ Theyȱ haveȱ noȱ linkage,ȱ soȱ theyȱ cannotȱ beȱ accessedȱ byȱnameȱ fromȱ anywhereȱ
outsideȱofȱthisȱfunctionȱ(whichȱisȱwhyȱtheyȱareȱcalledȱlocal).ȱTheȱstorageȱclassȱofȱ fȱisȱ
automatic,ȱandȱitȱisȱinitializedȱtoȱ15ȱbyȱanȱimplicitȱassignmentȱstatementȱeachȱtimeȱtheȱ
functionȱisȱcalled.ȱbȱhasȱregisterȱstorageȱclassȱsoȱitsȱinitialȱvalueȱisȱgarbage.ȱTheȱstorageȱ
classȱofȱgȱisȱstatic,ȱsoȱitȱexistsȱthroughoutȱtheȱprogramȇsȱexecution.ȱItȱisȱinitializedȱtoȱ20ȱ
onceȱatȱtheȱbeginningȱofȱexecution.ȱItȱisȱnotȱinitializedȱeachȱtimeȱtheȱfunctionȱisȱcalled.ȱ
ȱActually,ȱtheȱprototypeȱisȱonlyȱrequiredȱifȱdȱreturnȱsomethingȱotherȱthanȱanȱinteger.ȱPrototypingȱallȱfunctionsȱthatȱyouȱcallȱ
isȱrecommendedȱbecauseȱitȱreducesȱtheȱchancesȱforȱundetectedȱerrors.ȱ
21
Download at http://www.pin5i.com/
64 Chapter 3 Data
Theȱ declarationȱ inȱ lineȱ 9ȱ isȱ notȱ needed.ȱ Thisȱ blockȱ isȱ withinȱ theȱ scopeȱ ofȱ theȱ
declarationȱinȱlineȱ1.ȱ
Linesȱ12ȱandȱ13ȱdeclareȱlocalȱvariablesȱforȱtheȱblock.ȱTheyȱareȱautomatic,ȱhaveȱ
noȱlinkage,ȱandȱtheirȱscopesȱextendȱthroughȱlineȱ16.ȱTheseȱvariablesȱareȱseparateȱfromȱ
theȱ aȱ andȱ eȱ declaredȱ earlier,ȱ andȱ theȱ earlierȱ variableȱ areȱ inaccessibleȱ fromȱ thisȱ blockȱ
becauseȱofȱtheȱnameȱconflict.ȱ
Lineȱ 14ȱ makesȱ theȱ globalȱ variableȱ hȱ accessibleȱ fromȱ withinȱ theȱ block.ȱ Itȱ hasȱ
externalȱ linkageȱ andȱ residesȱ inȱ staticȱ storage.ȱ Thisȱ isȱ theȱ onlyȱ declarationȱ whereȱ theȱ
externȱisȱvital.ȱWithoutȱit,ȱhȱwouldȱbeȱanotherȱlocalȱvariable.ȱ
Linesȱ19ȱandȱ20ȱcreateȱlocalȱvariablesȱ(automatic,ȱnoȱlinkage,ȱscopeȱrestrictedȱtoȱ
thisȱblock).ȱThisȱ eȱisȱaȱdifferentȱvariableȱthanȱtheȱargumentȱ e,ȱandȱitȱisȱalsoȱaȱdifferentȱ
variableȱfromȱtheȱ eȱdeclaredȱinȱlineȱ12.ȱTheȱblocksȱstartingȱatȱlinesȱ11ȱandȱ18ȱareȱnotȱ
nested,ȱsoȱtheȱcompilerȱcanȱuseȱtheȱsameȱmemoryȱtoȱstoreȱtheirȱlocalȱvariables.ȱThus,ȱ
thereȱisȱaȱchanceȱthatȱtheȱsameȱmemoryȱlocationȱwillȱbeȱusedȱtoȱstoreȱtheȱvariableȱ eȱinȱ
bothȱblocks.ȱIfȱyouȱneedȱ eȱtoȱbeȱtheȱsameȱvariableȱinȱbothȱblocks,ȱthenȱitȱshouldnȇtȱbeȱ
declaredȱasȱlocalȱtoȱthem.ȱ
Finally,ȱ lineȱ 25ȱ declaresȱ theȱ functionȱ iȱ withȱ staticȱ linkage.ȱ Staticȱ linkageȱ
preventsȱ itȱ fromȱ beingȱ calledȱ byȱ anyȱ functionsȱ outsideȱ ofȱ thisȱ sourceȱ file.ȱ Indeed,ȱ
anotherȱsourceȱfileȱmayȱdeclareȱitsȱownȱfunctionȱcalledȱ i,ȱwhichȱwillȱbeȱseparateȱandȱ
distinctȱ formȱ thisȱ one.ȱ Theȱ scopeȱ ofȱ iȱ extendsȱ fromȱ thisȱ declarationȱ toȱ theȱ enȱ ofȱ thisȱ
sourceȱfile.ȱFunctionȱdȱcannotȱcallȱfunctionȱ iȱbecauseȱnoȱprototypeȱforȱ iȱappearȱpriorȱ
toȱd.ȱ
ȱ
ȱ
ȱ
3.10 Summary
ȱ
Entitiesȱ withȱ externalȱ linkageȱ areȱ whatȱ otherȱ languagesȱ wouldȱ termȱ globalȱ andȱ areȱ
accessibleȱ toȱ allȱ functionsȱ inȱ allȱ sourceȱ files.ȱ Externalȱ linkageȱ occursȱ byȱ defaultȱ withȱ
variableȱdeclarationsȱthatȱareȱnotȱinȱanyȱblockȱandȱwithȱfunctionȱdefinitions.ȱAddingȱ
externȱtoȱaȱvariableȱdeclarationȱinsideȱofȱaȱblockȱcausesȱitȱtoȱreferȱtoȱglobalȱvariablesȱ
ratherȱthanȱlocalȱones.ȱ
Entitiesȱwithȱexternalȱlinkageȱalwaysȱhaveȱstaticȱstorageȱclass.ȱGlobalȱvariablesȱ
areȱ createdȱ beforeȱ theȱ programȱ beginsȱ toȱ executeȱ andȱ existȱ throughoutȱ itsȱ execution.ȱ
Theȱ localȱvariablesȱbelongingȱ toȱfunctionsȱcomeȱandȱ goȱasȱtheȱfunctionsȱexecute,ȱ butȱ
theȱmachine,ȱinstructionsȱinȱtheȱfunctionsȱexistȱforȱtheȱlifeȱofȱtheȱprogram.ȱȱ
Localȱ variables,ȱ thoseȱ thatȱ areȱ usedȱ inȱ aȱ functionȱ andȱ notȱ referencedȱ byȱ nameȱ
fromȱanyȱotherȱfunction,ȱdefaultȱtoȱautomaticȱstorageȱforȱtwoȱreasons.ȱFirst,ȱstorageȱisȱ
allocatedȱ toȱ theseȱ variablesȱ onlyȱ whenȱ theyȱ areȱ needed,ȱ thusȱ reducingȱ theȱ totalȱ
memoryȱrequirementȱforȱtheȱprogram.ȱSecond,ȱallocatingȱthemȱonȱtheȱstackȱallowsȱ
Download at http://www.pin5i.com/
3.12 Summary of Programming Tips 65
ȱ
Variable
Type
globalȱ
localȱ
Where
Declared
outsideȱofȱallȱ
blocksȱ
beginningȱofȱaȱ
blockȱ
formalȱ
functionȱ
parametersȱ headerȱ
Stored
on Stack
noȱ1
yesȱ2
yesȱ2
Scope
If Declared static
remainderȱofȱ
thisȱsourceȱfileȱ
throughoutȱtheȱ
blockȱ3
preventsȱaccessȱfromȱotherȱ
sourceȱfilesȱ
variableȱisȱnotȱstoredȱonȱtheȱ
stack,ȱkeepsȱitsȱvaluedȱforȱtheȱ
entireȱdurationȱofȱtheȱprogramȱ
notȱallowedȱ
throughoutȱtheȱ
functionȱ3
ȱ
ȱVariablesȱstoredȱonȱtheȱstackȱretainȱtheirȱvaluesȱonlyȱwhileȱtheȱblockȱtoȱwhichȱtheyȱareȱlocalȱ
isȱactive.ȱWhenȱexecutionȱleavesȱtheȱblock,ȱtheȱvaluesȱareȱlost.ȱ
2ȱVariablesȱnotȱstoredȱonȱtheȱstackȱareȱcreatedȱwhenȱtheȱprogramȱbeginsȱexecutingȱandȱretainȱ
theirȱvaluesȱthroughoutȱexecution,ȱregardlessȱofȱwhetherȱtheyȱareȱlocalȱorȱglobal.ȱ
3ȱExceptȱinȱnestedȱblocksȱthatȱdeclareȱidenticalȱnames.ȱ
ȱ
Tableȱ3.4ȱScope,ȱlinkage,ȱandȱstorageȱclassȱsummaryȱ
ȱ
ȱ
recursionȱ toȱ beȱ implementedȱ efficiently.ȱ Youȱ canȱ changeȱ theȱ storageȱ classȱ ofȱ localȱ
variablesȱ toȱ staticȱ ifȱ itȱ isȱ importantȱ thatȱ theȱ valuesȱ ofȱ theseȱ variablesȱ beȱ retainedȱ
betweenȱexecutionsȱofȱtheȱfunction.ȱȱ
ThisȱinformationȱisȱsummarizedȱinȱTableȱ3.4.ȱ
ȱ
ȱ
ȱ
1
3.11 Summary of Cautions
ȱ
1. Writingȱmisleadingȱdeclarationsȱforȱpointerȱvariablesȱ(pageȱ50).ȱ
2. Misinterpretingȱtheȱmeaningȱofȱinitializationsȱinȱpointerȱdeclarationsȱ(pageȱ50).ȱ
ȱ
ȱ
ȱ
3.12 Summary of Programming Tips
ȱ
1. Forȱtheȱbestȱportability,ȱrestrictȱcharacterȱvariablesȱtoȱvaluesȱinȱtheȱintersectionȱofȱ
theȱ signedȱ andȱ unsignedȱ characterȱ rangesȱ orȱ donȇtȱ performȱ arithmeticȱ onȱ themȱ
(pageȱ41).ȱ
2. Expressȱliteralsȱinȱtheȱformȱthatȱisȱmostȱnaturalȱforȱhowȱtheyȱareȱusedȱ(pageȱ42).ȱ
3. Donȇtȱmixȱintegersȱwithȱenumeratedȱvaluesȱ(pageȱ44).ȱ
Download at http://www.pin5i.com/
66 Chapter 3 Data
4. Donȇtȱdependȱonȱimplicitȱdeclarationsȱ(pageȱ51).ȱ
5. Useȱtypedefȱratherȱthanȱ#defineȱtoȱdefineȱnewȱtypeȱnamesȱ(pageȱ52).ȱ
6. Useȱconstȱtoȱdeclareȱvariablesȱthatȱwillȱnotȱchangeȱ(pageȱ53).ȱ
7. Useȱnamedȱconstantsȱratherȱthanȱliteralȱconstantsȱ(pageȱ54).ȱ
8. Donȇtȱuseȱduplicateȱvariableȱnameȱinȱnestedȱblocksȱ(pageȱ55).ȱ
9. Useȱexternȱinȱallȱdeclarationsȱforȱanȱentityȱbutȱoneȱ(pageȱ58).ȱ
ȱ
ȱ
ȱ
3.13 Questions
ȱ
1. Whatȱisȱtheȱrangeȱforȱcharactersȱandȱtheȱvariousȱintegerȱtypesȱonȱyourȱmachine?ȱ
ȱ
2. WhatȱisȱtheȱrangeȱforȱeachȱofȱtheȱfloatingȬpointȱtypesȱonȱyourȱmachine?ȱ
ȱ
3. Supposeȱyouȱareȱwritingȱaȱprogramȱthatȱmustȱrunȱonȱtwoȱmachinesȱwhoseȱdefaultȱ
integersȱ areȱ differentȱ sizes:ȱ 16ȱ bitsȱ andȱ 32ȱ bits.ȱ Theȱ sizeȱ ofȱ longȱ integersȱ onȱ theseȱ
machinesȱ isȱ 32ȱ bitsȱ andȱ 64ȱ hits,ȱ respectively.ȱ Someȱ ofȱ theȱ valuesȱ usedȱ inȱ thisȱ
programȱ areȱ smallȱ enoughȱ toȱ fitȱ inȱ aȱ defaultȱ integerȱ onȱ eitherȱ machine,ȱ butȱ someȱ
valuesȱ areȱlargeȱ enoughȱ toȱ requireȱ 32ȱ bits.ȱ Oneȱ possibleȱ solutionȱ isȱ toȱ simplyȱ useȱ
longȱintegersȱforȱallȱvalues,ȱbutȱthisȱapproachȱwastesȱtimeȱandȱspaceȱonȱtheȱl6Ȭbitȱ
machineȱforȱthoseȱvaluesȱthatȱwouldȱfitȱinȱ16ȱbitsȱandȱwastesȱtimeȱandȱspaceȱonȱtheȱ
32Ȭbitȱmachineȱasȱwell.ȱ
Howȱcanȱyouȱwriteȱtheȱdeclarationsȱforȱtheseȱvariablesȱsoȱthatȱtheyȱareȱtheȱrightȱ
sizeȱ forȱ bothȱ machines?ȱ Theȱ correctȱ approachȱ avoidsȱ theȱ racedȱ toȱ modifyȱ theseȱ
declarationsȱwhenȱcompilingȱtheȱprogramȱonȱeitherȱmachine.ȱHint:ȱTryȱincludingȱaȱ
headerȱfileȱthatȱcontainsȱdeclarationsȱspecificȱtoȱeachȱparticularȱmachine.ȱ
ȱ
4. Supposeȱ youȱ haveȱ aȱ programȱ thatȱ assignsȱ aȱ long integerȱ variableȱ toȱ aȱ short
integerȱ variable.ȱ Whatȱ happensȱ whenȱ youȱ compileȱ thisȱ program?ȱ Whatȱ happensȱ
whenȱyouȱrunȱit?ȱDoȱyouȱthinkȱthatȱotherȱcompilersȱwillȱgiveȱtheȱsameȱresults?ȱ
ȱ
5. Supposeȱ youȱ haveȱ aȱ programȱ thatȱ assignsȱ aȱ doubleȱ variableȱ toȱ aȱ float.ȱ Whatȱ
happensȱwhenȱyouȱcompileȱthisȱprogram?ȱWhatȱhappensȱwhenȱyouȱrunȱit?ȱ
ȱ
6. Writeȱ aȱ declarationȱ forȱ anȱ enumerationȱ thatȱ definesȱ valuesȱ forȱ coins,ȱ usingȱ theȱ
symbolsȱPENNY,ȱNICKEL,ȱandȱsoȱforth.ȱ
ȱ
7. Whatȱisȱprintedȱbyȱthisȱfragmentȱofȱcode?ȱ
ȱ
Download at http://www.pin5i.com/
3.12 Summary of Programming Tips 67
enum Liquid { OUNCE = 1, CUP = 8, PINT = 16,
ȱ
QUART = 32, GALLON = 128 };
enum
Liquid jar;
...
jar = QART;
printf( "%s\n", jar );
jar = jar + PINT;
printf( "%s\n", jar );
8. DoesȱyourȱCȱimplementationȱallowȱstringȱliteralsȱtoȱbeȱmodifiedȱbyȱtheȱprogram?ȱ
Areȱthereȱanyȱ compilerȱoptionsȱthatȱ allowȱ theȱmodificationȱofȱ stringȱ literalsȱ toȱ beȱ
enabledȱorȱdisabled?ȱ
ȱ
9. Ifȱ theȱ integerȱ typesȱ areȱ normallyȱ signed,ȱ whatȱ isȱ theȱ purposeȱ ofȱ theȱ signedȱ
keyword?ȱ
ȱ
10. Canȱ anȱ unsignedȱ variableȱ holdȱ aȱ largerȱ rangeȱ ofȱ valuesȱ thanȱ aȱ signedȱ variableȱ ofȱ
theȱsameȱsize?ȱ
ȱ
11. Assumingȱ thatȱ theyȱ areȱ bothȱ 32ȱ bitsȱ long,ȱ whichȱ typeȱ ofȱ variableȱ canȱ holdȱ moreȱ
distinctȱvalues,ȱanȱintȱorȱaȱfloat?ȱ
ȱ
12. Theȱtwoȱfragmentsȱofȱcodeȱshownȱbelowȱcameȱfromȱtheȱbeginningȱofȱaȱfunction.ȱ
ȱ
int
a = 25;
int
a;
a = 25;
ȱ
Howȱdoȱtheyȱdifferȱinȱwhatȱtheyȱaccomplish?ȱ
ȱ
13. Ifȱtheȱdeclarationsȱinȱ theȱcodeȱfragmentsȱinȱquestionȱ12ȱincludedȱtheȱwordȱ const,ȱ
howȱwouldȱtheyȱdifferȱinȱwhatȱtheyȱaccomplished?ȱ
ȱ
14. Aȱ variableȱ declaredȱ inȱ aȱ blockȱ mayȱ beȱ accessedȱ byȱ nameȱ fromȱ anywhereȱ inȱ thatȱ
block.ȱTrueȱorȱfalse?ȱ
ȱ
15. Supposeȱfunctionȱaȱdeclaresȱanȱautomaticȱintegerȱvariableȱcalledȱ x.ȱYouȱcanȱaccessȱ
theȱvariableȱxȱfromȱaȱdifferentȱfunctionȱbyȱusingȱaȱdeclarationȱsuchȱasȱthisȱone.ȱ
ȱ
extern int x;
ȱ
Trueȱorȱfalse?ȱ
ȱ
16. Supposeȱ theȱ variableȱ xȱ inȱ questionȱ 15ȱ hadȱ beenȱ declaredȱ static.ȱ Doesȱ thisȱ
modificationȱchangeȱyourȱanswer?ȱ
ȱ
17. Supposeȱtheȱfileȱa.cȱbeginsȱwithȱthisȱdeclaration:ȱ
Download at http://www.pin5i.com/
68 Chapter 3 Data
int
x;
int
x;
int
a = 5;
ȱ
Whatȱdeclarationȱ(ifȱany)ȱwouldȱbeȱneededȱtoȱaccessȱthisȱvariableȱfromȱaȱfunctionȱ
foundȱlaterȱinȱtheȱsameȱfile?ȱ
ȱ
18. Supposeȱ theȱ declarationȱ inȱ questionȱ 17ȱ includedȱ theȱ keywordȱ static.ȱ Wouldȱ thisȱ
modificationȱchangeȱyourȱanswer?ȱ
ȱ
19. Supposeȱtheȱfileȱa.cȱbeginsȱwithȱthisȱdeclaration:ȱ
ȱ
ȱ
Whatȱdeclarationȱ(ifȱany)ȱwouldȱbeȱneededȱtoȱaccessȱthisȱvariableȱfromȱaȱfunctionȱ
foundȱinȱaȱdifferentȱsourceȱfileȱ
ȱ
20. Supposeȱ theȱ declarationȱ inȱ questionȱ 19ȱ includedȱ theȱ keywordȱ static.ȱ Wouldȱ thisȱ
modificationȱchangeȱyourȱanswer?ȱ
ȱ
21. Supposeȱaȱfunctionȱthatȱcontainsȱautomaticȱvariablesȱisȱcalledȱtwiceȱinȱaȱrow.ȱIsȱitȱ
possibleȱthatȱtheȱvariablesȱwillȱhaveȱtheȱsameȱvaluesȱatȱtheȱbeginningȱofȱtheȱsecondȱ
callȱthatȱtheyȱhadȱatȱtheȱendȱofȱtheȱfirstȱcall?ȱ
ȱ
22. Whatȱisȱtheȱdifferenceȱinȱtheȱbehaviorȱofȱtheȱdeclarationȱ
ȱ
ȱ
Whenȱitȱappearsȱinȱsideȱofȱaȱfunctionȱasȱcomparedȱtoȱwhenȱitȱappearsȱoutside?ȱ
ȱ
23. Supposeȱyouȱwantedȱtoȱwriteȱtwoȱfunctions,ȱ xȱandȱ y,ȱinȱtheȱsameȱsourceȱfile,ȱthatȱ
useȱtheȱfollowingȱvariables:ȱ
ȱ
Name Type
Storage Class Linkage
Scope
Initialized
to
a
int
staticȱ
externalȱ
accessibleȱtoȱx;ȱnotȱyȱ 1ȱ
b
char
staticȱ
noneȱ
accessibleȱtoȱxȱandȱyȱ 2ȱ
c
int
automaticȱ
noneȱ
localȱtoȱxȱ
3ȱ
d
float
staticȱ
noneȱ
localȱtoȱxȱ
4ȱ
ȱ
Howȱ andȱ whereȱ wouldȱ youȱ writeȱ theȱ declarationsȱ forȱ theseȱ variables?ȱ Note:ȱ Allȱ
initializationȱ mustȱ beȱmadeȱinȱ theȱ declarationsȱthemselves,ȱnotȱ byȱanyȱexecutableȱ
statementsȱinȱtheȱfunctions.ȱ
ȱ
24. Identifyȱ anyȱ errorsȱ containedȱ inȱ theȱ followingȱ program.ȱ (Youȱ mayȱ wishȱ toȱ tryȱ
compilingȱitȱtoȱbeȱsure.)ȱAfterȱyouȱhaveȱremovedȱtheȱerrors,ȱdetermineȱtheȱstorageȱ
class,ȱscope,ȱandȱlinkageȱofȱeveryȱidentifier.ȱWhatȱwillȱbeȱtheȱinitialȱvalueȱofȱeachȱ
variable?ȱThereȱareȱmanyȱduplicateȱidentifiers;ȱdoȱtheyȱreferȱtoȱtheȱsameȱvariableȱorȱ
noȱdifferentȱones?ȱFromȱwhereȱcanȱeachȱofȱtheseȱfunctionsȱbeȱcalled?ȱ
Download at http://www.pin5i.com/
3.13 Questions 69
1
2
static int
extern int
w = 5;
x;
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static float
func1( int a, int b, int c )
{
int
c, d, e = 1;
...
{
int
d,e,w;
...
{
int
static
...
}
}
...
{
register int
extern int y;
...
}
}
24
static int
25
26
27
28
29
30
31
float
func2( int a )
{
extern int
static int
...
}
y;
y;
z;
b, c, d;
int
a, d, x;
y = 2;
Download at http://www.pin5i.com/
Download at http://www.pin5i.com/
4
Statements
Youȱ willȱ findȱ thatȱ Cȱ implementsȱ allȱ ofȱ theȱ statementsȱ foundȱ inȱ other,ȱ modernȱ highȬ
levelȱlanguages,ȱandȱmostȱofȱthemȱworkȱtheȱwayȱyouȱwouldȱexpect.ȱTheȱ ifȱstatementȱ
choosesȱ betweenȱ alternateȱ sequencesȱ ofȱ code,ȱ andȱ theȱ while,ȱ for,ȱ andȱ doȱ statementsȱ
implementȱdifferentȱkindsȱofȱloops.ȱ
Thereȱ areȱ someȱ differences,ȱ though.ȱ Forȱ example,ȱ Cȱ doesȱ notȱ haveȱ anȱ
assignmentȱstatement;ȱanȱȈexpressionȱstatementȈȱisȱusedȱinstead.ȱTheȱswitchȱstatementȱ
performsȱtheȱsameȱjobȱasȱotherȱlanguagesȱcaseȱstatements,ȱthoughȱinȱanȱunusualȱway.ȱ
Beforeȱ Iȱ discussȱ theȱ detailsȱ ofȱ Cȱ statements,ȱ though,ȱ letȇsȱ reviewȱ theȱ differentȱ
typefacesȱusedȱinȱsyntaxȱdescriptions.ȱCodeȱthatȱmustȱbeȱwrittenȱexactlyȱasȱshownȱisȱ
setȱ inȱ Courier,ȱ whileȱ abstractȱ descriptionsȱ ofȱ codeȱ appearȱ inȱ Courier Italic.ȱ Someȱ
statementsȱalsoȱhaveȱoptionalȱparts.ȱCodeȱthatȱyouȱmustȱwriteȱexactlyȱasȱshownȱifȱyouȱ
decideȱtoȱuseȱtheȱoptionalȱpartȱisȱshownȱinȱ Courier Bold,ȱandȱdescriptionsȱofȱoptionalȱ
partsȱ areȱ inȱ Courier Bold-Italic.ȱ Also,ȱ theȱ statementȱ syntaxȱ isȱ illustratedȱ withȱ theȱ
sameȱindentationȱusedȱinȱtheȱprogramȱ examples.ȱThisȱspacingȱisȱ notȱ requiredȱ byȱ theȱ
compilerȱbutȱisȱvaluableȱforȱhumanȱreadersȱ(suchȱasȱyourself).ȱ
ȱ
ȱ
ȱ
4.1 Empty Statement
ȱ
TheȱsimplestȱstatementȱinȱCȱisȱtheȱemptyȱstatement,ȱwhichȱconsistsȱofȱaȱsemicolonȱallȱbyȱ
itself.ȱ Theȱ emptyȱ statementȱ doesnȇtȱ performȱ anyȱ workȱ butȱ isȱ occasionallyȱ usefulȱ
anyway.ȱItȱisȱusedȱinȱsituationsȱwhereȱtheȱsyntaxȱrequiresȱaȱstatement,ȱbutȱthereȱisn’tȱ
anyȱworkȱtoȱbeȱperformed.ȱSomeȱofȱtheȱlaterȱexamplesȱinȱthisȱchapterȱincludeȱemptyȱ
statements.ȱ
Download at http://www.pin5i.com/
72 Chapter 4 Statements
4.2 Expression Statement
ȱ
IfȱthereȱisȱnoȱȈassignmentȱstatementȈȱinȱC,ȱhowȱisȱassignmentȱperformed?ȱTheȱanswerȱ
isȱ thatȱ assignmentȱ isȱ anȱ operationȱ justȱ likeȱ additionȱ andȱ subtraction,ȱ soȱ assignmentȱ isȱ
performedȱbyȱwritingȱanȱexpression.ȱ
Youȱcanȱturnȱanȱexpressionȱintoȱaȱstatementȱsimplyȱbyȱputtingȱaȱsemicolonȱatȱ
theȱendȱofȱit.ȱThus,ȱstatementȱsuchȱasȱ
ȱ
x = y + 3;
ch = getchar();
CAUTION!
ȱ
areȱreallyȱexpressionȱstatements,ȱnotȱassignmentȱstatements.ȱ
ȱ
Thisȱ distinctionȱ isȱ importantȱ toȱ understandȱ becauseȱ itȱ isȱ perfectlyȱ legalȱ toȱ writeȱ
statementsȱsuchȱasȱthese:ȱ
ȱ
y + 3;
getchar();
ȱ
Whenȱtheseȱstatementsȱareȱexecuted,ȱtheȱexpressionsȱareȱevaluated,ȱbutȱtheȱresultsȱareȱ
notȱ savedȱ anywhereȱ becauseȱ anȱ assignmentȱ operatorȱ wasȱ notȱ used.ȱ Theȱ firstȱ
statementsȱ therefore,ȱ hasȱ noȱ effectȱ whatever,ȱ andȱ theȱ secondȱ statementȱ getsȱ theȱ nextȱ
characterȱofȱinputȱbutȱthanȱignoresȱit. 22
Ifȱ itȱ seemsȱ strangeȱ thatȱ youȱ canȱ writeȱ statementsȱ thatȱ haveȱ noȱ effect,ȱ considerȱ
thisȱone:ȱ
ȱ
printf( "Hello world!\n" );
ȱ
printfȱisȱaȱfunctionȱandȱfunctionsȱreturnȱvalues,ȱyetȱtheȱvalueȱreturnedȱbyȱprintfȱ(theȱ
numberȱofȱcharactersȱactuallyȱprinted)ȱisȱusuallyȱofȱnoȱconcernȱandȱthereforeȱignored.ȱ
Theȱ statementȱ Ȉhasȱ noȱ effectȈȱ onlyȱ inȱ theȱ senseȱ thatȱ theȱ valueȱ ofȱ theȱ expressionȱ isȱ
ignored;ȱtheȱprintfȱfunctionȱperformȱusefulȱwork.ȱSuchȱworkȱisȱcalledȱaȱsideȱeffect.ȱ
Hereȱisȱanotherȱexample:ȱ
ȱ
a++;
ȱ
Thereȱ isȱ noȱ assignmentȱ operator,ȱ yetȱ itȱ isȱ aȱ perfectlyȱ reasonableȱ expressionȱ
statement.ȱTheȱ ++ȱoperatorȱincrementsȱtheȱ variableȱaȱasȱ aȱsideȱeffect.ȱThereȱareȱ otherȱ
operatorsȱwithȱsideȱeffects,ȱandȱIȱwillȱdiscussȱthemȱinȱtheȱnextȱchapter.ȱ
ȱActually,ȱitȱcanȱaffectȱtheȱoutcomeȱofȱtheȱprogram,ȱbutȱhowȱitȱdoesȱsoȱisȱsoȱsubtleȱthatȱweȱmustȱwaitȱuntilȱChapterȱ18ȱandȱ
ourȱdiscussionȱofȱtheȱruntimeȱenvironmentȱtoȱexplainȱit.ȱ
22
Download at http://www.pin5i.com/
4.4 If Statement 73
4.3 Statement Blocks
ȱ
Aȱ blockȱ isȱ aȱ listȱ ofȱ declarationsȱ andȱ aȱ listȱ ofȱ statements,ȱ bothȱ optional,ȱ enclosedȱ inȱ
braces.ȱTheȱsyntaxȱforȱaȱblockȱisȱstraightforward:ȱ
ȱ
{
declarations
statements
}
ȱ
Aȱblockȱmayȱbeȱusedȱanywhereȱaȱstatementȱisȱrequired,ȱandȱitȱletsȱyouȱuseȱaȱlistȱ
ofȱ statementsȱ inȱ placesȱ whereȱ theȱ syntaxȱ onlyȱ callsȱ forȱ one.ȱ Blocksȱ alsoȱ allowȱ youȱ toȱ
declareȱdataȱveryȱcloseȱtoȱwhereȱitȱisȱused.ȱ
ȱ
ȱ
ȱ
4.4 If Statement
ȱ
Theȱ ifȱ statementȱ inȱ Cȱ worksȱ prettyȱ muchȱ theȱ sameȱ asȱ thoseȱ inȱ otherȱ languages.ȱ Theȱ
syntaxȱlooksȱlikeȱthis:ȱ
ȱ
if( expression )
statement
else
statement
CAUTION!
ȱ
Theȱ parenthesesȱ areȱ partȱ ofȱ theȱ ifȱ statement,ȱ notȱ partȱ ofȱ theȱ expression,ȱ soȱ theyȱ areȱ
requiredȱevenȱforȱsimpleȱexpressions.ȱȱ
ȱ
Eitherȱofȱtheȱ statementsȱmayȱbeȱaȱblockȱinstead.ȱAȱcommonȱerrorȱisȱtoȱforgetȱtoȱputȱinȱ
theȱbracesȱwhenȱaddingȱaȱsecondȱstatementȱtoȱeitherȱclauseȱofȱanȱ ifȱstatement.ȱManyȱ
programmersȱpreferȱtoȱuseȱtheȱbracesȱallȱtheȱtimeȱpreciselyȱtoȱavoidȱthisȱerror.ȱ
Ifȱ theȱ expressionȱ isȱ true,ȱ thenȱ theȱ firstȱ statementȱ isȱ executed;ȱ otherwise,ȱ itȱ isȱ
skipped.ȱ Ifȱ thereȱ isȱ anȱ elseȱ clause,ȱ thenȱ itsȱ statementȱ isȱ executedȱ onlyȱ whenȱ theȱ
expressionȱisȱfalse.ȱ
Thereȱ isȱ oneȱ differenceȱ betweenȱ Cȱ ifȱ statementsȱ andȱ ifȱ statementsȱ inȱ otherȱ
languages.ȱCȱdoesnȇtȱhaveȱaȱBooleanȱtype;ȱintegersȱareȱusedȱforȱthisȱpurpose.ȱThus,ȱtheȱ
expressionȱcanȱbeȱanyȱexpressionȱthatȱresultsȱinȱanȱintegerȱvalueȱ–ȱzeroȱmeansȱȈfalseȈȱ
andȱallȱnonzeroȱvaluesȱmeanȱȈtrueȈ.ȱ
Cȱhasȱallȱofȱtheȱrelationalȱoperatorsȱthatȱyouȱwouldȱexpect,ȱbutȱtheyȱproduceȱtheȱ
integerȱ valuesȱ zeroȱ andȱ oneȱ ratherȱ thanȱ booleanȱ valuesȱ ȈtrueȈȱ andȱ Ȉfalse.Ȉȱ Thusȱ theȱ
relationalȱoperatorsȱendȱupȱfunctioningȱtheȱsameȱasȱinȱotherȱlanguages.ȱ
Download at http://www.pin5i.com/
74 Chapter 4 Statements
if( x > 3 )
printf( "Greater\n" );
else
printf( "Not greater\n" );
ȱ
evaluatesȱtheȱexpressionȱ x > 3,ȱwhichȱyieldsȱaȱvalueȱofȱeitherȱzeroȱorȱone.ȱIfȱtheȱvalueȱ
isȱone,ȱGreaterȱisȱprinted;ȱifȱitȱisȱzero,ȱNot greaterȱisȱprinted.ȱȱ
Integerȱvariablesȱcanȱalsoȱholdȱbooleanȱvalues,ȱasȱinȱthisȱexampleȱ
ȱ
result = x > 3;
...
if( result )
printf( "Greater\n" );
else
printf( "Not greater\n" );
ȱ
Thisȱcodeȱfragmentȱexecutesȱexactlyȱtheȱsameȱasȱtheȱpreviousȱone;ȱtheȱonlyȱdifferenceȱ
isȱ thatȱ theȱ resultȱ ofȱ theȱ comparison,ȱ whichȱ isȱ eitherȱ aȱ zeroȱ orȱ aȱ one,ȱ isȱ savedȱ inȱ aȱ
variableȱandȱtestedȱlater.ȱThereȱisȱaȱpotentialȱtrapȱhere.ȱEvenȱthoughȱallȱnonzeroȱvaluesȱ
areȱconsideredȱtrue,ȱcomparingȱoneȱnonzeroȱvalueȱtoȱaȱdifferentȱnonzeroȱvalueȱyieldsȱ
false.ȱIȱdiscussȱthisȱproblemȱinȱmoreȱdetailȱinȱtheȱnextȱchapter.ȱȱ
Whenȱ ifȱ statementsȱ areȱ nestedȱ withinȱ oneȱ another,ȱ theȱ danglingȱ elseȱ problemȱ
canȱ appear.ȱ Forȱ example,ȱ toȱ whichȱ ifȱ statementȱ doesȱ theȱ elseȱ clauseȱ belongȱ inȱ theȱ
followingȱfragment?ȱ
ȱ
if( i > 1 )
if( j > 2 )
printf( "i > 1 and j > 2\n" );
else
printf( "no they're not\n" );
ȱ
Theȱelseȱclauseȱisȱindentedȱstrangelyȱtoȱillustrateȱthisȱquestion.ȱTheȱanswer,ȱasȱinȱmostȱ
otherȱlanguages,ȱisȱthatȱtheȱ elseȱclauseȱbelongsȱtoȱtheȱclosestȱ ifȱthatȱisȱincomplete.ȱIfȱ
youȱwantȱitȱtoȱheȱassociatedȱwithȱanȱearlierȱifȱstatement,ȱyouȱmustȱcompleteȱtheȱcloserȱ
ifȱeitherȱbyȱaddingȱanȱemptyȱelseȱtoȱitȱorȱbyȱenclosingȱitȱinȱaȱblockȱasȱinȱthisȱfragment.ȱ
ȱ
if( i > 1 ){
if( j > 2 )
printf( "i > 1 and j > 2\n" );
}
else
printf( "no they're not\n" );
Download at http://www.pin5i.com/
4.5 While Statement 75
4.5 While Statement
ȱ
Theȱ whileȱstatementȱisȱalsoȱaȱlotȱlikeȱitsȱcounterpartȱinȱotherȱlanguages.ȱTheȱonlyȱrealȱ
differenceȱisȱtheȱexpression,ȱwhichȱworksȱtheȱsameȱasȱinȱtheȱ ifȱstatement.ȱHereȱisȱtheȱ
syntax.ȱ
ȱ
while( expression )
statement
ȱ
Theȱtestȱinȱthisȱloopȱisȱperformedȱbeforeȱtheȱbodyȱisȱexecuted,ȱsoȱifȱtheȱtestȱisȱinitiallyȱ
false,ȱtheȱbodyȱwillȱnotȱbeȱexecutedȱatȱall.ȱAgain,ȱaȱblockȱmayȱbeȱusedȱifȱmoreȱthanȱoneȱ
statementȱisȱneededȱforȱtheȱbodyȱofȱtheȱloop.ȱ
ȱ
ȱ
ȱ
4.5.1 Break and Continue Statements
ȱ
Theȱ breakȱstatementȱmayȱbeȱusedȱinȱaȱ whileȱloopȱtoȱterminateȱtheȱloopȱprematurely.ȱ
Afterȱ aȱ break,ȱ theȱ nextȱ statementȱ toȱ beȱ executedȱ isȱ theȱ oneȱ thatȱ wouldȱ haveȱ beenȱ
performedȱhadȱtheȱloopȱterminatedȱnormally.ȱ
Theȱ continueȱ statementȱ mayȱ beȱ usedȱ inȱ aȱ whileȱ loopȱ toȱ terminateȱ theȱ currentȱ
iterationȱofȱtheȱloopȱprematurely.ȱAfterȱaȱ continue,ȱtheȱexpressionȱisȱevaluatedȱagainȱ
toȱdetermineȱwhetherȱtheȱloopȱshouldȱexecuteȱagainȱorȱend.ȱ
Ifȱ eitherȱ ofȱ theseȱ statementsȱ isȱ usedȱ withinȱ nestedȱ loops,ȱ itȱ appliesȱ onlyȱ toȱ
innermostȱloop;ȱitȱisȱnotȱpossibleȱtoȱaffectȱtheȱexecutionȱofȱtheȱouterȱnestedȱloopȱwithȱaȱ
breakȱorȱcontinue.ȱ
ȱ
ȱ
ȱ
4.5.2 Execution of the While
ȱ
Weȱ canȱ nowȱ illustrateȱ theȱ flowȱ ofȱ controlȱ throughȱ aȱ whileȱ loop.ȱ Forȱ thoseȱ whoȱ haveȱ
neverȱseenȱflowchartsȱbefore,ȱtheȱdiamondȱrepresentsȱaȱdecision,ȱtheȱboxȱrepresentsȱanȱ
actionȱtoȱbeȱperformed,ȱandȱtheȱarrowsȱshowȱtheȱflowȱofȱcontrolȱbetweenȱthem.ȱFigureȱ
4.1ȱ showsȱ howȱ theȱ whileȱ statementȱ operates.ȱ Executionȱ beginsȱ atȱ theȱ top,ȱ whereȱ theȱ
exprȱisȱevaluated.ȱIfȱitsȱvalueȱisȱzero,ȱtheȱloopȱterminates.ȱOtherwise,ȱtheȱbodyȱofȱtheȱ
loopȱ (stmt)ȱ isȱ executedȱ andȱ controlȱ returnsȱ toȱ theȱ topȱ whereȱ theȱ wholeȱ thingȱ startsȱ
again.ȱ Forȱ example,ȱ theȱ loopȱ belowȱ copiesȱ charactersȱ fromȱ theȱ standardȱ inputȱ toȱ theȱ
standardȱoutputȱuntilȱtheȱendȱofȱfileȱindicationȱisȱfound.ȱ
ȱ
while( (ch = getchar()) != EOF )
putchar( ch );
ȱ
Ifȱaȱcontinueȱstatementȱisȱexecutedȱinȱtheȱbodyȱofȱtheȱloop,ȱtheȱremainingȱstatementȱȱ
Download at http://www.pin5i.com/
76 Chapter 4 Statements
== 0
expr
!= 0
break
stmt
continue
ȱ
ȱ
Figureȱ4.1ȱExecutionȱofȱtheȱwhileȱstatementȱ
ȱ
ȱ
ȱ
inȱtheȱbodyȱareȱskippedȱandȱtheȱnextȱiterationȱbeginsȱimmediately.ȱ continueȱisȱusefulȱ
inȱ situationsȱ whereȱ theȱ bodyȱ ofȱ theȱ loopȱ onlyȱ appliesȱ toȱ someȱ ofȱ theȱ valuesȱ thatȱ areȱ
encountered.ȱ
ȱ
while( (ch = getchar()) != EOF ){
if( ch < '0' || ch > '9' )
continue;
/* process only the digits */
}
ȱ
Theȱalternativeȱisȱtoȱinvertȱtheȱtestȱperformedȱinȱtheȱ ifȱandȱhaveȱitȱcontrolȱtheȱentireȱ
bodyȱ ofȱ theȱ loop.ȱ Theȱ differenceȱ isȱ solelyȱ stylistic;ȱ thereȱ isȱ noȱ differenceȱ atȱ executionȱ
time.ȱȱ
Ifȱ aȱ breakȱ statementȱ isȱ executed,ȱ theȱ loopȱ exitsȱ immediately.ȱ Forȱ example,ȱ
supposeȱaȱlistȱofȱvaluesȱtoȱbeȱprocessedȱisȱterminatedȱwithȱaȱnegativeȱnumber:ȱ
ȱ
while( scanf( "%f", &value ) == 1 ){
if( value < 0 )
break;
/* process the nonnegative value */
}
ȱ
Anȱalternativeȱisȱtoȱincludeȱtheȱtestȱinȱtheȱwhileȱexpression,ȱlikeȱthis:ȱ
ȱ
while( scanf( "%f", &value ) == 1 && value >= 0 ){
Download at http://www.pin5i.com/
4.6 For Statement 77
TIP
Thisȱstyleȱmayȱbeȱdifficult,ȱhowever,ȱifȱsomeȱcomputationsȱmustȱbeȱperformedȱbeforeȱ
theȱvalueȱcanȱbeȱtested.ȱȱ
ȱ
Occasionally,ȱ aȱ whileȱ statementȱ doesȱ allȱ theȱ workȱ inȱ itsȱ expression,ȱ andȱ thereȱ isȱ noȱ
workȱleftȱforȱtheȱbody.ȱInȱthisȱcase,ȱtheȱemptyȱstatementȱisȱusedȱforȱtheȱbody.ȱItȱisȱgoodȱ
practiceȱ toȱ writeȱ theȱ emptyȱ statementȱ onȱ aȱ lineȱ byȱ itself,ȱ asȱ illustratedȱ inȱ theȱ loopȱ
below,ȱwhichȱdiscardsȱtheȱremainderȱofȱtheȱcurrentȱinputȱline.ȱȱ
ȱ
while( (ch = getchar()) != EOF && ch != '\n' )
;
ȱ
Thisȱformȱclearlyȱshowsȱthatȱtheȱbodyȱofȱtheȱloopȱisȱempty,ȱmakingȱitȱlessȱlikelyȱthatȱ
theȱ nextȱ statementȱ inȱ theȱ programȱ willȱ beȱ misinterpretedȱ byȱ aȱ humanȱ readerȱ asȱ theȱ
bodyȱofȱtheȱloop.ȱ
ȱ
ȱ
ȱ
4.6 For Statement
ȱ
Theȱ forȱstatementȱisȱmoreȱgeneralȱthanȱtheȱ forȱstatementsȱinȱotherȱlanguages.ȱInȱfact,ȱ
theȱ forȱ statementȱ inȱ Cȱ isȱ reallyȱ justȱ aȱ shorthandȱ notationȱ forȱ aȱ veryȱ commonȱ
arrangementȱofȱstatementsȱinȱaȱ whileȱloop.ȱTheȱsyntaxȱofȱtheȱ forȱstatementȱlooksȱlikeȱ
this:ȱ
ȱ
for( expressions1; expresssion2; expression3 )
statement
ȱ
Theȱstatementȱisȱcalledȱtheȱbodyȱofȱtheȱloop.ȱexpression1 isȱtheȱinitializationȱandȱ
isȱ evaluatedȱ onceȱ beforeȱ theȱ loopingȱ begins.ȱ expression2ȱ isȱ theȱ conditionȱ andȱ isȱ
evaluatedȱ beforeȱ eachȱ executionȱ ofȱ theȱ body,ȱ justȱ asȱ inȱ aȱ whileȱ loop.ȱ expression3ȱ isȱ
calledȱ theȱ adjustmentȱ andȱ isȱ evaluatedȱ afterȱ theȱ bodyȱ andȱ justȱ beforeȱ theȱ conditionȱ isȱ
evaluatedȱ again.ȱ Allȱ threeȱ expressionsȱ areȱ optionalȱ andȱ mayȱ beȱ omitted.ȱ Aȱ missingȱ
conditionȱmeansȱȈtrue.Ȉȱ
Theȱbreakȱandȱcontinueȱstatementsȱalsoȱworkȱinȱaȱforȱloop.ȱbreakȱexitsȱtheȱloopȱ
immediatelyȱ,ȱandȱcontinueȱgoesȱdirectlyȱtoȱtheȱadjustment.ȱ
ȱ
ȱ
ȱ
4.6.1 Execution of a For
ȱ
Theȱ forȱ statementȱ isȱ executedȱ (almost)ȱ exactlyȱ theȱ sameȱ asȱ theȱ followingȱ whileȱ
statement:ȱ
Download at http://www.pin5i.com/
78 Chapter 4 Statements
expression1;
while( expression2 ){
statement
expression3;
}
TIP
ȱ
Figureȱ 4.2ȱ diagramsȱ theȱ executionȱ ofȱ theȱ forȱ statement.ȱ Canȱ youȱ seeȱ howȱ itȱ differsȱ
fromȱaȱwhileȱloop?ȱ
Theȱdifferenceȱbetweenȱtheȱ forȱandȱtheȱ whileȱloopsȱisȱwithȱcontinue.ȱInȱtheȱ forȱ
statement,ȱ aȱ continueȱ skipsȱ theȱ nestȱ ofȱ theȱ bodyȱ ofȱ theȱ loopȱ andȱ goesȱ toȱ theȱ
adjustment.ȱInȱtheȱ whileȱloop,ȱtheȱadjustmentȱisȱpartȱofȱtheȱbody,ȱsoȱaȱ continueȱskipsȱ
it,ȱtoo.ȱȱ
Aȱ stylisticȱ advantageȱ ofȱ theȱ forȱ loopȱ isȱ thatȱ itȱ collectsȱ allȱ ofȱ theȱ expressionsȱ thatȱ areȱ
responsibleȱ forȱ theȱ operationȱ ofȱ theȱ loopȱ togetherȱ inȱ oneȱ placeȱ soȱ theyȱ areȱ easierȱ toȱ
find,ȱ especiallyȱ whenȱ theȱ bodyȱ ofȱ theȱ loopȱ isȱ large.ȱ Forȱ example,ȱ theȱ followingȱ loopȱ
initializesȱtheȱelementsȱofȱanȱarrayȱtoȱzero.ȱ
ȱ
for( i = 0; i < MAX_SIZE; i += 1 )
array[i] = 0;
ȱ
Theȱfollowingȱwhileȱloopȱperformsȱtheȱsameȱtask,ȱbutȱyouȱmustȱlookȱinȱthreeȱdifferentȱ
placesȱtoȱdetermineȱhowȱtheȱloopȱoperates.ȱ
ȱ
expr1
== 0
expr2
!= 0
break
stmt
expr3
continue
ȱ
ȱ
Figureȱ4.2ȱExecutionȱofȱtheȱforȱstatementȱ
Download at http://www.pin5i.com/
4.7 Do Statement 79
i = 0;
while( i < MAX_SIZE ){
array[i] = 0;
i += 1;
}
ȱ
ȱ
ȱ
4.7 Do statement
ȱ
TheȱCȱ doȱstatementȱisȱveryȱmuchȱlikeȱtheȱrepeatȱstatementȱfoundȱinȱotherȱlanguages.ȱitȱ
behavesȱ justȱ likeȱ aȱ whileȱ statementȱ exceptȱ thatȱ theȱ testȱ isȱ madeȱ afterȱ theȱ bodyȱ isȱ
executedȱratherȱthanȱbefore,ȱsoȱtheȱbodyȱofȱtheȱloopȱisȱalwaysȱexecutedȱatȱleastȱonce.ȱ
Hereȱisȱitsȱsyntax.ȱ
ȱ
do
statement
while( expression );
ȱ
Asȱusual,ȱaȱblockȱmayȱbeȱusedȱifȱmultipleȱstatementsȱareȱneededȱinȱtheȱbody.ȱFigureȱ
4.3ȱshowsȱhowȱexecutionȱflowsȱaȱdoȱstatementȱ
ȱ
Howȱdoȱyouȱchooseȱbetweenȱaȱwhileȱandȱaȱdo?ȱ
ȱ
Whenȱyouȱneedȱtheȱbodyȱofȱtheȱloopȱtoȱbeȱexecutedȱatȱleastȱonce,ȱuseȱaȱdo.ȱ
ȱ
ȱ
break
stmt
expr
continue
!= 0
== 0
ȱ
ȱ
Figureȱ4.3ȱExecutionȱofȱtheȱdoȱstatementȱ
Download at http://www.pin5i.com/
80 Chapter 4 Statements
Theȱloopȱbelow,ȱwhichȱprintsȱfromȱoneȱtoȱeightȱspacesȱtoȱadvanceȱtoȱtheȱnextȱtabȱstopȱ
(setȱeveryȱeightȱcolumns),ȱillustratesȱthis.ȱ
ȱ
do {
column += 1;
putchar( ' ' );
} while( column % 8 != 0 );
ȱ
ȱ
ȱ
4.8 Switch Statement
ȱ
Theȱ switchȱ statementȱ inȱ Cȱ isȱ aȱ littleȱ unusual.ȱ Itȱ servesȱ theȱ sameȱ roleȱ asȱ theȱ caseȱ
statementȱ inȱ otherȱ languages,ȱ butȱ itȱ isȱ differentȱ inȱ oneȱ veryȱ importantȱ respect.ȱ Letȇsȱ
lookȱatȱtheȱsyntaxȱfirst.ȱTheȱexpressionȱmustȱproduceȱanȱintegerȱvalue.ȱ
ȱ
switch( expression )
statement
ȱ
Althoughȱ itȱ isȱ legalȱ toȱ writeȱ aȱ switchȱ statementȱ withȱ onlyȱ aȱ singleȱ statementȱ asȱ itsȱ
body,ȱthereȱisȱnoȱpointȱinȱdoingȱso.ȱPracticalȱswitchȱstatementsȱlookȱlikeȱthisȱone:ȱ
ȱ
switch( expression ){
statement-list
}
ȱ
Sprinkledȱthroughoutȱtheȱstatementȱlistȱareȱoneȱorȱmoreȱcaseȱlabelsȱofȱtheȱformȱ
ȱ
case constant-expression:
CAUTION!
ȱ
Eachȱcaseȱlabelȱmustȱhaveȱaȱuniqueȱvalue.ȱAȱconstantȱexpressionȱisȱanȱexpressionȱthatȱisȱ
evaluatedȱ atȱ compileȱ time;ȱ itȱ mayȱ notȱ containȱ anyȱ variables.ȱ Whatȱ isȱ unusualȱ isȱ thatȱ
theȱcaseȱlabelsȱdoȱnotȱpartitionȱtheȱstatementȱlistȱintoȱseparateȱsections;ȱtheyȱidentifyȱ
entryȱpointsȱintoȱtheȱlistȱofȱstatements.ȱ
Let’sȱfollowȱtheȱexecutionȱofȱthisȱstatement.ȱFirst,ȱtheȱ expressionȱisȱevaluated.ȱ
Then,ȱ executionȱ goesȱ toȱ theȱ statementȱ inȱ theȱ listȱ thatȱ isȱ identifiedȱ byȱ theȱ caseȱ labelȱ
whoseȱvalueȱmatchesȱtheȱexpressionȇsȱvalue.ȱFromȱhere,ȱtheȱstatementȱlistȱisȱexecutedȱ
allȱtheȱwayȱtoȱitsȱend,ȱwhichȱisȱatȱtheȱbottomȱofȱtheȱswitchȱstatement.ȱ
ȱ
ȱ
ȱ
ȱ
Doȱyouȱseeȱtheȱdifferenceȱinȱtheȱexecutionȱofȱtheȱ switch?ȱExecutionȱflowsȱthroughȱcaseȱ
labelsȱratherȱthanȱstoppingȱatȱthem,ȱwhichȱisȱwhyȱcaseȱlabelsȱidentifyȱentryȱpointsȱtoȱ
Download at http://www.pin5i.com/
4.8 Switch Statement 81
theȱstatementȱlistȱratherȱthanȱpartitioningȱit.ȱIfȱthisȱbehaviorȱdoesn’tȱseemȱright,ȱthereȱ
isȱaȱwayȱtoȱfixȱit—theȱbreakȱstatement.ȱ
ȱ
ȱ
ȱ
4.8.1 break in a switch
ȱ
Ifȱaȱbreakȱisȱencounteredȱinȱaȱswitchȱstatement,ȱexecutionȱproceedsȱimmediatelyȱtoȱtheȱ
endȱ ofȱ theȱ statementȱ list.ȱ Thus,ȱ 97%ȱ ofȱ allȱ switchȱ statementsȱ inȱ Cȱ haveȱ breakȱ
statementsȱatȱtheȱendȱofȱeachȱcase.ȱTheȱfollowingȱexample,ȱwhichȱexaminesȱaȱcharacterȱ
enteredȱbyȱtheȱuserȱandȱinvokesȱtheȱfunctionȱthatȱitȱselects,ȱillustratesȱthisȱusage.ȱ
ȱ
switch( command ){
case 'A':
add_entry();
break;
case 'D':
delete_entry();
break;
case 'P':
print_entry();
break;
case 'E':
edit_entry();
break;
}
ȱ
Inȱeffect,ȱtheȱ breakȱstatementsȱpartitionȱtheȱstatementȱlistȱsoȱthatȱtheȱswitchȱwillȱworkȱ
inȱtheȱmoreȱtraditionalȱmanner.ȱ
Whatȱ isȱ theȱ purposeȱ ofȱ theȱ breakȱ inȱ theȱ lastȱ caseȱ ofȱ theȱ statement?ȱ Itȱ hasȱ noȱ
effectȱatȱrunȱtime,ȱbecauseȱthereȱarenȇtȱanyȱ moreȱstatementsȱinȱtheȱswitch,ȱbutȱitȱalsoȱ
doesnȇtȱ hurtȱ anything.ȱ Thisȱ breakȱ isȱ thereȱ forȱ futureȱ maintenance.ȱ Shouldȱ someoneȱ
decideȱ laterȱ toȱ addȱ anotherȱ caseȱ toȱ thisȱ statement,ȱ thereȱ isȱ noȱ chanceȱ thatȱ theyȱ willȱ
forgetȱtoȱaddȱaȱbreakȱatȱtheȱendȱofȱtheȱstatementsȱforȱtheȱpreviousȱcase.ȱ
Theȱ continueȱhasȱnoȱeffectȱinȱaȱ switchȱstatement.ȱYouȱmayȱputȱaȱ continueȱinȱaȱ
switchȱstatementȱonlyȱifȱtheȱ switchȱisȱenclosedȱbyȱaȱloop;ȱtheȱ continueȱappliesȱtoȱtheȱ
loopȱratherȱthanȱtheȱswitch.ȱ
Download at http://www.pin5i.com/
82 Chapter 4 Statements
Inȱ orderȱ toȱ executeȱ theȱ sameȱ groupȱ ofȱ statementsȱ withȱ twoȱ orȱ moreȱ values,ȱ
multipleȱcaseȱlabelsȱareȱgiven,ȱasȱinȱthisȱexample.ȱ
ȱ
switch( expression ){
case 1:
case 2:
case 3:
statement-list
break;
case 4:
case 5:
statement-list
break;
}
ȱ
Thisȱtechniqueȱworksȱbecauseȱexecutionȱflowsȱthroughȱtheȱcaseȱlabels.ȱCȱdoesȱnotȱhaveȱ
anyȱshorthandȱnotationȱforȱspecifyingȱrangesȱofȱvalues,ȱsoȱeveryȱvalueȱinȱaȱrangeȱmustȱ
beȱgivenȱasȱaȱseparateȱcaseȱlabel.ȱIfȱtheȱrangeȱofȱvaluesȱisȱlarge,ȱyouȱmayȱpreferȱaȱseriesȱ
ofȱnestedȱifȱstatementsȱinstead.ȱ
ȱ
ȱ
ȱ
4.8.2 Defaults
ȱ
Theȱnextȱquestionȱis,ȱwhatȱhappensȱifȱtheȱexpressionȇsȱvalueȱdoesȱnotȱmatchȱanyȱofȱtheȱ
caseȱ labels?ȱ Nothingȱ atȱ all—theȱ statementȱ listȱ isȱ skippedȱ entirely.ȱ Theȱ programȱ doesȱ
notȱ abortȱ orȱ giveȱ anyȱ indicationȱ ofȱ errorȱ becauseȱ thisȱ situationȱ isȱ notȱ consideredȱ anȱ
errorȱinȱC.ȱȱ
Whatȱifȱyouȱdon’tȱwantȱtoȱignoreȱexpressionȱvaluesȱthatȱdoȱnotȱmatchȱanyȱeaseȱ
labels?ȱYouȱcanȱaddȱaȱdefaultȱclauseȱtoȱtheȱstatementȱlistȱbyȱwritingȱ
ȱ
default:
TIP
ȱ
inȱ placeȱ ofȱ aȱ caseȱ label.ȱ Theȱ defaultȱ clauseȱ isȱ whereȱ executionȱ ofȱ theȱ statementȱ listȱ
beginsȱwhenȱtheȱexpressionȱvalueȱdoesȱnotȱmatchȱanyȱofȱtheȱeaseȱlabels,ȱsoȱthereȱcanȱ
beȱonlyȱoneȱofȱthem.ȱHowever,ȱitȱcanȱgoȱanywhereȱinȱtheȱstatementȱlist,ȱandȱexecutionȱ
flowsȱthroughȱtheȱdefaultȱtheȱsameȱasȱaȱcaseȱlabel.ȱ
ȱ
Itȱ isȱ goodȱ practiceȱ toȱ useȱ aȱ defaultȱ clauseȱ inȱ everyȱ switchȱ statementȱ soȱ thatȱ illegalȱ
valuesȱcanȱbeȱdetected.ȱOtherwiseȱtheȱprogramȱwillȱcontinueȱtoȱrunȱwithȱnoȱindicationȱ
thatȱanȱerrorȱoccurred.ȱTheȱonlyȱreasonableȱexceptionsȱtoȱthisȱruleȱareȱwhenȱtheȱvalueȱ
beingȱtestedȱhasȱbeenȱcheckedȱforȱvalidityȱearlier,ȱandȱwhenȱyouȱareȱonlyȱinterestedȱinȱ
aȱsubsetȱofȱtheȱpossibleȱvalues.ȱ
Download at http://www.pin5i.com/
4.8 Switch Statement 83
4.8.3 Execution of the Switch
ȱ
Whyȱisȱtheȱswitchȱstatementȱimplementedȱinȱthisȱmanner?ȱManyȱprogrammersȱthinkȱ
thatȱ itȱwasȱaȱmistake,ȱbutȱonceȱinȱaȱblueȱmoonȱitȱisȱ usefulȱ toȱ haveȱ controlȱ flowȱ fromȱ
oneȱstatementȱgroupȱintoȱtheȱnext.ȱ
Forȱexample,ȱconsiderȱaȱprogramȱthatȱcountsȱtheȱnumberȱofȱcharacters,ȱwords,ȱ
andȱ linesȱ inȱ itsȱ input.ȱ Eachȱ characterȱ mustȱ beȱ counted,ȱ butȱ spaceȱ andȱ tabȱ charactersȱ
alsoȱterminateȱwhateverȱwordȱtheyȱfollowed,ȱsoȱforȱthem,ȱbothȱtheȱcharacterȱcountȱandȱ
theȱ wordȱ countȱ mustȱ beȱ incremented.ȱ Thenȱ thereȱ isȱ theȱ newline;ȱ thisȱ characterȱ
terminatesȱaȱlineȱandȱaȱword,ȱsoȱthereȱareȱthreeȱcountersȱtoȱadjustȱforȱaȱnewline.ȱNowȱ
examineȱthisȱstatement:ȱ
ȱ
switch( ch ){
case '\n':
lines += 1;
/* FALL THRU */
case ' ':
case'\t':
words += 1;
/* FALL THRU */
default:
chars += 1;
}
ȱ
ȱ
Theȱlogicȱisȱsimplerȱthanȱwhatȱwouldȱappearȱinȱaȱrealȱprogram,ȱforȱexample,ȱonlyȱtheȱ
firstȱofȱaȱsequenceȱofȱspacesȱterminatesȱtheȱprecedingȱword.ȱNevertheless,ȱtheȱexampleȱ
doesȱwhatȱweȱwant:ȱnewlinesȱcauseȱallȱthreeȱcountersȱtoȱbeȱincremented,ȱspacesȱandȱ
tabsȱincrementȱonlyȱtwo,ȱandȱeverythingȱelseȱincrementsȱonlyȱtheȱcharacterȱcounter.ȱ
ȱ
TheȱFALL THRUȱcommentsȱmakeȱitȱclearȱtoȱtheȱreaderȱthatȱexecutionȱisȱsupposedȱ
toȱ fallȱ throughȱ theȱ caseȱ labels.ȱ Withoutȱ theȱ comments,ȱ aȱ carelessȱ maintenanceȱ
programmerȱ lookingȱ forȱ aȱ bugȱ mightȱ noticeȱ theȱ lackȱ ofȱ breakȱ statementsȱ andȱ decideȱ
thatȱthisȱomissionȱisȱtheȱerrorȱandȱnotȱlookȱanyȱfurther.ȱAfterȱall,ȱitȱisȱsoȱrareȱthatȱyouȱ
actuallyȱwantȱexecutionȱtoȱflowȱthroughȱtheȱcaseȱlabelsȱthatȱaȱmissingȱ breakȱstatementȱ
isȱmuchȱmoreȱlikelyȱtoȱbeȱanȱerrorȱthanȱnot.ȱButȱinȱȈfixingȈȱthisȱproblem,ȱheȱwouldȱnotȱ
onlyȱhaveȱmissedȱtheȱbugȱheȱwasȱoriginallyȱlookingȱfor,ȱbutȱheȱwouldȱhaveȱintroducedȱ
aȱnewȱoneȱasȱwell.ȱTheȱsmallȱeffortȱofȱwritingȱtheseȱcommentsȱnowȱmightȱpayȱoffȱinȱaȱ
lotȱofȱtimeȱsavedȱlater.ȱ
Download at http://www.pin5i.com/
84 Chapter 4 Statements
4.9 Goto Statement
ȱ
Lastly,ȱthereȱisȱtheȱgotoȱstatement,ȱwhichȱhasȱthisȱsyntax.ȱ
ȱ
goto statement-label;
ȱ
Toȱuseȱit,ȱyouȱmustȱputȱstatementȱlabelsȱbeforeȱeachȱstatementȱtoȱwhichȱyouȱwishȱtoȱgo.ȱ
Statementȱlabelsȱareȱidentifiersȱfollowedȱbyȱaȱcolon.ȱgotoȱstatementsȱthatȱincludeȱtheseȱ
labelsȱmayȱthenȱbeȱplacedȱanywhereȱinȱtheȱsameȱfunction.ȱ
ȱ
Theȱ gotoȱ isȱ aȱ dangerousȱ statement,ȱ becauseȱ whenȱ learningȱ Cȱ itȱ isȱ tooȱ easyȱ toȱ
becomeȱdependentȱonȱit.ȱInexperiencedȱprogrammersȱsometimesȱuseȱ gotoȇsȱasȱaȱwayȱ
toȱ avoidȱ thinkingȱ aboutȱ theȱ programȇsȱ design.ȱ Theȱ resultingȱ programsȱ areȱ nearlyȱ
alwaysȱmoreȱdifficultȱtoȱmaintainȱthanȱcarefullyȱdesignedȱones.ȱForȱexample,ȱhereȱisȱaȱ
programȱthatȱusesȱgotoȇsȱtoȱperformȱanȱexchangeȱsortȱofȱtheȱvaluesȱinȱanȱarray.ȱ
ȱ
ȱ
ȱ
i = 0;
outer_next:
if( i >= NUM_ELEMENTS – 1 )
goto outer_end;
j = i + 1;
inner_next:
if( j >= NUM_ELEMENTS )
goto inner_end;
if( value[i] <= value[j] )
goto no_swap;
temp = value[i];
value[i] = value[j];
value[j] = temp;
no_swap:
j += 1;
goto inner_next;
inner_end:
i += 1;
goto outer_next;
outer_end:
;
ȱ
Thisȱisȱaȱtinyȱprogram,ȱyetȱyouȱmustȱspendȱaȱconsiderableȱamountȱofȱtimeȱstudyingȱitȱ
toȱunderstandȱitsȱstructure.ȱȱ
ȱ
Hereȱisȱtheȱsameȱprogramȱwithoutȱgoto’s.ȱItsȱstructureȱisȱmuchȱeasierȱtoȱsee.ȱ
ȱ
Download at http://www.pin5i.com/
4.9 Goto Statement 85
for( i = 0; i < NUM_ELEMENTS – 1; i += 1 ){
for( j = i + 1; j < NUM_ELEMENTS; j += 1 ){
if( value[i] > value[j] ){
temp = value[i];
value[i] = value[j];
value[j] = temp;
}
}
}
ȱ
ȱ
However,ȱ thereȱ isȱ oneȱ situationȱ inȱ whichȱ manyȱ claimȱ thatȱ aȱ gotoȱ mightȱ beȱ
appropriateȱinȱaȱwellȱstructuredȱprogram—breakingȱoutȱofȱnestedȱloops.ȱBecauseȱtheȱ
breakȱ statementȱ onlyȱ affectsȱ theȱ innermostȱ loopȱ thatȱ enclosesȱ it,ȱ theȱ onlyȱ wayȱ toȱ
immediatelyȱexitȱaȱdeeplyȱnestedȱsetȱofȱloopsȱisȱwithȱaȱgoto,ȱasȱshownȱinȱthisȱexample.ȱ
ȱ
while( condition1 ){
while( condition2 ){
while( condition3 ){
if( someȱdisasterȱ)
goto quit;
}
}
}
quit: ;
ȱ
ȱ
Thereȱ areȱtwoȱalternativesȱtoȱ usingȱ aȱgoto.ȱ First,ȱ aȱ statusȱ flagȱ canȱ beȱsetȱ whenȱ
youȱwantȱtoȱexitȱallȱofȱtheȱloops,ȱbutȱtheȱflagȱmustȱthenȱbeȱtestedȱinȱeveryȱloop:ȱ
enum { EXIT, OK } status;
...
status = OK;
while( status == OK && condition1 ){
while( status == OK && condition2 ){
while( condition3 ){
if( someȱdisasterȱ){
status = EXIT;
break;
}
}
}
}
Download at http://www.pin5i.com/
86 Chapter 4 Statements
Thisȱ techniqueȱ doesȱ theȱ jobȱ butȱ makesȱ theȱ conditionsȱ moreȱ complex.ȱ Theȱ secondȱ
alternativeȱisȱtoȱputȱtheȱentireȱsetȱofȱloopsȱinȱaȱseparateȱfunction.ȱWhenȱdisasterȱstrikesȱ
inȱtheȱinnermostȱloop,ȱyouȱcanȱuseȱaȱ returnȱstatementȱtoȱleaveȱtheȱfunction.ȱChapterȱ7ȱ
discussesȱreturnȱstatements.ȱ
ȱ
ȱ
ȱ
4.10 Summary
ȱ
ManyȱofȱtheȱstatementsȱinȱCȱbehaveȱtheȱsameȱasȱtheirȱcounterpartsȱinȱotherȱlanguages.ȱ
Theȱ ifȱ statementȱ conditionallyȱ executesȱ statements,ȱ andȱ theȱ whileȱ statementȱ
repeatedlyȱexecutesȱstatements.ȱBecauseȱCȱdoesȱnotȱhaveȱaȱbooleanȱtype,ȱbothȱofȱtheseȱ
statementsȱ testȱ anȱ integerȱ expressionȱ instead.ȱ Theȱ valueȱ zeroȱ isȱ interpretedȱ asȱ false,ȱ
andȱnonzeroȱvaluesȱareȱinterpretedȱasȱtrue.ȱTheȱ forȱstatementȱisȱaȱshorthandȱnotationȱ
forȱ aȱ whileȱ loop;ȱ itȱ collectsȱ theȱ expressionsȱ thatȱ controlȱ theȱ loopȱ inȱ oneȱ placeȱ soȱ thatȱ
theyȱareȱeasyȱtoȱfind.ȱTheȱdoȱstatementȱisȱsimilarȱtoȱaȱwhile,ȱbutȱdoȱguaranteesȱthatȱtheȱ
bodyȱofȱtheȱloopȱisȱalwaysȱexecutedȱatȱleastȱonce.ȱFinally,ȱtheȱ gotoȱstatementȱtransfersȱ
executionȱfromȱoneȱstatementȱtoȱanother.ȱInȱgeneral,ȱgotoȱshouldȱbeȱavoided.ȱ
Cȱ alsoȱ hasȱ someȱ statementsȱ thatȱ behaveȱ aȱ littleȱ differentlyȱ thanȱ theirȱ
counterpartsȱ inȱ otherȱ languages.ȱ Assignmentȱ isȱ doneȱ withȱ anȱ expressionȱ statementȱ
ratherȱ thanȱ anȱ assignmentȱ statement.ȱ Theȱ switchȱ statementȱ performsȱ theȱ jobȱ ofȱ theȱ
caseȱstatementȱinȱotherȱlanguages,ȱbutȱexecutionȱinȱaȱ switchȱpassesȱthroughȱtheȱcaseȱ
labelsȱ toȱ theȱ endȱ ofȱ theȱ switch.ȱ Toȱ preventȱ thisȱ behavior,ȱ youȱ mustȱ putȱ aȱ breakȱ
statementȱatȱtheȱendȱofȱtheȱstatementsȱforȱeachȱcase.ȱAȱdefault:ȱclauseȱinȱaȱswitchȱwillȱ
catchȱ expressionsȱ whoseȱ valuesȱ doȱ notȱ matchȱ anyȱ ofȱ theȱ givenȱ caseȱ values.ȱ Inȱ theȱ
absenceȱofȱaȱdefault,ȱtheȱbodyȱofȱtheȱswitchȱisȱskippedȱifȱnoneȱofȱtheȱcaseȱlabelsȱmatchȱ
theȱexpressionsȱvalue.ȱ
Theȱemptyȱstatementȱisȱusedȱwhenȱaȱstatementȱisȱrequiredȱbutȱthereȱisȱnoȱworkȱ
needed.ȱ Statementȱ blocksȱ allowȱ youȱ toȱ writeȱ manyȱ statementsȱ inȱ placesȱ whereȱ theȱ
syntaxȱ callsȱ forȱ aȱ singleȱ statement.ȱ Whenȱ aȱ breakȱ statementȱ isȱ executedȱ insideȱ ofȱ aȱ
loop,ȱitȱterminatesȱtheȱloop.ȱWhenȱaȱ continueȱstatementȱisȱexecutedȱinsideȱofȱaȱloop,ȱ
theȱ remainderȱ ofȱ theȱ bodyȱ isȱ skippedȱ andȱ theȱ nextȱ iterationȱ ofȱ theȱ loopȱ beginsȱ
immediately.ȱInȱ whileȱandȱ doȱloops,ȱtheȱnextȱiterationȱbeginsȱwithȱtheȱtest,ȱbutȱinȱ forȱ
loops,ȱtheȱnextȱiterationȱbeginsȱwithȱtheȱadjustment.ȱ
Andȱthatȇsȱit!ȱCȱdoesȱnotȱhaveȱanyȱinput/outputȱstatements;ȱI/Oȱisȱperformedȱbyȱ
callingȱ libraryȱ functions.ȱ Norȱ doesȱ itȱ haveȱ anyȱ exceptionȱ handlingȱ statements;ȱ theseȱ
areȱalsoȱdoneȱwithȱlibraryȱfunctions.ȱ
ȱ
ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
4.13 Questions 87
4.11 Summary of Cautions
ȱ
1. Writingȱexpressionsȱthatȱhaveȱnoȱresultȱ(pageȱ72).ȱ
2. Beȱsureȱtoȱuseȱbracesȱaroundȱstatementȱlistȱinȱanȱifȱstatementȱ(pageȱ73).ȱ
3. Executionȱflowingȱunexpectedlyȱfromȱoneȱ caseȱofȱaȱ switchȱstatementȱintoȱtheȱnextȱ
(pageȱ81).ȱ
ȱ
ȱ
ȱ
4.12 Summary of Programming Tips
ȱ
1. Inȱaȱloopȱwithoutȱaȱbody,ȱputȱtheȱsemicolonȱforȱtheȱemptyȱstatementȱonȱaȱlineȱbyȱ
itselfȱ(pageȱ77.)ȱ
2. Itȱisȱeasierȱtoȱreadȱ forȱloopsȱthanȱ whileȱloopsȱbecauseȱtheȱexpressionsȱthatȱcontrolȱ
theȱloopȱareȱallȱtogetherȱ(pageȱ78).ȱ
3. Useȱaȱdefault:ȱclauseȱinȱeveryȱswitchȱstatementȱ(pageȱ82).ȱ
ȱ
ȱ
ȱ
4.13 Questions
ȱ
1. Isȱtheȱfollowingȱstatementȱlegal?ȱIfȱso,ȱwhatȱdoesȱitȱdo?ȱ
ȱ
3 * x * x – 4 * x + 6;
ȱ
2. Whatȱisȱtheȱsyntaxȱofȱtheȱassignmentȱstatement?ȱ
3. Isȱitȱlegalȱtoȱuseȱaȱblockȱinȱthisȱmanner?ȱIfȱso,ȱwhyȱwouldȱyouȱeverȱwantȱtoȱuseȱit?ȱ
ȱ
...
statement
{
statement
statement
}
statement
4. Howȱ wouldȱ youȱ writeȱ anȱ ifȱ statementȱ thatȱ hadȱ noȱ statementsȱ inȱ theȱ thenȱ clauseȱ
butȱhadȱstatementsȱinȱtheȱ elseȱclause?ȱHowȱelse,ȱcouldȱanȱequivalentȱstatementȱbeȱ
written?ȱ
5. Whatȱoutputȱisȱproducedȱfromȱtheȱloopȱbelow?ȱ
int
i;
Download at http://www.pin5i.com/
88 Chapter 4 Statements
...
for( i = 0; i < 10; i += 1 )
printf( "%d\n", i );
6. Whenȱmightȱaȱwhileȱstatementȱbeȱmoreȱappropriateȱthanȱaȱforȱstatement?ȱ
7. Theȱcodeȱfragmentȱbelowȱisȱsupposedȱtoȱcopyȱtheȱstandardȱinputȱtoȱtheȱstandardȱ
outputȱandȱcomputeȱaȱchecksumȱofȱtheȱcharacters.ȱWhatȱisȱwrongȱwithȱit?ȱ
while( (ch = getchar()) != EOF )
checksum += ch;
putchar( ch );
printf( "Checksum = %d\n", checksum );
8. Whenȱisȱtheȱdoȱstatementȱmoreȱappropriateȱthanȱaȱwhileȱorȱaȱforȱstatement?ȱ
9. Whatȱoutputȱisȱproducedȱfromȱthisȱcodeȱfragment?ȱNote:ȱTheȱ%ȱoperatorȱdividesȱitsȱ
leftȱoperandȱbyȱitsȱrightȱoperandȱandȱgivesȱyouȱtheȱremainder.ȱ
for( i = 1; i <= 4; i += 1 ){
switch( i % 2 ){
case 0:
printf( "even\n" );
case 1:
printf( "odd\n" );
}
}
10. Writeȱstatementsȱthatȱreadȱanȱintegerȱvalueȱfromȱtheȱstandardȱinputȱandȱthenȱprintȱ
thatȱmanyȱblankȱlines.ȱ
11. Writeȱ statementsȱ toȱ validateȱ andȱ reportȱ onȱ someȱ valuesȱ thatȱ haveȱ alreadyȱ beenȱ
read.ȱIfȱxȱisȱlessȱthanȱy,ȱprintȱtheȱwordȱWRONG.ȱAlso,ȱifȱaȱisȱgreaterȱthanȱorȱequalȱtoȱb,ȱ
printȱ WRONG.ȱ Otherwise,ȱ printȱ theȱ wordȱ RIGHT.ȱ Note:ȱ Inȱ caseȱ youȱ needȱ it,ȱ ||ȱ isȱ theȱ
ȈorȈȱoperator.ȱ
12. Yearsȱthatȱareȱdivisibleȱbyȱfourȱareȱleapȱyears,ȱexcept,ȱthatȱyearsȱthatȱareȱdivisibleȱ
byȱ 100ȱ areȱ not.ȱ However,ȱ yearsȱ thatȱ areȱ divisibleȱ byȱ 400ȱ areȱ leapȱ years.ȱ Writeȱ
statementsȱ toȱ determineȱ whetherȱ theȱ valueȱ inȱ yearȱ isȱ aȱ leapȱ year,ȱ andȱ setȱ theȱ
variableȱleap_yeasȱtoȱoneȱifȱitȱisȱaȱleapȱyear,ȱandȱzeroȱifȱitȱisȱnot.ȱ
13. Newspaperȱreportersȱareȱtrainedȱtoȱaskȱwho,ȱwhat,ȱwhen,ȱwhere,ȱandȱwhy?ȱWriteȱ
statementsȱthatȱwillȱprintȱwhoȱifȱtheȱvariableȱwhich_wordȱisȱone,ȱwhat if the ȱ
ȱ
variableȱisȱtwo,ȱandȱsoȱforth.ȱIfȱtheȱvalueȱisȱnotȱinȱtheȱrangeȱoneȱthroughȱfive,ȱprintȱ
don’t knowȱinstead.ȱ
14. Pretendȱ thatȱ aȱ ȈprogramȈȱ controlsȱ you,ȱ andȱ thisȱ programȱ containsȱ twoȱ function:ȱ
eat_hamburger()ȱmakesȱyouȱeatȱaȱhamburger,ȱandȱ hunger()ȱreturnsȱaȱtrueȱorȱfalseȱ
Download at http://www.pin5i.com/
4.14 Programming Exercises 89
valueȱdependingȱonȱwhetherȱyouȱareȱhungry.ȱWriteȱtheȱstatementȱthatȱallowȱyouȱtoȱ
eatȱasȱmanyȱhamburgersȱasȱyouȱwantȱuntilȱyouȇreȱnoȱlongerȱhungry.ȱ
15. Modifyȱyourȱanswerȱtoȱquestionȱ14ȱtoȱsatisfyȱyourȱgrandmother—Youȇveȱgotȱtoȱeatȱ
something!—soȱthatȱyouȱalwaysȱeatȱatȱleastȱoneȱhamburger.ȱ
16. Writeȱ statementsȱtoȱ printȱaȱ capsuleȱ summaryȱofȱtheȱcurrentȱ weatherȱaccordingȱtoȱ
theȱvaluesȱofȱtheȱvariablesȱprecipitatingȱandȱtemperature.ȱ
ȱ
Ifȱprecipitatingȱisȱ…ȱ
andȱtemperatureȱisȱ…ȱ
thenȱprintȱ…ȱ
snowing
<ȱ32ȱ
trueȱ
raining
>=ȱ32ȱ
cold
<ȱ60ȱ
falseȱ
warm
>=ȱ60ȱ
ȱ
ȱ
ȱ
ȱ
4.14 Programming Exercises
ȱ
1. Theȱ squareȱ rootȱ ofȱ aȱ positiveȱ numberȱ nȱ canȱ beȱ computedȱ asȱ aȱ seriesȱ ofȱ
approximations,ȱ eachȱ moreȱ accurateȱ thanȱ theȱ last.ȱ Theȱ firstȱ approximationȱ isȱ one;ȱ
successiveȱapproximationsȱareȱgivenȱbyȱtheȱfollowingȱformula.ȱ
ȱ
n
ai ai
ai 1
2 ȱ
ȱ
Writeȱaȱprogramȱtoȱreadȱaȱvalueȱandȱcomputeȱandȱprintȱitsȱsquareȱroot.ȱlfȱyouȱprintȱ
allȱ ofȱ theȱ approximationsȱ youȱ canȱ seeȱ howȱ quicklyȱ thisȱ methodȱ convergesȱ onȱ theȱ
correctȱvalue.ȱInȱprinciple,ȱtheȱcomputationȱcouldȱgoȱonȱforever,ȱyieldingȱmoreȱandȱ
moreȱaccurateȱvalues.ȱInȱpractice,ȱthough,ȱtheȱrestrictedȱprecisionȱofȱfloatingȬpointȱ
variablesȱ preventsȱ theȱ programȱ fromȱ continuing.ȱ Haveȱ yourȱ programȱ stopȱ
computingȱwhenȱanȱapproximationȱisȱequalȱtoȱtheȱpreviousȱone.ȱ
2. Anȱ integerȱ isȱ calledȱ primeȱ ifȱ itȱ isȱ notȱ evenlyȱ divisibleȱ byȱ anyȱ integerȱ otherȱ thanȱ
itselfȱandȱone.ȱWriteȱaȱprogramȱtoȱprintȱthoseȱnumbersȱinȱtheȱrangeȱ1–100ȱthatȱareȱ
prime.ȱ
3. Allȱthreeȱsidesȱofȱequilateralȱtrianglesȱareȱtheȱsameȱlength,ȱbutȱonlyȱtwoȱofȱtheȱsidesȱ
ofȱanȱisoscelesȱtriangleȱareȱequal.ȱlfȱallȱofȱtheȱsidesȱofȱaȱtriangleȱareȱdifferentȱlengthsȱ
Download at http://www.pin5i.com/
90 Chapter 4 Statements
itȱisȱcalledȱscalene.ȱWriteȱaȱprogramȱtoȱpromptȱforȱandȱreadȱthreeȱnumbersȱthatȱareȱ
theȱlengthsȱofȱtheȱthreeȱsideȱofȱaȱtriangle.ȱTheȱprogramȱshouldȱthanȱdetermineȱwhatȱ
typeȱ ofȱ triangleȱ theȱ numbersȱ represent.ȱ Hint:ȱ Whatȱ elseȱ shouldȱ theȱ programȱ beȱ
lookingȱfor?ȱ
4. Writeȱtheȱfunctionȱcopy_nȱwhoseȱprototypeȱisȱshownȱbelow.ȱ
void copy_n( char dst[], char src[], int n );
Theȱ functionȱ isȱ toȱ copyȱ aȱ stringȱ fromȱ theȱ arrayȱ srcȱ toȱ theȱ arrayȱ dstȱ butȱ withȱ theȱ
followingȱ requirement:ȱ exactlyȱ nȱ charactersȱ mustȱ beȱ storedȱ intoȱ dst;ȱ noȱ more,ȱ noȱ
less.ȱIfȱtheȱlengthȱofȱtheȱstringȱinȱ srcȱisȱlessȱthanȱ n,ȱthenȱyouȱmustȱaddȱenoughȱ NULȱ
charactersȱ afterȱ theȱ copiedȱ charactersȱ toȱ getȱ aȱ totalȱ ofȱ nȱ charactersȱ stored.ȱ Ifȱ theȱ
lengthȱ ofȱ theȱ stringȱ inȱ srcȱ isȱ greaterȱ thanȱ orȱ equalȱ toȱ n,ȱ thenȱ stopȱ afterȱ youȱ haveȱ
storedȱtheȱnȇthȱcharacter;ȱinȱthisȱcaseȱdstȱwillȱnotȱbeȱNULȬterminated.ȱNoteȱthatȱaȱcallȱ
toȱ copy_nȱ shouldȱ storeȱ somethingȱ intoȱ dst[0]ȱ throughȱ dst[n-1],ȱ andȱ onlyȱ thoseȱ
locations,ȱregardlessȱofȱtheȱlengthȱofȱsrc.ȱ
Ifȱ youȱ planningȱ onȱ usingȱ theȱ libraryȱ routineȱ strncpyȱ toȱ implementȱ yourȱ
program,ȱyouȱareȱcongratulatedȱforȱreadingȱahead,ȱbutȱtheȱgoalȱhereȱisȱforȱyouȱtoȱ
figureȱoutȱtheȱlogicȱyourself,ȱsoȱyouȱmayȱnotȱuseȱanyȱofȱtheȱlibraryȱstringȱroutines.ȱ
5. Writeȱaȱprogramȱthatȱreadsȱtheȱstandardȱinputȱlineȱbyȱlineȱandȱdocsȱtheȱfollowing:ȱ
forȱeachȱsetȱofȱtwoȱorȱmoreȱidentical,ȱadjacentȱlinesȱinȱtheȱfile,ȱoneȱlineȱfromȱtheȱsetȱ
shouldȱ beȱ printedȱ out;ȱ nothingȱ elseȱ shouldȱ beȱ printedȱ out.ȱ Youȱ mayȱ assumeȱ thatȱ
theȱlinesȱinȱtheȱfileȱwillȱnotȱexceedȱ128ȱcharactersȱinȱlengthȱ(127ȱcharactersȱplusȱoneȱ
forȱtheȱnewlineȱthatȱterminatesȱeachȱline).ȱ
Considerȱtheȱinputȱfileȱshownȱbelow.ȱ
ȱ
This is the first line.
Another line.
And another.
And another.
And another.
And another.
Still more.
Almost done now –
Almost done now –
Another line.
Still more.
Finished!
ȱ
Assumingȱ thatȱ thereȱ areȱ noȱ trailingȱ blanksȱ orȱ tabsȱ onȱ anyȱ ofȱ theȱ linesȱ (whichȱ
wouldnȇtȱ beȱ visibleȱ butȱ wouldȱ makeȱ theȱ lineȱ differentȱ fromȱ itsȱ neighbors),ȱ thisȱ
Download at http://www.pin5i.com/
4.14 Programming Exercises 91
programȱwouldȱproduceȱtheȱfollowingȱoutputȱfromȱthisȱinputȱfile.ȱ
ȱ ȱ
ȱ And another.
Almost done now –ȱ
ȱ
Oneȱ lineȱ fromȱ eachȱ setȱ ofȱ adjacentȱ identicalȱ linesȱ isȱ printed.ȱ Noticeȱ thatȱ ȈAnotherȱ
line.ȈȱandȱȈStillȱmoreȈȱareȱnotȱprintedȱbecause,ȱalthoughȱthereȱareȱtwoȱofȱeachȱinȱtheȱ
file,ȱtheyȱareȱnotȱadjacent.ȱȱ
Hints:ȱ Useȱ getsȱ toȱ readȱ theȱ inputȱ lines,ȱ andȱ strcpyȱ toȱ copyȱ them.ȱ Thereȱ isȱ aȱ
routineȱ calledȱ strcmpȱ thatȱ takesȱ twoȱ stringsȱ asȱ argumentsȱ andȱ comparesȱ them.ȱ Itȱ
returnsȱzeroȱifȱtheyȱareȱequalȱandȱaȱnonzeroȱvalueȱifȱtheyȱareȱnot.ȱ
6. Writeȱaȱfunctionȱthatȱextractsȱaȱsubstringȱfromȱaȱstring.ȱTheȱfunctionȱshouldȱhaveȱ
theȱfollowingȱprototype:ȱ
ȱ
int substr( char dst[], char src[], int start,
int len )
ȱ
Itȱ shouldȱ copyȱ theȱ stringȱ thatȱ beginsȱ startȱ charactersȱ pastȱ theȱ beginningȱ ofȱ theȱ
stringȱinȱ srcȱintoȱtheȱarrayȱ dst.ȱAtȱmost lenȱnonȬNULȱcharactersȱshouldȱbeȱcopiedȱ
fromȱ src.ȱ Afterȱ copying,ȱ dstȱ mustȱ beȱ NULȬterminated.ȱ Theȱ functionȱ shouldȱ returnȱ
theȱlengthȱofȱtheȱstringȱstoredȱinȱdst.ȱ
Ifȱ startȱspecifiesȱaȱpositionȱbeyondȱtheȱendȱofȱtheȱstringȱinȱ src,ȱorȱeitherȱ startȱ
orȱlenȱareȱnegative,ȱthenȱdscȱshouldȱbeȱgivenȱtheȱemptyȱstring.ȱ
7. Writeȱaȱfunctionȱthatȱremovesȱexcessȱwhiteȱspaceȱfromȱaȱstringȱofȱcharacters.ȱTheȱ
functionȱshouldȱhaveȱthisȱprototype:ȱ
ȱ
void deblank( char string[] );
ȱ
Everyȱrunȱofȱoneȱorȱmoreȱwhiteȱspaceȱcharactersȱshouldȱbeȱreplacedȱbyȱoneȱspaceȱ
character.ȱBeȱsureȱthatȱtheȱstringȱisȱterminatedȱwithȱaȱNULȱbyteȱwhenȱyouȇreȱthroughȱ
withȱit!ȱ
ȱ
Download at http://www.pin5i.com/
ȱ
ȱ
Download at http://www.pin5i.com/
5
Operators and Expressions
Cȱprovidesȱallȱofȱtheȱoperatorsȱthatȱyouȱexpectȱinȱaȱprogrammingȱlanguageȱandȱmanyȱ
more.ȱInȱfact,ȱoneȱofȱtheȱcharacteristicsȱofȱCȱthatȱmanyȱpeopleȱciteȱasȱaȱshortcomingȱisȱ
itsȱvastȱassortmentȱofȱoperators,ȱbecauseȱtheyȱmakeȱtheȱlanguageȱharderȱtoȱmaster.ȱOnȱ
theȱotherȱhand,ȱmanyȱofȱtheȱCȱoperatorsȱareȱunavailableȱinȱotherȱlanguages,ȱwhichȱisȱ
partȱofȱwhatȱmakesȱCȱsuitableȱforȱsuchȱaȱwideȱvarietyȱofȱapplications.ȱ
Afterȱ theȱ explanationsȱ ofȱ theȱ operators,ȱ Iȱ discussȱ theȱ rulesȱ forȱ expressionȱ
evaluation,ȱincludingȱoperatorȱprecedenceȱandȱarithmeticȱconversions.ȱ
ȱ
ȱ
ȱ
5.1 Operators
Forȱtheȱpurposesȱofȱexplanation,ȱtheȱoperatorsȱareȱgroupedȱintoȱcategoriesȱaccordingȱ
toȱ eitherȱ whatȱ theyȱ doȱ orȱ howȱ theyȱ areȱ used.ȱ Forȱ referenceȱ purposes,ȱ itȱ isȱ moreȱ
convenientȱ toȱ groupȱ themȱ byȱ theirȱ precedence;ȱ Tableȱ5.1,ȱ whichȱ appearsȱ laterȱ inȱ thisȱ
chapter,ȱisȱorganizedȱthisȱway.ȱ
ȱ
ȱ
ȱ
5.1.1 Arithmetic
ȱ
Cȱprovidesȱallȱtheȱusualȱarithmeticȱoperators:ȱ
ȱ
+
-
*
/
%
ȱ
Exceptȱ forȱ %,ȱ theseȱ operatorsȱ workȱ bothȱ forȱ floatingȬpointȱ andȱ integerȱ types.ȱ Theȱ /ȱ
operatorȱperformsȱaȱtruncatingȱintegerȱdivisionȱwhenȱbothȱofȱitsȱoperandsȱareȱintegers,ȱ
Download at http://www.pin5i.com/
94
Chapter 5 Operators and Expressions
otherwiseȱitȱperformsȱaȱfloatingȬpointȱdivision. 23 ȱ%ȱisȱtheȱmoduloȱoperator;ȱitȱtakesȱtwoȱ
integerȱ arguments,ȱ dividesȱ theȱ leftȱ operandȱ byȱ theȱ rightȱ operand,ȱ butȱ returnsȱ theȱ
remainderȱratherȱthanȱtheȱquotient.ȱ
ȱ
ȱ
ȱ
5.1.2 Shifting
ȱ
Assemblyȱ languageȱ programmersȱ areȱ alreadyȱ familiarȱ withȱ shifting.ȱ Hereȱ isȱ aȱ briefȱ
introductionȱ forȱ wellȬadjustedȱ people.ȱ Aȱ shiftȱ simplyȱ slidesȱ theȱ bitsȱ inȱ aȱ valueȱ toȱ theȱ
leftȱorȱtheȱright.ȱOnȱaȱleftȱshift,ȱbitsȱonȱtheȱleftȱsideȱofȱtheȱvalueȱareȱdiscarded,ȱandȱzeroȱ
bitsȱ areȱ putȱ intoȱ theȱ spaceȱ createdȱ onȱ theȱ rightȱ sideȱ byȱ theȱ shift,ȱ Figureȱ 5.1ȱ isȱ anȱ
exampleȱofȱaȱleftȱshiftȱofȱthreeȱbitsȱonȱanȱ8Ȭbitȱvalue,ȱshownȱinȱbinary.ȱTheȱbitsȱinȱtheȱ
valueȱ allȱ moveȱ leftȱ byȱ threeȱ positions;ȱ theȱ onesȱ thatȱ fallȱ offȱ theȱ leftȱ endȱ areȱ lost,ȱ andȱ
zerosȱareȱputȱintoȱtheȱpositionsȱvacatedȱonȱtheȱright.ȱ
Rightȱshiftsȱincludeȱaȱquirkȱnotȱfoundȱinȱleftȱshifts:ȱthereȱareȱtwoȱwaysȱthatȱnewȱ
bitsȱcanȱbeȱshiftedȱinȱonȱtheȱleftȱside.ȱTheȱfirstȱisȱcalledȱaȱlogicalȱshift,ȱinȱwhichȱzerosȱareȱ
shiftedȱinȱonȱtheȱleftȱside.ȱTheȱotherȱisȱcalledȱanȱarithmeticȱshift.ȱAȱrightȱarithmeticȱshiftȱ
putsȱcopiesȱofȱtheȱsignȱbitȱintoȱtheȱleftȱsideȱofȱtheȱvalue,ȱthusȱpreservingȱitsȱsign.ȱIfȱtheȱ
valueȱ 10010110ȱ isȱ shiftedȱ rightȱ twoȱ positions,ȱ theȱ resultȱ ofȱ aȱ logicalȱ shiftȱ isȱ 00100101,ȱ
butȱ theȱ resultȱ ofȱ anȱ arithmeticȱ shiftȱ isȱ 11100101.ȱ Arithmeticȱ andȱ logicalȱ leftȱ shiftsȱ areȱ
identical.ȱOnlyȱtheȱrightȱshiftsȱdiffer,ȱandȱthenȱonlyȱforȱnegativeȱvalues.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
0ȱȱȱȱȱ1ȱȱȱȱȱ1ȱȱȱȱȱ0ȱȱȱȱȱ1ȱȱȱȱȱ1ȱȱȱȱȱ0ȱȱȱȱȱ1
0ȱȱȱȱȱ1ȱȱȱȱȱ1ȱȱȱȱȱ0ȱȱȱȱȱ1ȱȱȱȱȱ1ȱȱȱȱȱ0ȱȱȱȱȱ1
Discardedȱ
Beforeȱshiftingȱ
Afterȱshiftingȱthreeȱpositions
Filledȱwithȱ0ȇsȱ
0ȱȱȱȱȱ1ȱȱȱȱȱ1ȱȱȱȱȱ0ȱȱȱȱȱ1ȱȱȱȱȱ0ȱȱȱȱȱ0ȱȱȱȱȱ0
Finalȱresultȱ
ȱ
ȱ
Figureȱ5.1ȱLeftȱshiftȱofȱthreeȱbitsȱ
ȱIfȱeitherȱofȱtheȱoperandsȱofȱanȱintegerȱdivisionȱisȱnegative,ȱtheȱresultȱofȱtheȱdivisionȱisȱimplementationȱdefined.ȱReferȱtoȱtheȱ
divȱfunctionȱinȱChapterȱ16ȱforȱdetails.ȱ
23
Download at http://www.pin5i.com/
5.1 Operators
CAUTION!
CAUTION!
95
Theȱleftȱshiftȱoperatorȱisȱ<<ȱandȱtheȱrightȱshiftȱoperatorȱisȱ>>.ȱTheȱvalueȱgivenȱbyȱ
theȱleftȱoperandȱisȱshiftedȱtheȱnumberȱofȱbitȱpositionsȱspecifiedȱbyȱtheȱrightȱoperand.ȱ
Bothȱoperandsȱmustȱhaveȱanȱintegralȱtype.ȱȱ
ȱ
TheȱStandardȱstatesȱthatȱlogicalȱshiftsȱareȱperformedȱonȱallȱunsignedȱvaluesȱbutȱleavesȱ
itȱ upȱ toȱ theȱ implementationȱ whetherȱ arithmeticȱ orȱ logicalȱ shiftsȱ areȱ usedȱ forȱ signedȱ
values.ȱYouȱcanȱwriteȱaȱsimpleȱtestȱprogramȱtoȱseeȱhowȱyourȱimplementationȱworks,ȱ
butȱ yourȱ testȱ isȱ noȱ guaranteeȱ thatȱ anyȱ otherȱ compilerȱ willȱ workȱ theȱ same,ȱ thusȱ
programsȱthatȱdoȱrightȱshiftsȱonȱsignedȱvaluesȱareȱinherentlyȱnonȬportable.ȱ
ȱ
Bewareȱofȱshiftsȱlikeȱthisȱone:ȱ
ȱ
a << -5
ȱ
WhatȱdoesȱaȱleftȱshiftȱofȱȬ5ȱbitȱpositionsȱmean?ȱAȱrightȱshiftȱofȱ5ȱbits?ȱNoȱshiftȱatȱall?ȱ
Onȱ oneȱ machine,ȱ thisȱ expressionȱ actuallyȱ doesȱ aȱ leftȱ shiftȱ ofȱ 27ȱ bits—notȱ exactlyȱ
intuitive.ȱ Whatȱ aboutȱ shiftȱ countsȱ thatȱ areȱ largerȱ thanȱ theȱ numberȱ ofȱ binsȱ inȱ theȱ
operand?ȱ
ȱ
TheȱStandardȱstatesȱthatȱtheȱbehaviorȱofȱsuchȱshiftsȱisȱundefined,ȱsoȱitȱisȱupȱtoȱ
theȱ implementation.ȱ However,ȱ fewȱ implementorsȱ addressȱ theseȱ situationsȱ explicitly,ȱ
soȱ theȱ resultsȱ areȱ notȱ likelyȱ toȱ beȱ meaningful.ȱ Thus,ȱ youȱ shouldȱ avoidȱ usingȱ theseȱ
typesȱofȱshiftsȱbecauseȱtheirȱeffectsȱareȱunpredictableȱandȱnonȬportable.ȱȱ
TheȱfunctionȱshownȱinȱProgramȱ5.1ȱusesȱaȱrightȱshiftȱtoȱcountȱtheȱnumberȱofȱ1ȱ
bitsȱinȱaȱvalue.ȱItȱacceptsȱanȱunsignedȱargumentȱtoȱavoidȱtheȱrightȱshiftȱambiguityȱandȱ
usesȱ theȱ moduloȱ operatorȱ toȱ determineȱ whetherȱ theȱ leastȱ significantȱ bitȱ isȱ nonzero.ȱ
We’1lȱ improveȱ thisȱ functionȱ laterȱ afterȱ theȱ &,ȱ <<=ȱ andȱ +=ȱ operatorsȱ haveȱ beenȱ
described.ȱ
ȱ
ȱ
ȱ
5.1.3 Bitwise
ȱ
TheȱbitwiseȱoperatorsȱperformȱtheȱlogicalȱoperationsȱAND,ȱOR,ȱandȱXORȱ(exclusiveȬ
OR)ȱonȱtheȱindividualȱbitsȱofȱtheirȱoperands.ȱAgain,ȱassemblyȱlanguageȱprogrammersȱ
areȱ familiarȱ withȱ theseȱ operationsȱ butȱ hereȱ isȱ aȱ briefȱ introductionȱ forȱ everyoneȱ else.ȱ
Theȱ ANDȱ ofȱ twoȱ bitsȱ producesȱ aȱ oneȱ onlyȱ ifȱ bothȱ ofȱ theȱ bitsȱ areȱ one;ȱ otherwiseȱ theȱ
resultȱisȱzero.ȱTheȱORȱofȱtwoȱbitsȱproducesȱaȱresultȱofȱzeroȱonlyȱifȱbothȱbitsȱareȱzero;ȱ
otherwiseȱtheȱresultȱisȱone.ȱFinally,ȱtheȱXORȱofȱtwoȱbitsȱproducesȱaȱresultȱofȱoneȱifȱbothȱ
bitsȱ areȱ different,ȱ andȱ aȱ resultȱ ofȱ zeroȱ ifȱ bothȱ bitsȱ areȱ theȱ same.ȱ Theseȱ operationsȱ areȱ
summarizedȱinȱchartsȱbelow.ȱ
Download at http://www.pin5i.com/
Chapter 5 Operators and Expressions
96
ȱ
/*
** This function returns the number of 1-bits that appeared in
** the argument value.
*/
int
count_one_bits( unsigned value )
{
int
ones;
/*
** While the value still has some 1-bits in it ...
*/
for( ones = 0; value != 0; value = value >> 1 )
/*
** If the low-order bit is a 1, count it.
*/
if( value % 2 != 0 )
ones = ones + 1;
return ones;
}
ȱ
Programȱ5.1ȱCountingȱoneȱbitsȱinȱaȱvalue:ȱpreliminaryȱversionȱ
ȱ
ȱ
ȱ
ȱ ȱ
Bȱ
ȱ ȱ
Bȱ
ȱ & 0 1
ȱ | 0 1
Aȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
0
0
0
1
0
1
A
ȱ
ȱ
ȱ
AȱANDȱBȱ
0
0
1
1
1
1
AȱORȱBȱ
ȱ
ȱ
count_1a.cȱ
ȱ
ȱ
ȱ
A
ȱ
ȱ
Bȱ
^
0
1
0
0
1
1
1
0
AȱXORȱBȱ
ȱ
Theȱbitwiseȱoperatorsȱare:ȱ
ȱ
&
|
^
ȱ
forȱ AND,ȱ OR,ȱ andȱ XORȱ respectively.ȱ Theyȱ requireȱ integerȬtypeȱ operands,ȱ andȱ theyȱ
performȱtheȱindicatedȱoperationȱonȱtheȱcorrespondingȱbitsȱofȱtheirȱoperands,ȱoneȱpairȱ
ofȱ bitsȱ atȱ aȱ time.ȱ Toȱ illustrateȱ this,ȱ supposeȱ theȱ variableȱ aȱ hasȱ theȱ binaryȱ valueȱ
00101110,ȱ andȱ bȱ hasȱ theȱ binaryȱ valueȱ 01011011.ȱ Thenȱ a & bȱ resultsȱ inȱ theȱ valueȱ
00001010,ȱa | bȱgivesȱtheȱvalueȱ01111111,ȱandȱa ^ bȱproducesȱ01110101.ȱ
Download at http://www.pin5i.com/
5.1 Operators
97
Bit Manipulation
ȱ
Theȱ followingȱ expressionsȱ showȱ howȱ youȱ canȱ useȱ shiftingȱ andȱ bitwiseȱ operatorsȱ toȱ
manipulateȱ individualȱ bitsȱ inȱ anȱ integerȱ value.ȱ Theȱ expressionsȱ assumeȱ thatȱ theȱ
variableȱbit_numberȱisȱanȱintegerȱvalueȱinȱtheȱrangeȱzeroȱtoȱoneȱlessȱthanȱtheȱnumberȱ
ofȱbitsȱinȱanȱintegerȱandȱthatȱtheȱbitsȱinȱanȱintegerȱareȱnumberedȱfromȱrightȱtoȱleft.ȱTheȱ
firstȱexampleȱsetsȱtheȱspecifiedȱbitȱtoȱone.ȱ
ȱ
ȱ
value = value | 1 << bit_number;
ȱ
Theȱnextȱclearsȱtheȱspecifiedȱbitȱtoȱzero. 24
ȱ
value = value & ~ ( 1 << bit_number );
ȱ
ȱ
Theseȱexpressionsȱareȱoftenȱwrittenȱwithȱtheȱ|=ȱandȱ&=ȱoperators,ȱdescribedȱinȱtheȱnextȱ
section.ȱFinally,ȱthisȱexpressionȱtestsȱtheȱspecifiedȱbitȱandȱisȱnonzeroȱifȱtheȱbitȱisȱset.ȱ
ȱ
ȱ
value & 1 << bit_number
ȱ
ȱ
ȱ
5.1.4 Assignment
ȱ
Finallyȱweȱgetȱtoȱtheȱassignmentȱoperator,ȱwhichȱisȱtheȱequalȱsign.ȱAssignmentȱisȱanȱ
expressionȱ ratherȱ thanȱ aȱ typeȱ ofȱ statement,ȱ soȱ anȱ assignmentȱ isȱ legalȱ anywhereȱ anȱ
expressionȱisȱlegal.ȱTheȱstatementȱ
ȱ
ȱ
x = y + 3;
ȱ
containsȱtwoȱoperators,ȱ+ȱandȱ=.ȱTheȱadditionȱisȱperformedȱfirst,ȱsoȱtheȱoperandsȱofȱtheȱ
=ȱ areȱ theȱ variableȱ xȱ andȱ theȱ valueȱ ofȱ theȱ expressionȱ y + 3.ȱ Theȱ assignmentȱ operatorȱ
storesȱtheȱvalueȱofȱtheȱoperandȱonȱtheȱrightȱintoȱtheȱlocationȱspecifiedȱbyȱtheȱoperandȱ
onȱ theȱ left.ȱ Butȱ anȱ assignmentȱ isȱ anȱ expression,ȱ andȱ anȱ expressionȱ hasȱ aȱ value.ȱ Theȱ
valueȱofȱanȱassignmentȱexpressionȱisȱtheȱnewȱvalueȱofȱtheȱleftȱoperand,ȱwhichȱcanȱbeȱ
usedȱasȱanȱoperandȱofȱanotherȱoperator,ȱasȱinȱthisȱstatement:ȱ
ȱ
a = x = y + 3;
ȱ
Theȱassignmentȱoperatorȱassociatesȱ(isȱevaluated)ȱfromȱrightȱtoȱleft,ȱsoȱthisȱstatementȱisȱ
equivalentȱto:ȱ
24
ȱTheȱunaryȱ~ȱoperator,ȱtoȱbeȱdescribedȱshortly,ȱcomputesȱtheȱoneȇsȱcomplementȱofȱitsȱoperand.ȱ
Download at http://www.pin5i.com/
Chapter 5 Operators and Expressions
98
a = ( x = y + 3 );
ȱ
andȱhasȱexactlyȱtheȱsameȱmeaningȱas:ȱ
ȱ
x = y + 3;
a = x;
ȱ
ȱ
ȱ
Hereȱisȱaȱslightlyȱmoreȱambitiousȱexample:ȱ
r = s + ( t = u – v ) / 3;
ȱ
Thisȱstatementȱassignsȱtoȱ tȱtheȱvalueȱofȱtheȱexpressionȱ u – v,ȱthenȱdividesȱthatȱvalueȱ
byȱ three,ȱ addsȱ s,ȱ andȱ assignsȱ theȱ resultȱ toȱ r.ȱ Althoughȱ thisȱ isȱ legal,ȱ theȱ followingȱ
statementsȱareȱjustȱasȱgoodȱ
ȱ
t = u – v;
r = s + t / 3;
CAUTION!
Inȱfact,ȱtheyȱareȱevenȱbetterȱbecauseȱtheyȱareȱeasierȱtoȱreadȱandȱeasierȱtoȱdebug.ȱItȱisȱ
veryȱeasyȱtoȱgoȱoverboardȱwithȱembeddedȱassignmentsȱandȱwriteȱexpressionsȱthatȱareȱ
difficultȱtoȱread.ȱTherefore,ȱbeforeȱyouȱuseȱthisȱȈfeature,Ȉȱbeȱsureȱthatȱitȱisȱjustifiedȱbyȱ
someȱsubstantial,ȱtangibleȱbenefit.ȱ
ȱ
Itȱisȱincorrectȱtoȱsayȱthatȱtheȱsameȱvalueȱisȱassignedȱtoȱbothȱaȱandȱxȱinȱtheȱstatement:ȱ
ȱ
a = x = y + 3;
ȱ
Ifȱ xȱ wereȱ aȱ character,ȱ theȱ valueȱ yȱ +ȱ 3ȱ wouldȱ beȱ truncatedȱ toȱ fit;ȱ aȱ wouldȱ thenȱ beȱ
assignedȱ thisȱ truncatedȱ value.ȱ Truncationȱ isȱ preciselyȱ theȱ problemȱ inȱ thisȱ commonȱ
mistake:ȱ
ȱ
char ch;
...
while( (ch = getchar()) != EOF ) ...
ȱ
TheȱvalueȱEOFȱrequiresȱmoreȱbitsȱthanȱaȱcharacterȱvalue,ȱwhichȱisȱwhyȱ getcharȱreturnsȱ
anȱintegerȱvalue,ȱnotȱaȱcharacter.ȱHowever,ȱstoringȱitȱfirstȱinȱ chȱtruncatesȱtheȱreturnedȱ
value.ȱ Thisȱ truncatedȱ valueȱ isȱ thenȱ promotedȱ toȱ anȱ integerȱ andȱ comparedȱ withȱ EOF.ȱ
Whenȱthisȱerroneousȱcodeȱisȱrunȱonȱmachinesȱwithȱsignedȱcharacters,ȱreadingȱtheȱbyteȱ
\377ȱ causesȱ theȱ loopȱ toȱ endȱ asȱ ifȱ endȱ ofȱ fileȱ hadȱ beenȱ reached.ȱ Whenȱ itȱ isȱ runȱ onȱ
machinesȱwithȱunsignedȱcharacters,ȱtheȱloopȱneverȱends!ȱ
Download at http://www.pin5i.com/
5.1 Operators
99
Compound Assignment
ȱ
Thereȱisȱaȱcompoundȱassignmentȱformȱforȱeachȱofȱtheȱoperatorsȱpresentedȱsoȱfar:ȱ
ȱ
+=
<<=
-=
>>=
*=
&=
/=
^=
%=
|=
ȱ
Weȱ discussȱ onlyȱ theȱ +=ȱ operatorȱ becauseȱ theȱ othersȱ workȱ theȱ sameȱ wayȱ withȱ theirȱ
respectiveȱoperators.ȱTheȱ+=ȱoperatorȱisȱusedȱlikeȱthis:ȱ
ȱ
a += expression
ȱ
ItȱreadsȱȈaddȱexpressionȱtoȱaȈȱandȱisȱequivalentȱtoȱtheȱfollowingȱexpressionȱ
ȱ
exceptȱthatȱtheȱoperandȱonȱtheȱleftȱsideȱofȱtheȱ+=ȱ(aȱinȱthisȱcase)ȱisȱonlyȱevaluatedȱonce.ȱ
Noteȱ theȱ parentheses:ȱ theyȱ ensureȱ thatȱ expressionȱ isȱ fullyȱ evaluatedȱ beforeȱ theȱ
addition,ȱevenȱifȱitȱcontainsȱanȱoperatorȱwhoseȱprecedenceȱisȱlowerȱthanȱaddition.ȱ
Whatȱisȱtheȱpointȱofȱhavingȱtwoȱwaysȱtoȱaddȱsomethingȱtoȱaȱvariable?ȱȱ
Theȱ K&Rȱ Cȱ designersȱ thoughtȱ thatȱ compoundȱ assignmentȱ operatorsȱ allowedȱ
theȱ programmerȱ toȱ writeȱ codeȱ moreȱ clearly.ȱ Plus,ȱ theȱ compilerȱ wouldȱ beȱ ableȱ toȱ
produceȱmoreȱcompactȱcode.ȱNow,ȱtheȱdifferenceȱbetweenȱ a = a + 5ȱ;ȱandȱ a += 5;ȱisȱ
notȱveryȱdramatic,ȱandȱmodemȱcompilersȱhaveȱnoȱtroubleȱproducingȱoptimalȱcodeȱforȱ
bothȱ expressions.ȱ Butȱ considerȱ theseȱ twoȱ statements,ȱ whichȱ areȱ equivalentȱ ifȱ theȱ
functionȱfȱhasȱnoȱsideȱeffects:ȱ
ȱ
a[ 2 * (y – 6*f(x)) ] = a[ 2 * (y – 6*f(x)) ] + 1;
a[ 2 * (y – 6*f(x)) ] += 1;
TIP
ȱ
Theȱfirstȱformȱrequiresȱthatȱtheȱexpressionȱselectingȱtheȱlocationȱtoȱbeȱincrementedȱbeȱ
writtenȱ twice,ȱonceȱ onȱtheȱ leftȱandȱonceȱ onȱ theȱrightȱ sideȱofȱ theȱequalsȱsign.ȱ Becauseȱ
theȱcompilerȱhasȱnoȱwayȱofȱknowingȱwhetherȱ fȱhasȱanyȱsideȱeffects,ȱitȱmustȱevaluateȱ
theȱsubscriptȱexpressionȱtwice.ȱTheȱsecondȱformȱisȱmoreȱefficientȱbecauseȱtheȱsubscriptȱ
isȱevaluatedȱonlyȱonce.ȱ
ȱ
Aȱmuchȱmoreȱimportantȱadvantageȱtoȱ+=ȱisȱthatȱitȱmakesȱtheȱsourceȱcodeȱeasierȱtoȱreadȱ
andȱ write.ȱ Toȱ figureȱ outȱ whatȱ theȱ firstȱ statementȱ inȱ theȱ exampleȱ aboveȱ isȱ doing,ȱ theȱ
readerȱ mustȱ closelyȱ examineȱ bothȱ subscriptȱ expressionsȱ toȱ verifyȱ thatȱ theyȱ areȱ
identicalȱandȱmustȱthenȱexamineȱtheȱfunctionȱfȱtoȱseeȱwhetherȱitȱhasȱanyȱsideȱeffects.ȱ
Thereȱisȱnoȱsuchȱproblemȱreadingȱtheȱsecondȱstatement.ȱItȱisȱalsoȱeasierȱtoȱwriteȱthanȱ
theȱfirst,ȱwithȱfewerȱchancesȱofȱtypingȱerrors.ȱItȱisȱbecauseȱofȱtheseȱadvantagesȱthatȱyouȱ
shouldȱuseȱassignmentȱoperators.ȱ
Download at http://www.pin5i.com/
Chapter 5 Operators and Expressions
100
Weȱ canȱ nowȱ rewriteȱ Programȱ 5.1ȱ usingȱ assignmentȱ operatorsȱ asȱ shownȱ inȱ Programȱ
5.2.ȱTheȱassignmentȱoperatorsȱalsoȱsimplifyȱtheȱexpressionsȱtoȱsetȱandȱclearȱindividualȱ
bitsȱinȱaȱvalue:ȱ
ȱ
value |= 1 << bit_number;
value &= ~ ( 1 << bit_number );
ȱ
ȱ
ȱ
5.1.5 Unary
ȱ
Thereȱareȱaȱnumberȱofȱunaryȱoperators,ȱthatȱis,ȱoperatorsȱthatȱtakeȱonlyȱoneȱoperand.ȱ
Theyȱareȱ
ȱ
!
~
++
--
+
&
*
sizeof
(type)
ȱ
Let’sȱlookȱatȱtheseȱoperatorsȱoneȱbyȱone.ȱȱ
Theȱ !ȱoperatorȱperformsȱaȱlogicalȱnegationȱofȱitsȱoperand;ȱifȱtheȱoperandȱisȱtrueȱ
theȱresultȱisȱfalse,ȱandȱifȱtheȱoperandȱisȱfalseȱtheȱresultȱisȱtrue.ȱLikeȱtheȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** This function returns the number of 1-bits that appeared in
** the argument value.
*/
int
count_one_bits( unsigned value )
{
int
ones;
/*
** While the value still has some 1-bits in it ...
*/
for( ones = 0; value != 0; value >>= 1 )
/*
** If the low-order bit is a 1, count it.
*/
if( ( value & 1 ) != 0 )
ones += 1;
return ones;
}
Programȱ5.2ȱCountingȱoneȱbitsȱinȱaȱvalue:ȱfinalȱversionȱ
ȱ
ȱ
ȱ
count_1b.cȱȱ
Download at http://www.pin5i.com/
5.1 Operators
101
relationalȱ operators,ȱ thisȱ operatorȱ actuallyȱ producesȱ anȱ integerȱ result,ȱ eitherȱ zeroȱ orȱ
one.ȱȱ
Theȱ ~ȱoperatorȱproducesȱtheȱoneȇsȱcomplementȱofȱanȱintegerȬtypeȱoperand.ȱTheȱ
oneȇsȱcomplementȱisȱobtainedȱbyȱchangingȱtheȱvalueȱofȱeachȱofȱtheȱoperandȇsȱbitsȱfromȱ
oneȱtoȱzeroȱorȱfromȱzeroȱtoȱone.ȱȱ
Theȱ-ȱoperatorȱproducesȱtheȱnegativeȱofȱitsȱoperand.ȱȱ
Theȱ+ȱoperatorȱyieldsȱtheȱvalueȱofȱitsȱoperand;ȱinȱotherȱwords,ȱitȱdoesȱnothing.ȱItȱ
isȱprovidedȱonlyȱforȱsymmetryȱwithȱ-.ȱȱ
&ȱproducesȱtheȱaddressȱofȱitsȱoperand.ȱForȱexample,ȱinȱtheȱfollowingȱstatementsȱ
anȱintegerȱvariableȱandȱaȱpointerȱtoȱanȱintegerȱvariableȱareȱdeclared.ȱThen,ȱtheȱaddressȱ
ofȱ theȱ variableȱ aȱ isȱ determinedȱ withȱ theȱ &ȱ operatorȱ andȱ isȱ assignedȱ toȱ theȱ pointerȱ
variable.ȱ
ȱ
int
a, *b;
...
b = &a;
ȱ
Thisȱ exampleȱ illustratesȱ howȱ youȱ giveȱ aȱ pointerȱ variableȱ theȱ addressȱ ofȱ anȱ existingȱ
variable.ȱ
*ȱisȱtheȱindirectionȱoperatorȱandȱisȱusedȱwithȱpointersȱtoȱaccessȱtheȱvalueȱbeingȱ
pointedȱ to.ȱ Afterȱ theȱ assignmentȱ inȱ theȱ previousȱ exampleȱ isȱ performed,ȱ theȱ valueȱ ofȱ
theȱexpressionȱbȱwouldȱbeȱtheȱaddressȱofȱtheȱvariableȱa,ȱbutȱtheȱvalueȱofȱtheȱexpressionȱ
*bȱwouldȱbeȱtheȱvalueȱof a.ȱ
Theȱ sizeofȱoperatorȱdeterminesȱtheȱsizeȱofȱitsȱoperand,ȱmeasuredȱinȱbytes.ȱTheȱ
operandȱmayȱbeȱeitherȱanȱexpressionȱ(oftenȱitȱisȱjustȱaȱsingleȱvariable),ȱorȱaȱtypeȱnameȱ
enclosedȱinȱparentheses.ȱHereȱareȱtwoȱexamples:ȱ
ȱ
sizeof( int )
sizeof x
ȱ
Theȱfirstȱreturnsȱtheȱnumberȱofȱbytesȱinȱanȱintegerȱvariable,ȱwhichȱofȱcourseȱdependsȱ
onȱ theȱ environmentȱyouȱ areȱ using.ȱTheȱsecondȱ exampleȱ returnsȱ theȱnumberȱ ofȱ bytesȱ
usedȱbyȱtheȱvariableȱ x.ȱNoteȱthatȱtheȱsizeȱofȱaȱcharacterȱvariable,ȱbyȱdefinition,ȱisȱone.ȱ
Whenȱusedȱwithȱtheȱnameȱofȱanȱarray,ȱ sizeofȱreturnsȱtheȱsizeȱofȱtheȱarrayȱinȱbytes.ȱItȱ
isȱlegalȱtoȱsurroundȱanȱexpressionȱoperandȱwithȱparentheses,ȱlikeȱthis:ȱ
ȱ
ȱ
sizeof( x )
ȱ
becauseȱ parenthesesȱ areȱ alwaysȱ legalȱ inȱ expressions.ȱ Determiningȱ theȱ sizeȱ ofȱ anȱ
expressionȱdoesȱnotȱevaluateȱtheȱexpression,ȱsoȱ sizeof( a = b + 1 )ȱdoesȱnotȱassignȱ
anythingȱtoȱa.ȱȱ
Theȱ(type)ȱoperatorȱisȱcalledȱaȱcastȱandȱisȱusedȱtoȱexplicitlyȱconvertȱtheȱvalueȱofȱ
anȱexpressionȱtoȱanotherȱtype.ȱForȱexample,ȱtoȱgetȱtheȱfloatingȬpointȱequivalentȱofȱtheȱ
integerȱvariableȱaȱyouȱwouldȱwriteȱ
Download at http://www.pin5i.com/
102
Chapter 5 Operators and Expressions
(float)a
Theȱ nameȱ ȈcastȈȱ isȱ easierȱ toȱ rememberȱ ifȱ youȱ useȱ theȱ metallurgyȱ metaphor:ȱ castingȱ
somethingȱintoȱaȱdifferentȱmold.ȱTheȱeastȱhasȱaȱveryȱhighȱprecedence,ȱsoȱaȱcastȱinȱfromȱ
ofȱanȱexpressionȱwillȱonlyȱchangeȱtheȱtypeȱofȱtheȱfirstȱtermȱinȱtheȱexpression.ȱInȱorderȱ
toȱcastȱtheȱresultȱofȱtheȱexpression,ȱyouȱmustȱencloseȱitȱinȱparentheses.ȱ
Finallyȱweȱcomeȱtoȱtheȱincrementȱ++ȱandȱdecrementȱ--ȱoperators.ȱIfȱthereȱisȱanyȱ
oneȱoperatorȱthatȱcapturesȱtheȱȈfeelȈȱofȱCȱprogramming,ȱitȱmustȱbeȱoneȱofȱthese.ȱEachȱ
oneȱcomesȱinȱtwoȱvariations,ȱcalledȱprefixȱandȱpostfix.ȱBothȱversionsȱofȱbothȱoperatorsȱ
requireȱ aȱ variable,ȱ notȱ anȱ expression,ȱ forȱ anȱ operand.ȱ Actually,ȱ theȱ restrictionȱ isȱ
somewhatȱ lessȱ rigid.ȱ Whatȱ theȱ operatorsȱ reallyȱ requireȱ isȱ anȱ ȈL—value,Ȉȱ butȱ weȱ
haven’tȱ coveredȱ thisȱ topicȱ yet.ȱ Theȱ gistȱ ofȱ theȱ restrictionȱ isȱ thatȱ ++ȱ andȱ --ȱ mayȱ beȱ
appliedȱ onlyȱ toȱ expressionsȱ thatȱ mayȱ appearȱ onȱ theȱ leftȱ sideȱ ofȱ anȱ assignmentȱ
operator.ȱ
Inȱ theȱ prefixȱ versionȱ ofȱ ++,ȱ theȱ operatorȱ appearsȱ aheadȱ ofȱ theȱ operand.ȱ Theȱ
operandȱ isȱ incremented,ȱ andȱ theȱ valueȱ ofȱ theȱ expressionȱ isȱ theȱ incrementedȱ valueȱ ofȱ
theȱ variable.ȱ Inȱ itsȱ postfixȱ version,ȱ theȱ operatorȱ appearsȱ afterȱ theȱ operand.ȱ Theȱ
operandȱisȱstillȱincremented,ȱbutȱtheȱvalueȱofȱtheȱexpressionȱisȱtheȱvalueȱtheȱoperandȱ
hadȱ beforeȱ theȱ incrementȱ tookȱ place.ȱ Thisȱ ruleȱ isȱ easyȱ toȱ rememberȱ ifȱ youȱ considerȱ
whereȱtheȱoperatorȱisȱplaced—beforeȱtheȱoperandȱincrementsȱbeforeȱtheȱvalueȱisȱusedȱ
inȱ theȱ expression;ȱ afterȱ theȱ operandȱ incrementsȱ afterȱ itsȱ valueȱ isȱ usedȱ inȱ theȱ
surroundingȱ expression.ȱ Theȱ --ȱ operatorȱ worksȱ theȱ sameȱ way,ȱ exceptȱ thatȱ itȱ
decrementsȱratherȱthanȱincrementing.ȱ
Hereȱareȱsomeȱexamples.ȱ
ȱ
int a, b, c, d;
...
a = b = 10; a andȱbȱgetȱtheȱvalue 10
c = ++a;
a isȱincrementedȱto 11,ȱand c getsȱtheȱvalue 11
d = b++;
b isȱincrementedȱto 11,ȱbut d getsȱtheȱvalue 10
ȱ
Theȱremarksȱaboveȱdescribeȱtheȱresultsȱofȱtheseȱoperatorsȱbutȱdoȱnotȱstateȱtheȱwayȱinȱ
whichȱtheȱresultȱisȱobtained.ȱAbstractly,ȱbothȱtheȱprefixȱandȱpostfixȱversionsȱmakeȱatȱ
copyȱofȱtheȱvariableȇsȱvalue.ȱItȱisȱthisȱcopyȱthatȱisȱusedȱinȱtheȱsurroundingȱexpressionȱ
(theȱ Ȉsurroundingȱ expressionȈȱ inȱ theȱ exampleȱ aboveȱ isȱ theȱ assignment).ȱ Theȱ prefixȱ
operatorȱ incrementsȱ beforeȱ makingȱ thisȱ copy,ȱ andȱ theȱ postfixȱ operatorȱ incrementsȱ
afterȱmakingȱtheȱcopy.ȱItȱisȱimportantȱtoȱrealizeȱthatȱtheȱresultsȱofȱtheseȱoperatorsȱareȱ
notȱ theȱ variableȱ thatȱ wasȱ modifiedȱ butȱ aȱ copyȱ ofȱ itsȱ value.ȱ Thisȱ pointȱ isȱ importantȱ
becauseȱitȱexplainsȱwhyȱyouȱcannotȱuseȱtheȱoperatorsȱinȱthisȱway:ȱ
Download at http://www.pin5i.com/
5.1 Operators
103
++a = 10;
ȱ
Theȱ resultȱ ofȱ ++aȱ isȱ aȱ copyȱ ofȱ theȱ valueȱ ofȱ a,ȱ notȱ theȱ variableȱ itself,ȱ andȱ youȱ cannotȱ
assignȱsomethingȱtoȱaȱvalue.ȱ
ȱ
ȱ
ȱ
5.1.6 Relational
ȱ
Theseȱoperatorsȱtestȱvariousȱrelationshipsȱbetweenȱtheirȱoperands.ȱAllȱtheȱusualȱonesȱ
areȱprovided,ȱthoughȱthereȱisȱaȱpitfallȱinȱthisȱgroup.ȱTheȱoperatorsȱareȱ
ȱ
>
>=
<
<=
.
!=
==
ȱ
ȱ
Theȱ firstȱ fourȱ areȱ selfȱ explanatory.ȱ Theȱ !=ȱ operatorȱ testsȱ forȱ Ȉnotȱ equal,Ȉȱ andȱ theȱ ==
operatorȱtestsȱforȱȈisȱequalȱto.Ȉȱ
Althoughȱtheȱrelationalȱoperatorsȱaccomplishȱwhatȱyouȱwouldȱexpect,ȱtheȱwayȱ
inȱ whichȱ theyȱ doȱ itȱ isȱ aȱ littleȱ different.ȱ Theseȱ operatorsȱ allȱ produceȱ anȱ integer,ȱ notȱ
boolean,ȱresult.ȱIfȱtheȱindicatedȱrelationshipȱholdsȱbetweenȱtheȱoperands,ȱtheȱresultȱisȱ
one;ȱotherwiseȱtheȱresultȱisȱzero.ȱTheȱresultȱisȱanȱintegerȱvalueȱandȱcanȱbeȱassignedȱtoȱ
integerȱ variables,ȱ butȱ whatȱ usuallyȱ happensȱ isȱ thatȱ theȱ valueȱ isȱ testedȱ inȱ anȱ ifȱ orȱ aȱ
whileȱstatement.ȱRememberȱhowȱthoseȱstatementsȱwork:ȱanȱexpressionȱthatȱevaluatesȱ
toȱ zeroȱ isȱ consideredȱ falseȱ andȱ anyȱ nonzeroȱ valueȱ isȱ consideredȱ true.ȱ Theȱ relationalȱ
operatorsȱ workȱ theȱ sameȱ way,ȱ producingȱ zeroȱ whenȱ theȱ relationȱ docsȱ notȱ holdȱ andȱ
oneȱwhenȱitȱdoes.ȱThus,ȱthereȱisȱnoȱfunctionalȱneedȱforȱaȱdistinctȱbooleanȱdataȱtype.ȱ
Thisȱuseȱofȱintegersȱtoȱrepresentȱbooleanȱvaluesȱleadsȱdirectlyȱtoȱsomeȱshortcutsȱ
thatȱareȱcommonlyȱusedȱwhenȱtestingȱexpressions.ȱ
ȱ
if( expression != 0 ) ...
if( expression ) ...
if( expression == 0 ) ...
if( !expression ) ...
ȱ
Theȱ twoȱ statementsȱ inȱ eachȱ ofȱ theseȱ pairsȱ areȱ equivalentȱ toȱ oneȱ another;ȱ theȱ testȱ forȱ
Ȉnotȱ equalȱ toȱ zeroȈȱ canȱ beȱ performedȱ withȱ aȱ relationalȱ operatorȱ orȱ byȱ simplyȱ testingȱ
theȱvalueȱofȱtheȱexpression.ȱSimilarly,ȱtheȱtestȱforȱȈequalȱtoȱzeroȈȱcanȱalsoȱbeȱperformedȱ
byȱtestingȱtheȱexpressionȇsȱvalueȱandȱthenȱtakingȱtheȱlocalȱNOTȱofȱtheȱresult.ȱWhichȱofȱ
theseȱformsȱyouȱchooseȱtoȱuseȱisȱaȱmatterȱofȱstyle.ȱBeȱcarefulȱwithȱtheȱlastȱone,ȱthough.ȱ
Theȱ !ȱoperatorȱhasȱhighȱprecedence,ȱsoȱifȱtheȱexpressionȱcontainsȱanyȱoperators,ȱyouȱ
willȱprobablyȱhaveȱtoȱencloseȱitȱinȱparentheses.ȱ
Download at http://www.pin5i.com/
104
CAUTION!
Chapter 5 Operators and Expressions
IfȱthisȱerrorȱisȱnotȱtheȱmostȱcommonȱmadeȱbyȱbeginningȱCȱprogrammers,ȱitȱisȱcertainlyȱ
theȱmostȱirritating.ȱMostȱotherȱlanguagesȱuseȱtheȱ=ȱoperatorȱtoȱperformȱaȱcomparison.ȱ
Inȱ C,ȱ youȱmustȱuseȱ theȱ doubleȱequalȱ signȱ ==ȱ forȱ comparison;ȱ aȱ singleȱ equalȱ signȱ willȱ
performȱanȱassignment.ȱ
Theȱ pitfallȱ isȱ thatȱ anȱ assignmentȱ isȱ legalȱ anywhereȱ itȱ isȱ legalȱ toȱ compareȱ forȱ
equality,ȱsoȱitȱisȱnotȱaȱsyntaxȱerror. 25 ȱThisȱunfortunateȱpropertyȱisȱtheȱdisadvantageȱofȱ
notȱhavingȱaȱdistinctȱbooleanȱtype;ȱbothȱexpressionsȱareȱlegitimateȱintegerȱexpressions,ȱ
soȱtheyȱareȱbothȱlegalȱinȱthisȱcontext.ȱ
Whatȱ happensȱ ifȱ youȱ useȱ theȱ wrongȱ operator?ȱ Considerȱ thisȱ example,ȱ whichȱ
looksȱperfectlyȱgoodȱtoȱPascalȱandȱModulaȱprogrammers:ȱ
x = get_some_value();
if( x = 5 )
doȱsomethingȱ
xȱgetsȱaȱvalueȱfromȱtheȱfunction,ȱbutȱinsteadȱofȱcomparingȱitȱtoȱtheȱliteralȱconstantȱfive,ȱ
weȱassignȱfiveȱtoȱ x,ȱthusȱdestroyingȱtheȱvalueȱobtainedȱfromȱtheȱfunction. 26 ȱThisȱresultȱ
isȱsurelyȱnotȱwhatȱtheȱprogrammerȱintended.ȱButȱthereȱisȱanotherȱproblem,ȱtoo.ȱTheȱifȱ
statementȱ willȱ alwaysȱ beȱ trueȱ becauseȱ theȱ valueȱ ofȱ theȱ assignmentȱ expressionȱ isȱ theȱ
newȱvalueȱofȱx,ȱwhichȱisȱnonzero.ȱ
GetȱintoȱtheȱhabitȱofȱdoubleȬcheckingȱcomparisonsȱforȱequalityȱwhenȱyouȱwriteȱ
themȱtoȱmakeȱsureȱyouȱusedȱtheȱdoubleȱequalȱsign.ȱWhenȱyouȱfindȱthatȱaȱprogramȱisȱ
notȱ working,ȱ takeȱ aȱ quickȱ lookȱ atȱ yourȱ comparisons;ȱ youȱ mayȱ saveȱ yourselfȱ aȱ lotȱ ofȱ
debuggingȱtime.ȱ
ȱ
ȱ
ȱ
5.1.7 Logical
ȱ
Theȱlogicalȱoperatorsȱareȱ&&ȱandȱ||.ȱTheseȱoperatorsȱlookȱlikeȱtheȱbitwiseȱoperators,ȱ
butȱtheirȱoperationȱisȱquiteȱdifferentȱ–ȱtheseȱvaluateȱexpressionsȱlookingȱforȱtrueȱandȱ
falseȱvalues.ȱLetȇsȱlookȱatȱoneȱofȱthemȱ
ȱ
expression1 && expression2ȱ
ȱ
ȱ
Theȱ resultȱ ofȱ thisȱ expressionȱ isȱ trueȱ ifȱ bothȱ expression1ȱ andȱ expression2ȱ areȱ true;ȱ ifȱ
eitherȱofȱthemȱisȱfalse,ȱtheȱentireȱexpressionȱisȱfalse.ȱSoȱfar,ȱsoȱgood.ȱ
ȱSomeȱcompilersȱproduceȱaȱwarningȱmessageȱforȱsuchȱsuspiciousȱexpressions.ȱInȱtheȱrareȱoccasionsȱwhenȱassignmentȱisȱ
whatȱyouȱwant,ȱtryȱenclosingȱtheȱassignmentȱinȱparenthesesȱtoȱgetȱridȱofȱtheȱwarningȱmessage.ȱ
26ȱTheȱ=ȱoperatorȱusedȱinȱthisȱmannerȱisȱsometimesȱjokinglyȱcalledȱtheȱȈitȱisȱnowȈȱoperator.ȱȈIsȱxȱequalȱtoȱfive?ȱItȱisȱnow!Ȉȱ
25
Download at http://www.pin5i.com/
5.1 Operators
105
Anȱinterestingȱaspectȱofȱthisȱoperatorȱisȱthatȱitȱcontrolsȱtheȱorderȱinȱwhichȱtheȱ
subexpressionsȱareȱevaluated.ȱForȱexample,ȱlookȱatȱthisȱexpression:ȱ
ȱ
a > 5 && a < 10
ȱ
Theȱprecedenceȱofȱ &&ȱisȱlowerȱthanȱthatȱofȱeitherȱtheȱ >ȱorȱtheȱ <ȱoperator,ȱsoȱtheȱ
subexpressionsȱareȱgroupedȱlikeȱthis:ȱ
ȱ
( a > 5 ) && ( a < 10 )
However,ȱdespiteȱitsȱlowerȱprecedence,ȱtheȱ&&ȱexertsȱcontrolȱoverȱtheȱevaluationȱofȱtheȱ
twoȱrelationals.ȱHereȱisȱhowȱitȱworks:ȱtheȱleftȱoperandȱofȱaȱ&&ȱisȱalwaysȱevaluatedȱfirst.ȱ
Ifȱitsȱvalueȱisȱtrue,ȱthenȱtheȱrightȱoperandȱisȱevaluated.ȱIfȱtheȱvalueȱofȱtheȱleftȱoperandȱ
isȱfalse,ȱtheȱrightȱoperandȱisȱnotȱevaluatedȱbecauseȱitȱdoesnȇtȱmatter:ȱtheȱresultȱofȱtheȱ&&ȱ
isȱalreadyȱknownȱtoȱbeȱfalse.ȱ ||ȱhasȱtheȱsameȱproperty.ȱTheȱleftȱoperandȱisȱevaluatedȱ
first:ȱ ifȱ itȱ isȱ true,ȱ theȱ rightȱ operandȱ isȱ notȱ evaluatedȱ becauseȱ theȱ valueȱ ofȱ theȱ overallȱ
expressionȱ hasȱ alreadyȱ beenȱ determined.ȱ Thisȱ behaviorȱ isȱ oftenȱ calledȱ shortȬcircuitedȱ
evaluation.ȱ
Thisȱorderingȱisȱguaranteedȱandȱisȱquiteȱuseful.ȱTheȱexampleȱbelowȱisȱillegalȱinȱ
standardȱPascal:ȱ
ȱ
if( x >= 0 && x < MAX && array[ x ] == 0 ) ...
CAUTION!
ȱ
InȱC,ȱtheȱcodeȱfirstȱchecksȱwhetherȱtheȱvalueȱisȱinȱtheȱlegalȱrangeȱofȱsubscriptsȱforȱtheȱ
array.ȱ Ifȱ itȱ isȱ not,ȱ theȱ subscriptȱ expressionȱ isȱ skippedȱ entirely.ȱ Becauseȱ Pascalȱ fullyȱ
evaluatesȱallȱexpressions,ȱanȱinvalidȱsubscriptȱwouldȱcauseȱtheȱprogramȱtoȱabortȱwithȱ
aȱsubscriptȱerror,ȱdespiteȱtheȱcheckingȱthatȱtheȱprogrammerȱtriedȱtoȱdo.ȱ
ȱ
Theȱ bitwiseȱ operatorsȱ areȱ oftenȱ confusedȱ withȱ theȱ logicalȱ operators,ȱ butȱ theyȱ areȱ notȱ
interchangeable.ȱTheȱfirstȱdifferenceȱisȱthatȱ||ȱandȱ&&ȱareȱshortȱcircuited;ȱifȱtheȱvalueȱ
ofȱtheȱexpressionȱcanȱbeȱdeterminedȱfromȱtheȱleftȱoperandȱalone,ȱtheȱrightȱoperandȱisȱ
notȱevaluated.ȱInȱcontrast,ȱbothȱoperandsȱofȱ|ȱandȱ&ȱareȱalwaysȱevaluated.ȱ
Second,ȱ theȱ logicalȱ operatorsȱ testȱ forȱ zeroȱ orȱ nonzeroȱ values,ȱ whereasȱ theȱ
bitwiseȱ operatorsȱ compareȱ theȱ correspondingȱ bitsȱ inȱ theirȱ operands.ȱ Hereȱ isȱ anȱ
example:ȱ
ȱ
if( a < b && c > d ) ...
if( a < b & c > d ) ...
ȱ
Becauseȱtheȱrelationalȱoperatorsȱproduceȱeitherȱ aȱzeroȱorȱaȱone,ȱtheseȱtwoȱstatementsȱ
willȱhaveȱtheȱsameȱresult.ȱButȱifȱaȱisȱoneȱandȱbȱisȱtwo,ȱtheȱnextȱpairȱofȱstatementȱdoȱnotȱ
produceȱtheȱsameȱresult.ȱ
Download at http://www.pin5i.com/
106
Chapter 5 Operators and Expressions
if( a && b ) ...
if( a & b ) ...
ȱ
Bothȱvaluesȱareȱnonzeroȱsoȱtheȱfirstȱstatementȱisȱtrue,ȱbutȱtheȱsecondȱisȱfalseȱbecauseȱ
thereȱareȱnoȱbitȱpositionsȱthatȱcontainȱaȱoneȱinȱbothȱaȱandȱb.ȱ
ȱ
ȱ
ȱ
5.1.8 Conditional
ȱ
Theȱ conditionalȱ operatorȱ takesȱ threeȱ operands.ȱ Itȱ alsoȱ controlsȱ theȱ orderȱ inȱ whichȱ itsȱ
subexpressionsȱareȱevaluated.ȱHereȱisȱhowȱitȱisȱused:ȱ
ȱ
ȱ
expression1 ? expression2 : expression3
ȱ
Theȱconditionerȱoperatorȱhasȱaȱveryȱlowȱprecedence,ȱsoȱoperandsȱthatȱareȱexpressionsȱ
willȱ groupȱ properlyȱ evenȱ withoutȱ parentheses.ȱ Nevertheless,ȱ manyȱ peopleȱ preferȱ toȱ
parenthesizeȱtheȱsubexpressionsȱforȱtheȱsakeȱofȱclarity.ȱ
ȱ
expression1 isȱ evaluatedȱ first.ȱ Ifȱ itȱ isȱ trueȱ (hasȱ anyȱ nonzeroȱ value),ȱ thenȱ theȱ
valueȱofȱtheȱentireȱexpressionȱisȱ expression2,ȱandȱ expression3ȱisȱnotȱevaluatedȱatȱall.ȱ
Butȱifȱexpression1 isȱfalseȱ(zero),ȱthenȱtheȱvalueȱofȱtheȱconditionalȱisȱexpression3,ȱandȱ
expression2 isȱnotȱevaluated.ȱ
Ifȱ youȱ haveȱ troubleȱ rememberingȱ howȱ thisȱ operatorȱ works,ȱ tryȱ readingȱ itȱ asȱ
question.ȱForȱexample,ȱ
ȱ
a > 5 ? b – 6 : c / 2
TIP
ȱ
isȱread:ȱȈaȱgreaterȱthanȱfive?ȱthenȱ b – 6,ȱotherwiseȱ c / 2.ȈȱTheȱchoideȱofȱtheȱquestionȱ
markȱcharacterȱforȱthisȱoperatorȱwasȱnoȱaccident.ȱ
ȱ
Whereȱisȱtheȱconditionalȱoperatorȱused?ȱHereȱareȱtwoȱprogramȱfragments:ȱ
ȱ
if( a > 5 )
b = a > 5 ? 3 : -20;
b = 3;
else
b = -20;
ȱ
Theȱtwoȱsequencesȱofȱcodeȱperformȱexactlyȱtheȱsameȱfunction,ȱbutȱtheȱoneȱonȱtheȱleftȱ
requiresȱthatȱȈbȱ=Ȉȱbeȱwrittenȱtwice.ȱBurȱsoȱwhatȇ?ȱThereȱisȱnoȱadvantageȱtoȱusingȱtheȱ
conditionalȱhere.ȱBut,ȱtakeȱaȱlookȱatȱthisȱstatement:ȱ
ȱ
if( a > 5 )
b[ 2 * c + d( e / 5 ) ] = 3;
else
b[ 2 * c + d( e / 5 ) ] = -20;
Download at http://www.pin5i.com/
5.1 Operators
107
Here,ȱ itȱ isȱ aȱ majorȱ nuisanceȱ toȱ haveȱ toȱ writeȱ theȱ subscriptȱ twice;ȱ theȱ conditionalȱ isȱ
muchȱcleaner;ȱ
ȱ
ȱ
b[ 2 * c + d( e / 5 ) ] = a > 5 ? 3 : -20;
ȱ
Thisȱexampleȱisȱaȱgoodȱplaceȱtoȱuseȱaȱconditionalȱbecauseȱthereȱisȱaȱtangibleȱbenefitȱinȱ
doingȱ so;ȱ thereȱ isȱ lessȱ chanceȱ forȱ errorȱ typingȱ theȱ conditionalȱ thanȱ inȱ theȱ previousȱ
version,ȱ andȱ theȱ conditionalȱ mayȱ resultȱ inȱ smallerȱ objectȱ codeȱ asȱ well.ȱ Afterȱ youȱ
becomeȱ accustomedȱ toȱ readingȱ conditionals,ȱ itȱ isȱ nearlyȱ asȱ easyȱ toȱ readȱ asȱ theȱ ifȱ
statement.ȱ
ȱ
ȱ
ȱ
5.1.9 Comma
ȱ
Theȱ commaȱ operatorȱ willȱ soundȱ triteȱ atȱ first,ȱ butȱ thereȱ areȱ situationsȱ inȱ whichȱ itȱ isȱ
quiteȱuseful.ȱItȱworksȱlikeȱthis:ȱ
ȱ
expression1, expression2, ... , expressionN
ȱ
Theȱ commaȱ operatorȱ separatesȱ twoȱ orȱ moreȱ expressions.ȱ Theȱ expressionsȱ areȱ
evaluatedȱ oneȱ byȱ one,ȱ leftȱ toȱ right,ȱ andȱ theȱ valueȱ ofȱ theȱ entireȱ expressionȱ isȱ justȱ theȱ
valueȱofȱtheȱlastȱexpressionȱinȱtheȱlist.ȱForȱexample,ȱ
ȱ
if( b + 1, c / 2, d > 0 )
ȱ
isȱtrueȱifȱtheȱvalueȱofȱdȱisȱgreaterȱthanȱzero.ȱNoȱoneȱeverȱwritesȱcodeȱlikeȱthisȱexample,ȱ
ofȱ course,ȱ becauseȱ thereȱ isȱ noȱ purposeȱ inȱ evaluatingȱ theȱ otherȱ twoȱ expressions;ȱ theirȱ
valuesȱareȱjustȱdiscarded.ȱHowever,ȱtakeȱaȱlookȱatȱthisȱpieceȱofȱcode.ȱ
ȱ
a = get_value();
count_value( a );
while( a > 0 ){
...
a = get_value();
count_value( a );
}
ȱ
Theȱ testȱ inȱ thisȱ loopȱ isȱ precededȱ byȱ twoȱ separateȱ statementsȱ toȱ obtainȱ theȱ value,ȱ soȱ
thereȱ mustȱ beȱ aȱ copyȱ ofȱ theseȱ statementsȱ bothȱ beforeȱ theȱ loopȱ andȱ atȱ theȱ endȱ ofȱ theȱ
loop’sȱbody.ȱHowever,ȱwithȱtheȱcommaȱoperatorȱyouȱcanȱrewriteȱthisȱloopȱas:ȱ
ȱ
ȱ
ȱ
while( a = get_value(), count_value( a ), a > 0 ){
}
Download at http://www.pin5i.com/
Chapter 5 Operators and Expressions
108
Youȱmightȱalsoȱuseȱanȱembeddedȱassignment,ȱlikeȱthis:ȱ
ȱ
ȱ
while( count_value( a = get_value() ), a > 0 ){
...
}
TIP
Newȱthereȱisȱonlyȱaȱsingleȱcopyȱofȱtheȱcodeȱneededȱtoȱgetȱtheȱnextȱvalueȱforȱtheȱloop.ȱ
Theȱ commaȱ operatorȱ makesȱ meȱ sourceȱ programȱ easierȱ toȱ maintain;ȱ ifȱ theȱ wayȱ theȱ
valuesȱareȱobtainedȱshouldȱchangeȱinȱtheȱfuture,ȱthereȱisȱonlyȱoneȱcopyȱofȱtheȱcodeȱthatȱ
needsȱtoȱbeȱfixed.ȱ
Itȱ isȱ easyȱ toȱ goȱ overboardȱ withȱ this,ȱ though,ȱ soȱ beforeȱ usingȱ theȱ commonȱ
operator,ȱaskȱyourselfȱwhetherȱitȱwouldȱmakeȱtheȱprogramȱbetterȱinȱsomeȱway.ȱIfȱtheȱ
answerȱisȱno,ȱthenȱdonȇtȱuseȱit.ȱByȱtheȱway,ȱȈbetterȈȱdoesȱnotȱincludeȱȈtrickier,ȈȱȈcooler,Ȉȱ
orȱȈmoreȱimpressive.Ȉȱ
Hereȇsȱaȱtechniqueȱthatȱyouȱmightȱoccasionallyȱsee:ȱ
ȱ
while( x < 10 )
b += x;
x += 1;
ȱ
Inȱthisȱexampleȱtheȱcommaȱoperatorȱisȱusedȱtoȱmakeȱaȱsingleȱstatementȱoutȱofȱtheȱtwoȱ
assignmentsȱinȱorderȱnoȱavoidȱputtingȱbracesȱaroundȱthem.ȱThisȱpracticeȱisȱaȱbadȱidea,ȱ
becauseȱtheȱsubtleȱvisualȱdifferenceȱbetweenȱaȱcommaȱandȱaȱsemicolonȱisȱtooȱeasyȱtoȱ
miss.ȱ
ȱ
ȱ
ȱ
5.1.10
Subscript, Function Call, and Structure Member
Iȱdescribeȱtheȱremainingȱoperatorsȱinȱmoreȱdetailȱelsewhereȱinȱtheȱbookȱbutȱmentionȱ
themȱ hereȱ forȱ completeness.ȱ Theȱ subscriptȱ operatorȱ isȱ aȱ pairȱ ofȱ brackets.ȱ Aȱ subscriptȱ
takesȱ twoȱ operands:ȱ anȱ arrayȱ nameȱ andȱ anȱ indexȱ value.ȱ Actually,ȱ youȱ canȱ useȱ
subscriptsȱonȱmoreȱthanȱjustȱarrayȱnames,ȱbutȱweȱwillȱdiscussȱthisȱissueȱinȱChapterȱ6.ȱ
Subscriptsȱ inȱ Cȱ workȱ muchȱ likeȱ subscriptsȱ inȱ otherȱ languages,ȱ althoughȱ theȱ
implementationȱ isȱ somewhatȱ different.ȱ Cȱ subscriptȱ valuesȱ alwaysȱ beginȱ atȱ zero,ȱ andȱ
subscriptsȱ areȱ notȱ checkedȱ forȱ validity.ȱ Exceptȱ forȱ theirȱ precedence,ȱ subscriptȱ
operationsȱareȱequivalentȱtoȱindirectionȱexpressions.ȱHereȱisȱtheȱmapping:ȱ
ȱ
array[ subscript ]
*( array + ( subscript ) )
ȱ
Theȱ factȱ thatȱ subscriptingȱ isȱ implementedȱ inȱ thisȱ wayȱ becomesȱ importantȱ whenȱ weȱ
beginȱtoȱuseȱpointersȱmore,ȱinȱChapterȱ6.ȱ
Download at http://www.pin5i.com/
5.2 Boolean Values
109
Theȱȱfunctionȱcallȱoperatorȱtakesȱoneȱorȱmoreȱoperands.ȱTheȱfirstȱisȱtheȱnameȱofȱ
theȱfunctionȱyouȱwishȱtoȱcall,ȱandȱtheȱremainingȱonesȱareȱtheȱargumentsȱtoȱpassȱtoȱtheȱ
function.ȱ Theȱ factȱ thatȱ functionȱ callingȱ isȱ implementedȱ asȱ anȱ operationȱ impliesȱ thatȱ
ȈexpressionsȈȱ mayȱ beȱ usedȱ insteadȱ ofȱ ȈconstantsȈȱ forȱ theȱ functionȱ name,ȱ whichȱ isȱ
indeedȱtheȱcase.ȱTheȱfunctionȱcallȱoperatorȱisȱcoveredȱinȱChapterȱ7.ȱ
The . and -> operatorsȱareȱusedȱtoȱaccessȱtheȱmembersȱofȱaȱstructure.ȱIfȱsȱisȱaȱ
structureȱ variable,ȱ thenȱ s.aȱ accessesȱ theȱ memberȱ ofȱ thatȱ structureȱ namedȱ a.ȱ Theȱ ->ȱ
operatorȱisȱusedȱinsteadȱof . whenȱyouȱhaveȱaȱpointerȱtoȱaȱstructureȱratherȱthanȱtheȱ
structureȱ itself.ȱ Structures,ȱ theirȱ members,ȱ andȱ theseȱ operatorsȱ areȱ allȱ describedȱ inȱ
Chapterȱ10.ȱ
ȱ
ȱ
ȱ
5.2 Boolean Values
ȱ
CȱdoesȱnotȱhaveȱanȱexplicitȱBooleanȱtypeȱsoȱintegersȱareȱusedȱinstead.ȱTheȱruleȱis.ȱ
ȱ
ȱ
Zeroȱisȱfalse,ȱandȱanyȱnonzeroȱvalueȱisȱtrueȱ
ȱ
However,ȱwhatȱtheȱStandardȱdoesnȇtȱsayȱisȱthatȱtheȱvalueȱoneȱisȱȈmoreȱtrueȈȱthanȱanyȱ
otherȱnonzeroȱvalue.ȱConsiderȱthisȱcodeȱfragment:ȱ
ȱ
a =
b =
if(
if(
if(
25;
15;
a )
...
b )
...
a == b )
...
ȱ
Theȱfirstȱtestȱchecksȱwhetherȱaȱisȱnonzero,ȱwhichȱisȱtrue.ȱTheȱsecondȱtestȱcheckȱtoȱseeȱifȱ
bȱisȱnotȱequalȱtoȱzero,ȱwhichȱisȱalsoȱtrue.ȱButȱtheȱthirdȱtestȱdoesȱnotȱcheckȱwhetherȱ aȱ
andȱbȱareȱbothȱtrue,ȱitȱchecksȱwhetherȱtheyȱareȱequalȱtoȱeachȱother.ȱ
TheȱsameȱkindȱofȱproblemȱcanȱhappenȱwithȱintegerȱvariablesȱtestedȱinȱBooleanȱ
contexts.ȱ
ȱ
nonzero_a = a != 0;
...
if( nonzero_a == ( b != 0 ) ) ...
ȱ
Thisȱtestȱisȱsupposedȱtoȱbeȱtrueȱifȱaȱandȱbȱareȱeitherȱzeroȱtogetherȱorȱareȱnonzeroȱ
together.ȱTheȱtestȱworksȱfineȱasȱshownȱbutȱtryȱsubstitutingȱtheȱȈequivalentȈȱexpressionȱ
bȱforȱ( b != 0 ).ȱ
Download at http://www.pin5i.com/
110
Chapter 5 Operators and Expressions
if( nonzero_a == b ) ...
CAUTION!
ȱ
Theȱexpressionȱisȱnoȱlongerȱtestingȱforȱ aȱandȱ bȱbeingȱzeroȱorȱnonzeroȱtogether:ȱnowȱitȱ
isȱcheckingȱwhetherȱbȱhasȱaȱspecificȱintegerȱvalue,ȱnamelyȱzeroȱorȱone.ȱ
ȱ
Althoughȱ allȱ nonzeroȱ valuesȱ areȱ consideredȱ true,ȱ youȱ mustȱ beȱ carefulȱ whenȱ
comparingȱ trueȱ valuesȱ toȱ oneȱ another,ȱ becauseȱ manyȱ differentȱ valuesȱ canȱ representȱ
true.ȱ
Hereȱisȱanotherȱshortcutȱthatȱprogrammersȱoftenȱuseȱwithȱifȱstatementsȱ–ȱoneȱinȱ
whichȱ thisȱ sameȱ kindȱ ofȱ troubleȱ canȱ occur.ȱ Assumingȱ thatȱ youȱ haveȱ madeȱ theȱ
followingȱ#defineȇs,ȱthenȱeachȱofȱtheȱpairsȱofȱstatementsȱbelowȱseemȱequivalent.ȱ
ȱ
#define FALSE
0
#define TRUE
1
...
if( flag == FALSE ) ...
if( !flag ) ...
if( flag == TRUE ) ...
if( flag ) ...
ȱ
Butȱ theȱ secondȱ pairȱ ofȱ statementsȱ isȱ notȱ equivalentȱ ifȱ flagȱ isȱ setȱ toȱ arbitraryȱ integerȱ
values.ȱItȱisȱtheȱsameȱonlyȱifȱtheȱflagȱwasȱsetȱtoȱTRUE,ȱtoȱFALSE,ȱorȱtoȱtheȱresultȱofȱaȱ
relationalȱorȱlogicalȱexpression.ȱ
TIP
Theȱsolutionȱtoȱallȱofȱtheseȱproblemsȱisȱtoȱavoidȱmixingȱintegerȱandȱbooleanȱvalues.ȱIfȱaȱ
variableȱcontainsȱanȱarbitraryȱintegerȱvalue,ȱtestȱitȱexplicitly:ȱ
ȱ
if( value != 0 ) ...
ȱ
Don’tȱ useȱ theȱ shortcutsȱ toȱ testȱ theȱ variableȱ forȱ zeroȱ orȱ nonzero,ȱ becauseȱ thoseȱ formsȱ
incorrectlyȱimplyȱthatȱtheȱvariableȱisȱbooleanȱinȱnature.ȱȱ
lfȱaȱvariableȱisȱsupposedȱtoȱcontainȱaȱbooleanȱvalue,ȱalwaysȱsetȱitȱtoȱeitherȱzeroȱ
orȱone,ȱforȱexample:ȱ
ȱ
positive_cash_flow = cash_balance >= 0;
ȱ
Doȱ notȱ testȱ theȱ variablesȱ truthȱ valueȱ byȱ comparingȱ itȱ withȱ anyȱ specificȱ value,ȱ evenȱ
TRUEȱorȱFALSE.ȱInstead,ȱtestȱtheȱvariablesȱasȱshownȱhere:ȱ
ȱ
if( positive_cash_flow ) ...
if( !positive_cash_flow ) ...
ȱ
Ifȱ youȱ haveȱ chosenȱ descriptiveȱ namesȱ forȱ youȱ booleanȱ variables,ȱ thisȱ techniqueȱ willȱ
rewardȱyouȱwithȱcodeȱthatȱisȱeasyȱtoȱread:ȱȈifȱpositiveȱcashȱflow,ȱthenȱ…Ȉȱ
Download at http://www.pin5i.com/
5.3 L-values and R-values
111
5.3 L-values and R-values
ȱ
Toȱ understandȱ theȱ restrictionsȱ onȱ someȱ ofȱ theseȱ operators,ȱ youȱ mustȱ understandȱ theȱ
differenceȱ betweenȱ LȬvaluesȱ andȱ RȬvalues.ȱ Theseȱ termsȱ wereȱ coinedȱ byȱ compilerȱ
writersȱmanyȱyearsȱagoȱandȱhaveȱsurvivedȱtoȱthisȱdayȱevenȱthoughȱtheirȱdefinitionsȱdoȱ
notȱexactlyȱfitȱwithȱtheȱCȱlanguage.ȱ
AnȱLȬvalueȱisȱsomethingȱthatȱcanȱappearȱonȱtheȱleftȱsideȱofȱanȱequalȱsignȱ(Lȱforȱ
left).ȱAnȱRȬvalueȱisȱsomethingȱthatȱcanȱappearȱonȱtheȱrightȱsideȱofȱanȱequalȱsign.ȱHereȱisȱ
anȱexample:ȱ
ȱ
a = b + 25;
ȱ
aȱisȱanȱLȬvalueȱbecauseȱitȱidentifiesȱaȱplaceȱwhereȱaȱresultȱcanȱbeȱstored.ȱb + 25ȱisȱanȱRȬ
valueȱbecauseȱitȱdesignatesȱaȱvalue.ȱ
ȱ
Canȱtheyȱbeȱinterchanged?ȱ
ȱ
b + 25 = a;
ȱ
a,ȱwhichȱwasȱusedȱasȱanȱLȬvalueȱbefore,ȱcanȱalsoȱbeȱusedȱasȱanȱRȬvaleȱbecauseȱeveryȱ
placeȱcontainsȱaȱvalue.ȱHowever,ȱ b + 25ȱcannotȱbeȱusedȱasȱanȱLȬvalueȱbecauseȱitȱdoesȱ
notȱidentifyȱaȱspecificȱplace.ȱThus,ȱthisȱassignmentȱisȱillegal.ȱ
Noteȱthatȱwhenȱtheȱcomputerȱevaluatesȱ b + 25ȱtheȱresultȱmustȱexistȱsomewhereȱ
inȱ theȱ machine.ȱ However,ȱ thereȱ isȱ noȱ wayȱ thatȱ theȱ programmerȱ canȱ eitherȱ predictȱ
whereȱ theȱ resultȱ willȱ beȱ orȱ referȱ toȱ theȱ sameȱ locationȱ later.ȱ Consequently,ȱ thisȱ
expressionȱisȱnotȱanȱLȬvalue.ȱLiteralȱconstantsȱareȱnotȱLȬvaluesȱforȱtheȱsameȱreason.ȱ
ItȱsoundsȱasȱthoughȱvariablesȱmayȱbeȱusedȱasȱLȬvaluesȱbutȱexpressionsȱmayȱnot,ȱ
butȱ thisȱ statementȱ isȱ notȱ quiteȱ accurate.ȱ Theȱ LȬvalueȱ inȱ theȱ assignmentȱ belowȱ isȱ anȱ
expression.ȱ
ȱ
int
a[30];
...
a[ b + 10 ] = 0;
ȱ
Subscriptingȱisȱinȱfactȱanȱoperatorȱsoȱtheȱconstructȱonȱtheȱleftȱisȱanȱexpression,ȱyetȱitȱisȱ
aȱlegitimateȱLȬvalueȱbecauseȱitȱidentifiesȱaȱspecificȱlocationȱthatȱweȱcanȱreferȱtoȱlaterȱinȱ
theȱprogram.ȱHereȱisȱanotherȱexample:ȱ
int
a, *pi;
...
pi = &a;
*pi = 20;
ȱ
Download at http://www.pin5i.com/
112
Chapter 5 Operators and Expressions
Theȱ secondȱ assignmentȱ isȱ whereȱ theȱ actionȱ is:ȱ theȱ valueȱ onȱ theȱ leftȱ isȱ clearlyȱ anȱ
expression,ȱyetȱitȱisȱaȱlegalȱLȬvalue.ȱWhy?ȱTheȱvalueȱinȱtheȱpointerȱ piȱisȱtheȱaddressȱofȱ
aȱspecificȱlocationȱinȱmemory,ȱandȱtheȱ *ȱoperatorȱdirectsȱtheȱmachineȱtoȱthatȱlocation.ȱ
WhenȱusedȱasȱanȱLȬvalue,ȱthisȱexpressionȱspecifiesȱtheȱlocationȱtoȱbeȱmodified.ȱWhenȱ
usedȱasȱanȱRȬvalue,ȱitȱgetsȱtheȱvalueȱcurrentlyȱstoredȱatȱthatȱlocation.ȱ
Someȱ operators,ȱ likeȱ indirectionȱ andȱ subscripting,ȱ produceȱ anȱ LȬvalueȱ asȱ aȱ
result.ȱ Othersȱ produceȱ RȬvalue.ȱ Forȱ reference,ȱ thisȱ informationȱ isȱ includedȱ inȱ theȱ
precedenceȱtable,ȱTableȱ5.1,ȱlaterȱinȱthisȱchapter.ȱ
ȱ
ȱ
ȱ
5.4 Expression Evaluation
ȱ
Theȱ orderȱ ofȱ expressionȱ evaluationȱ isȱ determinedȱ partiallyȱ byȱ theȱ precedenceȱ andȱ
associativityȱofȱtheȱoperatorsȱitȱcontains.ȱAlso,ȱsomeȱofȱtheȱexpressionȇsȱoperandsȱmayȱ
needȱtoȱbeȱconvertedȱtoȱotherȱtypesȱduringȱtheȱevaluationȱ
ȱ
ȱ
ȱ
5.4.1 Implicit Type Conversions
ȱ
ImagerȱarithmeticȱinȱCȱ isȱalwaysȱ performedȱwithȱ atȱ leastȱ theȱprecisionȱofȱ theȱ defaultȱ
integerȱ type.ȱ Toȱ achieveȱ thisȱ precision,ȱ characterȱ andȱ shortȱ integerȱ operandsȱ inȱ anȱ
expressionȱ areȱ convertedȱ toȱ integersȱ beforeȱ beingȱ usedȱ inȱ theȱ expression.ȱ Theseȱ
conversionsȱareȱcalledȱintegralȱpromotions.ȱForȱexample,ȱinȱtheȱevaluationȱofȱ
ȱ
char
...
a = b + c;
a, b, c;
ȱ
theȱ valuesȱ ofȱ bȱ andȱ cȱ areȱ promotedȱ toȱ integersȱ andȱ thenȱ added.ȱ Theȱ resultȱ isȱ thanȱ
truncatedȱtoȱfitȱintoȱa.ȱTheȱresultȱinȱthisȱfirstȱexampleȱisȱtheȱsameȱasȱtheȱresultȱifȱ8Ȭbitȱ
arithmeticȱwereȱused.ȱButȱtheȱresultȱinȱthisȱsecondȱexample,ȱwhichȱcomputesȱaȱsimpleȱ
checksumȱofȱaȱseriesȱofȱcharacters,ȱisȱnotȱtheȱsame.ȱ
ȱ
a = ( ~ a ^ b << 1 ) >> 1;
ȱ
ȱ
Becauseȱofȱtheȱoneȇsȱcomplementȱandȱtheȱleftȱshift,ȱ8ȱbitsȱofȱprecisionȱareȱinsufficient.ȱ
TheȱStandardȱdictatesȱfullȱintegerȱevaluation,ȱsoȱthatȱthereȱisȱnoȱambiguityȱinȱtheȱresultȱ
ofȱexpressionsȱsuchȱasȱthisȱone. 27
ȱActually,ȱtheȱStandardȱstatesȱthatȱtheȱresultȱshallȱbeȱthatȱobtainedȱbyȱfullȱintegerȱevaluation,ȱwhichȱallowsȱtheȱpossibilityȱofȱ
usingȱ8Ȭbitȱarithmeticȱifȱtheȱcompilerȱcanȱdetermineȱthatȱdoingȱsoȱwouldȱnotȱaffectȱtheȱresult.ȱ
27
Download at http://www.pin5i.com/
5.4 Expression Evaluation
113
5.4.2 Arithmetic Conversions
ȱ
Operationsȱ onȱ valuesȱ ofȱ differentȱ typesȱ cannotȱ proceedȱ untilȱ oneȱ ofȱ theȱ operandsȱ isȱ
convertedȱ toȱ theȱ typeȱ ofȱ theȱ other.ȱ Theȱ followingȱ hierarchyȱ isȱ calledȱ theȱ usualȱ
arithmeticȱconversions:ȱȱ
ȱ
long double
double
float
unsigned long int
long int
unsigned int
int
CAUTION!
ȱ
Theȱoperandȱwhoseȱtypeȱisȱlowerȱinȱtheȱlistȱisȱconvertedȱtoȱtheȱotherȱoperand’sȱtype.ȱ
ȱ
Thisȱfragmentȱofȱcodeȱcontainsȱaȱpotentialȱproblem.ȱ
ȱ
int
int
long
a = 5000;
b = 25;
c = a * b;
ȱ
Theȱ problemȱ isȱ thatȱ theȱ expressionȱ a * bȱ isȱ evaluatedȱ usingȱ integerȱ arithmetic.ȱ Thisȱ
codeȱworksȱfineȱonȱmachinesȱwithȱ32Ȭbitȱintegers,ȱbutȱtheȱmultiplicationȱoverflowsȱonȱ
machinesȱwithȱ16Ȭbitȱintegers,ȱsoȱcȱisȱinitializedȱtoȱtheȱwrongȱvalue.ȱ
Theȱ solutionȱ isȱ toȱ convertȱ oneȱ (orȱ both)ȱ ofȱ theȱ valuesȱ toȱ aȱ longȱ beforeȱ theȱ
multiplication.ȱ
ȱ
long
c = (long)a * b;
ȱ
Itȱ isȱ possibleȱ toȱ loseȱ precisionȱ whenȱ convertingȱ anȱ integerȱ toȱ aȱ float.ȱ Floatingȱ
valuesȱ areȱ onlyȱ requiredȱ toȱ haveȱ sixȱ decimalȱ digitsȱ ofȱ precision;ȱ ifȱ anȱ integerȱ thatȱ isȱ
longerȱthanȱsixȱdigitsȱisȱassignedȱtoȱaȱfloat,ȱtheȱresultȱmayȱbeȱonlyȱanȱapproximationȱofȱ
theȱintegerȱvalue.ȱ
Whenȱaȱfloatȱisȱconvertedȱtoȱanȱinteger,ȱtheȱfractionalȱpartȱisȱdiscardedȱ(itȱisȱnotȱ
rounded).ȱIfȱtheȱnumberȱisȱtooȱlargeȱfitȱinȱanȱinteger,ȱtheȱresultȱisȱundefined.ȱ
ȱ
ȱ
ȱ
5.4.3 Properties of Operators
ȱ
Thereȱareȱthreeȱfactorsȱthatȱdetermineȱtheȱorderȱinȱwhichȱcomplicatedȱexpressionȱareȱ
evaluated:ȱtheȱprecedenceȱofȱtheȱoperators,ȱtheirȱassociativity,ȱandȱwhetherȱtheyȱcontrolȱ
theȱ executionȱ order.ȱ Theȱ orderȱ inȱ whichȱ twoȱ adjacentȱ operatorsȱ areȱ evaluatedȱ isȱ
Download at http://www.pin5i.com/
Chapter 5 Operators and Expressions
114
ȱ
Oper
Description
Sample Usage
()
Groupingȱ
(ȱexpȱ)ȱ
()
&
Functionȱcallȱ
Subscriptȱ
Structureȱmemberȱ
Structureȱpointerȱmemberȱ
Postfixȱincrementȱ
Postfixȱincrementȱ
Logicalȱnegateȱ
Oneȇȱcomplementȱ
Unaryȱplusȱ
Unaryȱminusȱ
Prefixȱincrementȱ
Prefixȱdecrementȱ
Indirectionȱ
Addressȱofȱ
sizeof
Sizeȱinȱbytesȱ
(ȱtypeȱ)
*
Typeȱconversionȱ
Multiplicationȱ
Divisionȱ
Integerȱremainderȱ
Additionȱ
Subtractionȱ
Leftȱshiftȱ
Rightȱshiftȱ
rexp(ȱrexp,ȱ...ȱ,ȱrexp )ȱ
rexp[ȱrexpȱ]ȱ
lexp.member_nameȱ
rexp->member_nameȱ
lexp++ȱ
lexp--ȱ
!rexpȱ
~rexpȱ
+rexpȱ
-rexpȱ
++lexpȱ
--lexpȱ
*rexpȱ
&lexpȱ
sizeofȱrexpȱ
sizeof(ȱtypeȱ)ȱ
(ȱtypeȱ)rexpȱ
rexpȱ*ȱrexpȱ
rexpȱ/ȱrexpȱ
rexpȱ%ȱrexpȱ
rexpȱ+ȱrexpȱ
rexpȱ–ȱrexpȱ
rexpȱ<<ȱrexpȱ
rexpȱ>>ȱrexpȱ
[]
.
->
++
-!
~
+
++
-*
/
%
+
<<
>>
Result
Associa
tivity
sameȱ asȱ N/Aȱ
expȱ
rexpȱ
LȬRȱ
lexpȱ
LȬRȱ
lexpȱ
LȬRȱ
lexpȱ
LȬRȱ
rexpȱ
LȬRȱ
rexpȱ
LȬRȱ
rexpȱ
RȬLȱ
rexpȱ
RȬLȱ
rexpȱ
RȬLȱ
rexpȱ
RȬLȱ
rexpȱ
RȬLȱ
rexpȱ
RȬLȱ
lexpȱ
RȬLȱ
rexpȱ
RȬLȱ
Controls
Eval
ȱ
rexpȱ
RȬLȱ
Noȱ
rexpȱ
rexpȱ
rexpȱ
rexpȱ
rexpȱ
rexpȱ
rexpȱ
rexpȱ
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
ȱ
Tableȱ5.1ȱOperatorȱprecedenceȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱcontinued...ȱ
ȱ
determinedȱ byȱ theirȱ precedence.ȱ Ifȱ theyȱ haveȱ theȱ sameȱ precedence,ȱ theȱ orderȱ ofȱ
evaluationȱisȱdeterminedȱbyȱtheirȱassociativity.ȱSimplyȱstated,ȱassociativityȱisȱwhetherȱ
aȱ sequenceȱ ofȱoperatorsȱisȱ evaluatedȱ fromȱ leftȱtoȱ rightȱ orȱfromȱrightȱ toȱ left.ȱ ȱ ȱFinally,ȱ
thereȱ areȱ fourȱ operatorsȱ thatȱ exertȱ someȱ controlȱ overȱ theȱ orderȱ inȱ whichȱ theȱ entireȱ
expressionȱ isȱ evaluated,ȱ specifyingȱ eitherȱ thatȱ oneȱ subexpressionȱ isȱ guaranteedȱ toȱ beȱ
evaluatedȱ beforeȱ anythingȱ inȱ anotherȱ subexpressionȱ isȱ computed,ȱ orȱ thatȱ aȱ
subexpressionȱmayȱbeȱskippedȱentirely.ȱ
Allȱofȱtheȱpropertiesȱareȱlistedȱforȱeachȱofȱtheȱoperatorsȱinȱtheȱprecedenceȱtable,ȱ
Tableȱ 5.1.ȱ Theȱ columnsȱ showȱ theȱ operator,ȱ aȱ briefȱ descriptionȱ ofȱ whatȱ itȱ does,ȱ anȱ
exampleȱshowingȱhowȱitȱisȱused,ȱwhatȱtypeȱofȱresultȱitȱgives,ȱitsȱassociativity,ȱandȱ
Download at http://www.pin5i.com/
5.4 Expression Evaluation
Oper
Description
Sample Usage
>
Result
Associativity
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
LȬRȱ
N/Aȱ
RȬLȱ
RȬLȱ
RȬLȱ
RȬLȱ
RȬLȱ
RȬLȱ
RȬLȱ
RȬLȱ
RȬLȱ
RȬLȱ
RȬLȱ
LȬRȱ
115
Controls
Eval
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Yesȱ
Yesȱ
Yesȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Noȱ
Yesȱ
Greaterȱthanȱ
rexpȱ>ȱrexpȱ
rexpȱ
Greaterȱthanȱorȱequalȱ
rexpȱ>=ȱrexpȱ
rexpȱ
<
Lessȱthanȱ
rexpȱ<ȱrexpȱ
rexpȱ
<=
Lessȱthanȱorȱequalȱ
rexpȱ<=ȱrexpȱ
rexpȱ
==
Equalȱtoȱ
rexpȱ==ȱrexpȱ
rexpȱ
!=
Notȱequalȱtoȱ
rexpȱ!=ȱrexpȱ
rexpȱ
&
BitwiseȱANDȱ
rexpȱ&ȱrexpȱ
rexpȱ
^
BitwiseȱexclusiveȱORȱ
rexpȱ^ȱrexpȱ
rexpȱ
|
BitwiseȱinclusiveȱORȱ
rexpȱ|ȱrexpȱ
rexpȱ
&&
LogicalȱANDȱ
rexpȱ&&ȱrexpȱ
rexpȱ
||
LogicalȱORȱ
rexpȱ||ȱrexpȱ
rexpȱ
?:
Conditionalȱ
rexpȱ?ȱrexpȱ:ȱrexpȱ
rexpȱ
=
Assignmentȱ
lexpȱ=ȱrexpȱ
rexpȱ
+=
Addȱtoȱ
lexpȱ+=ȱrexpȱ
rexpȱ
-=
Subtractȱfromȱ
lexpȱ-=ȱrexpȱ
rexpȱ
*=
Multiplyȱbyȱȱ
lexpȱ*=ȱrexpȱ
rexpȱ
/=
Divideȱbyȱ
lexpȱ/=ȱrexpȱ
rexpȱ
%=
Moduloȱbyȱ
lexpȱ%=ȱrexpȱ
rexpȱ
<<=
Shiftȱleftȱbyȱ
lexpȱ<<=ȱrexpȱ
rexpȱ
>>=
Shiftȱrightȱbyȱȱ
lexpȱ>>=ȱrexpȱ
rexpȱ
&=
ANDȱwithȱ
lexpȱ&=ȱrexpȱ
rexpȱ
^=
ExclusiveȱORȱwithȱ
lexpȱ^=ȱrexpȱ
rexpȱ
|=
InclusiveȱORȱwithȱ
lexpȱ|=ȱrexpȱ
rexpȱ
,
Commaȱ
rexpȱ,ȱrexpȱ
rexpȱ
ȱ
Tableȱ5.1ȱOperatorȱprecedenceȱ
ȱ
whetherȱitȱexertsȱsomeȱcontrolȱoverȱtheȱorderȱofȱevaluationȱofȱtheȱexpressionȱinȱwhichȱ
itȱ appears.ȱ Theȱ sampleȱ usageȱ indicatesȱ whereȱ LȬvaluesȱ areȱ required;ȱ theȱ termȱ lexpȱ
indicatesȱanȱLȬvalueȱexpression,ȱandȱrexpȱisȱanȱRȬvalueȱexpression.ȱȱRememberȱthanȱanȱ
LȬvalueȱ denotesȱ aȱ placeȱ andȱ anȱ RȬvalueȱ denotesȱ aȱ value;ȱ soȱ anȱ LȬvalueȱ mayȱ beȱ usedȱ
anywhereȱ anȱ RȬvalueȱ isȱ needed,ȱ butȱ anȱ RȬvalueȱ cannotȱ beȱ usedȱ whereȱ anȱ LȬvalueȱ isȱ
needed.ȱ
ȱ
ȱ
ȱ
>=
5.4.4 Precedence and Order of Evaluation
Inȱanȱexpressionȱwithȱmoreȱthanȱoneȱoperator,ȱwhatȱdeterminesȱtheȱorderȱinȱwhichȱtheȱ
operationsȱareȱperformed?ȱȱEachȱofȱtheȱCȱoperatorsȱisȱassignedȱaȱprecedence,ȱwhichȱ
Download at http://www.pin5i.com/
116
Chapter 5 Operators and Expressions
indicatesȱitsȱrelationȱshipsȱtoȱtheȱremainingȱoperators.ȱButȱprecedenceȱaloneȱdoesȱnotȱ
determineȱtheȱorderȱofȱevaluation.ȱHereȱisȱtheȱrule:ȱ
ȱ
Theȱorderȱofȱevaluationȱofȱtwoȱadjacentȱoperatorsȱisȱdeterminedȱbyȱtheirȱprecedence.ȱIfȱ
theyȱhaveȱtheȱsameȱprecedence,ȱtheȱorderȱisȱdeterminedȱbyȱtheirȱassociativity.ȱOtherwise,ȱ
theȱcompilerȱisȱfreeȱtoȱevaluateȱexpressionsȱinȱanyȱorderȱthatȱdoesȱnotȱviolateȱtheȱorderȱofȱ
evaluationȱimposedȱbyȱparenthesesȱorȱbyȱtheȱcomma,ȱ&&,ȱ||,ȱorȱ?:ȱoperators.ȱ
ȱ
Inȱotherȱwords,ȱtheȱprecedenceȱofȱtheȱoperatorsȱinȱanȱexpressionȱonlyȱdeterminesȱhowȱ
theȱcomponentsȱofȱtheȱexpressionȱareȱgroupedȱtogetherȱduringȱevaluation.ȱ
Hereȱisȱanȱexample:ȱ
ȱ
a + b * c
ȱ
Inȱthisȱexpression,ȱtheȱmultiplicationȱandȱadditionȱareȱadjacent.ȱTheȱmultiplicationȱisȱ
performedȱbeforeȱtheȱadditionȱbecauseȱtheȱ*ȱoperatorȱhasȱhigherȱprecedenceȱthanȱ+.ȱȱ
Theȱcompilerȱhasȱnoȱchoiceȱhere:ȱtheȱmultiplicationȱmustȱoccurȱfirstȱ
Hereȱisȱaȱmoreȱinterestingȱexpression:ȱ
ȱ
a * b + c * d + e * f
ȱ
Ifȱ precedenceȱ aloneȱ determinedȱ theȱ orderȱ ofȱ evaluation,ȱ allȱ threeȱ multiplicationsȱ
wouldȱoccurȱbeforeȱanyȱofȱtheȱadditions.ȱInȱfact,ȱthisȱorderingȱisȱnotȱnecessary.ȱAllȱthatȱ
isȱ requiredȱ isȱ thatȱ theȱ multiplicationsȱ onȱ eitherȱ sideȱ ofȱ eachȱ additionȱ beȱ performedȱ
beforeȱtheȱaddition.ȱȱForȱexample,ȱtheȱexpressionȱmightȱbeȱevaluatedȱinȱtheȱfollowingȱ
order.ȱTheȱboldfacedȱoperatorȱisȱtheȱoneȱbeingȱcomputedȱinȱeachȱstep.ȱ
ȱ
a * b
c * d
(a*b) + (c*d)
e * f
(a*b)+(c*d) + (e*f)
ȱ
Noticeȱthatȱtheȱfirstȱadditionȱisȱperformedȱbeforeȱtheȱlastȱmultiplication.ȱTheȱsameȱ
resultȱwouldȱbeȱobtainedȱifȱtheȱexpressionȱwereȱevaluatedȱinȱthisȱorder:ȱ
c * d
e * f
a * b
(a*b) + (c*d)
(a*b)+(c*d) + (e*f)
Download at http://www.pin5i.com/
5.4 Expression Evaluation
CAUTION!
117
Theȱ associativityȱ forȱ additionȱ requiresȱ theȱ twoȱ additionsȱ toȱ beȱ doneȱ leftȱ toȱ right,ȱ butȱ
theȱorderȱforȱtheȱrestȱofȱtheȱexpressionȱisȱnotȱconstrained.ȱȱSpecifically,ȱthereȱisnȇtȱanyȱ
ruleȱthatȱrequiresȱallȱofȱtheȱmultiplicationsȱtoȱbeȱcomputedȱfirst,ȱnorȱisȱthereȱaȱruleȱthatȱ
determinesȱtheȱorderȱinȱwhichȱtheyȱareȱdoneȱrelativeȱtoȱoneȱanother.ȱȱTheȱprecedenceȱ
ofȱ theȱ operatorsȱ isȱ notȱ relevantȱ here.ȱ Precedenceȱ onlyȱ controlsȱ theȱ orderȱ inȱ whichȱ
adjacentȱoperatorsȱareȱevaluated.ȱ
ȱ
Theȱ factȱthatȱ theȱorderȱofȱ expressionȱevaluationȱ isȱ notȱ completelyȱ determinedȱbyȱ theȱ
precedenceȱofȱtheȱoperatorsȱmakesȱstatementsȱlikeȱthisȱoneȱdangerous.ȱ
ȱ
ȱ
c + --c
ȱ
Theȱprecedenceȱofȱtheȱoperatorsȱindicatesȱthatȱtheȱ --ȱshouldȱbeȱperformedȱbeforeȱtheȱ
+,ȱbutȱthereȱisȱnoȱwayȱtoȱtellȱwhetherȱtheȱleftȱoperandȱofȱtheȱ +ȱwillȱbeȱevaluatedȱbeforeȱ
orȱ afterȱ theȱ rightȱ operand.ȱ Itȱ makesȱ aȱ differenceȱ withȱ thisȱ expression,ȱ becauseȱ --ȱ
involvesȱ aȱ sideȱ effect.ȱ Theȱ expressionȱ producesȱ aȱ differentȱ resultȱ ifȱ --cȱ isȱ evaluatedȱ
beforeȱorȱafterȱc.ȱ
Theȱ Standardȱ statesȱ thatȱ theȱ valueȱ ofȱ expressionsȱ suchȱ asȱ theseȱ isȱ undefined.ȱ
Althoughȱeveryȱimplementationȱwillȱproduceȱsomeȱvalueȱforȱtheȱexpression,ȱthereȱisȱnoȱ
correctȱ answer.ȱ Expressionsȱ likeȱ thisȱ oneȱ areȱ thereforeȱ notȱ portableȱ andȱ mustȱ beȱ
avoided.ȱ Programȱ 5.3ȱ illustratesȱ thisȱ problemȱ ratherȱ dramatically.ȱ Tableȱ 5.2ȱ listsȱ theȱ
valuesȱ producedȱ byȱ thisȱ programȱ onȱ eachȱ ofȱ theseȱ implementations.ȱ Manyȱ
implementationsȱ giveȱ differentȱ valuesȱ dependingȱ onȱ whetherȱ theȱ programȱ wasȱ
compiledȱ withȱ orȱ withoutȱ optimization;ȱ forȱ example,ȱ usingȱ theȱ optimizerȱ withȱ gccȱ
changesȱ theȱ resultȱ fromȱ Ȭ63ȱ toȱ 22.ȱ Althoughȱ eachȱ compilerȱ hasȱ evaluatedȱ theȱ
expressionȱinȱaȱdifferentȱorder,ȱnoneȱofȱtheseȱanswersȱisȱwrong!ȱȱItȱisȱtheȱexpressionȱitselfȱ
thatȱisȱfaulty;ȱitsȱorderȱofȱevaluationȱisȱambiguousȱbecauseȱofȱtheȱsideȱeffectsȱofȱmanyȱ
ofȱtheȱtermsȱitȱcontains.ȱ
ȱ
ȱ
ȱ
ȱ
/*
** A program to demonstrate that the order of expression evaluation
** is only partially determined by operator precedence.
*/
main()
{
int
i = 10;
i = i-- - --i * ( i = -3 ) * i++ + ++i;
printf( "i = %d\n", i );
}
Programȱ5.3ȱAnȱillegalȱexpressionȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱbad_exp.cȱ
Download at http://www.pin5i.com/
118
K&R C
Chapter 5 Operators and Expressions
ȱ
Value
Implementation
Ȭ129ȱ
Tandyȱ6000ȱXenixȱ3.2ȱ
Ȭ95ȱ
ThinkȱCȱ5.0.2ȱ(Macintosh)ȱ
Ȭ86ȱ
IBMȱPowerPCȱAIXȱ3.2.5ȱ
Ȭ85ȱ
SunȱSparcȱccȱ(aȱK&Rȱcompiler)ȱ
Ȭ63ȱ
gcc,ȱHPȬUXȱ9.0,ȱPowerȱCȱ2.0.0ȱ
4ȱ
SunȱSparcȱaccȱ(anȱANSIȱcompiler)ȱ
21ȱ
TurboȱC/C++ȱ4.5ȱ
22ȱ
FreeBSDȱ2.1Rȱ
30ȱ
DecȱAlphaȱOSF1ȱ2.0ȱ
36ȱ
DecȱVAX/VMSȱ
42ȱ
MicrosoftȱCȱ5.1ȱ
ȱ
Tableȱ5.2ȱResultsȱofȱillegalȱexpressionȱprogramȱ
ȱ
ȱ
ȱ
Inȱ K&Rȱ C,ȱ theȱ compilerȱ wasȱ freeȱ toȱ evaluateȱ theȱ expressionsȱ shownȱ belowȱ inȱ anyȱ
order.ȱ
a + b + c
x * y * z
ȱ
Theȱreasoningȱbehindȱthisȱdecisionȱisȱthatȱtheȱvalueȱofȱb + cȱ(orȱofȱy * z)ȱmightȱstillȱbeȱ
availableȱ fromȱ someȱ earlierȱ expression,ȱ soȱ itȱ wouldȱ beȱ moreȱ efficientȱ toȱ reuseȱ thatȱ
valueȱthanȱcomputeȱitȱagain.ȱAdditionȱandȱmultiplicationȱareȱassociative,ȱsoȱwhereȱisȱ
theȱharm?ȱ
Considerȱtheȱexpressionȱbelow,ȱwhichȱusesȱsignedȱintegerȱvariables:ȱ
x + y + 1
Ifȱtheȱresultȱofȱtheȱexpressionȱ x + yȱisȱlargerȱthanȱanȱintegerȱisȱcapableȱofȱstoring,ȱanȱ
overflowȱhasȱoccurred.ȱOnȱsomeȱmachines,ȱtheȱresultȱofȱtheȱtestȱ
ȱ
if( x + y + 1 > 0 )
ȱ
willȱdependȱonȱwhetherȱx + yȱorȱ y + 1ȱisȱevaluatedȱfirst,ȱbecauseȱtheȱoverflowȱoccursȱ
atȱdifferentȱpointsȱinȱeachȱcase.ȱTheȱproblemȱisȱthatȱtheȱprogrammerȱcouldȱnotȱpredictȱ
withȱ certaintyȱ whichȱ wayȱ theȱ compilerȱ wouldȱ evaluateȱ theȱ expression.ȱ Experienceȱ
showedȱthatȱthisȱpracticeȱwasȱaȱbadȱidea,ȱsoȱitȱisȱnotȱallowedȱwithȱANSIȱCȱ
Theȱfollowingȱexpressionȱillustratesȱaȱrelatedȱproblem.ȱ
ȱ
f() + g() + h()
Download at http://www.pin5i.com/
5.5 Summary
119
Althoughȱtheȱleftȱadditionȱmustȱbeȱperformedȱbeforeȱtheȱrightȱaddition,ȱthereȱisȱnoȱ
ruleȱconstrainingȱtheȱorderȱinȱwhichȱtheȱfunctionsȱareȱcalled.ȱIfȱtheirȱexecutionȱbadȱ
sideȱeffects,ȱsuchȱasȱdoingȱanyȱI/Oȱorȱmodifyingȱglobalȱvariables,ȱtheȱresultȱmayȱbeȱ
differentȱforȱdifferentȱordersȱofȱevaluation.ȱIfȱtheȱorderȱmakesȱanyȱdifference,ȱuseȱ
temporaryȱvariablesȱsoȱthatȱeachȱfunctionȱisȱcalledȱinȱaȱseparateȱstatement.ȱ
ȱ
temp = f();
temp += g();
temp += h();
ȱ
ȱ
ȱ
5.5 Summary
ȱ
Cȱ hasȱ aȱ richȱ collectionȱ ofȱ operators.ȱ ȱ Theȱ arithmeticȱ operatorsȱ includeȱ +ȱ (addition),ȱ -ȱ
(subtraction),ȱ *ȱ (multiplication),ȱ /ȱ (division),ȱ andȱ %ȱ (modulo).ȱ ȱ Allȱ ofȱ theseȱ exceptȱ
moduloȱworkȱwithȱbothȱintegerȱandȱfloatingȬpointȱvalues.ȱ
Theȱ <<ȱandȱ >>ȱoperatorsȱperformȱleftȱandȱrightȱshifts,ȱrespectively.ȱTheȱ &,ȱ |ȱandȱ
^ȱoperatorsȱperformȱbitwiseȱAND,ȱOR,ȱandȱXORȱoperations,ȱrespectively.ȱAllȱofȱtheseȱ
operatorsȱrequireȱintegralȱoperands.ȱ
Theȱ =ȱ operatorȱ performsȱ assignment.ȱ Furthermore,ȱ thereȱ areȱ compoundȱ
assignmentȱoperatorsȱforȱallȱofȱtheȱprecedingȱoperators:ȱ
ȱ
+=
<<=
-=
>>=
*=
&=
/=
^=
%=
|=
ȱ
Theȱ compoundȱ assignmentsȱ performȱ theȱ indicatedȱ operationȱ betweenȱ theȱ leftȱ andȱ
rightȱoperands,ȱandȱthenȱassignȱtheȱresultȱtoȱtheȱleftȱoperand.ȱ
Theȱunaryȱoperatorsȱincludeȱ|ȱ(logicalȱNOT),ȱ-ȱ(oneȇsȱcomplement),ȱ-(negative),ȱ
andȱ +ȱ (positive).ȱ Theȱ ++ȱ andȱ --ȱ operatorsȱ incrementȱ andȱ decrementȱ theirȱ operand,ȱ
respectively.ȱ Bothȱ ofȱ theseȱ operatorsȱ haveȱ prefixȱ andȱ postfixȱ forms;ȱ theȱ prefixȱ formȱ
returnsȱtheȱvalueȱofȱtheȱoperandȱafterȱitȱisȱmodified,ȱwhileȱtheȱpostfixȱformȱreturnsȱtheȱ
valueȱbeforeȱtheȱoperandȱisȱmodified.ȱTheȱ &ȱoperatorȱreturnsȱaȱpointerȱtoȱ(theȱaddressȱ
of)ȱitsȱoperand,ȱandȱtheȱ*ȱoperatorȱperformsȱindirectionȱonȱitsȱoperandȱ(whichȱmustȱbeȱ
aȱpointer),ȱ sizeofȱreturnsȱtheȱsizeȱofȱitsȱoperand,ȱmeasuredȱinȱbytes.ȱȱFinally,ȱaȱcastȱisȱ
usedȱtoȱchangeȱtheȱtypeȱofȱanȱexpression.ȱ
Theȱrelationalȱoperatorsȱare:ȱ
ȱ
>
>=
<
<=
!=
==
ȱ
Eachȱoperatorȱreturnsȱeitherȱtrueȱorȱfalseȱdependingȱonȱwhetherȱtheȱoperandsȱhaveȱtheȱ
indicatedȱrelationship.ȱȱTheȱlogicalȱoperatorsȱevaluateȱcomplexȱbooleanȱexpression.ȱȱ
Download at http://www.pin5i.com/
120
Chapter 5 Operators and Expressions
&&ȱ isȱ trueȱ onlyȱ ifȱ bothȱ ofȱ itsȱ operandsȱ areȱ true,ȱ andȱ ||ȱ isȱ falseȱ onlyȱ ifȱ bothȱ ofȱ itsȱ
operandsȱareȱfalse.ȱBothȱofȱtheȱlogicalȱoperatorsȱexertȱcontrolȱoverȱtheȱevaluationȱofȱtheȱ
expressionȱ inȱ whichȱ theyȱ appear.ȱ Ifȱ theȱ resultȱ ofȱ theȱ expressionȱ canȱ beȱ determinedȱ
fromȱtheȱleftȱoperand,ȱthenȱtheȱrightȱoperandȱisȱnotȱevaluated.ȱ
Theȱconditionalȱoperatorȱ ?:ȱtakesȱthreeȱoperands,ȱandȱalsoȱexertsȱcontrolȱoverȱ
expressionȱevaluation.ȱIfȱtheȱfirstȱoperandȱisȱtrue,ȱtheȱresultȱisȱtheȱvalueȱofȱtheȱsecondȱ
operandȱandȱtheȱthirdȱoperandȱisȱnotȱevaluated.ȱOtherwise,ȱtheȱresultȱisȱtheȱvalueȱofȱ
theȱthirdȱoperand,ȱandȱtheȱsecondȱisȱnotȱevaluated.ȱTheȱcommaȱoperatorȱjoinsȱtwoȱorȱ
moreȱ expressions,ȱ whichȱ areȱ evaluatedȱ fromȱ leftȱ toȱ right.ȱ Theȱ resultȱ ofȱ theȱ entireȱ
expressionȱisȱtheȱresultȱofȱtheȱrightmostȱsubexpression.ȱ
Cȱ doesȱ notȱ haveȱ anȱ explicitȱ booleanȱ type,ȱ soȱ integerȱ expressionsȱ areȱ usedȱ toȱ
representȱbooleanȱvalues.ȱHowever,ȱmixingȱbooleanȱvaluesȱwithȱarbitraryȱintegersȱinȱ
expressionsȱ canȱ causeȱ errors.ȱ Toȱ avoidȱ theseȱ errors,ȱ treatȱ eachȱ variableȱ asȱ eitherȱ aȱ
booleanȱorȱanȱinteger.ȱDoȱnotȱuseȱbooleanȱtestsȱonȱintegerȱvariablesȱorȱviceȱversa.ȱ
AnȱLȬvalueȱisȱanȱexpressionȱthatȱcanȱbeȱusedȱonȱtheȱleftȱsideȱofȱanȱassignment;ȱitȱ
denotesȱaȱplaceȱinȱtheȱcomputerȇsȱmemory.ȱAnȱRȬvalueȱdenotesȱaȱvalue,ȱsoȱitȱcanȱonlyȱ
beȱusedȱonȱtheȱrightȱsideȱofȱanȱassignment.ȱEveryȱexpressionȱthatȱisȱanȱLȬvalueȱisȱalsoȱ
anȱRȬvalue,ȱbutȱtheȱreverseȱisȱnotȱtrue.ȱ
Operationsȱ onȱ valuesȱ ofȱ differentȱ typesȱ cannotȱ proceedȱ untilȱ oneȱ ofȱ theȱ
operandsȱ isȱ convertedȱ toȱ theȱ typeȱ ofȱ theȱ other.ȱ Theȱ usualȱ arithmeticȱ conversionsȱ
determineȱ whichȱ operandȱ isȱ converted.ȱ Theȱ precedenceȱ ofȱ operatorsȱ relativeȱ toȱ oneȱ
anotherȱ determinesȱ theȱ orderȱ inȱ whichȱ adjacentȱ operatorsȱ willȱ beȱ evaluated.ȱ ȱ Ifȱ theirȱ
precedenceȱisȱtheȱsame,ȱthenȱtheȱoperatorsȇȱassociativityȱdeterminesȱtheȱorderȱinȱwhichȱ
theyȱwillȱbeȱevaluated.ȱHowever,ȱtheseȱrulesȱdoȱnotȱcompletelyȱdetermineȱtheȱorderȱofȱ
evaluation,ȱandȱtheȱcompilerȱisȱfreeȱtoȱevaluateȱcomplexȱexpressionsȱinȱanyȱorderȱthatȱ
doesȱ notȱ violateȱ theȱ precedenceȱ orȱ associativityȱ rules.ȱ Expressionsȱ whoseȱ resultȱ
dependsȱonȱtheȱorderȱofȱevaluationȱareȱinherentlyȱnonportableȱandȱshouldȱbeȱavoided.ȱ
ȱ
ȱ
ȱ
5.6 Summary of Cautions
ȱ
1. Rightȱshiftsȱonȱsignedȱvaluesȱareȱnotȱportableȱ(pageȱ95).ȱ
ȱ
2. Shiftingȱwithȱnegativeȱshiftȱcountsȱ(pageȱ95).ȱ
ȱ
3. Chainedȱassignmentȱamongȱvariablesȱwithȱdifferentȱsizesȱ(pageȱ98).ȱ
ȱ
Download at http://www.pin5i.com/
5.8 Question
121
4. Usingȱ=ȱratherȱthanȱ==ȱtoȱperformȱaȱcomparisonȱ(pageȱ104).ȱ
5. Usingȱ|ȱinsteadȱofȱ||,ȱorȱ&ȱinsteadȱofȱ&&ȱ(pageȱ105).ȱ
6. ComparingȱdifferentȱnonzeroȱvaluesȱasȱBooleanȱvaluesȱ(pageȱ110).ȱ
7. Theȱlocationȱtoȱwhichȱanȱexpressionȱisȱassignedȱdoesȱnotȱdetermineȱtheȱprecisionȱ
withȱwhichȱtheȱexpressionȱisȱevaluatedȱ(pageȱ113).ȱ
8. Writingȱexpressionsȱwhoseȱvalueȱdependsȱonȱtheȱorderȱofȱevaluationȱ(pageȱ117).ȱ
ȱ
ȱ
ȱ
5.7 Summary of Programming Tips
ȱ
1. Usingȱassignmentȱoperatorsȱmakesȱtheȱprogramȱeasierȱtoȱmaintainȱ(pageȱ99).ȱ
2. Usingȱtheȱconditionalȱoperatorȱratherȱthanȱifȱtoȱsimplifyȱexpressionȱ(pageȱ106).ȱ
3. Usingȱtheȱcommaȱoperatorȱtoȱeliminateȱduplicateȱcodeȱ(pageȱ108).ȱ
4. Doȱnotȱmixȱintegerȱandȱbooleanȱvaluesȱ(pageȱ110).ȱ
ȱ
ȱ
ȱ
5.8 Summary
ȱ
1. Whatȱisȱtheȱtypeȱandȱvalueȱofȱtheȱexpression?ȱ
ȱ
(float)( 25 / 10 )
ȱ
2. Whatȱisȱtheȱresultȱofȱtheȱfollowingȱprogram?ȱ
ȱ
int
func( void )
{
static
return
int
counter = 1;
++counter;
}
int
main()
{
int
answer;
answer = func() – func() * func();
printf( "%d\n", answer );
}
Download at http://www.pin5i.com/
122
Chapter 5 Operators and Expressions
3. Whatȱusesȱcanȱyouȱthinkȱofȱtheȱbitwiseȱandȱshiftingȱoperators?ȱ
4. Isȱ theȱ conditionalȱ operatorȱ fasterȱ orȱ slowerȱ atȱ runȱ timeȱ thanȱ anȱ ifȱ statement?ȱ
Specifically,ȱcompareȱtheseȱtwoȱcodeȱfragments:ȱ
ȱ
if( a > 3 )
i = a > 3 ? b + 1 : c *5;
i = b + 1;
else
i = c * 5;
ȱ
5. Yearsȱthatȱareȱdivisibleȱbyȱfourȱareȱleapȱyearsȱwithȱoneȱexceptionȱ–ȱyearsȱthatȱareȱ
divisibleȱ byȱ 100ȱ areȱ not.ȱ However,ȱ yearsȱ thatȱ areȱ divisibleȱ byȱ 400ȱ areȱ leapȱ years.ȱ
Writeȱ aȱ singleȱ assignmentȱ thatȱ setsȱ leap_yearȱ trueȱ ifȱ theȱ valueȱ inȱ yearȱ isȱ aȱ leapȱ
year,ȱandȱfalseȱifȱitȱisȱnot.ȱ
6. Whichȱoperatorsȱhaveȱsideȱeffects,ȱandȱwhatȱareȱthey?ȱ
7. Whatȱisȱtheȱresultȱofȱthisȱcodeȱfragment?ȱ
ȱ
int
a = 20;
...
if( 1 <= a <= 10 )
printf( "In range\n" );
else
printf( "Out of range\n" );
ȱ
8. Rewriteȱthisȱfragmentȱofȱcodeȱtoȱeliminateȱtheȱredundancies.ȱ
ȱ
a = f1( x );
b = f2( x + a );
for( c = f3( a, b ); c > 0; c = f3( a, b ) ){
statements
a = f1( ++x );
b = f2( x + a );
}
ȱ
9. Doesȱtheȱfollowingȱloopȱaccomplishȱwhatȱitȱisȱtryingȱtoȱdo?ȱ
ȱ
non_zero = 0;
for( i = 0; i < ARRAY_SIZE; i += 1 )
non_zero += array[i];
if( !non_zero )
printf( "Values are all zero\n" );
else
printf( "There are nonzero values\n" );
Download at http://www.pin5i.com/
5.8 Question
123
ȱ
ȱ
10. Givenȱ theȱ variableȱ declarationsȱ andȱ initializationȱ below,ȱ evaluateȱ eachȱ ofȱ theȱ
followingȱ expressions.ȱ Ifȱ anȱ expressionȱ hasȱ sideȱ effectsȱ (thatȱ is,ȱ ifȱ itȱ changesȱ theȱ
valueȱ ofȱ oneȱ orȱ moreȱ variables),ȱ noteȱ themȱ asȱ well.ȱ ȱ Useȱ theȱ initialȱ valuesȱ givenȱ
belowȱ forȱ eachȱ variable,ȱ notȱ theȱ resultsȱ ofȱ theȱ precedingȱ expression,ȱ toȱ evaluateȱ
eachȱexpression.ȱ
ȱ
int
int
int
a = 10, b = -25;
c = 0, d = 3;
e = 20;
ȱ
a.
b
b.
b++
c.
–a
d.
a / 6
e.
a % 6
f.
b % 10
g.
a << 2
h.
b >> 3
i.
a > b
j.
b = a
k.
b == a
l.
a & b
m.
a ^ b
n.
a | b
o.
~b
p.
c && a
q.
c || a
r.
b ? a : c
s.
a += 2
Download at http://www.pin5i.com/
124
Chapter 5 Operators and Expressions
t.
b &= 20
u.
b >>= 3
v.
a %= 6
w.
d = a > b
x.
a = b = c = d
y.
e = d + ( c = a + b ) + c
z.
a + b * 3
aa.
b >> a – 4
bb.
a != b != c
cc.
a == b == c
dd.
d < a < e
ee.
e > a > d
ff.
a – 10 > b + 10
gg.
a & 0x1 == b & 0x1
hh.
a | b << a & b
ii.
a > c || ++a > b
jj.
a > c && ++a > b
kk.
! ~ b++
ll.
b++ & a <= 30
mm.
a – b, c += d, e – c
nn.
a >>= 3 > 0
oo.
a <<= d > 20 ? b && c++ : d—
11. Several expressions are listed below. Determine how each expression is being evaluated by
the compiler, and remove as many parentheses as possible without changing the order of
evaluation.
a.
a + ( b / c )
b.
( a + b ) / c
c.
( a * b ) % 6
d.
a * ( b % 6 )
e.
( a + b ) == 6
Download at http://www.pin5i.com/
5.9 Programming Exercises
f.
!( ( a >= '0' ) && ( a <= '9' ) )
g.
( ( a & 0x2f ) == ( b | 1 ) ) && ( ( ~ c ) > 0 )
h.
( ( a << b ) – 3 ) < ( b << ( a + 3 ) )
i.
~ ( a ++ )
j.
((a == 2) || (a == 4)) && ((b == 2) || (b == 4))
k.
( a & b ) ^ ( a | b )
l.
( a + ( b + c ) )
125
ȱ
12. Howȱ canȱ youȱ determineȱ whetherȱ aȱ rightȱ shiftȱ ofȱ aȱ signedȱ valueȱ isȱ performedȱ onȱ
yourȱmachineȱasȱanȱarithmeticȱorȱaȱlogicalȱshift?ȱ
ȱ
ȱ
ȱ
5.9 Programming Exercises
ȱ
1. Writeȱaȱprogramȱthatȱreadsȱcharactersȱfromȱtheȱstandardȱinputȱandȱwritesȱthemȱtoȱ
theȱ standardȱ output.ȱ Allȱ charactersȱ shouldȱ beȱ writtenȱ exactlyȱ asȱ theyȱ wereȱ readȱ
exceptȱthatȱuppercaseȱlettersȱshouldȱbeȱconvertedȱtoȱlowercase.ȱ
2. Writeȱaȱprogramȱthatȱreadsȱcharactersȱfromȱtheȱstandardȱinputȱandȱwritesȱthemȱtoȱ
theȱ standardȱ output.ȱ ȱ Allȱ charactersȱ shouldȱ beȱ writtenȱ exactlyȱ asȱ theyȱ wereȱ readȱ
exceptȱforȱalphabeticȱcharacters,ȱwhichȱareȱencryptedȱbeforeȱbeingȱwritten.ȱȱ
Theȱ encryptionȱ processȱ isȱ straightforward:ȱ eachȱ letterȱ isȱ changedȱ toȱ whateverȱ
letterȱ appearsȱ 13ȱ placesȱ afterȱ (orȱ before)ȱ itȱ inȱ theȱ alphabet.ȱ Forȱ instance,ȱ anȱ Aȱ isȱ
changedȱtoȱanȱ N,ȱ aȱ Bȱ isȱchangedȱtoȱanȱ O,ȱ aȱ Zȱisȱchangedȱtoȱanȱ M,ȱandȱsoȱforth.ȱȱNoteȱ
thatȱ bothȱ upperȱ andȱ lowercaseȱ lettersȱ mustȱ beȱ converted.ȱ Hint:ȱ Itȱ mayȱ helpȱ toȱ
rememberȱthatȱaȱcharacterȱisȱreallyȱjustȱanȱintegerȱwithȱaȱsmallȱvalue.ȱ
3. Writeȱtheȱfunctionȱ
unsigned int reverse_bits( unsigned in value );
Thisȱfunctionȱreturnsȱtheȱnumberȱconstructedȱbyȱreversingȱtheȱorderȱofȱtheȱbitsȱinȱ
valueȱfromȱleftȱtoȱright.ȱForȱexample,ȱonȱaȱ32Ȭbitȱmachineȱtheȱnumberȱ25ȱcontainsȱ
theseȱbits:ȱ
00000000000000000000000000011001
Theȱfunctionȱshouldȱreturnȱ2,550,136,832,ȱwhichȱisȱcomposedȱofȱtheseȱbits:ȱ
10011000000000000000000000000000
Tryȱ toȱ writeȱ yourȱ functionȱ soȱ thatȱ itȱ doesȱ notȱ dependȱ onȱ theȱ integerȱ sizeȱ ofȱ yourȱ
machine.ȱ
Download at http://www.pin5i.com/
Chapter 5 Operators and Expressions
126
4. Writeȱaȱsetȱofȱfunctionsȱthatȱimplementȱanȱarrayȱofȱbits.ȱȱTheȱfunctionsȱshouldȱhaveȱ
theȱfollowingȱprototypes:ȱ
void set_bit( char bit_array[],
unsigned bit_number );
void clear_bit( char bit_array[],
unsigned bit_number );
void assign_bit( char bit_array[],
unsigned bit_number, int value );
int test_bit( char bit_array[],
unsigned bit_numlber );
Theȱfirstȱargumentȱinȱeachȱofȱtheseȱfunctionsȱisȱaȱcharacterȱarrayȱinȱwhichȱtheȱbitsȱ
areȱactuallyȱstored.ȱȱTheȱsecondȱargumentȱidentifiesȱtheȱbitȱtoȱbeȱaccessed;ȱitȱisȱupȱ
toȱtheȱcallerȱtoȱensureȱthatȱthisȱvalueȱisȱnotȱtooȱlargeȱforȱtheȱarrayȱbeingȱused.ȱ
Theȱfirstȱfunctionȱsetsȱtheȱspecifiedȱbitȱtoȱone,ȱandȱtheȱsecondȱclearsȱit.ȱTheȱthirdȱ
functionȱsetsȱtheȱbitȱtoȱzeroȱifȱtheȱ valueȱisȱzero,ȱotherwiseȱitȱsetsȱtheȱbitȱtoȱone.ȱTheȱ
lastȱfunctionȱreturnsȱtrueȱifȱtheȱspecifiedȱbitȱisȱnonzero,ȱelseȱfalse.ȱ
5. Writeȱ aȱ functionȱ thatȱ willȱ storeȱ aȱ givenȱ valueȱ intoȱ specifiedȱ bitȱ positionsȱ ofȱ anȱ
integer.ȱItȱshouldȱhaveȱthisȱprototype:ȱ
ȱ
int store_bit_field( int original_value,
int value_to_stor,
unsigned starting_bit, unsigned ending_bit );
ȱ
Assumeȱ thatȱ theȱ bitsȱ inȱ anȱ integerȱ areȱ numberedȱ fromȱ rightȱ toȱ left.ȱ Thus,ȱ theȱ
startingȱbitȱpositionȱmayȱnotȱbeȱlessȱthanȱtheȱendingȱbitȱposition.ȱ
Toȱillustrate,ȱthisȱfunctionȱshouldȱreturnȱtheȱfollowingȱvalues:ȱ
ȱ
Original
Value to Store Starting Bit
Ending Bit
Returned
Value
Value
0x0
0xffff
0xffff
0x1
0x123
0x123
4
15
13
4
4
9
0x10
0x123f
0xc7ff
ȱ
Hint:ȱThereȱareȱfiveȱstepsȱinȱstoringȱaȱvalueȱinȱaȱfieldȱofȱbits.ȱ
ȱ
1. Constructȱ aȱ mask,ȱ aȱ valueȱ withȱ onesȱ inȱ theȱ bitȱ positionsȱ thatȱ correspondȱ toȱ
theȱdesiredȱfield.ȱ
Download at http://www.pin5i.com/
5.9 Programming Exercises
127
2. Usingȱtheȱoneȇsȱcomplementȱofȱtheȱmask,ȱclearȱallȱofȱtheȱbitsȱinȱtheȱfield.ȱ
3. Shiftȱtheȱnewȱvalueȱleftȱsoȱthatȱitȱisȱalignedȱinȱtheȱfield.ȱ
4. ANDȱtheȱshiftedȱvalueȱwithȱtheȱmaskȱtoȱensureȱthatȱitȱhasȱnoȱbitsȱoutsideȱofȱ
theȱfield.ȱ
5. ORȱtheȱresultingȱvalueȱintoȱtheȱoriginalȱinteger.ȱ
ȱ
Theȱ mostȱ difficultȱ ofȱ theseȱ tasksȱ isȱ constructingȱ theȱ mask.ȱ Youȱ mightȱ beginȱ byȱ
castingȱtheȱvalueȱ~0ȱtoȱanȱunsignedȱvalueȱandȱthenȱshiftingȱit.ȱ
Download at http://www.pin5i.com/
Download at http://www.pin5i.com/
6
Pointers
Itȇsȱ timeȱ weȱ talkȱ inȱ detailȱ aboutȱ pointers,ȱ becauseȱ weȱ willȱ beȱ usingȱ themȱ constantlyȱ
throughoutȱtheȱrestȱofȱtheȱbook.ȱYouȱmayȱalreadyȱbeȱfamiliarȱwithȱsomeȱorȱallȱofȱtheȱ
backgroundȱ informationȱ discussedȱ inȱ thisȱ chapter.ȱ ȱ Ifȱ youȱ arenȇt,ȱ studyȱ itȱ carefullyȱ
becauseȱyourȱunderstandingȱofȱpointersȱwillȱrestȱonȱthisȱfoundation.ȱ
ȱ
ȱ
ȱ
6.1 Memory and Addresses
ȱ
Asȱ mentionedȱ earlier,ȱ weȱ canȱ viewȱ theȱ computerȇsȱ memoryȱ asȱ aȱ rowȱ ofȱ housesȱ onȱ aȱ
longȱstreet.ȱEachȱhouseȱisȱcapableȱofȱholdingȱdataȱandȱisȱidentifiedȱbyȱaȱhouseȱnumber.ȱ
Thisȱ analogyȱ isȱ usefulȱ butȱ limited.ȱ Computerȱ memoriesȱ areȱ composedȱ ofȱ
millionsȱofȱbits,ȱeachȱcapableȱofȱholdingȱeitherȱtheȱvalueȱ0ȱorȱtheȱvalueȱ1.ȱThisȱlimitedȱ
rangeȱofȱvaluesȱisȱnotȱterriblyȱuseful,ȱsoȱbitsȱareȱusuallyȱgroupedȱtogetherȱandȱtreatedȱ
asȱaȱunitȱinȱorderȱtoȱstoreȱaȱwiderȱrangeȱofȱvalues.ȱHereȱisȱaȱpictureȱofȱaȱfewȱmemoryȱ
locationsȱonȱaȱrealȱmachine.ȱ
ȱ
100ȱ ȱ
101ȱ ȱ
102 ȱ
103 ȱ
104 ȱ
105ȱ ȱ
106 ȱ
107
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Eachȱofȱtheseȱlocationsȱisȱcalledȱaȱbyte,ȱandȱeachȱcontainsȱasȱmanyȱbitsȱasȱnecessaryȱtoȱ
storeȱ aȱ singleȱ character.ȱ Onȱ manyȱ modernȱ machines,ȱ eachȱ byteȱ containsȱ eightȱ bits,ȱ
whichȱcanȱ storeȱunsignedȱintegersȱ fromȱ0ȱ toȱ 255ȱ orȱ signedȱ integersȱfromȱȬ128ȱtoȱ 127.ȱȱ
Theȱ previousȱ diagramȱ doesȱ notȱ showȱ theȱ contentsȱ ofȱ theȱ locations,ȱ thoughȱ everyȱ
locationȱinȱmemoryȱalwaysȱcontainsȱsomeȱvalue.ȱEachȱbyteȱisȱidentifiedȱbyȱanȱaddress,ȱ
whichȱisȱrepresentedȱinȱtheȱdiagramȱbyȱtheȱnumbersȱaboveȱeachȱbox.ȱ
ȱ
Download at http://www.pin5i.com/
130ȱ
Chapter 6 Pointer
Toȱstoreȱevenȱlargerȱvalues,ȱweȱtakeȱtwoȱorȱmoreȱbytesȱandȱtreatȱthemȱasȱifȱtheyȱ
wereȱaȱsingle,ȱlargerȱunitȱofȱmemory.ȱȱForȱexample,ȱmanyȱmachinesȱstoreȱintegersȱinȱ
words,ȱeachȱcomposedȱofȱtwoȱorȱfourȱbytes.ȱȱHereȱareȱtheȱsameȱmemoryȱlocations,ȱthisȱ
timeȱviewedȱasȱfourȬbyteȱwords.ȱ
ȱȱ
100ȱ ȱ
ȱ
ȱ
ȱ
104 ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Becauseȱ theyȱ containȱ moreȱ bits,ȱ eachȱ wordȱ isȱ capableȱ ofȱ holdingȱ unsignedȱ integersȱ
fromȱ 0ȱ toȱ 4,294,967,295ȱ (232ȱ –ȱ 1)ȱ orȱ signedȱ integersȱ fromȱ –2,147,483,648ȱ (–231)ȱ toȱ
2,147,483,647ȱ(231ȱ–ȱ1).ȱ
Noteȱthatȱevenȱthoughȱaȱwordȱcontainsȱfourȱbytes,ȱitȱhasȱonlyȱoneȱaddress.ȱȱItȱisȱ
machineȬdependentȱwhetherȱtheȱaddressȱofȱaȱwordȱisȱtheȱaddressȱofȱtheȱleftmostȱbyteȱ
inȱ theȱ wordȱ orȱ theȱ rightmost.ȱ Boundaryȱ alignmentȱ isȱ anotherȱ hardwareȱ issue.ȱ Onȱ
machinesȱ withȱ thisȱ requirement,ȱ integersȱ canȱ onlyȱ beginȱ withȱ certainȱ bytes,ȱ usuallyȱ
thoseȱwhoseȱaddressesȱareȱmultiplesȱofȱtwoȱorȱfour.ȱButȱtheseȱissuesȱareȱtheȱhardwareȱ
designerȇsȱproblem,ȱandȱ theyȱrarelyȱ affectȱCȱprogrammers.ȱWeȱareȱ interestedȱ inȱ onlyȱ
twoȱissues:ȱ
ȱ
1. Eachȱlocationȱinȱmemoryȱisȱidentifiedȱbyȱaȱuniqueȱaddress.ȱ
2. Eachȱlocationȱinȱmemoryȱcontainsȱaȱvalue.ȱ
ȱ
ȱ
ȱ
6.1.1 Address Versus Contents
ȱ
Hereȱisȱanotherȱexample,ȱthisȱtimeȱshowingȱtheȱcontentsȱofȱfiveȱwordsȱinȱmemory.ȱ
ȱ
100ȱ ȱ
ȱ
104 ȱ
ȱ
108 ȱ
ȱ
112ȱ ȱ
ȱ
116 ȱ
ȱ
ȱ
ȱ
112ȱ
ȱ
ȱ
Ȭ1ȱ
1078523331ȱ
ȱ
ȱ
100ȱ
ȱ
ȱ
108
ȱ
Fiveȱ integerȱ valuesȱ areȱ shown,ȱ eachȱ inȱ itsȱ ownȱ word.ȱ Ifȱ youȱ rememberȱ theȱ addressȱ
whereȱyouȱstoredȱsomeȱvalue,ȱyouȱcanȱuseȱthatȱaddressȱlaterȱtoȱretrieveȱtheȱvalue.ȱ
ȱ
Itȱ isȱ cumbersomeȱ toȱ rememberȱ allȱ ofȱ thoseȱ addresses,ȱ though,ȱ soȱ oneȱ ofȱ theȱ
thingsȱthatȱhighȬlevelȱlanguagesȱprovideȱisȱtheȱabilityȱtoȱreferȱtoȱmemoryȱlocationsȱbyȱ
nameȱ ratherȱ thanȱ byȱ address.ȱ Hereȱ isȱ theȱ sameȱ picture,ȱ thisȱ timeȱ withȱ namesȱ
substitutedȱforȱaddresses.ȱ
Download at http://www.pin5i.com/
6.2 Values and Their Types
ȱ
aȱ
ȱ
ȱ
ȱ
ȱ
112ȱ
bȱ
ȱ
ȱ
ȱ
ȱ
cȱ
Ȭ1ȱ
ȱ
ȱ
1078523331ȱ
dȱ
ȱ
ȱ
ȱ
ȱ
100ȱ
eȱ
ȱ
ȱ
131
ȱ
ȱ
108
ȱ
Ofȱcourse,ȱtheseȱnamesȱareȱwhatȱweȱcallȱvariables.ȱItȱisȱimportantȱtoȱrememberȱthatȱthisȱ
associationȱofȱnamesȱwithȱlocationsȱisȱnotȱ providedȱbyȱtheȱhardware,ȱitȱisȱsomethingȱ
thatȱ theȱ compilerȱ doesȱ forȱ us.ȱ ȱ ȱ Allȱ variablesȱ giveȱ usȱ isȱ aȱ moreȱ convenientȱ wayȱ ofȱ
rememberingȱtheȱaddresses—theȱhardwareȱstillȱaccessesȱmemoryȱlocationsȱusingȱaddresses.ȱ
ȱ
ȱ
ȱ
6.2 Values and Their Types
ȱ
Nowȱletȇsȱlookȱatȱtheȱvaluesȱstoredȱinȱtheseȱlocations.ȱȱTheȱfirstȱtwoȱlocationsȱappearȱtoȱ
containȱintegerȱvalues.ȱȱTheȱthirdȱisȱaȱveryȱlargeȱinteger,ȱandȱtheȱfourthȱandȱfifthȱareȱ
alsoȱintegers.ȱȱOrȱsoȱitȱseems.ȱȱHereȱareȱtheȱdeclarationsȱforȱtheseȱvariables:ȱ
int
a = 112, b = -1;
float c = 3.14;
int
*d = &a;
float *e = &c;
ȱ
Theȱdeclarationsȱconfirmȱthatȱtheȱvariablesȱ aȱandȱ bȱdoȱindeedȱcontainȱintegerȱvalues,ȱ
butȱ claimȱ thatȱ cȱ oughtȱ toȱ containȱ aȱ floatingȬpointȱ value.ȱ ȱ Butȱ cȱ wasȱ shownȱ inȱ theȱ
illustrationȱasȱanȱinteger.ȱȱWell,ȱwhichȱisȱit,ȱanȱintegerȱorȱaȱfloatingȬpointȱnumber?ȱ
Theȱ answerȱ isȱ thatȱ theȱ variableȱ containsȱ aȱ sequenceȱ ofȱ bits,ȱ 0ȇsȱ andȱ 1ȇs.ȱ Theyȱ
couldȱbeȱinterpretedȱeitherȱasȱanȱintegerȱorȱasȱaȱfloatingȬpointȱnumber,ȱdependingȱonȱ
theȱ mannerȱ inȱ whichȱ theyȱ areȱ used.ȱ Ifȱ integerȱ arithmeticȱ instructionsȱ areȱ used,ȱ theȱ
valueȱ isȱ interpretedȱ asȱ anȱ integer.ȱ ȱ Ifȱ floatingȬpointȱ instructionsȱ areȱ used,ȱ itȱ isȱ aȱ
floatingȬpointȱnumber.ȱ
Thisȱfactȱleadsȱtoȱanȱimportantȱconclusion:ȱtheȱtypeȱofȱaȱvalueȱcannotȱbeȱdeterminedȱ
simplyȱ byȱ examiningȱ itsȱ bits.ȱ Toȱ determineȱ itsȱ typeȱ (andȱ thereforeȱ itsȱ value)ȱ youȱ mustȱ
lookȱatȱtheȱwayȱtheȱvalueȱisȱusedȱinȱtheȱprogram.ȱConsiderȱthisȱ32Ȭbitȱvalue,ȱshownȱinȱ
binary:ȱ
01100111011011000110111101100010
ȱ
Hereȱ areȱ aȱ fewȱ ofȱ theȱ manyȱ waysȱ thatȱ theseȱ bitsȱ mightȱ beȱ interpreted.ȱ Theseȱ valuesȱ
wereȱ allȱ obtainedȱ fromȱ aȱ Motorolaȱ 68000Ȭbasedȱ processor.ȱ Anotherȱ systemȱ withȱ
differentȱdataȱformatsȱandȱinstructionsȱwouldȱinterpretȱtheȱsameȱbitsȱdifferently.ȱ
Download at http://www.pin5i.com/
132ȱ
Chapter 6 Pointer
Type
Value(s)
oneȱ32Ȭbitȱintegerȱ
1,735,159,650ȱ
twoȱ16Ȭbitȱintegerȱ
26,476ȱfollowedȱbyȱ28,514ȱ
glob
fourȱcharactersȱ
floatingȬpointȱ
1.116533×1024
machineȱinstructionsȱ
beg .+110ȱfollowedȱby b1e .+102ȱ
ȱ
ȱ
ȱ
Hereȱisȱaȱsingleȱvalueȱthatȱcouldȱbeȱinterpretedȱasȱfiveȱdifferentȱtypes.ȱClearly,ȱ
theȱtypeȱofȱaȱvalueȱisȱnotȱsomethingȱinherentȱinȱtheȱvalueȱitselfȱbutȱdependsȱonȱhowȱitȱ
isȱused.ȱThusȱtoȱgetȱcorrectȱanswers,ȱitȱisȱimportantȱtoȱuseȱtheȱvaluesȱcorrectly.ȱ
Ofȱ course,ȱ theȱ compilerȱ helpsȱ usȱ avoidȱ theseȱ errors.ȱ Declaringȱ cȱ toȱ beȱ aȱ floatȱ
causesȱ theȱ compilerȱ toȱ generateȱ floatingȬpointȱ instructionsȱ whenȱ accessingȱ itȱ andȱ toȱ
complainȱwhenȱweȱattemptȱtoȱaccessȱitȱinȱaȱwayȱthatȱisȱnotȱappropriateȱforȱaȱ float.ȱȱItȱ
isȱ nowȱ obviousȱ thatȱ theȱ diagramȱ showingȱ theȱ valuesȱ wasȱ misleading,ȱ becauseȱ itȱ
showedȱtheȱintegerȱrepresentationȱofȱc.ȱȱTheȱfloatingȬpointȱvalueȱisȱreallyȱ3.14ȱ.ȱ
ȱ
ȱ
ȱ
6.3 Contents of a Pointer Variable
ȱ
Gettingȱbackȱtoȱpointers,ȱletȇsȱlookȱatȱtheȱdeclarationsȱforȱtheȱvariablesȱ dȱandȱ e.ȱȱTheyȱ
areȱ bothȱ declaredȱ asȱ pointers,ȱ andȱ theyȱ areȱ initializedȱ withȱ theȱ addressesȱ ofȱ otherȱ
variables.ȱȱTheȱinitializationȱisȱdoneȱwithȱtheȱ &ȱoperator,ȱwhichȱproducesȱtheȱmemoryȱ
addressȱofȱitsȱoperandȱ(seeȱChapterȱ5).ȱ
ȱ
aȱ
ȱ
ȱ
bȱ
ȱ
ȱ
cȱ
ȱ
ȱ
dȱ
ȱ
ȱ
eȱ
ȱ
ȱ
ȱ
ȱ
112ȱ
ȱ
ȱ
Ȭ1ȱ
ȱ
ȱ
3.14
ȱ
ȱ
100
ȱ
ȱ
108
ȱ
Theȱcontentsȱofȱ dȱandȱ eȱareȱaddressesȱratherȱthanȱintegersȱorȱfloatingȬpointȱnumbers.ȱȱ
Indeed,ȱitȱisȱeasyȱtoȱseeȱfromȱtheȱdiagramȱthatȱtheȱcontentsȱofȱ dȱmatchȱtheȱaddressȱatȱ
whichȱ aȱ isȱ storedȱ andȱ theȱ contentsȱ ofȱ eȱ matchȱ theȱ addressȱ whereȱ cȱ isȱ stored,ȱ asȱ weȱ
wouldȱexpectȱfromȱtheȱinitialization.ȱItȱisȱimportantȱtoȱdistinguishȱbetweenȱtheȱaddressȱ
ofȱtheȱvariableȱdȱ(112)ȱandȱitsȱcontentsȱ(100),ȱandȱtoȱrealizeȱatȱtheȱsameȱtimeȱthatȱthisȱ
numberȱ 100ȱ identifiesȱ (isȱ theȱ addressȱ of)ȱ someȱ otherȱ location.ȱ Atȱ thisȱ pointȱ theȱ
house/streetȱ addressȱ analogyȱ fails,ȱ becauseȱ theȱ contentsȱ ofȱ aȱ houseȱ areȱ neverȱ theȱ
addressȱofȱanotherȱhouse.ȱ
Beforeȱ movingȱ toȱ theȱ nextȱ step,ȱ letȇsȱ lookȱ atȱ someȱ expressionsȱ involvingȱ theseȱ
variables.ȱConsiderȱtheseȱdeclarationsȱonceȱmore.ȱ
Download at http://www.pin5i.com/
6.4 Indirection Operator
133
int
a = 112, b = -1;
float c = 3.14;
int
*d = &a;
float *e = &c;
Whatȱisȱtheȱvalueȱofȱeachȱofȱtheseȱexpressions?ȱ
a
b
c
d
e
ȱ
Theȱfirstȱthreeȱareȱeasy:ȱtheȱvalueȱofȱ aȱisȱ112,ȱtheȱvalueȱofȱ bȱisȱȬ1ȱandȱtheȱvalueȱofȱ cȱisȱ
3.14ȱ,ȱTheȱpointerȱvariablesȱareȱjustȱasȱeasy.ȱTheȱvalueȱofȱ dȱisȱ100,ȱandȱtheȱvalueȱofȱ eȱisȱ
108.ȱIfȱyouȱsaidȱ112ȱandȱ3.14ȱforȱ dȱandȱ e,ȱthenȱyouȇveȱmadeȱaȱveryȱcommonȱmistake.ȱȱ
Theȱfactȱthatȱ dȱandȱ eȱareȱdeclaredȱasȱpointersȱdoesȱnotȱchangeȱhowȱtheseȱexpressionsȱ
areȱ evaluated:ȱ theȱ valueȱ ofȱ aȱ variableȱ isȱ theȱ numberȱ storedȱ inȱ theȱ memoryȱ locationȱ
assignedȱ toȱ theȱ variable.ȱ Itȱ isȱ aȱ mistakeȱ toȱ thinkȱ thatȱ youȱ automaticallyȱ goȱ toȱ theȱ
locationsȱ100ȱandȱ108ȱandȱgetȱtheȱvaluesȱthereȱsimplyȱbecauseȱdȱandȱeȱareȱpointers.ȱTheȱ
valueȱ ofȱ aȱ variableȱ isȱ theȱ numberȱ storedȱ inȱ theȱ memoryȱ locationȱ assignedȱ toȱ theȱ
variable,ȱevenȱforȱpointerȱvariables.ȱ
ȱ
ȱ
ȱ
6.4 Indirection Operator
ȱ
Theȱprocessȱofȱfollowingȱaȱpointerȱtoȱtheȱlocationȱtoȱwhichȱitȱpointsȱisȱcalledȱindirectionȱ
orȱdereferencingȱtheȱpointer.ȱTheȱoperatorȱthatȱperformsȱindirectionȱisȱtheȱunaryȱ *.ȱHereȱ
areȱsomeȱexamplesȱusingȱtheȱdeclarationsȱinȱtheȱpreviousȱsection.ȱ
ȱ
Expression
R-Value
Type
a
112 ȱ
int
int
b
-1 ȱ
c
d
3 .14
100 ȱ
float
int *
e
108 ȱ
112 ȱ
float *
*d
*e
3 .14
int
float
ȱ
Theȱvalueȱofȱ dȱisȱ100.ȱȱȱWhenȱweȱapplyȱtheȱindirectionȱoperatorȱtoȱ d,ȱitȱmeansȱtoȱgoȱtoȱ
locationȱ 100ȱ inȱ memoryȱ andȱ lookȱ thereȱ instead.ȱ ȱ Thus,ȱ theȱ RȬvalueȱ ofȱ *dȱ isȱ 112—theȱ
contentsȱofȱlocationȱ100.ȱȱȱTheȱLȬvalueȱwouldȱbeȱlocationȱ100ȱitself.ȱ
Download at http://www.pin5i.com/
134ȱ
Chapter 6 Pointer
Noteȱtheȱtypesȱofȱtheȱexpressionsȱinȱtheȱ listȱabove:ȱ dȱisȱaȱpointerȱtoȱanȱ integerȱ
andȱdereferencingȱitȱproducesȱanȱinteger.ȱSimilarly,ȱapplyingȱindirectionȱtoȱaȱ float *ȱ
producesȱaȱfloat.ȱ
Normally,ȱ weȱ donȇtȱ knowȱ whichȱ locationȱ theȱ compilerȱ willȱ chooseȱ forȱ eachȱ
variable,ȱ soȱ weȱ cannotȱ predictȱ theirȱ addressesȱ inȱ advance.ȱ Thus,ȱ whenȱ drawingȱ
picturesȱ ofȱ pointersȱ inȱ memory,ȱ itȱ isȱ inconvenientȱ toȱ useȱ theȱ actualȱ numbersȱ forȱ
addresses,ȱsoȱmostȱbooksȱuseȱarrowsȱinstead,ȱlikeȱthis:ȱ
ȱ
ȱ
ȱ
aȱ
ȱ
ȱ
bȱ
ȱ
ȱ
cȱ
ȱ
ȱ
dȱ
ȱ
ȱ
eȱ
ȱ
ȱ
ȱ
ȱ
112ȱ
ȱ
ȱ
Ȭ1ȱ
ȱ
ȱ
3.14
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
However,ȱthisȱnotationȱcanȱbeȱmisleadingȱbecauseȱtheȱarrowsȱcanȱtrickȱyouȱintoȱdoingȱ
indirectionȱ evenȱ whenȱ thereȱ isȱ noȱ indirectionȱ toȱ beȱ done.ȱ Forȱ example,ȱ whatȱ isȱ theȱ
valueȱofȱtheȱexpressionȱdȱfromȱtheȱdiagramȱabove?ȱ
Ifȱyouȱansweredȱ112,ȱthenȱyouȱwereȱtrickedȱbyȱtheȱarrow.ȱTheȱcorrectȱanswerȱisȱ
theȱaddressȱofȱa,ȱnotȱitsȱcontents.ȱȱTheȱarrow,ȱthough,ȱseemsȱtoȱpullȱourȱeyesȱtoȱa.ȱȱItȱisȱ
hardȱnotȱtoȱfollowȱtheȱarrowȱandȱthatȱisȱtheȱproblem:ȱyouȱmustȱnotȱfollowȱtheȱarrowȱ
unlessȱthereȱisȱanȱindirectionȱoperator.ȱ
Theȱmodifiedȱarrowȱnotationȱshownȱbelowȱtriesȱtoȱeliminateȱthisȱproblem.ȱ
ȱ
ȱ
ȱ
aȱ
ȱ
ȱ
bȱ
ȱ
ȱ
cȱ
ȱ
ȱ
dȱ
ȱ
ȱ
eȱ
ȱ
ȱ
ȱ
ȱ
112ȱ
ȱ
ȱ
Ȭ1ȱ
ȱ
ȱ
3.14
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Theȱ intentȱ isȱ toȱ showȱ theȱ valueȱ ofȱ theȱ pointerȱ withoutȱ theȱ strongȱ visualȱ cueȱ thatȱ theȱ
arrowȱisȱaȱpathȱthatȱmustȱbeȱfollowed.ȱIndeed,ȱtheȱvalueȱofȱaȱpointerȱvariableȱisȱsimplyȱ
aȱ collectionȱ ofȱ bitsȱ untilȱ anȱ indirectionȱ isȱ performedȱ onȱ it.ȱ Whenȱ indirectionȱ isȱ
performed,ȱaȱsolidȱarrowȱisȱusedȱtoȱshowȱwhatȱactuallyȱtookȱplace.ȱ
Noteȱthatȱtheȱarrowȱoriginatesȱinsideȱofȱtheȱboxȱbecauseȱitȱrepresentsȱtheȱvalueȱ
storedȱ inȱ thatȱ variable.ȱ Also,ȱ theȱ arrowȱ pointsȱ toȱ aȱ location,ȱ notȱ toȱ theȱ valueȱ inȱ theȱ
location.ȱThisȱnotationȱimpliesȱthatȱfollowingȱtheȱarrowȱwithȱindirectionȱproducesȱanȱ
LȬvalue.ȱItȱdoes,ȱasȱweȱshallȱseeȱlater.
Download at http://www.pin5i.com/
6.5 Uninitialized and Illegal Pointers
135
Althoughȱtheȱarrowȱnotationȱisȱuseful,ȱinȱorderȱtoȱbeȱableȱtoȱuseȱitȱproperlyȱyouȱ
mustȱrememberȱthatȱtheȱvalueȱofȱaȱpointerȱvariableȱisȱjustȱaȱnumber.ȱTheȱarrowȱshowsȱ
theȱvalueȱofȱthisȱnumber,ȱbutȱtheȱarrowȱnotationȱdoesȱnotȱchangeȱtheȱfactȱthatȱitȱisȱjustȱ
aȱnumber.ȱȱAȱpointerȱhasȱnoȱbuiltȬinȱpropertyȱofȱindirection,ȱsoȱyouȱmustȱnotȱfollowȱ
theȱarrowȱunlessȱthereȱisȱartȱindirectionȱoperatorȱthatȱtellsȱyouȱtoȱdoȱso.ȱ
ȱ
ȱ
ȱ
6.5 Uninitialized and Illegal Pointer
ȱ
Theȱcodeȱfragmentȱbelowȱillustratesȱaȱveryȱcommonȱerror:ȱ
ȱ
int
*a;
...
*a = 12;
CAUTION!
ȱ
Theȱ declarationȱ createsȱ aȱ pointerȱ variableȱ calledȱ a,ȱ andȱ theȱ assignmentȱ storesȱ aȱ 12ȱ inȱ
theȱlocationȱtoȱwhichȱaȱpoints.ȱ
ȱ
Butȱwhereȱdoesȱaȱpoint?ȱWeȱdeclaredȱtheȱvariableȱbutȱneverȱinitializedȱit,ȱsoȱthereȱisȱnoȱ
wayȱ toȱ predictȱ whereȱ theȱ valueȱ 12ȱ isȱ beingȱ stored.ȱ Aȱ pointerȱ variableȱ isȱ noȱ differentȱ
fromȱanyȱotherȱvariableȱinȱthisȱrespect.ȱIfȱtheȱvariableȱisȱstatic,ȱitȱisȱinitializedȱtoȱzero;ȱ
butȱifȱtheȱvariableȱisȱautomatic,ȱitȱisȱnotȱinitializedȱatȱall.ȱInȱneitherȱcaseȱdoesȱdeclaringȱ
aȱpointerȱtoȱanȱintegerȱȈcreateȈȱanyȱmemoryȱforȱtheȱstorageȱofȱanȱinteger.ȱ
Soȱwhatȱhappensȱwhenȱthisȱassignmentȱisȱperformed?ȱIfȱyouȇreȱlucky,ȱtheȱinitialȱ
valueȱ ofȱ aȱ willȱ beȱ anȱ illegalȱ address,ȱ andȱ theȱ assignmentȱ willȱ causeȱ aȱ faultȱ thatȱ
terminatesȱ theȱ program.ȱ Onȱ UNIXȱ systems,ȱ thisȱ errorȱ isȱ calledȱ aȱ Ȉsegmentationȱ
violationȈȱorȱaȱȈmemoryȱfault.ȈȱItȱindicatesȱthatȱyouȱhaveȱtriedȱtoȱaccessȱaȱlocationȱthatȱ
isȱ outsideȱ ofȱ theȱ memoryȱ allocatedȱ toȱ yourȱ program.ȱ Onȱ aȱ PCȱ runningȱ Windows,ȱ
indirectionȱ onȱ anȱ unitializedȱ orȱ illegalȱ pointerȱ isȱ oneȱ ofȱ theȱ causesȱ ofȱ Generalȱ
ProtectionȱExceptions.ȱ
Onȱmachinesȱthatȱrequireȱintegersȱtoȱbeȱatȱaȱparticularȱboundary,ȱaccessingȱanȱ
addressȱ thatȱ isȱ onȱ theȱ wrongȱ boundaryȱ forȱ itsȱ typeȱ alsoȱ causesȱ aȱ fault.ȱ Thisȱ errorȱ isȱ
reportedȱonȱUNIXȱsystemsȱasȱaȱȈbusȱerror.Ȉȱ
Aȱmuchȱmoreȱseriousȱproblemȱisȱwhenȱtheȱpointerȱaccidentallyȱcontainsȱaȱlegalȱ
address.ȱ Whatȱ happensȱ thenȱ isȱ simple:ȱ theȱ valueȱ atȱ thatȱ locationȱ isȱ changed,ȱ evenȱ
thoughȱyouȱhadȱnotȱintendedȱtoȱchangeȱit.ȱErrorsȱlikeȱthisȱoneȱareȱveryȱdifficultȱtoȱfind,ȱ
becauseȱtheȱerroneousȱcodeȱmayȱbeȱcompletelyȱunrelatedȱtoȱtheȱcodeȱthatȱisȱsupposedȱ
toȱmanipulateȱtheȱvalueȱthatȱchanged.ȱBeȱextremelyȱcarefulȱthatȱpointerȱvariablesȱareȱ
initializedȱbeforeȱapplyingȱindirectionȱtoȱthem!ȱ
Download at http://www.pin5i.com/
136ȱ
Chapter 6 Pointer
6.6 The Null Pointer
TIP
CAUTION!
ȱ
TheȱStandardȱdefinesȱaȱNULLȱpointerȱasȱaȱpointerȱvalueȱthatȱdoesȱnotȱpointȱtoȱanythingȱ
atȱall.ȱToȱmakeȱaȱpointerȱvariableȱNULLȱyouȱassignȱitȱtheȱvalueȱzero,ȱandȱtoȱtestȱwhetherȱ
aȱ pointerȱ variableȱ isȱ NULLȱ youȱ compareȱ itȱ toȱ zero.ȱ Theȱ choiceȱ ofȱ theȱ valueȱ zeroȱ isȱ aȱ
sourceȱ codeȱ convention;ȱ internally,ȱ theȱ valueȱ forȱ aȱ NULLȱ pointerȱ mightȱ actuallyȱ beȱ
somethingȱ different.ȱ Inȱ thisȱ case,ȱ theȱ compilerȱ takesȱ careȱ ofȱ translatingȱ betweenȱ zeroȱ
andȱtheȱinternalȱvalue.ȱ
Theȱ conceptȱ ofȱ aȱ NULLȱ pointerȱ isȱ quiteȱ usefulȱ becauseȱ itȱ givesȱ youȱ aȱ wayȱ toȱ
specifyȱ thatȱ aȱ particularȱ pointerȱ isȱ notȱ currentlyȱ pointingȱ toȱ anythingȱ atȱ all.ȱ Forȱ
example,ȱaȱfunctionȱwhoseȱjobȱisȱtoȱsearchȱanȱarrayȱforȱaȱspecificȱvalueȱmayȱreturnȱaȱ
pointerȱtoȱtheȱarrayȱelementȱthatȱwasȱfound.ȱȱIfȱnoȱelementȱinȱtheȱarrayȱcontainedȱtheȱ
rightȱvalue,ȱaȱNULLȱpointerȱcouldȱbeȱreturnedȱinstead.ȱThisȱtechniqueȱallowsȱtheȱreturnȱ
valueȱ toȱ conveyȱ twoȱ differentȱ piecesȱ ofȱ information.ȱ First,ȱ wasȱ anȱ elementȱ found?ȱȱ
Second,ȱifȱanȱelementȱwasȱfound,ȱwhichȱoneȱwasȱit?ȱ
ȱ
ȱ
Althoughȱ thisȱ techniqueȱ isȱ commonlyȱ usedȱ inȱ Cȱ programs,ȱ itȱ violatesȱ aȱ softwareȱ
engineeringȱ principle.ȱ Itȱ isȱ riskyȱ forȱ aȱ singleȱ valueȱ toȱ haveȱ twoȱ differentȱ meaningsȱ
becauseȱ itȱ isȱ easyȱ toȱ beȱ confusedȱ laterȱ onȱ asȱ toȱ whichȱ meaningȱ isȱ actuallyȱ intended.ȱȱ
Thisȱproblemȱisȱmoreȱseriousȱinȱlargerȱprogramsȱbecauseȱitȱisȱimpossibleȱtoȱkeepȱtheȱ
entireȱdesignȱinȱyourȱheadȱatȱonce.ȱȱAȱsaferȱstrategyȱisȱtoȱhaveȱtheȱfunctionȱreturnȱtwoȱ
separateȱvalues:ȱtheȱfirstȱ isȱ aȱstatusȱvalueȱ indicatingȱtheȱresultȱofȱtheȱ operations,ȱ andȱ
theȱ secondȱ isȱ theȱ pointer,ȱ whichȱ isȱ usedȱ onlyȱ whenȱ theȱ statusȱ indicatesȱ thatȱ aȱ matchȱ
wasȱfound.ȱ
Dereferencingȱ aȱ pointerȱ givesȱ youȱ theȱ valueȱ toȱ whichȱ itȱ points.ȱ Butȱ theȱ nullȱ
pointer,ȱbyȱdefinition,ȱpointsȱtoȱnothingȱatȱall.ȱTherefore,ȱitȱisȱillegalȱtoȱdereferenceȱaȱ
NULLȱ pointer.ȱ ȱ Beforeȱ dereferencingȱ aȱ pointer,ȱ youȱ mustȱ firstȱ makeȱ sureȱ thatȱ itȱ isȱ notȱ
NULL.ȱ
ȱ
ȱ
Whatȱ happensȱ ifȱ indirectionȱ isȱ performedȱ onȱ aȱ NULLȱ pointer?ȱ Theȱ resultȱ isȱ
implementationȱ dependent.ȱ Onȱ someȱ machines,ȱ theȱ indirectionȱ accessesȱ memoryȱ
locationȱ zero.ȱ Theȱ compilerȱ ensuresȱ thatȱ thereȱ arenȇtȱ anyȱ variablesȱ storedȱ atȱ locationȱ
zero,ȱ butȱ theȱ machineȱ doesnȇtȱ preventȱ youȱ fromȱ accessingȱ orȱ modifyingȱ theȱ location.ȱ
Thisȱ behaviorȱ isȱ veryȱ unfortunate,ȱ becauseȱ theȱ programȱ containsȱ anȱ errorȱ butȱ theȱ
machineȱhidesȱitsȱsymptoms,ȱthusȱmakingȱtheȱerrorȱmoreȱdifficultȱtoȱfind.ȱ
Onȱ otherȱ machines,ȱ indirectionȱ onȱ aȱ NULLȱ pointerȱ causesȱ aȱ faultȱ thatȱ
terminatesȱ theȱ program.ȱ Itȱ isȱ muchȱ betterȱ toȱ announceȱ thatȱ anȱ errorȱ wasȱ discoveredȱ
thanȱtoȱhideȱit,ȱbecauseȱtheȱprogrammerȱcanȱthenȱcorrectȱitȱmoreȱeasily.ȱ
Download at http://www.pin5i.com/
6.7 Pointers, Indirection, and L-values
TIP
137
Itȱ wouldȱ beȱ niceȱ ifȱ allȱ pointerȱ variables,ȱ notȱ justȱ thoseȱ inȱ staticȱ memory,ȱ wereȱ
automaticallyȱ initializedȱ toȱ NULL,ȱ butȱ theyȱ areȱ not.ȱ Noȱ matterȱ howȱ yourȱ machineȱ
handlesȱ dereferencingȱaȱ NULLȱpointer,ȱ itȱisȱaȱgoodȱideaȱ toȱ explicitlyȱ initializeȱ allȱyourȱ
pointerȱvariables.ȱUseȱtheȱdesiredȱaddressȱifȱitȱisȱknown,ȱotherwiseȱinitializeȱthemȱtoȱ
NULL.ȱ Inȱ wellȬwrittenȱ programsȱ thatȱ checkȱ pointersȱ beforeȱ dereferencingȱ them,ȱ thisȱ
initializationȱcanȱsaveȱyouȱaȱlotȱofȱdebuggingȱtime.ȱ
ȱ
ȱ
ȱ
6.7 Pointers, Indirection, and L-values
ȱ
Canȱ expressionsȱ involvingȱ pointersȱ beȱ usedȱ asȱ LȬvalues?ȱ Ifȱ so,ȱ whichȱ ones?ȱ Aȱ quickȱ
checkȱ ofȱ theȱ precedenceȱ chartȱ inȱ Tableȱ 5.1ȱ confirmsȱ thatȱ theȱ operandȱ neededȱ byȱ theȱ
indirectionȱoperatorȱisȱanȱRȬvalue,ȱbutȱtheȱoperatorȱproducesȱanȱLȬvalue.ȱ
Weȇllȱreturnȱtoȱanȱearlierȱexample.ȱGivenȱtheseȱdeclarationsȱ
ȱ
int
int
a;
*d = &a;
ȱ
considerȱtheȱexpressionsȱbelow:ȱ
ȱ
Expression
L-value
Indicated Location
a
a
Yesȱ
d
d
Yesȱ
a
*d
Yesȱ
ȱ
PointerȱvariablesȱmayȱbeȱusedȱasȱLȬvalues,ȱnotȱbecauseȱtheyȱareȱpointersȱbutȱbecauseȱ
theyȱareȱvariables.ȱApplyingȱindirectionȱtoȱaȱpointerȱvariableȱindicatesȱthatȱweȱshouldȱ
followȱtheȱpointer.ȱTheȱindirectionȱidentifiesȱaȱspecificȱmemoryȱlocation,ȱthusȱweȱcanȱ
useȱtheȱresultȱofȱanȱindirectionȱexpressionȱasȱanȱLȬvalue.ȱFollowȱtheseȱstatements:ȱ
ȱ
*d = 10 - *d;
d = 10 - *d;
ƕ ???
ȱ
Theȱfirstȱstatementȱcontainsȱtwoȱindirections.ȱTheȱexpressionȱonȱtheȱrightȱisȱbeingȱusedȱ
asȱanȱRȬvalue,ȱsoȱitȱobtainsȱtheȱvalueȱinȱtheȱlocationȱtoȱwhichȱ dȱpointsȱ(theȱvalueȱofȱ a).ȱȱ
TheȱindirectionȱonȱtheȱleftȱisȱbeingȱusedȱasȱanȱLȬvalue,ȱsoȱtheȱlocationȱtoȱwhichȱdȱpointsȱ
(whichȱisȱa)ȱreceivesȱtheȱnewȱvalueȱcomputedȱbyȱtheȱrightȱside.ȱ
Theȱ secondȱ statementȱ isȱ illegalȱ becauseȱ itȱ specifiesȱ thatȱ anȱ integerȱ quantityȱȱȱȱȱ
(10 - *d)ȱbeȱstoredȱinȱaȱpointerȱvariable.ȱTheȱcompilerȱhelpsȱusȱoutȱbyȱcomplainingȱ
Download at http://www.pin5i.com/
138ȱ
K&R C
Chapter 6 Pointer
whenȱ weȱ tryȱ toȱ useȱ aȱ variableȱ inȱ aȱ contextȱ thatȱ isȱ inconsistentȱ withȱ itsȱ type.ȱ Theseȱ
warningȱandȱerrorȱmessagesȱareȱyourȱfriends.ȱTheȱcompilerȱisȱhelpingȱyouȱbyȱproducingȱ
them.ȱAlthoughȱweȱwouldȱallȱpreferȱnotȱtoȱhaveȱtoȱdealȱwithȱanyȱsuchȱmessages,ȱitȱisȱaȱ
goodȱideaȱtoȱcorrectȱtheȱerrorsȱrightȱaway,ȱespeciallyȱwithȱwarningȱmessagesȱthatȱdoȱ
notȱabortȱtheȱcompilation.ȱItȱisȱaȱlotȱeasierȱtoȱfixȱproblemsȱwhenȱtheȱcompilerȱtellsȱyouȱ
exactlyȱ whereȱ theyȱ areȱ thanȱ itȱ isȱ toȱ debugȱ theȱ programȱ later;ȱ theȱ debuggerȱ cannotȱ
pinpointȱsuchȱproblemsȱnearlyȱasȱwellȱasȱtheȱcompiler.ȱ
ȱ
OldȱCȱcompilersȱdidȱnotȱcomplainȱwhenȱpointerȱandȱintegerȱvaluesȱwereȱintermixed.ȱ
However,ȱweȱknowȱbetterȱtheseȱdays.ȱȱItȱisȱonlyȱrarelyȱusefulȱtoȱconvertȱanȱintegerȱtoȱaȱ
pointerȱorȱviceȱversa.ȱUsuallyȱsuchȱconversionsȱareȱunintentionalȱerrors.ȱ
ȱ
ȱ
ȱ
6.8 Pointers, Indirection, and Variables
ȱ
Ifȱyouȱthinkȱyouȇveȱmasteredȱpointers,ȱtakeȱaȱlookȱatȱthisȱexpressionȱandȱseeȱifȱyouȱcanȱ
figureȱoutȱwhatȱitȱdoesȱ
ȱ
*&a = 25;
ȱ
Ifȱyouȱsaidȱthatȱitȱassignsȱtheȱvalueȱ25ȱtoȱtheȱvariableȱa,ȱcongratulations—ȱyouȇreȱright.ȱ
Letȇsȱ unravelȱ theȱ expression.ȱ First,ȱ theȱ &ȱ operatorȱ generatesȱ theȱ addressȱ whereȱ theȱ
variableȱ aȱisȱstored,ȱwhichȱisȱaȱpointerȱconstant.ȱ(Noteȱthatȱitȱisȱnotȱnecessaryȱtoȱknowȱ
theȱ actualȱ valueȱ ofȱ theȱ constantȱ inȱ orderȱ toȱ useȱ it.)ȱ Then,ȱ theȱ *ȱ operatorȱ goesȱ toȱ theȱ
locationȱwhoseȱaddressȱisȱgivenȱasȱtheȱoperand.ȱȱInȱthisȱexpression,ȱtheȱoperandȱisȱtheȱ
addressȱofȱa,ȱsoȱtheȱvalueȱ25ȱisȱstoredȱinȱa.ȱ
Howȱisȱthisȱstatementȱanyȱdifferentȱfromȱjustȱsayingȱa * 25;ȱ?ȱFunctionally,ȱitȱisȱ
identical.ȱ Itȱ does,ȱ however,ȱ involveȱ moreȱ operations.ȱ Unlessȱ theȱ compilerȱ (orȱ
optimizer)ȱrealizesȱwhatȱyouȇreȱdoingȱandȱdiscardsȱtheȱextraȱoperations,ȱtheȱresultingȱ
objectȱcodeȱwillȱbeȱlargerȱandȱslower.ȱWorse,ȱtheȱadditionalȱoperatorsȱmakeȱtheȱsourceȱ
codeȱ harderȱ toȱ read.ȱ Forȱ theseȱ reasons,ȱ noȱ oneȱ everȱ (intentionally)ȱ usesȱ expressionsȱ
suchȱasȱ*&a.ȱ
ȱ
ȱ
ȱ
6.9 Pointer Constants
ȱ
Letȇsȱ examineȱ anotherȱ expression.ȱ Assumingȱ thatȱ theȱ variableȱ aȱ isȱ storedȱ atȱ locationȱ
100,ȱwhatȱdoesȱthisȱstatementȱdo?ȱ
ȱ
ȱ
*100 = 25;
Download at http://www.pin5i.com/
6.10 Pointers to Pointers
139
Itȱlooksȱlikeȱtheȱstatementȱassignsȱ25ȱtoȱ a,ȱbecauseȱ aȱisȱtheȱvariableȱatȱlocationȱ100.ȱButȱ
notȱso!ȱTheȱstatementȱisȱactuallyȱinvalidȱbecauseȱdieȱliteralȱ100ȱisȱofȱtypeȱinteger,ȱandȱ
indirectionȱcanȱonlyȱbeȱperformedȱonȱexpressionsȱofȱtypeȱpointer.ȱIfȱyouȱreallyȱwantȱtoȱ
storeȱ25ȱinȱlocationȱ100,ȱyouȱmustȱuseȱaȱcast.ȱ
ȱ
*(int *)100 = 25;
ȱ
Theȱcastȱconvertsȱtheȱvalueȱ100ȱfromȱanȱȈintegerȈȱtoȱaȱȈpointerȱtoȱanȱinteger.ȈȱItȱisȱlegalȱ
toȱapplyȱindirectionȱtoȱthisȱexpression,ȱsoȱifȱ aȱisȱstoredȱinȱlocationȱ100,ȱthisȱstatementȱ
storesȱ theȱ valueȱ 25ȱ inȱ a.ȱ However,ȱ youȱ willȱ needȱ thisȱ techniqueȱ rarely,ȱ ifȱ ever!ȱ Why?ȱ Asȱ
mentionedȱ earlier,ȱ youȱ usuallyȱ cannotȱ predictȱ whereȱ inȱ memoryȱ theȱ compilerȱ willȱ
chooseȱtoȱputȱanyȱspecificȱvariable,ȱsoȱyouȱdonȇtȱknowȱitsȱaddressȱaheadȱofȱtime.ȱItȱisȱ
easyȱtoȱobtainȱtheȱaddressȱofȱaȱvariableȱwithȱtheȱ&ȱoperatorȱbutȱtheȱexpressionȱwonȇtȱbeȱ
evaluatedȱ untilȱ theȱ programȱ executes,ȱ soȱ itȱ isȱ tooȱ lateȱ toȱ copyȱ theȱ answerȱ intoȱ theȱ
sourceȱcodeȱasȱaȱliteralȱconstant.ȱ
AȱȱTheȱonlyȱreasonȱthisȱexampleȱisȱusefulȱisȱforȱtheȱfewȱtimesȱwhenȱyouȱneedȱtoȱ
accessȱ aȱ specificȱ locationȱ inȱ memoryȱ byȱ itsȱ address,ȱ whichȱ isȱ neverȱ doneȱ toȱ accessȱ aȱ
variableȱ butȱ ratherȱ toȱ accessȱ theȱ hardwareȱ itself.ȱ Forȱ example,ȱ anȱ operatingȱ systemȱ
needsȱ toȱ communicateȱ withȱ theȱ inputȱ andȱ outputȱ deviceȱ controllersȱ toȱ startȱ I/Oȱ
operationsȱ andȱ toȱ obtainȱ resultsȱ ofȱ priorȱ operations.ȱ Onȱ someȱ machines,ȱ
communicationȱwithȱdeviceȱcontrollersȱisȱaccomplishedȱbyȱreadingȱandȱwritingȱvaluesȱ
atȱspecificȱmemoryȱaddresses.ȱInsteadȱofȱaccessingȱmemory,ȱhowever,ȱtheseȱoperationsȱ
accessȱtheȱdeviceȱcontrollerȱinterface.ȱTheseȱlocations,ȱthen,ȱmustȱbeȱaccessedȱviaȱtheirȱ
addresses,ȱwhichȱareȱknownȱinȱadvance.ȱ
Chapterȱ 3ȱ mentionedȱ thatȱ thereȱ isȱ noȱ builtȬinȱ notationȱ forȱ writingȱ pointerȱ
constants.ȱInȱtheȱrareȱinstancesȱwhenȱtheyȱareȱrequired,ȱtheyȱareȱgenerallyȱwrittenȱasȱ
integerȱliteralsȱandȱconvertedȱtoȱtheȱproperȱtypeȱwithȱaȱcast. 28
ȱ
ȱ
ȱ
6.10 Pointers to Pointers
ȱ
Weȱwillȱspendȱonlyȱaȱbriefȱmomentȱhereȱonȱanȱexampleȱthatȱsuggestsȱtopicsȱtoȱcome.ȱ
Considerȱtheseȱdeclarations:ȱ
ȱ
int
int
a = 12;
*b = &a;
ȱ Implementationsȱ forȱ segmentedȱ machines,ȱ suchȱ asȱ theȱ Intelȱ 80x86,ȱ mayȱ provideȱ aȱ macroȱ toȱ constructȱ pointerȱ constants.ȱȱ
Theȱmacroȱconvertsȱaȱsegmentȱandȱoffsetȱpairȱintoȱtheȱpointerȱvalue.ȱ
28
Download at http://www.pin5i.com/
140ȱ
Chapter 6 Pointer
Theyȱallocateȱmemoryȱasȱshownȱinȱtheȱfollowingȱdiagram:ȱ
ȱ
aȱ
ȱ
ȱ
ȱ
bȱ
12ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Supposeȱweȱhadȱaȱthirdȱvariableȱcalledȱcȱandȱinitializedȱitȱwithȱthisȱstatement;ȱ
ȱ
c = &b;
ȱ
Hereȱisȱwhatȱmemoryȱwouldȱlookȱlike:ȱ
ȱ
aȱ
ȱ
ȱ
ȱ
bȱ
ȱ
ȱ
12ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Theȱquestionȱis;ȱwhatȱisȱtheȱtypeȱofȱc?ȱClearlyȱitȱisȱaȱpointer,ȱbutȱwhatȱdoesȱitȱpointȱto?ȱ
Theȱ variableȱ bȱ isȱ aȱ Ȉpointerȱ toȱ anȱ integer,Ȉȱ soȱ anythingȱ thatȱ pointsȱ toȱ bȱ mustȱ beȱ aȱ
pointerȱtoȱaȱȈpointerȱtoȱanȱinteger,Ȉȱorȱmoreȱgenerally,ȱaȱpointerȱtoȱaȱpointer.ȱ
Isȱthisȱlegal?ȱYes!ȱAȱpointerȱvariableȱisȱlikeȱanyȱotherȱvariableȱinȱthatȱitȱoccupiesȱ
aȱspecificȱlocationȱinȱmemory,ȱsoȱitȱmakesȱsenseȱthatȱweȱcanȱobtainȱitsȱaddressȱwithȱtheȱ
&ȱoperator. 29
Howȱwouldȱthisȱvariableȱbeȱdeclared?ȱTheȱdeclarationȱ
ȱ
int
**c = &b;
ȱ
saysȱ thatȱ theȱ expressionȱ **cȱisȱ ofȱtypeȱ int.ȱTableȱ6.1ȱlistsȱsomeȱ expressionsȱthatȱ mayȱ
helpȱillustrateȱthisȱconcept;ȱtheȱexpressionsȱassumeȱtheseȱdeclarations.ȱ
ȱ
int
int
int
a = 12;
*b = &a;
**c = &b;
ȱ
Theȱonlyȱnewȱexpressionȱinȱtheȱtableȱisȱtheȱlastȱone,ȱsoȱletȇsȱunravelȱit.ȱTheȱ *ȱoperatorȱ
hasȱ rightȬtoȬleftȱ associativity,ȱ soȱ thisȱ expressionȱ isȱ equivalentȱ toȱ *(*c).ȱ Weȱ mustȱ
evaluateȱitȱfromȱtheȱinsideȱout.ȱ*cȱtakesȱusȱcoȱtheȱlocationȱtoȱwhichȱcȱpoints,ȱwhichȱweȱ
knowȱtoȱbeȱtheȱvariableȱb.ȱTheȱsecondȱindirectionȱthenȱtakesȱusȱtoȱwhereȱthisȱlocationȱȱ
29
ȱExceptȱvariablesȱdeclaredȱregister.ȱ
Download at http://www.pin5i.com/
6.11 Pointer Expressions
Expression
Equivalent expression(s)
a
b
*b
c
*c
**c
12
&a
a, 12
&b
b, &a
*b, a, 12
141
ȱ
Tableȱ6.1ȱDoubleȱindirectionȱ
ȱ
ȱ
ȱ
points,ȱwhichȱisȱa.ȱTheȱonlyȱthingȱtrickyȱaboutȱpointersȱtoȱpointersȱisȱkeepingȱallȱofȱtheȱ
arrowsȱ straightȱ andȱ rememberingȱ thatȱ anȱ arrowȱ isȱ followedȱ onlyȱ ifȱ anȱ indirectionȱ
operatorȱcausesȱit.ȱ
ȱ
ȱ
ȱ
6.11 Pointer Expressions
ȱ
Nowȱ letȇsȱ takeȱ aȱ lookȱ atȱ aȱ varietyȱ ofȱ pointerȱ expressionsȱ andȱ seeȱ howȱ theyȱ areȱ
evaluatedȱ whenȱ usedȱ bothȱ asȱ RȬvaluesȱ andȱ LȬvalues.ȱ Someȱ ofȱ theseȱ expressionsȱ areȱ
commonlyȱ used,ȱ batȱ notȱ all.ȱ Theȱ purposeȱ ofȱ thisȱ exerciseȱ isȱ notȱ toȱ giveȱ youȱ aȱ
ȈcookbookȈȱofȱexpressionsȱbutȱratherȱtoȱbuildȱyourȱskillȱinȱreadingȱandȱwritingȱthem.ȱȱ
First,ȱletȇsȱsetȱtheȱstageȱwithȱsomeȱdeclarations.ȱ
ȱ
char
char
ch = 'a';
*cp = &ch;
ȱ
Weȱnowȱhaveȱtwoȱvariablesȱinitializedȱlikeȱthis:ȱ
ȱ
cp
ch
a
?
ȱ
ȱ
TheȱmemoryȱLocationȱthatȱfollowsȱ chȱisȱalsoȱshownȱbecauseȱsomeȱofȱtheȱexpressionsȱ
thatȱ weȱ evaluateȱ willȱ accessȱ it,ȱ albeitȱ erroneously.ȱ Becauseȱ weȱ donȇtȱ knowȱ whatȱ itsȱ
initialȱvalueȱis,ȱaȱquestionȱmarkȱisȱshown.ȱ
Letȇsȱfigureȱoutȱanȱeasyȱoneȱfirstȱtoȱgetȱtheȱballȱrolling.ȱTheȱexpressionȱis:ȱ
ȱ
ch
Download at http://www.pin5i.com/
142ȱ
Chapter 6 Pointer
WhenȱusedȱasȱanȱRȬvalue,ȱthisȱexpressionȱhasȱtheȱvalueȱ'a'ȱandȱisȱillustratedȱas:ȱ
ȱ
cp
ch
a
?
ȱ
Theȱheavyȱovalȱindicatesȱthatȱtheȱvalueȱinȱtheȱvariableȱchȱisȱtheȱvalueȱofȱtheȱexpression.ȱ
Butȱ whenȱ thisȱ expressionȱ isȱ usedȱ asȱ anȱ LȬvalue,ȱ itȱ isȱ theȱ locationȱ thatȱ countsȱ ratherȱ
thanȱtheȱvalueȱthatȱitȱcontains,ȱsoȱitȱisȱillustratedȱdifferently:ȱ
ȱ
cp
ch
?
ȱ
Hereȱtheȱlocationȱisȱmarkedȱwithȱaȱheavyȱbox,ȱindicatingȱthatȱtheȱlocationȱisȱtheȱresult.ȱȱ
Additionally,ȱ itsȱ valueȱ isȱ notȱ shownȱ becauseȱ itȱ isnȇtȱ important;ȱ indeed,ȱ theȱ valueȱ isȱ
aboutȱ toȱ beȱ replacedȱ byȱ someȱ newȱ value.ȱ Theȱ remainingȱ expressionsȱ areȱ shownȱ inȱ aȱ
tabularȱform.ȱȱEachȱtableȱisȱfollowedȱbyȱaȱdescriptionȱofȱtheȱexpressionȇsȱevaluation.ȱ
ȱ
ȱ
ȱ
Expression
R-value
L-value
cp
ch
a
&ch
?
illegalȱ
ȱ
ȱ
ȱ
AsȱanȱRȬvalue,ȱthisȱexpressionȇsȱvalueȱisȱtheȱaddressȱofȱtheȱvariableȱ ch.ȱNoteȱthatȱthisȱ
valueȱ isȱ theȱ sameȱ asȱ theȱ valueȱ storedȱ inȱ theȱ variableȱ cp,ȱ butȱ theȱ expressionȱ doesnȇtȱ
mentionȱ cpȱsoȱthatȇsȱnotȱwhereȱtheȱvalueȱconiesȱfrom.ȱThusȱtheȱovalȱisȱnotȱaroundȱtheȱ
arrowȱ inȱ cp.ȱ Theȱ secondȱ questionȱ is,ȱ whyȱ isȱ thisȱ expressionȱ notȱ aȱ legalȱ LȬvalue?ȱ Theȱ
precedenceȱtableȱshowsȱthatȱtheȱ &ȱoperatorȱproducesȱanȱRȬvalueȱasȱaȱresult,ȱandȱtheyȱ
cannotȱbeȱusedȱasȱLȬvalues.ȱButȱwhy?ȱTheȱanswerȱisȱeasy.ȱWhenȱtheȱexpressionȱ &chȱisȱ
evaluated,ȱ whereȱ isȱ theȱ resultȱ heldȱ inȱ theȱ computer?ȱ Itȱ mustȱ beȱ somewhere,ȱ butȱ youȱ
haveȱnoȱwayȱofȱknowingȱwhere.ȱTheȱexpressionȱdoesȱnotȱidentifyȱanyȱspecificȱlocationȱ
inȱtheȱmachineȇsȱmemory,ȱandȱthusȱitȱisȱnotȱaȱlegalȱLȬvalue.ȱ
Download at http://www.pin5i.com/
6.11 Pointer Expressions
143
ȱ
Expression
R-value
L-value
cp
ch
cp
cp
a
ch
a
?
?
ȱ
ȱ
ȱ
Youȇveȱseenȱthisȱexpressionȱbefore.ȱItsȱRȬvalueȱisȱtheȱvalueȱinȱ cp,ȱasȱindicated.ȱTheȱLȬ
valueȱisȱtheȱlocationȱcp.ȱThereȱisȱnoȱindirectionȱinȱthisȱexpression,ȱsoȱyouȱdoȱnotȱfollowȱ
theȱarrow.ȱ
ȱ
ȱ
ȱ
ȱ
Expression
R-value
L-value
cp
&cp
ch
a
ȱ
ȱ
illegalȱ
?
ȱ
ȱ
ȱ
Thisȱexampleȱisȱsimilarȱtoȱ &chȱexceptȱthatȱthisȱtimeȱweȱtakeȱtheȱaddressȱofȱtheȱpointerȱ
variable.ȱTheȱtypeȱofȱthisȱresultȱisȱpointerȱtoȱpointerȱtoȱcharacter.ȱOnceȱagain,ȱtheȱvalueȱ
isȱstoredȱinȱanȱunidentifiableȱlocationȱsoȱtheȱexpressionȱisȱnotȱaȱlegalȱLȬvalue.ȱ
ȱ
ȱ
ȱ
ȱ
Expression
R-value
L-value
cp
*cp
cp
ch
a
?
ch
?
ȱ
ȱ
ȱ
ȱ
Nowȱ weȱ haveȱ addedȱ indirectionȱ soȱ theȱ resultsȱ shouldȱ comeȱ asȱ noȱ surprise.ȱ Butȱ theȱ
nextȱfewȱexpressionsȱbeginȱtoȱgetȱmoreȱinteresting.ȱ
Download at http://www.pin5i.com/
Chapter 6 Pointer
144ȱ
ȱ
Expression
R-value
cp
L-value
ch
a
?
*cp + 1
illegalȱ
ȱ
+
1
b
ȱ
ȱ
Thisȱ diagramȱ isȱ moreȱ involved,ȱ soȱ letȇsȱ doȱ itȱ stepȱ byȱ step.ȱ ȱ Thereȱ areȱ twoȱ operatorsȱ
here. *ȱhasȱaȱhigherȱprecedenceȱthanȱ +,ȱsoȱtheȱindirectionȱisȱperformedȱfirstȱ(asȱshownȱ
byȱ theȱ solidȱ arrowȱ fromȱ cpȱ toȱ ch),ȱ whichȱ getsȱ usȱ itsȱ valueȱ (indicatedȱ byȱ theȱ dottedȱ
oval).ȱ ȱ Aȱ copyȱ ofȱ thisȱ valueȱ isȱ takenȱ andȱ addedȱ toȱ one,ȱ givingȱ theȱ characterȱ 'b'ȱ asȱ aȱ
result.ȱTheȱdottedȱlinesȱshowȱtheȱmovementȱofȱdataȱasȱtheȱexpressionȱisȱevaluated.ȱTheȱ
finalȱresultȱdoesȱnotȱresideȱinȱanyȱidentifiableȱlocation,ȱsoȱthisȱexpressionȱisȱnotȱaȱlegalȱ
LȬvalue.ȱTheȱprecedenceȱtableȱconfirmsȱthatȱtheȱresultȱofȱ+ȱisȱnotȱanȱLȬvalue.ȱ
ȱ
Expression
R-value
L-value
cp
cp
ch
a
ch
a
?
*(cp+1)
ȱ
1
+
1
+
ȱ
Inȱthisȱexample,ȱweȇveȱaddedȱparenthesesȱtoȱtheȱpreviousȱexpression.ȱTheȱparenthesesȱ
forceȱtheȱadditionȱtoȱgoȱfirst,ȱwhichȱaddsȱoneȱtoȱaȱcopyȱofȱtheȱaddressȱinȱcp.ȱȱTheȱresultȱ
soȱ farȱ isȱ theȱ pointerȱ inȱ theȱ dottedȱ oval.ȱ ȱ Theȱ indirectionȱ followsȱ thisȱ arrowȱ toȱ theȱ
locationȱ justȱ afterȱ ch,ȱ andȱ theȱ RȬvalueȱ ofȱ theȱ expressionȱ isȱ theȱ valueȱ inȱ thatȱ location.ȱȱ
TheȱLȬvalue,ȱofȱcourse,ȱisȱtheȱlocationȱitself.ȱ
Thereȱ isȱ anȱ importantȱ pointȱ toȱ beȱ learnedȱ here.ȱ Noteȱ thatȱ theȱ resultȱ ofȱ theȱ
pointerȱadditionȱ isȱ anȱ RȬvalueȱ becauseȱ itȱ doesȱnotȱresideȱ inȱanyȱidentifiableȱlocation.ȱ
Withoutȱ theȱ indirection,ȱ thisȱ expressionȱ wouldȱ notȱ beȱ aȱ legalȱ LȬvalue.ȱ However,ȱ theȱ
indirectionȱfollowsȱtheȱpointerȱtoȱaȱspecificȱlocation.ȱThus,ȱ *(cp + 1)ȱmayȱbeȱusedȱasȱ
anȱLȬvalueȱevenȱthoughȱ cp + lȱmayȱnot.ȱTheȱindirectionȱoperatorȱisȱoneȱofȱonlyȱaȱfewȱ
whoseȱresultȱisȱanȱLȬvalue.ȱ
Butȱ theȱ expressionȱ isȱ accessingȱ theȱ locationȱ afterȱ ch;ȱ howȱ canȱ weȱ tellȱ whatȱ
residesȱthere?ȱInȱgeneral,ȱweȱcanȇt,ȱsoȱexpressionsȱlikeȱthisȱoneȱareȱillegal.ȱȱIȱdiscussȱthisȱ
topicȱinȱmoreȱdepthȱlaterȱinȱthisȱchapter.ȱ
Download at http://www.pin5i.com/
6.11 Pointer Expressions
ȱ
Expression
R-value
cp
145
L-value
ch
a
?
++cp
illegalȱ
ȱ
ȱ
ȱ
Theȱ ++ȱandȱ --ȱoperatorsȱareȱfrequentlyȱusedȱwithȱpointerȱvariables,ȱsoȱitȱisȱimportantȱ
toȱ understandȱ themȱ inȱ thisȱ context.ȱ Inȱ thisȱ expression,ȱ weȱ incrementȱ theȱ pointerȱ
variableȱ cp.ȱ(Toȱunclutterȱtheȱdiagrams,ȱweȱnoȱlongerȱshowȱtheȱaddition.)ȱTheȱresultȱisȱ
aȱcopyȱofȱtheȱincrementedȱpointer,ȱbecauseȱtheȱprefixȱ ++ȱincrementsȱbeforeȱusingȱtheȱ
valueȱ inȱ theȱ surroundingȱ expression.ȱ Theȱ copyȱ isȱ notȱ storedȱ inȱ anyȱ identifiableȱ
location,ȱsoȱitȱisȱnotȱaȱlegalȱLȬvalue.ȱ
ȱ
Expression
R-value
L-value
cp
ch
a
?
cp++
illegalȱ
ȱ
ȱ
ȱ
ȱ
Theȱpostfixȱ++ȱproducesȱtheȱsameȱvalueȱinȱcp,ȱbutȱitȱincrementsȱafterȱtheȱcopyȱisȱmade.ȱȱ
Thus,ȱtheȱvalueȱofȱtheȱexpressionȱisȱaȱcopyȱofȱtheȱoriginalȱvalueȱofȱcp.ȱ
NeitherȱofȱtheȱpreviousȱtwoȱexpressionsȱareȱlegalȱLȬvalues.ȱButȱtheyȱwouldȱbeȱifȱ
weȱaddȱindirection,ȱasȱillustratedȱinȱtheȱnextȱtwoȱexpressions.ȱ
ȱ
ȱ
Expression
R-value
L-value
cp
cp
ch
a
ch
a
?
?
*++cp
ȱ
ȱ
ȱ
ȱ
ȱ
Here,ȱindirectionȱisȱappliedȱtoȱ theȱcopyȱofȱtheȱincrementedȱpointer,ȱsoȱtheȱRȬvalueȱisȱ
theȱvalueȱinȱtheȱlocationȱfollowingȱchȱandȱtheȱLȬvalueȱisȱthatȱlocation.ȱ
Download at http://www.pin5i.com/
146ȱ
Chapter 6 Pointer
Expression
R-value
cp
L-value
cp
ch
a
ch
a
?
?
*cp++
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Usingȱ theȱ postfixȱ ++ȱ yieldsȱ aȱ differentȱ result:ȱ theȱ RȬvalueȱ andȱ LȬvalueȱ relateȱ toȱ theȱ
variableȱ ch,ȱwhichȱisȱwhereȱ cpȱoriginallyȱpointed.ȱAgain,ȱtheȱpostfixȱoperatorȱusesȱtheȱ
originalȱ valueȱ ofȱ itsȱ operandȱ inȱ theȱ surroundingȱ expression.ȱ Theȱ combinationȱ ofȱ
indirectionȱandȱtheȱpostfixȱ ++ȱisȱoftenȱmisunderstood.ȱȱTheȱprecedenceȱtableȱindicatesȱ
thatȱ theȱ postfixȱ ++ȱ hasȱ aȱ higherȱ precedenceȱ thanȱ theȱ *,ȱ yetȱ itȱ appearsȱ asȱ itȱ theȱ
indirectionȱ isȱ beingȱ performedȱ first.ȱ ȱ Inȱ fact,ȱ thereȱ areȱ threeȱ stepsȱ involved:ȱ (1)ȱ ++ȱ
makesȱ aȱ copyȱ ofȱ cp,ȱ (2)ȱ theȱ ++ȱ incrementsȱ cp,ȱ andȱ finally,ȱ (3)ȱ theȱ indirectionȱ isȱ
performedȱonȱtheȱcopy.ȱ
ȱ
Thisȱ expressionȱ isȱ oftenȱ usedȱ inȱ loopȱ toȱ sequentiallyȱ examineȱ theȱ contentsȱ ofȱ
someȱ arrayȱ toȱ whichȱ theȱ pointerȱ hasȱ previouslyȱ beenȱ initialized.ȱ Someȱ exampleȱ areȱ
shownȱlaterȱinȱthisȱchapter.ȱ
ȱ
ȱ
ȱ
ȱ
Expression
R-value
L-value
cp
ch
b
++*cp
ȱ
ȱ
ȱ
?
illegalȱ
b
ȱ
ȱ
Inȱthisȱexpression,ȱtheȱindirectionȱisȱevaluatedȱfirstȱdueȱtoȱtheȱrightȬtoȬleftȱassociativityȱ
ofȱtheseȱoperators.ȱTherefore,ȱtheȱlocationȱtoȱwhichȱcpȱpointsȱisȱincremented;ȱtheȱresultȱ
isȱaȱcopyȱofȱtheȱincrementedȱvalue.ȱ
Theȱ lastȱ threeȱ expressionsȱ areȱ notȱ usedȱ asȱ oftenȱ asȱ someȱ ofȱ theȱ previousȱ onesȱ
butȱdecipheringȱthemȱwillȱincreaseȱyourȱskill.ȱ
Download at http://www.pin5i.com/
6.11 Pointer Expressions
ȱ
Expression
R-value
cp
147
L-value
ch
b
?
(*cp)++
illegalȱ
ȱ
ȱ
ȱ
a
ȱ
ȱ
ȱ
Withȱ theȱ postfixȱ ++,ȱ weȱ needȱ parenthesesȱ toȱ makeȱ theȱ indirectionȱ goȱ first.ȱ Thisȱ
expressionȱ isȱ evaluatedȱ likeȱ theȱ previousȱ exampleȱ exceptȱ thatȱ theȱ resultȱ isȱ theȱ valueȱ
thatȱchȱhadȱbeforeȱtheȱincrementȱtookȱplace.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Expression
R-value
L-value
cp
++*++cp
ȱ
ch
ȱ
a
?+1
?+1
illegalȱ
ȱ
ȱ
ȱ
Thisȱ oneȱ looksȱ prettyȱ tricky,ȱ butȱ itȱ isnȇtȱ really.ȱ Thereȱ areȱ threeȱ operatorsȱ inȱ thisȱ
expression,ȱwhichȱisȱwhatȱmakesȱitȱlookȱintimidating.ȱȱIfȱyouȱanalyzeȱthemȱoneȱbyȱone,ȱ
though,ȱeachȱwillȱbeȱfamiliar.ȱȱInȱfact,ȱweȇveȱalreadyȱevaluatedȱ*++cpȱearlier;ȱallȱweȱareȱ
doingȱnowȱisȱtoȱincrementȱitsȱresult.ȱȱButȱletȇsȱstartȱfromȱscratch.ȱȱRememberȱthatȱtheȱ
associativityȱofȱtheseȱoperatorsȱisȱrightȱtoȱleft,ȱsoȱtheȱfirstȱthingȱthatȱhappensȱisȱ ++cp;ȱ
theȱ dottedȱ ovalȱ beneathȱ cpȱ illustratesȱ theȱ firstȱ intermediateȱ result.ȱ Thenȱ weȱ applyȱ
indirectionȱ toȱ thisȱ copy,ȱ whichȱ takesȱ usȱ toȱ theȱ locationȱ afterȱ ch.ȱ Theȱ secondȱ
intermediateȱresultȱisȱshownȱwithȱaȱdottedȱboxȱbecauseȱtheȱnextȱoperatorȱusesȱitȱasȱanȱ
LȬvalue.ȱFinally,ȱweȱapplyȱ ++ȱtoȱthisȱlocation,ȱwhichȱincrementsȱitsȱvalue.ȱȱWeȱdisplayȱ
theȱvalueȱasȱ? + 1ȱbecauseȱweȱdoȱnotȱknowȱtheȱoriginalȱvalueȱofȱtheȱlocation.ȱ
Download at http://www.pin5i.com/
Chapter 6 Pointer
148ȱ
ȱ
Expression
++*cp++
R-value
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
L-value
b
cp
ch
b
?
illegalȱ
ȱ
Theȱ differenceȱ betweenȱ thisȱ expressionȱ andȱ theȱ previousȱ oneȱ isȱ thatȱ theȱ firstȱ ++ȱ isȱ
postfixȱinsteadȱofȱprefix,ȱsoȱitȱisȱevaluatedȱfirstȱbecauseȱofȱitsȱhigherȱprecedence.ȱTheȱ
indirectionȱthenȱtakesȱusȱtoȱcpȱinsteadȱofȱtheȱfollowingȱlocation.ȱ
ȱ
ȱ
ȱ
6.12 Examples
ȱ
Hereȱ areȱ someȱ sampleȱ programsȱ toȱ illustrateȱ aȱ fewȱ commonȱ pointerȱ expressions.ȱȱ
Programȱ 6.1ȱ computesȱ theȱ lengthȱ ofȱ aȱ string.ȱ Youȱ shouldȱ neverȱ haveȱ toȱ writeȱ thisȱ
functionȱbecauseȱtheȱlibraryȱcontainsȱone,ȱbutȱitȱisȱaȱusefulȱexample.ȱ
/*
** Compute the length of a string.
*/
#include <stdlib.h>
size_t
strlen( char *string )
{
int
length = 0;
/*
** Advance through the string, counting characters
** until the terminating NUL byte is reached.
*/
while( *string++ != '\0' )
length += 1;
return length;
}
Programȱ6.1ȱStringȱlengthȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱstrlen.cȱ
Download at http://www.pin5i.com/
6.12 Examples
149
Theȱexpressionȱ *string++ȱinȱtheȱ whileȱstatementȱisȱtrueȱuntilȱtheȱpointerȱhasȱreachedȱ
theȱ terminatingȱ NULȱ byte.ȱ Itȱ alsoȱ incrementsȱ theȱ pointerȱ forȱ theȱ nextȱ test.ȱ Thisȱ
expressionȱevenȱhandlesȱemptyȱstringsȱproperly.ȱ
ȱ
Ifȱtheȱfunctionȱisȱcalledȱwithȱaȱ NULLȱpointer,ȱtheȱindirectionȱinȱtheȱ whileȱstatementȱwillȱ
fail.ȱShouldȱtheȱfunctionȱcheckȱforȱthisȱconditionȱbeforeȱdereferencingȱtheȱpointer?ȱToȱ
beȱ absolutelyȱ safe,ȱ itȱ should.ȱ However,ȱ thisȱ functionȱ doesȱ notȱ createȱ theȱ string.ȱ Ifȱ itȱ
findsȱthatȱtheȱargumentȱisȱNULL,ȱitȱhasȱreallyȱfoundȱanȱerrorȱthatȱoccurredȱelsewhereȱinȱ
theȱprogram.ȱItȱseemsȱlogicalȱthatȱtheȱpointerȱshouldȱbeȱcheckedȱwhereȱitȱwasȱcreated,ȱ
becauseȱthenȱitȱneedȱbeȱcheckedȱonlyȱonce.ȱThisȱapproachȱisȱtakenȱbyȱthisȱfunction.ȱIfȱ
theȱ functionȱ failsȱ becauseȱ aȱ carelessȱ clientȱ didnȇtȱ botherȱ toȱ checkȱ theȱ argument,ȱ theyȱ
deserveȱwhatȱtheyȱget.ȱ
Programsȱ 6.2ȱ andȱ 6.3ȱ addȱ aȱ levelȱ ofȱ indirection.ȱ Theyȱ searchȱ aȱ collectionȱ ofȱ
stringsȱforȱaȱspecificȱcharacterȱvalue,ȱbutȱanȱarrayȱofȱpointersȱisȱusedȱtoȱkeepȱtrackȱofȱ
theȱstrings,ȱasȱillustratedȱinȱFigureȱ6.1.ȱTheȱargumentsȱtoȱtheȱfunctionsȱareȱstrings,ȱtheȱ
pointerȱ toȱ theȱ arrayȱ ofȱ pointers;ȱ andȱ value,ȱ theȱ characterȱ valueȱ weȇreȱ lookingȱ for.ȱȱȱ
NoticeȱthatȱtheȱarrayȱofȱpointersȱendsȱwithȱaȱNULLȱpointer.ȱTheȱfunctionsȱwillȱcheckȱforȱ
thisȱvalueȱtoȱdetermineȱwhenȱtoȱstop.ȱTheȱexpressionȱinȱ
ȱ
while( ( string = *strings++ ) != NULL ){
ȱ
doesȱ threeȱ things:ȱ (1)ȱ itȱ copiesȱ theȱ pointerȱ thatȱ stringsȱ currentlyȱ pointsȱ toȱ intoȱ theȱ
variableȱ string,ȱ (2)ȱ itȱ incrementsȱ stringsȱ toȱ pointȱ toȱ theȱ nextȱ value,ȱ andȱ (3)ȱ itȱ testsȱ
whetherȱ stringȱ isȱ NULL.ȱ Theȱ innerȱ whileȱ loopȱ stopsȱ whenȱ stringȱ pointsȱ toȱ theȱ
terminatingȱNULȱbyteȱatȱtheȱendȱofȱtheȱcurrentȱstring.ȱ
ȱ
ȱ
stringsȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇAȇ ȇȱȇȱ ȇsȇȱ ȇtȇȱ ȇrȇȱ ȇiȇȱ ȇnȇȱ ȇgȇȱ 0ȱ
ȱ
ȱ
ȱ
ȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇTȇȱ ȇhȇ ȇiȇȱ ȇrȇ ȇdȇ 0ȱ
ȱ
ȱ
ȱ
ȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȇLȇȱ ȇaȇȱ ȇsȇȱ ȇtȇȱ 0ȱ
ȱ
0ȱ
ȇAȇ ȇnȇ ȇoȇ ȇtȇȱ ȇhȇ ȇeȇ ȇrȇȱ 0ȱ
ȱ
ȱ
ȱ
ȱ ȱ
ȱ
ȱ
ȱ
ȱ
Figureȱ6.1ȱArrayȱofȱpointersȱtoȱstringsȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
150ȱ
Chapter 6 Pointer
ȱ
/*
** Given a pointer to a NULL-terminated list of pointers, search
** the strings in the list for a particular character.
*/
#include <stdio.h>
#define
#define
TRUE 1
FALSE 0
int
find_char( char **strings, char value )
{
char *string;
/* the string we're looking at */
/*
** For each string in the list ...
*/
while( ( string = *strings++ ) != NULL ){
/*
** Look at each character in the string to see if
** it is the one we want.
*/
while( *string != '\0' ){
if( *string++ == value )
return TRUE;
}
}
return FALSE;
}
ȱ
Programȱ6.2ȱSearchȱaȱcollectionȱofȱstrings:ȱversionȱoneȱȱ
ȱ
ȱ
ȱ
ȱ
Untilȱthen,ȱ
ȱ
ȱ
ȱ
ȱȱȱ
ȱȱs_srch1.cȱ
if( *string++ == value )
ȱ
testsȱ whetherȱ theȱ currentȱ characterȱ matchesȱ theȱ desiredȱ valueȱ andȱ incrementsȱ theȱ
pointerȱtoȱtheȱnextȱcharacter.ȱ
Programȱ6.3ȱperformsȱtheȱsameȱfunctionȱwithoutȱmakingȱaȱcopyȱofȱtheȱpointerȱ
toȱeachȱstring.ȱAsȱaȱsideȱeffect,ȱhowever,ȱthisȱprogramȱdestroysȱtheȱarrayȱofȱpointers.ȱ
Thisȱsideȱeffectȱmakesȱtheȱfunctionȱlessȱusefulȱthanȱtheȱpreviousȱversion,ȱasȱitȱcanȱbeȱ
usedȱonlyȱwhenȱtheȱstringsȱareȱsearchedȱonce.ȱ
Download at http://www.pin5i.com/
6.12 Examples
151
ȱ
/*
**
**
**
**
*/
Given a pointer to a NULL-terminated list of pointers, search
the strings in the list for a particular character. This
version destroys the pointers so it can only be used when
the collection will be examined only once.
#include <stdio.h>
#include <assert.h>
#define
#define
TRUE 1
FALSE 0
int
find_char( char **strings, int value )
{
assert( strings != NULL );
/*
** For each string in the list ...
*/
while( *strings != NULL ){
/*
** Look at each character in the string to see if
** it is the one we want.
*/
while( **strings != '\0' ){
if( *(*strings)++ == value )
return TRUE;
}
strings++;
}
return FALSE;
}
ȱ
Programȱ6.3ȱSearchȱaȱcollectionȱofȱstrings:ȱversionȱtwoȱȱ
ȱ
ȱ
ȱ
ȱs_srch2.cȱ
ȱ
ȱ
ȱ
Thereȱare,ȱhowever,ȱtwoȱinterestingȱexpressionsȱinȱProgramȱ6.3.ȱȱTheȱfirstȱisȱ**strings.ȱ
Theȱfirstȱindirectionȱgoesȱtoȱtheȱcurrentȱpointerȱinȱtheȱarrayȱofȱpointers,ȱandȱtheȱsecondȱ
followsȱ thatȱ pointerȱ toȱ theȱ currentȱ characterȱ inȱ theȱ string.ȱ Theȱ innerȱ whileȱ statementȱ
testsȱthisȱcharacterȱtoȱseeȱwhetherȱtheȱendȱofȱtheȱstringȱhasȱbeenȱreached.ȱ
Theȱsecondȱinterestingȱexpressionȱisȱ *(*strings)++.ȱParenthesesȱareȱneededȱinȱorderȱ
forȱtheȱexpressionȱtoȱevaluateȱproperly.ȱTheȱfirstȱindirectionȱgoesȱtoȱtheȱcurrentȱ
Download at http://www.pin5i.com/
152ȱ
Chapter 6 Pointer
pointerȱinȱtheȱlist.ȱTheȱincrementȱaddsȱoneȱtoȱthatȱlocation,ȱbutȱtheȱsecondȱindirectionȱ
worksȱonȱaȱcopyȱofȱtheȱoriginalȱvalue.ȱTheȱnetȱresultȱisȱthatȱtheȱcurrentȱcharacterȱinȱtheȱ
currentȱ stringȱ isȱ testedȱ toȱ seeȱ whetherȱ weȇveȱ reachedȱ theȱ endȱ ofȱ theȱ string,ȱ andȱ theȱ
pointerȱtoȱtheȱcurrentȱstringȱcharacterȱisȱincrementedȱasȱaȱsideȱeffect.ȱ
ȱ
ȱ
ȱ
6.13 Pointer Arithmetic
ȱ
Programsȱ 6.1—6.3ȱ includeȱ expressionsȱ involvingȱ additionsȱ ofȱ pointerȱ valuesȱ andȱ
integers.ȱIsȱitȱlegalȱtoȱperformȱanyȱarithmeticȱwithȱpointers?ȱTheȱanswerȱisȱaȱqualifiedȱ
yes;ȱyouȱcanȱdoȱmoreȱthanȱjustȱadditionȱbutȱnotȱmuchȱmore.ȱ
Theȱresultȱofȱaȱpointerȱplusȱanȱintegerȱisȱanotherȱpointer.ȱTheȱquestionȱis,ȱwhereȱ
doesȱ itȱ point?ȱ Ifȱ youȱ addȱ oneȱ toȱ aȱ characterȱ pointer,ȱ theȱ resultȱ pointsȱ toȱ theȱ nextȱ
characterȱ inȱ memory.ȱ Aȱ floatȱ occupiesȱ moreȱ thanȱ oneȱ byte;ȱ whatȱ happensȱ ifȱ youȱ
incrementȱaȱpointerȱtoȱaȱfloat—doesȱtheȱresultȱpointȱsomewhereȱinsideȱofȱtheȱfloat?ȱ
Fortunately,ȱ no.ȱ Whenȱ arithmeticȱ isȱ performedȱ withȱ aȱ pointerȱ andȱ anȱ integerȱ
quantity,ȱ theȱ integerȱ isȱ alwaysȱ scaledȱ toȱ theȱ properȱ sizeȱ beforeȱ theȱ addition.ȱ Theȱ
ȈproperȱsizeȈȱisȱtheȱsizeȱofȱwhateverȱtypeȱtheȱpointerȱisȱpointingȱat,ȱandȱtheȱȈscalingȈȱisȱ
simplyȱmultiplication.ȱToȱillustrate,ȱimagineȱaȱmachineȱonȱwhichȱ floatsȱoccupyȱfourȱ
bytes.ȱ Inȱ evaluatingȱ anȱ expressionȱ thatȱ addsȱ threeȱ toȱ aȱ pointerȱ toȱ aȱ float,ȱ theȱ valueȱ
threeȱisȱscaledȱ(multiplied)ȱbyȱtheȱsizeȱofȱaȱ float,ȱwhichȱisȱfourȱinȱthisȱexample.ȱTheȱ
valueȱactuallyȱaddedȱtoȱtheȱpointerȱisȱtwelve.ȱ
Addingȱthreeȱtoȱtheȱpointerȱincreasedȱitȱbyȱtheȱsizeȱofȱthreeȱfloats,ȱnotȱbyȱthreeȱ
bytes.ȱ Thisȱ behaviorȱ isȱ muchȱ moreȱ sensibleȱ thanȱ gettingȱ aȱ pointerȱ thatȱ pointsȱ
somewhereȱinȱtheȱmiddleȱofȱaȱfloat.ȱTableȱ6.2ȱcontainsȱsomeȱadditionalȱexamples.ȱTheȱ
beautyȱofȱscalingȱisȱthatȱpointerȱarithmeticȱdoesnȇtȱ
ȱ
ȱ
Expression
Assuming p is a … and the Size of *p Value Added to the
Pointer to a ...
is …
Pointer
char
1ȱ
1ȱ
short
2ȱ
2ȱ
p + 1
int
4ȱ
4ȱ
double
8ȱ
8ȱ
char
1ȱ
2ȱ
short
2ȱ
4ȱ
p + 2
int
4ȱ
8ȱ
double
8ȱ
16ȱ
ȱ
Tableȱ6.2ȱPointerȱarithmeticȱresultsȱ
Download at http://www.pin5i.com/
6.13 Pointer Arithmetic
153
dependȱonȱtheȱtypeȱofȱtheȱpointer.ȱInȱotherȱwords,ȱtheȱexpressionȱ p + 1ȱpointsȱtoȱtheȱ
nextȱ charȱifȱ pȱwasȱaȱpointerȱtoȱaȱ char.ȱItȱpointsȱtoȱtheȱnextȱ floatȱifȱ pȱwasȱaȱpointerȱtoȱaȱ
float,ȱandȱsoȱforth.ȱ
ȱ
ȱ
ȱ
6.13.1
Arithmetic Operations
ȱ
PointerȱarithmeticȱinȱCȱisȱrestrictedȱtoȱexactlyȱtwoȱforms.ȱTheȱfirstȱformȱis:ȱ
ȱ
pointer ± integer
ȱ
ThisȱformȱisȱdefinedȱbyȱtheȱStandardȱonlyȱforȱpointersȱthatȱareȱpointingȱatȱanȱelementȱ
ofȱanȱarray,ȱsuchȱasȱthisȱone,ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
andȱ yieldsȱ aȱ resultȱ ofȱ theȱ sameȱ typeȱ asȱ theȱ pointer.ȱ Thisȱ formȱ alsoȱ worksȱ withȱ
dynamicallyȱ allocatedȱ memoryȱ obtainedȱ fromȱ mallocȱ (seeȱ Chapterȱ 11),ȱ thoughȱ
throughȱanȱoversightȱtheȱStandardȱfailsȱtoȱmentionȱthisȱfact.ȱ
Elementsȱinȱanȱarrayȱareȱstoredȱinȱconsecutiveȱmemoryȱlocations,ȱandȱtheȱlaterȱ
elementsȱhaveȱlargerȱaddressesȱthanȱtheȱearlierȱones.ȱGivenȱthisȱinformation,ȱitȱisȱeasyȱ
toȱseeȱthatȱaddingȱoneȱtoȱtheȱpointerȱmovesȱitȱtoȱtheȱnextȱelementȱinȱtheȱarray,ȱaddingȱ
fiveȱmovesȱitȱfiveȱelementsȱtoȱtheȱright,ȱandȱsoȱforth.ȱSubtractingȱthreeȱmovesȱitȱthreeȱ
elementsȱtoȱtheȱleft.ȱȱScalingȱtheȱintegerȱensuresȱthatȱtheȱadditionȱproducesȱthisȱresultȱ
noȱmatterȱwhatȱsizeȱelementsȱareȱinȱtheȱarray.ȱ
Theȱ effectȱ ofȱ anȱ additionȱ orȱ aȱ subtractionȱ isȱ undefinedȱ ifȱ theȱ resultȱ pointsȱ toȱ
anythingȱearlierȱthanȱtheȱfirstȱelementȱofȱtheȱarrayȱorȱifȱitȱpointsȱtoȱanyȱelementȱmoreȱ
thanȱ oneȱ beyondȱ theȱ lastȱ elementȱ ofȱ theȱ array.ȱ Itȱ isȱ legalȱ forȱ theȱ pointerȱ toȱ goȱ oneȱ
elementȱpastȱtheȱendȱofȱtheȱarray,ȱbutȱindirectionȱmayȱnotȱbeȱperformedȱonȱitȱthen.ȱ
Timeȱ forȱ anȱ example.ȱ Hereȱ isȱ aȱ loopȱ thatȱ initializesȱ allȱ ofȱ theȱ elementsȱ ofȱ anȱ
arrayȱ toȱ zero.ȱ (Chapterȱ 8ȱ discussesȱ theȱ efficiencyȱ ofȱ loopsȱ likeȱ thisȱ oneȱ comparedȱ toȱ
loopsȱthatȱuseȱsubscripts.)ȱ
Download at http://www.pin5i.com/
Chapter 6 Pointer
154ȱ
#define N_VALUES
5
float values[N_VALUES];
float *vp;
for( vp = &values[0]; vp < &values[N_VALUES]; )
*vp++ = 0;
Theȱinitializationȱstepȱofȱtheȱ forȱstatementȱmakesȱ vpȱpointȱ toȱtheȱfirstȱelementȱofȱtheȱ
array.ȱ
ȱ
ȱ
vpȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Theȱ pointerȱ arithmeticȱ inȱ thisȱ exampleȱ isȱ performedȱ byȱ theȱ ++ȱ operator.ȱ Theȱ
incrementȱvalue,ȱone,ȱisȱmultipliedȱbyȱtheȱsizeȱofȱaȱ float,ȱandȱthisȱvalueȱisȱaddedȱtoȱ
theȱ pointerȱ vp.ȱ Afterȱ theȱ firstȱ timeȱ throughȱ theȱ bodyȱ ofȱ theȱ loop,ȱ memoryȱ looksȱ likeȱ
this:ȱ
ȱ
ȱ
vpȱ
ȱ
ȱ
ȱ
ȱ
ȱ
0ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Afterȱfiveȱtimesȱthroughȱtheȱloop,ȱvpȱhasȱgoneȱpastȱtheȱendȱofȱtheȱarrayȱ
ȱ
ȱ
ȱ
vpȱ
ȱ
ȱ
ȱ
ȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
ȱ
ȱ
andȱ theȱ loopȱ stops.ȱ Withȱ subscriptȱ valuesȱ beginningȱ atȱ zero,ȱ theȱ lastȱ elementȱ ofȱ anȱ
arrayȱofȱfiveȱelementsȱwillȱhaveȱaȱsubscriptȱofȱfour.ȱThus &value[N_VALUES] ȱ
ȱ
Download at http://www.pin5i.com/
6.13 Pointer Arithmetic
155
representsȱtheȱaddressȱofȱtheȱfirstȱlocationȱbeyondȱtheȱrightȱendȱofȱtheȱarray.ȱȱWhenȱvpȱ
reachesȱ thisȱ value,ȱ weȱ knowȱ weȱ haveȱ reachedȱ theȱ endȱ ofȱ theȱ array,ȱ andȱ theȱ loopȱ
terminates.ȱ
Theȱpointerȱinȱthisȱexampleȱgoesȱoneȱelementȱbeyondȱtheȱendȱofȱtheȱarray.ȱTheȱ
pointerȱmayȱlegallyȱattainȱthisȱvalueȱbutȱapplyingȱindirectionȱtoȱitȱwillȱaccessȱwhateverȱ
otherȱ variableȱ (ifȱ any)ȱ happensȱ toȱ resideȱ inȱ thatȱ location.ȱ Theȱ programmerȱ generallyȱ
hasȱ noȱ wayȱ ofȱ determiningȱ whatȱ variableȱ thatȱ mightȱ be,ȱ whichȱ isȱ whyȱ indirectionȱ isȱ
notȱallowedȱinȱthisȱcircumstance.ȱ
Theȱsecondȱtypeȱofȱpointerȱarithmeticȱhasȱtheȱform:ȱ
ȱ
pointer - pointer
ȱ
Subtractingȱoneȱpointerȱfromȱanotherȱisȱallowedȱonlyȱwhenȱbothȱpointȱtoȱelementsȱofȱ
theȱsameȱarray,ȱlikeȱthis:ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
p1
ȱ
p2
ȱ
ȱ
ȱ
ȱ
ȱ
Theȱ resultȱ ofȱ subtractingȱ twoȱ pointersȱ isȱ ofȱ typeȱ ptrdiff_t,ȱ whichȱ willȱ beȱ aȱ signedȱ
integralȱ type.ȱ Theȱ valueȱ isȱ theȱ distanceȱ (measuredȱ inȱ arrayȱ elements,ȱ notȱ bytes)ȱ
betweenȱtheȱtwoȱpointers,ȱbecauseȱtheȱresultȱofȱtheȱsubtractionȱisȱdividedȱ(scaled)ȱbyȱ
theȱsizeȱofȱtheȱarrayȱelements.ȱForȱexample,ȱifȱ p1ȱpointsȱtoȱ array[i]ȱandȱ p2ȱpointsȱtoȱ
array[j]ȱthenȱp2 – p1ȱwillȱhaveȱtheȱsameȱvalueȱasȱj – i.ȱ
Letȇsȱseeȱhowȱthisȱworksȱwithȱaȱspecificȱtype.ȱȱSupposeȱtheȱarrayȱinȱtheȱpreviousȱ
diagramȱconsistedȱofȱ floatsȱoccupyingȱfourȱbytesȱeach.ȱIfȱtheȱarrayȱbeganȱatȱlocationȱ
1000,ȱ thenȱ p1ȱ wouldȱ containȱ 1004ȱ andȱ p2ȱ wouldȱ containȱ 1024.ȱ Theȱ resultȱ ofȱ theȱ
expressionȱ p2 – p1ȱwouldȱbeȱfive,ȱthough,ȱbecauseȱtheȱdifferenceȱbetweenȱtheȱpointerȱ
valuesȱ(20)ȱisȱdividedȱbyȱtheȱsizeȱofȱeachȱelementȱ(4).ȱ
Onceȱagain,ȱscalingȱmakesȱtheȱresultȱindependentȱofȱtheȱdataȇsȱtype.ȱTheȱresultȱ
ofȱthisȱpointerȱsubtractionȱwillȱbeȱfiveȱnoȱmatterȱwhatȱtypeȱofȱdataȱtheȱarrayȱcontains.ȱ
Isȱtheȱexpressionȱp1 - p2ȱlegal?ȱYes,ȱifȱbothȱpointersȱareȱpointingȱtoȱelementsȱofȱ
theȱsameȱarray.ȱȱInȱtheȱpreviousȱexample,ȱitsȱvalueȱwouldȱbeȱ–5.ȱ
Theȱ resultȱ ofȱ subtractingȱ twoȱ pointersȱ thatȱ doȱ notȱ pointȱ toȱ theȱ sameȱ arrayȱ isȱ
undefinedȱ forȱ theȱ sameȱ reasonȱ thatȱ subtractingȱ theȱ addressesȱ ofȱ twoȱ housesȱ onȱ
differentȱ streetsȱ doesnȇtȱ tellȱ youȱ theȱ numberȱ ofȱ housesȱ inȱ betweenȱ them.ȱ Theȱ
programmerȱhasȱnoȱwayȱofȱknowingȱwhereȱtheȱtwoȱarraysȱmightȱhaveȱbeenȱallocatedȱ
Download at http://www.pin5i.com/
Chapter 6 Pointer
156ȱ
CAUTION!
relativeȱ toȱ oneȱ another.ȱ Withoutȱ thisȱ knowledge,ȱ theȱ distanceȱ fromȱ oneȱ pointerȱ toȱ
anotherȱhasȱnoȱmeaning.ȱ
ȱ
Inȱ practice,ȱ mostȱ compilersȱ doȱ notȱ checkȱ whetherȱ theȱ resultȱ ofȱ aȱ pointerȱ expressionȱ
fallsȱ withinȱ anyȱ legalȱ bounds.ȱ Therefore,ȱ itȱ isȱ upȱ toȱ theȱ programmerȱ toȱ makeȱ sureȱ itȱ
does.ȱSimilarly,ȱtheȱcompilerȱwillȱnotȱpreventȱyouȱfromȱtakingȱtheȱaddressȱofȱaȱscalarȱ
variableȱ andȱ performingȱ pointerȱ arithmeticȱ onȱ it,ȱ evenȱ thoughȱ thereȱ isȱ noȱ wayȱ toȱ
predictȱ whatȱ variableȱ theȱ resultȱ willȱ pointȱ to.ȱ OutȬofȬrangeȱ pointersȱ andȱ pointerȱ toȱ
unknownȱvaluesȱareȱtwoȱcommonȱcausesȱofȱerrors.ȱWhenȱusingȱpointerȱarithmetic,ȱbeȱ
veryȱcarefulȱthatȱtheȱresultȱpointsȱtoȱsomethingȱmeaningful.ȱ
ȱ
ȱ
ȱ
6.13.2
Relational Operations
ȱ
Relationalȱ operationsȱ onȱ pointersȱ areȱ alsoȱ constrained.ȱ Itȱ isȱ possibleȱ toȱ compareȱ twoȱ
pointerȱvaluesȱwithȱtheȱrelationalȱoperatorsȱȱ
ȱ
ȱ
<
<=
>
>=
ȱ
onlyȱ ifȱ theyȱ bothȱ pointȱ toȱ elementsȱ ofȱ theȱ sameȱ array.ȱ Dependingȱ onȱ whichȱ operatorȱ
youȱ choose,ȱ theȱ comparisonȱ willȱ tellȱ youȱ whichȱ pointerȱ pointsȱ earlierȱ orȱ laterȱ inȱ theȱ
array.ȱTheȱresultsȱofȱcomparingȱarbitraryȱpointersȱareȱnotȱdefinedȱbyȱtheȱStandard.ȱ
However,ȱyouȱmayȱtestȱforȱequalityȱorȱinequalityȱbetweenȱanyȱpointers,ȱbecauseȱ
theȱ resultsȱofȱ suchȱcomparisonsȱ doȱnotȱ dependȱonȱwhereȱtheȱ compilerȱhasȱchosenȱtoȱ
allocateȱdata—theȱpointersȱeitherȱreferȱtoȱtheȱsameȱaddressȱorȱtoȱdifferentȱones.ȱ
Letȇsȱlookȱagainȱatȱtheȱloopȱtoȱclearȱtheȱelementsȱofȱanȱarray.ȱ
ȱ
#define
N_VALUES
float values[N_VALUES];
float *vp;
5
for( vp = &values[0]; vp < &values[N_VALUES]; )
*vp++ = 0;
ȱ
Theȱforȱstatementȱusesȱaȱrelationalȱtestȱtoȱterminateȱtheȱloop.ȱȱTheȱtestȱisȱlegalȱbecauseȱ
bothȱ vpȱ andȱ theȱ pointerȱ constantȱ pointȱ toȱ elementsȱ ofȱ theȱ sameȱ array.ȱ (Actually,ȱ theȱ
pointerȱconstantȱpointsȱoneȱbeyondȱtheȱendȱofȱfileȱarray,ȱandȱwhenȱtheȱlastȱcomparisonȱ
isȱmadeȱsoȱdoesȱvp,ȱbutȱindirectionȱisȱnotȱperformedȱsoȱweȇreȱsafe.)ȱUsingȱ!=ȱinsteadȱofȱ
<ȱ wouldȱ alsoȱ work,ȱ becauseȱ bothȱ expressionsȱ willȱ beȱ falseȱ whenȱ vpȱ attainsȱ itsȱ finalȱ
value.ȱ
ȱ
Download at http://www.pin5i.com/
6.14 Summary
157
Nowȱconsiderȱthisȱloop:ȱ
ȱ
for( vp = &values[N_VALUES]; vp > &values[0]; )
*--vp = 0
ȱ
Itȱperformsȱtheȱsameȱjobȱasȱtheȱpreviousȱloopȱexceptȱthatȱtheȱelementsȱareȱclearedȱinȱ
theȱoppositeȱorder.ȱȱWeȱinitializeȱvpȱtoȱpointȱjustȱbeyondȱtheȱrightȱendȱofȱtheȱarray,ȱbutȱ
theȱpointerȱisȱdecrementedȱjustȱbeforeȱtheȱindirectionȱoccurs.ȱȱWeȱstopȱtheȱloopȱwhenȱ
vpȱ pointsȱ toȱ theȱ firstȱ elementȱ ofȱ theȱ array,ȱ butȱ thisȱ occursȱ afterȱ theȱ firstȱ elementȱ hasȱ
alreadyȱbeenȱcleared.ȱ
Someȱ mightȱ objectȱ toȱ theȱ expressionȱ *--vpȱ onȱ theȱ groundsȱ ofȱ readability.ȱ Butȱ
lookȱwhatȱhappensȱtoȱthisȱloopȱwhenȱitȱisȱȈsimplified:Ȉȱ
ȱ
for( vp = &values[N_VALUES-1]; vp > &values[0]; vp-- )
*vp = 0;
ȱ
CAUTION!
Nowȱvpȱisȱinitializedȱtoȱpointȱtoȱtheȱlastȱelementȱofȱtheȱarrayȱandȱisȱdecrementedȱinȱtheȱ
adjustmentȱstepȱofȱtheȱforȱstatement.ȱThereȱisȱaȱproblemȱwithȱthisȱloop—doȱyouȱseeȱit?ȱ
ȱ
Afterȱ theȱ firstȱ elementȱ inȱ theȱ arrayȱ isȱ cleared,ȱ vpȱ isȱ decrementedȱ again,ȱ andȱ theȱ nextȱ
comparisonȱisȱsupposedȱtoȱterminateȱtheȱloop.ȱButȱhereȱisȱwhereȱtheȱproblemȱoccurs:ȱ
theȱcomparisonȱ vp >= &values[0]ȱisȱundefinedȱbecauseȱ vpȱhasȱmovedȱoutsideȱofȱtheȱ
boundsȱofȱtheȱarray.ȱTheȱStandardȱallowsȱforȱaȱcomparisonȱwithȱaȱpointerȱthatȱpointsȱ
justȱbeyondȱtheȱrightȱsideȱofȱanȱarrayȱbutȱnotȱforȱoneȱthatȱpointsȱjustȱbeyondȱtheȱleftȱ
side.ȱ
Inȱ practice,ȱ thisȱ loopȱ willȱ workȱ properlyȱ onȱ mostȱ ANSIȱ Cȱ implementations.ȱ
Nevertheless,ȱ itȱ shouldȱ beȱ avoidedȱ becauseȱ theȱ Standardȱ doesȱ notȱ guaranteeȱ thatȱ itȱ
willȱwork,ȱandȱsoonerȱorȱlaterȱyouȱareȱboundȱtoȱrunȱacrossȱaȱmachineȱonȱwhichȱitȱfails.ȱȱ
Suchȱareȱtheȱproblemsȱthatȱgiveȱnightmaresȱtoȱprogrammersȱresponsibleȱforȱportableȱ
code.ȱ
ȱ
ȱ
ȱ
6.14 Summary
ȱ
Eachȱlocationȱinȱtheȱcomputerȇsȱmemoryȱisȱidentifiedȱbyȱanȱaddress.ȱAdjacentȱlocationsȱ
areȱoftenȱgroupedȱtogetherȱtoȱallowȱlargerȱrangesȱofȱvaluesȱtoȱbeȱstored.ȱAȱpointerȱisȱaȱ
valueȱthatȱrepresentsȱaȱmemoryȱaddress.ȱ
Neitherȱyouȱnorȱtheȱcomputerȱcanȱdetermineȱtheȱtypeȱofȱaȱvalueȱbyȱexaminingȱ
itsȱbits;ȱtheȱtypeȱisȱimplicitȱinȱhowȱtheȱvalueȱisȱused.ȱTheȱcompilerȱhelpsȱusȱbyȱensuringȱ
thatȱvaluesȱareȱusedȱinȱaȱwayȱthatȱisȱappropriateȱtoȱhowȱtheyȱareȱdeclared.ȱ
Download at http://www.pin5i.com/
158ȱ
Chapter 6 Pointer
Theȱ valueȱ ofȱ aȱ pointerȱ variableȱ isȱ notȱ theȱ valueȱ toȱ whichȱ itȱ points.ȱ Indirectionȱ
mustȱbeȱappliedȱtoȱaȱpointerȱtoȱobtainȱtheȱvalueȱthatȱitȱpointsȱto.ȱTheȱresultȱofȱapplyingȱ
indirectionȱtoȱaȱȈpointerȱtoȱintegerȈȱisȱanȱinteger.ȱ
Declaringȱ pointerȱ variableȱ doesȱ notȱ automaticallyȱ allocateȱ anyȱ memoryȱ inȱ
whichȱtoȱstoreȱvalues.ȱBeforeȱindirectionȱcanȱbeȱperformedȱonȱtheȱpointer,ȱitȱmustȱbeȱ
initializedȱ coȱ pointȱ eitherȱ toȱ existingȱ memoryȱ orȱ toȱ dynamicallyȱ allocatedȱ memory.ȱ
Indirectionȱ onȱ anȱ uninitializedȱ pointerȱ variableȱ isȱ illegalȱ butȱ oftenȱ goesȱ undetected.ȱ
Theȱ resultȱ mayȱ beȱ thatȱ anȱ unrelatedȱ valueȱ isȱ modified.ȱ Theseȱ errorsȱ areȱ difficultȱ toȱ
debug.ȱ
TheȱNULLȱpointerȱisȱaȱvalueȱthatȱisȱdefinedȱasȱpointingȱtoȱnothingȱatȱall.ȱItȱcanȱ
beȱ assignedȱ toȱ aȱ pointerȱ variableȱ toȱ indicateȱ thatȱ theȱ variableȱ doesȱ notȱ pointȱ toȱ anyȱ
value.ȱ Theȱ resultȱ ofȱ applyingȱ indirectionȱ toȱ aȱ NULLȱ pointerȱ isȱ implementationȱ
dependent;ȱtwoȱcommonȱresultsȱareȱtoȱreturnȱtheȱvalueȱofȱmemoryȱlocationȱzeroȱandȱ
toȱabortȱtheȱprogram.ȱ
Aȱpointerȱvariable,ȱlikeȱanyȱotherȱvariable,ȱcanȱbeȱusedȱasȱanȱLȬvalue.ȱApplyingȱ
indirectionȱ toȱ aȱ pointerȱ alsoȱ resultsȱ inȱ anȱ LȬvalueȱ becauseȱ theȱ expressionȱ identifiesȱ aȱ
specificȱmemoryȱlocation.ȱ
Otherȱ thanȱ theȱ NULLȱ pointer,ȱ thereȱ isȱ noȱ builtȬinȱ notationȱ forȱ expressingȱ
pointerȱconstantsȱbecauseȱtheȱprogrammerȱusuallyȱhasȱnoȱwayȱofȱpredictingȱwhereȱtheȱ
compilerȱ willȱ placeȱ variables.ȱ Inȱ theȱ rareȱ casesȱ whereȱ theyȱ areȱ needed,ȱ pointerȱ
constantsȱcanȱbeȱcreatedȱbyȱcastingȱintegerȱvalues.ȱ
Limitedȱarithmeticȱcanȱbeȱperformedȱonȱpointerȱvalues.ȱYouȱcanȱaddȱanȱintegerȱ
valueȱ toȱ aȱ pointer,ȱ andȱ subtractȱ anȱ integerȱ valueȱ fromȱ aȱ pointer.ȱ Inȱ bothȱ cases,ȱ theȱ
integerȱ valueȱ isȱ scaledȱ byȱ theȱ sizeȱ ofȱ theȱ pointerȇsȱ targetȱ type.ȱ Thus,ȱ addingȱ oneȱ toȱ aȱ
pointerȱ makesȱ itȱ pointȱ toȱ theȱ nextȱ variableȱ regardlessȱ ofȱ theȱ sizeȱ ofȱ theȱ variablesȱ inȱ
memory.ȱ
However,ȱthisȱpointerȱarithmeticȱisȱpredictableȱonlyȱwithȱarrays.ȱItȱisȱillegalȱ(butȱ
oftenȱ notȱ detected)ȱ toȱ performȱ arithmeticȱ onȱ anyȱ pointerȱ thatȱ doesȱ notȱ pointȱ toȱ anȱ
elementȱofȱanȱarray.ȱItȱisȱalsoȱillegalȱtoȱsubtractȱfromȱaȱpointerȱifȱtheȱresultȱliesȱbeforeȱ
theȱfirstȱelementȱofȱtheȱarrayȱtoȱwhichȱitȱpoints,ȱandȱtoȱaddȱtoȱaȱpointerȱifȱtheȱresultȱliesȱ
moreȱ thanȱ oneȱ elementȱ afterȱ theȱ endȱ ofȱ theȱ arrayȱ toȱ whichȱ itȱ points.ȱ Theȱ resultȱ ofȱ aȱ
pointerȱadditionȱmayȱpointȱoneȱelementȱbeyondȱtheȱendȱofȱtheȱarray,ȱbutȱitȱisȱillegalȱtoȱ
applyȱindirectionȱtoȱthisȱresult.ȱ
Twoȱ pointersȱ mayȱ beȱ subtractedȱ fromȱ oneȱ anotherȱ onlyȱ ifȱ theyȱ bothȱ pointȱ toȱ
elementsȱofȱtheȱsameȱarray.ȱTheȱresultȱofȱpointerȱsubtractionȱisȱscaledȱbyȱtheȱsizeȱofȱtheȱ
valuesȱ inȱ theȱ array,ȱ soȱ theȱ resultȱ isȱ theȱ numberȱ ofȱ valuesȱ separatingȱ theȱ originalȱ
pointers.ȱSubtractingȱpointersȱtoȱelementsȱofȱdifferentȱarraysȱisȱanȱ(oftenȱundetected)ȱ
error.ȱ
ȱ
Download at http://www.pin5i.com/
6.17 Questions
159
Anyȱ pointersȱ mayȱ beȱ comparedȱ toȱ eachȱ otherȱ forȱ equalityȱ orȱ inequality.ȱ Twoȱ
pointersȱ thatȱ pointȱ toȱ elementsȱ ofȱ theȱ sameȱ arrayȱ mayȱ alsoȱ beȱ comparedȱ usingȱ theȱ
relationalȱoperatorsȱ <,ȱ <=,ȱ >,ȱandȱ >=ȱtoȱdetermineȱtheirȱpositionsȱinȱtheȱarrayȱrelativeȱtoȱ
eachȱ other.ȱ Theȱ resultȱ ofȱ aȱ relationalȱ comparisonȱ betweenȱ unrelatedȱ pointersȱ isȱ
undefined.ȱ
ȱ
ȱ
ȱ
6.15 Summary of Cautions
ȱ
1. Dereferencingȱanȱuninitializedȱpointerȱvariableȱ(pageȱ135).ȱ
2. DereferencingȱaȱNULLȱpointerȱ(pageȱ136).ȱ
3. NULLȱpointerȱargumentsȱtoȱfunctionsȱ(pageȱ149).ȱ
4. Unexpectedȱresultsȱfromȱerrorsȱinȱ pointerȱexpressionsȱthatȱareȱnotȱdetectedȱ (pageȱ
156).ȱ
5. Decrementingȱaȱpointerȱvariableȱpastȱtheȱbeginningȱofȱanȱarrayȱ(pageȱ157).ȱ
ȱ
ȱ
ȱ
6.16 Summary of Programming Tips
ȱ
1. Aȱvalueȱshouldȱonlyȱhaveȱoneȱmeaningȱ(pageȱ136).ȱ
2. SetȱpointerȱvariablesȱtoȱNULLȱwhenȱtheyȱareȱnotȱpointingȱtoȱanythingȱusefulȱ(pageȱ
137).ȱ
ȱ
ȱ
ȱ
6.17 Questions
ȱ
1. Ifȱtheȱtypeȱofȱaȱvalueȱcannotȱbeȱdeterminedȱsimplyȱbyȱlookingȱatȱitsȱbits,ȱhowȱdoesȱ
theȱmachineȱknowȱhowȱtheȱvalueȱshouldȱbeȱmanipulated?ȱ
2. WhyȱdoesnȇtȱCȱhaveȱaȱwayȱofȱdeclaringȱliteralȱpointerȱconstants?ȱ
3. Supposeȱanȱintegerȱcontainsȱtheȱvalueȱ244.ȱȱWhyȱdoesnȇtȱtheȱmachineȱinterpretȱthisȱ
valueȱasȱanȱaddress?ȱ
4. Onȱsomeȱmachines,ȱtheȱcompilerȱarrangesȱforȱmemoryȱlocationȱzeroȱtoȱcontainȱtheȱ
valueȱzero.ȱDereferencingȱaȱNULLȱpointerȱthenȱaccessesȱthisȱlocation.ȱWhatȱareȱtheȱ
consequencesȱofȱthisȱarrangement?ȱ
Download at http://www.pin5i.com/
Chapter 6 Pointer
160ȱ
5. Whatȱ isȱ theȱ differenceȱ (ifȱ any)ȱ betweenȱ theȱ workȱ thatȱ isȱ requiredȱ toȱ evaluateȱ
expressionsȱ(a)ȱandȱ(b)?ȱAssumeȱthatȱtheȱvariableȱoffsetȱhasȱtheȱvalueȱthree.ȱ
ȱ
int
int
int
i[ 10 ];
*p = &i[ 0 ];
offset;
p += offset;
p += 3;
(a)
(b)
6. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱcodeȱsegment?ȱ
int
int
array[ARRAY_SIZE];
*pi;
for( pi = &array[0]; pi < &array[ARRAY_SIZE]; )
*++pi = 0;
7. Theȱtableȱbelowȱshowsȱtheȱcontentsȱofȱseveralȱmemoryȱlocations.ȱEachȱlocationȱisȱ
identifiedȱ byȱ itsȱ addressȱ andȱ alsoȱ byȱ theȱ nameȱ ofȱ theȱ variableȱ storedȱ there.ȱ Allȱ
numbersȱareȱshownȱinȱdecimal.ȱ
ȱ
Variable
Address
Contents
Variable
Address
Contents
aȱ
1040ȱ
1028ȱ
oȱ
1096ȱ
1024ȱ
cȱ
dȱ
eȱ
fȱ
gȱ
hȱ
iȱ
jȱ
kȱ
mȱ
nȱ
1056ȱ
1008ȱ
1032ȱ
1052ȱ
1000ȱ
1080ȱ
1020ȱ
1064ȱ
1044ȱ
1016ȱ
1076ȱ
1076ȱ
1016ȱ
1088ȱ
1044ȱ
1064ȱ
1020ȱ
1080ȱ
1000ȱ
1052ȱ
1008ȱ
1056ȱ
qȱ
rȱ
sȱ
tȱ
uȱ
vȱ
wȱ
xȱ
yȱ
zȱ
ȱ
1084ȱ
1068ȱ
1004ȱ
1060ȱ
1036ȱ
1092ȱ
1012ȱ
1072ȱ
1048ȱ
2000ȱ
ȱ
1072ȱ
1048ȱ
2000ȱ
1012ȱ
1092ȱ
1036ȱ
1060ȱ
1080ȱ
1068ȱ
1000ȱ
ȱ
ȱ
Usingȱ theseȱ values,ȱ evaluateȱ eachȱ ofȱ theȱ expressionsȱ belowȱ fourȱ ways.ȱ First,ȱ
assumeȱthatȱallȱtheȱvariablesȱareȱintegers,ȱandȱfindȱtheȱexpressionsȱRȬvalue.ȱThenȱ
findȱitsȱLȬvalue,ȱandȱgiveȱtheȱaddressȱofȱtheȱlocationȱitȱspecifies.ȱȱNext,ȱassumeȱthatȱ
allȱ theȱ variablesȱ areȱ pointersȱ toȱ integersȱ andȱ repeatȱ theȱ exercise.ȱ Note:ȱ Doȱ yourȱ
addressȱarithmeticȱbasedȱonȱfourȬbyteȱintegersȱandȱpointers.ȱ
Download at http://www.pin5i.com/
6.17 Questions
161
ȱ
Integers
Expression
R-value
L-value addr
Pointers to Integers
R-value
L-value addr
a.
m
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
b.
v + 1
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
c.
j – 4
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
d.
a – d
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
e.
v – w
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
f.
&c
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
g.
&e + 1
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
h.
&o – 4
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
i.
&( f + 2 )
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
j.
*g
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
k.
*k + 1
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
l.
*( n + 1 )
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
m.
*h – 4
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
n.
*( u – 4 )
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
o.
*f – g
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
p.
*f - *g
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
q.
*s - *q
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
r.
*( r – t )
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
s.
y > i
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
t.
y > *i
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
u.
*y > *i
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
v.
**h
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
w.
c++
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
x.
++c
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
y.
*q++
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
z.
(*q)++
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
aa.
*++q
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
bb.
++*q
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
cc.
*++*q
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
dd.
++*(*q)++
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ . ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
Download at http://www.pin5i.com/
Chapter 6 Pointer
162ȱ
6.18 Programming Exercises
ȱ
1. Writeȱ aȱ functionȱ thatȱ willȱ searchȱ aȱ stringȱ forȱ anyȱ oneȱ ofȱ aȱ givenȱ setȱ ofȱ characters.ȱ
Yourȱfunctionȱshouldȱmatchȱthisȱprototype:ȱ
char *find_char( char const *source,
char const *chars );
Theȱ basicȱ ideaȱ isȱ toȱ locateȱ theȱ firstȱ characterȱ inȱ theȱ sourceȱ stringȱ thatȱ matchesȱ
anyȱofȱtheȱcharactersȱinȱtheȱ charsȱstring.ȱTheȱfunctionȱthenȱreturnsȱaȱpointerȱtoȱtheȱ
placeȱ inȱ sourceȱ whereȱ theȱ firstȱ matchȱ wasȱ found.ȱ ȱ Ifȱ noneȱ ofȱ theȱ charactersȱ inȱ
sourceȱmatchȱanyȱofȱtheȱchars,ȱthenȱaȱNULLȱpointerȱisȱreturned.ȱIfȱeitherȱargumentȱ
isȱNULL,ȱorȱeitherȱstringȱisȱempty,ȱthenȱaȱNULLȱpointerȱisȱreturned.ȱ
Toȱ illustrate,ȱ supposeȱ sourceȱ pointsȱ toȱ ABCDEFG.ȱ Ifȱ charsȱ pointsȱ toȱ XYZ,ȱ
JURY,ȱ orȱ QQQQ,ȱ theȱ functionȱ shouldȱ returnȱ NULL.ȱ ȱ Ifȱ charsȱ pointsȱ toȱ XRCQEF,ȱ
theȱ functionȱ shouldȱ returnȱ aȱ pointerȱ toȱ theȱ Cȱ inȱ source.ȱ Theȱ stringsȱ thatȱ theȱ
argumentsȱpointȱtoȱareȱneverȱmodified.ȱ
Asȱ itȱ happens,ȱ thereȱ isȱ aȱfunctionȱ inȱ theȱ Cȱlibraryȱ calledȱ strpbrkȱ thatȱ behavesȱ
almostȱexactlyȱtheȱsameȱasȱtheȱoneȱyouȱareȱtoȱwrite.ȱButȱtheȱobjectȱofȱthisȱprogramȱ
isȱforȱyouȱtoȱmanipulateȱtheȱpointersȱyourself,ȱso:ȱ
a.
Youȱmayȱnotȱuseȱanyȱofȱtheȱlibraryȱstringȱroutinesȱ(forȱexample,ȱ strcpy,ȱ
strcmp,ȱindex,ȱetc.),ȱandȱ
b.
youȱmayȱnotȱuseȱsubscriptsȱanywhereȱinȱyourȱfunction.ȱ
ȱ
2. Writeȱaȱfunctionȱthatȱdeletesȱaȱportionȱofȱaȱstring.ȱȱHereȱisȱitsȱprototype:ȱ
int del_substr( char *str char const *substr )
Theȱ functionȱ shouldȱ firstȱ determineȱ whetherȱ theȱ stringȱ substrȱ occursȱ inȱ str.ȱ Ifȱ itȱ
doesȱnot,ȱtheȱvalueȱ0ȱshouldȱbeȱreturned.ȱȱIfȱtheȱsubstringȱdoesȱappear,ȱtheȱfunctionȱ
shouldȱ removeȱ itȱ byȱ copyingȱ theȱ charactersȱ inȱ strȱ thatȱ followȱ theȱ substringȱ overȱ
theȱsubstringȱitself.ȱTheȱvalueȱ 1ȱshouldȱthenȱbeȱreturned.ȱIfȱtheȱsubstringȱappearsȱ
severalȱtimesȱinȱtheȱfirstȱargument,ȱonlyȱtheȱfirstȱoccurrenceȱshouldȱbeȱdeleted.ȱTheȱ
secondȱargumentȱshouldȱneverȱbeȱchangedȱ
Toȱillustrate,ȱsupposeȱ strȱpointsȱ toȱ ABCDEFG.ȱ Ifȱ substrȱpointsȱtoȱFGH,ȱCDF,ȱ
orȱ XABC,ȱ theȱ functionȱ shouldȱ returnȱ 0ȱ andȱ leaveȱ strȱ unchanged.ȱ Butȱ ifȱ substrȱ
pointsȱtoȱCDE,ȱtheȱfunctionȱshouldȱchangeȱ strȱtoȱABFGȱbyȱcopyingȱtheȱcharactersȱ
F,ȱ G,ȱ andȱ theȱ NULȱ byte.ȱ Theȱ functionȱ shouldȱ thenȱ returnȱ 1.ȱ Inȱ noȱ eventȱ isȱ theȱ
secondȱargumentȱstringȱeverȱmodified.ȱ
Asȱwithȱtheȱlastȱprogram:ȱ
a.
ȱ
ȱ
yonȱ mayȱ notȱ useȱ anyȱ ofȱ theȱ libraryȱ stringȱ routinesȱ (e.g.ȱ strcpy,ȱ strcmp,ȱ
etc.),ȱandȱ
Download at http://www.pin5i.com/
6.18 Programming Exercises
b.
163
youȱmayȱnotȱuseȱanyȱsubscriptsȱinȱyourȱfunction.ȱ
Onȱ aȱ philosophicalȱ note,ȱ theȱ emptyȱ stringȱ isȱ aȱ substringȱ ofȱ everyȱ stringȱ butȱ
removingȱanȱemptyȱsubstringȱproducesȱnoȱchangeȱinȱtheȱstring.ȱ
3. Writeȱtheȱfunctionȱreverse_string,ȱwhoseȱprototypeȱisȱshownȱbelow:ȱ
ȱ
void reverse_string( char *string );
Theȱ functionȱ reversesȱ theȱ charactersȱ inȱ theȱ argumentȱ string.ȱ Useȱ pointersȱ ratherȱ
thanȱsubscripts,ȱandȱdoȱnotȱuseȱanyȱofȱtheȱCȱlibraryȱstringȱfunctions.ȱHint:ȱThereȱisȱ
noȱneedȱtoȱdeclareȱaȱlocalȱarrayȱtoȱtemporarilyȱholdȱtheȱargumentȱstring.ȱ
4. Aȱ primeȱ numberȱ isȱ oneȱ thatȱ isȱ divisibleȱ onlyȱ byȱ itselfȱ andȱ one.ȱ Theȱ Sieveȱ ofȱ
Eratosthenesȱisȱanȱefficientȱalgorithmȱforȱtheȱcomputationȱofȱprimeȱnumbers.ȱTheȱ
firstȱstepȱofȱtheȱalgorithmȱisȱtoȱwriteȱdownȱallȱtheȱnumbersȱfromȱtwoȱtoȱsomeȱupperȱ
limit.ȱ Inȱ theȱ restȱ ofȱ theȱ algorithm,ȱ youȱ goȱ throughȱ theȱ listȱ andȱ crossȱ outȱ numbersȱ
thatȱareȱnotȱprime.ȱ
Hereȱareȱtheȱremainingȱsteps.ȱStartingȱatȱtheȱbeginningȱofȱtheȱlist,ȱfindȱtheȱfirstȱ
numberȱthatȱisȱnotȱcrossedȱout,ȱwhichȱwillȱbeȱtwo.ȱCrossȱoutȱeveryȱsecondȱnumberȱ
inȱtheȱlistȱafterȱtwo,ȱbecauseȱtheyȱareȱallȱmultiplesȱofȱtwo.ȱThenȱrepeatȱtheseȱstepsȱ
fromȱtheȱbeginningȱofȱtheȱlist.ȱTheȱfirstȱnumberȱinȱtheȱlistȱthatȱisȱnotȱcrossedȱoutȱisȱ
nowȱthree,ȱsoȱcrossȱoutȱeveryȱthirdȱnumberȱafterȱthree.ȱTheȱnextȱnumberȱinȱtheȱlist,ȱ
four,ȱisȱalreadyȱcrossedȱoutȱsoȱitȱisȱskipped.ȱWhenȱyouȱhaveȱfinishedȱthisȱprocess,ȱ
theȱnumbersȱthatȱhaveȱnotȱbeenȱcrossedȱoutȱareȱprime.ȱ
Writeȱ aȱ programȱ thatȱ implementsȱ thisȱ algorithm,ȱ usingȱ anȱ arrayȱ forȱ yourȱ list.ȱ
Theȱvalueȱinȱeachȱarrayȱelementȱkeepsȱtrackȱofȱwhetherȱtheȱcorrespondingȱnumberȱ
hasȱbeenȱcrossedȱout.ȱSetȱallȱelementsȱofȱtheȱarrayȱtoȱTRUEȱinitially,ȱthenȱsetȱthemȱ
FALSEȱaccordingȱtoȱtheȱalgorithmȱaboveȱtoȱȈcrossȱthemȱout.ȈȱIfȱyouȱareȱworkingȱonȱ
aȱ 16Ȭbitȱ machine,ȱ thinkȱ carefullyȱ whichȱ variablesȱ shouldȱ beȱ declaredȱ long.ȱ Startȱ
withȱanȱarrayȱofȱ1000ȱelements.ȱIfȱyouȱuseȱanȱarrayȱofȱcharactersȬȱyouȱcanȱfindȱmoreȱ
primeȱ numbersȱ thanȱ ifȱ youȱ useȱ anȱ arrayȱ ofȱ integers.ȱ Youȱ canȱ useȱ subscriptsȱ toȱ
computeȱ pointersȱ toȱ theȱ beginningȱ andȱ endȱ ofȱ theȱ array,ȱ butȱ youȱ shouldȱ useȱ
pointersȱtoȱaccessȱtheȱarrayȱelements.ȱ
Noteȱ thatȱ noneȱ ofȱ theȱ evenȱ numbersȱ areȱ primeȱ exceptȱ forȱ two.ȱ Withȱ aȱ littleȱ
thought,ȱyouȱcanȱmakeȱtheȱprogramȱmoreȱspaceȱefficientȱbyȱkeepingȱtrackȱofȱonlyȱ
theȱoddȱnumbersȱwithȱyourȱarray.ȱYouȱshouldȱthenȱbeȱableȱtoȱfindȱ(roughly)ȱtwiceȱ
asȱmanyȱprimeȱnumbersȱwithȱtheȱsameȱsizeȱarray.ȱ
5. ModifyȱtheȱSieveȱofȱEratosthenesȱprogramȱinȱtheȱpreviousȱproblemȱsoȱthatȱitȱusesȱ
anȱarrayȱofȱbitsȱratherȱthanȱ characters,ȱ usingȱtheȱbitȱarrayȱ functionsȱdevelopedȱinȱ
theȱChapterȱ5ȱprogrammingȱexercises.ȱThisȱchangeȱmakesȱtheȱprogramȱevenȱmoreȱ
spaceȱ efficient,ȱatȱaȱ costȱofȱtimeȱefficiency.ȱWhatȱisȱtheȱ largestȱ primeȱ numberȱ youȱ
canȱcomputeȱinȱthisȱmannerȱonȱyourȱsystem?ȱ
Download at http://www.pin5i.com/
164ȱ
Chapter 6 Pointer
6. Areȱ thereȱ asȱ manyȱ largeȱ primeȱ numbersȱ asȱ thereȱ areȱ smallȱ ones?ȱ Inȱ otherȱ words,ȱ
areȱthereȱasȱmanyȱprimeȱnumbersȱbetweenȱ50,000ȱandȱ51,000ȱasȱthereȱareȱbetween,ȱ
say,ȱ 1,000,000ȱ andȱ 1,001,000?ȱ Useȱ theȱ previousȱ programȱ toȱ determineȱ howȱ manyȱ
primeȱnumbersȱthereȱareȱbetweenȱ0ȱandȱ1000,ȱbetweenȱ1000ȱandȱ2000,ȱandȱsoȱforthȱ
upȱtoȱ1,000,000ȱ(orȱasȱhighȱasȱyouȱcanȱgoȱonȱyourȱsystem).ȱWhatȱisȱtheȱtrendȱinȱtheȱ
numberȱofȱprimesȱperȱthousandȱnumbers?ȱ
Download at http://www.pin5i.com/
7
Functions
Thereȱ isȱ muchȱ aboutȱ functionsȱ inȱ Cȱ thatȱ isȱ similarȱ toȱ functionsȱ inȱ otherȱ languages,ȱ
whichȱisȱwhyȱyouȇveȱbeenȱableȱtoȱuseȱthemȱthusȱfarȱwithȱonlyȱanȱinformalȱdiscussion.ȱȱ
Howeverȱ thereȱ areȱ someȱ aspectsȱ ofȱ functionsȱ thatȱ areȱ lessȱ intuitive,ȱ soȱ thisȱ chapterȱ
formallyȱdescribesȱfunctionsȱinȱC.ȱ
ȱ
ȱ
ȱ
7.1 Function Definition
ȱ
Theȱ definitionȱ ofȱ aȱ functionȱ specificsȱ theȱ functionȱ body,ȱ theȱ blockȱ ofȱ statementsȱ toȱ beȱ
executedȱwhenȱtheȱfunctionȱisȱcalled.ȱInȱcontrast,ȱaȱfunctionȱdeclarationȱisȱusedȱwhereȱ
theȱ functionȱ isȱ beingȱ called.ȱ ȱ Aȱ declarationȱ givesȱ theȱ compilerȱ informationȱ aboutȱ theȱ
functionȱsoȱthatȱitȱcanȱbeȱcalledȱcorrectly.ȱLetȇsȱlookȱfirstȱatȱdefinitions.ȱ
Aȱfunctionȱisȱdefinedȱwithȱthisȱsyntax:ȱ
ȱ
type
name( formal_parameters )
block
ȱ
Recallȱ thatȱ aȱ blockȱ isȱ aȱ pairȱ ofȱ bracesȱ enclosingȱ optionalȱ declarationsȱ followedȱ byȱ
optionalȱstatements.ȱTheȱminimalȱfunction,ȱtherefore,ȱlooksȱlikeȱthis:ȱ
ȱ
function_name()
{
}
ȱ
Whenȱcalled,ȱthisȱfunctionȱsimplyȱreturns.ȱNevertheless,ȱitȱservesȱaȱusefulȱpurposeȱasȱaȱ
stub,ȱ aȱ placeholderȱ forȱ codeȱ thatȱ hasȱ yetȱ toȱ beȱ implemented.ȱ Writingȱ stubs,ȱ orȱ
ȈstubbingȱoutȈȱcodeȱthatȱhasȱnotȱyetȱbeenȱwritten,ȱletsȱyouȱcompileȱandȱtestȱtheȱrestȱofȱ
theȱprogram.ȱ
Download at http://www.pin5i.com/
166
K&R C
Chapter 7 Functions
Theȱ listȱ ofȱ formalȱ parametersȱ includesȱ variableȱ namesȱ andȱ theirȱ typeȱ
declarations.ȱ Theȱ blockȱ containsȱ declarationsȱ forȱ localȱ variablesȱ andȱ theȱ statementsȱ
thatȱareȱexecutedȱwhenȱtheȱfunctionȱisȱcalled.ȱProgramȱ7.1ȱisȱanȱexampleȱofȱaȱsimpleȱ
function.ȱ
Writingȱtheȱfunctionȱtypeȱonȱaȱseparateȱlineȱfromȱtheȱfunctionȱnameȱisȱaȱmatterȱ
ofȱstyle;ȱitȱmakesȱitȱeasierȱtoȱlocateȱtheȱfunctionȱnamesȱwhenȱperusingȱtheȱsourceȱcodeȱ
eitherȱvisuallyȱorȱwithȱsomeȱprogram.ȱ
ȱ
Inȱ K&Rȱ C,ȱ theȱ typesȱ ofȱ formalȱ parametersȱ wereȱ declaredȱ inȱ aȱ separateȱ listȱ thatȱ
appearedȱbetweenȱtheȱparameterȱlistȱandȱtheȱopeningȱbraceȱofȱtheȱfunctionȱbody,ȱlikeȱ
this:ȱ
ȱ
int *
find_int( key, array, array_len )
int key;
int array[];
int array_len;
{
/*
** Find the place in an array where a particular integer value
** is stored, and return a pointer to that location.
*/
#include <stdio.h>
int *
find_int( int key, int array[], int array_len )
{
int
i;
/*
** For each location in the array ...
*/
for( i = 0; i < array_len; i += 1 )
/*
** Check the location for the desired value.
*/
if( array[ i ] == key )
return &array[ i ];
return NULL;
}
Programȱ7.1ȱFindȱanȱintegerȱinȱanȱarrayȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱfind_int.cȱ
Download at http://www.pin5i.com/
7.1 Function Definition
167
ThisȱdeclarationȱformȱisȱallowedȱbyȱtheȱStandardȱmainlyȱsoȱthatȱolderȱprogramsȱcanȱbeȱ
compiledȱ withoutȱ modification.ȱ Theȱ newerȱ declarationȱ styleȱ isȱ preferredȱ forȱ twoȱ
reasons.ȱ First,ȱ itȱ eliminatesȱ theȱ redundancyȱ ofȱ dieȱ oldȱ style.ȱ Moreȱ importantly,ȱ itȱ
allowsȱ forȱ theȱ useȱ ofȱ functionȱ prototypes,ȱ discussedȱ laterȱ inȱ thisȱ chapter,ȱ whichȱ
improveȱtheȱcompilerȇsȱerrorȱcheckingȱofȱfunctionȱcalls.ȱ
ȱ
ȱ
ȱ
7.1.1 Return Statement
ȱ
Whenȱexecutionȱreachesȱtheȱendȱofȱtheȱfunctionȱdefinition,ȱtheȱfunctionȱreturns,ȱthatȱis,ȱ
executionȱ goesȱ backȱ toȱ whereȱ theȱ functionȱ wasȱ called.ȱ Theȱ returnȱ statementȱ allowsȱ
youȱ toȱ returnȱ fromȱ anywhereȱ inȱ theȱ functionȱ body,ȱ notȱ justȱ atȱ itsȱ end.ȱ Itsȱ syntaxȱ isȱ
shownȱbelow.ȱ
ȱ
ȱ
return expression;
ȱ
Theȱ expressionȱisȱoptional.ȱItȱisȱomittedȱinȱfunctionsȱthatȱdoȱnotȱreturnȱaȱvalueȱtoȱtheȱ
callingȱ program,ȱ whatȱ mostȱ otherȱ languagesȱ callȱ aȱ procedure.ȱ Functionsȱ thatȱ returnȱ
implicitlyȱbyȱreachingȱtheȱendȱofȱtheirȱcodeȱalsoȱdoȱnotȱreturnȱaȱvalue.ȱȱProcedureȬtypeȱ
functionsȱshouldȱbeȱdeclaredȱwithȱtheȱtypeȱvoid.ȱ
Aȱtrueȱfunctionȱisȱcalledȱfromȱwithinȱanȱexpression,ȱandȱmustȱreturnȱaȱvalueȱthatȱ
isȱ usedȱ inȱ evaluatingȱ theȱ expression.ȱ Theȱ returnȱ statementȱ inȱ theseȱ functionsȱ mustȱ
includeȱ theȱ expression.ȱ Usually,ȱ theȱ expressionȱ willȱ beȱ ofȱ theȱ typeȱ thatȱ theȱ functionȱ
wasȱ declaredȱ toȱ return.ȱ Anȱ expressionȱ ofȱ aȱ differentȱ typeȱ isȱ permittedȱ onlyȱ ifȱ theȱ
compilerȱcanȱconvertȱitȱtoȱdieȱproperȱtypeȱthroughȱtheȱusualȱarithmeticȱconversions.ȱ
Someȱprogrammersȱpreferȱtoȱwriteȱreturnȱstatementsȱlikeȱthis:ȱ
ȱ
return( x );
ȱ
Theȱsyntaxȱdoesȱnotȱrequireȱparentheses,ȱbutȱyouȱcanȱuseȱthemȱifȱyouȱpreferȱbecauseȱ
parenthesesȱareȱalwaysȱlegalȱaroundȱanȱexpression.ȱ
InȱC,ȱbothȱtypesȱofȱsubprogramsȱareȱcalledȱfunctions.ȱȱItȱisȱpossibleȱtoȱcallȱaȱtrueȱ
functionȱ(oneȱthatȱreturnsȱaȱvalue)ȱwithoutȱusingȱtheȱvalueȱinȱanyȱexpression.ȱInȱthisȱ
situation,ȱtheȱreturnedȱvalueȱisȱjustȱdiscarded.ȱȱCallingȱaȱprocedureȬtypeȱfunctionȱfromȱ
withinȱ anȱ expressionȱ isȱ aȱ seriousȱ error,ȱ though,ȱ becauseȱ anȱ unpredictableȱ (garbage)ȱ
valueȱ isȱ usedȱ inȱ evaluatingȱ theȱ expression.ȱ Fortunately,ȱ modernȱ compilersȱ usuallyȱ
catchȱthisȱerrorȱbecauseȱtheyȱareȱstricterȱaboutȱfunctionȱreturnȱtypesȱthanȱwereȱearlierȱ
compilers.ȱ
Download at http://www.pin5i.com/
168
Chapter 7 Functions
7.2 Function Declaration
ȱ
Whenȱ theȱ compilerȱ encountersȱ aȱ callȱ toȱ aȱ function,ȱ itȱ generatesȱ codeȱ toȱ passȱ theȱ
argumentsȱandȱcallȱtheȱfunction,ȱandȱcodeȱtoȱreceiveȱtheȱvalueȱ(ifȱany)ȱsentȱbackȱbyȱtheȱ
function.ȱButȱhowȱdoesȱtheȱcompilerȱknowȱwhatȱkindsȱofȱargumentsȱ(andȱhowȱmany)ȱ
theȱfunctionȱexpectsȱtoȱget,ȱandȱwhatȱkindȱofȱvalueȱ(ifȱany)ȱthatȱtheȱfunctionȱreturns?ȱ
Ifȱ thereȱ isnȇtȱ anyȱ specificȱ informationȱ givenȱ aboutȱ theȱ function,ȱ theȱ compilerȱ
assumesȱthatȱtheȱcallȱhasȱtheȱcorrectȱnumberȱandȱtypesȱofȱarguments.ȱItȱalsoȱassumesȱ
thatȱtheȱfunctionȱwillȱreturnȱanȱinteger,ȱwhichȱusuallyȱleadsȱtoȱerrorsȱforȱfunctionsȱthatȱ
returnȱnonintegralȱtypes.ȱ
ȱ
ȱ
ȱ
7.2.1 Prototypes
K&R C
ȱ
Itȱisȱsaferȱtoȱgiveȱtheȱcompilerȱspecificȱinformationȱaboutȱtheȱfunction,ȱwhichȱweȱcanȱ
doȱ twoȱ differentȱ ways.ȱ First,ȱ ifȱ theȱ definitionȱ forȱ theȱ functionȱ appearsȱ earlierȱ inȱ theȱ
sameȱsourceȱfile,ȱtheȱcompilerȱwillȱrememberȱtheȱnumberȱandȱtypesȱofȱitsȱargumentsȱ
andȱtheȱtypeȱofȱitsȱreturnȱvalue.ȱItȱcanȱthenȱcheckȱallȱsubsequentȱcallsȱtoȱtheȱfunctionȱ
(inȱthatȱsourceȱfile)ȱtoȱmakeȱsureȱtheyȱareȱcorrect.ȱ
ȱ
Ifȱaȱfunctionȱisȱdefinedȱusingȱtheȱoldȱsyntax,ȱwithȱaȱseparateȱlistȱgivingȱtheȱtypesȱofȱtheȱ
arguments,ȱthenȱtheȱcompilerȱremembersȱonlyȱtheȱtypeȱofȱtheȱfunctionȇsȱreturnȱvalue.ȱȱ
Noȱinformationȱisȱsavedȱonȱtheȱnumberȱorȱtypesȱofȱtheȱarguments.ȱBecauseȱofȱthisȱfact,ȱ
itȱisȱimportantȱtoȱuseȱtheȱnewȱfunctionȱdeclarationȱstyleȱwheneverȱpossible.ȱ
Theȱ secondȱ wayȱ toȱ giveȱ theȱ compilerȱ informationȱ aboutȱ aȱ functionȱ isȱ toȱ useȱ aȱ
functionȱ prototype,ȱ whichȱ youȱ sawȱ inȱ Chapterȱ 1.ȱ Aȱ prototypeȱ summarizesȱ theȱ
declarationȱ atȱ theȱ beginningȱ ofȱ theȱ functionȱ definition,ȱ thusȱ givingȱ theȱ compilerȱ
completeȱ informationȱ onȱ howȱ theȱ functionȱ isȱ toȱ beȱ called.ȱ Theȱ mostȱ convenientȱ (andȱ
safest)ȱwayȱtoȱuseȱaȱprototypeȱisȱtoȱputȱitȱinȱaȱseparateȱfileȱandȱthenȱ #includeȱthatȱfileȱ
whereverȱitȱisȱneeded.ȱThisȱtechniqueȱavoidsȱtheȱpossibilityȱofȱmistypingȱaȱprototype.ȱ
Itȱalsoȱsimplifiesȱmaintenanceȱofȱtheȱprogramȱbyȱonlyȱhavingȱoneȱphysicalȱcopyȱofȱtheȱ
prototype.ȱ Shouldȱ theȱ prototypeȱ needȱ toȱ beȱ changed,ȱ thereȱ isȱ onlyȱ oneȱ copyȱ ofȱ itȱ toȱ
modify.ȱ
Toȱ illustrate,ȱ hereȱ isȱ aȱ prototypeȱ forȱ theȱ find_intȱ functionȱ fromȱ theȱ previousȱ
example:ȱ
ȱ
int *find_int( int key, int array[], int len );
ȱ
Noteȱ theȱ semicolonȱ atȱ theȱ end:ȱ itȱ distinguishesȱ aȱ prototypeȱ fromȱ theȱ beginningȱ ofȱ aȱ
functionȱdefinition.ȱTheȱprototypeȱtellsȱtheȱcompilerȱtheȱnumberȱofȱarguments,ȱtheȱȱ
ȱ
Download at http://www.pin5i.com/
7.2 Function Declaration
TIP
169
typeȱ ofȱ eachȱ argument,ȱ andȱ theȱ typeȱ ofȱ theȱ returnedȱ value.ȱ Afterȱ theȱ prototypeȱ hasȱ
beenȱseen,ȱtheȱcompilerȱwillȱcheckȱcallsȱmadeȱtoȱtheȱfunctionȱtoȱ makeȱsureȱthatȱtheirȱ
argumentsȱareȱcorrectȱandȱthatȱtheȱreturnedȱvalueȱisȱusedȱproperly.ȱWhereȱmismatchesȱ
occurȱ (forȱ example,ȱ anȱ argumentȱ ofȱ theȱ wrongȱ type)ȱ theȱ compilerȱ willȱ convertȱ theȱ
valueȱtoȱtheȱcorrectȱtypeȱifȱsuchȱaȱconversionȱisȱpossible.ȱ
ȱ
NoteȱthatȱIȱputȱargumentȱnamesȱinȱtheȱaboveȱprototype.ȱWhileȱnotȱrequired,ȱitȱisȱwiseȱ
toȱ includeȱ descriptiveȱ parameterȱ namesȱ inȱ functionȱ prototypesȱ becauseȱ theyȱ giveȱ
usefulȱ informationȱ toȱ clientsȱ wishingȱ toȱ callȱ theȱ function.ȱ Forȱ example,ȱ whichȱ ofȱ theȱ
followingȱtwoȱprototypesȱdoȱyouȱfindȱmoreȱuseful?ȱ
ȱ
char *strcpy( char *, char * );
char *strcpy( char *destination, char *source );
CAUTION!
Theȱfollowingȱcodeȱfragmentȱillustratesȱaȱdangerousȱwayȱtoȱuseȱfunctionȱprototypes.ȱ
ȱ
void
a()
{
int
...
*func( int *value, int len );
int
...
func( int len, int *value );
}
void
b()
{
}
ȱ
Lookȱcloselyȱatȱtheȱprototypesȱandȱyouȱwillȱseeȱthatȱtheyȱareȱdifferent.ȱTheȱargumentsȱ
areȱ reversed,ȱ andȱ theȱ returnȱ valuesȱ areȱ differentȱ types.ȱ Theȱ problemȱ isȱ thatȱ eachȱ
prototypeȱ isȱ writtenȱ insideȱ theȱ bodyȱ ofȱ aȱ function.ȱ Theyȱ haveȱ blockȱ scope,ȱ soȱ theȱ
compilerȱ throwsȱ outȱ whatȱ itȱ learnedȱ fromȱ theȱ prototypeȱ atȱ theȱ endȱ ofȱ eachȱ functionȱ
andȱneverȱdetectsȱtheȱmismatch.ȱ
ȱ
TheȱStandardȱstatesȱthatȱaȱfunctionȱprototypeȱmustȱmarchȱanyȱearlierȱprototypeȱ
forȱ theȱ sameȱ functionȱ thatȱ isȱ inȱ scope,ȱ orȱ elseȱ anȱ errorȱ messageȱ isȱ printed.ȱ Inȱ thisȱ
example,ȱ though,ȱ theȱ scopeȱ forȱ theȱ firstȱ blockȱ doesȱ notȱ overlapȱ theȱ secondȱ block.ȱȱ
Therefore,ȱ theȱ mistakesȱ inȱ theȱ prototypesȱ goȱ undetected.ȱ Oneȱ orȱ theȱ otherȱ ofȱ theseȱ
prototypesȱisȱwrongȱ(maybeȱboth),ȱbutȱtheȱcompilerȱneverȱseesȱtheȱcontradictionȱsoȱnoȱ
errorȱmessagesȱareȱproduced.ȱ
Download at http://www.pin5i.com/
170
Chapter 7 Functions
Theȱcodeȱfragmentȱbelowȱillustratesȱtheȱpreferredȱwayȱtoȱuseȱprototypes:ȱ
ȱ
*include "func.h"
void
a()
{
...
}
void
b()
{
...
}
ȱ
Theȱfileȱfunc.hȱcontainsȱtheȱprototypeȱ
ȱ
int
*func( int *value, int len );
ȱ
Thisȱtechniquesȱisȱbetterȱinȱseveralȱways.ȱ
ȱ
1. Theȱprototypeȱnowȱhasȱfileȱscopeȱsoȱthatȱoneȱcopyȱofȱitȱappliesȱtoȱtheȱentireȱsourceȱ
file,ȱ whichȱ isȱ easierȱ thanȱ writingȱ aȱ separateȱ copyȱ inȱ eachȱ placeȱ fromȱ whichȱ theȱ
functionȱisȱcalled.ȱ
2. Theȱ prototypeȱ isȱ onlyȱ writtenȱ once,ȱ soȱ thereȱ isȱ noȱ chanceȱ forȱ disagreementsȱ
betweenȱmultipleȱcopies.ȱ
3. Ifȱ theȱ functionȱ definitionȱ changes,ȱ allȱ weȱ haveȱ toȱ doȱ isȱ modifyȱ theȱ prototypeȱ andȱ
recompileȱeachȱsourceȱfileȱthatȱincludesȱit.ȱ
4. Ifȱ theȱ prototypeȱ isȱ alsoȱ #includeȇdȱ intoȱ theȱ fileȱ whereȱ theȱ functionȱ isȱ defined,ȱ theȱ
compilerȱwillȱbeȱableȱtoȱverifyȱthatȱtheȱprototypeȱmatchesȱtheȱfunctionȱdefinition.ȱ
ȱ
Byȱwritingȱtheȱprototypeȱonce,ȱweȱeliminateȱtheȱchanceȱthatȱmultipleȱcopiesȱofȱitȱdiffer.ȱ
However,ȱ theȱ prototypeȱ mustȱ matchȱ theȱ functionȱ definition.ȱ Includingȱ theȱ prototypeȱ
inȱtheȱfileȱwhereȱtheȱfunctionȱisȱdefinedȱletsȱtheȱcompilerȱverifyȱthatȱtheyȱmatch.ȱ
Considerȱthisȱdeclaration,ȱwhichȱlooksȱambiguous:ȱ
int
*func();
Itȱ couldȱ beȱ eitherȱ anȱ oldȬstyleȱ declarationȱ (givingȱ theȱ returnȱ typeȱ ofȱ func)ȱ orȱ aȱ newȬ
styleȱprototypeȱforȱaȱfunctionȱwithȱnoȱarguments.ȱWhichȱisȱit?ȱTheȱdeclarationȱmustȱbeȱ
interpretedȱ asȱ anȱ oldȬstyleȱ declarationȱ inȱ orderȱ toȱ maintainȱ compatibilityȱ with
Download at http://www.pin5i.com/
7.2 Function Declaration
171
preȬANSIȱprograms.ȱAȱprototypeȱforȱaȱfunctionȱwithoutȱargumentsȱisȱwrittenȱlikeȱthis:ȱ
ȱ
int
*func( void );
ȱ
Theȱ keywordȱ voidȱ indicatesȱ thatȱ thereȱ arenȇtȱ anyȱ arguments,ȱ notȱ thatȱ thereȱ isȱ oneȱ
argumentȱofȱtypeȱvoid.ȱ
ȱ
ȱ
ȱ
7.2.2 Default Function Assumptions
CAUTION!
ȱ
Whenȱaȱcallȱisȱmadeȱtoȱaȱfunctionȱforȱwhichȱnoȱprototypeȱhasȱbeenȱseen,ȱtheȱfunctionȱisȱ
assumedȱtoȱreturnȱanȱintegerȱvalue.ȱThisȱcanȱleadȱtoȱerrorsȱforȱfunctionsȱwhichȱreturnȱ
nonintegralȱvalues.ȱ
ȱ
Whileȱitȱisȱrecommendedȱthatȱallȱfunctionsȱbeȱprototyped,ȱitȱisȱespeciallyȱimportantȱtoȱ
prototypeȱfunctionsȱthatȱreturnȱnonintegralȱvalues.ȱRememberȱthatȱtheȱtypeȱofȱaȱvalueȱ
isȱnotȱinherentȱinȱtheȱvalueȱitself,ȱbutȱratherȱinȱtheȱwayȱthatȱitȱisȱused.ȱIfȱtheȱcompilerȱ
assumesȱthatȱaȱfunctionȱreturnsȱanȱintegralȱvalue,ȱitȱwillȱgenerateȱintegerȱinstructionsȱ
toȱmanipulateȱtheȱvalue.ȱIfȱtheȱvalueȱisȱactuallyȱaȱnonintegralȱtype,ȱfloatingȬpointȱforȱ
example,ȱtheȱresultȱwillȱusuallyȱbeȱincorrect.ȱ
Letȇsȱ lookȱ atȱ anȱ exampleȱ ofȱ thisȱ error.ȱ Imagineȱ aȱ functionȱ xyzȱ thatȱ returnsȱ theȱ
floatȱvalueȱ3.14ȱ.ȱTheȱbitsȱusedȱtoȱrepresentȱthisȱfloatingȬpointȱnumberȱonȱaȱSunȱSparcȱ
workstationȱareȱ
ȱ
01000000010010001111010111000011
ȱ
Nowȱassumeȱthatȱtheȱfunctionȱisȱcalledȱlikeȱthis:ȱ
ȱ
ȱ
float f;
...
f = xyz();
ȱ
Ifȱthereȱisȱnoȱprototypeȱforȱtheȱfunction,ȱtheȱcompilerȱwillȱassumeȱthatȱitȱisȱreturningȱ
anȱintegerȱandȱwillȱgenerateȱinstructionsȱtoȱconvertȱtheȱvalueȱtoȱfloatingȬpointȱbeforeȱ
assigningȱitȱtoȱf.ȱ
Theȱ functionȱ returnsȱ theȱ bitsȱ shownȱ above.ȱ Theȱ conversionȱ instructionsȱ
interpretȱ themȱ asȱ theȱ integerȱ 1,078,523,331ȱ andȱ convertȱ thisȱ integerȱ valueȱ toȱ floatingȬ
point,ȱandȱtheȱresultȱisȱstoredȱinȱf.ȱ
Whyȱ wasȱ thisȱ conversionȱ doneȱ whenȱ theȱ valueȱ returnedȱ wasȱ alreadyȱ inȱ
floatingȬpointȱformat?ȱTheȱcompilerȱhasȱnoȱwayȱofȱknowingȱitȱwas,ȱbecauseȱthereȱwasȱ
noȱ prototypeȱ orȱ declarationȱ toȱ tellȱ itȱ so.ȱ Thisȱ exampleȱ illustratesȱ whyȱ itȱ isȱ vitalȱ forȱ
functionsȱthatȱreturnȱvaluesȱotherȱthanȱintegersȱtoȱhaveȱprototypes.ȱ
Download at http://www.pin5i.com/
172
Chapter 7 Functions
7.3 Function Arguments
ȱ
Allȱ argumentsȱ toȱ Cȱ functionsȱ areȱ passedȱ withȱ aȱ techniqueȱ knownȱ asȱ callȱ byȱ value,ȱ
whichȱ meansȱ thatȱtheȱfunctionȱ getsȱaȱcopyȱofȱtheȱargumentȱ value.ȱȱThusȱtheȱ functionȱ
mayȱ modifyȱ itsȱ parametersȱ withoutȱ fearȱ ofȱ affectingȱ theȱ valuesȱ ofȱ theȱ argumentsȱ
passedȱ fromȱ theȱ callingȱ program.ȱ Thisȱ behaviorȱ isȱ theȱ sameȱ asȱ valueȱ (notȱ var)ȱ
parametersȱinȱModulaȱandȱPascal.ȱ
TheȱruleȱinȱCȱisȱsimple:ȱallȱargumentsȱareȱpassedȱbyȱvalue.ȱȱHowever,ȱifȱanȱarrayȱ
nameȱ isȱ passedȱ asȱ anȱ argumentȱ andȱ aȱ subscriptȱ isȱ usedȱ onȱ theȱ argumentȱ inȱ theȱ
function,ȱthenȱmodifyingȱarrayȱelementsȱinȱtheȱfunctionȱactuallyȱchangesȱtheȱelementsȱ
ofȱ theȱ arrayȱ inȱ theȱ callingȱ program.ȱ Theȱ functionȱ accessesȱ theȱ veryȱ sameȱ arrayȱ thatȱ
existsȱ inȱ theȱ callingȱ program;ȱ theȱ arrayȱ isȱ notȱ copied.ȱ Thisȱ behaviorȱ isȱ termedȱ callȱ byȱ
referenceȱandȱisȱhowȱvarȱparametersȱareȱimplementedȱinȱmanyȱotherȱlanguages.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Check the value for even parity.
*/
int
even_parity( int value, int n_bits )
{
int
parity = 0;
/*
** Count the number of 1-bits in the value.
*/
while( n_bits > 0 ){
parity += value & 1;
value >>= 1;
n_bits -= 1;
}
/*
** Return TRUE if the low order bit of the count is zero
** (which means that there were an even number of 1's).
*/
return ( parity % 2 ) == 0;
}
ȱ
Programȱ7.2ȱParityȱcheckȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱparity.cȱ
Download at http://www.pin5i.com/
7.3 Function Arguments
173
Theȱbehaviorȱwithȱarrayȱ argumentsȱ seemsȱtoȱcontradictȱtheȱcallȱbyȱvalueȱ rule.ȱȱ
Howeverȱ thereȱ isnȇtȱ aȱ contradiction—theȱ valueȱ ofȱ theȱ arrayȱ nameȱ isȱ reallyȱ aȱ pointer,ȱ
andȱ aȱ copyȱ ofȱ theȱ pointerȱ isȱ passedȱ toȱ theȱ function.ȱ Aȱ subscriptȱ isȱ reallyȱ aȱ formȱ ofȱ
indirectionȱandȱapplyingȱindirectionȱtoȱtheȱpointerȱaccessesȱtheȱlocationsȱthatȱitȱpointsȱ
to.ȱ Theȱ argumentȱ (theȱ pointer)ȱ isȱ indeedȱ aȱ copy,ȱ butȱ theȱ indirectionȱ usesȱ theȱ copyȱ toȱ
accessȱ theȱ originalȱ arrayȱ values.ȱ Weȱ returnȱ toȱ thisȱ pointȱ inȱ theȱ nextȱ chapter,ȱ butȱ forȱ
nowȱrememberȱtheseȱtwoȱrules:ȱ
ȱ
1. Scalarȱargumentsȱtoȱaȱfunctionȱareȱpassedȱbyȱvalue.ȱ
2. Arrayȱargumentsȱtoȱaȱfunctionȱbehaveȱasȱthoughȱtheyȱareȱpassedȱbyȱreference.ȱ
ȱ
Programȱ 7.2ȱ illustratesȱ theȱ callȬbyȬvalueȱ behaviorȱ ofȱ scalarȱ functionȱ arguments.ȱ Thisȱ
functionȱchecksȱwhetherȱtheȱfirstȱargumentȱhasȱevenȱparity,ȱthatȱis,ȱifȱtheȱnumberȱofȱ1ȇsȱ
itȱ containsȱ isȱ anȱ evenȱ number.ȱ Theȱ secondȱ argumentȱ specifiesȱ theȱ numberȱ ofȱ
significantȱbitsȱinȱtheȱvalue.ȱȱTheȱfunctionȱworksȱbyȱshiftingȱtheȱvalueȱbyȱoneȱbit,ȱoverȱ
andȱover,ȱsoȱthatȱeveryȱbitȱappearsȱsoonerȱorȱlaterȱinȱtheȱrightȬmostȱposition.ȱTheȱbitsȱ
areȱ addedȱ together,ȱ oneȱ byȱ one,ȱ soȱ thatȱ afterȱ theȱ loopȱ endsȱ weȱ haveȱ aȱ countȱ ofȱ theȱ
numberȱ ofȱ 1ȇsȱ inȱ theȱ originalȱ value.ȱ Finally,ȱ theȱ countȱ isȱ testedȱ toȱ seeȱ ifȱ itsȱ leastȱ
significantȱbitȱisȱset.ȱIfȱnot,ȱtheȱnumberȱofȱ1ȇsȱwasȱeven.ȱ
Theȱinterestingȱfeatureȱofȱthisȱfunctionȱisȱthatȱitȱdestroysȱbothȱofȱitsȱargumentsȱ
asȱ theȱ workȱ progresses.ȱ Thisȱ techniqueȱ worksȱ fine,ȱ becauseȱ withȱ callȬbyȬvalueȱ theȱ
argumentsȇȱareȱcopiesȱofȱtheȱcallerȇsȱvalues.ȱDestroyingȱtheȱcopiesȱdoesȱnotȱaffectȱtheȱ
originalȱvalues.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Exchange two integers in the calling program (doesn't work!).
*/
void
swap( int x, int y )
{
int temp;
temp = x;
x = y;
y = temp;
}
Programȱ7.3aȱȱSwapȱintegers:ȱbadȱversionȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱswap1.cȱ
Download at http://www.pin5i.com/
174
Chapter 7 Functions
Programȱ7.3aȱisȱdifferent;ȱitȱwantsȱtoȱmodifyȱtheȱcallerȇsȱarguments.ȱȱTheȱintentȱ
ofȱthisȱfunctionȱisȱtoȱexchangeȱtheȱcontentsȱofȱtwoȱargumentsȱinȱtheȱcallingȱprogram.ȱItȱ
doesnȇtȱ work,ȱ though,ȱ becauseȱ allȱ thatȱ isȱ exchangedȱ areȱ theȱ copiesȱ ofȱ theȱ valuesȱ thatȱ
wereȱsentȱtoȱtheȱfunction.ȱTheȱoriginalȱvaluesȱareȱuntouched.ȱ
Toȱaccessȱtheȱcallerȇsȱvaluesȱyouȱmustȱpassȱpointersȱtoȱtheȱlocationsȱyouȱwishȱtoȱ
modify.ȱTheȱfunctionȱmustȱthenȱuseȱindirectionȱtoȱfollowȱtheȱpointersȱandȱmodifyȱtheȱ
desiredȱ locations.ȱ Programȱ 7.3bȱ usesȱ thisȱ technique.ȱ Becauseȱ theȱ functionȱ expectsȱ
pointersȱasȱarguments,ȱweȱwouldȱcallȱitȱlikeȱthis:ȱ
ȱ
swap( &a, &b );
ȱ
Programȱ7.4ȱsetsȱallȱofȱtheȱelementsȱofȱanȱarrayȱtoȱzero,ȱȱ n_elementsȱisȱaȱscalarȱ
soȱ itȱ isȱ passedȱ byȱ value;ȱ modifyingȱ itsȱ valueȱ inȱ theȱ functionȱ doesȱ notȱ affectȱ theȱ
correspondingȱargumentȱinȱtheȱcallingȱprogram.ȱOnȱtheȱotherȱhand,ȱtheȱfunctionȱdoesȱ
indeedȱsetȱtheȱelementsȱofȱtheȱcallingȱprogramȇsȱarrayȱtoȱzero.ȱTheȱvalueȱofȱtheȱarrayȱ
argumentȱisȱaȱpointer,ȱandȱtheȱsubscriptȱperformsȱindirectionȱwithȱthisȱpointer.ȱ
Thisȱ exampleȱ alsoȱ illustratesȱ anotherȱ feature.ȱ Itȱ isȱ legalȱ toȱ declareȱ arrayȱ
parametersȱ withoutȱ specifyingȱ aȱ sizeȱ becauseȱ memoryȱ isȱ notȱ allocatedȱ forȱ theȱ arrayȱ
elementsȱ inȱ theȱ function;ȱ theȱ indirectionȱ causesȱ theȱ arrayȱ elementsȱ inȱ theȱ callingȱ
programȱtoȱbeȱaccessedȱinstead.ȱThus,ȱaȱsingleȱfunctionȱcanȱaccessȱarrayȱofȱanyȱsize,ȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Exchange two integers in the calling program.
*/
void
swap( int *x, int *y )
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
ȱ
Programȱ7.3bȱȱSwapȱintegers:ȱgoodȱversionȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱswap2.cȱ
Download at http://www.pin5i.com/
7.3 Function Arguments
K&R C
175
ȱwhichȱ shouldȱ exciteȱ Pascalȱ programmers.ȱ However,ȱ thereȱ isnȇtȱ anyȱ wayȱ forȱ theȱ
functionȱ toȱ figureȱ outȱ theȱ actualȱ sizeȱ ofȱ anȱarrayȱ argument,ȱ soȱ thisȱ informationȱ mustȱ
alsoȱbeȱpassedȱexplicitlyȱifȱitȱisȱneeded.ȱ
ȱ
RecallȱthatȱinȱK&RȱC,ȱfunctionȱparametersȱwereȱdeclaredȱlikeȱthis:ȱ
ȱ
int
func( a, b, c )
int a;
char b;
float c;
{
...
CAUTION!
ȱ
Anotherȱ reasonȱ toȱ avoidȱ thisȱ styleȱ isȱ thatȱ K&Rȱ compilersȱ handledȱ argumentsȱ aȱ littleȱ
differently:ȱ charȱandȱshortȱargumentsȱwereȱpromotedȱtoȱ intȱbeforeȱbeingȱpassed,ȱandȱ
floatȱ argumentsȱ wereȱ promotedȱ toȱ doubleȬȱ Theseȱ conversionsȱ areȱ calledȱ theȱ defaultȱ
argumentȱpromotions,ȱandȱbecauseȱofȱthemȱyouȱwillȱfrequentlyȱseeȱfunctionȱparametersȱ
inȱpreȬANSIȱprogramsȱdeclaredȱasȱintȱwhenȱinȱfactȱcharȱvaluesȱareȱpassed.ȱ
ȱ
Toȱ maintainȱ compatibility,ȱ ANSIȱ compilersȱ alsoȱ performȱ theseȱ conversionsȱ forȱ
functionsȱ declaredȱ inȱ theȱ oldȱ style.ȱ Theyȱ areȱ notȱ doneȱ onȱ functionsȱ thatȱ haveȱ beenȱ
prototyped,ȱthough,ȱsoȱmixingȱtheȱtwoȱstylesȱcanȱleadȱtoȱerrors.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Set all of the elements of an array to zero.
*/
void
clear_array( int array[], int n_elements
{
/*
** Clear the elements of the array
** and working towards the first.
** avoids going off the end of the
*/
while( n_elements > 0 )
array[ --n_elements ] = 0;
}
ȱ
Programȱ7.4ȱȱSetȱanȱarrayȱtoȱzeroȱ ȱ
ȱ
)
starting with the last
Note the predecrement
array.
ȱ
ȱ
ȱ
ȱ
ȱ
clrarray.cȱ
Download at http://www.pin5i.com/
176
Chapter 7 Functions
7.4 ADTs and Black Boxes
ȱ
Cȱfacilitatesȱtheȱdesignȱandȱimplementationȱofȱabstractȱdataȱtypes,ȱorȱADTs,ȱbecauseȱofȱ
itsȱ abilityȱ toȱ limitȱ theȱ scopeȱ ofȱ functionȱ andȱ dataȱ definitions.ȱ Thisȱ techniqueȱ isȱ alsoȱ
referredȱtoȱasȱblackȱboxȱdesign.ȱTheȱbasicȱideaȱbehindȱanȱabstractȱdataȱtypeȱisȱsimple—aȱ
moduleȱ hasȱ aȱ functionalȱ specification,ȱ whichȱ statesȱ theȱ workȱ thatȱ theȱ moduleȱ willȱ
perform,ȱ andȱ anȱ interfaceȱ specification,ȱ whichȱ definesȱ howȱ theȱ moduleȱ isȱ used.ȱ
However,ȱusersȱofȱtheȱmoduleȱdoȱnotȱneedȱtoȱknowȱanyȱdetailsȱofȱitsȱimplementationȱ
andȱareȱpreventedȱfromȱaccessingȱtheȱmoduleȱinȱanyȱwayȱotherȱthanȱwithȱtheȱdefinedȱ
interface.ȱ
Limitingȱaccessȱtoȱtheȱmoduleȱisȱaccomplishedȱthroughȱtheȱjudiciousȱuseȱofȱtheȱ
staticȱkeywordȱtoȱrestrictȱtheȱaccessibilityȱofȱfunctionsȱandȱdataȱthatȱareȱnotȱpartȱofȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Declarations for the address list module.
*/
/*
** Data characteristics
**
**
Maximum lengths of the various data (includes space for the
**
terminating NUL byte), and maximum number of addresses.
*/
#define
NAME_LENGTH 30
/* longest name allowed */
#define
ADDR_LENGTH 100
/* longest address allowed */
#define
PHONE_LENGTH
11
/* longest phone # allowed */
#define
MAX_ADDRESSES
1000
/* # of addresses allowed */
/*
** Interface functions
**
**
Given a name, find the corresponding address.
*/
char const *
lookup_address( char const *name );
/*
**
Given a name, find the corresponding phone number.
*/
char const *
lookup_phone( char const *name );
ȱ
Programȱ7.5aȱȱAddressȱlistȱmodule:ȱheaderȱfileȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱaddrlist.hȱ
Download at http://www.pin5i.com/
7.4 ADTs and Black Boxes
177
theȱ interface.ȱ Forȱ example,ȱ considerȱ aȱ moduleȱ thatȱ maintainsȱ anȱ address/phoneȱ
numberȱlist.ȱTheȱmoduleȱmustȱprovideȱfunctionsȱtoȱlookȱupȱanȱaddressȱandȱtoȱlookȱupȱ
aȱphoneȱnumberȱforȱaȱspecificȱname.ȱHowever,ȱtheȱmannerȱinȱwhichȱtheȱlistȱisȱstoredȱisȱ
implementationȱdependent,ȱsoȱthisȱinformationȱisȱkeptȱprivateȱwithinȱtheȱmoduleȱandȱ
isȱnotȱavailableȱtoȱtheȱclient.ȱ
Theȱ nextȱ exampleȱ illustratesȱ oneȱ possibleȱ implementationȱ ofȱ thisȱ module.ȱ
Programȱ7.5aȱshowsȱtheȱincludeȱfileȱthatȱdefinesȱtheȱinterfaceȱusedȱbyȱtheȱclient,ȱandȱ
Programȱ7.5bȱshowsȱtheȱimplementation. 30
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Abstract data type to maintain an address list.
*/
#include "addrlist.h"
#include <stdio.h>
/*
**
The three parts to each address are kept in corresponding
**
elements of these three arrays.
*/
static
char name[MAX_ADDRESSES][NAME_LENGTH];
static
char address[MAX_ADDRESSES][ADDR_LENGTH];
static
char phone[MAX_ADDRESSES][PHONE_LENGTH];
/*
**
This routine locates a name in the array and returns the
**
subscript of the location found. If the name does not exist,
**
-1 is returned.
*/
static int
find_entry( char const *name_to_find )
{
int
entry;
for( entry = 0; entry < MAX_ADDRESSES; entry += 1 )
if( strcmp( name_to_find, name[ entry ] ) == 0 )
return entry;
Programȱ7.5bȱȱAddressȱlistȱmodule:ȱimplementationȱ ȱ
ȱ
ȱ
ȱ
continue…ȱ
ȱItȱwouldȱbeȱbetterȱifȱeachȱname,ȱaddress,ȱandȱphoneȱnumberȱwereȱstoredȱinȱaȱstructure,ȱbutȱstructuresȱarenȇtȱcoveredȱuntilȱ
Chapterȱ10.ȱ
30
Download at http://www.pin5i.com/
178
Chapter 7 Functions
return -1;
}
/*
**
Given a name, look up and return the corresponding address.
**
If the name was not found, return a NULL pointer instead.
*/
char const *
lookup_address( char const *name )
{
int
entry;
entry = find_entry( name );
if( entry == -1 )
return NULL;
else
return address[ entry ];
}
/*
**
Given a name, look up and return the corresponding phone
**
number. If the name was not found, return a NULL pointer
**
instead.
*/
char const *
lookup_phone( char const *name )
{
int
entry;
entry = find_entry( name );
if( entry == -1 )
return NULL;
else
return phone[ entry ];
}
ȱ
Programȱ7.5bȱȱAddressȱlistȱmodule:ȱimplementationȱ ȱ
ȱ
ȱ
ȱ
ȱȱaddrlist.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Programȱ 7.5ȱ isȱ aȱ goodȱ exampleȱ ofȱ aȱ blackȱ box.ȱ Theȱ functionalityȱ inȱ theȱ boxȱ isȱ
accessedȱ throughȱ theȱ specifiedȱ interface,ȱ whichȱ inȱ thisȱ caseȱ areȱ theȱ functionȱ
lookup_addressȱandȱ lookup_phone.ȱHowever,ȱtheȱuserȱcannotȱdirectlyȱaccessȱdataȱthatȱ
relateȱtoȱtheȱimplementation,ȱsuchȱasȱtheȱarrayȱorȱtheȱsupportȱfunctionȱ lookup_entry,ȱ
becauseȱtheseȱitemsȱareȱdeclaredȱstatic.
Download at http://www.pin5i.com/
7.5 Recursion
179
Theȱ powerȱ ofȱ thisȱ typeȱ ofȱ implementationȱ isȱ thatȱ itȱ makesȱ theȱ variousȱ partsȱ ofȱ theȱ
programȱ moreȱ independentȱ ofȱ oneȱ another.ȱ Forȱ example,ȱ asȱ theȱ addressȱ listȱ growsȱ
larger,ȱtheȱsimpleȱsequentialȱsearchȱmayȱbecomeȱtooȱslow,ȱorȱtheȱtableȱmightȱbecomeȱ
full.ȱAtȱthatȱtimeȱyouȱcanȱrewriteȱtheȱfindingȱfunctionȱtoȱbeȱmoreȱefficient,ȱperhapsȱbyȱ
usingȱsomeȱformȱofȱhashedȱlookup,ȱorȱyouȱcouldȱevenȱscrapȱtheȱarrayȱaltogetherȱandȱ
dynamicallyȱallocateȱtheȱspaceȱforȱtheȱentries.ȱButȱifȱtheȱclientȱprogramȱhadȱbeenȱableȱ
toȱ accessȱ theȱ tableȱ directly,ȱ changingȱ theȱ organizationȱ ofȱ theȱ tableȱ wouldȱ causeȱ theȱ
programȱtoȱfailȱinȱeachȱofȱtheseȱplaces.ȱ
Theȱ blackȱ boxȱ conceptȱ removesȱ theȱ temptationȱ toȱ useȱ theȱ implementationȱ
detailsȱbyȱmakingȱthoseȱdetailsȱunavailable.ȱThus,ȱtheȱonlyȱpossibleȱwayȱtoȱaccessȱtheȱ
moduleȱisȱthroughȱitsȱdefinedȱinterface.ȱ
ȱ
ȱ
ȱ
7.5 Recursion
ȱ
Cȱsupportsȱrecursiveȱfunctionsȱthroughȱitsȱruntimeȱstack. 31 ȱAȱrecursiveȱfunctionȱisȱoneȱ
thatȱ callsȱ itself,ȱ eitherȱ directlyȱ orȱ indirectly.ȱ Computingȱ factorialsȱ andȱ Fibonacciȱ
numbersȱareȱtwoȱapplicationsȱoftenȱusedȱinȱtextbooksȱtoȱillustrateȱrecursion,ȱwhichȱisȱ
veryȱ unfortunate.ȱ Recursionȱ doesȱ notȱ offerȱ anyȱ advantageȱ forȱ theȱ first,ȱ andȱ itȱ isȱ
horriblyȱinefficientȱforȱtheȱsecond.ȱ
Hereȱisȱaȱsimpleȱprogramȱtoȱillustrateȱrecursion.ȱTheȱobjectiveȱisȱtoȱconvertȱanȱ
integerȱfromȱbinaryȱtoȱprintableȱcharacters.ȱȱForȱexample,ȱfromȱtheȱvalueȱ4267ȱweȱwantȱ
toȱ produceȱ theȱ charactersȱ '4',ȱ '2',ȱ '6',ȱ andȱ '7',ȱ inȱ thatȱ order.ȱ printfȱ performsȱ thisȱ
typeȱofȱprocessingȱforȱtheȱ%dȱformatȱcode.ȱ
Theȱ strategyȱ weȱ useȱ isȱ toȱ repeatedlyȱ divideȱ theȱ valueȱ byȱ 10ȱ andȱ printȱ theȱ
remainders.ȱ Forȱ example,ȱ 4267ȱ modȱ 10ȱ givesȱ theȱ valueȱ 7.ȱ Weȱ cannotȱ justȱ printȱ thisȱ
remainder,ȱ though;ȱ weȱ needȱ toȱ printȱ theȱ valueȱ thatȱ representsȱ theȱ digitȱ '7'ȱ inȱ theȱ
machineȇsȱcharacterȱset.ȱȱInȱASCII,ȱtheȱcharacterȱ'7'ȱhasȱtheȱvalueȱ55,ȱsoȱweȱmightȱaddȱ
48ȱ toȱ theȱ remainderȱ toȱ getȱ theȱ properȱ character.ȱ However,ȱ usingȱ characterȱ constantsȱ
ratherȱthanȱintegerȱconstantsȱenhancesȱportablility.ȱ
Considerȱtheȱrelationshipsȱbelow:ȱ
ȱ
'0' + 0 = '0'
'0' + 1 = '1'
'0' + 2 = '2'
etc.ȱ
ȱ
Fromȱtheseȱrelationshipsȱitȱisȱeasyȱtoȱseeȱthatȱaddingȱȇ0ȇȱtoȱtheȱremainderȱproducesȱtheȱ
ȱInterestingly,ȱtheȱStandardȱdoesȱnotȱrequireȱaȱstack.ȱAȱstackȱprovidesȱtheȱmandatedȱbehavior,ȱthough,ȱandȱisȱusedȱinȱmanyȱ
implementations.ȱ
31
Download at http://www.pin5i.com/
180
Chapter 7 Functions
codeȱforȱtheȱcorrespondingȱcharacter.ȱThenȱtheȱremainderȱisȱprinted. 32 ȱTheȱnextȱstepȱisȱ
toȱgetȱtheȱquotient:ȱ4267/10ȱisȱ426.ȱTheȱprocessȱnowȱbeginsȱagainȱwithȱthisȱvalue.ȱ
Theȱonlyȱproblemȱwithȱthisȱprocessȱisȱthatȱitȱgeneratesȱtheȱdigitsȱinȱtheȱwrongȱ
order:ȱtheyȱareȱprintedȱbackwards.ȱProgramȱ7.6ȱusesȱrecursionȱtoȱcorrectȱthisȱproblem.ȱ
Thisȱ functionȱ isȱ recursiveȱ becauseȱ itȱ containsȱ aȱ callȱ toȱ itself.ȱ Atȱ firstȱ glance,ȱ itȱ
appearsȱthatȱtheȱfunctionȱwillȱneverȱstop.ȱWhenȱtheȱfunctionȱisȱcalled,ȱitȱwillȱcallȱitself;ȱ
thisȱsecondȱexecutionȱwillȱcallȱitselfȱagain,ȱandȱsoȱforth,ȱforeverȱandȱever.ȱThisȱisȱnotȱ
theȱcase,ȱthough.ȱ
Theȱrecursionȱinȱthisȱprogramȱimplementsȱaȱkindȱofȱtwistedȱ whileȱloop.ȱJustȱasȱ
aȱ whileȱ loopȱ mustȱ makeȱ someȱ progressȱ towardsȱ itsȱ terminationȱ criteriaȱ duringȱ eachȱ
executionȱ ofȱ theȱ body,ȱ soȱ tooȱ mustȱ aȱ recursiveȱ functionȱ getȱ closerȱ toȱ aȱ limitingȱ caseȱ
withȱeachȱrecursiveȱcall.ȱTheȱlimitingȱcaseȱisȱtheȱoneȱinȱwhichȱtheȱfunctionȱdoesȱnotȱcallȱ
itself.ȱ
Inȱ Programȱ 7.6,ȱ theȱ limitingȱ caseȱ occursȱ whenȱ theȱ quotientȱ isȱ zero.ȱ Weȱ divideȱ
theȱvalueȱbyȱ10ȱbeforeȱeachȱrecursiveȱcall,ȱsoȱitȱgetsȱcloserȱandȱcloserȱtoȱzeroȱeachȱtimeȱ
andȱeventuallyȱtheȱrecursionȱstops.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Take an integer value (unsigned), convert it to characters, and
** print it. Leading zeros are suppressed.
*/
#include <stdio.h>
void
binary_to_ascii( unsigned int value )
{
unsigned int
quotient;
quotient = value / 10;
if( quotient != 0 )
binary_to_ascii( quotient );
putchar( value % 10 + '0' );
}
ȱ
Programȱ7.6ȱȱConvertȱaȱbinaryȱintegerȱtoȱcharactersȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱȱȱbtoa.cȱ
ȱTheseȱrelationshipsȱrequireȱthatȱtheȱdigitsȱbeȱassignedȱsequentialȱcodes.ȱThisȱcharacteristicȱisȱtrueȱofȱallȱcommonȱcharacterȱ
sets.ȱ
32
Download at http://www.pin5i.com/
7.5 Recursion
181
Howȱ doesȱ recursionȱ helpȱ getȱ theȱ digitsȱ toȱ printȱ inȱ theȱ properȱ order?ȱ ȱ Hereȱ isȱ
howȱtoȱreadȱthisȱfunction,ȱ
ȱ
1. Divideȱtheȱvalueȱbyȱ10.ȱ
2. Ifȱtheȱquotientȱisȱnonzero,ȱcallȱbinary_to_asciiȱtoȱprintȱthoseȱdigitsȱnow.ȱ
3. Thenȱprintȱtheȱremainderȱofȱtheȱdivisionȱinȱstepȱ1.ȱ
ȱ
Noteȱthatȱtheȱmiddleȱstep,ȱprintingȱtheȱdigitsȱofȱaȱnumber,ȱisȱexactlyȱtheȱsameȱproblemȱ
weȱwereȱtryingȱtoȱsolveȱinȱtheȱfirstȱplaceȱexceptȱthatȱtheȱnumberȱisȱsmaller.ȱWeȱsolveȱ
theȱproblemȱbyȱcallingȱtheȱfunctionȱthatȱweȱjustȱwrote,ȱtheȱoneȱthatȱconvertsȱintegersȱ
toȱ digitsȱ andȱ printsȱ them.ȱ Becauseȱ theȱ numberȱ isȱ smaller,ȱ theȱ recursionȱ eventuallyȱ
stops.ȱ
Onceȱyouȱunderstandȱrecursion,ȱtheȱeasiestȱwayȱtoȱreadȱaȱrecursiveȱfunctionȱisȱ
toȱnotȱgetȱhungȱupȱonȱtracingȱitsȱexecution.ȱJustȱtakeȱitȱonȱfaithȱthatȱtheȱrecursiveȱcallȱ
willȱdoȱwhatȱitȱclaimsȱtoȱdo.ȱIfȱyouȱdoȱtheȱrightȱworkȱforȱeachȱstep,ȱyourȱlimitingȱcaseȱ
isȱcorrect,ȱandȱyouȱgetȱcloserȱtoȱitȱeachȱtime,ȱthenȱtheȱfunctionȱwillȱworkȱcorrectly.ȱ
ȱ
ȱ
ȱ
7.5.1 Tracing a Recursive Function
ȱ
Butȱ inȱorderȱ toȱunderstandȱhowȱ recursionȱworksȱinȱtheȱfirstȱplace,ȱyouȱneedȱtoȱ traceȱ
theȱ executionȱ ofȱ theȱ recursiveȱ calls.ȱ Soȱ letȇsȱ doȱ thatȱ now.ȱ Theȱ keyȱ toȱ followingȱ theȱ
executionȱ ofȱ aȱ recursiveȱ functionȱ isȱ understandingȱ howȱ theȱ variablesȱ declaredȱ innȱ aȱ
functionȱareȱstored.ȱWhenȱaȱfunctionȱisȱcalled,ȱspaceȱforȱitsȱvariablesȱisȱcreatedȱonȱtheȱ
runtimeȱstack.ȱTheȱvariablesȱbelongingȱtoȱtheȱpreviousȱfunctionsȱremainȱonȱtheȱstack,ȱ
butȱtheyȱareȱcoveredȱupȱbyȱtheȱnewȱonesȱandȱareȱinaccessible.ȱ
ȱ
Whenȱ aȱ recursiveȱ functionȱ callsȱ itself,ȱ theȱ sameȱ thingȱ happens.ȱ Aȱ newȱ setȱ ofȱ
variablesȱ isȱ createdȱ forȱ theȱ newȱ call,ȱ whichȱ coverȱ upȱ theȱ variablesȱ thatȱ belongȱ toȱ theȱ
previousȱcall(s)ȱtoȱthisȱfunction.ȱWhenȱtracingȱtheȱexecutionȱofȱaȱrecursiveȱfunction,ȱweȱ
mustȱ keepȱ theseȱ differentȱ setsȱ ofȱ variablesȱ separateȱ fromȱ oneȱ anotherȱ toȱ avoidȱ
confusion.ȱ
ȱ
Theȱ functionȱ inȱ Programȱ 7.6ȱ hasȱ twoȱ variables:ȱ theȱ argumentȱ valueȱ andȱ theȱ
localȱvariableȱ quotient.ȱTheȱfollowingȱdiagramsȱshowȱtheȱstateȱofȱtheȱstack,ȱwithȱtheȱ
setȱ ofȱ variablesȱ currentlyȱ beingȱ accessedȱ onȱ theȱ topȱ ofȱ theȱ stack.ȱ Allȱ otherȱ setsȱ ofȱ
variablesȱ areȱ shadedȱ inȱ gray,ȱ becauseȱ (heyȱ areȱ inaccessibleȱ toȱ theȱ functionȱ currentlyȱ
executing.ȱ
Download at http://www.pin5i.com/
182
Chapter 7 Functions
Supposeȱweȱcallȱtheȱfunctionȱwithȱtheȱvalueȱ4267.ȱȱHereȱisȱwhatȱtheȱstackȱlooksȱ
likeȱasȱtheȱfunctionȱbeginsȱtoȱexecute.ȱ
ȱ
ȱ
value 4267
quotient
ȱ
ȱ
Variables from other function calls
ȱ
ȱ
ȱ
Afterȱtheȱdivisionȱoccurs,ȱtheȱstackȱlooksȱlikeȱthis.ȱ
ȱ
ȱ
value 4267
quotient 426
ȱ
ȱ
Variables from other function calls
ȱ
ȱ
ȱ
Next,ȱtheȱ ifȱstatementȱdeterminesȱthatȱtheȱquotientȱisȱnotȱzeroȱandȱmakesȱaȱrecursiveȱ
callȱtoȱtheȱfunction.ȱHereȱisȱwhatȱtheȱstackȱlooksȱlikeȱasȱtheȱsecondȱcallȱofȱtheȱfunctionȱ
begins.ȱ
ȱ
ȱ
value 426
quotient
ȱ
ȱ
value 4267
quotient 426
ȱ
ȱ
Variables from other function calls
ȱ
ȱ
ȱ
ȱ
Aȱ newȱ setȱ ofȱ variablesȱ hasȱ beenȱ createdȱ onȱ theȱ stack,ȱ hidingȱ theȱ previousȱ set,ȱ whichȱ
willȱ remainȱ inaccessibleȱ untilȱ thisȱ recursiveȱ callȱ toȱ theȱ functionȱ returns.ȱ Afterȱ theȱ
division,ȱtheȱstackȱlooksȱlikeȱthis.ȱ
ȱ
value
426
quotient
42
value
4267
quotient
426
Variables from other function calls
Download at http://www.pin5i.com/
7.5 Recursion
183
Theȱquotientȱhasȱtheȱvalueȱ42,ȱwhichȱisȱnonzero,ȱsoȱweȱgetȱanotherȱrecursiveȱcallȱwithȱ
anotherȱsetȱofȱvariables.ȱAfterȱtheȱdivision,ȱtheȱstackȱlooksȱlikeȱthis:ȱ
ȱ
ȱ
value 42
quotient 4
ȱ
ȱ
ȱ
value 426
quotient 42
ȱ
ȱ
value 4267
quotient 426
ȱ
ȱ
ȱ
Variables from other function calls
ȱ
ȱ
ȱ
Theȱquotientȱisȱstillȱnonzero,ȱsoȱanotherȱrecursiveȱcallȱisȱmade.ȱAfterȱtheȱdivision,ȱtheȱ
stackȱlooksȱlikeȱthis:ȱ
ȱ
ȱ
value 4
quotient 0
ȱ
ȱ
ȱ
value 42
quotient 4
ȱ
ȱ
value 426
quotient 42
ȱ
ȱ
ȱ
value 4267
quotient 426
ȱ
ȱ
Variables from other function calls
ȱ
ȱ
ȱ
ȱ
Disregardingȱtheȱrecursiveȱcallȱitself,ȱtheȱ onlyȱstatementsȱthatȱ haveȱbeenȱexecutedȱ soȱ
farȱareȱtheȱdivisionȱandȱtheȱtestȱofȱtheȱquotient.ȱBecauseȱtheȱrecursiveȱcallȱhasȱcausedȱ
theseȱ statementsȱ toȱ beȱ repeated,ȱ theȱ effectȱ isȱ similarȱ toȱ thatȱ ofȱ aȱ loop;ȱ whileȱ theȱ
quotientȱisȱnonzero,ȱ useȱitȱasȱtheȱinitialȱvalueȱ andȱstartȱ overȱagain.ȱButȱ theȱrecursionȱ
savesȱ informationȱ thatȱ aȱ loopȱ wouldȱ not,ȱ theȱ stackedȱ valuesȱ ofȱ theȱ variables.ȱ Thisȱ
informationȱisȱaboutȱtoȱbecomeȱimportant.ȱ
Theȱquotientȱisȱzero,ȱsoȱtheȱfunctionȱdoesȱnotȱcallȱitselfȱagain.ȱInstead,ȱitȱbeginsȱ
toȱ printȱ output.ȱ Theȱ functionȱ thenȱ returns,ȱ whichȱ beginsȱ toȱ removeȱ valuesȱ fromȱ theȱ
stack.ȱ
Download at http://www.pin5i.com/
184
Chapter 7 Functions
Eachȱcallȱtoȱ putcharȱgetsȱtheȱlastȱdigitȱofȱtheȱvalueȱbyȱtakingȱtheȱvalueȱmoduloȱ
ten.ȱTheȱresultȱisȱanȱintegerȱinȱtheȱrangeȱzeroȱtoȱnine;ȱtheȱcharacterȱconstantȱforȱaȱzeroȱ
isȱ addedȱ inȱ orderȱ toȱ getȱ theȱ ASCIIȱ characterȱ thatȱ correspondsȱ toȱ theȱ digit,ȱ whichȱ isȱ
printed.ȱ
ȱ
0 ȱ
ȱ
ȱ valueȱ 4 ȱ
ȱ quotient
ȱ
ȱȱOutput:ȱ4ȱ
ȱ
ȱ
value 42
quotient 4
ȱ
ȱ
value 426
quotient 42
ȱ
ȱ
ȱ
value 4267
quotient 426
ȱ
ȱ
Variables from other function calls
ȱ
ȱ
ȱ
Theȱfunctionȱthenȱreturns,ȱandȱitsȱvariablesȱareȱdiscardedȱfromȱtheȱstack.ȱTheȱpreviousȱ
invocationȱofȱtheȱfunctionȱthenȱcontinuesȱtoȱexecuteȱfromȱtheȱpointȱofȱtheȱrecursiveȱcallȱ
usingȱitsȱownȱvariables,ȱwhichȱareȱnowȱonȱtheȱtopȱofȱtheȱstack.ȱBecauseȱitsȱvalueȱisȱ42,ȱ
theȱcallȱtoȱputcharȱprintsȱtheȱdigitȱtwo.ȱ
ȱ
ȱ
4 ȱ
ȱ
ȱ
ȱ valueȱ 42 ȱ
ȱ quotient
ȱ
ȱȱOutput:ȱ42ȱ
ȱ
ȱ
value 426
quotient 42
ȱ
ȱ
value 4267
quotient 426
ȱ
ȱ
ȱ
Variables from other function calls
ȱ
ȱ
ȱ
Thisȱ invocationȱ ofȱ theȱ functionȱ thenȱ returns,ȱ whichȱ uncoversȱ theȱ variablesȱ forȱ theȱ
previousȱ invocation.ȱ Executionȱ continuesȱ thereȱ fromȱ theȱ pointȱ ofȱ theȱ recursiveȱ call,ȱ
andȱaȱsixȱisȱprinted.ȱJustȱbeforeȱtheȱfunctionȱreturnsȱagain,ȱtheȱstackȱlooksȱlikeȱthis:ȱ
Download at http://www.pin5i.com/
7.5 Recursion
185
ȱ
value 426
quotient 42
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱOutput:ȱ426ȱ
ȱ
ȱ
value 4267
quotient 426
ȱ
ȱ
Variables from other function calls
ȱ
ȱ
ȱ
Weȱhaveȱnowȱunwoundȱtheȱrecursionȱandȱareȱbackȱtoȱtheȱoriginalȱcallȱtoȱtheȱfunction.ȱ
Itȱprintsȱtheȱdigitȱseven,ȱwhichȱisȱtheȱremainderȱofȱitsȱvalueȱdividedȱbyȱten.ȱ
ȱ
ȱ
426ȱ
ȱ
ȱ
ȱ valueȱ 4267ȱ
ȱ quotient
ȱ
ȱȱOutput:ȱ4267ȱ
ȱ
Variables from other function calls
ȱ
ȱ
ȱ
Theȱfunctionȱthenȱreturnsȱtoȱwhateverȱotherȱfunctionȱcalledȱit.ȱ
Ifȱ youȱ putȱ allȱ ofȱ theȱ charactersȱ thatȱ wereȱ printedȱ sideȱ byȱ sideȱ asȱ theyȱ wouldȱ
appearȱonȱaȱprinterȱorȱscreen,ȱyouȱwillȱseeȱtheȱcorrectȱvalue:ȱ4267.ȱ
ȱ
ȱ
ȱ
7.5.2 Recursion versus Iteration
ȱ
Recursionȱisȱaȱpowerfulȱtechnique,ȱbutȱlikeȱanyȱtechniqueȱitȱcanȱbeȱmisused.ȱHereȱisȱanȱ
example.ȱTheȱdefinitionȱofȱaȱfactorialȱisȱoftenȱstatedȱrecursively,ȱlikeȱthis:ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱnȱǂȱ0:ȱȱ1ȱ
ȱ
factorial(n)ȱ=ȱȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱnȱ>ȱ0:ȱȱnȱ×ȱfactorial(nȱ–ȱ1)ȱ
ȱ
Thisȱdefinitionȱhasȱbothȱofȱtheȱpropertiesȱweȱdiscussedȱearlierȱforȱrecursion:ȱthereȱisȱaȱ
limitingȱcaseȱfromȱwhichȱnoȱrecursionȱisȱperformed,ȱandȱeachȱrecursiveȱcallȱgetsȱaȱlittleȱ
closerȱtoȱtheȱlimitingȱcase.ȱ
Definitionsȱ likeȱ thisȱ oneȱ oftenȱ leadȱ peopleȱ toȱ useȱ recursionȱ toȱ implementȱ aȱ
factorialȱfunction,ȱsuchȱasȱtheȱoneȱshownȱinȱProgramȱ7.7a.ȱThisȱfunctionȱproducesȱtheȱ
correctȱ answers,ȱ butȱ itȱ isȱ notȱ aȱ goodȱ useȱ ofȱ recursion.ȱ Why?ȱ Theȱ recursiveȱ functionȱ
callsȱinvolveȱsomeȱruntimeȱoverhead—argumentsȱmustȱbeȱpushedȱonȱtheȱstack,ȱspaceȱ
allocatedȱforȱlocalȱvariablesȱ(inȱgeneral,ȱthoughȱnotȱforȱthisȱspecificȱexample),ȱregistersȱ
Download at http://www.pin5i.com/
186
Chapter 7 Functions
ȱ
/*
** Compute the factorial of n, recursively
*/
long
factorial( int n )
{
if( n <= 0 )
return 1;
else
return n * factorial( n - 1 );
}
ȱ
Programȱ7.7aȱȱRecursiveȱfactorialsȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱfact_rec.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
mustȱbeȱsaved,ȱandȱsoȱforth.ȱWhenȱeachȱcallȱtoȱtheȱfunctionȱreturns,ȱallȱthisȱworkȱmustȱ
beȱ undone.ȱ Forȱ allȱ ofȱ thisȱ overhead,ȱ however,ȱ recursionȱ doesȱ littleȱ toȱ simplifyȱ theȱ
solutionȱtoȱthisȱproblem.ȱ
Programȱ 7.7bȱ computesȱ theȱ sameȱ resultȱ withȱ aȱ loop.ȱ Althoughȱ thisȱ programȱ
withȱitsȱsimpleȱloopȱdoesȱnotȱresembleȱtheȱmathematicalȱdefinitionȱofȱfactorialȱnearlyȱ
asȱclosely,ȱitȱcomputesȱtheȱsameȱresultȱmoreȱefficiently.ȱIfȱyouȱlookȱmoreȱcloselyȱatȱtheȱ
recursiveȱfunction,ȱyouȱwillȱseeȱthatȱtheȱrecursiveȱcallȱisȱtheȱlastȱthingȱtheȱfunctionȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Compute the factorial of n, iteratively
*/
long
factorial( int n )
{
int
result = 1;
while( n > 1 ){
result *= n;
n -= 1;
}
return result;
}
ȱ
Programȱ7.7bȱȱIterativeȱfactorialsȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱfact_itr.cȱ
Download at http://www.pin5i.com/
7.5 Recursion
187
does.ȱ Thisȱ functionȱ isȱ anȱ exampleȱ ofȱ tailȱ recursion.ȱ Becauseȱ noȱ workȱ isȱ doneȱ inȱ theȱ
functionȱ afterȱ theȱ recursiveȱ callȱ returns,ȱ tailȱ recursionȱ canȱ easilyȱ beȱ convertedȱ toȱ aȱ
simpleȱloopȱthatȱaccomplishesȱtheȱsameȱtask.ȱ
ȱ
Manyȱ problemsȱ areȱ explainedȱ recursivelyȱ onlyȱ becauseȱ itȱ isȱ clearerȱ thanȱ aȱ nonȬ
recursiveȱ explanation.ȱ However,ȱ anȱ iterativeȱ implementationȱ ofȱ theseȱ problemsȱ isȱ
oftenȱmoreȱefficientȱthanȱaȱrecursiveȱimplementation,ȱevenȱthoughȱtheȱresultingȱcodeȱ
isȱ lessȱ clear.ȱ Whenȱ aȱ problemȱ isȱ complexȱ enoughȱ thatȱ anȱ iterativeȱ implementationȱ isȱ
difficultȱ forȱ someoneȱ elseȱ toȱ follow,ȱ thenȱ theȱ clarityȱ ofȱ theȱ recursiveȱ implementationȱ
mayȱjustifyȱtheȱruntimeȱoverheadȱthatȱitȱwillȱincur.ȱ
InȱProgramȱ7.7a,ȱrecursionȱaddedȱlittleȱtoȱtheȱsolutionȱofȱtheȱproblem.ȱProgramȱ
7.7bȱ withȱ itsȱ loopȱ wasȱ justȱ asȱ simple.ȱ Hereȱ isȱ aȱ moreȱ extremeȱ example.ȱ Fibonacciȱ
numbersȱ areȱ aȱ sequenceȱ ofȱ numbersȱ inȱ whichȱ eachȱ valueȱ isȱ theȱ sumȱ ofȱ theȱ previousȱ
twoȱvalues.ȱȱThisȱrelationshipȱisȱoftenȱdescribedȱrecursively:ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱnȱǂȱ1:ȱȱ1ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱ
ȱ
factorial(n)ȱ=ȱȱȱȱȱȱȱnȱ=ȱ2;ȱȱ1ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱnȱ>ȱ2:ȱȱȱFibonacci(nȱ–ȱ1)ȱ+ȱFibonacci(nȱ–ȱ2)ȱ
ȱ
Again,ȱ theȱ recursiveȱ definitionȱ suggestsȱ thatȱ theȱ solutionȱ shouldȱ beȱ
implementedȱ usingȱ recursion,ȱ asȱ illustratedȱ inȱ Programȱ 7.8a.ȱ ȱ Hereȱ isȱ theȱ trap:ȱ theȱ
recursiveȱstepȱcomputesȱFibonacci(nȱȬȱ1)ȱandȱFibonacci(nȱȬȱ2).ȱȱBut,ȱtheȱcomputationȱofȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Compute the value of the n'th Fibonacci number, recursively.
*/
long
fibonacci( int n )
{
if( n <= 2 )
return 1;
return fibonacci( n - 1 ) + fibonacci( n - 2 );
}
Programȱ7.8bȱȱȱRecursiveȱFibonacciȱnumbersȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱfib_rec.cȱ
Download at http://www.pin5i.com/
188
Chapter 7 Functions
ȱFibonacci(nȱȬȱ1)ȱalsoȱcomputesȱFibonacci(nȱȬȱ2).ȱHowȱmuchȱcouldȱoneȱextraȱcomputationȱ
cost?ȱ
Theȱanswerȱisȱthatȱthereȱisȱfarȱmoreȱthanȱjustȱoneȱredundantȱcomputation:ȱeachȱ
recursiveȱcallȱbeginsȱtwoȱmoreȱrecursiveȱcalls,ȱandȱeachȱofȱthoseȱcallsȱbeginsȱtwoȱmore,ȱ
andȱ soȱ forth.ȱ Therefore,ȱ theȱ numberȱ ofȱ redundantȱ computationsȱ growsȱ veryȱ rapidly.ȱȱ
Forȱ instance,ȱ inȱ computingȱ Fibonacci(l0),ȱ theȱ valueȱ ofȱ Fibonacci(3)ȱ isȱ computedȱ 21ȱ
times.ȱ Butȱ toȱ computeȱ Fibonacci(30)ȱ recursively,ȱ Fibonacci(3)ȱ isȱ computedȱ 317,811ȱ
times.ȱ Ofȱ course,ȱ everyȱ oneȱ ofȱ theseȱ 317,811ȱ calculationsȱ producedȱ exactlyȱ theȱ sameȱ
result,ȱsoȱallȱbutȱoneȱwereȱwasted.ȱȱThisȱoverheadȱisȱhorrible!ȱ
Considerȱ Programȱ 7.8b,ȱ whichȱ usesȱ aȱ simpleȱ loopȱ insteadȱ ofȱ recursion.ȱ Onceȱ
again,ȱ theȱ loopȱ doesȱ notȱ resembleȱ theȱ abstractȱ definitionȱ asȱ closelyȱ asȱ theȱ recursiveȱ
version,ȱbutȱitȱisȱhundredsȱofȱthousandsȱofȱtimesȱmoreȱefficient!ȱ
Beforeȱimplementingȱaȱfunctionȱrecursively,ȱaskȱyourselfȱwhetherȱtheȱbenefitȱtoȱ
beȱgainedȱbyȱusingȱrecursionȱoutweightsȱtheȱcosts.ȱAndȱbeȱcareful:ȱtheȱcostsȱmightȱbeȱ
moreȱthanȱwhatȱtheyȱfirstȱappearȱtoȱbe.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Compute the value of the n'th Fibonacci number, iteratively.
*/
long
fibonacci( int n )
{
long result;
long previous_result;
long next_older_result;
result = previous_result = 1;
while( n > 2 ){
n -= 1;
next_older_result = previous_result;
previous_result = result;
result = previous_result + next_older_result;
}
return result;
}
ȱ
Programȱ7.8bȱȱIterativeȱFibonacciȱnumbersȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱfib_iter.cȱ
Download at http://www.pin5i.com/
7.6 Variable Argument Lists
189
7.6 Variable Argument Lists
ȱ
Aȱfunctionȱprototypeȱlistsȱtheȱargumentsȱthatȱtheȱfunctionȱexpects,ȱbutȱaȱprototypeȱcanȱ
onlyȱ showȱ aȱ 6xedȱ numberȱ ofȱ arguments.ȱ Isȱ itȱ possibleȱ forȱ aȱ functionȱ toȱ acceptȱ aȱ
differentȱnumberȱofȱargumentsȱatȱdifferentȱtimes?ȱȱYes,ȱbutȱthereȱareȱsomeȱrestrictions.ȱ
Considerȱaȱfunctionȱthatȱcomputesȱtheȱaverageȱofȱaȱseriesȱofȱvalues.ȱThisȱtaskȱisȱtrivialȱ
ifȱ theȱ valuesȱ areȱ storedȱ inȱ anȱ array,ȱ soȱ toȱ makeȱ theȱ problemȱ moreȱ interestingȱ letȇsȱ
assumeȱthatȱtheyȱareȱnot.ȱProgramȱ7.9aȱattemptsȱtoȱdoȱtheȱjob.ȱ
Thisȱ functionȱ hasȱ severalȱ problems.ȱ First,ȱ thereȱ isnȇtȱ aȱ testȱ forȱ tooȱ manyȱ
arguments,ȱ butȱ oneȱ couldȱ easilyȱ beȱ added.ȱ Second,ȱ theȱ functionȱ cannotȱ handleȱ moreȱ
thanȱfiveȱvalues.ȱThisȱproblemȱcanȱonlyȱbeȱrectifiedȱbyȱaddingȱevenȱmoreȱcopiesȱofȱtheȱ
alreadyȱredundantȱcode.ȱ
Butȱ thereȱ isȱ aȱ moreȱ seriousȱ problemȱ whichȱ occursȱ whenȱ youȱ tryȱ toȱ callȱ theȱ
functionȱlikeȱthis:ȱ
ȱ
avg1 = average( 3, x, y, z );
ȱ
Thereȱ areȱ onlyȱ fourȱ arguments,ȱ butȱ theȱ functionȱ hasȱ sixȱ formalȱ parameters.ȱ Theȱ
Standardȱ coversȱ thisȱ situation:ȱ theȱ behaviorȱ isȱ undefined.ȱ Thus,ȱ theȱ firstȱ argumentȱ
mightȱcorrespondȱtoȱtheȱn_valuesȱparameterȱorȱmaybeȱtoȱtheȱv2ȱparameter.ȱYouȱcanȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Compute the average of the specified number of values (bad).
*/
float
average( int n_values, int v1, int v2, int v3, int v4, int v5 )
{
float sum = v1;
if( n_values
sum +=
if( n_values
sum +=
if( n_values
sum +=
if( n_values
sum +=
return sum /
>= 2 )
v2;
>= 3 )
v3;
>= 4 )
v4;
>= 5 )
v5;
n_values;
}
ȱ
Programȱ7.9aȱȱComputeȱtheȱaverageȱofȱscalarȱvalues:ȱbadȱversionȱ
ȱ
ȱ
average1.cȱ
Download at http://www.pin5i.com/
190
Chapter 7 Functions
certainlyȱtestȱyourȱimplementationȱtoȱseeȱwhatȱitȱdoes,ȱbutȱtheȱprogramȱisȱcertainlyȱnotȱ
portable.ȱWhatȱisȱneedȱisȱaȱmechanismȱtoȱaccessȱanȱunboundedȱargumentȱlistȱinȱaȱwellȬ
definedȱway.ȱ
ȱ
ȱ
ȱ
7.6.1 The stdarg Macros
ȱ
Variableȱargumentȱlistȱareȱimplementedȱusingȱmacrosȱdefinedȱinȱtheȱ stdarg.hȱheader,ȱ
whichȱ isȱ partȱ ofȱ theȱ standardȱ library.ȱ Theȱ headerȱ declaresȱ aȱ typeȱ va_listȱ andȱ threeȱ
macrosȱ –ȱ va_start,ȱ va_arg,ȱ andȱ va_end. 33 ȱ Aȱ variableȱ ofȱ typeȱ va_listȱ isȱ declaredȱ andȱ
usedȱwithȱtheȱmacrosȱtoȱaccessȱtheȱargumentȱvalues.ȱ
Programȱ 7.9bȱ usesȱ theseȱ macrosȱ toȱ correctlyȱ accomplishȱ whatȱ programȱ 7.9aȱ
triedȱ toȱ do.ȱ Noticeȱ theȱ ellipsisȱ inȱ theȱ argument,ȱ list:ȱ itȱ indicatesȱ thatȱ anȱ unspecifiedȱ
numberȱ ofȱ argumentsȱ withȱ unspecifiedȱ typesȱ mayȱ beȱ passed.ȱ Theȱ sameȱ notationȱ isȱ
usedȱwhenȱprototypingȱtheȱfunction.ȱ
Theȱ functionȱ declaresȱ aȱ variableȱ calledȱ var_argȱ withȱ whichȱ toȱ accessȱ theȱ
unspecifiedȱ portionȱ ofȱ theȱ argumentȱ list.ȱ Thisȱ variableȱ isȱ initializedȱ byȱ callingȱ
va_start.ȱ Theȱ firstȱ parameterȱ isȱ theȱ nameȱ ofȱ theȱ va_listȱ variable,ȱ andȱ theȱ secondȱ
parameterȱ isȱ theȱ lastȱ namedȱ argumentȱ beforeȱ theȱ ellipsis.ȱ Thisȱ initializationȱ setsȱ theȱ
var_argȱvariableȱtoȱpointȱtoȱtheȱfirstȱofȱtheȱvariableȱarguments.ȱ
Toȱ accessȱ anȱ argument,ȱ va_argȱ isȱ used.ȱ Thisȱ macroȱ takesȱ twoȱ parameters:ȱ theȱ
va_listȱvariableȱandȱtheȱtypeȱofȱtheȱnextȱvalueȱinȱtheȱlist.ȱInȱthisȱexample,ȱtheȱvariableȱ
argumentsȱareȱallȱintegers.ȱInȱsomeȱfunctions,ȱyouȱmayȱhaveȱtoȱdetermineȱtheȱtypeȱofȱ
theȱnextȱargumentȱbyȱexaminingȱpreviouslyȱobtainedȱdata. 34 ȱ va_argȱreturnsȱtheȱvalueȱ
ofȱthisȱargumentȱandȱadvancesȱvar_argȱtoȱpointȱtoȱtheȱnextȱvariableȱargument.ȱ
Finally,ȱva_endȱisȱcalledȱafterȱtheȱlastȱaccessȱtoȱtheȱvariableȱarguments.ȱ
ȱ
ȱ
ȱ
7.6.2 Limitations of Variable Arguments
ȱ
Noteȱthatȱtheȱvariableȱargumentsȱmustȱbeȱaccessedȱoneȱbyȱone,ȱinȱorder,ȱfromȱstartȱtoȱ
finish.ȱȱYouȱcanȱstopȱearlyȱifȱyouȱwish,ȱbutȱthereȱisnȇtȱanyȱwayȱtoȱbeginȱaccessingȱinȱtheȱ
middleȱofȱtheȱlist.ȱInȱaddition,ȱbecauseȱtheȱvariableȱportionȱofȱtheȱargumentȱlistȱisȱnotȱ
prototyped,ȱ theȱ defaultȱ argumentȱ promotionsȱ areȱ performedȱ onȱ allȱ valuesȱ passedȱ asȱ
variableȱarguments.ȱ
ȱMacrosȱareȱimplementedȱbyȱtheȱpreprocessorȱandȱareȱdiscussedȱinȱChapterȱ14.ȱ
ȱForȱexample, printfȱexaminesȱtheȱcharactersȱinȱtheȱformatȱstringȱtoȱdetermineȱtheȱtypesȱofȱtheȱargumentsȱitȱisȱsupposedȱ
toȱprintȱ
33
34
Download at http://www.pin5i.com/
7.6 Variable Argument Lists
191
ȱ
/*
** Compute the average of the specified number of values.
*/
#include <stdarg.h>
float
average( int n_values, ... )
{
va_list
var_arg;
int
count;
float sum = 0;
/*
** Prepare to access the variable arguments.
*/
va_start( var_arg, n_values );
/*
** Add the values from the variable argument list.
*/
for( count = 0; count < n_values; count += 1 ){
sum += va_arg( var_arg, int );
}
/*
** Done processing variable arguments.
*/
va_end( var_arg );
return sum / n_values;
}
ȱ
Programȱ7.9bȱȱComputeȱtheȱaverageȱofȱscalarȱvalues:ȱgoodȱversionȱ ȱ
ȱ
average2.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Youȱ mayȱ alsoȱ haveȱ noticedȱ theȱ requirementȱ thatȱ thereȱ mustȱ beȱ atȱ leastȱ oneȱ
namedȱ argumentȱ inȱ theȱ argumentȱ list;ȱ youȱ cannotȱ useȱ va_startȱ withoutȱ it.ȱ Thisȱ
argumentȱprovidesȱaȱwayȱtoȱlocateȱtheȱvaryingȱportionȱofȱtheȱargumentȱlist.ȱ
Thereȱ areȱ twoȱ fundamentalȱ limitationsȱ ofȱ theseȱ macros,ȱ bothȱ ofȱ whichȱ areȱ aȱ
directȱ resultȱ ofȱ theȱ factȱ thatȱ theȱ typeȱ ofȱ aȱ valueȱ cannotȱ beȱ determinedȱ simplyȱ byȱ
examiningȱit.ȱ
Download at http://www.pin5i.com/
192
Chapter 7 Functions
1. Theȱmacrosȱcannotȱdetermineȱhowȱmanyȱargumentsȱactuallyȱexist.ȱ
CAUTION!
2. Theȱmacrosȱcannotȱdetermineȱtheȱtypeȱofȱeachȱargument.ȱ
ȱ
Theȱ namedȱ argument(s)ȱ mustȱ answerȱ bothȱ ofȱ theseȱ questions.ȱ Inȱ Programȱ 7.9b,ȱ theȱ
namedȱargumentȱspecifiesȱhowȱmanyȱvaluesȱwereȱpassed,ȱbutȱtheirȱtypesȱareȱassumedȱ
toȱ beȱ integers.ȱ Theȱ namedȱ argumentȱ inȱ printfȱ isȱ theȱ formatȱ string,ȱ whichȱ indicatesȱ
bothȱtheȱnumberȱandȱtypesȱofȱtheȱarguments.ȱ
ȱ
Ifȱyouȱspecifyȱtheȱwrongȱtypeȱwithȱ va_argȱtheȱresultsȱareȱunpredictable.ȱThisȱerrorȱisȱ
easyȱtoȱmakeȱbecauseȱva_argȱdoesnȇtȱcompensateȱforȱtheȱdefaultȱargumentȱpromotionsȱ
thatȱareȱperformedȱonȱvariableȱarguments,ȱ char,ȱ short,ȱandȱ floatȱvaluesȱwillȱactuallyȱ
beȱpassedȱasȱintȇsȱandȱdoubleȇs.ȱBeȱcarefulȱtoȱuseȱtheseȱlatterȱtypesȱwithȱva_arg.ȱ
ȱ
ȱ
ȱ
7.7 Summary
ȱ
Aȱfunctionȱdefinitionȱspecifiesȱbothȱtheȱparameterȱlistȱandȱtheȱbodyȱofȱtheȱfunction,ȱtheȱ
statementsȱ thatȱ areȱ executedȱ whenȱ theȱ functionȱ isȱ called.ȱ Thereȱ areȱ twoȱ acceptableȱ
formsȱ forȱ writingȱ theȱ parameterȱ list.ȱ Theȱ K&Rȱ styleȱ declaresȱ theȱ typesȱ ofȱ theȱ
parametersȱ inȱ aȱ separateȱ listȱ thatȱ occursȱ priorȱ toȱ theȱ openingȱ braceȱ ofȱ theȱ functionȇsȱ
body.ȱ Theȱ newȱ style,ȱ whichȱ isȱ preferred,ȱ includesȱ theȱ typesȱ inȱ theȱ parameterȱ list.ȱ Aȱ
functionȱwithȱnoȱstatementsȱinȱitsȱbody,ȱcalledȱaȱstub,ȱisȱusefulȱinȱtestingȱincompleteȱ
programs.ȱ
Aȱfunctionȱdeclarationȱgivesȱlimitedȱinformationȱaboutȱaȱfunction,ȱandȱisȱusedȱ
whereȱtheȱfunctionȱisȱcalled.ȱThereȱareȱtwoȱacceptableȱformsȱforȱfunctionȱdeclarations.ȱ
TheȱK&Rȱstyle,ȱwithȱnoȱparameterȱlist,ȱonlyȱdeclaresȱtheȱtypeȱofȱvalueȱreturnedȱbyȱtheȱ
function.ȱTheȱnewȱstyle,ȱwhichȱisȱpreferred,ȱisȱcalledȱaȱfunctionȱprototype.ȱItȱincludesȱ
declarationsȱofȱtheȱtypesȱofȱtheȱparametersȱasȱwell,ȱwhichȱallowsȱtheȱcompilerȱtoȱcheckȱ
theȱ typesȱ andȱ numberȱ ofȱ argumentsȱ inȱ callsȱ toȱ theȱ function.ȱ Youȱ canȱ alsoȱ putȱ
parameterȱnamesȱinȱaȱfunctionȱprototypeȱasȱwell.ȱWhileȱoptional,ȱthisȱpracticeȱmakesȱ
theȱ prototypeȱ moreȱ usefulȱ forȱ otherȱ readersȱ becauseȱ itȱ conveysȱ moreȱ information.ȱȱ
Prototypesȱ forȱ functionsȱ withoutȱ parametersȱ haveȱ justȱ theȱ keywordȱ voidȱ asȱ aȱ
parameterȱlist.ȱȱTheȱpreferredȱwayȱtoȱuseȱfunctionȱprototypesȱisȱtoȱputȱtheȱprototypeȱinȱ
aȱ separateȱ fileȱ whichȱ isȱ thenȱ #includeȇdȱ whereverȱ theȱ prototypeȱ isȱ needed.ȱ Thisȱ
techniqueȱminimizesȱtheȱnumberȱofȱseparateȱcopiesȱofȱtheȱprototypeȱthatȱareȱneeded,ȱ
whichȱsimplifiesȱmaintenance.ȱ
Theȱ returnȱ statementȱ isȱ usedȱ toȱ specifyȱ theȱ valueȱ toȱ beȱ returnedȱ fromȱ aȱ
function.ȱIfȱnoȱvalueȱisȱgivenȱinȱtheȱ returnȱstatement,ȱorȱifȱaȱfunctionȱdoesȱnotȱcontainȱ
anyȱ returnȱ statements,ȱ noȱ valueȱ willȱ beȱ returned.ȱ Suchȱ functionsȱ areȱ calledȱ
Download at http://www.pin5i.com/
7.7 Summary
193
ȱinȱ manyȱ otherȱ languages.ȱ Inȱ ANSIȱ C,ȱ functionȱ thatȱ doȱ notȱ returnȱ aȱ valueȱ shouldȱ beȱ
declaredȱasȱreturningȱtheȱtypeȱvoid.ȱ
Ifȱ aȱ functionȱ itȱ isȱ calledȱ beforeȱ anyȱ declarationsȱ forȱ itȱ haveȱ beenȱ seen,ȱ theȱ
compilerȱassumesȱthatȱtheȱfunctionȱreturnsȱanȱintegerȱvalue.ȱItȱisȱimportantȱtoȱdeclareȱ
functionsȱthatȱreturnȱnonintegralȱtypesȱinȱorderȱtoȱavoidȱerrorsȱcausedȱbyȱunexpectedȱ
typeȱ conversions.ȱ ȱ Argumentsȱ toȱ functionsȱ thatȱ areȱ notȱ prototypedȱ underȱ goȱ theȱ
defaultȱ argumentȱ promotions:ȱ charȱ andȱ shortȱ argumentsȱ areȱ convertedȱ toȱ int,ȱ andȱ
floatȱargumentsȱareȱconvertedȱtoȱdouble.ȱ
Argumentsȱ toȱ functionsȱareȱpassedȱcallȱbyȱvalue,ȱwhichȱmakesȱ aȱ copyȱofȱeachȱ
argument.ȱ Aȱ functionȱ canȱ thereforeȱ modifyȱ itsȱ parametersȱ (theȱ copies)ȱ withoutȱ
affectingȱtheȱcallerȇsȱarguments.ȱArrayȱnamesȱareȱalsoȱpassedȱusingȱcallȱbyȱvalue,ȱbutȱ
allȱthatȱisȱcopiedȱisȱaȱpointerȱtoȱtheȱcallerȇsȱarray.ȱWhenȱaȱsubscriptȱisȱusedȱonȱtheȱarrayȱ
parameterȱ inȱ theȱ function,ȱ indirectionȱ causesȱ anȱ elementȱ inȱ theȱ callerȇsȱ arrayȱ toȱ beȱ
accessed.ȱ Thus,ȱ modifyingȱ anȱ arrayȱ elementȱ inȱ theȱ functionȱ actuallyȱ modifiesȱ theȱ
callerȇsȱarray.ȱThisȱbehaviorȱisȱnamedȱcallȱbyȱreference.ȱYouȱcanȱgetȱcallȱbyȱreferenceȱ
semanticsȱ withȱ scalarȱ argumentsȱ byȱ passingȱ pointersȱ toȱ theȱ argumentsȱ andȱ usingȱ
indirectionȱinȱtheȱfunctionȱtoȱaccessȱorȱmodifyȱtheȱvalues.ȱ
Anȱ abstractȱ dataȱ type,ȱ orȱ blackȱ box,ȱ consistsȱ ofȱ anȱ interfaceȱ andȱ anȱ
implementation.ȱ Theȱ interface,ȱ whichȱ isȱ public,ȱ specifiesȱ howȱ aȱ clientȱ usesȱ theȱ
functionalityȱprovidedȱbyȱtheȱADT.ȱTheȱimplementation,ȱwhichȱisȱprivate,ȱisȱwhereȱtheȱ
workȱ isȱ actuallyȱ done.ȱ Keepingȱ theȱ implementationȱ privateȱ preventsȱ clientsȱ fromȱ
makingȱ theirȱ programsȱ dependentȱ onȱ detailsȱ ofȱ theȱ implementation.ȱ Theȱ
implementationȱ canȱ thenȱ beȱ changedȱ whenȱ necessaryȱ withoutȱ affectingȱ theȱ clientsȇȱ
code.ȱ
Aȱ recursiveȱ functionȱ isȱ oneȱ thatȱ callsȱ itself,ȱ eitherȱ directlyȱ orȱ indirectly.ȱ Forȱ
recursionȱtoȱwork,ȱeachȱinvocationȱofȱtheȱfunctionȱmustȱmakeȱsomeȱprogressȱtowardȱaȱ
goal.ȱWhenȱtheȱgoalȱisȱreached,ȱnoȱmoreȱrecursiveȱcallsȱareȱmade.ȱToȱreadȱaȱrecursiveȱ
function,ȱdoȱnotȱgetȱhungȱupȱonȱtracingȱeachȱrecursiveȱcall.ȱItȱisȱeasierȱtoȱunderstandȱ
whatȱisȱhappeningȱifȱyouȱsimplyȱassumeȱthatȱtheȱrecursiveȱcallȱperformsȱtheȱworkȱthatȱ
itȱclaimsȱtoȱdo.ȱ
Someȱ functionsȱ thatȱ areȱ describedȱ recursively,ȱ suchȱ asȱ factorialȱ andȱ Fibonacciȱ
numbers,ȱcanȱbeȱimplementedȱmoreȱefficientlyȱiteratively.ȱWhenȱaȱrecursiveȱcallȱisȱtheȱ
lastȱthingȱthatȱisȱdoneȱinȱaȱfunction,ȱitȱisȱcalledȱtailȱrecursion.ȱȱTailȱrecursionȱcanȱeasilyȱ
beȱconvertedȱtoȱaȱloop,ȱwhichȱisȱusuallyȱmoreȱefficient.ȱ
Functionsȱ withȱ argumentȱ listsȱ containingȱ variableȱ numbersȱ andȱ typesȱ ofȱ
argumentsȱcanȱbeȱimplementedȱusingȱtheȱmacrosȱdefinedȱinȱtheȱstdarg.hȱheader.ȱȱTheȱ
varyingȱ portionȱ ofȱ theȱ parameterȱ list,ȱ whichȱ followsȱ oneȱ orȱ moreȱ ordinaryȱ (named)ȱ
parameters,ȱ isȱ indicatedȱ withȱ anȱ elipsisȱ inȱ theȱ functionȱ prototype.ȱ Theȱ namedȱ
parameter(s)ȱmustȱsomehowȱindicateȱtheȱnumberȱofȱargumentsȱpassedȱinȱtheȱvaryingȱ
Download at http://www.pin5i.com/
194
Chapter 7 Functions
partȱand,ȱifȱnotȱknownȱinȱadvance,ȱtheirȱtypes.ȱTheȱargumentsȱinȱtheȱvaryingȱportionȱ
ofȱtheȱlistȱundergoȱtheȱdefaultȱargumentȱpromotionsȱwhenȱtheyȱareȱpassed,ȱandȱtheyȱ
canȱonlyȱbeȱaccessedȱinȱorderȱfromȱfirstȱtoȱlast.ȱ
ȱ
ȱ
ȱ
7.8 Summary of Cautions
ȱ
1. Writingȱfunctionȱprototypesȱwithinȱtheȱscopeȱofȱotherȱfunctionsȱ(pageȱ169).ȱ
2. Notȱprototypingȱfractionsȱthatȱreturnȱnonintegralȱvaluesȱ(pageȱ171).ȱ
3. MixingȱfunctionȱprototypesȱwithȱoldȬstyleȱfunctionȱdefinitionsȱ(pageȱ175).ȱ
4. Usingȱtheȱwrongȱargumentȱtypeȱinȱva_argȱgivesȱundefinedȱresultsȱ(pageȱ192).ȱ
ȱ
ȱ
ȱ
7.9 Summary of Programming Tips
ȱ
1. Puttingȱargumentȱnamesȱinȱfunctionȱprototypesȱmakesȱitȱeasierȱforȱtheȱclientȱtoȱuseȱ
theȱfunctionȱ(pageȱ169).ȱ
2. Abstractȱ dataȱ typesȱ increaseȱ reliabilityȱ byȱ decreasingȱ theȱ programȇsȱ relianceȱ onȱ
implementationȱdetailsȱ(pageȱ179).ȱ
3. Useȱrecursionȱasȱaȱnotationalȱtoolȱwhenȱtheȱbenefitȱjustifiesȱtheȱcostȱ(pageȱ187).ȱ
ȱ
ȱ
ȱ
7.10 Questions
ȱ
1. Aȱfunctionȱwithȱanȱemptyȱbodyȱisȱusefulȱasȱaȱstub.ȱHowȱmightȱsuchȱaȱfunctionȱbeȱ
modifiedȱtoȱbeȱmoreȱuseful?ȱ
2. PrototypesȱforȱfunctionsȱareȱnotȱmandatoryȱinȱANSIȱC.ȱȱIsȱthisȱfactȱanȱadvantageȱorȱ
aȱdisadvantage?ȱ
3. Whatȱ happensȱ ifȱ aȱ functionȱ thatȱ isȱ declaredȱ toȱ returnȱ aȱ specificȱ typeȱ includesȱ aȱ
returnȱstatementȱwithȱanȱexpressionȱofȱaȱdifferentȱtype?ȱ
4. Whatȱhappensȱifȱaȱfunctionȱthatȱisȱdeclaredȱvoidȱcontainsȱaȱreturnȱstatementȱwithȱ
anȱexpression?ȱ
5. Ifȱaȱfunctionȱisȱcalledȱbeforeȱtheȱcompilerȱhasȱseenȱaȱprototypeȱforȱit,ȱwhatȱhappensȱ
ifȱtheȱfunctionȱreturnsȱsomeȱtypeȱotherȱthanȱinteger?ȱ
6. Ifȱaȱfunctionȱisȱcalledȱbeforeȱtheȱcompilerȱhasȱseenȱaȱprototypeȱforȱit,ȱwhatȱhappensȱ
Download at http://www.pin5i.com/
7.11 Programming Exercises
195
ifȱtheȱtypesȱofȱtheȱargumentsȱdoȱnotȱmatchȱthoseȱofȱtheȱformalȱparameters?ȱ
7. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱfunction?ȱ
ȱ
int
find_max( int array[10] )
{
int
i;
int
max = array[0];
for( i = 1; i < 10; i += 1 )
if( array[i] > max )
max = array[i];
return max;
}
8. Howȱisȱrecursionȱsimilarȱtoȱaȱwhileȱloop?ȱ
9. Explainȱtheȱadvantagesȱofȱputtingȱfunctionȱprototypesȱinȱ#includeȱfiles.ȱ
10. EnterȱtheȱrecursiveȱFibonacciȱfunctionȱonȱyourȱsystem,ȱandȱaddȱaȱstatementȱatȱtheȱ
beginningȱ ofȱ theȱ functionȱ thatȱ incrementsȱ aȱ globalȱ integerȱ variable.ȱ Nowȱ writeȱ aȱ
mainȱfunctionȱtoȱsetȱtheȱglobalȱvariableȱtoȱzeroȱandȱcomputeȱ fibonacci(1).ȱRepeatȱ
forȱ fibonacci(2)ȱ throughȱ fibonacci(10).ȱ Howȱ manyȱ timesȱ wasȱ theȱ fibonacciȱ
functionȱ calledȱ forȱ eachȱ ofȱ theseȱ computations?ȱ ȱ Isȱ thisȱ progressionȱ ofȱ valuesȱ
relatedȱ inȱ anyȱ wayȱ toȱ theȱ Fibonacciȱ numbersȱ themselves?ȱ Basedȱ onȱ thisȱ
information,ȱ canȱ youȱ calculateȱ theȱ numberȱ ofȱ callsȱ thatȱ wouldȱ beȱ neededȱ toȱ
computeȱfibonacci(11)?ȱfibonacci(25)?ȱȱȱfibonacci(50)?ȱ
ȱ
ȱ
ȱ
7.11 Programming Exercises
ȱ
1. TheȱHermiteȱPolynomialsȱareȱdefinedȱasȱfollows:ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱnȱǂȱ0:ȱȱ1ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱ
ȱ
Hn(x)ȱ=ȱȱȱȱȱȱnȱ=ȱ1;ȱȱ2xȱ
ȱ
ȱ
ȱȱȱȱȱnȱǃȱ2:ȱȱȱ2xHnȱ–ȱ1(x)ȱ–ȱ2(nȱ–ȱ1)Hnȱ–ȱ2(x)ȱ
ȱ
Forȱ example,ȱ theȱ valueȱ ofȱ H3(2)ȱ isȱ 40.ȱ Writeȱ aȱ recursiveȱ functionȱ toȱ computeȱ theȱ
valueȱofȱHn(x).ȱYourȱfunctionȱshouldȱmatchȱthisȱprototype:ȱ
ȱ
ȱ int hermite( int n, int x );
Download at http://www.pin5i.com/
Chapter 7 Functions
196
2. Theȱ greatestȱ commonȱ divisorȱ ofȱ twoȱ integersȱ Mȱ andȱ Nȱ (whereȱ M,ȱ Nȱ >ȱ 0)ȱ canȱ beȱ
computedȱasȱfollows:ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱMȱ%ȱNȱ=ȱ0:ȱ
ȱ
Nȱ
ȱ
gcd(M,ȱN)ȱ=ȱȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱMȱ%ȱNȱ=ȱR,ȱRȱ>ȱ0:ȱȱ
gcd(N,ȱR)ȱ
ȱ
Writeȱ aȱ functionȱ calledȱ gcdȱ thatȱ takesȱ twoȱ integerȱ argumentsȱ andȱ returnsȱ theȱ
greatestȱcommonȱdivisorȱofȱthoseȱnumbers.ȱIfȱeitherȱofȱtheȱargumentsȱisȱnotȱgreaterȱ
thanȱzero,ȱyourȱfunctionȱshouldȱreturnȱzero.ȱ
3. Writeȱtheȱfunctionȱforȱtheȱfollowingȱprototype:ȱ
int ascii_to_integer( char *string );
Theȱ stringȱ argumentȱ mustȱ containȱ oneȱ orȱ moreȱ digits,ȱ andȱ theȱ functionȱ shouldȱ
convertȱthoseȱdigitsȱtoȱanȱintegerȱandȱreturnȱtheȱresult.ȱIfȱanyȱnondigitȱcharactersȱ
areȱfound,ȱreturnȱtheȱvalueȱzeroȱinstead.ȱDoȱnotȱworryȱaboutȱarithmeticȱoverflow.ȱ
Hint:ȱTheȱtechniqueȱisȱsimple—forȱeachȱdigitȱyouȱfind,ȱmultiplyȱtheȱvalueȱyouȱhaveȱ
soȱfarȱandȱthenȱaddȱtheȱvalueȱrepresentedȱbyȱtheȱnewȱdigitȱ
4. Writeȱ aȱ functionȱ calledȱ max_listȱ thatȱ examinesȱ anȱ arbitraryȱ numberȱ ofȱ integerȱ
argumentsȱandȱreturnsȱtheȱlargestȱofȱthem.ȱȱTheȱargumentsȱwillȱbeȱterminatedȱbyȱaȱ
valueȱthatȱisȱlessȱthanȱzero.ȱ
5. ImplementȱaȱbareȬbonesȱ printfȱfunctionȱthatȱisȱcapableȱofȱhandlingȱtheȱ %d,ȱ %f,ȱ %s,ȱ
andȱ %cȱformatȱcodes.ȱTheȱbehaviorȱforȱotherȱformatȱcodes,ȱinȱtheȱtrueȱspiritȱofȱtheȱ
ANSIȱ Standard,ȱ isȱ undefined.ȱ Youȱ mayȱ assumeȱ theȱ existenceȱ ofȱ theȱ functionsȱ
print_integerȱandȱprint_floatȱtoȱprintȱvaluesȱofȱthoseȱtypes.ȱUseȱputcharȱtoȱprintȱ
everythingȱelse.ȱ
6. Writeȱaȱfunctionȱ
void written_amount( unsigned int amount, char *buffer );
thatȱ convertsȱ theȱ valueȱ inȱ amountȱ toȱ wordsȱ andȱ storesȱ themȱ inȱ theȱ buffer.ȱ Thisȱ
functionȱ mightȱ beȱ usedȱ inȱ aȱ programȱ thatȱ printsȱ checks.ȱ Forȱ example,ȱ ifȱ valueȱ isȱ
16,312,ȱthenȱtheȱstringȱ
SIXTEEN THOUSAND THRSE HUNDRED TWELVE
shouldȱ beȱ storedȱ inȱ theȱ buffer.ȱ Itȱ isȱ theȱ callerȇsȱ responsibilityȱ toȱ makeȱ theȱ bufferȱ
largeȱenough.ȱ
Someȱvaluesȱcanȱbeȱprintedȱinȱtwoȱdifferentȱways.ȱForȱexample,ȱ1,200ȱcouldȱbeȱ
eitherȱ ONE THOUSAND TWO HUNDRED OR TWELVE HUNDREDȱ Youȱ mayȱ convertȱ theseȱ
valuesȱwhicheverȱwayȱyouȱwish.ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
8
Arrays
Youȇveȱ beenȱ usingȱ simple,ȱ oneȬdimensionalȱ arraysȱ sinceȱ Chapterȱ 2.ȱ Thisȱ chapterȱ
explainsȱ moreȱ aboutȱ theseȱ arraysȱ andȱ exploresȱ moreȱ advancedȱ arrayȱ topicsȱ suchȱ asȱ
multidimensionalȱarrays,ȱarraysȱandȱpointers,ȱandȱarrayȱinitialization.ȱ
ȱ
ȱ
ȱ
8.1 One-Dimensional Arrays
ȱ
Beforeȱ weȱintroduceȱmultidimensionalȱarrays,ȱthereȱ isȱ aȱlotȱmoreȱtoȱ learnȱaboutȱ oneȬ
dimensionalȱarrays.ȱLetȇsȱbeginȱwithȱaȱconceptȱthatȱmanyȱconsiderȱaȱflawȱinȱtheȱdesignȱ
ofȱtheȱCȱlanguage,ȱbutȱthisȱconceptȱactuallyȱtiesȱsomeȱdisparateȱconceptsȱtogetherȱquiteȱ
nicely.ȱ
ȱ
ȱ
ȱ
8.1.1 Array Names
ȱ
Considerȱtheseȱdeclarations:ȱ
ȱ
ȱ
int
a;
int
b[10];
Weȱ callȱ theȱ variableȱ aȱ aȱ scalarȱ becauseȱ itȱ isȱ aȱ singleȱ value.ȱ Theȱ typeȱ ofȱ theȱ valueȱ isȱ
integer.ȱȱWeȱcallȱtheȱvariableȱbȱanȱarrayȱbecauseȱitȱisȱaȱcollectionȱofȱvalues.ȱȱAȱsubscriptȱ
isȱ usedȱ withȱ theȱ arrayȱ nameȱ toȱ identifyȱ oneȱ specificȱ valueȱ fromȱ thatȱ collection;ȱ forȱ
example,ȱb[0]ȱidentifiesȱtheȱfirstȱvalueȱinȱtheȱbȱarray,ȱandȱb[4]ȱidentifiesȱtheȱfifth.ȱEachȱ
specificȱ valueȱ isȱ aȱ scalarȱ andȱ mayȱ beȱ usedȱ inȱ anyȱ contextȱ inȱ whichȱ aȱ scalarȱ mayȱ beȱ
used.ȱ
Theȱtypeȱofȱ b[4]ȱisȱinteger,ȱbutȱwhatȱisȱtheȱtypeȱofȱ b?ȱToȱwhatȱdoesȱitȱrefer?ȱAȱ
logicalȱanswerȱwouldȱbeȱthatȱitȱrefersȱtoȱtheȱwholeȱarray,ȱbutȱitȱdoesnȇt.ȱInȱC,ȱwhenȱtheȱ
Download at http://www.pin5i.com/
198ȱ
Chapter 8 Arrays
nameȱofȱanȱarrayȱisȱusedȱinȱalmostȱanyȱexpression,ȱtheȱvalueȱofȱtheȱnameȱisȱaȱpointerȱ
constantȱ thatȱ isȱ theȱ addressȱ ofȱ theȱ firstȱ elementȱ ofȱ theȱ array.ȱ Itsȱ typeȱ dependsȱ onȱ theȱ
typeȱ ofȱ theȱ arrayȱ elements:ȱ ifȱ theyȱ areȱ int,ȱ thenȱ theȱ valueȱ ofȱ theȱ arrayȱ nameȱ isȱ aȱ
Ȉconstantȱpointerȱtoȱ int.ȈȱIfȱtheyȱareȱsomethingȱelse,ȱthenȱtheȱvalueȱofȱtheȱarrayȱnameȱ
isȱaȱȈconstantȱpointerȱtoȱsomethingȱelse.Ȉȱ
Doȱnotȱconcludeȱfromȱthisȱthatȱarraysȱandȱpointersȱareȱtheȱsame.ȱAnȱarrayȱhasȱ
quiteȱ differentȱ characteristicsȱ thanȱ aȱ pointer,ȱ forȱ example,ȱ anȱ arrayȱ hasȱ aȱ certainȱ
numberȱofȱelements,ȱwhileȱaȱpointerȱisȱaȱscalar.ȱTheȱcompilerȱusesȱtheȱarrayȱnameȱtoȱ
keepȱtrackȱofȱtheseȱproperties.ȱItȱisȱonlyȱwhenȱtheȱarrayȱnameȱisȱusedȱinȱanȱexpressionȱ
thatȱtheȱcompilerȱgeneratesȱtheȱpointerȱconstant.ȱ
NoteȬthatȱthisȱvalueȱisȱaȱpointerȱconstantȱasȱopposedȱtoȱaȱpointerȱvariable;ȱyouȱ
cannotȱchangeȱtheȱ valueȱ ofȱ aȱ constant.ȱ Onȱreflectionȱthisȱrestrictionȱmakesȱ sense;ȱtheȱ
valueȱpointsȱtoȱwhereȱtheȱarrayȱbeginsȱinȱmemory,ȱsoȱtheȱonlyȱwayȱtoȱchangeȱitȱisȱtoȱ
moveȱtheȱarrayȱsomewhereȱelseȱinȱmemory.ȱButȱmemoryȱforȱarraysȱisȱfixedȱwhenȱtheȱ
programȱisȱlinked,ȱsoȱbyȱtheȱtimeȱtheȱprogramȱisȱrunning,ȱitȱisȱmuchȱtooȱlateȱtoȱmoveȱ
anȱarray.ȱHence,ȱtheȱvaluesȱofȱarrayȱnamesȱareȱpointerȱconstants.ȱ
Thereȱ areȱ onlyȱ twoȱ placesȱ whereȱ thisȱ pointerȱ substitutionȱ doesȱ notȱ occur—
whenȱ anȱ arrayȱ nameȱ isȱ anȱ operandȱ ofȱ eitherȱ sizeofȱ orȱ theȱ unaryȱ operatorȱ &.ȱ sizeofȱ
returnsȱ theȱ sizeȱ ofȱ theȱ entireȱ array,ȱ notȱ theȱ sizeȱ ofȱ aȱ pointerȱ toȱ theȱ array.ȱ Takingȱ theȱ
addressȱofȱanȱarrayȱnameȱgivesȱaȱpointerȱtoȱtheȱfirstȱelementȱinȱtheȱarray,ȱnotȱaȱpointerȱ
toȱsomeȱsubstitutedȱpointerȱconstantȱvalue.ȱ
Nowȱconsiderȱthisȱexample:ȱ
ȱ
int
a[10];
int
b[10];
int
*c;
...
c = &a[0];
ȱ
Theȱexpressionȱ &a[0]ȱisȱaȱpointerȱtoȱtheȱfirstȱelementȱofȱtheȱarray.ȱButȱthatȇsȱtheȱvalueȱ
ofȱtheȱarrayȱnameȱitself,ȱsoȱtheȱfollowingȱassignmentȱperformsȱexactlyȱtheȱsameȱjobȱasȱ
theȱoneȱabove:ȱ
ȱ
c = a;
ȱ
Thisȱassignmentȱshowsȱwhyȱitȱisȱimportantȱtoȱunderstandȱtheȱtrueȱmeaningȱofȱanȱarrayȱ
nameȱinȱanȱexpression.ȱIfȱtheȱnameȱreferredȱtoȱtheȱentireȱarray,ȱthisȱstatementȱwouldȱ
implyȱ thatȱtheȱ entireȱarrayȱisȱbeingȱcopiedȱ toȱ aȱnewȱarray.ȱButȱ thisȱ isȱ notȱ atȱallȱ whatȱ
happens;ȱwhatȱisȱassignedȱisȱaȱcopyȱofȱaȱpointer,ȱmakingȱcȱpointȱtoȱtheȱfirstȱelementȱofȱ
theȱarray.ȱThus,ȱassignmentsȱsuchȱasȱ
Download at http://www.pin5i.com/
8.1 One-Dimensional Arrays
199
b = a;
ȱ
areȱ illegal.ȱ Youȱ cannotȱ useȱ theȱ assignmentȱ operatorȱ toȱ copyȱ allȱ theȱ elementsȱ ofȱ oneȱ
arrayȱtoȱanotherȱarray;ȱyouȱmustȱuseȱaȱloopȱandȱcopyȱoneȱelementȱatȱaȱtime.ȱ
Considerȱthisȱstatement:ȱ
ȱ
a = c;
ȱ
Withȱ cȱ declaredȱ asȱ aȱ pointerȱ variable,ȱ thisȱ assignmentȱ looksȱ likeȱ itȱ oughtȱ toȱ performȱ
anotherȱ pointerȱ assignment,ȱ copyingȱ theȱ valueȱ ofȱ cȱ intoȱ a.ȱ Butȱ thisȱ assignmentȱ isȱ
illegal:ȱ rememberȱ thatȱ theȱ valueȱ ofȱ aȱ inȱ thisȱ expressionȱ isȱ aȱ constant,ȱ soȱ itȱ cannotȱ beȱ
changed.ȱ
ȱ
ȱ
ȱ
8.1.2 Subscripts
ȱ
Inȱtheȱcontextȱofȱtheȱpreviousȱdeclarations,ȱwhatȱisȱtheȱmeaningȱofȱthisȱexpression?ȱ
ȱ
*( b + 3 )
First,ȱtheȱvalueȱofȱ bȱisȱaȱpointerȱtoȱanȱinteger,ȱsoȱtheȱvalueȱthreeȱisȱscaledȱtoȱtheȱsizeȱofȱ
anȱ integer.ȱ Theȱ additionȱ yieldsȱ aȱ pointerȱ toȱ theȱ integerȱ thatȱ isȱ locatedȱ threeȱ integersȱ
beyondȱ theȱ firstȱ oneȱ inȱ theȱ array.ȱ Theȱ indirectionȱ thenȱ takesȱ usȱ toȱ thisȱ newȱ location,ȱ
eitherȱtoȱgetȱtheȱvalueȱthereȱ(RȬvalue)ȱorȱtoȱstoreȱaȱnewȱoneȱ(LȬvalue).ȱ
Ifȱ thisȱ processȱ soundsȱ familiar,ȱ itȱ isȱ becauseȱ aȱ subscriptȱ doesȱ exactlyȱ theȱ sameȱ
thing.ȱȱWeȱcanȱnowȱexplainȱaȱstatementȱthatȱwasȱmentionedȱinȱChapterȱ5:ȱexceptȱforȱitsȱ
precedence,ȱ aȱ subscriptȱ isȱ exactlyȱ theȱ sameȱ asȱ anȱ indirection.ȱ Forȱ example,ȱ theȱ
followingȱexpressionsȱareȱequivalent:ȱ
ȱ
array[subscript]
*( array + ( subscript ) )
ȱ
Nowȱthatȱyouȱknowȱthatȱtheȱvalueȱofȱanȱarrayȱnameȱisȱjustȱaȱpointerȱconstant,ȱyouȱcanȱ
verifyȱ thisȱ equivalence.ȱ Inȱ theȱ subscriptȱ expression,ȱ theȱ subscriptȱ isȱ evaluatedȱ first.ȱȱ
Thenȱtheȱsubscriptȱvalueȱselectsȱaȱspecificȱarrayȱelement.ȱȱInȱtheȱsecondȱexpression,ȱtheȱ
innerȱ parenthesesȱ guaranteeȱ thatȱ theȱ subscriptȱ isȱ evaluatedȱ first,ȱ asȱ before.ȱ Usingȱ
pointerȱ arithmetic,ȱ theȱ additionȱ producesȱ aȱ pointerȱ toȱ theȱ desiredȱ element.ȱ Theȱ
indirectionȱthenȱfollowsȱthatȱpointer,ȱandȱvoila—anȱarrayȱelement.ȱ
Whereverȱ aȱ subscriptȱ isȱ used,ȱ theȱ equivalentȱ pointerȱ expressionȱ canȱ alsoȱ beȱ
used;ȱ andȱ whereverȱ aȱ pointerȱ expressionȱ ofȱ theȱ formȱ shownȱ aboveȱ isȱ used,ȱ youȱ canȱ
alsoȱuseȱaȱsubscript.ȱ
Download at http://www.pin5i.com/
200ȱ
Chapter 8 Arrays
Hereȱisȱaȱlittleȱexercisesȱtoȱillustrateȱthisȱequivalence.ȱ
ȱ
int
int
array[10];
*ap = array + 2;
ȱ
Rememberȱtheȱscalingȱthatȱisȱperformedȱonȱtheȱaddition:ȱtheȱresultȱisȱthatȱ apȱpointsȱatȱ
array[2],ȱlikeȱthis:ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
arrayȱ
ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ
ȱ
Forȱ eachȱ ofȱ theȱ followingȱ expressionsȱ involvingȱ ap,ȱ seeȱ ifȱ youȱ canȱ thinkȱ ofȱ anȱ
equivalentȱexpressionȱthatȱusesȱarray.ȱ
ȱ
ap
Thisȱoneȱisȱeasy,ȱyouȱcanȱjustȱreadȱtheȱanswerȱfromȱtheȱinitialization:ȱ
array + 2.ȱȱTheȱexpressionȱ&array[2]ȱisȱequivalent.ȱ
*ap
Anotherȱeasyȱone:ȱtheȱindirectionȱfollowsȱtheȱpointerȱtoȱtheȱlocationȱitȱ
isȱpointingȱat,ȱwhichȱisȱarray[2].ȱȱYouȱcouldȱalsoȱwrite *(array + 2).ȱ
ap[0]
ȈYouȱ canȇtȱ doȱ that,ȱ apȱ isnȇtȱ anȱ array!Ȉȱ Ifȱ youȱ thoughtȱ somethingȱ likeȱ
this,ȱyouȇreȱstuckȱinȱtheȱȈcanȇtȱdoȱitȱinȱotherȱlanguagesȈȱrut.ȱRemember,ȱ
aȱ subscriptȱ inȱ Cȱ isȱ exactlyȱ likeȱ anȱ indirectionȱ expression,ȱ soȱ youȱ canȱ
useȱoneȱanywhereȱyouȱcanȱuseȱindirection.ȱInȱthisȱcase,ȱtheȱequivalentȱ
expressionȱisȱ *( ap + ( 0 ) )ȱwhich,ȱafterȱgettingȱridȱofȱtheȱzeroȱandȱ
theȱ parentheses,ȱ endsȱ upȱ beingȱ identicalȱ toȱ theȱ previousȱ expression.ȱ
Thereforeȱitȱhasȱtheȱsameȱanswer:ȱarray [2].ȱ
ap + 6
Ifȱapȱpointsȱtoȱarray[2],ȱthisȱadditionȱgivesȱaȱpointerȱtoȱtheȱlocationȱsixȱ
integersȱ laterȱ inȱ theȱ array,ȱ whichȱ isȱ equivalentȱ toȱ array + 8ȱ orȱ
&array[8].ȱ
*ap + 6
Beȱ careful,ȱ thereȱ areȱ twoȱ operatorsȱ here;ȱ whichȱ goesȱ first?ȱ Theȱ
indirection.ȱ Theȱ resultȱ ofȱ theȱ indirectionȱ isȱ thenȱ addedȱ toȱ six,ȱ soȱ thisȱ
expressionȱisȱtheȱsameȱasȱarray[2] * 6.ȱ
*(ap + 6)
Theȱparenthesesȱforceȱtheȱadditionȱtoȱgoȱfirst,ȱsoȱthisȱtimeȱweȱgetȱtheȱ
valueȱofȱ array[8].ȱObserveȱthatȱtheȱindirectionȱusedȱhereȱisȱinȱexactlyȱ
theȱsameȱformȱasȱtheȱindirectionȱofȱaȱsubscript.ȱ
Download at http://www.pin5i.com/
8.1 One-Dimensional Arrays
201
ap[6]
Convertȱthisȱsubscriptȱtoȱitsȱindirectionȱform,ȱandȱyouȇllȱseeȱtheȱsameȱ
expressionȱweȱjustȱdid,ȱsoȱitȱhasȱtheȱsameȱanswer.ȱ
&ap
Thisȱexpressionȱisȱperfectlyȱlegal,ȱbutȱthereȱisȱnoȱequivalentȱexpressionȱ
involvingȱ arrayȱ becauseȱ youȱ cannotȱ predictȱ whereȱ theȱ compilerȱ willȱ
locateȱapȱrelativeȱtoȱarray.ȱ
ap[-1]
Howȇsȱ thatȱ again,ȱ aȱ negativeȱ subscript?ȱ Aȱ subscriptȱ isȱ justȱ anȱ
indirectionȱexpression;ȱconvertȱitȱtoȱthatȱformȱandȱthenȱevaluateȱitȱȱ apȱ
pointsȱatȱtheȱthirdȱelementȱ(theȱoneȱwhoseȱsubscriptȱisȱtwo),ȱsoȱusingȱ
anȱoffsetȱofȱȬ1ȱgetsȱusȱtheȱpreviousȱelement:ȱarray[1].ȱ
ap[9]
Thisȱ oneȱ looksȱ fineȱ butȱ isȱ actuallyȱ aȱ problem.ȱ Theȱ equivalentȱ
expressionȱ isȱ array[11],ȱ butȱ theȱ problemȱ isȱ thatȱ thereȱ areȱ onlyȱ tenȱ
elementsȱ inȱ theȱ array.ȱ Evaluatingȱ theȱ subscriptȱ producesȱ aȱ pointerȱ
expressionȱthatȱrunsȱoffȱtheȱendȱofȱtheȱarray,ȱwhichȱmakesȱthisȱillegalȱ
accordingȱ toȱ theȱ Standard.ȱ However,ȱ fewȱ compilersȱ detectȱ thisȱ error,ȱ
soȱtheȱprogramȱgoesȱmerrilyȱonȱitsȱway.ȱȱButȱwhatȱdoesȱtheȱexpressionȱ
do?ȱ Theȱ Standardȱ saysȱ thatȱ itsȱ behaviorȱ isȱ undefined,ȱ butȱ onȱ mostȱ
machinesȱ itȱ accessesȱ whateverȱ valueȱ happensȱ toȱ beȱ storedȱ inȱ theȱ
secondȱlocationȱbeyondȱtheȱendȱofȱtheȱarray.ȱYouȱcanȱsometimesȱfigureȱ
outȱwhatȱthisȱvalueȱisȱbyȱaskingȱtheȱcompilerȱtoȱproduceȱanȱassemblyȱ
languageȱversionȱofȱtheȱprogramȱandȱexaminingȱthatȱcode,ȱbutȱthereȱisȱ
noȱuniversalȱwayȱtoȱpredictȱwhatȱvalueȱwillȱbeȱstoredȱthere.ȱȱThus,ȱthisȱ
expressionȱwillȱaccessȱ(or,ȱifȱusedȱasȱanȱLȬvalue,ȱwillȱchange)ȱtheȱvalueȱ
ofȱ someȱ randomȱ variable.ȱ Thisȱ resultȱ isȱ notȱ likelyȱ toȱ beȱ whatȱ youȱ
wanted.ȱ
ȱ
Theȱ lastȱ twoȱ examplesȱ showȱ whyȱ subscriptȱ checkingȱ isȱ aȱ difficultȱ taskȱ inȱ C.ȱ Theȱ
Standardȱdoesȱnotȱrequireȱthatȱitȱbeȱdoneȱatȱall;ȱtheȱearliestȱCȱcompilersȱdidnȇtȱcheckȱ
subscripts,ȱandȱmostȱcurrentȱonesȱstillȱdonȇt.ȱTheȱfactȱthatȱsubscriptsȱcanȱbeȱappliedȱtoȱ
arbitraryȱ pointers,ȱ notȱ justȱ arrayȱ names,ȱ makesȱ theȱ jobȱ difficult.ȱ Theȱ validityȱ ofȱ aȱ
subscriptȱappliedȱtoȱaȱpointerȱvariableȱdependsȱonȱwhereȱitȱhappensȱtoȱbeȱpointingȱatȱ
theȱtime,ȱasȱwellȱasȱtheȱvalueȱofȱtheȱsubscript.ȱ
Consequently,ȱsubscriptȱcheckingȱinȱCȱinvolvesȱmoreȱoverheadȱthanȱyouȱmightȱ
firstȱ think.ȱ Instructionsȱmustȱbeȱinsertedȱ intoȱtheȱprogramȱtoȱ verifyȱthatȱtheȱ resultȱofȱ
theȱ subscriptȱ refersȱ toȱ anȱ elementȱ inȱ theȱ sameȱ arrayȱ asȱ theȱ pointer.ȱ Thisȱ comparisonȱ
requiresȱinformationȱaboutȱtheȱlocationsȱandȱsizesȱofȱallȱarraysȱinȱtheȱprogram,ȱwhichȱ
willȱ takeȱ someȱ space.ȱ Theȱ informationȱ mustȱ alsoȱ beȱ updatedȱ asȱ theȱ programȱ runsȱ toȱ
reflectȱautomaticȱandȱdynamicallyȱallocatedȱarrays,ȱwhichȱwillȱtakeȱsomeȱtime.ȱThus,ȱ
Download at http://www.pin5i.com/
202ȱ
Chapter 8 Arrays
compilersȱthatȱofferȱsubscriptȱcheckingȱusuallyȱalsoȱofferȱaȱwayȱtoȱturnȱitȱoff.ȱ
Hereȇsȱ anȱ interesting,ȱ thoughȱ admittedlyȱ arcane,ȱ tangent.ȱ Inȱ theȱ contextȱ ofȱ theȱ
previousȱdeclarations,ȱwhatȱisȱtheȱmeaningȱofȱthisȱexpression?ȱ
ȱ
2[array]
ȱ
Theȱ answerȱ mayȱ surpriseȱ you:ȱ itȱ isȱ legal.ȱ Convertȱ itȱ toȱ theȱ equivalentȱ indirectionȱ
expressionȱandȱyouȱwillȱseeȱitsȱvalidity:ȱ
ȱ
*( 2 + ( array ) )
ȱ
Theȱ innerȱ parenthesesȱ areȱ redundant,ȱ soȱ weȱ canȱ deleteȱ them.ȱ Also,ȱ additionȱ isȱ
commutative,ȱsoȱthisȱexpressionȱhasȱexactlyȱtheȱsameȱmeaningȱasȱ
ȱ
*( array + 2 )
ȱ
meaningȱthatȱtheȱoriginal,ȱfunnyȬlookingȱexpressionȱisȱidenticalȱtoȱarray[2].ȱ
Thisȱ quirkȱ existsȱ becauseȱ ofȱ theȱ wayȱ thatȱ subscriptsȱ areȱ implementedȱ inȱ C.ȱ
Eitherȱ formȱ isȱ fineȱ asȱ farȱ asȱ theȱ compilerȱ isȱ concerned.ȱ However,ȱ youȱ shouldȱ neverȱ
writeȱ2[array]:ȱitȱonlyȱmakesȱtheȱprogramȱharderȱforȱothersȱtoȱread.ȱ
ȱ
ȱ
ȱ
8.1.3 Pointers versus Subscripts
ȱ
Ifȱ youȱ canȱ useȱ indirectionȱ expressionsȱ andȱ subscriptsȱ interchangeably,ȱ whichȱ shouldȱ
youȱuse?ȱAsȱusual,ȱthereȱisȱnoȱsimpleȱanswer.ȱSubscriptsȱareȱeasierȱforȱȈmostȱpeopleȱtoȱ
understand,ȱespeciallyȱwithȱmultidimensionalȱarrays,ȱsoȱthereȱisȱsomeȱbenefitȱgainedȱ
inȱ readabilityȱ byȱ usingȱ them.ȱ Onȱ theȱ otherȱ hand,ȱ thisȱ choiceȱ mayȱ affectȱ runtimeȱ
efficiency.ȱ
ȱ
Assumingȱ thatȱ theyȱ areȱ bothȱ usedȱ correctly,ȱ subscriptsȱ areȱ neverȱ moreȱ efficientȱ thanȱ
pointers,ȱbutȱpointersȱareȱsometimesȱmoreȱefficientȱthanȱsubscripts.ȱ
ȱ
Toȱ understandȱ thisȱ efficiencyȱ issueȱ letȇsȱ examineȱ twoȱ loopsȱ thatȱ performȱ theȱ
sameȱwork.ȱȱFirst,ȱweȱclearȱtheȱelementsȱofȱanȱarrayȱusingȱsubscripts.ȱ
ȱ
int
array[10], a;
for( a = 0; a < 10; a += 1 )
array[a] = 0;
ȱ
Toȱevaluateȱthisȱsubscript,ȱtheȱcompilerȱinsertsȱinstructionsȱinȱtheȱprogramȱtoȱtakeȱtheȱ
valueȱofȱaȱandȱmultiplyȱitȱbyȱtheȱsizeȱofȱanȱintegerȱ(say,ȱfour).ȱThisȱmultiplicationȱtakesȱ
bothȱspaceȱandȱtime.ȱ
Download at http://www.pin5i.com/
8.1 One-Dimensional Arrays
ȱ
ȱ
203
Nowȱconsiderȱthisȱloop,ȱwhichȱdoesȱexactlyȱtheȱsameȱwork.ȱ
ȱ
int
array[10], *ap;
for( ap = array; ap < array + 10; ap++ )
*ap = 0;
ȱ
Theȱ multiplicationȱ isȱ stillȱ inȱ hereȱ somewhere,ȱ evenȱ thoughȱ thereȱ isȱ noȱ longerȱ anyȱ
subscript.ȱLookȱcloselyȱnowȱandȱseeȱifȱyouȱcanȱfindȱit.ȱ
Theȱ multiplicationȱ isȱ nowȱ performedȱ inȱ theȱ adjustmentȱ stepȱ ofȱ theȱ forȱ
statement;ȱtheȱvalueȱoneȱmustȱbeȱscaledȱtoȱtheȱsizeȱofȱanȱintegerȱbeforeȱitȱisȱaddedȱtoȱ
theȱ pointer.ȱ Butȱ thereȱ isȱ aȱ bigȱ differenceȱ here:ȱ theȱ sameȱ twoȱ valuesȱ (1ȱ ×ȱ 4)ȱ areȱ
multipliedȱ eachȱ timeȱ throughȱ theȱ loop.ȱ Asȱ aȱ result,ȱ thisȱ multiplicationȱ isȱ performedȱ
onceȱ atȱ compileȱ time—theȱ programȱ nowȱ containsȱ anȱ instructionȱ toȱ addȱ fourȱ toȱ theȱ
pointer.ȱȱNoȱmultiplicationsȱareȱperformedȱatȱrunȱtime.ȱ
Thisȱ exampleȱ illustratesȱ theȱ typeȱ ofȱ situationȱ inȱ whichȱ pointersȱ areȱ moreȱ
efficientȱthanȱsubscriptsȱ–ȱwhenȱmovingȱthroughȱanȱarrayȱbyȱoneȱ(orȱanyȱotherȱfixedȱ
amount).ȱ Theȱ multiplicationȱ isȱ performedȱ onȱ theȱ fixedȱ amountȱ atȱ compileȱ time,ȱ soȱ
thereȱareȱfewerȱinstructionsȱtoȱexecuteȱatȱrunȱtime.ȱOnȱmostȱmachinesȱtheȱprogramȱisȱ
smallerȱandȱfaster.ȱ
Nowȱconsiderȱtheseȱtwoȱfragmentsȱofȱcode:ȱ
ȱ
a = get_value();
array[a] = 0;
a = get_value();
*( array + a ) = 0;
ȱ
Thereȱisȱnoȱdifferenceȱinȱtheȱcodeȱgeneratedȱforȱtheseȱstatements.ȱaȱcouldȱbeȱanyȱ
value,ȱ soȱ theȱ multiplicationȱ instructionȱ isȱ neededȱ inȱ bothȱ placesȱ toȱ scaleȱ it.ȱ Thisȱ
exampleȱillustratesȱtheȱtypeȱofȱsituationȱinȱwhichȱpointersȱandȱsubscriptsȱareȱequallyȱ
efficient.ȱ
ȱ
ȱ
ȱ
8.1.4 Pointer Efficiency
ȱ
Iȱ statedȱ earlierȱ thatȱ pointersȱ areȱ sometimesȱ moreȱ efficientȱ thanȱ subscripts,ȱ assumingȱ
thatȱ theyȱ areȱ usedȱ correctly.ȱ Asȱ theyȱ sayȱ onȱ TV,ȱ yourȱ resultsȱ mayȱ vary;ȱ itȱ dependsȱ onȱ
yourȱ compilerȱ andȱ machine.ȱ However,ȱ theȱ efficiencyȱ ofȱ yourȱ programȱ dependsȱ
primarilyȱonȱtheȱcodeȱyouȱwrite,ȱandȱitȱisȱjustȱasȱeasyȱtoȱwriteȱbadȱcodeȱwithȱpointersȱ
asȱitȱisȱwithȱsubscripts.ȱȱInȱfact,ȱitȱisȱprobablyȱeasier.ȱ
Toȱ illustrateȱ someȱ badȱ techniquesȱ asȱ wellȱ asȱ goodȱ ones,ȱ letȇsȱ lookȱ atȱ aȱ simpleȱ
functionȱthatȱcopiesȱtheȱcontentsȱofȱoneȱarrayȱintoȱaȱsecondȱarrayȱusingȱsubscripts.ȱWeȱ
willȱanalyzeȱtheȱassemblyȱcodeȱproducedȱforȱthisȱfunctionȱbyȱoneȱparticularȱcompilerȱ
forȱ aȱ computerȱ usingȱ aȱ processorȱ fromȱ theȱ Motorolaȱ M68000ȱ family.ȱ Weȱ willȱ then
Download at http://www.pin5i.com/
Chapter 8 Arrays
204ȱ
ȱmodifyȱ theȱ functionȱ inȱ variousȱ waysȱ toȱ useȱ pointersȱ andȱ seeȱ whatȱ effectȱ eachȱ
modificationȱȱhasȱonȱtheȱresultingȱobjectȱcode.ȱ
Beforeȱ beginningȱ theȱ example,ȱ twoȱ cautionsȱ areȱ inȱ order.ȱ First,ȱ theȱ wayȱ youȱ
writeȱyourȱprogramȱaffectsȱnotȱonlyȱitsȱruntimeȱefficiencyȱbutȱalsoȱitsȱreadability.ȱItȱisȱ
importantȱ notȱ toȱ sacrificeȱ readabilityȱ forȱ negligibleȱ gainsȱ inȱ efficiency.ȱ Moreȱ willȱ beȱ
saidȱaboutȱthisȱissueȱlater.ȱ
Second,ȱtheȱassemblyȱlanguageȱshownȱisȱobviouslyȱspecificȱtoȱtheȱ68000ȱfamilyȱ
ofȱ processors.ȱ Otherȱ machinesȱ (andȱ otherȱ compilers)ȱ mayȱ translateȱ theȱ programsȱ
differently.ȱ Ifȱ youȱ needȱ theȱ utmostȱ efficiencyȱ forȱ yourȱ environment,ȱ youȱ canȱ
experimentȱasȱIȇveȱdoneȱhereȱtoȱseeȱhowȱvariousȱsourceȱcodeȱidiomsȱareȱimplemented.ȱ
First,ȱtheȱfollowingȱdeclarationsȱapplyȱtoȱallȱversionsȱofȱtheȱfunction.ȱ
ȱ
#define
int
int
int
int
SIZE
x[SIZE];
y[SIZE];
I;
*p1, *p2;
50
ȱ
Hereȱisȱtheȱsubscriptȱversionȱofȱtheȱfunction.ȱ
ȱ
void
try1()
{
for( i = 0; i < SIZE; i++ )
x[i] = y[i];
}
ȱ
Thisȱversionȱisȱprettyȱstraightforward.ȱTheȱcompilerȱproducedȱtheȱfollowingȱassemblyȱ
languageȱcode.ȱ
ȱ
ȱ
00000004
0000000a
0000000c
00000012
00000014
0000001a
00000020
00000022
00000028
0000002e
00000034
00000036
0000003c
ȱ
42b90000
6028
20390000
e580
207c0000
22390000
e581
227c0000
23b00800
52b9G00C
7032
b0b90000
6ece
0000
_tryl:
0000
L20001:
0000
0000
0000
1800
0000
L20:
0000
clrl
jra
movl
asll
movl
movl
asll
movl
movl
addql
moveq
cmpl
jgt
_i
L20
_i,d0
#2,d0
#_y,a0
_i,d1
#2,d1
#_x,a1
a0@(0,d0:L),a1@(0,d1:L)
#1,_i
#50,d0
_i,d0
L20001
Download at http://www.pin5i.com/
8.1 One-Dimensional Arrays
205
Letȇsȱ walkȱ throughȱ theseȱ instructions,ȱ oneȱ byȱ one.ȱ First,ȱ theȱ locationȱ containingȱ theȱ
variableȱ iȱisȱcleared,ȱwhichȱimplementsȱtheȱassignmentȱtoȱzero.ȱThenȱexecutionȱjumpsȱ
toȱtheȱinstructionȱlabeledȱ L20,ȱwhich,ȱwithȱtheȱfollowingȱinstruction,ȱtestsȱwhetherȱ iȱisȱ
lessȱthanȱ50.ȱIfȱitȱis,ȱexecutionȱjumpsȱbackȱupȱtoȱtheȱinstructionȱlabeledȱL20001.ȱ
Theȱ instructionȱ labeledȱ L20001ȱ beginsȱ theȱ bodyȱ ofȱ theȱ loop. iȱ isȱ copiedȱ toȱ
registerȱd0ȱwhereȱitȱisȱshiftedȱleftȱbyȱtwoȱbits.ȱȱTheȱshiftȱisȱusedȱbecauseȱitȱproducesȱtheȱ
sameȱresultȱasȱaȱmultiplicationȱbyȱfourȱbutȱisȱfaster.ȱȱTheȱaddressȱofȱtheȱarrayȱ yȱisȱthenȱ
copiedȱtoȱaddressȱregisterȱa0.ȱ
Nowȱ theȱ sameȱ calculationȱ thatȱ wasȱ previouslyȱ performedȱ onȱ iȱ isȱ doneȱ again,ȱ
butȱthisȱtimeȱtheȱresultȱisȱputȱinȱregisterȱ d1.ȱThenȱtheȱaddressȱofȱtheȱarrayȱ xȱisȱputȱintoȱ
addressȱregisterȱa1.ȱ
Theȱ movlȱ instructionȱ withȱ theȱ complicatedȱ operandsȱ isȱ whatȱ reallyȱ doesȱ theȱ
work:ȱtheȱvalueȱthatȱ a0 + d0ȱpointsȱatȱisȱcopiedȱtoȱtheȱlocationȱthatȱ a1 + d1ȱpointsȱat.ȱ
Thenȱiȱisȱincremented,ȱandȱcomparedȱtoȱ50ȱtoȱseeȱifȱtheȱloopȱshouldȱrepeat.ȱ
ȱ
Doesȱitȱseemȱsillyȱthatȱtheȱcompilerȱevaluatesȱtheȱexpressionȱ i * 4ȱtwice,ȱwhenȱ iȱhasȱ
notȱ changedȱ betweenȱ theȱ expressions?ȱ Well,ȱ thisȱ compilerȱ isȱ fairlyȱ old,ȱ andȱ itsȱ
optimizerȱisnȇtȱveryȱsmart.ȱModernȱcompilersȱmayȱdoȱaȱbetterȱjob,ȱbutȱmaybeȱnot.ȱItȱisȱ
betterȱtoȱwriteȱgoodȱsourceȱcodeȱinȱtheȱfirstȱplaceȱthanȱtoȱdependȱonȱtheȱcompilerȱtoȱ
produceȱefficientȱobjectȱcodeȱfromȱbadȱsourceȱcode.ȱRemember,ȱthough,ȱthatȱefficiencyȱ
isȱnotȱtheȱonlyȱfactor;ȱusuallyȱtheȱclarityȱofȱtheȱcodeȱisȱmoreȱimportant.ȱ
ȱ
ȱ
ȱ
Switching to Pointers
ȱ
Nowȱletȇsȱrewriteȱtheȱfunctionȱwithȱpointers.ȱ
ȱ
void
try2()
{
for( p1 = x, p2 = y; p1 – x < SIZE; )
*p1++ = *p2++;
}
ȱ
Iȇveȱ replacedȱ theȱ subscriptsȱ withȱ pointerȱ variables.ȱ Oneȱ ofȱ theȱ pointersȱ isȱ testedȱ toȱ
determineȱwhenȱtoȱexitȱtheȱloop,ȱsoȱtheȱcounterȱisȱnoȱlongerȱneeded.ȱ
ȱ
00000046
00000050
0000005a
23fc0000
0000
23fc0000
0000
601a
00000000
00000000
_try2:
movl
#_x,_p1
movl
#_y,_p2
jra
L25
Download at http://www.pin5i.com/
206ȱ
Chapter 8 Arrays
0000005c
00000062
00000068
0000006a
00000070
00000076
00000078
0000007a
00000080
00000086
00000088
0000008e
00000090
00000092
00000094
20790000
22790000
2290
58b90000
58b90000
7004
2f00
20390000
04800000
2f00
4eb90000
508f
7232
b280
6ec6
0000
0000
L20003:
0000
0000
L2 S:
0000
0000
0000
movl
movl
movl
addql
addql
moveg
movl
movl
subl
movl
jbsr
addql
moveq
cmpl
jgt
_p2,a0
_p1,a1
a0@,a1@
#4,_p2
#4,_p1
#4,d0
d0,sp@_p1,d0
#_x,d0
d0,sp@ldiv
#8,sp
#50,d1
d0,d1
L20003
ȱ
Theseȱchangesȱdoȱnotȱgiveȱmuchȱofȱanȱimprovementȱoverȱtheȱfirstȱversion.ȱTheȱcodeȱ
neededȱ toȱ copyȱ anȱ integerȱ andȱ incrementȱ theȱ pointersȱ hasȱ decreased,ȱ butȱ theȱ
initializationȱ codeȱ hasȱ increased.ȱ Theȱ shiftsȱ toȱ scaleȱ theȱ subscriptȱ areȱ gone,ȱ andȱ theȱ
movlȱinstructionȱthatȱdoesȱtheȱrealȱworkȱnoȱlongerȱusesȱindexing.ȱButȱtheȱcodeȱtoȱcheckȱ
forȱ theȱ endȱ ofȱ theȱ loopȱ hasȱ increasedȱ aȱ lot,ȱ becauseȱ theȱ subtractionȱ ofȱ twoȱ pointersȱ
mustȱbeȱscaledȱ(inȱthisȱcase,ȱdividedȱbyȱ4).ȱTheȱdivisionȱisȱperformedȱbyȱpushingȱtheȱ
valuesȱonȱtheȱstackȱandȱcallingȱaȱsubroutineȱnamedȱ ldiv.ȱȱIfȱthisȱmachineȱhadȱaȱ32Ȭbitȱ
divideȱinstruction,ȱtheȱdivisionȱmightȱhaveȱbeenȱdoneȱmoreȱefficiently.ȱ
ȱ
ȱ
ȱ
Bringing Back the Counter
ȱ
Letȇsȱtryȱanotherȱapproachȱ
ȱ
void
try3()
{
for( i = 0, p1 = x, p2 = y; i < SIZE; i++ )
*p1++ = *p2++;
}
ȱ
Iȇveȱ usedȱ theȱ counterȱ againȱ toȱ controlȱ whenȱ theȱ loopȱ shouldȱ exitȱ toȱ getȱ ridȱ ofȱ theȱ
pointerȱsubtractionȱandȱtheȱresultingȱlongȱsequenceȱofȱcode.ȱ
ȱ
0000009e
000000a4
000000ae
000000b8
42b90000
0000
23fc0000 0000 00000000
23fc0000
00000000
0000
6020
_try3:
clrl
movl
movl
_i
#_x,_p1
#_y,_p2
jra
L30
Download at http://www.pin5i.com/
8.1 One-Dimensional Arrays
000000ba
000000c0
000000c6
000000c8
000000ce
000000d4
000000da
000000dc
000000e2
20790000
22790000
2290
58b90000
58b90000
52b90000
7032
b0b90000
5ed6
0000
0000
L20005:
0000
0000
0000
L30:
0000
movl
movl
movl
addql
addql
addql
moveq
cmpl
jgt
207
_p2,a0
_p1,a1
a0@,a1@
#4,_p2
#4,_p1
#l,_i
#50,d0
_i,d0
L20005
ȱ
Thisȱversionȱhasȱtheȱshorterȱcodeȱtoȱcopyȱtheȱintegerȱandȱincrementȱtheȱpointers,ȱandȱ
toȱ controlȱ whenȱ theȱ loopȱ breaks.ȱ Butȱ weȇreȱ stillȱ copyingȱ theȱ pointerȱ variablesȱ intoȱ
addressȱregistersȱbeforeȱtheȱindirection.ȱ
ȱ
ȱ
ȱ
Register Pointer Variables
ȱ
Weȱ canȱ eliminateȱ copyingȱ theȱ pointerȱ valuesȱ byȱ usingȱ registerȱ variablesȱ forȱ theȱ
pointers.ȱHowever,ȱtheyȱmustȱbeȱdeclaredȱasȱlocalȱvariables.ȱ
ȱ
void
try4()
{
register int *p1, *p2;
register int i;
for( i = 0, p1 = x, p2 = y; i < SIZE; i++ )
*p1++ = *p2++;
}
ȱ
Thisȱchangeȱimprovesȱmoreȱthanȱjustȱeliminatingȱtheȱcopyingȱofȱtheȱpointers.ȱ
ȱ
000000f0
000000f2
000000f8
000000fe
00000100
00000102
00000104
00000106
00000108
7e00
2a7c0000
287c0000
6004
2adc
5287
7032
b087
6ef6
_try4:
0000
0000
L20007:
L35:
moveq
movl
movl
jra
movl
addql
moveq
cmpl
jgt
#0,d7
#,x,a5
#_y,a4
L35
a4@+,a5@+
#1,37
#50,dO
d7,d0
L200O7
ȱ
Noteȱthatȱtheȱpointerȱvariableȱexistȱinȱregistersȱa4ȱandȱa5ȱfromȱtheȱstart.ȱWeȱcanȱ
incrementȱthemȱdirectlyȱwithȱtheȱhardwareȇsȱautoincrementȱaddressingȱmodeȱ(whichȱ
Download at http://www.pin5i.com/
208ȱ
Chapter 8 Arrays
behavesȱ veryȱ muchȱ likeȱ theȱ Cȱ postfixȱ ++ȱ operator).ȱ Theȱ initializationȱ andȱ loopȱ
terminationȱcodeȱis,ȱforȱtheȱmostȱpart,ȱunchanged.ȱThisȱcodeȱisȱlookingȱbetter.ȱ
ȱ
ȱ
ȱ
Eliminating the Counter
ȱ
Ifȱweȱcanȱfindȱaȱwayȱtoȱterminateȱtheȱloopȱwithoutȱusingȱtheȱpointerȱsubtractionȱthatȱ
causedȱtroubleȱearlier,ȱweȱcanȱeliminateȱtheȱcounter.ȱ
ȱ
void
try5()
{
register int *p1, *p2;
for( p1 = x, p2 = y, p1 < &x[SIZE]; )
*p1++ = *p2++;
}
ȱ
Insteadȱofȱtheȱsubtractionȱtoȱseeȱnowȱmanyȱelementsȱweȇveȱcopied,ȱthisȱloopȱchecksȱtoȱ
seeȱwhetherȱtheȱpointerȱ p1ȱhasȱreachedȱtheȱendȱofȱtheȱsourceȱarray.ȱFunctionallyȱthisȱ
testȱisȱjustȱasȱgood,ȱbutȱitȱshouldȱbeȱmoreȱefficientȱbecauseȱitȱdoesȱnotȱdoȱaȱsubtraction.ȱ
Furthermore,ȱtheȱexpressionȱ &x[SIZE]ȱcanȱbeȱevaluatedȱatȱcompileȱtime,ȱbecauseȱ SIZEȱ
isȱaȱliteralȱconstant.ȱHereȱisȱtheȱresult.ȱ
ȱ
0000011c
00000122
00000128
0000012a
0000012c
00000132
2a7c0000
287c0000
6002
2adc
bbfc0000
65f6
0000
0000
00c8
_try5:
L20009:
L40;
movl
movl
jra
movl
cmpl
jcs
#_x,a5
#_y,a4
L40
a4@+,a5@+
#_x+200,a5
L20009
ȱ
Thisȱ codeȱ isȱ compactȱ andȱ fastȱ andȱ rivalsȱ whatȱ anȱ assemblyȱ languageȱ programmerȱ
wouldȱ haveȱ produced.ȱ Theȱ counterȱ andȱ itsȱ associatedȱ instructionsȱ areȱ gone.ȱ Theȱ
comparisonȱ instructionȱ containsȱ theȱ expressionȱ _x+200,ȱ whichȱ isȱ theȱ expressionȱ
&x[SIZE].ȱThisȱcomputationȱwasȱdoneȱatȱcompileȱtimeȱbecauseȱ SIZEȱisȱaȱconstant.ȱThisȱ
codeȱisȱaboutȱasȱtightȱasȱweȱcanȱgetȱonȱthisȱmachine.ȱ
ȱ
ȱ
ȱ
Conclusions
ȱ
Whatȱcanȱweȱlearnȱfromȱtheseȱexperiments?ȱ
1. Pointerȱ variablesȱ canȱ resultȱ inȱ moreȱ efficientȱ codeȱ thanȱ subscriptsȱ whenȱ youȱ areȱ
movingȱ throughȱ anȱ arrayȱ byȱ someȱ fixedȱ increment.ȱ Thisȱ pointȱ isȱ especiallyȱ true
Download at http://www.pin5i.com/
8.1 One-Dimensional Arrays
209
whenȱ ȱ theȱ incrementȱ isȱ oneȱ andȱ theȱ machineȱ hasȱ anȱ autoincrementȱ addressingȱ
mode.ȱ
2. Pointersȱ declaredȱ asȱ registerȱ variablesȱ areȱ oftenȱ moreȱ efficientȱ thanȱ pointersȱ inȱ
staticȱ memoryȱ orȱ onȱ theȱ stackȱ (theȱ amountȱ ofȱ improvementȱ dependsȱ onȱ theȱ
particularȱmachineȱyouȇreȱworkingȱwith).ȱ
3. Ifȱ youȱ canȱ checkȱ forȱ loopȱ terminationȱ byȱ testingȱ somethingȱ thatȱ isȱ alreadyȱ beingȱ
initializedȱandȱadjustedȱforȱtheȱloop,ȱthenȱyouȱdonȇtȱneedȱaȱseparateȱcounter.ȱ
4. Expressionsȱthatȱmustȱbeȱevaluatedȱatȱrunȱtimeȱareȱmoreȱexpensiveȱthanȱconstantȱ
expressionsȱsuchȱasȱ&array[SIZE]ȱor array + SIZE.ȱ
ȱ
TIP
Theȱ previousȱ examplesȱ mustȱ nowȱ beȱ putȱ intoȱ perspective.ȱ Isȱ itȱ worthȱ replacingȱ theȱ
firstȱloop,ȱwhichȱisȱeasilyȱunderstood,ȱwithȱtheȱlastȱone,ȱwhichȱoneȱreaderȱcalledȱȈotterȱ
gibberish,Ȉȱjustȱtoȱsaveȱaȱfewȱdozenȱmicrosecondsȱofȱexecutionȱtime?ȱOccasionallyȱyes,ȱ
butȱinȱmostȱcasesȱtheȱanswerȱisȱdefinitelyȱnot!ȱTheȱcostȱofȱgainingȱruntimeȱefficiencyȱinȱ
thisȱ wayȱ isȱ toȱ makeȱ theȱ programȱ moreȱ difficultȱ toȱ writeȱ inȱ theȱ firstȱ placeȱ andȱ moreȱ
difficultȱ toȱ maintainȱ later.ȱ Ifȱ theȱ programȱ doesnȇtȱ workȱ orȱ cannotȱ beȱ maintained,ȱ itsȱ
executionȱspeedȱisȱirrelevant.ȱ
ItȱisȱeasyȱtoȱargueȱthatȱexperiencedȱCȱprogrammersȱwillȱhaveȱlittleȱtroubleȱwithȱ
theȱ pointerȱ loop,ȱ butȱ thereȱ areȱ twoȱ fallaciesȱ toȱ thisȱ argument.ȱ First,ȱ Ȉlittleȱ troubleȈȱ
actuallyȱ meansȱ Ȉsomeȱ trouble.Ȉȱ Usingȱ complexȱ idiomsȱ naturallyȱ involvesȱ moreȱ riskȱ
thanȱusingȱsimpleȱones.ȱSecond,ȱtheȱmaintenanceȱprogrammersȱwhoȱworkȱonȱtheȱcodeȱ
laterȱmayȱnotȱbeȱasȱexperiencedȱasȱyouȱare.ȱProgramȱmaintenanceȱisȱtheȱmajorȱcostȱofȱaȱ
softwareȱ product,ȱ soȱ programmingȱ techniquesȱ thatȱ makeȱ maintenanceȱ moreȱ difficultȱ
mustȱbeȱusedȱwithȱcare.ȱ
Also,ȱ someȱ machinesȱ areȱ designedȱ withȱ specificȱ instructionsȱ toȱ performȱ arrayȱ
subscripting,ȱwithȱtheȱintentȱofȱmakingȱthisȱcommonȱoperationȱveryȱfast.ȱAȱcompilerȱ
forȱ suchȱ aȱ machineȱ willȱ implementȱ subscriptȱ expressionsȱ withȱ theseȱ specializedȱ
instructionsȱ butȱ mayȱ notȱ useȱ themȱ toȱ implementȱ pointerȱ expressions,ȱ evenȱ thoughȱ itȱ
should.ȱ Onȱ suchȱ aȱ machine,ȱ then,ȱ aȱ subscriptȱ mayȱ indeedȱ beȱ moreȱ efficientȱ thanȱ aȱ
pointer.ȱ
Thenȱwhatȱisȱtheȱpointȱofȱtheseȱexperimentsȱwithȱefficiency?ȱYouȱmayȱhaveȱtoȱ
readȱsomeȱȇȈgibberishȈȱthatȱsomeoneȱelseȱwrote,ȱsoȱitȱisȱimportantȱthatȱyouȱunderstandȱ
it.ȱ Butȱ thereȱ areȱ alsoȱ aȱ fewȱ placesȱ whereȱ peakȱ efficiencyȱ isȱ vital,ȱ suchȱ asȱ realȬtimeȱ
programsȱthatȱmustȱrespondȱquicklyȱtoȱeventsȱasȱtheyȱoccur.ȱButȱanyȱprogramȱthatȱisȱ
tooȱslowȱcanȱbenefitȱfromȱtheseȱtechniques.ȱTheȱkeyȱisȱtoȱidentifyȱtheȱsectionsȱofȱcodeȱ
thatȱ areȱ takingȱ theȱ mostȱ timeȱ andȱ concentrateȱ yourȱ energiesȱ onȱ improvingȱ them,ȱ forȱ
thatȱ isȱ howȱ youȱ achieveȱ theȱ biggestȱ gainsȱ forȱ yourȱ effort.ȱ Techniquesȱ forȱ identifyingȱ
theseȱsectionsȱofȱcodeȱareȱdiscussedȱinȱChapterȱ18.ȱ
Download at http://www.pin5i.com/
Chapter 8 Arrays
210ȱ
8.1.5 Arrays and Pointers
ȱ
Pointersȱ andȱ arraysȱ areȱ notȱ equivalent.ȱ Toȱ illustrateȱ thisȱ idea,ȱ considerȱ theseȱ
declarations:ȱ
ȱ
ȱ
ȱ
int
a[5];
int
*b;
ȱ
Canȱ aȱ andȱ bȱ beȱ usedȱ interchangeably?ȱ Bothȱ haveȱ pointerȱ values,ȱ andȱ youȱ canȱ useȱ
indirectionȱandȱsubscriptsȱonȱeitherȱone.ȱTheyȱare,ȱnevertheless,ȱquiteȱdifferent.ȱ
Declaringȱ anȱ arrayȱ setsȱ asideȱ spaceȱ inȱ memoryȱ forȱ theȱ indicatedȱ numberȱ ofȱ
elements,ȱandȱthenȱcreatesȱtheȱarrayȱnameȱwhoseȱvalueȱisȱaȱconstantȱthatȱpointsȱtoȱtheȱ
beginningȱ ofȱ thisȱ space.ȱ Declaringȱ aȱ pointerȱ variableȱ reservesȱ spaceȱ forȱ theȱ pointerȱ
itself,ȱbutȱthatȱisȱall.ȱSpaceȱisȱnotȱallocatedȱforȱanyȱintegers.ȱFurthermore,ȱtheȱpointerȱ
variableȱisȱnotȱinitializedȱtoȱpointȱtoȱanyȱexistingȱspace.ȱȱIfȱitȱisȱanȱautomaticȱvariableȱitȱ
isȱnotȱinitializedȱatȱall.ȱȱTheseȱtwoȱdeclarationsȱlookȱveryȱdifferentȱwhenȱdiagrammed.ȱ
ȱ
aȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
bȱ
ȱ
ȱ
Thus,ȱ afterȱ theȱ declarationsȱ theȱ expressionȱ *aȱ isȱ perfectlyȱ legal,ȱ butȱ theȱ
expressionȱ *bȱ isȱ not.ȱ *bȱ willȱ accessȱ someȱ indeterminateȱ locationȱ inȱ memoryȱ orȱ causeȱ
theȱprogramȱtoȱterminate.ȱOnȱtheȱotherȱhand,ȱtheȱexpressionȱ b++ȱwillȱcompile,ȱbutȱ a++ȱ
willȱnotȱbecauseȱtheȱvalueȱofȱaȱisȱaȱconstant.ȱ
Itȱ isȱ importantȱ thatȱ youȱ understandȱ thisȱ distinctionȱ clearly,ȱ becauseȱ theȱ nextȱ
topicȱmayȱmuddyȱtheȱwaters.ȱ
ȱ
ȱ
ȱ
8.1.6 Array Names as Function Arguments
ȱ
Whatȱhappensȱwhenȱanȱarrayȱnameȱisȱpassedȱasȱanȱargumentȱtoȱaȱfunction?ȱYouȱnowȱ
knowȱthatȱtheȱvalueȱofȱanȱarrayȱnameȱisȱaȱpointerȱtoȱtheȱfirstȱelementȱofȱtheȱarray,ȱsoȱitȱ
makesȱ senseȱ thatȱ aȱ copyȱ ofȱ thisȱ pointerȱ valueȱ isȱ passedȱ toȱ theȱ function.ȱ Aȱ subscriptȱ
usedȱ inȱ theȱ functionȱ willȱ performȱ indirectionȱ onȱ thisȱ pointer,ȱ andȱ itȱ isȱ throughȱ thisȱ
indirectionȱthatȱtheȱfunctionȱcanȱaccessȱorȱmodifyȱtheȱelementsȱofȱtheȱcallingȱprogramȇsȱ
array.ȱ
Nowȱ Iȱ canȱ explainȱ theȱ apparentȱ contradictionȱ aboutȱ argumentȱ passingȱ inȱ C.ȱ Iȱ
statedȱ earlierȱ thatȱ allȱ argumentsȱ toȱ functionsȱ areȱ passedȱ byȱ valueȱ butȱ thatȱ arrays
Download at http://www.pin5i.com/
8.1 One-Dimensional Arrays
211
behaveȱasȱthoughȱtheyȱwereȱpassedȱbyȱreference.ȱCallȱbyȱreferenceȱisȱimplementedȱbyȱ
passingȱaȱpointerȱtoȱtheȱdesiredȱargumentȱandȱthenȱusingȱindirectionȱinȱtheȱfunctionȱtoȱ
accessȱ theȱ dataȱ throughȱ theȱ pointer.ȱ Theȱ arrayȱ nameȱ isȱ aȱ pointer,ȱ andȱ subscriptsȱ
performȱindirection.ȱ
Soȱ whereȱ isȱ theȱ callȬbyȬvalueȱ behaviorȱ withȱ arrays?ȱ Theȱ functionȱ isȱ passedȱ aȱ
copyȱ ofȱ theȱ argumentȱ (aȱ copyȱ ofȱ theȱ pointerȱ toȱ theȱ beginningȱ ofȱ theȱ array)ȱ soȱ theȱ
functionȱ isȱ freeȱ toȱ manipulateȱ itsȱ pointerȱ parameterȱ withoutȱ fearȱ ofȱ modifyingȱ theȱ
correspondingȱargumentȇsȱvalue.ȱ
Soȱ thereȱ isȱ noȱ contradictionȱ afterȱ all:ȱ allȱ argumentsȱ areȱ passedȱ byȱ value.ȱ Ofȱ
course,ȱwhenȱyouȱpassȱaȱpointerȱtoȱaȱvariableȱandȱtheȱfunctionȱusesȱindirectionȱonȱtheȱ
pointer,ȱ theȱ functionȱ canȱ modifyȱ theȱ variable.ȱ Thoughȱ itȱ wasȱ notȱ obviousȱ atȱ firstȱ
glance,ȱ thisȱ processȱ occursȱ withȱ arrayȱ nameȱ arguments.ȱ Theȱ argument,ȱ aȱ pointer,ȱ isȱ
actuallyȱ passedȱ byȱ value,ȱ andȱ theȱ functionȱ getsȱ aȱ copyȱ ofȱ theȱ pointer,ȱ whichȱ canȱ beȱ
modifiedȱwithoutȱfearȱofȱchangingȱtheȱcallerȇsȱargument.ȱ
Programȱ8.1ȱisȱaȱsimpleȱfunctionȱthatȱillustratesȱtheseȱpoints.ȱItȱcopiesȱtheȱstringȱ
containedȱ inȱ theȱ secondȱ argumentȱ toȱ theȱ bufferȱ toȱ whichȱ theȱ firstȱ argumentȱ points.ȱȱ
Theȱ callerȇsȱ bufferȱ isȱ modifiedȱ becauseȱ ofȱ theȱ indirection,ȱ yetȱ theȱ argumentsȱ (theȱ
pointers)ȱareȱmodifiedȱwithoutȱchangingȱtheȱcallerȇsȱpointerȱarguments.ȱ
Noteȱtheȱexpressionȱ*string++ȱinȱtheȱwhileȱstatement.ȱItȱfetchesȱtheȱcharacterȱtoȱ
whichȱ stringȱ pointsȱ and,ȱ asȱ aȱ sideȱ effect,ȱ modifiesȱ stringȱ toȱ pointȱ toȱ theȱ nextȱ
character.ȱ Changingȱ theȱ parameterȱ inȱ thisȱ wayȱ doesȱ notȱ affectȱ theȱ argumentȱ inȱ theȱ
callingȱprogram,ȱbecauseȱonlyȱtheȱfunctionȇsȱcopyȱisȱchanged.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Copy the string contained in the second argument to the
** buffer specified by the first argument.
*/
void
strcpy( char *buffer, char const *string )
{
/*
** Copy characters until a NUL byte is copied.
*/
while( (*buffer++ = *string++) != '\0' )
;
}
ȱ
Programȱ8.1ȱȱStringȱcopyȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱstrcpy.cȱ
Download at http://www.pin5i.com/
212ȱ
TIP
TIP
Chapter 8 Arrays
Thereȱ areȱ twoȱ otherȱ pointsȱ aboutȱ thisȱ functionȱ thatȱ areȱ worthȱ mentioningȱ (orȱ
reiterating).ȱ First,ȱ theȱ parameterȱ isȱ declaredȱ asȱ aȱ pointerȱ toȱ constȱ characters.ȱ Whyȱ isȱ
thisȱdeclarationȱimportantȱforȱaȱfunctionȱthatȱisȱnotȱgoingȱtoȱmodifyȱtheȱcharactersȱinȱ
theȱ firstȱ place?ȱ Thereȱ areȱ atȱ leastȱ threeȱ reasons.ȱ First,ȱ itȱ isȱ goodȱ documentation.ȱ
Someoneȱwishingȱtoȱuseȱthisȱfunctionȱcanȱseeȱfromȱtheȱprototypeȱthatȱtheȱdataȱwillȱnotȱ
beȱ changed,ȱ withoutȱ readingȱ theȱ codeȱ (whichȱ mightȱ notȱ beȱ available).ȱ Second,ȱ theȱ
compilerȱ willȱ beȱ ableȱ toȱ catchȱ anyȱ programmingȱ errorȱ thatȱ causesȱ accidentalȱ
modification.ȱ Lastly,ȱ theȱ declarationȱ allowsȱ constȱ argumentsȱ toȱ beȱ passedȱ toȱ theȱ
function.ȱ
ȱ
Theȱ secondȱ pointȱ toȱ beȱ madeȱ aboutȱ thisȱ functionȱ isȱ theȱ declarationȱ ofȱ theȱ argumentȱ
andȱ theȱ localȱ variableȱ asȱ registerȱ variables.ȱ Onȱ manyȱ machinesȱ registerȱ variablesȱ
willȱ resultȱ inȱ codeȱ thatȱ executesȱ fasterȱ thanȱ ifȱ theyȱ wereȱ inȱ staticȱ memoryȱ orȱ onȱ theȱ
stack,ȱ asȱ illustratedȱ earlierȱ withȱ theȱ arrayȱ copyȱ functions.ȱ Runtimeȱ efficiencyȱ isȱ
especiallyȱimportantȱwithȱaȱfunctionȱsuchȱasȱthisȱone,ȱwhichȱisȱlikelyȱtoȱbeȱcalledȱquiteȱ
oftenȱbecauseȱitȱperformsȱsuchȱaȱusefulȱtask.ȱ
However,ȱ itȱ dependsȱ onȱ yourȱ environmentȱ whetherȱ usingȱ registerȱ variablesȱ
willȱresultȱinȱanȱimprovement.ȱManyȱcurrentȱcompilersȱcanȱdoȱaȱbetterȱjobȱofȱregisterȱ
allocationȱ thanȱ theȱ programmer.ȱ ȱ Withȱ suchȱ aȱ compiler,ȱ usingȱ registerȱ declarationsȱ
canȱactuallyȱcauseȱaȱdecreaseȱinȱefficiency.ȱCheckȱtheȱdocumentationȱthatȱcomesȱwithȱ
yourȱcompilerȱtoȱseeȱifȱitȱperformsȱitsȱownȱregisterȱallocation.ȱ
ȱ
ȱ
ȱ
8.1.7 Declaring Array Parameters
ȱ
Hereȱ isȱ anȱ interestingȱ question.ȱ Whatȱ isȱ theȱ correctȱ wayȱ toȱ declareȱ aȱ functionȱ
parameterȱifȱyouȱintendȱtoȱpassȱitȱanȱarrayȱnameȱargument?ȱIsȱitȱdeclaredȱasȱaȱpointer,ȱ
orȱasȱanȱarray?ȱ
Asȱ youȱ haveȱ seen,ȱ aȱ pointerȱ isȱ actuallyȱ passed,ȱ soȱ theȱ functionȱ parameterȱ isȱ
reallyȱ aȱ pointer.ȱ Butȱ toȱ makeȱ thingsȱ aȱ littleȱ easierȱ forȱ theȱ noviceȱ programmer,ȱ theȱ
compilerȱ willȱ alsoȱ acceptȱ anȱ arrayȱ declarationȱ forȱ aȱ functionȱ parameter.ȱ Thus,ȱ theȱ
followingȱfunctionȱprototypesȱareȱequivalent:ȱ
ȱ
int
int
strlen( char *string );
strlen( char string[] );
ȱ
Thisȱ equivalenceȱ impliesȱ thatȱ aȱ pointerȱ andȱ anȱ arrayȱ nameȱ areȱ reallyȱ identicalȱ
afterȱallȱbutȱdonȇtȱbeȱfooled—theseȱtwoȱdeclarationsȱareȱequivalentȱinȱthisȱcontextȱonly!ȱ
Everywhereȱ elseȱ theyȱ areȱ quiteȱ different,ȱ asȱ discussedȱ earlier.ȱ Butȱ forȱ arrayȱ
parameters,ȱyouȱmayȱuseȱeitherȱdeclaration.ȱ
Download at http://www.pin5i.com/
8.1 One-Dimensional Arrays
213
Youȱ canȱ useȱ eitherȱ declaration,ȱ butȱ whichȱ isȱ Ȉmoreȱ correct?Ȉȱ Theȱ pointer.ȱ Theȱ
argumentȱ isȱ reallyȱ aȱ pointer,ȱ notȱ theȱ array.ȱ Also,ȱ theȱ expressionȱ sizeof stringȱ willȱ
produceȱtheȱsizeȱofȱaȱpointerȱtoȱaȱcharacter,ȱnotȱtheȱsizeȱofȱtheȱarray.ȱ
Itȱ shouldȱ nowȱ beȱ clearȱ whyȱ aȱ parameterȱ forȱ aȱ oneȬdimensionalȱ arrayȱ inȱ aȱ
functionȱ prototypeȱ doesȱ notȱ needȱ aȱ dimension—spaceȱ isȱ notȱ beingȱ allocatedȱ forȱ theȱ
arrayȱinȱtheȱfunction;ȱtheȱparameterȱisȱsimplyȱaȱpointerȱtoȱspaceȱthatȱwasȱ previouslyȱ
allocatedȱ elsewhere.ȱ Thisȱ factȱ explainsȱ whyȱ anȱ arrayȱ parameterȱ isȱ compatibleȱ withȱ
arraysȱ ofȱ anyȱ size—allȱ thatȱ isȱ passedȱ isȱ aȱ pointerȱ toȱ theȱ firstȱ element.ȱ Onȱ theȱ otherȱ
hand,ȱthisȱimplementationȱmakesȱitȱimpossibleȱforȱtheȱfunctionȱtoȱdetermineȱtheȱsizeȱ
ofȱtheȱarray.ȱȱIfȱtheȱarrayȱsizeȱisȱneededȱinȱtheȱfunction,ȱitȱmustȱbeȱpassedȱasȱanȱexplicitȱ
argument.ȱ
ȱ
ȱ
ȱ
8.1.8 Initialization
ȱ
Justȱ asȱ scalarȱ variablesȱ canȱ beȱ initializedȱ inȱ theirȱ declarations,ȱ soȱ tooȱ canȱ arrays.ȱ Theȱ
onlyȱ differenceȱ isȱ thatȱ aȱ seriesȱ ofȱ valuesȱ isȱ neededȱ toȱ initializeȱ anȱ array.ȱ Aȱ seriesȱ isȱ
easilyȱspecified:ȱtheȱvaluesȱareȱwrittenȱasȱaȱcommaȬseparatedȱlistȱenclosedȱinȱbraces,ȱasȱ
inȱthisȱexample:ȱ
ȱ
int
vector[5] = ( 10, 20, 30, 40, 50 );
ȱ
Theȱvaluesȱgivenȱinȱtheȱinitializerȱlistȱareȱassignedȱtoȱtheȱelementsȱofȱtheȱarrayȱoneȱbyȱ
one,ȱsoȱvector[0]ȱgetsȱtheȱvalueȱ10,ȱvector[1]ȱgetsȱtheȱvalueȱ20,ȱandȱsoȱforth.ȱ
ȱ
ȱ
ȱ
Static and Automatic Initialization
ȱ
Theȱ wayȱ arrayȱ initializationȱ takesȱ placeȱ isȱ analogousȱ toȱ theȱ wayȱ scalarsȱ areȱ
initialized—itȱ dependsȱ uponȱ theirȱ storageȱ class.ȱ Arraysȱ storedȱ inȱ staticȱ memoryȱ areȱ
initializedȱonce,ȱbeforeȱtheȱprogramȱbeginsȱtoȱexecute.ȱNoȱinstructionsȱareȱexecutedȱtoȱ
putȱ theȱ valuesȱ inȱ theȱ properȱ places,ȱ theyȱ justȱ startȱ outȱ there.ȱ Thisȱ magicȱ isȱ
accomplishedȱbyȱhavingȱtheȱlinkerȱinitializeȱtheȱarrayȱelementsȱtoȱtheirȱproperȱvaluesȱ
inȱtheȱfileȱcontainingȱtheȱexecutableȱprogram.ȱIfȱtheȱarrayȱwasȱnotȱinitialized,ȱtheȱinitialȱ
valuesȱwillȱbeȱzero.ȱWhenȱthisȱfileȱisȱloadedȱintoȱmemoryȱforȱexecution,ȱtheȱinitializedȱ
arrayȱ valuesȱ areȱ loadedȱ inȱ exactlyȱ theȱ sameȱ wayȱ asȱ theȱ programȱ instructions.ȱ Thusȱ
whenȱexecutionȱbegins,ȱstaticȱarraysȱareȱalreadyȱinitialized.ȱ
Theȱ situationȱ isȱ notȱ asȱ rosyȱ withȱ automaticȱ variables,ȱ however.ȱ Becauseȱ theyȱ
resideȱonȱtheȱruntimeȱstack,ȱautomaticȱvariablesȱmayȱuseȱdifferentȱmemoryȱlocationsȱ
eachȱtimeȱtheȱblockȱinȱwhichȱtheyȱareȱdeclaredȱisȱentered.ȱȱThereȱisnȇtȱanyȱwayȱthatȱtheȱ
Download at http://www.pin5i.com/
Chapter 8 Arrays
214ȱ
compilerȱ canȱ initializeȱ theseȱ locationsȱ beforeȱ theȱ programȱ begins,ȱ soȱ automaticȱ
variablesȱ areȱ uninitializedȱ byȱ default.ȱ Ifȱ initialȱ valuesȱ areȱ given,ȱ theȱ variablesȱ areȱ
initializedȱwithȱimplicitȱassignmentȱstatementsȱeachȱtimeȱexecutionȱentersȱtheȱscopeȱinȱ
whichȱtheyȱwereȱdeclared.ȱTheȱimplicitȱassignmentȱstatementȱtakeȱupȱspaceȱandȱtakeȱ
timeȱ toȱ executeȬjustȱ asȱ ordinaryȱ assignmentsȱ would.ȱ Theȱ problemȱ forȱ arraysȱ isȱ thatȱ
thereȱmayȱbeȱmanyȱvaluesȱinȱtheȱinitializerȱlist,ȱresultingȱinȱjustȱasȱmanyȱassignments.ȱ
Forȱveryȱlargeȱarrays,ȱtheȱinitializationȱcouldȱtakeȱconsiderableȱtime.ȱ
Hereȱisȱtheȱtradeoff,ȱthen.ȱWhenȱinitializingȱanȱarrayȱthatȱisȱlocalȱtoȱaȱfunctionȱ
(orȱ aȱ block),ȱ thinkȱ carefullyȱ aboutȱ whetherȱ itȱ shouldȱ beȱ reinitializedȱ eachȱ timeȱ theȱ
functionȱ(orȱblock)ȱisȱentered.ȱIfȱtheȱanswerȱisȱno,ȱthenȱdeclareȱtheȱarrayȱstaticȱsoȱthatȱ
theȱinitializationȱcanȱbeȱperformedȱonceȱbeforeȱtheȱprogramȱbegins.ȱ
ȱ
ȱ
ȱ
8.1.9 Incomplete Initialization
ȱ
Whatȱhappensȱwithȱtheseȱtwoȱdeclarations?ȱ
ȱ
int
int
vector[5] = { 1, 2, 3, 4, 5, 6 };
vector[5] = { 1, 2, 3, 4 };
ȱ
Inȱbothȱcases,ȱtheȱnumberȱofȱinitializersȱdoesȱnotȱmatchȱtheȱsizeȱofȱtheȱarray.ȱTheȱfirstȱ
declarationȱ isȱ anȱ error;ȱ thereȱ isȱ noȱ wayȱ toȱ packȱ sixȱ integerȱ valuesȱ intoȱ fiveȱ integerȱ
variables.ȱTheȱsecond,ȱhowever,ȱisȱlegal.ȱȱItȱprovidesȱvaluesȱforȱtheȱfirstȱfourȱelementsȱ
ofȱtheȱarray;ȱtheȱlastȱelementȱisȱinitializedȱtoȱzero.ȱ
ȱ
Canȱtheȱmiddleȱvaluesȱbeȱomittedȱfromȱtheȱlistȱasȱwell?ȱ
ȱ
int
vector[5] = { 1, 5 };
ȱ
Theȱcompilerȱcanȱonlyȱtellȱthatȱthereȱareȱnotȱenoughȱinitializers,ȱbutȱitȱhasȱnoȱwayȱtoȱ
figureȱoutȱwhichȱonesȱareȱmissing.ȱȱTherefore,ȱonlyȱtrailingȱinitializersȱcanȱbeȱomitted.ȱ
ȱ
ȱ
ȱ
8.1.10
Automatic Array Sizing
ȱ
Hereȱisȱanȱexampleȱofȱanotherȱusefulȱtechnique.ȱ
int
vector[] = { 1, 2, 3, 4, 5 };
ȱ
Ifȱtheȱarrayȱsizeȱisȱmissing,ȱtheȱcompilerȱmakesȱtheȱarrayȱjustȱbigȱenoughȱtoȱholdȱtheȱ
initializersȱthatȱwereȱgiven.ȱThisȱtechniqueȱisȱparticularlyȱhelpfulȱifȱtheȱinitializerȱlistȱisȱ
frequentlyȱmodified.ȱ
Download at http://www.pin5i.com/
8.2 Multidimensional Arrays
8.1.11
215
Character Array Initialization
ȱ
Fromȱ whatȱ weȱ haveȱ saidȱ soȱ far,ȱ youȱ mightȱ thinkȱ thatȱ characterȱ arraysȱ areȱ initializedȱ
likeȱthis:ȱ
ȱ
ȱ
char
message[] = { 'H', 'e', 'l', 'l', 'o', 0 };
ȱ
Theȱ codeȱ works,ȱ butȱ itȱ isȱ cumbersomeȱ forȱ allȱ butȱ theȱ shortestȱ strings.ȱ Therefore,ȱ theȱ
languageȱStandardȱprovidesȱaȱshorthandȱnotationȱforȱinitializingȱcharacterȱarrays:ȱ
ȱ
ȱ
char
message[] = "Hello";
ȱ
Althoughȱthisȱlooksȱlikeȱaȱstringȱliteral,ȱitȱisȱnot.ȱItȱisȱsimplyȱanȱalternateȱwayȱofȱwritingȱ
theȱinitializerȱlistȱinȱtheȱpreviousȱexample.ȱȱ
Howȱ canȱ youȱ tellȱ theȱ differenceȱ betweenȱ stringȱ literalsȱ andȱ theseȱ shorthandȱ
initializerȱlistsȱifȱtheyȱlookȱexactlyȱtheȱsame?ȱTheyȱareȱdistinguishedȱfromȱoneȱanotherȱ
byȱ theȱ contextȱ inȱ whichȱ theyȇreȱ used.ȱ Whenȱ initializingȱ aȱ characterȱ array,ȱ itȱ isȱ anȱ
initializerȱlist.ȱEverywhereȱelseȱitȱisȱaȱstringȱliteral.ȱ
Hereȱisȱanȱexample:ȱ
ȱ
char
char
message1[] = "Hello";
*message2 = "Hello";
ȱ
Theȱ initializersȱ lookȱ alike,ȱ butȱ theyȱ haveȱ differentȱ meanings.ȱ Theȱ firstȱ initializesȱ theȱ
elementsȱ ofȱ aȱ characterȱ array,ȱ butȱ theȱ secondȱ isȱ aȱ trueȱ siringȱ literal.ȱ Theȱ pointerȱ
variableȱisȱinitializedȱtoȱpointȱtoȱwhereverȱtheȱliteralȱisȱstored,ȱasȱillustratedȱbelow:ȱ
ȱ
message1ȱ
ȱ
ȇHȇȱ ȇeȇȱ ȇlȇȱ ȇlȇȱ ȇoȇ 0ȱ ȱ
message2 ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇHȇȱ ȇeȇȱ ȇlȇȱ ȇlȇȱ ȇoȇ 0ȱ
ȱ
ȱ
ȱ
8.2 Multidimensional Arrays
ȱ
Anȱarrayȱisȱcalledȱmultidimensionalȱifȱitȱhasȱmoreȱthanȱoneȱdimension.ȱForȱexample,ȱtheȱ
declarationȱ
ȱ
ȱ
int
matrix[6][10];
ȱ
createsȱ aȱ matrixȱ containingȱ 60ȱ elements.ȱ However,ȱ isȱ thisȱ sixȱ rowsȱ ofȱ tenȱ elementsȱ
each,ȱorȱtenȱrowsȱofȱsixȱelementsȱeach?ȱ
Toȱ answerȱ thisȱ question,ȱ youȱ needȱ toȱ lookȱ atȱ multidimensionalȱ arraysȱ fromȱ aȱ
differentȱviewpoint.ȱConsiderȱthisȱprogressionȱofȱdeclarations:ȱ
Download at http://www.pin5i.com/
216ȱ
Chapter 8 Arrays
int
int
int
int
a;
b[10];
c[6][10];
d[3][6][10];
ȱ
aȱ isȱ aȱ singleȱ integer.ȱ Byȱ addingȱ theȱ dimensionȱ toȱ theȱ nextȱ declaration,ȱ bȱ isȱ aȱ vectorȱ
containingȱtenȱintegerȱelements.ȱ
Butȱallȱthatȱhasȱbeenȱdoneȱforȱ cȱisȱtoȱaddȱanotherȱdimension,ȱsoȱweȱcanȱviewȱ cȱ
asȱaȱvectorȱcontainingȱsixȱelements,ȱexceptȱthatȱeachȱofȱthoseȱelementsȱhappensȱtoȱbeȱaȱ
vectorȱofȱtenȱintegers.ȱInȱotherȱwords,ȱcȱisȱaȱoneȬdimensionalȱarrayȱofȱoneȬdimensionalȱ
arrays.ȱȱTheȱsameȱcanȱbeȱsaidȱofȱ d:ȱitȱisȱanȱarrayȱofȱthreeȱelements,ȱeachȱofȱwhichȱisȱaȱ
matrix.ȱWait,ȱȈmatrixȈȱisȱtheȱwrongȱviewpoint.ȱ dȱisȱanȱarrayȱofȱthreeȱelements,ȱeachȱofȱ
whichȱisȱanȱarrayȱofȱsixȱelements,ȱandȱeachȱofȱthoseȱisȱanȱarrayȱofȱtenȱintegers.ȱMoreȱ
concisely,ȱdȱisȱanȱarrayȱofȱthreeȱarraysȱofȱsixȱarraysȱofȱtenȱintegersȱeach.ȱ
Itȱisȱimportantȱthatȱyouȱunderstandȱthisȱviewpoint,ȱbecauseȱitȱisȱtheȱbasisȱforȱCsȱ
implementationȱofȱmultidimensionalȱarrays.ȱToȱreinforceȱthisȱidea,ȱletȇsȱtalkȱaboutȱtheȱ
orderȱinȱwhichȱarrayȱelementsȱareȱstoredȱinȱmemory.ȱ
ȱ
ȱ
ȱ
8.2.1 Storage Order
ȱ
Considerȱthisȱarray:ȱ
ȱ
int
array[3];
ȱ
Itȱcontainsȱthreeȱelements,ȱasȱshownȱinȱthisȱdiagram.ȱ
ȱ
ȱ
ȱ
arrayȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ
Butȱ nowȱ supposeȱ youȱ areȱ toldȱ thatȱ eachȱ ofȱ theseȱ elementsȱ isȱ inȱ factȱ anȱ arrayȱ ofȱ sixȱ
elements?ȱHereȱisȱtheȱnewȱdeclaration:ȱ
ȱ
ȱ
int
array[3][6];
ȱ
andȱhereȱisȱhowȱitȱlooks:ȱ
ȱ
ȱ
arrayȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Theȱ solidȱ boxesȱ showȱ theȱ threeȱ elementsȱ ofȱ theȱ firstȱ dimension,ȱ andȱ theȱ dottedȱ
divisionsȱ showȱ theȱ sixȱ elementsȱ ofȱ theȱ secondȱ dimension.ȱ Theȱ subscriptsȱ ofȱ theȱ
elementsȱabove,ȱfromȱleftȱtoȱright,ȱare:ȱ
Download at http://www.pin5i.com/
8.2 Multidimensional Arrays
217
ȱ
0,0
1,3
0,1
1,4
0,2
1,5
0,3
2,0
0,4
2,1
0,5
2,2
1,0
2,3
1,1
2,4
1,2
2,5
ȱ
Thisȱ exampleȱ illustratesȱ whatȱ isȱ calledȱ theȱ storageȱ orderȱ ofȱ arrayȱ elements.ȱ Inȱ C,ȱ
elementsȱ ofȱ aȱ multidimensionalȱ arrayȱ areȱ storedȱ inȱ theȱ orderȱ givenȱ byȱ varyingȱ theirȱ
rightmostȱ subscriptȱ mostȱ rapidly,ȱ calledȱ rowȱ majorȱ order.ȱ Knowingȱ theȱ storageȱ orderȱ
helpsȱyouȱanswerȱsomeȱusefulȱquestions,ȱforȱexample,ȱtheȱorderȱinȱwhichȱtoȱwriteȱtheȱ
valuesȱinȱanȱinitializerȱlist.ȱWhatȱvaluesȱdoesȱtheȱfollowingȱcodeȱprint?ȱ
ȱ
int
matrix[6][10];
int
*mp;
...
mp = &matrix[3][8];
printf( "First value is %d\n", *mp );
printf( "Second value is %d\n", *++mp );
printf( "Third value is %d\n", *++mp );
ȱ
Itȱisȱobviousȱthatȱtheȱfirstȱvalueȱprintedȱwillȱheȱtheȱcontentsȱofȱmatrix[3][8],ȱbutȱwhatȱ
isȱprintedȱnext?ȱTheȱstorageȱorderȱdeterminesȱtheȱanswer—theȱnextȱelementȱisȱtheȱoneȱ
whoseȱ rightmostȱ subscriptȱ hasȱ changed,ȱ namelyȱ matrix[3][9].ȱ Whatȱ aboutȱ theȱ nextȱ
one?ȱ Columnȱ nineȱ isȱ theȱ lastȱ columnȱ inȱ theȱ row.ȱ Becauseȱ theȱ rowsȱ ofȱ theȱ matrixȱ areȱ
storedȱoneȱafterȱanother,ȱtheȱnextȱelementȱprintedȱwillȱbeȱmatrix[4][0]. 35
ȱ
Hereȱisȱaȱrelatedȱquestion.ȱȱDoesȱmatrixȱhaveȱthreeȱrowsȱofȱtenȱcolumnsȱeach,ȱorȱ
tenȱ rowsȱ ofȱ threeȱ columnsȱ each?ȱ Theȱ answerȱ mayȱ surpriseȱ you—inȱ someȱ contexts,ȱ itȱ
couldȱbeȱeitherȱway.ȱ
ȱ
Eitherȱway?ȱHowȱcouldȱitȱbeȱtwoȱdifferentȱthings?ȱEasy.ȱȱIfȱyouȱuseȱsubscriptsȱ
toȱputȱdataȱintoȱtheȱarrayȱandȱyouȱlaterȱuseȱsubscriptsȱtoȱlookȱupȱvaluesȱinȱtheȱarray,ȱ
thenȱ itȱ makesȱ noȱ differenceȱ whetherȱ youȱ interpretȱ theȱ firstȱ subscriptȱ asȱ theȱ rowȱ
numberȱorȱtheȱcolumnȱnumber.ȱAsȱlongȱasȱyouȱdoȱitȱtheȱsameȱwayȱeachȱtime,ȱitȱwillȱworkȱ
withȱeitherȱinterpretation.ȱ
However,ȱinterpretingȱtheȱfirstȱsubscriptȱasȱaȱrowȱorȱasȱaȱcolumnȱcannotȱchangeȱ
theȱstorageȱorderȱofȱtheȱarray.ȱIfȱyouȱuseȱtheȱfirstȱsubscriptȱasȱtheȱrowȱnumberȱandȱtheȱ
secondȱasȱtheȱcolumnȱnumber,ȱthenȱaccessingȱtheȱelementsȱoneȱafterȱanotherȱinȱtheirȱ
storageȱ orderȱ willȱ giveȱ youȱ theȱ dataȱ rowȱ byȱ row.ȱ ȱ Onȱ theȱ otherȱ hand,ȱ ifȱ youȱ useȱ theȱ
firstȱsubscriptȱasȱtheȱcolumnȱnumber,ȱthenȱtheȱsameȱkindȱofȱaccessȱwillȱgiveȱyouȱyourȱ
dataȱinȱorderȱcolumnȱbyȱcolumn.ȱYouȱcanȱchooseȱwhicheverȱinterpretationȱmakesȱtheȱ
ȱThisȱexampleȱusedȱaȱpointerȱtoȱanȱintegerȱtoȱtraverseȱtheȱmemoryȱlocationsȱusedȱtoȱholdȱaȱtwoȬdimensionalȱarrayȱofȱ
integers.ȱCalledȱȱflatteningȱtheȱarray,ȱthisȱtechniqueȱisȱactuallyȱillegal,ȱbecauseȱmovingȱfromȱoneȱrowȱtoȱtheȱnextȱinvolvesȱ
leavingȱtheȱsubȬarrayȱthatȱcontainsȱtheȱfirstȱrow.ȱThoughȱitȱusuallyȱworks,ȱitȱshouldȱbeȱavoidedȱifȱpossible.ȱ
ȱ
35
Download at http://www.pin5i.com/
218ȱ
Chapter 8 Arrays
mostȱ senseȱ forȱ yourȱ application.ȱ Youȱ cannot,ȱ however,ȱ changeȱ theȱ wayȱ theȱ elementsȱ
areȱactuallyȱstoredȱinȱmemory.ȱThatȱorderȱisȱdefinedȱbyȱtheȱStandard.ȱ
ȱ
ȱ
ȱ
8.2.2 Array Names
ȱ
Theȱ valueȱ ofȱ theȱ nameȱ ofȱ aȱ oneȬdimensionalȱ arrayȱ isȱ aȱ pointerȱ constant,ȱ itsȱ typeȱ isȱ
ȈpointerȱtoȱelementȬtypeȈȱandȱitȱpointsȱtoȱtheȱfirstȱelementȱofȱtheȱarray.ȱȱ
Multidimensionalȱarraysȱareȱalmostȱasȱeasy.ȱȱTheȱonlyȱdifferenceȱisȱthatȱanȱelementȱinȱ
theȱ firstȱ dimensionȱ ofȱ aȱ multidimensionalȱ arrayȱ isȱ anotherȱ array.ȱ Forȱ example,ȱ theȱ
declaration:ȱ
ȱ
ȱ
ȱ
int
matrix[3][10];
ȱ
createsȱ matrix,ȱ aȱ oneȬdimensionalȱ arrayȱ containingȱ threeȱ elements.ȱ Eachȱ ofȱ theseȱ
elementsȱhappensȱtoȱbeȱanȱartsyȱofȱtenȱintegers.ȱ
Theȱvalueȱofȱtheȱnameȱ matrixȱisȱaȱpointerȱtoȱtheȱfirstȱelement,ȱsoȱ matrixȱpointsȱ
toȱanȱarrayȱofȱtenȱintegers.ȱ
K&R C
TheȱideaȱofȱaȱpointerȱtoȱanȱarrayȱwasȱaȱfairlyȱlateȱadditionȱtoȱK&RȱC,ȱandȱsomeȱolderȱ
compilersȱ doȱ notȱ fullyȱ implementȱ it.ȱ However,ȱ theȱ notionȱ ofȱ aȱ pointerȱ toȱ anȱ arrayȱ isȱ
crucialȱtoȱtheȱunderstandingȱofȱsubscriptsȱwithȱmultidimensionalȱarrays.ȱ
ȱ
ȱ
ȱ
8.2.3 Subscripts
ȱ
Toȱ identifyȱ aȱ singleȱ elementȱ fromȱ aȱ multidimensionalȱ array,ȱ oneȱ subscriptȱ mustȱ beȱ
givenȱ forȱ eachȱ dimension,ȱ inȱ theȱ sameȱ orderȱ thatȱ theȱ dimensionsȱ wereȱ givenȱ inȱ theȱ
declaration,ȱ andȱ eachȱ subscriptȱ isȱ enclosedȱ inȱ itsȱ ownȱ setȱ ofȱ brackets.ȱ Withȱ thisȱ
declaration:ȱ
ȱ
ȱ
int
matrix[3][10];
ȱ
theȱexpressionȱ
ȱ
ȱ
ȱ
matrix[1][5]
ȱ
accessesȱthisȱelement:ȱ
ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
8.2 Multidimensional Arrays
219
Butȱ subscriptsȱ ateȱ reallyȱ indirectionȱ expressionsȱ inȱ disguise,ȱ evenȱ withȱ
multidimensionalȱarrays.ȱConsiderȱdieȱexpressionȱ
ȱ
matrix
ȱ
ȱ
ItsȱtypeȱisȱȈpointerȱtoȱanȱarrayȱofȱtenȱintegersȈ,ȱandȱitsȱvalueȱis:ȱ
ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ
Itȱpointsȱtoȱtheȱfirstȱarrayȱofȱtenȱintegers.ȱ
ȱ
Theȱexpressionȱ
ȱ
ȱ
matrix
ȱ
isȱ alsoȱ aȱ Ȉpointerȱ toȱ anȱ arrayȱ ofȱ tenȱ integers,Ȉȱ butȱ itȱ pointsȱ toȱ aȱ differentȱ rowȱ ofȱ theȱ
matrix:ȱ
ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ
Why?ȱBecauseȱtheȱvalueȱoneȱisȱscaledȱbyȱtheȱsizeȱofȱanȱarrayȱofȱtenȱintegers.ȱApplyingȱ
indirectionȱfollowsȱtheȱarrowȱandȱselectsȱthisȱarray:ȱ
ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ
Soȱtheȱexpressionȱ
ȱ
ȱ
*(ȱmatrix + 1 )
ȱ
reallyȱ identifiesȱ aȱ particularȱ arrayȱ ofȱ tenȱ integers.ȱ Theȱ valueȱ ofȱ anȱ arrayȱ nameȱ isȱ aȱ
constantȱ pointerȱ toȱ theȱ firstȱ elementȱ inȱ theȱ array,ȱ andȱ theȱ sameȱ isȱ trueȱ ofȱ thisȱ
expression.ȱ Itsȱ typeȱ isȱ Ȉpointerȱ toȱ integer,Ȉȱ andȱ weȱ canȱ nowȱ showȱ itsȱ valueȱ inȱ theȱ
contextȱofȱtheȱnextȱdimension:ȱ
Download at http://www.pin5i.com/
Chapter 8 Arrays
220ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Nowȱholdȱonȱtoȱyourȱhat.ȱWhatȱisȱtheȱresultȱofȱthisȱexpression?ȱ
ȱ
*( matrix + 1 ) + 5
ȱ
Theȱpreviousȱexpressionȱpointedȱtoȱanȱinteger,ȱsoȱvalueȱfiveȱisȱscaledȱbyȱtheȱsizeȱofȱanȱ
integer.ȱȱTheȱresultȱpointsȱfiveȱintegersȱafterȱtheȱoriginalȱexpression:ȱ
ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ
ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ
ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ
Applyingȱindirection,ȱ
ȱ
ȱ
*( *( matrix + 1 ) + 5 )
ȱ
takesȱ usȱ toȱ theȱ integerȱ inȱ question.ȱ Ifȱ usedȱ asȱ anȱ RȬvalue,ȱ youȱ wouldȱ getȱ theȱ valueȱ
storedȱthere.ȱAsȱanȱLȬvalue,ȱtheȱlocationȱwouldȱreceiveȱaȱnewȱvalue.ȱ
Thisȱ intimidatingȱ expressionȱ isȱ actuallyȱ ourȱ oldȱ friend,ȱ theȱ subscript.ȱ Weȱ canȱ
rewriteȱ theȱ subexpressionȱ *( matrix + 1 )ȱ asȱ matrix[1].ȱ Substitutingȱ thisȱ
subexpressionȱintoȱtheȱoriginalȱexpressionȱgivesȱus:ȱ
ȱ
*( matrix[1] + 5 )
ȱ
Thisȱexpressionȱisȱperfectlyȱvalid,ȱmatrix[1]ȱselectsȱanȱarrayȱofȱtenȱintegers,ȱsoȱitsȱtypeȱ
isȱaȱpointerȱtoȱanȱinteger.ȱToȱthisȱpointerȱweȱaddȱfive,ȱandȱthenȱapplyȱindirection.ȱ
Butȱonceȱagain,ȱweȱhaveȱtheȱsubscriptȱformȱofȱindirection,ȱsoȱweȱcanȱsubstituteȱ
andȱgetȱ
ȱ
matrix[1][5]
Download at http://www.pin5i.com/
8.2 Multidimensional Arrays
CAUTION!
221
Thus,ȱ subscriptsȱ areȱ simplyȱ anotherȱ formȱ ofȱ indirectionȱ expressionȱ evenȱ forȱ
multidimensionalȱarrays.ȱ
Theȱ pointȱ ofȱ thisȱ exerciseȱ isȱ toȱ illustrateȱ howȱ subscriptsȱ workȱ forȱ
multidimensionalȱarraysȱandȱhowȱtheyȱdependȱonȱtheȱnotionȱofȱaȱpointerȱtoȱanȱarray.ȱ
Subscriptsȱ areȱ evaluatedȱ fromȱ leftȱ toȱ right.ȱ Theȱ arrayȱ nameȱ isȱ aȱ pointerȱ toȱ theȱ firstȱ
elementȱofȱtheȱfirstȱdimension,ȱsoȱtheȱfirstȱsubscriptȱvalueȱisȱscaledȱbyȱtheȱsizeȱofȱthatȱ
element.ȱ Theȱ resultȱ pointsȱ toȱ theȱ desiredȱ elementȱ inȱ thatȱ dimension.ȱ Theȱ indirectionȱ
thenȱ selectsȱ thatȱ specificȱ element.ȱ Becauseȱ theȱ elementȱ isȱ anȱ array,ȱ theȱ typeȱ ofȱ thisȱ
expressionȱisȱaȱpointerȱtoȱtheȱfirstȱelementȱofȱtheȱnextȱdimension.ȱȱTheȱnextȱsubscriptȱisȱ
scaledȱ byȱ thatȱ size,ȱ andȱ theȱ processȱ isȱ repeatedȱ untilȱ allȱ ofȱ theȱ subscriptsȱ haveȱ beenȱ
evaluated.ȱ
ȱ
Inȱmanyȱotherȱlanguages,ȱmultipleȱsubscriptsȱareȱwrittenȱasȱaȱcommaȬseparatedȱlistȱofȱ
values.ȱSomeȱlanguagesȱallowȱbothȱforms.ȱNotȱsoȱinȱC:ȱwritingȱ
ȱ
matrix[4,3]
ȱ
looksȱ perfectlyȱ fine,ȱ butȱ almostȱ certainlyȱ doesȱ notȱ accomplishȱ whatȱ youȱ want.ȱ
Rememberȱthatȱtheȱcommaȱoperatorȱevaluatesȱtheȱfirstȱexpressionȱbutȱthrowsȱawayȱitsȱ
value.ȱTheȱresultȱisȱtheȱvalueȱofȱtheȱsecondȱexpression.ȱThus,ȱtheȱpreviousȱexpressionȱisȱ
equivalentȱtoȱ
ȱ
matrix[3]
ȱ
Theȱ problemȱ isȱ thatȱ theȱ expressionȱ mayȱ compileȱ withoutȱ anyȱ errorȱ orȱ warning.ȱ Theȱ
expressionȱisȱperfectlyȱlegitimate,ȱitȱjustȱdoesnȇtȱmeanȱwhatȱyouȱhadȱintended.ȱ
ȱ
ȱ
ȱ
8.2.4 Pointers to Arrays
ȱ
Areȱtheseȱdeclarationsȱlegal?ȱ
ȱ
int
int
vector[10], *vp = vector;
matrix[3] [10], *mp = matrix;
ȱ
Theȱfirstȱisȱlegal.ȱItȱallocatesȱaȱvectorȱofȱintegers,ȱandȱthenȱdeclaresȱvpȱtoȱbeȱaȱpointerȱtoȱ
anȱ integerȱ andȱ initializesȱ theȱ pointerȱ toȱ pointȱ toȱ theȱ firstȱ elementȱ inȱ vector.ȱ Bothȱ
vectorȱandȱvpȱhaveȱtheȱsameȱtype:ȱpointerȱtoȱinteger.ȱTheȱsecondȱdeclarationȱisȱillegal,ȱ
however.ȱItȱcreatesȱtheȱmatrixȱcorrectlyȱandȱdeclaresȱ mpȱtoȱbeȱaȱpointerȱtoȱanȱinteger,ȱ
butȱtheȱinitializationȱofȱmpȱisȱincorrectȱbecauseȱmatrixȱisȱnotȱaȱpointerȱtoȱanȱinteger,ȱitȱisȱ
aȱ pointerȱ toȱ anȱ arrayȱ ofȱ integers.ȱ Howȱ wouldȱ weȱ declareȱ aȱ pointerȱ toȱ anȱ arrayȱ ofȱ
integers?ȱ
Download at http://www.pin5i.com/
222ȱ
Chapter 8 Arrays
int
(*p)[10];
ȱ
ȱ
Thisȱ declarationȱ isȱ moreȱ complexȱ thanȱ thoseȱ youȱ haveȱ seenȱ before,ȱ butȱ itȱ reallyȱ isnȇtȱ
tooȱ difficult.ȱ Justȱ pretendȱ thatȱ itȱ isȱ anȱ expressionȱ andȱ evaluateȱ it.ȱ Subscriptsȱ haveȱ aȱ
higherȱ precedenceȱ thanȱ indirection,ȱ butȱ theȱ parenthesesȱ surroundingȱ theȱ indirectionȱ
forceȱitȱtoȱgoȱfirst.ȱSoȱpȱisȱaȱpointerȱtoȱsomething,ȱbutȱtoȱwhat?ȱ
Theȱsubscriptȱisȱappliedȱnext,ȱsoȱpȱpointsȱtoȱsomeȱkindȱofȱarray.ȱThereȱarenȇtȱanyȱ
moreȱ operatorsȱ inȱ theȱ declarationȱ expression,ȱ soȱ eachȱ elementȱ ofȱ theȱ arrayȱ isȱ anȱ
integer.ȱ
Theȱdeclarationȱdoesnȇtȱtellȱyouȱdirectlyȱwhatȱpȱis,ȱbutȱitȱisȱnotȱdifficultȱtoȱfigureȱ
out—whenȱ weȱ appliedȱ indirectionȱ toȱ pȱ weȱ gotȱ anȱ array,ȱ andȱ puttingȱ aȱ subscriptȱ onȱ
thatȱexpressionȱproducedȱanȱinteger.ȱSoȱpȱisȱaȱpointerȱtoȱanȱarrayȱofȱintegers.ȱ
Addingȱinitializationȱtoȱtheȱdeclarationȱgivesȱus:ȱ
ȱ
int
(*p)[10] = matrix;
ȱ
whichȱmakesȱpȱpointȱtoȱtheȱfirstȱrowȱofȱmatrix.ȱ
pȱisȱaȱpointerȱtoȱanȱarrayȱofȱtenȱintegers.ȱȱAddingȱanȱintegerȱtoȱ pȱwillȱcauseȱtheȱ
integerȱvalueȱtoȱbeȱscaledȱbyȱtheȱsizeȱofȱtenȱintegersȱbeforeȱtheȱadditionȱtakesȱplace.ȱSoȱ
weȱcanȱuseȱthisȱpointerȱtoȱstepȱthroughȱtheȱmatrixȱrowȱbyȱrow.ȱ
Whatȱ shouldȱ youȱ doȱ ifȱ youȱ wantȱ aȱ pointerȱ thatȱ willȱ goȱ throughȱ theȱ matrixȱ
integerȱbyȱintegerȱratherȱthanȱrowȱbyȱrow?ȱBothȱofȱtheȱfollowingȱdeclarationsȱcreateȱaȱ
simpleȱintegerȱpointer,ȱinitializedȱinȱtwoȱdifferentȱwaysȱtoȱpointȱtoȱtheȱfirstȱintegerȱinȱ
theȱmatrix.ȱ
ȱ
int
int
*pi = &matrix[0][0];
*pi = matrix[0];
ȱ
Incrementingȱthisȱpointerȱadvancesȱitȱtoȱtheȱnextȱinteger.ȱ
CAUTION!
Ifȱ youȱ intendȱ toȱ performȱ anyȱ arithmeticȱ withȱ theȱ pointer,ȱ avoidȱ thisȱ kindȱ ofȱ
declaration:ȱ
int
(*p)[] = matrix
pȱ isȱ stillȱ aȱ pointerȱ toȱ anȱ arrayȱ ofȱ integers,ȱ butȱ theȱ arrayȱ sizeȱ isȱ missing.ȱ Integersȱ
involvedȱinȱpointerȱarithmeticȱwithȱthisȱvariableȱwillȱbeȱscaledȱbyȱtheȱsizeȱofȱanȱemptyȱ
arrayȱ(thatȱis,ȱmultipliedȱbyȱzero),ȱwhichȱisȱprobablyȱnotȱwhatȱyouȱhadȱinȱmind.ȱSomeȱ
compilersȱcatchȱthisȱerrorȱandȱsomeȱdonȇt.ȱ
Download at http://www.pin5i.com/
8.2 Multidimensional Arrays
223
8.2.5 Multidimensional Arrays as Function Arguments
ȱ
Aȱmultidimensionalȱarrayȱnameȱusedȱasȱanȱargumentȱtoȱaȱfunctionȱisȱpassedȱtheȱsameȱ
asȱaȱoneȬdimensionalȱarrayȱname—aȱpointerȱtoȱtheȱfirstȱelementȱofȱtheȱarrayȱisȱpassed.ȱȱ
However,ȱ theȱ differenceȱ betweenȱ themȱ isȱ thatȱ eachȱ elementȱ ofȱ theȱ multidimensionalȱ
arrayȱ isȱ anotherȱ array,ȱ andȱ theȱ compilerȱ needsȱ toȱ knowȱ itsȱ dimensionsȱ inȱ orderȱ toȱ
evaluateȱsubscriptsȱforȱtheȱarrayȱparameterȱinȱtheȱfunction.ȱHereȱareȱtwoȱexamplesȱtoȱ
illustrateȱtheȱdifference:ȱ
ȱ
int
vector[10];
...
func1( vector );
ȱ
Theȱtypeȱofȱtheȱargumentȱvectorȱisȱaȱpointerȱtoȱanȱinteger,ȱsoȱfunc1ȱcanȱbeȱprototypedȱ
inȱeitherȱofȱtheȱfollowingȱways:ȱ
ȱ
void func1( int *vec );
void func1( int vec[] );
ȱ
Pointerȱarithmeticȱonȱvecȱinȱtheȱfunctionȱusesȱtheȱsizeȱofȱanȱintegerȱforȱitsȱscaleȱfactor.ȱ
Nowȱletȇsȱlookȱatȱaȱmatrix.ȱ
ȱ
int
matrix[3][10];
...
func2( matrix );
ȱ
Hereȱ theȱ typeȱ ofȱ theȱ argumentȱ matrixȱ isȱ aȱ pointerȱ toȱ anȱ arrayȱ ofȱ tenȱ integers.ȱ Whatȱ
shouldȱtheȱprototypeȱfor func2ȱlookȱlike?ȱEitherȱofȱtheȱfollowingȱformsȱcouldȱbeȱused:ȱ
ȱ
void func2( int (*mat)[10] );
void func2( int mat[][10] );
ȱ
Inȱtheȱfunction,ȱtheȱfirstȱsubscriptȱusedȱwithȱ matȱisȱscaledȱbyȱtheȱsizeȱofȱanȱarrayȱofȱtenȱ
integers;ȱtheȱsecondȱsubscriptȱisȱthenȱscaledȱbyȱtheȱsizeȱofȱanȱinteger,ȱjustȱasȱitȱwouldȱ
beȱforȱtheȱoriginalȱmatrix.ȱ
Theȱ keyȱ hereȱ isȱ thatȱ theȱ compilerȱ mustȱ knowȱ theȱ sizesȱ ofȱ theȱ secondȱ andȱ
subsequentȱ dimensionsȱ inȱ orderȱ toȱ evaluateȱ subscripts,ȱ thusȱ theȱ prototypeȱ mustȱ
declareȱtheseȱdimensions.ȱTheȱsizeȱofȱtheȱfirstȱdimensionȱisnȇtȱneededȱbecauseȱitȱisȱnotȱ
usedȱinȱtheȱcalculationȱofȱsubscripts.ȱ
YouȱcanȱwriteȱtheȱprototypeȱforȱaȱoneȬdimensionalȱarrayȱparameterȱeitherȱasȱanȱ
arrayȱ orȱ asȱ aȱ pointer.ȱ Forȱ multidimensionalȱ arrays,ȱ youȱ onlyȱ haveȱ thisȱ choiceȱ forȱ theȱ
firstȱdimension,ȱthough.ȱȱSpecifically,ȱitȱisȱincorrectȱtoȱprototypeȱfunc2ȱlikeȱthis:ȱ
Download at http://www.pin5i.com/
224ȱ
Chapter 8 Arrays
void func2( int **mat );
ȱ
Thisȱexampleȱdeclaresȱ matȱtoȱbeȱaȱpointerȱtoȱaȱpointerȱtoȱanȱinteger,ȱwhichȱisȱnotȱatȱallȱ
theȱsameȱthingȱasȱaȱpointerȱtoȱanȱarrayȱofȱtenȱintegers.ȱ
ȱ
ȱ
ȱ
8.2.6 Initialization
ȱ
Theȱ storageȱ orderȱ ofȱ arrayȱ elementsȱ becomesȱ importantȱ whenȱ initializingȱ
multidimensionalȱarrays.ȱȱThereȱareȱtwoȱwaysȱtoȱwriteȱtheȱinitializerȱlist.ȱTheȱfirstȱisȱtoȱ
justȱgiveȱaȱlongȱlistȱofȱinitializers,ȱasȱinȱtheȱfollowingȱexample.ȱ
ȱ
int matrix[2][3] = { 100, 101, 102, 110, 111, 112 };
ȱ
Theȱ storageȱ orderȱ hasȱ theȱ rightmostȱ subscriptȱ varyingȱ mostȱ rapidly,ȱ soȱ thisȱ
initializationȱproducesȱtheȱsameȱresultȱasȱtheseȱassignments:ȱ
ȱ
matrix[0][0]
matrix[0][1]
matrix[0][2]
matrix[1][0]
matrix[1][1]
matrix[1][2]
=
=
=
=
=
=
100;
101;
102;
110;
111;
112;
ȱ
Theȱ secondȱ wayȱ isȱ basedȱ onȱ theȱ ideaȱ thatȱ aȱ multidimensionalȱ arrayȱ isȱ reallyȱ aȱ oneȬ
dimensionalȱ arrayȱ ofȱ complicatedȱ elements.ȱ Forȱ example,ȱ hereȇsȱ aȱ declarationȱ forȱ aȱ
twoȬdimensionalȱarray:ȱ
ȱ
ȱ
int
two_dim[3][5];
ȱ
Viewȱ two_dimȱ asȱ anȱ arrayȱ ofȱ threeȱ (complicated)ȱ elements.ȱ Toȱ initializeȱ anȱ arrayȱ ofȱ
threeȱelements,ȱweȱuseȱaȱlistȱcontainingȱthreeȱinitializers:ȱ
ȱ
int
two_dim[3][5] = { Ș, Ș, Ș };
ȱ
ȱ
Butȱeachȱofȱtheseȱelementsȱisȱactuallyȱanȱarrayȱofȱfiveȱintegers,ȱsoȱeachȱofȱtheȱȘȇsȱshouldȱ
beȱaȱlistȱofȱfiveȱvaluesȱenclosedȱinȱbraces.ȱReplacingȱeachȱ Șȱwithȱsuchȱaȱlistȱresultsȱinȱ
codeȱthatȱlooksȱlikeȱthis:ȱ
ȱ
ȱ
int
two_dim[3][5] = {
{ 00, 01, 02, 03, 04 },
{ 10, 11, 12, 13, 14 },
{ 20, 21, 22, 23, 24 }
};
ȱ
Ofȱcourse,ȱtheȱindentingȱandȱspacingȱweȱhaveȱusedȱareȱnotȱrequired,ȱalthoughȱtheyȱdoȱ
makeȱtheȱlistȱeasierȱtoȱread.ȱ
Download at http://www.pin5i.com/
8.2 Multidimensional Arrays
225
Ifȱ youȱ eraseȱ allȱ butȱ theȱ outermostȱ bracesȱ fromȱ thisȱ example,ȱ youȱ willȱ seeȱ thatȱ
whatȱisȱleftȱisȱaȱsimpleȱinitializerȱlistȱlikeȱtheȱfirstȱone.ȱTheȱbracesȱmerelyȱdelimitȱtheȱ
initializerȱlistȱbyȱrow.ȱ
Figuresȱ8.1ȱandȱ8.2ȱillustrateȱinitializingȱthreeȬȱandȱfourȬdimensionalȱarrays.ȱInȱ
theseȱexamples,ȱtheȱdigitsȱofȱeachȱinitializerȱshowȱtheȱsubscriptȱvaluesȱofȱtheȱlocationȱ
inȱwhichȱitȱisȱstored. 36
ȱ
Whyȱ goȱ toȱ allȱ theȱ troubleȱ ofȱ puttingȱ inȱ theseȱ bracesȱ whenȱ theȱ initializationȱ worksȱ
exactlyȱtheȱsameȱwayȱwithoutȱthem?ȱThereȱareȱtwoȱreasons.ȱTheȱfirstȱisȱorganization.ȱ
Aȱ single,ȱ longȱ listȱ ofȱ numbersȱ makesȱ itȱ difficultȱ toȱ seeȱ whichȱ valueȱ belongsȱ toȱ eachȱ
locationȱofȱtheȱarray,ȱthusȱtheȱbracesȱactȱasȱsignpostsȱandȱmakeȱitȱeasierȱtoȱverifyȱthatȱ
theȱrightȱvaluesȱappearȱinȱtheȱrightȱplaces.ȱ
Second,ȱ theȱ bracesȱ areȱ valuableȱ forȱ incompleteȱ initialization.ȱ Withoutȱ them,ȱ
onlyȱ trailingȱ initializersȱ mayȱ beȱ omitted.ȱ Evenȱ ifȱ onlyȱ aȱ fewȱ elementsȱ ofȱ aȱ largeȱ
multidimensionalȱarrayȱwereȱtoȱbeȱinitialized,ȱtheȱlistȱmightȱstillȱbeȱquiteȱlongȱbecauseȱ
onlyȱ theȱ trailingȱ initializersȱ canȱ beȱ omitted.ȱ Withȱ theȱ braces,ȱ though,ȱ trailingȱ
initializersȱmayȱbeȱomittedȱfromȱeachȱlist.ȱAlso,ȱtheȱinitializersȱforȱeachȱdimensionȱalsoȱ
formȱaȱlist.ȱ
Toȱ illustrateȱ thisȱ point,ȱ letȇsȱ revisitȱ theȱ fourȬdimensionalȱ arrayȱ initializationȱ inȱ
Figureȱ8.2ȱandȱchangeȱourȱrequirementsȱaȱlittle.ȱSupposeȱweȱonlyȱneedȱtoȱinitializeȱtwoȱ
elementsȱinȱtheȱarray.ȱElementȱ [0][0][0][0]ȱshouldȱbeȱ100ȱandȱelementȱ [1][0][0][0]
shouldȱbeȱ200,ȱȱAllȱotherȱelementsȱshouldȱbeȱleftȱtoȱtheirȱdefaultȱ
ȱ
ȱ
ȱ
int
three_dim[2][3][5] = {
{
{ 000, 001, 002,
{ 010, Oil, 012,
{ 020, 021, 022,
},
{ 100, 101, 102,
{ 110, 111, 112,
{ 120, 121, 122,
}
003, 004 },
013, 014 },
023, 024 }
103, 104 },
113, 114 },
123, 124 }
};
ȱ
Figureȱ8.1ȱInitializingȱaȱthreeȬdimensionalȱarrayȱ
ȱIfȱtheseȱexamplesȱwereȱcompiled,ȱtheȱinitializersȱthatȱbeginȱwithȱzeroȱwouldȱactuallyȱbeȱinterpretedȱasȱoctalȱ
numbers.ȱȱIgnoreȱthisȱpoint,ȱandȱlookȱonlyȱatȱtheȱindividualȱdigitsȱofȱeachȱinitializer.ȱ
36
Download at http://www.pin5i.com/
226ȱ
Chapter 8 Arrays
int
four_dim[2][2][3][5] = {
{
{
{ 0000, 0001,
{ 0010, 0011,
{ 0020, 0021,
},
{
{ 0100, 0101,
{ 0110, 0111,
{ 0120, 0121,
},
},
{
{
{ 1000, 1001,
{ 1010, 1011,
{ 1020, 1021,
},
{
{ 1100, 1101,
{ 1110, 1111,
{ 1120, 1121,
},
}
0002, 0003, 0004 },
0012, 0013, 0014 },
0022, 0023, 0024 }
0102, 0103, 0104 },
0112, 0113, 0114 },
0122, 0123, 0124 }
1002, 1003, 1004 },
1012, 1013, 1014 },
1022, 1023, 1024 }
1102, 1103, 1104 },
1112, 1113, 1114 },
1122, 1123, 1124 }
}
ȱ
Figureȱ8.2ȱInitializingȱaȱfourȬdimensionalȱarrayȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
values.ȱHereȱisȱhowȱweȱcanȱaccomplishȱthisȱtask:ȱ
ȱ
int
four_dim[2][2][3][5] = {
{
{
{ 100 }
}
},
{
{
{ 200 }
}
}
}
ȱ
Withoutȱtheȱbraces,ȱyouȱwouldȱneedȱthisȱlongerȱinitializerȱlist:ȱ
Download at http://www.pin5i.com/
8.3 Arrays of Pointers
227
int
four_dim[2][2][3][5] = { 100, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200 };
ȱ
Thisȱlistȱisȱnotȱonlyȱharderȱtoȱreadȱbutȱalsoȱmoreȱdifficultȱtoȱgetȱrightȱinȱfirstȱplace.ȱ
ȱ
ȱ
ȱ
8.2.7 Automatic Array Sizing
ȱ
Withȱmultidimensionalȱarrays,ȱonlyȱtheȱfirstȱdimensionalȱofȱtheȱarrayȱcanȱbeȱimpliedȱbyȱ
theȱinitializerȱlist.ȱTheȱremainingȱonesȱareȱneededȱsoȱthatȱtheȱcompilerȱcanȱdetermineȱ
theȱsizeȱofȱeachȱsubordinateȱdimension.ȱForȱexample:ȱ
ȱ
int
two_dim[][5] = {
{ 00, 01, 02 },
{ 10, 11 },
{ 20, 21, 22, 23 }
};
ȱ
Theȱ leftmostȱ dimensionȱ isȱ determinedȱ toȱ beȱ threeȱ byȱ countingȱ theȱ numberȱ ofȱ
initializersȱitȱcontains.ȱ
Whyȱ canȇtȱ theȱ otherȱ dimensionȱ beȱ determinedȱ automaticallyȱ byȱ countingȱ theȱ
valuesȱ inȱ itsȱ longestȱ initializerȱ list?ȱ Inȱ principle,ȱ theȱ compilerȱ couldȱ figureȱitȱ out,ȱ butȱ
thenȱatȱleastȱoneȱofȱtheȱinitializersȱinȱeachȱlistȱwouldȱhaveȱtoȱbeȱfullȱsizeȱinȱorderȱforȱtheȱ
dimensionȱtoȱbeȱdeterminedȱaccurately.ȱȱByȱrequiringȱthatȱallȱdimensionsȱafterȱtheȱfirstȱ
oneȱbeȱgiven,ȱallȱofȱtheȱinitializerȱlistsȱcanȱbeȱincomplete.ȱ
ȱ
ȱ
ȱ
8.3 Arrays of Pointers
ȱ
Asideȱfromȱitsȱtype,ȱaȱpointerȱvariableȱisȱlikeȱanyȱotherȱvariable.ȱJustȱasȱyouȱcanȱcreateȱ
arraysȱofȱintegers,ȱyouȱcanȱalsoȱdeclareȱarraysȱofȱpointers.ȱHereȱisȱanȱexample:ȱ
ȱ
int
*api[10];
ȱ
Toȱfigureȱoutȱthisȱcomplexȱdeclaration,ȱpretendȱthatȱitȱisȱanȱexpressionȱandȱevaluateȱit.ȱ
Subscriptsȱhaveȱaȱhigherȱprecedenceȱthanȱindirection,ȱsoȱinȱthisȱexpression,ȱtheȱ
subscriptȱwouldȱbeȱappliedȱfirst.ȱTherefore,ȱ apiȱisȱanȱarrayȱofȱsomethingȱ(andȱoh,ȱbyȱ
theȱway,ȱthereȱareȱtenȱofȱthem).ȱAfterȱgettingȱoneȱelementȱofȱtheȱarray,ȱtheȱindirectionȱ
isȱappliedȱnext.ȱThereȱarenȇtȱanyȱmoreȱoperators,ȱsoȱtheȱresultȱofȱthisȱexpressionȱisȱanȱ
integer.ȱ
Download at http://www.pin5i.com/
228ȱ
Chapter 8 Arrays
Soȱwhatȱisȱ api?ȱWeȱgotȱanȱintegerȱbyȱapplyingȱindirectionȱtoȱanȱelementȱofȱanȱ
array,ȱsoȱapiȱmustȱbeȱanȱarrayȱofȱpointersȱtoȱintegers.ȱ
Whereȱwouldȱyouȱeverȱuseȱanȱarrayȱofȱpointers?ȱHereȱisȱoneȱexample:ȱ
ȱ
char
};
#define
const *keyword[] = {
"do",
"for",
"if",
"register",
"return",
"switch",
"while"
N_KEYWORD
( sizeof( keyword ) / sizeof( keyword[0] ) )
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Determine whether the argument matches any of the words in
** a list of keywords, and return the index to the one it matches.
** If no match is found, return the value -1.
*/
#include <string.h>
int
lookup_keyword( char const * const desired_word,
char const *keyword_table[], int const size )
{
char const **kwp;
/*
** For each word in the table ...
*/
for( kwp = keyword_table; kwp < keyword_table + size; kwp++ )
/*
** If this word matches the one we're looking for,
** return its position in the table.
*/
if( strcmp( desired_word, *kwp ) == 0 )
return kwp - keyword_table;
/*
** Not found.
*/
return -1;
}
ȱ
Programȱ8.2ȱȱKeywordȱlookupȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
keyword.cȱ
Download at http://www.pin5i.com/
8.3 Arrays of Pointers
229
Noticeȱtheȱuseȱofȱ sizeofȱtoȱautomaticallyȱcountȱtheȱnumberȱofȱelementsȱinȱtheȱ
array.ȱ sizeof( keyword )ȱgivesȱtheȱnumberȱofȱbytesȱinȱtheȱentireȱarray,ȱandȱ sizeof(
keyword[0] )ȱisȱtheȱnumberȱofȱbytesȱinȱoneȱelement.ȱTheȱresultingȱdivisionȱgivesȱtheȱ
numberȱofȱelements.ȱ
ThisȱarrayȱwouldȱbeȱusefulȱinȱaȱprogramȱthatȱcountsȱkeywordsȱinȱCȱsourceȱfiles.ȱ
Eachȱwordȱfromȱtheȱinputȱwouldȱbeȱcomparedȱtoȱtheȱstringsȱinȱtheȱlist,ȱandȱallȱmatchesȱ
wouldȱbeȱcounted.ȱProgramȱ8.2ȱgoesȱthroughȱtheȱlistȱofȱkeywordsȱlookingȱforȱaȱmatchȱ
withȱtheȱargumentȱstring.ȱWhenȱaȱmatchȱisȱfound,ȱtheȱ offsetȱintoȱtheȱlistȱisȱreturned.ȱ
Theȱcallingȱprogramȱmustȱknowȱthatȱzeroȱmeansȱ do,ȱoneȱmeansȱ for,ȱandȱsoȱforth,ȱandȱ
itȱ alsoȱ hasȱ toȱ knowȱ thatȱ Ȭ1ȱ isȱ returnedȱ forȱ aȱ nonkeyword.ȱ Thisȱ informationȱ wouldȱ
probablyȱbeȱobtainedȱviaȱsymbolsȱdefinedȱinȱanȱincludedȱfile.ȱ
Weȱcouldȱalsoȱstoreȱtheȱkeywordsȱinȱaȱmatrix,ȱlikeȱthis:ȱ
ȱ
char
const keyword[][9] = {
"do",
"for",
"if",
"register",
"return",
"switch",
"while"
};
ȱ
Whatȱ isȱ theȱ differenceȱ betweenȱ thisȱ declarationȱ andȱ theȱ precedingȱ one?ȱ Theȱ secondȱ
declarationȱ createsȱ aȱ matrixȱ whoseȱ rowsȱ areȱ eachȱ longȱ enoughȱ toȱ holdȱ theȱ longestȱ
keywordȱ(plusȱitsȱterminatingȱNULȱbyte).ȱTheȱmatrixȱlooksȱlikeȱthis:ȱ
ȱ
ȱ
ȱ
keywordȱ
ȇdȇȱ ȇoȇȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
ȇfȇȱ
ȇoȇȱ ȇrȇȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
ȇiȇȱ
ȇfȇȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
ȇrȇȱ
ȇeȇȱ ȇgȇȱ
ȇiȇȱ
ȇsȇȱ
ȇtȇȱ
ȇeȇȱ ȇrȇȱ
0ȱ
ȇrȇȱ
ȇeȇȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
0ȱ
ȇtȇȱ ȇuȇȱ ȇrȇȱ ȇnȇȱ
ȇsȇȱ ȇwȇȱ ȇiȇȱ
ȇtȇȱ
ȇwȇȱ ȇhȇȱ
ȇlȇȱ ȇeȇȱ
ȇiȇȱ
ȇcȇȱ ȇhȇȱ
0ȱ
Download at http://www.pin5i.com/
Chapter 8 Arrays
230ȱ
Theȱ firstȱ declarationȱ createsȱ anȱ arrayȱ ofȱ pointers,ȱ whichȱ areȱ initializedȱ toȱ pointȱ toȱ
variousȱstringȱliterals,ȱasȱillustratedȱbelow.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇdȇȱ ȇoȇȱ 0ȱ ȱ
ȇfȇȱ ȇoȇȱ ȇrȇȱ 0ȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇrȇȱ
ȇeȇȱ
ȇtȇȱ ȇuȇȱ ȇrȇȱ ȇnȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇsȇȱ ȇwȇ
ȇiȇȱ
ȇtȇȱ
ȇcȇȱ ȇhȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇwȇ
ȇhȇȱ
ȇiȇȱ
ȇlȇȱ ȇeȇȱ
ȇiȇȱ
ȱ
ȱ
0ȱ ȱ
ȇfȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇrȇȱ ȇeȇȱ ȇgȇȱ
ȇiȇȱ
ȇsȇȱ
ȇtȇȱ
ȇeȇȱ ȇrȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
0ȱ
ȱ
ȱ
0ȱ
0ȱ
ȱ
ȱ
Noticeȱ theȱ differenceȱ inȱ theȱ amountȱ ofȱ memoryȱ used.ȱ Theȱ matrixȱ looksȱ
inefficientȱbecauseȱeveryȱrowȱmustȱbeȱlongȱenoughȱtoȱstoreȱtheȱlongestȱkeyword.ȱȱButȱ
itȱdoesȱnotȱneedȱanyȱpointers.ȱOnȱtheȱotherȱhand,ȱtheȱarrayȱofȱpointersȱtakesȱspace,ȱbutȱ
eachȱofȱtheȱstringȱliteralsȱisȱonlyȱasȱlongȱasȱitȱneedsȱtoȱbe.ȱ
WhatȱwouldȱweȱneedȱtoȱchangeȱinȱProgramȱ8.2ȱtoȱuseȱtheȱmatrixȱinsteadȱofȱtheȱ
arrayȱofȱpointers?ȱItȱmayȱsurpriseȱyouȱtoȱlearnȱthatȱonlyȱtheȱdeclarationsȱforȱtheȱtableȱ
parameterȱandȱtheȱlocalȱvariableȱwouldȱbeȱdifferent.ȱTheȱcodeȱwouldnȇtȱchangeȱatȱall.ȱȱ
Becauseȱ theȱ valueȱ ofȱ anȱ arrayȱ nameȱ isȱ aȱ pointer,ȱ theȱ bodyȱ ofȱ theȱ functionȱ willȱ workȱ
withȱeitherȱaȱpointerȱvariableȱorȱanȱarrayȱname.ȱ
Whichȱisȱbetter?ȱItȱdependsȱonȱtheȱspecificȱwordsȱyouȱwishȱtoȱstore.ȱIfȱtheyȱareȱ
allȱ nearlyȱ theȱ sameȱ length,ȱ theȱ matrixȱ isȱ moreȱ compactȱ becauseȱ thereȱ isȱ noȱ spaceȱ
neededȱforȱpointers.ȱȱHowever,ȱifȱtheȱwordsȱareȱdifferentȱlengths,ȱorȱworseȱyet,ȱmostȱofȱ
themȱ areȱ shortȱ butȱ aȱ fewȱ areȱ quiteȱ long,ȱ thenȱ theȱ arrayȱ ofȱ pointersȱ mayȱ beȱ moreȱ
compact.ȱItȱ dependsȱ onȱwhetherȱ theȱspaceȱ consumedȱbyȱtheȱ pointersȱ isȱ lessȱthanȱ theȱ
spaceȱwastedȱbyȱusingȱfixedȬlengthȱrowsȱforȱeachȱword.ȱ
Inȱ practice,ȱ theseȱ differencesȱ areȱ soȱ slightȱ asȱ toȱ beȱ unimportantȱ forȱ allȱ butȱ theȱ
largestȱofȱtables.ȱȱMoreȱoftenȱthanȱnot,ȱtheȱarrayȱofȱpointersȱisȱused,ȱbutȱwithȱaȱtwist:ȱ
ȱ
char
const *keyword[] = {
"do",
"for",
"if",
"register",
"return",
"switch",
ȱ
0ȱ
Download at http://www.pin5i.com/
8.4 Summary
231
"while",
NULL
};
ȱ
Hereȱ weȱ addȱ aȱ NULLȱ pointerȱ toȱ theȱ endȱ ofȱ theȱ table.ȱ Theȱ NULLȱ letsȱ functionsȱ thatȱ
searchȱ theȱtableȱ detectȱ theȱ endȱ ofȱ theȱ tableȱwithoutȱ knowingȱ itsȱ sizeȱ inȱ advance,ȱ likeȱ
this:ȱ
for( kwp = keyword_table; *kwp != NULL;
kwp++ )
ȱ
ȱ
ȱ
8.4 Summary
ȱ
Theȱvalueȱofȱanȱarrayȱnameȱinȱmostȱexpressionsȱisȱaȱpointerȱtoȱtheȱfirstȱelementȱofȱtheȱ
array.ȱȱThereȱareȱonlyȱtwoȱexceptionsȱtoȱthisȱrule,ȱȱ sizeofȱreturnsȱtheȱnumberȱofȱbytesȱ
inȱ theȱ entireȱ arrayȱ ratherȱ thanȱ theȱ sizeȱ ofȱ aȱ pointer.ȱ Theȱ unaryȱ &ȱ operatorȱ returnsȱ aȱ
pointerȱtoȱtheȱfirstȱelementȱofȱtheȱarray,ȱnotȱaȱpointerȱtoȱaȱpointerȱtoȱtheȱfirstȱelement.ȱ
Exceptȱforȱtheirȱprecedence,ȱtheȱsubscriptȱexpressionȱ array[value]ȱisȱtheȱsameȱ
asȱtheȱindirectionȱexpressionȱ *( array + ( value ) ).ȱThus,ȱsubscriptsȱmayȱbeȱusedȱ
withȱpointerȱexpressionsȱasȱwellȱasȱwithȱarrayȱnames,ȱwhichȱmakesȱitȱdifficultȱforȱtheȱ
compilerȱtoȱcheckȱtheȱvalidityȱofȱsubscripts.ȱPointerȱexpressionsȱmayȱbeȱmoreȱefficientȱ
thanȱ subscripts,ȱ butȱ subscriptsȱ areȱ neverȱ moreȱ efficientȱ thanȱ pointerȱ expressions.ȱ
However,ȱ reducingȱ program,ȱ maintainabilityȱ toȱ gainȱ runtimeȱ efficiencyȱ isȱ rarelyȱ aȱ
goodȱidea.ȱ
Pointersȱandȱarraysȱareȱnotȱequivalent.ȱTheȱpropertiesȱofȱanȱarrayȱandȱaȱpointerȱ
variableȱ areȱ quiteȱ different.ȱ Declaringȱ anȱ arrayȱ createsȱ spaceȱ toȱ storeȱ theȱ arrayȱ
elements,ȱwhileȱdeclaringȱaȱpointerȱvariableȱonlyȱcreatesȱspaceȱtoȱstoreȱtheȱpointer.ȱ
Whenȱ anȱ arrayȱ nameȱ isȱ passedȱ asȱ aȱ functionȱ argument,ȱ aȱ pointerȱ toȱ theȱ firstȱ
elementȱ isȱ passedȱ toȱ theȱ function.ȱ Thisȱ parameterȱ isȱ aȱ copy,ȱ soȱ theȱ functionȱ canȱ
manipulateȱitȱwithoutȱaffectingȱtheȱactualȱargument.ȱHowever,ȱapplyingȱindirectionȱtoȱ
theȱ pointerȱ parameterȱ allowsȱ theȱ functionȱ toȱ modifyȱ theȱ originalȱ arrayȱ elements.ȱȱ
Arrayȱparametersȱmayȱbeȱdeclaredȱeitherȱasȱarrayȱnamesȱorȱpointers;ȱbothȱdeclarationȱ
formsȱareȱequivalentȱforȱfunctionȱparametersȱonly.ȱ
Anȱ arrayȱ mayȱ beȱ initializedȱ withȱ aȱ listȱ ofȱ valuesȱ enclosedȱ inȱ braces.ȱ Staticȱ
variablesȱ (includingȱ arrays)ȱ receiveȱ theirȱ initialȱ valuesȱ whenȱ theȱ programȱ isȱ loadedȱ
intoȱ memory.ȱ Automaticȱ variablesȱ (includingȱ arrays)ȱ mustȱ beȱ reinitializedȱ withȱ
implicitȱassignmentȱstatementsȱeachȱtimeȱexecutionȱentersȱtheȱblockȱinȱwhichȱtheyȱareȱ
declared.ȱ Ifȱ anȱ initializerȱ listȱ hasȱ fewerȱ valuesȱ thanȱ theȱ sizeȱ ofȱ theȱ array,ȱ theȱ lastȱ
elementsȱ ofȱ theȱ arrayȱ areȱ initializedȱ withȱ theȱ defaultȱ value.ȱ Ifȱ theȱ dimensionȱ ofȱ anȱ
initializedȱarrayȱisȱomitted,ȱtheȱcompilerȱwillȱmakeȱtheȱarrayȱjustȱlargeȱenoughȱtoȱholdȱ
Download at http://www.pin5i.com/
232ȱ
Chapter 8 Arrays
theȱ valuesȱ givenȱ inȱ theȱ initializerȱ list.ȱ Characterȱ arraysȱ mayȱ beȱ initializedȱ withȱ aȱ
shorthandȱnotationȱthatȱresemblesȱaȱstringȱliteral.ȱ
Multidimensionalȱ arraysȱ areȱ actuallyȱ oneȬdimensionalȱ arraysȱ whoseȱ elementsȱ
areȱ eachȱ anȱ array.ȱ Theȱ valuesȱ inȱ multidimensionalȱ arraysȱ areȱ storedȱ inȱ rowȱ majorȱ
order,ȱ withȱ theȱ rightmostȱ subscriptȱ varyingȱ mostȱ rapidly.ȱ Theȱ valueȱ ofȱ aȱ
multidimensionalȱarrayȱnameȱisȱaȱpointerȱtoȱitsȱfirstȱelement,ȱwhichȱwillȱbeȱaȱpointerȱtoȱ
anȱarray.ȱArithmeticȱwithȱthisȱpointerȱwillȱbeȱscaledȱbyȱtheȱsizeȱofȱtheȱarray.ȱSubscriptsȱ
forȱ multidimensionalȱ arraysȱ areȱ alsoȱ pointerȱ expressions.ȱ Whenȱ theȱ nameȱ ofȱ aȱ
multidimensionalȱ arrayȱ isȱ passedȱ asȱ anȱ argumentȱ toȱ aȱ function,ȱ theȱ correspondingȱ
functionȱ parameterȱ mustȱ beȱ declaredȱ withȱ theȱ sizesȱ ofȱ theȱ secondȱ andȱ subsequentȱ
dimensions.ȱ Becauseȱ aȱ multidimensionalȱ arrayȱ isȱ reallyȱ aȱ oneȬdimensionalȱ arrayȱ ofȱ
complexȱ elements,ȱ theȱ initializerȱ listȱ forȱ aȱ multidimensionalȱ arrayȱ containsȱ aȱ listȱ ofȱ
initializersȱforȱtheȱcomplexȱelements.ȱEachȱofȱtheseȱlistsȱmayȱalsoȱcontainȱnestedȱlists,ȱ
asȱ neededȱ byȱ theȱ numberȱ ofȱ dimensionsȱ inȱ theȱ array.ȱ Theȱ interiorȱ bracesȱ mayȱ beȱ
omittedȱ ifȱ theȱ initializerȱ listsȱ areȱ allȱ complete.ȱ Onlyȱ theȱ firstȱ dimensionȱ ofȱ aȱ
multidimensionalȱarrayȱmayȱbeȱautomaticallyȱsizedȱfromȱtheȱinitializerȱlist.ȱ
Itȱ isȱ possibleȱ toȱ createȱ arraysȱ ofȱ pointers.ȱ Listsȱ ofȱ stringsȱ mayȱ beȱ storedȱ inȱ aȱ
matrix,ȱorȱasȱaȱlistȱofȱpointersȱtoȱvectorsȱorȱstringȱliterals.ȱInȱaȱmatrix,ȱeachȱrowȱmustȱbeȱ
asȱlongȱasȱtheȱlongestȱstring,ȱhoweverȱnoȱpointersȱareȱstored.ȱTheȱlistȱofȱpointersȱtakesȱ
space,ȱbutȱeachȱofȱtheȱstringsȱneedȱonlyȱbeȱasȱlongȱasȱnecessary.ȱ
ȱ
ȱ
ȱ
8.5 Summary of Cautions
ȱ
1. Usingȱ commasȱ toȱ separateȱ subscriptsȱ whenȱ accessingȱ aȱ multidimensionalȱ arrayȱ
(pageȱ221).ȱ
2. Doingȱarithmeticȱwithȱaȱpointerȱtoȱanȱunsizedȱarrayȱ(pageȱ222).ȱ
ȱ
ȱ
ȱ
8.6 Summary of Programming Tips
ȱ
1. Writingȱgoodȱcodeȱinȱtheȱfirstȱplaceȱisȱbetterȱthanȱdependingȱonȱtheȱcompilerȱtoȱfixȱ
upȱbadȱcodeȱ(pageȱ205).ȱ
2. Sourceȱ codeȱ readabilityȱ isȱ nearlyȱ alwaysȱ moreȱ importantȱ thanȱ runtimeȱ efficiencyȱ
(pageȱ209).ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
8.7 Questions
233
3. Pointerȱparametersȱtoȱfunctionsȱshouldȱbeȱdeclaredȱ constȱwheneverȱpossibleȱ(pageȱ
212).ȱ
4. Usingȱ registerȱ variablesȱ increasesȱ runtimeȱ efficiencyȱ inȱ someȱ environmentsȱ (pageȱ
212).ȱ
5. Usingȱbracesȱtoȱfullyȱencloseȱtheȱinitializersȱofȱaȱmultidimensionalȱarrayȱincreasesȱ
readabilityȱ(pageȱ225).ȱ
ȱ
ȱ
ȱ
8.7 Questions
ȱ
1. Givenȱtheȱdeclarationsȱandȱdataȱshownȱbelow,ȱevaluateȱeachȱofȱtheȱexpressionsȱandȱ
stateȱitsȱvalue.ȱEvaluateȱeachȱexpressionȱwithȱtheȱoriginalȱdataȱshownȱ(thatȱis,ȱtheȱ
resultsȱ ofȱ oneȱ expressionȱ doȱ notȱ affectȱ theȱ followingȱ ones).ȱ Assumeȱ thatȱ theȱ intsȱ
arrayȱbeginsȱatȱlocationȱ100ȱandȱthatȱintegersȱandȱpointersȱbothȱoccupyȱfourȱbytes.ȱ
ȱ
int
ints[20] = {
10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
110, 120, 130, 140, 150, 160, 170, 180, 190, 200
};
(Otherȱdeclarations)
int
*ip = ints + 3;
ȱ
ȱ
ȱ
Expression
ints
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ints + 4
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
4
*(ints + 4)
ints[-2]
&ints
&ints[4]
&ints + 4
&ints[-2]
ȱ
Expression
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ip
ints[4]
*ints +
Value
ip[4]
ip + 4
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. *ip + 4;
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
*(ip + 4)
ip[-2]
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. &ip
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
&ip[4]
&ip + 4
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱ. &ip[-2]
Value
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
Download at http://www.pin5i.com/
234ȱ
Chapter 8 Arrays
2. Areȱtheȱexpressions array[ i + j ]ȱand i + j[ array ]ȱequivalent?ȱ
3. Theȱfollowingȱdeclarationsȱareȱanȱattemptȱtoȱaccessȱtheȱarrayȱdataȱusingȱsubscriptsȱ
thatȱstartȱatȱone.ȱWillȱitȱwork?ȱ
ȱ
int
int
actual_data[ 20 ];
*data = actual_data – 1;
4. Rewriteȱ theȱ followingȱ loop,ȱ whichȱ testsȱ whetherȱ aȱ stringȱ isȱ aȱ palindrome,ȱ toȱ useȱ
pointerȱvariablesȱinsteadȱofȱsubscripts.ȱ
char buffer[SIZE];
int
front, rear;
...
front = 0;
rear = strlen( buffer ) – 1;
while( front < rear ){
if( buffer[front] != buffer[rear] )
break;
front += 1;
rar -= 1;
}
if( front >= rear ){
printf( "It is a palindrome!\n" );
}
5. Theȱ potentialȱ efficiencyȱ ofȱ pointersȱ overȱ subscriptsȱ isȱ aȱ motivationȱ toȱ useȱ them.ȱ
Whenȱisȱitȱreasonableȱtoȱuseȱsubscriptsȱdespiteȱtheȱpossibleȱlossȱofȱruntimeȱspeed?ȱ
6. Compileȱ theȱ functionsȱ try1ȱ throughȱ try5ȱ onȱ yourȱ machine,ȱ andȱ analyzeȱ theȱ
resultingȱassemblyȱcode.ȱWhatȱisȱyourȱconclusion?ȱ
7. Testȱ yourȱ conclusionȱ forȱ theȱ previousȱ questionȱ byȱ runningȱ eachȱ ofȱ theȱ functionsȱ
andȱ timingȱ theirȱ execution.ȱ Makingȱ theȱ arraysȱ severalȱ thousandȱ elementsȱ longȱ
increasesȱtheȱaccuracyȱofȱtheȱexperimentȱbecauseȱtheȱcopyingȱtakesȱfarȱmoreȱtimeȱ
thanȱtheȱirrelevantȱpartsȱofȱtheȱprogram.ȱAlso,ȱcallȱtheȱfunctionsȱfromȱwithinȱaȱloopȱ
thatȱ iteratesȱ enoughȱ timesȱ soȱ thatȱ youȱ canȱ accuratelyȱ timeȱ theȱ entireȱ execution.ȱȱ
Compileȱ theȱ programsȱ twiceȱ forȱ thisȱ experiment—onceȱ withoutȱ anyȱ optimizationȱ
atȱ all,ȱ andȱ onceȱ withȱ optimization.ȱ Ifȱ yourȱ compilerȱ offersȱ aȱ choice,ȱ selectȱ
optimizationȱforȱbestȱspeed.ȱ
Download at http://www.pin5i.com/
8.7 Questions
235
8. Theȱfollowingȱdeclarationsȱwereȱfoundȱinȱoneȱsourceȱfile:ȱ
ȱ
int
int
a[10];
*b = a;
ȱ
Butȱinȱaȱdifferentȱsourceȱfile,ȱthisȱcodeȱwasȱfound:ȱ
ȱ ȱ
extern
extern
int
...
x = a[3];
y = b[3];
int
*a;
int
b[];
x, y;
Explainȱwhatȱhappensȱwhenȱtheȱtwoȱassignmentȱstatementsȱareȱexecuted.ȱ(Assumeȱ
thatȱintegersȱandȱpointersȱbothȱoccupyȱfourȱbytes).ȱ
9. Writeȱaȱdeclarationȱthatȱwillȱinitializeȱanȱarrayȱofȱintegersȱcalledȱcoin_valuesȱtoȱtheȱ
valuesȱofȱcurrentȱU.S.ȱcoins.ȱ
10. Givenȱtheȱdeclarationȱ
int
array[4][2];
ȱ
giveȱtheȱvalueȱofȱeachȱofȱtheȱfollowingȱexpressions.ȱAssumeȱthatȱtheȱarrayȱbeginsȱatȱ
locationȱ1000ȱandȱthatȱintegersȱoccupyȱtwoȱbytesȱofȱmemory.ȱ
ȱ
Expression
Value
array
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
array + 2
array[3]
array[2] - 1
&array[1][2]
&array[2][0]
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱ
11. Givenȱtheȱdeclarationȱ
ȱ
int
array[4][2][3][6];
ȱ
computeȱtheȱvalueȱofȱeachȱofȱtheȱfollowingȱexpressions.ȱAlso,ȱshowȱtheȱdeclarationȱ
thatȱwouldȱbeȱneededȱforȱtheȱvariableȱ xȱinȱorderȱforȱtheȱexpressionȱtoȱbeȱassignedȱ
toȱ xȱ withoutȱ usingȱ aȱ cast.ȱ Assumeȱ thatȱ theȱ arrayȱ beginsȱ atȱ locationȱ 1000ȱ andȱ thatȱ
integersȱoccupyȱfourȱbytesȱofȱmemory.ȱ
Download at http://www.pin5i.com/
236ȱ
Chapter 8 Arrays
ȱ
Expression
array
Value
Type of x
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
array + 2
array[3]
array[2] - 1
array[2][1]
array[1][0] + 1
array[1][0][2]
array[0][1][0] + 2
array[3][1][2][5]
&array[3][1][2][5]
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱ. ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱ
12. ArraysȱinȱCȱareȱstoredȱinȱrowȬmajorȱorder.ȱWhenȱisȱthisȱinformationȱrelevant?ȱ
13. Givenȱtheȱdeclaration:ȱ
ȱ
int
array[4][5][3];
ȱ
convertȱtheȱfollowingȱpointerȱexpressionȱtoȱuseȱsubscripts.ȱ
ȱ
Expression
Type of x
*array
*( array + 2 )
*( array + 1 ) + 4
*( *( array + 1 ) + 4 )
*( *( *( array + 3 ) + 1 ) + 2 )
*( *( *array + 1 ) + 2 )
*{ **array + 2 )
**( *array + 1 )
***array
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ .
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱ
14. Theȱ subscriptsȱ forȱ aȱ multidimensionalȱ arrayȱ mustȱ eachȱ beȱ givenȱ inȱ itsȱ ownȱ setȱ ofȱ
brackets.ȱ Underȱ whatȱ conditionsȱ wouldȱ theȱ followingȱ codeȱ fragmentȱ compileȱ
withoutȱproducingȱanyȱwarningsȱorȱerrors?ȱ
ȱ
int
array[10][20];
...
i = array[3,4];
Download at http://www.pin5i.com/
8.7 Questions
237
15. Givenȱtheȱdeclarations:ȱ
ȱ
unsigned
int
int
which;
array[ SIZE ];
ȱ
whichȱofȱtheȱfollowingȱstatementsȱmakesȱmoreȱsense,ȱandȱwhy?ȱ
ȱ
ȱ
ȱ if( array[ which ] == 5 && which < SIZE ) ...
if( which < SIZE && array[ which ] == 5 ) ...
ȱ
16. Whatȱ isȱ theȱ differenceȱ (ifȱ any)ȱ betweenȱ theȱ variablesȱ array1ȱ andȱ array2ȱ inȱ thisȱ
program?ȱ
ȱ
void
function( int array1[10] ){
int
array2[10];
...
}
ȱ
17. Explainȱ theȱ significantȱ differencesȱ betweenȱ theȱ followingȱ twoȱ usesȱ ofȱ theȱ constȱ
keyword.ȱ
ȱ
void function( int const a, int const b[] )[
ȱ
18. Howȱ elseȱ couldȱ theȱ followingȱ functionȱ prototypeȱ beȱ writtenȱ toȱ achieveȱ theȱ sameȱ
results?ȱ
ȱ
void function( int array[3][2][5] );
ȱ
19. Inȱ Programȱ 8.2,ȱ theȱ keywordȱ lookupȱ example,ȱ theȱ arrayȱ ofȱ pointersȱ toȱ charactersȱ
wasȱmodifiedȱbyȱaddingȱaȱNULLȱpointerȱtoȱtheȱendȱofȱit,ȱthusȱeliminatingȱtheȱneedȱ
toȱ knowȱ theȱ sizeȱ ofȱ theȱ table.ȱ Howȱ couldȱ theȱ matrixȱ ofȱ keywordsȱ beȱ modifiedȱ toȱ
achieveȱtheȱsameȱresult?ȱShowȱtheȱ forȱstatementȱthatȱwouldȱbeȱusedȱtoȱaccessȱtheȱ
modifiedȱmatrix.ȱ
ȱ
ȱ
ȱ
8.8 Programming Exercises
ȱ
1. Writeȱ aȱ declarationȱ forȱ anȱ arrayȱ thatȱ initializesȱ certainȱ locationsȱ ofȱ theȱ arrayȱ toȱ
specificȱ values.ȱ Theȱ arrayȱ shouldȱ beȱ calledȱ char_valuesȱ andȱ containȱ 3ȱ ×ȱ 6ȱ ×ȱ 4ȱ ×ȱ 5ȱ
unsignedȱ characters.ȱ Theȱ followingȱ locationsȱ shouldȱ beȱ staticallyȱ initializedȱ toȱ
theseȱvalues:ȱ
Download at http://www.pin5i.com/
238ȱ
Chapter 8 Arrays
ȱ
Loc
1,2,2,3ȱ
2,4,3,2ȱȱ
2,4,3,3ȱȱ
2,1,1,2ȱ
Value
'A'
'3'
3
0320
Loc
1,1,1,1ȱȱ
1,4,2,3ȱȱ
2,5,3,4ȱ
2,2,2,2ȱ
Value
' '
'\n'
125
'\''
Loc
1,3,2,2ȱ
2,2,3,1ȱȱ
1,2,3,4ȱ
2,2,1,1ȱ
Value
0xf3
'\121'
'x'
'0'
ȱ
Locationsȱotherȱthanȱthoseȱmentionedȱaboveȱshouldȱbeȱinitializedȱtoȱbinaryȱ(notȱtheȱ
character)ȱzero.ȱNote:ȱStaticȱinitializationȱisȱtoȱbeȱused;ȱthereȱcanȱbeȱnoȱexecutableȱ
codeȱinȱyourȱsolution!ȱ
Althoughȱitȱwillȱnotȱbeȱpartȱofȱtheȱsolution,ȱyouȱwillȱprobablyȱwantȱtoȱwriteȱaȱ
programȱtoȱcheckȱyourȱinitializationȱbyȱprintingȱoutȱtheȱarray.ȱBecauseȱsomeȱofȱtheȱ
valuesȱ areȱ notȱ printableȱ characters,ȱ printȱ theȱ valuesȱ asȱ integersȱ (octalȱ orȱ
hexadecimalȱoutputȱwouldȱbeȱconvenient).ȱ
Note:ȱSolvingȱthisȱproblemȱtwice,ȱonceȱusingȱnestedȱbracesȱinȱtheȱinitializerȱlistȱ
andȱ onceȱ without,ȱ willȱ giveȱ youȱ aȱ greaterȱ appreciationȱ ofȱ theȱ usefulnessȱ ofȱ theȱ
nestedȱbraces.ȱ
2. TheȱU.S.ȱfederalȱincomeȱtaxȱforȱ singleȱpeopleȱinȱ1995ȱwasȱcomputedȱaccordingȱ toȱ
theȱfollowingȱrules:ȱ
ȱ
If Your Taxable
of the Amount
income Is Over
But Not Over
Your Tax is
Over
$0ȱ
23,350ȱ
56,550ȱ
117,950ȱ
256,500ȱ
$23,350ȱ
56,550ȱ
117,950ȱ
256,500ȱ
––ȱȱ
15%ȱ
$3,502.50ȱ+ȱ28%ȱ
12,798.50ȱ+ȱ31%ȱ
31,832.50ȱ+ȱ36%ȱ
81,710.50ȱ+ȱ39.8%ȱ
$0ȱ
23,350ȱ
56,550ȱ
117,950ȱ
256,500ȱ
ȱ
Writeȱtheȱfunctionȱprototypedȱbelow:ȱ
ȱ float single_tax( float income );
Theȱargumentȱisȱtaxableȱincome,ȱandȱtheȱfunctionȱreturnsȱtheȱappropriateȱamountȱ
ofȱtax.ȱ
3. Anȱidentityȱmatrixȱisȱaȱsquareȱmatrixȱwhoseȱvaluesȱareȱallȱzeroȱexceptȱforȱthoseȱonȱ
theȱmainȱdiagonal,ȱwhichȱareȱone.ȱForȱexample:ȱ
ȱ
1
0
0
0
1
0
0
0
1
ȱ
isȱaȱ3ȱ×ȱ3ȱidentityȱmatrix.ȱWriteȱaȱfunctionȱcalledȱ identity_matrixȱthatȱtakesȱaȱ10ȱ×ȱ
10ȱmatrixȱ ofȱintegersȱasȱitsȱonlyȱargumentȱandȱreturnsȱaȱbooleanȱvalueȱindicatingȱ
whetherȱtheȱmatrixȱisȱanȱidentityȱmatrix.ȱ
Download at http://www.pin5i.com/
8.8 Programming Exercises
239
4. Modifyȱtheȱidentity_matrixȱfunctionȱfromȱtheȱpreviousȱproblemȱsoȱthatȱitȱcanȱtakeȱ
matricesȱofȱanyȱsizeȱbyȱflatteningȱtheȱarray.ȱTheȱfirstȱargumentȱshouldȱbeȱaȱpointerȱ
toȱ anȱ integer,ȱ andȱ youȱ willȱ needȱ aȱ secondȱ argumentȱ thatȱ specifiesȱ theȱ sizeȱ ofȱ theȱ
matrix.ȱ
5. IfȱAȱisȱaȱmatrixȱofȱxȱrowsȱandȱyȱcolumnsȱandȱBȱisȱaȱmatrixȱofȱyȱrowsȱandȱzȱcolumns,ȱ
thenȱAȱandȱ Bȱ canȱ beȱmultipliedȱ togetherȱandȱ theȱ resultȱwillȱ beȱ aȱ matrixȱ Cȱ withȱ xȱ
rowsȱandȱzȱcolumns.ȱEachȱelementȱofȱthisȱmatrixȱisȱdeterminedȱwithȱtheȱfollowingȱ
formula:ȱ
ȱ
y
Ci , j
¦A
i ,k
u Bk , j
ȱ
ȱ
Forȱexample:ȱ
ȱ
ª 2 6 º
ª 50 14 44 52 º
« 3 5 » u ª 4 2 4 5 º « 23 21 18 20 »
»
«
» « 7 3 6 7 » «
¼ «
«¬ 1 1»¼ ¬
1 10 12 »¼
¬ 11
ȱ
ȱ
ȱ
Theȱvalueȱ14ȱinȱtheȱanswerȱwasȱtheȱresultȱofȱaddingȱ2ȱ×ȱ–2ȱȱandȱ–6ȱ×ȱ–3.ȱ
Writeȱ aȱ functionȱ toȱ multiplyȱ twoȱ matrices.ȱ Theȱ functionȱ shouldȱ haveȱ thisȱ
prototype:ȱ
ȱ
k 1
ȱ
void matrix_multiply( int *m1, int *m2, int *r,
int x, int y, int z );
m1ȱwillȱbeȱaȱmatrixȱwithȱxȱrowsȱandȱyȱcolumns;ȱm2ȱwillȱbeȱaȱmatrixȱwithȱyȱrowsȱandȱ
zȱcolumns.ȱTheseȱmatricesȱshouldȱbeȱmultipliedȱtogether,ȱandȱtheȱresultsȱshouldȱbeȱ
storedȱ inȱ r,ȱ whichȱ willȱ beȱ aȱ matrixȱ withȱ xȱ rowsȱ andȱ zȱ columns.ȱ ȱ Rememberȱ toȱ
modifyȱtheȱformulaȱasȱnecessaryȱtoȱaccountȱforȱtheȱfactȱthatȱsubscriptsȱinȱCȱbeginȱ
withȱzero,ȱnotȱone!ȱ
6. Asȱyouȱknow,ȱtheȱCȱcompilerȱallocatesȱarraysȱwithȱsubscriptsȱthatȱalwaysȱbeginȱatȱ
zeroȱ andȱ doesȱ notȱ checkȱ subscriptsȱ whenȱ arrayȱ elementsȱ areȱ accessed.ȱ Inȱ thisȱ
project,ȱ youȱ willȱ writeȱ aȱ functionȱ thatȱ allowsȱ theȱ userȱ toȱ accessȱ ȈpseudoȬarraysȈȱ
whoseȱsubscriptsȱcanȱbeȱinȱanyȱranges,ȱwithȱcompleteȱerrorȱchecking.ȱ
Hereȱisȱaȱprototypeȱforȱtheȱfunctionȱyouȱwillȱwrite:ȱ
ȱ
int array_offset( int arrayinfo[], ... );
ȱ
Theȱ functionȱ takesȱ aȱ setȱ ofȱ informationȱ describingȱ theȱ dimensionsȱ ofȱ aȱ pseudoȬ
arrayȱ andȱ aȱ setȱ ofȱ subscriptȱ values.ȱ Itȱ thenȱ usesȱ theȱ informationȱ toȱ translateȱ theȱ
subscriptȱ valuesȱ intoȱ anȱ integerȱ thatȱ canȱ beȱ usedȱ asȱ aȱ subscriptȱ onȱ aȱ vector.ȱ Withȱ
thisȱfunction,ȱtheȱuserȱcanȱallocateȱspaceȱeitherȱasȱaȱvectorȱorȱwithȱ malloc,ȱbutȱthenȱ
accessȱthatȱspaceȱasȱaȱmultidimensionalȱarray.ȱȱTheȱarrayȱisȱcalledȱaȱȈpseudoȬȱ
Download at http://www.pin5i.com/
240ȱ
Chapter 8 Arrays
arrayȈȱ becauseȱ theȱ compilerȱ thinksȱ thatȱ itȱ isȱ aȱ vector,ȱ evenȱ thoughȱ thisȱ functionȱ
allowsȱitȱtoȱbeȱaccessedȱasȱaȱmultidimensionalȱarray.ȱ
Theȱfunctionȇsȱargumentsȱare:ȱ
ȱ
Argument
Meaing
arrayinfo
AȱvariableȬlengthȱarrayȱofȱintegersȱthatȱcontainsȱinformationȱ
aboutȱtheȱpseudoȬarray,ȱarrayinfo[0]ȱspecifiesȱhowȱmanyȱ
dimensionsȱtheȱpseudoȬarrayȱhas,ȱwhichȱmustȱbeȱaȱvalueȱinȱtheȱ
rangeȱ1Ȭ10,ȱinclusive.ȱarrayinfo[1]ȱandȱarrayinfo[2]ȱgiveȱtheȱ
lowȱandȱhighȱlimitsȱforȱtheȱfirstȱdimension,ȱarrayinfo[3]ȱandȱ
arrayinfo[4]ȱgiveȱtheȱlowȱandȱhighȱlimitsȱforȱtheȱsecondȱ
dimension,ȱandȱsoȱforth.ȱ
...
Theȱvariableȱportionȱofȱtheȱargumentȱlistȱmayȱcontainȱupȱtoȱtenȱ
integers,ȱwhichȱareȱsubscriptȱvaluesȱthatȱidentifyȱaȱparticularȱ
locationȱinȱtheȱpseudoȬarray.ȱYouȱmustȱuseȱva_ȱargumentȱmacrosȱ
toȱaccessȱthem.ȱWhenȱtheȱfunctionȱisȱcalled,ȱarrayinfo[0]ȱ
argumentsȱwillȱbeȱpassed.ȱ
ȱ
Theȱ formulaȱ toȱ useȱ forȱ computingȱ anȱ arrayȱ locationȱ fromȱ itsȱ subscriptsȱ isȱ givenȱ
below.ȱ Theȱ variablesȱ s1,ȱ s2,ȱ etc.ȱ representȱ theȱ subscriptȱ argumentsȱ s1,ȱ s2,ȱ etc.ȱ Theȱ
variablesȱ lo1ȱ andȱ hi1ȱ representȱ dieȱ lowȱ andȱ highȱ limitsȱ forȱ subscriptȱ s1,ȱ fromȱ theȱ
arrayinfoȱ argument,ȱ andȱ soȱ forthȱ forȱ theȱ remainingȱ dimensions.ȱ Theȱ variableȱ locȱ
representsȱ theȱ desiredȱ locationȱ inȱ theȱ pseudoȬarray,ȱ asȱ anȱ integerȱ offsetȱ fromȱ theȱ
beginningȱofȱaȱvector.ȱForȱaȱoneȬdimensionalȱpseudoȬarray:ȱ
ȱ ȱ
ȱ loc s1 lo1 ȱ
ȱ
ForȱaȱtwoȬdimensionalȱpseudoȬarray:ȱ
ȱ
loc s1 lo1 u hi2 lo2 1 s2 lo2
ȱ
ȱ
ȱ
ForȱaȱthreeȬdimensionalȱpseudoȬarray:ȱ
ȱ
loc ª¬ s1 lo1 u hi2 lo2 1 s2 lo2 º¼ u hi3 lo3 1 s3 lo3
ȱ
ȱ
ȱ
ForȱaȱfourȬdimensionalȱpseudoȬarray:ȱ
ȱ
loc ¬ª s1 lo1 u hi2 lo2 1 s2 lo2 ¼º
^
u hi3 lo3 1 s3 lo3 ` u hi4 lo4 1 s4 lo4
ȱ
ȱ
ȱ
andȱsoȱforthȱupȱtoȱtenȱdimensions.ȱ
Download at http://www.pin5i.com/
8.8 Programming Exercises
241
Youȱmayȱassumeȱthatȱ arrayinfoȱisȱaȱvalidȱpointerȱandȱthatȱtheȱcorrectȱnumberȱ
ofȱ subscriptȱ argumentsȱ areȱ passedȱ toȱ array_offset.ȱ Everythingȱ elseȱ mustȱ beȱ
checkedȱforȱerrors.ȱȱAȱfewȱofȱtheȱpossibleȱerrorsȱare:ȱnumberȱofȱdimensionsȱnotȱinȱ
theȱrangeȱ1Ȭ10,ȱaȱsubscriptȱisȱlessȱthanȱitsȱlowȱvalue,ȱaȱlowȱvalueȱisȱgreaterȱthanȱtheȱ
correspondingȱhighȱvalue,ȱetc.ȱIfȱtheseȱorȱanyȱotherȱerrorsȱareȱdetected,ȱtheȱvalueȱȬ1ȱ
shouldȱbeȱreturned.ȱ
Hint:ȱ Copyȱ theȱ subscriptȱ argumentsȱ intoȱ aȱ localȱ array.ȱ Youȱ canȱ thenȱ codeȱ theȱ
calculationȱasȱaȱloopȱwithȱanȱiterationȱforȱeachȱdimension.ȱ
Example:ȱ Assumeȱ thatȱ theȱ arrayinfoȱ arrayȱ containsȱ theȱ valuesȱ 3,ȱ 4,ȱ 6,ȱ 1,ȱ 5,ȱ Ȭ3,ȱ
andȱ3.ȱTheseȱvaluesȱindicateȱthatȱweȱareȱworkingȱwithȱaȱthreeȬdimensionalȱpseudoȬ
array.ȱ Theȱ firstȱ subscriptȱ isȱ aȱ valueȱ fromȱ 4ȱ throughȱ 6,ȱ theȱ secondȱ subscriptȱ isȱ aȱ
valueȱfromȱ1ȱthroughȱ5,ȱandȱtheȱthirdȱsubscriptȱisȱaȱvalueȱfromȱȬ3ȱthroughȱ3.ȱȱInȱthisȱ
example,ȱ array_offsetȱwillȱbeȱcalledȱwithȱthreeȱsubscriptȱarguments.ȱSeveralȱsetsȱ
ofȱsubscriptsȱareȱshownȱbelowȱalongȱwithȱtheȱoffsetsȱthatȱtheyȱrepresentȱ
ȱ
Subscripts
Offset
Subscripts
Offset
Subscripts
Offset
4,ȱ1,ȱȬ3ȱ
0ȱ
4,ȱ1,ȱ3ȱ
6ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ 5,ȱ1,ȱȬ3ȱȱ
35ȱ
4,ȱ1,ȱȬ2ȱ
1ȱ
4,ȱ2,ȱȬ3ȱ
7ȱȱȱȱȱȱȱȱȱȱ
6,ȱ3,ȱ1ȱ
88ȱ
ȱ
7. Modifyȱtheȱarray_offsetȱfunctionȱfromȱProblemȱ6ȱsoȱthatȱitȱaccessesȱpseudoȬarraysȱ
whoseȱ elementsȱ areȱ allocatedȱ inȱ columnȱ majorȱ order,ȱ thatȱ is,ȱ withȱ theȱ leftmostȱ
subscriptȱ varyingȱ mostȱ rapidly.ȱ ȱ Thisȱ newȱ function,ȱ array_offset2,ȱ shouldȱ
otherwiseȱworkȱtheȱsameȱasȱtheȱoriginalȱfunction.ȱ
Theȱformulasȱforȱcalculatingȱsubscriptsȱforȱtheseȱarraysȱareȱgivenȱbelow.ȱ
ForȱaȱoneȬdimensionalȱpseudoȬarray:ȱ
ȱ
loc s1 lo1 ȱ
ȱ
ForȱaȱtwoȬdimensionalȱpseudoȬarray:ȱ
ȱ
loc s2 lo2 u hi1 lo1 1 s1 lo1
ȱ
ȱ
ȱ
ForȱaȱthreeȬdimensionalȱpseudoȬarray:ȱ
ȱ ȱ
loc ª¬ s3 lo3 u hi2 lo2 1 s2 lo2 º¼ u hi1 lo1 1 s1 lo1
ȱ
ȱ
ȱ
ForȱaȱfourȬdimensionalȱpseudoȬarray:ȱ
ȱ
loc ª¬ s4 lo4 u hi3 lo3 1 s3 lo3 º¼
^
u hi2 lo2 1 s2 lo2 ` u hi1 lo1 1 s1 lo1
ȱ
ȱ
ȱ
andȱsoȱforthȱupȱtoȱtenȱdimensions.ȱ
Download at http://www.pin5i.com/
Chapter 8 Arrays
242ȱ
Example:ȱAssumeȱthatȱtheȱarrayinfoȱarrayȱcontainsȱtheȱvaluesȱ3,ȱ4,ȱ6,ȱ1,ȱ5,ȱȬ3,ȱandȱ3.ȱ
TheseȱvaluesȱindicateȱthatȱweȱareȱworkingȱwithȱaȱthreeȬdimensionalȱpseudoȬarray.ȱ
Theȱfirstȱsubscriptȱisȱaȱvalueȱfromȱ4ȱthroughȱ6,ȱtheȱsecondȱsubscriptȱisȱaȱvalueȱfromȱ
1ȱthroughȱ5,ȱandȱtheȱthirdȱsubscriptȱisȱaȱvalueȱfromȱȬ3ȱthroughȱ3.ȱInȱthisȱexample,ȱ
array_offset2ȱ willȱ beȱ calledȱ withȱ threeȱ subscriptȱ arguments.ȱ Severalȱ setsȱ ofȱ
subscriptsȱareȱshownȱbelowȱalongȱwithȱtheȱoffsetsȱthatȱtheyȱrepresent.ȱ
ȱ
ȱ
Subscripts
4,ȱ1,ȱȬ3ȱ
5,ȱ1,ȱȬ3ȱ
6,ȱ1,ȱȬ3ȱ
Offset_
0ȱ
1ȱ
2ȱ
Subscripts
4,ȱ2,ȱȬ3ȱ
4,ȱ3,ȱȬ3ȱ
4,ȱ1,ȱȬ2ȱ
Offset
3ȱ
6ȱ
15ȱ
Subscripts
4,ȱ1,ȱȬ1ȱ
5,ȱ3,ȱȬ1ȱ
6,ȱ5,ȱ3ȱ
Offset
30ȱ
37ȱ
104ȱ
ȱ
8. Theȱqueenȱisȱtheȱmostȱpowerfulȱpieceȱinȱtheȱgameȱofȱchess.ȱȱOnȱtheȱboardȱshownȱ
below,ȱtheȱqueenȱcanȱcaptureȱanyȱpieceȱonȱanyȱsquareȱcoveredȱbyȱtheȱeightȱarrows.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȣ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Isȱitȱpossibleȱtoȱplaceȱeightȱqueensȱonȱaȱchessboardȱinȱsuchȱaȱwayȱthatȱnoneȱofȱthemȱ
canȱ attackȱ anyȱ ofȱ theȱ others?ȱ Thisȱ questionȱ isȱ calledȱ Theȱ Eightȱ Queensȱ Problem.ȱ
YourȱtaskȱisȱtoȱwriteȱaȱprogramȱtoȱfindȱallȱsolutionsȱtoȱtheȱEightȱQueensȱProblem.ȱ
Howȱmanyȱsolutionsȱareȱthere?ȱ
Hint:ȱ Theȱ programȱ isȱ easyȱ ifȱ youȱ useȱ aȱ techniqueȱ calledȱ backtracking.ȱ Writeȱ aȱ
functionȱ thatȱ placesȱ aȱ queenȱ inȱ theȱ firstȱ columnȱ ofȱ oneȱ rowȱ andȱ thenȱ checksȱ toȱ
makeȱsureȱthatȱthereȱareȱnoȱconflictsȱwithȱanyȱotherȱqueensȱonȱtheȱboard.ȱIfȱthereȱisȱ
aȱconflict,ȱtheȱfunctionȱshouldȱmoveȱtheȱqueenȱtoȱtheȱnextȱcolumnȱofȱthatȱrowȱandȱ
tryȱagain.ȱIfȱthereȱisȱaȱconflictȱinȱeveryȱcolumn,ȱtheȱfunctionȱshouldȱreturn.ȱ
Ifȱ theȱ queenȱ canȱ beȱ placed,ȱ though,ȱ theȱ functionȱ shouldȱ thenȱ callȱ itselfȱ
recursivelyȱtoȱplaceȱaȱqueenȱinȱtheȱnextȱrow.ȱȱWhenȱtheȱrecursiveȱcallȱreturns,ȱtheȱ
functionȱ thenȱ movesȱ itsȱ queenȱ toȱ theȱ nextȱ column.ȱ Wheneverȱ aȱ queenȱ isȱ placedȱ
successfullyȱinȱtheȱlastȱrow,ȱtheȱfunctionȱshouldȱprintȱtheȱchessboard,ȱshowingȱtheȱ
locationsȱofȱtheȱeightȱqueens.ȱ
Download at http://www.pin5i.com/
9
Strings, Characters, and Bytes
Stringsȱareȱanȱimportantȱtypeȱofȱdata,ȱyetȱCȱdoesȱnotȱhaveȱanȱexplicitȱstringȱdataȱtypeȱ
becauseȱ stringsȱ areȱ storedȱ inȱ characterȱ arraysȱ orȱ asȱ stringȱ literals.ȱ Literalsȱ areȱ
appropriateȱ forȱ stringsȱ thatȱ theȱ programȱ doesȱ notȱ needȱ toȱ modify.ȱ Allȱ otherȱ stringsȱ
mustȱbeȱstoredȱinȱcharacterȱarraysȱorȱdynamicallyȱallocatedȱmemoryȱ(seeȱChapterȱ11).ȱȱ
Thisȱchapterȱdescribesȱtheȱlibraryȱfunctionsȱthatȱdealȱwithȱstringsȱandȱcharactersȱandȱaȱ
relatedȱ groupȱ ofȱ functionsȱ withȱ similarȱ capabilitiesȱ thatȱ dealȱ withȱ bothȱ stringȱ andȱ
nonstringȱdata.ȱ
ȱ
ȱ
ȱ
9.1 String Basics
ȱ
First,ȱletȇsȱreviewȱtheȱbasicsȱofȱstrings.ȱAȱstringȱisȱaȱsequenceȱofȱzeroȱorȱmoreȱcharactersȱ
followedȱ byȱ aȱ NULȱ byte,ȱ whichȱ isȱ aȱ byteȱ whoseȱ bitsȱ areȱ allȱ zero.ȱ Therefore,ȱ itȱ isȱ notȱ
possibleȱ forȱ aȱ stringȱ toȱ containȱ aȱ NULȱ asȱ oneȱ ofȱ itsȱ characters.ȱ Thisȱ restrictionȱ rarelyȱ
causesȱproblemsȱbecauseȱthereȱisnȇtȱaȱprintableȱcharacterȱassociatedȱwithȱNUL,ȱwhichȱ
isȱ whyȱ itȱ wasȱ chosenȱ asȱ aȱ terminator.ȱ Theȱ NULȱ terminatesȱ theȱ stringȱ butȱ isȱ notȱ
consideredȱaȱpartȱofȱit,ȱsoȱtheȱlengthȱofȱaȱstringȱdoesȱnotȱincludeȱtheȱNUL.ȱ
Theȱ headerȱ fileȱ string.hȱ containsȱ theȱ prototypesȱ andȱ declarationsȱ neededȱ toȱ
useȱtheȱstringȱfunctions.ȱAlthoughȱitsȱuseȱisȱnotȱrequired,ȱitȱisȱaȱgoodȱideaȱtoȱincludeȱ
thisȱheaderȱfileȱbecauseȱwithȱtheȱprototypesȱitȱcontainsȱtheȱcompilerȱcanȱdoȱaȱbetterȱjobȱ
errorȱcheckingȱyourȱprogram. 37
ȱ Oldȱ Cȱ programsȱ oftenȱ didȱ notȱ includeȱ thisȱ file.ȱ Withoutȱ functionȱ prototypes,ȱ allȱ thatȱ couldȱ beȱ declaredȱ wasȱ theȱ typeȱ
returnedȱbyȱeachȱfunction,ȱandȱtheȱvaluesȱreturnedȱbyȱmostȱofȱtheseȱfunctionsȱareȱignoredȱanyway.ȱ
37
Download at http://www.pin5i.com/
Chapter 9 Strings, Characters, and Bytes
244
9.2 String Length
ȱ
Theȱ lengthȱ ofȱ aȱ stringȱ isȱ theȱ numberȱ ofȱ charactersȱ itȱ contains.ȱ Theȱ lengthȱ isȱ
easilyȱ computedȱ byȱ countingȱ theȱ characters,ȱ asȱ isȱ doneȱ inȱ Programȱ 9.1.ȱ Thisȱ
implementationȱillustratesȱtheȱtypeȱofȱprocessingȱusedȱwhenȱdealingȱwithȱstrings,ȱbutȱ
inȱ factȱ youȱ rarelyȱ needȱ toȱ writeȱ stringȱ functionsȱ becauseȱ theȱ onesȱ providedȱ inȱ theȱ
standardȱ libraryȱ usuallyȱ willȱ doȱ theȱ job.ȱ Shouldȱ youȱ wishȱ toȱ writeȱ aȱ stringȱ function,ȱ
though,ȱbeȱawareȱthatȱtheȱStandardȱreservesȱallȱfunctionȱnamesȱthatȱbeginȱwithȱstrȱforȱ
futureȱexpansionȱofȱtheȱlibrary.ȱȱ
Theȱprototypeȱforȱtheȱlibraryȱstrlenȱis:ȱ
ȱ
size_t
CAUTION!
strlen( char const *string );
ȱ
Noteȱthatȱstrlenȱreturnsȱaȱvalueȱofȱtypeȱsize_t.ȱThisȱtypeȱisȱdefinedȱinȱtheȱincludeȱfileȱ
stddef.hȱ andȱ isȱ anȱ unsignedȱ integerȱ type.ȱ Usingȱ unsignedȱ valuesȱ inȱ expressionsȱ canȱ
leadȱ toȱ unexpectedȱ results.ȱ Forȱ example,ȱ theȱ followingȱ twoȱ statementsȱ appearȱ toȱ beȱ
equivalent,ȱ
ȱ
if( strlen( x ) >= strlen( y ) ) ...
if( strlen( x ) – strlen( y ) >= 0 ) ...
ȱ
butȱ theyȱ areȱ not.ȱ Theȱ firstȱ worksȱ asȱ youȱ wouldȱ expect,ȱ butȱ theȱ secondȱ oneȱ isȱ alwaysȱ
true.ȱ Theȱ resultȱ ofȱ strlenȱ isȱ unsigned,ȱ soȱ theȱ expressionȱ onȱ theȱ leftȱ ofȱ theȱ >=ȱ isȱ
unsigned,ȱandȱunsignedȱvaluesȱcanȱneverȱbeȱnegative.ȱ
ȱ
ȱ
ȱ
/*
** Compute the length of the string argument.
*/
#include <stddef.h>
size_t
strlen( char const *string )
{
int length;
for( length = 0; *string++ != '\0'; )
length += 1;
return length;
}
ȱ
Programȱ9.1ȱȱStringȱlengthȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱȱstrlen.cȱ
Download at http://www.pin5i.com/
9.3 Unrestricted String Functions
CAUTION!
245
Expressionsȱ containingȱ bothȱ signedȱ andȱ unsignedȱ valuesȱ canȱ alsoȱ produceȱ strangeȱ
results.ȱ Theȱ followingȱ statementsȱ areȱ notȱ equivalentȱ forȱ theȱ sameȱ reasonȱ asȱ theȱ
previousȱpair.ȱ
ȱ
if( strlen( x ) >= 10 ) ...
if( strlen( x ) - 10 >= 0 ) ...
TIP
ȱ
Castingȱtheȱvalueȱreturnedȱbyȱstrlenȱtoȱanȱintȱeliminatesȱthisȱproblem.ȱ
ȱ
Itȱ isȱ temptingȱ toȱ writeȱ yourȱ ownȱ strlenȱ function,ȱ makingȱ judiciousȱ useȱ ofȱ registerȱ
declarationsȱ andȱ cleverȱ tricksȱ toȱ makeȱ itȱ fasterȱ thanȱ theȱ libraryȱ function.ȱ Itȱ rarelyȱ
works.ȱ Theȱ standardȱ libraryȱ functionsȱ areȱ sometimesȱ implementedȱ inȱ assemblyȱ
languageȱ inȱ orderȱ toȱ exploitȱ theȱ speedȱ ofȱ specialȱ stringȱ manipulationȱ instructionsȱ
providedȱbyȱcertainȱmachines.ȱȱEvenȱonȱmachinesȱwithoutȱsuchȱinstructions,ȱyourȱtimeȱ
isȱ betterȱ spentȱ concentratingȱ onȱ theȱ algorithmsȱ forȱ otherȱ partsȱ ofȱ yourȱ program.ȱȱ
Findingȱ aȱ betterȱ algorithmȱ isȱ moreȱ effectiveȱ thanȱ tuningȱ aȱ badȱ one,ȱ andȱ itȱ isȱ moreȱ
efficientȱtoȱreuseȱexistingȱsoftwareȱthanȱtoȱreinventȱit.ȱ
ȱ
ȱ
ȱ
9.3 Unrestricted String Functions
ȱ
Theȱ mostȱ commonlyȱ usedȱ stringȱ functionsȱ areȱ Ȉunrestricted,Ȉȱ meaningȱ thatȱ theyȱ
determineȱ theȱ lengthȱ ofȱ theirȱ stringȱ argumentsȱ solelyȱ byȱ lookingȱ forȱ theȱ terminatingȱ
NULȱbyte.ȱWhenȱusingȱtheseȱfunctions,ȱitȱisȱtheȱprogrammerȇsȱresponsibilityȱtoȱmakeȱ
sureȱthatȱtheȱresultingȱstringȱdoesȱnotȱoverflowȱtheȱmemoryȱinȱwhichȱitȱisȱsupposedȱtoȱ
fit.ȱThisȱproblemȱisȱdescribedȱinȱmoreȱdetailȱforȱeachȱofȱtheȱfunctionsȱdiscussedȱinȱthisȱ
section.ȱ
ȱ
ȱ
ȱ
9.3.1 Copying Strings
ȱ
Stringsȱareȱcopiedȱusingȱstrcpyȱwhoseȱprototypeȱisȱshownȱbelow.ȱ
ȱ
ȱ
char *strcpy( char *dst, char const *src );
ȱ
ThisȱfunctionȱcopiesȱtheȱstringȱfromȱtheȱsrcȱargumentȱintoȱtheȱdstȱargumentȱIfȱtheȱsrcȱ
andȱ dstȱargumentsȱoverlap,ȱtheȱresultȱisȱundefined.ȱ Becauseȱitȱisȱmodified,ȱ dstȱmustȱ
beȱ aȱ characterȱ arrayȱ orȱ aȱ pointerȱ toȱ anȱ arrayȱ orȱ toȱ dynamicallyȱ allocatedȱ memory.ȱ Aȱ
stringȱ literalȱ mayȱ notȱ beȱ used.ȱ Theȱ functionȱ returnsȱ aȱ value,ȱ whichȱ isȱ describedȱ inȱ
Sectionȱ9.3.3.ȱ
Theȱpreviousȱcontentsȱofȱtheȱdestinationȱargumentȱareȱoverwrittenȱandȱareȱlost.ȱ
Evenȱifȱtheȱnewȱstringȱisȱshorterȱthanȱtheȱoldȱcontentsȱofȱdst,ȱtheȱlastȱcharactersȱofȱtheȱȱ
Download at http://www.pin5i.com/
246
Chapter 9 Strings, Characters, and Bytes
previousȱstringȱareȱeffectivelyȱerasedȱbecauseȱtheyȱappearȱafterȱtheȱterminatingȱNULȱ
byteȱofȱtheȱnewȱstring.ȱ
Considerȱthisȱexample:ȱ
char message[] = "Original message";
...
if( ... )
strcpy( mesaage, "Different" );
Ifȱtheȱconditionȱisȱtrueȱandȱtheȱcopyȱisȱperformed,ȱtheȱarrayȱwillȱcontainȱtheȱfollowing:ȱ
ȱ
TheȱcharactersȱafterȱtheȱfirstȱNULȱbyteȱareȱneverȱaccessedȱbyȱtheȱstringȱfunctionsȱandȱ
are,ȱforȱallȱpracticalȱpurposes,ȱlost.ȱ
ȱ
ȇDȇȱ ȇiȇȱ
CAUTION!
ȇfȇȱ
ȇfȇȱ
ȇeȇȱ ȇrȇȱ ȇeȇȱ ȇnȇȱ ȇtȇȱ
0ȱ
ȇeȇȱ ȇsȇȱ
ȇsȇȱ ȇaȇȱ ȇgȇȱ ȇeȇȱ
0ȱ
ȱ
Itȱisȱupȱtoȱtheȱprogrammerȱtoȱmakeȱsureȱthatȱtheȱdestinationȱarrayȱisȱlargeȱenoughȱtoȱ
holdȱ theȱ string.ȱ Ifȱ theȱ stringȱ isȱ longerȱ thanȱ theȱ array,ȱ theȱ excessȱ charactersȱ willȱ beȱ
copiedȱ anywayȱ andȱ willȱ overwriteȱ whateverȱ valuesȱ happenȱ toȱ beȱ afterȱ theȱ arrayȱ inȱ
memory,ȱȱ strcpyȱisȱunableȱtoȱavoidȱthisȱproblemȱbecauseȱitȱcannotȱdetermineȱtheȱsizeȱ
ofȱtheȱdestinationȱarray.ȱForȱexample:ȱ
ȱ
ȱ
char message[] = "Original message";
...
strcpy( message, "A different message" );
ȱ
Theȱsecondȱstringȱisȱtooȱlongȱtoȱfitȱinȱtheȱarray,ȱsoȱtheȱstrcpyȱwillȱrunȱoffȱtheȱendȱofȱtheȱ
arrayȱandȱoverwriteȱwhateverȱvariablesȱhappenȱtoȱfollowȱitȱinȱmemory.ȱYouȱcanȱavoidȱ
aȱ lotȱ ofȱ debuggingȱ byȱ makingȱ sureȱ thatȱ theȱ destinationȱ argumentȱ isȱ largeȱ enoughȱ
beforeȱcallingȱstrcpy.ȱ
ȱ
ȱ
ȱ
9.3.2 Concatenating Strings
ȱ
Toȱappendȱ(concatenate)ȱoneȱstringȱtoȱtheȱendȱofȱanother,ȱstrcatȱisȱusedȱprototypeȱis:ȱ
ȱ
ȱ
char *strcat( char *dst, char const *src );
ȱ
strcatȱrequiresȱthatȱ dstȱalreadyȱcontainȱaȱ(possiblyȱempty)ȱstring.ȱȱItȱfindsȱtheȱendȱofȱ
thisȱstring,ȱandȱappendsȱtoȱitȱaȱcopyȱofȱtheȱstringȱfromȱ src.ȱIfȱtheȱ srcȱandȱ dstȱstringsȱ
overlap,ȱtheȱresultȱisȱundefined.ȱ
Download at http://www.pin5i.com/
9.3 Unrestricted String Functions
247
Theȱfollowingȱexampleȱshowsȱaȱcommonȱuseȱofȱthisȱfunction.ȱ
ȱ
strcpy( message, "Hello " );
strcat( message, customer_name );
strcat( message, ", how are you?" );
ȱ
Eachȱ ofȱ theȱ argumentsȱ toȱ strcatȱ areȱ appendedȱ toȱ theȱ stringȱ alreadyȱ inȱ message.ȱ Theȱ
resultȱisȱaȱstringȱsuchȱasȱthisȱone:ȱ
ȱ
Hello Jim, how are you?
ȱ
Onceȱagain,ȱtheȱprogrammerȱmustȱensureȱthatȱthereȱisȱenoughȱspaceȱremainingȱinȱtheȱ
destinationȱarrayȱtoȱholdȱtheȱentireȱsourceȱstring.ȱButȱthisȱtimeȱitȱisȱincorrectȱtoȱsimplyȱ
compareȱ theȱ lengthȱ ofȱ theȱ sourceȱ stringȱ withȱ theȱ sizeȱ ofȱ theȱ array.ȱ ȱ Youȱ mustȱ alsoȱ
accountȱforȱtheȱlengthȱofȱdieȱexistingȱstring.ȱ
ȱ
ȱ
ȱ
9.3.3 Function Return Value
ȱ
Bothȱstrcpyȱandȱ strcatȱreturnȱaȱcopyȱofȱtheirȱfirstȱargument,ȱwhichȱisȱaȱpointerȱtoȱtheȱ
destinationȱ array.ȱ Becauseȱ ofȱ thisȱ value,ȱ youȱ canȱ nestȱ callsȱ toȱ theseȱ functions,ȱ asȱ
illustratedȱinȱtheȱfollowingȱexample.ȱ
ȱ
strcat( strcpy( dst, a ), b );
ȱ
ȱ
Theȱstrcpyȱisȱperformedȱfirst.ȱItȱcopiesȱtheȱstringȱfromȱaȱintoȱdetȱandȱreturnsȱtheȱvalueȱ
dst.ȱ Theȱ returnedȱ valueȱ becomesȱ theȱ firstȱ argumentȱ toȱ strcat,ȱ whichȱ appendsȱ theȱ
stringȱinȱbȱtoȱdst.ȱ
Thisȱnestedȱstyleȱdoesȱnotȱhaveȱaȱfunctionalȱadvantageȱoverȱtheȱmoreȱreadableȱ
ȱ
strcpy( dst, a );
strcpy( dst, b );
ȱ
Indeed,ȱtheȱvaluesȱreturnedȱbyȱtheȱvastȱmajorityȱofȱcallsȱtoȱtheseȱfunctionsȱareȱsimplyȱ
ignored.ȱ
ȱ
ȱ
ȱ
9.3.4 String Comparisons
ȱ
Comparingȱtwoȱstringsȱinvolvesȱcomparingȱtheȱcorrespondingȱcharactersȱinȱthem,ȱoneȱ
byȱone,ȱuntilȱaȱmismatchȱisȱfound.ȱTheȱstringȱfromȱwhichȱtheȱȈlowerȈȱcharacterȱ(thatȱis,ȱ
theȱcharacterȱnearerȱtheȱbeginningȱofȱtheȱcharacterȱ set)ȱcameȱisȱsaidȱtoȱ beȱ ȈlessȱthanȈȱ
theȱ otherȱ string.ȱ Ifȱ oneȱ stringȱ isȱ aȱ prefixȱ ofȱ theȱ other,ȱ itȱ willȱ beȱ Ȉlessȱ thanȈȱ theȱ otherȱ
stringȱbecauseȱitsȱterminatingȱNULȱisȱreachedȱfirst.ȱCalledȱaȱlexicographicȱcomparison,ȱ
Download at http://www.pin5i.com/
248
Chapter 9 Strings, Characters, and Bytes
thisȱ processȱ givesȱ theȱ sameȱ resultȱ asȱ anȱ everydayȱ alphabeticȱ orderingȱ forȱ stringsȱ
containingȱonlyȱuppercaseȱorȱonlyȱlowercaseȱcharacters.ȱ
Theȱlibraryȱfunctionȱstrcmpȱcomparesȱtwoȱstringȱarguments,ȱȱitsȱprototypeȱis:ȱ
ȱ
int
CAUTION!
strcmp( char const *s1, char const *s2 );
ȱ
strcmpȱreturnsȱaȱvalueȱlessȱthanȱzeroȱifȱs1ȱisȱlessȱthanȱs2;ȱaȱvalueȱgreaterȱthanȱzeroȱifȱs1ȱ
isȱgreaterȱthanȱs2;ȱandȱzeroȱifȱtheȱtwoȱstringsȱareȱequal.ȱ
ȱ
Beginnersȱoftenȱwriteȱ
ȱ
if( strcmp( a, b ) )
CAUTION!
CAUTION!
ȱ
andȱassumeȱthatȱtheȱresultȱreturnedȱwillȱbeȱtrueȱifȱtheȱstringsȱareȱequal.ȱTheȱresultȱisȱ
justȱ theȱ oppositeȱ though,ȱ becauseȱ zeroȱ (false)ȱ isȱ returnedȱ inȱ thisȱ case.ȱ However,ȱ itȱ isȱ
badȱstyleȱtoȱtestȱthisȱvalueȱasȱifȱitȱwereȱbooleanȱbecauseȱitȱhasȱthreeȱdistinctȱoutcomes:ȱ
less,ȱequal,ȱandȱgreater.ȱComparingȱtheȱvalueȱtoȱzeroȱisȱthereforeȱpreferred.ȱ
ȱ
Noteȱ thatȱ theȱ Standardȱ doesȱ notȱ specifyȱ theȱ specificȱ valuesȱ usedȱ toȱ indicateȱ
inequalities.ȱItȱonlyȱstatesȱthatȱtheȱvalueȱreturnedȱbeȱgreaterȱthanȱzeroȱifȱtheȱfirstȱstringȱ
isȱ greaterȱ thanȱ theȱ secondȱ andȱ beȱ lessȱ thanȱ zeroȱ ifȱ theȱ firstȱ stringȱ isȱ lessȱ thanȱ theȱ
second.ȱAȱcommonȱmistakeȱisȱtoȱassumeȱthatȱtheȱvaluesȱ1ȱandȱȬ1ȱwillȱbeȱreturned,ȱbutȱ
thisȱassumptionȱisȱnotȱalwaysȱcorrect.ȱ
ȱ
Becauseȱ strcmpȱ doesȱ notȱ changeȱ eitherȱ ofȱ itsȱ arguments,ȱ thereȱ isnȇtȱ anyȱ dangerȱ ofȱ
overflowingȱ anȱ array.ȱ However,ȱ asȱ withȱ theȱ otherȱ unrestrictedȱ stringȱ functions,ȱ theȱ
stringȱ argumentsȱ mustȱ beȱ NULȱ terminated.ȱ Ifȱ theyȱ areȱ not,ȱ strcmpȱ willȱ continueȱ
comparingȱbytesȱbeyondȱtheȱendȱofȱtheȱdata,ȱandȱtheȱresultȱwillȱhaveȱnoȱmeaning.ȱ
ȱ
ȱ
ȱ
9.4 Length-Restricted String Functions
ȱ
Theȱ libraryȱ includesȱ severalȱ functionsȱ thatȱ dealȱ withȱ stringsȱ inȱ aȱ differentȱ way.ȱ Thisȱ
groupȱofȱfunctionsȱtakesȱanȱexplicitȱlengthȱargumentȱthatȱlimitsȱhowȱmanyȱcharactersȱ
canȱ beȱ copiedȱ orȱ compared.ȱ Theseȱ functionsȱ provideȱ anȱ easyȱ mechanismȱ toȱ preventȱ
unexpectedlyȱlongȱstringsȱfromȱoverflowingȱtheirȱdestinations.ȱ
Theȱ prototypesȱ forȱ theseȱ functionsȱ areȱ shownȱ onȱ theȱ nextȱ page.ȱ Likeȱ theirȱ
unrestrictedȱcousins,ȱtheȱresultsȱfromȱ strncpyȱandȱ strncatȱareȱundefinedȱifȱtheȱsourceȱ
andȱdestinationȱargumentsȱoverlap.ȱ
ȱ
Download at http://www.pin5i.com/
9.4 Length-Restricted String Functions
char
char
int
CAUTION!
CAUTION!
249
*strncpy( char *dst, char const *src, size_t len );
*strncat( char *dst, char const *src, size_t len );
strncmp( char const *s1, char const *s2, size_t len );
ȱ
Likeȱ scrcpy,ȱ strncpyȱcopiesȱcharactersȱfromȱtheȱsourceȱstringȱtoȱtheȱdestinationȱarray.ȱ
However,ȱitȱalwaysȱwritesȱexactlyȱ lenȱcharactersȱtoȱ dst.ȱIfȱ strlen( src )ȱisȱlessȱthanȱ
len,ȱthenȱdstȱisȱpaddedȱtoȱaȱlengthȱofȱ lenȱwithȱadditionalȱNULȱcharacters.ȱȱIfȱ strlen(
src )ȱisȱgreaterȱthanȱorȱequalȱtoȱ len,ȱthenȱonlyȱ lenȱcharactersȱwillȱbeȱwrittenȱtoȱ dst,ȱ
andȱtheȱresultȱwillȱnotȱbeȱNULȬterminated!ȱ
ȱ
Theȱ resultȱ ofȱ aȱ callȱ toȱ strncpyȱ mightȱ notȱ beȱ aȱ string,ȱ becauseȱ stringsȱ mustȱ beȱ
terminatedȱwithȱaȱNULȱbyte.ȱWhatȱhappensȱifȱanȱunterminatedȱsequenceȱofȱcharactersȱ
isȱ usedȱ whereȱ aȱ stringȱ isȱ required,ȱ forȱ example,ȱ asȱ anȱ argumentȱ toȱ strlen?ȱ Theȱ
functionȱ willȱ beȱ unableȱ toȱ tellȱ thatȱ theȱ NULȱ isȱ missing,ȱ soȱ itȱ willȱ continueȱ looking,ȱ
characterȱ byȱ character,ȱ untilȱ itȱ findsȱ one.ȱ Itȱ mightȱ notȱ findȱ oneȱ untilȱ hundredsȱ ofȱ
charactersȱ later,ȱ andȱ theȱ valueȱ returnedȱ byȱ strlenȱ willȱ essentiallyȱ beȱ aȱ randomȱ
number.ȱ Or,ȱ theȱ programȱ mightȱ crashȱ tryingȱ toȱ accessȱ memoryȱ beyondȱ whatȱ wasȱ
allocatedȱtoȱitȱ
ȱ
Thisȱproblemȱonlyȱoccursȱwhenȱyouȱcreateȱstringsȱwithȱtheȱstrncpyȱfunction,ȱandȱthenȱ
eitherȱ useȱ themȱ withȱ theȱ str---ȱ functionsȱ orȱ printȱ themȱ withȱ theȱ %sȱ formatȱ codeȱ ofȱ
printf.ȱBeforeȱusingȱtheȱunrestrictedȱfunctions,ȱyouȱmustȱfirstȱensureȱthatȱtheȱstringȱisȱ
actuallyȱNULȬterminated.ȱForȱexample,ȱconsiderȱthisȱcodeȱfragment:ȱ
ȱ
char buffer[BSIZE];
...
strncpy( buffer, name, BSIZE );
buffer[BSIZE – 1] = '\0';
ȱ
Ifȱtheȱcontentsȱofȱnameȱfitȱintoȱbuffer,ȱtheȱassignmentȱhasȱnoȱeffect.ȱIfȱnameȱisȱtooȱlong,ȱ
though,ȱ theȱ assignmentȱ ensuresȱ thatȱ theȱ stringȱ inȱ bufferȱ isȱ properlyȱ terminated.ȱ
Subsequentȱ callsȱ toȱ strlenȱ orȱ otherȱ unrestrictedȱ stringȱ functionsȱ onȱ thisȱ arrayȱ willȱ
workȱproperly.ȱ
Althoughȱ strncatȱisȱalsoȱaȱlengthȬrestrictedȱfunction,ȱitȱworksȱdifferentlyȱthanȱ
strncpy.ȱ Itȱ appendsȱ upȱ toȱ lenȱ charactersȱ fromȱ srcȱ toȱ theȱ destinationȱ string.ȱ Butȱ
strncatȱalwaysȱappendsȱaȱNULȱcharacterȱtoȱtheȱendȱofȱtheȱresult,ȱandȱitȱdoesȱnotȱpadȱ
theȱ resultȱ withȱ NULsȱ likeȱ strncpy.ȱ Noteȱ thatȱ theȱ lengthȱ ofȱ theȱ existingȱ stringȱ inȱ theȱ
destinationȱarrayȱisȱnotȱaccountedȱforȱbyȱstrncat.ȱItȱcanȱwriteȱupȱtoȱlenȱcharactersȱplusȱ
aȱ terminatingȱ NULȱ byteȱ regardlessȱ ofȱ whetherȱ theȱ initialȱ contentsȱ ofȱ theȱ destinationȱ
argumentȱleaveȱenoughȱroomȱforȱthem.ȱ
Download at http://www.pin5i.com/
250
Chapter 9 Strings, Characters, and Bytes
Finally,ȱ strncmpȱcomparesȱupȱtoȱ lenȱcharactersȱofȱtwoȱstrings.ȱIfȱtheȱstringsȱareȱ
unequalȱ beforeȱ orȱ atȱ theȱ lenȇthȱ character,ȱ theȱ comparisonȱ stopsȱ asȱ itȱ wouldȱ withȱ
strcmp.ȱIfȱtheȱfirstȱlenȱcharactersȱofȱtheȱstringsȱareȱequal,ȱvalueȱzeroȱisȱreturned.ȱ
ȱ
ȱ
ȱ
9.5 Basic String Searching
ȱ
Thereȱareȱmanyȱfunctionsȱinȱtheȱlibraryȱthatȱsearchȱstringsȱinȱvariousȱways.ȱThisȱwideȱ
varietyȱofȱtoolsȱgivesȱtheȱCȱprogrammerȱgreatȱflexibility.ȱ
ȱ
ȱ
ȱ
9.5.1 Finding a Character
ȱ
Theȱeasiestȱwayȱtoȱlocateȱaȱspecificȱcharacterȱinȱaȱstringȱisȱwithȱtheȱstrchrȱandȱstrrchrȱ
functions,ȱwhoseȱprototypesȱare:ȱ
ȱ
char
char
*strchr( char const *str, int ch );
*strrchr( char const *str, int char );
ȱ
Noteȱ thatȱ theȱ secondȱ argumentȱ isȱ anȱ integer.ȱ Itȱ containsȱ aȱ characterȱ value,ȱ however.ȱ
strchrȱsearchesȱ theȱstringȱ strȱtoȱ findȱtheȱfirstȱoccurrenceȱ ofȱtheȱcharacterȱ ch.ȱ Thenȱ aȱ
pointerȱtoȱthisȱpositionȱisȱreturned.ȱIfȱtheȱcharacterȱdoesȱnotȱappearȱatȱallȱinȱtheȱstring,ȱ
aȱ NULLȱ pointerȱ isȱ returned.ȱ strrchrȱ worksȱ exactlyȱ theȱ sameȱ exceptȱ thatȱ itȱ returnsȱ aȱ
pointerȱtoȱtheȱlastȱ(rightmost)ȱoccurrenceȱofȱtheȱcharacter.ȱ
Hereȱisȱanȱexample;ȱ
ȱ
char
char
string[20] = "Hello there, honey.";
*ans;
ans = strchr( string, 'h' );
ȱ
ansȱwillȱgetȱtheȱvalueȱ string + 7ȱbecauseȱtheȱfirstȱ 'h'ȱappearsȱinȱthisȱposition.ȱNoteȱ
thatȱcaseȱisȱsignificant.ȱ
ȱ
ȱ
ȱ
9.5.2 Finding Any of Several Characters
ȱ
Theȱstrpbrkȱfunctionȱisȱmoreȱgeneral.ȱInsteadȱofȱsearchingȱforȱoneȱspecificȱcharacter,ȱitȱ
looksȱforȱtheȱfirstȱoccurrenceȱofȱanyȱofȱgroupȱofȱcharacters.ȱItsȱprototypeȱis:ȱ
ȱ
Download at http://www.pin5i.com/
9.6 Advanced String Searching
char
251
*strpbrk( char const *str, char const *group );
ȱ
Thisȱ functionȱ returnsȱ aȱ pointerȱ toȱ theȱ firstȱ characterȱ inȱ strȱ thatȱ matchesȱ anyȱ ofȱ theȱ
charactersȱinȱgroup,ȱorȱNULLȱifȱnoneȱmatched.ȱ
Inȱtheȱfollowingȱcodeȱfragment,ȱ
ȱ
char
char
string[20] = "Hello there, honey.";
*ans;
ans = strpbrk( string, "aeiou" );
ȱ
ansȱwillȱgetȱtheȱvalueȱ string + 1ȱbecauseȱthisȱpositionȱisȱtheȱfirstȱthatȱcontainsȱanyȱofȱ
theȱcharactersȱinȱtheȱsecondȱargument.ȱȱOnceȱagain,ȱcaseȱisȱsignificant.ȱ
ȱ
ȱ
ȱ
9.5.3 Finding a Substring
ȱ
Toȱlocateȱaȱsubstring,ȱstrstrȱisȱused.ȱItsȱprototypeȱis:ȱ
ȱ
ȱ
char *strstr( char const *s1, char const *s2 );
ȱ
Thisȱfunctionȱfindsȱtheȱfirstȱplaceȱinȱ s1ȱwhereȱtheȱentireȱstringȱ s2ȱbeginsȱandȱreturnsȱaȱ
pointerȱ toȱ thisȱ location.ȱ Ifȱ s2ȱ doesȱ notȱ appearȱ inȱ itsȱ entiretyȱ anywhereȱ inȱ s1,ȱ thenȱ
NULLȱisȱreturned.ȱIfȱtheȱsecondȱargumentȱisȱanȱemptyȱstring,ȱthenȱs1ȱisȱreturned.ȱ
Theȱ standardȱ libraryȱ includesȱ neitherȱ aȱ strrstrȱ norȱ aȱ strrpbrkȱ function,ȱ butȱ
theyȱ areȱ easyȱ toȱ implementȱ ifȱ youȱ needȱ them.ȱ Programȱ 9.2ȱ showsȱ oneȱ wayȱ ofȱ
implementingȱstrrstr.ȱTheȱsameȱtechniqueȱcouldȱbeȱusedȱforȱstrrpbrk.ȱ
ȱ
ȱ
ȱ
9.6 Advanced String Searching
ȱ
Theȱ nextȱ groupȱ ofȱ functionsȱ simplifyȱ theȱ locationȱ andȱ extractionȱ ofȱ individualȱ
substringsȱfromȱaȱstring.ȱ
ȱ
ȱ
ȱ
9.6.1 Finding String Prefixes
ȱ
Theȱ strspnȱandȱ strcspnȱfunctionsȱcountȱcharactersȱatȱtheȱbeginningȱofȱaȱstring.ȱTheirȱ
prototypesȱareȱshownȱatȱtheȱtopȱofȱpageȱ253.ȱ
Download at http://www.pin5i.com/
252
Chapter 9 Strings, Characters, and Bytes
ȱ
/*
** Look in the string s1 for the rightmost occurrence of the string
** s2, and return a pointer to where it begins.
*/
#include <string.h>
char *
my_strrstr( char const *s1, char const *s2 )
{
register char
*last;
register char
*current;
/*
** Initialize pointer for the last match we've found.
*/
last = NULL;
/*
** Search only if the second string is not empty. If s2 is
** empty, return NULL.
*/
if( *s2 != '\0' ){
/*
** Find the first place where s2 appears in s1.
*/
current = strstr( s1, s2 );
/*
** Each time we find the string, save the pointer to
** where it begins. Then look after the string for
** another occurrence.
*/
while( current != NULL ){
last = current;
current = strstr( last + 1, s2 );
}
}
/*
** Return pointer to the last occurrence we found.
*/
return last;
}
Programȱ9.2ȱȱFindȱrightmostȱoccurrenceȱofȱaȱsubstringȱȱ
ȱ
ȱ
ȱ
ȱ
mstrrstr.cȱ
Download at http://www.pin5i.com/
9.6 Advanced String Searching
253
size_t strspn( char const *str, char const *group );
size_t strcspn( char const *str, char const *group );
ȱ
Theȱ groupȱ stringȱ specifiesȱ oneȱ orȱ moreȱ characters.ȱ strspnȱ returnsȱ theȱ numberȱ ofȱ
charactersȱatȱtheȱbeginningȱofȱ strȱthatȱmatchȱanyȱofȱtheseȱcharacters.ȱForȱexample,ȱifȱ
groupȱcontainedȱtheȱwhitespaceȱcharactersȱspace,ȱtab,ȱandȱsoȱforth,ȱthisȱfunctionȱwouldȱ
returnȱ theȱ numberȱ ofȱ whitespaceȱ charactersȱ foundȱ atȱ theȱ beginningȱ ofȱ str.ȱ Theȱ nextȱ
characterȱofȱstrȱwouldȱbeȱtheȱfirstȱnonȬwhitespaceȱcharacter.ȱ
Considerȱthisȱexample:ȱ
ȱ
int
char
len1, len2;
buffer[] = "25,142,330,Smith,J,239-4123";
len1 = strspn( buffer, "0123456789" );
len2 = strspn( buffer, ",0123456789" );
ȱ
Ofȱ course,ȱ theȱ bufferȱ wouldȱ notȱ normallyȱ beȱ initializedȱ inȱ thisȱ manner;ȱ itȱ wouldȱ
containȱ dataȱ readȱ inȱ atȱ runȱ time.ȱ Butȱ withȱ thisȱ valueȱ inȱ theȱ buffer,ȱ theȱ variableȱ len1ȱ
wouldȱbeȱsetȱtoȱtwo,ȱandȱtheȱvariableȱlen2ȱwouldȱbeȱsetȱtoȱ11.ȱTheȱfollowingȱcodeȱwillȱ
computeȱaȱpointerȱtoȱtheȱfirstȱnonȬwhitespaceȱcharacterȱinȱaȱstring.ȱ
ȱ
ȱ
ptr = buffer + strspn( buffer, " \n\r\f\t\v" );
ȱ
strcspnȱ worksȱ similarlyȱ exceptȱ thatȱ onlyȱ charactersȱ thatȱ areȱ notȱ inȱ groupȱ areȱ
counted.ȱTheȱ cȱinȱtheȱnameȱ strcspnȱcomesȱfromȱtheȱnotionȱthatȱtheȱcharacterȱgroupȱisȱ
complemented,ȱthatȱis,ȱexchangedȱforȱallȱofȱtheȱcharactersȱitȱdidȱnotȱoriginallyȱcontain.ȱIfȱ
youȱusedȱtheȱstringȱȈ \n\r\f\t\vȈȱforȱtheȱgroupȱargument,ȱthisȱfunctionȱwouldȱreturnȱ
theȱnumberȱofȱnonȬwhitespaceȱcharactersȱfoundȱatȱtheȱbeginningȱofȱtheȱfirstȱargument.ȱ
ȱ
ȱ
ȱ
9.6.2 Finding Tokens
ȱ
Aȱstringȱoftenȱcontainsȱseveralȱindividualȱpartsȱthatȱareȱsomehowȱseparatedȱfromȱeachȱ
other.ȱToȱprocessȱtheseȱpartsȱoneȱatȱaȱtime,ȱyouȱmustȱfirstȱextractȱthemȱfromȱtheȱstring.ȱ
ȱ
Thisȱtaskȱisȱexactlyȱwhatȱtheȱstrtokȱfunctionȱaccomplishes.ȱItȱisolatesȱindividualȱ
parts,ȱcalledȱtokens,ȱfromȱaȱstringȱandȱdiscardsȱtheȱseparators.ȱItsȱprototypeȱis:ȱ
Download at http://www.pin5i.com/
254
Chapter 9 Strings, Characters, and Bytes
char
*strtok( char *str, char const *sep );
ȱ
CAUTION!
Theȱ sepȱ argumentȱ isȱ aȱ stringȱ thatȱ definesȱ theȱ setȱ ofȱ charactersȱ thatȱ areȱ usedȱ asȱ
separators.ȱ Theȱ firstȱ argumentȱ specifiesȱ aȱ stringȱ thatȱ isȱ assumedȱ toȱ containȱ zeroȱ orȱ
moreȱ tokensȱ separatedȱ fromȱ oneȱ anotherȱ byȱ oneȱ orȱ moreȱ charactersȱ fromȱ theȱ sepȱ
string. strtokȱfindsȱandȱNULȬterminatesȱtheȱnextȱtokenȱinȱ str,ȱandȱreturnsȱaȱpointerȱ
toȱtheȱtoken.ȱ
ȱ
Whileȱitȱisȱdoingȱitsȱwork,ȱ strtokȱmodifiesȱtheȱstringȱthatȱitȱisȱprocessing.ȱIfȱtheȱstringȱ
mustȱnotȱbeȱchanged,ȱcopyȱitȱandȱuseȱstrtokȱonȱtheȱcopy.ȱ
Ifȱtheȱfirstȱargumentȱtoȱ strtokȱisȱnotȱNULL,ȱtheȱfunctionȱfindsȱtheȱfirstȱtokenȱinȱ
theȱstring,ȱ strtokȱalsoȱsavesȱitsȱpositionȱinȱtheȱstring.ȱIfȱtheȱfirstȱargumentȱtoȱ strtokȱisȱ
NULL,ȱtheȱfunctionȱusesȱtheȱsavedȱpositionȱtoȱfindȱtheȱnextȱtokenȱfromȱtheȱsameȱstringȱ
asȱ before.ȱ strtokȱ returnsȱ aȱ NULLȱ pointerȱ whenȱ thereȱ arenȇtȱ anyȱ moreȱ tokensȱ inȱ theȱ
string.ȱTypically,ȱaȱpointerȱtoȱaȱstringȱisȱpassedȱonȱtheȱfirstȱcallȱtoȱ strtok.ȱTheȱfunctionȱ
isȱthenȱcalledȱrepeatedlyȱwithȱNULLȱfirstȱargumentȱuntilȱitȱreturnsȱNULL.ȱ
Programȱ9.3ȱisȱaȱshortȱexample.ȱThisȱfunctionȱextractsȱtokensȱfromȱitsȱargumentȱ
andȱ printsȱ themȱ oneȱ perȱ line.ȱ Theȱ tokensȱ areȱ separatedȱ byȱ whiteȱ space.ȱ Doȱ notȱ beȱ
confusedȱ byȱ theȱ appearanceȱ ofȱ theȱ forȱ statement.ȱ Itȱ wasȱ brokenȱ ontoȱ threeȱ linesȱ
becauseȱofȱitsȱlength.ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Extract whitespace-delimited tokens from a character array and
** print them one per line.
*/
#include <stdio.h>
#include <string.h>
void
print_tokens( char *line )
{
static
char whitespace[] = " \t\f\r\v\n";
char
*token;
for( token = strtok( line, whitespace );
token != NULL;
token = strtok( NULL, whitespace ) )
printf( "Next token is %s\n", token );
}
ȱ
Programȱ9.3ȱȱExtractȱtokensȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱtoken.c
Download at http://www.pin5i.com/
9.8 Character Operations
CAUTION!
255
Ifȱ youȱ wish,ȱ youȱ mayȱ useȱ differentȱ separatorȱ setsȱ inȱ eachȱ callȱ toȱ strtok.ȱ Thisȱ
techniqueȱisȱhandyȱwhenȱdifferentȱpartsȱofȱaȱstringȱareȱseparatedȱbyȱdifferentȱgroupsȱ
ofȱcharacters.ȱ
ȱ
Becauseȱ strtokȱsavesȱlocalȱstateȱinformationȱaboutȱtheȱstringȱitȱisȱparsing,ȱyouȱcannotȱ
useȱ itȱ toȱ parseȱ twoȱ stringsȱ concurrently.ȱ Thus,ȱ Programȱ 9.3ȱ wouldȱ failȱ ifȱ theȱ bodyȱ ofȱ
theȱforȱloopȱcalledȱaȱfunctionȱthatȱalsoȱcalledȱstrtok.ȱ
ȱ
ȱ
ȱ
9.7 Error Messages
ȱ
Whenȱ callsȱ areȱ madeȱ toȱ theȱ operatingȱ systemȱ toȱ performȱ functions,ȱ suchȱ asȱ openingȱ
files,ȱerrorsȱthatȱoccurȱareȱreportedȱbyȱsettingȱanȱexternalȱintegerȱvariableȱcalledȱ errnoȱ
toȱanȱerrorȱcode.ȱTheȱ strerrorȱfunctionȱtakesȱoneȱofȱtheseȱerrorȱcodesȱasȱanȱargumentȱ
andȱreturnsȱaȱpointerȱtoȱaȱmessageȱdescribingȱtheȱerror.ȱTheȱprototypeȱofȱthisȱfunctionȱ
is:ȱ
ȱ
ȱ
char *strerror( in error_number );
ȱ
Inȱfact,ȱtheȱreturnedȱvalueȱoughtȱtoȱbeȱdeclaredȱconst,ȱbecauseȱyouȱareȱnotȱsupposedȱtoȱ
modifyȱit.ȱ
ȱ
ȱ
ȱ
9.8 Character Operations
ȱ
Theȱ libraryȱ includesȱ twoȱ groupsȱ ofȱ functionsȱ thatȱ operateȱ onȱ individualȱ characters,ȱ
prototypedȱinȱtheȱincludeȱfileȱctype.h.ȱTheȱfirstȱgroupȱisȱusedȱinȱclassifyingȱcharacters,ȱ
andȱtheȱsecondȱgroupȱtransformsȱthem.ȱ
ȱ
ȱ
ȱ
9.8.1 Character Classification
ȱ
Eachȱclassificationȱfunctionȱtakesȱanȱintegerȱargumentȱthatȱcontainsȱaȱcharacterȱvalue.ȱ
Theȱfunctionȱtestsȱtheȱcharacterȱandȱreturnsȱanȱintegerȱtrueȱorȱfalseȱvalue. 38 ȱTableȱ9.1ȱ
listsȱtheȱclassificationȱfunctionsȱandȱtheȱtestȱthatȱeachȱperforms.ȱ
38
ȱNoteȱthatȱtheȱStandardȱdoesȱnotȱspecifyȱanyȱparticularȱvalue,ȱsoȱanyȱnonzeroȱvalueȱmightȱbeȱreturned.ȱ
Download at http://www.pin5i.com/
Chapter 9 Strings, Characters, and Bytes
256
ȱ
Function
iscntrl
isspace
isdigit
isxdigit
islower
isupper
isalpha
isalnum
ispunct
isgraph
isprint
Returns True if its Argument is
anyȱcontrolȱcharacterȱ
aȱwhitespaceȱcharacter:ȱspaceȱ' ',ȱformȱfeedȱ'\f',ȱnewlineȱ'\n',ȱcarriageȱreturnȱlabȱ
'\t',ȱorȱverticalȱtabȱ'\v'.ȱ
aȱdecimalȱdigitȱ0ȱthroughȱ9.ȱ
aȱhexadecimalȱdigit,ȱwhichȱincludesȱtheȱdecimalȱdigitsȱandȱtheȱlettersȱaȱthroughȱfȱandȱ
AȱthroughȱF.ȱ
aȱlowercaseȱletterȱaȱthroughȱz.ȱ
anȱuppercaseȱletterȱAȱthroughȱZ.ȱ
anȱalphabeticȱcharacterȱaȱthroughȱzȱorȱAȱthroughȱZ.ȱ
anȱalphabeticȱorȱaȱnumericȱcharacterȱaȱthroughȱz,ȱAȱthroughȱZ,ȱorȱ0ȱthroughȱ9.ȱ
punctuation:ȱanyȱcharacterȱwithȱaȱgraphicȱ(printableȱsymbol)ȱassociatedȱwithȱitȱthatȱisȱ
notȱalphanumeric.ȱ
anyȱcharacterȱwithȱaȱgraphicȱassociatedȱwithȱit.ȱ
anyȱprintingȱcharacter,ȱwhichȱincludesȱtheȱgraphicȱcharactersȱandȱtheȱspaceȱcharacter.
ȱ
Tableȱ9.1ȱȱCharacterȱclassificationȱfunctionsȱ
ȱ
ȱ
ȱ
9.8.2 Character Transformation
ȱ
Theȱ transformationȱ functionsȱ translateȱ uppercaseȱ charactersȱ toȱ lowercaseȱ andȱ viceȱ
versa.ȱ
ȱ
ȱ
int
int
tolower( int ch );
toupper( int ch );
toupperȱ returnsȱ theȱ uppercaseȱ equivalentȱ ofȱ itsȱ argument,ȱ andȱ tolowerȱ returnsȱ theȱ
TIP
lowercaseȱ equivalentȱ ofȱ itsȱ argument.ȱ Ifȱ theȱ argumentȱ toȱ eitherȱ functionȱ isȱ notȱ aȱ
characterȱofȱtheȱappropriateȱcase,ȱthenȱitȱisȱreturnedȱunchanged.ȱ
ȱ
Testingȱ orȱ manipulatingȱ charactersȱ directlyȱ reducesȱ aȱ programȇsȱ portability.ȱ Forȱ
example,ȱconsiderȱtheȱfollowingȱstatement,ȱwhichȱattemptsȱtoȱtestȱwhetherȱchȱcontainsȱ
anȱuppercaseȱcharacter.ȱ
ȱ
if( ch >= 'A' && ch <= 'Z' )
ȱ
ȱ
ThisȱstatementȱworksȱonȱmachinesȱusingȱtheȱASCIIȱcharacterȱset,ȱbutȱfailsȱonȱmachinesȱ
usingȱtheȱEBCDICȱcharacterȱset.ȱOnȱtheȱotherȱhand,ȱtheȱstatementȱ
ȱ
if( isupper( ch ) )
ȱ
ȱ
willȱworkȱcorrectlyȱwithȱanyȱcharacterȱset.ȱ
Download at http://www.pin5i.com/
9.9 Memory Operations
257
9.9 Memory Operations
ȱ
Byȱdefinition,ȱaȱstringȱisȱterminatedȱwithȱaȱNULȱbyte,ȱsoȱstringsȱmayȱnotȱcontainȱanyȱ
NULs.ȱHowever,ȱitȱisȱnotȱuncommonȱforȱnonstringȱdataȱtoȱcontainȱzeros.ȱYouȱcannotȱ
useȱtheȱstringȱfractionsȱtoȱprocessȱthisȱkindȱofȱdataȱbecauseȱtheyȱwouldȱstopȱworkingȱ
whenȱtheyȱreachedȱtheȱfirstȱNUL.ȱ
Thereȱisȱaȱrelatedȱsetȱofȱfunctionsȱwhoseȱoperationsȱareȱsimilarȱtoȱsomeȱofȱtheȱ
stringȱ functions,ȱbutȱtheseȱfunctionsȱdealȱwithȱarbitraryȱsequencesȱofȱbytes.ȱ Hereȱ areȱ
theirȱprototypes.ȱ
ȱ
void
void
void
void
void
*memcpy( void *dst, void const *src, size_t length );
*memmove( void *dst, void const *src, size_t length );
*memcmp( void const *a, void const *b, size_t length );
*memchr( void const *a, int ch, size_t length );
*memset( void *a, int ch, size_t length );
ȱ
Eachȱprototypeȱincludesȱanȱexplicitȱargumentȱtoȱindicateȱhowȱmanyȱbytesȱtoȱprocess,ȱ
butȱunlikeȱtheȱstrn---ȱfunctions,ȱtheirȱoperationsȱdoȱnotȱstopȱifȱtheyȱencounterȱaȱNULȱ
byte.ȱ
memcpyȱcopiesȱlengthȱbytes,ȱbeginningȱatȱsrc,ȱintoȱtheȱmemoryȱbeginningȱatȱdst.ȱ
Youȱcanȱcopyȱanyȱtypeȱofȱvalueȱinȱthisȱmanner,ȱsoȱlongȱasȱtheȱthirdȱargumentȱspecifiesȱ
theȱlengthȱofȱtheȱvalueȱinȱbytes.ȱTheȱresultȱisȱundefinedȱifȱ srcȱandȱ dstȱoverlapȱinȱanyȱ
way.ȱ
Forȱexample:ȱ
char temp[SIZE], values[SIZE];
...
memcpy( temp, values, SIZE );
ȱ
copiesȱtheȱSIZEȱbytesȱfromȱtheȱarrayȱvaluesȱintoȱtheȱarrayȱtemp.ȱ
Butȱwhatȱifȱbothȱwereȱarraysȱofȱintegers?ȱThenȱ(heȱfollowingȱstatementȱwouldȱ
doȱtheȱjob:ȱ
memcpy( temp, values, sizeof( values ) );
ȱ
Noȱ castsȱ areȱ neededȱ onȱ theȱ firstȱ twoȱ argumentsȱ becauseȱ theȱ prototypeȱ callsȱ forȱ voidȱ
pointers,ȱandȱanyȱtypeȱofȱpointerȱcanȱbeȱconvertedȱtoȱaȱvoid *.ȱ
Ifȱonlyȱpartȱofȱtheȱarrayȱisȱtoȱbeȱcopied,ȱtheȱdesiredȱcountȱmayȱbeȱgivenȱforȱtheȱ
thirdȱargument.ȱForȱdataȱthatȱisȱlargerȱthanȱoneȱbyte,ȱbeȱsureȱtoȱmultiplyȱtheȱcountȱbyȱ
theȱsizeȱofȱeachȱdatum,ȱforȱexample:ȱ
ȱ
memcpy( saved_answers, answers,
count * sizeof( answers[ 0 ] ) );
ȱ
Youȱcanȱalsoȱcopyȱstructuresȱorȱarraysȱofȱstructuresȱwithȱthisȱtechnique.ȱ
Download at http://www.pin5i.com/
258
Chapter 9 Strings, Characters, and Bytes
memmoveȱ behavesȱ exactlyȱ theȱ sameȱ asȱ memcpyȱ exceptȱ thatȱ itsȱ sourceȱ andȱ
destinationȱoperandsȱmayȱoverlap.ȱThoughȱitȱneedȱnotȱbeȱimplementedȱthisȱway,ȱtheȱ
resultȱofȱmemmoveȱisȱtheȱsameȱasȱtheȱresultȱobtainedȱbyȱcopyingȱtheȱsourceȱoperandȱtoȱaȱ
temporaryȱlocationȱthatȱoverlapsȱneitherȱtheȱsourceȱnorȱtheȱdestination,ȱthenȱcopyingȱ
fromȱ thisȱ temporaryȱ locationȱ toȱ theȱ destinationȱ operand.ȱ memmoveȱ usuallyȱ cannotȱ beȱ
implementedȱ usingȱ theȱ specialȱ byteȬstringȱ handlingȱ instructionsȱ providedȱ onȱ someȱ
machines,ȱ soȱ itȱ mayȱ beȱ slowerȱ thanȱ memcpy.ȱ However,ȱ memmoveȱ shouldȱ beȱ usedȱ whenȱ
thereȱisȱaȱrealȱpossibilityȱofȱoverlappingȱarguments,ȱasȱinȱtheȱfollowingȱexample.ȱ
ȱ
/*
** Shift the values in the x array left one position
*/
memmove( x, x + 1, ( count – 1 ) * sizeof( x[ 0 ] ) );
ȱ
memcmpȱ comparesȱ theȱ lengthȱ bytesȱ ofȱ memoryȱ beginningȱ atȱ aȱ toȱ theȱ bytesȱ
beginningȱatȱ b.ȱTheȱvaluesȱareȱcomparedȱbyteȱbyȱbyteȱasȱunsignedȱcharacters,ȱandȱtheȱ
functionȱreturnsȱtheȱsameȱtypeȱofȱvalueȱasȱ strcmpȱ–ȱaȱnegativeȱvalueȱifȱ aȱisȱlessȱthanȱ b,ȱ
aȱpositiveȱvalueȱifȱaȱisȱgreaterȱthanȱb,ȱandȱzeroȱifȱtheyȱareȱequal.ȱBecauseȱtheȱvaluesȱareȱ
comparedȱasȱsequencesȱofȱunsignedȱbytes,ȱ memcmpȱmayȱgiveȱunexpectedȱresultsȱifȱitȱisȱ
usedȱtoȱcompareȱnonbyteȱdataȱsuchȱasȱintegersȱorȱfloats.ȱ
memchrȱ searchesȱ theȱ lengthȱ bytesȱ beginningȱ atȱ aȱ forȱ theȱ firstȱ occurrenceȱ ofȱ theȱ
characterȱ chȱ andȱ returnsȱ aȱ pointerȱ toȱ thatȱ location.ȱ Ifȱ theȱ characterȱ doesȱ notȱ occur,ȱ
NULLȱisȱreturned.ȱ
Finally,ȱ memsetȱ setsȱ eachȱ ofȱ theȱ lengthȱ bytesȱ beginningȱ atȱ aȱ toȱ theȱ characterȱ
valueȱch.ȱForȱexample,ȱ
ȱ
memset( buffer, 0, SIZE );
ȱ
initializesȱtheȱfirstȱSIZEȱbytesȱofȱtheȱbufferȱtoȱzero.ȱ
ȱ
ȱ
ȱ
9.10 Summary
ȱ
Aȱ stringȱ isȱ aȱ sequenceȱ ofȱ zeroȱ orȱ moreȱ characters.ȱ Theȱ sequenceȱ isȱ terminatedȱ byȱ aȱ
NULȱbyte.ȱTheȱlengthȱofȱaȱstringȱisȱtheȱnumberȱofȱcharactersȱitȱcontains.ȱTheȱstandardȱ
libraryȱprovidesȱaȱhostȱofȱfunctionsȱthatȱprocessȱstrings;ȱtheirȱprototypesȱareȱinȱtheȱfileȱ
string.h.ȱ
ȱ
Theȱ strlenȱfunctionȱcomputesȱtheȱlengthȱofȱaȱstring.ȱTheȱvalueȱthatȱisȱreturnedȱ
isȱunsigned,ȱsoȱbeȱcarefulȱwhenȱusingȱitȱinȱexpressions. strcpyȱcopiesȱaȱstringȱfromȱ
Download at http://www.pin5i.com/
9.10 Summary
259
oneȱlocationȱtoȱanother,ȱandȱ strcatȱappendsȱaȱcopyȱofȱaȱstringȱtoȱtheȱendȱofȱanotherȱ
string.ȱBothȱofȱtheseȱfunctionsȱassumeȱthatȱtheirȱargumentsȱareȱvalidȱstrings,ȱandȱtheȱ
resultsȱ ofȱ bothȱ areȱ undefinedȱ ifȱ theȱ sourceȱ andȱ destinationȱ stringsȱ overlap. strcmpȱ
performsȱaȱlexicographicȱcomparisonȱofȱtwoȱstrings.ȱItsȱreturnȱvalueȱindicatesȱwhetherȱ
theȱfirstȱstringȱisȱlessȱthan,ȱequalȱto,ȱorȱgreaterȱthanȱtheȱsecondȱstring.ȱ
ȱ
Theȱ lengthȬrestrictedȱ functionsȱ strncpy, strncat,ȱ andȱ strncmpȱ areȱ similarȱ loȱ
theirȱ unrestrictedȱ counterparts.ȱ Theȱ differenceȱ isȱ thatȱ theseȱ functionsȱ takeȱ aȱ lengthȱ
argument.ȱWithȱ strncpy,ȱtheȱlengthȱspecifiesȱhowȱmanyȱcharactersȱwillȱbeȱwrittenȱtoȱ
theȱdestinationȱarray.ȱIfȱtheȱsourceȱstringȱisȱlongerȱthanȱtheȱlength,ȱtheȱresultȱwillȱnotȱ
beȱNULȱterminated.ȱTheȱlengthȱargumentȱtoȱ strncatȱindicatesȱtheȱmaximumȱnumberȱ
ofȱcharactersȱthatȱwillȱbeȱcopiedȱfromȱtheȱsourceȱstring,ȱbutȱtheȱresultȱisȱalwaysȱNULȱ
terminated.ȱ Theȱ lengthȱargumentȱtoȱ strncmpȱlimitsȱtheȱ numberȱofȱcharactersȱthatȱ areȱ
compared.ȱIfȱtheȱstringsȱdoȱnotȱdifferȱwithinȱthisȱlength,ȱtheyȱareȱconsideredȱequal.ȱ
ȱ
Thereȱareȱseveralȱfunctionsȱthatȱsearchȱstrings. strchrȱsearchesȱaȱstringȱforȱtheȱ
firstȱoccurrenceȱofȱaȱcharacter,ȱandȱ strrchrȱsearchesȱaȱstringȱforȱtheȱlastȱoccurrenceȱofȱ
aȱ character.ȱ strpbrkȱ searchesȱ aȱ stringȱ forȱ theȱ firstȱ occurrenceȱ ofȱ anyȱ characterȱ inȱ aȱ
specifiedȱset.ȱTheȱ strstrȱfunctionȱsearchesȱaȱstringȱforȱtheȱfirstȱoccurrenceȱofȱanotherȱ
string.ȱ
ȱ
Moreȱ advancedȱ stringȱ searchesȱ areȱ alsoȱ provided.ȱ Theȱ strspnȱ functionȱ countsȱ
theȱ numberȱ ofȱ charactersȱ atȱ theȱ beginningȱ ofȱ aȱ stringȱ thatȱ matchȱ anyȱ characterȱ inȱ aȱ
specifiedȱset. strcspnȱcountsȱtheȱnumberȱofȱcharactersȱatȱtheȱbeginningȱofȱaȱstringȱthatȱ
doȱ notȱ matchȱ anyȱ ofȱ theȱ charactersȱ inȱ aȱ specifiedȱ set.ȱ Theȱ strtokȱ functionȱ breaksȱ aȱ
stringȱ intoȱ tokens.ȱ Eachȱ timeȱ itȱ isȱ called,ȱ itȱ returnsȱ aȱ pointerȱ toȱ theȱ nextȱ tokenȱ inȱ theȱ
string.ȱTheȱtokensȱareȱseparatedȱbyȱoneȱorȱmoreȱcharactersȱfromȱaȱspecifiedȱset.ȱ
ȱ
Theȱstrerrorȱtakesȱanȱerrorȱcodeȱasȱanȱargument.ȱItȱreturnsȱaȱpointerȱtoȱaȱstringȱ
thatȱdescribesȱtheȱerror.ȱ
ȱ
Aȱ varietyȱ ofȱ functionsȱ areȱ suppliedȱ forȱ testingȱ andȱ transformingȱ character.ȱ
Programsȱthatȱuseȱtheseȱfunctionsȱareȱmoreȱportableȱthanȱthoseȱthatȱperformȱtheirȱownȱ
testsȱ orȱ transformationsȱ ofȱ characters.ȱ Theȱ touperȱ functionȱ convertsȱ aȱ lowercaseȱ
characterȱ toȱ uppercase,ȱandȱtheȱ tolowerȱfunctionȱ convertsȱaȱ characterȱtheȱ otherȱway.ȱȱ
Theȱ iscntrlȱfunctionȱchecksȱwhetherȱitsȱargumentȱisȱaȱcontrolȱcharacter,ȱandȱ isspaceȱ
testsȱ forȱ whiteȱ space,ȱ isdigitȱ checksȱ forȱ aȱ decimalȱ digit,ȱ andȱ isxdigitȱ checksȱ forȱ
hexadecimalȱ digits. islowerȱ andȱ isupperȱ checkȱ forȱ lowercaseȱ andȱ uppercaseȱ
characters,ȱ respectively,ȱ isalphaȱ looksȱ forȱ alphabeticȱ characters,ȱ isalnumȱ looksȱ forȱ
alphanumericȱ characters,ȱ andȱ ispunctȱ looksȱ forȱ punctuationȱ characters.ȱ Finally,ȱ
isgraphȱ checksȱ whetherȱ itsȱ argumentȱ hasȱ aȱ printableȱ graphicȱ associatedȱ withȱ it,ȱ andȱ
isprintȱchecksȱforȱeitherȱaȱgraphicȱcharacterȱorȱaȱspace.ȱ
Download at http://www.pin5i.com/
260
Chapter 9 Strings, Characters, and Bytes
Theȱ memxxxȱ functionsȱ provideȱ capabilitiesȱ similarȱ toȱ someȱ ofȱ theȱ stringȱ
functions,ȱ butȱ processȱ arbitraryȱ byteȱ values,ȱ includingȱ NUL.ȱ Eachȱ ofȱ theȱ functionsȱ
takesȱ aȱ lengthȱ argumentȱ memcpyȱ copiesȱ bytesȱ fromȱ aȱ sourceȱ toȱ aȱ destination,ȱ memmoveȱ
performsȱ theȱ sameȱ function,ȱ butȱ itsȱ behaviorȱ isȱ wellȬdefinedȱ whenȱ theȱ sourceȱ andȱ
destinationȱargumentsȱoverlap. memcmpȱcomparesȱtwoȱsequencesȱofȱbytes,ȱandȱ memchrȱ
searchesȱ aȱ sequenceȱ ofȱ bytesȱ forȱ aȱ specificȱ value.ȱ Finally,ȱ memsetȱ storesȱ aȱ specifiedȱ
valueȱinȱaȱsequence.ȱ
ȱ
ȱ
ȱ
9.11 Summary of Cautions
ȱ
1. Usingȱstrlenȱinȱexpressionsȱthatȱshouldȱbeȱsignedȱ(pageȱ244).ȱ
2. Mixingȱsignedȱandȱunsignedȱquantitiesȱinȱexpressionsȱ(pageȱ245).ȱ
3. Overflowingȱaȱshortȱarrayȱbyȱusingȱstrcpyȱtoȱcopyȱaȱlongȱstringȱintoȱitȱ(pageȱ246).ȱ
4. Overflowingȱ anȱ arrayȱ byȱ appendingȱ aȱ stringȱ thatȱ isȱ tooȱ longȱ usingȱ strcatȱ (pageȱ
247).ȱ
5. Testingȱtheȱresultȱreturnedȱbyȱstrcmpȱasȱaȱbooleanȱ(pageȱ248).ȱ
6. Comparingȱtheȱvalueȱreturnedȱbyȱstrcmpȱtoȱ1ȱorȱȬ1ȱ(pageȱ248).ȱ
7. UsingȱcharacterȱsequencesȱthatȱareȱnotȱNULȱterminatedȱ(pageȱ248).ȱ
8. Producingȱunterminatedȱstringsȱwithȱstrncpyȱ(pageȱ249).ȱ
9. Mixingȱstrncpyȱwithȱstrxxxȱ(pageȱ249).ȱ
10. Forgettingȱthatȱstrtokȱmodifiesȱtheȱstringȱthatȱitȱprocessesȱ(pageȱ254).ȱ
11. Theȱstrtokȱfunctionȱisȱnotȱreentrantȱ(pageȱ255).ȱ
ȱ
ȱ
ȱ
9.12 Summary of Programming Tips
ȱ
1. Donȇtȱtryȱtoȱbeatȱtheȱlibraryȱstringȱfunctionsȱbyȱwritingȱyourȱownȱ(pageȱ245).ȱ
2. Usingȱ theȱ libraryȱ characterȱ classificationȱ andȱ transformationȱ functionsȱ enhancesȱ
portabilityȱ(pageȱ256).ȱ
ȱ
Download at http://www.pin5i.com/
9.13 Questions
261
9.13 Questions
ȱ
1. IsȱtheȱabsenceȱofȱanȱexplicitȱstringȱdataȱtypeȱinȱCȱanȱadvantageȱorȱaȱdisadvantage?ȱ
ȱ
2. strlenȱ returnsȱ anȱ unsignedȱ (size_t)ȱ quantity.ȱ Whyȱ isȱ anȱ unsignedȱ valueȱ moreȱ
appropriateȱthanȱaȱsignedȱvalue?ȱWhyȱisȱanȱunsignedȱvalueȱlessȱappropriate?ȱ
ȱ
3. Wouldȱthereȱbeȱanyȱadvantageȱinȱhavingȱ strcatȱandȱ strcpyȱreturnȱaȱpointerȱtoȱtheȱ
endȱofȱtheȱdestinationȱstringȱratherȱthanȱreturningȱaȱpointerȱtoȱitsȱbeginning?ȱ
ȱ
4. Whatȱisȱtheȱsimplestȱwayȱtoȱcopyȱ50ȱbytesȱfromȱtheȱarrayȱxȱintoȱtheȱarrayȱy?ȱ
ȱ
5. Supposeȱ youȱ haveȱ anȱ arrayȱ calledȱ bufferȱ thatȱ isȱ BSIZEȱ bytesȱ long,ȱ andȱ youȱ haveȱ
copiedȱaȱstringȱintoȱthisȱarrayȱwithȱtheȱfollowingȱstatement:ȱ
ȱ
strncpy( buffer, some_other_string, BSIZE – 1 );
ȱ
Isȱitȱguaranteedȱthatȱtheȱresultȱinȱbufferȱisȱaȱvalidȱstring?ȱ
ȱ
6. Whatȱareȱtheȱadvantagesȱofȱusingȱ
ȱ
if( isalpha( ch ) ){
ȱ
insteadȱofȱtheȱexplicitȱtestȱ
ȱ
if( ch >= 'A' && ch <= 'Z' ||
ch >= 'a' && ch <= 'z' ){
7. Howȱcanȱtheȱfollwingȱcodeȱbeȱsimplified?ȱ
for( p_str = message; *p_str != '\0'; p_str++ ){
if( islower( *p_str ) )
*p_str = toupper( *p_str );
}
8. Howȱdoȱtheȱexpressionsȱbelowȱdiffer?ȱ
ȱ
memchr( buffer, 0, SIZE ) – buffer
strlen( buffer )
Download at http://www.pin5i.com/
Chapter 9 Strings, Characters, and Bytes
262
9.14 Programming Exercises
ȱ
1. Writeȱaȱprogramȱthatȱreadsȱfromȱtheȱstandardȱinputȱandȱcomputesȱtheȱpercentageȱ
ofȱcharactersȱitȱfindsȱinȱeachȱofȱtheȱfollowingȱcategories:ȱ
ȱ
ȱ
controlȱcharactersȱ
whitespaceȱcharactersȱ
digitsȱ
lowerȱcaseȱlettersȱ
upperȱcaseȱlettersȱ
punctuationȱcharactersȱ
nonȬprintableȱcharactersȱ
Useȱtheȱcharacterȱcategoriesȱthatȱareȱdefinedȱforȱtheȱctype.hȱfunctions.ȱ
ȱ
2. Writeȱ aȱ functionȱ calledȱ my_strnlenȱ thatȱ isȱ similarȱ toȱ strlenȱ butȱ isȱ ableȱ toȱ handleȱ
unterminatedȱstringsȱcreatedȱwithȱtheȱ strn---ȱfunctions.ȱYouȱwillȱhaveȱtoȱpassȱanȱ
argumentȱcontainingȱtheȱsizeȱofȱtheȱarrayȱthatȱholdsȱtheȱstringȱtoȱbeȱtested.ȱ
ȱ
3. Writeȱaȱfunctionȱcalledȱmy_strcpyȱthatȱisȱsimilarȱtoȱstrcpyȱbutȱwillȱnotȱoverflowȱtheȱ
destinationȱarray.ȱTheȱresultȱofȱtheȱcopyȱmustȱbeȱaȱtrueȱstring.ȱ
ȱ
4. Writeȱaȱfunctionȱcalledȱmy_strcatȱthatȱisȱsimilarȱtoȱstrcatȱbutȱwillȱnotȱoverflowȱtheȱ
destinationȱarray.ȱTheȱresultȱmustȱbeȱaȱtrueȱstring.ȱ
ȱ
5. Writeȱtheȱfunctionȱ
ȱ
ȱ
void
my_strncat( char *dest, char *src, int dest_len );
whichȱconcatenatesȱtheȱstringȱinȱ srcȱtoȱtheȱendȱofȱtheȱstringȱinȱ dest,ȱmakingȱsureȱ
notȱtoȱoverflowȱtheȱ destȱarray,ȱwhichȱisȱ dest_lenȱbytesȱlong.ȱUnlikeȱ strncat,ȱthisȱ
functionȱtakesȱintoȱaccountȱtheȱlengthȱofȱtheȱstringȱalreadyȱinȱdestȱtherebyȱinsuringȱ
thatȱtheȱarrayȱboundsȱareȱnotȱexceeded.ȱ
ȱ
6. Writeȱaȱ strcpyȱreplacementȱcalledȱ my_strcpy_endȱthatȱreturnsȱaȱpointerȱtoȱtheȱendȱ
ofȱtheȱdestinationȱstringȱ(thatȱis,ȱaȱpointerȱtoȱtheȱNULȱbyte)ȱratherȱthanȱaȱpointerȱtoȱ
theȱbeginningȱofȱtheȱdestinationȱstring.ȱ
ȱ
7. Writeȱaȱfunctionȱcalledȱmy_strrchrȱwithȱthisȱprototype:ȱ
ȱ
ȱ
char
*my_strrchr( char const *str, int ch );
Theȱ functionȱ isȱ similarȱ toȱ strchrȱ exceptȱ thatȱ itȱ returnsȱ aȱ pointerȱ toȱ theȱ lastȱ
(rightmost)ȱoccurrenceȱofȱtheȱcharacter.ȱ
ȱ
Download at http://www.pin5i.com/
9.14 Programming Exercises
263
8. Writeȱaȱfunctionȱcalledȱmy_strnchrȱwithȱthisȱprototype:ȱ
ȱ
char
*my_strnchr( char const *str, in ch, int which );
ȱ
Theȱ functionȱ isȱ similarȱ toȱ strchrȱ exceptȱ thatȱ theȱ thirdȱ argumentȱ specifiesȱ whichȱ
occurrenceȱofȱtheȱcharacterȱisȱdesired.ȱForȱexample,ȱifȱtheȱthirdȱargumentȱisȱone,ȱtheȱ
functionȱ behavesȱ exactlyȱ likeȱ strchr.ȱ Ifȱ theȱ thirdȱ argumentȱ isȱ two,ȱ theȱ functionȱ
returnsȱaȱpointerȱtoȱtheȱsecondȱoccurrenceȱofȱchȱinȱtheȱstringȱstr.ȱ
ȱ
9. Writeȱaȱfunctionȱwithȱthisȱprototype:ȱ
ȱ
int
count_chars( char const *str,
char const *chars );
ȱ
Theȱ functionȱ shouldȱ lookȱ throughȱ theȱ firstȱ argumentȱ andȱ returnȱ theȱ numberȱ ofȱ
charactersȱthatȱmatchȱcharactersȱinȱtheȱsecondȱargument.ȱ
ȱ
10. Writeȱthisȱfunction:ȱ
ȱ
int
palindrome( char *string );
ȱ
whichȱ returnsȱ aȱ trueȱ valueȱ ifȱ theȱ argumentȱ stringȱ isȱ aȱ palindromeȱ andȱ falseȱ
otherwise.ȱAȱpalindromeȱisȱaȱstringȱthatȱreadsȱtheȱsameȱforwardsȱandȱbackwards. 39 ȱ
Theȱ functionȱ shouldȱ ignoreȱ allȱ nonalphabeticȱ characters,ȱ andȱ characterȱ
comparisonsȱshouldȱbeȱcaseȱindependent.ȱ
ȱ
11. Writeȱaȱprogramȱthatȱscansȱtheȱstandardȱinputȱandȱcountsȱtheȱnumberȱofȱtimesȱtheȱ
wordȱ ȈtheȈȱ appears.ȱ Theȱ comparisonȱ shouldȱ beȱ caseȱ independent,ȱ soȱ ȇTheȈȱ andȱ
ȈTHEȈȱdonȇtȱcount.ȱYouȱmayȱassumeȱthatȱwordsȱwillȱbeȱseparatedȱfromȱeachȱotherȱ
byȱoneȱorȱmoreȱwhiteȬspaceȱcharactersȱandȱthatȱtheȱinputȱlinesȱwillȱbeȱlessȱthanȱ100ȱ
charactersȱinȱlength.ȱTheȱcountȱshouldȱbeȱwrittenȱtoȱtheȱstandardȱoutput.ȱ
ȱ
12. Thereȱisȱaȱtechniqueȱforȱencryptingȱdataȱthatȱusesȱaȱwordȱasȱitsȱkey.ȱHereȱisȱhowȱitȱ
works.ȱFirst,ȱaȱwordȱisȱchosenȱasȱtheȱkey,ȱforȱexample,ȱ TRAIL-BLAZERS.ȱIfȱtheȱwordȱ
containsȱanyȱduplicateȱletters,ȱonlyȱtheȱfirstȱofȱeachȱisȱkept;ȱtheȱrestȱareȱdiscarded.ȱȱ
Nowȱtheȱmodifiedȱwordȱisȱwrittenȱbeneathȱtheȱalphabet,ȱasȱshownȱhere:ȱ
ȱ
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
T R A I L B Z E S
ȱWhenȱtheȱspacing,ȱpunctuation,ȱandȱcapitalizationȱareȱignored.ȱAnȱexampleȱisȱwhatȱAdamȱmightȱhaveȱsaidȱwhenȱheȱfirstȱ
metȱEve:ȱȈMadam,ȱIȇmȱAdam.Ȉȱ
39
Download at http://www.pin5i.com/
264
Chapter 9 Strings, Characters, and Bytes
Finally,ȱ theȱ bottomȱ lineȱ isȱ completedȱ byȱ fillingȱ inȱ theȱ remainingȱ lettersȱ ofȱ theȱ
alphabet:ȱ
ȱ
A B C D E P G H T J K L M N O P Q R S T U V W X Y Z
T R A I L B Z E S C D F G H J K M N O P Q U V W X Y
ȱ
Toȱencryptȱaȱmessage,ȱeachȱletterȱinȱtheȱmessageȱisȱlocatedȱinȱtheȱtopȱrow,ȱandȱtheȱ
correspondingȱ characterȱ fromȱ theȱ bottomȱ rowȱ isȱ usedȱ instead.ȱ Thus,ȱ ATTACT AT
DAWNȱwouldȱbeȱencryptedȱusingȱthisȱkeyȱasȱTPPTAD TP ITVH.ȱ
ȱ Inȱthisȱfirstȱofȱthreeȱprograms,ȱyouȱwillȱwriteȱtheȱfunctionȱ
ȱ
int
prepare_key( char *key );
ȱ
whichȱ acceptsȱ aȱ stringȱ containingȱ theȱ desiredȱ keyȱ wordȱ andȱ convertsȱ itȱ asȱ
describedȱaboveȱtoȱtheȱarrayȱofȱencodedȱcharacters.ȱAssumeȱthatȱtheȱkeyȱargumentȱ
isȱanȱarrayȱatȱleastȱ27ȱcharactersȱlong.ȱTheȱfunctionȱmustȱconvertȱallȱtheȱcharactersȱ
inȱ theȱ keyȱ toȱ eitherȱ upperȬȱ orȱ lowercaseȱ (yourȱ choice),ȱ eliminateȱ anyȱ duplicateȱ
lettersȱfromȱtheȱword,ȱandȱthenȱfillȱinȱtheȱrestȱofȱtheȱalphabetȱinȱtheȱsameȱcaseȱyouȱ
choseȱ earlier.ȱ Ifȱ theȱ processingȱ succeeds,ȱ theȱ functionȱ returnsȱ aȱ trueȱ result.ȱ Ifȱ theȱ
keyȱ argumentȱ isȱ emptyȱ orȱ containsȱ anyȱ nonalphabeticȱ characters,ȱ theȱ functionȱ
shouldȱreturnȱaȱfalseȱresult.ȱ
ȱ
13. Writeȱtheȱfunctionȱ
ȱ
void
encrypt( char *data, char const *key );
ȱ
whichȱ usesȱ aȱ keyȱ producedȱ byȱ prepare_keyȱ toȱ encryptȱ theȱ charactersȱ inȱ data.ȱ
Nonalphabeticȱ charactersȱ inȱ dataȱ areȱ notȱ changed,ȱ butȱ alphabeticȱ charactersȱ areȱ
encryptedȱ usingȱ theȱ keyȱ providedȱ byȱ replacingȱ theȱ originalȱ characterȱ withȱ theȱ
codedȱcharacter.ȱTheȱcaseȱofȱalphabeticȱcharactersȱshouldȱbeȱpreserved.ȱ
ȱ
14. Theȱfinalȱpartȱofȱthisȱproblemȱisȱtoȱwriteȱtheȱfunctionȱ
ȱ
void
decrypt( char *data, char const *key );
ȱ
whichȱtakesȱanȱencryptedȱstringȱandȱreconstructsȱtheȱoriginalȱmessage.ȱExceptȱforȱ
decrypting,ȱthisȱfunctionȱshouldȱworkȱtheȱsameȱasȱencrypt.ȱ
ȱ
15. Theȱ standardȱ I/Oȱ libraryȱ doesȱ notȱ provideȱ aȱ mechanismȱ forȱ puttingȱ commasȱ inȱ
largeȱ integersȱ whenȱ theyȱ areȱ printed.ȱ Forȱ thisȱ exerciseȱ youȱ willȱ writeȱ aȱ programȱ
thatȱprovidesȱthisȱcapabilityȱforȱdollarȱamounts.ȱTheȱfunctionȱwillȱconvertȱaȱstringȱ
ofȱ digitsȱ (representingȱ anȱ amountȱ inȱ pennies)ȱ toȱ dollarsȱ asȱ illustratedȱ byȱ theȱ
followingȱexamples.ȱ
Download at http://www.pin5i.com/
9.14 Programming Exercises
ȱ
Input
Output
(empty)ȱ
$0.00ȱ
1ȱ
$0.01ȱ
12ȱ
$0.12ȱ
123ȱ
$1.23ȱ
1234ȱ
$12.34ȱ
ȱ
Hereȱisȱaȱprototypeȱforȱtheȱfunction:ȱ
ȱ
Input
12345ȱ
123456ȱ
1234567ȱ
12345678ȱ
123456789ȱ
void
dollars( char *dest, char const *src );
int
format( char *format_string,
char const *digit_string );
265
Output
$123.45ȱ
$1,234.56ȱ
$12,345.67ȱ
$123,456.78ȱ
$1,234,567.89ȱ
ȱ
srcȱwillȱpointȱtoȱtheȱcharactersȱtoȱbeȱformatted.ȱ(Youȱmayȱassumeȱthatȱtheseȱareȱallȱ
digits.)ȱ Yourȱ functionȱ shouldȱ formatȱ theȱ charactersȱ asȱ shownȱ inȱ theȱ examples,ȱ
leavingȱtheȱresultingȱstringȱinȱdest.ȱȱBeȱsureȱthatȱtheȱstringȱyouȱcreateȱisȱterminatedȱ
withȱaȱNULȱbyte. srcȱshouldȱnotȱbeȱmodified.ȱUseȱpointersȱratherȱthanȱsubscripts.ȱ
Hint:ȱFirstȱfindȱtheȱlengthȱofȱtheȱstringȱinȱtheȱsecondȱargument.ȱThisȱvalueȱwillȱ
helpȱdetermineȱwhereȱtheȱcommasȱshouldȱbeȱinserted.ȱAlso,ȱtheȱdecimalȱpointȱandȱ
lastȱtwoȱdigitsȱshouldȱbeȱtheȱonlyȱspecialȱcaseȱyouȱneedȱtoȱhandle.ȱ
ȱ
16. Thisȱprogramȱisȱsimilarȱtoȱtheȱpreviousȱoneȱbutȱisȱmoreȱgeneral.ȱItȱformatsȱaȱstringȱ
ofȱdigitsȱasȱspecifiedȱbyȱaȱformatȱstring,ȱsimilarȱtoȱtheȱȈprintȱusingȈȱstatementȱfoundȱ
inȱmanyȱimplementationsȱofȱbasic.ȱTheȱfunctionȱshouldȱhaveȱthisȱprototype:ȱ
ȱ
ȱ
Workingȱ fromȱ rightȱ toȱ left,ȱ theȱ digitsȱ inȱ digit_stringȱ areȱ copiedȱ intoȱ theȱ
format_stringȱ accordingȱ toȱ theȱ charactersȱ initiallyȱ foundȱ inȱ format_string.ȱ Noteȱ
thatȱ format_stringȱ isȱ modifiedȱ asȱ aȱ resultȱ ofȱ thisȱ process.ȱ Makeȱ sureȱ thatȱ theȱ
format_scringȱisȱstillȱNULȬterminatedȱwhenȱyouȱareȱfinishedȱwithȱit.ȱTheȱreturnedȱ
valueȱ isȱ eitherȱ trueȱ orȱ falseȱ dependingȱ onȱ whetherȱ anyȱ errorsȱ occurredȱ inȱ
formatting.ȱ
ȱ Theȱformatȱstringȱmayȱcontainȱtheȱfollowingȱcharacters:ȱ
ȱ
ȱ
#ȱ
Workingȱ fromȱ rightȱ toȱ leftȱ inȱ bothȱ strings,ȱ eachȱ poundȱ signȱ inȱ theȱ
formatȱstringȱisȱreplacedȱbyȱtheȱnextȱdigitȱfromȱtheȱdigitȱstring.ȱIfȱtheȱ
digitȱstringȱrunsȱout,ȱallȱremainingȱpoundȱsignsȱinȱtheȱformatȱstringȱ
areȱreplacedȱwithȱblanksȱ(butȱseeȱtheȱdiscussionȱforȱperiodsȱbelow).ȱ
,ȱ
Aȱcommaȱisȱnotȱchangedȱifȱthereȱwillȱbeȱatȱleastȱoneȱdigitȱtoȱitsȱleftȱinȱ
theȱresult,ȱotherwiseȱitȱisȱreplacedȱwithȱaȱblank.ȱ
ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
266
Chapter 9 Strings, Characters, and Bytes
.ȱ
Aȱperiodȱisȱalwaysȱleftȱasȱaȱperiod.ȱIfȱthereȱisnȇtȱaȱdigitȱtoȱtheȱleftȱofȱ
theȱ period,ȱ zerosȱ areȱ filledȱ inȱ fromȱ whereȱ theȱ digitsȱ endedȱ toȱ theȱ
positionȱjustȱtoȱtheȱleftȱofȱtheȱperiod.ȱ
ȱ
Theȱ followingȱ examplesȱ illustrateȱ severalȱ callsȱ toȱ thisȱ function.ȱ Theȱ ¤ȱ symbolȱ isȱ
usedȱtoȱindicateȱaȱblankȱspace.ȱ
ȱ
Format
Digits
Resulting Format
#####
#####
##,###
##,###
##,###
#,###,###.##
#,###,###.##
#,###,###.##
#,###,###.##
#####.#####
12345
123
1234
123
1234567
123456789
1234567
123
1
1
12345
¤¤123
¤1,234
¤¤¤123
34,567
1,234,567.89
¤¤¤12,345.67
¤¤¤¤¤¤¤¤1.23
¤¤¤¤¤¤¤¤0.01
¤¤¤¤0.0000l
ȱ
Toȱ simplifyȱ theȱ project,ȱ youȱ mayȱ assumeȱ thatȱ theȱ formatȱ stringȱ isȱ correctlyȱ
formed.ȱThereȱwillȱalwaysȱbeȱatȱleastȱoneȱpoundȱsignȱtoȱtheȱleftȱandȱtoȱtheȱrightȱofȱaȱ
periodȱandȱeveryȱcomma,ȱandȱcommasȱwillȱneverȱappearȱtoȱtheȱrightȱofȱaȱperiod.ȱȱ
Theȱonlyȱerrorsȱyouȱneedȱtoȱcheckȱforȱare:ȱ
ȱ
a.
moreȱ digitsȱ inȱ theȱ digitȱ stringȱ thanȱ thereȱ areȱ poundȱ signsȱ inȱ theȱ formatȱ
stringȱ(asȱinȱtheȱbottomȱleftȱexampleȱabove),ȱandȱ
b.
anȱemptyȱdigitȱstring.ȱ
ȱ
Eitherȱ ofȱ theseȱ errorsȱ resultȱ inȱ theȱ functionȱ returningȱ FALSE,ȱ otherwiseȱ itȱ shouldȱ
returnȱ TRUE.ȱ Ifȱ theȱ digitȱ stringȱ isȱ empty,ȱ theȱ formatȱ stringȱ shouldȱ beȱ returnedȱ
unchanged.ȱYouȱwillȱlearnȱmoreȱifȱyouȱuseȱpointersȱratherȱthanȱsubscripts.ȱ
Hint:ȱStartȱbyȱgettingȱpointersȱtoȱtheȱendȱofȱbothȱtheȱformatȱstringȱandȱtheȱdigitȱ
string,ȱthenȱworkȱfromȱrightȱ toȱ left.ȱYouȱmustȱ retainȱtheȱpointerȱ valuesȱthatȱ wereȱ
passedȱ asȱ argumentsȱ soȱ thatȱ youȱ canȱ determineȱ whenȱ youȱ haveȱ reachedȱ theȱ leftȱ
endȱofȱtheseȱstrings.ȱ
17. Thisȱ programȱ isȱ similarȱ toȱ theȱ previousȱ twoȱ butȱ moreȱ generalȱ still.ȱ Itȱ allowsȱ theȱ
callerȱtoȱputȱcommasȱinȱlargeȱnumbers,ȱsuppressȱleadingȱzeros,ȱprovideȱaȱfloatingȱ
dollarȱsign,ȱandȱsoȱforth.ȱ
TheȱfunctionȱisȱsimilarȱinȱoperationȱtoȱtheȱEditȱandȱMarkȱinstructionȱonȱtheȱIBMȱ
370ȱcomputer.ȱItȱhasȱthisȱprototype:ȱ
ȱ
char
*edit( char *pattern, char const *digits );
ȱ
Theȱbasicȱideaȱisȱsimple.ȱTheȱpatternȱisȱaȱpictureȱofȱwhatȱtheȱresultȱshouldȱlookȱlikeȱ
Download at http://www.pin5i.com/
9.14 Programming Exercises
267
Charactersȱ fromȱ theȱ digitȱ stringȱ areȱ copiedȱ intoȱ theȱ patternȱ stringȱ fromȱ theȱ leftȱ toȱ
rightȱinȱaȱmannerȱdeterminedȱbyȱthisȱpicture.ȱ
Theȱ firstȱ significantȱ digitȱ inȱ theȱ digitȱ stringȱ isȱ important.ȱ Allȱ charactersȱ inȱ theȱ
resultȱ thatȱ areȱ toȱ theȱ leftȱ ofȱ theȱ firstȱ significantȱ digitȱ areȱ replacedȱ byȱ aȱ ȈfillȈȱ
character,ȱandȱtheȱfunctionȱwillȱreturnȱaȱpointerȱtoȱtheȱplaceȱinȱtheȱresultȱwhereȱtheȱ
firstȱsignificantȱdigitȱwasȱstored.ȱ(Theȱcallingȱprogramȱcanȱuseȱtheȱreturnedȱpointerȱ
toȱ putȱ aȱ floatingȱ dollarȱ signȱ immediatelyȱ toȱ theȱ leftȱ ofȱ theȱ value.)ȱ Theȱ resultingȱ
outputȱlooksȱ likeȱwhatȱyouȱmayȱhaveȱ seenȱprintedȱ onȱchecks—allȱ ofȱtheȱ spaceȱ toȱ
theȱleftȱofȱtheȱvalueȱisȱfilledȱinȱwithȱstarsȱorȱsomeȱotherȱcharacter.ȱ
Beforeȱtheȱdetailedȱworkingsȱofȱtheȱfunctionȱareȱdescribed,ȱitȱwillȱbeȱhelpfulȱtoȱ
seeȱsomeȱexamplesȱofȱitsȱoperation.ȱForȱclarity,ȱtheȱ ¤ȱcharacterȱisȱusedȱtoȱrepresentȱ
aȱ space.ȱ Theȱ underlineȱ inȱ theȱ resultȱ indicatesȱ theȱ characterȱ toȱ whichȱ theȱ returnedȱ
valueȱpoints.ȱIfȱthereȱisnȇtȱanȱunderlinedȱcharacter,ȱtheȱreturnedȱvalueȱwasȱNULL.ȱ
ȱ
Format
Digits
Resulting Format
*#,###
*#,###
*#,###
*#,###
*#,###
*#,###
*X#Y#Z
¤#,##!.##
¤#,##!.##
$#,##!.##
$#,##!.##
$#,##!.##
$#,##!.##
$#,##!.##
1234
123456
12
0012
¤¤12
¤1¤¤
(empty)
¤23456
023456
¤¤¤456
0¤¤¤¤6
0
1
Hi¤there
*1,234
*1,234
*1,2
****12
****12
***100
**
¤¤¤234.56
¤¤¤234.56
$$$$$4.56
$$$$$0.06
$$$
$1,
$H,i0t.he
ȱ
Now,ȱtheȱdetails.ȱTheȱfirstȱargumentȱisȱtheȱpattern,ȱandȱtheȱfirstȱcharacterȱinȱtheȱ
patternȱ isȱ theȱ Ȉfillȱ character.Ȉȱ Theȱ functionȱ usesȱ theȱ digitȱ stringȱ toȱ modifyȱ theȱ
remainingȱ charactersȱ ofȱ theȱ patternȱ toȱ produceȱ theȱ outputȱ string.ȱ Theȱ patternȱ isȱ
overwrittenȱ inȱ thisȱ process.ȱ Theȱ outputȱ stringȱ cannotȱ beȱ longerȱ thanȱ theȱ originalȱ
pattern,ȱ soȱ thereȱ isȱ noȱ dangerȱ ofȱ (andȱ noȱ needȱ toȱ checkȱ for)ȱ overflowingȱ theȱ firstȱ
argument.ȱ
Theȱ patternȱ isȱ processedȱ characterȱ byȱ characterȱ fromȱ leftȱ toȱ right.ȱ Forȱ eachȱ
characterȱafterȱtheȱfillȱcharacter,ȱoneȱofȱthreeȱthingsȱhappens:ȱ(a)ȱtheȱcharacterȱisȱleftȱ
unchanged,ȱ(b)ȱitȱisȱreplacedȱbyȱaȱcharacterȱfromȱtheȱdigitȱstring,ȱorȱ(c)ȱitȱisȱreplacedȱ
byȱtheȱfillȱcharacter.ȱ
Theȱdigitȱstringȱisȱalsoȱprocessedȱfromȱleftȱtoȱright,ȱbutȱitȱisȱneverȱmodifiedȱinȱ
anyȱway.ȱAlthoughȱitȱisȱcalledȱaȱȈdigitȱstring,Ȉȱitȱcanȱcontainȱanyȱcharacters,ȱasȱoneȱ
ofȱtheȱaboveȱexamplesȱillustrates.ȱHowever,ȱeveryȱspaceȱinȱtheȱdigitȱstringȱshouldȱ
Download at http://www.pin5i.com/
268
Chapter 9 Strings, Characters, and Bytes
beȱtreatedȱ(andȱproduceȱtheȱsameȱresults)ȱasȱifȱitȱwereȱtheȱdigitȱ0.ȱ
ȱ Theȱ functionȱ mustȱ keepȱ aȱ ȈsignificanceȈȱ flag,ȱ whichȱ remembersȱ whetherȱ anyȱ
significantȱdigitsȱhaveȱbeenȱcopiedȱfromȱtheȱdigitȱstring.ȱLeadingȱspacesȱandȱ0ȇsȱinȱ
theȱdigitȱstringȱareȱnotȱsignificant;ȱallȱotherȱcharactersȱare.ȱ
ItȱisȱanȱerrorȱforȱeitherȱtheȱpatternȱorȱdigitȱargumentsȱtoȱbeȱNULL.ȱInȱthisȱcase,ȱ
theȱfunctionȱshouldȱimmediatelyȱreturnȱnull.ȱ
Theȱ followingȱ tableȱ listsȱ allȱ processingȱ thatȱ isȱ required.ȱ Theȱ columnsȱ headedȱ
signifȱreferȱtoȱtheȱsignificanceȱflag.ȱȈPatternȈȱandȱȈDigitȈȱreferȱtoȱtheȱnextȱcharacterȱ
inȱtheȱpatternȱstringȱandȱdigitȱstring,ȱrespectively.ȱȱTheȱleftȱsideȱofȱtheȱtableȱlistsȱallȱ
ofȱ theȱ differentȱ casesȱ thatȱ mightȱ occur.ȱ Theȱ rightȱ sideȱ describesȱ theȱ processingȱ
neededȱ forȱ eachȱ case.ȱ Forȱ example,ȱ ifȱ theȱ nextȱ patternȱ characterȱ isȱ '#',ȱ theȱ
significanceȱ indicatorȱ isȱ false,ȱ andȱ theȱ nextȱ characterȱ inȱ theȱ digitȱ stringȱ isȱ '0',ȱ
replaceȱtheȱ '#'ȱinȱtheȱpatternȱwithȱaȱcopyȱofȱtheȱfillȱcharacterȱandȱdonȇtȱchangeȱtheȱ
significanceȱindicator.ȱ
ȱ
If you find this…
Then you do this…
signif
signif
Pattern
Digit
Pattern
Notes
'\0'
(doesnȇtȱmatter)ȱ (notȱused)ȱ
(unchanged) (unchanged) Returnȱsavedȱpointerȱ
'\0'
'\0'
(doesnȇtȱmatter)ȱ
(unchanged) Returnȱsavedȱpointerȱ
'\0'ȱorȱ' '
fillȱcharȱ
(unchanged) ȱ
'#'
falseȱ
anyȱotherȱ
theȱdigitȱ
trueȱ
Saveȱpointerȱtoȱthisȱchar
trueȱ
anyȱ
theȱdigitȱ
(unchanged) ȱ
'!'
'\0'
(doesnȇtȱmatter)ȱ '\0'
(unchanged) Returnȱsavedȱpointerȱ
falseȱ
anyȱ
theȱdigitȱ
trueȱ
Saveȱpointerȱtoȱthisȱchar
trueȱ
anyȱ
theȱdigitȱ
(unchanged) ȱ
anythingȱ falseȱ
(notȱused)ȱ
fillȱcharȱ
(unchanged) ȱ
elseȱ
trueȱ
(notȱused)ȱ
(unchanged) (unchanged) ȱ
ȱ
Download at http://www.pin5i.com/
10
Structures and Unions
Dataȱ frequentlyȱ existsȱ inȱ groups.ȱ Forȱ example,ȱ anȱ employerȱ mustȱ keepȱ trackȱ ofȱ theȱ
name,ȱ age,ȱ andȱ salaryȱ ofȱ eachȱ employee.ȱ Accessingȱ theseȱ valuesȱ isȱ simplifiedȱ ifȱ theyȱ
canȱ beȱ storedȱ together.ȱ However,ȱ ifȱ theȱ valuesȱ areȱ differentȱ types,ȱ asȱ theyȱ areȱ inȱ thisȱ
example,ȱtheyȱcannotȱbeȱstoredȱtogetherȱinȱanȱarray.ȱInȱC,ȱvaluesȱwithȱdissimilarȱtypesȱ
canȱbeȱstoredȱtogetherȱusingȱaȱstructure.ȱ
ȱ
ȱ
ȱ
10.1 Structure Basics
ȱ
Anȱaggregateȱdataȱtypeȱisȱoneȱthatȱcanȱholdȱmoreȱthanȱoneȱindividualȱpieceȱofȱdataȱatȱaȱ
time.ȱ Cȱ providesȱ twoȱ typesȱ ofȱ aggregateȱ data,ȱ arraysȱ andȱ structures.ȱ Arraysȱ areȱ
collectionsȱofȱelementsȱofȱtheȱsameȱtype,ȱandȱindividualȱelementsȱareȱselectedȱthroughȱ
aȱsubscriptȱorȱindirectionȱonȱaȱpointer.ȱ
Aȱstructureȱ isȱ alsoȱ aȱcollectionȱofȱvalues,ȱ calledȱmembers,ȱbutȱtheȱmembersȱ ofȱ aȱ
structureȱmayȱbeȱofȱdifferentȱtypes.ȱAȱstructureȱisȱquiteȱsimilarȱtoȱaȱrecordȱinȱPascalȱorȱ
Modula.ȱ
Arrayȱelementsȱcanȱbeȱaccessedȱviaȱaȱsubscriptȱonlyȱbecauseȱallȱofȱtheȱelementsȱ
areȱ theȱ sameȱ size.ȱ Theȱ situationȱ isȱ differentȱ withȱ structures.ȱ Becauseȱ aȱ structureȇsȱ
membersȱcanȱbeȱofȱdifferentȱsizes,ȱsubscriptsȱcannotȱbeȱusedȱtoȱaccessȱthem.ȱInstead,ȱ
structureȱmembersȱareȱgivenȱnamesȱandȱareȱaccessedȱbyȱthoseȱnames.ȱ
Thisȱdistinctionȱisȱimportant.ȱAȱstructureȱisȱnotȱanȱarrayȱofȱitsȱmembers.ȱUnlikeȱ
anȱarrayȱname,ȱtheȱnameȱofȱaȱstructureȱvariableȱisȱnotȱreplacedȱwithȱaȱpointerȱwhenȱitȱ
isȱ usedȱ inȱ anȱ expression.ȱ Subscriptsȱ cannotȱ beȱ usedȱ onȱ aȱ structureȱ variableȱ toȱ selectȱ
specificȱmembers.ȱ
Aȱ structureȱ variableȱ isȱ aȱ scalar,ȱ soȱ youȱ canȱ performȱ theȱ sameȱ kindsȱ ofȱ
operationsȱ withȱ itȱ thatȱ youȱ canȱ withȱ otherȱ scalars.ȱ Structuresȱ mayȱ beȱ passedȱ asȱ
argumentsȱtoȱfunctions,ȱtheyȱmayȱbeȱreturnedȱbyȱfunctions,ȱandȱstructuresȱofȱtheȱsameȱ
Download at http://www.pin5i.com/
Chapter 10 Structures and Unions
270ȱ
typeȱmayȱbeȱassignedȱtoȱoneȱanother.ȱYouȱcanȱdeclareȱpointersȱtoȱstructures,ȱtakeȱtheȱ
addressȱ ofȱ structureȱ variables,ȱ andȱ declareȱ arraysȱ ofȱ structures.ȱ However,ȱ weȱ mustȱ
firstȱcoverȱaȱfewȱmoreȱbasicsȱbeforeȱdiscussingȱtheseȱissues.ȱ
ȱ
ȱ
ȱ
10.1.1
Structure Declarations
ȱ
Structuresȱareȱdeclaredȱbyȱlistingȱtheȱmembersȱthatȱtheyȱwillȱcontain.ȱThisȱlistȱincludesȱ
theȱtypeȱandȱtheȱnameȱofȱeachȱmember.ȱ
ȱ
ȱ
struct
tag { member-list } variable-list ;
ȱ
Thisȱ structureȱ declarationȱ syntaxȱ requiresȱ someȱ explanation.ȱ Theȱ optionalȱ fieldsȱ
cannotȱallȱbeȱomitted—atȱleastȱtwoȱofȱthemȱmustȱappear. 40
Hereȱareȱseveralȱexamples.ȱ
ȱ
struct
{
int
char
float c;
a;
b;
} x;
ȱ
Thisȱdeclarationȱcreatesȱaȱsingleȱvariableȱnamedȱ x,ȱwhichȱcontainsȱthreeȱmembers:ȱanȱ
integer,ȱaȱcharacterȱandȱaȱfloat.ȱ
ȱ
struct
{
int
char
float c;
} y[20], *z;
CAUTION!
a;
b;
ȱ
Thisȱdeclarationȱcreatesȱanȱarrayȱ yȱofȱtwentyȱstructuresȱandȱ z,ȱwhichȱisȱaȱpointerȱtoȱaȱ
structureȱofȱthisȱtype.ȱ
ȱ
Theseȱ twoȱ declarationsȱ areȱ treatedȱ byȱ theȱ compilerȱ asȱ entirelyȱ differentȱ types,ȱ evenȱ
thoughȱtheirȱmemberȱlistsȱareȱidentical.ȱThus,ȱtheȱvariablesȱyȱandȱzȱareȱaȱdifferentȱtypeȱ
thanȱx,ȱsoȱtheȱstatementȱ
ȱ
z = &x;
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
40
ȱAnȱexceptionȱtoȱthisȱruleȱisȱtheȱincompleteȱdeclarationȱofȱstructureȱtag,ȱdescribedȱlaterȱinȱthisȱchapter.ȱ
Download at http://www.pin5i.com/
10.1 Structure Basics
271
isȱillegal.ȱButȱdoesȱthisȱfactȱmeanȱthatȱailȱstructuresȱofȱaȱgivenȱtypeȱmustȱbeȱcreatedȱinȱaȱ
singleȱdeclaration?ȱ
Fortunately,ȱno.ȱTheȱtagȱfieldȱallowsȱaȱnameȱtoȱbeȱgivenȱtoȱtheȱmemberȱlistȱsoȱthatȱitȱ
canȱbeȱreferencedȱinȱsubsequentȱdeclarations.ȱTheȱtagȱallowsȱmanyȱdeclarationsȱtoȱuseȱ
theȱsameȱmemberȱlistȱandȱthusȱcreateȱstructuresȱofȱtheȱsameȱtype.ȱHereȱisȱanȱexample.ȱ
ȱ
struct
SIMPLE
int
char
float c;
{
a;
b;
};
ȱ
Theȱ declarationȱ associatesȱ theȱ tagȱ SIMPLEȱ withȱ thisȱ memberȱ list.ȱ Theȱ declarationȱ
doesnȇtȱhaveȱaȱvariableȱlist,ȱsoȱitȱdoesnȇtȱcreateȱanyȱvariables.ȱ
Thisȱdeclarationȱisȱsimilarȱtoȱmakingȱaȱcookieȱcutter.ȱAȱcookieȱcutterȱdeterminesȱ
theȱ shapeȱ ofȱ cookiesȱ yetȱ toȱ beȱ made,ȱ butȱ theȱ cookieȱ cutterȱ isȱ notȱ aȱ cookie.ȱ Theȱ tagȱ
identifiesȱ aȱ patternȱ forȱ declaringȱ futureȱ variables,ȱ butȱ neitherȱ theȱ tagȱ norȱ theȱ patternȱ
areȱvariables.ȱ
ȱ
struct
struct
SIMPLE
SIMPLE
x;
y[20], *z;
ȱ
Theseȱdeclarationsȱuseȱtheȱtagȱtoȱcreateȱvariables.ȱTheyȱcreateȱtheȱsameȱvariablesȱasȱtheȱ
firstȱ twoȱ examplesȱ butȱ withȱ oneȱ importantȱ difference—now x, y,ȱ and z areȱ allȱ theȱ
sameȱkindȱofȱstructure.ȱ
Anotherȱgoodȱtechniqueȱforȱdeclaringȱstructuresȱisȱtoȱcreateȱaȱnewȱtypeȱwithȱaȱ
typedef,ȱasȱinȱtheȱfollowingȱexample.ȱ
ȱ
typedef
struct
int
char
float c;
{
a;
b;
} Simple;
ȱ
Thisȱtechniqueȱhasȱalmostȱtheȱsameȱeffectȱasȱdeclaringȱaȱstructureȱtag.ȱTheȱdifferenceȱisȱ
thatȱ Simpleȱisȱnowȱtypeȱnameȱratherȱthanȱaȱstructureȱtag,ȱsoȱsubsequentȱdeclarationsȱ
wouldȱlookȱlikeȱthisȱone.ȱ
ȱ
Simple
Simple
TIP
x;
y[20], *z;
ȱ
Ifȱyouȱwantȱtoȱuseȱaȱparticularȱstructureȱinȱmoreȱthanȱoneȱsourceȱfile,ȱyouȱshouldȱputȱ
theȱtagȱdeclarationȱorȱ typedefȱinȱaȱheaderȱfile.ȱYouȱcanȱthenȱ #includeȱtheȱdeclarationȱ
whereverȱitȱisȱneeded.ȱ
Download at http://www.pin5i.com/
Chapter 10 Structures and Unions
272ȱ
10.1.2
Structure Members
ȱ
Inȱ theȱ examplesȱ soȱ far,ȱ Iȱ haveȱ usedȱ onlyȱ simpleȱ typesȱ forȱ members.ȱ Butȱ anyȱ kindȱ ofȱ
variableȱ thatȱ canȱ beȱ declaredȱ outsideȱ ofȱ aȱ structureȱ mayȱ alsoȱ beȱ usedȱ asȱ aȱ structureȱ
member.ȱ Specifically,ȱ structureȱ membersȱ canȱ beȱ scalars,ȱ arrays,ȱ pointers,ȱ andȱ evenȱ
otherȱstructures.ȱ
Hereȱisȱaȱmoreȱcomplexȱexample:ȱ
ȱ
struct
COMPLEX
float f;
int
long
struct
struct
struct
{
a[20];
*lp;
SIMPLE
SIMPLE
SIMPLE
s;
sa[10];
*sp;
};
ȱ
Theȱ membersȱ ofȱ aȱ structureȱ mayȱ haveȱ namesȱ thatȱ areȱ identicalȱ toȱ membersȱ ofȱ otherȱ
structures,ȱsoȱtheȱmemberȱaȱofȱthisȱstructureȱdoesnȇtȱconflictȱwithȱtheȱmemberȱ aȱwhichȱ
isȱaȱpartȱofȱtheȱ struct SIMPLEȱ s.ȱAsȱyouȱwillȱseeȱnext,ȱtheȱwayȱinȱwhichȱmembersȱareȱ
accessedȱallowsȱeitherȱmemberȱtoȱbeȱspecifiedȱwithoutȱambiguity.ȱ
ȱ
ȱ
ȱ
10.1.3
Direct Member Access
ȱ
Theȱ membersȱofȱaȱ structureȱ variableȱ areȱaccessedȱwithȱtheȱ dotȱoperator,ȱ whichȱtakesȱ
twoȱ operands.ȱ Theȱ leftȱ operandȱ isȱ theȱ nameȱ ofȱ aȱ structureȱ variableȱ andȱ theȱ rightȱ
operandȱ isȱ theȱ nameȱ ofȱ theȱ desiredȱ member.ȱ Theȱ resultȱ ofȱ thisȱ expressionȱ isȱ theȱ
designatedȱmember.ȱForȱinstance,ȱconsiderȱtheȱdeclarationȱ
ȱ
struct
COMPLEX comp;
ȱ
ȱ
Theȱmemberȱnamedȱ aȱisȱanȱarray,ȱsoȱtheȱexpressionȱ comp.aȱselectsȱthatȱmember.ȱThisȱ
expressionȱisȱanȱarrayȱname,ȱsoȱyouȱcanȱuseȱitȱinȱanyȱcontextȱinȱwhichȱanȱarrayȱnameȱ
couldȱbeȱused.ȱSimilarly,ȱtheȱmemberȱ sȱisȱaȱstructure,ȱsoȱtheȱexpressionȱ comp.sȱisȱtheȱ
nameȱ ofȱ aȱ structureȱ variableȱ andȱ mayȱ beȱ usedȱ inȱ anyȱ wayȱ thatȱ weȱ mightȱ useȱ anȱ
ordinaryȱstructureȱvariable.ȱȱSpecifically,ȱweȱcanȱuseȱthisȱexpressionȱasȱtheȱleftȱoperandȱ
ofȱ anotherȱ dotȱ operator,ȱ asȱ inȱ (comp.s).a,ȱ toȱ selectȱ theȱ memberȱ namedȱ aȱ ofȱ theȱ
structureȱ s,ȱwhichȱisȱaȱmemberȱofȱtheȱstructureȱ comp.ȱTheȱdotȱoperatorȱassociatesȱfromȱ
leftȱtoȱrightȱsoȱweȱdoȱnotȱneedȱtheȱparentheses;ȱtheȱexpressionȱcomp.s.aȱisȱequivalent.ȱ
Hereȱisȱaȱ moreȱcomplexȱ example.ȱTheȱ memberȱ saȱisȱanȱarrayȱ ofȱstructures,ȱsoȱ
comp.saȱisȱanȱarrayȱnameȱwhoseȱvalueȱisȱaȱpointerȱconstant.ȱ
Download at http://www.pin5i.com/
10.1 Structure Basics
273
Applyingȱaȱsubscriptȱtoȱthisȱexpression,ȱasȱinȱ (comp.sa)[4],ȱyieldsȱoneȱelementȱofȱtheȱ
array.ȱButȱthisȱelementȱisȱaȱstructure,ȱsoȱweȱcanȱuseȱanotherȱdotȱoperatorȱtoȱgetȱoneȱofȱ
itsȱmembers.ȱHereȱisȱtheȱexpression:ȱ
ȱ
( (comp.sa)[4] ).c
ȱ
Theȱ subscriptȱ andȱ dotȱ operatorsȱ haveȱ theȱ sameȱ precedenceȱ andȱ allȱ associateȱ leftȱ toȱ
right,ȱsoȱweȱdonȇtȱneedȱtheseȱparenthesesȱeither.ȱTheȱexpressionȱ
ȱ
comp.sa[4].c
ȱ
isȱequivalent.ȱ
ȱ
ȱ
ȱ
10.1.4
Indirect Member Access
ȱ
Howȱdoȱyouȱaccessȱtheȱmembersȱofȱaȱstructureȱifȱallȱyouȱhaveȱisȱaȱpointerȱtoȱit?ȱTheȱ
firstȱstepȱisȱtoȱapplyȱindirectionȱtoȱtheȱpointer,ȱwhichȱtakesȱyouȱtoȱtheȱstructure.ȱThenȱ
youȱ useȱ theȱ dotȱ operatorȱ toȱ selectȱ aȱ member.ȱ However,ȱ theȱ dotȱ operatorȱ hasȱ higherȱ
precedenceȱ thanȱ theȱ indirection,ȱ soȱ youȱ mustȱ useȱ parenthesesȱ toȱ ensureȱ thatȱ theȱ
indirectionȱisȱevaluatedȱfirst.ȱAsȱanȱexample,ȱsupposeȱanȱargumentȱtoȱaȱfunctionȱisȱaȱ
pointerȱtoȱaȱstructure,ȱasȱinȱthisȱprototype:ȱ
ȱ
void
func( struct COMPLEX *cp );
ȱ
Theȱ functionȱ canȱ accessȱ theȱ memberȱ fȱ ofȱ theȱ structureȱ toȱ whichȱ thisȱ variableȱ pointsȱ
withȱthisȱexpression:ȱ
ȱ
(*cp).f
ȱ
Theȱindirectionȱfollowsȱtheȱpointerȱtoȱtheȱstructure;ȱonceȱthereȱtheȱdotȱoperatorȱselectsȱ
aȱmember.ȱ
Becauseȱ thisȱnotationȱ isȱaȱ nuisance,ȱCȱprovidesȱaȱ moreȱ convenientȱoperatorȱ toȱ
doȱthisȱjob—theȬ>ȱorȱarrowȱoperator.ȱLikeȱtheȱdot,ȱtheȱarrowȱtakesȱtwoȱ operands,ȱbutȱ
theȱ leftȱ operandȱ mustȱ beȱ aȱ pointerȱ toȱ aȱ structure!ȱ Theȱ arrowȱ operatorȱ appliesȱ
indirectionȱ toȱ theȱ leftȱ operandȱ toȱ followȱ theȱ pointer,ȱ andȱ thenȱ selectsȱ theȱ memberȱ
specifiedȱ byȱ theȱ rightȱ operandȱ exactlyȱ likeȱ theȱ dotȱ operator.ȱ Theȱ indirectionȱ isȱ builtȱ
intoȱ theȱ arrowȱ operator,ȱ though,ȱ soȱ weȱ donȇtȱ needȱ anȱ explicitȱ indirectionȱ orȱ theȱ
accompanyingȱparentheses.ȱHereȱareȱaȱfewȱexamplesȱusingȱtheȱsameȱpointerȱasȱbefore.ȱ
ȱ
cp->f
cp->a
cp->s
Download at http://www.pin5i.com/
Chapter 10 Structures and Unions
274ȱ
TheȱfirstȱexpressionȱaccessesȱtheȱfloatingȬpointȱmember.ȱTheȱsecondȱisȱanȱarrayȱname,ȱ
andȱ theȱ thirdȱ isȱ aȱ structure.ȱ Shortlyȱ youȱ willȱ seeȱ numerousȱ additionalȱ examplesȱ toȱ
clarifyȱaccessingȱstructureȱmembers.ȱ
ȱ
ȱ
ȱ
10.1.5
Self-Referential Structures
ȱ
Isȱitȱ legalȱforȱaȱ structureȱ toȱ containȱ aȱ memberȱ thatȱisȱ theȱsameȱtypeȱasȱtheȱ structure?ȱȱ
Hereȱisȱanȱexampleȱtoȱillustrateȱthisȱidea.ȱ
ȱ
struct
SELF_REF1
int
struct
int
{
a;
SELF_REF1 b;
c;
};
ȱ
Thisȱ typeȱ ofȱ selfȱ referenceȱ isȱ notȱ legal,ȱ becauseȱ theȱ memberȱ bȱ isȱ anotherȱ completeȱ
structureȱ thatȱ willȱ containȱ itsȱ ownȱ memberȱ b.ȱ Thisȱ secondȱ memberȱ isȱ yetȱ anotherȱ
completeȱstructureȱandȱcontainsȱitsȱownȱmemberȱb,ȱandȱsoȱforth,ȱforever.ȱTheȱproblemȱ
isȱ somewhatȱ likeȱ aȱ recursiveȱ programȱ thatȱ neverȱ stopsȱ recursing.ȱ Butȱ theȱ followingȱ
declarationȱisȱlegal.ȱCanȱyouȱseeȱtheȱdifference?ȱ
ȱ
struct
SELF_REF2
int
struct
int
{
a;
SELF_REF2 *b;
c;
};
CAUTION!
ȱ
Theȱdifferenceȱbetweenȱthisȱdeclarationȱandȱtheȱpreviousȱoneȱisȱthatȱbȱisȱnowȱaȱpointerȱ
ratherȱ thanȱ aȱ structure.ȱ Theȱcompilerȱ knowsȱ theȱ sizeȱ ofȱ aȱ pointerȱ toȱ aȱ structureȱ evenȱ
beforeȱtheȱsizeȱofȱtheȱstructureȱhasȱbeenȱdetermined,ȱsoȱthisȱselfȱreferenceȱisȱlegal.ȱ
Ifȱ theȱ ideaȱ ofȱ aȱ structureȱ containingȱ aȱ pointerȱ toȱ itselfȱ seemsȱ strange,ȱ keepȱ inȱ
mindȱ thatȱ itȱ willȱ actuallyȱ beȱ pointingȱ toȱ aȱ differentȱ structureȱ ofȱ theȱ sameȱ type.ȱ Moreȱ
advancedȱ dataȱ structures,ȱ suchȱ asȱ linkedȱ listsȱ andȱ trees,ȱ areȱ implementedȱ withȱ thisȱ
technique.ȱȱEachȱstructureȱpointsȱtoȱtheȱnextȱelementȱonȱtheȱlistȱorȱdownȱthisȱbranchȱofȱ
aȱtree.ȱ
ȱ
Watchȱoutȱforȱthisȱtrap:ȱ
ȱ
typedef
struct
{
int
a;
SELF_REF3 *b;
int
c;
} SELF_REF3;
Download at http://www.pin5i.com/
10.1 Structure Basics
275
Theȱ intentȱ ofȱ thisȱ declarationȱ isȱ toȱ createȱ SELF_REF3ȱ asȱ theȱ typeȱ nameȱ forȱ thisȱ
structure.ȱ Itȱ fails,ȱ however.ȱ Theȱ typeȱ nameȱ SELFT_REF3ȱ onlyȱ becomesȱ definedȱ atȱ theȱ
endȱofȱtheȱdeclaration,ȱsoȱitȱisȱundefinedȱinsideȱofȱtheȱdeclarationȱ
Theȱsolutionȱisȱtoȱdefineȱaȱstructureȱtagȱtoȱuseȱinȱdeclaringȱb,ȱasȱshownȱnext.ȱ
ȱ
typedef
struct
int
struct
int
} SELF_REF3;
SELF_REF3_TAG {
a;
SELF_REF3_TAG
c;
*b;
ȱ
ȱ
ȱ
ȱ
10.1.6
Incomplete Declarations
ȱ
Occasionallyȱyouȱwillȱhaveȱtoȱdeclareȱstructuresȱthatȱareȱmutuallyȱdependent,ȱthatȱis,ȱ
eachȱ containsȱ oneȱ orȱ moreȱ membersȱ ofȱ theȱ otherȱ type.ȱ Asȱ withȱ selfȱ referentialȱ
structures,ȱatȱleastȱoneȱofȱtheȱstructuresȱmustȱreferȱtoȱtheȱotherȱonlyȱthroughȱpointers.ȱȱ
Theȱproblemȱisȱinȱtheȱdeclaration:ȱifȱeachȱstructureȱrefersȱtoȱtheȱotherȇsȱstructureȱtag,ȱ
whichȱoneȱisȱdeclaredȱfirst?ȱ
Theȱ solutionȱ toȱ thisȱ problemȱ isȱ theȱ incompleteȱ declaration,ȱ whichȱ declaresȱ anȱ
identifierȱtoȱbeȱaȱstructureȱtag.ȱȱWeȱcanȱthenȱuseȱtheȱtagȱinȱdeclarationsȱwhereȱtheȱsizeȱ
ofȱ theȱ structureȱ isȱ notȱ needed,ȱ suchȱ asȱ declaringȱ pointersȱ toȱ it.ȱ Aȱ subsequentȱ
declarationȱassociatesȱaȱmemberȱlistȱwithȱtheȱtag.ȱ
Considerȱ thisȱ example,ȱ inȱ whichȱ twoȱ differentȱ structureȱ typesȱ eachȱ containȱ aȱ
pointerȱtoȱtheȱother.ȱ
ȱ
struct
B;
struct
A
{
struct
B
*partner;
/* other declarations */
};
struct
B;
struct
A
*partner;
/* other declarations */
};
ȱ
Theȱincompleteȱdeclarationȱofȱtheȱtagȱ Bȱisȱneededȱinȱdieȱmemberȱlistȱofȱ A.ȱOnceȱ Aȱhasȱ
beenȱdeclared,ȱtheȱmemberȱlistȱforȱBȱcanȱbeȱdeclared.ȱ
Download at http://www.pin5i.com/
Chapter 10 Structures and Unions
276ȱ
10.1.7
Initializing Structures
ȱ
Structuresȱ canȱ beȱ initializedȱ inȱ muchȱ theȱ sameȱ wayȱ asȱ arrays.ȱ Aȱ commaȬseparatedȱ
initializerȱ listȱ enclosedȱ inȱ bracesȱ isȱ usedȱ toȱ specifyȱ theȱ valuesȱ forȱ theȱ structureȱ
members.ȱȱTheȱvaluesȱareȱwrittenȱinȱtheȱorderȱgivenȱinȱtheȱmemberȱlist.ȱMissingȱvaluesȱ
causeȱtheȱremainingȱmembersȱtoȱgetȱdefaultȱinitialization.ȱ
Structuresȱ containingȱ arrayȱ orȱ structureȱ membersȱ areȱ initializedȱ similarȱ toȱ
multidimensionalȱarrays.ȱAȱcompleteȱinitializerȱlistȱforȱtheȱaggregateȱmemberȱisȱnestedȱ
withinȱtheȱinitializerȱlistȱforȱtheȱstructure.ȱȱHereȱisȱanȱexample:ȱ
ȱ
struct
INIT_EX
{
int
a;
short b[10];
Simple
c;
} x = {
10,
{ 1, 2, 3, 4, 5 },
{ 25, 'x', 1.9 }
};
ȱ
ȱ
ȱ
10.2 Structures, Pointers, and Members
ȱ
Theȱ operatorsȱ forȱ accessingȱ structuresȱ andȱ theirȱ membersȱ directlyȱ andȱ throughȱ
pointersȱareȱquiteȱsimple,ȱbutȱtheyȱcanȱbecomeȱconfusingȱwhenȱappliedȱinȱcomplicatedȱ
situations.ȱHereȱareȱsomeȱexamplesȱtoȱhelpȱyouȱbetterȱunderstandȱhowȱtheȱoperatorsȱ
work.ȱTheȱexamplesȱuseȱtheȱfollowingȱdeclarations.ȱ
ȱ
typedef
} Ex2;
typedef
} Ex;
struct
{
int
a;
short b[2];
struct
int
char
Ex2
struct
EX {
a;
b[3];
c;
EX
*d;
ȱ
StructuresȱofȱtypeȱExȱwillȱbeȱpicturedȱlikeȱthis:ȱ
ȱ
c
aȱ
d
bȱ
a
b
Download at http://www.pin5i.com/
10.2 Structures, Pointers, and Members
277
Theȱstructuresȱareȱpicturedȱthisȱwayȱtoȱmakeȱtheȱexamplesȱclearer.ȱInȱfact,ȱtheȱdiagramȱ
isȱ notȱ completelyȱ accurate,ȱ becauseȱ theȱ compilerȱ avoidsȱ wastingȱ spaceȱ betweenȱ theȱ
membersȱwheneverȱitȱcan.ȱ
Theȱfirstȱexamplesȱwillȱuseȱtheseȱdeclarations:ȱ
ȱ
Ex
Ex
x = { 10, "Hi", {5, { -1, 25 } }, 0 };
*px = &x;
ȱ
whichȱproduceȱtheȱfollowingȱvariables:ȱ
ȱ
xȱ
ȱ
ȱ
c
pxȱ
a
dȱ
b
ȱ
a
b
0
10
ȇHȇȱȱȇiȇȱȱȱȱ0
ȱ
Ȭ1ȱȱ25ȱ
5
ȱ
ȱ
ȱ
Weȱ willȱ nowȱ examineȱ andȱ diagramȱ differentȱ expressionsȱ usingȱ theȱ notationȱ fromȱ
Chapterȱ6.ȱ
ȱ
ȱ
ȱ
10.2.1
Accessing the Pointer
ȱ
Letȇsȱbeginȱwithȱtheȱpointerȱvariable.ȱTheȱRȬvalueȱofȱtheȱexpressionȱpxȱis:ȱ
ȱ
xȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
pxȱ
a
10
b
ȇHȇȱȱȇiȇȱȱȱȱ0
c
a
5
b
Ȭ1ȱȱ25ȱ
dȱ
0
pxȱ isȱ aȱ pointerȱ variableȱ butȱ thereȱ isnȇtȱ anyȱ indirectionȱ operator,ȱ soȱ theȱ valueȱ ofȱ theȱ
expressionȱisȱtheȱcontentsȱofȱpx.ȱTheȱLȬvalueȱofȱthisȱexpressionȱis:ȱ
ȱ
xȱ
ȱ
ȱ
c
pxȱ
a
dȱ
b
ȱ
a
b
0
10
ȇHȇȱȱȇiȇȱȱȱȱ0
ȱ
Ȭ1ȱȱ25ȱ
5
ȱ
ȱ
whichȱshowsȱthatȱtheȱoldȱvalueȱofȱpxȱisȱaboutȱtoȱbeȱreplacedȱbyȱaȱnewȱvalue.ȱ
Download at http://www.pin5i.com/
Chapter 10 Structures and Unions
278ȱ
Nowȱ considerȱ theȱ expressionȱ px + l.ȱ Thisȱ expressionȱ isȱ notȱ aȱ legalȱ LȬvalueȱ
becauseȱitsȱvalueȱisȱnotȱstoredȱinȱanyȱidentifiableȱmemoryȱlocation.ȱȱTheȱexpressionȇsȱ
RȬvalueȱ isȱ moreȱ interesting.ȱ Ifȱ pxȱ hadȱ beenȱ pointingȱ toȱ anȱ elementȱ ofȱ anȱ arrayȱ ofȱ
structures,ȱthisȱexpressionȱwouldȱpointȱtoȱtheȱnextȱstructureȱinȱtheȱarray.ȱAsȱitȱis,ȱtheȱ
expressionȱ isȱ illegalȱ becauseȱ thereȱ isȱ noȱ wayȱ ofȱ tellingȱ whetherȱ whatȱ comesȱ nextȱ inȱ
memoryȱisȱoneȱofȱtheseȱstructuresȱorȱsomethingȱelse.ȱȱTheȱcompilerȱisȱnotȱableȱtoȱdetectȱ
suchȱerrors,ȱsoȱitȱisȱupȱtoȱyouȱtoȱdetermineȱwhenȱpointerȱarithmeticȱisȱmeaningful.ȱ
ȱ
ȱ
ȱ
10.2.2
Accessing the Structure
ȱ
Weȱ canȱ applyȱ indirectionȱ toȱ theȱ pointerȱ withȱ theȱ *ȱ operator.ȱ Theȱ RȬvalueȱ ofȱ theȱ
expressionȱ*pxȱisȱtheȱentireȱstructureȱtoȱwhichȱpxȱpoints.ȱ
ȱ
xȱ
ȱ
ȱ
c
pxȱ
a
dȱ
b
ȱ
a
b
0
10
ȇHȇȱȱȇiȇȱȱȱȱ0
ȱ
Ȭ1ȱȱ25ȱ
5
ȱ
ȱ
ȱ
Theȱindirectionȱfallowsȱtheȱarrow,ȱwhichȱisȱshownȱasȱaȱsolidȱline,ȱandȱtheȱresultȱisȱtheȱ
wholeȱstructure.ȱȱYouȱcanȱassignȱthisȱexpressionȱtoȱanotherȱstructureȱofȱtheȱsameȱtype,ȱ
orȱ youȱ canȱ useȱ itȱ asȱ theȱ leftȱ operandȱ ofȱ theȱ dotȱ operatorȱ toȱ selectȱ aȱ specificȱ member.ȱȱ
Youȱcanȱalsoȱpassȱitȱasȱanȱargumentȱtoȱaȱfunctionȱorȱreturnȱitȱasȱtheȱvalueȱofȱaȱfunctionȱ
(thoughȱthereȱareȱsomeȱefficiencyȱconcernsȱaboutȱtheseȱlastȱtwoȱoperationsȱthatȱwillȱbeȱ
discussedȱlater).ȱTheȱLȬvalueȱofȱtheȱexpressionȱ*pxȱis:ȱ
ȱ
xȱ
ȱ
ȱ
c
pxȱ
a
dȱ
b
ȱ
a
b
ȱ
ȱ
ȱ
ȱ
Here,ȱtheȱstructureȱisȱaboutȱtoȱreceiveȱaȱnewȱvalue,ȱofȱmoreȱprecisely,ȱnewȱvaluesȱforȱ
allȱ ofȱ itsȱ members.ȱ Asȱ anȱ LȬvalue,ȱ itȱ isȱ theȱ placeȱ thatȱ isȱ important,ȱ notȱ theȱ valuesȱ
containedȱinȱtheȱplace.ȱ
Theȱexpressionȱ *px + 1ȱisȱillegal,ȱbecauseȱtheȱresultȱofȱ *pxȱisȱaȱstructure.ȱAdditionȱisȱ
notȱ definedȱ betweenȱ structuresȱ andȱ integers.ȱ Butȱ whatȱ aboutȱ theȱ expressionȱ
Download at http://www.pin5i.com/
10.2 Structures, Pointers, and Members
279
ȱ*( px + 1 )ȱ?ȱIfȱxȱhadȱbeenȱanȱelementȱofȱanȱarray,ȱthisȱexpressionȱwouldȱreferȱtoȱtheȱ
structureȱthatȱfollowedȱit.ȱButȱxȱisȱaȱscalar,ȱsoȱthisȱexpressionȱisȱactuallyȱillegal.ȱ
ȱ
ȱ
ȱ
ȱ
10.2.3
Accessing Structure Members
ȱ
Nowȱletȇsȱlookȱatȱtheȱarrowȱoperator.ȱTheȱRȬvalueȱofȱtheȱexpressionȱpx->aȱisȱ
ȱ
xȱ
ȱ
ȱ
c
pxȱ
a
dȱ
b
ȱ
a
b
0
10
ȇHȇȱȱȇiȇȱȱȱȱ0
ȱ
Ȭ1ȱȱ25ȱ
5
ȱ
ȱ
ȱ
TheȱȬ>ȱoperatorȱappliesȱindirectionȱtoȱ pxȱ(indicatedȱbyȱtheȱsolidȱarrow)ȱinȱorderȱtoȱgetȱ
theȱstructure,ȱandȱthenȱselectsȱtheȱaȱmember.ȱTheȱexpressionȱ px->aȱisȱusedȱwhenȱyouȱ
haveȱaȱpointerȱtoȱaȱstructureȱbutȱdoȱnotȱknowȱitsȱname.ȱȱIfȱyouȱknewȱtheȱnameȱofȱthisȱ
structure,ȱyouȱcouldȱuseȱtheȱequivalentȱexpressionȱx.aȱinstead.ȱ
Letȇsȱ pauseȱ hereȱ andȱ compareȱ theȱ expressionsȱ *pxȱ andȱ px->aȱ toȱ eachȱ other.ȱ Inȱ
bothȱcases,ȱtheȱaddressȱinȱ pxȱisȱusedȱtoȱfoldȱtheȱstructure.ȱButȱtheȱfirstȱmemberȱinȱtheȱ
structureȱisȱ a,ȱsoȱtheȱaddressȱofȱ aȱisȱtheȱsameȱasȱtheȱaddressȱofȱtheȱstructure.ȱItȱwouldȱ
seem,ȱthen,ȱthatȱpxȱpointsȱtoȱtheȱstructureȱandȱtoȱtheȱfirstȱmemberȱofȱtheȱstructure:ȱafterȱ
all,ȱ theyȱ bothȱ haveȱ theȱ sameȱ address.ȱ Thisȱ analysisȱ isȱ onlyȱ halfȱ correct,ȱ though.ȱ
Althoughȱbothȱaddressesȱhaveȱtheȱsameȱvalue,ȱtheyȱhaveȱdifferentȱtypes.ȱTheȱvariableȱ
pxȱ wasȱ declaredȱ asȱ aȱ pointerȱ toȱ aȱ structure,ȱ soȱ theȱ resultȱ ofȱ theȱ expressionȱ *pxȱ isȱ theȱ
wholeȱstructure,ȱnotȱitsȱfirstȱmember.ȱ
Letȇsȱcreateȱaȱpointerȱtoȱanȱinteger.ȱ
ȱ
int
*pi;
ȱ
Canȱweȱmakeȱ piȱpointȱtoȱtheȱintegerȱmemberȱ a?ȱIfȱ piȱhadȱtheȱsameȱvalueȱasȱ px,ȱthenȱ
theȱresultȱofȱtheȱexpressionȱ*piȱwouldȱbeȱtheȱmemberȱa.ȱȱButȱtheȱassignmentȱ
ȱ
ȱ
pi = px;
ȱ
illegalȱbecauseȱtheirȱtypesȱdoȱnotȱmatch.ȱUsingȱaȱcastȱworks,ȱ
ȱ
pi = (int *) px;
ȱ
ȱ
butȱ isȱ dangerousȱ becauseȱ itȱ circumventsȱ theȱ compilerȇsȱ typeȱ checking.ȱ Theȱ correct
Download at http://www.pin5i.com/
280ȱ
Chapter 10 Structures and Unions
expressionȱisȱsimpler—toȱgetȱaȱpointerȱtoȱpx->a,ȱuseȱtheȱ&ȱoperator:ȱ
ȱ
ȱ
pi = &px->a;
ȱ
Theȱ precedenceȱ ofȱ theȱ ->ȱ operatorȱ isȱ higherȱ thanȱ thatȱ ofȱ &,ȱ soȱ parenthesesȱ areȱ notȱ
neededȱinȱthisȱexpression.ȱȱLetȇsȱexamineȱaȱdiagramȱofȱ&px->a:ȱ
ȱ
xȱ
ȱ
ȱ
c
a
dȱ
b
ȱ
a
b
0
10
ȇHȇȱȱȇiȇȱȱȱȱ0
ȱ
Ȭ1ȱȱ25ȱ
5
pxȱ
ȱ
ȱ
ȱ
Noteȱ howȱ theȱ valueȱ inȱ theȱ ovalȱ pointsȱ directlyȱ toȱ theȱ aȱ memberȱ ofȱ theȱ structure,ȱ asȱ
opposedȱtoȱpx,ȱwhichȱpointsȱtoȱtheȱentireȱstructure.ȱAfterȱtheȱassignmentȱabove,ȱpiȱandȱ
pxȱ willȱ haveȱ theȱ sameȱ value.ȱ Butȱ theirȱ typesȱ areȱ different,ȱ soȱ theȱ resultȱ ofȱ applyingȱ
indirectionȱ toȱ themȱ willȱ alsoȱ beȱ different: *pxȱ isȱ theȱ wholeȱ structure,ȱ and *piȱ isȱ aȱ
singleȱinteger.ȱ
Hereȱ isȱ anotherȱ exampleȱ usingȱ theȱ arrowȱ operator.ȱ Theȱ valueȱ ofȱ px->bȱ isȱ aȱ
pointerȱconstantȱbecauseȱbȱisȱanȱarray.ȱThisȱexpressionȱisȱnotȱaȱlegalȱLȬvalue.ȱHereȱisȱitsȱ
RȬvalue.ȱ
ȱ
ȱ
ȱ
xȱ
ȱ
ȱ
c
pxȱ
a
dȱ
b
ȱ
a
b
0
10
ȇHȇȱȱȇiȇȱȱȱȱ0
ȱ
Ȭ1ȱȱ25ȱ
5
ȱ
ȱ
ȱ
Ifȱweȱaddȱindirectionȱtoȱthisȱexpression,ȱitȱselectsȱtheȱfirstȱelementȱofȱtheȱarray.ȱȱ
Withȱaȱsubscriptȱorȱpointerȱarithmetic,ȱotherȱelementsȱofȱtheȱarrayȱcanȱbeȱobtainedȱasȱ
well.ȱTheȱexpressionȱpx->b[1]ȱselectsȱtheȱsecondȱarrayȱelement,ȱlikeȱthis:ȱ
ȱ
xȱ
ȱ
ȱ
c
pxȱ
a
dȱ
b
ȱ
a
b
0
10
ȇHȇȱȱȇiȇȱȱȱȱ0
ȱ
Ȭ1ȱȱ25ȱ
5
ȱ
Download at http://www.pin5i.com/
10.2 Structures, Pointers, and Members
10.2.4
281
Accessing a Nested Structure
ȱ
Toȱaccessȱtheȱmemberȱc,ȱwhichȱisȱaȱstructure,ȱuseȱtheȱexpressionȱ px->c.ȱItsȱRȬvalueȱisȱ
theȱentireȱstructure.ȱ
ȱ
xȱ
ȱ
ȱ
c
pxȱ
a
dȱ
b
ȱ
a
b
0
10
ȇHȇȱȱȇiȇȱȱȱȱ0
ȱ
Ȭ1ȱȱ25ȱ
5
ȱ
ȱ
ȱ
Theȱdotȱoperatorȱcanȱbeȱaddedȱtoȱthisȱexpressionȱtoȱaccessȱspecificȱmembersȱofȱ c.ȱForȱ
example,ȱtheȱexpressionȱpx->c.aȱhasȱtheȱfollowingȱRȬvalue:ȱ
ȱ
xȱ
ȱ
ȱ
c
pxȱ
a
dȱ
b
ȱ
a
b
0
10
ȇHȇȱȱȇiȇȱȱȱȱ0
ȱ
Ȭ1ȱȱ25ȱ
5
ȱ
ȱ
ȱ
Thisȱexpressionȱcontainsȱbothȱtheȱdotȱandȱarrowȱoperators.ȱTheȱarrowȱisȱusedȱbecauseȱ
pxȱisȱnotȱaȱstructure,ȱitȱpointsȱtoȱaȱstructure.ȱThenȱtheȱdotȱoperatorȱisȱusedȱbecauseȱȱȱpx>cȱdoesȱnotȱpointȱtoȱaȱstructure,ȱitȱisȱaȱstructure.ȱ
Hereȱisȱaȱmoreȱcomplexȱexpression:ȱ
ȱ
*px->c.b
ȱ
Examiningȱ thisȱ expressionȱ isȱ easyȱ ifȱ youȱ takeȱ oneȱ stepȱ atȱ aȱ time.ȱ Thereȱ areȱ threeȱ
operators,ȱ andȱ theȱ arrowȱ goesȱ firstȱ px->cȱ givesȱ theȱ structureȱ c.ȱ Addingȱ .bȱ toȱ theȱ
expressionȱ selectsȱ theȱ memberȱ bȱ fromȱ structureȱ c.ȱ bȱ isȱ anȱ array,ȱ soȱ px->c.b isȱ aȱ
(constant)ȱpointerȱtoȱtheȱfirstȱelementȱofȱtheȱarray.ȱFinally,ȱtheȱindirectionȱisȱappliedȱtoȱ
thisȱ pointer,ȱ soȱ theȱ resultȱ isȱ theȱ firstȱ elementȱ ofȱ theȱ array.ȱ Theȱ expressionȱ isȱ
diagrammedȱbelow.ȱ
ȱ
xȱ
ȱ
ȱ
c
pxȱ
a
dȱ
b
ȱ
a
b
0
10
ȇHȇȱȱȇiȇȱȱȱȱ0
ȱ
Ȭ1ȱȱ25ȱ
5
ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
Chapter 10 Structures and Unions
282ȱ
10.2.5
Accessing a Pointer Member
ȱ
Theȱexpressionȱpx->dȱgivesȱtheȱresultȱyouȱwouldȱexpect—itsȱRȬvalueȱisȱ0,ȱandȱitsȱȱȱȱȱȱLȬ
valueȱisȱtheȱlocationȱitself.ȱTheȱexpressionȱ *px->dȱisȱmoreȱinteresting.ȱHereȱindirectionȱ
isȱappliedȱtoȱtheȱpointerȱvalueȱfoundȱinȱtheȱmemberȱ d.ȱButȱdȱcontainsȱtheȱnullȱpointer,ȱ
soȱ itȱ doesnȇtȱ pointȱ toȱ anything.ȱ Dereferencingȱ aȱ nullȱ pointerȱ isȱ anȱ error,ȱ butȱ asȱ
discussedȱearlier,ȱsomeȱenvironmentsȱwillȱnotȱcatchȱitȱatȱrunȱtime.ȱOnȱtheseȱmachines,ȱ
theȱ programȱ willȱ accessȱ whateverȱ isȱ atȱ locationȱ zeroȱ asȱ ifȱ itȱ wereȱ oneȱ ofȱ theseȱ
structures,ȱ andȱ thenȱ continueȱ merrilyȱ onȱ asȱ ifȱ nothingȱ wereȱ wrong.ȱ Thisȱ exampleȱ
illustratesȱ theȱ importanceȱ ofȱ checkingȱ toȱ seeȱ thatȱ pointersȱ reallyȱ pointȱ toȱ somethingȱ
beforeȱdereferencingȱthem.ȱ
Letȇsȱcreateȱanotherȱstructureȱandȱsetȱx.dȱtoȱpointȱtoȱitȱ
ȱ
Ex
y;
x.d = &y;
ȱ
Nowȱweȱcanȱevaluateȱ*px->d.ȱ
ȱ
xȱ
ȱ
ȱ
c
pxȱ
a
dȱ
b
ȱ
a
b
10
ȇHȇȱȱȇiȇȱȱȱȱ0
ȱ
Ȭ1ȱȱ25ȱ
5
ȱ
ȱ
ȱ
yȱ
ȱ
ȱ
c
a
dȱ
b
ȱ
a
b
ȱ
ȱ
ȱ
ȱ
Theȱ memberȱ dȱ pointsȱ toȱ aȱ structure,ȱ soȱ applyingȱ indirectionȱ toȱ itȱ yieldsȱ theȱ entireȱ
structure.ȱTheȱnewȱstructureȱwasȱnotȱinitializedȱexplicitly,ȱsoȱnoȱvaluesȱareȱshownȱforȱ
itsȱmembersȱinȱtheȱdiagram.ȱ
Asȱ youȱ mayȱ expect,ȱ membersȱ ofȱ thisȱ newȱ structureȱ canȱ beȱ selectedȱ byȱ addingȱ
moreȱ operatorsȱ toȱ theȱ expression.ȱ Weȱ useȱ theȱ arrowȱ becauseȱ dȱ pointsȱ toȱ aȱ structure.ȱȱ
Whatȱdoȱtheseȱexpressionsȱaccomplish?ȱ
ȱ
px->d->a
px->d->b
px->d->c
px->d->c.a
px->d->c.b[1]
Download at http://www.pin5i.com/
10.3 Structure Storage Allocation
HereȱisȱaȱdiagramȱofȱtheȱRȬvalueȱofȱtheȱlastȱexpression.ȱ
ȱ
xȱ
ȱ
ȱ
c
pxȱ
a
b
ȱ
a
b
10
ȇHȇȱȱȇiȇȱȱȱȱ0
ȱ
Ȭ1ȱȱ25ȱ
5
ȱ
ȱ
ȱ
yȱ
ȱ
ȱ
c
a
b
ȱ
a
b
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
283
dȱ
dȱ
10.3 Structure Storage Allocation
ȱ
Howȱ areȱ structuresȱ actuallyȱ storedȱ inȱ memory?ȱ Theȱ diagramsȱ inȱ theȱ previousȱ
examplesȱ implyȱ thatȱ structuresȱ containȱ aȱ lotȱ ofȱ emptyȱ space.ȱ Thisȱ pictureȱ isȱ notȱ
entirelyȱaccurate.ȱMemoryȱisȱallocatedȱforȱeachȱofȱtheȱmembers,ȱoneȱafterȱanother,ȱinȱ
theȱorderȱgivenȱbyȱtheȱmemberȱlist.ȱExtraȱmemoryȱisȱusedȱonlyȱwhenȱneededȱtoȱgetȱtheȱ
correctȱboundaryȱalignmentȱofȱaȱmember.ȱToȱillustrate,ȱconsiderȱthisȱstructure:ȱ
Toȱillustrate,ȱconsiderȱthisȱstructure:ȱ
ȱ
struct
ALIGN {
char
int
char
a;
b;
c;
};
ȱ
Onȱ aȱ machineȱ whoseȱ integersȱ occupyȱ fourȱ bytesȱ andȱ mustȱ beginȱ atȱ aȱ byteȱ whoseȱ
addressȱisȱevenlyȱdivisibleȱbyȱfour,ȱthisȱstructureȱwouldȱappearȱlikeȱthisȱinȱmemory:ȱ
ȱ
aȱ ȱ ȱ ȱ b ȱ ȱ ȱ cȱ ȱ ȱ ȱ
ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ ȱ
ȱ
Theȱcompilerȱisȱforbiddenȱtoȱskipȱbytesȱforȱboundaryȱalignmentȱatȱtheȱbeginningȱofȱaȱ
structure,ȱsoȱallȱstructuresȱmustȱbeginȱonȱwhateverȱboundaryȱisȱrequiredȱforȱtheȱmostȱ
stringentȱ dataȱ type.ȱ Thus,ȱ theȱ memberȱ a,ȱ shownȱ byȱ theȱ leftmostȱ box,ȱ beginsȱ atȱ anȱ
addressȱ divisibleȱ byȱ four.ȱ Theȱ nextȱ memberȱ isȱ anȱ integer,ȱ soȱ threeȱ bytesȱ (shownȱ in
Download at http://www.pin5i.com/
284ȱ
Chapter 10 Structures and Unions
ȱgray)ȱmustȱbeȱskippedȱtoȱreachȱanȱappropriateȱboundary.ȱAfterȱtheȱintegerȱcomesȱtheȱ
lastȱcharacter.ȱ
Ifȱaȱsecondȱvariableȱofȱtheȱsameȱtypeȱwereȱdeclared,ȱitȱwouldȱhaveȱtoȱbeginȱonȱaȱ
boundaryȱ ofȱ fourȱ asȱ well,ȱ soȱ threeȱ moreȱ bytesȱ wouldȱ beȱ skippedȱ atȱ dieȱ endȱ ofȱ theȱ
structure.ȱThus,ȱeachȱstructureȱwouldȱrequireȱtwelveȱbytesȱofȱmemoryȱbutȱwouldȱonlyȱ
useȱsixȱofȱthem,ȱwhichȱisȱnotȱveryȱgoodȱutilization.ȱ
Youȱ canȱ minimizeȱ theȱ spaceȱ lostȱ toȱ boundaryȱ alignmentȱ inȱ structuresȱ byȱ
rearrangingȱtheȱmemberȱlistȱinȱtheȱstructureȱdeclarationȱsoȱthatȱtheȱmembersȱwithȱtheȱ
strictestȱboundaryȱrequirementsȱappearȱfirstȱandȱthoseȱwithȱtheȱweakestȱrequirementsȱ
appearȱlast.ȱForȱexample,ȱthisȱstructureȱ
ȱ
struct
ALIGN2
int
char
char
{
b;
a;
c;
};
ȱ
containsȱtheȱsameȱmembersȱasȱtheȱpreviousȱstructure,ȱbutȱrequiresȱonlyȱeightȱbytes,ȱaȱ
savingsȱofȱ33%.ȱȱTheȱtwoȱcharactersȱcanȱbeȱstoredȱadjacentȱtoȱoneȱanother,ȱsoȱtheȱonlyȱ
wastedȱspaceȱisȱtheȱtwoȱbytesȱskippedȱafterȱtheȱstructure.ȱ
ȱ
Thereȱ mayȱ beȱ goodȱ reasonsȱ whyȱ weȱ mightȱ notȱ wantȱ toȱ rearrangeȱ theȱ membersȱ ofȱ aȱ
structureȱtoȱreduceȱtheȱmemoryȱlostȱtoȱalignment.ȱForȱexample,ȱweȱmayȱwantȱtoȱkeepȱ
relatedȱ structureȱ membersȱ togetherȱ forȱ easierȱ maintenanceȱ andȱ readability.ȱ (Lackingȱ
anyȱsuchȱreasons,ȱhowever,ȱtheȱmembersȱofȱaȱstructureȱshouldȱbeȱarrangedȱaccordingȱ
toȱ theirȱ boundaryȱ needsȱ inȱ orderȱ toȱ minimizeȱ theȱ memoryȱ thatȱ willȱ beȱ lostȱ toȱ
alignment.ȱ
Whenȱtheȱprogramȱwillȱbeȱcreatingȱhundredsȱorȱthousandsȱofȱtheȱstructures,ȱtheȱ
needȱtoȱreduceȱwastedȱmemoryȱcanȱbecomeȱmoreȱimportantȱthanȱreadabilityȱconcerns.ȱ
Inȱthisȱtypeȱofȱsituation,ȱaddingȱcommentsȱtoȱtheȱdeclarationȱmayȱhelpȱregainȱmuchȱofȱ
theȱlostȱreadability.ȱ
sizeofȱ givesȱ theȱ totalȱ sizeȱ ofȱ aȱ structure,ȱ whichȱ includesȱ anyȱ bytesȱ thatȱ areȱ
skippedȱ forȱ boundaryȱ alignment.ȱ Ifȱ youȱ mustȱ determineȱ theȱ actualȱ positionȱ ofȱ aȱ
memberȱ inȱ aȱ structure,ȱ takingȱ intoȱ accountȱ boundaryȱ alignment,ȱ useȱ theȱ offsetofȱ
macroȱ(whichȱisȱdefinedȱinȱstddef.h).ȱ
ȱ
offsetoff( type, member )
ȱ
typeȱisȱtheȱtypeȱofȱtheȱstructure,ȱandȱ memberȱisȱtheȱnameȱofȱtheȱmemberȱyouȱwant.ȱTheȱ
resultȱ isȱ aȱ size_tȱ valueȱ specifyingȱ theȱ numberȱ ofȱ bytesȱ fromȱ theȱ beginningȱ ofȱ theȱ
structureȱ whereȱ theȱ specifiedȱ memberȱ begins.ȱ Forȱ example,ȱ withȱ theȱ declarationȱ
above,ȱ
ȱ
offsetof( struct ALIGN, b )
ȱ
returnsȱfour.ȱ
Download at http://www.pin5i.com/
10.4 Structures as Function Arguments
285
10.4 Structures as Function Arguments
ȱ
Aȱstructureȱvariableȱisȱaȱscalarȱandȱcanȱbeȱusedȱwhereverȱanyȱotherȱscalarȱcanȱbeȱused.ȱ
Thusȱitȱisȱlegalȱtoȱpassȱaȱstructureȱasȱanȱargumentȱtoȱaȱfunction,ȱbutȱthisȱtechniqueȱisȱ
oftenȱinappropriate.ȱ
Theȱ followingȱ codeȱ fragmentsȱ areȱ fromȱ aȱ programȱ writtenȱ toȱ operateȱ anȱ
electronicȱ cashȱ register.ȱ Hereȱ isȱ theȱ declarationȱ forȱ aȱ structureȱ thatȱ containsȱ
informationȱaboutȱanȱindividualȱtransaction.ȱ
ȱ
typedef
struct
char
int
float
float
} Transaction;
{
product[PRODUCT_SIZE];
quantity;
unit_price;
total_amount;
ȱ
Whenȱaȱtransactionȱoccurs,ȱthereȱareȱmanyȱstepsȱinvolved,ȱoneȱofȱwhichȱisȱprintingȱtheȱ
receipt.ȱLetȇsȱlookȱatȱsomeȱdifferentȱwaysȱtoȱperformȱthisȱtask.ȱ
ȱ
void
print_receipt( Transaction trans )
{
printf( "%s\n", trans.product );
printf( "%d @ %.2f total %.2f\n", trans.quantity,
trans.unit_price, trans.total_amount );
}
CAUTION!
ȱ
Ifȱcurrent_transȱisȱaȱTransactionȱstructure,ȱweȱcouldȱcallȱtheȱfunctionȱlikeȱthis:ȱ
ȱ
ȱ
print_receipt( current_trans );
ȱ
Thisȱapproachȱproducesȱtheȱcorrectȱresult,ȱbutȱitȱisȱinefficientȱbecauseȱtheȱcallȬbyȬvalueȱ
argumentȱpassingȱofȱCȱrequiresȱthatȱaȱcopyȱofȱtheȱargumentȱbeȱgivenȱtoȱtheȱfunction.ȱȱ
Ifȱ PRODUCT_SIZEȱisȱ20ȱandȱweȱareȱusingȱaȱmachineȱwithȱfourȬbyteȱintegersȱandȱfloats,ȱ
thisȱparticularȱstructureȱoccupiesȱ32ȱbytes.ȱToȱpassȱitȱasȱanȱargument,ȱ32ȱbytesȱmustȱbeȱ
copiedȱontoȱtheȱstackȱandȱthenȱdiscardedȱlater.ȱ
Compareȱtheȱpreviousȱfunctionȱwithȱthisȱone:ȱ
ȱ
void
print_receipt( Transaction *trans )
{
printf( "%s\n", trans->product );
printf( "%d @ %.2f total %.2f\n", trans->quantity,
trans->unit_price, trans->total_amount );
}
Download at http://www.pin5i.com/
286ȱ
Chapter 10 Structures and Unions
whichȱwouldȱbeȱcalledȱinȱthisȱmanner:ȱ
ȱ
ȱ
print_receipt( &current_trans );
ȱ
Here,ȱ aȱ pointerȱ toȱ theȱ structureȱ isȱ passed.ȱ Theȱ pointerȱ isȱ smallerȱ thanȱ theȱ entireȱ
structureȱandȱthereforeȱmoreȱefficientȱtoȱpushȱonȱtheȱstack.ȱTheȱpriceȱpaidȱforȱpassingȱ
aȱpointerȱisȱthatȱweȱmustȱuseȱindirectionȱinȱtheȱfunctionȱtoȱaccessȱtheȱmembersȱofȱtheȱ
structure.ȱTheȱbiggerȱtheȱstructure,ȱtheȱmoreȱefficientȱitȱisȱtoȱpassȱaȱpointerȱtoȱit.ȱ
Onȱ manyȱ machines,ȱ youȱ canȱ improveȱ theȱ efficiencyȱ ofȱ theȱ pointerȱ versionȱ byȱ
declaringȱtheȱparameterȱtoȱbeȱaȱregisterȱvariable.ȱOnȱsomeȱmachines,ȱthisȱdeclarationȱ
requiresȱ anȱ extraȱ instructionȱ atȱ theȱ beginningȱ ofȱ theȱ functionȱ toȱ copyȱ theȱ argumentȱ
fromȱtheȱstackȱ(whereȱitȱwasȱpassed)ȱtoȱtheȱregisterȱinȱwhichȱitȱwillȱbeȱused.ȱButȱifȱtheȱ
functionȱ performsȱ indirectionȱ onȱ theȱ pointerȱ moreȱ thanȱ twoȱ orȱ threeȱ times,ȱ thenȱ theȱ
savingsȱ realizedȱ inȱ theȱ indirectionsȱ willȱ beȱ greaterȱ thanȱ theȱ costȱ ofȱ theȱ additionalȱ
instruction.ȱ
Aȱdrawbackȱofȱpassingȱaȱpointerȱisȱthatȱtheȱfunctionȱisȱnowȱableȱtoȱmodifyȱtheȱ
valuesȱinȱtheȱcallingȱprogramȇsȱstructureȱvariable.ȱIfȱitȱisȱnotȱsupposedȱtoȱdoȱthisȱyouȱ
canȱuseȱtheȱconstȱkeywordȱinȱtheȱfunctionȱtoȱpreventȱsuchȱmodifications.ȱHereȱisȱwhatȱ
theȱfunctionȱprototypeȱlooksȱlikeȱwithȱtheseȱtwoȱchanges:ȱ
ȱ
void print_receipt( register Transaction const *trans );
ȱ
Letȇsȱmoveȱonȱtoȱanotherȱstepȱinȱprocessingȱaȱtransaction;ȱcomputingȱtheȱtotalȱ
amountȱdue.ȱYouȱwouldȱexpectȱthatȱtheȱfunctionȱcompute_total_amountȱwouldȱmodifyȱ
theȱ total_amountȱ memberȱ ofȱ theȱ structure.ȱ Thereȱ areȱ threeȱ waysȱ toȱ accomplishȱ thisȱ
task.ȱȱLetȇsȱlookȱatȱtheȱleastȱefficientȱwayȱfirst.ȱTheȱfollowingȱfunctionȱ
ȱ
Transaction
compute_total_amount( Transaction trans )
{
trans.total_amount =
trans.quantity * trans.unit_price;
return trans;
}
ȱ
wouldȱbeȱcalledȱinȱthisȱmanner:ȱ
ȱ
current_trans = compute_total_amount( current_trans );
ȱ
Aȱ copyȱofȱ theȱ structureȱisȱpassedȱasȱ anȱargumentȱ andȱ modified.ȱȱThenȱaȱ copyȱ ofȱ theȱ
modifiedȱstructureȱisȱreturned,ȱsoȱtheȱstructureȱisȱcopiedȱtwice.ȱ
Download at http://www.pin5i.com/
10.4 Structures as Function Arguments
287
ȱ
Aȱ slightlyȱ betterȱ methodȱ isȱ toȱ returnȱ onlyȱ theȱ modifiedȱ valueȱ ratherȱ thanȱ theȱ
entireȱstructure.ȱThisȱapproachȱisȱusedȱbyȱtheȱsecondȱfunction.ȱ
ȱ
float
compute_total_amount( Transaction trans )
{
return trans.quantity * trans.unit_price;
}
ȱ
However,ȱthisȱfunctionȱmustȱbeȱinvokedȱinȱthisȱmannerȱ
ȱ
current_trans.total_amount =
compute_total_amount( current_trans );
ȱ
Thisȱversionȱisȱbetterȱthanȱreturningȱtheȱentireȱstructure,ȱbutȱtheȱtechniqueȱonlyȱworksȱ
whenȱ aȱ singleȱ valueȱ isȱ toȱ beȱ computed.ȱ Ifȱ weȱ wantedȱ theȱ functionȱ toȱ modifyȱ twoȱ orȱ
moreȱmembersȱofȱtheȱstructure,ȱthisȱapproachȱfails.ȱBesides,ȱthereȱisȱstillȱtheȱoverheadȱ
ofȱ passingȱ theȱ structureȱ asȱ anȱ argument.ȱ Worse,ȱ itȱ requiresȱ thatȱ theȱ callingȱ programȱ
haveȱ knowledgeȱ ofȱ theȱ contentsȱ ofȱ theȱ structure,ȱ specifically,ȱ theȱ nameȱ ofȱ theȱ totalȱ
field.ȱ
Theȱthirdȱapproach,ȱpassingȱaȱpointer,ȱisȱbetter:ȱ
ȱ
void
compute_total_amount( register Transaction *trans )
{
trans->total_amount =
trans->quantity * trans->unit_price;
}
ȱ
Thisȱfunctionȱisȱcalledȱlikeȱthis:ȱ
ȱ
compute_total_amount( &current_trans );
ȱ
Now,ȱ theȱ total_amountȱ fieldȱ inȱ theȱ callerȇsȱ structureȱ isȱ modifiedȱ directly;ȱ thereȱ isȱ noȱ
needȱtoȱpassȱtheȱentireȱstructureȱintoȱtheȱfunctionȱorȱtoȱcopyȱtheȱmodifiedȱstructureȱasȱ
theȱreturnȱvalue.ȱThisȱversionȱisȱmoreȱefficientȱthanȱeitherȱofȱtheȱotherȱtwoȱfunctions.ȱ
Inȱaddition,ȱtheȱcallerȱnoȱlongerȱneedsȱtoȱknowȱaboutȱtheȱinternalsȱofȱtheȱstructure,ȱsoȱ
modularityȱisȱalsoȱimproved.ȱ
Whenȱ shouldȱ youȱ passȱ aȱ structure,ȱ ratherȱ thanȱ aȱ pointer,ȱ asȱ anȱ argumentȱ toȱ aȱ
function?ȱ Rarely.ȱ Onlyȱ whenȱ aȱ structureȱ isȱ extremelyȱ smallȱ (theȱ sizeȱ ofȱ aȱ pointer,ȱ orȱ
smaller)ȱisȱitȱasȱefficientȱtoȱ passȱtheȱstructureȱasȱitȱisȱtoȱpassȱaȱpointerȱtoȱit.ȱForȱmostȱ
structures,ȱitȱisȱmoreȱefficientȱtoȱpassȱaȱpointer.ȱIfȱyouȱwantȱtheȱfunctionȱtoȱbeȱableȱtoȱ
modifyȱanyȱofȱtheȱstructureȇsȱmembers,ȱaȱpointerȱisȱalsoȱpreferred.ȱ
Download at http://www.pin5i.com/
288ȱ
K&R C
Chapter 10 Structures and Unions
Withȱ veryȱ earlyȱ K&Rȱ Cȱ compilers,ȱ youȱ couldnȇtȱ passȱ structuresȱ asȱ arguments—theȱ
compilerȱsimplyȱdidȱnotȱallowȱit.ȱLaterȱK&Rȱcompilersȱdidȱallowȱstructureȱarguments.ȱȱ
However,ȱ theseȱ compilersȱ didȱ notȱ supportȱ const,ȱ soȱ theȱ onlyȱ wayȱ toȱ preventȱ aȱ
functionȱfromȱmodifyingȱaȱstructureȱargumentȱwasȱtoȱpassȱaȱcopyȱofȱtheȱstructure.ȱ
ȱ
ȱ
ȱ
10.5 Bit Fields
TIP
TIP
ȱ
Oneȱ lastȱ thingȱ toȱ mentionȱ aboutȱ structuresȱ isȱ theirȱ capabilityȱ forȱ implementingȱ bitȱ
fields.ȱAȱbitȱfieldȱisȱdeclaredȱexactlyȱlikeȱaȱstructureȱexceptȱthatȱitsȱmembersȱareȱfieldsȱ
ofȱ oneȱ orȱ moreȱ bits.ȱ Theseȱ variableȱ lengthȱ fieldsȱ areȱ actuallyȱ storedȱ inȱ oneȱ orȱ moreȱ
integerȱvariables.ȱ
Theȱ declarationȱ ofȱ aȱ bitȱ fieldȱ isȱ theȱ sameȱ asȱ theȱ declarationȱ ofȱ anyȱ ordinaryȱ
structureȱ memberȱ withȱ twoȱ exceptions.ȱ First,ȱ bitȱ fieldȱ membersȱ mustȱ beȱ declaredȱ asȱ
int,ȱ signed int,ȱ orȱ unsigned int.ȱ Second,ȱ aȱ colonȱ andȱ anȱ integerȱ appearȱ afterȱ theȱ
memberȱname,ȱandȱtheȱintegerȱvalueȱspecifiesȱtheȱnumberȱofȱbitsȱinȱthatȱfield.ȱ
ȱ
Itȱisȱaȱgoodȱideaȱtoȱexplicitlyȱdeclareȱbitȱfieldsȱasȱeitherȱ signedȱorȱ unsignedȱintegers.ȱItȱ
isȱ implementationȱ dependentȱ whetherȱ bitȱ fieldsȱ declaredȱ asȱ intȱ areȱ interpretedȱ asȱ
signedȱorȱunsignedȱvalues.ȱ
ȱ
Programsȱ thatȱ areȱ intendedȱ toȱ beȱ portableȱ shouldȱ avoidȱ bitȱ fields.ȱ Becauseȱ ofȱ theȱ
followingȱ implementationȱ dependencies,ȱ bitȱ fieldsȱ mayȱ workȱ differentlyȱ onȱ variousȱ
systems.ȱ
ȱ
1. Whetherȱanȱintȱbitȱfieldȱisȱtreatedȱasȱsignedȱorȱunsigned.ȱ
2. Theȱmaximumȱnumberȱofȱbitsȱinȱaȱbitȱfield.ȱManyȱcompilersȱlimitȱbitȱfieldȱmembersȱ
toȱtheȱsizeȱofȱanȱinteger,ȱsoȱaȱbitȱfieldȱdeclarationȱthatȱworksȱonȱaȱmachineȱwithȱ32Ȭ
bitȱintegersȱmayȱnotȱworkȱonȱoneȱthatȱusesȱ16Ȭbitȱintegers.ȱ
3. Whetherȱtheȱmembersȱinȱaȱbitȱfieldȱareȱallocatedȱfromȱleftȱtoȱrightȱorȱfromȱrightȱtoȱ
leftȱinȱmemory.ȱ
4. Whenȱaȱdeclarationȱspecifiesȱtwoȱbitȱfieldsȱandȱtheȱsecondȱisȱtooȱlargeȱtoȱfitȱinȱtheȱ
bitsȱleftȱoverȱfromȱtheȱfirst,ȱtheȱcompilerȱmayȱeitherȱputȱtheȱsecondȱbitȱfieldȱinȱtheȱ
nextȱ wordȱ ofȱ memoryȱ orȱ immediatelyȱ afterȱ theȱ firstȱ field,ȱ overlappingȱ theȱ
boundaryȱbetweenȱmemoryȱlocations.ȱ
ȱ
Hereȱisȱanȱexampleȱofȱȱaȱbitȱfieldȱdeclaration:ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
10.5 Bit Fields
struct
};
struct
CHAR {
unsigned ch
unsigned font
unsigned size
CHAR
289
: 7;
: 6;
: 19;
ch1;
ȱ
Thisȱdeclarationȱisȱfromȱaȱtextȱformattingȱprogramȱthatȱisȱcapableȱofȱmanipulatingȱupȱ
toȱ128ȱdifferentȱcharacterȱvaluesȱ(forȱwhichȱsevenȱbitsȱareȱrequired),ȱupȱtoȱ64ȱdifferentȱ
fontsȱ(whichȱtakesȱsixȱbits),ȱinȱsizesȱfromȱ0ȱtoȱ524,287ȱunits.ȱTheȱsizeȱfieldȱisȱtooȱlargeȱtoȱ
beȱheldȱinȱaȱshortȱinteger,ȱbutȱtheȱotherȱfieldsȱareȱbothȱsmallerȱthanȱaȱcharacter.ȱTheȱbitȱ
fieldȱ letsȱ theȱ programmerȱ useȱ theȱ bitsȱ leftȱ overȱ fromȱ chȱ andȱ fontȱ toȱ increaseȱ theȱ
numberȱ ofȱ bitsȱ forȱ size,ȱ thusȱ avoidingȱ theȱ needȱ toȱ declareȱ aȱ wholeȱ integerȱ toȱ store
size.ȱ
Manyȱ compilersȱ forȱ machinesȱ withȱ 16Ȭbitȱ integersȱ willȱ flagȱ thisȱ declarationȱ asȱ
illegalȱ becauseȱ theȱ lastȱ fieldȱ isȱ tooȱ large.ȱ Butȱ onȱ aȱ 32Ȭbitȱ machine,ȱ thisȱ declarationȱ
wouldȱcreateȱch1ȱasȱoneȱofȱtheseȱtwoȱpossibilities.ȱ
ȱ
chȱ
font
size
ȱ
6
19ȱ
ȱ 7ȱ
ȱ
ȱ
sizeȱ
ch
fontȱ
ȱ
7
19
6ȱ
ȱ
ȱ
Thisȱexampleȱillustratesȱaȱgoodȱreasonȱtoȱuseȱbitȱfields:ȱtheȱabilityȱtoȱpackȱoddȬ
sizedȱdataȱtogetherȱtoȱsaveȱstorage.ȱThisȱsavingsȱbecomesȱparticularlyȱimportantȱwhenȱ
thousandsȱofȱtheseȱstructuresȱareȱbeingȱused.ȱ
Theȱotherȱreasonȱtoȱuseȱbitȱfieldsȱisȱbecauseȱtheyȱmakeȱitȱconvenientȱtoȱaccessȱ
partsȱ ofȱ anȱ integer.ȱ Letȇsȱ examineȱ anȱ exampleȱ thatȱ mightȱ beȱ foundȱ inȱ anȱ operatingȱ
system.ȱTheȱcodeȱtoȱoperateȱtheȱfloppyȱdiskȱmustȱcommunicateȱwithȱtheȱcontrollerȱforȱ
theȱ disk.ȱ Oftenȱ theseȱ deviceȱ controllersȱ containȱ severalȱ registers,ȱ eachȱ ofȱ whichȱ
containsȱ manyȱ differentȱ valuesȱ allȱ packedȱ togetherȱ intoȱ oneȱ integer.ȱ Aȱ bitȱ fieldȱ isȱ aȱ
convenientȱwayȱtoȱaccessȱtheȱindividualȱvalues.ȱ
Supposeȱoneȱofȱtheȱregistersȱforȱtheȱcontrollerȱwasȱdefinedȱas:ȱ
Ready
ErrorȱOccurred
DiskȱSpinning
HeadȱLoaded
WriteȱProtected
ErrorȱCode
1ȱȱ1ȱȱ1ȱȱ1ȱȱ1ȱ
8
Track
Sectorȱ
9
5ȱ
Command
5
Download at http://www.pin5i.com/
Chapter 10 Structures and Unions
290ȱ
Theȱfirstȱfiveȱfieldsȱareȱoneȱbitȱeach,ȱandȱtheȱremainingȱfieldsȱareȱlarger.ȱOnȱaȱmachineȱ
thatȱallocatedȱbitȱfieldsȱfromȱrightȱtoȱleft,ȱtheȱfollowingȱdeclarationȱwouldȱallowȱeasyȱ
accessȱtoȱtheȱvariousȱfieldsȱinȱthisȱregister.ȱ
ȱ
struct
DISK_REGISTER_FORMAT
{
unsigned
command
unsigned
sector
unsigned
track
unsigned
error_code
unsigned
head_loaded
unsigned
write_protect
unsigned
disk_spinning
unsigned
error_occurred
unsigned
ready
:
:
:
:
:
:
:
:
:
5;
5;
9;
8;
1;
1;
1;
1;
1;
};
ȱ
Ifȱ theȱ diskȱ registerȱ isȱaccessedȱ atȱ memoryȱ addressȱ 0xc0200142,ȱ weȱ wouldȱ declareȱ theȱ
followingȱpointerȱconstant:ȱ
ȱ
#define DISK_REGISTER
\
((struct DISK_REGISTER_FORMAT *) 0xc0200142)
ȱ
Withȱthisȱpreparation,ȱtheȱcodeȱneededȱtoȱactuallyȱaccessȱtheȱdiskȱregisterȱisȱsimple,ȱasȱ
shownȱinȱthisȱcodeȱfragment.ȱ
ȱ
ȱ
ȱ
/*
** Tell the controller which sector and track,
** and start the read operation.
*/
DISK_REGISTER->sector = new_sector;
DISK_REGISTER->track = new_track;
DISK_REGISTER->command = READ;
/*
** Wait until the operation is done,
** indicated by ready becoming true.
*/
while( ! DISK_REGISTER->ready )
;
/*
** Check for errors.
* /
if( DISK_REGISTER->error_occurred ){
switch( DISK_REGISTER->error_code ){
...
ȱ
ȱ
Download at http://www.pin5i.com/
10.6 Unions
291
Bitȱfieldsȱareȱaȱconvenience.ȱAnyȱtaskȱthatȱcanȱbeȱcompletedȱwithȱbitȱfieldsȱcanȱ
alsoȱbeȱaccomplishedȱthroughȱshiftingȱandȱmasking.ȱForȱexample,ȱtheȱfollowingȱcodeȱ
accomplishesȱexactlyȱtheȱsameȱthingȱasȱtheȱfirstȱassignmentȱinȱtheȱpreviousȱexample.ȱ
ȱ
#define DISK_REGISTER
(unsigned int *) 0xc0200142
*DISK_REGISTER &= 0xfffffc1f;
*DISK_REGISTER |= ( new_sector & 0x1f ) << 5;
TIP
ȱ
TheȱfirstȱassignmentȱusesȱaȱbitwiseȱANDȱtoȱclearȱallȱofȱtheȱbitsȱinȱtheȱsectorȱfieldȱ
toȱ zeroȱ withoutȱ affectingȱ theȱ otherȱ bits.ȱ Theȱ secondȱ takesȱ theȱ valueȱ ofȱ new_sector,ȱ
ANDȇsȱitȱtoȱmakeȱsureȱthatȱtheȱvalueȱdoesȱnotȱexceedȱtheȱwidthȱofȱtheȱfield,ȱshiftsȱitȱleftȱ
toȱtheȱproperȱposition,ȱandȱthenȱusesȱaȱbitwiseȱORȱtoȱsetȱtheȱfieldȱtoȱtheȱdesiredȱvalue.ȱ
ȱ
Theȱbitȱfieldȱexpressesȱthisȱprocessȱmoreȱsimplyȱinȱtheȱsourceȱcode,ȱbutȱthereȱisnȇtȱanyȱ
differenceȱinȱtheȱobjectȱcode.ȱTheȱsameȱshiftingȱandȱmaskingȱoperationsȱareȱrequiredȱ
whetherȱ orȱ notȱ theȱ bitȱ fieldȱ isȱ used.ȱ Theȱ onlyȱ advantageȱ providedȱ byȱ theȱ bitȱ fieldȱ isȱ
simplifyingȱ theȱ sourceȱ code.ȱ Thisȱ advantageȱ mustȱ beȱ weighedȱ againstȱ theȱ bitȱ fieldȇsȱ
lackȱofȱportability.ȱ
ȱ
ȱ
ȱ
10.6 Unions
ȱ
Aȱ unionȱ isȱ aȱ differentȱ animalȱ altogether.ȱ Aȱ unionȱ isȱ declaredȱ likeȱ aȱ structureȱ butȱ
doesnȇtȱworkȱlikeȱaȱstructure.ȱAllȱofȱtheȱmembersȱofȱaȱunionȱreferȱtoȱtheȱsameȱlocation(s)ȱ
inȱ memory.ȱ Unionsȱ areȱ usedȱ whenȱ youȱ needȱ toȱ storeȱ differentȱ thingsȱ inȱ oneȱ placeȱ atȱ
differentȱtimes.ȱ
ȱ
First,ȱletȇsȱlookȱatȱaȱsimpleȱexample.ȱ
ȱ
union {
float f;
int
i;
} fi;
ȱ
Onȱ aȱ machineȱ inȱ whichȱ floatsȱ andȱ integersȱ bothȱ occupyȱ 32ȱ bits,ȱ theȱ variableȱ fiȱ
occupiesȱ onlyȱ oneȱ 32Ȭbitȱ wordȱ ofȱ memory.ȱ Ifȱ theȱ memberȱ fȱ isȱ used,ȱ theȱ wordȱ isȱ
accessedȱasȱaȱfloatingȬpointȱvalue;ȱifȱtheȱmemberȱ iȱisȱused,ȱtheȱwordȱisȱaccessedȱasȱanȱ
integer.ȱSoȱthisȱcodeȱ
ȱ
fi.f = 3.14159;
printf( "%d\n", fi.i );
ȱ
firstȱstoresȱtheȱfloatingȬpointȱrepresentationȱofȱΔȱintoȱfi,ȱandȱthenȱinterpretsȱthoseȱsameȱ
bitsȱasȱifȱtheyȱwereȱanȱintegerȱandȱprintsȱoutȱthatȱvalue.ȱȱNoteȱthatȱbothȱmemberȱareȱ
Download at http://www.pin5i.com/
292ȱ
Chapter 10 Structures and Unions
referringȱ toȱ theȱ sameȱ bits;ȱ theȱ onlyȱ differenceȱ isȱ thatȱ theȱ typeȱ ofȱ eachȱ memberȱ
determinesȱhowȱtheȱbitsȱareȱinterpreted.ȱ
Whyȱ wouldȱ anyoneȱ everȱ wantȱ toȱ doȱ anythingȱ likeȱ thisȱ example?ȱ Itȱ wouldȱ beȱ
helpfulȱ ifȱ youȱ wantedȱ toȱ seeȱ howȱ floatingȬpointȱ numbersȱ areȱ storedȱ onȱ aȱ particularȱ
machineȱbutȱprobablyȱnotȱforȱanythingȱelse.ȱHereȱisȱaȱmoreȱrealisticȱexample.ȱOneȱtaskȱ
ofȱaȱBASICȱinterpreterȱisȱtoȱkeepȱtrackȱofȱtheȱvaluesȱofȱvariablesȱusedȱin.ȱtheȱprogram.ȱ
BASICȱprovidesȱseveralȱdifferentȱtypesȱofȱvariables,ȱsoȱtheȱtypeȱofȱeachȱvariableȱmustȱ
beȱstoredȱalongȱwithȱitsȱvalue.ȱHereȱisȱaȱstructureȱthatȱsavesȱthisȱinformation,ȱbutȱitȱisȱ
notȱtooȱefficient.ȱ
ȱ
struct
VARIABLE
enum { INT, FLOAT, STRING }
int
int_value;
float float_value;
char *string_value;
type;
};
ȱ
WhenȱaȱvariableȱinȱtheȱBASICȱprogramȱisȱcreated,ȱtheȱinterpreterȱcreatesȱoneȱofȱtheseȱ
structuresȱ andȱ recordsȱ theȱ typeȱ ofȱ theȱ variable.ȱ Then,ȱ basedȱ onȱ theȱ type,ȱ oneȱ ofȱ theȱ
threeȱvalueȱfieldsȱisȱusedȱtoȱstoreȱtheȱvariableȇsȱvalue.ȱ
Whatȱisȱinefficientȱaboutȱthisȱstructureȱisȱtheȱamountȱofȱmemoryȱused—ȱeveryȱ
VARIABLEȱcontainsȱtwoȱvalueȱfieldsȱthatȱareȱnotȱused.ȱAȱunionȱcanȱreduceȱthisȱwasteȱbyȱ
storingȱ eachȱ ofȱ theȱ threeȱ valueȱ fieldsȱ inȱ theȱ sameȱ memory.ȱ Theȱ threeȱ fieldsȱ willȱ notȱ
conflictȱbecauseȱeachȱvariableȱcanȱonlyȱhaveȱoneȱtype,ȱthusȱonlyȱoneȱofȱtheȱfieldsȱinȱtheȱ
unionȱwillȱeverȱbeȱneededȱatȱaȱtime.ȱ
ȱ
struct
VARIABLE
enum { INT, FLOAT, STRING } type;
union {
int
i;
float f;
char *s;
} value;
};
ȱ
Now,ȱ forȱ anȱ integerȱ variable,ȱ youȱ wouldȱ storeȱ INTȱ inȱ theȱ typeȱ fieldȱ andȱ theȱ integerȱ
valueȱinȱtheȱvalue.iȱfield.ȱȱForȱaȱfloatingȬpointȱvalue,ȱyouȱwouldȱuseȱtheȱvalue.fȱfield.ȱ
Whenȱ obtainingȱ theȱ valueȱ ofȱ thisȱ variableȱ later,ȱ theȱ typeȱ fieldȱ wouldȱ beȱ checkedȱ toȱ
determineȱwhichȱvalueȱfieldȱtoȱuse.ȱThisȱchoiceȱdeterminesȱhowȱtheȱmemoryȱlocationȱ
willȱbeȱaccessed,ȱsoȱoneȱlocationȱcanȱbeȱusedȱtoȱstoreȱanyȱofȱtheseȱthreeȱdifferentȱkindsȱ
ofȱvalues.ȱNoteȱthatȱtheȱcompilerȱdoesnȇtȱcheckȱtheȱ typeȱfieldȱtoȱverifyȱthatȱtheȱproperȱ
unionȱ memberȱ isȱ used.ȱ Itȱ isȱ upȱ toȱ theȱ programmerȱ toȱ maintainȱ theȱ typeȱ fieldȱ andȱ toȱ
checkȱit.ȱ
ȱ
Ifȱ theȱ memberȱ ofȱ aȱ unionȱ areȱ differentȱ sizes,ȱ theȱ unionȱ willȱ beȱ asȱ largeȱ asȱ theȱ
largestȱmember.ȱTheȱnextȱsectionȱdiscussesȱthisȱsituation.ȱ
Download at http://www.pin5i.com/
10.6 Unions
10.6.1
293
Variant Records
ȱ
Letȇsȱ examineȱ anȱ exampleȱ thatȱ implementsȱ whatȱ Pascalȱ andȱ Modulaȱ callȱ aȱ variantȱ
record.ȱConceptually,ȱthisȱisȱtheȱsameȱsituationȱweȱjustȱdiscussed—aȱparticularȱareaȱinȱ
memoryȱ willȱ storeȱ differentȱ typesȱ ofȱ valuesȱ atȱ differentȱ times.ȱ Inȱ thisȱ case,ȱ however,ȱ
theȱvaluesȱareȱmoreȱcomplexȱthanȱsimpleȱintegersȱorȱfloats.ȱEachȱisȱanȱentireȱstructure.ȱ
Iȱtookȱtheȱfollowingȱexampleȱfromȱanȱinventoryȱsystemȱthatȱkeepsȱtrackȱofȱtwoȱ
differentȱ kindsȱ ofȱ entities:ȱ partsȱ andȱ subassemblies.ȱ Aȱ partȱ isȱ aȱ gadgetȱ thatȱ isȱ
purchasedȱ fromȱ anotherȱ manufacturer.ȱ Itȱ hasȱ variousȱ characteristicsȱ suchȱ asȱwhoȱ weȱ
buyȱ itȱ from,ȱ howȱ muchȱ itȱ costs,ȱ andȱ soȱ forth.ȱ Aȱ subassemblyȱ isȱ somethingȱ thatȱ weȱ
make,ȱandȱisȱaȱcombinationȱofȱaȱbunchȱofȱpartsȱandȱotherȱsubassemblies.ȱ
Theȱ firstȱ twoȱ structuresȱ specifyȱ whatȱ mustȱ beȱ storedȱ forȱ aȱ partȱ andȱ forȱ aȱ
subassembly.ȱ
ȱ
struct
PARTINFO
{
int
cost;
int
supplier;
...
};
struct
SUBASSYINFO {
int
n_parts;
struct
{
char partno[10];
short quan;
} parts[MAXPARTS];
};
ȱ
Theȱ inventoryȱ recordȱ containsȱ commonȱ informationȱ forȱ eachȱ entryȱ andȱ aȱ unionȱ toȱ
storeȱeitherȱpartȱinformationȱorȱsubassemblyȱinformation.ȱ
ȱ
struct
INVREC
{
char partno[10];
int
quan;
enum { PART, SUBASSY }
union {
struct PARTINFO
struct SUBASSYINFO
} info;
type;
part;
subassy;
};
ȱ
HereȱareȱsomeȱstatementsȱthatȱmanipulateȱanȱINVRECȱstructureȱvariableȱcalledȱrec.ȱ
Download at http://www.pin5i.com/
Chapter 10 Structures and Unions
294ȱ
if( rec.type == PART ){
y = rec.info.part.cons;
z = rec.info.part.supplier;
}
else {
y = rec.info.subassy.nparts;
z = rec.info.subassy.parts[0].quan;
}
ȱ
Althoughȱnotȱveryȱrealistic,ȱthisȱcodeȱillustratesȱhowȱtoȱaccessȱeachȱofȱtheȱmembersȱofȱ
theȱunion.ȱTheȱfirstȱpartȱofȱtheȱstatementȱgetsȱtheȱcostȱandȱtheȱsupplierȱforȱaȱpart,ȱandȱ
theȱsecondȱpartȱofȱtheȱstatementȱgetsȱtheȱnumberȱofȱdifferentȱpartsȱinȱaȱsubassemblyȱ
andȱtheȱquantityȱofȱtheȱfirstȱpart.ȱ
Inȱaȱunionȱwhoseȱmembersȱareȱdifferentȱsizes,ȱtheȱamountȱofȱmemoryȱallocatedȱ
forȱ theȱ unionȱ isȱ determinedȱ byȱ theȱ sizeȱ ofȱ itsȱ largestȱ member.ȱ Thus,ȱ aȱ unionȱ willȱ
alwaysȱbeȱbigȱenoughȱtoȱstoreȱitsȱlargestȱmember.ȱIfȱtheȱmembersȱareȱwildlyȱdifferentȱ
sizes,ȱthereȱwillȱbeȱaȱlotȱofȱwastedȱmemoryȱwhenȱstoringȱtheȱshorterȱmembers.ȱInȱthisȱ
typeȱofȱsituation,ȱitȱmightȱbeȱpreferableȱforȱtheȱunionȱtoȱstoreȱpointersȱtoȱtheȱdifferentȱ
membersȱratherȱthanȱtheȱmembersȱthemselves.ȱTheȱpointersȱwouldȱallȱbeȱtheȱsameȱsizeȱ
thusȱ avoidingȱ theȱ problemȱ ofȱ wastedȱ memory.ȱ Whenȱ itȱ isȱ decidedȱ whichȱ memberȱ isȱ
needed,ȱ theȱ rightȱ amountȱ ofȱ memoryȱ canȱ beȱ obtainedȱ toȱ storeȱ it.ȱ Chapterȱ 11,ȱ whichȱ
dealsȱ withȱ dynamicȱ memoryȱ allocation,ȱ containsȱ anȱ exampleȱ illustratingȱ thisȱ
technique.ȱ
ȱ
ȱ
ȱ
10.6.2
Initializing Unions
ȱ
Aȱunionȱvariableȱcanȱbeȱinitialized,ȱbutȱtheȱvalueȱmustȱappropriateȱforȱtheȱtypeȱofȱtheȱ
firstȱmemberȱofȱtheȱunion,ȱandȱitȱmustȱbeȱenclosedȱinȱbraces.ȱȱForȱexample,ȱ
ȱ
union {
int
a;
float b;
char c[4];
} x = { 5 };
ȱ
initializesȱx.aȱtoȱhaveȱtheȱvalueȱfive.ȱ
Itȱ isȱ notȱ possibleȱ toȱ initializeȱ thisȱ variableȱ toȱ aȱ floatingȬpointȱ orȱ aȱ characterȱ
value.ȱ Ifȱ anȱ initializerȱ ofȱ anyȱ otherȱ typeȱ isȱ given,ȱ itȱ isȱ convertedȱ (ifȱ possible)ȱ toȱ anȱ
integerȱandȱassignedȱtoȱx.a.ȱ
ȱ
Download at http://www.pin5i.com/
10.7 Summary
295
ȱ
10.7 Summary
ȱ
Valuesȱ ofȱ differentȱ typesȱ canȱ beȱ storedȱ togetherȱ inȱ aȱ structure.ȱ Theȱ valuesȱ inȱ aȱ
structure,ȱcalledȱmembers,ȱareȱaccessedȱbyȱname.ȱAȱstructureȱvariableȱisȱaȱscalar,ȱandȱ
canȱappearȱwhereverȱanȱordinaryȱscalarȱvariableȱcanȱappear,ȱ
Theȱdeclarationȱofȱaȱstructureȱlistsȱtheȱmembersȱthatȱtheȱstructureȱwillȱcontain.ȱȱ
Differentȱ declarationsȱ areȱ consideredȱ toȱ beȱ differentȱ typesȱ evenȱ ifȱ theirȱ memberȱ listsȱ
areȱ identical.ȱ Aȱ structureȱ tagȱ isȱ aȱ nameȱ associatedȱ withȱ aȱ memberȱ list.ȱ Youȱ canȱ useȱ
differentȱ declarationsȱ toȱ declareȱ structuresȱ ofȱ theȱ sameȱ typeȱ byȱ usingȱ aȱ structureȱ tagȱ
ratherȱthanȱrepeatingȱtheȱmemberȱlistȱinȱtheȱdeclarations.ȱAȱ typedefȱmayȱalsoȱbeȱusedȱ
toȱaccomplishȱthisȱgoal.ȱ
Structureȱ membersȱ mayȱ beȱ scalars,ȱ arrays,ȱ orȱ pointers.ȱ Aȱ structureȱ mayȱ alsoȱ
containȱmembersȱwhichȱareȱstructures.ȱThereȱisȱnoȱconflictȱbetweenȱidenticallyȱnamedȱ
membersȱofȱdifferentȱstructures.ȱYouȱuseȱtheȱdotȱoperatorȱtoȱaccessȱtheȱmembersȱofȱaȱ
structureȱvariable.ȱIfȱyouȱhaveȱaȱpointerȱtoȱaȱstructure,ȱyouȱuseȱtheȱarrowȱoperatorȱtoȱ
accessȱtheȱstructureȇsȱmembers.ȱ
Aȱ structureȱ mayȱ notȱ containȱ aȱ memberȱ thatȱ isȱ theȱ sameȱ typeȱ ofȱ structure,ȱ butȱ
mayȱcontainȱaȱmemberȱthatȱisȱaȱpointerȱtoȱtheȱsameȱtypeȱofȱstructure.ȱThisȱtechniqueȱisȱ
oftenȱ usedȱ inȱ linkedȱ dataȱ structures.ȱ Toȱ declareȱ twoȱ structuresȱ thatȱ eachȱ containȱ aȱ
pointerȱtoȱtheȱotherȱtype,ȱanȱincompleteȱdeclarationȱisȱneededȱtoȱdefineȱaȱstructureȱtagȱ
name.ȱ Structureȱ variablesȱ mayȱ beȱ initializedȱ byȱ givingȱ aȱ listȱ ofȱ valuesȱ enclosedȱ inȱ
braces.ȱȱTheȱtypeȱofȱeachȱvalueȱmustȱbeȱappropriateȱforȱtheȱmemberȱthatȱitȱinitializes.ȱ
Theȱ compilerȱ allocatesȱ memoryȱ forȱ theȱ membersȱ ofȱ aȱ structureȱ variableȱ inȱ
accordanceȱ withȱ theirȱ boundaryȱ alignmentȱ requirements.ȱ Memoryȱ mayȱ beȱwastedȱ inȱ
theȱ structureȱ toȱ achieveȱ theȱ properȱ alignment.ȱ Listingȱ theȱ structureȱ membersȱ inȱ
decreasingȱ orderȱ ofȱ theirȱ alignmentȱ requirementsȱ minimizesȱ theȱ amountȱ ofȱ wastedȱ
memoryȱinȱtheȱstructure.ȱTheȱvalueȱreturnedȱbyȱ sizeofȱincludesȱanyȱwastedȱmemoryȱ
inȱaȱstructure.ȱ
Structuresȱ mayȱ beȱ passedȱ asȱ argumentsȱ toȱ functionsȱ andȱ returnedȱ fromȱ
functions.ȱ However,ȱ itȱ isȱ usuallyȱ moreȱ efficientȱ toȱ passȱ aȱ pointerȱ toȱ theȱ structureȱ
instead.ȱ Theȱ constȱ keywordȱ canȱ beȱ usedȱ inȱ theȱ declarationȱ ofȱ aȱ pointerȱ argumentȱ toȱ
preventȱtheȱfunctionȱfromȱmodifyingȱtheȱstructure.ȱ
Bitȱ fieldsȱ areȱ structureȱ membersȱ whoseȱ sizeȱ isȱ specifiedȱ inȱ bits.ȱ Bitȱ fieldȱ
declarationsȱ areȱ inherentlyȱ nonportableȱ dueȱ toȱ theȱ manyȱ factorsȱ thatȱ areȱ
implementationȱ dependent.ȱ However,ȱ bitȱ fieldsȱ allowȱ youȱ toȱ packȱ oddȱ sizedȱ valuesȱ
togetherȱ toȱ conserveȱ space.ȱ Theyȱ alsoȱ simplifyȱ theȱ sourceȱ codeȱ neededȱ toȱ accessȱ
arbitraryȱrunsȱofȱbitsȱfromȱwithinȱaȱvalue.ȱ
Theȱmembersȱofȱaȱunionȱareȱallȱstoredȱinȱtheȱsameȱmemory.ȱȱByȱaccessingȱunionȱ
membersȱ ofȱ differentȱ types,ȱ theȱ sameȱ bitsȱ inȱ memoryȱ canȱ beȱ interpretedȱ differently.ȱ
Unionsȱ areȱ usefulȱ inȱ implementingȱ variantȱ records,ȱ thoughȱ theȱ programmerȱ isȱ
responsibleȱforȱkeepingȱtrackȱofȱwhichȱvariantȱhasȱbeenȱstoredȱandȱforȱselectingȱtheȱȱ
Download at http://www.pin5i.com/
296ȱ
Chapter 10 Structures and Unions
properȱunionȱmemberȱtoȱaccessȱ theȱdata.ȱAȱunionȱvariableȱcanȱbeȱinitialized,ȱbutȱtheȱ
valueȱmustȱmatchȱtheȱtypeȱofȱitsȱfirstȱmember.ȱ
ȱ
ȱ
ȱ
10.8 Summary of Cautions
ȱ
1. Structureȱ declarationsȱ withȱ identicalȱ memberȱ listsȱ produceȱ variablesȱ ofȱ differentȱ
typesȱ(pageȱ270).ȱ
2. BeȱcarefulȱusingȱtypedefȱtoȱdefineȱaȱnameȱforȱaȱselfȬreferentialȱstructureȱ(pageȱ274).ȱ
3. Passingȱstructuresȱasȱargumentsȱisȱinefficientȱ(pageȱ285).ȱ
ȱ
ȱ
ȱ
10.9 Summary of Programming Tips
ȱ
1. Putȱ structureȱ tagȱ declarationsȱ andȱ typedefȇsȱ intoȱ headerȱ files,ȱ whichȱ canȱ beȱ
#includeȇdȱwhereverȱneededȱ(pageȱ271).ȱ
2. Theȱ bestȱ arrangementȱ ofȱ structureȱ membersȱ mayȱ notȱ beȱ theȱ oneȱ thatȱ wastesȱ theȱ
leastȱamountȱofȱspaceȱdueȱtoȱboundaryȱalignmentȱ(pageȱ284).ȱ
3. Explicitlyȱ declareȱ bitȱ fieldȱ membersȱ asȱ either signed intȱ orȱ unsigned intȱ (pageȱ
288).ȱ
4. Bitȱfieldsȱareȱnotȱportableȱ(pageȱ288).ȱ
5. Bitȱfieldsȱallowȱbitȱoperationsȱtoȱbeȱexpressedȱmoreȱclearlyȱinȱtheȱsourceȱcodeȱ(pageȱ
291).ȱ
ȱ
ȱ
ȱ
10.10 Questions
ȱ
1. Howȱareȱstructureȱmembersȱdifferentȱfromȱarrayȱelements?ȱ
2. Howȱisȱaȱstructureȱnameȱdifferentȱfromȱanȱarrayȱname?ȱ
3. Theȱsyntaxȱforȱstructureȱdeclarationsȱshowsȱsomeȱoptionalȱcomponents.ȱListȱallȱtheȱ
legalȱformsȱofȱaȱstructureȱdeclaration,ȱandȱexplainȱwhatȱisȱaccomplishedȱbyȱeach.ȱ
4. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱprogramȱfragment?ȱ
ȱ
struct abc {
int
a;
int
b;
int
c;ȱ
Download at http://www.pin5i.com/
10.10 Questions
297
};
...
abc.a = 25;
abc.b = 15;
abc.c = -1
5. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱprogramȱfragment?ȱ
ȱ
typedef
struct {
int
a;
int
b;
int
c;
} abc;
...
abc.a = 25;
abc.b = 15;
abc.c = -1
6. Completeȱtheȱfollowingȱdeclarationȱtoȱinitializeȱxȱsoȱthatȱtheȱmemberȱaȱisȱthree,ȱbȱisȱ
theȱstringȱhello,ȱandȱcȱisȱzero.ȱYouȱmayȱassumeȱthatȱxȱisȱstoredȱinȱstaticȱmemory.ȱ
ȱ
struct {
int
a;
char b[10];
float c;
} x =
7. Considerȱtheȱfollowingȱdeclarationsȱandȱdata.ȱ
ȱ
struct NODE {
int a;
struct NODE *b;
struct NODE *c;
};
struct NODE
{ 5,
{ 15,
{ 22,
{ 12,
{ 18,
};
nodes[5] = {
nodes + 3, NULL },
nodes + 4, nodes + 3 },
NULL,
nodes + 4 },
nodes + 1, nodes },
nodes + 2, nodes + 1 }
(Otherȱdeclarations...)ȱ
struct NODE *np
struct NODE *npp
= nodes + 2;
= &nodes[1].b;
Download at http://www.pin5i.com/
298ȱ
Chapter 10 Structures and Unions
Evaluateȱ eachȱ ofȱ theȱ expressionsȱ belowȱ andȱ stateȱ itsȱ value.ȱ Also,ȱ stateȱ anyȱ sideȱ
effectsȱ thatȱ occurȱ whenȱ theȱ expressionȱ isȱ evaluated.ȱ Youȱ shouldȱ evaluateȱ eachȱ
expressionȱ withȱ theȱ originalȱ valuesȱ shownȱ (thatȱ is,ȱ donȇtȱ useȱ theȱ resultsȱ ofȱ oneȱ
expressionȱtoȱevaluateȱtheȱnextȱone).ȱAssumeȱthatȱtheȱnodesȱarrayȱbeginsȱatȱlocationȱ
200ȱandȱthatȱintegersȱandȱpointersȱareȱfourȱbytesȱonȱthisȱmachine.ȱ
ȱ
Expression
Value
Expression
Value
nodes
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. &nodes[3].c->a
nodes.a
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
nodes[3].a
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
nodes[3].c
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
nodes[31.c->a
*nodes
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
{*nodes}.a
np
np->a
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. np->c->c->a
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
*nodes.a
&nodes->a
npp
npp->a
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. *npp
nodes->a
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
nodes[3].b->b
*nodes[3].b->b
&nodes
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
&nodes[3].c
*npp->a
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. (*npp)->a
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
&nodes[3].a
**npp
&np
&np->a
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ. &np->c->c->a
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ ȱȱȱȱȱȱȱ.
ȱ
8. Howȱmuchȱspaceȱisȱwastedȱinȱtheȱfollowingȱstructureȱdueȱtoȱboundaryȱalignmentȱ
onȱaȱmachineȱwithȱ16Ȭbitȱintegers?ȱOnȱaȱmachineȱwithȱ32Ȭbitȱintegers?ȱ
ȱ
struct {
char
int
char
};
a;
b;
c;
9. Nameȱatȱleastȱtwoȱreasonsȱwhyȱbitȱfieldȱdeclarationsȱareȱnotȱportable.ȱ
10. Writeȱ aȱ declarationȱ thatȱ allowsȱ easyȱ accessȱ toȱ theȱ individualȱ partsȱ ofȱ aȱ floatingȬ
pointȱinȱtheȱfollowingȱformat.ȱ
ȱ
Fractionȱ(24ȱbits)
Exponentȱ(7ȱbits)
Signȱ(1ȱbit)
ȱ
Download at http://www.pin5i.com/
10.10 Questions
299
11. Howȱ wouldȱ youȱ accomplishȱ theȱ sameȱ resultȱ asȱ theȱ followingȱ codeȱ withoutȱ usingȱ
bitȱfields?ȱAssumeȱthatȱyouȱhaveȱaȱ16Ȭbitȱmachineȱthatȱallocatesȱbitȱfieldsȱfromȱleftȱ
toȱright.ȱ
ȱ
struct {
int
int
int
int
} x;
...
x.a = aaa;
x.b = bbb;
x.c = ccc;
x.d = ddd;
a:4;
b:8;
c:3;
d:1;
12. Whatȱdoesȱtheȱfollowingȱcodeȱfragmentȱprint?ȱ
ȱ
struct {
int
a:2;
} x;
...
x.a = 1;
x.a += 1;
printf( "%d\n", x.a );
13. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱcodeȱfragment?ȱ
ȱ
union {
int
float
char
} x;
...
x.a = 25;
x.b = 3.14;
x.c = 'x';
printf( "%d
a;
b;
c;
%g %c\n", x.a, x.b, x.c );
14. Supposeȱ someȱ informationȱ hasȱ beenȱ assignedȱ toȱ aȱ unionȱ variable.ȱ Howȱ canȱ thisȱ
informationȱbeȱretrievedȱcorrectly?ȱ
15. TheȱfollowingȱstructureȱcouldȱbeȱusedȱbyȱaȱBASICȱinterpreterȱtoȱkeepȱtrackȱofȱtheȱ
typeȱandȱvalueȱofȱvariables.ȱ
ȱ
struct VARIABLE
{
Download at http://www.pin5i.com/
300ȱ
Chapter 10 Structures and Unions
enum { INT, FLOAT, STRING }
union {
int
i;
float f;
char *s;
} value;
type;
};
ȱ
Whatȱwouldȱbeȱdifferentȱifȱtheȱstructureȱwereȱwrittenȱlikeȱthisȱinstead:ȱ
ȱ
struct VARIABLE
{
enum { INT, FLOAT, STRING } type;
union {
int
i;
float f;
char s[MAX_STRING_LENGTH];
} value;
};
ȱ
ȱ
ȱ
10.11 Programming Exercises
ȱ
1. Theȱinformationȱsavedȱbyȱtheȱtelephoneȱcompanyȱwhenȱyouȱmakeȱaȱlongȱdistanceȱ
phoneȱ callȱ includesȱ theȱ dateȱ andȱ timeȱ youȱ placedȱ theȱ call.ȱ Itȱ alsoȱ includesȱ threeȱ
phoneȱnumbers:ȱtheȱoneȱyouȱcalled,ȱtheȱoneȱyouȱareȱcallingȱfrom,ȱandȱtheȱoneȱthatȱ
willȱ beȱ billed.ȱ Eachȱ ofȱ theseȱ phoneȱ numbersȱ hasȱ threeȱ parts:ȱ theȱ areaȱ code,ȱ theȱ
exchange,ȱ andȱ theȱ stationȱ number.ȱ Writeȱ aȱ structureȱ declarationȱ forȱ thisȱ billingȱ
information.ȱ
2. Writeȱaȱdeclarationȱforȱanȱinformationȱsystemȱthatȱrecordsȱsalesȱatȱanȱautoȱdealer.ȱȱȱ
Theȱ followingȱ dataȱ mustȱ beȱ savedȱ forȱ everyȱ sale.ȱ Theȱ maximumȱ lengthȱ ofȱ stringȱ
valuesȱgivenȱdoesȱnotȱincludeȱspaceȱforȱtheȱterminatingȱNULȱbyte.ȱ
ȱ
customerȇsȱnameȱ
customerȇsȱaddressȱ
modelȱ ȱ
ȱ
stringȱ(20)ȱ
stringȱ(40)ȱ
stringȱ(20)ȱ
ȱ
Threeȱ differentȱ typesȱ ofȱ transactionsȱ areȱ possible:ȱ allȬcashȱ sales,ȱ salesȱ involvingȱ aȱ
loan,ȱ andȱ leases.ȱ Forȱ allȬcashȱ sales,ȱ theȱ followingȱ additionalȱ informationȱ mustȱ beȱ
saved:ȱ
ȱ ȱ
ȱ
ȱ
manufacturerȇsȱsuggestedȱretailȱpriceȱ
ȱ
ȱ
actualȱsellingȱpriceȱ ȱ
salesȱtaxȱ
ȱ
ȱ
ȱ
ȱ
licensingȱfeeȱ ȱ
ȱ
ȱ
ȱ
floatȱ
floatȱ
floatȱ
floatȱ
Download at http://www.pin5i.com/
10.11 Programming Exercises
301
Forȱleases,ȱtheȱfollowingȱadditionalȱinformationȱmustȱbeȱsaved:ȱ
ȱ
manufacturerȇsȱsuggestedȱretailȱpriceȱ
ȱ
ȱ
actualȱsellingȱpriceȱ ȱ
downȱpaymentȱ
ȱ
ȱ
ȱ
securityȱdepositȱ
ȱ
ȱ
ȱ
monthlyȱpaymentȱ
ȱ
ȱ
ȱ
leaseȱtermȱ
ȱ
ȱ
ȱ
ȱ
floatȱ
floatȱ
floatȱ
floatȱ
floatȱ
intȱ
ȱ
Forȱsalesȱinvolvingȱaȱloan,ȱtheȱfollowingȱadditionalȱinformationȱmustȱbeȱsaved:ȱ
ȱ
manufacturerȇsȱsuggestedȱretailȱpriceȱ
ȱ
ȱ
actualȱsellingȱpriceȱ ȱ
salesȱtaxȱ
ȱ
ȱ
ȱ
ȱ
licensingȱfeeȱ ȱ
ȱ
ȱ
ȱ
downȱpaymentȱ
ȱ
ȱ
ȱ
loanȱdurationȱ ȱ
ȱ
ȱ
ȱ
interestȱrateȱ ȱ
ȱ
ȱ
ȱ
monthlyȱpaymentȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
nameȱofȱbankȱ ȱ
floatȱ
floatȱ
floatȱ
floatȱ
floatȱ
intȱ
floatȱ
floatȱ
stringȱ(20)ȱ
3. Oneȱ ofȱ theȱ computerȇsȱ tasksȱ isȱ toȱ decodeȱ eachȱ instructionȱ inȱ theȱ programȱ thatȱ isȱ
runningȱtoȱdetermineȱwhatȱoperationȱtoȱperform.ȱOnȱmanyȱmachines,ȱtheȱdecodingȱ
processȱisȱcomplicatedȱbyȱtheȱfactȱthatȱdifferentȱinstructionsȱhaveȱdifferentȱformats.ȱ
Onȱ oneȱ particularȱ machine,ȱ eachȱ instructionȱ isȱ 16ȱ bitsȱ long,ȱ andȱ theȱ followingȱ
differentȱformatsȱareȱimplemented.ȱBitsȱareȱnumberedȱfromȱrightȱtoȱleft.ȱ
ȱ
Single Operand (sgl_op)
Doubla Operand (dpl_op)
Branch (branch)
Bits
Field Name
Bits
Field Name
Bits
Field Name
0-2
3-5
6-15
dst_reg
dst_mode
opcode
ȱ
ȱ
Register Source (rag_src)
Bits
Field Name
0-2
3-5
6-8
9-15
dst_reg
dst_mode
src_reg
opcode
0-2
3-5
6-8
9-11
12-15
dst_reg
dst_mode
src_reg
src_mode
opcode
0-7
8-15
offset
opcode
Miscellaneous (misc)
Bits
Field Name
0-15
opcode
ȱ
Yourȱ taskȱ isȱ toȱ writeȱ aȱ declarationȱ thatȱ willȱ allowȱ aȱ programȱ toȱ interpretȱ anȱ
instructionȱinȱanyȱofȱtheseȱformats.ȱȱYourȱdeclarationȱmustȱalsoȱhaveȱanȱunsigned
Download at http://www.pin5i.com/
302ȱ
Chapter 10 Structures and Unions
shortȱfieldȱcalledȱaddrȱthatȱaccessesȱallȱ16ȱbits.ȱUseȱaȱtypedefȱinȱyourȱdeclarationȱtoȱ
createȱaȱnewȱtypeȱcalledȱmachine_inst.ȱ
Givenȱtheȱdeclaration:ȱ
ȱ
machine_inst
x;
ȱ
theȱexpressionsȱbelowȱshouldȱaccessȱtheȱindicatedȱbits.ȱ
ȱ
Expression
Bits
x.addr
x.misc.opcode
x.branch.opcode
x.sgl_op.dst_mode
x.reg_src.src_reg
x.dbl_op.opcode
ȱ
ȱ
ȱ
0-15
0-15
8-15
3-5
6-8
12-15
Download at http://www.pin5i.com/
11
Dynamic Memory Allocation
Theȱelementsȱofȱanȱarrayȱareȱstoredȱinȱcontiguousȱlocationsȱinȱmemory.ȱWhenȱanȱarrayȱ
isȱ declared,ȱ itsȱ memoryȱ isȱ allocatedȱ atȱ compileȱ time.ȱ However,ȱ youȱ canȱ alsoȱ allocateȱ
theȱ memoryȱ atȱ runtimeȱ withȱ dynamicȱ memoryȱ allocation.ȱ Inȱ thisȱ chapter,ȱ weȱ willȱ
examineȱ theȱ differencesȱ betweenȱ theseȱ techniquesȱ andȱ seeȱ whenȱ andȱ howȱ toȱ useȱ
dynamicȱmemoryȱallocation.ȱ
ȱ
ȱ
ȱ
11.1 Why Use Dynamic Allocation
TIP
ȱ
Whenȱdeclaringȱarrays,ȱtheȱarrayȱsizeȱmustȱbeȱgivenȱasȱaȱcompileȬtimeȱconstant.ȱOften,ȱ
theȱactualȱsizeȱneededȱforȱtheȱarrayȱisȱnotȱknownȱuntilȱrunȱtimeȱbecauseȱtheȱamountȱofȱ
spaceȱ dependsȱ uponȱ theȱ inputȱ data.ȱ Forȱ example,ȱ aȱ programȱ thatȱ computesȱ studentȱ
gradesȱ andȱ averagesȱ mightȱ needȱ toȱ storeȱ dataȱ forȱ allȱ ofȱ theȱ studentsȱ inȱ aȱ class,ȱ butȱ
differentȱclassesȱwillȱhaveȱdifferentȱnumbersȱofȱstudents.ȱInȱtheseȱsituations,ȱtheȱusualȱ
approachȱisȱtoȱdeclareȱanȱarrayȱthatȱisȱasȱbigȱasȱitȱeverȱwillȱneedȱtoȱbe.ȱ
ȱ
Thisȱ approachȱ hasȱ theȱ advantageȱ ofȱ beingȱ simple,ȱ butȱ itȱ hasȱ severalȱ disadvantages.ȱ
First,ȱ suchȱ declarationsȱ buildȱ anȱ artificialȱ limitationȱ intoȱ theȱ program,ȱ makingȱ itȱ
incapableȱ ofȱ handlingȱ problemsȱ largerȱ thanȱ theȱ sizeȱ usedȱ inȱ theȱ declaration.ȱ Theȱ
obviousȱ solutionȱ isȱ toȱ makeȱ theȱ arrayȱ evenȱ bigger,ȱ butȱ theȱ secondȱ problemȱ thenȱ
becomesȱevenȱworse.ȱNearlyȱallȱofȱtheȱmemoryȱusedȱforȱaȱhugeȱarrayȱisȱwastedȱwhenȱ
theȱ numberȱ ofȱ elementsȱ actuallyȱ requiredȱ isȱ small.ȱ Aȱ thirdȱ disadvantageȱ isȱ thatȱ theȱ
programȱmustȱrespondȱinȱaȱreasonableȱwayȱwhenȱthereȱisȱmoreȱinputȱthanȱtheȱarrayȱ
canȱhold.ȱItȱshouldȱnotȱfailȱwithȱanȱexception,ȱandȱitȱmustȱnotȱprintȱanswersȱthatȱlookȱ
validȱbutȱinȱfactȱareȱwrong.ȱTheȱrequiredȱlogicȱisȱsimpleȱenough,ȱbutȱtheȱassumptionȱ
thatȱ Ȉtheȱ arrayȱ willȱ neverȱ overflowȈȱ makesȱ itȱ veryȱ temptingȱ toȱ notȱ botherȱ
implementingȱit.ȱ
Download at http://www.pin5i.com/
304ȱ
Chapter 11 Dynamic Memory Allocationȱ
11.2 Malloc and Free
ȱ
TheȱCȱlibraryȱprovidesȱtwoȱfunctions,ȱmallocȱandȱfree,ȱthatȱperformȱdynamicȱmemoryȱ
allocationȱ andȱ deallocation.ȱ Theseȱ functionsȱ maintainȱ aȱ poolȱ ofȱ availableȱ memory.ȱ
Whenȱaȱprogramȱneedsȱadditionalȱmemory,ȱitȱcallsȱmalloc,ȱwhichȱtakesȱanȱappropriateȱ
pieceȱ ofȱmemoryȱ fromȱ theȱ poolȱandȱ returnsȱaȱpointerȱtoȱ thisȱblockȱofȱmemoryȱtoȱ theȱ
program.ȱTheȱmemoryȱisȱnotȱinitializedȱinȱanyȱway.ȱIfȱitȱisȱimportantȱthatȱtheȱmemoryȱ
beȱinitialized,ȱyouȱmustȱeitherȱdoȱitȱyourselfȱorȱuseȱtheȱ callocȱfunctionȱ(describedȱinȱ
theȱnextȱsection).ȱWhenȱaȱpreviouslyȱallocatedȱpieceȱofȱmemoryȱisȱnoȱlongerȱneeded,ȱ
freeȱisȱcalledȱtoȱreturnȱitȱtoȱtheȱpoolȱforȱlaterȱreuse.ȱ
Theȱprototypesȱforȱtheseȱtwoȱfunctionsȱareȱshownȱbelow,ȱandȱareȱinȱstdlib.h.ȱ
ȱ
ȱ
void
void
*malloc( size_t size );
free( void *pointer );
ȱ
ȱ
Theȱ argumentȱ toȱ mallocȱ isȱ theȱ numberȱ ofȱ bytesȱ (characters)ȱ ofȱ memoryȱ thatȱ areȱ
needed. 41 ȱIfȱtheȱdesiredȱamountȱofȱmemoryȱisȱavailable,ȱmallocȱreturnsȱaȱpointerȱtoȱtheȱ
beginningȱofȱtheȱallocatedȱblock.ȱ
ȱ
ȱ
mallocȱ allocatesȱ contiguousȱ blocksȱ ofȱ memory.ȱ Forȱ example,ȱ aȱ requestȱ forȱ 100ȱ
bytesȱ willȱ beȱ satisfiedȱ withȱ 100ȱ adjacentȱ bytes,ȱ neverȱ withȱ twoȱ orȱ moreȱ separateȱ
chunksȱ ofȱ memory.ȱ Also,ȱ mallocȱ mayȱ actuallyȱ allocateȱ aȱ chunkȱ ofȱ memoryȱ slightlyȱ
largerȱ thanȱ requested.ȱ However,ȱ thisȱ behaviorȱ isȱ implementationȱ dependent,ȱ soȱ youȱ
shouldȱnotȱcountȱonȱgettingȱmoreȱmemoryȱthanȱyouȱrequested.ȱ
ȱ
Whatȱifȱtheȱpoolȱofȱmemoryȱisȱempty,ȱorȱitȱdoesȱnotȱcontainȱaȱbigȱenoughȱblock?ȱ
Inȱ thisȱ case,ȱ mallocȱ callsȱ theȱ operatingȱ systemȱ toȱ obtainȱ moreȱ memoryȱ andȱ beginsȱ
allocatingȱpiecesȱfromȱthisȱnewȱchunk.ȱIfȱtheȱoperatingȱsystemȱisȱunableȱtoȱgiveȱmoreȱ
memoryȱ toȱ malloc,ȱ thenȱ aȱ NULLȱ pointerȱ isȱ returned.ȱ Thusȱ itȱ isȱ vitalȱ thatȱ theȱ pointerȱ
returnedȱbyȱeveryȱcallȱtoȱmalloc beȱcheckedȱtoȱensureȱthatȱitȱisȱnotȱNULL.ȱ
ȱ
Theȱ argumentȱ toȱ freeȱ mustȱ eitherȱ beȱ NULLȱ orȱ aȱ valueȱ thatȱ wasȱ previouslyȱ
returnedȱ fromȱ malloc,ȱ calloc,ȱ orȱ reallocȱ (describedȱ below).ȱ Passingȱ aȱ NULLȱ
argumentȱtoȱfree hasȱnoȱeffect.ȱ
ȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
41
ȱNoteȱthatȱtheȱtypeȱofȱthisȱargumentȱisȱsize_t,ȱwhichȱisȱanȱunsignedȱtype.ȱItȱisȱdefinedȱin stdlib.h.ȱ
Download at http://www.pin5i.com/
11.3 Calloc and Reallocȱ
305
Howȱ doesȱ mallocȱ knowȱ whetherȱ youȱ wantȱ toȱ storeȱ integers,ȱ floatingȬpointȱ
values,ȱ structures,ȱ orȱ arraysȱ inȱ theȱ memoryȱ youȇveȱ requested?ȱ Itȱ doesnȇt—mallocȱ
returnsȱ aȱ pointerȱ ofȱ typeȱ void *ȱ forȱ preciselyȱ thisȱ reason.ȱ Theȱ Standardȱ statesȱ thatȱ aȱ
void *ȱ pointerȱ canȱ beȱ convertedȱ toȱ anyȱ otherȱ pointerȱ type.ȱ Someȱ compilerȱ though,ȱ
especiallyȱolderȱones,ȱmayȱrequireȱyouȱtoȱuseȱaȱcastȱforȱtheȱconversion.ȱ
Onȱmachinesȱwithȱboundaryȱalignmentȱrequirements,ȱtheȱmemoryȱreturnedȱbyȱ
mallocȱwillȱalwaysȱbeginȱonȱaȱboundaryȱthatȱisȱsuitableȱforȱtheȱdataȱtypeȱwithȱtheȱmostȱ
stringentȱalignmentȱrequirements.ȱ
ȱ
ȱ
ȱ
11.3 Calloc and Realloc
ȱ
Thereȱ areȱ twoȱ additionalȱ memoryȱ allocationȱ functions,ȱ callocȱ andȱ realloc.ȱ Theirȱ
prototypesȱareȱshownȱbelow.ȱ
ȱ
void
void
*calloc( size_t num_elementa,
size_t element_size );
*realloc( void *ptr, size_t new_size );
ȱ
callocȱalsoȱallocatesȱmemory.ȱTheȱmajorȱdifferenceȱbetweenȱmallocȱandȱcallocȱisȱthatȱ
theȱ latterȱ initializesȱ theȱ memoryȱ toȱ zeroȱ beforeȱ returningȱ aȱ pointerȱ toȱ it.ȱ Thisȱ
initializationȱisȱoftenȱconvenient,ȱbutȱisȱaȱwasteȱofȱtimeȱifȱtheȱfirstȱthingȱyourȱprogramȱ
doesȱisȱtoȱstoreȱvaluesȱintoȱtheȱarray.ȱAȱminorȱdifferenceȱbetweenȱcallocȱandȱmallocȱisȱ
theȱ wayȱ theȱ amountȱ ofȱ memoryȱ isȱ requested,ȱ callocȱ takesȱ theȱ numberȱ ofȱ elementsȱ
desiredȱandȱtheȱnumberȱofȱbytesȱinȱeachȱelement.ȱFromȱtheseȱvaluesȱitȱcomputesȱtheȱ
totalȱnumberȱofȱbytesȱneeded.ȱ
Theȱ reallocȱfunctionȱisȱusedȱtoȱchangeȱtheȱsizeȱofȱaȱpreviouslyȱallocatedȱblockȱ
ofȱ memory.ȱ Youȱ canȱ makeȱ aȱ blockȱ largerȱ orȱ smallerȱ withȱ thisȱ functionȱ Ifȱ aȱ blockȱ isȱ
madeȱ larger,ȱ itsȱ oldȱ contentsȱ remainȱ unchangedȱ andȱ additionalȱ memoryȱ isȱ addedȱ toȱ
theȱ endȱ ofȱ theȱ block.ȱ Theȱ newȱ memoryȱ isȱ notȱ initializedȱ inȱ anyȱ way.ȱ Ifȱ theȱ blockȱ isȱ
madeȱ smaller,ȱ thenȱ memoryȱ isȱ takenȱ offȱ ofȱ theȱ end.ȱ Whatȱ remainsȱ ofȱ theȱ originalȱ
contentsȱareȱunchanged.ȱ
Ifȱtheȱoriginalȱblockȱcannotȱbeȱresized,ȱreallocȱwillȱallocateȱaȱdifferentȱblockȱofȱtheȱ
rightȱsizeȱandȱcopyȱtheȱcontentsȱofȱtheȱoldȱblockȱtoȱtheȱnewȱone.ȱThus,ȱyouȱmustȱnotȱ
useȱ theȱ oldȱ pointerȱ toȱ theȱ blockȱ afterȱ aȱ callȱ toȱ realloc.ȱ Useȱ theȱ newȱ pointerȱ thatȱ isȱ
returnedȱinstead.ȱ
Finally,ȱ ifȱ theȱ firstȱ argumentȱ toȱ reallocȱ isȱ NULL,ȱ thenȱ itȱ behavesȱ exactlyȱ like
malloc.ȱ
Download at http://www.pin5i.com/
Chapter 11 Dynamic Memory Allocationȱ
306ȱ
11.4 Using Dynamically Allocated Memory
ȱ
Hereȱisȱanȱexampleȱthatȱobtainsȱaȱchunkȱofȱmemoryȱfromȱmalloc.ȱ
ȱ
int
*pi;
...
pi = malloc( 100 );
if( pi == NULL ){
printf( "Out of memory!\n" );
exit( 1 );
}
TIP
ȱ
TheȱsymbolȱNULLȱisȱdefinedȱinȱ stdio.hȱasȱtheȱliteralȱconstantȱzero.ȱItȱactsȱasȱaȱvisualȱ
reminderȱthatȱtheȱvalueȱbeingȱtestedȱisȱaȱpointerȱtypeȱratherȱthanȱanȱinteger.ȱ
Ifȱthereȱwasȱmemoryȱavailable,ȱweȱwillȱnowȱhaveȱaȱpointerȱtoȱ100ȱbytes.ȱOnȱaȱ
machineȱ withȱ 4Ȭbyteȱ integers,ȱ theȱ memoryȱ willȱ beȱ treatedȱ asȱ anȱ arrayȱ ofȱ 25ȱ integersȱ
becauseȱpiȱisȱaȱpointerȱtoȱanȱinteger.ȱ
ȱ
Ifȱ yourȱ goalȱ isȱ toȱ getȱ enoughȱ memoryȱ forȱ 25ȱ integers,ȱ though,ȱ hereȱ isȱ aȱ muchȱ betterȱ
techniqueȱforȱobtainingȱit.ȱ
ȱ
ȱ
pi = malloc( 25 * sizeof( int ) );
ȱ
Thisȱapproachȱisȱbetterȱbecauseȱitȱisȱportable.ȱItȱworksȱproperlyȱevenȱonȱmachinesȱwithȱ
differentȱsizeȱintegers.ȱ
Nowȱthatȱyouȱhaveȱaȱpointer,ȱhowȱdoȱyouȱuseȱtheȱmemory?ȱOfȱcourseȱyouȱcanȱ
useȱindirectionȱandȱpointerȱarithmeticȱtoȱaccessȱdifferentȱintegerȱlocationsȱinȱthisȱarray,ȱ
asȱinȱthisȱloop,ȱwhichȱsetsȱeachȱelementȱofȱtheȱnewlyȱallocatedȱarrayȱtoȱzero:ȱ
ȱ
int
*pi2, i;
...
pi2 = pi;
for( i = 0; i < 25; i += 1 )
*pi2++ = 0;
ȱ
Asȱ youȱ haveȱ seen,ȱ youȱ canȱ useȱ aȱ subscriptȱ onȱ theȱ pointerȱ asȱ well.ȱ Thisȱ secondȱ loopȱ
performsȱtheȱsameȱworkȱasȱtheȱpreviousȱone.ȱ
ȱ
int
i;
...
for( i = 0; i < 25; i += 1 )
pi[i] = 0;
ȱ
Download at http://www.pin5i.com/
11.5 Common Dynamic Memory Errorsȱ
307
11.5 Common Dynamic Memory Errors
CAUTION!
CAUTION!
ȱ
Thereȱ areȱ manyȱ errorsȱ thatȱ canȱ occurȱ inȱ programsȱ thatȱ useȱ dynamicȱ memoryȱ
allocation.ȱ Theseȱ includeȱ dereferencingȱ NULLȱ pointers,ȱ goingȱ outsideȱ dieȱ boundsȱ ofȱ
theȱ memoryȱ thatȱ wasȱ allocated,ȱ freeingȱ memoryȱ blocksȱ thatȱ wereȱ notȱ dynamicallyȱ
allocated,ȱ attemptingȱ toȱ freeȱ aȱ portionȱ ofȱ aȱ dynamicȱ block,ȱ andȱ continuingȱ toȱ useȱ
dynamicȱmemoryȱafterȱitȱhasȱbeenȱfreed.ȱ
ȱ
Theȱ mostȱ commonȱ errorȱ withȱ dynamicȱ memoryȱ allocationȱ isȱ forgettingȱ toȱ checkȱ
whetherȱtheȱrequestedȱmemoryȱwasȱallocated.ȱProgramȱ11.1ȱpresentsȱaȱtechniqueȱthatȱ
makesȱ thisȱ errorȱ checkingȱ almostȱ foolproofȱ Theȱ MALLOCȱ macroȱ cakesȱ theȱ numberȱ ofȱ
elementsȱ andȱ typeȱ ofȱ eachȱelement,ȱcomputesȱtheȱtotalȱnumberȱofȱbytesȱneeded,ȱandȱ
callsȱ allocȱ toȱ obtainȱ theȱ memory. 42 ȱ allocȱ callsȱ mallocȱ andȱ thenȱ checksȱ toȱ makeȱ sureȱ
thatȱtheȱpointerȱreturnedȱwasȱnotȱNULL.ȱ
Theȱ finalȱ pieceȱ ofȱ thisȱ puzzleȱ isȱ theȱ veryȱ firstȱ #define.ȱ Itȱ preventsȱ accidentalȱ
callsȱ directlyȱ toȱ mallocȱ byȱ substitutingȱ junkȱ intoȱ theȱ program.ȱ Ifȱ anȱ accidentalȱ callȱ isȱ
made,ȱ theȱ programȱ willȱ notȱ compileȱ dueȱ toȱ syntaxȱ errors.ȱ Theȱ #undefȱ isȱ neededȱ inȱ
allocȱsoȱthatȱitȱcanȱcallȱmallocȱwithoutȱerror.ȱ
ȱ
Theȱ secondȱ biggestȱ sourceȱ ofȱ errorȱ withȱ dynamicallyȱ allocatedȱ memoryȱ isȱ goingȱ
outsideȱ ofȱ theȱ boundsȱ ofȱ theȱ memoryȱ thatȱ wasȱ allocated.ȱ Forȱ example,ȱ ifȱ youȱ haveȱ
obtainedȱanȱarrayȱofȱ25ȱintegers,ȱaccessingȱelementsȱwithȱsubscriptsȱlessȱthanȱzeroȱorȱ
greaterȱthanȱ24ȱcanȱcauseȱtwoȱtypesȱofȱproblems.ȱ
Theȱ firstȱ problemȱ isȱ obvious;ȱ theȱ memoryȱ beingȱ accessedȱ mightȱ beȱ holdingȱ
someȱ otherȱ variable.ȱ Changingȱ itȱ hereȱ willȱ destroyȱ theȱ variable,ȱ andȱ changingȱ theȱ
variableȱwillȱdestroyȱanyȱvalueȱyouȱstoreȱhere.ȱTheseȱkindsȱofȱbugsȱareȱveryȱdifficultȱtoȱ
trackȱdown.ȱ
Theȱ secondȱ problemȱ isȱ notȱ soȱ obvious.ȱ Someȱ implementationsȱ ofȱ mallocȱ andȱ
freeȱkeepȱtheȱpoolȱofȱavailableȱstorageȱasȱaȱlinkedȱlist.ȱȱModifyingȱlocationȱoutsideȱtheȱ
ȱ
ȱ
ȱ
ȱ
/*
** Definitions for a less error-prone memory allocator.
*/
#include <stdlib.h>
#define
#define
extern
malloc
DON'T CALL malloc DIRECTLY!
MALLOC(num,type)
(type *)alloc( (num) * sizeof(type) )
void *alloc( size_t size );
Programȱ11.1aȱȱErrorȱcheckingȱallocator:ȱinterfaceȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
42
ȱ#defineȱmacrosȱareȱdescribedȱinȱdetailȱinȱChapterȱ14.ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱȱȱalloc.hȱ
Download at http://www.pin5i.com/
308ȱ
Chapter 11 Dynamic Memory Allocationȱ
ȱ
/*
** Implementation for a less error-prone memory allocator.
*/
#include <stdio.h>
#include "alloc.h"
#undef
malloc
void *
alloc( size_t size )
{
void *new_mem;
/*
** Ask for the requested memory, and check that we really
** got it.
*/
new_mem = malloc( size );
if( new_mem == NULL ){
printf( "Out of memory!\en" );
exit( 1 );
}
return new_mem;
}
ȱ
Programȱ11.1bȱȱErrorȱcheckingȱallocator:ȱimplementationȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱȱalloc.cȱ
ȱ
ȱȱȱȱa_client.cȱ
/*
** A program that uses the less error-prone memory allocator.
*/
#include "alloc.h"
void
function()
{
int
*new_memory;
/*
** Get space for a bunch of integers
*/
new_memory = MALLOC( 25, int );
/* ... */
}
ȱ
Programȱ11.1cȱȱUsingȱtheȱerrorȱcheckingȱallocatorȱ
ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
11.5 Common Dynamic Memory Errorsȱ
309
boundsȱ ofȱ allocatedȱ memoryȱ canȱ corruptȱ thisȱ list,ȱ whichȱ canȱ causeȱ exceptionsȱ thatȱ
terminateȱtheȱprogram.ȱ
Whenȱaȱprogramȱthatȱusesȱdynamicallyȱallocatedȱmemoryȱfails,ȱitȱisȱtemptingȱtoȱ
blameȱ theȱ problemsȱ onȱ mallocȱ andȱ free.ȱ Theyȱ areȱ rarelyȱ theȱ culprit,ȱ though.ȱ Inȱ
practice,ȱ theȱ problemȱ isȱ nearlyȱ alwaysȱ inȱ yourȱ programȱ andȱ isȱ frequentlyȱ causedȱ byȱ
accessingȱdataȱoutsideȱofȱtheȱallocatedȱmemory.ȱ
CAUTION!
Differentȱ errorsȱ canȱ occurȱ whenȱ usingȱ free.ȱ Theȱ pointerȱ passedȱ toȱ freeȱ mustȱ beȱ aȱ
pointerȱthatȱwasȱobtainedȱfromȱmalloc,ȱcalloc,ȱorȱrealloc.ȱCallingȱfreeȱwithȱaȱpointerȱ
toȱ memoryȱ thatȱ wasȱ notȱ dynamicallyȱ allocatedȱ canȱ causeȱ theȱ programȱ toȱ terminateȱ
eitherȱrightȱawayȱorȱatȱsomeȱlaterȱtime.ȱSimilarȱproblemsȱcanȱbeȱcausedȱbyȱattemptingȱ
toȱfreeȱonlyȱaȱportionȱofȱaȱdynamicallyȱallocatedȱblock,ȱlikeȱthis:ȱ
ȱ
/*
** Get 10 integers
*/
pi = malloc( 10 * sizeof( int ) );
...
/*
** Free only the last 5 integers; keep the first 5
*/
free( pi + 5 );
ȱ
Freeingȱaȱportionȱofȱaȱblockȱisȱnotȱallowed;ȱtheȱwholeȱblockȱmustȱbeȱfreed.ȱHowever,ȱ
theȱ reallocȱ functionȱ canȱ makeȱ aȱ dynamicallyȱ allocatedȱ chunkȱ ofȱ memoryȱ smaller,ȱ
effectivelyȱfreeingȱtheȱendȱofȱit.ȱ
CAUTION!
Finally,ȱyouȱmustȱbeȱcarefulȱnotȱtoȱaccessȱmemoryȱthatȱhasȱbeenȱ freeȇd.ȱThisȱwarningȱ
mayȱ seemȱ obvious,ȱ butȱ thereȱ isȱ aȱ subtleȱ problemȱ hereȱ afterȱ all.ȱ Supposeȱ copiesȱ areȱ
madeȱofȱtheȱpointerȱtoȱaȱdynamicallyȱallocatedȱblock,ȱandȱtheseȱcopiesȱareȱsentȱoffȱtoȱ
manyȱ differentȱ partsȱ ofȱ theȱ program.ȱ Itȱ isȱ difficultȱ toȱ makeȱ sureȱ thatȱ noneȱ ofȱ theseȱ
otherȱareasȱinȱtheȱprogramȱuseȱtheirȱcopiesȱofȱtheȱpointerȱafterȱtheȱmemoryȱhasȱbeenȱ
freed.ȱConversely,ȱyouȱmustȱbeȱsureȱthatȱallȱpartsȱofȱtheȱprogramȱareȱfinishedȱusingȱaȱ
chunkȱofȱmemoryȱbeforeȱfreeingȱit.ȱ
ȱ
ȱ
ȱ
11.5.1
Memory Leaks
ȱ
Dynamicallyȱallocatedȱmemoryȱshouldȱbeȱfreedȱwhenȱitȱisȱnoȱlongerȱneededȱsoȱthatȱitȱ
canȱ beȱ reusedȱ laterȱ forȱ otherȱ purposes.ȱ Allocatingȱ memoryȱ butȱ notȱ freeingȱ itȱ laterȱ
causesȱ aȱ memoryȱ leak.ȱ Withȱ operatingȱ systemsȱ thatȱ shareȱ aȱ commonȱ poolȱ ofȱ memoryȱ
amongȱallȱ executingȱprograms,ȱmemoryȱleaksȱdribbleȱawayȱtheȱavailableȱmemoryȱsoȱ
thatȱeventuallyȱthereȱisnȇtȱanyȱleft.ȱRebootingȱtheȱcomputerȱisȱtheȱonlyȱrecoveryȱforȱthisȱ
situation.ȱ
Download at http://www.pin5i.com/
310ȱ
Chapter 11 Dynamic Memory Allocationȱ
Otherȱoperatingȱsystemsȱ keepȱtrackȱ ofȱ whichȱpiecesȱofȱ memoryȱeachȱ programȱ
currentlyȱ has,ȱ soȱ thatȱ whenȱ aȱ programȱ terminatesȱ allȱ ofȱ theȱ memoryȱ thatȱ itȱ hadȱ
allocatedȱ butȱ hadȱ notȱ freedȱ isȱ returnedȱ toȱ theȱ pool.ȱ Memoryȱ leaksȱ areȱ aȱ seriousȱ
problemȱevenȱonȱtheseȱsystems,ȱbecauseȱaȱprogramȱthatȱcontinuallyȱallocatesȱmemoryȱ
withoutȱeverȱfreeingȱanyȱwillȱeventuallyȱexhaustȱtheȱavailableȱmemory.ȱAtȱthisȱpoint,ȱ
theȱdefectiveȱprogramȱwillȱnotȱbeȱableȱtoȱcontinueȱexecuting,ȱandȱitsȱfailureȱmayȱresultȱ
inȱtheȱlossȱofȱtheȱworkȱcompletedȱsoȱfar.ȱ
ȱ
ȱ
ȱ
11.6 Memory Allocation Examples
ȱ
Aȱ commonȱ useȱ forȱ dynamicȱ memoryȱ allocationȱ isȱ obtainingȱ spaceȱ forȱ arraysȱ whoseȱ
sizesȱ areȱ notȱ knownȱ untilȱ runȱ time.ȱ Programȱ 11.2ȱ readsȱ aȱ listȱ ofȱ integers,ȱ sortsȱ themȱ
intoȱascendingȱsequence,ȱandȱprintsȱtheȱlist.ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Read, sort, and print a list of integer values.
*/
#include <stdlib.h>
#include <stdio.h>
/*
**
Function called by 'qsort' to compare integer values
*/
int
compare_integers( void const *a, void const *b )
{
register int
const *pa = a;
register int
const *pb = b;
return *pa > *pb ? 1 : *pa < *pb ? -1 : 0;
}
int
main()
{
int
int
int
*array;
n_values;
i;
/*
** See how many numbers there will be.
ȱ
Programȱ11.2ȱȱSortȱaȱlistȱofȱintegersȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued…ȱ
Download at http://www.pin5i.com/
11.6 Memory Allocation Examplesȱ
ȱ
ȱ
311
*/
printf( "How many values are there? " );
if( scanf( "%d", &n_values ) != 1 || n_values <= 0 ){
printf( "Illegal number of values.\n" );
exit( EXIT_FAILURE );
}
/*
** Get memory to store them.
*/
array = malloc( n_values * sizeof( int ) );
if( array == NULL ){
printf( "Can't get memory for that many values.\n" );
exit( EXIT_FAILURE );
}
/*
** Read the numbers.
*/
for( i = 0; i < n_values; i += 1 ){
printf( "? " );
if( scanf( "%d", array + i ) != 1 ){
printf( "Error reading value #%d\n", i );
exit( EXIT_FAILURE );
}
}
/*
** Sort the values.
*/
qsort( array, n_values, sizeof( int ), compare_integers );
/*
** Print them out.
*/
for( i = 0; i < n_values; i += 1 )
printf( "%d\n", array[i] );
/*
** Free the memory and exit.
*/
free( array );
return EXIT_SUCCESS;
}
ȱ
Programȱ11.2ȱȱSortȱaȱlistȱofȱintegersȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
sort.cȱ
Download at http://www.pin5i.com/
312ȱ
Chapter 11 Dynamic Memory Allocationȱ
Memoryȱtoȱholdȱtheȱlistȱisȱdynamicallyȱallocatedȱsoȱthatȱwhenȱyouȱareȱwritingȱ
theȱ programȱ youȱ donȇtȱ haveȱ toȱ guessȱ howȱ manyȱ valuesȱ theȱ userȱ mightȱ wishȱ toȱ sort.ȱ
Theȱonlyȱlimitȱonȱ theȱ numberȱofȱvaluesȱthatȱcanȱbeȱsortedȱisȱtheȱamountȱofȱ dynamicȱ
memoryȱavailableȱtoȱtheȱprogram.ȱWhenȱsmallȱlistsȱareȱsorted,ȱthough,ȱonlyȱasȱmuchȱ
memoryȱasȱisȱactuallyȱneededȱisȱallocated,ȱsoȱmemoryȱisȱnotȱwasted.ȱ
Nowȱconsiderȱaȱprogramȱthatȱreadsȱstrings.ȱIfȱyouȱdonȇtȱknowȱtheȱlengthȱofȱtheȱ
longestȱ stringȱ inȱ advanceȱ youȱ cannotȱ useȱ anȱ ordinaryȱ arrayȱ asȱ aȱ buffer.ȱ Instead,ȱ useȱ
dynamicallyȱallocatedȱmemory.ȱWhenȱyouȱfindȱanȱinputȱlineȱthatȱdoesnȇtȱfit,ȱreallocateȱ
aȱlargerȱbufferȱandȱreadȱtheȱremainderȱofȱtheȱlineȱintoȱit.ȱTheȱimplementationȱofȱthisȱ
techniqueȱisȱleftȱasȱaȱprogrammingȱexercise.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Make a copy of a string in dynamically allocated memory. Note:
** caller is responsible for checking whether the memory was
** allocated! This allows the caller to respond to an error in
** any way they wish.
*/
#include <stdlib.h>
#include <string.h>
char *
strdup( char const *string )
{
char *new_string;
/*
** Ask for enough memory to hold the string and its
** terminating NUL byte.
*/
new_string = malloc( strlen( string ) + 1 );
/*
** If we got the memory, copy the string.
*/
if( new_string != NULL )
strcpy( new_string, string );
return new_string;
}
ȱ
Programȱ11.3ȱȱDuplicateȱaȱstringȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱstrdup.cȱ
Download at http://www.pin5i.com/
11.6 Memory Allocation Examplesȱ
313
Theȱinputȱisȱreadȱintoȱthisȱbuffer,ȱoneȱlineȱatȱaȱtime.ȱTheȱlengthȱofȱtheȱstringȱisȱ
determined,ȱandȱthenȱmemoryȱisȱallocatedȱtoȱholdȱit.ȱFinally,ȱtheȱstringȱisȱcopiedȱintoȱ
theȱnewȱmemoryȱsoȱtheȱbufferȱcanȱbeȱusedȱtoȱreadȱtheȱnextȱline.ȱ
TheȱfunctionȱinȱProgramȱ11.3,ȱcalledȱstrdup,ȱreturnsȱaȱcopyȱofȱitsȱinputȱstringȱinȱ
dynamicallyȱ allocatedȱ memory.ȱ Theȱ functionȱ firstȱ triesȱ toȱ obtainȱ enoughȱ memoryȱ toȱ
holdȱtheȱcopy.ȱTheȱadditionalȱbyteȱbeyondȱtheȱstringȱlengthȱisȱneededȱtoȱholdȱtheȱNULȱ
byteȱthatȱterminatesȱtheȱstring.ȱȱIfȱtheȱmemoryȱwasȱsuccessfullyȱallocated,ȱtheȱstringȱisȱ
copiedȱ intoȱ theȱ newȱ memory.ȱ Finally,ȱ aȱ pointerȱ toȱ theȱ newȱ memoryȱ isȱ returned.ȱȱ
Noticeȱ thatȱ new_stringȱ willȱ beȱ NULLȱ ifȱ theȱ allocationȱ failedȱ forȱ someȱ reason,ȱ soȱ aȱ
NULLȱpointerȱwouldȱbeȱreturnedȱinȱthisȱcase.ȱ
Thisȱ functionȱ isȱ veryȱ handy.ȱ Itȱ isȱ soȱ useful,ȱ inȱ fact,ȱ thatȱ manyȱ environmentsȱ
includeȱitȱasȱpartȱofȱtheȱlibraryȱevenȱthoughȱtheȱStandardȱdoesȱnotȱmentionȱit.ȱ
Ourȱ finalȱ exampleȱ illustratesȱ howȱ youȱ canȱ useȱ dynamicȱ memoryȱ allocationȱ toȱ
eliminateȱwastedȱmemoryȱwithȱvariantȱrecords.ȱProgramȱ11.4ȱisȱaȱmodificationȱofȱtheȱ
inventoryȱ systemȱ exampleȱ fromȱ Chapterȱ 10.ȱ Programȱ 11.4aȱ containsȱ theȱ declarationsȱ
forȱtheȱinventoryȱrecords.ȱ
Asȱ before,ȱ theȱ inventoryȱ systemȱ mustȱ handleȱ twoȱ typesȱ ofȱ records,ȱ thoseȱ forȱ
partsȱandȱthoseȱforȱsubassemblies.ȱTheȱfirstȱstructureȱholdsȱtheȱinformationȱspecificȱtoȱ
aȱ partȱ (onlyȱ aȱ portionȱ ofȱ thisȱ structureȱ isȱ shown),ȱ andȱ theȱ secondȱ holdsȱ informationȱ
aboutȱsubassemblies.ȱTheȱlastȱdeclarationȱisȱforȱtheȱinventoryȱrecord.ȱItȱcontainsȱsomeȱ
commonȱdataȱneededȱforȱbothȱsubassembliesȱandȱpartsȱandȱaȱvariantȱportion.ȱ
Becauseȱ theȱ differentȱ fieldsȱ inȱ theȱ variantȱ partȱ areȱ differentȱ sizesȱ (inȱ fact,ȱ theȱ
subassemblyȱ recordȱ isȱ variableȱ size),ȱ theȱ unionȱ containsȱ pointersȱ toȱ structuresȱ ratherȱ
thanȱ theȱ structures.ȱ Dynamicȱ allocationȱ letsȱ theȱ programȱ createȱ anȱ inventoryȱ recordȱ
thatȱisȱtheȱcorrectȱsizeȱforȱtheȱitemȱbeingȱstored,ȱsoȱthereȱisȱnoȱwastedȱmemory.ȱ
Programȱ11.4bȱisȱaȱfunctionȱthatȱcreatesȱanȱinventoryȱrecordȱforȱaȱsubassembly.ȱ
Thisȱtaskȱdependsȱonȱtheȱnumberȱofȱdifferentȱpartsȱtheȱsubassemblyȱcontains,ȱsoȱthisȱ
valueȱisȱpassedȱasȱanȱargument.ȱ
Thisȱ functionȱ allocatesȱ threeȱ things:ȱ theȱ inventoryȱ record,ȱ theȱ subassemblyȱ
structure,ȱ andȱ theȱ arrayȱ ofȱ partsȱ inȱ theȱ subassemblyȱ structure.ȱ Ifȱ anyȱ ofȱ theseȱ
allocationsȱfails,ȱanyȱmemoryȱthatȱwasȱalreadyȱobtainedȱisȱfreedȱandȱaȱNULLȱpointerȱisȱ
returned.ȱOtherwise,ȱtheȱ typeȱandȱ info.subassy->n_partsȱfieldsȱareȱinitializedȱandȱaȱ
pointerȱtoȱtheȱrecordȱisȱreturned.ȱ
Obtainingȱmemoryȱforȱanȱinventoryȱrecordȱtoȱstoreȱaȱpartȱisȱaȱlittleȱeasierȱthanȱ
forȱaȱsubassemblyȱbecauseȱonlyȱtwoȱallocationsȱareȱneeded.ȱThisȱfunctionȱisȱthereforeȱ
notȱillustratedȱhere.ȱ
Download at http://www.pin5i.com/
314ȱ
Chapter 11 Dynamic Memory Allocationȱ
ȱ
/*
** Declarations for the inventory record.
**
**
Structure that contains information about a part.
*/
typedef struct
{
int
cost;
int
supplier;
/* etc. */
} Partinfo;
/*
**
Structure to hold information about a subassembly.
*/
typedef
struct
{
int
n_parts;
struct
SUBASSYPART {
char partno[10];
short quan;
} *part;
} Subassyinfo;
/*
**
Structure for an inventory record, which is a variant record.
*/
typedef
struct
{
char partno[10];
int
quan;
enum { PART, SUBASSY } type;
union {
Partinfo
*part;
Subassyinfo *subassy;
} info;
} Invrec;
ȱ
Programȱ11.4aȱȱInventoryȱsystemȱdeclarationsȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱinventor.hȱ
Download at http://www.pin5i.com/
11.6 Memory Allocation Examplesȱ
315
ȱ
/*
** Function to create a SUBASSEMBLY inventory record.
*/
#include <stdlib.h>
#include <stdio.h>
#include "inventor.h"
Invrec *
create_subassy_record( int n_parts )
{
Invrec
*new_rec;
/*
** Try to get memory for the Invrec portion.
*/
new_rec = malloc( sizeof( Invrec ) );
if( new_rec != NULL ){
/*
** That worked; now get the SUBASSYINFO portion.
*/
new_rec->info.subassy =
malloc( sizeof( Subassyinfo ) );
if( new_rec->info.subassy != NULL ){
/*
** Get an array big enough for the parts.
*/
new_rec->info.subassy->part = malloc(
n_parts * sizeof( struct SUBASSYPART ) );
if( new_rec->info.subassy->part != NULL ){
/*
** Got the memory; fill in the fields
** whose values we know and return.
*/
new_rec->type = SUBASSY;
new_rec->info.subassy->n_parts =
n_parts;
return new_rec;
}
/*
** Out of memory: free what we've got so far.
*/
free( new_rec->info.subassy );
}
free( new_rec );
}
return NULL;
}
ȱ
Programȱ11.4bȱȱDynamicȱcreationȱofȱaȱvariantȱrecordȱ ȱ
ȱ
ȱ
ȱ
ȱȱȱȱinvcreat.cȱ
Download at http://www.pin5i.com/
316ȱ
Chapter 11 Dynamic Memory Allocationȱ
Programȱ 11.4cȱ containsȱ theȱ lastȱ partȱ ofȱ thisȱ example:ȱ aȱ functionȱ thatȱ destroysȱ
inventoryȱ records.ȱ Thisȱ functionȱ worksȱ forȱ eitherȱ typeȱ ofȱ inventoryȱ record.ȱ Itȱ usesȱ aȱ
switchȱ statementȱ toȱ determineȱ theȱ typeȱ ofȱ recordȱ itȱ wasȱ givenȱ andȱ thenȱ freesȱ allȱ
dynamicallyȱallocatedȱfieldsȱinȱtheȱrecord.ȱFinally,ȱtheȱrecordȱisȱdeleted.ȱ
Aȱcommonȱmistakeȱmadeȱinȱsituationsȱlikeȱthisȱoneȱisȱtoȱfreeȱtheȱrecordȱbeforeȱ
freeingȱtheȱmemoryȱpointedȱtoȱbyȱfieldsȱinȱtheȱrecord.ȱAfterȱtheȱrecordȱhasȱbeenȱfreed,ȱ
youȱmayȱnoȱlongerȱsafelyȱaccessȱanyȱofȱtheȱfieldsȱthatȱitȱcontains.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Function to discard an inventory record.
*/
#include <stdlib.h>
#include "inventor.h"
void
discard_inventory_record( Invrec *record )
{
/*
** Delete the variant parts of the record
*/
switch( record->type ){
case SUBASSY:
free( record->info.subassy->part );
free( record->info.subassy );
break;
case PART:
free( record->info.part );
break;
}
/*
** Delete the main part of the record
*/
free( record );
}
ȱ
Programȱ11.4cȱȱDestructionȱofȱaȱvariantȱrecordȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱinvdelet.cȱ
Download at http://www.pin5i.com/
11.7 Summaryȱ
317
Althoughȱ itȱ isȱ aȱ littleȱ lessȱ obvious,ȱ theȱ followingȱ codeȱ fragmentȱ isȱ aȱ slightlyȱ
moreȱefficientȱimplementationȱofȱProgramȱ11.4c.ȱ
ȱ
if( record->typ == SUBASSY )
free( record->info.subassy->part );
free( record->info.part );
free( record );
ȱ
Thisȱ codeȱ doesȱ notȱ distinguishȱ betweenȱ subassembliesȱ andȱ partsȱ whenȱ freeingȱ theȱ
variantȱ partȱ ofȱ theȱ record.ȱ Eitherȱ memberȱ ofȱ theȱ unionȱ canȱ beȱ used,ȱ asȱ freeȱ doesȱ notȱ
careȱwhichȱtypeȱofȱpointerȱitȱgets.ȱ
ȱ
ȱ
ȱ
11.7 Summary
ȱ
Whenȱanȱarrayȱisȱdeclared,ȱitsȱsizeȱmustȱbeȱknownȱatȱcompileȱtime.ȱDynamicȱallocationȱ
allowsȱaȱprogramȱtoȱcreateȱspaceȱforȱanȱarrayȱwhoseȱsizeȱisnȇtȱknownȱuntilȱruntime.ȱ
Theȱ mallocȱandȱ callocȱfunctionsȱbothȱallocateȱmemoryȱandȱreturnȱaȱpointerȱtoȱ
it.ȱ Theȱ argumentȱ toȱ mallocȱ isȱ theȱ numberȱ ofȱ bytesȱ ofȱ memoryȱ needed.ȱ Inȱ contrast,ȱ
callocȱrequiresȱtheȱnumberȱofȱelementsȱyouȱwantȱandȱtheȱsizeȱofȱeachȱelement.ȱcallocȱ
initializesȱ theȱ memoryȱ toȱ zeroȱ beforeȱ returning,ȱ whereasȱ mallocȱ leavesȱ theȱ memoryȱ
uninitialized.ȱTheȱ reallocȱfunctionȱisȱcalledȱtoȱchangeȱtheȱsizeȱofȱanȱexistingȱblockȱofȱ
dynamicallyȱallocatedȱmemory.ȱIncreasesȱinȱsizeȱmayȱbeȱaccomplishedȱbyȱcopyingȱtheȱ
dataȱ fromȱ theȱ existingȱ blockȱ toȱ aȱ new,ȱ largerȱ block.ȱ Whenȱ aȱ dynamicallyȱ allocatedȱ
blockȱisȱnoȱlongerȱneeded,ȱfreeȱisȱcalledȱtoȱreturnȱitȱtoȱtheȱpoolȱofȱavailableȱmemory.ȱ
Memoryȱmustȱnotȱbeȱaccessedȱafterȱitȱhasȱbeenȱfreed.ȱ
Theȱ pointerȱ returnedȱ byȱ malloc,ȱ calloc,ȱ andȱ reallocȱ willȱ beȱ NULLȱ ifȱ theȱ
requestedȱ allocationȱ couldȱ notȱ beȱ performed.ȱ Erroneouslyȱ accessingȱ memoryȱ outsideȱ
ofȱ anȱ allocatedȱ blockȱ mayȱ causeȱ theȱ sameȱ errorsȱ asȱ accessingȱ memoryȱ outsideȱ ofȱ anȱ
array,ȱbutȱcanȱalsoȱcorruptȱtheȱpoolȱofȱavailableȱmemoryȱandȱleadȱtoȱaȱprogramȱfailure.ȱ
Youȱmayȱnotȱpassȱaȱpointerȱtoȱfreeȱthatȱwasȱnotȱobtainedȱfromȱanȱearlierȱcallȱtoȱmalloc,ȱ
calloc,ȱorȱrealloc.ȱNorȱmayȱyouȱfreeȱaȱportionȱofȱaȱblock.ȱ
Aȱ memoryȱ leakȱ isȱ memoryȱ thatȱ hasȱ beenȱ dynamicallyȱ allocatedȱ butȱ hasȱ notȱ
beenȱ freedȱ andȱ isȱ noȱ longerȱ inȱ use.ȱ ȱ Memoryȱ leaksȱ increaseȱ theȱ sizeȱ ofȱ theȱ program,ȱ
andȱmayȱleadȱtoȱaȱcrashȱofȱtheȱprogramȱorȱtheȱsystem.ȱ
Download at http://www.pin5i.com/
318ȱ
Chapter 11 Dynamic Memory Allocationȱ
11.8 Summary of Cautions
ȱ
1. NotȱcheckingȱtheȱpointerȱreturnedȱfromȱmallocȱforȱNULLȱ(pageȱ307).ȱ
2. Accessingȱoutsideȱtheȱboundsȱofȱdynamicallyȱallocatedȱmemoryȱ(pageȱ307).ȱ
3. Passingȱaȱpointerȱtoȱfreeȱthatȱdidȱnotȱoriginallyȱcomeȱfromȱmallocȱ(pageȱ309).ȱ
4. Accessingȱdynamicȱmemoryȱafterȱitȱhasȱbeenȱfreedȱ(pageȱ309).ȱ
ȱ
ȱ
ȱ
11.9 Summary of Programming Tips
ȱ
1. DynamicȱallocationȱhelpsȱeliminateȱbuiltȬinȱlimitationsȱinȱtheȱprogramȱ(pageȱ303).ȱ
2. Usingȱsizeofȱtoȱcomputeȱtheȱsizeȱofȱdataȱtypesȱenhancesȱportabilityȱ(pageȱ306).ȱ
ȱ
ȱ
ȱ
11.10 Questions
ȱ
1. Whatȱ isȱ theȱ largestȱ staticȱ arrayȱ thatȱ youȱ canȱ declareȱ onȱ yourȱ system?ȱ Theȱ largestȱ
dynamicallyȱallocatedȱpieceȱofȱmemory?ȱ
2. Whatȱ isȱ theȱ totalȱ amountȱ ofȱ memoryȱ thatȱ youȱ canȱ dynamicallyȱ allocateȱ onȱ yourȱ
systemȱwhenȱyouȱaskȱforȱitȱ500ȱbytesȱatȱaȱtime?ȱWhenȱyouȱaskȱforȱitȱ5000ȱbytesȱatȱaȱ
time?ȱIsȱthereȱaȱdifference?ȱIfȱso,ȱhowȱdoȱyouȱexplainȱit?ȱ
3. Inȱaȱprogramȱthatȱreadsȱstringsȱfromȱaȱfile,ȱisȱthereȱanyȱvalueȱthatȱcanȱlogicallyȱbeȱ
usedȱforȱtheȱsizeȱofȱtheȱinputȱbuffer?ȱ
4. Someȱ Cȱ implementationsȱ provideȱ aȱ functionȱ calledȱ alloca,ȱ whichȱ differsȱ fromȱ
mallocȱ inȱ thatȱ itȱ allocatesȱ memoryȱ onȱ theȱ stack.ȱ Whatȱ areȱ theȱ advantagesȱ andȱ
disadvantagesȱofȱthisȱtypeȱofȱallocation?ȱ
5. Theȱ followingȱ program,ȱ whichȱ isȱ supposedȱ toȱ readȱ integersȱ inȱ theȱ rangeȱ oneȱ
throughȱ sizeȱfromȱtheȱstandardȱinputȱandȱreturnȱcountsȱofȱhowȱmanyȱtimesȱeachȱ
valueȱoccurs,ȱcontainsȱseveralȱerrors.ȱȱWhatȱareȱthey?ȱ
ȱ
#include <stdlib.h>
int *
frequency( int size )
{
int
*array;
int
i;
Download at http://www.pin5i.com/
11.11 Programming Exercisesȱ
319
/*
** Get enough memory to hold the counts.
*/
array = (int *)malloc( size * 2 );
/*
** Adjust the pointer back one integer so we
** can use subscripts in the range 1 – size.
*/
array -= 1;
/*
** Clear the values to zero
*/
for( i = 0; i <= size; i += 1 )
array[i] = 0;
/*
** Count how many times each value appears,
** then return the answers.
*/
while( scanf( "%d", &i ) == 1 )
array[ i ] += 1;
free( array );
return array;
}
6. Supposeȱ youȱ areȱ writingȱ aȱ programȱ andȱ wishȱ toȱ minimizeȱ theȱ amountȱ ofȱ stackȱ
spaceȱitȱuses.ȱȱWillȱallocatingȱarraysȱdynamicallyȱhelp?ȱHowȱaboutȱscalars?ȱ
7. WhatȱwouldȱbeȱtheȱeffectȱofȱdeletingȱtheȱtwoȱcallsȱtoȱfreeȱinȱProgramȱ11.4b?ȱ
ȱ
ȱ
ȱ
11.11 Programming Exercises
ȱ
1. Writeȱyourȱownȱversionȱofȱtheȱcallocȱfunction,ȱusingȱmallocȱtoȱobtainȱmemory.ȱ
2. Writeȱ aȱ functionȱ thatȱ readsȱ aȱ listȱ ofȱ integersȱ fromȱ theȱ standardȱ inputȱ andȱ returnsȱ
theȱvaluesȱinȱaȱdynamicallyȱallocatedȱarray.ȱTheȱendȱofȱtheȱinputȱlistȱisȱdeterminedȱ
byȱwatchingȱforȱ EOF.ȱTheȱfirstȱnumberȱinȱtheȱarrayȱshouldȱbeȱaȱcountȱofȱhowȱmanyȱ
valuesȱtheȱarrayȱcontains.ȱThisȱnumberȱisȱfollowedȱbyȱtheȱvalues.ȱ
Download at http://www.pin5i.com/
Chapter 11 Dynamic Memory Allocationȱ
320ȱ
3. Writeȱaȱfunctionȱthatȱreadsȱaȱstringȱfromȱtheȱstandardȱinputȱandȱreturnsȱaȱcopyȱofȱ
theȱ stringȱ inȱ dynamicallyȱ allocatedȱ memory.ȱ Theȱ functionȱ mayȱ notȱ imposeȱ anyȱ
limitȱonȱtheȱsizeȱofȱtheȱstringȱbeingȱread!ȱ
4. Writeȱ aȱ programȱ toȱ createȱ theȱ dataȱ structureȱ inȱ theȱ followingȱ diagram.ȱ Theȱ lastȱ
threeȱobjectsȱareȱstructuresȱwhichȱareȱdynamicallyȱallocated.ȱTheȱfirstȱobject,ȱwhichȱ
mayȱ beȱ static,ȱ isȱ aȱ pointerȱ toȱ aȱ structure.ȱ Youȱ doȱ notȱ needȱ toȱ makeȱ thisȱ programȱ
general—weȱwillȱdiscussȱthisȱdataȱstructureȱinȱtheȱnextȱchapter.ȱ
ȱ
headȱ
ȱ
5ȱ
ȱ
10ȱ
ȱ
15ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
0ȱ
ȱ
Download at http://www.pin5i.com/
12
Using Structures and Pointers
Youȱcanȱcreateȱpowerfulȱdataȱstructuresȱbyȱcombiningȱstructuresȱandȱpointers.ȱInȱthisȱ
chapterȱ weȱ takeȱ aȱ closerȱ lookȱ atȱ someȱ techniquesȱ forȱ usingȱ structuresȱ andȱ pointers.ȱȱ
Weȱspendȱaȱlotȱofȱtimeȱwithȱaȱdataȱstructureȱcalledȱaȱlinkedȱlist,ȱnotȱonlyȱbecauseȱitȱisȱ
veryȱ usefulȱ butȱ alsoȱ becauseȱ manyȱ ofȱ theȱ techniquesȱ usedȱ toȱ manipulateȱ linkedȱ listsȱ
areȱapplicableȱtoȱotherȱdataȱstructures.ȱ
ȱ
ȱ
ȱ
12.1 Linked Lists
ȱ
Forȱthoseȱofȱyouȱwhoȱareȱnotȱfamiliarȱwithȱlinkedȱlists,ȱhereȱisȱaȱbriefȱintroduction.ȱAȱ
linkedȱlistȱisȱaȱcollectionȱofȱindependentȱstructuresȱ(oftenȱcalledȱnodes)ȱthatȱcontainȱdata.ȱ
Theȱ individualȱ nodesȱ inȱ theȱ listȱ areȱ connectedȱ byȱ links,ȱ orȱ pointers.ȱ Aȱ programȱ
accessesȱ theȱ nodesȱ inȱ theȱ listȱ byȱ followingȱ theȱ pointers.ȱ Usuallyȱ theȱ nodesȱ areȱ
dynamicallyȱ allocated,ȱ thoughȱ occasionallyȱ youȱ willȱ findȱ linkedȱ listsȱ constructedȱ
amongȱelementsȱofȱanȱarrayȱofȱnodes.ȱEvenȱinȱthisȱcase,ȱthough,ȱaȱprogramȱtraversesȱ
theȱlistȱbyȱfollowingȱtheȱpointers.ȱ
ȱ
ȱ
ȱ
12.2 Singly Linked Lists
ȱ
Inȱ aȱ singlyȱ linkedȱ list,ȱ eachȱ nodeȱ containsȱ aȱ pointerȱ toȱ theȱ nextȱ nodeȱ inȱ theȱ list.ȱ Theȱ
pointerȱ fieldȱ ofȱ theȱ lastȱ nodeȱ inȱ theȱ listȱ containsȱ NULLȱ toȱ indicateȱ thatȱ thereȱ areȱ noȱ
moreȱnodesȱinȱtheȱlist.ȱAfterȱyouȱhaveȱfoundȱtheȱfirstȱnodeȱonȱaȱlist,ȱtheȱpointersȱwillȱ
leadȱyouȱtoȱtheȱremainingȱnodes.ȱToȱkeepȱtrackȱofȱwhereȱtheȱlistȱbegins,ȱaȱrootȱpointerȱ
isȱ used.ȱ Theȱ rootȱ pointerȱ pointsȱ toȱ theȱ firstȱ nodeȱ onȱ theȱ list.ȱ Noticeȱ thatȱ theȱ rootȱ isȱ aȱ
pointerȱandȱitȱdoesȱnotȱcontainȱanyȱdata.ȱȱ
Hereȱisȱaȱdiagramȱofȱaȱsinglyȱlinkedȱlist.ȱ
Download at http://www.pin5i.com/
Chapter 12 Using Structures and Pointersȱ
322ȱ
rootȱ
link
link
link
0
value
value
value
5
10
15
ȱ
Theȱnodesȱinȱthisȱexampleȱareȱstructuresȱcreatedȱwithȱtheȱfollowingȱdeclaration.ȱ
typedef
struct
struct
int
NODE
NODE
{
*link;
value;
} Node;
Theȱdataȱstoredȱinȱeachȱnodeȱisȱanȱinteger.ȱThisȱlistȱcontainsȱthreeȱnodes.ȱIfȱyouȱbeginȱ
atȱtheȱrootȱandȱfollowȱtheȱpointerȱtoȱtheȱfirstȱnode,ȱyouȱcanȱaccessȱtheȱdataȱstoredȱinȱ
thatȱnode.ȱFollowingȱtheȱpointerȱinȱtheȱfirstȱnodeȱtakesȱyouȱtoȱtheȱsecondȱnode,ȱwhereȱ
youȱ canȱ getȱ itsȱ data.ȱ Finally,ȱ theȱ nextȱ pointerȱ bringsȱ youȱ toȱ theȱ lastȱ node.ȱ Theȱ valueȱ
zeroȱisȱusedȱtoȱindicateȱaȱNULLȱpointer;ȱhereȱitȱmeansȱthatȱthereȱareȱnoȱmoreȱnodesȱinȱ
theȱlist.ȱ
Inȱtheȱdiagramȱtheȱnodesȱareȱshownȱasȱadjacentȱtoȱdisplayȱtheȱlogicalȱorderingȱ
thatȱ theȱ linksȱ provide.ȱ Inȱ fact,ȱ theȱ nodesȱ mightȱ actuallyȱ beȱ scatteredȱ allȱ throughȱ
memory.ȱItȱ doesnȇtȱ makeȱ anyȱdifferenceȱtoȱaȱprogramȱprocessingȱsuchȱaȱlistȱwhetherȱ
theȱnodesȱareȱphysicallyȱadjacentȱorȱnot,ȱbecauseȱtheȱprogramȱalwaysȱusesȱtheȱlinksȱtoȱ
getȱfromȱoneȱnodeȱtoȱtheȱnext.ȱ
Aȱ singlyȱ linkedȱ listȱ canȱ beȱ traversedȱ fromȱ startȱ toȱ endȱ byȱ followingȱ theȱ links,ȱ
butȱ theȱ listȱ cannotȱ beȱ traversedȱ backwards.ȱ Inȱ otherȱ words,ȱ onceȱ yourȱ programȱ hasȱ
reachedȱtheȱlastȱnodeȱinȱtheȱlist,ȱtheȱonlyȱwayȱtoȱgetȱbackȱtoȱanyȱearlierȱnodeȱisȱtoȱstartȱ
againȱfromȱtheȱrootȱpointer.ȱOfȱcourse,ȱtheȱprogramȱcouldȱsaveȱaȱpointerȱtoȱtheȱcurrentȱ
nodeȱbeforeȱadvancingȱtoȱtheȱnextȱone,ȱorȱitȱcouldȱevenȱsaveȱpointersȱtoȱtheȱprecedingȱ
fewȇȱnodes.ȱHowever,ȱtheseȱlinkedȱlistsȱareȱdynamicȱandȱcanȱgrowȱtoȱholdȱhundredsȱ
orȱ thousandsȱ ofȱ nodes,ȱ soȱ itȱ isȱ notȱ feasibleȱ toȱ saveȱ pointersȱ toȱ allȱ ofȱ theȱ precedingȱ
nodesȱinȱaȱlist.ȱ
Theȱ nodesȱ inȱ thisȱ particularȱ listȱ areȱ linkedȱ soȱ thatȱ theȱ dataȱ valuesȱ areȱ inȱ
ascendingȱorder.ȱThisȱorderingȱisȱimportantȱforȱsomeȱapplications,ȱsuchȱasȱorganizingȱ
appointmentsȱ byȱ timeȱ ofȱ day.ȱ Itȱ isȱ alsoȱ possibleȱ toȱ createȱ anȱ unorderedȱ listȱ forȱ
applicationsȱthatȱdoȱnotȱrequireȱanyȱordering.ȱ
ȱ
ȱ
ȱ
12.2.1
Inserting into a Singly Linked List
ȱ
Howȱwouldȱweȱinsertȱaȱnewȱnodeȱintoȱanȱorderedȱsinglyȱlinkedȱlist?ȱSupposeȱweȱhadȱ
aȱnewȱvalue,ȱsayȱ12,ȱtoȱinsertȱintoȱtheȱpreviousȱlist.ȱConceptuallyȱthisȱtaskȱisȱeasy:ȱstartȱ
Download at http://www.pin5i.com/
12.2 Singly Linked Lists
323
atȱ theȱ beginningȱ ofȱ theȱ list,ȱ followȱ theȱ pointersȱ untilȱ youȱ findȱ theȱ firstȱ nodeȱ whoseȱ
valueȱisȱlargerȱthanȱ12,ȱandȱthenȱinsertȱtheȱnewȱvalueȱintoȱtheȱlistȱjustȱbeforeȱthatȱnode.ȱ
Inȱpracticeȱtheȱalgorithmȱisȱmoreȱinteresting.ȱWeȱtraverseȱtheȱlistȱandȱstopȱwhenȱ
weȱreachȱtheȱnodeȱcontainingȱ15,ȱtheȱfirstȱvalueȱgreaterȱthanȱ12.ȱWeȱknowȱthatȱtheȱnewȱ
valueȱ shouldȱ beȱ addedȱ toȱ theȱ listȱ justȱ beforeȱ thisȱ node,ȱ butȱ theȱ pointerȱ fieldȱ ofȱ theȱ
previousȱ nodeȱ mustȱ beȱ modifiedȱ toȱ accomplishȱ theȱ insertion.ȱ However,ȱ weȇveȱ passedȱ
thisȱ node,ȱ andȱ weȱ cannotȱ goȱ back.ȱ Theȱ solutionȱ isȱ toȱ alwaysȱ saveȱ aȱ pointerȱ toȱ theȱ
previousȱnodeȱinȱtheȱlist.ȱ
Weȱwillȱnowȱdevelopȱaȱfunctionȱtoȱinsertȱaȱnodeȱintoȱanȱordered,ȱsinglyȱlinkedȱ
list.ȱProgramȱ12.1ȱisȱourȱfirstȱattempt.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Insert into an ordered, singly linked list. The arguments are
** a pointer to the first node in the list, and the value to
** insert.
*/
#include <stdlib.h>
#include <stdio.h>
#include "sll_node.h"
#define
#define
FALSE 0
TRUE 1
int
sll_insert( Node *current, int new_value )
{
Node *previous;
Node *new;
/*
** Look for the right place by walking down the list
** until we reach a node whose value is greater than
** or equal to the new value.
*/
while( current->value < new_value ){
previous = current;
current = current->link;
}
ȱ
Programȱ12.1ȱȱInsertȱintoȱanȱordered,ȱsinglyȱlinkedȱlist:ȱfirstȱtryȱ
ȱ
ȱ
continued…ȱ
Download at http://www.pin5i.com/
Chapter 12 Using Structures and Pointersȱ
324ȱ
ȱ
/*
** Allocate a new node and store the new value into it.
** In this event, we return FALSE.
*/
new = (Node *)malloc( sizeof( Node ) );
if( new == NULL )
return FALSE;
new->value = new_value;
/*
** Insert the new node into the list, and return TRUE.
*/
new->link = current;
previous->link = new;
return TRUE;
}
ȱ
Programȱ12.1ȱȱInsertȱintoȱanȱordered,ȱsinglyȱlinkedȱlist:ȱfirstȱtryȱ
ȱ
ȱ
ȱȱȱȱȱȱinsert1.cȱ
ȱ
Weȱcallȱtheȱfunctionȱinȱthisȱmanner:ȱ
ȱ
result = sll_insert( root, 12 );
ȱ
ȱ
Letȇsȱ traceȱthisȱcodeȱandȱseeȱwhetherȱitȱ correctlyȱinsertsȱtheȱ newȱvalueȱ 12ȱ intoȱ
theȱlist.ȱFirst,ȱtheȱfunctionȱisȱcalledȱwithȱtheȱvalueȱofȱtheȱrootȱvariable,ȱaȱpointerȱtoȱtheȱ
firstȱnodeȱinȱtheȱlist.ȱHereȱisȱtheȱstateȱofȱtheȱlistȱwhenȱtheȱfunctionȱbegins:ȱ
ȱ
previousȱ
current
?ȱ
link
link
link
0
value
value
value
5
10
15
ȱ
ȱ
Thisȱdiagramȱdoesȱnotȱshowȱtheȱ rootȱvariableȱbecauseȱtheȱfunctionȱcannotȱaccessȱit.ȱAȱ
copyȱ ofȱ itsȱ valueȱ cameȱ intoȱ theȱ functionȱ asȱ theȱ parameterȱ current,ȱ butȱ theȱ functionȱ
cannotȱaccessȱ root.ȱNowȱ current->valueȱisȱ5,ȱwhichȱisȱlessȱthanȱ12,ȱsoȱtheȱbodyȱofȱtheȱ
loopȱisȱexecutedȱonce.ȱWhenȱweȱgetȱbackȱtoȱtheȱtopȱofȱtheȱloop,ȱourȱpointersȱwillȱhaveȱ
advanced.ȱ
Download at http://www.pin5i.com/
12.2 Singly Linked Lists
previousȱ
link
325
current
link
link
0
valueȱ
value
valueȱ
5ȱ
10
15
ȱ
current->valueȱisȱnowȱ10,ȱsoȱtheȱbodyȱofȱtheȱloopȱexecutesȱagain,ȱwithȱthisȱresult:ȱ
previous
link
link
currentȱ
link
0
valueȱ
value
valueȱ
5ȱ
10
15
ȱ
Nowȱcurrent->valueȱisȱgreaterȱthanȱ12ȱsoȱtheȱloopȱbreaks.ȱ
Atȱthisȱpointȱtheȱ previousȱpointerȱisȱtheȱimportantȱone,ȱbecauseȱitȱpointsȱtoȱtheȱ
nodeȱ thatȱ mustȱ beȱ changedȱ toȱ insertȱ theȱ newȱ value.ȱ Butȱ first,ȱ aȱ newȱ nodeȱ mustȱ beȱ
obtainedȱtoȱholdȱtheȱvalue.ȱTheȱnextȱdiagramȱshowsȱtheȱstateȱofȱtheȱlistȱafterȱtheȱvalueȱ
isȱcopiedȱintoȱtheȱnewȱnode.ȱ
previous
link
link
currentȱ
new
link
link
0
?
valueȱ
value
valueȱ
value
5ȱ
10
15
12
ȱ
Download at http://www.pin5i.com/
326ȱ
Chapter 12 Using Structures and Pointersȱ
Linkingȱtheȱnewȱnodeȱintoȱtheȱlistȱrequiresȱtwoȱsteps.ȱFirst,ȱ
ȱ
new->link = current;
ȱ
makesȱ theȱ newȱ nodeȱ pointȱ toȱ whatȱ willȱ beȱ theȱ nextȱ nodeȱ inȱ theȱ list,ȱ theȱ firstȱ oneȱ weȱ
foundȱwithȱaȱvalueȱlargerȱthanȱ12.ȱAfterȱthisȱstep,ȱtheȱlistȱlooksȱlikeȱthis:ȱ
ȱ
previous
currentȱ
new
link
link
link
link
0
valueȱ
value
valueȱ
value
5ȱ
10
15
12
ȱ
ȱ
Theȱsecondȱstepȱisȱtoȱmakeȱtheȱ previousȱnode,ȱtheȱlastȱoneȱwhoseȱvalueȱwasȱsmallerȱ
thanȱ12,ȱpointȱtoȱtheȱnewȱnode.ȱTheȱfollowingȱstatementȱperformsȱthisȱtask.ȱ
ȱ
previous->link = new;
ȱ
ȱ
Theȱresultȱofȱthisȱstepȱis:ȱ
ȱ
previous
link
link
currentȱ
link
new
link
0
valueȱ
value
valueȱ
value
5ȱ
10
15
12
ȱ
ȱ
Theȱfunctionȱthenȱreturns,ȱleavingȱtheȱlistȱlookingȱlikeȱthis:ȱ
Download at http://www.pin5i.com/
12.2 Singly Linked Lists
327
rootȱ
link
link
link
link
0
valueȱ
value
valueȱ
value
5ȱ
10
15
12
ȱ
Startingȱatȱtheȱrootȱpointerȱandȱfollowingȱtheȱlinksȱverifiesȱthatȱtheȱnewȱnodeȱhasȱbeenȱ
correctlyȱinserted.ȱ
ȱ
ȱ
ȱ
Debugging the Insert Function
CAUTION!
Unfortunately,ȱ theȱ insertȱ functionȱ isȱ incorrect.ȱ Tryȱ insertingȱ theȱ valueȱ 20ȱ intoȱ theȱ listȱ
andȱ youȱ willȱ seeȱ oneȱ problem:ȱ theȱ whileȱ loopȱ runsȱ offȱ theȱ endȱ ofȱ theȱ listȱ andȱ thenȱ
appliesȱindirectionȱtoȱaȱNULLȱpointer.ȱToȱsolveȱthisȱproblem,ȱweȱmustȱtestȱ currentȱtoȱ
makeȱsureȱthatȱitȱisȱnotȱNULLȱbeforeȱevaluatingȱcurrent->value:ȱ
ȱ
while( current != NULL && current->value < value ){
ȱ
ȱ
Theȱ nextȱ problemȱ isȱ tougher.ȱ Traceȱ theȱ functionȱ toȱ insertȱ theȱ valueȱ 3ȱ intoȱ theȱ
list.ȱWhatȱhappens?ȱ
Inȱorderȱtoȱaddȱaȱnodeȱtoȱtheȱbeginningȱofȱtheȱlist,ȱtheȱfunctionȱmustȱchangeȱtheȱ
rootȱpointer.ȱTheȱfunction,ȱhowever,ȱcannotȱaccessȱtheȱvariableȱ root.ȱTheȱeasiestȱwayȱ
toȱfixȱthisȱproblemȱisȱtoȱjustȱmakeȱ rootȱaȱglobalȱvariableȱsoȱthatȱtheȱinsertionȱfunctionȱ
canȱ modifyȱ it.ȱ Unfortunately,ȱ thisȱ approachȱ isȱ alsoȱ theȱ worstȱ wayȱ toȱ fixȱ theȱ problem,ȱ
becauseȱthenȱtheȱfunctionȱworksȱonlyȱforȱthatȱoneȱlist.ȱ
Theȱ betterȱ solutionȱ isȱ toȱ passȱ aȱ pointerȱ toȱ rootȱ asȱ anȱ argument.ȱ Thenȱ theȱ
functionȱ canȱ useȱ indirectionȱ bothȱ toȱ obtainȱ theȱ valueȱ ofȱ rootȱ (theȱ pointerȱ toȱ theȱ firstȱ
nodeȱofȱtheȱlist),ȱandȱtoȱstoreȱaȱnewȱpointerȱintoȱit.ȱWhatȱisȱtheȱtypeȱofȱthisȱparameter?ȱ
rootȱisȱaȱpointerȱtoȱaȱNode,ȱsoȱtheȱparameterȱisȱofȱtypeȱNode **:ȱaȱpointerȱtoȱaȱpointerȱtoȱ
aȱ Node.ȱTheȱfunctionȱinȱProgramȱ12.2ȱcontainsȱtheseȱmodifications.ȱȱWeȱmustȱnowȱcallȱ
theȱfunctionȱlikeȱthis:ȱ
ȱ
result = sll_insert( &root, 12 );
Download at http://www.pin5i.com/
328ȱ
Chapter 12 Using Structures and Pointersȱ
ȱ
/*
** Insert into an ordered, singly linked list. The arguments are
** a pointer to the root pointer for the list, and the value to
** insert.
*/
#include <stdlib.h>
#include <stdio.h>
#include "sll_node.h"
#define
#define
int
sll_insert(
{
Node
Node
Node
FALSE 0
TRUE 1
Node **rootp, int new_value )
*current;
*previous;
*new;
/*
** Get the pointer to the first node.
*/
current = *rootp;
previous = NULL;
/*
** Look for the right place by walking down the list
** until we reach a node whose value is greater than
** or equal to the new value.
*/
while( current != NULL && current->value < new_value ){
previous = current;
current = current->link;
}
/*
** Allocate a new node and store the new value into it.
** In this event, we return FALSE.
*/
new = (Node *)malloc( sizeof( Node ) );
if( new == NULL )
return FALSE;
new->value = new_value;
/*
** Insert the new node into the list, and return TRUE.
*/
new->link = current;
if( previous == NULL )
*rootp = new;
else
previous->link = new;
return TRUE;
}
ȱ
Programȱ12.2ȱȱInsertȱintoȱanȱordered,ȱsinglyȱlinkedȱlist:ȱsecondȱtryȱ ȱ
ȱ
ȱȱȱȱȱinsert2.cȱ
Download at http://www.pin5i.com/
12.2 Singly Linked Lists
329
Thisȱsecondȱversionȱcontainsȱsomeȱadditionalȱstatements.ȱ
ȱ
ȱ
previous = NULL;
ȱ
isȱneededȱsoȱthatȱweȱcanȱcheckȱlaterȱwhetherȱtheȱnewȱvalueȱwillȱbeȱtheȱfirstȱnodeȱinȱtheȱ
list.ȱ
ȱ
ȱ
current = *rootp;
ȱ
usesȱindirectionȱonȱtheȱrootȱpointerȱargumentȱtoȱgetȱtheȱvalueȱofȱ root,ȱaȱpointerȱtoȱtheȱ
firstȱnodeȱinȱdieȱlist.ȱFinallyȱ
ȱ
if( previous == NULL )
*rootp = new;
else
previous->link = new;
ȱ
wasȱ addedȱ toȱ theȱ endȱ ofȱ theȱ function.ȱ Itȱ checksȱ whetherȱ theȱ newȱ valueȱ shouldȱ beȱ
addedȱtoȱtheȱbeginningȱofȱtheȱlist.ȱIfȱso,ȱweȱuseȱindirectionȱonȱtheȱrootȱpointerȱtoȱmakeȱ
rootȱpointȱtoȱtheȱnewȱnode.ȱ
ȱ
Thisȱ functionȱ works,ȱ andȱ inȱ manyȱ languagesȱ itȱ isȱ asȱ goodȱ asȱ youȱ canȱ get.ȱ
However,ȱweȱcanȱdoȱbetterȱbecauseȱCȱallowsȱyouȱtoȱgetȱtheȱaddressȱofȱ(aȱpointerȱto)ȱ
existingȱobjects.ȱ
ȱ
ȱ
ȱ
Optimizing the Insert Function
ȱ
Itȱappearsȱthatȱinsertingȱaȱnodeȱatȱtheȱbeginningȱofȱtheȱlistȱmustȱbeȱaȱspecialȱcase.ȱAfterȱ
all,ȱ theȱ pointerȱ thatȱ mustȱ beȱ adjustedȱ toȱ insertȱ theȱ firstȱ nodeȱ isȱ theȱ rootȱ pointer.ȱ Forȱ
everyȱ otherȱ node,ȱ theȱ pointerȱ toȱ beȱ adjustedȱ isȱ theȱ linkȱ fieldȱ ofȱ theȱ previousȱ node.ȱ
Theseȱseeminglyȱdifferentȱoperationsȱareȱreallyȱtheȱsame.ȱ
ȱ
Theȱ keyȱ toȱ eliminatingȱ theȱ specialȱ caseȱ isȱ toȱ realizeȱ thatȱ everyȱ nodeȱ inȱ theȱ listȱ
hasȱaȱpointerȱsomewhereȱpointingȱtoȱit.ȱForȱtheȱfirstȱnode,ȱitȱisȱtheȱrootȱpointer,ȱandȱforȱ
everyȱotherȱnodeȱitȱisȱtheȱlinkȱfieldȱofȱtheȱprecedingȱnode.ȱTheȱimportantȱpointȱisȱthatȱ
thereȱisȱaȱ pointerȱsomewhereȱpointingȱtoȱ eachȱnode.ȱWhetherȱ theȱpointerȱ isȱorȱisȱnotȱ
containedȱinȱaȱnodeȱisȱirrelevant.ȱ
Download at http://www.pin5i.com/
330ȱ
Chapter 12 Using Structures and Pointersȱ
Letȇsȱlookȱatȱtheȱlistȱonceȱmoreȱtoȱclarifyȱthisȱpoint.ȱHereȱisȱtheȱfirstȱnodeȱandȱitsȱ
correspondingȱpointer.ȱ
ȱ
rootȱ
link
link
link
0
value
value
value
5
10
15
ȱ
ȱ
Ifȱtheȱnewȱvalueȱisȱinsertedȱbeforeȱtheȱfirstȱnode,ȱthenȱthisȱpointerȱmustȱbeȱchanged.ȱ
Hereȱisȱtheȱsecondȱnodeȱandȱitsȱpointer.ȱ
ȱ
rootȱ
link
link
link
0
value
value
value
5
10
15
ȱ
ȱ
Ifȱtheȱnewȱvalueȱisȱinsertedȱbeforeȱtheȱsecondȱnode,ȱthenȱthisȱpointerȱmustȱbeȱchanged.ȱ
Noteȱthatȱweȇreȱconcernedȱonlyȱwithȱtheȱpointer;ȱtheȱnodeȱthatȱcontainsȱitȱisȱirrelevant.ȱ
Theȱsameȱpatternȱholdsȱforȱeveryȱnodeȱinȱtheȱlist.ȱ
Nowȱletȇsȱtakeȱaȱlookȱatȱtheȱmodifiedȱfunctionȱasȱitȱbeginsȱtoȱexecute.ȱHereȱareȱ
itsȱvariablesȱasȱtheyȱappearȱjustȱafterȱtheȱfirstȱassignmentȱstatement.ȱ
ȱ
ȱ
rootpȱ
current
rootȱ
link
link
link
0
value
value
value
5
10
15
ȱ
Download at http://www.pin5i.com/
12.2 Singly Linked Lists
331
Weȱ haveȱ aȱ pointerȱ toȱ theȱ currentȱ nodeȱ andȱ aȱ pointerȱ toȱ theȱ linkȱ thatȱ pointsȱ toȱ theȱ
currentȱ node.ȱ Weȱ donȇtȱ needȱ anythingȱ else!ȱ Ifȱ theȱ valueȱ inȱ theȱ currentȱ nodeȱ isȱ largerȱ
thanȱtheȱnewȱvalue,ȱtheȱrootpȱpointerȱtellsȱusȱwhichȱlinkȱfieldȱmustȱbeȱchangedȱtoȱlinkȱ
theȱnewȱnodeȱintoȱtheȱlist.ȱIfȱinsertionsȱelsewhereȱinȱtheȱlistȱcanȱbeȱexpressedȱtheȱsameȱ
way,ȱ theȱ specialȱ caseȱ disappears.ȱ Theȱ keyȱ isȱ theȱ pointer/nodeȱ relationshipȱ weȱ sawȱ
earlier.ȱ
Whenȱmovingȱtoȱtheȱnextȱnode,ȱsaveȱaȱpointerȱtoȱtheȱlinkȱthatȱpointsȱtoȱtheȱnextȱ
nodeȱ insteadȱofȱkeepingȱ aȱpointerȱtoȱ theȱ previousȱnode.ȱItȱisȱeasyȱtoȱ diagramȱ whatȱ isȱ
desired.ȱ
ȱ
rootp
currentȱ
rootȱ
link
link
link
0
value
value
value
5
10
15
ȱ
ȱ
Noticeȱhereȱthatȱ rootpȱisȱnotȱpointingȱtoȱtheȱnode;ȱitȱpointsȱtoȱtheȱlinkȱfieldȱwithinȱtheȱ
node.ȱThisȱfactȱisȱtheȱkeyȱtoȱsimplifyingȱtheȱinsertȱfunction,ȱbutȱitȱdependsȱuponȱourȱ
beingȱableȱtoȱobtainȱtheȱaddressȱofȱtheȱlinkȱfieldȱofȱtheȱcurrentȱnode.ȱThisȱoperationȱisȱ
easyȱ inȱ C.ȱ Theȱ expressionȱ &current->linkȱ doesȱ theȱ trick.ȱ Programȱ 12.3ȱ isȱ theȱ finalȱ
versionȱofȱourȱinsertionȱfunction.ȱȱTheȱ rootpȱparameterȱisȱnowȱcalledȱ linkp,ȱbecauseȱitȱ
pointsȱ toȱ manyȱ differentȱ linksȱ now,ȱ notȱ justȱ theȱ root.ȱ Weȱ donȇtȱ needȱ previousȱ anyȱ
more,ȱ becauseȱ ourȱ linkȱ pointerȱ takesȱ careȱ ofȱ locatingȱ theȱ linkȱ thatȱ needsȱ toȱ beȱ
modified.ȱTheȱspecialȱcaseȱatȱtheȱendȱofȱtheȱfunctionȱisȱgoneȱbecauseȱweȱalwaysȱhaveȱaȱ
pointerȱ toȱ theȱ linkȱ fieldȱ thatȱ needsȱ toȱ beȱ changed—weȱ modifyȱ theȱ rootȱ variableȱ inȱ
exactlyȱ theȱ sameȱ wayȱ asȱ theȱ linkȱ fieldȱ ofȱ aȱ node.ȱ Finally,ȱ registerȱ declarationsȱ haveȱ
beenȱaddedȱtoȱtheȱpointerȱvariablesȱtoȱimproveȱtheȱefficiencyȱofȱtheȱresultingȱcode.ȱ
Theȱ whileȱ loopȱ inȱ thisȱ finalȱ versionȱ isȱ trickierȱ becauseȱ ofȱ theȱ embeddedȱ
assignmentȱtoȱcurrent.ȱHereȱisȱanȱequivalent,ȱthoughȱslightlyȱlongerȱloop.ȱ
ȱ
/*
** Look for the right place.
*/
current = *linkp;
while( current != NULL && current->value < value ){
linkp = &current->link;
current = *linkp;
}
Download at http://www.pin5i.com/
332ȱ
Chapter 12 Using Structures and Pointersȱ
ȱ
ȱ
ȱ
/*
** Insert into an ordered, singly linked list. The arguments are
** a pointer to the first node in the list, and the value to
** insert.
*/
#include <stdlib.h>
#include <stdio.h>
#include "sll_node.h"
#define
#define
FALSE 0
TRUE 1
int
sll_insert( register Node **linkp, int new_value )
{
register Node
*current;
register Node
*new;
/*
** Look for the right place by
** until we reach a node whose
** or equal to the new value.
*/
while( ( current = *linkp ) !=
current->value < new_value
linkp = &current->link;
walking down the list
value is greater than
NULL &&
)
/*
** Allocate a new node and store the new value into it.
** In this event, we return FALSE.
*/
new = (Node *)malloc( sizeof( Node ) );
if( new == NULL )
return FALSE;
new->value = new_value;
/*
** Insert the new node into the list, and return TRUE.
*/
new->link = current;
*linkp = new;
return TRUE;
}
ȱ
Programȱ12.3ȱȱInsertȱintoȱanȱordered,ȱsinglyȱlinkedȱlist:ȱfinalȱversionȱȱ
ȱ
ȱȱȱȱȱȱinsert3.cȱ
Download at http://www.pin5i.com/
12.2 Singly Linked Lists
TIP
CAUTION!
333
Toȱ begin,ȱ currentȱ isȱ setȱ toȱ pointȱ toȱ theȱ firstȱ nodeȱ inȱ theȱ list.ȱ Theȱ whileȱ testȱ checksȱ
whetherȱweȇveȱreachedȱtheȱendȱofȱtheȱlist.ȱIfȱnot,ȱitȱthenȱchecksȱwhetherȱweȱareȱatȱtheȱ
properȱplaceȱforȱtheȱinsertion.ȱIfȱnot,ȱtheȱbodyȱofȱtheȱloopȱexecutes,ȱwhichȱsetsȱlinkpȱtoȱ
pointȱtoȱtheȱlinkȱfieldȱinȱtheȱcurrentȱnode,ȱandȱadvancesȱcurrentȱtoȱtheȱnextȱnode.ȱ
Theȱfactȱthatȱtheȱlastȱstatementȱinȱtheȱloopȱbodyȱisȱidenticalȱtoȱtheȱstatementȱjustȱ
priorȱtoȱtheȱloopȱleadsȱtoȱtheȱȈsimplificationȈȱofȱembeddingȱtheȱassignmentȱtoȱ currentȱ
withinȱ theȱ whileȱ expression.ȱ Theȱ resultȱ isȱ aȱ moreȱ complexȱ butȱ moreȱ compactȱ loop,ȱ
becauseȱweȱhaveȱeliminatedȱtheȱredundantȱassignmentȱtoȱcurrent.ȱ
ȱ
ȱ
Eliminatingȱ theȱ specialȱ caseȱ madeȱ thisȱ functionȱ simpler.ȱ Thereȱ areȱ twoȱ factorsȱ thatȱ
makeȱthisȱimprovementȱpossible.ȱTheȱfirstȱfactorȱisȱourȱabilityȱtoȱinterpretȱtheȱproblemȱ
correctly.ȱUnlessȱyouȱcanȱidentifyȱtheȱcommonalityȱinȱseeminglyȱdifferentȱoperations,ȱ
youȱwillȱbeȱstuckȱwritingȱextraȱcodeȱtoȱhandleȱspecialȱcases.ȱOftenȱthisȱknowledgeȱisȱ
acquiredȱ onlyȱ afterȱ youȱ haveȱ workedȱ withȱ theȱ dataȱ structureȱ forȱ aȱ whileȱ andȱ
understandȱitȱmoreȱclearly.ȱTheȱsecondȱfactorȱisȱthatȱtheȱCȱlanguageȱprovidesȱtheȱrightȱ
toolsȱforȱyouȱtoȱexploitȱtheȱcommonality.ȱ
TheȱimprovedȱfunctionȱdependsȱonȱCȇsȱabilityȱtoȱobtainȱtheȱaddressȱofȱexistingȱ
objects.ȱLikeȱmanyȱCȱfeatures,ȱthisȱabilityȱisȱbothȱpowerfulȱandȱdangerous.ȱInȱModulaȱ
andȱPascal,ȱforȱexample,ȱthereȱisnȇtȱanȱȈaddressȱofȈȱoperator,ȱsoȱtheȱonlyȱpointersȱthatȱ
existȱareȱthoseȱproducedȱbyȱdynamicȱmemoryȱallocation.ȱItȱisȱnotȱpossibleȱtoȱobtainȱaȱ
pointerȱtoȱanȱordinaryȱvariableȱorȱevenȱtoȱaȱfieldȱofȱaȱdynamicallyȱallocatedȱstructure.ȱ
Pointerȱarithmeticȱisȱnotȱallowed,ȱandȱthereȱisnȇtȱanyȱmeansȱforȱcastingȱaȱpointerȱfromȱ
oneȱ typeȱ toȱ another.ȱ Theseȱ restrictionsȱ areȱ advantageousȱ inȱ thatȱ theyȱ preventȱ theȱ
programmerȱ fromȱ makingȱ mistakesȱ suchȱ asȱ subscriptingȱ offȱ theȱ endȱ ofȱ anȱ arrayȱ andȱ
generatingȱpointersȱofȱoneȱtypeȱthatȱinȱfactȱpointȱtoȱobjectsȱofȱsomeȱotherȱtype.ȱ
ȱ
ȱ
Thereȱ areȱ farȱ fewerȱ restrictionsȱ onȱ pointersȱ inȱ C,ȱ whichȱ isȱ whyȱ weȱ wereȱ ableȱ toȱ
improveȱ theȱ insertionȱ function.ȱ Onȱ theȱ otherȱ hand,ȱ Cȱ programmersȱ mustȱ beȱ moreȱ
carefulȱ whenȱ usingȱ pointersȱ toȱ avoidȱ mistakes.ȱ Theȱ Pascalȱ philosophyȱ toȱ pointersȱ isȱ
sortȱ ofȱ likeȱ saying,ȱ ȈYouȱ mightȱ hurtȱ yourselfȱ withȱ aȱ hammer,ȱ soȱ weȱ wonȇtȱ giveȱ youȱ
one.Ȉȱ Theȱ Cȱ philosophyȱ is,ȱ ȈHereȱ isȱ aȱ hammer.ȱ Inȱ fact,ȱ hereȱ areȱ severalȱ kindsȱ ofȱ
hammers.ȱ Goodȱ luck.Ȉȱ Withȱ thisȱ power,ȱ Cȱ programmersȱ canȱ getȱ intoȱ moreȱ troubleȱ
thanȱ Pascalȱ programmers,ȱ butȱ goodȱ Cȱ programmersȱ canȱ produceȱ smaller,ȱ moreȱ
efficient,ȱandȱmoreȱmaintainableȱcodeȱthanȱtheirȱPascalȱorȱModulaȱcounterparts.ȱThisȱ
isȱ oneȱ ofȱ theȱ reasonsȱ whyȱ Cȱ isȱ soȱ popularȱ inȱ industry,ȱ andȱ whyȱ experiencedȱ Cȱ
programmersȱareȱinȱsuchȱdemand.ȱ
Download at http://www.pin5i.com/
Chapter 12 Using Structures and Pointersȱ
334ȱ
12.2.2
Other List Operations
ȱ
Toȱmakeȱsinglyȱlinkedȱlistsȱreallyȱuseful,ȱweȱneedȱmoreȱoperationsȱsuchȱasȱsearchingȱ
andȱ deletion.ȱ However,ȱ theȱ algorithmsȱ forȱ theseȱ operationsȱ areȱ straightforwardȱ andȱ
easilyȱ implementedȱ usingȱ theȱ techniquesȱ illustratedȱ inȱ theȱ insertionȱ function.ȱ Theseȱ
functionsȱareȱleftȱasȱexercises.ȱ
ȱ
ȱ
ȱ
12.3 Doubly Linked Lists
ȱ
Anȱalternativeȱtoȱsinglyȱlinkedȱlistsȱisȱtheȱdoublyȱlinkedȱlist.ȱInȱaȱdoublyȱlinkedȱlist,ȱeachȱ
nodeȱhasȱtwoȱpointers—oneȱtoȱtheȱnextȱnodeȱinȱtheȱlistȱandȱoneȱtoȱtheȱpreviousȱnode.ȱ
Theȱbackȱpointerȱletsȱusȱtraverseȱdoublyȱlinkedȱlistsȱinȱeitherȱdirection.ȱWeȱcanȱevenȱgoȱ
backȱandȱforth.ȱTheȱfollowingȱdiagramȱillustratesȱaȱdoublyȱlinkedȱlist.ȱ
ȱ
rootȱ
fwd
fwd
fwd
0ȱ
bwdȱ
bwdȱ
valueȱ
bwdȱ
0
15ȱ
value
valueȱ
10
15ȱ
ȱ
ȱ
Hereȱisȱtheȱdeclarationȱforȱtheȱnodeȱtype.ȱ
ȱ
typedef
struct
struct
struct
int
NODE
NODE
NODE
{
*fwd;
*bwd;
value;
} Node;
ȱ
Theȱ rootȱ isȱ nowȱ twoȱ pointers:ȱ oneȱ pointsȱ toȱ theȱ firstȱ nodeȱ inȱ theȱ list,ȱ andȱ theȱ otherȱ
pointsȱtoȱtheȱlastȱnode.ȱTheseȱtwoȱpointersȱletȱusȱbeginȱaȱtraversalȱatȱeitherȱendȱofȱtheȱ
listȱ
Weȱ mightȱ declareȱ theȱ twoȱ rootȱ pointersȱ asȱ separateȱ variables,ȱ butȱ thenȱ weȱ
wouldȱ haveȱ toȱ passȱ pointersȱ toȱ bothȱ ofȱ themȱ toȱ theȱ insertionȱ function.ȱ Itȱ isȱ moreȱ
convenientȱ toȱ declareȱ anȱ entireȱ nodeȱ forȱ theȱ rootȱ pointers,ȱ oneȱ whoseȱ valueȱ fieldȱ isȱ
neverȱused.ȱInȱourȱexample,ȱthisȱtechniqueȱonlyȱwastesȱtheȱmemoryȱforȱoneȱinteger.ȱȱ
Download at http://www.pin5i.com/
12.3 Doubly Linked Lists
335
Separateȱpointersȱmightȱbeȱbetterȱforȱlistsȱwhoseȱvalueȱfieldȱisȱlarge.ȱAlternatively,ȱweȱ
mightȱuseȱtheȱvalueȱfieldȱofȱtheȱrootȱnodeȱtoȱstoreȱotherȱinformationȱaboutȱtheȱlist,ȱforȱ
example,ȱtheȱnumberȱofȱnodesȱitȱcurrentlyȱcontains.ȱ
Theȱ fwdȱ fieldȱ ofȱ theȱ footȱ nodeȱ pointsȱ toȱ theȱ firstȱ nodeȱ inȱ theȱ Use,ȱ andȱ theȱ bwdȱ
fieldȱ ofȱ theȱ rootȱ nodeȱ pointsȱ toȱ theȱ lastȱ nodeȱ inȱ theȱ list.ȱ Bothȱ ofȱ theseȱ fieldsȱ willȱ beȱ
NULLȱifȱtheȱlistȱisȱempty.ȱTheȱ bwdȱfieldȱofȱtheȱfirstȱnodeȱinȱtheȱlistȱandȱtheȱ fwdȱfieldȱofȱ
theȱlastȱnodeȱwillȱbeȱNULL.ȱInȱanȱorderedȱlist,ȱnodesȱareȱstoredȱinȱincreasingȱorderȱofȱ
theȱvalueȱfield.ȱ
ȱ
ȱ
ȱ
12.3.1
Inserting into a Doubly Linked List
ȱ
Thisȱ time,ȱ weȱ developȱ aȱ functionȱ thatȱ insertsȱ aȱ valueȱ intoȱ anȱ ordered,ȱ doublyȱ linkedȱ
list.ȱdll_insertȱtakesȱtwoȱarguments:ȱaȱpointerȱtoȱtheȱrootȱnodeȱandȱanȱintegerȱvalue.ȱ
Theȱsinglyȱ linkedȱinsertionȱ functionȱ weȱwroteȱ earlierȱ addsȱ duplicateȱvaluesȱtoȱ
theȱ list.ȱ Itȱ mayȱ beȱ moreȱ appropriateȱ forȱ someȱ applicationsȱ toȱ notȱ addȱ duplicates.ȱȱ
dll_insertȱwillȱaddȱaȱnewȱvalueȱonlyȱifȱisȱnotȱalreadyȱinȱtheȱlist.ȱ
Letȇsȱ takeȱ aȱ moreȱ disciplinedȱ approachȱ toȱ developingȱ thisȱ function.ȱ Thereȱ areȱ
fourȱcasesȱthatȱcanȱoccurȱwhenȱinsertingȱaȱnodeȱintoȱaȱlinkedȱlist:ȱ
1. Theȱvalueȱmightȱhaveȱtoȱbeȱinsertedȱinȱtheȱmiddleȱofȱtheȱlist.ȱ
2. Theȱvalueȱmightȱhaveȱtoȱbeȱinsertedȱatȱtheȱbeginningȱofȱtheȱlist.ȱ
3. Theȱvalueȱmightȱhaveȱtoȱbeȱinsertedȱatȱtheȱendȱofȱtheȱlistȱ
4. Theȱ valueȱ mightȱ haveȱ toȱ beȱ insertedȱ atȱ bothȱ theȱ beginningȱ andȱ theȱ endȱ (thatȱ is,ȱ
insertedȱintoȱanȱemptyȱlist).ȱ
ȱ
Inȱeachȱofȱtheseȱcases,ȱfourȱpointersȱmustȱbeȱmodified.ȱ
ȱ
x Inȱcasesȱ(1)ȱandȱ(2),ȱtheȱ fwdȱfieldȱofȱtheȱnewȱnodeȱmustȱbeȱsetȱtoȱpointȱtoȱtheȱnextȱ
nodeȱinȱtheȱlist,ȱandȱtheȱ bwdȱfieldȱofȱtheȱnextȱnodeȱinȱtheȱlistȱmustȱbeȱsetȱtoȱpointȱtoȱ
theȱ newȱ node.ȱ Inȱ casesȱ (3)ȱ andȱ (4),ȱ theȱ fwdȱ fieldȱ ofȱ theȱ newȱ nodeȱ mustȱ beȱ setȱ toȱ
NULL,ȱandȱtheȱbwdȱfieldȱofȱtheȱrootȱnodeȱmustȱbeȱsetȱtoȱpointȱtoȱtheȱnewȱnode.ȱ
x
Inȱ casesȱ (1)ȱ andȱ (3),ȱ theȱ bwdȱ fieldȱ ofȱ theȱ newȱ nodeȱ mustȱ beȱ setȱ toȱ pointȱ toȱ theȱ
previousȱ nodeȱ inȱ theȱ list,ȱ andȱ theȱ fwdȱ fieldȱ ofȱ theȱ previousȱ nodeȱ mustȱ beȱ setȱ toȱ
pointȱtoȱtheȱnewȱnode.ȱInȱcasesȱ(2)ȱandȱ(4),ȱtheȱ bwdȱfieldȱofȱtheȱnewȱnodeȱmustȱbeȱ
setȱ toȱ NULL,ȱ andȱ theȱ fwdȱ fieldȱ ofȱ theȱ rootȱ nodeȱ mustȱ beȱ setȱ toȱ pointȱ toȱ theȱ newȱ
node.ȱ
ȱ
Ifȱthisȱdescriptionȱseemsȱunclear,ȱtheȱstraightforwardȱimplementationȱinȱProgramȱ12.4ȱ
shouldȱhelp.ȱ
Download at http://www.pin5i.com/
Chapter 12 Using Structures and Pointersȱ
336ȱ
ȱ
/*
** Insert a value into a doubly linked list. rootp is a pointer to
** the root node, and value is the new value to be inserted.
** Returns: 0 if the value is already in the list, -1 if there was
** no memory to create a new node, 1 if the value was added
** successfully.
*/
#include <stdlib.h>
#include <stdio.h>
#include "dll_node.h"
int
dll_insert(
{
Node
Node
Node
Node *rootp, int value )
*this;
*next;
*newnode;
/*
** See if value is already in the list; return if it is.
** Otherwise, allocate a new node for the value ("newnode"
** will point to it). "this" will point to the node that the
** new value should follow, and "next" will point to the one
** after it.
*/
for( this = rootp; (next = this->fwd) != NULL; this = next ){
if( next->value == value )
return 0;
if( next->value > value )
break;
}
newnode = (Node *)malloc( sizeof( Node ) );
if( newnode == NULL )
return -1;
newnode->value = value;
/*
** Add the new node to the list.
*/
if( next != NULL ){
/*
** Case 1 or 2: not at end of the list
*/
if( this != rootp ){
/* Case 1: not at front */
newnode->fwd = next;
ȱ
Programȱ12.4ȱȱStraightforwardȱdoublyȱlinkedȱlistȱinsertȱfunctionȱ
ȱ
ȱ
continued…ȱ
Download at http://www.pin5i.com/
12.3 Doubly Linked Lists
337
ȱ
this->fwd = newnode;
newnode->bwd = this;
next->bwd = newnode;
}
else {
/* Case 2: at front */
newnode->fwd = next;
rootp->fwd = newnode;
newnode->bwd = NULL;
next->bwd = newnode;
}
}
else {
/*
** Case 3 or 4: at end of the list
*/
if( this != rootp ){
/* Case 3: not at front */
newnode->fwd = NULL;
this->fwd = newnode;
newnode->bwd = this;
rootp->bwd = newnode;
}
else {
/* Case 4: at front */
newnode->fwd = NULL;
rootp->fwd = newnode;
newnode->bwd = NULL;
rootp->bwd = newnode;
}
}
return 1;
}
ȱ
Programȱ12.4ȱȱStraightforwardȱdoublyȱlinkedȱlistȱinsertȱfunctionȱ ȱ
ȱ
ȱȱȱȱdll_ins1.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Theȱ functionȱ beginsȱ byȱ makingȱ thisȱ pointȱ toȱ theȱ rootȱ node.ȱ Theȱ nextȱ pointerȱ
alwaysȱ pointsȱ toȱ theȱ nodeȱ afterȱ this;ȱ theȱ ideaȱ isȱ toȱ advanceȱ theseȱ pointersȱ togetherȱ
untilȱtheȱnewȱnodeȱshouldȱbeȱinsertedȱbetweenȱthem.ȱTheȱforȱloopȱchecksȱtheȱvalueȱinȱ
theȱnextȱnodeȱtoȱdetermineȱwhenȱthisȱpositionȱhasȱbeenȱreached.ȱ
Ifȱtheȱnewȱvalueȱisȱfoundȱinȱtheȱlist,ȱtheȱfunctionȱsimplyȱreturns.ȱOtherwise,ȱtheȱ
loopȱendsȱwhenȱtheȱendȱofȱtheȱlistȱisȱreachedȱorȱwhenȱtheȱproperȱpositionȱforȱinsertionȱ
isȱreached.ȱInȱeitherȱcase,ȱtheȱnewȱnodeȱshouldȱbeȱinsertedȱafterȱtheȱ thisȱnode.ȱNoteȱ
thatȱspaceȱforȱtheȱnewȱnodeȱisȱnotȱallocatedȱuntilȱafterȱweȱdetermineȱwhetherȱtheȱvalueȱ
shouldȱactuallyȱbeȱaddedȱtoȱtheȱlist.ȱ
Download at http://www.pin5i.com/
338ȱ
Chapter 12 Using Structures and Pointersȱ
Allocatingȱ theȱ newȱ nodeȱ firstȱ wouldȱ causeȱ aȱ potentialȱ memoryȱ leakȱ forȱ duplicateȱ
values.ȱ
Theȱfourȱcasesȱhaveȱbeenȱimplementedȱseparately.ȱLetȇsȱtraceȱcaseȱ1ȱbyȱinsertingȱ
theȱvalueȱ12ȱintoȱtheȱlist.ȱTheȱfollowingȱdiagramȱshowsȱtheȱstateȱofȱourȱvariablesȱjustȱ
afterȱtheȱforȱloopȱbreaks.ȱ
rootpȱ
this
nextȱ
rootȱ
fwd
fwd
fwd
0ȱ
bwdȱ
valueȱ
bwdȱ
bwdȱ
0
15ȱ
value
valueȱ
10
15ȱ
ȱ
Aȱnewȱnodeȱisȱthenȱallocated.ȱAfterȱexecutingȱtheȱstatementsȱ
ȱ
newnode->fwd = next;
this->fwd = newnode;
ȱ
theȱlistȱlooksȱlikeȱthis:ȱ
rootpȱ
rootȱ
fwd
this
fwd
nextȱ
fwd
newnode
fwd
0ȱ
bwdȱ
valueȱ
bwdȱ
bwdȱ
bwdȱ
0
15ȱ
?
15
value
valueȱ
value
10
15ȱ
12
ȱ
Download at http://www.pin5i.com/
12.3 Doubly Linked Lists
339
Then,ȱtheȱstatementsȱ
ȱ
newnode->bwd = this;
next->bwd = newnode;
ȱ
finishȱlinkingȱtheȱnewȱvalueȱintoȱtheȱlist:ȱ
ȱ
rootpȱ
this
rootȱ
fwd
fwd
nextȱ
fwd
newnode
fwd
0ȱ
bwdȱ
valueȱ
bwdȱ
bwdȱ
bwdȱ
0
15ȱ
15
value
valueȱ
value
10
15ȱ
12
ȱ
Studyȱ theȱ codeȱ toȱ determineȱ howȱ theȱ remainingȱ casesȱ work,ȱ andȱ convinceȱ yourselfȱ
thatȱeachȱcaseȱisȱcompletedȱproperly.ȱ
ȱ
ȱ
ȱ
Simplifying the Insert Function
TIP
ȱ
Theȱ observantȱ programmerȱ willȱ noticeȱ thatȱ thereȱ isȱ aȱ lotȱ ofȱ similarityȱ amongȱ theȱ
groupsȱ ofȱ statementsȱ inȱ theȱ nestedȱ ifȱ statementsȱ inȱ theȱ function,ȱ andȱ theȱ goodȱ
programmerȱwillȱbeȱbotheredȱbyȱallȱofȱtheȱduplication.ȱSoȱweȱwillȱnowȱeliminateȱtheȱ
duplicationȱ usingȱ twoȱ techniques.ȱ Theȱ firstȱ isȱ statementȱ factoring,ȱ andȱ isȱ illustratedȱ inȱ
theȱfollowingȱexample.ȱ
ȱ
if( x == 3 ){
i = 1;
something;
j = 2;
}
else {
i = 1;
something different;
j = 2;
}
Download at http://www.pin5i.com/
340ȱ
Chapter 12 Using Structures and Pointersȱ
Noticeȱthatȱtheȱstatementsȱi = 1;ȱandȱj = 2;ȱwillȱbeȱexecutedȱwhetherȱtheȱexpressionȱȱ
x == 3ȱisȱtrueȱorȱfalse.ȱDoingȱi = 1;ȱbeforeȱtheȱifȱwillȱnotȱaffectȱtheȱresultȱofȱtheȱtestȱȱȱȱ
x == 3,ȱsoȱbothȱpairsȱofȱassignmentsȱcanȱbeȱfactoredȱout,ȱleavingȱtheȱsimpler,ȱbutȱ
completelyȱequivalent,ȱstatements:ȱ
ȱ
i = 1;
if( x == 3 )
something;
else
something different;
j = 2;
CAUTION!
ȱ
ȱ
Beȱcarefulȱnotȱtoȱfactorȱaȱstatementȱaboveȱtheȱifȱthatȱchangesȱtheȱresultȱofȱtheȱtest.ȱForȱ
example,ȱinȱ
ȱ
if( x == 3 ){
x = 0;
something;
}
else {
x = 0;
something different;
}
ȱ
theȱ statementȱ x = 0;ȱ cannotȱ beȱ factoredȱ outȱ becauseȱ itȱ wouldȱ affectȱ theȱ resultȱ ofȱ theȱ
comparison.ȱ
Factoringȱ theȱ innermostȱ ofȱ theȱ nestedȱ ifȇsȱ inȱ Programȱ 12.4ȱ yieldsȱ theȱ codeȱ
fragmentȱ inȱ Programȱ 12.5.ȱ Compareȱ thisȱ codeȱ toȱ theȱ previousȱ functionȱ andȱ convinceȱ
yourselfȱthatȱitȱisȱequivalent.ȱ
Theȱsecondȱsimplificationȱtechniqueȱisȱeasilyȱillustratedȱwithȱanȱexample:ȱ
ȱ
if( pointer != NULL )
field = pointer;
else
field = NULL;
ȱ
Theȱ intentȱ hereȱ isȱ toȱ setȱ aȱ variableȱ equalȱ toȱ pointer,ȱ orȱ toȱ NULLȱ ifȱ pointerȱ doesnȇtȱ
pointȱtoȱanything.ȱButȱlookȱatȱthisȱstatement:ȱ
ȱ
field = pointer;
ȱ
Ifȱ pointerȱ isȱ notȱ NULL,ȱ fieldȱ getsȱ aȱ copyȱ ofȱ itsȱ value,ȱ asȱ before.ȱ ȱ Butȱ ifȱ pointerȱ is
Download at http://www.pin5i.com/
12.3 Doubly Linked Lists
341
ȱ
/*
** Add the new node to the list.
*/
if( next != NULL ){
/*
** Case 1 or 2: not at end of
*/
newnode->fwd = next;
if( this != rootp ){
/*
this->fwd = newnode;
newnode->bwd = this;
}
else {
/*
rootp->fwd = newnode;
newnode->bwd = NULL;
}
next->bwd = newnode;
}
else {
/*
** Case 3 or 4: at end of the
*/
newnode->fwd = NULL;
if( this != rootp ){
/*
this->fwd = newnode;
newnode->bwd = this;
}
else {
/*
rootp->fwd = newnode;
newnode->bwd = NULL;
}
rootp->bwd = newnode;
}
the list
Case 1: not at front */
Case 2: at front */
list
Case 3: not at front */
Case 4: at front */
ȱ
Programȱ12.5ȱȱFactoredȱdoublyȱlinkedȱlistȱinsertionȱlogicȱ
ȱ
ȱ
ȱ
ȱȱȱȱdll_ins2.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
NULL,ȱ fieldȱ getsȱ aȱ copyȱ ofȱ theȱ NULLȱ fromȱ pointer,ȱ whichȱ hasȱ theȱ sameȱ effectȱ asȱ
assigningȱ theȱ constantȱ NULL.ȱ Thisȱ statementȱ performsȱ theȱ sameȱ workȱ asȱ theȱ previousȱ
oneȱandȱisȱobviouslyȱsimpler.ȱ
Theȱ keyȱ toȱ applyingȱ thisȱ techniqueȱ toȱ theȱ codeȱ inȱ Programȱ 12.5ȱ isȱ toȱ identifyȱ theȱ
statementsȱ thatȱ performȱ theȱ sameȱ workȱ evenȱ thoughȱ theyȱ lookȱ differentȱ andȱ rewriteȱ
themȱsoȱthatȱtheyȱareȱidentical.ȱWeȱcanȱrewriteȱtheȱfirstȱstatementȱinȱcasesȱ3ȱandȱ4ȱasȱ
ȱ
newnode->fwd = next;
Download at http://www.pin5i.com/
342ȱ
Chapter 12 Using Structures and Pointersȱ
becauseȱ theȱ ifȱ statementȱ hasȱ justȱ determinedȱ thatȱ next == null.ȱ Thisȱ changeȱ makesȱ
theȱfirstȱstatementȱonȱbothȱsidesȱofȱtheȱ ifȱstatementȱidentical,ȱsoȱweȱcanȱfactorȱitȱout.ȱ
Writeȱdownȱthisȱchange,ȱandȱstudyȱwhatȱremains.ȱ
Didȱyouȱseeȱit?ȱBothȱnestedȱ ifȇsȱareȱnowȱidentical,ȱsoȱtheyȱcanȱalsoȱbeȱfactored.ȱ
TheȱresultȱofȱtheseȱchangesȱisȱshownȱinȱProgramȱ12.6.ȱ
Weȱcanȱimproveȱthisȱcodeȱstillȱfurther.ȱTheȱfirstȱstatementȱinȱtheȱ elseȱclauseȱofȱ
theȱfirstȱifȱcanȱbeȱrewrittenȱasȱ
ȱ
this->fwd = newnode;
ȱ
becauseȱ theȱ ifȱ statementȱ hasȱ alreadyȱ decidedȱ thatȱ this == rootp.ȱ Theȱ rewrittenȱ
statementȱandȱitsȱmateȱcanȱnowȱbeȱfactoredȱout,ȱtoo.ȱ
Programȱ 12.7ȱ isȱ theȱ entireȱ functionȱ afterȱ allȱ ofȱ theȱ changesȱ haveȱ beenȱ
implemented.ȱ Itȱ doesȱ theȱ sameȱ workȱ asȱ theȱ originalȱ butȱ isȱ muchȱ smaller.ȱ Theȱ localȱ
pointersȱ haveȱ beenȱ declaredȱ registerȱ variablesȱ toȱ improveȱ theȱ sizeȱ andȱ speedȱ ofȱ theȱ
codeȱevenȱfurther.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Add the new node to the list.
*/
newnode->fwd = next;
if( this != rootp ){
this->fwd = newnode;
newnode->bwd = this;
}
else {
rootp->fwd = newnode;
newnode->bwd = NULL;
}
if( next != NULL )
next->bwd = newnode;
else
rootp->bwd = newnode;
ȱ
Programȱ12.6ȱȱFurtherȱfactoredȱdoublyȱlinkedȱlistȱinsertionȱlogicȱ
ȱ
ȱ
ȱȱȱȱdll_ins3.cȱ
Download at http://www.pin5i.com/
12.3 Doubly Linked Lists
343
ȱ
/*
** Insert a value into a doubly linked list. rootp is a pointer to
** the root node, and value is the new value to be inserted.
** Returns: 0 if the value is already in the list, -1 if there was
** no memory to create a new node, 1 if the value was added
** successfully.
*/
#include <stdlib.h>
#include <stdio.h>
#include "dll_node.h"
int
dll_insert( register Node *rootp, int value )
{
register Node
*this;
register Node
*next;
register Node
*newnode;
/*
** See if value is already in the list; return if it is.
** Otherwise, allocate a new node for the value ("newnode"
** will point to it). "this" will point to the node that the
** new value should follow, and "next" will point to the one
** after it.
*/
for( this = rootp; (next = this->fwd) != NULL; this = next ){
if( next->value == value )
return 0;
if( next->value > value )
break;
}
newnode = (Node *)malloc( sizeof( Node ) );
if( newnode == NULL )
return -1;
newnode->value = value;
/*
** Add the new node to the list.
*/
newnode->fwd = next;
this->fwd = newnode;
if( this != rootp )
newnode->bwd = this;
else
newnode->bwd = NULL;
if( next != NULL )
next->bwd = newnode;
else
rootp->bwd = newnode;
return 1;
}
ȱ
Programȱ12.7ȱȱFullyȱsimplifiedȱdoublyȱlinkedȱlistȱinsertionȱfunctionȱȱȱ
ȱ
ȱȱȱȱdll_ins4.cȱ
Download at http://www.pin5i.com/
344ȱ
Chapter 12 Using Structures and Pointersȱ
Thisȱ functionȱ cannotȱ beȱ madeȱ significantlyȱ better,ȱ thoughȱ weȱ canȱ makeȱ theȱ sourceȱ
codeȱsmaller.ȱTheȱpurposeȱofȱtheȱfirstȱ ifȱstatementȱisȱtoȱdetermineȱtheȱrightȱsideȱofȱanȱ
assignment.ȱWeȱcanȱreplaceȱtheȱ ifȱwithȱaȱconditionalȱexpression.ȱWeȱcanȱalsoȱreplaceȱ
theȱsecond ifȱwithȱaȱconditional,ȱthoughȱthisȱchangeȱisȱlessȱobvious.ȱ
ȱ
ȱ
TheȱcodeȱinȱProgramȱ12.8ȱisȱcertainlyȱsmaller,ȱbutȱisȱitȱreallyȱbetter?ȱAlthoughȱthereȱareȱ
fewerȱstatements,ȱtheȱnumberȱofȱcomparisonsȱandȱassignmentsȱthatȱmustȱbeȱmadeȱisȱ
theȱsameȱasȱbefore,ȱsoȱthisȱcodeȱisnȇtȱanyȱfasterȱthanȱwhatȱweȱhadȱbefore.ȱThereȱareȱtwoȱ
minorȱ differences:ȱ newnode->bwdȱ andȱ ->bwd = newnodeȱ areȱ bothȱ writtenȱ onceȱ ratherȱ
thanȱtwice.ȱWillȱtheseȱdifferencesȱresultȱinȱsmallerȱcode?ȱPossibly,ȱdependingȱonȱhowȱ
wellȱyourȱcompilerȱcanȱoptimize.ȱButȱtheȱdifferenceȱwillȱbeȱsmallȱatȱbest,ȱandȱthisȱcodeȱ
isȱ lessȱ readableȱ thanȱ before,ȱ particularlyȱ forȱ anȱ inexperiencedȱ Cȱ programmer.ȱ Thus,ȱ
Programȱ12.8ȱmayȱbeȱmoreȱtroubleȱtoȱmaintain.ȱ
ȱ
Ifȱtheȱprogramȱsizeȱorȱexecutionȱspeedȱwereȱreallyȱimportant,ȱtheȱonlyȱthingȱleftȱ
toȱ tryȱ wouldȱ beȱ toȱ handȱ codeȱ theȱ functionȱ inȱ assemblyȱ language.ȱ Evenȱ thisȱ drasticȱ
optionȱdoesȱnotȱguaranteeȱanyȱsignificantȱimprovement,ȱandȱtheȱdifficultyȱofȱwriting,ȱ
reading,ȱ andȱ maintainingȱ assemblyȱ codeȱ suggestsȱ thatȱ thisȱ approachȱ shouldȱ beȱ usedȱ
onlyȱasȱaȱlastȱresort.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Add the new node to the list.
*/
newnode->fwd = next;
this->fwd = newnode;
newnode->bwd = this != rootp ? this : NULL;
( next != NULL ? next : rootp )->bwd = newnode;
ȱ
Programȱ12.8ȱȱInsertȱfunctionȱusingȱconditionalȱexpressionsȱ ȱ
ȱ
ȱ
ȱ
ȱȱȱȱdll_ins5.cȱ
Download at http://www.pin5i.com/
12.4 Summary
345
ȱȱ
12.3.2
Other List Operations
ȱ
Asȱ withȱ singlyȱ linkedȱ lists,ȱ moreȱ operationsȱ areȱ neededȱ forȱ doublyȱ linkedȱ lists.ȱ Theȱ
exercisesȱwillȱgiveȱyouȱpracticeȱinȱwritingȱthem.ȱ
ȱ
ȱ
ȱ
12.4 Summary
ȱ
Aȱsinglyȱlinkedȱlistȱisȱaȱdataȱstructureȱthatȱstoresȱvaluesȱusingȱpointers.ȱEachȱnodeȱinȱ
theȱ listȱ containsȱ aȱ fieldȱ whichȱ pointsȱ toȱ theȱ nextȱ node.ȱ Aȱ separateȱ pointer,ȱ calledȱ theȱ
root,ȱpointsȱtoȱtheȱfirstȱnode.ȱWhenȱtheȱnodesȱareȱdynamicallyȱallocated,ȱtheyȱmayȱbeȱ
scatteredȱ throughoutȱ memory.ȱ However,ȱ theȱ listȱ isȱ traversedȱ byȱ followingȱ theȱ
pointers,ȱ soȱ theȱ physicalȱ arrangementȱ ofȱ theȱ nodesȱ isȱ irrelevant.ȱ ȱ Aȱ singlyȱ linkedȱ listȱ
canȱonlyȱbeȱtraversedȱinȱoneȱdirection.ȱ
Toȱinsertȱaȱnewȱvalueȱintoȱanȱordered,ȱsinglyȱlinkedȱlist,ȱyouȱmustȱfirstȱfindȱtheȱ
properȱpositionȱinȱtheȱlist.ȱȱNewȱvaluesȱmayȱbeȱinsertedȱintoȱunorderedȱlistsȱanywhere.ȱȱ
Thereȱ areȱ twoȱ stepsȱ toȱ linkȱ aȱ newȱ nodeȱ intoȱ theȱ list.ȱ First,ȱ theȱ newȱ nodeȇsȱ linkȱ fieldȱ
mustȱbeȱsetȱtoȱpointȱtoȱwhatȱwillȱbeȱtheȱnextȱnode.ȱSecond,ȱtheȱpreviousȱlinkȱfieldȱmustȱ
beȱchangedȱtoȱpointȱtoȱtheȱnewȱnode.ȱȱInȱmanyȱotherȱlanguages,ȱanȱinsertionȱfunctionȱ
wouldȱ saveȱ aȱ pointerȱ toȱ theȱ previousȱ nodeȱ toȱ accomplishȱ theȱ secondȱ step.ȱ However,ȱ
thisȱtechniqueȱmakesȱinsertingȱatȱtheȱbeginningȱofȱtheȱlistȱaȱspecialȱcase.ȱInȱC,ȱyouȱcanȱ
eliminateȱ theȱ specialȱ caseȱ byȱ savingȱ aȱ pointerȱ toȱ theȱ linkȱ fieldȱ thatȱ mustȱ beȱ changedȱ
insteadȱofȱaȱpointerȱtoȱtheȱpreviousȱnode.ȱ
Eachȱnodeȱinȱaȱdoublyȱlinkedȱlistȱcontainsȱtwoȱlinkȱfields:ȱoneȱpointsȱtoȱtheȱnextȱ
nodeȱinȱtheȱlist,ȱandȱtheȱotherȱpointsȱtoȱtheȱpreviousȱnode.ȱTwoȱrootȱpointersȱareȱusedȱ
toȱpointȱtoȱtheȱfirstȱandȱtheȱlastȱnodesȱinȱtheȱlist.ȱThus,ȱtraversalsȱofȱdoublyȱlinkedȱlistsȱ
mayȱbeginȱfromȱeitherȱendȱofȱtheȱlistȱandȱmayȱproceedȱinȱeitherȱdirection.ȱToȱinsertȱaȱ
newȱ nodeȱ intoȱ aȱ doublyȱ linkedȱ list,ȱ fourȱ linksȱ mustȱ beȱ changed.ȱ Theȱ newȱ nodeȇsȱ
forwardȱandȱbackwardȱlinksȱmustȱbeȱset,ȱandȱtheȱpreviousȱnodeȇsȱforwardȱpointerȱandȱ
theȱnextȱnodeȇsȱbackwardȱpointerȱmustȱbothȱbeȱchangedȱtoȱpointȱtoȱtheȱnewȱnode.ȱ
Statementȱ factoringȱ isȱ aȱ techniqueȱ thatȱ simplifiesȱ aȱ programȱ byȱ removingȱ
redundantȱ statementsȱ fromȱ it.ȱ Ifȱ theȱ ȈthenȈȱ andȱ theȱ ȈelseȈȱ clausesȱ ofȱ anȱ ifȱ endȱ withȱ
identicalȱ sequencesȱ ofȱ statements,ȱ theyȱ canȱ beȱ replacedȱ byȱ aȱ singleȱ copyȱ ofȱ theȱ
sequenceȱafterȱtheȱ if.ȱȱIdenticalȱsequencesȱofȱstatementsȱcanȱalsoȱbeȱfactoredȱfromȱtheȱ
beginningȱofȱanȱ ifȱstatementȱunlessȱtheirȱexecutionȱchangesȱtheȱtestȱperformedȱbyȱtheȱ
if.ȱIfȱdifferentȱstatementsȱactuallyȱperformȱtheȱsameȱwork,ȱyouȱmayȱbeȱableȱtoȱrewriteȱ
themȱ identically.ȱ Youȱ mayȱ thenȱ beȱ ableȱ toȱ applyȱ statementȱ factoringȱ toȱ simplifyȱ theȱ
program.ȱ
Download at http://www.pin5i.com/
346ȱ
Chapter 12 Using Structures and Pointersȱ
12.5 Summary of Cautions
ȱ
1. Fallingȱoffȱtheȱendȱofȱaȱlinkedȱlistȱ(pageȱ327).ȱ
2. Beȱ especiallyȱ carefulȱ withȱ pointers,ȱ becauseȱ Cȱ doesȱ notȱ provideȱ aȱ safetyȱ netȱ forȱ
theirȱuseȱ(pageȱ333).ȱ
3. Factoringȱaȱstatementȱoutȱofȱanȱifȱthatȱchangesȱtheȱresultȱofȱtheȱtestȱ(pageȱ340).ȱ
ȱ
ȱ
ȱ
12.6 Summary of Programming Tips
ȱ
1. Eliminatingȱspecialȱcasesȱmakesȱcodeȱeasierȱtoȱmaintainȱ(pageȱ333).ȱ
2. Eliminateȱduplicateȱstatementsȱfromȱifȱstatementsȱbyȱfactoringȱthemȱ(pageȱ339).ȱ
3. Doȱnotȱjudgeȱtheȱqualityȱofȱcodeȱsolelyȱbyȱitsȱsizeȱ(pageȱ344).ȱ
ȱ
ȱ
ȱ
12.7 Questions
ȱ
1. CanȱProgramȱ12.3ȱbeȱwrittenȱwithoutȱusingȱaȱ currentȱvariable?ȱIfȱso,ȱcompareȱtheȱ
resultingȱfunctionȱtoȱtheȱoriginal.ȱ
2. Someȱ dataȱ structuresȱ textbooksȱ suggestȱ usingȱ aȱ Ȉheaderȱ nodeȈȱ inȱ aȱ singlyȱ linkedȱ
list.ȱ Thisȱ dummyȱ nodeȱ isȱ alwaysȱ theȱ firstȱ elementȱ inȱ theȱ listȱ andȱ eliminatesȱ theȱ
specialȱcaseȱcodeȱforȱinsertingȱatȱtheȱbeginningȱofȱtheȱlist.ȱDiscussȱtheȱprosȱandȱconsȱ
ofȱthisȱtechnique.ȱ
3. Whereȱ wouldȱ theȱ insertionȱ functionȱ inȱ Programȱ 12.3ȱ putȱ aȱ nodeȱ withȱ aȱ duplicateȱ
value?ȱWhatȱwouldȱbeȱtheȱeffectȱofȱchangingȱtheȱcomparisonȱfromȱ<ȱtoȱ<=?ȱ
4. Discussȱ techniquesȱ forȱ omittingȱ theȱ valueȱ fieldȱ fromȱ theȱ rootȱ nodeȱ ofȱ aȱ doublyȱ
linkedȱlist.ȱ
5. Whatȱwouldȱbeȱtheȱresultȱifȱtheȱcallȱtoȱ mallocȱinȱProgramȱ12.7ȱwereȱperformedȱatȱ
theȱbeginningȱofȱtheȱfunction?ȱ
6. Isȱitȱpossibleȱtoȱsortȱtheȱnodesȱinȱanȱunordered,ȱsinglyȱlinkedȱlist?ȱ
7. Aȱconcordanceȱlistȱisȱanȱalphabeticȱlistȱofȱtheȱwordsȱthatȱappearȱinȱaȱbookȱorȱarticle.ȱ
Youȱcanȱimplementȱaȱconcordanceȱlistȱusingȱanȱordered,ȱsinglyȱlinkedȱlistȱofȱstringsȱ
withȱ anȱ insertionȱ functionȱ thatȱ doesȱ notȱ addȱ duplicateȱ wordsȱ toȱ theȱ list.ȱ Theȱ
problemȱ withȱ thisȱ implementationȱ isȱ thatȱ theȱ timeȱ itȱ takesȱ toȱ searchȱ theȱ listȱ
increasesȱasȱtheȱlistȱgrowsȱinȱsize.ȱ
ȱ
Download at http://www.pin5i.com/
12.8 Programming Exercises
ȇaȇ
347
ȇbȇ
listȱ
15
(etc.)
(etc.)
ȈaȈ
ȈbagȈ
ȈanȈ
ȈbeȈ
(etc.)
ȱ
ȱ
Figureȱ12.1ȱȱAȱconcordanceȱlistȱ
ȱ
ȱ
Figureȱ12.1ȱillustratesȱanȱalternativeȱdataȱstructureȱforȱstoringȱtheȱconcordanceȱ
list.ȱ Theȱ ideaȱ isȱ toȱ breakȱ theȱ largeȱ listȱ intoȱ 26ȱ smallerȱ lists—oneȱ listȱ ofȱ wordsȱ forȱ
eachȱ letterȱ ofȱ theȱ alphabet.ȱ Eachȱ ofȱ theȱ nodesȱ inȱ theȱ primaryȱ listȱ containsȱ aȱ letterȱ
andȱpointsȱtoȱanȱordered,ȱsinglyȱlinkedȱlistȱofȱwordsȱ(storedȱasȱstrings)ȱthatȱbeginȱ
withȱthisȱletter.ȱ
Howȱ doesȱtheȱ timeȱ toȱsearchȱthisȱstructureȱforȱaȱ specificȱwordȱcompareȱtoȱ theȱ
timeȱtoȱsearchȱanȱordered,ȱsinglyȱlinkedȱlistȱcontainingȱallȱofȱtheȱwords?ȱ
ȱ
ȱ
ȱ
12.8 Programming Exercises
ȱ
1. Writeȱaȱfunctionȱthatȱcountsȱtheȱnumber,ȱofȱnodesȱinȱaȱsinglyȱlinkedȱlist.ȱItȱshouldȱ
takeȱ aȱ pointerȱ toȱ theȱ firstȱ nodeȱ inȱ theȱ listȱ asȱ itsȱ onlyȱ argument.ȱ Whatȱ mustȱ you
Download at http://www.pin5i.com/
348ȱ
Chapter 12 Using Structures and Pointersȱ
knowȱinȱorderȱtoȱwriteȱthisȱfunction?ȱWhatȱotherȱjobsȱcanȱthisȱfunctionȱperform?ȱ
2. Writeȱaȱfunctionȱtoȱlocateȱaȱparticularȱvalueȱinȱanȱunordered,ȱsinglyȱlinkedȱlist,ȱandȱ
returnȱaȱpointerȱtoȱthatȱnode.ȱYouȱmayȱassumeȱthatȱtheȱnodeȱstructureȱisȱdefinedȱinȱ
theȱfileȱsingly_linked_list_node.h.ȱ
Areȱ anyȱ changesȱ neededȱ inȱ orderȱ toȱ makeȱ theȱ functionȱ workȱ onȱ anȱ ordered,ȱ
singlyȱlinkedȱlist?ȱ
3. RewriteȱProgramȱ12.7,ȱ dll_insert,ȱsoȱthatȱtheȱheadȱandȱtailȱpointersȱareȱpassedȱinȱ
asȱseparateȱpointersȱratherȱthanȱasȱpartȱofȱaȱrootȱnode.ȱWhatȱeffectȱdoesȱthisȱchangeȱ
haveȱonȱtheȱlogicȱofȱtheȱfunction?ȱ
4. Writeȱ aȱ functionȱ thatȱ reversesȱ theȱ orderȱ ofȱ theȱ nodesȱ inȱ aȱ singlyȱ linkedȱ list.ȱ Theȱ
functionȱshouldȱhaveȱtheȱfollowingȱprototype:ȱ
ȱ
struct NODE * sll_reverse( struct NODE *first );
ȱ
Declareȱtheȱnodeȱstructureȱinȱtheȱfile singly_linked_list_node.h.ȱ
Theȱargumentȱpointsȱtoȱtheȱfirstȱnodeȱinȱtheȱlist.ȱAfterȱtheȱlistȱisȱrearranged,ȱtheȱ
functionȱreturnsȱaȱpointerȱtoȱtheȱnewȱheadȱofȱtheȱlist.ȱTheȱlinkȱfieldȱofȱtheȱlastȱnodeȱ
inȱtheȱlistȱwillȱcontainȱNULL,ȱandȱinȱtheȱeventȱofȱanȱemptyȱlistȱ(first == NULL)ȱtheȱ
functionȱshouldȱreturnȱNULL,ȱ
5. Writeȱaȱprogramȱ toȱ removeȱ aȱ nodeȱ fromȱ aȱsinglyȱlinkedȱlist.ȱ Theȱfunctionȱshouldȱ
haveȱtheȱfollowingȱprototype:ȱ
ȱ
int sll_remove( struct NODE **rootp, struct NODE *node );
ȱ
Youȱ mayȱ assumeȱ thatȱ theȱ nodeȱ structureȱ isȱ definedȱ inȱ theȱ fileȱ
singly_Iinked_list_node.h.ȱ Theȱ firstȱ argumentȱ pointsȱ toȱ theȱ rootȱ pointerȱ ofȱ theȱ
list,ȱandȱtheȱsecondȱpointsȱtoȱtheȱnodeȱthatȱisȱtoȱbeȱremoved.ȱTheȱfunctionȱreturnsȱ
falseȱifȱtheȱlistȱdoesȱnotȱcontainȱtheȱindicatedȱnode,ȱotherwiseȱitȱremovesȱtheȱnodeȱ
andȱreturnsȱtrue.ȱ
Isȱthereȱanyȱadvantageȱinȱtakingȱaȱpointerȱtoȱtheȱnodeȱtoȱremoveȱasȱopposedȱtoȱ
takingȱtheȱvalue?ȱ
6. Writeȱaȱprogramȱtoȱremoveȱaȱnodeȱfromȱaȱdoublyȱlinkedȱlist.ȱTheȱfunctionȱshouldȱ
haveȱtheȱfollowingȱprototype:ȱ
ȱ
int
dll_remove( struct NODE *rootp, struct NODE *node );
ȱ
Youȱ mayȱ assumeȱ thatȱ theȱ nodeȱ structureȱ isȱ definedȱ inȱ theȱ fileȱ
doubly_linked_list_node.h.ȱ Theȱ firstȱ argumentȱ pointsȱ toȱ aȱ nodeȱ containingȱ theȱ
rootȱpointersȱforȱtheȱlistȱ(theȱsameȱasȱwithȱProgramȱ12.7),ȱandȱtheȱsecondȱpointsȱtoȱȱ
Download at http://www.pin5i.com/
12.8 Programming Exercises
349
ȱtheȱ nodeȱ thatȱ isȱ toȱ beȱ removed.ȱ Theȱ functionȱ returnsȱ falseȱ ifȱ theȱ listȱ doesȱ notȱ
containȱtheȱindicatedȱnode,ȱotherwiseȱitȱremovesȱtheȱnodeȱandȱreturnsȱtrue.ȱ
7. Writeȱ aȱ functionȱ toȱ insertȱ aȱ newȱ wordȱ intoȱ theȱ concordanceȱ listȱ describedȱ inȱ
Questionȱ7.ȱȱTheȱfunctionȱshouldȱtakeȱaȱpointerȱtoȱtheȱ listȱpointerȱandȱaȱstringȱasȱ
itsȱarguments.ȱTheȱstringȱisȱassumedȱtoȱcontainȱaȱsingleȱword.ȱȱIfȱtheȱwordȱdoesȱnotȱ
alreadyȱexistȱinȱtheȱlist,ȱitȱshouldȱbeȱcopiedȱintoȱdynamicallyȱallocatedȱmemoryȱandȱ
thenȱinserted.ȱTheȱfunctionȱshouldȱreturnȱtrueȱifȱtheȱstringȱwasȱinserted;ȱandȱfalseȱifȱ
theȱstringȱalreadyȱexistedȱinȱtheȱlist,ȱdidȱnotȱbeginȱwithȱaȱletter,ȱorȱifȱanythingȱelseȱ
wentȱwrong.ȱ
Theȱfunctionȱshouldȱmaintainȱtheȱprimaryȱlistȱinȱorderȱbyȱtheȱletterȱofȱtheȱnodeȱ
andȱtheȱsecondaryȱlistsȱinȱorderȱbyȱtheȱwords.ȱ
Download at http://www.pin5i.com/
13
Advanced Pointers Topics
Thisȱchapterȱisȱaȱcollectionȱofȱvariousȱtechniquesȱinvolvingȱpointers.ȱȱSomeȱofȱthemȱareȱ
veryȱ useful,ȱ othersȱ areȱ ofȱ moreȱ academicȱ interest,ȱ andȱ aȱ fewȱ areȱ justȱ fun,ȱ butȱ allȱ areȱ
goodȱillustrationsȱofȱvariousȱprinciplesȱinȱtheȱlanguage.ȱ
ȱ
ȱ
ȱ
13.1 More Pointers to Pointers
ȱ
Weȱusedȱpointersȱtoȱpointersȱinȱtheȱlastȱchapterȱtoȱsimplifyȱtheȱfunctionȱthatȱinsertsȱaȱ
newȱvalueȱintoȱaȱsinglyȱlinkedȱlist.ȱThereȱareȱmanyȱotherȱareasȱwhereȱhavingȱaȱpointerȱ
toȱaȱpointerȱisȱalsoȱvaluable.ȱ
Hereȱisȱaȱgeneralȱexample.ȱ
ȱ
int
int
int
i;
*pi;
**ppi;
ȱ
Theseȱ declarationsȱ createȱ theȱ followingȱ variablesȱ inȱ memory.ȱ Ifȱ theseȱ areȱ automaticȱ
variables,ȱweȱcannotȱmakeȱanyȱassumptionsȱaboutȱtheirȱinitialȱvalues.ȱ
ȱ
iȱ
ȱ
piȱ
ȱ
ppiȱ
?ȱ
ȱ
?ȱ
ȱ
?ȱ
ȱ
Givenȱthisȱinformation,ȱwhatȱisȱtheȱeffectȱofȱeachȱofȱtheseȱstatements?ȱ
ȱ
1 printf( "%d\n", ppi );
2 printf( "%d\n", &ppi );
3 *ppi = 5;
Download at http://www.pin5i.com/
352ȱ
Chapter 13 Advanced Pointer Topicsȱ
1 Ifȱppiȱisȱanȱautomaticȱvariable,ȱitȱisȱuninitializedȱandȱaȱrandomȱvalueȱisȱprinted.ȱIfȱitȱ
isȱaȱstaticȱvariable,ȱzeroȱisȱprinted.ȱ
2 Thisȱstatementȱprints,ȱasȱaȱdecimalȱinteger,ȱtheȱaddressȱwhereȱ ppiȱisȱstored.ȱȱThisȱ
valueȱisȱnotȱveryȱuseful.ȱ
3 Theȱresultȱofȱthisȱstatementȱisȱunpredictable.ȱIndirectionȱshouldȱnotȱbeȱperformedȱ
onȱppiȱbecauseȱitȱisȱnotȱyetȱinitialized.ȱ
ȱ
Theȱnextȱtwoȱstatementsȱareȱmoreȱuseful.ȱ
ȱ
ppi = &pli;
ȱ
Thisȱ statementȱ initializesȱ ppiȱ toȱ pointȱ toȱ theȱ variableȱ pi.ȱ Weȱ canȱ nowȱ safelyȱ applyȱ
indirectionȱtoȱppi.ȱ
ȱ
*ppi = &i;
ȱ
Thisȱ statementȱ initializesȱ piȱ (whichȱ isȱ accessedȱ indirectlyȱ throughȱ ppi)ȱ toȱ pointȱ toȱ i.ȱ
Afterȱtheseȱlastȱtwoȱstatements,ȱtheȱvariablesȱlookȱlikeȱthis:ȱ
ȱ
iȱ
ȱ
piȱ
ȱ
ppiȱ
?ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Now,ȱeachȱofȱtheȱfollowingȱstatementsȱhasȱtheȱsameȱeffect:ȱ
ȱ
i = 'a';
*pi = 'a';
**ppi = 'a';
ȱ
Whyȱ wouldȱ anyoneȱ everȱ useȱ theȱ moreȱ complicatedȱ versionsȱ withȱ indirectionȱ ifȱ aȱ
simpleȱ assignmentȱ toȱ iȱ doesȱ theȱ job?ȱ Becauseȱ theȱ simpleȱ assignmentȱ isȱ notȱ alwaysȱ
possible,ȱsuchȱasȱinȱtheȱlinkedȱlistȱinsertion.ȱWeȱcouldȱnotȱuseȱaȱsimpleȱassignmentȱinȱ
thatȱ functionȱ becauseȱ theȱ variableȱ nameȱ wasȱ notȱ knownȱ withinȱ theȱ scopeȱ ofȱ theȱ
function.ȱȱAllȱtheȱfunctionȱhadȱwasȱaȱpointerȱtoȱtheȱlocationȱthatȱneededȱtoȱbeȱchanged,ȱ
soȱindirectionȱwasȱusedȱonȱtheȱpointerȱtoȱaccessȱtheȱdesiredȱvariable.ȱ
Inȱtheȱpreviousȱexample,ȱtheȱvariableȱ iȱisȱanȱinteger,ȱandȱ piȱisȱaȱpointerȱtoȱanȱ
integer.ȱButȱ ppiȱisȱpointingȱatȱ pi,ȱsoȱitȱisȱaȱpointerȱtoȱaȱpointerȱtoȱanȱinteger.ȱSupposeȱ
weȱwantedȱanotherȱvariable,ȱoneȱthatȱwouldȱpointȱtoȱppi.ȱItsȱtype,ȱofȱcourse,ȱwouldȱbeȱ
Ȉpointerȱtoȱaȱpointerȱtoȱaȱpointerȱtoȱanȱinteger,Ȉȱandȱitȱwouldȱbeȱdeclaredȱinȱthisȱway:ȱ
ȱ
int
***pppi;
Download at http://www.pin5i.com/
13.2 Advanced Declarations
TIP
353
Theȱ moreȱlevelsȱ ofȱindirection,ȱtheȱlessȱoftenȱ youȱwillȱ needȱtoȱ useȱit.ȱ Butȱonceȱ
youȱ trulyȱ understandȱ indirection,ȱ itȱ isȱ easyȱ toȱ applyȱ asȱ manyȱ levelsȱ ofȱ indirectionȱ asȱ
youȱneedȱforȱanyȱsituation.ȱ
ȱ
Useȱonlyȱasȱmanyȱlevelsȱofȱindirectionȱasȱyouȱreallyȱneed.ȱOtherwise,ȱyourȱprogramsȱ
willȱendȱupȱbeingȱlarger,ȱslower,ȱandȱharderȱtoȱmaintain.ȱ
ȱ
ȱ
ȱ
13.2 Advanced Declarations
ȱ
Beforeȱusingȱmoreȱadvancedȱpointerȱtypes,ȱweȱmustȱseeȱhowȱtheyȱareȱdeclared.ȱEarlierȱ
chaptersȱ introducedȱ theȱ ideaȱ ofȱ aȱ declarationȱ expressionȱ andȱ howȱ variablesȱ inȱ Cȱ areȱ
declaredȱ byȱ inference.ȱ Weȱ sawȱ someȱ examplesȱ ofȱ declarationȱ byȱ inferenceȱ whenȱ weȱ
declaredȱ pointersȱ toȱ arraysȱ inȱ Chapterȱ 8.ȱ Letȇsȱ exploreȱ thisȱ topicȱ byȱ lookingȱ atȱ aȱ
sequenceȱofȱincreasinglyȱcomplexȱdeclarations.ȱ
Weȇllȱstartȱwithȱsomeȱeasyȱones.ȱ
ȱ
int
int
f;
*f;
/* an integer */
/* a pointer to an integer */
ȱ
Rememberȱhowȱtheȱsecondȱdeclarationȱworks,ȱthough;ȱitȱdeclaresȱtheȱexpressionȱ
*fȱ toȱ beȱ anȱ integer.ȱ Fromȱ thisȱ factȱ youȱ mustȱ deduceȱ thatȱ fȱ isȱ aȱ pointerȱ toȱ anȱ integer.ȱ
ThisȱinterpretationȱofȱCȱdeclarationsȱisȱvalidatedȱbyȱtheȱdeclarationȱ
ȱ
int*
f, g;
ȱ
whichȱdoesȱnotȱdeclareȱtwoȱpointers.ȱDespiteȱtheȱspacing,ȱtheȱstarȱisȱassociatedȱwithȱf,ȱ
andȱonlyȱfȱisȱaȱpointer,ȱgȱisȱanȱordinaryȱinteger.ȱ
Hereȱisȱanotherȱoneȱyouȱhaveȱseenȱbefore:ȱ
ȱ
int
f();
ȱ
Itȱ declaresȱ fȱ toȱ beȱ aȱ functionȱ thatȱ returnsȱ anȱ integer.ȱ Theȱ oldȬstyleȱ declarationȱ saysȱ
nothingȱaboutȱtheȱfunctionȇsȱparameters.ȱItȱonlyȱdeclaresȱtheȱtypeȱofȱvalueȱthatȱ fȱwillȱ
return.ȱ Iȱ willȱ useȱ thisȱ styleȱ forȱ nowȱ toȱ keepȱ theȱ examplesȱ simplerȱ andȱ returnȱ toȱ fullȱ
prototypesȱlater.ȱ
Hereȇsȱaȱnewȱone:ȱ
ȱ
int
*f();
ȱ
Toȱfigureȱthisȱoneȱout,ȱyouȱmustȱdetermineȱhowȱtheȱexpressionȱ *f()ȱisȱevaluated.ȱTheȱ
functionȱ callȱ operatorȱ ()ȱ goesȱ firstȱ becauseȱ itsȱ precedenceȱ isȱ higherȱ thanȱ thatȱ ofȱ
indirection,ȱsoȱfȱisȱaȱfunctionȱthatȱreturnsȱaȱpointerȱtoȱanȱinteger.ȱ
Download at http://www.pin5i.com/
354ȱ
Chapter 13 Advanced Pointer Topicsȱ
Ifȱ Ȉdeclarationȱ byȱ inferenceȈȱ seemsȱ likeȱ aȱ nuisance,ȱ considerȱ thatȱ theȱ
expressionsȱ usedȱ forȱ declaringȱ variablesȱ areȱ evaluatedȱ withȱ theȱ sameȱ rulesȱ usedȱ forȱ
ordinaryȱexpressions.ȱYouȱdonȇtȱneedȱtoȱlearnȱaȱseparateȱsyntaxȱforȱdeclarations.ȱIfȱyouȱ
canȱ evaluateȱ complexȱ expressions,ȱ youȱ canȱ alsoȱ figureȱ outȱ complexȱ declarationsȱ
becauseȱtheyȱworkȱtheȱsameȱway.ȱ
Theȱnextȱdeclarationȱisȱmoreȱinteresting.ȱ
ȱ
int
(*f)();
ȱ
Figuringȱ outȱ whatȱ theȱ parenthesesȱ meanȱ isȱ anȱ importantȱ stepȱ inȱ decipheringȱ thisȱ
declaration.ȱThereȱareȱtwoȱsetsȱofȱparentheses,ȱandȱeachȱhasȱaȱdifferentȱmeaning.ȱTheȱ
secondȱsetȱofȱparenthesesȱisȱtheȱfunctionȱcallȱoperator,ȱbutȱtheȱfirstȱsetȱisȱusedȱonlyȱforȱ
grouping.ȱ Itȱ forcesȱ theȱ indirectionȱ toȱ beȱ appliedȱ beforeȱ theȱ functionȱ call,ȱ makingȱ fȱ aȱ
pointerȱtoȱaȱfunctionȱthatȱreturnsȱanȱinteger.ȱ
Aȱpointerȱtoȱaȱfunction?ȱYes,ȱeachȱfunctionȱinȱaȱprogramȱbeginsȱatȱsomeȱaddressȱ
inȱ memory,ȱ soȱ itȱ isȱ possibleȱ forȱ aȱ variableȱ toȱ pointȱ toȱ thatȱ location.ȱ Theȱ initializationȱ
andȱuseȱofȱpointersȱtoȱfunctionsȱisȱcoveredȱlaterȱinȱthisȱchapter.ȱ
Theȱnextȱdeclarationȱshouldȱnowȱbeȱeasy:ȱ
ȱ
int
*(*f)();
ȱ
Itȱ isȱ theȱ sameȱ asȱ theȱ previousȱ exampleȱ exceptȱ thatȱ inȱ orderȱ toȱ getȱ anȱ integer,ȱ
indirectionȱ isȱ appliedȱ toȱ theȱ valueȱ returnedȱ byȱ theȱ function.ȱ Hereȱ fȱ isȱ aȱ pointerȱ toȱ aȱ
functionȱthatȱreturnsȱaȱpointerȱtoȱanȱinteger.ȱ
Nowȱletȇsȱconsiderȱarrays,ȱtoo.ȱ
ȱ
int
f[];
ȱ
indicatesȱ thatȱ fȱ isȱ anȱ arrayȱ ofȱ integers.ȱ Theȱ sizeȱ hasȱ beenȱ omittedȱ forȱ nowȱ becauseȱ
weȇreȱnotȱconcernedȱwithȱtheȱarrayȇsȱsize,ȱonlyȱitsȱtype. 43
Howȱaboutȱthisȱone?ȱ
ȱ
int
*f[];
ȱ
Again,ȱthereȱareȱtwoȱoperators.ȱTheȱsubscriptȱhasȱtheȱhigherȱprecedence,ȱsoȱ fȱisȱnowȱ
anȱarrayȱofȱpointersȱtoȱintegers.ȱ
Theȱnextȱexampleȱisȱaȱtrickȱquestion,ȱbutȱtryȱtoȱfigureȱitȱoutȱanyway.ȱ
ȱ
int
f()[];
ȱ
fȱ appearsȱ toȱ beȱ aȱ functionȱ thatȱ returnsȱ anȱ arrayȱ ofȱ integers.ȱ Theȱ trickȱ isȱ thatȱ itȱ isȱ
illegal—functionsȱcanȱonlyȱreturnȱscalars,ȱnotȱarrays.ȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
43
ȱEvenȱwithoutȱaȱsize,ȱtheseȱdeclarationsȱareȱstillȱlegalȱifȱtheyȱareȱexternalȱorȱareȱfunction,ȱparameters.ȱ
Download at http://www.pin5i.com/
13.2 Advanced Declarations
355
Hereȱisȱanotherȱoneȱthatȱwillȱrequireȱsomeȱthought:ȱ
ȱ
int
f[]();
ȱ
Nowȱfȱappearsȱtoȱbeȱanȱarrayȱofȱfunctionsȱthatȱreturnȱintegers.ȱThisȱdeclarationȱisȱalsoȱ
illegalȱbecauseȱarrayȱelementsȱmustȱallȱbeȱtheȱsameȱsize,ȱbutȱitȱisȱquiteȱreasonableȱforȱ
differentȱfunctionsȱcoȱbeȱdifferent,ȱsizes.ȱ
Theȱnextȱdeclarationȱisȱlegal,ȱthough:ȱ
ȱ
int
(*f[])();
ȱ
Youȱmustȱfirstȱfindȱallȱofȱtheȱoperatorsȱandȱthenȱapplyȱthemȱinȱtheȱcorrectȱorder.ȱOnceȱ
again,ȱ thereȱ areȱ twoȱ setsȱ ofȱ parenthesesȱ withȱ differentȱ meanings.ȱ Theȱ parenthesizedȱ
expressionȱ *f[]ȱ isȱ evaluatedȱ first,ȱ soȱ fȱ isȱ anȱ arrayȱ ofȱ pointersȱ toȱ something.ȱ Theȱ
trailingȱ ()ȱisȱtheȱfunctionȱcallȱoperator,ȱsoȱ fȱmustȱbeȱanȱarrayȱofȱpointersȱtoȱfunctionsȱ
thatȱreturnȱintegers.ȱ
Ifȱyouȱgotȱthatȱlastȱoneȱright,ȱthenȱthisȱoneȱshouldȱbeȱeasy:ȱ
ȱ
int
*(*f[])();
ȱ
Theȱonlyȱchangeȱisȱoneȱfinalȱindirection,ȱsoȱthisȱdeclarationȱcreatesȱanȱarrayȱofȱpointersȱ
toȱfunctionsȱthatȱreturnȱpointersȱtoȱintegers.ȱ
Upȱ toȱ now,ȱ Iȇveȱ usedȱ oldȬstyleȱ declarationsȱ toȱ keepȱ theȱ examplesȱ simple.ȱ Butȱ
ANSIȱCȱletsȱusȱuseȱfullȱfunctionȱprototypesȱtoȱmakeȱtheȱdeclarationȱmoreȱspecific.ȱForȱ
example:ȱ
ȱ
int
int
TIP
(*f)( int, float );
*(*g[])( int, float );
ȱ
declaresȱ fȱ toȱ beȱ aȱ pointerȱ toȱ aȱ functionȱ thatȱ takesȱ twoȱ arguments,ȱ anȱ integerȱ andȱ aȱ
float,ȱ andȱ returnsȱ anȱ integer.ȱ ȱ gȱ isȱ anȱ arrayȱ ofȱ pointersȱ toȱ functionsȱ thatȱ takeȱ twoȱ
arguments,ȱ anȱ integerȱ andȱ aȱ floatȱ andȱ returnȱ aȱ pointerȱ toȱ anȱ integer.ȱ Despiteȱ theȱ
increasedȱ complexityȱ inȱ theȱ declaration,ȱ theȱ prototypeȱ formȱ isȱ greatlyȱ preferredȱ
becauseȱofȱtheȱadditionalȱinformationȱitȱgivesȱtheȱcompiler.ȱ
ȱ
Ifȱ youȱ haveȱ aȱ UNIXȱ systemȱ andȱ haveȱ accessȱ toȱ theȱ Internet,ȱ youȱ canȱ getȱ cdec1,ȱ aȱ
programȱthatȱconvertsȱbetweenȱCȱdeclarationsȱandȱEnglish.ȱItȱcanȱexplainȱanȱexistingȱ
Cȱdeclaration:ȱ
ȱ
cdec1> explain int (*(*f)())[10];
declare f as pointer to function returning pointer to array 10 of int
ȱ
orȱgiveȱyouȱtheȱsyntaxȱforȱaȱdeclaration:ȱ
Download at http://www.pin5i.com/
356ȱ
Chapter 13 Advanced Pointer Topicsȱ
cdec1> declare x as pointer to array 10 of pointer to
function returning int
int (*(*x)[10])()
ȱ
Theȱ sourceȱ codeȱ forȱ cdec1ȱ canȱ beȱ foundȱ inȱ Volumeȱ 14ȱ ofȱ theȱ archivesȱ forȱ theȱ
comp.sources.unixȱnewsgroup.ȱ
ȱ
ȱ
ȱ
13.3 Pointers to Functions
CAUTION!
ȱ
Youȱwillȱnotȱuseȱpointersȱtoȱfunctionsȱeveryȱday.ȱHowever,ȱtheyȱhaveȱtheirȱuses,ȱandȱ
theȱtwoȱmostȱcommonȱareȱjumpȱtablesȱandȱpassingȱaȱfunctionȱpointerȱasȱanȱargumentȱ
inȱaȱfunctionȱcall.ȱWeȇllȱexploreȱbothȱofȱtheseȱtechniquesȱthisȱsection.ȱFirst,ȱthough,ȱitȱisȱ
importantȱtoȱpointȱoutȱaȱcommonȱerror.ȱ
ȱ
Simplyȱ declaringȱ aȱ pointerȱ toȱ aȱ functionȱ doesȱ notȱ makeȱ itȱ usable.ȱ Likeȱ anyȱ otherȱ
pointer,ȱ aȱ pointerȱ toȱ aȱ functionȱ mustȱ beȱ initializedȱ toȱ pointȱ toȱ somethingȱ beforeȱ
indirectionȱcanȱbeȱperformedȱonȱit.ȱTheȱfollowingȱcodeȱfragmentȱillustratesȱoneȱwayȱtoȱ
initializeȱaȱpointerȱtoȱaȱfunction.ȱ
ȱ
int
int
f( int );
(*pf)( int ) = &f;
ȱ
Theȱsecondȱdeclarationȱcreatesȱ pf,ȱaȱpointerȱtoȱaȱfunction,ȱandȱinitializesȱitȱtoȱpointȱtoȱ
theȱ functionȱ f.ȱ Theȱ initializationȱ canȱ alsoȱ beȱ accomplishedȱ withȱ anȱ assignmentȱ
statement.ȱ Itȱ isȱ importantȱ toȱ haveȱ aȱ prototypeȱ forȱ fȱ priorȱ toȱ theȱ initialization,ȱ forȱ
withoutȱitȱ theȱcompilerȱwouldȱbeȱunableȱtoȱcheckȱwhetherȱtheȱtypeȱofȱ fȱagreedȱwithȱ
thatȱofȱpf.ȱ
Theȱ ampersandȱ inȱ theȱ initializationȱ isȱ optional,ȱ becauseȱ theȱ compilerȱ alwaysȱ
convertsȱ functionȱ namesȱ toȱ functionȱ pointersȱ whereverȱ theyȱ areȱ used.ȱ Theȱ ampersandȱ
doesȱexplicitlyȱwhatȱtheȱcompilerȱwouldȱhaveȱdoneȱimplicitlyȱanyway.ȱ
Afterȱtheȱpointerȱhasȱbeenȱdeclaredȱandȱinitialized,ȱthereȱareȱthreeȱwaysȱtoȱcallȱ
theȱfunction:ȱ
ȱ
int
ans;
ans = f( 25 );
ans = (*pf)( 25 );
ans = pf( 25 );
ȱ
Theȱ firstȱ statementȱ simplyȱ callsȱ theȱ functionȱ fȱ byȱ name,ȱ thoughȱ itsȱ evaluationȱ isȱ
probablyȱnotȱwhatȱyouȱexpected.ȱTheȱfunctionȱnameȱfȱisȱfirstȱconvertedȱtoȱaȱpointerȱtoȱ
theȱ function;ȱ theȱ pointerȱ specifiesȱ whereȱ theȱ functionȱ isȱ located.ȱ Theȱ functionȱ call
Download at http://www.pin5i.com/
13.3 Pointers to Functions
357
operatorȱthenȱinvokesȱtheȱfunctionȱbyȱexecutingȱtheȱcodeȱbeginningȱatȱthisȱaddress.ȱ
Theȱ secondȱ statementȱ appliesȱ indirectionȱ toȱ pf,ȱ whichȱ convertsȱ theȱ functionȱ
pointerȱ toȱ aȱ functionȱ name.ȱ Thisȱ conversionȱ isȱ notȱ reallyȱ necessary,ȱ becauseȱ theȱ
compilerȱ convertsȱ itȱ backȱ toȱ aȱ pointerȱ beforeȱ applyingȱ theȱ functionȱ callȱ operator.ȱ
Nevertheless,ȱthisȱstatementȱhasȱexactlyȱtheȱsameȱeffectȱasȱtheȱfirstȱone.ȱ
Theȱ thirdȱ statementȱ hasȱ theȱ sameȱ effectȱ asȱ theȱ firstȱ two.ȱ Indirectionȱ isȱ notȱ
needed,ȱ becauseȱ theȱ compilerȱ wantsȱ aȱ pointerȱ toȱ theȱ functionȱ anyway.ȱ Thisȱ exampleȱ
showsȱhowȱfunctionȱpointersȱareȱusuallyȱused.ȱ
Whenȱ wouldȱ anyoneȱ everȱ wantȱ toȱ useȱ aȱ pointerȱ toȱ aȱ function?ȱ Asȱ mentionedȱ
earlier,ȱ theȱ twoȱ mostȱ commonȱ usesȱ ofȱ pointersȱ toȱ functionsȱ areȱ passingȱ aȱ functionȱ
pointerȱasȱanȱargumentȱinȱaȱfunctionȱcallȱandȱjumpȱtables.ȱLetȇsȱlookȱatȱanȱapplicationȱ
ofȱeach.ȱ
ȱ
ȱ
ȱ
13.3.1
Callback Functions
ȱ
Hereȱisȱaȱsimpleȱfunctionȱthatȱlocatesȱaȱvalueȱinȱaȱsinglyȱlinkedȱlist.ȱItsȱargumentsȱareȱaȱ
pointerȱtoȱtheȱfirstȱnodeȱinȱtheȱlistȱandȱtheȱvalueȱtoȱlocate.ȱ
ȱ
Node*
search_list( Node *node, int const value )
{
while( node != NULL ){
if( node->value == value )
break;
node = node->link;
}
return node;
}
ȱ
Thisȱ functionȱ looksȱ simpleȱ enough,ȱ butȱ itȱ worksȱ onlyȱ withȱ linkedȱ listsȱ whoseȱ valuesȱ
areȱintegers.ȱIfȱyouȱalsoȱhadȱaȱlinkedȱlistȱofȱstrings,ȱyouȱwouldȱneedȱtoȱwriteȱaȱdifferentȱ
function,ȱ identicalȱ inȱ everyȱ respectȱ toȱ thisȱ oneȱ exceptȱ forȱ theȱ typeȱ ofȱ theȱ parameterȱ
valueȱandȱtheȱmannerȱinȱwhichȱtheȱnodeȱvaluesȱareȱcompared.ȱ
ȱ
Aȱ moreȱ generalȱ approachȱ isȱ toȱ makeȱ theȱ searchingȱ functionȱ typelessȱ soȱ thatȱ itȱ
willȱworkȱonȱlistsȱwithȱvaluesȱofȱanyȱtype.ȱȱWeȱmustȱreviseȱtwoȱaspectsȱofȱtheȱfunctionȱ
toȱ makeȱ itȱ typeless.ȱ First,ȱ weȱ mustȱ changeȱ howȱ theȱ comparisonȱ isȱ performedȱ soȱ thatȱ
theȱfunctionȱcanȱcompareȱvaluesȱofȱanyȱtype.ȱThisȱgoalȱsoundsȱimpossible.ȱIfȱyouȱwriteȱ
statementsȱ toȱ compareȱ integerȱ values,ȱ howȱ canȱ theyȱ possiblyȱ workȱ withȱ otherȱ typesȱ
suchȱasȱstrings?ȱȱTheȱsolutionȱusesȱaȱpointerȱtoȱaȱfunction.ȱTheȱcallerȱwritesȱaȱfunctionȱ
Download at http://www.pin5i.com/
358ȱ
TIP
Chapter 13 Advanced Pointer Topicsȱ
ȱtoȱ compareȱ twoȱ valuesȱ andȱ passesȱ aȱ pointerȱ toȱ itȱ asȱ anȱ argumentȱ toȱ theȱ searchȱ
function.ȱTheȱsearchȱfunctionȱthenȱcallsȱtheȱcomparisonȱfunctionȱtoȱmakeȱcomparisons.ȱ
Inȱthisȱway,ȱvaluesȱofȱanyȱtypeȱmayȱbeȱcompared.ȱ
Theȱsecondȱaspectȱweȱmustȱchangeȱisȱtoȱpassȱaȱpointerȱtoȱtheȱvalueȱratherȱthanȱ
theȱvalue.ȱTheȱfunctionȱwillȱreceiveȱthisȱargumentȱinȱaȱvoid*ȱparameter.ȱTheȱpointerȱtoȱ
theȱ valueȱ isȱ thenȱ passedȱ toȱ theȱ comparisonȱ function.ȱ Thisȱ changeȱ alsoȱ enablesȱ stringȱ
andȱ arrayȱ objectsȱ toȱ beȱ used.ȱ Stringȱ andȱ arraysȱ cannotȱ beȱ passedȱ asȱ arguments,ȱ butȱ
pointersȱtoȱthemȱcan.ȱ
Functionsȱ usedȱ inȱ thisȱ mannerȱ areȱ callbackȱ functionsȱ becauseȱ theȱ userȱ passesȱ aȱ
pointerȱ toȱ aȱ functionȱ toȱ someȱ otherȱ routine,ȱ whichȱ thenȱ Ȉcallsȱ backȈȱ toȱ theȱ userȇsȱ
function.ȱYouȱcanȱuseȱtheȱtechniqueȱanyȱtimeȱyouȱareȱwritingȱaȱfunctionȱthatȱmustȱbeȱ
ableȱtoȱperformȱdifferentȱtypesȱofȱworkȱatȱaȱgivenȱpointȱorȱperformȱworkȱthatȱcanȱbeȱ
definedȱonlyȱbyȱtheȱfunctionȇsȱcaller.ȱManyȱwindowingȱsystemsȱuseȱcallbackȱfunctionsȱ
toȱ connectȱ actions,ȱ suchȱ asȱ draggingȱ theȱ mouseȱ andȱ clickingȱ buttons,ȱ toȱ specificȱ
functionsȱinȱtheȱuserȇsȱprogram.ȱ
Weȱcannotȱwriteȱanȱaccurateȱprototypeȱforȱtheȱcallbackȱfunctionȱinȱthisȱcontextȱ
becauseȱweȱdonȇtȱknowȱwhatȱtypeȱofȱvaluesȱareȱbeingȱcompared.ȱIndeed,ȱweȱwantȱtheȱ
searchȱ functionȱ toȱ workȱ withȱ anyȱ typeȱ ofȱ value.ȱ Theȱ solutionȱ toȱ thisȱ dilemmaȱ isȱ toȱ
declareȱtheȱargumentsȱasȱvoid *,ȱwhichȱmeansȱȈaȱpointerȱtoȱsomethingȱwhoseȱtypeȱweȱ
doȱnotȱknow.Ȉȱ
ȱ
Beforeȱusingȱtheȱpointersȱinȱtheȱcomparisonȱfunction,ȱtheyȱmustȱbeȱcastȱtoȱtheȱcorrectȱ
type.ȱBecauseȱaȱcastȱcircumventsȱtheȱusualȱtypeȱchecking,ȱbeȱextremelyȱcarefulȱthatȱtheȱ
functionȱisȱcalledȱwithȱtheȱproperȱtypeȱofȱarguments.ȱ
Inȱ thisȱ case,ȱ theȱ callbackȱ functionȱ comparesȱ twoȱ values.ȱ Theȱ searchȱ functionȱ
passesȱpointersȱtoȱ theȱtwoȱvaluesȱtoȱ beȱ comparedȱandȱchecksȱtheȱreturnedȱvalue;ȱ forȱ
example,ȱzeroȱforȱequalȱvaluesȱandȱnonzeroȱforȱunequalȱvalues.ȱTheȱsearchȱfunctionȱisȱ
nowȱtypelessȱbecauseȱitȱdoesnȇtȱperformȱtheȱactualȱcomparison.ȱItȱisȱtrueȱthatȱtheȱcallerȱ
mustȱnowȱwriteȱtheȱnecessaryȱcomparisonȱfunction,ȱbutȱdoingȱsoȱisȱeasyȱbecauseȱtheȱ
callerȱ knowsȱ whatȱ typeȱ ofȱ valuesȱ areȱ containedȱ inȱ theȱ list.ȱ Andȱ ifȱ severalȱ listsȱ withȱ
differentȱ typesȱ ofȱ valuesȱ areȱ used,ȱ writingȱ oneȱ comparisonȱ functionȱ forȱ eachȱ typeȱ
allowsȱaȱsingleȱsearchȱfunctionȱtoȱoperateȱonȱallȱofȱtheȱlists.ȱ
Programȱ13.1ȱisȱanȱimplementationȱofȱaȱtypelessȱsearchȱfunction.ȱNoteȱthatȱtheȱ
thirdȱparameterȱtoȱtheȱfunctionȱisȱaȱpointerȱtoȱaȱfunction.ȱTheȱfullȱprototypeȱisȱusedȱtoȱ
declareȱ thisȱparameter.ȱ Noteȱalsoȱthatȱ theȱ parameterȱ nodeȱisȱ notȱdeclaredȱ constȱ evenȱ
thoughȱtheȱfunctionȱneverȱmodifiesȱanyȱofȱtheȱnodesȱtoȱwhichȱitȱpoints.ȱIfȱ nodeȱwereȱ
declaredȱ constȱtheȱfunctionȱwouldȱhaveȱtoȱreturnȱaȱ constȱresult,ȱwhichȱwouldȱrestrictȱ
theȱcallerȱfromȱmodifyingȱtheȱnodeȱthatȱwasȱlocated.ȱ
Download at http://www.pin5i.com/
13.3 Pointers to Functions
359
ȱ
/*
** Function to search a linked list for a specific value. Arguments
** are a pointer to the first node in the list, a pointer to the
** value we're looking for, and a pointer to a function that compares
** values of the type stored on the list.
*/
#include <stdio.h>
#include "node.h"
Node *
search_list( Node *node, void const *value,
int (*compare)( void const *, void const * ) )
{
while( node != NULL ){
if( compare( &node->value, value ) == 0 )
break;
node = node->link;
}
return node;
}
ȱ
Programȱ13.1ȱȱTypelessȱlinkedȱlistȱsearchȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱsearch.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Pointersȱtoȱtheȱvalueȱargumentȱandȱ &node->valueȱareȱpassedȱtoȱtheȱcomparisonȱ
function.ȱ Theȱ latterȱ isȱ theȱ valueȱ inȱ theȱ nodeȱ weȱ areȱ currentlyȱ examining.ȱ Iȱ choseȱ theȱ
counterȬintuitiveȱconventionȱofȱhavingȱtheȱcomparisonȱfunctionȱreturnȱzeroȱforȱequalȱ
operandsȱ inȱ orderȱ toȱ beȱ compatibleȱ withȱ theȱ specificationȱ forȱ comparisonȱ functionsȱ
usedȱ byȱ severalȱ functionsȱ inȱ theȱ standardȱ library.ȱ Inȱ thisȱ specification,ȱ unequalȱ
operandsȱ areȱ reportedȱ moreȱ explicitly—aȱ negativeȱ valueȱ indicatesȱ thatȱ theȱ firstȱ
argumentȱwasȱlessȱthanȱtheȱsecond,ȱandȱaȱpositiveȱvalueȱindicatesȱthatȱitȱwasȱgreater.ȱ
Toȱ searchȱ aȱ particularȱ linkedȱ list,ȱ theȱ userȱ wouldȱ writeȱ theȱ appropriateȱ
comparisonȱ functionȱ andȱ passȱ pointersȱ toȱ itȱ andȱ toȱ theȱ desiredȱ value.ȱ Forȱ example,ȱ
hereȱisȱaȱcomparisonȱfunctionȱforȱsearchingȱaȱlistȱofȱintegers.ȱ
ȱ
int
compare_ints( void const *a, void const *b )
{
if( *(int *)a == *(int *)b )
return 0;
else
return 1;
}
Download at http://www.pin5i.com/
Chapter 13 Advanced Pointer Topicsȱ
360ȱ
Theȱfunctionȱwouldȱbeȱusedȱlikeȱthis:ȱ
ȱ
desired_node = search_list( root, &desired_value,
compare_ints );
ȱ
Noteȱtheȱcasts:ȱTheȱargumentsȱtoȱtheȱcomparisonȱfunctionȱmustȱbeȱdeclaredȱ void *ȱtoȱ
matchȱ theȱ prototypeȱ ofȱ theȱ searchȱ function;ȱ theyȱ areȱ thenȱ castȱ toȱ int *ȱ inȱ orderȱ toȱ
compareȱtheȱvaluesȱasȱintegers.ȱ
Ifȱyouȱwishȱtoȱsearchȱaȱlistȱofȱstrings,ȱthisȱcodeȱwillȱdoȱtheȱjob:ȱ
ȱ
#include <string.h>
...
desired_node = search_list( root, "desired_value",
strcmp );
ȱ
Itȱ happensȱ thatȱ theȱ libraryȱ functionȱ strcmpȱ doesȱ exactlyȱ theȱ comparisonȱ weȱ need,ȱ
thoughȱsomeȱcompilersȱwillȱissueȱwarningsȱbecauseȱitsȱargumentsȱareȱdeclaredȱchar *ȱ
ratherȱthanȱvoid *.ȱ
ȱ
ȱ
ȱ
13.3.2
Jump Tables
ȱ
Jumpȱtablesȱareȱbestȱexplainedȱwithȱanȱexample.ȱTheȱfollowingȱcodeȱfragmentȱisȱfromȱ
aȱ programȱ thatȱ implementsȱ aȱ pocketȱ calculator.ȱ Otherȱ partsȱ ofȱ theȱ programȱ haveȱ
alreadyȱreadȱinȱtwoȱnumbersȱ(op1ȱandȱ op2)ȱandȱanȱoperatorȱ(oper).ȱThisȱcodeȱtestsȱtheȱ
operatorȱtoȱdetermineȱwhichȱfunctionȱtoȱinvoke.ȱ
ȱ
switch( oper ){
case ADD:
result = add( op1, op2 );
break;
case SUB:
result = sub( op1, op2 );
break;
case MUL:
result = mul( op1, op2 );
break;
case DIV:
result = div( op1, op2 );
break;
...
Download at http://www.pin5i.com/
13.3 Pointers to Functions
361
Forȱ aȱ fancyȱ calculatorȱ withȱ aȱ hundredȱ orȱ soȱ operators,ȱ thisȱ switchȱ statementȱ willȱ
becomeȱextremelyȱlarge.ȱ
Whyȱareȱfunctionsȱbeingȱcalledȱtoȱperformȱtheseȱoperations?ȱItȱisȱgoodȱdesignȱtoȱ
separateȱ theȱ operationsȱ fromȱ theȱ codeȱ thatȱ choosesȱ amongȱ them.ȱ Theȱ moreȱ complexȱ
operationsȱ willȱ certainlyȱ beȱ implementedȱ asȱ separateȱ functionsȱ becauseȱ ofȱ theirȱ size,ȱ
butȱevenȱtheȱsimpleȱoperationsȱmayȱhaveȱsideȱeffects,ȱsuchȱasȱsavingȱaȱconstantȱvalueȱ
forȱlaterȱoperations.ȱ
Inȱ orderȱ toȱ useȱ aȱ switch,ȱ theȱ codesȱ thatȱ representȱ theȱ operatorsȱ mustȱ beȱ
integers.ȱIfȱtheyȱareȱconsecutiveȱintegersȱstartingȱwithȱzero,ȱweȱcanȱuseȱaȱjumpȱtableȱtoȱ
accomplishȱtheȱsameȱthing.ȱAȱjumpȱtableȱisȱjustȱanȱarrayȱofȱpointersȱtoȱfunctions.ȱ
Thereȱ areȱ twoȱ stepsȱ inȱ creatingȱ aȱ jumpȱ table.ȱ First,ȱ anȱ arrayȱ ofȱ pointersȱ toȱ
functionsȱisȱdeclaredȱandȱinitialized.ȱTheȱonlyȱtrickȱisȱtoȱmakeȱsureȱthatȱtheȱprototypesȱ
forȱtheȱfunctionsȱappearȱbeforeȱtheȱarrayȱdeclaration.ȱ
ȱ
double
double
double
double
...
double
add(
sub(
mul(
div(
double,
double,
double,
double,
double
double
double
double
);
);
);
);
(*oper_func[])( double, double ) = {
add, sub, mul, div, ...
};
ȱ
Theȱproperȱorderȱforȱtheȱfunctionsȇȱnamesȱinȱtheȱinitializerȱlistȱisȱdeterminedȱbyȱ
theȱ integerȱ codesȱ usedȱ toȱ representȱ eachȱ operatorȱ inȱ theȱ program.ȱ Thisȱ exampleȱ
assumesȱthatȱADDȱisȱzero,ȱSUBȱisȱone,ȱMULȱisȱtwo,ȱandȱsoȱforth.ȱ
Theȱsecondȱstepȱisȱtoȱreplaceȱtheȱentireȱswitchȱstatementȱwithȱthisȱone!ȱ
ȱ
result = oper_func[ oper ]( op1, op2 );
CAUTION!
ȱ
operȱselectsȱtheȱcorrectȱpointerȱfromȱtheȱarray,ȱandȱtheȱfunctionȱcallȱoperatorȱexecutesȱ
it.ȱ
ȱ
AnȱoutȬofȬboundsȱsubscriptȱisȱjustȱasȱillegalȱonȱaȱjumpȱtableȱasȱitȱisȱonȱanyȱotherȱarray,ȱ
butȱ itȱ isȱ muchȱ moreȱ difficultȱ toȱ diagnose.ȱ Thereȱ areȱ threeȱ placesȱ whereȱ theȱ programȱ
mightȱterminateȱwhenȱthisȱerrorȱoccurs.ȱFirst,ȱifȱtheȱsubscriptȱvalueȱisȱfarȱenoughȱoutȱ
ofȱbounds,ȱtheȱlocationȱthatȱitȱidentifiesȱmightȱbeȱoutsideȱofȱdieȱmemoryȱallocatedȱtoȱ
theȱ program.ȱ Someȱ operatingȱ systemsȱ detectȱ thisȱ errorȱ andȱ abortȱ theȱ program,ȱ butȱ
othersȱ doȱ not.ȱ Ifȱ theȱ programȱ isȱ terminated,ȱ theȱ faultȱ willȱ beȱ reportedȱ nearȱ theȱ jumpȱ
tableȱstatement,ȱmakingȱtheȱproblemȱfairlyȱeasyȱtoȱdiagnosis.ȱ
Ifȱ theȱ programȱ doesȱ notȱ abort,ȱ theȱ valueȱ identifiedȱ byȱ theȱ illegalȱ subscriptȱ isȱ
fetched,ȱ andȱ theȱ processorȱ jumpsȱ toȱ thatȱ location.ȱ Thisȱ unpredictableȱ valueȱ mayȱ or
Download at http://www.pin5i.com/
362ȱ
TIP
Chapter 13 Advanced Pointer Topicsȱ
ȱmayȱ notȱ representȱ aȱ validȱ addressȱ forȱ theȱ program.ȱ Ifȱ itȱ doesȱ notȱ theȱ programȱ mayȱ
alsoȱ abort,ȱ butȱ theȱ addressȱ reportedȱ forȱ theȱ faultȱ isȱ essentiallyȱ aȱ randomȱ number,ȱ
makingȱdebuggingȱmoreȱdifficult.ȱ
Ifȱtheȱprogramȱhasnȇtȱfailedȱyet,ȱtheȱmachineȱwillȱbeginȱtoȱexecuteȱinstructionsȱ
atȱ theȱ bogusȱ addressȱ obtainedȱ withȱ theȱ illegalȱ subscript,ȱ andȱ debuggingȱ theȱ errorȱ
becomesȱ muchȱ harder.ȱ Ifȱ theȱ randomȱ addressȱ isȱ inȱ anȱ areaȱ inȱ memoryȱ thatȱ containsȱ
data,ȱtheȱprogramȱusuallyȱabortsȱveryȱquicklyȱdueȱtoȱanȱillegalȱinstructionȱorȱanȱillegalȱ
operandȱ addressȱ (althoughȱ dataȱ valuesȱ sometimesȱ representȱ validȱ instructions,ȱ theyȱ
doȱnotȱoftenȱmakeȱanyȱsense).ȱTheȱonlyȱclueȱtoȱhowȱtheȱcomputerȱgotȱwhereȱitȱdidȱisȱ
theȱreturnȱaddressȱstoredȱonȱtheȱstackȱbyȱtheȱfunctionȱcallȱmadeȱinȱtheȱjumpȱtable.ȱIfȱ
anyȱofȱtheȱrandomȱinstructionsȱmodifiedȱtheȱstackȱorȱchangedȱtheȱstackȱpointerȱwhenȱ
theyȱwereȱexecuted,ȱthisȱclueȱisȱlost.ȱ
Worseȱstillȱisȱifȱtheȱrandomȱaddressȱhappensȱtoȱbeȱinȱtheȱmiddleȱofȱaȱfunction.ȱ
Thenȱtheȱfunctionȱexecutesȱmerrilyȱalong,ȱchangingȱwhoȱknowsȱwhatȱdata,ȱuntilȱitȱisȱ
finished.ȱButȱtheȱreturnȱaddressȱisnȇtȱwhereȱtheȱfunctionȱexpectsȱitȱtoȱbeȱonȱtheȱstack,ȱ
soȱanotherȱrandomȱvalueȱisȱusedȱinstead.ȱThisȱvalueȱbecomesȱtheȱaddressȱofȱtheȱnextȱ
instructionȱ toȱ execute,ȱ andȱ theȱ computerȱ goesȱ toȱ aȱ differentȱ randomȱ locationȱ andȱ
continuesȱtoȱexecuteȱwhateverȱitȱfindsȱthere.ȱ
Theȱ problemȱ isȱ thatȱ theȱ instructionsȱ destroyȱ theȱ lastȱ clueȱ asȱ toȱ howȱ theȱ
computerȱgotȱtoȱwhereȱtheȱfaultȱfinallyȱoccurs.ȱWithoutȱthisȱinformation,ȱitȱisȱdifficultȱ
toȱpinpointȱtheȱsourceȱofȱtheȱproblem.ȱIfȱyouȱareȱsuspiciousȱofȱaȱjumpȱtable,ȱthenȱprintȱ
aȱ messageȱ beforeȱ andȱ afterȱ itsȱ functionȱ call.ȱ Itȱ willȱ thenȱ beȱ obviousȱ ifȱ theȱ calledȱ
functionȱ neverȱ returns.ȱ Theȱ trickȱ isȱ toȱ realizeȱ thatȱ aȱ faultȱ inȱ oneȱ partȱ ofȱ theȱ programȱ
mightȱ beȱ causedȱ byȱ anȱ errorȱ inȱ aȱ jumpȱ tableȱ inȱ someȱ distant,ȱ unrelatedȱ partȱ ofȱ theȱ
program.ȱ
ȱ
Itȱisȱmuchȱeasierȱtoȱmakeȱsureȱthatȱtheȱsubscriptȱusedȱinȱaȱjumpȱtableȱisȱwithinȱrangeȱinȱ
theȱ firstȱ place.ȱ Inȱ theȱ calculatorȱ example,ȱ theȱ functionȱ thatȱ readsȱ inȱ theȱ operatorȱ andȱ
convertsȱitȱtoȱitsȱcorrespondingȱintegerȱshouldȱverifyȱthatȱtheȱoperatorȱisȱvalid.ȱ
ȱ
ȱ
ȱ
13.4 Command Line Arguments
ȱ
Processingȱ commandȱ lineȱ argumentsȱ isȱ anotherȱ applicationȱ ofȱ pointersȱ toȱ pointers.ȱȱ
Someȱoperatingȱsystems,ȱincludingȱUNIXȱandȱMSȬDOS,ȱletȱtheȱuserȱwriteȱargumentsȱ
onȱtheȱcommandȱthatȱinitiatesȱtheȱexecutionȱofȱaȱprogram.ȱTheseȱargumentsȱareȱpassedȱ
toȱtheȱprogram,ȱwhichȱcanȱprocessȱthemȱinȱanyȱwayȱitȱseesȱfit.ȱ
ȱ
Download at http://www.pin5i.com/
13.4 Command Line Arguments
363
ȱ
13.4.1
Passing Command Line Arguments
ȱ
Howȱareȱtheseȱargumentsȱpassedȱtoȱtheȱprogram?ȱTheȱ mainȱfunctionȱofȱaȱCȱprogramȱ
hasȱ twoȱ parameters. 44 ȱ Theȱ first,ȱ oftenȱ calledȱ argc,ȱ isȱ aȱ countȱ ofȱ theȱ numberȱ ofȱ
argumentsȱinȱtheȱcommandȱline.ȱTheȱsecond,ȱoftenȱcalledȱ argv,ȱpointsȱtoȱtheȱvaluesȱofȱ
theȱarguments.ȱBecauseȱthereȱisnȇtȱanȱinherentȱlimitȱonȱtheȱnumberȱofȱarguments,ȱ argvȱ
pointsȱtoȱtheȱfirstȱelementȱofȱwhatȱisȱessentiallyȱanȱarray.ȱEachȱofȱtheseȱelementsȱisȱaȱ
pointerȱtoȱtheȱtextȱofȱoneȱargument.ȱIfȱtheȱprogramȱneedsȱtoȱaccessȱtheȱcommandȱlineȱ
arguments,ȱtheȱmainȱfunctionȱisȱdeclaredȱwithȱtheseȱparameters:ȱ
ȱ
int
main( int argc, char **argv )
ȱ
Noteȱthatȱtheȱnamesȱargcȱandȱargvȱareȱfrequentlyȱusedȱbutȱareȱnotȱmagicalȱinȱanyȱway.ȱ
TheyȱcouldȱbeȱcalledȱȈfredȈȱandȱȈgingerȈȱifȱyouȱsoȱdesired,ȱthoughȱtheȱprogramȱwouldȱ
beȱharderȱtoȱread.ȱ
Figureȱ13.1ȱshowsȱhowȱtheȱargumentsȱinȱthisȱcommandȱlineȱwouldȱbeȱpassed:ȱ
ȱ
$cc –c –O main.c insert.c –o test
ȱ
Noteȱtheȱarrayȱofȱpointers:ȱEachȱelementȱofȱthisȱarrayȱisȱaȱpointerȱtoȱaȱcharacter,ȱ
andȱtheȱarrayȱisȱterminatedȱbyȱaȱNULLȱpointer.ȱTheȱvalueȱinȱargcȱandȱthisȱNULLȱmayȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇcȇȱ ȇcȇȱ 0ȱ ȱ
ȇȬȇȱ ȇcȇȱ 0ȱ
ȱ
ȱ ȱ
argcȱ
7ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
argvȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇmȇ
ȇaȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇnȇȱ
ȇsȇȱ ȇeȇȱ ȇrȇȱ
ȇtȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
0ȱ
ȱ
ȱ
ȱ
ȇtȇȱ ȇeȇȱ ȇsȇȱ
ȱ
ȱ
ȱ
ȱ
ȇȬȇȱ ȇOȇ
ȇiȇȱ
ȱ
ȇȬȇȱ
ȇoȇȱ
ȱ
0ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇiȇȱ
ȱ
ȇnȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇ.ȇȱ
ȱ
ȱ
0ȱ
ȱ
ȱ
ȱ
ȇcȇȱ
ȱ
ȱ
0ȱ
ȱ
ȇ.ȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇcȇȱ 0ȱ
ȱ
ȱ
ȱ
ȱ
ȇtȇȱ
0ȱ
ȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
ȱ Actually,ȱ someȱ operatingȱ systemsȱ alsoȱ passȱ aȱ thirdȱ parameterȱ toȱ theȱ mainȱ function,ȱ aȱ pointerȱ toȱ aȱ listȱ ofȱ environmentȱ
variablesȱandȱtheirȱvalues.ȱConsultȱyourȱcompilerȇsȱorȱoperatingȱsystemȇsȱdocumentationȱforȱdetails.ȱ
44
Download at http://www.pin5i.com/
364ȱ
Chapter 13 Advanced Pointer Topicsȱ
ȱbothȱbeȱusedȱtoȱdetermineȱhowȱmanyȱargumentsȱwereȱpassed,ȱ argvȱpointsȱtoȱtheȱfirstȱ
elementȱ ofȱ thisȱ array,ȱ whichȱ isȱ whyȱ itȱ isȱ declaredȱ asȱ aȱ pointerȱ toȱ aȱ pointerȱ toȱ aȱ
character.ȱ
Oneȱ lastȱ thingȱ toȱ observeȱ isȱ thatȱ theȱ veryȱ firstȱ argumentȱ isȱ theȱ nameȱ ofȱ theȱ
program.ȱWhatȱ isȱ theȱ purposeȱofȱpassingȱ theȱprogramȱnameȱ asȱanȱ argument?ȱSurelyȱ
theȱprogramȱknowsȱwhatȱitȱis.ȱUsuallyȱthisȱargumentȱisȱignored,ȱbutȱitȱcanȱbeȱusefulȱ
forȱprogramsȱthatȱareȱcommonlyȱinvokedȱwithȱdifferentȱsetsȱofȱoptions.ȱTheȱUNIXȱ lsȱ
command,ȱ whichȱ listsȱ theȱ filesȱ inȱ aȱ directory,ȱ isȱ suchȱ aȱ program.ȱ Onȱ manyȱ UNIXȱ
systems,ȱtheȱcommandȱhasȱseveralȱdifferentȱnames.ȱWhenȱinvokedȱwithȱtheȱnameȱ ls,ȱ
itȱ producesȱ aȱ briefȱ listingȱ ofȱ files.ȱ Whenȱ invokedȱ withȱ theȱ nameȱ l,ȱ itȱ producesȱ aȱ
multicolumnȱ briefȱ listing,ȱ andȱ theȱ nameȱ l1ȱ producesȱ aȱ detailedȱ listing.ȱ Theȱ programȱ
examinesȱ theȱ firstȱ argumentȱ toȱ determineȱ whichȱ nameȱ wasȱ usedȱ toȱ invokeȱ itȱ andȱ
selectsȱoptionsȱbasedȱonȱtheȱname.ȱ
Onȱsomeȱsystems,ȱtheȱargumentȱstringsȱareȱstoredȱoneȱrightȱafterȱtheȱother,ȱsoȱ
advancingȱaȱpointerȱtoȱtheȱfirstȱargumentȱpastȱtheȱendȱofȱtheȱstringȱwillȱtakeȱyouȱtoȱtheȱ
beginningȱofȱtheȱnextȱone.ȱThisȱarrangementȱisȱimplementationȱdependent,ȱthough,ȱsoȱ
youȱ mustȱ notȱ dependȱ uponȱ it.ȱ Toȱ findȱ theȱ beginningȱ ofȱ anȱ argument,ȱ useȱ theȱ
appropriateȱpointerȱfromȱtheȱarray.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** A program to print its command line arguments.
*/
#include <stdio.h>
#include <stdlib.h>
int
main( int argc, char **argv )
{
/*
** Print arguments until a NULL pointer is reached (argc is
** not used). The program name is skipped.
*/
while( *++argv != NULL )
printf( "%s\n", *argv );
return EXIT_SUCCESS;
}
ȱ
Porgramȱ13.2ȱȱPrintȱcommandȱlineȱargumentsȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱȱȱȱecho.cȱ
Download at http://www.pin5i.com/
13.4 Command Line Arguments
365
Howȱ doesȱ aȱ programȱ accessȱ theseȱ arguments?ȱ Programȱ 13.2ȱ isȱ aȱ veryȱ simpleȱ
example—itȱ simplyȱ printsȱ outȱ allȱ ofȱ itsȱ argumentsȱ (exceptȱ forȱ theȱ programȱ name)ȱ
muchȱlikeȱtheȱUNIXȱechoȱcommand.ȱ
Theȱ whileȱloopȱincrementsȱ argvȱandȱthenȱchecksȱ *argvȱtoȱseeȱifȱtheȱendȱofȱtheȱ
argumentȱlistȱhasȱbeenȱreached.ȱItȱisȱlookingȱforȱtheȱNULLȱthatȱterminatesȱtheȱlist.ȱIfȱ
thereȱ isȱ anotherȱ argument,ȱ theȱ bodyȱ ofȱ theȱ loopȱ isȱ executedȱ andȱ printsȱ it.ȱ Byȱ
incrementingȱargvȱfirstȱinȱtheȱloop,ȱtheȱprogramȱnameȱisȱautomaticallyȱskipped.ȱ
Theȱ %sȱcodeȱusedȱinȱtheȱformatȱstringȱofȱ printfȱrequiresȱanȱargumentȱthatȱisȱaȱ
pointerȱtoȱcharacter.ȱ printfȱassumesȱthatȱthisȱcharacterȱisȱtheȱfirstȱofȱNULȬterminatedȱ
string.ȱApplyingȱindirectionȱonȱ argvȱyieldsȱtheȱvalueȱtoȱwhichȱitȱpoints,ȱaȱpointerȱtoȱaȱ
characterȱ–ȱjustȱwhatȱtheȱformatȱrequires.ȱ
ȱ
ȱ
ȱ
13.4.2
Processing Command Line Arguments
ȱ
Letȇsȱwriteȱaȱprogramȱthatȱprocessesȱcommandȱlineȱargumentsȱmoreȱrealistically.ȱThisȱ
programȱ willȱ handleȱ aȱ veryȱ commonȱ paradigm—optionȱ argumentsȱ followedȱ byȱ fileȱ
nameȱ arguments.ȱ Afterȱ theȱ programȱ name,ȱ thereȱ mayȱ beȱ zeroȱ orȱ moreȱ options,ȱ
followedȱbyȱzeroȱorȱmoreȱfileȱnames,ȱlikeȱthis:ȱ
ȱ
prog –a –b –c name1 name2 name3
ȱ
Eachȱ optionȱ argumentȱ isȱ aȱ dashȱ followedȱ byȱ aȱ singleȱ letterȱ thatȱ identifiesȱ whichȱ ofȱ
severalȱpossibleȱoptionsȱisȱdesired.ȱEachȱfileȱnameȱargumentȱisȱprocessedȱinȱsomeȱway.ȱȱ
Ifȱthereȱareȱnoȱfileȱnames,ȱtheȱstandardȱinputȱisȱprocessedȱinstead.ȱ
Toȱ makeȱ theseȱ examplesȱ generic,ȱ ourȱ programȱ setsȱ variablesȱ toȱ rememberȱ
whichȱ optionsȱ wereȱ found.ȱ Otherȱ partsȱ ofȱ aȱ realȱ programȱ mightȱ thenȱ testȱ theseȱ
variablesȱ toȱ determineȱ whatȱ processingȱ wasȱ requested.ȱ Inȱ aȱ realȱ program,ȱ theȱ
processingȱrequiredȱforȱanȱoptionȱmightȱalsoȱbeȱdoneȱwhenȱtheȱoptionȱisȱdiscoveredȱinȱ
theȱarguments.ȱ
Download at http://www.pin5i.com/
366ȱ
Chapter 13 Advanced Pointer Topicsȱ
ȱ
/*
** Process command-line arguments
*/
#include <stdio.h>
#define
TRUE 1
/*
**
*/
void
void
/*
**
*/
int
Prototypes for functions that do the real work.
process_standard_input( void );
process_file( char *file_name );
Option flags, default initialization is FALSE.
option_a, option_b /* etc. */ ;
void
main( int argc, char **argv )
{
/*
** Process option arguments: skip to next argument, and
** check that it begins with a dash.
*/
while( *++argv != NULL && **argv == '-' ){
/*
** Check the letter after the dash.
*/
switch( *++*argv ){
case 'a':
option_a = TRUE;
break;
case 'b':
option_b = TRUE;
break;
/* etc. */
}
}
/*
** Process file name arguments
*/
if( *argv == NULL )
process_standard_input();
else {
do {
process_file( *argv );
} while( *++argv != NULL );
}
}
ȱ
Programȱ13.3ȱȱProcessingȱcommandȱlineȱargumentsȱȱ ȱ
ȱ
ȱ
ȱ
ȱcmd_line.cȱ
Download at http://www.pin5i.com/
13.4 Command Line Arguments
367
ȱ
Programȱ 13.3ȱ resemblesȱ Programȱ 13.2ȱ becauseȱ itȱ containsȱ aȱ loopȱ thatȱ goesȱ
throughȱ allȱ ofȱ theȱ arguments.ȱ Theȱ mainȱ differenceȱ isȱ thatȱ weȱ mustȱ nowȱ distinguishȱ
betweenȱoptionȱargumentsȱandȱtileȱnameȱarguments.ȱTheȱloopȱstopsȱwhenȱitȱreachesȱ
anȱargumentȱthatȱdoesȱnotȱbeginȱwithȱaȱdash.ȱAȱsecondȱloopȱprocessesȱtheȱfileȱnames.ȱ
NoticeȱtheȱtestȱthatȱwasȱaddedȱtoȱtheȱwhileȱloopȱinȱProgramȱ13.3:ȱ
ȱ
**argv == '-'
ȱ
Theȱ doubleȱ indirectionȱ accessesȱ theȱ firstȱ characterȱ ofȱ theȱ argument,ȱ asȱ illustratedȱ inȱ
Figureȱ13.2.ȱIfȱthisȱcharacterȱisȱnotȱaȱdashȱthenȱthereȱarenȇtȱanyȱmoreȱoptionsȱandȱtheȱ
loopȱbreaks.ȱNoteȱthatȱitȱisȱimportantȱtoȱtestȱ *argvȱbeforeȱtestingȱ **argv.ȱIfȱ *argvȱwereȱ
NULL,ȱtheȱsecondȱindirectionȱinȱ**argvȱwouldȱbeȱillegal.ȱ
Theȱ *++*argvȱ expressionȱ inȱ theȱ switchȱ statementȱ isȱ oneȱ youȱ haveȱ seenȱ before.ȱȱ
Theȱfirstȱindirectionȱgoesȱtoȱwhereȱ argvȱpoints,ȱandȱthisȱlocationȱisȱincremented.ȱTheȱ
lastȱ indirectionȱ followsȱ theȱ incrementedȱ pointer,ȱ asȱ diagrammedȱ inȱ Figureȱ 13.3.ȱ Theȱ
switchȱstatementȱsetsȱaȱvariableȱdependingȱonȱwhichȱoptionȱletterȱwasȱfound,ȱandȱtheȱ
++ȱinȱtileȱ whileȱloopȱadvancesȱ argvȱtoȱtheȱnextȱargumentȱforȱtheȱnextȱiterationȱofȱtheȱ
loop.ȱ
Whenȱ thereȱ arenȇtȱ anyȱ moreȱ options,ȱ theȱ fileȱ namesȱ areȱ handled.ȱ Ifȱ argvȱ isȱ
pointingȱtoȱtheȱnull,ȱthereȱarenȇtȱanyȱandȱtheȱstandardȱinputȱisȱprocessed.ȱOtherwise,ȱ
eachȱnameȱisȱprocessedȱoneȱbyȱone.ȱTheȱfunctionȱcallsȱinȱthisȱprogramȱareȱgenericȱsoȱ
theyȱdonȇtȱshowȱanyȱofȱtheȱworkȱthatȱaȱrealȱprogramȱmightȱperform.ȱNevertheless,ȱthisȱ
designȱ isȱ good.ȱ Theȱ mainȱ programȱ dealsȱ withȱ theȱ argumentsȱ soȱ thatȱ theȱ functionsȱ
doingȱ theȱ processingȱ donȇtȱ haveȱ toȱ worryȱ aboutȱ parsingȱ optionsȱ orȱ loopingȱ throughȱ
fileȱnames.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇpȇȱ ȇrȇȱ ȇoȇȱ ȇgȇȱ 0ȱ
ȱ
ȱ ȇȬȇȱ ȇaȇȱ 0ȱ
argcȱ
7ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
argvȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇnȇȱ ȇaȇȱ ȇmȇ
ȇeȇȱ ȇ1ȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇnȇȱ ȇaȇȱ ȇmȇ
ȇeȇȱ ȇ2ȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
0ȱ
ȱ
ȱ
ȇnȇȱ ȇaȇȱ ȇmȇ
ȱ
ȱ
Figureȱ13.2ȱȱAccessingȱtheȱargumentȱ
ȱ
ȱ
ȇȬȇȱ
ȱ
ȇbȇȱ
ȱ
ȱ
ȱ
0ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇȬȇȱ
ȇcȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇeȇȱ ȇ3ȇȱ
ȱ
ȱ
0ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
0ȱ
0ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
0ȱ
ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
Chapter 13 Advanced Pointer Topicsȱ
368ȱ
ȱ
argcȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇpȇȱ
ȇrȇȱ
ȇoȇȱ ȇgȇȱ
7ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
argvȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇnȇȱ ȇaȇȱ ȇmȇ
ȇeȇȱ ȇ1ȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇnȇȱ ȇaȇȱ ȇmȇ
ȇeȇȱ ȇ2ȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
0ȱ
ȱ
ȱ
ȇnȇȱ ȇaȇȱ ȇmȇ
ȱ
ȇȬȇȱ
ȇbȇȱ
ȱ
ȱ
ȱ
0ȱ
ȱ
ȱ
ȱ
0ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇȬȇȱ
ȇcȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȇeȇȱ ȇ3ȇȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
0ȱ
0ȱ
ȱ
ȱ
0ȱ
ȱ
ȇaȇȱ 0ȱ
0ȱ
ȱ
ȱ
ȇȬȇȱ
ȱ
ȱ
Figureȱ13.3ȱȱAccessingȱtheȱnextȱcharacterȱinȱtheȱargumentȱ
ȱ
ȱ
ȱ
Someȱprogramsȱallowȱtheȱuserȱtoȱputȱmultipleȱoptionȱlettersȱinȱoneȱargument,ȱ
likeȱthis:ȱ
ȱ
prog –abc name1 name2 name3
ȱ
Atȱ firstȱ youȱ mightȱ thinkȱ thatȱ thisȱ changeȱ willȱ complicateȱ ourȱ program,ȱ butȱ itȱ
turnsȱ outȱ toȱ beȱ fairlyȱ easyȱ toȱ process.ȱ Eachȱ argumentȱ mayȱ nowȱ containȱ multipleȱ
options,ȱsoȱweȱ useȱ anotherȱ loopȱ toȱ processȱthem.ȱ Theȱloopȱshouldȱterminateȱ whenȱitȱ
encountersȱtheȱtrailingȱNULȱbyteȱatȱtheȱendȱofȱtheȱargument.ȱ
Theȱ switchȱ statementȱ inȱ Programȱ 13.3ȱ isȱ replacedȱ byȱ theȱ followingȱ codeȱ
fragment:ȱ
ȱ
while( ( opt = *++*argv ) != '\0' ){
switch( opt ){
case 'a':
option_a = TRUE;
break;
/* etc. */
}
}
ȱ
Theȱtestȱinȱtheȱloopȱadvancesȱtheȱargumentȱpointerȱbeyondȱtheȱdashȱandȱmakesȱaȱcopyȱ
ofȱ theȱ characterȱ foundȱ there.ȱ Ifȱ thisȱ characterȱ isȱ notȱ dieȱ NULȱ byte,ȱ thenȱ theȱ switchȱ
statementȱ isȱ usedȱ asȱ beforeȱ toȱ setȱ theȱ appropriateȱ variable.ȱ Noteȱ thatȱ theȱ optionȱ
characterȱ isȱ savedȱ inȱ aȱ localȱ variableȱ optȱ toȱ avoidȱ havingȱ toȱ evaluateȱ **argvȱ inȱ theȱ
switchȱstatement.ȱ
Download at http://www.pin5i.com/
13.5 String Literals
TIP
369
Beȱ awareȱ thatȱ theȱ commandȱ lineȱ argumentsȱ mayȱ onlyȱ beȱ processedȱ onceȱ inȱ thisȱ
mannerȱbecauseȱtheȱpointersȱtoȱtheȱargumentsȱareȱdestroyedȱbyȱtheȱinnerȱloop.ȱIfȱtheȱ
argumentsȱmustȱbeȱprocessedȱmoreȱthanȱonce,ȱmakeȱaȱcopyȱofȱeachȱpointerȱthatȱyouȱ
mustȱincrementȱasȱyouȱgoȱthroughȱtheȱlist.ȱ
Thereȱ areȱ otherȱ possibilitiesȱ forȱ processingȱ options.ȱ Forȱ example,ȱ theȱ optionsȱ
mightȱ beȱ wordsȱ ratherȱ thanȱ singleȱ letters,ȱ orȱ thereȱ mightȱ beȱ valuesȱ associatedȱ withȱ
someȱoptions,ȱasȱinȱthisȱexample:ȱ
ȱ
cc –o prog prog.c
ȱ
Oneȱofȱtheȱchapterȱproblemsȱexpandsȱonȱthisȱidea.ȱ
ȱ
ȱ
ȱ
13.5 String Literals
ȱ
Itȱisȱtimeȱtoȱtakeȱaȱcloserȱlookȱatȱaȱtopicȱmentionedȱearlier:ȱstringȱliterals.ȱWhenȱaȱstringȱ
literalȱappearsȱinȱanȱexpression,ȱitsȱvalueȱisȱaȱpointerȱconstant.ȱTheȱcompilerȱstoresȱaȱ
copyȱofȱtheȱspecifiedȱcharactersȱsomewhereȱinȱmemory,ȱandȱtheȱpointerȱpointsȱtoȱtheȱ
firstȱ ofȱ theseȱ characters.ȱ Butȱ whenȱ arrayȱ namesȱ areȱ usedȱ inȱ expressions,ȱ theirȱ valuesȱ
areȱ alsoȱ pointerȱ constants.ȱ Weȱ canȱ performȱ subscripting,ȱ indirection,ȱ andȱ pointerȱ
arithmeticȱonȱthem.ȱAreȱtheseȱoperationsȱmeaningfulȱonȱstringȱliterals,ȱtoo?ȱLetȇsȱlookȱ
atȱsome.ȱ
Whatȱisȱtheȱmeaningȱofȱthisȱexpression?ȱ
ȱ
"xyz" + 1
ȱ
Toȱmostȱprogrammers,ȱitȱlooksȱlikeȱgibberish.ȱItȱappearsȱtoȱbeȱtryingȱtoȱperformȱsomeȱ
kindȱofȱadditionȱonȱaȱstring.ȱButȱwhenȱyouȱrememberȱthatȱtheȱstringȱliteralȱisȱaȱpointer,ȱ
theȱ meaningȱ becomesȱ clear.ȱ Thisȱ expressionȱ computesȱ theȱ sumȱ ofȱ theȱ pointerȱ valueȱ
plusȱone.ȱTheȱresultȱisȱaȱpointerȱtoȱtheȱsecondȱcharacterȱinȱtheȱliteral:ȱy.ȱ
Howȱaboutȱthisȱexpression?ȱ
ȱ
*"xyz"
ȱ
Whenȱindirectionȱisȱappliedȱtoȱaȱpointer,ȱtheȱresultȱisȱtheȱthingȱtoȱwhichȱitȱpoints.ȱTheȱ
typeȱ ofȱ aȱ stringȱ literalȱ isȱ Ȉpointerȱ toȱ character,Ȉȱ soȱ theȱ resultȱ ofȱ theȱ indirectionȱ isȱ theȱ
characterȱtoȱwhichȱitȱpoints:ȱ x.ȱNoteȱthatȱtheȱresultȱisȱnotȱtheȱentireȱstring,ȱjustȱtheȱfirstȱ
character.ȱ
Thisȱnextȱexampleȱalsoȱlooksȱstrange,ȱbutȱbyȱnowȱyouȱshouldȱbeȱableȱtoȱfigureȱ
outȱthatȱtheȱvalueȱofȱthisȱexpressionȱisȱtheȱcharacterȱz.ȱ
ȱ
"xyz"[2]
Download at http://www.pin5i.com/
370ȱ
Chapter 13 Advanced Pointer Topicsȱ
Theȱ lastȱ exampleȱ containsȱ anȱ error.ȱ Theȱ offsetȱ ofȱ fourȱ goesȱ offȱ theȱ endȱ ofȱ theȱ
string,ȱsoȱtheȱresultȱisȱanȱunpredictableȱcharacter.ȱ
ȱ
*( "xyz" + 4 )
ȱ
Whenȱ wouldȱ anyoneȱ everȱ wantȱ toȱ useȱ expressionsȱ likeȱ these?ȱ Theȱ functionȱ inȱ
Programȱ 13.4ȱ isȱ oneȱ usefulȱ example.ȱ Canȱ youȱ figureȱ outȱ whatȱ thisȱ mysteryȱ functionȱ
does?ȱ Hereȱ isȱ aȱ hint:ȱ Traceȱ theȱ functionȱ withȱ severalȱ differentȱ inputȱ valuesȱ andȱ seeȱ
whatȱisȱprinted.ȱTheȱanswerȱisȱgivenȱatȱtheȱendȱofȱtheȱchapter.ȱ
Inȱ theȱ meantime,ȱ letȇsȱ lookȱ atȱ anotherȱ example.ȱ Programȱ 13.5ȱ containsȱ aȱ
functionȱthatȱconvertsȱbinaryȱvaluesȱtoȱcharactersȱandȱprintsȱthem.ȱYouȱfirstȱsawȱthisȱ
functionȱ asȱ Programȱ 7.6.ȱ Forȱ thisȱ example,ȱ weȇllȱ modifyȱ itȱ toȱ printȱ valuesȱ inȱ
hexadecimal.ȱ Theȱ firstȱ changeȱ isȱ easy:ȱ justȱ divideȱ byȱ 16ȱ insteadȱ ofȱ 10.ȱ Butȱ nowȱ theȱ
remainderȱ mightȱ beȱ anyȱ valueȱ fromȱ 0ȱ toȱ 15,ȱ andȱ theȱ valuesȱ fromȱ 10ȱ toȱ 15ȱ shouldȱ beȱ
printedȱ asȱ theȱ lettersȱ Aȱ toȱ F.ȱ Theȱ followingȱ codeȱ isȱ aȱ typicalȱ approachȱ toȱ thisȱ newȱ
problem.ȱ
ȱ
remainder = value % 16;
if( remainder < 10 )
putchar( remainder + '0' );
else
putchar( remainder – 10 + 'A' );
ȱ
Iȇveȱusedȱaȱlocalȱvariableȱtoȱsaveȱtheȱremainderȱratherȱthanȱcomputingȱitȱthreeȱseparateȱ
times.ȱForȱremaindersȱinȱtheȱrangeȱ0ȱthroughȱ9,ȱaȱdigitȱisȱprintedȱtheȱsameȱasȱbefore.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Mystery function
**
**
The argument is a value in the range 0 through 100.
*/
#include <stdio.h>
void
mystery( int n )
{
n += 5;
n /= 10;
printf( "%s\n", "**********" + 10 - n );
}
ȱ
Programȱ13.4ȱȱȱMysteryȱfunctionȱȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱmystery.cȱ
Download at http://www.pin5i.com/
13.5 String Literals
371
ȱ
/*
** Take an integer value (unsigned), convert it to characters, and
** print it. Leading zeros are suppressed.
*/
#include <stdio.h>
void
binary_to_ascii( unsigned int value )
{
unsigned int
quotient;
quotient = value / 10;
if( quotient != 0 )
binary_to_ascii( quotient );
putchar( value % 10 + '0' );
}
ȱ
Programȱ13.5ȱȱȱConvertȱaȱbinaryȱintegerȱtoȱcharactersȱ ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱȱȱȱȱbtoa.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ButȱtheȱotherȱremaindersȱareȱprintedȱasȱlettersȬȱTheȱtestȱisȱneededȱbecauseȱtheȱlettersȱAȱ
throughȱFȱdoȱnotȱimmediatelyȱfollowȱtheȱdigitsȱinȱanyȱcommonȱcharacterȱset.ȱ
Theȱfollowingȱcodeȱsolvesȱtheȱproblemȱinȱaȱdifferentȱway.ȱ
ȱ
putchar( "0123456789ABCDEF"[ value % 16 ] );
TIP
ȱ
Onceȱagainȱtheȱremainderȱwillȱbeȱaȱvalueȱinȱtheȱrangeȱofȱ0ȱthroughȱ15,ȱbutȱthisȱtimeȱitȱ
isȱusedȱasȱaȱsubscriptȱtoȱselectȱoneȱofȱtheȱcharactersȱfromȱtheȱstringȱliteralȱtoȱprint.ȱTheȱ
previousȱ codeȱ isȱ complicatedȱ becauseȱ theȱ lettersȱ andȱ digitsȱ areȱ notȱ adjacentȱ inȱ theȱ
characterȱset.ȱThisȱsolutionȱavoidsȱtheȱcomplicationȱbyȱdefiningȱaȱstringȱinȱwhichȱtheyȱ
areȱadjacent.ȱTheȱremainderȱselectsȱtheȱrightȱdigitȱfromȱthisȱstring.ȱ
Thisȱ secondȱ approachȱ isȱ fasterȱ thanȱ theȱ traditionalȱ one,ȱ becauseȱ fewerȱ
operationsȱ areȱ needed.ȱ Theȱ codeȱ mayȱ orȱ mayȱ notȱ beȱ smallerȱ thanȱ theȱ original,ȱ
however.ȱ Theȱ decreaseȱ inȱ instructionsȱ isȱ offsetȱ byȱ theȱ additionȱ ofȱ theȱ 17Ȭbyteȱ stringȱ
literal.ȱ
ȱ
However,ȱaȱlargeȱreductionȱinȱreadabilityȱisȱaȱbigȱpriceȱtoȱpayȱforȱaȱsmallȱimprovementȱ
inȱexecutionȱspeed.ȱWhenȱyouȱuseȱanȱunusualȱtechniqueȱorȱstatement,ȱbeȱsureȱthatȱyouȱ
includeȱaȱcommentȱdescribingȱhowȱitȱworks.ȱOnceȱthisȱexampleȱhasȱbeenȱexplained,ȱitȱ
isȱactuallyȱeasierȱtoȱfollowȱthanȱtheȱtraditionalȱcodeȱbecauseȱitȱisȱshorter.ȱ
Download at http://www.pin5i.com/
372ȱ
Chapter 13 Advanced Pointer Topicsȱ
Nowȱbackȱtoȱtheȱmysteryȱfunction.ȱDidȱyouȱfigureȱitȱout?ȱItȱprintsȱaȱnumberȱofȱ
starsȱproportionalȱtoȱtheȱvalueȱofȱtheȱargument.ȱItȱprintsȱ0ȱstarsȱifȱtheȱargumentȱwasȱ0,ȱ
10ȱstarsȱifȱtheȱargumentȱwasȱ100,ȱandȱanȱintermediateȱnumberȱofȱstarsȱforȱintermediateȱ
values.ȱInȱotherȱwords,ȱthisȱfunctionȱprintsȱoneȱbarȱofȱaȱhistogram,ȱandȱitȱdoesȱitȱmuchȱ
moreȱeasilyȱandȱefficientlyȱthanȱtheȱmoreȱtraditionalȱloop.ȱ
ȱ
ȱ
ȱ
13.6 Summary
ȱ
Ifȱdeclaredȱproperly,ȱaȱpointerȱvariableȱmayȱpointȱtoȱanotherȱpointerȱvariable.ȱLikeȱanyȱ
otherȱpointerȱvariable,ȱaȱpointerȱtoȱaȱpointerȱmustȱbeȱinitializedȱbeforeȱitȱcanȱbeȱused.ȱ
Twoȱ indirectionȱ operationsȱ areȱ neededȱ onȱ aȱ pointerȱ toȱ aȱ pointerȱ toȱ obtainȱ theȱ targetȱ
object.ȱMoreȱlevelsȱofȱindirectionȱareȱallowedȱ(forȱexample,ȱaȱpointerȱtoȱaȱpointerȱtoȱaȱ
pointerȱ toȱ an int),ȱ butȱ areȱ neededȱ lessȱ oftenȱ thanȱ simplerȱ pointers.ȱ Youȱ mayȱ alsoȱ
createȱ pointerȱ variablesȱ thatȱ pointȱ toȱ functionsȱ andȱ arrays,ȱ andȱ createȱ arraysȱ ofȱ suchȱ
pointers.ȱ
DeclarationsȱinȱCȱareȱbyȱinference.ȱTheȱdeclarationȱ
ȱ
int
*a;
ȱ
declaresȱtheȱexpressionȱ*aȱtoȱbeȱanȱinteger.ȱYouȱmustȱthenȱinferȱthatȱaȱisȱaȱpointerȱtoȱanȱ
integer.ȱWithȱdeclarationȱbyȱinference,ȱtheȱrulesȱforȱreadingȱdeclarationsȱareȱȱtheȱsameȱ
asȱthoseȱforȱreadingȱexpressions.ȱ
Youȱcanȱuseȱpointersȱtoȱfunctionsȱtoȱimplementȱcallbackȱfunctions.ȱAȱpointerȱtoȱ
yourȱcallbackȱfunctionȱisȱpassedȱasȱanȱargumentȱtoȱanotherȱfunction,ȱwhichȱcallsȱyourȱ
functionȱusingȱtheȱpointer.ȱWithȱthisȱtechnique,ȱyouȱcanȱcreateȱgenericȱfunctionsȱthatȱ
performȱcommonȱoperationsȱsuchȱasȱsearchingȱaȱlinkedȱlist.ȱAnyȱworkȱthatȱisȱspecificȱ
toȱoneȱinstanceȱofȱtheȱproblem,ȱsuchȱasȱcomparingȱvaluesȱinȱtheȱlist,ȱisȱperformedȱinȱaȱ
callbackȱfunctionȱsuppliedȱbyȱtheȱclient.ȱ
Jumpȱ tablesȱ alsoȱ useȱ pointersȱ toȱ functions.ȱ Aȱ jumpȱ tableȱ performsȱ aȱ selectionȱ
muchȱ likeȱ aȱ switchȱ statement.ȱ Theȱ tableȱ consistsȱ ofȱ anȱ arrayȱ ofȱ pointersȱ toȱ functionsȱ
(whichȱmustȱhaveȱidenticalȱprototypes).ȱOneȱpointerȱisȱselectedȱwithȱaȱsubscript,ȱandȱ
theȱ correspondingȱ functionȱ isȱ called.ȱ Alwaysȱ verifyȱ thatȱ theȱ subscriptȱ valueȱ isȱ inȱ theȱ
properȱrange,ȱbecauseȱdebuggingȱerrorsȱinȱjumpȱtablesȱisȱdifficult.ȱ
Ifȱ anȱ executionȱ environmentȱ implementsȱ commandȱ lineȱ arguments,ȱ theȱ
argumentsȱareȱpassedȱtoȱtheȱmainȱfunctionȱviaȱtwoȱparameters,ȱoftenȱcalledȱ argcȱandȱ
argv. argcȱisȱanȱintegerȱandȱcontainsȱaȱcountȱofȱtheȱnumberȱofȱarguments. argvȱisȱaȱ
pointerȱtoȱaȱsequenceȱofȱpointersȱtoȱcharacters.ȱEachȱpointerȱinȱtheȱsequenceȱpointsȱtoȱaȱ
commandȱlineȱargument.ȱTheȱsequenceȱisȱterminatedȱwithȱaȱNULLȱpointer.ȱTheȱfirstȱ
ȱ
Download at http://www.pin5i.com/
13.9 Questions
373
argumentȱ isȱ theȱ nameȱ ofȱ theȱ program.ȱ Aȱ programȱ canȱ accessȱ itsȱ commandȱ lineȱ
argumentsȱbyȱusingȱindirectionȱonȱargv.ȱ
Theȱvalueȱofȱaȱstringȱliteralȱthatȱappearsȱinȱanȱexpressionȱisȱaȱconstantȱpointerȱtoȱ
theȱfirstȱcharacterȱinȱtheȱliteral.ȱLikeȱarrayȱnames,ȱyouȱcanȱuseȱstringȱliteralsȱinȱpointerȱ
expressionsȱandȱwithȱsubscripts.ȱ
ȱ
ȱ
ȱ
13.7 Summary of Cautions
ȱ
1. Applyingȱindirectionȱtoȱanȱuninitializedȱpointerȱ(pageȱ356).ȱ
2. UsingȱanȱoutȬofȬboundsȱsubscriptȱinȱaȱjumpȱtableȱ(pageȱ361).ȱ
ȱ
ȱ
ȱ
13.8 Summary of Programming Tips
ȱ
1. Avoidȱusingȱmoreȱlevelsȱofȱindirectionȱthanȱnecessaryȱ(pageȱ353).ȱ
2. Theȱcdec1ȱprogramȱisȱhelpfulȱforȱdecipheringȱcomplicatedȱdeclarationsȱ(pageȱ355).ȱ
3. Beȱcarefulȱwhenȱcastingȱfromȱvoid *ȱtoȱotherȱpointerȱtypesȱ(pageȱ358).ȱ
4. Alwaysȱvalidateȱtheȱsubscriptȱusedȱinȱaȱjumpȱtableȱ(pageȱ362).ȱ
5. Destructivelyȱ processingȱ commandȱ lineȱ argumentsȱ preventsȱ themȱ fromȱ beingȱ
processedȱagainȱlaterȱ(pageȱ369).ȱ
6. Unusualȱ codeȱ shouldȱ alwaysȱ beȱ accompaniedȱ byȱ aȱ commentȱ describingȱ whatȱ itȱ
doesȱandȱhowȱitȱworksȱ(pageȱ371).ȱ
ȱ
ȱ
ȱ
13.9 Questions
ȱ
1. Aȱlistȱofȱdeclarationsȱisȱshownȱbelow.ȱ
a. int
abc();ȱ
b. int
abc[3];ȱ
c. int
**abc();ȱ
d. int
(*abc)();ȱ
e. int
(*abc)[6];ȱ
Download at http://www.pin5i.com/
374ȱ
Chapter 13 Advanced Pointer Topicsȱ
f. int
*abc();ȱ
g. int
**(*abc[5])();ȱ
h. int
*abc[6];ȱ
i. int
*(*abc)[6];ȱ
j.
*(*abc())();ȱ
int
k. int
(**(*abc)())();ȱ
l. int
(*(*abc)())[6];ȱ
m. int
*(*(*(*abc)())[6])();ȱ
Matchȱeachȱofȱtheȱdeclarationsȱwithȱtheȱbestȱdescriptionȱfromȱthisȱlist.ȱ
I.
Pointerȱtoȱanȱint.ȱ
II.
Pointerȱtoȱaȱpointerȱtoȱanȱint.ȱ
III.
Arrayȱofȱint.ȱ
IV.
Pointerȱtoȱarrayȱofȱint.ȱ
V.
Arrayȱofȱpointerȱtoȱint.ȱ
VI.
Pointerȱtoȱarrayȱofȱpointerȱtoȱint.ȱ
VII.
Arrayȱofȱpointerȱtoȱpointerȱtoȱint.ȱ
VIII.
Functionȱreturningȱint.ȱ
IX.
Functionȱreturningȱpointerȱtoȱint.ȱ
X.
Functionȱreturningȱpointerȱtoȱpointerȱtoȱint.ȱ
XI.
Pointerȱtoȱfunctionȱreturningȱint.ȱ
XII.
Pointerȱtoȱfunctionȱreturningȱpointerȱtoȱint.ȱ
XIII.
Pointerȱtoȱfunctionȱreturningȱpointerȱtoȱpointerȱtoȱint.ȱ
XIV.
Arrayȱofȱpointerȱtoȱfunctionȱreturningȱint.ȱ
XV.
Arrayȱofȱpointerȱtoȱfunctionȱreturningȱpointerȱtoȱint.ȱ
XVI.
Arrayȱofȱpointerȱtoȱfunctionȱreturningȱpointerȱtoȱpointerȱtoȱint.ȱ
XVII.
Functionȱreturningȱpointerȱtoȱfunctionȱreturningȱint.ȱ
XVIII.
Functionȱreturningȱpointerȱtoȱpointerȱtoȱfunctionȱreturningȱint.ȱ
XIX.
Functionȱreturningȱpointerȱtoȱfunctionȱreturningȱpointerȱtoȱint.ȱ
XX.
Pointerȱtoȱfunctionȱreturningȱpointerȱtoȱfunctionȱreturningȱint.ȱ
XXI.
Pointerȱ toȱ functionȱ returningȱ pointerȱ toȱ pointerȱ toȱ functionȱ returningȱ
int.ȱ
Download at http://www.pin5i.com/
13.9 Questions
375
XXII.
Pointerȱ toȱ functionȱ returningȱ pointerȱ toȱ functionȱ returningȱ pointerȱ toȱ
int.ȱ
XXIII.
Pointerȱtoȱfunctionȱreturningȱpointerȱtoȱarrayȱofȱint.ȱ
XXIV.
Pointerȱtoȱfunctionȱreturningȱpointerȱtoȱarrayȱofȱpointerȱtoȱint.ȱ
XXV.
Pointerȱ toȱ functionȱ returningȱ pointerȱ toȱ arrayȱ ofȱ pointerȱ toȱ functionȱ
returningȱpointerȱtoȱint.ȱ
XXVI. Illegalȱ
2. Givenȱtheȱfollowingȱdeclarations:ȱ
ȱ
char
char
*array[10];
**ptr = array;
ȱ
whatȱisȱtheȱeffectȱofȱaddingȱoneȱtoȱtheȱvariableȱptr?ȱ
3. Supposeȱyouȱareȱwritingȱaȱfunctionȱthatȱbeginsȱlikeȱthis:ȱ
ȱ
void func( int ***arg ){
ȱ
Whatȱ isȱ theȱ typeȱ ofȱ theȱ argument?ȱ Drawȱ aȱ diagramȱ thatȱ showsȱ howȱ thisȱ variableȱ
wouldȱbeȱcorrectlyȱused.ȱWhatȱexpressionȱwouldȱyouȱuseȱtoȱgetȱtheȱintegerȱthatȱtheȱ
argumentȱisȱreferringȱto?ȱ
4. Howȱcanȱtheȱfollowingȱcodeȱfragmentȱbeȱimproved?ȱ
Transaction *trans;
trans->product->orders += 1;
trans->product->quantity_on_hand -= trans->quantity;
trans->product->supplier->reorder_quantity
+= trans->quantity;
if( trans->product->export_restricted ){
...
}
5. Givenȱtheȱfollowingȱdeclarations:ȱ
ȱ
typedef
int
int
} Point;
struct {
x;
y;
Point p;
Point *a = &p;
Point **b = &a;
ȱ
determineȱtheȱvalueȱofȱeachȱofȱtheȱfollowingȱexpressions.ȱ
Download at http://www.pin5i.com/
376ȱ
Chapter 13 Advanced Pointer Topicsȱ
a. aȱ
b. *aȱ
c. a->xȱ
d. bȱ
e. b->aȱ
f. b->xȱ
g. *bȱ
h. *b->aȱ
i. *b->xȱ
j.
b->a->xȱ
k. (*b)->aȱ
l. (*b)->xȱ
m. **bȱ
ȱ
6. Givenȱtheȱfollowingȱdeclarations:ȱ
ȱ
typedeef
int
int
} Point;
struct {
x;
y;
Point x, y;
Point *a = &x, *b = &y;
ȱ
explainȱtheȱmeaningȱofȱeachȱofȱtheseȱstatements.ȱ
ȱ
a. x = y;ȱ
b. a = y;ȱ
c. a = b;ȱ
d. a = *b;ȱ
e. *a = *b;ȱ
ȱ
7. ManyȱimplementationsȱofȱANSIȱCȱincludeȱaȱfunctionȱcalledȱ getopt.ȱThisȱfunctionȱ
helpsȱprocessȱcommandȱlineȱarguments.ȱHowever,ȱ getoptȱisȱnotȱmentionedȱinȱtheȱ
Standard.ȱWhatȱareȱtheȱadvantagesȱandȱdisadvantagesȱofȱhavingȱsuchȱaȱfunction?ȱ
Download at http://www.pin5i.com/
13.10 Programming Exercises
377
8. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱthisȱcodeȱfragment,ȱandȱhowȱwouldȱyouȱfixȱit?ȱ
ȱ
char *pathname = " /usr/temp/XXXXXXXXXXXXXXX";
...
/*
** Insert the filename into the pathname.
*/
strcpy( pathname + 10, "abcde" );
9. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱcodeȱfragment,ȱandȱhowȱwouldȱyouȱ
fixȱit?ȱ
ȱ
char pathname[] = "/usr/temp/";
...
/*
** Append the filename to the pathname.
*/
strcat( pathname, "abcde" );
10. Whatȱ(ifȱanything)ȱisȱwrongȱwithȱtheȱfollowingȱcodeȱfragment,ȱandȱhowȱwouldȱyouȱ
fixȱit?ȱ
ȱ
char pathname[20] = "/usr/temp/";
...
/*
** Append the filename to the pathname.
*/
strcat( pathname, filename );
11. Theȱ Standardȱ slatesȱ thatȱ theȱ effectsȱ ofȱ modifyingȱ aȱ stringȱ literalȱ areȱ undefined.ȱ
Whatȱproblemsȱmightȱbeȱcausedȱifȱyouȱdidȱmodifyȱstringȱliterals?ȱ
ȱ
ȱ
ȱ
13.10 Programming Exercises
ȱ
1. Writeȱaȱprogramȱthatȱreadsȱfromȱtheȱstandardȱinputȱandȱcomputesȱtheȱpercentageȱ
ofȱcharactersȱitȱfindsȱinȱeachȱofȱtheȱfollowingȱcategories:ȱ
ȱ
controlȱcharactersȱ
whitespaceȱcharactersȱ
digitsȱ
lowerȱcaseȱlettersȱ
upperȱcaseȱlettersȱ
punctuationȱcharactersȱ
nonȬprintableȱcharactersȱ
Download at http://www.pin5i.com/
378ȱ
Chapter 13 Advanced Pointer Topicsȱ
Theȱcharacterȱcategoriesȱareȱtoȱbeȱasȱtheyȱareȱdefinedȱforȱtheȱctype.hȱfunctions.ȱDoȱ
notȱuseȱaȱseriesȱofȱifȱstatements.ȱ
2. WriteȱaȱgeneralȬpurposeȱfunctionȱtoȱtraverseȱaȱsinglyȱlinkedȱlist.ȱItȱshouldȱtakeȱtwoȱ
parameters:ȱ aȱ pointerȱ toȱ theȱ firstȱ nodeȱ inȱ theȱ listȱ andȱ aȱ pointerȱ toȱ aȱ callbackȱ
function.ȱ Theȱ callbackȱ functionȱ shouldȱ takeȱ aȱ singleȱ argument,ȱ aȱ pointerȱ toȱ aȱ listȱ
node,ȱandȱshouldȱbeȱinvokedȱonceȱforȱeachȱnodeȱinȱtheȱlist.ȱWhatȱdoesȱtheȱfunctionȱ
needȱtoȱknowȱaboutȱtheȱnodesȱinȱtheȱlist?ȱ
3. Convertȱ theȱ followingȱ codeȱ fragmentȱ soȱ thatȱ itȱ usesȱ aȱ jumpȱ tableȱ insteadȱ ofȱ aȱ
switchȱstatement.ȱ
ȱ
Node *list;
Node *current;
Transaction *transaction;
typedef enum
{ NEW, DELETE, FORWARD, BACKWARD,
SEARCH, EDIT } Trans_type;
...
case NEW:
add_new_trans( list, transaction );
break;
case DELETE:
current = delete_trans( list, current );
break;
case FORWARD:
current = current->next;
break;
case BACKWARD:
current = current->prev;
break;
case SEARCH:
current = search( list, transaction );
break;
case EDIT:
edit( current, transaction );
break;
default:
printf( "Illegal transaction type!\n" );
break;
}
Download at http://www.pin5i.com/
13.10 Programming Exercises
379
4. Writeȱaȱfunctionȱcalledȱ sortȱthatȱwillȱsortȱanȱarrayȱofȱanyȱkindȱofȱvalue.ȱToȱmakeȱ
theȱ functionȱ generic,ȱ oneȱ ofȱ itsȱ argumentsȱ mustȱ beȱ aȱ pointerȱ toȱ aȱ callbackȱ
comparisonȱfunctionȱthatȱtheȱcallerȱwillȱsupply.ȱTheȱcomparisonȱfunctionȱwillȱtakeȱ
twoȱarguments,ȱwhichȱareȱpointersȱtoȱtheȱvaluesȱbeingȱcompared,ȱȱitȱwillȱreturnȱanȱ
integerȱthatȱisȱzeroȱifȱtheȱtwoȱvaluesȱareȱequal,ȱlessȱthanȱzeroȱifȱtheȱfirstȱvalueȱisȱlessȱ
thanȱtheȱsecond,ȱandȱgreaterȱthanȱzeroȱifȱtheȱfirstȱvalueȱisȱgreaterȱthanȱtheȱsecond.ȱ
Theȱargumentsȱtoȱsortȱwillȱbe:ȱ
1. aȱpointerȱtoȱtheȱfirstȱvalueȱinȱtheȱarrayȱtoȱbeȱsorted,ȱ
2. theȱnumberȱofȱvaluesȱinȱtheȱarray,ȱ
3. theȱsizeȱofȱeachȱarrayȱelement,ȱandȱ
4. aȱpointerȱtoȱtheȱcomparisonȱcallbackȱfunction.ȱ
ȱ
Theȱsortȱfunctionȱdoesȱnotȱreturnȱaȱvalue.ȱ
Youȱwillȱnotȱbeȱableȱtoȱdeclareȱtheȱarrayȱargumentȱwithȱitsȱrealȱtypeȱbecauseȱtheȱ
functionȱcanȱbeȱcalledȱtoȱsortȱdifferentȱtypesȱofȱarray.ȱIfȱyouȱtreatȱtheȱdataȱasȱifȱitȱ
wereȱ anȱ arrayȱ ofȱ characters,ȱ youȱ canȱ useȱ theȱ thirdȱ argumentȱ bothȱ toȱ locateȱ theȱ
beginningȱ ofȱ eachȱ elementȱ ofȱ theȱ actualȱ arrayȱ andȱ toȱ interchangeȱ twoȱ arrayȱ
elementsȱoneȱbyteȱatȱaȱtime.ȱ
Youȱ mayȱ useȱ theȱ followingȱ algorithmȱ forȱ aȱ simpleȱ exchangeȱ sort,ȱ orȱ youȱ mayȱ
feelȱfreeȱtoȱuseȱanyȱbetterȱalgorithmȱyouȱknow.ȱ
ȱ
forȱiȱ=ȱ1ȱtoȱnumberȬofȬrecordsȱ–ȱ1ȱdoȱ
ȱ
forȱjȱ=ȱiȱ+ȱ1ȱtoȱnumberȬofȬrecordsȱdoȱ
ȱ
ȱ
ifȱrecordȱiȱ>ȱrecordȱjȱthenȱ
ȱ
ȱ
ȱ
interchangeȱrecordsȱiȱandȱjȱ
5. Writingȱ theȱ codeȱ toȱ processȱ commandȱ lineȱ argumentsȱ isȱ tedious,ȱ whichȱ suggestsȱ
thatȱthereȱoughtȱtoȱbeȱaȱstandardȱfunctionȱtoȱdoȱit.ȱDifferentȱprogramsȱhandleȱtheirȱ
argumentsȱinȱdifferentȱways,ȱhowever,ȱsoȱtheȱfunctionȱmustȱbeȱflexibleȱinȱorderȱforȱ
itȱ toȱ beȱ usefulȱ inȱ moreȱ thanȱ justȱ aȱ coupleȱ ofȱ programs.ȱ Forȱ thisȱ project,ȱ youȱ willȱ
writeȱ suchȱ aȱ function.ȱ Yourȱ routineȱ willȱ provideȱ flexibilityȱ byȱ locatingȱ andȱ
extractingȱtheȱarguments.ȱCallbackȱfunctionsȱprovidedȱbyȱtheȱuserȱwillȱperformȱtheȱ
actualȱprocessing.ȱ
Hereȱisȱaȱprototypeȱforȱyourȱfunction.ȱȱNoteȱthatȱtheȱfourthȱandȱfifthȱargumentsȱ
prototypeȱcallbackȱfunctions.ȱ
ȱ
char **
do_args( int argc, char **argv, char *control,
void (*do_arg)( int ch, char * value ),
void (*illegal_arg)( int ch ) );
Download at http://www.pin5i.com/
380ȱ
Chapter 13 Advanced Pointer Topicsȱ
Theȱfirstȱtwoȱparametersȱareȱthoseȱreceivedȱbyȱtheȱmainȱfunction,ȱwhichȱareȱpassedȱ
unchangedȱ toȱ do_args.ȱ Theȱ thirdȱ isȱ aȱ stringȱ thatȱ identifiesȱ whatȱ commandȱ lineȱ
argumentsȱ areȱ expected.ȱ Theȱ lastȱ twoȱ parametersȱ areȱ pointersȱ toȱ functionsȱ
providedȱbyȱtheȱuser.ȱ
do_argsȱprocessesȱcommandȱlineȱargumentsȱlikeȱthis:ȱ
ȱ
Skipȱpastȱtheȱprogramȱnameȱargumentȱ
Whileȱtheȱnextȱargumentȱbeginsȱwithȱaȱdashȱ
Forȱeachȱcharacterȱinȱtheȱargumentȱafterȱtheȱdashȱ
Processȱtheȱcharacterȱ
Returnȱaȱpointerȱtoȱtheȱnextȱargumentȱpointer.ȱ
ȱ
ToȱȈprocessȱtheȱcharacter,Ȉȱyouȱmustȱfirstȱseeȱwhetherȱtheȱcharacterȱisȱinȱtheȱcontrolȱ
string.ȱIfȱitȱisȱnotȱthere,ȱcallȱtheȱfunctionȱtoȱwhichȱ illegal_argȱpoints,ȱpassingȱtheȱ
characterȱ asȱ anȱ argument.ȱ Ifȱ itȱ isȱ thereȱ butȱ isȱ notȱ followedȱ byȱ aȱ plus,ȱ callȱ theȱ
functionȱ toȱ whichȱ do_argȱ points,ȱ passingȱ theȱ characterȱ andȱ aȱ NULLȱ pointerȱ asȱ
arguments.ȱ
Ifȱtheȱcharacterȱisȱinȱ controlȱandȱisȱfollowedȱbyȱaȱplus,ȱthenȱthereȱshouldȱbeȱaȱ
valueȱassociatedȱwithȱtheȱcharacter.ȱIfȱthereȱareȱanyȱmoreȱcharactersȱinȱtheȱcurrentȱ
argument,ȱ theyȱ areȱ theȱ desiredȱ value.ȱ Otherwise,ȱ theȱ nextȱ argumentȱ isȱ theȱ value.ȱȱ
Inȱ eitherȱ case,ȱ youȱ shouldȱ callȱ theȱ functionȱ toȱ whichȱ do_argȱ points,ȱ passingȱ asȱ
argumentsȱ theȱ characterȱ andȱ aȱ pointerȱ toȱ theȱ value.ȱ Ifȱ thereȱ wasnȇtȱ aȱ valueȱ (noȱ
additionalȱcharactersȱandȱnoȱnextȱargument),ȱthenȱyonȱshouldȱcallȱtheȱ illegal_argȱ
functionȱ instead.ȱ Note:ȱ Beȱ sureȱ thatȱ theȱ charactersȱ inȱ theȱ valueȱ areȱ notȱ processedȱ asȱ
argumentsȱlater!ȱ
Whenȱ allȱ theȱ argumentsȱ thatȱ beginȱ withȱ aȱ dashȱ haveȱ beenȱ processed,ȱ youȱ
shouldȱreturnȱaȱpointerȱtoȱtheȱpointerȱtoȱtheȱnextȱcommandȱlineȱargumentȱ(thatȱis,ȱaȱ
valueȱsuchȱasȱ &argv[4]ȱorȱ argv + 4).ȱIfȱallȱofȱtheȱcommandȱlineȱargumentsȱbeganȱ
withȱdashes,ȱyouȱwillȱreturnȱaȱpointerȱtoȱtheȱNULLȱthatȱterminatesȱtheȱcommandȱ
lineȱargumentȱlist.ȱ
Theȱ functionȱ mustȱ notȱ modifyȱ eitherȱ theȱ commandȱ lineȱ argumentȱ pointersȱ orȱ
theȱarguments.ȱToȱillustrate,ȱsupposeȱthatȱtheȱprogramȱprogȱcallsȱthisȱfunction:ȱtheȱ
followingȱexamplesȱshowȱtheȱresultsȱwithȱseveralȱdifferentȱsetsȱofȱarguments.ȱ
ȱ
$ prog –x –y z
Commandȱline:
"x"
control:
(*do_arg)( 'x', 0 )
do_argsȱcalls:
andȱreturns:
Commandȱline:
control:
do_argsȱcalls:
(*illegal_arg)( 'y' )
&argv[3]
$ prog –x –y –z
"x+y+z+"
(*do_arg)( 'x', "-y" )
(*illegal_arg)( 'z' )
Download at http://www.pin5i.com/
13.10 Programming Exercises
andȱreturns:
Commandȱline:
control:
do_argsȱcalls:
andȱreturns:
Commandȱline:
control:
do_argsȱcalls:
andȱreturns:
&argv[4]
$ prog –abcd –ef ghi jkl
"ab+cdef+g"
(*do_arg)(
(*do_arg)(
(*do_arg)(
(*do_arg)(
&argv[4]
'a',
'b',
'e',
'f',
0 )
"cd" )
0 )
"ghi" )
$ prog –a b –c –d –e –f
"abcdef"
(*do_arg)( 'a', 0 )
&argv[2]
381
Download at http://www.pin5i.com/
Download at http://www.pin5i.com/
ȱȱ
Download at http://www.pin5i.com/
14
The Preprocessor
Thereȱ areȱ manyȱ stepsȱ involvedȱ inȱ compilingȱ aȱ Cȱ program.ȱ Theȱ firstȱ stepȱ isȱ calledȱ
preprocessing.ȱ Theȱ Cȱ preprocessorȱ performsȱ textualȱ manipulationsȱ onȱ theȱ sourceȱ codeȱ
beforeȱ itȱ isȱ compiled.ȱ Theȱ majorȱ tasksȱ includeȱ deletingȱ comments,ȱ insertingȱ theȱ
contentsȱ ofȱ #includeȇdȱ filesȱ intoȱ theȱ code,ȱ definingȱ andȱ substitutingȱ #defineȇdȱ
symbols,ȱ andȱ decidingȱ whetherȱ orȱ notȱ certainȱ partsȱ ofȱ theȱ codeȱ shouldȱ beȱ compiledȱ
basedȱonȱconditionalȱcompilationȱdirectives.ȱ
ȱ
ȱ
ȱ
14.1 Predefined Symbols
ȱ
Tableȱ 14.1ȱ summarizesȱ theȱ symbolsȱ definedȱ byȱ theȱ preprocessor.ȱ Theȱ valuesȱ areȱ allȱ
eitherȱ stringȱ literalsȱ orȱ decimalȱ constants.ȱ __FILE__ȱ andȱ __LINE__ȱ areȱ usefulȱ inȱ
identifyingȱtheȱsourceȱofȱdebuggingȱoutput.ȱ __DATE__ȱandȱ __TIME__ȱareȱoftenȱusedȱtoȱ
encodeȱ versionȱ informationȱ intoȱ theȱ compiledȱ program.ȱ __STDC__ȱ isȱ usedȱ inȱ
conjunctionȱwithȱconditionalȱcompilationȱ(describedȱlaterȱinȱthisȱchapter)ȱforȱprogramsȱ
thatȱmustȱbeȱcompiledȱinȱbothȱANSIȱandȱnonȬANSIȱenvironments.ȱ
ȱ
Symbol
Sample Value
Meaning
__FILE__ "name.c"
Nameȱofȱtheȱsourceȱfileȱbeingȱcompiledȱ
__LINE__ 25
Lineȱnumberȱofȱtheȱcurrentȱlineȱinȱtheȱfile.ȱ
__DATE__ "Jan 31 1997"
Dateȱthatȱtheȱfileȱwasȱcompiled.ȱ
__TIME__ "18:04:30"
Timeȱthatȱtheȱfileȱwasȱcompiled.ȱ
__STDC__
1ȱifȱtheȱcompilerȱconformsȱtoȱANSIȱC,ȱelseȱundefined.ȱ
ȱ
Tableȱ14.1ȱȱPreprocessorȱsymbolsȱ
Download at http://www.pin5i.com/
384ȱ
Chapter 14 The Preprocessorȱ
14.2 #define
K&R C
ȱ
Youȱhaveȱalreadyȱseenȱsimpleȱusesȱofȱtheȱ #defineȱdirectiveȱthatȱgiveȱsymbolicȱnamesȱ
toȱ numericȱ values.ȱ Inȱ thisȱ section,ȱ Iȇllȱ introduceȱ moreȱ usesȱ ofȱ #define.ȱ Letȇsȱ startȱ byȱ
lookingȱatȱaȱmoreȱformalȱdescriptionȱofȱit.ȱ
ȱ
ȱ
#define name stuff
ȱ
Wheneverȱ theȱ symbolȱ nameȱ appearsȱ afterȱ thisȱ directive,ȱ theȱ preprocessorȱ replacesȱ itȱ
withȱstuff.ȱ
ȱ
Earlyȱ Cȱ compilersȱ requiredȱ thatȱ theȱ #ȱ appearȱ atȱ theȱ beginningȱ ofȱ aȱ line,ȱ althoughȱ itȱ
couldȱbeȱfollowedȱbyȱwhiteȱspace.ȱInȱANSIȱC,ȱthisȱrestrictionȱisȱremoved.ȱ
Theȱreplacementȱtextȱneedȱnotȱbeȱlimitedȱtoȱnumericȱliteralȱconstants.ȱAnyȱtextȱ
canȱbeȱsubstitutedȱintoȱtheȱprogramȱwithȱaȱ#define.ȱHereȱareȱaȱfewȱexamples:ȱ
ȱ
#define reg
#define do_forever
#define CASE
register
for(;;)
break;case
ȱ
Theȱfirstȱdefinitionȱmerelyȱcreatesȱaȱshortȱaliasȱforȱtheȱ registerȱkeyword.ȱThisȱshorterȱ
nameȱ makesȱ itȱ easierȱ toȱ lineȱ upȱ declarationsȱ withȱ tabs.ȱ Theȱ secondȱ isȱ aȱ moreȱ
descriptiveȱ synonymȱ forȱtheȱvariantȱofȱtheȱ forȱstatementȱthatȱ implementsȱ anȱinfiniteȱ
loop.ȱ Finally,ȱ theȱ lastȱ oneȱ isȱ aȱ shorthandȱ notationȱ forȱ useȱ withȱ switchȱ statements.ȱ ȱ Itȱ
automaticallyȱputsȱaȱ breakȱbeforeȱeachȱ caseȱthusȱmakingȱtheȱ switchȱstatementȱappearȱ
toȱbeȱmoreȱlikeȱcaseȱstatementsȱinȱotherȱlanguages.ȱ
ȱ
Ifȱtheȱstuffȱinȱtheȱdefinitionȱisȱlong,ȱitȱcanȱbeȱsplitȱoverȱmultipleȱlinesȱbyȱendingȱ
eachȱlineȱofȱtheȱdefinition,ȱexceptȱtheȱlastȱone,ȱwithȱaȱbackslash,ȱasȱinȱthisȱexample:ȱ
ȱ
#define DEBUG_PRINT
printf( "File %s line %d:" \
" x=%d, y=%d, z=%d", \
__FILE__, __LINE__, \
x, y, z )
ȱ
Iȇmȱtakingȱadvantageȱofȱtheȱfactȱthatȱadjacentȱstringȱliteralsȱareȱconcatenatedȱinȱtoȱoneȱ
string.ȱ Thisȱ typeȱ ofȱ declarationȱ isȱ usefulȱ whenȱ debuggingȱ aȱ programȱ withȱ manyȱ
differentȱ computationsȱ involvingȱ aȱ setȱ ofȱ variables.ȱ Itȱ makesȱ insertingȱ aȱ debuggingȱ
statementȱtoȱprintȱtheirȱcurrentȱvaluesȱeasier.ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
14.2 #defineȱ
385
x * = 2;
y += x;
z = x * y;
DEBUG_PRINT;
CAUTION!
ȱ
Theȱstatementȱinvokingȱ debug_printȱendsȱwithȱaȱsemicolon,ȱsoȱyouȱshouldnȇtȱhaveȱaȱ
semicolonȱ atȱ theȱ endȱ ofȱ theȱ macroȱ definition.ȱ Ifȱ youȱ do,ȱ theȱ resultȱ willȱ beȱ twoȱ
statements—aȱ printfȱ followedȱ byȱ anȱ emptyȱ statement.ȱ Havingȱ twoȱ statementsȱ willȱ
causeȱproblemsȱinȱcontextsȱwhereȱonlyȱoneȱstatementȱisȱallowed,ȱforȱexample:ȱ
ȱ
if( ... )
DEBUG_PRINT;
else
...
ȱ
Youȱcanȱalsoȱuseȱaȱ #defineȱtoȱinsertȱaȱsequenceȱofȱstatementsȱintoȱtheȱprogram.ȱ
Hereȱisȱaȱdeclarationȱforȱanȱentireȱloop:ȱ
ȱ
#define PROCESS_LOOP
\
for( i = 0; i < 10; i += 1 ){ \
sum += i;
\
if( i > 0 )
\
prod *= i;
\
}
TIP
ȱ
Donȇtȱ misuseȱ thisȱ technique.ȱ Ifȱ theȱ sameȱ codeȱ isȱ neededȱ inȱ severalȱ areasȱ ofȱ theȱ
program,ȱ itȱ isȱ usuallyȱ betterȱ toȱ implementȱ itȱ asȱ aȱ function.ȱ Iȇllȱ discussȱ theȱ tradeoffsȱ
betweenȱ#defineȇsȱandȱfunctionsȱinȱdetailȱlaterȱinȱtheȱchapter.ȱ
ȱ
ȱ
ȱ
14.2.1
Macros
ȱ
Theȱ #defineȱ mechanismȱ includesȱ aȱ provisionȱ toȱ substituteȱ argumentsȱ intoȱ theȱ text,ȱ
implementingȱwhatȱareȱoftenȱcalledȱmacrosȱorȱdefinedȱmacros.ȱHereȱisȱhowȱmacrosȱareȱ
declared:ȱ
ȱ
#define name(parameter-list) stuff
ȱ
Theȱ parameter-listȱ isȱ aȱ commaȬseparatedȱ listȱ ofȱ symbolsȱ thatȱ mayȱ appearȱ inȱ theȱ
stuff.ȱTheȱopeningȱparenthesisȱofȱtheȱparameterȱlistȱmustȱbeȱadjacentȱtoȱtheȱname.ȱIfȱ
thereȱisȱanyȱwhiteȱspaceȱbetweenȱthem,ȱtheȱparameterȱlistȱwillȱbeȱinterpretedȱasȱpartȱofȱ
stuff.ȱ
Download at http://www.pin5i.com/
386ȱ
Chapter 14 The Preprocessorȱ
Whenȱtheȱmacroȱisȱinvoked,ȱtheȱnameȱisȱfollowedȱbyȱaȱcommaȬseparatedȱlistȱofȱ
values,ȱ oneȱ forȱ eachȱ parameter,ȱ enclosedȱ inȱ parentheses.ȱ Theȱ actualȱ valueȱ givenȱ forȱ
eachȱparameterȱisȱsubstitutedȱintoȱtheȱstuffȱwheneverȱtheȱparameterȱappears.ȱ
Hereȱisȱaȱmacroȱthatȱtakesȱoneȱparameter:ȱ
ȱ
#define SQUARE(x)
x * x
ȱ
Ifȱyouȱputȱ
ȱ
SQUARE( 5 )
ȱ
inȱtheȱprogramȱafterȱthisȱdeclaration:ȱtheȱpreprocessorȱsubstitutesȱ
ȱ
5 * 5
CAUTION!
ȱ
inȱitsȱplace.ȱ
Thereȱisȱaȱproblemȱwithȱthisȱmacro,ȱhowever.ȱLookȱatȱthisȱfragmentȱofȱcode;ȱ
ȱ
a = 5;
printf( "%d\n", SQUARE( a + 1 ) );
ȱ
Atȱfirstȱglance,ȱyouȱwouldȱexpectȱthatȱthisȱcodeȱwouldȱprintȱ36.ȱInȱfact,ȱitȱprintsȱ 11.ȱToȱ
seeȱwhy,ȱ lookȱatȱtheȱ macroȱ textȱ thatȱisȱ substituted.ȱ Theȱparameterȱ xȱisȱreplacedȱwithȱ
theȱtextȱa + 1,ȱsoȱtheȱstatementȱisȱactuallyȱ
ȱ
printf( "%d\n", a + 1 * a + 1 );
ȱ
Theȱproblemȱisȱnowȱclear:ȱtheȱexpressionȱresultingȱfromȱtheȱsubstitutionȱisȱnotȱbeingȱ
evaluatedȱinȱtheȱintendedȱorder.ȱ
Thisȱerrorȱisȱeasyȱtoȱcorrectȱbyȱaddingȱparenthesesȱtoȱtheȱmacroȱdefinition:ȱ
ȱ
#define SQUARE(x)
(x) * (x)
ȱ
Theȱpreprocessorȱnowȱsubstitutesȱthisȱstatement,ȱwhichȱhasȱtheȱexpectedȱresult,ȱinȱtheȱ
previousȱexample,ȱ
ȱ
printf( "%d\n", ( a + 1 ) * ( a + 1 ) );
ȱ
Hereȱisȱanotherȱmacroȱdefinition.ȱ
ȱ
#define DOUBLE(x)
(x) + (x)
ȱ
Theȱparenthesesȱareȱinȱplaceȱtoȱavoidȱtheȱearlierȱproblem,ȱbutȱaȱdifferentȱerrorȱ
canȱoccurȱwithȱthisȱmacro.ȱWhatȱvalueȱisȱprintedȱbyȱtheȱfollowingȱcode?ȱ
Download at http://www.pin5i.com/
14.2 #defineȱ
387
a = 5;
printf( "%d\n", 10 * DOUBLE( a ) );
ȱ
Itȱlooksȱlikeȱitȱshouldȱprintȱ100,ȱbutȱinȱfactȱitȱprintsȱ55.ȱAgain,ȱtheȱtextȱresultingȱfromȱ
theȱmacroȱsubstitutionȱrevealsȱtheȱproblem:ȱ
ȱ
printf( "%d\n", 10 * ( a ) + ( a ) );
ȱ
Theȱ multiplicationȱ isȱ performedȱ beforeȱ theȱ additionȱ definedȱ inȱ theȱ macroȱ isȱ
completed.ȱ Thisȱ errorȱ isȱ alsoȱ easyȱ toȱ fix:ȱ surroundȱ theȱ entireȱ expressionȱ withȱ
parenthesesȱwhenȱtheȱmacroȱisȱdefined.ȱ
ȱ
#define DOUBLE(x)
TIP
( (x) + (x) )
ȱ
Allȱmacroȱdefinitionȱthatȱevaluateȱnumericȱexpressionsȱshouldȱbeȱparenthesizedȱinȱthisȱ
mannerȱ toȱ avoidȱ unexpectedȱ interactionsȱ withȱ operatorsȱ inȱ theȱ argumentsȱ orȱ withȱ
operatorsȱadjacentȱtoȱwhereȱtheȱmacroȱisȱused.ȱ
Hereȱisȱanȱinterestingȱpairȱofȱmacros:ȱ
ȱ
#define repeat
#define until( x )
do
while( ! (x) )
ȱ
Theseȱ createȱ aȱ ȈnewȈȱ loop,ȱ whichȱ worksȱ theȱ sameȱ asȱ theȱ repeat/untilȱ loopȱ inȱ
otherȱlanguages.ȱItȱisȱusedȱlikeȱthis:ȱ
ȱ
repeat {
statements
} until( i >= 10 );
ȱ
Theȱpreprocessorȱsubstitutesȱtheȱfollowingȱcode.ȱ
ȱ
do {
statements
} while( ! ( i >= 10 ) );
TIP
ȱ
Theȱ parenthesesȱ aroundȱ theȱ expressionȱ makeȱ sureȱ thatȱ itȱ isȱ completelyȱ evaluatedȱ
beforeȱtheȱ!ȱoperatorȱcomplementsȱitsȱvalue.ȱ
ȱ
Itȱisȱpossibleȱtoȱcreateȱsuitesȱofȱ #defineȱmacrosȱinȱorderȱtoȱwriteȱCȱprogramsȱthatȱlookȱ
likeȱ otherȱ languages.ȱ Inȱ mostȱ cases,ȱ youȱ shouldȱ avoidȱ thisȱ temptationȱ becauseȱ theȱ
resultingȱ programsȱ areȱ difficultȱ forȱ otherȱ Cȱ programmersȱ toȱ understand.ȱ Theyȱ mustȱ
constantlyȱ lookȱ upȱ theȱ definitionsȱ toȱ seeȱ whatȱ isȱ reallyȱ happening.ȱ Evenȱ ifȱ everyoneȱ
workingȱonȱtheȱprojectȱnowȱandȱforȱtheȱrestȱofȱtheȱprojectȇsȱlifeȱisȱfamiliarȱwithȱtheȱotherȱ
language,ȱthisȱtechniqueȱmayȱcauseȱconfusionȱbecauseȱofȱaspectsȱofȱtheȱotherȱlanguageȱ
cannotȱbeȱmimickedȱexactly.ȱ
Download at http://www.pin5i.com/
Chapter 14 The Preprocessorȱ
388ȱ
14.2.2
#define Substitution
ȱ
Thereȱ areȱ severalȱ stepsȱ involvedȱ inȱ expandingȱ #defineȇdȱ symbolsȱ andȱ macrosȱ inȱ theȱ
program.ȱ
ȱ
1. Forȱmacroȱinvocations,ȱtheȱargumentsȱareȱfirstȱexaminedȱtoȱseeȱifȱtheyȱcontainȱanyȱ
#defineȇdȱsymbols.ȱȱIfȱso,ȱtheyȱareȱreplacedȱfirst.ȱ
2. Theȱsubstitutionȱtextȱisȱthenȱinsertedȱintoȱtheȱprogramȱinȱplaceȱofȱtheȱoriginalȱtext.ȱ
Forȱmacros,ȱtheȱargumentȱnamesȱareȱreplacedȱbyȱtheirȱvalues.ȱ
3. Finally,ȱ theȱ resultingȱ textȱ isȱ scannedȱ againȱ toȱ seeȱ ifȱ itȱ containsȱ anyȱ #defineȇdȱ
symbols;ȱifȱso,ȱtheȱprocessȱisȱrepeated.ȱ
ȱ
Thus,ȱmacroȱargumentsȱandȱ#defineȱdefinitionsȱmayȱcontainȱotherȱ#defineȇdȱsymbols.ȱ
Macrosȱmayȱnotȱbeȱrecursive,ȱhowever.ȱ
Stringȱ literalsȱ areȱ notȱ examinedȱ whenȱ theȱ preprocessorȱ isȱ searchingȱ forȱ
#defineȇdȱ symbols.ȱ Thereȱ areȱ twoȱ techniquesȱ thatȱ areȱ usefulȱ inȱ injectingȱ macroȱ
argumentȱvaluesȱintoȱstringȱliterals.ȱFirst,ȱtheȱconcatenationȱofȱadjacentȱstringsȱmakesȱ
itȱeasyȱtoȱbreakȱaȱstringȱintoȱpieces,ȱoneȱofȱwhichȱisȱactuallyȱaȱmacroȱargument.ȱHereȱisȱ
anȱexampleȱofȱthisȱtechnique:ȱ
ȱ
#define PRINT(FORMAT,VALUE)
\
printf( "The value is " FORMAT "\n", VALUE )
...
PRINT( "%d", x + 3 );
ȱ
Thisȱtechniqueȱonlyȱworksȱifȱaȱstringȱliteralȱisȱgivenȱasȱtheȱmacroȱargument.ȱ
Theȱsecondȱtechniqueȱusesȱtheȱpreprocessorȱtoȱconvertȱaȱmacroȱargumentȱtoȱaȱ
string.ȱTheȱconstructȱ #argumentȱisȱtranslatedȱbyȱtheȱpreprocessorȱintoȱȈargumentȈ.ȱThisȱ
translationȱletsȱyouȱwriteȱcodeȱlikeȱthis:ȱ
ȱ
#define PRINT(FORMAT,VALUE)
printf( "The value of " #VALUE
" is " FORMAT "\n", VALUE )
...
PRINT( "%d", x + 3 );
\
\
ȱ
whichȱproducesȱthisȱoutput:ȱ
ȱ
The value of x + 3 is 25
ȱ
Theȱ ##ȱ constructȱ performsȱ aȱ differentȱ task.ȱ Itȱ causesȱ theȱ twoȱ tokensȱ onȱ eitherȱ
sideȱ ofȱ itȱ toȱ beȱ concatenated.ȱ Amongȱ otherȱ uses,ȱ thisȱ capabilityȱ allowsȱ macroȱ
definitionsȱtoȱconstructȱidentifiersȱfromȱseparateȱpiecesȱofȱtext.ȱTheȱfollowingȱexampleȱ
usesȱconcatenationȱtoȱaddȱaȱvalueȱtoȱoneȱofȱseveralȱvariables:ȱ
Download at http://www.pin5i.com/
14.2 #defineȱ
#define ADD_TO_SUM( sum_number, value )
sum ## sum_number += value
...
ADD_TO_SUM( 5, 25 );
389
\
ȱ
Theȱlastȱstatementȱaddsȱtheȱvalueȱ25ȱtoȱtheȱvariableȱ sum5.ȱNoteȱthatȱtheȱconcatenationȱ
mustȱresultȱinȱaȱlegalȱconstruct,ȱotherwiseȱtheȱresultȱisȱundefined.ȱ
ȱ
ȱ
ȱ
14.2.3
Macros versus Functions
ȱ
Macrosȱareȱfrequentlyȱusedȱtoȱperformȱsimpleȱcomputations,ȱsuchȱasȱfindingȱtheȱlargerȱ
(orȱsmaller)ȱofȱtwoȱexpressions:ȱ
ȱ
#define MAX( a, b )
( (a) > (b) ? (a) : (b) )
ȱ
Whyȱnotȱuseȱaȱfunctionȱtoȱaccomplishȱthisȱtask?ȱThereȱareȱtwoȱreasons.ȱȱFirst,ȱtheȱcodeȱ
neededȱ toȱ callȱ andȱ returnȱ fromȱ aȱ functionȱ isȱ likelyȱ toȱ beȱ largerȱ thanȱ theȱ codeȱ thatȱ
actuallyȱ performsȱ thisȱ smallȱ amountȱ ofȱ work,ȱ soȱ theȱ macroȱ makesȱ theȱ programȱ bothȱ
smallerȱandȱfasterȱthanȱusingȱaȱfunction.ȱ
Moreȱ important,ȱ though,ȱ isȱ theȱ factȱ thatȱ aȱ functionȇsȱ parametersȱ mustȱ beȱ
declaredȱtoȱbeȱaȱspecificȱtype,ȱsoȱitȱcanȱonlyȱbeȱcalledȱwithȱexpressionsȱofȱtheȱproperȱ
type.ȱOnȱtheȱotherȱhand,ȱthisȱparticularȱmacroȱcanȱbeȱusedȱforȱintegers,ȱlongs,ȱfloats,ȱ
doubles,ȱ andȱ anyȱ otherȱ typeȱ whoseȱ valuesȱ mayȱ beȱ comparedȱ withȱ theȱ >ȱ operator.ȱ Inȱ
otherȱwords,ȱmacrosȱareȱtypeless.ȱ
Theȱdisadvantageȱtoȱusingȱmacrosȱasȱopposedȱtoȱfunctionsȱisȱthatȱaȱcopyȱofȱtheȱ
codeȱ isȱ insertedȱ intoȱ theȱ programȱ eachȱ timeȱ theȱ macroȱ isȱ used.ȱ Unlessȱ theȱ macroȱ isȱ
veryȱshort,ȱusingȱmacrosȱcanȱgreatlyȱincreaseȱtheȱsizeȱofȱtheȱprogram.ȱ
Thereȱ areȱ someȱ tasksȱ thatȱ functionsȱ simplyȱ cannotȱ accomplish.ȱ Letȇsȱ takeȱ aȱ
closerȱlookȱatȱtheȱmacroȱdefinedȱinȱProgramȱ11.1ȱa.ȱȱTheȱsecondȱargumentȱtoȱtheȱmacroȱ
isȱaȱtype,ȱwhichȱcannotȱbeȱpassedȱasȱaȱfunctionȱargument.ȱ
ȱ
#define MALLOC(n, type) \
( (type *)malloc( (n) * sizeof( type ) ) )
ȱ
Youȱ canȱ nowȱ seeȱexactlyȱ howȱ thisȱ macroȱworks.ȱ Theȱ firstȱ statementȱ inȱ theȱ followingȱ
exampleȱisȱconvertedȱbyȱtheȱpreprocessorȱtoȱtheȱsecondȱstatement.ȱ
ȱ
pi = MALLOC( 25, int );
pi = ( ( int * )malloc( ( 25 ) * sizeof( int ) ) );
ȱ
Again,ȱ noticeȱ thatȱ theȱ definitionȱ ofȱ theȱ macroȱ doesȱ notȱ endȱ withȱ aȱ semicolon.ȱ Theȱ
semicolonȱappearsȱonȱtheȱstatementȱthatȱinvokesȱtheȱmacro.ȱ
Download at http://www.pin5i.com/
Chapter 14 The Preprocessorȱ
390ȱ
14.2.4
Macro Arguments with Side Effects
ȱ
Whenȱmacroȱparametersȱappearȱmoreȱthanȱonceȱinȱtheȱdefinition,ȱthereȱisȱtheȱdangerȱ
ofȱunexpectedȱresultsȱwhenȱtheȱmacroȱisȱusedȱwithȱargumentsȱthatȱhaveȱsideȱeffects.ȱAȱ
sideȱeffectȱisȱaȱpermanentȱeffectȱcausedȱbyȱevaluatingȱtheȱexpression.ȱForȱexample,ȱtheȱ
expressionȱ
ȱ
x + 1
ȱ
canȱ beȱ evaluatedȱ hundredsȱ ofȱ timesȱ andȱ theȱ sameȱ resultȱ willȱ beȱ obtainedȱ eachȱ rime.ȱ
Thisȱexpressionȱdoesnȇtȱhaveȱanyȱsideȱeffects.ȱButȱ
ȱ
x++
ȱ
hasȱ aȱ sideȱ effect:ȱ itȱ incrementsȱ x.ȱ Theȱ nextȱ timeȱ thisȱ expressionȱ isȱ evaluated,ȱ itȱ willȱ
produceȱ aȱ differentȱ result.ȱ Theȱ MAXȱ macroȱ demonstratesȱ theȱ problemsȱ causedȱ byȱ
argumentsȱwithȱsideȱeffects.ȱTraceȱtheȱfollowingȱcode.ȱWhatȱdoȱyouȱthinkȱitȱwillȱprintȱ
out?ȱ
ȱ
#define MAX( a, b )
( (a) > (b) ? (a) : (b) )
...
x = 5;
y = 8;
z = MAX( x++, y++ );
printf( "x=%d, y=%d, z=%d\n", x, y, z );
ȱ
Thisȱ problemȱ isȱ notȱ easy.ȱ Keepȱ inȱ mindȱ thatȱ theȱ firstȱ expressionȱ inȱ theȱ conditionalȱ
determinesȱ whichȱ oneȱ ofȱ theȱ otherȱ twoȱ expressionsȱ willȱ beȱ evaluated.ȱ Theȱ otherȱ
expressionȱisȱnotȱevaluatedȱatȱall.ȱTheȱresultȱisȱx=6,ȱy=10,ȱz=9.ȱ
Asȱ usual,ȱ theȱ strangeȱ resultȱ becomesȱ clearerȱ byȱ examiningȱ theȱ codeȱ thatȱ isȱ
substitutedȱforȱtheȱmacro:ȱ
ȱ
z = ( ( x++ ) > ( y++ ) ? ( x++ ) : ( y++ ) );
ȱ
Althoughȱ theȱ smallerȱ valueȱ isȱ incrementedȱ once,ȱ theȱ largerȱ valueȱ isȱ incrementedȱ
twice—onceȱ duringȱ theȱ comparisonȱ andȱ againȱ whenȱ theȱ expressionȱ afterȱ theȱ ?ȱ isȱ
evaluated.ȱ
Sideȱ effectsȱ areȱ notȱ limitedȱ onlyȱ toȱ changingȱ theȱ valuesȱ ofȱ variables.ȱ Theȱ
expressionȱ
ȱ
getchar()
ȱ
hasȱ aȱ sideȱ effect.ȱ Callingȱ theȱ functionȱ consumesȱ aȱ characterȱ ofȱ input,ȱ soȱ subsequentȱ
callsȱ retrieveȱ differentȱ characters.ȱ Theȱ expressionȱ mustȱ notȱ beȱ evaluatedȱ repeatedlyȱ
unlessȱtheȱintentȱisȱtoȱconsumeȱinputȱcharacters.ȱ
Download at http://www.pin5i.com/
14.2 #defineȱ
391
Considerȱtheȱfollowingȱmacro.ȱ
ȱ
#define EVENPARITY( ch )
( ( count_one_bits( ch ) & 1 ) ?
( ch ) | PARITYBIT : ( ch ) )
\
\
ȱ
Itȱusesȱtheȱ count_one_bitsȱfunctionȱfromȱProgramȱ5.1ȱthatȱreturnsȱtheȱnumberȱofȱoneȬ
bitsȱ inȱ itsȱ argument.ȱ Theȱ purposeȱ ofȱ theȱ macroȱ isȱ toȱ generateȱ aȱ characterȱ withȱ evenȱ
parity. 45 ȱItȱfirstȱcountsȱtheȱnumberȱofȱonesȱinȱtheȱcharacter,ȱandȱifȱtheȱresultȱisȱanȱoddȱ
numberȱtheȱ PARITYBITȱvalueȱ(aȱoneȬbit)ȱisȱORȇedȱinȱwithȱtheȱcharacter;ȱotherwiseȱtheȱ
characterȱ isȱ usedȱ unchanged.ȱ Butȱ imagineȱ whatȱ happensȱ whenȱ theȱ macroȱ isȱ usedȱ inȱ
thisȱmanner:ȱ
ȱ
ch = EVENPARITY( getchar() );
ȱ
Theȱstatementȱlooksȱreasonable:ȱreadȱaȱcharacterȱandȱcomputeȱitsȱparity.ȱHowever,ȱitȱ
failsȱbecauseȱitȱactuallyȱreadsȱtwoȱcharacters!ȱ
ȱ
ȱ
ȱ
14.2.5
Naming Conventions
ȱ
#defineȇdȱ macrosȱ behaveȱ differentlyȱ thanȱ trueȱ functionsȱ inȱ aȱ numberȱ ofȱ ways,ȱ asȱ
TIP
summarizedȱ inȱ Tableȱ 14.2.ȱ Becauseȱ ofȱ theseȱ differences,ȱ itȱ isȱ veryȱ importantȱ thatȱ theȱ
programmerȱknowsȱwhetherȱanȱidentifierȱisȱaȱmacroȱorȱaȱfunction.ȱUnfortunately,ȱtheȱ
syntaxȱforȱusingȱmacrosȱisȱidenticalȱtoȱtheȱsyntaxȱforȱfunctions,ȱsoȱtheȱlanguageȱdoesnȇtȱ
helpȱhighlightȱtheȱdifference.ȱ
ȱ
Thisȱconfusionȱisȱoneȱreasonȱitȱisȱimportantȱtoȱadoptȱaȱnamingȱconventionȱforȱmacrosȱ
(andȱ forȱ mostȱ otherȱ #defineȇdȱ symbolsȱ asȱ well).ȱ Aȱ commonȱ conventionȱ isȱ toȱ makeȱ
macroȱnamesȱallȱuppercaseȱletters.ȱInȱtheȱstatementȱ
ȱ
value = max( a, b );
ȱ
itȱisȱnotȱapparentȱwhetherȱmaxȱisȱaȱfunctionȱorȱaȱmacro.ȱYouȱhaveȱtoȱprobeȱtheȱsourceȱ
fileȱandȱanyȱheaderȱfilesȱitȱincludedȱtoȱfindȱoutȱforȱsure.ȱOnȱtheȱotherȱhand,ȱinȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
ȱ Parityȱ isȱ anȱ errorȱ detectionȱ mechanism.ȱ Beforeȱ dataȱ isȱ scoredȱ orȱ transmittedȱ overȱ aȱ communicationsȱ line,ȱ aȱ parityȱ bitȱ isȱ
computedȱwithȱaȱvalueȱthatȱmakesȱtheȱtotalȱnumberȱofȱoneȬbitsȱanȱevenȱnumber.ȱLater,ȱtheȱdataȱcanȱbeȱverifiedȱbyȱcountingȱ
theȱnumberȱofȱoneȬbits;ȱifȱtheȱresultȱisȱodd,ȱanȱerrorȱhasȱoccurred.ȱThisȱtechniqueȱisȱcalledȱevenȱparity.ȱOddȱparityȱworksȱtheȱ
sameȱway,ȱexceptȱthatȱtheȱparityȱbitȱisȱcomputedȱsoȱthatȱtheȱtotalȱnumberȱofȱoneȬbitsȱisȱanȱoddȱnumber.ȱ
ȱ
45
Download at http://www.pin5i.com/
Chapter 14 The Preprocessorȱ
392ȱ
ȱ
Property
#define Macro
Function
Codeȱsizeȱ
Macroȱ codeȱ isȱ insertedȱ intoȱ theȱ
programȱ eachȱ timeȱ theȱ macroȱ isȱ
used.ȱProgramȱendsȱupȱbeingȱlargerȱ
forȱallȱbutȱtheȱsmallestȱmacros.ȱ
Functionȱcodeȱappearsȱonlyȱonce;ȱcallsȱtoȱtheȱ
functionȱ appearȱ eachȱ timeȱ theȱ functionȱ isȱ
used.ȱ
Executionȱ
speedȱ
Faster.ȱ
Extraȱoverheadȱofȱfunctionȱcall/return.ȱ
Operatorȱ
precedenceȱ
Macroȱ argumentsȱ areȱ evaluatedȱ inȱ
theȱ contextȱ ofȱ anyȱ surroundingȱ
expression;ȱ unlessȱ parenthesized,ȱ
theȱprecedenceȱofȱadjacentȱoperatorsȱ
canȱyieldȱunexpectedȱresults.ȱ
Functionȱ argumentsȱ areȱ evaluatedȱ onceȱ
whenȱ theȱ functionȱ isȱ called;ȱ theȱ resultingȱ
valueȱ isȱ passedȱ toȱ theȱ function.ȱ Expressionȱ
evaluationȱisȱmoreȱpredictable.ȱ
Argumentȱ
evaluationȱ
Argumentsȱ evaluatedȱ everyȱ timeȱ
theyȱ areȱ usedȱ inȱ theȱ macroȱ
definition;ȱ argumentsȱ withȱ sideȱ
effectsȱ canȱ produceȱ unexpectedȱ
resultsȱdueȱtoȱmultipleȱevaluations.ȱ
ArgumentsȱevaluatedȱonlyȱonceȱbeforeȱfuncȬ
tionȱ isȱ called;ȱ multipleȱ usesȱ ofȱ argumentsȱ inȱ
theȱ functionȱ doȱ notȱ causeȱ multipleȱ evaluaȬ
tions.ȱ Sideȱ effectsȱ inȱ argumentsȱ doȱ notȱ poseȱ
anyȱspecialȱproblems.ȱ
Argumentȱ
typesȱ
Macrosȱareȱtypeless;ȱworkȱwithȱanyȱ
argumentȱ typeȱ forȱ whichȱ theȱ
operationsȱperformedȱareȱlegal.ȱ
Functionȱargumentsȱareȱtyped;ȱseparateȱfuncȬ
tionsȱareȱneededȱforȱdifferentȱargumentȱtypesȱ
evenȱifȱtheȱworkȱperformedȱisȱidentical.ȱ
ȱ
Tableȱ14.2ȱȱDifferencesȱbetweenȱmacrosȱandȱfunctionsȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
value = MAX( a, b );
ȱ
thenȱnamingȱconventionȱmakesȱitȱobvious.ȱThisȱconventionȱisȱespeciallyȱimportantȱinȱ
macrosȱthatȱmightȱbeȱusedȱwithȱargumentsȱthatȱhaveȱsideȱeffects,ȱbecauseȱitȱalertsȱtheȱ
programmerȱ toȱ theȱ needȱ toȱ evaluateȱ theȱ argumentȱ intoȱ aȱ temporaryȱ variableȱ beforeȱ
usingȱitȱinȱtheȱmacro.ȱ
ȱ
ȱ
ȱ
14.2.6
#undef
ȱ
ThisȱdirectiveȱunȬ#defineȇsȱaȱnameȱbyȱremovingȱitsȱdefinition.ȱ
ȱ
#undef
name
ȱ
Ifȱ anȱ existingȱ nameȱ isȱ toȱ beȱ redefined,ȱ theȱ oldȱ definitionȱ mustȱ firstȱ beȱ removedȱ withȱ
#undef.ȱ
Download at http://www.pin5i.com/
14.2 #defineȱ
14.2.7
393
Command Line Definitions
ȱ
Manyȱ Cȱ compilersȱ provideȱ theȱ abilityȱ toȱ defineȱ symbolsȱ onȱ theȱ commandȱ lineȱ thatȱ
initiatesȱtheȱcompilation.ȱThisȱfeatureȱisȱusefulȱwhenȱcompilingȱdifferentȱversionsȱofȱaȱ
programȱ fromȱ theȱ sameȱ sourceȱ file.ȱ Forȱ example,ȱ supposeȱ aȱ particularȱ programȱ
declaresȱanȱarrayȱofȱaȱcertainȱsize.ȱOnȱmachinesȱwithȱlimitedȱmemoryȱtheȱarrayȱmustȱ
beȱsmall,ȱbutȱonȱmachinesȱwithȱlotsȱofȱmemoryȱyouȇdȱpreferȱtoȱmakeȱtheȱarrayȱlarger.ȱ
Ifȱtheȱarrayȱisȱdeclaredȱusingȱaȱsymbolȱlikeȱthis.ȱ
ȱ
int
array[ARRAY_SIZE];
ȱ
thenȱtheȱvalueȱforȱ ARRAY_SIZEȱcanȱbeȱgivenȱonȱtheȱcommandȱlineȱwhenȱtheȱprogramȱisȱ
compiled.ȱ
OnȱUNKȱcompilers,ȱtheȱ -Dȱoptionȱdoesȱthisȱjob.ȱThereȱareȱtwoȱwaysȱtoȱuseȱthisȱ
option.ȱ
ȱ
-Dname
-Dname=stuff
ȱ
Theȱfirstȱformȱdefinesȱtheȱsymbolȱ nameȱtoȱhaveȱtheȱvalueȱone.ȱTheȱsecondȱformȱdefinesȱ
theȱ symbolȇsȱ valueȱ toȱ beȱ theȱ stuffȱ afterȱ theȱ equalȱ sign.ȱ Theȱ Borlandȱ Cȱ compilersȱ forȱ
MSȬDOSȱ provideȱ theȱ sameȱ capabilityȱ withȱ theȱ sameȱ syntax.ȱ Consultȱ yourȱ compilerȇsȱ
documentationȱforȱinformationȱaboutȱyourȱsystem.ȱ
Toȱ returnȱ toȱ ourȱ example,ȱ theȱ commandȱ lineȱ toȱ compileȱ thisȱ programȱ onȱ aȱ
UNIXȱsystemȱmightȱlookȱlikeȱthis:ȱ
ȱ
cc –DARRAY_SIZE=100 prog.c
ȱ
Thisȱ exampleȱ illustratesȱ anotherȱ benefitȱ thatȱ youȱ getȱ byȱ parameterizingȱ
quantitiesȱsuchȱasȱarrayȱsizesȱinȱtheȱprogram.ȱIfȱtheȱarrayȱsizeȱwereȱgivenȱasȱaȱliteralȱ
constantȱinȱtheȱdeclaration,ȱorȱifȱtheȱarrayȱwereȱeverȱaccessedȱwithinȱaȱloopȱthatȱusedȱaȱ
literalȱconstantȱasȱaȱlimit,ȱtheȱtechniqueȱwouldȱnotȱwork.ȱTheȱsymbolicȱconstantȱmustȱ
beȱusedȱwhereverȱyouȱneedȱtoȱreferenceȱtheȱsizeȱofȱtheȱarrays.ȱ
Compilersȱ thatȱ offerȱ commandȬlineȱ definitionȱ ofȱ symbolsȱ usuallyȱ offerȱ
commandȬlineȱunȬdefinitionȱofȱsymbols.ȱOnȱUNIXȱcompilers,ȱtheȱ -Uȱoptionȱperformsȱ
this.ȱ Specifyingȱ -Unameȱ causesȱ theȱ initialȱ definitionȱ ofȱ nameȱ inȱ theȱ programȱ toȱ beȱ
ignored.ȱThisȱfeatureȱisȱusefulȱinȱconjunctionȱwithȱconditionalȱcompilation.ȱ
Download at http://www.pin5i.com/
394ȱ
Chapter 14 The Preprocessorȱ
14.3 Conditional Compilation
ȱ
ȱ
Itȱ isȱ oftenȱ handyȱ toȱ beȱ ableȱ toȱ selectȱ whetherȱ certainȱ statementsȱ orȱ groupsȱ ofȱ
statementsȱ shouldȱ beȱ translatedȱ orȱ ignoredȱ whenȱ compilingȱ aȱ program.ȱ Statementsȱ
usedȱsolelyȱinȱtheȱdebuggingȱofȱaȱprogramȱareȱanȱobviousȱexample.ȱTheyȱshouldȱnotȱ
appearȱ inȱ productionȱ versionsȱ ofȱ theȱ program,ȱ yetȱ youȱ wouldȱ ratherȱ notȱ physicallyȱ
removeȱthemȱfromȱtheȱsourceȱcodeȱasȱtheyȱmightȱbeȱneededȱforȱdebuggingȱagainȱafterȱ
theȱprogramȱhasȱundergoneȱsomeȱmaintenanceȱmodifications.ȱ
ȱ
Conditionalȱcompilationȱisȱperfectȱforȱthisȱpurpose.ȱWithȱconditionalȱcompilation,ȱ
selectedȱpartsȱofȱtheȱcodeȱcanȱbeȱeitherȱcompiledȱnormallyȱorȱcompletelyȱignored.ȱTheȱ
basicȱ constructȱ toȱ supportȱ conditionalȱ compilationȱ isȱ theȱ #ifȱ directiveȱ withȱ itsȱ
matchingȱ#endif.ȱTheȱsyntaxȱforȱitsȱsimplestȱformȱisȱshownȱbelow.ȱ
ȱ
#if constant-expression
statements
#endif
ȱ
Theȱ constant-expressionȱ isȱ evaluatedȱ byȱ theȱ preprocessor.ȱ Ifȱ itsȱ valueȱ isȱ nonzeroȱ
(true),ȱ thenȱ the statementsȱ areȱ compiledȱ normally;ȱ otherwiseȱ theȱ preprocessorȱ
silentlyȱdeletesȱthem.ȱ
ȱ
Aȱconstantȱexpressionȱisȱonȱwhoseȱtermsȱareȱeitherȱliteralȱconstantsȱorȱ #defineȇdȱ
symbols.ȱVariablesȱthatȱdoȱnotȱattainȱtheirȱvaluesȱuntilȱexecutionȱtimeȱareȱnotȱlegalȱinȱ
constantȱexpressionsȱbecauseȱtheirȱvaluesȱcannotȱbeȱpredictedȱatȱcompileȱtime.ȱ
Forȱexample,ȱbracketingȱallȱyourȱdebuggingȱcodeȱlikeȱthis:ȱ
ȱ
#if DEBUG
printf( "x=%d, y=%d\n", x, y );
#endif
ȱ
makesȱitȱeasyȱtoȱeitherȱcompileȱorȱignoreȱtheȱcode.ȱToȱcompileȱit,ȱ
ȱ
#define DEBUG
1
ȱ
wouldȱ beȱ used.ȱ Toȱ ignoreȱ it,ȱ thisȱ symbolȱ wouldȱ beȱ definedȱ asȱ 0ȱ instead.ȱ Theȱ codeȱ
remainsȱinȱtheȱsourcesȱfileȱinȱeitherȱcase.ȱ
ȱ
Anotherȱ useȱ ofȱ conditionalȱ compilationȱ isȱ toȱ selectȱ betweenȱ differentȱ
alternativesȱwhenȱcompiling.ȱToȱsupportȱthisȱcapability,ȱtheȱ #ifȱdirectiveȱhasȱoptionalȱ
#elifȱandȱ#elseȱclauses.ȱTheȱcompleteȱsyntaxȱlooksȱlikeȱthis:ȱ
ȱ
ȱ
Download at http://www.pin5i.com/
14.3 Conditional Compilationȱ
395
#if constant-expression
statements
#elif constant-expression
other statements ...
#else
other statements
#endif
K&R C
ȱ
Thereȱ mayȱ beȱ anyȱ numberȱ ofȱ #elifȱ clauses.ȱ Theȱ constant-expressionȱ inȱ eachȱ isȱ
evaluatedȱ onlyȱ ifȱ noneȱ ofȱ theȱ previousȱ onesȱ areȱ true.ȱ Theȱ statementsȱ inȱ theȱ #elseȱ
clauseȱ areȱ compiledȱ onlyȱ whenȱ allȱ ofȱ theȱ expressionsȱ areȱ false,ȱ otherwiseȱ theyȱ areȱ
ignored.ȱ
ȱ
Theȱ originalȱ K&Rȱ Cȱ didȱ notȱ haveȱ anȱ #elifȱ directive.ȱ However,ȱ directivesȱ canȱ beȱ
nestedȱtoȱachieveȱtheȱsameȱresultȱwithȱsuchȱcompilers.ȱ
Theȱ followingȱ exampleȱ isȱ fromȱ aȱ programȱ thatȱ isȱ soldȱ inȱ severalȱ differentȱ
versions.ȱEachȱversionȱhasȱaȱdifferentȱsetȱofȱoptionalȱfeatures.ȱTheȱchallengeȱinȱwritingȱ
thisȱcodeȱwasȱfiguringȱoutȱhowȱtoȱproduceȱtheȱvariousȱversions.ȱYouȱmustȱavoidȱatȱallȱ
costsȱwritingȱaȱdifferentȱsetȱofȱsourceȱfilesȱforȱeachȱversion!ȱMostȱofȱtheȱcodeȱinȱeachȱsetȱ
wouldȱbeȱidenticalȱandȱmaintainingȱtheȱprogramȱwouldȱbeȱaȱnightmare.ȱFortunately,ȱ
conditionalȱcompilationȱdoesȱtheȱjob.ȱ
ȱ
if( feature_selected == FEATURE1 )
#if
FEATURE1_ENABLED_FULLY
feature1_function( arguments );
#elif FEATURE1_ENABLED_PARTIALLY
feature1_partial_function( arguments );
#else
printf( "To use this feature, send $39.95;"
" allow ten weeks for delivery. \n" );
#endif
ȱ
Thereȱisȱonlyȱoneȱsingleȱsetȱofȱsourceȱfiles.ȱWhenȱtheyȱareȱcompiled,ȱsymbolsȱforȱeachȱ
ofȱtheȱdesiredȱfeaturesȱ(orȱfeatureȱlevels)ȱareȱdefinedȱasȱone,ȱandȱtheȱremainingȱsymbolȱ
areȱdefinedȱasȱzero.ȱ
ȱ
ȱ
ȱ
14.3.1
If Defined
ȱ
Itȱ isȱ alsoȱ possibleȱ toȱ testȱ whetherȱ orȱ notȱ aȱ symbolȱ isȱ defined.ȱ Thisȱ taskȱ isȱ oftenȱ moreȱ
convenientȱforȱconditionalȱcompilationȱbecauseȱtheȱsymbolȱcontrollingȱtheȱcompilationȱ
needȱ notȱ beȱ definedȱ atȱ allȱ unlessȱ theȱ featureȱ itȱ controlsȱ isȱ wanted.ȱ Thisȱ testȱ canȱ beȱ
madeȱinȱanyȱofȱtheȱfollowingȱways:ȱ
Download at http://www.pin5i.com/
Chapter 14 The Preprocessorȱ
396ȱ
ȱ
#if
#ifdef
defined(symbol)
symbol
#if
#ifndef
!defined(symbol)
symbol
ȱ
Theȱ membersȱofȱeachȱofȱtheseȱpairsȱareȱ equivalentȱtoȱ eachȱother,ȱ butȱ theȱ #ifȱformȱ isȱ
moreȱversatileȱbecauseȱtheȱconstantȱexpressionȱmayȱcontainȱadditionalȱterms,ȱasȱin:ȱ
ȱ
#if X > 0 || defined( ABC ) && defined( BCD )
K&R C
ȱ
Dependingȱuponȱhowȱoldȱtheyȱare,ȱsomeȱK&RȱCȱcompilersȱmayȱnotȱincludeȱallȱofȱthisȱ
capability.ȱ
ȱ
ȱ
ȱ
ȱ
14.3.2
Nested Directives
ȱ
Theseȱdirectivesȱmayȱbeȱnestedȱwithinȱoneȱanother,ȱasȱinȱtheȱfollowingȱcodeȱfragment:ȱ
ȱ
#if
defined( OS_UNIX )
#ifdef
OPTION1
unix_version_of_option1();
#endif
#ifdef
OPTION2
unix_version_of_option2();
#endif
#elif defined( OS_MSDOS )
#ifdef
OPTION2
msdos_version_of_option2();
#endif
#endif
ȱ
Inȱ thisȱ example,ȱ theȱ choiceȱ ofȱ operatingȱ systemsȱ determinesȱ whichȱ alternativesȱ areȱ
availableȱ forȱ theȱ differentȱ options.ȱ Theȱ exampleȱ alsoȱ illustratesȱ thatȱ preprocessorȱ
directivesȱmayȱbeȱindentedȱforȱreadabilityȱbyȱprecedingȱthemȱwithȱwhiteȱspace.ȱ
ȱ
Toȱhelpȱ theȱreaderȱkeepȱtrackȱ ofȱcomplicatedȱ nestedȱ directives,ȱitȱ isȱhelpfulȱtoȱ
labelȱeachȱ #endifȱwithȱtheȱexpressionȱfromȱtheȱ #ifȱtoȱwhichȱitȱapplies.ȱThisȱpracticeȱisȱ
particularlyȱusefulȱwhenȱtheȱenclosedȱstatementsȱareȱlengthy.ȱForȱexample:ȱ
Download at http://www.pin5i.com/
14.4 File Inclusionȱ
#ifdef
397
OPTION1
lengthy code for option1;
#else
#endif
lengthy code for alternative;
/* OPTION1 */
ȱ
Someȱcompilersȱallowȱaȱsymbolȱtoȱappearȱonȱanȱ #endifȱdirective,ȱevenȱthoughȱitȱhasȱ
noȱeffect.ȱTheȱStandardȱdoesnȇtȱmentionȱtheȱlegalityȱofȱthisȱpractice,ȱsoȱitȱisȱsaferȱtoȱuseȱ
aȱcomment.ȱ
ȱ
ȱ
ȱ
14.4 File Inclusion
TIP
TIP
TIP
ȱ
Asȱyouȱhaveȱalreadyȱseen,ȱtheȱ #includeȱdirectiveȱcausesȱtheȱcontentsȱofȱanotherȱfileȱtoȱ
beȱcompiledȱasȱifȱ theyȱactuallyȱ appearedȱ inȱplaceȱofȱtheȱ #includeȱdirective.ȱTheȱwayȱ
thisȱ substitutionȱ isȱ performedȱ isȱ simple:ȱ theȱ preprocessorȱ removesȱ theȱ directiveȱ andȱ
substitutesȱtheȱcontentsȱofȱtheȱnamedȱfile.ȱThus,ȱaȱheaderȱfileȱthatȱisȱincludedȱintoȱtenȱ
otherȱsourceȱfilesȱisȱactuallyȱcompiledȱtenȱtimes.ȱ
ȱ
Thisȱfactȱsuggestsȱthatȱusingȱ #includeȱfilesȱinvolvesȱsomeȱoverhead,ȱbutȱthereȱareȱtwoȱ
veryȱgoodȱreasonsȱwhyȱyouȱshouldȱnotȱworryȱaboutȱit.ȱFirst,ȱthereȱisȱactuallyȱnotȱmuchȱ
extraȱoverhead.ȱIfȱaȱsetȱofȱdeclarationsȱisȱneededȱinȱtwoȱsourceȱfiles,ȱitȱwillȱtakeȱnearlyȱ
theȱ sameȱ amountȱ ofȱ timeȱ toȱ compileȱ thoseȱ sourceȱ filesȱ ifȱ theȱ declarationsȱ areȱ
duplicatedȱ asȱ itȱ wouldȱ ifȱ theȱ declarationsȱ wereȱ #includeȇdȱ inȱ theȱ files.ȱ Also,ȱ theȱ
overheadȱ occursȱ onlyȱ whenȱ theȱ programȱ isȱ beingȱ compiled,ȱ soȱ runtimeȱ efficiencyȱ isȱ
notȱaffected.ȱMoreȱimportantly,ȱthough,ȱtheȱadvantagesȱofȱhavingȱtheȱdeclarationsȱinȱaȱ
headerȱfileȱareȱsignificant.ȱTheyȱdoȱnotȱhaveȱtoȱbeȱreplicatedȱinȱeveryȱfileȱinȱwhichȱtheyȱ
areȱneeded,ȱsoȱmaintainingȱthemȱisȱeasier.ȱ
ȱ
Theȱ factȱ thatȱ everythingȱ inȱ theȱ headerȱ fileȱ isȱ compiledȱ eachȱ timeȱ itȱ isȱ #includeȇdȱ
suggestsȱthatȱeachȱheaderȱfileȱshouldȱonlyȱcontainȱdeclarationsȱforȱoneȱsetȱofȱfunctionsȱ
orȱ data.ȱ Itȱ isȱ betterȱ toȱ useȱ severalȱ headerȱ files,ȱ eachȱ containingȱ theȱ declarationsȱ
appropriateȱforȱaȱparticularȱfunctionȱorȱmodule,ȱthanȱtoȱputȱallȱofȱtheȱdeclarationsȱforȱaȱ
programȱinȱoneȱgiantȱheaderȱfile.ȱ
ȱ
Theȱprinciplesȱofȱprogramȱdesignȱandȱmodularityȱsupportȱthisȱapproachȱasȱwell.ȱItȱisȱ
betterȱtoȱincludeȱintoȱaȱfileȱonlyȱtheȱnecessaryȱdeclarationsȱsoȱthatȱtheȱstatementsȱinȱtheȱ
fileȱcannotȱaccidentallyȱaccessȱfunctionsȱorȱvariablesȱthatȱshouldȱbeȱprivate.ȱAlso,ȱitȱisȱ
easierȱtoȱmaintainȱaȱsetȱofȱdeclarationsȱifȱyouȱdonȇtȱhaveȱtoȱwadeȱthroughȱhundredsȱofȱ
linesȱofȱunrelatedȱcodeȱtoȱfindȱthem.ȱ
Download at http://www.pin5i.com/
Chapter 14 The Preprocessorȱ
398ȱ
14.4.1
Library Includes
ȱ
Theȱcompilerȱsupportsȱtwoȱdifferentȱtypesȱofȱ#includeȇs:ȱlibraryȱfilesȱandȱlocalȱfiles.ȱInȱ
fact,ȱthereȱisȱlittleȱdifferenceȱbetweenȱthem.ȱ
Libraryȱheaderȱfilesȱareȱincludedȱusingȱtheȱfollowingȱsyntax.ȱ
ȱ
#include <filename>
ȱ
Thereȱarenȇtȱanyȱrestrictionsȱonȱtheȱfilename,ȱalthoughȱbyȱconventionȱtheȱnamesȱofȱtheȱ
standardȱlibraryȱheaderȱfilesȱendȱwithȱaȱ.hȱsuffix. 46
Theȱ compilerȱ searchesȱ forȱ libraryȱ headerȱ filesȱ byȱ lookingȱ aȱ Ȉseriesȱ ofȱ standardȱ
locationsȈȱ definedȱ byȱ theȱ implementation.ȱ Theȱ documentationȱ forȱ yourȱ particularȱ
compilerȱ shouldȱ indicateȱ whatȱ theȱ standardȱ locationsȱ areȱ andȱ howȱ youȱ canȱ changeȱ
themȱ orȱ addȱ otherȱ locationsȱ toȱ theȱ list.ȱ Forȱ example,ȱ Cȱ compilersȱ onȱ UNIXȱ systemsȱ
typicallyȱlookȱforȱlibraryȱheaderȱfilesȱinȱaȱdirectoryȱcalledȱ /usr/include.ȱAȱcommandȱ
lineȱ optionȱ toȱ theȱcompilerȱ letsȱyouȱaddȱadditionalȱdirectoriesȱ toȱ thisȱlistȱsoȱthatȱ youȱ
canȱ createȱ yourȱ ownȱ librariesȱ ofȱ headerȱ files.ȱ Again,ȱ consultȱ yourȱ compilerȇsȱ
documentationȱtoȱseeȱhowȱyourȱsystemȱbehaves.ȱ
ȱ
ȱ
ȱ
14.4.2
Local Includes
ȱ
Hereȱisȱtheȱotherȱformȱofȱtheȱ#includeȱdirective.ȱ
ȱ
#include "filename"
ȱ
Theȱ Standardȱ letsȱ eachȱ implementationȱ decideȱ whetherȱ toȱ treatȱ theȱ localȱ formȱ ofȱ
#includeȱ differentlyȱ thanȱ theȱ libraryȱ form.ȱ Ifȱ anyȱ specialȱ processingȱ thatȱ isȱ providedȱ
forȱ theȱ localȱ formȱ failsȱ forȱ aȱ givenȱ file,ȱ thenȱ theȱ compilerȱ searchesȱ forȱ theȱ fileȱ asȱ ifȱ aȱ
libraryȱ #includeȱhadȱbeenȱused.ȱAȱcommonȱstrategyȱforȱprocessingȱlocalȱincludesȱisȱtoȱ
lookȱ inȱ theȱ currentȱ directoryȱ forȱ theȱ file.ȱ ȱ Ifȱ theȱ fileȱ isȱ notȱ found,ȱ thenȱ theȱ standardȱ
locationsȱareȱsearchedȱasȱusual.ȱ
Youȱcanȱwriteȱallȱofȱyourȱ#includeȱstatementsȱwithȱquotationȱmarksȱinsteadȱofȱ
angleȱbrackets.ȱHowever,ȱsomeȱcompilersȱwouldȱwasteȱaȱsmallȱamountȱofȱtimeȱwhenȱ
tryingȱtoȱlocateȱlibraryȱincludeȱfiles.ȱAȱbetterȱreasonȱtoȱuseȱtheȱangleȱbracketȱformȱforȱ
libraryȱ filesȱ isȱ theȱ informationȱ thatȱ itȱ givesȱ theȱ reader.ȱ Theȱ angleȱ bracketsȱ makeȱ itȱ
obviousȱthatȱ
ȱ
#include <erno.h>ȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
46
ȱTechnically,ȱlibraryȱheaderȱfilesȱneedȱnotȱbeȱstoredȱasȱfilesȱatȱall,ȱthoughȱthisȱwonȇtȱbeȱapparentȱtoȱtheȱprogrammerȱ
Download at http://www.pin5i.com/
14.4 File Inclusionȱ
399
referencesȱaȱlibraryȱfile.ȱWithȱtheȱalternateȱformȱ
ȱ
#include "errno.h"
ȱ
itȱisȱnotȱclearȱwhetherȱtheȱlibraryȱheaderȱorȱaȱlocalȱfileȱofȱtheȱsameȱnameȱisȱbeingȱused.ȱȱ
Theȱonlyȱwayȱtoȱfindȱoutȱforȱsureȱisȱtoȱexamineȱtheȱdirectoryȱinȱwhichȱtheȱcompilationȱ
isȱperformed.ȱ
Aȱ variantȱ supportedȱ onȱ Unixȱ systemsȱ andȱ theȱ Borlandȱ Cȱ compilersȱ isȱ theȱ
absoluteȱ pathname,ȱ whichȱ identifiesȱ notȱ onlyȱ theȱ nameȱ ofȱ aȱ fileȱ butȱ itsȱ location.ȱ Anȱ
absoluteȱpathnameȱonȱaȱUNIXȱsystemȱbeginsȱwithȱaȱslash,ȱlikeȱthis:ȱ
ȱ
/home/fred/C/my_proj/declaration2.h
ȱ
OnȱMSȬDOSȱsystems,ȱbackslashesȱareȱusedȱinsteadȱofȱslashes.ȱIfȱanȱabsoluteȱpathnameȱ
isȱ usedȱ inȱ eitherȱ formȱ ofȱ #include,ȱ thenȱ theȱ usualȱ directoryȱ searchingȱ isȱ skippedȱ
becauseȱtheȱpathnameȱspecifiesȱtheȱlocationȱofȱtheȱfile.ȱ
ȱ
ȱ
ȱ
14.4.3
Nested File Inclusion
ȱ
Itȱ isȱ possibleȱ toȱ putȱ #includeȱ directivesȱ inȱ filesȱ thatȱ areȱ included.ȱ Forȱ example,ȱ
considerȱ aȱ collectionȱ ofȱ functionsȱ thatȱ readȱ inputȱ andȱ thenȱ performȱ variousȱ inputȱ
validationȱtasks.ȱTheȱvalidatedȱdataȱisȱthenȱreturned.ȱWhenȱendȱofȱfileȱisȱreached,ȱtheȱ
constantȱEOFȱisȱreturnedȱinstead.ȱ
Prototypesȱ forȱ theseȱ functionsȱ wouldȱ beȱ putȱ inȱ aȱ headerȱ fileȱ andȱ #includeȇedȱ
intoȱ eachȱ sourceȱ fileȱ thatȱ usesȱ theȱ functions.ȱ However,ȱ everyȱ fileȱ thatȱ usesȱ theseȱ
functionsȱ mustȱ alsoȱ includeȱ stdio.hȱ toȱ getȱ theȱ declarationȱ forȱ EOF.ȱ Therefore,ȱ theȱ
headerȱfileȱcontainingȱtheȱprototypesȱmayȱalsoȱcontain:ȱ
ȱ
#include <stdio.h>
TIP
ȱ
soȱthatȱincludingȱtheȱheaderȱfileȱautomaticallyȱbringsȱinȱtheȱstandardȱI/Oȱdeclarationsȱ
asȱwell.ȱ
TheȱStandardȱrequiresȱthatȱnestedȱ #includeȱfilesȱbeȱsupportedȱtoȱaȱdepthȱofȱatȱ
leastȱeight,ȱbutȱitȱdoesnȇtȱimposeȱaȱmaximumȱlimitȱonȱnestingȱdepth.ȱInȱpractice,ȱthereȱ
isȱlittleȱreasonȱtoȱnestȱ#includeȇsȱtoȱdepthsȱgreaterȱthanȱoneȱorȱtwo.ȱ
ȱ
Aȱdisadvantageȱofȱnestedȱ #includeȱfilesȱisȱthatȱtheyȱmakeȱitȱdifficultȱtoȱdetermineȱtheȱ
trueȱ dependenciesȱ ofȱ sourceȱ filesȱ onȱ oneȱ another.ȱ Someȱ programs,ȱ suchȱ asȱ theȱ UNIXȱ
makeȱutility,ȱmustȱknowȱtheseȱdependenciesȱinȱorderȱtoȱdetermineȱwhichȱfilesȱneedȱtoȱ
beȱcompiledȱafterȱsomeȱfilesȱareȱmodified.ȱ
Download at http://www.pin5i.com/
400ȱ
Chapter 14 The Preprocessorȱ
Anotherȱdisadvantageȱofȱnestedȱ #includeȇsȱisȱtheȱpossibilityȱofȱoneȱheaderȱfileȱ
beingȱincludedȱmultipleȱtimes.ȱToȱillustrateȱthisȱerror,ȱconsiderȱthisȱcode:ȱ
ȱ
#include "x.h"
#include "x.h"
ȱ
Itȱ isȱ obviousȱ hereȱ thatȱ theȱ fileȱ x.hȱ isȱ beingȱ includedȱ twice.ȱ Noȱ oneȱ wouldȱ everȱ writeȱ
thisȱcodeȱintentionally.ȱButȱthisȱcodeȱ
ȱ
#include "a.h"
#include "b.h"
ȱ
seemsȱfine.ȱIfȱbothȱa.hȱandȱb.hȱcontainȱaȱnestedȱ#includeȱofȱx.h,ȱthenȱx.hȱisȱonceȱagainȱ
beingȱincludedȱtwice,ȱonlyȱthisȱtimeȱitȱisȱnotȱasȱobvious.ȱ
Multipleȱ inclusionȱ occursȱ mostȱ oftenȱ inȱ largerȱ programsȱ withȱ aȱ multitudeȱ ofȱ
headerȱfiles,ȱthusȱitȱisȱnotȱeasyȱtoȱfind.ȱAȱsimpleȱsolutionȱtoȱtheȱproblemȱisȱprovidedȱbyȱ
theȱconditionalȱcompilationȱfeature.ȱIfȱallȱheaderȱfilesȱareȱwrittenȱas:ȱ
ȱ
#ifndef _HEADERNAME_H
#define _HEADERNAME_H 1
/*
** All the stuff that you want in the header file
*/
#endif
ȱ
thenȱ theȱ risksȱ ofȱ multipleȱ inclusionȱ areȱ eliminated.ȱ Theȱ firstȱ timeȱ theȱ headerȱ fileȱ isȱ
included,ȱitȱisȱprocessedȱnormallyȱandȱtheȱsymbolȱ _HEADERNAME_Hȱisȱdefinedȱtoȱbeȱone.ȱ
Ifȱ theȱ headerȱ isȱ includedȱ again,ȱ itsȱ entireȱ contentsȱ areȱ ignoredȱ byȱ theȱ conditionalȱ
compilationȱdirectives.ȱ Theȱsymbolȱ _HEADERNAME_Hȱisȱnamedȱafterȱtheȱfilenameȱofȱ theȱ
includeȱfileȱinȱorderȱtoȱavoidȱconflictsȱwithȱsimilarȱsymbolsȱinȱotherȱheaderȱfiles.ȱ
Noteȱthatȱtheȱdefinitionȱinȱtheȱpreviousȱexampleȱcanȱalsoȱbeȱwrittenȱ
ȱ
#define _HEADERNAME_H
ȱ
withȱexactlyȱtheȱsameȱeffect.ȱEvenȱthoughȱitsȱvalueȱisȱnowȱtheȱemptyȱstringȱratherȱthanȱ
Ȉ1Ȉ,ȱtheȱsymbolȱisȱstillȱdefined.ȱ
Keepȱ inȱ mind,ȱ though,ȱ thatȱ theȱ preprocessorȱ mustȱ stillȱ readȱ theȱ entireȱ headerȱ
file,ȱevenȱifȱtheȱwholeȱfileȱisȱignored.ȱBecauseȱthisȱprocessingȱslowsȱdownȱcompilation,ȱ
multipleȱ inclusion,ȱ whetherȱ byȱ nestedȱ #includeȇsȱ orȱ not,ȱ shouldȱ beȱ avoidedȱ whenȱ
possible.ȱ
Download at http://www.pin5i.com/
14.5 Other Directivesȱ
401
14.5 Other Directives
ȱ
Thereȱareȱaȱfewȱadditionalȱdirectivesȱsupportedȱbyȱtheȱpreprocessor.ȱFirst,ȱtheȱ #errorȱ
directiveȱletsȱyouȱgenerateȱerrorȱmessagesȱwhenȱtheȱprogramȱisȱcompiled.ȱHereȱisȱitsȱ
syntax:ȱ
ȱ
#error
text of error message
ȱ
Theȱfollowingȱcodeȱfragmentȱshowsȱhowȱyouȱmightȱuseȱthisȱdirective.ȱ
ȱ
#if
defined( OPTION_A )
stuff needed for option Aȱ
#elif defined( OPTION_B )
stuff needed for option B
#elif defined( OPTION_C )
stuff needed for option C
#else
#error No option selected!
#endif
ȱ
Somewhatȱlessȱusefulȱisȱtheȱ#lineȱdirective,ȱwhichȱhasȱthisȱform:ȱ
ȱ
#line
number "string"
ȱ
Itȱinformsȱtheȱpreprocessorȱthatȱnumberȱisȱtheȱlineȱnumberȱofȱtheȱnextȱlineȱofȱinput.ȱIfȱ
theȱoptionalȱ"string"ȱisȱgiven,ȱtheȱpreprocessorȱtakesȱitȱasȱtheȱnameȱofȱtheȱcurrentȱfile.ȱȱ
Specifically,ȱthisȱdirectiveȱmodifiesȱtheȱvalueȱofȱtheȱ __LINE__ȱsymbolȱand,ȱoptionally,ȱ
theȱ__FILE__ȱsymbolȱasȱwell.ȱ
Thisȱdirectiveȱisȱmostȱoftenȱusedȱinȱprogramsȱthatȱtranslateȱotherȱlanguagesȱtoȱ
Cȱ code.ȱErrorȱ messagesȱproducedȱbyȱtheȱCȱ compilerȱ canȱ referenceȱ theȱfileȱ nameȱ andȱ
lineȱ numbersȱ ofȱ theȱ originalȱ sourceȱ fileȱ insteadȱ ofȱ theȱ intermediateȱ Cȱ sourceȱ fileȱ
producedȱbyȱtheȱtranslatingȱprogram.ȱ
Theȱ #pragmaȱdirectiveȱisȱaȱmechanismȱthatȱsupportsȱimplementationȬdependentȱ
directives.ȱ Itsȱ syntaxȱ isȱ implementationȱ dependent.ȱ Anȱ environmentȱ mayȱ provideȱ
#pragmaȇsȱ toȱ allowȱ optionsȱ orȱ otherȱ processingȱ notȱ availableȱ anyȱ otherȱ way.ȱ Forȱ
example,ȱsomeȱcompilersȱuseȱ#pragmaȇsȱtoȱturnȱlistingsȱonȱorȱoffȱduringȱcompilationȱorȱ
toȱ insertȱ assemblyȱ codeȱ intoȱ Cȱ programs.ȱ Pragmasȱ areȱ inherentlyȱ notȱ portable.ȱ
Unrecognizedȱ #pragmaȱ directivesȱ areȱ ignoredȱ byȱ theȱ preprocessor,ȱ andȱ twoȱ differentȱ
compilersȱmightȱinterpretȱtheȱsameȱ#pragmaȱinȱdifferentȱways.ȱ
Finally,ȱ theȱ nullȱ directiveȱ isȱ aȱ lineȱ thatȱ beginsȱ withȱ aȱ poundȱ signȱ butȱ containsȱ
nothingȱ else.ȱ Theseȱ directivesȱ areȱ simplyȱ deletedȱ byȱ theȱ preprocessor.ȱ Theȱ nullȱ
directivesȱinȱtheȱfollowingȱexampleȱemphasizeȱtheȱ#includeȱdirectiveȱbyȱseparatingȱitȱ
Download at http://www.pin5i.com/
402ȱ
Chapter 14 The Preprocessorȱ
fromȱtheȱsurroundingȱcode.ȱ
ȱ
#
#include <stido.h>
#
ȱ
Theȱsameȱeffectȱcanȱbeȱachievedȱwithȱblankȱlines.ȱ
ȱ
ȱ
ȱ
14.6 Summary
ȱ
TheȱfirstȱstepȱinȱcompilingȱaȱCȱprogramȱisȱtoȱpreproeessȱit.ȱTheȱpreprocessorȱmaintainsȱ
fiveȱsymbols,ȱwhichȱareȱdescribedȱinȱTableȱ14.1.ȱ
Theȱ #defineȱ directiveȱ attachesȱ aȱ symbolicȱ nameȱ toȱ anȱ arbitraryȱ sequenceȱ ofȱ
characters.ȱ Forȱ example,ȱ theseȱ charactersȱ mayȱ beȱ literalȱ constants,ȱ expressions,ȱ orȱ
programȱ statements.ȱ Theȱ sequenceȱ isȱ terminatedȱ byȱ theȱ endȱ ofȱ theȱ line.ȱ Longȱ
sequencesȱofȱcharactersȱmayȱbeȱsplitȱoverȱmultipleȱlinesȱbyȱendingȱeachȱlineȱexceptȱtheȱ
lastȱoneȱwithȱaȱbackslash.ȱMacrosȱareȱdefinedȱsequencesȱintoȱwhichȱargumentȱvaluesȱ
areȱsubstituted.ȱWhenȱaȱmacroȱisȱinvoked,ȱvaluesȱareȱgivenȱforȱeachȱofȱitsȱarguments.ȱ
Toȱ preventȱ errorsȱ withȱ macrosȱ thatȱ mayȱ appearȱ inȱ egressions,ȱ surroundȱ theȱ entireȱ
definitionȱofȱtheȱmacroȱwithȱparentheses.ȱAlso,ȱsurroundȱeachȱoccurrenceȱofȱtheȱmacroȱ
parametersȱinȱtheȱdefinitionȱwithȱparentheses.ȱ #defineȱmayȱbeȱusedȱtoȱȈrewriteȈȱtheȱCȱ
languageȱsoȱthatȱitȱresemblesȱanotherȱlanguage.ȱ
Theȱ #argumentȱconstructȱisȱconvertedȱbyȱtheȱpreprocessorȱintoȱtheȱstringȱliteralȱ
ȈargumentȈ.ȱȱTheȱ##ȱoperatorȱconcatenatesȱtheȱtextȱappearingȱonȱeachȱsideȱofȱit.ȱ
Someȱ tasksȱ canȱ beȱ implementedȱ withȱ bothȱ macrosȱ andȱ functions.ȱ However,ȱ
macrosȱareȱtypeless,ȱwhichȱcanȱbeȱanȱadvantage.ȱMacrosȱexecuteȱfasterȱthanȱfunctionsȱ
becauseȱ thereȱ isȱ noȱ overheadȱ usedȱ callingȱ orȱ returningȱ fromȱ theȱ function,ȱ howeverȱ
usingȱ macrosȱ ratherȱ thanȱ functionsȱ usuallyȱ increasesȱ theȱ sizeȱ ofȱ theȱ program.ȱ Also,ȱ
argumentsȱwithȱsideȱeffectsȱcanȱcauseȱunexpectedȱresultsȱwithȱmacros.ȱTheȱbehaviorȱofȱ
theseȱargumentsȱwithȱfunctionsȱisȱmoreȱpredictable.ȱBecauseȱofȱtheseȱdifferences,ȱitȱisȱ
importantȱtoȱuseȱaȱnamingȱconventionȱthatȱletsȱtheȱprogrammerȱdetermineȱwhetherȱanȱ
identifierȱisȱaȱfunctionȱorȱaȱmacro.ȱ
Withȱ manyȱ compilers,ȱ symbolsȱ canȱ beȱ definedȱ fromȱ theȱ commandȱ line.ȱ Theȱ
#undefȱdirectiveȱcausesȱtheȱinitialȱdefinitionȱforȱaȱnameȱtoȱbeȱignored.ȱ
Youȱcanȱcreateȱdifferentȱversionsȱofȱaȱprogramȱfromȱaȱsingleȱsetȱofȱsourceȱfilesȱ
byȱ usingȱ conditionalȱ compilation.ȱ Theȱ #ifȱ directiveȱ eitherȱ includesȱ orȱ ignoresȱ aȱ
sequenceȱ ofȱ codeȱ accordingȱ toȱ theȱ resultȱ ofȱ aȱ compileȬtimeȱ test.ȱ Whenȱ theȱ #elifȱ andȱ
#elseȱ directivesȱ areȱ alsoȱ used,ȱ youȱ canȱ selectȱ oneȱ ofȱ severalȱ sequencesȱ ofȱ codeȱ to
Download at http://www.pin5i.com/
14.8 Summary of Programming Tipsȱ
403
compile.ȱInȱadditionȱtoȱtestingȱconstantȱexpressions,ȱtheseȱdirectivesȱcanȱtestȱwhetherȱ
orȱnotȱsymbolsȱareȱdefined.ȱTheȱ#ifdefȱandȱ#ifndefȱdirectivesȱalsoȱperformȱthisȱtask.ȱ
Theȱ #includeȱdirectiveȱperformsȱfileȱinclusion.ȱItȱhasȱtwoȱforms.ȱIfȱtheȱfilenameȱ
isȱenclosedȱinȱangleȱbrackets,ȱtheȱcompilerȱsearchesȱforȱtheȱfileȱinȱanȱimplementationȬ
definedȱstandardȱplace.ȱThisȱformȱisȱusuallyȱusedȱwhenȱincludingȱlibraryȱheaders.ȱInȱ
theȱotherȱform,ȱtheȱfilenameȱisȱenclosedȱinȱquotationȱmarks.ȱEachȱimplementationȱmayȱ
processȱthisȱformȱdifferently.ȱHowever,ȱifȱanyȱspecialȱprocessingȱforȱthisȱformȱfailsȱtoȱ
locateȱtheȱ file,ȱthenȱ theȱstandardȱplaceȱisȱsearchedȱinstead.ȱ Thisȱformȱisȱusuallyȱusedȱ
forȱincludingȱfilesȱthatȱyouȱhaveȱwritten.ȱFileȱinclusionȱmayȱbeȱnested,ȱthoughȱthereȱisȱ
usuallyȱ littleȱ needȱ forȱ nestingȱ thatȱ isȱ moreȱ thanȱ oneȱ orȱ twoȱ levelsȱ deep.ȱ Nestedȱ
includesȱ increaseȱ theȱ riskȱ ofȱ includingȱ aȱ fileȱ moreȱ thanȱ once,ȱ andȱ makeȱ itȱ harderȱ toȱ
determineȱwhichȱincludeȱfilesȱaȱgivenȱsourceȱfileȱdependsȱon.ȱ
Theȱ#errorȱdirectiveȱgeneratesȱanȱerrorȱmessageȱatȱcompileȱtimeȱcontainingȱtextȱ
ofȱyourȱchoice.ȱTheȱ #lineȱdirectiveȱallowsȱyouȱtoȱtellȱtheȱcompilerȱtheȱlineȱnumberȱofȱ
theȱ nextȱ lineȱ ofȱ inputȱ and,ȱ optionally,ȱ theȱ nameȱ ofȱ theȱ fileȱ itȱ cameȱ from.ȱ Theȱ
implementationȬdependentȱ #pragmaȱ directiveȱ allowsȱ compilersȱ toȱ provideȱ
nonstandardȱprocessingȱsuchȱasȱinsertingȱinlineȱassemblyȱcodeȱintoȱaȱfunction.ȱ
ȱ
ȱ
ȱ
14.7 Summary of Cautions
ȱ
1. Doȱ notȱ putȱ aȱ semicolonȱ atȱ theȱ endȱ ofȱ aȱ macroȱ definitionȱ thatȱ formsȱ anȱ entireȱ
statementȱ(pageȱ385).ȱ
2. Usingȱ macroȱ argumentsȱ inȱ theȱ definitionȱ withoutȱ surroundingȱ themȱ withȱ
parenthesesȱ(pageȱ386).ȱ
3. Notȱsurroundingȱtheȱentireȱmacroȱdefinitionȱwithȱparenthesesȱ(pageȱ387).ȱ
ȱ
ȱ
ȱ
14.8 Summary of Programming Tips
ȱ
1. Avoidȱ usingȱ aȱ #defineȱ forȱ longȱ sequencesȱ ofȱ codeȱ thatȱ canȱ beȱ implementedȱ asȱ aȱ
functionȱ(pageȱ385).ȱ
2. Inȱ macrosȱ thatȱ evaluateȱ expressions,ȱ parenthesizeȱ allȱ occurrencesȱ ofȱ theȱ macroȱ
arguments,ȱandȱsurroundȱtheȱentireȱdefinitionȱwithȱparenthesesȱ(pageȱ387).ȱ
3. Avoidȱusingȱ#defineȱmacrosȱtoȱcreateȱaȱnewȱlanguageȱ(pageȱ387).ȱ
Download at http://www.pin5i.com/
404ȱ
Chapter 14 The Preprocessorȱ
4. Adoptȱaȱnamingȱconventionȱthatȱmakesȱitȱobviousȱwhenȱaȱ #defineȱmacroȱisȱbeingȱ
usedȱ(pageȱ391).ȱ
5. Useȱ fileȱ inclusionȱ whereverȱ itȱ isȱ appropriate;ȱ doȱ notȱ worryȱ aboutȱ overheadȱ (pageȱ
397).ȱ
6. Aȱheaderȱfileȱshouldȱonlyȱcontainȱdeclarationsȱforȱoneȱsetȱofȱfunctionsȱand/orȱdataȱ
(pageȱ397).ȱ
7. Separateȱheaderȱfilesȱforȱdifferentȱsetsȱofȱdeclarationsȱimprovesȱinformationȱhidingȱ
(pageȱ397).ȱ
8. Nestingȱ #includeȱ filesȱ makesȱ itȱ moreȱ difficultȱ toȱ determineȱ theȱ dependenciesȱ
amongȱsourceȱfilesȱ(pageȱ399).ȱ
ȱ
ȱ
ȱ
14.9 Questions
ȱ
1. Theȱ preprocessorȱ definesȱ fiveȱ symbolsȱ thatȱ giveȱ theȱ nameȱ ofȱ theȱ fileȱ beingȱ
compiled,ȱ theȱ currentȱ lineȱ numberȱ inȱ thatȱ file,ȱ theȱ currentȱ dateȱ andȱ time,ȱ andȱ
whetherȱtheȱcompilerȱisȱanȱANSIȱcompiler.ȱNameȱoneȱwayȱinȱwhichȱeachȱofȱtheseȱ
symbolsȱmightȱbeȱuseful.ȱ
2. Nameȱtwoȱadvantagesȱofȱusingȱ#defineȇdȱnamesȱinȱplaceȱofȱliteralȱconstants.ȱ
3. Writeȱ aȱ macroȱ forȱ debuggingȱ thatȱ willȱ printȱ arbitraryȱ expressions.ȱ Itȱ shouldȱ beȱ
calledȱwithȱtwoȱarguments.ȱTheȱfirstȱisȱaȱ printfȱformatȱcode,ȱandȱtheȱsecondȱisȱtheȱ
expressionȱtoȱbeȱprinted.ȱ
4. Whatȱwillȱtheȱfollowingȱprogramȱprint?ȱBeȱsureȱtoȱexpandȱtheȱ#defineȇsȱcarefully!ȱ
ȱ
#define MAX(a,b)
#define SQUARE(x)
#define DOUBLE(x)
main()
{
int
(a)>(b)?(a):(b)
x*x
x+x
x, y, z;
y = 2; z = 3;
x = MAX(y,z);
/* a */ printf( "%d %d %d\n", x, y, z );
y = 2; z = 3;
x = MAX(++y,++z);
ȱ
Download at http://www.pin5i.com/
14.9 Questionsȱ
405
/* b */ printf( "%d %d %d\n", x, y, z );
x
y
z
/* c */
= 2;
= SQUARE(x);
= SQUARE(x+6);
printf( "%d %d %d\n", x, y, z );
x
y
z
/* d */
}
= 2;
= 3;
= MAX(5*DOUBLE(x),++y);
printf( "%d %d %d\n", x, y, z );
5. Theȱ putcharȱfunctionȱisȱdefinedȱinȱtheȱfileȱ stdio.hȱasȱaȱmacro,ȱdespiteȱtheȱfactȱthatȱ
itȱisȱfairlyȱlong.ȱWhyȱdoȱyouȱthinkȱitȱwasȱdefinedȱthisȱway?ȱ
6. What,ȱifȱanything,ȱisȱwrongȱwithȱtheȱfollowingȱprogramȱfragment?ȱ
ȱ
/*
** Process all the values in the array.
*/
result = 0;
i = 0;
while( i < SIZE ){
result += process( value[ i++ ] );
}
7. What,ȱifȱanything,ȱisȱwrongȱwithȱtheȱfollowingȱprogramȱfragment?ȱ
ȱ
#define SUM( value )
( ( value ) + ( value ) )
int
array[SIZE];
...
/*
** Sum all the values in the array.
*/
sum = 0;
i = 0;
while( i < SIZE )
sum += SUM( array[ i++ ] );
8. What,ȱifȱanything,ȱisȱwrongȱwithȱtheȱfollowingȱcodeȱfragments?ȱ
ȱ
Inȱfileȱheader1.h:ȱ
#ifndef
#define
#include
ȱ
_HEADER1_H
_HEADER1_H
"header2.h"
otherȱdeclarationsȱ
#endif
Download at http://www.pin5i.com/
406ȱ
Chapter 14 The Preprocessorȱ
ȱ
Inȱfileȱheader2.h:ȱ
#ifndef
#define
#include
ȱ
_HEADER2_H
_HEADER2_H
"header1.h"
otherȱdeclarationsȱ
#endif
9. Inȱ anȱ attemptȱ toȱ improveȱ portability,ȱ oneȱ programmerȱ wroteȱ theȱ followingȱ
declarations.ȱ
ȱ
#if sizeof( int ) == 2
typedef long int32;
#else
typedef int int32;
#endif
ȱ
What,ȱifȱanything,ȱisȱwrongȱwithȱthem?ȱ
ȱ
ȱ
ȱ
14.10 Programming Exercises
ȱ
1. Theȱ companyȱ youȱ areȱ workingȱ forȱ marketsȱ aȱ programȱ thatȱ handlesȱ financialȱ
transactionsȱ andȱ printsȱ reportsȱ aboutȱ them.ȱ Toȱ broadenȱ theȱ potentialȱ market,ȱ theȱ
programȱ isȱ soldȱ inȱ severalȱ editions,ȱ eachȱ withȱ variousȱ combinationsȱ ofȱ options—
theȱ moreȱ options,ȱ theȱ higherȱ theȱ price.ȱ Yourȱ taskȱ isȱ toȱ implementȱ theȱ codeȱ forȱ aȱ
certainȱprintingȱfunctionȱsoȱthatȱitȱcanȱbeȱeasilyȱcompiledȱtoȱproduceȱtheȱdifferentȱ
versionsȱofȱtheȱprogram.ȱ
Yourȱfunctionȱwillȱbeȱnamedȱ print_ledger.ȱItȱtakesȱaȱsingleȱ intȱargument,ȱandȱ
doesȱ notȱ returnȱ anyȱ value.ȱ Itȱ shouldȱ callȱ oneȱ orȱ moreȱ ofȱ theȱ followingȱ functionsȱ
dependingȱonȱwhichȱ(ifȱany)ȱsymbolsȱareȱdefinedȱwhenȱtheȱfunctionȱisȱcompiled.ȱ
ȱ
If this symbol is defined…
Then you call this function.
OPTION_LONG
OPTION_DETAILED
(neither)ȱ
print_ledger_long
print_ledger_detailed
print_ledger_default
ȱ
Eachȱ ofȱ theseȱ functionsȱ alsoȱ takesȱ aȱ singleȱ intȱ argument.ȱ Passȱ theȱ valueȱ youȱ
receivedȱtoȱwhicheverȱfunction(s)ȱyouȱcall.ȱ
2. Writeȱaȱfunctionȱthatȱreturnsȱaȱvalueȱindicatingȱtheȱtypeȱofȱcomputerȱonȱwhichȱitȱisȱ
running.ȱ Theȱ functionȱ willȱ heȱ usedȱ inȱ aȱ programȱ thatȱ runsȱ onȱ aȱ wideȱ varietyȱ ofȱ
computers.ȱ
Download at http://www.pin5i.com/
14.10 Programming Exercisesȱ
407
Weȱ willȱ useȱ conditionalȱ compilationȱ toȱ accomplishȱ thisȱ magic.ȱ Yourȱ functionȱ
shouldȱ beȱ calledȱ cpu_type,ȱ andȱ shouldȱ notȱ takeȱ anyȱ arguments.ȱ Whenȱ yourȱ
functionȱisȱcompiled,ȱoneȱofȱtheȱsymbolsȱinȱtheȱȈDefinedȈȱcolumnȱofȱtheȱtableȱbelowȱ
mayȱ beȱ defined.ȱ Yourȱ functionȱ shouldȱ returnȱ theȱ correspondingȱ symbolȱ fromȱ theȱ
ȈReturnedȈȱ column.ȱ Ifȱ noneȱ ofȱ theȱ symbolsȱ inȱ theȱ leftȱ columnȱ wereȱ defined,ȱ thenȱ
theȱ valueȱ CPU_UNKHOWNȱ shouldȱ beȱ returned.ȱ Ifȱ moreȱ thanȱ oneȱ ofȱ theȱ symbolsȱ wasȱ
defined,ȱtheȱresultȱisȱundefined.ȱ
ȱ
Defined
Returned
VAX
M68000
K68020
I80386
X6809
X6502
U3B2
CPU_VAX
CPU_68000
CPU_68020
CPU_80386
CPU_6809
CPU_6502
CPU_3B2
CPU_UNKNOWN
(none)ȱ
ȱ
Theȱ symbolsȱ inȱ theȱ ȈReturnedȈȱ columnȱ willȱ beȱ #defineȇdȱ asȱ variousȱ integerȱ
valuesȱinȱanȱincludeȱtileȱcalledȱcpu_types.hȱ.ȱ
Download at http://www.pin5i.com/
Download at http://www.pin5i.com/
15
Input/Output Functions
Oneȱ ofȱ theȱ biggestȱ advantagesȱ ofȱ ANSIȱ Cȱ overȱ earlierȱ implementationsȱ isȱ thatȱ theȱ
libraryȱ isȱ includedȱ inȱ theȱ specification.ȱ Everyȱ ANSIȱ implementationȱ willȱ haveȱ theȱ
mandatedȱsetȱofȱfunctions,ȱandȱtheyȱwillȱhaveȱtheȱrequiredȱinterfaceȱandȱworkȱinȱtheȱ
prescribedȱ manner.ȱ Thisȱ situationȱ isȱ aȱ greatȱ improvementȱ overȱ theȱ earlyȱ daysȱ ofȱ Cȱ
whenȱ differentȱ implementationsȱ ȈimprovedȈȱ theȱ commonȱ libraryȱ functionsȱ byȱ
modifyingȱ orȱ extendingȱ theirȱ functionality.ȱ Theseȱ changesȱ mayȱ haveȱ beenȱ usefulȱ onȱ
theȱparticularȱsystemȱforȱwhichȱtheyȱwereȱmade,ȱbutȱtheyȱinhibitedȱportabilityȱbecauseȱ
codeȱ thatȱ dependedȱ onȱtheȱ changesȱ wouldȱfailȱonȱotherȱimplementationsȱthatȱlackedȱ
themȱ(orȱhadȱdifferentȱchanges).ȱ
ANSIȱ implementationsȱ arenȇtȱ prohibitedȱ fromȱ havingȱ additionalȱ functionsȱ inȱ
theirȱ libraries.ȱ However,ȱ theȱ standardȱ functionsȱ mustȱ operateȱ asȱ definedȱ byȱ theȱ
Standard.ȱ Ifȱ youȱ areȱ concernedȱ withȱ portability,ȱ simplyȱ avoidȱ anyȱ nonstandardȱ
functions.ȱ
Thisȱ chapterȱ coversȱ ANSIȱ Cȱ inputȱ andȱ outputȱ (I/O).ȱ However,ȱ weȱ beginȱ withȱ
twoȱveryȱusefulȱfunctionsȱtoȱreportȱandȱreactȱtoȱerrors.ȱ
ȱ
ȱ
ȱ
15.1 Error Reporting
ȱ
Theȱ perrorȱfunctionȱreportsȱerrorsȱinȱaȱsimple,ȱuniformȱway.ȱManyȱofȱtheȱfunctionsȱinȱ
theȱANSIȱCȱlibraryȱcallȱtheȱoperatingȱsystemȱtoȱperformȱsomeȱwork,ȱespeciallyȱtheȱI/Oȱ
functions.ȱAnyȱtimeȱtheȱoperatingȱsystemȱisȱaskedȱtoȱdoȱsomething,ȱthereȱisȱtheȱchanceȱ
thatȱitȱmightȱfail.ȱȱForȱinstance,ȱifȱaȱprogramȱattemptsȱtoȱreadȱfromȱaȱdiskȱfileȱthatȱdoesȱ
notȱexist,ȱthereȱisȱnotȱmuchȱtheȱoperatingȱsystemȱcanȱdoȱexceptȱindicateȱthatȱsomethingȱ
wentȱ wrong.ȱ Theȱ libraryȱ functionsȱ passȱ thisȱ indicationȱ toȱ theȱ userȇsȱ programȱ afterȱ
savingȱ aȱ codeȱ inȱ theȱ externalȱ integerȱ variableȱ errnoȱ (definedȱ inȱ errno.h)ȱ toȱ indicateȱ
exactlyȱwhyȱtheȱoperationȱfailed.ȱ
Download at http://www.pin5i.com/
410ȱ
Chapter 15 Input/Output Functionsȱ
Theȱ perrorȱfunctionȱsimplifiesȱreportingȱtheseȱspecificȱerrorsȱtoȱtheȱuser.ȱItsȱprototypeȱ
fromȱstdio.hȱisȱshownȱbelow.ȱ
ȱ
void perror( char const *message );
TIP
ȱ
Ifȱ messageȱisȱ notȱ NULLȱ andȱ pointsȱ toȱ aȱ nonemptyȱ string,ȱ theȱ stringȱ isȱ printedȱ andȱ isȱ
followedȱ byȱ aȱ colonȱ andȱ aȱ space.ȱ Aȱ messageȱ explainingȱ theȱ errorȱ codeȱ currentlyȱ inȱ
errnoȱisȱthenȱprinted.ȱ
ȱ
perrnoȇsȱ bestȱ featureȱ isȱ itsȱ easeȱ ofȱ use.ȱ Goodȱ programmingȱ practiceȱ dictatesȱ thatȱ anyȱ
operationȱ thatȱ mightȱ resultȱ inȱ anȱ errorȱ shouldȱ beȱ checkedȱ afterwardsȱ toȱ determineȱ
whetherȱ orȱ notȱ itȱ succeeded.ȱ Evenȱ operationsȱ thatȱ areȱ supposedlyȱ ȈguaranteedȈȱ toȱ
workȱ shouldȱ beȱ checked,ȱ becauseȱ soonerȱ orȱ laterȱ theyȱ willȱ fail.ȱ Theȱ smallȱ amountȱ ofȱ
extraȱworkȱneededȱtoȱdoȱthisȱcheckingȱwillȱbeȱrepaidȱtoȱyouȱmanyȱtimesȱoverȱinȱsavedȱ
debuggingȱtime.ȱperrorȱisȱillustratedȱinȱexamplesȱthroughoutȱthisȱchapter.ȱ
Noteȱthatȱerrnoȱisȱsetȱonlyȱwhenȱaȱlibraryȱfunctionȱfails.ȱWhenȱtheȱfunctionsȱareȱ
successful,ȱ errnoȱ isȱ notȱ modifiedȱ atȱ all.ȱ Thisȱ behaviorȱ meansȱ thatȱ errnoȱ cannotȱ beȱ
testedȱ toȱ determineȱ whetherȱ anȱ errorȱ occurred.ȱ Instead,ȱ checkȱ errnoȱ onlyȱ whenȱ theȱ
functionȱthatȱwasȱcalledȱindicatesȱthatȱitȱfailed.ȱ
ȱ
ȱ
ȱ
15.2 Terminating Execution
ȱ
Anotherȱ usefulȱ functionȱ isȱ exit,ȱ whichȱ isȱ usedȱ toȱ terminateȱ theȱ executionȱ ofȱ aȱ
program.ȱItsȱprototype,ȱfoundȱinȱstdlib.h,ȱisȱshownȱbelow.ȱ
ȱ
void exit( int status );
ȱ
Theȱ statusȱ argumentȱ isȱ returnedȱ toȱ theȱ operatingȱ systemȱ andȱ isȱ anȱ indicationȱ ofȱ
whetherȱorȱnotȱtheȱprogramȱcompletedȱnormally.ȱThisȱvalueȱisȱtheȱsameȱasȱtheȱintegerȱ
statusȱ returnedȱ byȱ theȱ mainȱ function.ȱ Theȱ predefinedȱ symbolsȱ EXIT_SUCCESSȱ andȱ
EXIT_FAILUREȱ indicateȱ successfulȱ andȱ unsuccessfulȱ termination,ȱ respectively.ȱ Otherȱ
valuesȱmayȱbeȱused,ȱbutȱtheirȱmeaningsȱareȱimplementationȱdependent.ȱ
Thisȱ functionȱ isȱ particularlyȱ usefulȱ whenȱ errorȱ conditionsȱ thatȱ preventȱ theȱ
programȱ fromȱ continuingȱ toȱ executeȱ areȱ discovered.ȱ Youȱ willȱ oftenȱ followȱ callsȱ toȱ
perrorȱwithȱaȱcallȱtoȱ exit.ȱAlthoughȱterminatingȱtheȱprogramȱisȱnotȱtheȱrightȱwayȱtoȱ
handleȱallȱerrors,ȱitȱisȱbetterȱthanȱlettingȱaȱdoomedȱprogramȱcontinueȱtoȱexecuteȱandȱ
abortȱlater.ȱ
Noteȱthatȱthisȱfunctionȱ neverȱreturns.ȱWhenȱ exitȱ isȱ finished,ȱtheȱprogramȱ hasȱ
disappeared,ȱsoȱthereȱisȱnothingȱtoȱreturnȱto.ȱ
Download at http://www.pin5i.com/
15.4 ANSI I/O Conceptsȱ
411
15.3 The Standard I/O Library
ȱ
Theȱ earliestȱ implementationsȱ ofȱ K&Rȱ Cȱ hadȱ littleȱ inȱ theȱ wayȱ ofȱ libraryȱ functionsȱ toȱ
supportȱ inputȱ andȱ output.ȱ Asȱ aȱ result,ȱ everyȱ programmerȱ whoȱ wantedȱ moreȱ
sophisticatedȱI/Oȱfunctionalityȱthanȱthatȱprovidedȱhadȱtoȱimplementȱtheirȱown.ȱ
ThisȱsituationȱwasȱgreatlyȱimprovedȱbyȱtheȱStandardȱI/OȱLibrary,ȱaȱcollectionȱofȱ
I/Oȱ functionsȱ thatȱ implementedȱ muchȱ ofȱ theȱ addedȱ functionalityȱ thatȱ programmersȱ
hadȱ beenȱ implementingȱ onȱ theirȱ own.ȱ Thisȱ libraryȱ expandedȱ onȱ existingȱ functions,ȱ
suchȱasȱprintf,ȱcreatingȱdifferentȱversionsȱthatȱcouldȱbeȱusedȱinȱaȱvarietyȱofȱsituations.ȱ
TheȱlibraryȱalsoȱintroducedȱtheȱnotionȱofȱbufferedȱI/O,ȱwhichȱincreasesȱtheȱefficiencyȱ
ofȱmostȱprograms.ȱ
Thereȱ wereȱtwoȱmajorȱdrawbacksȱ toȱthisȱlibrary.ȱ First,ȱ itȱwasȱ implementedȱ onȱ
oneȱ specificȱ typeȱ ofȱ machineȱ withoutȱ muchȱ considerationȱ ofȱ otherȱ machinesȱ withȱ
differentȱcharacteristics.ȱThisȱfactȱledȱtoȱsituationsȱwhereȱcodeȱthatȱworkedȱfineȱonȱoneȱ
machineȱ couldȱ notȱ heȱ madeȱ toȱ workȱ onȱ anotherȱ solelyȱ becauseȱ ofȱ architecturalȱ
differencesȱbetweenȱtheȱmachines.ȱTheȱsecondȱdrawbackȱisȱdirectlyȱrelatedȱtoȱtheȱfirst.ȱ
Whenȱ implementorsȱ discoveredȱ theseȱ deficiencies,ȱ theyȱ attemptedȱ toȱ fixȱ themȱ byȱ
modifyingȱ theȱ libraryȱ functions.ȱ Asȱ soonȱ asȱ theyȱ didȱ so,ȱ though,ȱ theȱ libraryȱ wasȱ noȱ
longerȱȈstandard,Ȉȱandȱprogramȱportabilityȱwasȱreduced.ȱ
TheȱI/0ȱfunctionsȱinȱtheȱANSIȱCȱlibraryȱareȱdirectȱdescendentsȱofȱthoseȱfromȱtheȱ
oldȱ Standardȱ I/Oȱ Libraryȱ exceptȱ thatȱ theȱ ANSIȱ functionsȱ haveȱ beenȱ improved.ȱ
Portabilityȱ andȱ completenessȱ wereȱ keyȱ considerationsȱ inȱ theȱ designȱ ofȱ theȱ ANSIȱ
library.ȱ However,ȱ backwardȱ compatibilityȱ withȱ existingȱ programsȱ wasȱ anotherȱ
consideration.ȱ Mostȱ ofȱ theȱ differencesȱ betweenȱ ANSIȱ functionsȱ andȱ theirȱ olderȱ
counterpartsȱareȱtheȱadditionsȱthatȱenhanceȱportabilityȱorȱfunctionality.ȱ
Oneȱlastȱcommentȱonȱportability:ȱTheseȱfunctionsȱareȱtheȱresultȱofȱconsiderableȱ
evolution,ȱ butȱ thereȱ areȱ probablyȱ additionalȱ revisionsȱ thatȱ couldȱ makeȱ themȱ evenȱ
better.ȱ Aȱ majorȱ advantageȱ toȱ ANSIȱ Cȱ isȱ thatȱ anyȱ suchȱ changesȱ willȱ haveȱ toȱ beȱ
implementedȱasȱdifferentȱfunctionsȱratherȱthanȱmodificationsȱtoȱtheȱexistingȱfunctions.ȱ
Therefore,ȱprogramȱportabilityȱwillȱnotȱsufferȱasȱitȱhasȱinȱtheȱpast.ȱ
ȱ
ȱ
ȱ
15.4 ANSI I/O Concepts
ȱ
Theȱincludeȱfileȱ stdio.hȱcontainsȱdeclarationsȱrelevantȱtoȱtheȱI/OȱportionȱofȱtheȱANSIȱ
library.ȱ Itsȱ nameȱ comesȱ fromȱ theȱ oldȱ Standardȱ I/Oȱ Library.ȱ Althoughȱ aȱ fewȱ I/Oȱ
functionsȱmayȱbeȱusedȱwithoutȱincludingȱthisȱfile,ȱmostȱfunctionsȱwillȱrequireȱit.ȱ
Download at http://www.pin5i.com/
Chapter 15 Input/Output Functionsȱ
412ȱ
15.4.1
Streams
ȱ
ComputersȱtodayȱhaveȱaȱlargeȱvarietyȱofȱdevicesȱonȱwhichȱI/Oȱmayȱbeȱperformed.ȱCDȬ
ROMȱ drives,ȱ hardȱ andȱ floppyȱ diskȱ drives,ȱ networkȱ connections,ȱ communicationsȱ
ports,ȱ andȱ videoȱ adaptersȱ areȱ aȱ fewȱ ofȱ theȱ moreȱ commonȱ devices.ȱ Eachȱ deviceȱ hasȱ
differentȱ characteristicsȱ andȱ operatingȱ protocols.ȱ Theȱ operatingȱ systemȱ takesȱ careȱ ofȱ
theȱ detailsȱ ofȱ communicatingȱ withȱ theseȱ differentȱ devicesȱ andȱ providesȱ aȱ simpler,ȱ
moreȱuniformȱI/Oȱinterfaceȱtoȱtheȱprogrammer.ȱ
ANSIȱ Cȱ abstractsȱ theȱ notionȱ ofȱ I/Oȱ evenȱ further.ȱ Asȱ farȱ asȱ Cȱ programsȱ areȱ
concerned,ȱallȱI/Oȱisȱsimplyȱaȱmatterȱofȱmovingȱbytesȱintoȱorȱoutȱofȱtheȱprogram.ȱThisȱ
streamȱ ofȱ bytes,ȱ notȱ surprisingly,ȱ isȱ calledȱ aȱ stream.ȱ Theȱ programȱ isȱ onlyȱ concernedȱ
withȱ creatingȱ theȱ correctȱ bytesȱ ofȱ dataȱ forȱ outputȱ andȱ interpretingȱ theȱ bytesȱ ofȱ dataȱ
thatȱ comeȱ inȱ asȱ input.ȱ Detailsȱ ofȱ theȱ specificȱ I/Oȱ deviceȱ areȱ hiddenȱ fromȱ theȱ
programmer.ȱ
Mostȱ streamsȱ areȱ fullyȱ buffered,ȱ whichȱ meansȱ thatȱ ȈreadingȈȱ andȱ ȈwritingȈȱ
actuallyȱcopyȱdataȱoutȱofȱandȱintoȱanȱareaȱinȱmemoryȱcalledȱtheȱbuffer.ȱCopyingȱtoȱandȱ
fromȱ memoryȱ isȱ veryȱ fast.ȱ Theȱ bufferȱ forȱ anȱ outputȱ streamȱ isȱ flushedȱ (physicallyȱ
written)ȱtoȱtheȱdeviceȱorȱfileȱonlyȱwhenȱ itȱ becomesȱfull.ȱWritingȱaȱfullȱbufferȱisȱmoreȱ
efficientȱ thanȱ writingȱ theȱ dataȱ inȱ littleȱ bitsȱ andȱ piecesȱ asȱ theȱ programȱ producesȱ it.ȱȱ
Similarly,ȱinputȱbuffersȱareȱrefilledȱwhenȱtheyȱbecomeȱemptyȱbyȱreadingȱtheȱnextȱlargeȱ
chunkȱofȱinputȱfromȱtheȱdeviceȱorȱfileȱintoȱtheȱbuffer.ȱ
CAUTION!
Thisȱ bufferingȱ couldȱ causeȱ confusionȱ withȱ theȱ standardȱ inputȱ andȱ standardȱ
output,ȱsoȱtheyȱareȱfullyȱbufferedȱonlyȱifȱtheȱoperatingȱsystemȱcanȱdetermineȱthatȱtheyȱ
areȱ notȱ associatedȱ withȱ interactiveȱ devices.ȱ Otherwise,ȱ theirȱ bufferingȱ stateȱ isȱ
implementationȱ dependent.ȱ Aȱ commonȱ (butȱ notȱ universal)ȱ strategyȱ isȱ toȱ tieȱ theȱ
standardȱoutputȱtoȱtheȱstandardȱinputȱinȱsuchȱaȱwayȱthatȱtheȱoutputȱbufferȱisȱflushedȱ
whenȱinputȱisȱrequested.ȱȱThen,ȱanyȱpromptsȱorȱotherȱoutputȱpreviouslyȱwrittenȱtoȱtheȱ
outputȱbufferȱwillȱappearȱonȱtheȱscreenȱbeforeȱtheȱuserȱmustȱenterȱtheȱinput.ȱ
ȱ
ȱ
Althoughȱ thisȱ bufferingȱ isȱ usuallyȱ desirable,ȱ itȱ canȱ causeȱ confusionȱ whenȱ youȱ areȱ
debuggingȱyourȱprogram.ȱAȱcommonȱdebuggingȱstrategyȱisȱtoȱsprinkleȱcallsȱtoȱ printfȱ
throughoutȱtheȱprogramȱtoȱdetermineȱtheȱspecificȱareaȱinȱwhichȱanȱerrorȱisȱoccurring.ȱ
However,ȱtheȱoutputȱfromȱtheseȱcallsȱisȱbufferedȱandȱdoesȱnotȱimmediatelyȱshowȱupȱ
onȱtheȱscreen.ȱȱInȱfactȱifȱtheȱprogramȱaborts,ȱtheȱbufferedȱoutputȱmayȱnotȱbeȱwrittenȱatȱ
all,ȱ whichȱ leadsȱ theȱ programmerȱ toȱ incorrectȱ conclusionsȱ aboutȱ whereȱ theȱ errorȱ
occurred.ȱTheȱsolutionȱtoȱthisȱproblemȱisȱtoȱalwaysȱfollowȱdebuggingȱ printfȇsȱwithȱaȱ
callȱtoȱfflush,ȱlikeȱthis:ȱ
Download at http://www.pin5i.com/
15.4 ANSI I/O Conceptsȱ
413
printf( "something or other" );
fflush( stdout );
ȱ
fflushȱ (describedȱ inȱ moreȱ detailȱ laterȱ inȱ theȱ chapter)ȱ forcesȱ theȱ bufferȱ toȱ writtenȱ
immediatelyȱwhetherȱorȱnotȱitȱisȱfull.ȱ
ȱ
ȱ
Text Streams
TIP
ȱ
Thereȱ areȱ twoȱ typesȱ ofȱ streams,ȱ textȱ andȱ binary.ȱ Textȱ streamsȱ haveȱ certainȱ
characteristicsȱ thatȱ mayȱ varyȱ fromȱ systemȱ toȱ system.ȱ Oneȱ ofȱ theseȱ isȱ theȱ maximumȱ
lengthȱ ofȱ aȱ textȱ line.ȱ Theȱ Standardȱ requiresȱ thatȱ thisȱ limitȱ beȱ atȱ leastȱ 254ȱ characters.ȱȱ
Anotherȱisȱtheȱmannerȱinȱwhichȱtextȱlinesȱareȱterminated.ȱForȱexample,ȱtheȱconventionȱ
forȱtextȱfilesȱonȱMSȬDOSȱsystemsȱisȱthatȱeachȱlineȱisȱterminatedȱwithȱaȱcarriageȱreturnȱ
characterȱandȱaȱnewlineȱ(alsoȱcalledȱaȱlinefeed)ȱcharacter.ȱHowever,ȱUNIXȱsystemsȱuseȱ
onlyȱaȱnewline.ȱ
ȱ
Theȱ Standardȱ definesȱ aȱ textȱ lineȱ toȱ beȱ zeroȱ orȱ moreȱ charactersȱ followedȱ byȱ aȱ
terminatingȱnewlineȱcharacter.ȱOnȱsystemsȱwhereȱtheȱexternalȱrepresentationȱofȱaȱtextȱ
lineȱdiffersȱfromȱthisȱdefinition,ȱtheȱlibraryȱfunctionsȱtakeȱcareȱofȱtranslatingȱbetweenȱ
theȱ externalȱ andȱ internalȱ forms.ȱ Onȱ MSȬDOSȱ systems,ȱ forȱ example,ȱ aȱ newlineȱ isȱ
writtenȱasȱtheȱcarriageȱreturn/newlineȱpair.ȱOnȱinput,ȱtheȱcarriageȱreturnȱcharacterȱisȱ
discarded.ȱ Theȱ abilityȱ toȱ manipulateȱ textȱ withoutȱ regardȱ toȱ itsȱ externalȱ appearanceȱ
simplifiesȱtheȱcreationȱofȱportableȱprograms.ȱ
ȱ
ȱ
Binary Streams
ȱ
Theȱbytesȱinȱaȱbinaryȱstream,ȱonȱtheȱotherȱhand,ȱareȱwrittenȱtoȱtheȱfileȱorȱdeviceȱexactlyȱ
asȱtheȱprogramȱwroteȱthemȱandȱareȱdeliveredȱtoȱtheȱprogramȱexactlyȱasȱtheyȱwereȱreadȱ
fromȱ theȱ fileȱ orȱ device.ȱ Theyȱ areȱ notȱ changedȱ inȱ anyȱ manner.ȱ Thisȱ typeȱ ofȱ streamȱ isȱ
appropriateȱ forȱ nontextualȱ data,ȱ butȱ binaryȱ streamsȱ mayȱ alsoȱ beȱusedȱ forȱ textȱ filesȱ ifȱ
youȱdoȱnotȱwantȱtheȱI/OȱfunctionsȱtoȱmodifyȱtheȱendȬofȬlineȱcharacters.ȱ
ȱ
ȱ
ȱ
15.4.2
FILEs
ȱ
Oneȱ ofȱ theȱ declarationsȱ containedȱ inȱ stdio.hȱ isȱ forȱ theȱ fileȱ structure.ȱ Notȱ toȱ beȱ
confusedȱwithȱaȱdataȱfileȱstoredȱonȱaȱdisk,ȱaȱ FILEȱisȱaȱdataȱstructureȱusedȱtoȱaccessȱaȱ
stream.ȱ Ifȱyouȱhaveȱseveralȱdifferentȱstreamsȱ activeȱ atȱaȱtime,ȱ eachȱwillȱhaveȱ itsȱ ownȱ
FILEȱ associatedȱ withȱ it.ȱ Toȱ performȱ someȱ operationȱ onȱ aȱ stream,ȱ youȱ callȱ theȱ
appropriateȱfunctionȱandȱpassȱitȱtheȱFILEȱassociatedȱwithȱthatȱstream.ȱ
Download at http://www.pin5i.com/
Chapter 15 Input/Output Functionsȱ
414ȱ
Theȱ runtimeȱ environmentȱ mustȱ provideȱ atȱ leastȱ threeȱ streamsȱ toȱ everyȱ ANSIȱ Cȱ
program—theȱstandardȱinput,ȱtheȱstandardȱoutput,ȱandȱtheȱstandardȱerror.ȱTheȱnamesȱofȱ
theseȱstreamsȱareȱstdin,ȱstdout,ȱandȱstderr,ȱrespectively,ȱandȱtheyȱareȱsimplyȱpointersȱ
toȱ FILEȱstructures.ȱTheȱstandardȱinputȱisȱwhereȱinputȱcomesȱfromȱbyȱdefault,ȱandȱtheȱ
standardȱ outputȱ isȱ theȱ defaultȱ outputȱ device.ȱ Theȱ defaultsȱ dependȱ onȱ theȱ
implementation;ȱ oftenȱ theȱ standardȱ inputȱ isȱ aȱ keyboardȱ deviceȱ andȱ theȱ standardȱ
outputȱisȱaȱterminalȱorȱscreen.ȱ
Manyȱ operatingȱ systemsȱ letȱ theȱ userȱ changeȱ theȱ standardȱ inputȱ andȱ outputȱ
fromȱ theirȱ defaultȱ devicesȱ whenȱ aȱ programȱ isȱ executed.ȱ Forȱ example,ȱ MSȬDOSȱ andȱ
UNIXȱsystemsȱbothȱsupportȱinput/outputȱredirectionȱusingȱthisȱnotation:ȱ
ȱ
$program < data > answer
ȱ
Whenȱthisȱprogramȱexecutes,ȱitȱwillȱreadȱitsȱstandardȱinputȱfromȱtheȱfileȱ dataȱinsteadȱ
ofȱtheȱkeyboard,ȱandȱitȱwillȱwriteȱitsȱstandardȱoutputȱtoȱtheȱfileȱ answerȱinsteadȱofȱtheȱ
screen.ȱ Referȱ toȱ yourȱ systemȇsȱ documentationȱ forȱ detailsȱ onȱ howȱ (orȱ whether)ȱ I/Oȱ
redirectionȱisȱperformed.ȱ
Theȱstandardȱerrorȱisȱtheȱplaceȱwhereȱerrorȱmessagesȱareȱwritten.ȱ perrorȱwritesȱ
itsȱoutputȱhere.ȱOnȱmanyȱsystemsȱtheȱstandardȱerrorȱandȱtheȱstandardȱoutputȱdefaultȱ
toȱtheȱsameȱlocation,ȱbutȱhavingȱaȱseparateȱstreamȱforȱerrorȱmessagesȱmeansȱthatȱtheyȱ
willȱ stillȱ appearȱ onȱ theȱ screenȱ orȱ otherȱ defaultȱ outputȱ deviceȱ evenȱ ifȱ theȱ standardȱ
outputȱhasȱbeenȱredirectedȱsomewhereȱelse.ȱ
ȱ
ȱ
ȱ
15.4.3
Standard I/O Constants
ȱ
Thereȱ areȱ numerousȱ constantsȱ definedȱ inȱ stdio.hȱ thatȱ areȱ relatedȱ inȱ someȱ wayȱ toȱ
inputȱ andȱ output.ȱ EOF,ȱ whichȱ youȱ haveȱ alreadyȱ seen,ȱ isȱ theȱ valueȱ returnedȱ byȱ manyȱ
functionsȱtoȱindicateȱthatȱendȱofȱfileȱhasȱbeenȱreached.ȱTheȱactualȱvalueȱchosenȱforȱ EOFȱ
usesȱ moreȱ bitsȱ thanȱ aȱ characterȱ inȱ orderȱ toȱ preventȱ binaryȱ characterȱ valuesȱ fromȱ
mistakenlyȱbeingȱinterpretedȱasȱEOF.ȱ
Howȱ manyȱ filesȱ canȱ aȱ programȱ naveȱ openȱ atȱ once?ȱ Itȱ dependsȱ onȱ theȱ
implementation,ȱbutȱyouȱareȱguaranteedȱofȱbeingȱableȱtoȱsimultaneouslyȱopenȱatȱleastȱ
FOPEN_MAXȱfiles.ȱThisȱconstant,ȱwhichȱincludesȱtheȱthreeȱstandardȱstreams,ȱmustȱbeȱatȱ
leastȱeight.ȱ
Theȱ constantȱ FILENAME_MAXȱ isȱ anȱ integerȱ thatȱ indicatesȱ howȱ largeȱ aȱ characterȱ
arrayȱshouldȱbeȱtoȱholdȱtheȱlongestȱlegalȱfileȱnameȱthatȱtheȱimplementationȱsupports.ȱ
Ifȱ thereȱ isnȇtȱ aȱ practicalȱ limitȱ toȱ theȱ lengthȱ ofȱ aȱ fileȱ name,ȱ thenȱ thisȱ valueȱ isȱ theȱ
recommendedȱsizeȱforȱsuchȱstrings.ȱTheȱremainingȱconstantsȱareȱdescribedȱlaterȱinȱthisȱ
chapterȱalongȱwithȱtheȱfunctionsȱwithȱwhichȱtheyȱareȱused.ȱ
ȱ
Download at http://www.pin5i.com/
15.5 Overview of Stream I/Oȱ
415
15.5 Overview of Stream I/O
ȱ
Theȱ standardȱ libraryȱ functionsȱ makeȱ itȱ veryȱ convenientȱ toȱ performȱ I/Oȱ toȱ andȱ fromȱ
filesȱinȱCȱprograms.ȱHereȱisȱaȱgeneralȱoverviewȱofȱfileȱI/O.ȱ
1.
Theȱprogramȱdeclaresȱaȱpointerȱvariableȱofȱtypeȱ FILE *ȱforȱeachȱfileȱthatȱmustȱbeȱ
simultaneouslyȱactive.ȱThisȱvariableȱwillȱpointȱtoȱtheȱ FILEȱstructureȱusedȱbyȱtheȱ
streamȱwhileȱitȱisȱactive.ȱ
2.
Theȱ streamȱ isȱ openedȱ byȱ callingȱ theȱ fopenȱ function.ȱ Toȱ openȱ aȱ stream,ȱ youȱ mustȱ
specifyȱ whichȱ fileȱ orȱ deviceȱ isȱ toȱ beȱ accessedȱ andȱ howȱ itȱ isȱ toȱ beȱ accessedȱ (forȱ
example,ȱ reading,ȱ writing,ȱ orȱ both).ȱ fopenȱ andȱ theȱ operatingȱ systemȱ verifyȱ thatȱ
theȱ fileȱ orȱ deviceȱ existsȱ (and,ȱ onȱ someȱ operatingȱ systems,ȱ thatȱ youȱ haveȱ
permissionȱ toȱ accessȱ itȱ inȱ theȱ mannerȱ youȱ specify)ȱ andȱ initializesȱ theȱ FILEȱ
structure.ȱ
3.
Theȱfileȱisȱthenȱreadȱand/orȱwrittenȱasȱdesired.ȱ
4.
Finally,ȱ theȱ streamȱisȱclosedȱwithȱ theȱ fcloseȱfunction.ȱ Closingȱaȱ streamȱpreventsȱ
theȱassociatedȱfileȱfromȱbeingȱaccessedȱagain,ȱguaranteesȱthatȱanyȱdataȱstoredȱinȱ
theȱstreamȱbufferȱisȱcorrectlyȱwrittenȱtoȱtheȱfile,ȱandȱreleasesȱtheȱFILEȱstructureȱsoȱ
thatȱitȱcanȱbeȱusedȱagainȱwithȱanotherȱfile.ȱ
ȱ
I/Oȱ onȱ theȱ standardȱ streamsȱ isȱ simplerȱ becauseȱ theyȱ doȱ notȱ haveȱ toȱ beȱ openedȱ orȱ
closed.ȱ
TheȱI/Oȱfunctionsȱdealȱwithȱdataȱinȱthreeȱbasicȱforms:ȱindividualȱcharacters,ȱtextȱ
lines,ȱandȱbinaryȱdata.ȱAȱdifferentȱsetȱofȱfunctionsȱisȱusedȱtoȱprocessȱeachȱform.ȱTableȱ
15.1ȱlistsȱtheȱfunctionȱorȱfunctionȱfamilyȱusedȱforȱeachȱformȱofȱI/O.ȱFunctionȱfamilies,ȱ
listedȱ inȱ theȱ tableȱ inȱitalic,ȱ areȱ groupsȱ ofȱfunctionsȱwhoseȱmembersȱeachȱperformȱtheȱ
sameȱbasicȱworkȱinȱaȱslightlyȱdifferentȱway.ȱTheȱfunctionsȱdifferȱinȱwhereȱtheȱinputȱisȱ
obtainedȱorȱwhereȱtheȱoutputȱgoes.ȱTheȱvariantsȱareȱtoȱperformȱtheȱwork:ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Function or Family Name Description
Type of Data
Input
Output
Characterȱ
getcharȱ
putcharȱ
Readȱ(write)ȱaȱsingleȱcharacterȱ
Lineȱ
getsȱ
putsȱ
Unformattedȱinputȱ(output)ȱofȱaȱlineȱ
scanfȱ
printfȱ
Formattedȱinputȱ(output)ȱ
fread
fwrite
Readȱ(write)ȱbinaryȱdataȱ
Binaryȱ
ȱ
Tableȱ15.1ȱȱFunctionsȱtoȱperformȱcharacter,ȱline,ȱandȱbinaryȱI/Oȱ
Download at http://www.pin5i.com/
416ȱ
Chapter 15 Input/Output Functionsȱ
ȱ
Family Name Purpose
To Any Stream Only stdin and stdout String in Memory
fgetc, getc
getchar
Characterȱinputȱ
1
getcharȱ
fputc,
putc
putchar
Characterȱoutputȱ
1
putcharȱ
fgets
gets
Lineȱinputȱ
2
getsȱ
fputs
puts
Lineȱoutputȱ
2
putsȱ
fscanf
scanf
sscanf
Formattedȱinputȱ
scanfȱ
printf
sprintf
Formattedȱoutputȱ fprintf
printfȱ
ȱ
1
Useȱ aȱ subscriptȱ orȱ indirectionȱ onȱ aȱ pointerȱ toȱ get/putȱ singleȱ charactersȱ to/fromȱ
memory,ȱ
2
Use strcpyȱtoȱget/putȱlinesȱto/fromȱmemory.ȱ
ȱ
Tableȱ15.2ȱȱInput/outputȱfunctionȱfamiliesȱ
ȱ
ȱ
ȱ
ȱ
1. onlyȱwithȱstdinȱorȱstdout,ȱ
2. withȱaȱstreamȱgivenȱasȱanȱargument,ȱ
3. usingȱcharacterȱstringsȱinȱmemoryȱratherȱthanȱstreams.ȱ
ȱ
Theȱ functionsȱ thatȱ requireȱ aȱ streamȱ argumentȱ willȱ acceptȱ stdinȱ orȱ stdoutȱ asȱ
arguments.ȱSomeȱfamiliesȱdoȱnotȱhaveȱfunctionsȱforȱtheȱstringȱvariants,ȱbecauseȱitȱisȱsoȱ
easyȱtoȱaccomplishȱtheȱsameȱresultȱwithȱotherȱstatementsȱorȱfunctions.ȱTableȱ15.2ȱlistsȱ
theȱ functionsȱ inȱ eachȱ family.ȱ Theȱ individualȱ functionsȱ areȱ describedȱ laterȱ inȱ thisȱ
chapter.ȱ
ȱ
ȱ
ȱ
15.6 Opening Streams
ȱ
Theȱ fopenȱ functionȱ opensȱ aȱ specificȱ fileȱ andȱ associatesȱ aȱ streamȱ withȱ theȱ file.ȱ Itsȱ
prototypeȱisȱshownȱbelow.ȱ
ȱ
FILE *fopen( char const *name, char const *mode );
ȱ
Theȱargumentsȱareȱbothȱstrings.ȱ nameȱisȱtheȱnameȱofȱtheȱfileȱorȱdeviceȱthatȱyouȱwishȱtoȱ
open.ȱTheȱrulesȱforȱconstructingȱfilenamesȱvaryȱfromȱsystemȱtoȱsystem,ȱwhichȱisȱwhyȱ
fopenȱ takesȱ theȱ filenameȱ inȱ oneȱ stringȱ ratherȱ thanȱ inȱ separateȱ argumentsȱ forȱ pathȱ
name,ȱ driveȱ letter,ȱ fileȱ extension,ȱ andȱ soȱ forth.ȱ Thisȱ argumentȱ specifiesȱ theȱ fileȱ toȱ
open—theȱ nameȱ ofȱ theȱ FILE *ȱ variableȱ thatȱ theȱ programȱ usesȱ toȱ saveȱ theȱ valueȱ
returnedȱbyȱfopenȱdoesȱnotȱinfluenceȱwhichȱfileȱisȱopened.ȱ
Download at http://www.pin5i.com/
15.6 Opening Streamsȱ
CAUTION!
417
Theȱmodeȱargumentȱindicatesȱwhetherȱtheȱstreamȱwillȱbeȱusedȱforȱinput,ȱoutput,ȱ
orȱ bothȱ andȱ whetherȱ theȱ streamȱ willȱ beȱ textȱ orȱ binary.ȱ Theȱ modesȱ usedȱ mostȱ
frequentlyȱareȱshownȱinȱtheȱfollowingȱtable.ȱ
ȱ
ȱ
Read
Write
Append
"r"
"w"
"a"
Textȱ
"rb"
"wb"
"ab"
Binaryȱ
ȱ
ȱ
Theȱmodesȱbeginȱwithȱr,ȱw,ȱorȱaȱtoȱindicateȱthatȱtheȱstreamȱisȱtoȱbeȱopenedȱforȱreading,ȱ
writing,ȱ orȱ appending,ȱ respectively.ȱ Aȱ fileȱ openedȱ forȱ readingȱ mustȱ alreadyȱ exist,ȱ
whereasȱaȱfileȱopenedȱforȱwritingȱisȱtruncatedȱifȱitȱalreadyȱexistsȱandȱcreatedȱifȱitȱdoesȱ
not.ȱIfȱaȱfileȱopenedȱforȱappendingȱdoesȱnotȱexist,ȱitȱwillȱbeȱcreated;ȱifȱitȱalreadyȱexists,ȱ
itȱisȱnotȱtruncated.ȱInȱeitherȱcase,ȱdataȱcanȱonlyȱbeȱwrittenȱtoȱtheȱendȱofȱtheȱfile.ȱ
Adding a + toȱ theȱ modeȱ opensȱ theȱ fileȱ forȱ update,ȱ andȱ bothȱ readingȱ andȱ
writingȱareȱallowedȱonȱ theȱstream.ȱHowever,ȱ ifȱyouȱ haveȱbeenȱreadingȱ fromȱ theȱfile,ȱ
youȱmustȱcallȱoneȱofȱtheȱfileȱpositioningȱfunctionsȱ(fseek,ȱ fsetpos,ȱandȱ rewind,ȱwhichȱ
areȱdescribedȱlaterȱinȱthisȱchapter)ȱbeforeȱyouȱmayȱbeginȱwritingȱtoȱit.ȱAfterȱwritingȱtoȱ
theȱfile,ȱyouȱmustȱcallȱeitherȱ fflushȱorȱoneȱofȱtheȱfileȱpositioningȱfunctionsȱbeforeȱyouȱ
mayȱbeginȱreadingȱfromȱit.ȱ
Ifȱ itȱ isȱ successful,ȱ fopenȱ returnsȱ aȱ pointerȱ toȱ theȱ FILEȱ structureȱ forȱ theȱ newlyȱ
createdȱ stream.ȱ Otherwiseȱ aȱ NULLȱ pointerȱ isȱ returnedȱ andȱ errnoȱ willȱ indicateȱ theȱ
natureȱofȱtheȱproblem.ȱ
ȱ
Alwaysȱ checkȱ theȱ valueȱ returnedȱ byȱ fopen!ȱ Ifȱ theȱ functionȱ fails,ȱ aȱ NULLȱ valueȱ isȱ
returned.ȱIfȱtheȱprogramȱdoesȱnotȱcheckȱforȱerrors,ȱtheȱNULLȱpointerȱwillȱbeȱgivenȱtoȱ
subsequentȱI/Oȱfunctions.ȱTheyȱwillȱperformȱindirectionȱonȱitȱandȱfail.ȱ
Theȱfollowingȱexampleȱillustratesȱtheȱuseȱofȱfopen.ȱ
ȱ
FILE
*input;
input = fopen( "data3", "r" );
if( input == NULL ){
perror( "data3" );
exit( EXIT_FAILURE );
}
ȱ
First,ȱtheȱ fopenȱfunctionȱisȱcalled;ȱtheȱfileȱtoȱbeȱopenedȱisȱnamedȱ data3ȱandȱitȱisȱtoȱbeȱ
openedȱforȱreading.ȱThisȱstepȱisȱfollowedȱbyȱtheȱallȬimportantȱcheckȱtoȱseeȱwhetherȱtheȱ
openȱ succeeded.ȱ Ifȱ itȱ didȱ not,ȱ theȱ errorȱ isȱ reportedȱ toȱ theȱ userȱ andȱ theȱ programȱ
terminates.ȱTheȱexactȱoutputȱproducedȱbyȱthisȱcallȱtoȱ perrorȱwillȱvaryȱdependingȱonȱ
theȱoperatingȱsystemȱinȱuse,ȱbutȱitȱmightȱlookȱsomethingȱlikeȱthis:ȱ
Download at http://www.pin5i.com/
418ȱ
Chapter 15 Input/Output Functionsȱ
data3: No such file or directory
ȱ
Thisȱtypeȱofȱmessageȱclearlyȱindicatesȱtoȱtheȱuserȱthatȱsomethingȱhasȱgoneȱwrongȱandȱ
givesȱ theȱ userȱ aȱ goodȱ indicationȱ ofȱ whatȱ theȱ problemȱ is.ȱ Itȱ isȱ especiallyȱ importantȱ toȱ
reportȱtheseȱerrorsȱinȱprogramsȱwhichȱreadȱfilenamesȱorȱtakeȱthemȱfromȱtheȱcommandȱ
line.ȱWheneverȱtheȱuserȱentersȱaȱfilename,ȱthereȱisȱtheȱpossibilityȱthatȱtheyȱmayȱmakeȱaȱ
mistake.ȱClear,ȱdescriptiveȱerrorȱmessagesȱhelpȱtheȱuserȱdetermineȱwhatȱwentȱwrongȱ
andȱbowȱtoȱfixȱit.ȱ
Theȱ freopenȱfunctionȱisȱusedȱtoȱopenȱ(orȱreopen)ȱaȱspecificȱstreamȱonȱaȱfile.ȱȱItsȱ
prototypeȱis:ȱ
ȱ
FILE *freopen( char const *filename, char const *mode, FILE *stream );
ȱ
Theȱlastȱargumentȱisȱtheȱstreamȱtoȱbeȱopened.ȱȱItȱmayȱbeȱaȱstreamȱthatȱwasȱpreviouslyȱ
returnedȱbyȱfopen,ȱorȱitȱmaybeȱoneȱofȱtheȱstandardȱstreamȱstdin,ȱstdout,ȱorȱstderr.ȱ
Theȱfunctionȱfirstȱattemptsȱtoȱcloseȱtheȱstream.ȱItȱthenȱopensȱtheȱstreamȱwithȱtheȱ
givenȱfileȱnameȱandȱmode.ȱIfȱtheȱopenȱfails,ȱtheȱvalueȱ NULLȱisȱreturned,ȱotherwiseȱtheȱ
thirdȱargumentȱvalueȱisȱreturned.ȱ
ȱ
ȱ
ȱ
15.7 Closing Streams
ȱ
Streamsȱareȱclosedȱwithȱtheȱfcloseȱfunction,ȱwhichȱhasȱthisȱprototype:ȱ
ȱ
int fclose( FILE *f );
ȱ
Forȱ outputȱ streams,ȱ fcloseȱ flushesȱ theȱ bufferȱ beforeȱ theȱ fileȱ isȱ closed.ȱ fcloseȱ returnȱ
zeroȱifȱitȱsuccessfulȱandȱEOFȱotherwise.ȱ
Programȱ 15.1ȱ interpretsȱ itsȱ commandȱ lineȱ argumentsȱ asȱ aȱ listȱ ofȱ filenames.ȱ Itȱ
opensȱeachȱfileȱandȱprocessesȱthem,ȱoneȱbyȱone.ȱIfȱanyȱfileȱcannotȱbeȱopened,ȱanȱerrorȱ
messageȱthatȱincludesȱtheȱnameȱofȱtheȱfileȱisȱprinted,ȱandȱtheȱprogramȱcontinuesȱtoȱtheȱ
nextȱnameȱinȱtheȱlist.ȱTheȱexitȱstatusȱisȱbasedȱonȱwhetherȱanyȱerrorsȱoccurred.ȱ
Iȱ saidȱ earlierȱ thatȱ anyȱ operationȱ thatȱ mightȱ failȱ shouldȱ beȱ checkedȱ toȱ seeȱ
whetherȱorȱnotȱitȱsucceeded.ȱInȱthisȱprogram,ȱtheȱvalueȱreturnedȱbyȱ fcloseȱisȱcheckedȱ
toȱ seeȱ ifȱ anythingȱ wentȱ wrong.ȱ Manyȱ programmersȱ doȱ notȱ botherȱ withȱ thisȱ test,ȱ
arguingȱ thatȱ thereȱ isȱ noȱ reasonȱ whyȱ theȱ closeȱ willȱ failȱ toȱ work.ȱ Furthermore,ȱ theyȇreȱ
finishedȱwithȱtheȱfile,ȱsoȱitȱdoesnȇtȱmatterȱevenȱifȱitȱdidȱfail.ȱHowever,ȱthisȱanalysisȱisȱ
notȱentirelyȱcorrect.ȱ
ȱ
Download at http://www.pin5i.com/
15.7 Closing Streamsȱ
419
ȱ
/*
** Process each of the files whose names appear on the command line.
*/
#include <stdlib.h>
#include <stdio.h>
int
main( int ac, char **av )
{
int
exit_status = EXIT_SUCCESS;
FILE *input;
/*
** While there are more names ...
*/
while( *++av != NULL ){
/*
** Try opening the file.
*/
input = fopen( *av, "r" );
if( input == NULL ){
perror( *av );
exit_status = EXIT_FAILURE;
continue;
}
/*
** Process the file here ...
*/
/*
** Close the file (don't expect any errors here).
*/
if( fclose( input ) != 0 ){
perror( "fclose" );
exit( EXIT_FAILURE );
}
}
return exit_status;
}
ȱ
Programȱ15.1ȱȱOpeningȱandȱclosingȱfilesȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱopen_cls.cȱ
Download at http://www.pin5i.com/
420ȱ
Chapter 15 Input/Output Functionsȱ
Theȱ inputȱvariableȱmightȱhaveȱchangedȱbecauseȱofȱaȱprogramȱbugȱbetweenȱtheȱ
fopenȱ andȱ theȱ fclose.ȱ Thisȱ bugȱ wouldȱ certainlyȱ causeȱ aȱ failure.ȱ Inȱ programsȱ thatȱ doȱ
notȱcheckȱtheȱresultȱofȱanȱfopen,ȱinputȱmightȱevenȱbeȱNULL.ȱEitherȱofȱtheseȱconditionsȱ
willȱ causeȱ theȱ fcloseȱ toȱ fail.ȱ Butȱ ifȱ eitherȱ ofȱ theseȱ conditionsȱ existed,ȱ theȱ I/Oȱ wouldȱ
haveȱ failedȱ asȱ well,ȱ andȱ theȱ programȱ probablyȱ wouldȱ haveȱ terminatedȱ longȱ beforeȱ
fcloseȱwasȱcalled.ȱ
Soȱshouldȱyouȱcheckȱ fcloseȱ(orȱanyȱotherȱoperation,ȱforȱthatȱmatter)ȱforȱerrorsȱ
orȱnot?ȱWhenȱmakingȱthisȱdecision,ȱaskȱyourselfȱtwoȱquestions.ȱ
ȱ
1. Whatȱshouldȱbeȱdoneȱifȱtheȱoperationȱsucceeded?ȱ
2. Whatȱshouldȱbeȱdoneȱifȱtheȱoperationȱfailed?ȱ
ȱ
Ifȱtheȱanswersȱtoȱtheseȱquestionsȱareȱdifferent,ȱthenȱyouȱshouldȱcheckȱforȱtheȱerror.ȱItȱisȱ
reasonableȱ toȱ skipȱ theȱ errorȱ checkingȱ onlyȱ inȱ casesȱ whereȱ bothȱ questionsȱ haveȱ theȱ
sameȱanswer.ȱ
ȱ
ȱ
ȱ
15.8 Character I/O
ȱ
Afterȱ aȱ streamȱ isȱ open,ȱ itȱ canȱ beȱ usedȱ forȱ inputȱ andȱ output.ȱ Theȱ simplestȱ formȱ isȱ
characterȱI/O.ȱCharacterȱinputȱisȱperformedȱbyȱtheȱgetcharȱfamilyȱofȱfunctions,ȱwhoseȱ
prototypesȱareȱshownȱbelow.ȱ
ȱ
int fgetc( FILE *stream );
int getc( FILE *stream );
int getchar( void );
ȱ
Theȱ desiredȱ streamȱ isȱ givenȱ asȱ theȱ argumentȱ toȱ getcȱ andȱ fgetc,ȱ butȱ getcharȱ alwaysȱ
readsȱfromȱtheȱstandardȱinput.ȱȱEachȱfunctionȱreadsȱtheȱnextȱcharacterȱfromȱtheȱstreamȱ
andȱreturnsȱitȱasȱtheȱvalueȱofȱtheȱfunction.ȱIfȱthereȱarenȇtȱanyȱmoreȱcharactersȱonȱtheȱ
stream,ȱtheȱconstantȱEOFȱisȱreturnedȱinstead.ȱ
Theseȱ functionsȱ areȱ supposedȱ toȱ readȱ characters,ȱ yetȱ theyȱ allȱ returnȱ anȱ intȱ
ratherȱthanȱaȱchar.ȱAlthoughȱcodesȱthatȱrepresentȱcharactersȱareȱjustȱsmallȱintegers,ȱtheȱ
realȱreasonȱforȱreturningȱanȱ intȱisȱtoȱallowȱtheȱfunctionsȱtoȱreportȱendȱofȱfile.ȱIfȱaȱ charȱ
wereȱ returned,ȱ thenȱ oneȱ ofȱ theȱ 256ȱ characterȱ valuesȱ wouldȱ haveȱ toȱ beȱ chosenȱ toȱ
designateȱendȱofȱfile.ȱIfȱthisȱcharacterȱappearedȱinȱaȱfile,ȱitȱwouldȱbeȱimpossibleȱtoȱreadȱ
beyondȱitsȱpositionȱbecauseȱtheȱcharacterȱwouldȱseemȱtoȱsignalȱtheȱendȱofȱtheȱfile.ȱ
Havingȱ theȱ functionsȱ returnȱ anȱ intȱ solvesȱ theȱ problem.ȱ EOFȱ isȱ definedȱ asȱ anȱ
integerȱwhoseȱvalueȱisȱoutsideȱofȱtheȱrangeȱofȱpossibleȱcharacterȱvalues.ȱThisȱsolutionȱ
letsȱusȱuseȱtheseȱfunctionsȱtoȱreadȱbinaryȱfiles,ȱwhereȱallȱcharactersȱmayȱoccur,ȱasȱwellȱ
asȱtextȱfiles.ȱ
Download at http://www.pin5i.com/
15.8 Character I/Oȱ
421
Toȱ writeȱ individualȱ charactersȱ toȱ aȱ stream,ȱ functionsȱ inȱ theȱ putcharȱ familyȱ areȱ
used.ȱTheirȱprototypesȱare:ȱ
ȱ
int fputc( int character, FILE *stream );
int putc( int character, FILE *stream );
int putchar( int character );
ȱ
Theȱ firstȱ argumentȱ isȱ theȱ characterȱ toȱ beȱ printed.ȱ Theȱ functionsȱ truncateȱ theȱ
integerȱargumentȱtoȱanȱunsignedȱcharacterȱbeforeȱprinting,ȱsoȱ
ȱ
putchar( 'abc' );
ȱ
onlyȱprintsȱoneȱcharacterȱ(whichȱoneȱisȱimplementationȱdependent).ȱ
ȱTheseȱfunctionsȱreturnȱtheȱvalueȱ EOFȱifȱtheyȱfailȱforȱanyȱreason,ȱsuchȱasȱwritingȱ
toȱaȱstreamȱthatȱhasȱbeenȱclosed.ȱ
ȱ
ȱ
ȱ
15.8.1
Character I/O Macros
ȱ
fgetcȱandȱfputcȱareȱtrueȱfunctions,ȱbutȱgetc,ȱputc,ȱgetchar,ȱandȱputcharȱareȱ#defineȇdȱ
macros.ȱ Theȱ macrosȱ areȱ slightlyȱ moreȱ efficientȱ inȱ termsȱ ofȱ executionȱ time,ȱ andȱ theȱ
functionsȱwillȱbeȱmoreȱefficientȱinȱtermsȱofȱprogramȱsize.ȱHavingȱbothȱtypesȱavailableȱ
allowsȱ youȱ toȱ chooseȱ theȱ rightȱ oneȱ dependingȱ onȱ whetherȱ sizeȱ orȱ speedȱ isȱ moreȱ
important.ȱThisȱdistinctionȱisȱrarelyȱaȱmatterȱofȱgreatȱconcern,ȱbecauseȱtheȱdifferencesȱ
observedȱinȱactualȱprogramsȱusingȱoneȱorȱtheȱotherȱareȱusuallyȱnotȱsignificant.ȱ
ȱ
ȱ
ȱ
15.8.2
Undoing Character I/O
ȱ
Youȱcannotȱtellȱwhatȱtheȱnextȱcharacterȱonȱaȱstreamȱwillȱbeȱuntilȱyouȇveȱreadȱit.ȱThus,ȱ
youȱ willȱ occasionallyȱ readȱ oneȱ characterȱ beyondȱ whatȱ youȱ wanted.ȱ Forȱ example,ȱ
supposeȱ youȱ mustȱ readȱ aȱ sequenceȱ ofȱ digitsȱ fromȱ aȱ streamȱ oneȱ byȱ one.ȱ Becauseȱ youȱ
cannotȱseeȱwhatȱtheȱnextȱcharacterȱwillȱbeȱwithoutȱreadingȱit,ȱyouȱmustȱkeepȱreadingȱ
untilȱyouȱgetȱaȱnondigit.ȱButȱwhatȱdoȱyouȱdoȱwithȱtheȱextraȱcharacterȱtoȱavoidȱlosingȱ
it?ȱ
The ungetc functionȱsolvesȱthisȱtypeȱofȱproblem.ȱHereȱisȱitsȱprototype.ȱ
ȱ
int ungetc( int character, FILE *stream );
ȱ
ungetcȱ returnȱ aȱ characterȱ previouslyȱ readȱ backȱ toȱ theȱ streamȱ soȱ thatȱ itȱ canȱ beȱ readȱ
againȱlater.ȱProgramȱ15.2ȱillustratesȱungetc.ȱItȱreadsȱcharactersȱfromȱtheȱstandardȱinputȱ
andȱconvertsȱthemȱtoȱanȱinteger.ȱWithoutȱanȱungetcȱcapability,ȱthisȱfunctionȱwouldȱ
Download at http://www.pin5i.com/
Chapter 15 Input/Output Functionsȱ
422ȱ
ȱ
/*
** Convert a series of digits from the standard input to an integer.
*/
#include <stdio.h>
#include <ctype.h>
int
read_int()
{
int
int
value;
ch;
value = 0;
/*
** Convert digits from the standard input; stop when we get a
** character that is not a digit.
*/
while( ( ch = getchar() ) != EOF && isdigit( ch ) ){
value *= 10;
value += ch - '0';
}
/*
** Push back the nondigit so we don't lose it.
*/
ungetc( ch, stdin );
return value;
}
ȱ
Programȱ15.2ȱȱConvertingȱcharactersȱtoȱanȱintegerȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱchar_int.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
haveȱ toȱ returnȱ theȱ excessȱ characterȱ toȱ theȱ caller,ȱ whoȱ wouldȱ thenȱ beȱ responsibleȱ forȱ
sendingȱitȱtoȱwhateverȱpartȱofȱtheȱprogramȱreadsȱtheȱnextȱcharacter.ȱTheȱspecialȱcasesȱ
andȱ extraȱ logicȱ involvedȱ inȱ handlingȱ theȱ extraȱ characterȱ makeȱ theȱ programȱ
significantlyȱmoreȱcomplex.ȱ
Eachȱstreamȱallowsȱatȱleastȱoneȱcharacterȱtoȱbeȱpushedȱbackȱ(ungotten).ȱIfȱmoreȱ
charactersȱareȱpushedȱbackȱonȱaȱstreamȱthatȱallowsȱit,ȱtheyȱwillȱbeȱreadȱinȱtheȱoppositeȱ
orderȱthatȱtheyȱwereȱpushed.ȱNoteȱthatȱpushingȱcharactersȱbackȱtoȱaȱstreamȱisȱnotȱtheȱ
sameȱ asȱ writingȱ toȱ theȱ stream.ȱ Theȱ externalȱ storageȱ associatedȱ withȱ aȱ streamȱ isȱ notȱ
affectedȱbyȱanȱungetc.ȱ
ȱ
Download at http://www.pin5i.com/
15.9 Unformatted Line I/Oȱ
CAUTION!
423
ȈUngottenȈȱ charactersȱ areȱ associatedȱ withȱ theȱ currentȱ positionȱ inȱ theȱ stream,ȱ soȱ
changingȱ theȱstreamȇsȱpositionȱ withȱ fseek,ȱ fsetpos,ȱorȱ rewindȱ discardsȱanyȱungottenȱ
characters.ȱ
ȱ
ȱ
ȱ
15.9 Unformatted Line I/O
ȱ
Lineȱ orientedȱ I/Oȱ canȱ beȱ performedȱ inȱ oneȱ ofȱ twoȱ ways—unformattedȱ orȱ formatted.ȱȱ
Bothȱformsȱmanipulateȱcharacterȱstrings.ȱTheȱdifferenceȱisȱthatȱunformattedȱI/Oȱsimplyȱ
readsȱorȱwritesȱstrings,ȱwhereasȱformattedȱI/Oȱperformsȱconversionsȱbetweenȱinternalȱ
andȱexternalȱrepresentationsȱofȱnumericȱandȱotherȱvariables.ȱInȱthisȱsection,ȱweȇllȱlookȱ
atȱunformattedȱlineȱI/O.ȱ
Theȱ getsȱ andȱ putsȱ familiesȱ operateȱ onȱ characterȱ stringsȱ ratherȱ thanȱ individualȱ
characters.ȱ Thisȱ characteristicȱ makesȱ themȱ usefulȱ inȱ programsȱ thatȱ dealȱ withȱ textualȱ
inputȱonȱaȱlineȬbyȬlineȱbasis.ȱTheȱprototypesȱforȱtheseȱfunctionsȱareȱshownȱbelow.ȱ
ȱ
char *fgets( char *buffer, int buffer_size, FILE *stream );
char *gets( char *buffer );
int fputs( char const *buffer, FILE *stream );
int puts( char const *buffer );
ȱ
fgetsȱ readsȱ charactersȱ fromȱ theȱ specifiedȱ streamȱ andȱ copiesȱ themȱ intoȱ theȱ buffer.ȱ
Readingȱstopsȱafterȱaȱnewlineȱcharacterȱhasȱbeenȱreadȱandȱstoredȱinȱtheȱbuffer.ȱItȱalsoȱ
stopsȱafterȱ buffer_size – 1ȱcharactersȱhaveȱbeenȱstoredȱinȱtheȱbuffer.ȱDataȱisȱnotȱlostȱ
inȱthisȱcase,ȱbecauseȱtheȱnextȱcallȱtoȱ fgetsȱwillȱgetȱtheȱnextȱcharactersȱfromȱtheȱstream.ȱ
Inȱeitherȱcase,ȱaȱ NULȱbyteȱisȱappendedȱtoȱtheȱendȱofȱwhateverȱwasȱstoredȱinȱtheȱbuffer,ȱ
thusȱmakingȱitȱaȱstring.ȱ
Ifȱ endȱ ofȱ fileȱ isȱ reachedȱ beforeȱ anyȱ charactersȱ haveȱ beenȱ read,ȱ theȱ bufferȱ isȱ
unchangedȱ andȱ fgetsȱ returnsȱ aȱ NULLȱ pointer.ȱ Otherȱ wise,ȱ fgestsȱ returnsȱ itsȱ firstȱ
argumentȱ(theȱpointerȱtoȱtheȱbuffer).ȱTheȱreturnedȱvalueȱisȱusuallyȱusedȱonlyȱtoȱcheckȱ
forȱendȱofȱfile.ȱ
Theȱ bufferȱ passedȱ loȱ fputsȱ mustȱ containȱ aȱ string;ȱ itsȱ charactersȱ areȱ writtenȱ toȱ
theȱ stream.ȱ Theȱ stringȱ isȱ expectedȱ toȱ beȱ NULȬterminated,ȱ whichȱ isȱ whyȱ thereȱ isnȇtȱ aȱ
bufferȱsizeȱargument.ȱTheȱstringȱisȱwrittenȱverbatim:ȱifȱitȱdoesȱnotȱcontainȱaȱnewline,ȱ
noneȱ isȱ written;ȱ ifȱ itȱ containsȱ severalȱ newlines,ȱ theyȱ areȱ allȱ written.ȱ Thus,ȱ whereasȱ
fgetsȱ triesȱ toȱ readȱ oneȱ wholeȱ line,ȱ fputsȱ canȱ writeȱ aȱ partȱ ofȱ aȱ line,ȱ aȱ wholeȱ line,ȱ orȱ
severalȱ lines.ȱ Ifȱ anȱ errorȱ occurredȱ whileȱ writing,ȱ fputsȱ returnsȱ theȱ constantsȱ EOF;ȱ
otherwiseȱitȱreturnsȱaȱnonȬnegativeȱvalue.ȱ
Download at http://www.pin5i.com/
424ȱ
CAUTION!
CAUTION!
Chapter 15 Input/Output Functionsȱ
Programȱ 15.3ȱ isȱ aȱ functionȱ thatȱ readsȱ linesȱ ofȱ inputȱ fromȱ oneȱ fileȱ andȱ writesȱ
themȱunchangedȱtoȱanotherȱfile.ȱTheȱconstantȱ MAX_LINE_LENGTHȱdeterminesȱtheȱsizeȱofȱ
theȱbuffer,ȱandȱthereforeȱtheȱsizeȱofȱtheȱlongestȱlineȱthatȱwillȱbeȱread.ȱInȱthisȱfunctionȱ
theȱvalueȱhasȱlittleȱsignificanceȱbecauseȱtheȱresultingȱfileȱwillȱbeȱtheȱsameȱwhetherȱlongȱ
linesȱareȱwrittenȱailȱatȱonceȱorȱpieceȱbyȱpiece.ȱOnȱtheȱotherȱhand,ȱifȱtheȱfunctionȱwereȱ
toȱ countȱ theȱ numberȱ ofȱ linesȱ thatȱ areȱ copied,ȱ aȱ tooȱ smallȱ bufferȱ wouldȱ produceȱ anȱ
incorrectȱcountȱbecauseȱlongȱlinesȱwouldȱbeȱreadȱinȱtwoȱorȱmoreȱchunks.ȱWeȱcouldȱfixȱ
thisȱproblemȱbyȱaddingȱcodeȱtoȱseeȱifȱeachȱchunkȱendedȱwithȱaȱnewline.ȱ
Theȱ correctȱ valueȱ forȱ theȱ bufferȱsizeȱ isȱ usuallyȱ aȱ compromiseȱ thatȱ dependsȱ onȱ
theȱ natureȱ ofȱ theȱ processingȱ required.ȱ However,ȱ fgetsȱ willȱ neverȱ causeȱ errorsȱ byȱ
overflowingȱitsȱbuffer.ȱ
ȱ
Noteȱ thatȱ fgetsȱ cannotȱ readȱ intoȱ aȱ bufferȱ whoseȱ sizeȱ isȱ lessȱ thanȱ two,ȱ becauseȱ oneȱ
spaceȱinȱtheȱbufferȱisȱreservedȱforȱtheȱNULȱbyteȱthatȱwillȱbeȱadded.ȱ
Theȱ getsȱ andȱ putsȱ functionsȱ areȱ almostȱ identicalȱ toȱ fgetsȱ andȱ fputs.ȱ Theȱ
differencesȱ allowȱ backwardȱ compatibility.ȱ Theȱ majorȱ functionalȱ differenceȱ isȱ thatȱ
whenȱ getsȱreadsȱaȱlineȱofȱinput,ȱitȱdoesȱnotȱstoreȱtheȱterminatingȱnewȬlineȱinȱtheȱbuffer.ȱ
Whenȱputsȱwritesȱaȱstring,ȱitȱaddsȱaȱnewlineȱtoȱtheȱoutputȱafterȱtheȱstringȱisȱwritten.ȱ
ȱ
Anotherȱdifferenceȱpertainsȱonlyȱtoȱ getsȱandȱisȱobviousȱfromȱtheȱfunctionȱprototypes:ȱ
thereȱisȱnoȱbufferȱsizeȱargument.ȱThusȱ getsȱcannotȱdetermineȱtheȱlengthȱofȱtheȱbuffer.ȱ
Ifȱ aȱ longȱ inputȱ lineȱ isȱ readȱ intoȱ aȱ shortȱ buffer,ȱ theȱ excessȱ charactersȱ areȱ writtenȱ inȱ
whateverȱmemoryȱlocationsȱfollowȱtheȱbuffer,ȱthusȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Copy the standard input to the standard output, line by line.
*/
#include <stdio.h>
#define
MAX_LINE_LENGTH
1024
/* longest line I can copy */
void
copylines( FILE *input, FILE *output )
{
char buffer[MAX_LINE_LENGTH];
while( fgets( buffer, MAX_LINE_LENGTH, input ) != NULL )
fputs( buffer, output );
}
ȱ
Programȱ15.3ȱȱCopyȱlinesȱfromȱoneȱfileȱtoȱanotherȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱcopyline.c
Download at http://www.pin5i.com/
15.10 Formatted Line I/Oȱ
425
destroyingȱ theȱ valuesȱ ofȱ oneȱ orȱ moreȱ unrelatedȱ variables.ȱ Thisȱ characteristicȱ makesȱ
getsȱ suitableȱ forȱ onlyȱ theȱ mostȱ trivialȱ ofȱ programs,ȱ becauseȱ theȱ onlyȱ wayȱ toȱ guardȱ
againstȱoverflowingȱtheȱinputȱbufferȱisȱtoȱdeclareȱaȱhugeȱone.ȱButȱnoȱmatterȱhowȱlargeȱ
itȱis,ȱthereȱisȱalwaysȱtheȱpossibilityȱthatȱtheȱnextȱlineȱofȱinputȱwillȱbeȱlarger,ȱespeciallyȱ
whenȱtheȱstandardȱinputȱhasȱbeenȱredirectedȱtoȱaȱfile.ȱ
ȱ
ȱ
ȱ
15.10 Formatted Line I/O
ȱ
Theȱ nameȱ Ȉformattedȱ lineȱ I/OȈȱ isȱ somethingȱ ofȱ aȱ misnomer,ȱ becauseȱ theȱ functionsȱ inȱ
theȱ scanfȱ andȱ printfȱ familiesȱ areȱ notȱ limitedȱ toȱ singleȱ lines.ȱ Theyȱ canȱ performȱ I/Oȱ onȱ
partialȱlinesȱandȱmultipleȱlinesȱasȱwell.ȱ
ȱ
ȱ
ȱ
15.10.1 The scanf Family
ȱ
Theȱ prototypesȱ forȱ theȱ scanfȱ familyȱ areȱ shownȱ below.ȱ Theȱ ellipsisȱ inȱ eachȱ prototypeȱ
representsȱaȱvariableȬlengthȱ listȱofȱ pointers.ȱ Theȱvaluesȱ convertedȱ fromȱtheȱ inputȱ areȱ
storedȱoneȱbyȱoneȱintoȱtheȱlocationsȱtoȱwhichȱtheseȱargumentsȱpoint.ȱ
ȱ
int fscanf( FILE *stream, char const *format, ... );
int scanf( char const *format, ... );
int sscanf( char const *string, char const *format, ... );
CAUTION!
ȱ
Theseȱfunctionsȱallȱreadȱcharactersȱfromȱanȱinputȱsourceȱandȱconvertȱthemȱaccordingȱ
toȱtheȱcodesȱgivenȱinȱtheȱformatȱstring.ȱTheȱinputȱsourceȱforȱfscanfȱisȱtheȱstreamȱgivenȱ
asȱ anȱ argument,ȱ scanfȱ readsȱ fromȱ theȱ standardȱ input,ȱ andȱ sscanfȱ takesȱ inputȱ
charactersȱfromȱtheȱcharacterȱstringȱgivenȱasȱtheȱfirstȱargument.ȱȱ
Inputȱ stopsȱ whenȱ theȱ endȱ ofȱ theȱ formatȱ stringȱ isȱ reachedȱ orȱ inputȱ isȱreadȱ thatȱ
doesȱ notȱ matchȱ whatȱ theȱ formatȱ suingȱ specifies.ȱ Inȱ eitherȱ case,ȱ theȱ numberȱ ofȱ inputȱ
valuesȱ thatȱ wereȱ convertedȱ isȱ returnedȱ asȱ theȱ functionȱ value.ȱ Ifȱ endȱ ofȱ fileȱ isȱ
encounteredȱ beforeȱ anyȱ inputȱ valuesȱ haveȱ beenȱ converted,ȱ theȱ functionȱ returnsȱ theȱ
constantȱEOF.ȱ
ȱ
Forȱtheseȱfunctionsȱtoȱworkȱproperly,ȱtheȱpointerȱargumentsȱmustȱbeȱtheȱrightȱtypeȱforȱ
theȱ correspondingȱ formatȱ codes.ȱ Theȱ functionsȱ cannotȱ verifyȱ whetherȱ theirȱ pointerȱ
argumentsȱareȱ theȱ correctȱtypes,ȱ soȱtheyȱassumeȱ thatȱ theyȱ areȱandȱgoȱ aheadȱ andȱ useȱ
chem.ȱ Ifȱ theȱ pointerȱ typesȱ areȱ incorrect,ȱ theȱ resultingȱ valuesȱ willȱ beȱ garbage,ȱ andȱ
adjacentȱvariablesȱmayȱbeȱoverwrittenȱinȱtheȱprocess.ȱ
Download at http://www.pin5i.com/
426ȱ
Chapter 15 Input/Output Functionsȱ
Byȱ nowȱ theȱ purposeȱ ofȱ theȱ ampersandsȱ beforeȱ theȱ argumentsȱ toȱ theȱ scanfȱ functionsȱ
shouldȱ beȱ clear.ȱ Becauseȱ ofȱ Cȇsȱ callȬbyȬvalueȱ argumentȱ passingȱ mechanism,ȱ theȱ onlyȱ
wayȱ toȱ identifyȱ aȱ locationȱ asȱ aȱ functionȱ argumentȱ isȱ toȱ passȱ aȱ pointerȱ toȱ it.ȱ Aȱ veryȱ
commonȱ errorȱ isȱ toȱ forgetȱ theȱ ampersand.ȱ Thisȱ omissionȱ causesȱ theȱ valueȱ ofȱ theȱ
variableȱ toȱ beȱ passedȱ asȱ theȱ argument,ȱ whichȱ scanfȱ (orȱ eitherȱ ofȱ theȱ otherȱ two)ȱ
interpretsȱasȱifȱitȱwereȱaȱpointer.ȱWhenȱitȱisȱdeȬreferenced,ȱeitherȱtheȱprogramȱabortsȱorȱ
dataȱinȱanȱunexpectedȱlocationȱisȱoverwritten.ȱ
ȱ
ȱ
ȱ
15.10.2 scanf Format Codes
ȱ
Theȱformatȱstringȱmayȱcontainȱanyȱofȱtheȱfollowing:ȱ
x
Whitespaceȱ characters—theseȱ matchȱ zeroȱ orȱ moreȱ whitespaceȱ charactersȱ inȱ theȱ
input,ȱwhichȱareȱignored.ȱ
x
Formatȱ codes—theseȱ specifyȱ howȱ theȱ functionȱ shouldȱ interpretȱ theȱ nextȱ inputȱ
characters.ȱ
x
Otherȱcharacters—eachȱtimeȱanyȱotherȱcharacterȱappearsȱinȱtheȱformatȱstring,ȱthenȱ
theȱnextȱinputȱcharacterȱmustȱmatchȱit.ȱIfȱitȱdoes,ȱtheȱinputȱcharacterȱisȱdiscarded;ȱifȱ
itȱdoesȱnot,ȱtheȱfunctionȱreturns.ȱ
ȱ
Theȱformatȱcodesȱforȱtheȱscanfȱfunctionsȱallȱbeginȱwithȱaȱpercentȱsign,ȱfollowedȱbyȱ(1)ȱ
anȱoptionalȱasterisk,ȱ(2)ȱanȱoptionalȱwidth,ȱ(3)ȱanȱoptionalȱqualifier,ȱandȱ(4)ȱtheȱformatȱ
code.ȱTheȱasteriskȱcausesȱtheȱconvertedȱvalueȱtoȱbeȱdiscardedȱratherȱthanȱstored.ȱThisȱ
techniqueȱ isȱ oneȱ wayȱ toȱ skipȱ pastȱ unneededȱ input.ȱ Theȱ widthȱ isȱ givenȱ asȱ aȱ nonȬ
negativeȱinteger.ȱItȱlimitsȱtheȱnumberȱofȱinputȱcharactersȱthatȱwillȱbeȱreadȱinȱorderȱtoȱ
convertȱthisȱvalue.ȱIfȱaȱwidthȱisnȇtȱgiven,ȱcharactersȱareȱreadȱuntilȱtheȱnextȱwhitespaceȱ
characterȱisȱfoundȱinȱtheȱinput.ȱTheȱqualifiersȱmodifyȱtheȱmeaningsȱofȱcertainȱformatȱ
codes,ȱandȱareȱlistedȱinȱTableȱ15.3.ȱ
ȱ
ȱ
ȱ
ȱ
Result when used with qualifier
ȱ
Format code
h
l
L
d, I, n
o, u, x
e, f, g
short
unsigned short
long
unsigned long
double
long double
ȱ
Tableȱ15.3ȱȱscanfȱqualifiersȱ
Download at http://www.pin5i.com/
15.10 Formatted Line I/Oȱ
427
Theȱ purposeȱ ofȱ theȱ qualifierȱ isȱ toȱ specifyȱ theȱ sizeȱ ofȱ theȱ argument.ȱ Omittingȱ theȱ
qualifierȱ whenȱ anȱ integerȱ argumentȱ isȱ shorterȱ orȱ longerȱ thanȱ theȱ defaultȱ integerȱ isȱ aȱ
commonȱ mistake.ȱ Theȱ sameȱ isȱ trueȱ withȱ theȱ floatingȬpointȱ types.ȱ Dependingȱ onȱ theȱ
relativeȱsizesȱofȱtheseȱtypes,ȱomittingȱtheȱqualifierȱmayȱresultȱinȱlongȱvariablesȱthatȱareȱ
onlyȱhalfȱinitializedȱorȱvariablesȱadjacentȱtoȱshortȱonesȱbeingȱoverwritten.ȱ
ȱ
Onȱaȱmachineȱwhoseȱdefaultȱintegerȱisȱtheȱsameȱsizeȱasȱaȱ short,ȱtheȱ hȱqualifierȱisȱnotȱ
neededȱ whenȱ convertingȱ aȱ short.ȱ However,ȱ theȱ qualifierȱ isȱ neededȱ onȱ aȱ machineȱ
whoseȱdefaultȱ integerȱ sizeȱ isȱlongerȱ thanȱ aȱ short.ȱThus,ȱ yourȱprogramsȱ willȱbeȱ moreȱ
portableȱ ifȱ youȱ useȱ theȱ appropriateȱ qualifierȱ whenȱ convertingȱ allȱ shortȱ andȱ longȱ
integers,ȱandȱallȱlong doubleȱvariables.ȱȱ
Theȱformatȱcodeȱisȱaȱsingleȱcharacterȱthatȱspecifiesȱhowȱtheȱinputȱcharactersȱareȱ
toȱbeȱinterpreted.ȱTableȱ15.4ȱdescribesȱtheȱcodes.ȱ
Letȇsȱ lookȱ atȱ someȱ examplesȱ thatȱ useȱ theȱ scanfȱ functions.ȱ Onceȱ again,ȱ onlyȱ theȱ
partsȱ relevantȱ toȱ theseȱ functionsȱ areȱ shown.ȱ Ourȱ firstȱ exampleȱ isȱ straightforward.ȱ Itȱ
readsȱ pairsȱ ofȱ numbersȱ fromȱ anȱ inputȱ streamȱ andȱ doesȱ someȱ processingȱ onȱ them.ȱȱ
Whenȱendȱofȱtileȱisȱreached,ȱtheȱloopȱbreaks.ȱ
ȱ
int
a, b;
while( fscanf( input, "%d %d", &a, &b ) == 2 ){
/*
** Process the values a and b.
*/
}
ȱ
Thisȱcodeȱisȱratherȱunsophisticatedȱbecauseȱanyȱillegalȱcharactersȱinȱtheȱinputȱstreamȱ
alsoȱ breakȱ theȱ loop.ȱ Also,ȱ becauseȱ fscanfȱ skipsȱ overȱ whiteȱ space,ȱ thereȱ isȱ noȱ wayȱ toȱ
verifyȱwhetherȱtheȱtwoȱvaluesȱwereȱbothȱonȱtheȱsameȱlineȱorȱonȱdifferentȱinputȱlines.ȱȱ
Aȱtechniqueȱtoȱsolveȱthisȱproblemȱisȱshownȱinȱaȱlaterȱexample.ȱ
Theȱnextȱexampleȱusesȱaȱfieldȱwidth.ȱ
ȱ
nfields = fscanf( input, "%4d %4d %4d", &a, &b, &c )
ȱ
Theȱwidthsȱrestrictȱeachȱofȱtheȱintegerȱvaluesȱtoȱbeȱfourȱorȱfewerȱdigitsȱlong.ȱWithȱthisȱ
input,ȱ
ȱ
1 2
ȱ
aȱwouldȱbecomeȱoneȱandȱ bȱwouldȱbecomeȱtwo.ȱ cȱwouldȱbeȱunchanged,ȱandȱ nfieldsȱ
wouldȱbeȱtwo.ȱButȱwithȱthisȱinput,ȱ
ȱ
12345 67890
Download at http://www.pin5i.com/
428ȱ
Chapter 15 Input/Output Functionsȱ
ȱ
Code
Argument
Meaning
c
char *
Aȱsingleȱcharacterȱisȱreadȱandȱstored.ȱLeadingȱwhitespaceȱisȱnotȱskipped.ȱIfȱaȱ
widthȱisȱgiven,ȱthatȱnumberȱofȱcharactersȱareȱreadȱandȱstored;ȱnoȱNULȱbyteȱisȱ
appended;ȱtheȱargumentȱmustȱpointȱtoȱaȱcharacterȱarrayȱthatȱisȱlargeȱenough.ȱ
i
d
int *
Anȱoptionallyȱsignedȱintegerȱisȱconverted.ȱ dȱinterpretsȱtheȱinputȱasȱdecimal;ȱ
iȱ determinesȱ theȱ baseȱ ofȱ theȱ valueȱ byȱ itsȱ firstȱ charactersȱ asȱ isȱ doneȱ withȱ
integerȱliteralȱconstants.ȱ
u
o
x
unsigned *
Anȱ optionallyȱ signedȱ integerȱ isȱ converted,ȱ butȱ isȱ storedȱ asȱ unsigned.ȱ Theȱ
valueȱisȱinterpretedȱasȱdecimalȱwithȱu,ȱoctalȱwithȱo,ȱandȱhexadecimalȱwithȱx.ȱ
TheȱcodeȱXȱisȱaȱsynonymȱforȱx.ȱ
e
f
g
float *
Aȱ floatingȬpointȱ valueȱ isȱ expected.ȱ Itȱ mustȱ lookȱ likeȱ aȱ floatingȬpointȱ literalȱ
constantȱexceptȱthatȱaȱdecimalȱpointȱisȱnotȱrequired.ȱ Eȱandȱ Gȱareȱsynonymsȱ
forȱeȱandȱg.ȱ
s
char *
Aȱsequenceȱofȱnonwhitespaceȱcharactersȱisȱread.ȱTheȱargumentȱmustȱpointȱ
toȱ aȱ characterȱ arrayȱ thatȱ isȱ largeȱ enough.ȱ Inputȱ stopsȱ whenȱ whitespaceȱ isȱ
found;ȱtheȱstringȱisȱthenȱNULȬterminated.ȱ
[xxx]
char *
Aȱ sequenceȱ ofȱ charactersȱ fromȱ theȱ givenȱ setȱ isȱ read.ȱ Theȱ argumentȱ mustȱ
pointȱ toȱ aȱ characterȱ arrayȱ thatȱ isȱ largeȱ enough,ȱ inputȱ stopsȱ whenȱ theȱ firstȱ
characterȱ thatȱ isȱ notȱ inȱ theȱ setȱ isȱ encountered.ȱ Theȱ stringȱ isȱ thenȱ NULȬ
terminated.ȱ Theȱ codeȱ %[abc]ȱ specifiesȱ theȱ setȱ includingȱ a,ȱ b,ȱ andȱ c.ȱ
Beginningȱ theȱ listȱ withȱ ^ȱ complementsȱ theȱ set,ȱ soȱ %[^abc]ȱ meansȱ allȱ
charactersȱexceptȱa,ȱb,ȱandȱc.ȱAȱrightȱbracketȱmayȱbeȱincludedȱinȱtheȱlistȱonlyȱ
ifȱ itȱ isȱ firstȱ itȱ isȱ implementationȱ dependentȱ whetherȱ aȱ dashȱ (forȱ example,ȱ
%[a-z])ȱspecifiesȱaȱrangeȱofȱcharacters.ȱ
p
void *
Theȱinputȱisȱexpectedȱtoȱbeȱaȱsequenceȱofȱcharactersȱsuchȱasȱthoseȱproducedȱ
byȱtheȱ %pȱformatȱcodeȱofȱ printfȱ(seeȱbelow).ȱTheȱconversionȱisȱperformedȱ
inȱanȱimplementationȬdependentȱmanner,ȱbutȱtheȱresultȱwillȱcompareȱequalȱ
toȱtheȱvalueȱthatȱproducedȱtheȱcharactersȱwhenȱprintedȱasȱdescribedȱabove.ȱ
n
int *
Theȱnumberȱofȱcharactersȱreadȱfromȱtheȱinputȱsoȱfarȱbyȱthisȱcallȱtoȱ scanfȱisȱ
returned.ȱ%nȱconversionȱareȱnotȱcountedȱinȱtheȱvalueȱreturnedȱby scanf.ȱNoȱ
inputȱisȱconsumed.ȱ
%
(none)
Thisȱcodeȱmatchesȱaȱsingleȱ%ȱinȱtheȱinput,ȱwhichȱisȱdiscarded.ȱ
ȱ
Tableȱ15.4ȱȱscanfȱformatȱcodesȱ
ȱ
ȱ
aȱwouldȱbeȱ1234,ȱ bȱwouldȱbeȱfive,ȱ cȱwouldȱbeȱ6789,ȱandȱ nfieldsȱwouldȱbeȱthree.ȱTheȱ
finalȱzeroȱwouldȱremainȱunreadȱinȱtheȱinputȱ
Itȱ isȱ difficultȱ toȱ maintainȱ synchronizationȱ withȱ lineȱ boundariesȱ inȱ theȱ inputȱ
whenȱ usingȱ fscanf,ȱ becauseȱ itȱ skipsȱ newlinesȱ asȱ whiteȱ space.ȱ Forȱ example,ȱ supposeȱ
thatȱ aȱ programȱ readsȱ inputȱ thatȱ consistsȱ ofȱ groupsȱ ofȱ fourȱ values.ȱ Theseȱ valuesȱ areȱ
thenȱprocessedȱinȱsomeȱway,ȱandȱtheȱnextȱfourȱvaluesȱareȱread.ȱTheȱsimplestȱwayȱto
Download at http://www.pin5i.com/
15.10 Formatted Line I/Oȱ
429
prepareȱ inputȱ forȱ suchȱ aȱ programȱ isȱ toȱ putȱ eachȱ setȱ ofȱ fourȱ valuesȱ onȱ itsȱ ownȱ inputȱ
line,ȱmakingȱitȱeasyȱtoȱseeȱwhichȱvaluesȱformȱaȱset.ȱButȱifȱoneȱofȱtheȱlinesȱcontainsȱtooȱ
manyȱ orȱ tooȱ fewȱ values,ȱ theȱ programȱ becomesȱ confused.ȱ Forȱ example,ȱ considerȱ thisȱ
input,ȱwhichȱcontainsȱanȱerrorȱinȱitsȱsecondȱline:ȱ
ȱ
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2 2
3
4
5
ȱ
Ifȱweȱusedȱ fscanfȱtoȱreadȱtheȱvaluesȱfourȱatȱaȱtime,ȱtheȱfirstȱandȱsecondȱsetsȱofȱvaluesȱ
wouldȱ beȱ correct,ȱ butȱ theȱ thirdȱ setȱ ofȱ valuesȱ wouldȱ beȱ readȱ asȱ 2,ȱ 3,ȱ 3,ȱ 3.ȱ ȱ Eachȱ
subsequentȱsetȱwouldȱalsoȱbeȱincorrect.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Line-oriented input processing with sscanf
*/
#include <stdio.h>
#define
BUFFER_SIZE 100
/* Longest line we'll handle */
void
function( FILE *input )
{
int
a, b, c, d, e;
char buffer[ BUFFER_SIZE ];
while( fgets( buffer, BUFFER_SIZE, input ) != NULL ){
if( sscanf( buffer, "%d %d %d %d %d",
&a, &b, &c, &d, &e ) != 4 ){
fprintf( stderr, "Bad input skipped: %s",
buffer );
continue;
}
/*
** Process this set of input.
*/
}
}
ȱ
Programȱ15.4ȱȱProcessingȱlineȬorientedȱinputȱwithȱsscanfȱȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱscanf1.cȱ
Download at http://www.pin5i.com/
430ȱ
Chapter 15 Input/Output Functionsȱ
Programȱ15.4ȱusesȱaȱmoreȱreliableȱapproachȱforȱreadingȱthisȱtypeȱofȱinput.ȱTheȱ
advantageȱ ofȱ thisȱ methodȱ isȱ thatȱ theȱ inputȱ isȱ nowȱ processedȱ lineȱ byȱ line.ȱ Itȱ isȱ
impossibleȱ toȱ readȱ aȱ setȱ ofȱ valuesȱ thatȱ beginsȱ onȱ oneȱ lineȱ andȱ endsȱ onȱ theȱ next.ȱ
Furthermore,ȱbyȱtryingȱ toȱ convertȱfiveȱvalues,ȱ inputȱ linesȱ thatȱhaveȱtooȱ manyȱ valuesȱ
areȱdetectedȱasȱwellȱasȱthoseȱwithȱtooȱfew.ȱ
Aȱ relatedȱ techniqueȱ isȱ usedȱ toȱ readȱ lineȬorientedȱ inputȱ thatȱ mayȱ beȱ inȱ severalȱ
differentȱ formats.ȱ Aȱ lineȱ isȱ readȱ withȱ fgetsȱ andȱ thenȱ scannedȱ withȱ severalȱ sscanfȇs,ȱ
eachȱ usingȱ aȱ differentȱ format.ȱ Theȱ formatȱ ofȱ theȱ inputȱ lineȱ isȱ determinedȱ byȱ theȱ firstȱ
sscanfȱ thatȱ convertsȱ theȱ expectedȱ numberȱ ofȱ values.ȱ Forȱ instance,ȱ Programȱ 15.5ȱ
examinesȱtheȱcontentsȱofȱaȱbufferȱthatȱwasȱreadȱearlier.ȱItȱextractsȱeitherȱone,ȱtwo,ȱorȱ
threeȱvaluesȱfromȱaȱlineȱofȱinputȱandȱassignsȱdefaultȱvaluesȱtoȱvariablesȱforȱwhichȱanȱ
inputȱvalueȱwasȱnotȱgiven.ȱ
ȱ
ȱ
ȱ
15.10.3 The printf Family
ȱ
Functionsȱ inȱ theȱ printfȱ familyȱ areȱ usedȱ toȱ createȱ formattedȱ output.ȱ Thereȱ areȱ threeȱ
functionsȱ inȱ thisȱ family:ȱ fprintf,ȱ printf,ȱ andȱ sprintf.ȱ ȱ Theirȱ prototypesȱ areȱ shownȱ
below.ȱ
ȱ
int fprintf( FILE *stream, char const *format, ... );
int printf( char const *format, ... );
int sprintf( char *buffer, char const *format, ... );
CAUTION!
ȱ
AsȱyouȱsawȱinȱChapterȱ1,ȱ printfȱformatsȱtheȱvaluesȱinȱitsȱargumentȱlistȱaccordingȱtoȱ
theȱformatȱcodesȱandȱotherȱcharactersȱinȱtheȱ formatȱargument.ȱTheȱotherȱmembersȱofȱ
thisȱfamilyȱworkȱtheȱsameȱway.ȱȱWithȱprintf,ȱtheȱresultingȱoutputȱgoesȱtoȱtheȱstandardȱ
output.ȱWithȱfprintf,ȱanyȱoutputȱstreamȱcanȱbeȱused,ȱandȱsprintfȱwritesȱitsȱresultsȱasȱ
aȱNULȬterminatedȱstringȱinȱtheȱspecifiedȱbufferȱratherȱthanȱtoȱaȱstream.ȱ
ȱ
sprintfȱisȱaȱpotentialȱsourceȱofȱerror.ȱTheȱbufferȱsizeȱisȱnotȱanȱargumentȱtoȱsprintf,ȱsoȱ
outputȱthatȱisȱunexpectedlyȱlongȱ canȱspillȱoutȱofȱtheȱendȱofȱtheȱbufferȱandȱoverwriteȱ
whateverȱhappensȱtoȱfollowȱtheȱbufferȱinȱmemory.ȱThereȱareȱtwoȱstrategiesȱforȱmakingȱ
sureȱ thatȱ thisȱ problemȱ neverȱ happens.ȱ Theȱ firstȱ isȱ toȱ declareȱ aȱ veryȱ largeȱ buffer.ȱ Butȱ
thisȱ solutionȱ wastesȱ memory,ȱ andȱ althoughȱ aȱ largeȱ bufferȱ reducesȱ theȱ chanceȱ ofȱ
overflow,ȱitȱdoesȱnotȱeliminateȱit.ȱTheȱsecondȱapproachȱisȱtoȱanalyzeȱtheȱformatȱtoȱseeȱ
howȱ longȱ theȱ resultingȱ outputȱ wouldȱ beȱ whenȱ theȱ largestȱ possibleȱ valuesȱ areȱ
converted.ȱ Forȱ example,ȱ theȱ largestȱ integerȱ onȱ aȱ machineȱ withȱ 4Ȭbyteȱ integersȱ isȱ 11ȱ
charactersȱ includingȱ aȱ sign,ȱ soȱ theȱ bufferȱ shouldȱ alwaysȱ beȱ atȱ leastȱ 12ȱ charactersȱ inȱ
orderȱtoȱholdȱtheȱvalueȱandȱtheȱterminatingȱNULȱbyte.ȱThereȱisnȇtȱaȱlimitȱonȱtheȱlengthȱȱ
Download at http://www.pin5i.com/
15.10 Formatted Line I/Oȱ
431
ȱ
ȱ
/*
** Variable format input processing with sscanf
*/
#include <stdio.h>
#include <stdlib.h>
#define
#define
DEFAULT_A
DEFAULT_B
1
2
/* or whatever ... */
/* or whatever ... */
void
function( char *buffer )
{
int
a, b, c;
/*
** See if all three values are given.
*/
if( sscanf( buffer, "%d %d %d", &a, &b, &c ) != 3 ){
/*
** No, use default value for a, see if other two
** values are both given.
*/
a = DEFAULT_A;
if( sscanf( buffer, "%d %d", &b, &c ) != 2 ){
/*
** Use default value for b too, look for
** remaining value.
*/
b = DEFAULT_B;
if( sscanf( buffer, "%d", &c ) != 1 ){
fprintf( stderr, "Bad input: %s",
buffer );
exit( EXIT_FAILURE );
}
}
}
/*
** Process the values a, b, and c.
*/
}
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱscanf2.cȱ
Programȱ15.5ȱȱProcessingȱvariableȱformatȱinputȱwithȱsscanfȱ ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ofȱstrings,ȱbutȱtheȱnumberȱofȱcharactersȱprintedȱforȱaȱstringȱcanȱbeȱrestrictedȱwithȱanȱ
optionalȱfieldȱinȱtheȱformatȱcode.ȱ
Download at http://www.pin5i.com/
432ȱ
Chapter 15 Input/Output Functionsȱ
Theȱformatȱcodesȱusedȱwithȱtheȱprintfȱfamilyȱworkȱdifferentlyȱthanȱthoseȱusedȱwithȱtheȱ
scanfȱ functions,ȱ soȱ youȱ mustȱ beȱ carefulȱ notȱ toȱ intermixȱ them.ȱ Thisȱ problemȱ isȱ madeȱ
moreȱ difficultȱ byȱ theȱ factȱ thatȱ someȱ ofȱ theȱ formatȱ codesȱ lookȱ identicalȱ withoutȱ theirȱ
optionalȱfields.ȱUnfortunately,ȱmanyȱofȱtheȱcommonlyȱusedȱcodes,ȱsuchȱasȱ %d,ȱfallȱintoȱ
thisȱcategory.ȱ
ȱ
Anotherȱ sourceȱ ofȱ errorȱ isȱ havingȱ argumentsȱ whoseȱ typesȱ doȱ notȱ matchȱ theȱ
CAUTION!
correspondingȱformatȱcodes.ȱUsuallyȱtheȱresultȱofȱthisȱerrorȱisȱgarbageȱinȱtheȱoutput,ȱ
butȱ itȱ isȱ possibleȱ forȱ suchȱ aȱ mismatchȱ toȱ causeȱ theȱ programȱ toȱ abort.ȱ Asȱ inȱ theȱ scanfȱ
family,ȱ theseȱ functionsȱ cannotȱ verifyȱ thatȱ aȱ valueȱ hasȱ theȱ properȱ typeȱ forȱ aȱ formatȱ
code,ȱsoȱitȱisȱupȱtoȱyouȱtoȱmakeȱsureȱtheyȱmatchȱproperly.ȱ
ȱ
ȱ
ȱ
ȱ
Code
Argument
Meaning
CAUTION!
c
int
Theȱargumentȱisȱtruncatedȱtoȱunsigned charȱandȱprintedȱasȱaȱcharacter.ȱ
d
i
int
Theȱargumentȱisȱprintedȱasȱaȱdecimalȱinteger.ȱIfȱaȱprecisionȱisȱgivenȱandȱtheȱ
valueȱhasȱfewerȱdigits,ȱzerosȱareȱaddedȱatȱtheȱfront.ȱ
u
o
x,X
unsigned
int
Theȱ argumentȱ isȱ printedȱ asȱ anȱ unsignedȱ valueȱ inȱ decimalȱ (u),ȱ octalȱ (o),ȱ orȱ
hexadecimalȱ(xȱorȱX).ȱxȱandȱXȱareȱidenticalȱexceptȱthatȱabcdefȱareȱusedȱforȱxȱ
conversions,ȱandȱABCDEFȱareȱusedȱwithȱX.ȱ
e
E
double
Theȱ argumentȱ isȱ printedȱ inȱ exponentȱ form;ȱ forȱ example,ȱ 6.023000e23ȱ forȱ
theȱ eȱ code,ȱ andȱ 6.023000E23ȱ forȱ theȱ Eȱ code.ȱ Theȱ numberȱ ofȱ digitsȱ behindȱ
theȱ decimalȱ pointȱ isȱ determinedȱ byȱ theȱ precisionȱ field;ȱ theȱ defaultȱ isȱ sixȱ
digits.ȱ
f
double
Theȱargumentȱisȱprintedȱinȱconventionalȱnotation.ȱTheȱprecisionȱdeterminesȱ
theȱnumberȱofȱdigitsȱbehindȱtheȱdecimalȱpoint;ȱtheȱdefaultȱisȱsix.ȱ
g
G
double
Theȱ argumentȱ isȱ printedȱ inȱ eitherȱ %fȱ orȱ %eȱ (orȱ %E,ȱ ifȱ Gȱ isȱ given)ȱ notation,ȱ
dependingȱonȱitsȱvalue.ȱTheȱ %fȱformȱisȱusedȱifȱtheȱexponentȱisȱgreaterȱthanȱ
orȱequalȱtoȱ –4ȱȱbutȱlessȱthanȱtheȱprecision.ȱOtherwiseȱtheȱexponentȱformȱisȱ
used.ȱ
s
char *
Aȱstringȱisȱprinted.ȱ
p
void *
Theȱ valueȱ ofȱ theȱ pointerȱ isȱ convertedȱ toȱ anȱ implementationȬdependentȱ
sequenceȱofȱprintableȱcharacters.ȱThisȱcodeȱisȱusedȱprimarilyȱinȱconjunctionȱ
withȱtheȱ%pȱcodeȱinȱscanf.ȱ
n
int *
Thisȱ codeȱ isȱ uniqueȱ inȱ thatȱ itȱ doesȱ notȱ produceȱ anyȱ output.ȱ Instead,ȱ theȱ
numberȱ ofȱ charactersȱ ofȱ outputȱ producedȱ soȱ farȱ isȱ storedȱ inȱ theȱ
correspondingȱargument.ȱ
%
(none)
Aȱsingleȱ%ȱisȱproducedȱinȱtheȱoutput.ȱ
ȱ
Tableȱ15.5ȱȱprintfȱformatȱcodesȱ
Download at http://www.pin5i.com/
15.10 Formatted Line I/Oȱ
433
15.10.4 printf Format Codes
ȱ
Theȱformatȱstringȱmayȱcontainȱformattingȱcodes,ȱwhichȱcauseȱtheȱnextȱvalueȱfromȱtheȱ
argumentȱlistȱtoȱbeȱformattedȱinȱtheȱspecifiedȱmanner,ȱandȱotherȱcharacters,ȱwhichȱareȱ
printedȱverbatim.ȱFormatȱcodesȱconsistȱofȱaȱpercentȱsignȱfollowedȱbyȱ(1)ȱzeroȱorȱmoreȱ
flagȱ charactersȱ thatȱ modifyȱ howȱ someȱ conversionsȱ areȱ performed,ȱ (2)ȱ anȱ optionalȱ
minimumȱ fieldȱ width.ȱ (3)ȱ anȱ optionalȱ precision,ȱ (4)ȱ anȱ optionalȱ modifier,ȱ andȱ (5)ȱ theȱ
conversionȱtype.ȱ
Theȱpreciseȱmeaningsȱofȱtheȱflagsȱandȱotherȱfieldsȱdependȱonȱwhichȱconversionȱ
isȱ used.ȱ Tableȱ 15.5ȱ describesȱ theȱ conversionȱ typeȱ codes,ȱ andȱ Tableȱ 15.6ȱ describesȱ theȱ
flagȱcharactersȱandȱtheirȱmeanings.ȱ
Theȱ fieldȱ widthȱ isȱ aȱ decimalȱ integerȱ specifyingȱ theȱ minimumȱ numberȱ ofȱ
charactersȱthatȱwillȱappearȱinȱtheȱresult.ȱIfȱaȱvalueȱhasȱfewerȱcharactersȱthanȱtheȱfieldȱ
width,ȱpaddingȱoccursȱtoȱincreaseȱitsȱlength.ȱTheȱflagsȱdetermineȱwhetherȱpaddingȱisȱ
doneȱ withȱ spacesȱ orȱ zerosȱ andȱ whetherȱ itȱ occursȱ onȱ theȱ leftȱ orȱ fileȱ rightȱ endȱ ofȱ theȱ
value.ȱ
Forȱd,ȱi,ȱ u,ȱ o,ȱ x,ȱandȱ Xȱconversions,ȱtheȱprecisionȱspecifiesȱtheȱminimumȱnumberȱ
ofȱ digitsȱ thatȱ willȱ appearȱ inȱ theȱ resultȱ andȱ overridesȱ theȱ zeroȱ flag.ȱ Ifȱ theȱ convertedȱ
valueȱhasȱfewerȱdigits,ȱleadingȱzerosȱareȱinserted.ȱDigitsȱareȱnotȱproducedȱifȱtheȱvalueȱ
zeroȱ isȱ convertedȱ withȱ aȱ precisionȱ ofȱ zero.ȱ Forȱ e,ȱ E,ȱ andȱ fȱ conversions,ȱ theȱ precisionȱ
determinesȱtheȱnumberȱofȱdigitsȱthatȱwillȱappearȱafterȱtheȱdecimalȱpoint.ȱForȱ gȱandȱ Gȱ
conversions,ȱ itȱ specifiesȱ theȱ maximumȱ numberȱ ofȱ significantȱ digitsȱ thatȱ willȱ appear.ȱ
Whenȱusedȱwithȱsȱconversions,ȱtheȱprecisionȱspecifiesȱtheȱmaximumȱnumberȱofȱȱ
ȱ
ȱ
ȱ
Flag
Meaning
-
Leftȱjustifyȱtheȱvalueȱinȱitsȱfield.ȱTheȱdefaultȱisȱtoȱrightȱjustify.ȱ
0
Whenȱrightȱjustifyingȱnumericȱvalues,ȱtheȱdefaultȱisȱtoȱuseȱspacesȱtoȱfillȱunusedȱcolumnsȱtoȱ
theȱleftȱofȱtheȱvalue.ȱThisȱflagȱcausesȱzerosȱtoȱbeȱusedȱinstead,ȱandȱitȱappliesȱtoȱtheȱd,ȱi,ȱu,ȱo,ȱ
x,ȱ X,ȱ e,ȱ E,ȱ f,ȱ g,ȱandȱ Gȱcodes.ȱWithȱtheȱ d,ȱ i,ȱ u,ȱ o,ȱ x,ȱandȱ Xȱcodes,ȱtheȱzeroȱflagȱisȱignoredȱifȱaȱ
precisionȱisȱgiven.ȱTheȱzeroȱflagȱhasȱnoȱeffectȱifȱtheȱminusȱflagȱisȱalsoȱgiven.ȱ
+
Whenȱusedȱwithȱaȱcodeȱthatȱformatsȱaȱsignedȱvalue,ȱthisȱforcesȱaȱplusȱsignȱtoȱappearȱwhenȱ
theȱ valueȱ isȱ notȱ negative.ȱ Ifȱ theȱ valueȱ isȱ negative,ȱ aȱ minusȱ signȱ isȱ shownȱ asȱ usual.ȱ Byȱ
default,ȱplusȱsignsȱareȱnotȱshown.ȱ
spaceȱ
Usefulȱonlyȱforȱcodesȱthatȱconvertȱsignedȱvalues,ȱthisȱflagȱcausesȱaȱspaceȱtoȱbeȱaddedȱtoȱtheȱ
beginningȱ ofȱ theȱ resultȱ whenȱ theȱ valueȱ isȱ notȱ negative.ȱ Noteȱ thatȱ thisȱ flagȱ andȱ +ȱ areȱ
mutuallyȱexclusive;ȱifȱbothȱareȱgivenȱtheȱspaceȱflagȱisȱignored.ȱ
#
Selectsȱanȱalternateȱformȱofȱconversionȱforȱsomeȱcodes.ȱTheseȱareȱdescribedȱinȱTableȱ15.8.ȱ
ȱ
Tableȱ15.6ȱȱprintfȱformatȱflagsȱ
Download at http://www.pin5i.com/
Chapter 15 Input/Output Functionsȱ
434ȱ
ȱ
Modifier
Used With …
h
d, I, u, o, x, X
h
n
l
d, I, u, o, x, X
l
n
L
e, E, f, g, G
Means the Arguments is …
aȱ(possiblyȱunsigned)ȱshortȱinteger
aȱpointerȱtoȱaȱshortȱintegerȱ
aȱ(possiblyȱunsigned)ȱlongȱintegerȱ
aȱpointerȱtoȱaȱlongȱintegerȱ
aȱlong doubleȱ
ȱ
Tableȱ15.7ȱȱprintfȱformatȱcodeȱmodifiersȱ
ȱ
ȱ
charactersȱ thatȱ willȱ beȱ converted.ȱ Theȱ precisionȱ isȱ givenȱ asȱ aȱ periodȱ followedȱ byȱ anȱ
optionalȱdecimalȱinteger.ȱIfȱtheȱintegerȱisȱmissingȱȱaȱprecisionȱofȱzeroȱisȱused.ȱ
Ifȱ anȱ asteriskȱ isȱ givenȱ inȱ placeȱ ofȱ aȱ decimalȱ integerȱ forȱ theȱ fieldȱ widthȱ and/orȱ
precision,ȱ thenȱ theȱ nextȱ argumentȱ toȱ printfȱ (whichȱ mustȱ beȱ anȱ integer)ȱ suppliesȱ theȱ
widthȱ and/orȱ precision.ȱ Thus,ȱ eitherȱ ofȱ theseȱ valuesȱ mayȱ beȱ computedȱ ratherȱ thanȱ
specifiedȱinȱadvance.ȱ
Whenȱcharacterȱorȱshortȱintegerȱvaluesȱareȱgivenȱasȱargumentsȱtoȱ printf,ȱtheyȱ
areȱconvertedȱtoȱintegersȱbeforeȱbeingȱpassed.ȱSometimesȱtheȱconversionȱcanȱaffectȱtheȱ
outputȱ thatȱ isȱ produced.ȱ Also,ȱ whenȱ passingȱ aȱ longȱ integerȱ asȱ anȱ argumentȱ inȱ anȱ
environmentȱwhereȱlongȱintegersȱoccupyȱmoreȱmemoryȱthanȱordinaryȱintegers,ȱprintfȱ
mustȱ beȱ toldȱ thatȱ theȱ argumentȱ isȱ aȱ long.ȱ Theȱ modifiers,ȱ shownȱ inȱ Tableȱ 15.7,ȱ solveȱ
theseȱproblemsȱbyȱindicatingȱtheȱexactȱsizeȱofȱintegerȱandȱfloatingȬpointȱarguments.ȱ
Onȱ implementationsȱ inȱ whichȱ intsȱ andȱ shortȱ intsȱ areȱ theȱ sameȱ length,ȱ theȱ hȱ
modifierȱhasȱnoȱeffect.ȱOtherwise,ȱtheȱvalueȱtoȱbeȱconvertedȱwillȱhaveȱbeenȱpromotedȱ
toȱanȱ(unsigned)ȱintegerȱwhenȱitȱwasȱpassedȱasȱanȱargument;ȱthisȱmodifierȱcausesȱitȱtoȱ
beȱ truncatedȱ backȱ toȱ itsȱ shortȱ formȱ beforeȱ theȱ conversionȱ takesȱ place.ȱ Withȱ decimalȱ
conversions,ȱ theȱ truncationȱ isȱ generallyȱ notȱ needed.ȱ Butȱ withȱ someȱ octalȱ orȱ
hexadecimalȱconversions,ȱtheȱ hȱmodifierȱwillȱensureȱthatȱtheȱproperȱnumberȱofȱdigitsȱ
isȱprinted.ȱ
ȱ
ȱ
ȱ
Used With …
The # Flag …
o
guaranteesȱthatȱtheȱvalueȱproducedȱbeginsȱwithȱaȱzero.ȱ
x, X
prefixesȱaȱnonzeroȱvalueȱwithȱ0xȱ(0Xȱforȱtheȱ%Xȱcode).ȱ
e, E, f
ensuresȱtheȱresultȱalwaysȱcontainsȱaȱdecimalȱpoint,ȱevenȱifȱnoȱ
digitsȱfollowȱit.ȱ
g, G
doesȱtheȱsameȱasȱforȱtheȱe,ȱE,ȱandȱfȱcodesȱabove;ȱinȱaddition,ȱ
trailingȱzerosȱareȱnotȱremovedȱfromȱtheȱfraction.ȱ
ȱ
Tableȱ15.8ȱȱAlternativeȱformsȱofȱprintfȱconversionsȱ
Download at http://www.pin5i.com/
15.10 Formatted Line I/Oȱ
435
ȱ
CAUTION!
TIP
Format
Code
String Converted
A
ABC
ABCDEFGH
%s
A
ABC
ABCDEFGH
%5s
¤¤¤¤A
¤¤ABC
ABCDEFGH
%.5s
A
ABC
ABCDE
%5.5s
¤¤¤¤A
¤¤ABC
ABCDE
%-5s
A¤¤¤¤
ABC¤¤
ABCDEFGH
ȱ
Figureȱ15.1ȱȱFormattingȱstringsȱwithȱprintfȱ
ȱ
ȱ
Onȱimplementationsȱinȱwhichȱ intsȱandȱ long intsȱareȱtheȱsameȱlength,ȱtheȱ lȱmodifierȱ
hasȱ noȱ effect.ȱ Onȱ allȱ otherȱ implementations,ȱ theȱ lȱ modifierȱ isȱ required,ȱ becauseȱ longȱ
integersȱonȱsuchȱmachinesȱareȱpassedȱinȱtwoȱpartsȱonȱtheȱruntimeȱstack.ȱIfȱtheȱmodifierȱ
isȱ notȱ given,ȱ onlyȱ theȱ firstȱ partȱ isȱ retrievedȱ forȱ theȱ conversion.ȱ Notȱ onlyȱ willȱ thisȱ
conversionȱ produceȱ incorrectȱ results,ȱ butȱ theȱ secondȱ partȱ ofȱ theȱ valueȱ isȱ thenȱ
interpretedȱ asȱ aȱ separateȱ argument,ȱ disruptingȱ theȱ correspondenceȱ betweenȱ theȱ
subsequentȱargumentsȱandȱtheirȱformatȱcodes.ȱ
Whenȱusedȱwithȱseveralȱofȱtheȱprintfȱformatȱcodes,ȱtheȱ#ȱflagȱselectsȱanȱalternateȱ
formȱofȱconversion.ȱTheȱdetailsȱofȱtheseȱformsȱareȱlistedȱinȱTableȱ15.8.ȱ
ȱ
Becauseȱ someȱ implementationsȱ requireȱ theȱ lȱ modifierȱ whenȱ printingȱ longȱ integerȱ
valuesȱandȱothersȱdoȱnot,ȱitȱisȱbetterȱtoȱuseȱitȱwheneverȱprintingȱlongs.ȱThenȱyouȱcanȱ
portȱtheȱprogramȱtoȱeitherȱtypeȱofȱimplementationȱwithȱfewerȱmodifications.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Format
Number Converted
Code
1
-12
12345
123456789
%d
1
-12
12345ȱ
123456789
%6d
¤¤¤¤¤1
¤¤¤-12
¤12345ȱ
123456789
%.4d
0001
-0012
12345ȱ
123456789
%6.4d
¤¤0001
¤-0012
¤12345ȱ
123456789
%-4d
1¤¤¤
-12¤
12345ȱ
123456789
%04d
0001
-012
12345ȱ
123456789
%+d
+1
-12
+12345ȱ
+123456789
ȱ
Figureȱ15.2ȱȱformattingȱintegersȱwithȱprintfȱ
Download at http://www.pin5i.com/
Chapter 15 Input/Output Functionsȱ
436ȱ
ȱ
Format
Code
Number Converted
1
.01
.00012345
12345.6789
%f
1.000000
0.010000
0.000123
12345.678900
%10.2f
¤¤¤¤¤¤1.00
¤¤¤¤¤¤0.01
¤¤¤¤¤¤0.00
¤¤12345.68
%e
1.000000e+00
1.000000e-02
1.234500e-04
1.234568e+04
%.4e
1.0000e+00
1.0000e-02
1.2345e-04
1.2346e+04
%g
1
0.01
0.00012345
12345.7
ȱ
Figureȱ15.3ȱȱFormattingȱfloatingȬpointȱvaluesȱwithȱprintfȱ
ȱ
Theȱ abundanceȱ ofȱ codes,ȱ modifiers,ȱ qualifiers,ȱ alternateȱ forms,ȱ andȱ optionalȱ
fieldsȱ thatȱ canȱ beȱ usedȱ withȱ printfȱ canȱ beȱ overwhelming,ȱ burȱ theyȱ provideȱ greatȱ
flexibilityȱ inȱ formattingȱ yourȱ output.ȱ Beȱ patient,ȱ itȱ takesȱ timeȱ toȱ learnȱ themȱ all!ȱ Hereȱ
areȱsomeȱexamplesȱtoȱgetȱyouȱstarted.ȱ
Figureȱ15.1ȱshowsȱsomeȱofȱtheȱpossibleȱvariationsȱinȱformattingȱofȱstrings.ȱOnlyȱ
theȱcharactersȱshownȱareȱprinted.ȱToȱavoidȱambiguity,ȱtheȱsymbolȱ¤ȱisȱusedȱtoȱdenoteȱaȱ
blankȱ space.ȱ Figureȱ 15.2ȱ showsȱ theȱ resultsȱ ofȱ formattingȱ severalȱ integerȱ valuesȱ withȱ
variousȱintegerȱformats.ȱȱFigureȱ15.3ȱshowsȱsomeȱofȱtheȱwaysȱthatȱfloatingȬpointȱvaluesȱ
canȱ beȱ formatted.ȱ Finally,ȱ Figureȱ 15.4ȱ showsȱ theȱ resultsȱ ofȱ formattingȱ aȱ muchȱ largerȱ
floatingȬpointȱ numberȱ withȱ theȱ sameȱ formatȱ codesȱ asȱ theȱ previousȱ figure.ȱ Theȱ
apparentȱerrorȱinȱtheȱfirstȱtwoȱoutputsȱoccursȱbecauseȱmoreȱsignificantȱdigitsȱareȱbeingȱ
printedȱthanȱcanȱbeȱstoredȱinȱmemory.ȱ
ȱ
ȱ
ȱ
15.11 Binary I/O
ȱ
Theȱmostȱefficientȱwayȱofȱwritingȱdataȱtoȱaȱfileȱisȱtoȱwriteȱitȱinȱbinary.ȱBinaryȱoutputȱ
avoidsȱtheȱoverheadȱandȱlossȱofȱprecisionȱinvolvedȱwithȱconvertingȱnumericȱvaluesȱtoȱ
characterȱstrings.ȱButȱbinaryȱdataȱisȱnotȱreadableȱbyȱhumanȱbeings,ȱsoȱthisȱtechniqueȱisȱȱ
ȱ
ȱ
Format
Number Converted
Code
6.023e23
%f
602299999999999975882752.000000
%10.2f
602299999999999975882752.00
%e
6.023000e+23
%.4e
6.0230e+23
%g
6.023e+23
ȱ
Figureȱ15.4ȱȱFormattingȱlargeȱfloatingȬpointȱvaluesȱwithȱprintfȱ
Download at http://www.pin5i.com/
15.11 Binary I/Oȱ
437
usefulȱonlyȱforȱdataȱthatȱwillȱbeȱsubsequentlyȱreadȱbyȱanotherȱprogram.ȱ
Theȱ freadȱfunctionȱisȱusedȱtoȱreadȱbinaryȱdata;ȱ fwriteȱisȱusedȱtoȱwriteȱit.ȱTheirȱ
prototypesȱlookȱlikeȱthis:ȱ
ȱ
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
size_t fwrite( void *buffer, size_t size, size_t count, FILE *stream );
ȱ
bufferȱisȱaȱpointerȱtoȱtheȱareaȱthatȱholdsȱtheȱdata.ȱ sizeȱisȱtheȱnumberȱofȱbytesȱinȱeachȱ
elementȱ ofȱ theȱ buffer,ȱ countȱ isȱ theȱ numberȱ ofȱ elementsȱ toȱ beȱ readȱ orȱ written,ȱ andȱ ofȱ
courseȱstreamȱisȱtheȱstreamȱwithȱwhichȱtoȱreadȱorȱwriteȱtheȱdata.ȱ
Theȱbufferȱisȱinterpretedȱasȱanȱarrayȱofȱoneȱorȱmoreȱvalues.ȱTheȱcountȱargumentȱ
specifiesȱhowȱmanyȱvaluesȱareȱinȱtheȱarray,ȱsoȱtoȱreadȱorȱwriteȱaȱscalar,ȱuseȱaȱcountȱofȱ
one.ȱTheȱfunctionsȱreturnȱtheȱnumberȱofȱelementsȱ(notȱbytes)ȱactuallyȱreadȱorȱwritten.ȱȱ
Thisȱnumberȱmayȱbeȱsmallerȱthanȱtheȱrequestedȱnumberȱofȱelementsȱifȱendȱofȱfileȱwasȱ
reachedȱonȱinputȱorȱanȱerrorȱoccurredȱonȱoutput.ȱ
Letȇsȱlookȱatȱaȱcodeȱfragmentȱthatȱusesȱtheseȱfunctions.ȱ
ȱ
struct
VALUE {
long a;
float b;
char c[SIZE];
} values[ARRAY_SIZE];
...
n_values = fread( values, sizeof( struct VALUE ),
ARRAY_SIZE, input_stream );
(processȱtheȱdataȱinȱtheȱarray)ȱ
fwrite( values, sizeof( struct VALUE ),
n_values, output_stream );
ȱ
Thisȱprogramȱreadsȱbinaryȱdataȱfromȱanȱinputȱfile,ȱperformsȱsomeȱtypeȱofȱprocessingȱ
onȱit,ȱandȱwritesȱtheȱresultȱtoȱanȱoutputȱfile.ȱAsȱmentioned,ȱthisȱtypeȱofȱI/Oȱisȱefficientȱ
becauseȱtheȱbitsȱinȱeachȱvalueȱareȱwrittenȱ(orȱread)ȱtoȱ(orȱfrom)ȱtheȱstreamȱwithoutȱanyȱ
conversions.ȱForȱexample,ȱsupposeȱoneȱofȱtheȱlongȱintegerȱvaluesȱinȱtheȱarrayȱhadȱtheȱ
valueȱ4,023,817.ȱTheȱbitsȱthatȱrepresentȱthisȱvalueȱareȱ0x003d6609—theseȱbitsȱwouldȱbeȱ
writtenȱtoȱtheȱstream.ȱBinaryȱinformationȱisȱnotȱreadableȱbyȱhumanȱbeingsȱbecauseȱtheȱ
bitsȱ doȱ notȱ correspondȱ toȱ anyȱ reasonableȱ characters.ȱ Ifȱ interpretedȱ asȱ characters,ȱ thisȱ
valueȱisȱ \0=f\t,ȱwhichȱcertainlyȱdoesȱnotȱconveyȱtheȱvalueȱofȱtheȱnumberȱveryȱwellȱtoȱ
us.ȱ
Download at http://www.pin5i.com/
438ȱ
Chapter 15 Input/Output Functionsȱ
15.12 Flushing and Seeking Functions
ȱ
Thereȱ areȱ aȱ fewȱ additionalȱ functionsȱ thatȱ areȱ usefulȱ whenȱ dealingȱ withȱ streams.ȱ Theȱ
firstȱ isȱ fflush,ȱ whichȱ forcesȱ theȱ bufferȱ forȱ anȱ outputȱ streamȱ toȱ beȱ physicallyȱ writtenȱ
evenȱifȱitȱisȱnotȱyetȱfull.ȱItsȱprototypeȱis:ȱ
ȱ
int fflush( FILE *stream );
ȱ
Thisȱ functionȱ shouldȱ beȱ calledȱ wheneverȱ itȱ isȱ importantȱ forȱ bufferedȱ outputȱ toȱ beȱ
physicallyȱ writtenȱ immediately.ȱ Forȱ example,ȱ callingȱ fflushȱ guaranteesȱ thatȱ
debuggingȱinformationȱisȱphysicallyȱprintedȱinsteadȱofȱheldȱinȱtheȱbufferȱuntilȱaȱlaterȱ
time.ȱ
Normally,ȱ dataȱ isȱ writtenȱ toȱ aȱ fileȱ sequentially,ȱ whichȱ meansȱ thatȱ dataȱ writtenȱ
laterȱappearsȱinȱtheȱfileȱafterȱanyȱdataȱwrittenȱearlier.ȱCȱalsoȱsupportsȱrandomȱaccessȱI/Oȱ
inȱwhichȱdifferentȱlocationsȱofȱtheȱfileȱcanȱbeȱaccessedȱinȱanyȱorder.ȱRandomȱaccessȱisȱ
accomplishedȱ byȱ seekingȱ toȱ theȱ desiredȱ positionȱ inȱ theȱ fileȱ beforeȱ readingȱ orȱ writing.ȱȱ
Thereȱareȱtwoȱfunctionsȱthatȱperformȱthisȱoperation,ȱandȱtheirȱprototypesȱare:ȱ
ȱ
long ftell( FILE *stream );
int fseek( FILE *stream, long offset, int from );
ȱ
Theȱ ftellȱfunctionȱreturnsȱtheȱcurrentȱpositionȱinȱtheȱstream,ȱthatȱis,ȱtheȱoffsetȱ
fromȱ theȱ beginningȱ ofȱ theȱ fileȱ atȱ whichȱ theȱ nextȱ readȱ orȱ writeȱ wouldȱ begin.ȱ Thisȱ
functionȱ letsȱ youȱ saveȱ theȱ currentȱ positionȱ inȱ aȱ fileȱ soȱ thatȱ youȱ canȱ returnȱ toȱ itȱ later.ȱȱ
Onȱbinaryȱstreamsȱtheȱvalueȱwillȱbeȱtheȱnumberȱofȱbytesȱtheȱcurrentȱpositionȱisȱfromȱ
theȱbeginningȱofȱtheȱfile.ȱȱ
Onȱ textȱ streams,ȱ theȱ valueȱ representȱ aȱ position,ȱ butȱ itȱ mayȱ notȱ accuratelyȱ
representȱtheȱnumberȱofȱcharactersȱfromȱtheȱbeginningȱofȱtheȱfileȱbecauseȱofȱtheȱendȬ
ofȬlineȱ characterȱ translationsȱ performedȱ onȱ textȱ streamsȱ byȱ someȱ systems.ȱ However,ȱ
theȱvalueȱreturnedȱbyȱftellȱmayȱalwaysȱbeȱusedȱasȱanȱoffsetȱfromȱtheȱbeginningȱofȱtheȱ
fileȱwithȱfseek.ȱȱ
fseekȱ allowsȱ youȱ toȱ seekȱ onȱ aȱ stream.ȱ Thisȱ operationȱ changesȱ theȱ positionȱ atȱ
whichȱ theȱ nextȱ readȱ orȱ writeȱ willȱ occur.ȱ Theȱ firstȱ argumentȱ isȱ theȱ streamȱ toȱ change.ȱ
Theȱ secondȱ andȱ thirdȱ argumentsȱ identifyȱ theȱ desiredȱ locationȱ inȱ theȱ file.ȱ Tableȱ 15.9ȱ
describesȱthreeȱwaysȱthatȱtheȱsecondȱandȱthirdȱargumentsȱcanȱbeȱused.ȱ
Itȱisȱanȱerrorȱtoȱattemptȱtoȱseekȱbeforeȱtheȱbeginningȱofȱaȱfile.ȱSeekingȱbeyondȱ
theȱendȱofȱtheȱfileȱandȱwritingȱextendsȱtheȱfile.ȱSeekingȱbeyondȱtheȱendȱreadingȱcausesȱ
anȱendȬofȬfileȱindicationȱtoȱbeȱreturned.ȱOnȱbinary,ȱstreams,ȱseeksȱfromȱ SEEK_ENDȱmayȱ
notȱbeȱsupportedȱandȱshouldȱthereforeȱbeȱavoided.ȱOnȱtextȱstreams,ȱtheȱoffsetȱmustȱbeȱ
ȱ
Download at http://www.pin5i.com/
15.12 Flushing and Seeking Functionsȱ
439
If from is…
Then you will seek to…
SEEK_SET
offsetȱbytesȱfromȱtheȱbeginningȱofȱtheȱstream;ȱ offsetȱmustȱbeȱ
nonȬnegative.ȱ
SEEK_CUR
offsetȱ bytesȱ fromȱ theȱ currentȱ locationȱ inȱ theȱ stream;ȱ offsetȱ
mayȱbeȱpositiveȱorȱnegative.ȱ
SEEK_END
offsetȱbytesȱfromȱtheȱendȱofȱtheȱfile;ȱ offsetȱmayȱbeȱpositiveȱorȱ
negative,ȱpositiveȱvaluesȱseekȱbeyondȱtheȱendȱofȱtheȱfile.ȱ
ȱ
Tableȱ15.9ȱȱfseekȱargumentsȱ
ȱ
ȱ
ȱ
ȱ
zeroȱ ifȱ fromȱ isȱ eitherȱ SEEK_CURȱ orȱ SEEK_END.ȱ Theȱ offsetȱ mustȱ beȱ aȱ valueȱ previouslyȱ
returnedȱfromȱaȱcallȱtoȱftellȱonȱtheȱsameȱstreamȱifȱfromȱisȱSEEK_SET.ȱ
Partȱ ofȱ theȱ reasonȱ forȱ theseȱ restrictionsȱ isȱ theȱ endȬofȬlineȱ characterȱ mappingȱ
performedȱonȱtextȱstreams.ȱBecauseȱofȱtheȱmapping,ȱtheȱnumberȱofȱbytesȱinȱtheȱtextȱfileȱ
mayȱ beȱ differentȱ thanȱ theȱ numberȱ ofȱ bytesȱ theȱ programȱ wrote.ȱ Thus,ȱ aȱ portableȱ
programȱcannotȱseekȱtoȱaȱpositionȱinȱaȱtextȱstreamȱusingȱtheȱresultȱofȱaȱcomputationȱ
basedȱonȱtheȱnumberȱofȱcharactersȱwritten.ȱ
Thereȱareȱthreeȱsideȱeffectsȱofȱchangingȱaȱstreamȇsȱpositionȱwithȱfseek.ȱFirst,ȱtheȱ
endȬofȬfileȱindicatorȱisȱcleared.ȱSecond,ȱifȱaȱcharacterȱhadȱbeenȱreturnedȱtoȱtheȱstreamȱ
withȱ ungetcȱ priorȱ toȱ anȱ fseek,ȱ theȱ ungottenȱ characterȱ isȱ forgottenȱ becauseȱ afterȱ theȱ
seekȱitȱisȱnoȱlongerȱtheȱnextȱcharacter.ȱFinally,ȱseekingȱletsȱyouȱswitchȱfromȱreadingȱtoȱ
writingȱandȱbackȱonȱstreamsȱopenedȱforȱupdate.ȱ
Programȱ 15.6ȱ usesȱ fseekȱ toȱ accessȱ aȱ fileȱ ofȱ studentȱ information.ȱ Theȱ recordȱ
numberȱargumentȱisȱaȱ size_tȱbecauseȱitȱdoesnȇtȱmakeȱsenseȱforȱitȱtoȱbeȱnegative.ȱTheȱ
desiredȱlocationȱinȱtheȱfileȱisȱcomputedȱbyȱmultiplyingȱtheȱrecordȱnumberȱandȱrecordȱ
size.ȱ Thisȱ calculationȱ worksȱ onlyȱ whenȱ allȱ recordsȱ inȱ theȱ fileȱ areȱ theȱ sameȱ length.ȱȱ
Finally,ȱ theȱ resultȱ ofȱ freadȱ isȱ returnedȱ soȱ theȱ callerȱ canȱ determineȱ whetherȱ theȱ
operationȱwasȱsuccessful.ȱ
Thereȱ areȱ threeȱ additionalȱ functionsȱ thatȱ performȱ theseȱ sameȱ tasksȱ inȱ moreȱ
limitedȱways.ȱTheirȱprototypesȱfollow,ȱ
ȱ
void rewind( FILE *stream );
int fgetpos( FILE *stream, fpos_t *position );
int fsetpos( FILE *stream, fpos_t const *position );
ȱ
Theȱ rewindȱfunctionȱsetsȱtheȱread/writeȱpointerȱbackȱtoȱtheȱbeginningȱonȱtheȱindicatedȱ
stream.ȱ Itȱ alsoȱ clearsȱ theȱ errorȱ indicatorȱ forȱ theȱ stream.ȱ Theȱ fgetposȱ andȱ fsetposȱ
functionsȱareȱalternativesȱtoȱftellȱandȱfseek,ȱrespectively.ȱ
Download at http://www.pin5i.com/
Chapter 15 Input/Output Functionsȱ
440ȱ
ȱ
/*
** Reads a specific record from a file. The arguments are the stream
** from which to read, the desired record number, and a pointer to
** the buffer into which the data should be placed.
*/
#include <stdio.h>
#include "studinfo.h"
int
read_random_record( FILE *f, size_t rec_number, StudentInfo *buffer )
{
fseek( f, (long)rec_number * sizeof( StudentInfo ),
SEEK_SET );
return fread( buffer, sizeof( StudentInfo ), 1, f );
}
ȱ
Programȱ15.6ȱȱRandomȱfileȱaccessȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱrd_rand.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Theȱprimaryȱdifferenceȱisȱthatȱthisȱpairȱofȱfunctionsȱtakesȱaȱpointerȱtoȱaȱ fpos_tȱasȱanȱ
argument.ȱ fgetposȱstoresȱtheȱcurrentȱfileȱpositionȱinȱthisȱlocationȱandȱ fsetposȱsetsȱtheȱ
fileȱpositionȱtoȱtheȱvalue.ȱ
Theȱ wayȱ aȱ fileȱ positionȱ isȱ representedȱ byȱ anȱ fpos_tȱ isȱ notȱ definedȱ byȱ theȱ
standard.ȱȱItȱmayȱbeȱaȱbyteȱoffsetȱinȱtheȱfile,ȱorȱitȱmayȱnot.ȱTherefore,ȱtheȱonlyȱsafeȱwayȱ
toȱuseȱanȱfpos_tȱobtainedȱfromȱfgetposȱisȱasȱanȱargumentȱtoȱaȱsubsequentȱfsetpos.ȱ
ȱ
ȱ
ȱ
15.13 Changing the Buffering
ȱ
Theȱbufferingȱperformedȱonȱstreamsȱisȱsometimesȱinappropriate,ȱsoȱtheȱfollowingȱtwoȱ
functionsȱ areȱ providedȱ toȱ modifyȱ it.ȱ Bothȱ functionsȱ mayȱ beȱ calledȱ onlyȱ afterȱ theȱ
specifiedȱ streamȱ hasȱ beenȱ openedȱ butȱ beforeȱ anyȱ otherȱ operationsȱ haveȱ beenȱ
performedȱonȱit.ȱ
ȱ
void setbuf( FILE *stream, char *buf );
int setvbuf( FILE *stream, char *buf, int mode, size_t size );
ȱ
setbufȱinstallsȱanȱalternateȱarrayȱtoȱbeȱusedȱforȱbufferingȱtheȱstream.ȱTheȱarrayȱ
mustȱ beȱ BUFSIZȱ (whichȱ isȱ definedȱ inȱ stdio.h)ȱ charactersȱ long.ȱ Assigningȱ yourȱ ownȱ
bufferȱtoȱaȱstreamȱpreventsȱtheȱI/Oȱlibraryȱfromȱdynamicallyȱallocatingȱaȱbufferȱforȱit.ȱ
IfȱcalledȱwithȱaȱNULLȱargument,ȱsetbufȱturnsȱoffȱallȱbufferingȱforȱtheȱstream.ȱCharactersȱ
ȱ
Download at http://www.pin5i.com/
15.14 Stream Error Functionsȱ
CAUTION!
441
areȱwrittenȱtoȱandȱreadȱfromȱtheȱfileȱexactlyȱasȱdirectedȱbyȱtheȱprogram. 47
ȱ
Itȱ isȱ dangerousȱ toȱ useȱ anȱ automaticȱ arrayȱ forȱ aȱ streamȱ buffer.ȱ Ifȱ executionȱ leavesȱ theȱ
blockȱ inȱ whichȱ theȱ arrayȱ wasȱ declaredȱ beforeȱ theȱ streamȱ isȱ closed,ȱ theȱ streamȱ willȱ
continueȱ toȱ useȱ theȱ memoryȱ even,ȱ afterȱ itȱ hasȱ beenȱ allocatedȱ toȱ otherȱ functionsȱ forȱ
otherȱpurposes.ȱ
Theȱ setvbufȱfunctionȱisȱmoreȱgeneral.ȱTheȱmodeȱargumentȱindicatesȱwhatȱtypeȱ
ofȱ bufferingȱ isȱ desired. _IOFBFȱ indicatesȱ aȱ fullyȱ bufferedȱ stream,ȱ _IONBFȱ indicatesȱ anȱ
unbufferedȱstream,ȱandȱ_IOLBFȱindicatesȱaȱlineȱbufferedȱstream.ȱAnȱoutputȱstreamȱthatȱ
isȱlineȱbufferedȱisȱflushedȱeachȱtimeȱaȱnewlineȱisȱwrittenȱtoȱtheȱbuffer.ȱ
Theȱ bufȱ andȱ sizeȱ argumentsȱ areȱ usedȱ toȱ specifyȱ theȱ bufferȱ toȱ use;ȱ ifȱ bufȱ isȱ
NULL,ȱthenȱzeroȱmustȱbeȱgivenȱforȱsize.ȱȱGenerally,ȱitȱisȱbestȱtoȱuseȱanȱarrayȱofȱBUFSIZȱ
charactersȱforȱaȱbuffer.ȱAlthoughȱusingȱaȱveryȱlargeȱbufferȱmayȱincreaseȱtheȱefficiencyȱ
ofȱ theȱ programȱ slightly,ȱ itȱ mayȱ alsoȱ decreaseȱ theȱ efficiency.ȱ Forȱ example,ȱ mostȱ
operatingȱ systemsȱ bufferȱ input/outputȱ operationsȱ toȱ diskȱ internally.ȱ Specifyingȱ aȱ
bufferȱ thatȱ isȱ notȱ aȱ multipleȱ ofȱ theȱ operatingȱ systemȇsȱ bufferȱ sizeȱ mayȱ resultȱ inȱ extraȱ
diskȱoperationsȱtoȱreadȱorȱwriteȱaȱfractionȱofȱaȱblock.ȱIfȱaȱlargerȱbufferȱisȱneeded,ȱyouȱ
shouldȱ useȱ aȱ multipleȱ ofȱ BUFSIZ.ȱ Onȱ MSȬDOSȱ machines,ȱ aȱ bufferȱ thatȱ matchesȱ theȱ
clusterȱsizeȱusedȱforȱyourȱdiskȱmayȱprovideȱsomeȱimprovement.ȱ
ȱ
ȱ
ȱ
15.14 Stream Error Functions
ȱ
Theȱfollowingȱfunctionsȱareȱusedȱtoȱdetermineȱtheȱstateȱofȱaȱstream.ȱ
ȱ
int feof( FILE *stream );
int ferror( FILE *stream );
void clearer( FILE *stream );
ȱ
feofȱreturnsȱtrueȱifȱtheȱstreamȱisȱcurrentlyȱatȱendȱofȱfile.ȱThisȱconditionȱcanȱbeȱclearedȱ
byȱ performingȱ fseek,ȱ rewind,ȱ orȱ fsetposȱ onȱ theȱ stream.ȱ ferrorȱ reportsȱ onȱ theȱ errorȱ
stateȱ ofȱ theȱ streamȱ andȱ returnsȱ trueȱ ifȱ anyȱ read/writeȱ errorsȱ haveȱ occurred.ȱ Finally,ȱ
clearerrȱresetsȱtheȱerrorȱindicationȱforȱtheȱgivenȱstream.ȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
ȱInȱhostedȱruntimeȱenvironments,ȱtheȱoperatingȱsystemȱmayȱperformȱitsȱownȱbuffering,ȱindependentȱofȱtheȱstream.ȱThus,ȱ
merelyȱcallingȱsetbufȱwillȱnotȱallowȱaȱprogramȱtoȱreadȱcharactersȱfromȱaȱkeyboardȱasȱtheyȱareȱtyped,ȱbecauseȱtheȱoperatingȱ
systemȱusuallyȱbuffersȱtheseȱcharactersȱinȱorderȱtoȱimplementȱbackspaceȱediting.ȱ
47
Download at http://www.pin5i.com/
442ȱ
Chapter 15 Input/Output Functionsȱ
15.15 Temporary Files
ȱ
Occasionally,ȱitȱisȱconvenientȱtoȱuseȱaȱfileȱtoȱholdȱdataȱtemporarily.ȱWhenȱtheȱprogramȱ
isȱ finished,ȱ theȱ fileȱ isȱ deletedȱ becauseȱ theȱ dataȱ itȱ containsȱ isȱ noȱ longerȱ useful.ȱ Theȱ
tmpfileȱfunctionȱservesȱforȱthisȱpurpose.ȱ
ȱ
FILE *tmpfile( void );
ȱ
Thisȱfunctionȱcreatesȱaȱfileȱthatȱisȱremovedȱautomaticallyȱwhenȱtheȱfileȱisȱclosedȱorȱtheȱ
programȱterminates.ȱTheȱfileȱisȱopenedȱwithȱmodeȱ wb+,ȱmakingȱitȱsuitableȱforȱuseȱwithȱ
binaryȱorȱtextȱdataȱ
tmpfileȱ isȱ notȱ appropriateȱ forȱ aȱ temporaryȱ fileȱ thatȱ mustȱ beȱ openedȱ withȱ aȱ
differentȱ modeȱ orȱ createdȱ byȱ oneȱ programȱ andȱ readȱ byȱ another.ȱ Inȱ theseȱ
circumstances,ȱ fopenȱ mustȱ beȱ used,ȱ andȱ theȱ resultingȱ fileȱ mustȱ beȱ explicitlyȱ deletedȱ
usingȱremoveȱ(seeȱbelow)ȱwhenȱitȱisȱnoȱlongerȱneeded.ȱ
Temporaryȱfileȱnamesȱcanȱbeȱconstructedȱwithȱtheȱ tmpnamȱfunction,ȱwhichȱ hasȱ
thisȱprototype:ȱ
ȱ
char *tmpnam( char * name );
ȱ
Ifȱ calledȱ withȱ aȱ NULLȱ argument,ȱ theȱ functionȱ returnsȱ aȱ pointerȱ toȱ aȱ staticȱ arrayȱ
containingȱtheȱconstructedȱfileȱname.ȱOtherwise,ȱtheȱargumentȱisȱassumedȱtoȱpointȱtoȱ
anȱarrayȱthatȱisȱatȱleastȱ L_tmpnamȱcharactersȱlong.ȱInȱthisȱcase,ȱtheȱnameȱisȱconstructedȱ
inȱtheȱarrayȱandȱtheȱargumentȱisȱreturned.ȱ
Eitherȱway,ȱtheȱnameȱthatȱisȱconstructedȱisȱguaranteedȱnotȱtoȱbeȱtheȱnameȱofȱanȱ
existingȱfile. 48 ȱtmpnamȱgeneratesȱaȱnewȱuniqueȱnameȱeachȱtimeȱitȱisȱcalledȱupȱtoȱTMP_MAXȱ
times.ȱ
ȱ
ȱ
ȱ
15.16 File Manipulation Functions
ȱ
Thereȱ areȱ twoȱ functionsȱ thatȱ manipulateȱ filesȱ withoutȱ performingȱ anyȱ input/output.ȱȱ
Theirȱ prototypesȱ areȱ shownȱ below.ȱ Bothȱ functionsȱ returnȱ zeroȱ ifȱ theyȱ succeedȱ andȱ aȱ
nonzeroȱvalueȱifȱtheyȱfail.ȱ
ȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
ȱ Beware:ȱ Theȱ schemeȱ usedȱ toȱ guaranteeȱ uniquenessȱ mayȱ failȱ onȱ multiprogrammingȱ systemsȱ orȱ systemsȱ thatȱ shareȱ aȱ
networkȱ fileȱ server.ȱ Theȱ causeȱ ofȱ theȱ problemȱ isȱ theȱ delayȱ betweenȱ whenȱ theȱ nameȱ isȱ constructedȱ andȱ whenȱ aȱ fileȱ ofȱ thatȱ
nameȱisȱcreated.ȱIfȱseveralȱprogramsȱhappenȱtoȱconstructȱtheȱsameȱnameȱandȱtestȱforȱtheȱexistenceȱofȱaȱfileȱbeforeȱanyȱhaveȱ
actuallyȱcreatedȱit,ȱeachȱprogramȱwillȱthinkȱthatȱitȱhasȱaȱuniqueȱname.ȱCreatingȱtheȱfileȱasȱsoonȱasȱtheȱtemporaryȱnameȱhasȱ
beenȱconstructedȱreducesȱ(butȱdoesȱnotȱeliminate)ȱtheȱpotentialȱconflict.ȱ
48
Download at http://www.pin5i.com/
15.17 Summaryȱ
443
int remove( char const *filename );
int rename( char const *oldname, char const *newname );
ȱ
removeȱdeletesȱtheȱspecifiedȱfile.ȱIfȱtheȱfileȱisȱopenȱwhenȱ removeȱisȱcalled,ȱtheȱbehaviorȱ
isȱimplementationȱdependent.ȱ
Theȱ renameȱ functionȱ isȱ usedȱ toȱ changeȱ theȱ nameȱ ofȱ aȱ fileȱ fromȱ oldnameȱ toȱ
newname.ȱ Ifȱ aȱ fileȱ alreadyȱ existsȱ withȱ theȱ newȱ name,ȱ theȱ behaviorȱ isȱ implementationȱ
dependent.ȱIfȱthisȱfunctionȱfails,ȱtheȱfileȱwillȱstillȱbeȱaccessibleȱwithȱitsȱoriginalȱname.ȱ
ȱ
ȱ
ȱ
15.17 Summary
ȱ
Theȱ Standardȱ dictatesȱ theȱ interfaceȱ andȱ operationȱ ofȱ theȱ functionsȱ inȱ theȱ standardȱ
library,ȱ whichȱ enhancesȱ programȱ portability.ȱ Anȱ implementationȱ mayȱ provideȱ
additionalȱfunctionsȱinȱitsȱlibrary,ȱbutȱmayȱnotȱchangeȱtheȱrequiredȱfunctions.ȱ
perrorȱprovidesȱaȱsimpleȱmethodȱofȱreportingȱerrorsȱtoȱtheȱuser.ȱWhenȱaȱfatalȱ
errorȱisȱdetected,ȱyouȱcanȱuseȱexitȱtoȱterminateȱtheȱprogram.ȱ
Theȱ stdio.hȱ headerȱ containsȱ declarationsȱ necessaryȱ forȱ usingȱ theȱ I/Oȱ libraryȱ
functions.ȱȱAllȱI/Oȱisȱaȱmatterȱofȱmovingȱbytesȱintoȱorȱoutȱofȱtheȱprogram.ȱTheȱinterfaceȱ
providedȱbyȱtheȱ libraryȱ forȱI/Oȱ isȱcalledȱaȱstream.ȱByȱdefault,ȱstreamȱ I/Oȱ isȱ buffered.ȱ
Binaryȱstreamsȱareȱusedȱprimarilyȱforȱbinaryȱdata.ȱBytesȱareȱwrittenȱtoȱorȱreadȱfromȱaȱ
binaryȱ streamȱ withoutȱ modification.ȱ Textȱ streams,ȱ onȱ theȱ otherȱ hand,ȱ areȱ usedȱ forȱ
characters.ȱ Theȱ longestȱ lineȱ allowedȱ inȱ aȱ textȱ streamȱ isȱ implementationȬdefined,ȱ butȱ
mustȱ beȱ atȱ leastȱ 254ȱ charactersȱ long.ȱ Byȱ definition,ȱ aȱ lineȱ isȱ terminatedȱ byȱ aȱ newlineȱ
character.ȱ Ifȱ theȱ hostȱ operatingȱ systemȱ usesȱ aȱ differentȱ conventionȱ forȱ terminatingȱ
lines,ȱtheȱI/Oȱfunctionsȱmustȱtranslateȱbetweenȱthatȱformȱandȱtheȱinternalȱform.ȱ
Aȱ FILEȱisȱaȱdataȱstructureȱthatȱmanagesȱtheȱbufferȱandȱstoresȱtheȱI/Oȱstateȱforȱaȱ
stream.ȱ Theȱ runtimeȱ environmentȱ providesȱ threeȱ streamsȱ toȱ eachȱ program—theȱ
standardȱ input,ȱ standardȱ output,ȱ andȱ standardȱ error.ȱ Itȱ isȱ commonȱ forȱ theȱ standardȱ
inputȱtoȱdefaultȱtoȱaȱkeyboardȱandȱtheȱotherȱtwoȱstreamsȱtoȱdefaultȱtoȱaȱdisplayȱscreen.ȱȱ
Aȱseparateȱstreamȱisȱprovidedȱforȱerrorȱmessagesȱsoȱthatȱtheyȱwillȱbeȱdisplayedȱinȱtheȱ
defaultȱ locationȱ evenȱ ifȱ theȱ standardȱ outputȱ hasȱ beenȱ redirectedȱ toȱ anotherȱ location.ȱ
FOPEN_MAXȱisȱtheȱimplementationȬdefinedȱlimitȱofȱtheȱnumberȱofȱ FILEsȱyouȱmayȱhaveȱ
openȱ simultaneously.ȱ Theȱ valueȱ mustȱ beȱ atȱ leastȱ eight.ȱ FILENAME_MAXȱ isȱ eitherȱ theȱ
maximumȱlengthȱor,ȱifȱthereȱisnȇtȱaȱmaximumȱlength,ȱtheȱrecommendedȱsizeȱtoȱuseȱforȱ
characterȱarraysȱinȱwhichȱfilenamesȱareȱstored.ȱ
Download at http://www.pin5i.com/
444ȱ
Chapter 15 Input/Output Functionsȱ
ToȱperformȱstreamȱI/Oȱ onȱaȱfile,ȱ itȱisȱ firstȱ openedȱ withȱ fopen,ȱ whichȱ returnsȱ aȱ
pointerȱtoȱtheȱ FILEȱstructureȱassignedȱtoȱ theȱstream.ȱThisȱpointerȱmustȱbeȱsavedȱinȱaȱ
FILE *ȱvariable.ȱTheȱfileȱmayȱthenȱbeȱreadȱfromȱand/orȱwrittenȱto.ȱAfterwards,ȱtheȱfileȱ
isȱ closed.ȱ Manyȱ ofȱ theȱ I/Oȱ functionsȱ belongȱ toȱ familiesȱ whoseȱ membersȱ performȱ
essentiallyȱ theȱ sameȱ workȱ withȱ minorȱ differencesȱ asȱ toȱ whereȱ inputȱ isȱ obtainedȱ orȱ
outputȱisȱwritten.ȱTheȱusualȱvariantsȱincludeȱaȱfunctionȱthatȱtakesȱaȱstreamȱargument,ȱ
aȱfunctionȱthatȱworksȱonlyȱwithȱoneȱofȱtheȱstandardȱstreams,ȱandȱaȱfunctionȱthatȱworksȱ
withȱaȱbufferȱinȱmemoryȱratherȱthanȱaȱstream.ȱ
Streamsȱareȱopenedȱwithȱ fopen.ȱItsȱargumentsȱareȱtheȱnameȱofȱtheȱfileȱtoȱopenȱ
andȱ theȱ desiredȱ modeȱ ofȱ theȱ stream.ȱ Theȱ modeȱ specifiesȱ reading,ȱ writing,ȱ orȱ
appending,ȱ andȱ alsoȱ specifiesȱ whetherȱ theȱ streamȱ willȱ beȱ textȱ orȱ binary.ȱ freopenȱ
performsȱtheȱsameȱtask,ȱexceptȱthatȱyouȱcanȱspecifyȱtheȱstreamȱtoȱuse.ȱThisȱfunctionȱisȱ
mostȱ oftenȱ usedȱ toȱ reopenȱ oneȱ ofȱ theȱ standardȱ streams.ȱ Alwaysȱ checkȱ theȱ valueȱ
returnedȱfromȱfopenȱorȱfreopenȱforȱerrors.ȱȱAfterȱyouȱhaveȱfinishedȱwithȱaȱstream,ȱyouȱ
shouldȱcloseȱitȱwithȱfclose.ȱ
CharacterȬbyȬcharacterȱ I/Oȱ isȱ performedȱ byȱ theȱ getcharȱ andȱ putcharȱ familiesȱ ofȱ
functions.ȱ Theȱ inputȱ functionsȱ fgetcȱ andȱ getcȱ bothȱ takeȱ aȱ streamȱ argument,ȱ andȱ
getcharȱ readsȱ onlyȱ fromȱ theȱ standardȱ input.ȱ Theȱ firstȱ isȱ implementedȱ asȱ aȱ functionȱ
andȱtheȱotherȱtwoȱareȱimplementedȱasȱmacros.ȱAllȱthreeȱreturnȱaȱsingleȱcharacterȱasȱanȱ
integerȱ value.ȱ Exceptȱ forȱ performingȱ outputȱ insteadȱ ofȱ input,ȱ theȱ fputc,ȱ putc,ȱ andȱ
putcharȱfunctionsȱshareȱtheȱpropertiesȱofȱtheȱcorrespondingȱinputȱfunctions.ȱ ungetcȱisȱ
usedȱ toȱ pushȱ anȱ unwantedȱ characterȱ backȱ toȱ aȱ stream.ȱ Theȱ pushedȱ characterȱ willȱ beȱ
theȱ firstȱ oneȱ returnedȱ byȱ theȱ nextȱ inputȱ operation.ȱ Changingȱ theȱ streamȇsȱ positionȱ
(seeking)ȱcausesȱungottenȱcharactersȱtoȱbeȱforgotten.ȱ
Lineȱ I/Oȱ canȱ beȱ eitherȱ formattedȱ orȱ unformatted.ȱ Theȱ getsȱ andȱ putsȱ familiesȱ
performȱunformattedȱlineȱI/O.ȱfgetsȱandȱgetsȱbothȱreadȱaȱlineȱofȱinputȱintoȱaȱspecifiedȱ
buffer.ȱ Theȱ formerȱ takesȱ aȱ streamȱ argumentȱ andȱ theȱ latterȱ worksȱ withȱ theȱ standardȱ
input.ȱ fgetsȱ isȱ safer.ȱ Itȱ takesȱ theȱ bufferȱ sizeȱ asȱ anȱ argumentȱ andȱ thereforeȱ canȱ
guaranteeȱthatȱaȱlongȱinputȱlineȱwillȱnotȱoverflowȱtheȱbuffer.ȱDataȱisȱnotȱlost—theȱnextȱ
partȱ ofȱ aȱ longȱ inputȱ lineȱ willȱ beȱ readȱ byȱ theȱ nextȱ callȱ toȱ fgets.ȱ Theȱ fputsȱ andȱ putsȱ
functionsȱ writeȱ textȱ toȱ aȱ stream.ȱ Theirȱ interfacesȱ areȱ analogousȱ toȱ theȱ correspondingȱ
inputȱfunctions.ȱȱForȱbackwardȱcompatibility,ȱ getsȱremovesȱtheȱnewlineȱfromȱtheȱlineȱ
itȱread,ȱandȱputsȱwritesȱaȱnewlineȱafterȱtheȱtextȱfromȱtheȱbuffer.ȱ
Theȱ scanfȱ andȱ printfȱ familiesȱ performȱ formattedȱ I/O.ȱ Thereȱ areȱ threeȱ inputȱ
functions.ȱ fscanfȱtakesȱaȱstreamȱargument,ȱ scanfȱreadsȱfromȱtheȱstandardȱinput,ȱandȱ
sscanfȱ takesȱ charactersȱ fromȱ aȱ bufferȱ inȱ memory.ȱ Theȱ printfȱ famiJyȱ alsoȱ hasȱ threeȱ
functionsȱwithȱsimilarȱproperties.ȱTheȱscanfȱfunctionsȱconvertȱcharactersȱaccordingȱtoȱaȱ
formatȱstring.ȱAȱlistȱofȱpointerȱargumentsȱindicatesȱwhereȱtheȱresultingȱvaluesȱareȱ
Download at http://www.pin5i.com/
15.17 Summaryȱ
445
ȱ
stored.ȱTheȱfunctionȱreturnsȱtheȱnumberȱofȱvaluesȱthatȱwereȱconverted,ȱorȱEOFȱifȱendȱofȱ
fileȱ wasȱ reachedȱ beforeȱ theȱ firstȱ conversion.ȱ Theȱ printfȱ functionsȱ convertȱ valuesȱ toȱ
characterȱformȱaccordingȱtoȱaȱformatȱstring.ȱTheȱvaluesȱareȱpassedȱasȱarguments.ȱ
ȱ
Itȱ isȱ moreȱ efficientȱ toȱ writeȱ binaryȱ data,ȱ suchȱ asȱ integersȱ andȱ floatingȬpointȱ
values,ȱwithȱbinaryȱI/OȱthanȱwithȱcharacterȱI/O.ȱBinaryȱI/Oȱreadsȱandȱwritesȱtheȱbitsȱinȱ
theȱ valueȱ directly,ȱ withoutȱ convertingȱ theȱ valueȱ toȱ characters.ȱ Theȱ resultȱ ofȱ binaryȱ
output,ȱhowever,ȱisȱnotȱhumanȬreadable.ȱ freadȱandȱ fwriteȱperformȱbinaryȱI/O.ȱEachȱ
takesȱfourȱarguments:ȱaȱpointerȱtoȱaȱbuffer,ȱtheȱsizeȱofȱoneȱelementȱinȱtheȱbuffer,ȱtheȱ
desiredȱnumberȱofȱelementsȱtoȱreadȱorȱwrite,ȱandȱaȱstream.ȱ
ȱ
Byȱ default,ȱ streamsȱ areȱ sequential.ȱ However,ȱ youȱ canȱ performȱ randomȱ I/Oȱ byȱ
seekingȱtoȱaȱdifferentȱpositionȱinȱtheȱfileȱbeforeȱreadingȱorȱwriting.ȱTheȱ fseekȱfunctionȱ
letsȱ youȱ specifyȱ aȱ positionȱ inȱ theȱ fileȱ asȱ anȱ offsetȱ fromȱ theȱ beginningȱ ofȱ theȱ file,ȱ theȱ
currentȱfileȱposition,ȱorȱtheȱendȱofȱtheȱfile.ȱ ftellȱreturnsȱtheȱcurrentȱfileȱposition.ȱTheȱ
fsetpos andȱ fgetposȱ functionsȱ areȱ alternativesȱ toȱ theȱ previousȱ twoȱ functions.ȱȱ
However,ȱ theȱ onlyȱ legalȱ argumentȱ toȱ fsetposȱ isȱ aȱ valueȱ previouslyȱ returnedȱ byȱ
fgetposȱonȱtheȱsameȱstream.ȱFinally,ȱtheȱ rewindȱfunctionȱreturnsȱtoȱtheȱbeginningȱofȱaȱ
file.ȱ
ȱ
Theȱ bufferȱusedȱforȱaȱstreamȱcanȱ beȱ changedȱbyȱcallingȱ setbufȱbeforeȱ anyȱ I/Oȱ
hasȱoccurredȱonȱtheȱstream.ȱAssigningȱaȱbufferȱinȱthisȱmannerȱpreventsȱoneȱfromȱbeingȱ
dynamicallyȱ allocated.ȱ Passingȱ aȱ NULLȱ pointerȱ asȱ theȱ bufferȱ argumentȱ disablesȱ
bufferingȱaltogether.ȱTheȱ setvbufȱfunctionȱisȱmoreȱgeneral.ȱȱWithȱit,ȱyouȱcanȱspecifyȱaȱ
bufferȱwithȱaȱnonstandardȱsize.ȱYouȱmayȱalsoȱchooseȱtheȱtypeȱofȱbufferingȱyouȱdesire:ȱ
fullyȱbuffered,ȱlineȱbuffered,ȱorȱunbuffered.ȱ
ȱ
Theȱ ferrorȱandȱ clearerrȱfunctionsȱrelateȱtoȱtheȱerrorȱstateȱofȱaȱstream,ȱthatȱis,ȱ
whetherȱanyȱread/writeȱerrorsȱhaveȱoccurred.ȱTheȱfirstȱfunctionȱreturnsȱtheȱerrorȱstate,ȱ
andȱ theȱ secondȱ functionȱ resetsȱ it.ȱ Theȱ feofȱ functionȱ returnsȱ trueȱ ifȱ theȱ streamȱ isȱ
currentlyȱatȱendȱofȱfile.ȱ
ȱ
Theȱ tmpfileȱfunctionȱreturnsȱaȱstreamȱthatȱisȱassociatedȱwithȱaȱtemporaryȱfile.ȱȱ
Theȱ fileȱ isȱ automaticallyȱ deletedȱ afterȱ theȱ streamȱ isȱ closed.ȱ Theȱ tmpnameȱ functionȱ
createsȱaȱfilenameȱsuitableȱforȱuseȱasȱaȱtemporaryȱfile.ȱTheȱnameȱdoesȱnotȱconflictȱwithȱ
theȱnamesȱofȱanyȱexistingȱfiles.ȱAȱfileȱcanȱbeȱdeletedȱbyȱpassingȱitsȱnameȱtoȱtheȱ removeȱ
function.ȱTheȱ renameȱfunctionȱchangesȱtheȱnameȱofȱaȱfile.ȱItȱtakesȱtwoȱarguments,ȱtheȱ
currentȱnameȱofȱtheȱfileȱandȱtheȱnewȱname.ȱ
Download at http://www.pin5i.com/
446ȱ
Chapter 15 Input/Output Functionsȱ
15.18 Summary of Cautions
ȱ
1. Forgettingȱtoȱfollowȱdebuggingȱprintfȇsȱwithȱaȱcallȱtoȱfȱflushȱ(pageȱ412).ȱ
2. Notȱcheckingȱtheȱvalueȱreturnedȱbyȱfopenȱ(pageȱ417).ȱ
3. Changingȱtheȱfileȱpositionȱdiscardsȱanyȱungottenȱcharactersȱ(pageȱ423).ȱ
4. Specifyingȱtooȱsmallȱaȱbufferȱwithȱfgetsȱ(pageȱ424).ȱ
5. Inputȱfromȱgetsȱoverflowingȱtheȱbufferȱundetectedȱ(pageȱ424).ȱ
6. Mismatchedȱ formatȱ codesȱ andȱ argumentȱ pointerȱ typesȱ withȱ anyȱ ofȱ theȱ scanfȱ
functionsȱ(pageȱ425).ȱ
7. Forgettingȱtoȱputȱanȱampersandȱbeforeȱeachȱnonarray,ȱnonpointerȱargumentȱtoȱanyȱ
ofȱtheȱscanfȱfunctionsȱ(pageȱ426).ȱ
8. Beȱ sureȱ toȱ specifyȱ theȱ properȱ qualifierȱ inȱ scanfȱ formatȱ codesȱ toȱ convertȱ doubles,ȱ
longȱdoubles,ȱandȱshortȱandȱlongȱintegersȱ(pageȱ427).ȱ
9. Outputȱfromȱsprintfȱoverflowingȱtheȱbufferȱundetectedȱ(pageȱ430).ȱ
10. Interchangingȱprintfȱandȱscanfȱformatȱcodesȱ(pageȱ432).ȱ
11. Mismatchedȱ formatȱ codesȱ andȱ argumentȱ typesȱ withȱ anyȱ ofȱ theȱ printfȱ functionsȱ
(pageȱ432).ȱ
12. Onȱimplementationsȱinȱwhichȱlongȱintegersȱareȱlongerȱthanȱintegers,ȱnotȱspecifyingȱ
theȱlȱmodifierȱwhenȱprintingȱlongȱintegerȱvaluesȱ(pageȱ435).ȱ
13. Beȱcarefulȱwhenȱusingȱanȱautomaticȱarrayȱasȱaȱstreamȱbufferȱ(pageȱ441).ȱ
ȱ
ȱ
ȱ
15.19 Summary of Programming Tips
ȱ
1. Checkȱforȱandȱreportȱerrorsȱwheneverȱtheyȱmayȱoccurȱ(pageȱ410).ȱ
2. Theȱabilityȱtoȱmanipulateȱtextȱlinesȱwithoutȱregardȱforȱtheirȱexternalȱrepresentationȱ
improvesȱprogramȱportabilityȱ(pageȱ413).ȱ
3. Usingȱscanfȱqualifiersȱenhancesȱportabilityȱ(pageȱ427).ȱ
4. Portabilityȱisȱenhancedȱifȱyouȱuseȱtheȱ lȱmodifierȱwhenȱprintingȱlongȱintegersȱevenȱ
ifȱyourȱimplementationȱdoesnȇtȱrequireȱitȱ(pageȱ435).ȱ
ȱ
ȱ
ȱ
15.20 Questions
ȱ
1. Whatȱhappensȱifȱtheȱvalueȱreturnedȱfromȱfopenȱisȱnotȱcheckedȱforȱerrors?ȱ
Download at http://www.pin5i.com/
15.20 Questionsȱ
447
2. WhatȱwillȱhappenȱifȱI/Oȱisȱattemptedȱonȱaȱstreamȱthatȱhasȱneverȱbeenȱopened?ȱ
3. Whatȱ willȱ happenȱ ifȱ aȱ callȱ toȱ fcloseȱ fails,ȱ butȱ theȱ programȱ doesȱ notȱ checkȱ theȱ
returnedȱvalueȱforȱerrors?ȱ
4. Ifȱaȱprogramȱisȱexecutedȱwithȱitsȱstandardȱinputȱredirectedȱtoȱcomeȱfromȱaȱfile,ȱhowȱ
doesȱtheȱprogramȱdetectȱthisȱfact?ȱ
5. Whatȱhappensȱifȱfgetsȱisȱcalledȱwithȱaȱbufferȱsizeȱofȱone?ȱȱOfȱtwo?ȱ
6. Howȱlongȱmustȱtheȱbufferȱbeȱtoȱensureȱthatȱtheȱstringȱproducedȱbyȱsprintf willȱnotȱ
overflowȱit?ȱȱAssumeȱthatȱyourȱmachineȱusesȱ2Ȭbyteȱintegers.ȱ
sprintf( buffer, "%d %c %x", a, b, c );
7. Howȱlongȱmustȱtheȱbufferȱbeȱtoȱensureȱthatȱtheȱstringȱproducedȱbyȱsprintfȱwillȱnotȱ
overflowȱit?ȱ
sprintf( buffer, "%s", a );
8. Isȱtheȱlastȱdigitȱprintedȱbyȱtheȱ %fȱformalȱcodeȱroundedȱorȱareȱtheȱunprintedȱdigitsȱ
simplyȱtruncated?ȱ
9. Howȱcanȱyouȱobtainȱaȱlistȱofȱallȱofȱtheȱerrorȱmessagesȱthatȱperrorȱcanȱprint?ȱ
10. Whyȱdoȱ fprintf,ȱ fscanf,ȱ fputs,ȱandȱ fcloseȱallȱtakeȱaȱpointerȱtoȱaȱ FILEȱratherȱthanȱ
dieȱFILEȱstructure?ȱ
11. Whatȱmodeȱwouldȱyouȱuseȱtoȱopenȱaȱfileȱthatȱyouȱwantedȱtoȱwriteȱto,ȱassumingȱ(1)ȱ
youȱdoȱnotȱwantȱtoȱloseȱtheȱformerȱcontentsȱofȱtheȱfile,ȱandȱ(2)ȱyouȱwantȱtoȱbeȱableȱ
toȱwriteȱanywhereȱinȱtheȱfile?ȱ
12. Whyȱisȱtheȱfrepoenȱfunctionȱnecessary?ȱ
13. Forȱ mostȱ programs,ȱ doȱ youȱ thinkȱ itȱ isȱ worthȱ theȱ effortȱ toȱ thinkȱ aboutȱ whetherȱ
fgetc( stdin )ȱorȱgetchar()ȱwouldȱbeȱbetter?ȱ
14. Whatȱdoesȱtheȱfollowingȱstatementȱprintȱonȱyourȱsystem?ȱ
printf( "%d\n", 3.14 );
15. Explainȱhowȱstringsȱwillȱbeȱprintedȱwithȱtheȱ%-6.10sȱformatȱcode.ȱ
16. Whenȱ aȱ particularȱ valueȱ isȱ printedȱ withȱ theȱ formatȱ codeȱ %.3f,ȱ theȱ resultȱ isȱ 1.405,ȱ
butȱ whenȱ theȱ sameȱ valueȱ isȱ printedȱ withȱ theȱ formatȱ codeȱ %.2f,ȱ theȱ resultȱ isȱ 1.40.ȱȱ
Explainȱthisȱapparentȱerror.ȱ
Download at http://www.pin5i.com/
448ȱ
Chapter 15 Input/Output Functionsȱ
15.21 Programming Exercises
ȱ
1. Writeȱ aȱ programȱ thatȱ copiesȱ theȱ standardȱ inputȱ toȱ theȱ standardȱ outputȱ oneȱ
characterȱatȱaȱtime.ȱ
2. Changeȱ yourȱ solutionȱ toȱ Exerciseȱ 1ȱ soȱ thatȱ itȱ readsȱ andȱ writesȱ anȱ entireȱ lineȱ atȱ aȱ
time.ȱYouȱmayȱassumeȱthatȱeachȱlineȱinȱtheȱfileȱwillȱcontainȱ80ȱorȱfewerȱcharactersȱ
(notȱcountingȱtheȱterminatingȱnewline).ȱ
3. Changeȱ yourȱ solutionȱ toȱ Exerciseȱ 2ȱ toȱ removeȱ theȱ 80ȱ characterȱ lineȱ lengthȱ
restriction.ȱYouȱshouldȱstillȱprocessȱtheȱfileȱaȱlineȱatȱaȱtime,ȱbutȱlinesȱlongerȱthanȱ80ȱ
charactersȱmayȱbeȱprocessedȱaȱpieceȱatȱaȱtime.ȱ
4. ChangeȱyourȱsolutionȱtoȱExerciseȱ3ȱtoȱpromptȱforȱandȱreadȱtwoȱfilenamesȱfromȱtheȱ
standardȱ input.ȱ Theȱ firstȱ willȱ beȱ theȱ inputȱ file,ȱ andȱ theȱ secondȱ willȱ beȱ theȱ outputȱ
file.ȱTheȱrevisedȱprogramȱshouldȱopenȱbothȱfilesȱandȱcopyȱfromȱtheȱinputȱfileȱtoȱtheȱ
outputȱfileȱasȱbefore.ȱ
5. Changeȱ yourȱ solutionȱ toȱ Exerciseȱ 4ȱ soȱ thatȱ itȱ looksȱ forȱ linesȱ beginningȱ withȱ anȱ
integer.ȱȱTheseȱintegerȱvaluesȱshouldȱbeȱsummedȱandȱtheȱtotalȱshouldȱbeȱwrittenȱatȱ
theȱendȱofȱtheȱoutputȱfile.ȱOtherȱthanȱthisȱoneȱchange,ȱtheȱrevisedȱprogramȱshouldȱ
performȱasȱbefore.ȱ
6. Inȱ Chapterȱ 9ȱ youȱ wroteȱ aȱ functionȱ calledȱ palindromeȱ thatȱ wouldȱ determineȱ
whetherȱorȱnotȱaȱstringȱcontainedȱaȱpalindrome.ȱForȱthisȱproblem,ȱyouȱareȱtoȱwriteȱ
aȱfunctionȱthatȱwillȱdetermineȱwhetherȱorȱnotȱtheȱvalueȱofȱanȱintegerȱvariableȱisȱaȱ
palindrome.ȱ Forȱ example,ȱ theȱ valueȱ 245ȱ isȱ notȱ aȱ palindromeȱ butȱ 14741ȱ is.ȱ Theȱ
functionȱshouldȱhaveȱthisȱprototype:ȱ
ȱ
int numeric_palindrome( int value );
ȱ
Itȱshouldȱreturnȱtrueȱifȱtheȱvalueȱisȱaȱpalindrome,ȱotherwiseȱfalse.ȱ
7. Aȱcertainȱdataȱfileȱcontainsȱtheȱagesȱofȱfamilyȱmembers.ȱTheȱagesȱofȱtheȱmembersȱofȱ
oneȱfamilyȱareȱallȱonȱtheȱsameȱline,ȱandȱareȱseparatedȱbyȱwhiteȱspace.ȱForȱexample,ȱ
thisȱdataȱ
ȱ
45 42 22
36 35 7 3 1
22 20
ȱ
describesȱthreeȱfamiliesȱhavingȱthree,ȱfive,ȱandȱtwoȱmembers,ȱrespectively.ȱ
Writeȱaȱprogramȱthatȱcomputesȱtheȱaverageȱageȱofȱeachȱfamilyȱrepresentedȱinȱaȱ
fileȱofȱthisȱsort.ȱItȱshouldȱprintȱtheȱaverageȱageȱusingȱtheȱ%5.2fȱformat,ȱfollowedȱbyȱ
aȱcolonȱandȱtheȱinputȱdata.ȱYouȱmayȱassumeȱthatȱnoȱfamilyȱcontainsȱmoreȱthanȱ10ȱ
members.ȱ
8. Writeȱaȱprogramȱtoȱproduceȱaȱhexȱdumpȱofȱaȱfile.ȱȱItȱshouldȱtakeȱaȱsingleȱargumentȱ
ȱ
Download at http://www.pin5i.com/
15.21 Programming Exercisesȱ
449
fromȱtheȱcommandȱline,ȱwhichȱisȱtheȱnameȱofȱtheȱfileȱtoȱdump.ȱIfȱthisȱargumentȱisȱ
missing,ȱtheȱprogramȱshouldȱdumpȱtheȱstandardȱinputȱinstead.ȱ
Eachȱlineȱofȱtheȱdumpȱshouldȱhaveȱtheȱfollowingȱformat.ȱ
ȱ
Columns
Contents
1–6ȱȱ
Theȱcurrentȱoffsetȱinȱtheȱfile,ȱinȱhexadecimal,ȱwithȱleadingȱzeros.ȱ
9–43ȱ
Theȱ hexadecimalȱ representationȱ ofȱ theȱ nextȱ 16ȱ bytesȱ inȱ theȱ file.ȱ
Theseȱ areȱ printedȱ inȱ fourȱ groupsȱ ofȱ 8ȱ hexȱ digits,ȱ withȱ oneȱ spaceȱ
betweenȱeachȱgroup.ȱ
46ȱ
Anȱasterisk.ȱ
47–62ȱ
Theȱ characterȱ representationȱ ofȱ theȱ sameȱ 16ȱ bytesȱ inȱ theȱ file.ȱ Ifȱ aȱ
byteȱ isȱ notȱ aȱ printableȱ characterȱ orȱ aȱ space,ȱ aȱ periodȱ isȱ printedȱ
instead.ȱ
63ȱ
Anȱasterisk.ȱ
ȱ
AllȱhexadecimalȱnumbersȱshouldȱuseȱuppercaseȱAȬFȱratherȱthanȱlowercaseȱletters.ȱ
Hereȱareȱsomeȱsampleȱlinesȱillustratingȱthisȱformat.ȱ
ȱ
000200
000210
000220
D4O5C000 82102004 91D02000 9010207F
82102001 91D02000 0001C000 2F757372
2F6C6962 2F6C642E 736F002F 6465762F
*...... ... ... .*
*.. ... ...../usr*
*/lib/ld.so./dev/*
9. TheȱUNIXȱfgrepȱprogramȱtakesȱaȱstringȱandȱaȱseriesȱofȱfilenamesȱasȱcommandȱlineȱ
arguments.ȱ Itȱ thenȱ looksȱ throughȱ theȱ filesȱ oneȱ byȱ one.ȱ Forȱ eachȱ lineȱ thatȱ containsȱ
theȱgivenȱstring,ȱtheȱnameȱofȱtheȱfile,ȱaȱcolon,ȱandȱtheȱlineȱcontainingȱtheȱstringȱareȱ
printed.ȱ
Writeȱ thisȱ program.ȱ Theȱ stringȱ argumentȱ comesȱ first,ȱ andȱ itȱ mayȱ notȱ containȱ
anyȱ newlineȱ characters.ȱ Theȱ filenameȱ argumentsȱ comeȱ next.ȱ Ifȱ thereȱ arenȇtȱ anyȱ
filenamesȱgiven,ȱtheȱprogramȱshouldȱreadȱtheȱstandardȱinput.ȱInȱthisȱcase,ȱtheȱlinesȱ
printedȱbyȱtheȱprogramȱareȱnotȱprefixedȱwithȱaȱfilenameȱorȱcolon.ȱYouȱmayȱassumeȱ
thatȱtheȱlinesȱofȱtextȱinȱtheȱfilesȱwillȱbeȱnoȱlongerȱthanȱ510ȱcharacters.ȱ
10. Writeȱ aȱ programȱ toȱ computeȱ checksumsȱ forȱ files.ȱ Theȱ programȱ isȱ invokedȱ asȱ
follows:ȱ
ȱ
$sum [-f] [file...]
ȱ
Theȱ-fȱoptionȱisȱoptional.ȱIȇllȱdescribeȱitsȱmeaningȱlater.ȱ
Nextȱ comesȱ anȱ optionalȱ listȱ ofȱ fileȱ names.ȱ Ifȱ thereȱ arenȇtȱ anyȱ namesȱ given,ȱ theȱ
programȱprocessesȱtheȱstandardȱinput.ȱOtherwise,ȱtheȱprogramȱprocessesȱeachȱfileȱ
inȱ theȱ orderȱ inȱ whichȱ theyȱ areȱ namedȱ onȱ theȱ commandȱ line.ȱ ȈProcessingȱ aȱ fileȈȱ
meansȱtoȱcomputeȱandȱprintȱtheȱchecksumȱforȱtheȱfile.ȱ
Theȱalgorithmȱforȱcomputingȱtheȱchecksumȱisȱsimple.ȱEachȱcharacterȱinȱtheȱfileȱ
isȱaddedȱtoȱaȱ16Ȭbit,ȱunsignedȱinteger,ȱandȱtheȱresultȱisȱtheȱchecksumȱvalue.ȱ
Download at http://www.pin5i.com/
450ȱ
Chapter 15 Input/Output Functionsȱ
Althoughȱ simpleȱ toȱ implement,ȱ thisȱ algorithmȱ isȱ notȱ aȱ greatȱ errorȱ detectionȱ
method.ȱInterchangingȱtwoȱcharactersȱinȱtheȱfileȱwouldȱnotȱbeȱdetectedȱasȱanȱerror.ȱ
Ordinarily,ȱ theȱ checksumȱ isȱ writtenȱ toȱ theȱ standardȱ outputȱ whenȱ theȱ endȱ ofȱ
eachȱfileȱisȱfound.ȱIfȱtheȱ -fȱoptionȱisȱgiven,ȱtheȱchecksumȱisȱwrittenȱtoȱaȱfileȱinsteadȱ
ofȱtheȱstandardȱoutput.ȱTheȱnameȱofȱtheȱfileȱshouldȱbeȱ file.cksȱwhereȱ fileȱisȱtheȱ
inputȱ fileȱ name.ȱ Thisȱ optionȱ isȱ illegalȱ whenȱ readingȱ fromȱ theȱ standardȱ inputȱ
becauseȱthereȱisnȇtȱanȱinputȱfileȱname.ȱ
Belowȱ areȱ aȱ fewȱ sampleȱ runsȱ ofȱ theȱ program.ȱ Theyȱ areȱ validȱ forȱ systemsȱ thatȱ
useȱ ASCIIȱ characters.ȱ Theȱ fileȱ hwȱ containsȱ theȱ lineȱ ȈHelloȱ World!Ȉȱ followedȱ byȱ aȱ
newline.ȱ Theȱ fileȱ hw2ȱ containsȱ twoȱ suchȱ lines.ȱ Noneȱ ofȱ theȱ inputȱ containsȱ anyȱ
trailingȱblanksȱorȱtabs.ȱ
ȱ
$sum
hi
^D
219
%sum hw
1095
$sum –f
-f illegal when reading standard input
$sum –f hw2
$
ȱ
(fileȱhw2.cksȱnowȱcontainsȱ2190)ȱ
ȱ
11. Writeȱaȱprogramȱtoȱkeepȱtrackȱofȱanȱinventoryȱofȱpartsȱandȱtheirȱvalue.ȱEachȱpartȱ
hasȱaȱdescriptionȱthatȱmayȱbeȱfromȱ1ȱtoȱ20ȱcharactersȱinȱlength.ȱWhenȱaȱnewȱpartȱisȱ
addedȱtoȱtheȱinventory,ȱitȱisȱassignedȱtheȱnextȱavailableȱpartȱnumber.ȱTheȱfirstȱpartȱ
numberȱisȱ1.ȱTheȱprogramȱshouldȱstoreȱtheȱquantityȱonȱhandȱandȱtheȱtotalȱvalueȱforȱ
eachȱpart.ȱ
Theȱprogramȱshouldȱtakeȱaȱsingleȱargumentȱfromȱtheȱcommandȱline,ȱwhichȱisȱ
theȱnameȱofȱtheȱinventoryȱtile.ȱIfȱtheȱfileȱdoesȱnotȱexist,ȱanȱemptyȱinventoryȱfileȱisȱ
created.ȱ Theȱ programȱ thenȱ promptsȱ forȱ transactionsȱ andȱ processesȱ themȱ oneȱ byȱ
one.ȱ
Theȱfollowingȱtransactionsȱareȱallowed.ȱ
ȱ
new description, quantity, cost-each
ȱ
Theȱ newȱ transactionȱ entersȱ aȱ newȱ partȱ intoȱ theȱ system.ȱ descriptionȱ isȱ theȱ
descriptionȱofȱtheȱpart,ȱwhichȱmayȱnotȱbeȱlongerȱthanȱ20ȱcharacters.ȱquantityȱisȱtheȱ
numberȱofȱpartsȱinitiallyȱplacedȱintoȱinventory;ȱitȱmayȱnotȱbeȱnegative.ȱcost-eachȱisȱ
theȱcostȱofȱeachȱpart.ȱItȱisȱnotȱanȱerrorȱforȱaȱnewȱpartȱtoȱhaveȱtheȱsameȱdescriptionȱ
Download at http://www.pin5i.com/
15.21 Programming Exercisesȱ
451
asȱ anȱ existingȱ part.ȱ Theȱ programȱ mustȱ computeȱ andȱ saveȱ theȱ totalȱ valueȱ ofȱ theseȱ
parts.ȱTheȱnextȱavailableȱpartȱnumberȱisȱassignedȱtoȱeachȱnewȱpart.ȱPartȱnumbersȱ
startȱatȱ1ȱandȱincreaseȱsequentially.ȱTheȱnumbersȱofȱdeletedȱpartsȱarcȱreusedȱwhenȱ
newȱpartsȱareȱentered.ȱ
ȱ
buy part-number,quantity,cost-each
ȱ
Theȱ buyȱ transactionȱ addsȱ additionalȱ unitsȱ toȱ anȱ existingȱ partȱ inȱ inventory.ȱ partnumberȱisȱtheȱnumberȱofȱtheȱpart,ȱ quantityȱisȱtheȱnumberȱofȱpartsȱobtainedȱ(whichȱ
mayȱnotȱbeȱnegative),ȱandȱ cost-eachȱisȱtheȱcostȱofȱeachȱofȱtheȱparts.ȱTheȱprogramȱ
shouldȱ addȱ theȱ quantityȱ andȱ theȱ totalȱ valueȱ ofȱ theȱ newȱ partsȱ toȱ theȱ existingȱ
inventory.ȱ
ȱ
sell part-number,quantity,price-each
ȱ
Theȱsellȱtransactionȱremovesȱunitsȱfromȱanȱexistingȱpartȱinȱinventory.ȱpart-numberȱ
isȱtheȱnumberȱofȱtheȱpart,ȱ quantityȱisȱtheȱnumberȱofȱpartsȱsoldȱ(whichȱmayȱnotȱbeȱ
negativeȱorȱlargerȱthanȱtheȱquantityȱonȱhand),ȱandȱprice-eachȱisȱtheȱpriceȱobtainedȱ
forȱ eachȱ ofȱ theȱ partsȱ sold.ȱ Theȱ programȱ shouldȱ subtractȱ thisȱ quantityȱ fromȱ theȱ
inventoryȱ andȱ reduceȱ theȱ totalȱ valueȱ forȱ thisȱ partȱ byȱ theȱ numberȱ sold.ȱ ȱ Itȱ shouldȱ
thenȱ computeȱ theȱ profitȱ forȱ theȱ saleȱ asȱ theȱ differenceȱ betweenȱ theȱ priceȱ obtainedȱ
andȱtheȱinventoryȱvalueȱforȱtheȱpartsȱsold.ȱ
ȱ
delete part-number
ȱ
Thisȱtransactionȱdeletesȱtheȱspecifiedȱpartȱfromȱtheȱinventoryȱfile.ȱ
ȱ
print part-number
ȱ
Thisȱtransactionȱprintsȱinformationȱforȱtheȱspecifiedȱpartȱincludingȱtheȱdescription,ȱ
quantityȱonȱhand,ȱandȱtotalȱvalueȱofȱthoseȱparts.ȱ
ȱ
print all
ȱ
Thisȱtransactionȱprintsȱinformationȱforȱallȱpartsȱinȱinventoryȱinȱaȱtabularȱform.ȱ
ȱ
total
ȱ
Thisȱtransactionȱcomputesȱandȱprintsȱtheȱtotalȱvalueȱofȱallȱpartsȱinȱinventory.ȱ
ȱ
end
ȱ
Thisȱtransactionȱterminatesȱexecutionȱofȱtheȱprogram.ȱ
Computingȱtheȱtrueȱvalueȱofȱanȱinventoryȱwhenȱpartsȱareȱobtainedȱatȱdifferentȱ
costsȱisȱcomplexȱandȱdependsȱonȱwhetherȱtheȱcheapestȱorȱmostȱexpensiveȱpartsȱareȱ
usedȱfirst.ȱTheȱmethodȱusedȱbyȱthisȱprogramȱisȱsimple:ȱOnlyȱtheȱtotalȱvalueȱofȱeachȱ
typeȱofȱ partȱisȱkept,ȱandȱallȱunitsȱ ofȱoneȱ particularȱpartȱ areȱ consideredȱ equal.ȱ Forȱ
example,ȱ supposeȱ 10ȱ paperȱ clipsȱ areȱ initiallyȱ purchasedȱ forȱ $1.00ȱ each.ȱ Theȱ totalȱ
valueȱofȱthisȱinventoryȱisȱ$10.00.ȱLater,ȱ10ȱmoreȱpaperȱclipsȱareȱpurchasedȱforȱ$1.25ȱ
Download at http://www.pin5i.com/
Chapter 15 Input/Output Functionsȱ
452ȱ
each,ȱbringingȱtheȱtotalȱvalueȱofȱtheȱinventoryȱtoȱ$22.50.ȱAtȱthisȱpoint,ȱeachȱpaperȱ
clipȱ isȱ valuedȱ atȱ $1.125.ȱ Noȱ recordȱ isȱ keptȱ ofȱ theȱ individualȱ batchesȱ evenȱ thoughȱ
theyȱ wereȱ purchasedȱ atȱ differentȱ prices.ȱ Whenȱ paperȱ clipsȱ areȱ sold,ȱ theȱ profitȱ isȱ
computedȱbasedȱonȱtheirȱcurrentȱvalueȱasȱcalculatedȱabove.ȱ
Hereȱ areȱ someȱ hintsȱ onȱ designingȱ theȱ program.ȱ First,ȱ useȱ theȱ partȱ numberȱ toȱ
determineȱwhereȱinȱtheȱinventoryȱfileȱaȱpartȱisȱwritten.ȱTheȱfirstȱpanȱnumberȱisȱ1,ȱsoȱ
theȱ locationȱ inȱ theȱ inventoryȱ fileȱ whereȱ partȱ numberȱ 0ȱ wouldȱ goȱ canȱ beȱ usedȱ toȱ
storeȱ otherȱ information.ȱ Second,ȱ youȱ canȱ detectȱ deletedȱ partsȱ byȱ settingȱ theirȱ
descriptionȱtoȱtheȱemptyȱstring.ȱ
ȱ
Download at http://www.pin5i.com/
16
Standard Library
TheȱStandardȱLibraryȱisȱaȱtoolkitȱthatȱgreatlyȱexpandsȱtheȱpowerȱofȱtheȱCȱprogrammer.ȱ
Beforeȱ youȱ canȱ useȱ thisȱ power,ȱ however,ȱ youȱ mustȱ becomeȱ familiarȱ withȱ theȱ libraryȱ
functions.ȱ Neglectingȱ theȱ libraryȱ isȱ likeȱ onlyȱ learningȱ howȱ toȱ useȱ theȱ gasȱ pedal,ȱ
steeringȱ wheel,ȱ andȱ brakeȱ inȱ yourȱ carȱ butȱ notȱ botheringȱ toȱ learnȱ aboutȱ theȱ cruiseȱ
control,ȱradio,ȱandȱairȱconditioning.ȱȱYouȱmayȱbeȱableȱtoȱgetȱwhereȱyouȱwantȱtoȱgo,ȱbutȱ
itȱwillȱbeȱharderȱandȱwonȇtȱbeȱasȱmuchȱfun.ȱ
Thisȱ chapterȱ describesȱ theȱ libraryȱ functionsȱ thatȱ haveȱ notȱ beenȱ coveredȱ inȱ
previousȱchapters.ȱTheȱsectionȱtitlesȱincludeȱtheȱfileȱnameȱthatȱyouȱneedȱtoȱ#includeȱtoȱ
obtainȱtheȱfunctionȱprototypes.ȱ
ȱ
ȱ
ȱ
16.1 Integer Functions
ȱ
Thisȱ groupȱ ofȱ functionsȱ returnȱ integerȱ values.ȱ Theȱ functionsȱ fallȱ intoȱ threeȱ families:ȱ
arithmetic,ȱrandomȱnumbers,ȱandȱstringȱconversion.ȱ
ȱ
ȱ
16.1.1
Arithmetic <stdlib.h>
ȱ
Theȱlibraryȱincludesȱfourȱintegerȱarithmeticȱfunctions.]ȱ
ȱ
int abs( int value );
long int labs( long int value );
div_t div( int numerator, int denominator );
ldiv_t ldiv( long int numer, long int denom );
ȱ
Theȱ absȱ functionȱ returnsȱ theȱ absoluteȱ valueȱ ofȱ itsȱ argument.ȱ Ifȱ theȱ resultȱ cannotȱ beȱ
representedȱasȱanȱinteger,ȱtheȱbehaviorȱisȱundefined.ȱlabsȱdoesȱtheȱsameȱworkȱforȱlongȱ
integerȱvalues.ȱ
Download at http://www.pin5i.com/
Chapter 16 Standard Libraryȱ
454ȱ
Theȱ divȱ functionȱ dividesȱ theȱ firstȱ argumentȱ (theȱ numerator)ȱ byȱ theȱ secondȱ
argumentȱ (theȱ denominator)ȱ andȱ producesȱ aȱ quotientȱ andȱ aȱ remainderȱ thatȱ areȱ
returnedȱinȱaȱdiv_tȱstructure.ȱȱThisȱstructureȱcontainsȱtheȱfieldsȱ
ȱ
int quot;
int rem;
ȱ
thoughȱnotȱnecessarilyȱinȱthisȱorder.ȱIfȱtheȱdivisionȱisȱnotȱeven,ȱtheȱquotientȱwillȱbeȱtheȱ
integerȱ ofȱ smallerȱ magnitudeȱ thatȱ isȱ nearestȱ toȱ theȱ algebraicȱ quotient.ȱ Noteȱ thatȱ theȱ
resultsȱofȱdivisionȱwithȱtheȱ /ȱoperatorȱareȱnotȱasȱpreciselyȱdefined.ȱWhenȱeitherȱofȱtheȱ
operandsȱ ofȱ /ȱ areȱ negativeȱ andȱ theȱ resultȱ isȱ notȱ exact,ȱ itȱ isȱ implementationȱ definedȱ
whetherȱtheȱquotientȱisȱtheȱlargestȱintegerȱlessȱthanȱorȱequalȱtoȱtheȱalgebraicȱquotientȱ
orȱ theȱ smallestȱ integerȱ greaterȱ thanȱ orȱ equalȱ toȱ theȱ algebraicȱ quotient.ȱ ldivȱ doesȱ theȱ
sameȱworkȱforȱlongȱintegerȱvaluesȱandȱreturnsȱanȱldiv_tȱstructure.ȱ
ȱ
ȱ
ȱ
16.1.2
Random Numbers <stdlib.h>
ȱ
Randomȱ numbersȱ areȱ usefulȱ inȱ programsȱ thatȱ shouldȱ notȱ produceȱ theȱ sameȱ resultsȱ
everyȱtimeȱtheyȱareȱexecuted,ȱsuchȱasȱgamesȱandȱsimulations.ȱTogether,ȱtheȱfollowingȱ
twoȱ functionsȱ produceȱ pseudoȬrandomȱ numbers,ȱ soȱ calledȱ becauseȱ theyȱ areȱ computedȱ
andȱthereforeȱrepeatable,ȱandȱthusȱnotȱtrulyȱrandom.ȱ
ȱ
int rand( void );
void srand( unsigned int seed );
ȱ
randȱreturnsȱaȱpseudoȬrandomȱnumberȱinȱtheȱrangeȱzeroȱtoȱ RAND_MAXȱ(whichȱmustȱbeȱ
atȱ leastȱ 32,767).ȱ Whenȱ calledȱ repeatedly,ȱ theȱ functionȱ returnsȱ otherȱ numbersȱ inȱ thisȱ
range.ȱȱToȱobtainȱnumbersȱfromȱaȱsmallerȱrange,ȱfirstȱtakeȱtheȱrandomȱnumberȱmoduloȱ
theȱsizeȱofȱtheȱdesiredȱrange,ȱthenȱscaleȱitȱbyȱaddingȱorȱsubtractingȱanȱoffsetȱasȱneeded.ȱ
Toȱ preventȱ theȱ randomȱ numberȱsequenceȱ fromȱ beingȱ theȱ sameȱeveryȱ timeȱ theȱ
programȱ isȱ run,ȱ theȱ srandȱ functionȱ mayȱ beȱ called.ȱ Itȱ initializesȱ theȱ randomȱ numberȱ
generatorȱ withȱ theȱ valueȱ passedȱ asȱ itsȱ argument.ȱ Aȱ commonȱ techniqueȱ isȱ toȱ useȱ theȱ
timeȱofȱdayȱtoȱseedȱtheȱrandomȱnumberȱgenerator,ȱasȱinȱthisȱexample:ȱ
ȱ
srand( (unsigned int)time( 0 ) );
ȱ
Theȱtimeȱfunctionȱisȱdescribedȱlaterȱinȱthisȱchapter.ȱ
TheȱfunctionȱinȱProgramȱ16.1ȱusesȱintegersȱtoȱrepresentȱplayingȱcardsȱandȱusesȱ
randomȱnumbersȱtoȱȈshuffleȈȱtheȱspecifiedȱnumberȱofȱcardsȱinȱtheȱȈdeck.Ȉȱ
Download at http://www.pin5i.com/
16.1 Integer Functionsȱ
455
ȱ
/*
** Use random numbers to shuffle the "cards" in the deck. The second
** argument indicates the number of cards. The first time this
** function is called, srand is called to initialize the random
** number generator.
*/
#include <stdlib.h>
#include <time.h>
#define
TRUE 1
#define
FALSE 0
void shuffle( int *deck, int n_cards )
{
int
i;
static
int
first_time = TRUE;
/*
** Seed the random number generator with the current time
** of day if we haven't done so yet.
*/
if( first_time ){
first_time = FALSE;
srand( (unsigned int)time( NULL ) );
}
/*
** "Shuffle" by interchanging random pairs of cards.
*/
for( i = n_cards - 1; i > 0; i -= 1 ){
int
where;
int
temp;
where = rand() % i;
temp = deck[ where ];
deck[ where ] = deck[ i ];
deck[ i ] = temp;
}
}
ȱ
Programȱ16.1ȱȱShufflingȱplayingȱcardsȱwithȱrandomȱnumbersȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
16.1.3
ȱ
ȱ
ȱȱȱȱȱȱshuffle.cȱ
String Conversion <stdlib.h>
ȱ
Theȱ stringȱ conversionȱ functionsȱ convertȱ characterȱ stringsȱ toȱ numericȱ values.ȱ Theȱ
simplestȱones,ȱatoiȱandȱatol,ȱperformȱbaseȱ10ȱconversions.ȱstrtolȱandȱstrtoulȱallowȱ
Download at http://www.pin5i.com/
456ȱ
Chapter 16 Standard Libraryȱ
youȱ toȱ specifyȱ theȱ baseȱ forȱ theȱ conversion,ȱ andȱ theyȱ alsoȱ giveȱ youȱ accessȱ toȱ theȱ
remainingȱpartȱofȱtheȱstring.ȱ
ȱ
int atoi( char const *string );
long int atol( char const *string );
long int strtol( char const *string, char **unused, int base );
unsigned long int strtoul( char const *string, char **unused, int base );
ȱ
Ifȱtheȱfirstȱargumentȱtoȱanyȱofȱtheseȱfunctionsȱcontainsȱleadingȱwhiteȱspaceȱcharacters,ȱ
theyȱareȱskipped.ȱTheȱfunctionsȱthenȱconvertȱlegalȱcharactersȱtoȱtheȱindicatedȱtypeȱofȱ
value.ȱIfȱthereȱareȱanyȱtrailingȱillegalȱcharacters,ȱtheyȱareȱignored.ȱ
atoiȱ andȱ atolȱ convertȱ charactersȱ toȱ integerȱ andȱ longȱ integerȱ values,ȱ
respectively.ȱ strtolȱ convertsȱ theȱ argumentȱ stringȱ toȱ aȱ longȱ inȱ theȱ sameȱ mannerȱ asȱ
atol.ȱ However,ȱ strtolȱ savesȱ aȱ pointerȱ toȱ theȱ firstȱ characterȱ inȱ theȱ stringȱ afterȱ theȱ
convertedȱ value.ȱ Ifȱ theȱ secondȱ argumentȱ toȱ theȱ functionȱ isȱ notȱ NULL,ȱ theȱ savedȱ
pointerȱisȱstoredȱinȱtheȱlocationȱpointedȱtoȱbyȱtheȱsecondȱargument.ȱTheȱpointerȱallowsȱ
theȱ remainderȱ ofȱ theȱ stringȱ toȱ beȱ processedȱ withoutȱ havingȱ toȱ guessȱ whereȱ theȱ
conversionȱstopped.ȱȱ strtoulȱbehavesȱinȱtheȱsameȱmannerȱbutȱproducesȱanȱunsignedȱ
longȱinstead.ȱ
Theȱ thirdȱ argumentȱ toȱ bothȱ ofȱ theseȱ functionsȱ isȱ theȱ baseȱ withȱ whichȱ theȱ
conversionȱ isȱ performed.ȱ Ifȱ theȱ baseȱ isȱ 0,ȱ anyȱ ofȱ theȱ formsȱ usedȱ forȱ writingȱ integerȱ
literalsȱ inȱ aȱ programȱ areȱ accepted,ȱ includingȱ theȱ formsȱ thatȱ specifyȱ theȱ baseȱ ofȱ theȱ
number,ȱsuchȱasȱ 0x2af4ȱandȱ 0377.ȱOtherwise,ȱtheȱbaseȱmayȱbeȱaȱvalueȱinȱtheȱrangeȱ2ȱ
throughȱ 36—theȱ conversionȱ isȱ thenȱ performedȱ withȱ theȱ givenȱ base.ȱ Forȱ basesȱ 11ȱ
throughȱ 36,ȱ theȱ charactersȱ Aȱ throughȱ Zȱ areȱ interpretedȱ asȱ digitsȱ withȱ valuesȱ 10ȱ
throughȱ35,ȱrespectively.ȱȱLowercaseȱcharactersȱaȱthroughȱzȱareȱinterpretedȱtheȱsameȱasȱ
uppercaseȱcharactersȱinȱthisȱcontext.ȱThus,ȱ
ȱ
x = strtol( "
590bear", next, 12 );
ȱ
wouldȱreturnȱtheȱvalueȱ9947ȱandȱstoreȱaȱpointerȱtoȱtheȱletterȱeȱinȱtheȱvariableȱthatȱnextȱ
pointsȱ to.ȱ Theȱ conversionȱ stopsȱ withȱ bȱ becauseȱ eȱ isȱ notȱ aȱ validȱ digitȱ forȱ aȱ baseȱ 12ȱ
number.ȱ
Ifȱtheȱstringȱargumentȱtoȱanyȱofȱtheseȱfunctionsȱdoesȱnotȱcontainȱaȱlegalȱnumericȱ
value,ȱ thenȱ 0ȱ isȱ returned.ȱ Ifȱ theȱ convertedȱ valueȱ cannotȱ beȱ represented,ȱ theȱ valueȱ
ERANGEȱisȱstoredȱinȱerrno,ȱandȱoneȱofȱtheȱvaluesȱinȱTableȱ16.1ȱisȱreturned.ȱ
Download at http://www.pin5i.com/
16.2 Floating-Point Functionsȱ
457
Function
Returns
strol
LONG_MINȱifȱtheȱvalueȱisȱtooȱlargeȱandȱnegative,ȱorȱLONG_MAXȱifȱtheȱ
strtoul
valueȱisȱtooȱlargeȱandȱpositive.ȱ
ULONG_MAXȱifȱtheȱvalueȱisȱtooȱlarge.ȱ
ȱ
Tableȱ16.1ȱErrorȱvaluesȱreturnedȱbyȱstrtolȱandȱstrtoulȱ
ȱ
ȱ
ȱ
16.2 Floating-Point Functions
CAUTION!
ȱ
Theȱheaderȱfileȱ math.hȱcontainsȱdeclarationsȱforȱtheȱremainingȱmathematicalȱfunctionsȱ
inȱtheȱlibrary.ȱTheȱreturnȱvaluesȱfromȱtheseȱfunctionsȱandȱmostȱofȱtheirȱargumentsȱareȱ
double.ȱ
ȱ
Aȱcommonȱsourceȱofȱerrorȱisȱtoȱomitȱtheȱheaderȱfileȱwhenȱusingȱtheseȱfunctions,ȱlikeȱ
this:ȱ
ȱ
double x;
x = sqrt( 5.5 );
ȱ
Theȱ compiler,ȱ neverȱ havingȱ seenȱ aȱ prototypeȱ forȱ sqrt,ȱ mistakenlyȱ assumesȱ thatȱ itȱ
returnsȱanȱintegerȱandȱerroneouslyȱconvertsȱtheȱvalueȱtoȱdouble.ȱTheȱresultingȱvalueȱisȱ
meaningless.ȱ
Aȱ domainȱ errorȱ occursȱ ifȱ theȱ argumentȱ toȱ aȱ functionȱ isȱ notȱ withinȱ theȱ domainȱ
definedȱforȱthatȱfunction.ȱForȱexample,ȱ
ȱ
sqrt( -5.0 );
ȱ
isȱ aȱ domainȱ errorȱ becauseȱ squareȱ rootȱ isȱ undefinedȱ forȱ negativeȱ numbers.ȱ Whenȱ aȱ
domainȱ errorȱ occurs,ȱ theȱ functionȱ returnsȱ anȱ errorȱ valueȱ definedȱ byȱ theȱ
implementation,ȱandȱtheȱvalueȱ EDOMȱisȱstoredȱinȱerrno.ȱAȱrangeȱerrorȱoccursȱifȱtheȱresultȱ
ofȱaȱfunctionȱisȱtooȱlargeȱorȱtooȱsmallȱtoȱbeȱrepresentedȱinȱaȱdouble.ȱForȱexample,ȱ
ȱ
exp( DBL_MAX )
ȱ
willȱproduceȱaȱrangeȱerrorȱbecauseȱitsȱresultȱisȱtooȱlarge.ȱInȱthisȱcase,ȱtheȱfunctionȱwillȱ
returnȱ HUGE_VAL,ȱaȱ doubleȱvalueȱthatȱisȱdefinedȱinȱ math.h.ȱȱIfȱtheȱresultȱofȱaȱfunctionȱisȱ
tooȱsmallȱtoȱbeȱrepresentedȱinȱaȱdouble,ȱthenȱtheȱfunctionȱwillȱreturnȱzeroȱinstead.ȱThisȱ
caseȱisȱalsoȱaȱrangeȱerror,ȱbutȱitȱisȱimplementationȱdependentȱwhetherȱ errnoȱisȱsetȱtoȱ
ERANGEȱinȱthisȱcase.ȱ
Download at http://www.pin5i.com/
Chapter 16 Standard Libraryȱ
458ȱ
16.2.1
Trigonometry <math.h>
ȱ
Theȱusualȱtrigonometryȱfunctionsȱareȱprovided.ȱ
ȱ
double
double
double
double
double
double
double
sin( double angle );
cos( double angle );
tan( double angle );
asin( double value );
acos( double value );
atan( double value );
atan2( double x, double y );
ȱ
Theȱargumentȱtoȱ sin,ȱ cos,ȱandȱtanȱisȱanȱangleȱinȱradians;ȱtheȱfunctionsȱreturnȱtheȱsine,ȱ
cosine,ȱandȱtangentȱofȱtheȱangle,ȱrespectively.ȱ
Theȱ asin,ȱ acos,ȱ andȱ atanȱ functionsȱ returnȱ theȱ arcȱ sine,ȱ arcȱ cosine,ȱ andȱ arcȱ
tangentȱofȱtheirȱargument,ȱrespectively.ȱAȱdomainȱerrorȱwillȱoccurȱifȱtheȱargumentȱtoȱ
asinȱorȱ acosȱisȱnotȱinȱtheȱrangeȱȬ1ȱtoȱ1.ȱȱ asinȱandȱ atanȱreturnȱaȱvalueȱinȱtheȱrangeȱȬΔ/2ȱ
toȱΔ/2ȱradians,ȱandȱacosȱreturnsȱaȱvalueȱinȱtheȱrangeȱ0ȱtoȱΔȱradians.ȱ
Theȱ atan2ȱ functionȱ returnsȱ theȱ arcȱ tangentȱ ofȱ theȱ expressionȱ y/xȱ butȱ usesȱ theȱ
signsȱofȱbothȱargumentsȱtoȱdetermineȱwhichȱquadrantȱtheȱresultȱliesȱwithin.ȱItȱreturnsȱ
aȱresultȱinȱtheȱrangeȱȬȱΔȱtoȱΔȱradians.ȱ
ȱ
ȱ
ȱ
16.2.2
Hyperbolic <math.h>
ȱ
double sinh( double angle );
double cosh( double angle );
double tanh( double angle );
ȱ
Theseȱfunctionsȱreturnȱtheȱhyperbolicȱsine,ȱhyperbolicȱcosine,ȱandȱhyperbolicȱtangentȱ
ofȱtheirȱargument,ȱrespectively.ȱTheȱargumentȱtoȱeachȱisȱanȱangleȱinȱradians.ȱ
ȱ
ȱ
ȱ
16.2.3
Logarithm and Exponent <math.h>
ȱ
Thereȱareȱthreeȱfunctionsȱthatȱdealȱdirectlyȱwithȱlogarithmsȱandȱexponents.ȱ
ȱ
double exp( double x );
double log( double x );
double log10( double x );
Download at http://www.pin5i.com/
16.2 Floating-Point Functionsȱ
459
ex
Theȱexpȱfunctionȱreturnsȱtheȱvalueȱeȱraisedȱtoȱtheȱpowerȱgivenȱbyȱtheȱargument,ȱorȱȱȱȱ.ȱ
Theȱlogȱfunctionȱreturnsȱtheȱbaseȱeȱlogarithmȱofȱitsȱargument,ȱalsoȱknownȱasȱtheȱ
naturalȱ logarithm.ȱ Theȱ logl0ȱ functionȱ returnsȱ theȱ baseȱ 10ȱ logarithmȱ ofȱ itsȱ argument.ȱ
Noteȱthatȱtheȱlogȱofȱaȱnumberȱxȱtoȱanȱarbitraryȱbaseȱbȱmayȱbeȱcomputedȱlikeȱthis:ȱ
ȱ
log e x
log b x
log e b ȱ
ȱ
Aȱdomainȱerrorȱoccursȱforȱbothȱlogȱfunctionsȱifȱtheȱargumentȱisȱnegative.ȱ
ȱ
ȱ
ȱ
16.2.4
Floating-point Representation <math.h>
ȱ
Theseȱ threeȱ functionsȱ provideȱ aȱ wayȱ toȱ storeȱ floatingȬpointȱ valuesȱ inȱ anȱ
implementationȬindependentȱformat.ȱ
ȱ
double frexp( double value, int *exponent );
double ldexp( double fraction, int exponent );
double modf( double value, double *ipart );
ȱ
Theȱ frexpȱ functionȱ computesȱ anȱ exponentȱ andȱ aȱ fractionȱ suchȱ thatȱ ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
fraction u 2 exponent value , whereȱ 0.5 d fraction 1 andȱ exponentȱ isȱ anȱ integer.ȱ Theȱ
exponentȱisȱstoredȱinȱtheȱlocationȱpointedȱtoȱbyȱtheȱsecondȱargumentȱandȱtheȱfunctionȱ
returnsȱ theȱ fraction.ȱ Theȱ relatedȱ functionȱ ldexpȱ returnsȱ theȱ valueȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
fractionu 2 exponent ,whichȱisȱtheȱoriginalȱvalue.ȱTheseȱfunctionsȱareȱveryȱusefulȱwhenȱyouȱ
mustȱ passȱ floatingȬpointȱ numbersȱ amongȱ machinesȱ withȱ incompatibleȱ floatingȬpointȱ
formats.ȱ
TheȱmodfȱfunctionȱbreaksȱaȱfloatingȬpointȱvalueȱintoȱintegerȱandȱfractionalȱparts,ȱ
eachȱhavingȱtheȱsameȱsignȱasȱtheȱoriginalȱvalue.ȱTheȱintegerȱpartȱisȱstoredȱasȱaȱ doubleȱ
inȱtheȱlocationȱpointedȱtoȱbyȱtheȱsecondȱargument,ȱandȱtheȱfractionalȱpartȱisȱreturnedȱ
asȱtheȱfunctionȱvalue.ȱ
ȱ
ȱ
ȱ
16.2.5
Power <math.h>
ȱ
Thereȱareȱtwoȱfunctionsȱinȱthisȱfamily.ȱ
ȱ
double pow( double x, double y );
double sqrt( double x );
Download at http://www.pin5i.com/
Chapter 16 Standard Libraryȱ
460ȱ
Theȱ powȱfunctionȱreturnsȱtheȱvalueȱxy.ȱBecauseȱlogarithmsȱmayȱbeȱusedȱinȱcomputingȱ
thisȱvalue,ȱaȱdomainȱerrorȱoccursȱifȱxȱisȱnegativeȱandȱyȱisȱnotȱanȱintegralȱvalue.ȱȱ
Theȱ sqrtȱ functionȱ returnsȱ theȱ squareȱ rootȱ ofȱ itsȱ argument.ȱ Aȱ domainȱ errorȱ
occursȱifȱtheȱargumentȱisȱnegative.ȱ
ȱ
ȱ
ȱ
16.2.6
Floor, Ceiling, Absolute Value, and Remainder <math.h>
ȱ
Theȱprototypesȱforȱtheseȱfunctionsȱareȱshownȱbelow.ȱ
ȱ
double
double
double
double
floor( double x );
ceil( double x );
fabs( double x );
fmod( double x, double y );
ȱ
Theȱ floorȱ functionȱ returnsȱ theȱ largestȱ integralȱ valueȱ thatȱ isȱ notȱ greaterȱ thanȱ itsȱ
argument.ȱ Thisȱ valueȱ isȱ returnedȱ asȱ aȱ doubleȱ dueȱ toȱ theȱ greatlyȱ increasedȱ rangeȱ ofȱ
doublesȱoverȱintegers.ȱTheȱ ceilȱfunctionȱreturnsȱtheȱsmallestȱintegralȱvalueȱthatȱisȱnotȱ
lessȱthanȱitsȱargument.ȱ
fabsȱreturnsȱ theȱabsoluteȱvalueȱofȱitsȱargument.ȱ Theȱ fmodȱfunctionȱreturnsȱ theȱ
remainderȱ thatȱ resultsȱ whenȱ xȱ isȱ dividedȱ byȱ y,ȱ andȱ theȱ quotientȱ isȱ restrictedȱ toȱ anȱ
integralȱvalue.ȱ
ȱ
ȱ
ȱ
16.2.7
String Conversion <stdlib.h>
ȱ
Theseȱfunctionsȱareȱsimilarȱtoȱtheȱintegerȱstringȱconversionȱfunctionsȱexceptȱthatȱtheyȱ
returnȱfloatingȬpointȱvalues.ȱ
ȱ
double atof( char const *string );
double strtod( char const *string, char **unused );
ȱ
Ifȱ theȱ argumentȱ toȱ eitherȱ ofȱ theseȱ functionsȱ containsȱ leadingȱ whiteȱ spaceȱ characters,ȱ
theyȱareȱskipped.ȱTheȱfunctionsȱthenȱconvertȱlegalȱcharactersȱtoȱaȱdouble,ȱignoringȱanyȱ
trailingȱ illegalȱ characters.ȱ Bothȱ functionsȱ acceptȱ allȱ ofȱ theȱ formsȱ usedȱ forȱ writingȱ
floatingȬpointȱliteralsȱinȱaȱprogram.ȱ
strtodȱ convertsȱ theȱ argumentȱ stringȱ toȱ aȱ doubleȱ inȱ theȱ sameȱ mannerȱ asȱ atof.ȱȱ
However,ȱstrtodȱsavesȱaȱpointerȱtoȱtheȱfirstȱcharacterȱinȱtheȱstringȱafterȱtheȱconvertedȱ
Download at http://www.pin5i.com/
16.3 Date and Time Functionsȱ
461
value.ȱIfȱtheȱsecondȱargumentȱtoȱtheȱfunctionȱisȱnotȱNULL,ȱtheȱsavedȱpointerȱisȱstoredȱ
inȱtheȱlocationȱpointedȱtoȱbyȱtheȱsecondȱargument.ȱTheȱpointerȱallowsȱtheȱremainderȱ
ofȱtheȱstringȱtoȱbeȱprocessedȱwithoutȱhavingȱtoȱguessȱwhereȱtheȱconversionȱstopped.ȱ
Ifȱ theȱ stringȱ argumentȱ toȱ eitherȱ ofȱ theseȱ functionsȱ doesȱ notȱ containȱ aȱ legalȱ
numericȱvalue,ȱthenȱzeroȱisȱreturned.ȱIfȱtheȱconvertedȱvalueȱisȱtooȱlargeȱorȱsmallȱtoȱbeȱ
represented,ȱtheȱvalueȱERANGEȱisȱstoredȱinȱerrno.ȱHUGE_VALȱisȱreturnedȱifȱtheȱvalueȱisȱtooȱ
largeȱ(eitherȱpositiveȱorȱnegative),ȱandȱzeroȱisȱreturnedȱifȱitȱisȱtooȱsmall.ȱ
ȱ
ȱ
ȱ
16.3 Date and Time Functions
ȱ
Theȱlibraryȱoffersȱaȱlargeȱcollectionȱofȱfunctionsȱthatȱsimplifyȱdealingȱwithȱdatesȱandȱ
times.ȱTheirȱprototypesȱareȱfoundȱinȱtime.h.ȱ
ȱ
ȱ
ȱ
16.3.1
Processor Time <time.h.
ȱ
Theȱ clockȱfunctionȱreturnsȱtheȱamountȱofȱprocessorȱtimeȱusedȱbyȱtheȱprogramȱsinceȱitȱ
beganȱexecuting.ȱ
ȱ
clock_t clock( void );
ȱ
Noteȱthatȱthisȱvalueȱmayȱbeȱanȱapproximation.ȱIfȱaȱmoreȱpreciseȱvalueȱisȱrequired,ȱcallȱ
clockȱ atȱ theȱ veryȱ beginningȱ ofȱ yourȱ mainȱ functionȱ andȱ subtractȱ theȱ valueȱ obtainedȱ
thereȱfromȱanyȱfutureȱvalueȱreturnedȱbyȱ clock.ȱIfȱtheȱimplementationȱcannotȱprovideȱ
theȱprocessorȱtime,ȱorȱifȱtheȱtimeȱisȱtooȱlargeȱtoȱbeȱrepresentedȱinȱaȱ clock_tȱvariable,ȱ
theȱvalueȱ-1ȱisȱreturned,ȱ
clockȱreturnsȱaȱnumberȱthatȱisȱimplementationȱdefined;ȱusuallyȱitȱisȱtheȱnumberȱ
CAUTION!
ofȱtimesȱtheȱprocessorȇsȱclockȱhasȱticked.ȱToȱconvertȱtheȱvalueȱtoȱseconds,ȱdivideȱitȱbyȱ
theȱconstantȱCLOCKS_PER_SEC.ȱ
ȱ
Onȱ someȱ implementations,ȱ thisȱ functionȱ mayȱ onlyȱ returnȱ anȱ approximationȱ ofȱ theȱ
processorȱ timeȱ used.ȱ Ifȱ theȱ hostȱ operatingȱ systemȱ isȱ incapableȱ ofȱ trackingȱ processorȱ
time,ȱ itȱ mayȱ returnȱ theȱ amountȱ ofȱ realȱ timeȱ thatȱ hasȱ elapsedȱ instead.ȱ Thisȱ behaviorȱ
mayȱalsoȱoccurȱwithȱsimpleȱoperatingȱsystemsȱthatȱcannotȱrunȱmoreȱthanȱoneȱprogramȱ
atȱ aȱ time.ȱ Oneȱ ofȱ theȱ chapterȱ exercisesȱ exploresȱ howȱ toȱ findȱ outȱ whichȱ wayȱ yourȱ
systemȱbehaves.ȱ
Download at http://www.pin5i.com/
Chapter 16 Standard Libraryȱ
462ȱ
16.3.2
Time of Day <time.h>
ȱ
Theȱtimeȱfunctionȱreturnsȱtheȱcurrentȱdateȱandȱtimeȱofȱday.ȱ
ȱ
time_t time( time_t *returned_value );
CAUTION!
ȱ
Ifȱ theȱ argumentȱ isȱ aȱ nonȬNULLȱ pointer,ȱ theȱ timeȱ valueȱ isȱ alsoȱ storedȱ throughȱ thisȱ
pointer.ȱIfȱtheȱimplementationȱcannotȱprovideȱtheȱcurrentȱdateȱandȱtimeȱorȱifȱtheȱtimeȱ
isȱtooȱlargeȱtoȱbeȱrepresentedȱinȱaȱtime_tȱvariable,ȱtheȱvalueȱ-1ȱisȱreturned.ȱ
Theȱ mannerȱ inȱ whichȱ theȱ timeȱ isȱ encodedȱ isȱ notȱ specifiedȱ byȱ theȱ Standard,ȱ soȱ
youȱ shouldȱ notȱ useȱ literalȱ constantsȱ becauseȱ theyȱ mayȱ haveȱ differentȱ meaningsȱ onȱ
differentȱ implementations.ȱ Aȱ commonȱ representationȱ isȱ toȱ returnȱ theȱ numberȱ ofȱ
secondsȱ thatȱ haveȱ elapsedȱ sinceȱ anȱ arbitrarilyȱ chosenȱ epoch.ȱ Onȱ MSȬDOSȱ andȱ UNIXȱ
systems,ȱtheȱepochȱisȱ00:00:00ȱJanuaryȱ1,ȱ1970. 49
ȱ
Itȱisȱtemptingȱtoȱcallȱ timeȱtwiceȱandȱsubtractȱtheȱvaluesȱobtainedȱtoȱdetermineȱelapsedȱ
time,ȱ butȱthisȱ techniqueȱisȱdangerousȱbecauseȱtheȱStandardȱdoesȱnotȱ requireȱ thatȱtheȱ
resultingȱvalueȱrepresentȱseconds.ȱ difftimeȱ(describedȱinȱtheȱnextȱsection)ȱshouldȱbeȱ
usedȱforȱthisȱpurpose.ȱ
ȱ
ȱ
ȱ
Date and Time Conversions <time.h>
ȱ
Theȱfollowingȱfunctionsȱmanipulateȱtime_tȱvalues.ȱ
ȱ
char *ctime( time_t const *time_value );
double difftime( time_t time1, time_t time2 );
ȱ
ctimeȱtakesȱaȱpointerȱtoȱaȱtimeȱvalueȱandȱreturnsȱaȱpointerȱtoȱaȱstringȱofȱtheȱformȱ
ȱ
Sun Jul
4 04:02:48 1976\n\0
ȱ
Theȱ spacingȱ inȱ thisȱ stringȱ isȱ fixed.ȱ Theȱ dayȱ ofȱ theȱ monthȱ alwaysȱ takesȱ twoȱ positionsȱ
evenȱifȱtheȱfirstȱisȱaȱspace,ȱandȱtwoȱdigitsȱalwaysȱappearȱforȱeachȱofȱtheȱtimeȱvalues.ȱȱ
Theȱ Standardȱdoesnȇtȱmentionȱtheȱ storageȱclassȱofȱtheȱmemoryȱ containingȱ theȱ string,ȱ
andȱmanyȱimplementationsȱuseȱaȱstaticȱarrayȱforȱthisȱpurpose.ȱȱThus,ȱtheȱstringȱwillȱbeȱ
overwrittenȱbyȱtheȱnextȱcallȱtoȱ ctime,ȱsoȱyouȱshouldȱmakeȱaȱcopyȱofȱitȱifȱyouȱneedȱtoȱ
saveȱit.ȱȱNoteȱthatȱctimeȱmayȱactuallyȱbeȱimplementedȱasȱ
ȱ
asctime( localtime( time_value ) );
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
ȱOnȱmanyȱimplementations,ȱtime_tȱisȱdefinedȱasȱaȱsigned,ȱ32Ȭbitȱquantity.ȱTheȱyearȱ2038ȱshouldȱbeȱinteresting:ȱinȱthatȱ
yearȱtheȱnumberȱofȱsecondsȱsinceȱ1970ȱwillȱoverflowȱaȱtime_tȱvariable.ȱ
49
Download at http://www.pin5i.com/
16.3 Date and Time Functionsȱ
463
Theȱdifftimeȱfunctionȱcomputesȱtheȱdifferenceȱtimel - time2ȱandȱconvertsȱtheȱ
resultȱtoȱseconds;ȱnoteȱthatȱitȱreturnsȱaȱdouble.ȱ
Theȱnextȱtwoȱfunctionsȱconvertȱaȱ time_tȱvalueȱintoȱaȱ struct tm,ȱwhichȱallowsȱ
easierȱaccessȱtoȱtheȱcomponentsȱofȱtheȱdateȱandȱtime.ȱ
ȱ
struct tm *gmtime( time_t const *time_value );
struct tm *locatime( time_t const *time_value );
ȱ
CAUTION!
Theȱ gmtimeȱfunctionȱconvertsȱtheȱtimeȱvalueȱintoȱCoordinatedȱUniversalȱTimeȱ(UTC).ȱ
UTCȱwasȱformerlyȱcalledȱGreenwichȱMeanȱTime,ȱhenceȱtheȱnameȱgmtime.ȱAsȱtheȱnameȱ
implies,ȱlocaltimeȱconvertsȱaȱtimeȱvalueȱintoȱlocalȱtime.ȱTheȱStandardȱincludesȱbothȱofȱ
theseȱ functionsȱ butȱ doesȱ notȱ describeȱ howȱ theȱ relationshipȱ betweenȱ UTCȱ andȱ localȱ
timeȱisȱtoȱbeȱimplemented.ȱ
Aȱ struct tmȱ containsȱ theȱ fieldsȱ listedȱ inȱ Tableȱ 16.2,ȱ thoughȱ notȱ necessarilyȱ inȱ
theȱorderȱinȱwhichȱtheyȱareȱlisted.ȱ
ȱ
Theȱ mostȱ commonȱ errorȱ madeȱ whenȱ usingȱ theseȱ valuesȱ isȱ toȱ interpretȱ theȱ monthȱ
incorrectly.ȱ Theseȱ valuesȱ areȱ theȱ numberȱ ofȱ monthsȱ sinceȱ January,ȱ soȱ 0ȱ representsȱ
Januaryȱ andȱ 11ȱ representsȱ December.ȱ Althoughȱ notȱ intuitiveȱ atȱ first,ȱ thisȱ numberingȱ
turnsȱoutȱtoȱbeȱaȱusefulȱencodingȱforȱtheȱmonthsȱbecauseȱitȱletsȱyouȱuseȱtheȱvaluesȱasȱ
subscriptsȱtoȱanȱarrayȱcontainingȱtheȱmonthȱnames.ȱ
ȱ
ȱ
ȱ
ȱ
Type & name
Range
Meaning
int tm_set;
0ȱȬȱ61ȱ
Secondsȱafterȱtheȱminute†
int tm_min;
0ȱȬȱ59ȱ
Minutesȱafterȱtheȱhourȱ
int tm_hour;
0ȱȬȱ23ȱ
Hoursȱafterȱmidnightȱ
int tm_mday;
0ȱȬȱ31ȱ
Dayȱofȱtheȱmonthȱ
int tm_mon;
0ȱȬȱ11ȱ
MonthsȱafterȱJanuaryȱ
int tm_year;
0ȱȬȱ??ȱ
Yearsȱafterȱ1900ȱ
int tm_wday;
0ȱȬȱ6ȱ
DaysȱafterȱSundayȱ
int tm_yday;
0ȱȬȱ365ȱ
DaysȱafterȱJanuaryȱ1ȱ
int tm_isdst;
ȱ
DaylightȱSavingsȱTimeȱflagȱ
ȱ
†
Oneȱ mustȱ admireȱ theȱ thoroughnessȱ ofȱ theȱ ANSIȱ Standardsȱ committeeȱ thatȱ formulatedȱ theȱ
C++ȱstandardȱforȱmakingȱallowanceȱforȱtheȱȈleapȱsecondsȈȱthatȱareȱoccasionallyȱaddedȱtoȱtheȱ
lastȱminuteȱofȱtheȱyearȱtoȱadjustȱourȱtimeȱstandardsȱtoȱtheȱEarthȇsȱslowingȱrotation.ȱ
ȱ
Tableȱ16.2ȱȱFieldsȱinȱaȱstruct tmȱ
Download at http://www.pin5i.com/
464ȱ
CAUTION!
Chapter 16 Standard Libraryȱ
Theȱnextȱmostȱcommonȱerrorȱisȱtoȱforgetȱthatȱtheȱ tm_yearȱvalueȱisȱonlyȱtheȱyearsȱsinceȱ
1900.ȱȱToȱcomputeȱtheȱactualȱyear,ȱ1900ȱmustȱbeȱaddedȱtoȱtheȱvalue.ȱ
Afterȱyouȱhaveȱaȱ struct tm,ȱyouȱmayȱeitherȱuseȱitsȱvaluesȱdirectly,ȱorȱyouȱmayȱ
passȱitȱtoȱeitherȱofȱtheseȱfunctions.ȱ
ȱ
char *asctime( struct tm const*tm_ptr );
size_t strftime( char *string, size_t maxsize, char const *format,
struct tm const *tm_ptr );
ȱ
Theȱ asctimeȱfunctionȱconvertsȱtheȱtimeȱrepresentedȱinȱtheȱargumentȱtoȱaȱstringȱ
ofȱtheȱfollowingȱform:ȱ
ȱ
Sun Jul
4 04:02:48 1976\n\0
ȱ
Thisȱformȱisȱtheȱsameȱoneȱusedȱbyȱtheȱ ctimeȱfunction,ȱwhichȱinȱfactȱmayȱcallȱ asctimeȱ
toȱperformȱitsȱwork.ȱ
Theȱ strftimeȱfunctionȱconvertsȱaȱ struct tmȱintoȱaȱstringȱaccordingȱtoȱaȱformatȱ
string.ȱȱThisȱfunctionȱprovidesȱtremendousȱflexibilityȱinȱformattingȱdates.ȱIfȱtheȱstringȱ
resultingȱ fromȱ theȱ conversionȱ isȱ lessȱ thanȱ theȱ maxsizeȱ argument,ȱ thenȱ theȱ stringȱ isȱ
copiedȱintoȱtheȱarrayȱthatȱtheȱfirstȱargumentȱpointsȱtoȱandȱ strftimeȱreturnsȱtheȱlengthȱ
ofȱtheȱstring.ȱȱOtherwiseȱ0ȱisȱreturnedȱandȱtheȱarrayȱcontentsȱareȱundefined.ȱ
Theȱ formatȱ stringȱ containsȱ ordinaryȱ charactersȱ andȱ formatȱ codes.ȱ Ordinaryȱ
charactersȱareȱcopiedȱwhereȱtheyȱappear.ȱFormatȱcodesȱareȱreplacedȱbyȱaȱdareȱorȱtimeȱ
value.ȱ Formatȱ codesȱ consistȱ ofȱ aȱ %ȱ characterȱ followedȱ byȱ aȱ characterȱ thatȱ indicatesȱ
valueȱdesired.ȱTableȱ16.3ȱlistsȱtheȱformatȱcodesȱthatȱareȱimplemented.ȱAȱ %ȱfollowedȱbyȱ
anyȱ otherȱ characterȱ isȱ undefined,ȱ whichȱ leavesȱ individualȱ implementationsȱ freeȱ toȱ
defineȱadditionalȱformatȱcodes.ȱYouȱshouldȱavoidȱusingȱthemȱunlessȱyouȱareȱwillingȱtoȱ
sacrificeȱportability.ȱTheȱlocaleȬspecificȱvaluesȱareȱdeterminedȱbyȱtheȱcurrentȱlocale,ȱasȱ
discussedȱlaterȱinȱthisȱchapter.ȱTheȱ%Uȱandȱ%Wȱcodesȱareȱidenticalȱexceptȱthatȱtheȱformerȱ
countsȱ theȱ firstȱ Sundayȱ ofȱ theȱ yearȱ asȱ theȱ beginningȱ ofȱ theȱ firstȱ weekȱ andȱ theȱ latterȱ
countsȱtheȱfirstȱMondayȱofȱtheȱyearȱasȱtheȱbeginningȱofȱtheȱfirstȱweek.ȱIfȱtheȱtimeȱzoneȱ
cannotȱbeȱdetermined,ȱtheȱ%zȱcodeȱisȱreplacedȱbyȱanȱemptyȱstring.ȱ
Finally,ȱtheȱmktimeȱfunctionȱisȱusedȱtoȱconvertȱaȱstruct tmȱtoȱaȱtime_tȱvalue,ȱ
ȱ
time_t mktime( struct tm *tm_ptr );
ȱ
Theȱvaluesȱofȱ tm_wdayȱandȱ tm_ydayȱinȱtheȱ struct tmȱareȱignored,ȱandȱtheȱvalueȱinȱtheȱ
otherȱfieldsȱneedȱnotȱbeȱwithinȱtheirȱusualȱranges.ȱAfterȱtheȱconversion,ȱtheȱ struct tmȱ
isȱthenȱnormalized,ȱsoȱthatȱtm_wdayȱandȱtm_yday areȱcorrectȱandȱtheȱremainingȱfieldsȱ
Download at http://www.pin5i.com/
16.4 Nonlocal Jumps <setjmp.h>ȱ
Code
%%
%a
%A
%b
%B
%c
%d
%H
%I
%j
%m
%M
%p
%S
%U
%w
%W
%x
%X
%y
%Y
%Z
465
is Replaced By
aȱ%ȱ
theȱdayȱofȱweek,ȱusingȱtheȱlocaleȇsȱabbreviatedȱweekdayȱnamesȱ
theȱdayȱofȱweek,ȱusingȱtheȱlocaleȇsȱfullȱweekdayȱnamesȱ
theȱmonth,ȱusingȱtheȱlocaleȇsȱabbreviatedȱmonthȱnamesȱ
theȱmonth,ȱusingȱtheȱlocaleȇsȱfullȱmonthȱnamesȱ
theȱdateȱandȱtime,ȱusingȱ%x %Xȱ
theȱdayȱofȱmonthȱ(01Ȭ31)ȱ
theȱhour,ȱinȱ24Ȭhourȱclockȱformatȱ(00Ȭ23)ȱ
theȱhour,ȱinȱ12Ȭhourȱclockȱformatȱ(01Ȭ12)ȱ
theȱdayȱnumberȱofȱtheȱyearȱ(001Ȭ366)ȱ
theȱmonthȱnumberȱ(01Ȭ12)ȱ
theȱminuteȱ(00Ȭ59)ȱ
theȱlocaleȇsȱequivalentȱofȱAMȱorȱPM,ȱwhicheverȱisȱappropriateȱ
theȱsecondsȱ(00Ȭ61)ȱ
theȱweekȱnumberȱofȱtheȱyearȱ(00Ȭ53),ȱstartingȱwithȱSundayȱ
theȱdayȱofȱtheȱweek;ȱSundayȱisȱdayȱ0ȱ
theȱweekȱnumberȱofȱtheȱyearȱ(00Ȭ53),ȱstartingȱwithȱMondayȱ
theȱdate,ȱusingȱtheȱlocaleȇsȱdateȱformatȱ
theȱtime,ȱusingȱtheȱlocaleȇsȱtimeȱformatȱ
theȱyearȱwithinȱtheȱcenturyȱ(00Ȭ99)ȱ
theȱyear,ȱincludingȱcenturyȱ(forȱexample,ȱ1984)ȱ
theȱtimeȱzoneȱabbreviationȱ
ȱ
Tableȱ16.3ȱȱstrftimeȱformatȱcodesȱ
ȱ
ȱ
areȱ allȱ withinȱ theirȱ usualȱ ranges.ȱ Thisȱ techniqueȱ isȱ aȱ simpleȱ wayȱ ofȱ determiningȱ theȱ
dayȱofȱtheȱweekȱforȱaȱparticularȱdate.ȱ
ȱ
ȱ
ȱ
16.4 Nonlocal Jumps <setjmp.h>
ȱ
Theȱ setjmpȱandȱ longjmpȱfunctionsȱprovideȱaȱmechanismȱsimilarȱtoȱtheȱ gotoȱstatementȱ
exceptȱ thatȱ itȱ isȱ notȱ limitedȱ inȱ scopeȱ toȱ oneȱ function.ȱ Theseȱ functionsȱ areȱ commonlyȱ
usedȱwithȱdeeplyȱnestedȱchainsȱofȱfunctionȱcalls.ȱIfȱanȱerrorȱisȱdetectedȱinȱaȱlowerȬlevelȱ
function,ȱ youȱ canȱ returnȱ immediatelyȱ toȱ theȱ topȬlevelȱ functionȱ withoutȱ havingȱ toȱ
returnȱanȱerrorȱflagȱtoȱeachȱintermediateȱfunctionȱinȱtheȱchain.ȱ
Toȱ useȱ theseȱ functions,ȱ youȱ mustȱ includeȱ theȱ headerȱ fileȱ setjmp.h;ȱ theirȱ
prototypesȱareȱshownȱbelow.ȱ
Download at http://www.pin5i.com/
Chapter 16 Standard Libraryȱ
466ȱ
int setjmp( jmp_buf state );
void longjmp( jump_buf state, int value );
ȱ
Youȱ declareȱ aȱ jmp_bufȱ variableȱ andȱ initializeȱ itȱ byȱ callingȱ setjmp,ȱ whichȱ returnsȱ theȱ
valueȱ zero.ȱ setjmpȱ savesȱ programȱ stateȱ informationȱ (forȱ example,ȱ theȱ currentȱ stackȱ
pointerȱ andȱ programȱ counter)ȱ inȱ theȱ jumpȱ buffer. 50 ȱ Theȱ functionȱ inȱ whichȱ youȱ callȱ
setjmpȱbecomesȱyourȱȈtopȬlevelȈȱfunction.ȱ
Later,ȱ aȱ callȱ toȱ longjmpȱ fromȱ anywhereȱ withinȱ theȱ topȬlevelȱ functionȱ orȱ anyȱ
otherȱ functionȱ thatȱ itȱ calls,ȱ eitherȱ directlyȱ orȱ indirectly,ȱ causesȱ theȱ savedȱ stateȱ toȱ beȱ
restored.ȱTheȱeffectȱofȱlongjmpȱisȱthatȱexecutionȱimmediatelyȱgoesȱbackȱtoȱtheȱtopȬlevelȱ
functionȱbyȱreturningȱagainȱfromȱtheȱsetjmpȱfunction.ȱ
Howȱ canȱ youȱ distinguishȱ betweenȱ theseȱ twoȱ differentȱ returnsȱ formȱ setjmp?ȱ
Whenȱitȱisȱinitiallyȱcalled,ȱsetjmpȱreturnsȱtheȱvalueȱzero.ȱWhenȱsetjmpȱreturnsȱagainȱasȱ
theȱresultȱofȱaȱ longjmp,ȱtheȱvalueȱthatȱitȱreturnsȱisȱtheȱsecondȱargumentȱtoȱtheȱ longjmpȱ
call,ȱwhichȱmustȱbeȱnonzero.ȱByȱcheckingȱtheȱreturnȱvalue,ȱtheȱprogramȱcanȱdetermineȱ
whetherȱ(and,ȱinȱtheȱcaseȱofȱmultipleȱcalls,ȱwhich)ȱlongjmpȱwasȱcalled.ȱ
ȱ
ȱ
ȱ
16.4.1
Example
ȱ
Programȱ 16.2ȱ usesȱ setjmpȱ toȱ handleȱ errorsȱ detectedȱ inȱ functionsȱ thatȱ itȱ callsȱ withoutȱ
theȱ usualȱ logicȱ ofȱ returningȱ andȱ checkingȱ forȱ errorȱ codes.ȱ Theȱ initialȱ callȱ toȱ setjmpȱ
establishesȱtheȱpointȱatȱwhichȱexecutionȱwillȱresumeȱafterȱaȱcallȱtoȱ longjmp.ȱȱIfȱreturnsȱ
theȱ valueȱ zero,ȱ soȱ theȱ programȱ entersȱ theȱ transactionȱ processingȱ loop.ȱ Ifȱ get_trans,ȱ
process_trans,ȱ orȱ anyȱ functionsȱ calledȱ byȱ theseȱ functionsȱ detectsȱ anȱ error,ȱ itȱ callsȱ
longjmpȱlikeȱthis:ȱ
ȱ
longjmp( restart, 1 );
ȱ
Executionȱimmediatelyȱresumesȱatȱtheȱrestartȱpoint,ȱandȱsetjmpȱreturnsȱwithȱtheȱvalueȱ
one.ȱ
Inȱ thisȱ example,ȱ twoȱ differentȱ typesȱ ofȱ errorsȱ areȱ handled:ȱ fatalȱ errorsȱ thatȱ
preventȱ theȱ programȱ fromȱ continuing,ȱ andȱ minorȱ errorsȱ thatȱ onlyȱ disruptȱ theȱ
transactionȱ thatȱ wasȱ beingȱ processed.ȱ Thisȱ callȱ toȱ longjmpȱ isȱ theȱ latter.ȱ Whenȱ setjmpȱ
returnsȱone,ȱanȱerrorȱmessageȱisȱprintedȱandȱtheȱtransactionȱloopȱisȱenteredȱonceȱagain.ȱ
Toȱreportȱaȱfatalȱerror,ȱ longjmpȱisȱcalledȱwithȱanyȱotherȱvalue,ȱandȱtheȱprogramȱsavesȱ
itsȱdataȱandȱexits.ȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
50
ȱTheȱaddressȱofȱtheȱinstructionȱcurrentlyȱbeingȱexecutedȱinȱtheȱprogram.ȱ
Download at http://www.pin5i.com/
16.4 Nonlocal Jumps <setjmp.h>ȱ
467
ȱ
/*
** A program to demonstrate the use of setjmp
*/
#include "trans.h"
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
/*
**
The variable that stores setjmp's state information.
*/
jmp_buf
restart;
int
main()
{
int
value;
Trans *transaction;
/*
** Establish the point at which we want to resume execution
** after a call to longjmp.
*/
value = setjmp( restart );
/*
** Figure out what to do after a return from setjmp.
*/
switch( value ){
default:
/*
** longjmp was called -- fatal error
*/
fputs( "Fatal error.\n", stderr );
break;
case 1:
/*
** longjmp was called -- minor error
*/
fputs( "Invalid transaction.\n", stderr );
/* FALL THROUGH and continue processing */
case 0:
/*
** Original return from setjmp: perform normal
** processing.
*/
while( (transaction = get_trans()) != NULL )
process_trans( transaction );
}
ȱ
Programȱ16.2ȱȱsetjmpȱandȱlongjmpȱexampleȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
Chapter 16 Standard Libraryȱ
468ȱ
ȱ
/*
** Save data and exit the program
*/
write_data_to_file();
return value == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}ȱ
ȱ
Programȱ16.2ȱȱsetjmpȱandȱlongjmpȱexampleȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
16.4.2
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱsetjmp.cȱ
When to Use Nonlocal Jumps
ȱ
setjmpȱandȱ longjmpȱareȱnotȱabsolutelyȱnecessary,ȱbecauseȱyouȱcanȱalwaysȱachieveȱtheȱ
CAUTION!
TIP
sameȱ resultȱ byȱ returningȱ anȱ errorȱ codeȱ andȱ checkingȱ forȱ itȱ inȱ theȱ callingȱ function.ȱ
Returningȱ inȱ thisȱ mannerȱ isȱ sometimesȱ inconvenient,ȱ especiallyȱ ifȱ theȱ functionsȱ areȱ
alreadyȱ returningȱ someȱ value.ȱ Ifȱ thereȱ isȱ aȱ longȱ chainȱ ofȱ functionȱ callingȱ functionȱ
callingȱ function,ȱ thenȱ eachȱ functionȱ inȱ theȱ chainȱ mustȱ checkȱ forȱ andȱ returnȱ theȱ errorȱ
codeȱevenȱifȱtheȱlastȱfunctionȱcalledȱisȱtheȱonlyȱoneȱthatȱeverȱdetectsȱanyȱerrors.ȱUsingȱ
setjmpȱandȱlongjmpȱinȱthisȱsituationȱsimplifiesȱtheȱintermediateȱfunctionsȱbyȱremovingȱ
theȱerrorȱcodeȱlogicȱfromȱthem.ȱ
ȱ
WhenȱtheȱtopȬlevelȱfunctionȱ(theȱoneȱthatȱcalledȱ setjmp)ȱreturns,ȱtheȱstateȱinformationȱ
inȱ theȱ jumpȱ bufferȱ becomesȱ invalid.ȱ Callsȱ toȱ longjmpȱ afterȱ thisȱ timeȱ areȱ likelyȱ toȱ fail,ȱ
andȱ theȱ symptomsȱ willȱ beȱ difficultȱ toȱ debug.ȱ Thisȱ factȱ isȱ whyȱ longjmpȱ canȱ beȱ calledȱ
onlyȱbyȱtheȱtopȬlevelȱfunction,ȱorȱbyȱfunctionsȱcalledȱfromȱtheȱtopȬlevelȱfunction.ȱOnlyȱ
thenȱisȱtheȱstateȱinformationȱsavedȱinȱtheȱjumpȱbufferȱvalid.ȱ
ȱ
Becauseȱsetȱ jmpȱandȱ longjmpȱimplementȱwhatȱisȱeffectivelyȱaȱ goto,ȱyouȱmustȱexerciseȱ
someȱ disciplineȱ inȱ theirȱ use.ȱ Inȱ situationsȱ likeȱ theȱ exampleȱ inȱ Programȱ 16.2,ȱ theseȱ
functionsȱ canȱ contributeȱ toȱ cleaner,ȱ lessȱ complicatedȱ code.ȱ However,ȱ ifȱ setjmpȱ andȱ
longjmpȱareȱusedȱtoȱsimulateȱaȱ gotoȱwithinȱoneȱfunctionȱorȱifȱthereȱareȱdozensȱofȱjumpȱ
buffersȱ toȱ whichȱ executionȱ canȱ return,ȱ theȱ logicȱ willȱ becomeȱ moreȱ difficultȱ toȱ
understandȱ andȱ theȱ programȱ willȱ beȱ harderȱ toȱ debugȱ andȱ maintain,ȱ inȱ additionȱ toȱ
beingȱ moreȱ likelyȱ toȱ fail.ȱ Youȱ canȱ useȱ setjmpȱ andȱ longjmp,ȱ butȱ youȱ shouldȱ useȱ themȱ
wisely.ȱ
ȱ
Download at http://www.pin5i.com/
16.5 Signalsȱ
469
16.5 Signals
ȱ
Mostȱofȱtheȱactionsȱthatȱhappenȱinȱaȱprogramȱareȱcausedȱbyȱtheȱprogram,ȱforȱexample,ȱ
executingȱvariousȱstatementsȱorȱrequestingȱinput.ȱHowever,ȱthereȱareȱsomeȱeventsȱthatȱ
theȱprogramȱmustȱreachȱtoȱthatȱareȱnotȱcausedȱbyȱtheȱprogram.ȱAȱcommonȱexampleȱisȱ
whenȱ theȱ riserȱ interruptsȱ aȱ program.ȱ Ifȱ partiallyȱ computedȱ resultsȱ mustȱ beȱ savedȱ inȱ
orderȱtoȱavoidȱlossȱofȱdata,ȱtheȱprogramȱmustȱbeȱpreparedȱtoȱreactȱtoȱthisȱeventȱevenȱ
thoughȱthereȱisȱnoȱwayȱtoȱpredictȱwhenȱitȱwillȱoccur.ȱ
Signalsȱ areȱ usedȱ forȱ thisȱ purpose.ȱ Aȱ signalȱ representsȱ anȱ eventȱ thatȱ canȱ occurȱ
asynchronously,ȱthatȱis,ȱnotȱsynchronizedȱwithȱanythingȱinȱtheȱprogramȇsȱexecution.ȱIfȱ
theȱ programȱ hasȱ notȱ arrangedȱ toȱ handleȱ aȱ particularȱ signal,ȱ aȱ defaultȱ actionȱ isȱ takenȱ
whenȱ theȱ signalȱoccurs.ȱTheȱStandardȱdoesȱnotȱ defineȱwhatȱtheȱdefaultȱ actionȱ is,ȱbutȱ
mostȱ implementationsȱ abortȱ theȱ program.ȱ Alternatively,ȱ theȱ programȱ canȱ callȱ theȱ
signalȱfunctionȱtoȱeitherȱignoreȱtheȱsignalȱorȱtoȱinstallȱaȱsignalȱhandler,ȱaȱfunctionȱinȱtheȱ
programȱtoȱbeȱcalledȱwhenȱaȱsignalȱoccurs.ȱ
ȱ
ȱ
ȱ
ȱ
16.5.1
Signal Names <signal.h>
ȱ
Tableȱ 16.4ȱ listsȱ theȱ signalsȱ definedȱ byȱ theȱ Standard,ȱ thoughȱ anȱ implementationȱ needȱ
notȱgenerateȱallȱofȱtheseȱsignalsȱandȱitȱcanȱdefineȱadditionalȱonesȱifȱappropriate.ȱ
SIGABRTȱ isȱ theȱ signalȱ raisedȱ byȱ theȱ abortȱ functionȱ toȱ abortȱ theȱ program.ȱ Theȱ
specificȱ errorsȱ thatȱ willȱ raiseȱ aȱ SIGFPEȱ signalȱ areȱ implementationȱ dependent.ȱ Someȱ
commonȱonesȱareȱarithmeticȱoverflowȱorȱunderflowȱandȱdivideȱbyȱzeroȱerrors.ȱSomeȱȱ
ȱ
ȱ
ȱ
ȱ
Signal
Meaning
SIGABRT
Theȱprogramȱhasȱrequestedȱabnormalȱtermination.ȱ
SIGFPE
Anȱarithmeticȱerrorȱoccurred.ȱ
SIGILL
Anȱillegalȱinstructionȱwasȱdetected.ȱ
SIGSEGV
Anȱinvalidȱaccessȱtoȱmemoryȱwasȱdetected.ȱ
SIGINT
Anȱinteractiveȱattentionȱsignalȱwasȱreceived.ȱ
SIGTERM
Aȱrequestȱtoȱterminateȱtheȱprogramȱwasȱreceived.ȱ
ȱ
Tableȱ16.4ȱȱSignalsȱ
Download at http://www.pin5i.com/
Chapter 16 Standard Libraryȱ
470ȱ
implementationsȱextendȱthisȱsignalȱtoȱprovideȱspecificȱinformationȱaboutȱtheȱoperationȱ
thatȱcausedȱtheȱsignal.ȱUsingȱthisȱinformationȱmayȱletȱtheȱprogramȱreactȱtoȱtheȱsignalȱ
moreȱintelligently,ȱbutȱreducesȱitsȱportability.ȱ
Theȱ SIGILLȱsignalȱindicatesȱthatȱtheȱCPUȱtriedȱtoȱexecuteȱanȱillegalȱinstruction.ȱ
Thisȱ errorȱ mayȱ beȱ causedȱ byȱ incorrectȱ compilerȱ settings;ȱ forȱ example,ȱ compilingȱ aȱ
programȱwithȱIntelȱ80386ȱinstructionsȱbutȱrunningȱitȱonȱanȱ80286ȱcomputer.ȱAnotherȱ
possibleȱ causeȱ isȱ anȱerrorȱ inȱ theȱ executionȱ ofȱtheȱprogram,ȱ suchȱ asȱcallingȱ aȱ functionȱ
usingȱanȱuninitializedȱfunctionȱpointerȱthatȱhasȱcausedȱtheȱCPUȱtoȱattemptȱtoȱexecuteȱ
whatȱisȱactuallyȱdata.ȱ SIGSEGVȱindicatesȱanȱattemptȱbyȱtheȱprogramȱtoȱaccessȱmemoryȱ
illegally.ȱ Theȱ twoȱmostȱcommonȱcausesȱofȱthisȱsignalȱ areȱattemptsȱ toȱ accessȱmemoryȱ
thatȱisȱnotȱinstalledȱonȱtheȱmachineȱorȱnotȱallocatedȱtoȱyourȱprogramȱbyȱtheȱoperatingȱ
systemȱ andȱ violatingȱ boundaryȱ requirements.ȱ Theȱ latterȱ occursȱ onȱ machinesȱ thatȱ
enforceȱboundaryȱalignmentȱonȱdata.ȱForȱexample,ȱifȱintegersȱareȱrequiredȱtoȱbeȱonȱanȱ
evenȱboundaryȱ(beginȱatȱanȱevenȱnumberedȱaddress),ȱanȱinstructionȱthatȱspecifiesȱanȱ
oddȱ addressȱ toȱ accessȱ anȱ integerȱ willȱ causeȱ aȱ boundaryȱ violation.ȱ Uninitializedȱ
pointersȱareȱoftenȱtheȱcauseȱofȱthisȱerror.ȱ
Theȱprecedingȱsignalsȱareȱsynchronousȱbecauseȱtheyȱareȱallȱcausedȱfromȱwithinȱ
theȱprogram.ȱAlthoughȱyouȱmayȱnotȱbeȱableȱtoȱpredictȱwhenȱanȱarithmeticȱerrorȱmayȱ
occur,ȱ ifȱ youȱ runȱ theȱ programȱ overȱ andȱ overȱ withȱ theȱ sameȱ dataȱ theȱ sameȱ errorȱ willȱ
occurȱ atȱ theȱ sameȱ placeȱ everyȱ time.ȱ Theȱ lastȱ twoȱ signals,ȱ SIGINTȱ andȱ SIGTERM,ȱ areȱ
asynchronous.ȱ Theyȱ originateȱ fromȱ outsideȱ theȱ program,ȱ usuallyȱ byȱ theȱ programȇsȱ
user,ȱandȱindicateȱthatȱtheȱuserȱisȱtryingȱtoȱtellȱtheȱprogramȱsomething.ȱ
SIGINTȱ isȱ theȱ signalȱ thatȱ mostȱ implementationsȱ raiseȱ whenȱ theȱ userȱ triesȱ toȱ
interruptȱ theȱ program.ȱ SIGTERMȱ isȱ anȱ alternativeȱ signalȱ thatȱ anȱ implementationȱ mayȱ
useȱ toȱ requestȱ thatȱ theȱ programȱ beȱ terminated.ȱ Inȱ systemsȱ thatȱ implementȱ bothȱ ofȱ
theseȱ signals,ȱ aȱ commonȱ strategyȱ isȱ toȱ defineȱ aȱ signalȱ handlerȱ forȱ SIGINTȱ inȱ orderȱ toȱ
performȱ housekeepingȱ andȱ saveȱ dataȱ beforeȱ exitingȱ theȱ program,ȱ butȱ toȱ notȱ installȱ aȱ
signalȱhandlerȱforȱ SIGTERMȱsoȱthatȱtheȱprogramȱcanȱbeȱterminatedȱwithoutȱdoingȱthisȱ
housekeeping.ȱ
ȱ
ȱ
ȱ
16.5.2
Processing Signals <signal.h>
ȱ
Usuallyȱ weȱ areȱ concernedȱ withȱ handlingȱ signalsȱ thatȱ occurȱ onȱ theirȱ own,ȱ thatȱ is,ȱ
unplannedȱsignals.ȱTheȱraiseȱfunctionȱisȱprovidedȱtoȱraiseȱaȱsignalȱexplicitly.ȱ
ȱ
int raise( int sig );
Download at http://www.pin5i.com/
16.5 Signalsȱ
471
ȱ
Callingȱthisȱfunctionȱraisesȱtheȱindicatedȱsignal.ȱȱTheȱprogramȱrespondsȱtoȱtheȱsignalȱ
exactlyȱ asȱ ifȱ itȱ hadȱ occurredȱ onȱ itsȱ own.ȱ Youȱ canȱ callȱ thisȱ functionȱ toȱ testȱ signalȱ
handlers,ȱ butȱ itȱ canȱ alsoȱ beȱ misusedȱ toȱ effectȱ aȱ nonlocalȱ goto.ȱ Avoidȱ usingȱ itȱ inȱ thisȱ
way.ȱ
Thereȱareȱthreeȱwaysȱthatȱaȱprogramȱcanȱreactȱwhenȱaȱsignalȱoccurs.ȱTheȱdefaultȱ
actionȱisȱdefinedȱbyȱtheȱimplementation,ȱoftenȱtheȱdefaultȱisȱtoȱabortȱtheȱprogram.ȱȱTheȱ
programȱcanȱspecifyȱotherȱbehaviorsȱforȱrespondingȱtoȱsignals:ȱaȱsignalȱcanȱbeȱignored,ȱ
orȱtheȱprogramȱcanȱinstallȱaȱsignalȱhandlerȱthatȱisȱcalledȱwhenȱtheȱsignalȱoccurs.ȱTheȱ
signalȱfunctionȱisȱusedȱtoȱspecifyȱtheȱdesiredȱaction.ȱ
ȱ
void ( *signal( int si, void ( *handler )( int ) ) )( int );
ȱ
Thisȱprototypeȱisȱdaunting,ȱsoȱnowȱweȱwillȱunravelȱit.ȱFirst,ȱIȇllȱomitȱtheȱreturnȱtypeȱsoȱ
weȱcanȱexamineȱtheȱarguments:ȱ
ȱ
signal( int sig, void ( *handler )( int ) )
ȱ
TheȱfirstȱargumentȱisȱaȱsignalȱfromȱTableȱ16.4,ȱandȱtheȱsecondȱargumentȱisȱtheȱhandlerȱ
youȱwantȱtoȱinstallȱforȱthatȱsignal.ȱTheȱhandlerȱisȱaȱpointerȱtoȱaȱfunctionȱthatȱtakesȱaȱ
singleȱintegerȱargumentȱandȱdoesnȇtȱreturnȱaȱresult.ȱWhenȱtheȱsignalȱoccurs,ȱtheȱcodeȱ
forȱ theȱ signalȱ isȱ passedȱ asȱ anȱ argumentȱ toȱ theȱ handler.ȱ Thisȱ argumentȱ allowsȱ oneȱ
handlerȱtoȱprocessȱseveralȱdifferentȱsignals.ȱ
Nowȱ Iȇllȱ omitȱ theȱ argumentsȱ fromȱ theȱ prototypeȱ toȱ makeȱ theȱ returnȱ valueȱ
apparent:ȱ
ȱ
void ( *signal() )( int );
ȱ
signalȱ isȱ aȱ functionȱ thatȱ returnsȱ aȱ pointerȱ toȱ anotherȱ function,ȱ whichȱ takesȱ aȱ singleȱ
integerȱ argumentȱ andȱ doesnȇtȱ returnȱ aȱ result.ȱ Inȱ fact,ȱ signalȱ returnsȱ aȱ pointerȱ toȱ theȱ
previousȱ handlerȱ forȱ theȱ signal.ȱ Byȱ savingȱ thisȱ valueȱ youȱ canȱ installȱ aȱ handlerȱ forȱ aȱ
signalȱandȱthenȱlaterȱreturnȱtoȱtheȱpreviousȱsignalȱhandler.ȱIfȱtheȱcallȱtoȱsignalȱfails,ȱforȱ
exampleȱbecauseȱofȱanȱillegalȱsignalȱcode,ȱtheȱvalueȱSIG_ERRȱisȱreturned.ȱThisȱvalueȱisȱaȱ
macroȱthatȱisȱdefinedȱinȱtheȱheaderȱfile.ȱ
Thereȱareȱtwoȱadditionalȱmacros,ȱSIG_DFLȱandȱSIG_IGN,ȱthatȱmayȱbeȱgivenȱasȱtheȱ
secondȱ argumentȱ toȱ signal.ȱ SIG_DFȱ reinstatesȱ theȱ defaultȱ actionȱ forȱ theȱ signal,ȱ andȱ
SIG_IGNȱcausesȱtheȱsignalȱtoȱbeȱignored.ȱ
Download at http://www.pin5i.com/
Chapter 16 Standard Libraryȱ
472ȱ
16.5.3
Signal Handlers
ȱ
Whenȱaȱsignalȱoccursȱforȱwhichȱaȱhandlerȱhasȱbeenȱinstalled,ȱtheȱsystemȱfirstȱreinstatesȱ
theȱ defaultȱ actionȱ forȱ theȱ signal. 51 ȱ Thisȱ changeȱ preventsȱ anȱ infiniteȱ loopȱ ifȱ theȱ signalȱ
recursȱwithinȱtheȱhandler.ȱNextȱtheȱhandlerȱisȱcalled,ȱandȱtheȱsignalȱcodeȱisȱpassedȱasȱ
anȱargument.ȱ
Theȱ typeȱ ofȱ workȱ theȱ handlerȱ canȱ performȱ isȱ limited.ȱ Ifȱ theȱ signalȱ isȱ
asynchronous,ȱ thatȱ is,ȱ itȱ isȱ notȱ causedȱ byȱ callingȱ theȱ abortȱ orȱ raiseȱ functions,ȱ theȱ
handlerȱshouldȱnotȱcallȱanyȱlibraryȱfunctionȱotherȱthanȱsignalȱbecauseȱtheirȱresultsȱareȱ
undefinedȱ inȱ thisȱ context.ȱ Furthermore,ȱ theȱ handlerȱ mayȱ notȱ accessȱ anyȱ staticȱ dataȱ
exceptȱtoȱassignȱaȱvalueȱtoȱaȱstaticȱvariableȱofȱtypeȱ volatile sig_atomic_t.ȱ(volatileȱ
isȱdescribedȱinȱtheȱnextȱsection.)ȱToȱbeȱtrulyȱsafe,ȱaboutȱallȱthatȱaȱsignalȱhandlerȱcanȱdoȱ
isȱsetȱoneȱofȱtheseȱvariablesȱandȱthenȱreturn.ȱTheȱrestȱofȱtheȱprogramȱmustȱperiodicallyȱ
examineȱtheȱvariableȱtoȱseeȱifȱaȱsignalȱhasȱoccurred.ȱ
Theseȱ harshȱ restrictionsȱ ariseȱ fromȱ theȱ natureȱ ofȱ signalȱ handling.ȱ Theȱ signalȱ
usuallyȱ indicatesȱ thatȱ somethingȱ wentȱ wrong.ȱ Theȱ behaviorȱ ofȱ theȱ CPUȱ isȱ preciselyȱ
definedȱinȱsuchȱcircumstances,ȱbutȱtheȱprogramȱaddsȱaȱlotȱofȱcontextȱsurroundingȱtheȱ
errorȱthatȱmayȱnotȱbeȱsoȱwellȱdefined.ȱForȱexample,ȱaȱsignalȱthatȱoccurredȱwhileȱstrcpyȱ
wasȱexecutingȱmightȱleaveȱtheȱdestinationȱstringȱtemporarilyȱunterminated,ȱorȱaȱsignalȱ
occurringȱ whileȱ aȱ functionȱ wasȱ beingȱ calledȱ mightȱ leaveȱ theȱ stackȱ inȱ anȱ incompleteȱ
state.ȱ Ifȱ libraryȱ functionsȱ thatȱ dependȱ onȱ thisȱ contextȱ wereȱ called,ȱ theyȱ mayȱ failȱ inȱ
unexpectedȱways,ȱpossiblyȱcausingȱanotherȱsignalȱcoȱoccur.ȱ
CAUTION!
Theȱ accessȱ restrictionsȱ defineȱ theȱ minimalȱ functionalityȱ thatȱ isȱ guaranteedȱ toȱ
workȱinȱtheȱsignalȱhandler.ȱTheȱtype sig_atomic_tȱdefinesȱaȱdataȱtypeȱthatȱtheȱCPUȱ
canȱaccessȱatomically,ȱthatȱis,ȱasȱaȱsingleȱunit.ȱForȱexample,ȱaȱ16Ȭbitȱmachineȱcanȱaccessȱ
aȱ 16Ȭbitȱ integerȱ atomicallyȱ butȱ mayȱ needȱ twoȱ operationsȱ toȱ accessȱ aȱ 32Ȭbitȱ integer.ȱȱ
Restrictingȱdataȱaccessȱinȱtheȱsignalȱhandlerȱtoȱatomicȱunitsȱeliminatesȱtheȱpossibilityȱ
ofȱinconsistentȱresultsȱifȱanotherȱsignalȱoccursȱinȱtheȱmiddleȱofȱtheȱstepsȱthatȱaccessȱaȱ
nonatomicȱvariable.ȱ
ȱ
TheȱStandardȱstatesȱthatȱaȱsignalȱhandlerȱmayȱterminateȱtheȱprogramȱbyȱcallingȱ exit.ȱȱ
Aȱhandlerȱforȱanyȱsignal,ȱexceptȱ SIGABRT,ȱmayȱalsoȱterminateȱtheȱprogramȱbyȱcallingȱ
abort.ȱ Howeverȱ bothȱ ofȱ theseȱ areȱ libraryȱ functions,ȱ soȱ theyȱ mayȱ notȱ workȱ properlyȱ
whenȱ calledȱ fromȱ handlersȱ ofȱ asynchronousȱ signals.ȱ Ifȱ youȱ mustȱ terminateȱ theȱ
programȱ inȱ thisȱ way,ȱ beȱ awareȱ thatȱ thereȱ isȱ aȱ remoteȱ chanceȱ thatȱ ifȱ mayȱ fail.ȱ Ifȱ itȱ
occurs,ȱaȱfailureȱmayȱdestroyȱdataȱorȱexhibitȱbizarreȱsymptoms,ȱbutȱtheȱprogramȱwillȱ
eventuallyȱterminate.ȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
ȱAnȱimplementationȱmayȱchooseȱtoȱȈblockȈȱtheȱsignalȱwhileȱtheȱhandlerȱisȱbeingȱexecutedȱinsteadȱofȱreinstatingȱtheȱdefaultȱ
action.ȱConsultȱyourȱsystemȇsȱdocumentation.ȱ
51
Download at http://www.pin5i.com/
16.5 Signalsȱ
473
Volatile Data
ȱ
Aȱ signalȱ mayȱ occurȱ atȱ anyȱ time,ȱ soȱ theȱ valuesȱ ofȱ variablesȱ thatȱ areȱ modifiedȱ byȱ theȱ
signalȱ handlerȱ mayȱ changeȱ atȱ anyȱ time.ȱ Becauseȱ ofȱ this,ȱ youȱ cannotȱ countȱ onȱ theseȱ
variablesȱ havingȱ theȱ sameȱ valuesȱ fromȱ oneȱ programȱ statementȱ toȱ theȱ next.ȱ Theȱ
volatileȱ keywordȱ informsȱ theȱ compilerȱ ofȱ thisȱ fact,ȱ whichȱ preventsȱ itȱ fromȱ
ȈoptimizingȈȱ theȱ programȱ inȱ aȱ wayȱ thatȱ mayȱ changeȱ itsȱ meaning.ȱ Considerȱ thisȱ
programȱfragment:ȱ
ȱ
if( value ){
printf(
}
else {
printf(
}
if( value ){
printf(
}
else {
printf(
}
"True\n" );
"False\n" );
"True\n" );
"False\n" );
ȱ
Ordinarily,ȱyouȱwouldȱexpectȱtheȱsecondȱtestȱtoȱhaveȱtheȱsameȱresultȱasȱtheȱfirst.ȱIfȱaȱ
signalȱhandlerȱchangesȱthisȱvariable,ȱthenȱtheȱsecondȱtestȱmayȱbeȱdifferent.ȱUnlessȱtheȱ
variableȱ wereȱ declaredȱ volatile,ȱ theȱ compilerȱ mightȱ ȈoptimizeȈȱ theȱ programȱ byȱ
substitutingȱtheȱfollowingȱcode,ȱwhichȱisȱordinarilyȱequivalent:ȱ
ȱ
if( value ){
printf(
printf(
}
else {
printf(
printf(
}
"True\n" );
"True\n" );
"False\n" );
"False\n" );
ȱ
ȱ
ȱ
Returning From a Handler
ȱ
Returningȱfromȱaȱsignalȱhandlerȱcausesȱtheȱexecutionȱofȱtheȱprogramȱtoȱresumeȱfromȱ
theȱpointȱ whereȱtheȱ signalȱoccurred.ȱ Anȱ exceptionȱ toȱ thisȱ ruleȱ isȱ SIGFPE.ȱBecauseȱ theȱ
computationȱcannotȱbeȱcompleted,ȱtheȱeffectȱofȱreturningȱfromȱthisȱsignalȱisȱundefined.ȱ
Download at http://www.pin5i.com/
Chapter 16 Standard Libraryȱ
474ȱ
CAUTION!
TIP
Ifȱyouȱwishȱtoȱcatchȱfutureȱsignalsȱofȱtheȱtypeȱthatȱoccurred,ȱbeȱsureȱtoȱcallȱ signalȱtoȱ
reinstallȱtheȱhandlerȱbeforeȱreturningȱfromȱtheȱhandler.ȱOtherwise,ȱonlyȱtheȱfirstȱsignalȱ
willȱbeȱcaught.ȱTheȱnextȱsignalȱwillȱbeȱprocessedȱwithȱtheȱdefaultȱaction.ȱ
ȱ
Becauseȱofȱtheȱdifferencesȱinȱhowȱvariousȱcomputersȱreactȱtoȱunanticipatedȱerrors,ȱtheȱ
specificationȱ ofȱ theȱ signalȱ mechanismȱ isȱ somewhatȱ loose.ȱ Forȱ example,ȱ
implementationsȱneedȱnotȱuseȱanyȱorȱallȱofȱtheȱsignalsȱdefined,ȱandȱtheȱdefaultȱactionȱ
forȱaȱsignalȱmayȱorȱmayȱnotȱbeȱreinstatedȱbeforeȱcallingȱitsȱhandler.ȱOnȱtheȱotherȱhand,ȱ
theȱsevereȱlimitationsȱimposedȱonȱsignalȱhandlingȱfunctionsȱreflectsȱtheȱintersectionȱofȱ
theȱrestrictionsȱimposedȱbyȱdifferentȱhardwareȱandȱsoftwareȱenvironments.ȱ
Theȱ resultȱ ofȱ theseȱ restrictionsȱ andȱ implementationȱ dependenciesȱ isȱ thatȱ
programsȱ thatȱ handleȱ signalsȱ areȱ lessȱ portableȱ thanȱ thoseȱ thatȱ doȱ not.ȱ Usingȱ signalsȱ
onlyȱ whereȱ necessaryȱ andȱ notȱ violatingȱ theȱ rulesȱ inȱ signalȱ handlingȱ functionsȱ (evenȱ
thoughȱ itȱ mayȱ appearȱ toȱ workȱ onȱ oneȱ machine)ȱ helpȱ minimizeȱ theȱ portabilityȱ
problemsȱinherentȱinȱthisȱtypeȱofȱprogram.ȱ
ȱ
ȱ
ȱ
16.6 Printing Variable Argument Lists <stdarg.h>
ȱ
Theȱ functionsȱ inȱ thisȱ groupȱ areȱ usedȱ whenȱ variableȱ argumentȱ listsȱ mustȱ beȱ printed.ȱȱ
Note:ȱTheyȱrequireȱinclusionȱofȱbothȱtheȱstdio.hȱandȱstdarg.hȱheaderȱfiles.ȱ
ȱ
int vprintf( char const *format, va_list arg );
int vfprintf( FILE *stream, char const *format, va_list arg );
int vsprintf( char *buffer, char const *format, va_list arg );
ȱ
Theseȱ functionsȱ areȱ equivalentȱ toȱ theirȱ standardȱ counterpartsȱ exceptȱ thatȱ aȱ variableȱ
argumentȱlistȱisȱusedȱ(seeȱChapterȱ7ȱforȱdetailsȱonȱvariableȱargumentȱlists).ȱargȱmustȱbeȱ
initializedȱusingȱ va_startȱbeforeȱtheȱfunctionsȱareȱcalled,ȱandȱnoneȱofȱtheseȱfunctionsȱ
callȱva_end.ȱ
ȱ
ȱ
ȱ
16.7 Execution Environment
ȱ
Theseȱfunctionsȱcommunicateȱwithȱorȱaffectȱtheȱprogramȇsȱexecutionȱenvironment.ȱ
ȱ
ȱ
ȱ
16.7.1
ȱ
Terminating Execution <stdlib.h>
Download at http://www.pin5i.com/
16.7 Execution Environment
475
ȱ
Theseȱthreeȱfunctionsȱrelateȱtoȱnormalȱandȱabnormalȱprogramȱtermination.ȱ
ȱ
void abort( void )
void atexit( void (func)( void ) );
void exit( int status );
ȱ
abortȱ isȱ calledȱ toȱ terminateȱ theȱ executionȱ ofȱ aȱ programȱ abnormally.ȱ Becauseȱ theȱ
functionȱraisesȱtheȱ SIGABRTȱsignalȱtoȱaccomplishȱthisȱresult,ȱtheȱprogramȱcanȱinstallȱaȱ
signalȱhandlerȱtoȱperformȱanyȱdesiredȱactionȱpriorȱtoȱ(orȱinsteadȱof)ȱaborting.ȱ
atexitȱ registersȱ functionsȱ asȱ exitȱ functions.ȱ Exitȱ functionsȱ areȱ calledȱ whenȱ theȱ
programȱisȱaboutȱtoȱterminateȱnormally,ȱeitherȱbecauseȱexitȱwasȱcalledȱorȱbecauseȱtheȱ
mainȱfunctionȱhasȱreturned.ȱAnȱexitȱfunctionȱmayȱnotȱtakeȱanyȱarguments.ȱ
exit,ȱ whichȱ wasȱ describedȱ inȱ Chapterȱ 15,ȱ isȱ calledȱ toȱ terminateȱ theȱ programȱ
normally.ȱIfȱtheȱinitialȱinvocationȱofȱtheȱ mainȱfunctionȱreturnsȱaȱvalue,ȱtheȱeffectȱisȱtheȱ
sameȱasȱifȱexitȱhadȱbeenȱcalledȱwithȱthatȱvalueȱasȱitsȱargument.ȱ
CAUTION!
Whenȱexitȱisȱcalled,ȱallȱofȱtheȱexitȱfunctionsȱregisteredȱwithȱ atexitȱareȱcalledȱinȱ
theȱ reverseȱ orderȱ thatȱ theyȱ wereȱ registered.ȱ Then,ȱ theȱ buffersȱ areȱ flushedȱ forȱ allȱ
streamsȱ thatȱ needȱ it,ȱ andȱ allȱ openȱ filesȱ areȱ closed.ȱ Filesȱ createdȱ withȱ tmpfileȱ areȱ
removed.ȱ Theȱ exitȱ statusȱ isȱ thenȱ returnedȱ toȱ theȱ hostȱ environmentȱ andȱ theȱ programȱ
ceasesȱtoȱexecute.ȱ
ȱ
Becauseȱexecutionȱceases,ȱtheȱexitȱfunctionȱneverȱreturnsȱtoȱitsȱcaller.ȱHowever,ȱifȱoneȱ
ofȱ theȱ functionsȱ registeredȱ withȱ atexitȱ makesȱ anotherȱ callȱ toȱ exit,ȱ theȱ effectȱ isȱ
undefined.ȱThisȱerrorȱmayȱresultȱinȱanȱinfiniteȱloop,ȱpossiblyȱstoppingȱwhenȱthereȱisnȇtȱ
anyȱmoreȱmemoryȱforȱtheȱstack.ȱ
ȱ
ȱ
ȱ
16.7.2
Assertions <assert.h>
ȱ
Anȱassertionȱisȱaȱdeclarationȱofȱsomethingȱthatȱshouldȱbeȱtrue.ȱANSIȱCȱimplementsȱanȱ
aessertȱ macroȱ thatȱ isȱ usefulȱ whenȱ debuggingȱ programs.ȱ Itsȱ prototypeȱ isȱ shownȱ
below. 52
ȱ
void assert( int expression );
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
ȱBecauseȱitȱisȱaȱmacroȱratherȱthanȱaȱfunction,ȱassert doesnȇtȱactuallyȱhaveȱaȱprototype.ȱȱHowever,ȱtheȱprototypeȱshownȱ
illustratesȱhowȱassertȱisȱused.ȱ
52
Download at http://www.pin5i.com/
476ȱ
Chapter 16 Standard Libraryȱ
Whenȱ executed,ȱ theȱ macroȱ testsȱ theȱ expressionȱ argument.ȱ Ifȱ itȱ isȱ falseȱ (zero),ȱ thenȱ aȱ
diagnosticȱmessageȱisȱprintedȱtoȱtheȱstandardȱerrorȱandȱtheȱprogramȱterminates.ȱTheȱ
formatȱ ofȱ thisȱ messageȱ isȱ implementationȱ defined,ȱ butȱ itȱ willȱ includeȱ theȱ expressionȱ
andȱtheȱnameȱofȱtheȱsourceȱfileȱandȱtheȱlineȱnumberȱofȱtheȱassertion.ȱIfȱtheȱexpressionȱ
isȱtrueȱ(nonzero),ȱnothingȱisȱprinted.ȱ
Thisȱmacroȱprovidesȱaȱconvenientȱwayȱtoȱcheckȱforȱthingsȱthatȱoughtȱtoȱbeȱtrue.ȱȱ
Forȱexample,ȱaȱfunctionȱthatȱisȱcalledȱwithȱaȱpointerȱargumentȱthatȱmustȱnotȱbeȱNULLȱ
couldȱverifyȱtheȱvalueȱwithȱanȱassertion:ȱ
ȱ
assert( value != NULL );
ȱ
IfȱtheȱfunctionȱisȱmistakenlyȱcalledȱwithȱaȱNULLȱargument,ȱtheȱprogramȱwillȱprintȱaȱ
messageȱthatȱlooksȱsomethingȱlikeȱthis:ȱ
ȱ
Assertion failed: value != NULL, file list.c, line 274
TIP
ȱ
ȱ
Usingȱ assertionsȱ inȱ thisȱ wayȱ makesȱ debuggingȱ easierȱ becauseȱ theȱ programȱ stopsȱ asȱ
soonȱ asȱ anȱ errorȱ isȱ detected.ȱ Furthermore,ȱ theȱ messageȱ indicatesȱ exactlyȱ whereȱ theȱ
symptomȱ appeared.ȱWithoutȱanȱassertion,ȱtheȱprogramȱmayȱcontinueȱtoȱ runȱ andȱfailȱ
later,ȱmakingȱitȱharderȱtoȱdebug.ȱ
Noteȱthatȱassertȱisȱonlyȱappropriateȱforȱverifyingȱexpressionsȱthatȱmustȱbeȱtrue.ȱ
Youȱ cannotȱ useȱ itȱ toȱ checkȱ forȱ conditionsȱ thatȱ youȱ areȱ tryingȱ toȱ handle,ȱ suchȱ asȱ
detectingȱillegalȱinputȱandȱaskingȱtheȱuserȱforȱanotherȱvalue,ȱbecauseȱitȱterminatesȱtheȱ
program.ȱ
Whenȱ theȱ programȱ isȱ thoroughlyȱ tested,ȱ youȱ canȱ eliminateȱ theȱ assertionsȱ byȱ
definingȱ theȱ nameȱ NDEBUGȱ whenȱ compilingȱ theȱ program. 53 ȱ Youȱ canȱ useȱ theȱ –DNDEBUGȱ
compilerȱcommandȱlineȱoptionȱorȱaddȱ
ȱ
#define NDEBUG
ȱ
toȱ theȱ sourceȱ fileȱ priorȱ toȱ whereȱ assert.hȱ isȱ included.ȱ Withȱ NDEBUGȱ defined,ȱ theȱ
preprocessorȱdiscardsȱtheȱassertions,ȱthusȱeliminatingȱtheirȱoverheadȱwithoutȱhavingȱ
toȱphysicallyȱdeleteȱthemȱfromȱtheȱsourceȱcode.ȱ
ȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
53
ȱAnyȱvalueȱmayȱbeȱused;ȱallȱthatȱmattersȱisȱwhetherȱNDEBUGȱisȱdefinedȱorȱnot.ȱ
Download at http://www.pin5i.com/
16.8 Sorting and Searching <stdlib.h>
16.7.3
477
The Environment <stdlib.h>
ȱ
TheȱenvironmentȱisȱanȱimplementationȬdefinedȱlistȱofȱname/valueȱpairsȱmaintainedȱbyȱ
theȱoperatingȱsystem.ȱTheȱ getenvȱfunctionȱsearchesȱthisȱlistȱforȱaȱspecificȱnameȱand,ȱifȱ
found,ȱ returnsȱ aȱ pointerȱ toȱ itsȱ value.ȱ Theȱ programȱ mustȱ notȱ modifyȱ theȱ returnedȱ
string.ȱIfȱtheȱnameȱisȱnotȱfound,ȱaȱNULLȱpointerȱisȱreturnedȱinstead.ȱ
ȱ
char *getenv( char const *name );
ȱ
Noteȱthatȱtheȱstandardȱdoesȱnotȱdefineȱaȱcorrespondingȱ putenvȱfunction.ȱSomeȱ
implementationsȱprovideȱ oneȱanyway,ȱbutȱ youȱshouldȱavoidȱ usingȱitȱifȱ portabilityȱ isȱ
anȱissue.ȱ
ȱ
ȱ
ȱ
16.7.4
Executing System Commands <stdlib.h>
ȱ
Theȱ systemȱfunctionȱpassesȱitsȱstringȱargumentȱtoȱtheȱhostȱenvironmentȱsoȱthatȱitȱcanȱ
beȱexecutedȱasȱaȱcommandȱbyȱtheȱsystemȇsȱcommandȱprocessor.ȱ
ȱ
void system( char const *command );
ȱ
Theȱexactȱmannerȱinȱwhichȱthisȱtaskȱisȱperformedȱisȱimplementationȱdependent,ȱ
asȱ isȱ theȱ valueȱ returnedȱ byȱ system.ȱ However,ȱ systemȱ mayȱ beȱ calledȱ withȱ aȱ NULLȱ
argumentȱtoȱinquireȱwhetherȱaȱcommandȱprocessorȱactuallyȱexists.ȱȱInȱthisȱcase,ȱsystemȱ
returnsȱaȱnonzeroȱvalueȱifȱaȱcommandȱprocessorȱisȱavailable,ȱotherwiseȱitȱreturnsȱzero.ȱ
ȱ
ȱ
ȱ
16.8 Sorting and Searching <stdlib.h>
ȱ
Theȱ qsortȱfunctionȱsortsȱdataȱinȱanȱarrayȱintoȱascendingȱorder.ȱBecauseȱitȱisȱtypeless,ȱ
youȱ canȱ useȱ qsortȱ toȱ sortȱ anyȱ typeȱ ofȱ data,ȱ asȱ longȱ asȱ theȱ elementsȱ ofȱ theȱ arrayȱ areȱ
fixedȱsize.ȱ
ȱ
void qsort( void *base, size_t n_elements, size_t el_size,
int (*compare)( void const *, void const * ) );
ȱ
Theȱ firstȱ argumentȱ pointsȱ toȱ theȱ arrayȱ toȱ beȱ sorted,ȱ theȱ secondȱ indicatesȱ howȱ manyȱ
elementsȱareȱinȱtheȱarray,ȱandȱtheȱthirdȱisȱtheȱsizeȱfinȱcharacters)ȱofȱeachȱelement.ȱTheȱ
fourthȱ argumentȱ isȱ aȱ pointerȱ toȱ aȱ functionȱ thatȱ comparesȱ elementsȱ ofȱ theȱ typeȱ beingȱ
sorted.ȱȱȱqsortȱcallsȱthisȱfunctionȱtoȱcompareȱtheȱdataȱinȱtheȱarrayȱwhenȱsortingȱit.ȱByȱȱ
Download at http://www.pin5i.com/
Chapter 16 Standard Libraryȱ
478ȱ
ȱ
ȱ
/*
** Demonstrates sorting an array of structures with qsort
*/
#include <stdlib.h>
#include <string.h>
typedef
char
int
} Record;
struct
{
key[ 10 ]; /* the sort key for the array */
other_data; /* data associated with the key */
/*
** Comparison function: compares only the key value.
*/
int r_compare( void const *a, void const *b ){
return strcmp( ((Record *)a)->key, ((Record *)b)->key );
}
int
main()
{
Record
array[ 50 ];
/*
** Code that fills the array with 50 elements.
*/
qsort( array, 50, sizeof( Record ), r_compare );
/*
** Array is now sorted by the key field of the structures.
*/
return EXIT_SUCCESS;
}
ȱ
Programȱ16.3ȱȱSortingȱanȱarrayȱwithȱqsortȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱȱȱqsort.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
passingȱaȱpointerȱtoȱanȱappropriateȱcomparisonȱfunction,ȱyouȱcanȱuseȱ qsortȱtoȱsonȱanȱ
arrayȱofȱanyȱtypeȱofȱvalues.ȱ
Theȱ comparisonȱ functionȱ takesȱ twoȱ arguments,ȱ whichȱ areȱ pointersȱ toȱ twoȱ
valuesȱ toȱ beȱ compared.ȱ Theȱ functionȱ shouldȱ returnȱ anȱ integerȱ lessȱ than,ȱ equalȱ to,ȱ orȱ
greaterȱthanȱzeroȱaccordingȱtoȱwhetherȱtheȱfirstȱvalueȱisȱlessȱthan,ȱequalȱto,ȱorȱgreaterȱ
thanȱtheȱsecond,ȱrespectively.ȱ
Download at http://www.pin5i.com/
16.8 Sorting and Searching <stdlib.h>
479
Becauseȱ ofȱ theȱ typelessȱ natureȱ ofȱ thisȱ function,ȱ theȱ argumentsȱ areȱ declaredȱ asȱ
void *.ȱCastsȱmustȱbeȱusedȱinȱtheȱcomparisonȱfunctionȱtoȱconvertȱthemȱtoȱpointersȱofȱ
theȱproperȱtype.ȱProgramȱ16.3ȱillustratesȱhowȱanȱarrayȱofȱstructuresȱcontainingȱaȱkeyȱ
valueȱandȱsomeȱadditionalȱdataȱwouldȱbeȱsorted.ȱ
Theȱ bsearchȱfunctionȱperformsȱaȱbinaryȱsearchȱtoȱlocateȱaȱspecificȱelementȱinȱaȱ
sortedȱarray.ȱTheȱresultȱisȱundefinedȱifȱtheȱarrayȱisȱnotȱsorted.ȱ
ȱ
void *bsearch( void const *key, void const *base, size_t n_elements,
size_t el_size, int (*compare)( void const *, void const * ) );
ȱ
Theȱfirstȱargumentȱpointsȱtoȱtheȱvalueȱyouȱwantȱtoȱfind,ȱtheȱsecondȱpointsȱtoȱtheȱ
arrayȱtoȱbeȱsearched,ȱtheȱthirdȱindicatesȱtheȱnumberȱofȱelementsȱinȱtheȱarray,ȱandȱtheȱ
fourthȱisȱtheȱsizeȱ(inȱcharacters)ȱofȱeachȱelement.ȱȱTheȱfinalȱargumentȱisȱaȱpointerȱtoȱaȱ
comparisonȱ functionȱ asȱ weȱ describedȱ forȱ qsort.ȱ bsearchȱ returnsȱ aȱ pointerȱ toȱ theȱ
desiredȱarrayȱelement.ȱȱIfȱtheȱdesiredȱvalueȱdoesȱnotȱexist,ȱNULLȱisȱreturned.ȱ
Noteȱ thatȱ theȱ keyȱ argumentȱ mustȱ beȱ theȱ sameȱ typeȱ ofȱ valueȱ asȱ theȱ arrayȱ
elements.ȱ Ifȱ theȱ arrayȱ containsȱ structuresȱ thatȱ haveȱ aȱ keyȱ fieldȱ andȱ someȱ otherȱ data,ȱ
youȱmustȱcreateȱanȱentireȱstructureȱandȱfillȱinȱtheȱkeyȱfield.ȱTheȱotherȱfieldsȱcanȱbeȱleftȱ
empty,ȱ becauseȱtheȱ comparisonȱfunctionȱwillȱexamineȱ onlyȱ theȱ keyȱ field.ȱ Thisȱ useȱofȱ
bsearchȱisȱillustratedȱinȱProgramȱ16.4.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Demonstrates searching an array of structures with bsearch
*/
#include <stdlib.h>
#include <string.h>
typedef
char
int
} Record;
struct
{
key[ 10 ]; /* the sort key for the array */
other_data; /* data associated with the key */
/*
** Comparison function: compares only the key value.
*/
int r_compare( void const *a, void const *b ){
return strcmp( ((Record *)a)->key, ((Record *)b)->key );
}
ȱ
Programȱ16.4ȱȱSearchingȱanȱarrayȱwithȱbsearchȱȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱcontinue...ȱ
Download at http://www.pin5i.com/
480ȱ
Chapter 16 Standard Libraryȱ
ȱ
int
main()
{
Record
Record
Record
array[ 50 ];
key;
*ans;
/*
** Code that fills the array with 50 elements and sorts it
*/
/*
** Create a key record (only the key field filled in with the
** value we want to locate) and search the array.
*/
strcpy( key.key, "value" );
ans = bsearch( &key, array, 50, sizeof( Record ),
r_compare );
/*
** ans now points to the array element whose key field
** matches the value, or NULL if none matched.
*/
return EXIT_SUCCESS;
}
ȱ
Programȱ16.4ȱȱSearchingȱanȱarrayȱwithȱbsearchȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱbsearch.cȱ
16.9 Locales
ȱ
InȱanȱeffortȱtoȱmakeȱCȱmoreȱusefulȱworldwide,ȱtheȱStandardȱdefinesȱaȱlocale,ȱwhichȱisȱaȱ
particularȱsetȱofȱparametersȱforȱthingsȱthatȱvaryȱfromȱcountryȱtoȱcountry.ȱTheȱdefaultȱ
isȱ theȱ ȈCȈȱ locale,ȱ andȱ otherȱ localesȱ mayȱ beȱ definedȱ byȱ theȱ implementation.ȱ Changingȱ
theȱ localeȱ mayȱ affectȱ howȱ otherȱ libraryȱ functionsȱ work.ȱ Theȱ effectsȱ ofȱ changingȱ theȱ
localeȱareȱdescribedȱatȱtheȱendȱofȱthisȱsection.ȱ
Theȱ setlocaleȱ function,ȱ whoseȱ prototypeȱ isȱ shownȱ below,ȱ isȱ usedȱ toȱ changeȱ
eitherȱtheȱentireȱlocaleȱorȱaȱportionȱofȱit.ȱ
ȱ
char *setlocale( int category, char const *locale );
ȱ
Theȱ categoryȱ argumentȱ specifiesȱ whichȱ portionȱ ofȱ theȱ localeȱ toȱ change.ȱ Theȱ
permissibleȱvaluesȱareȱlistedȱinȱTableȱ16.5.ȱ
Download at http://www.pin5i.com/
16.9 Locales
481
Ifȱ theȱ secondȱ argumentȱ toȱ setlocaleȱ isȱ NULL,ȱ theȱ functionȱ returnsȱ aȱ pointerȱ toȱ
theȱ nameȱ ofȱ theȱ currentȱ localeȱ forȱ theȱ givenȱ category.ȱ Thisȱ valueȱ mayȱ beȱ savedȱ andȱ
usedȱ inȱ aȱ subsequentȱ callȱ toȱ setȱ localeȱ toȱ restoreȱ aȱ previousȱ locale.ȱ Ifȱ theȱ secondȱ
argumentȱ isȱ notȱ NULL,ȱ itȱ specifiesȱ theȱ nameȱ ofȱ theȱ newȱ localeȱ toȱ use.ȱ Ifȱ theȱ callȱ isȱ
successful,ȱtheȱfunctionȱreturnsȱtheȱnameȱofȱtheȱnewȱlocale,ȱotherwiseȱNULLȱisȱreturnedȱ
andȱtheȱlocaleȱisȱnotȱaffected.ȱ
ȱ
ȱ
ȱ
16.9.1
Numeric and Monetary Formatting <locale.h>
ȱ
Theȱrulesȱforȱformattingȱnumericȱandȱmonetaryȱvaluesȱdifferȱfromȱplaceȱtoȱplaceȱinȱtheȱ
world.ȱ Forȱ example,ȱ aȱ numberȱ thatȱ wouldȱ beȱ writtenȱ 1,234.56ȱ inȱ theȱ Unitedȱ Statesȱ
wouldȱ beȱ writtenȱ 1.234,56ȱ inȱ manyȱ Europeanȱ countries.ȱ Theȱ localeconvȱ functionȱ
obtainsȱ theȱ informationȱ neededȱ toȱ properlyȱ formatȱ bothȱ nonmonetaryȱ andȱ monetaryȱ
valuesȱ accordingȱ toȱ theȱ currentȱ locale.ȱ Noteȱ thatȱ thisȱ functionȱ doesȱ notȱ actuallyȱ
performȱtheȱformatting;ȱitȱsimplyȱprovidesȱinformationȱaboutȱhowȱitȱshouldȱbeȱdone.ȱ
ȱ
struct lconv *localeconv( void );
ȱ
Theȱ lconvȱ structureȱ containsȱ twoȱ typesȱ ofȱ parameters:ȱ charactersȱ andȱ characterȱ
pointers.ȱȱTheȱcharacterȱparametersȱhaveȱnonnegativeȱvalues.ȱȱIfȱaȱcharacterȱparameterȱ
isȱ CHAR_MAX,ȱ thenȱ thatȱ valueȱ isȱ notȱ availableȱ (orȱ notȱ used)ȱ inȱ theȱ currentȱ locale.ȱ Aȱ
pointerȱ toȱ anȱ emptyȱ stringȱ indicatesȱ theȱ sameȱ thingȱ forȱ theȱ characterȱ pointerȱ
parameters.ȱ
ȱ
ȱ
ȱ
Value
Changes
LC_ALL
Theȱentireȱlocale.ȱ
LC_COLLATE
Theȱcollatingȱsequence,ȱwhichȱaffectsȱtheȱbehaviorȱofȱtheȱ strcollȱandȱ
strxfrm functionsȱ(seeȱbelow).ȱ
LC_CTYPE
Theȱ characterȱ typeȱ classificationsȱ usedȱ byȱ theȱ functionsȱ definedȱ inȱ
ctype.h.ȱ
LC_MONETARY
Theȱcharactersȱtoȱbeȱusedȱwhenȱformattingȱmonetaryȱvalues.ȱ
LC_NUMERIC
Theȱ charactersȱ toȱ beȱ usedȱ whenȱ formattingȱ nonmonetaryȱ values.ȱ Alsoȱ
changesȱ theȱ decimalȱ pointȱ characterȱ usedȱ byȱ theȱ formattedȱ
input/outputȱfunctionsȱandȱstringȱconversionȱfunctions.ȱ
LC_TIME
Theȱbehaviorȱofȱtheȱstrftimeȱfunction.ȱ
ȱ
Tableȱ16.5ȱȱsetlocaleȱcategoriesȱ
Download at http://www.pin5i.com/
482ȱ
Chapter 16 Standard Libraryȱ
ȱ
Field and Type
Meaning
char *decimal_point:
Theȱcharacterȱtoȱuseȱasȱaȱdecimalȱpoint.ȱThisȱvalueȱwillȱ
neverȱbeȱanȱemptyȱstring.ȱ
char *thousands_sep
Theȱcharacterȱusedȱtoȱseparateȱgroupsȱofȱdigitsȱthatȱ
appearȱtoȱtheȱleftȱofȱtheȱdecimalȱpoint.ȱ
char *grouping
Specifiesȱhowȱmanyȱdigitsȱareȱinȱeachȱdigitȱgroupȱtoȱtheȱ
leftȱofȱtheȱdecimalȱpoint.ȱ
ȱ
Tableȱ16.6ȱȱParametersȱforȱformattingȱnonmonetaryȱnumericȱvaluesȱ
ȱ
ȱ
ȱ
Numeric Formatting
ȱ
TheȱparametersȱlistedȱinȱTableȱ16.6ȱareȱusedȱwhenȱformattingȱnumericȱquantitiesȱthatȱ
areȱnotȱmonetary.ȱTheȱ groupingȱstringȱisȱinterpretedȱasȱfollows.ȱTheȱfirstȱvalueȱinȱtheȱ
stringȱ specifiesȱ howȱ manyȱ digitsȱ appearȱ inȱ theȱ firstȱ groupȱ toȱ theȱ leftȱ ofȱ theȱ decimalȱ
point.ȱ Theȱ nextȱ valueȱ inȱ theȱ stringȱ correspondsȱ toȱ theȱ nextȱ groupȱ toȱ theȱ left,ȱ andȱ soȱ
forth.ȱ Twoȱ valuesȱ haveȱ specialȱ significance:ȱ CHAR_MAXȱ indicatesȱ thatȱ theȱ remainingȱ
digitsȱareȱnotȱbrokenȱintoȱgroups,ȱandȱ0ȱindicatesȱthatȱtheȱprecedingȱvalueȱappliesȱtoȱ
allȱremainingȱgroupsȱinȱtheȱnumber.ȱ
TypicalȱNorthȱAmericanȱformattingȱisȱindicatedȱwithȱtheȱparametersȱ
ȱ
decimal_point="."
thousands_sep=","
grouping="\3"
ȱ
Theȱgroupingȱstringȱcontainsȱaȱthreeȱfollowedȱbyȱaȱzeroȱ(theȱterminatingȱNULȱbyte). 54 ȱ
Theseȱ valuesȱ meanȱ thatȱ theȱ firstȱ groupȱ toȱ theȱ leftȱ ofȱ theȱ decimalȱ pointȱ willȱ containȱ
threeȱ digits,ȱ andȱ allȱ theȱ remainingȱ groupsȱ willȱ alsoȱ containȱ threeȱ digits.ȱ Theȱ valueȱ
1234567.89ȱ wouldȱ appearȱ asȱ 1,234,567.89ȱ whenȱ formattedȱ accordingȱ toȱ theseȱ
parameters.ȱ
Hereȱisȱanotherȱexample.ȱ
ȱ
grouping="\4\3"
thousands_sep="-"
ȱ
Theseȱ valuesȱ expressȱ theȱ rulesȱ forȱ formattingȱ telephoneȱ numbersȱ inȱ Northȱ America.ȱ
Theȱ valueȱ 2125551234ȱ wouldȱ beȱ formattedȱ asȱ 212-555-1234ȱ accordingȱ toȱ theseȱ
parameters.ȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
54
ȱNoteȱthatȱthisȱnumberȱisȱaȱbinaryȱthree,ȱnotȱtheȱcharacterȱthree!ȱ
Download at http://www.pin5i.com/
16.9 Locales
483
Monetary Formatting
ȱ
Theȱ rulesȱ forȱ formattingȱ monetaryȱ valuesȱ areȱ muchȱ moreȱ complexȱ dueȱ toȱ theȱ manyȱ
differentȱ waysȱ ofȱ indicatingȱ positiveȱ andȱ negativeȱ values,ȱ positioningȱ theȱ currencyȱ
symbolȱ relativeȱ toȱ theȱ value,ȱ andȱ soȱ forth.ȱ Inȱ addition,ȱ theȱ rulesȱ changeȱ whenȱ
formattingȱ aȱ monetaryȱ valueȱ forȱ internationalȱ publication.ȱ Weȱ beginȱ withȱ theȱ
parametersȱusedȱwhenȱformattingȱlocalȱ(notȱinternational)ȱmonetaryȱquantities,ȱshownȱ
inȱTableȱ16.7.ȱ
Whenȱ formattingȱ monetaryȱ valuesȱ forȱ internationalȱ use,ȱ theȱ stringȱ
int_curr_symbolȱ isȱ usedȱ insteadȱ ofȱ currency_symbol,ȱ andȱ theȱ characterȱ
int_frac_digitsȱisȱusedȱinsteadȱofȱfrac_digits.ȱȱInternationalȱcurrencyȱsymbolsȱareȱ
ȱ
ȱ
ȱ
ȱ
Field and Type
Meaning
char *currency_symbol
Theȱlocalȱcurrencyȱsymbol.ȱ
char *mon_decimal_point Theȱdecimalȱpointȱcharacter.ȱ
char *mon_thousands_sep Theȱcharacterȱusedȱtoȱseparateȱdigitȱgroupsȱthatȱappearȱtoȱtheȱleftȱofȱ
theȱdecimalȱpoint.ȱ
char *mon_grouping
Specifiesȱtheȱnumberȱofȱdigitsȱinȱeachȱgroupȱappearingȱtoȱtheȱleftȱofȱtheȱ
decimalȱpointȱ
char *positive_sign
Theȱstringȱusedȱtoȱindicateȱaȱnonnegativeȱamount.ȱ
char *negative_sign
Theȱstringȱusedȱtoȱindicateȱaȱnegativeȱamount.ȱ
char frac_digits
Theȱnumberȱofȱdigitsȱappearingȱtoȱtheȱrightȱofȱtheȱdecimalȱpoint.ȱ
char p_cs_precedes
1ȱifȱtheȱcurrency_symbolȱprecedesȱaȱnonnegativeȱvalue;ȱ0ȱIfȱitȱfollows.
char n_cs_precedes
1ȱifȱtheȱcurrency_symbolȱprecedesȱaȱnegativeȱvalue;ȱ0ȱifȱitȱfollows.ȱ
char p_sep_by_space
1ȱifȱtheȱcurrency_symbolȱisȱseparatedȱbyȱaȱspaceȱfromȱaȱnonnegativeȱ
value;ȱelseȱ0.ȱ
char n_sep_by_space
1ȱifȱtheȱcurrency_symbolȱisȱseparatedȱbyȱaȱspaceȱfromȱaȱnegativeȱ
value;ȱelseȱ0.ȱ
char p_sign_posn
Indicatesȱwhereȱtheȱpositive_signȱappearsȱinȱaȱnonnegativeȱvalue.ȱ
Theȱfollowingȱvaluesȱareȱallowed:ȱ
0ȱȱȱȱȱȱParenthesesȱsurroundȱtheȱcurrencyȱsymbolȱandȱvalue.ȱ
1ȱȱȱȱȱȱTheȱsignȱprecedesȱtheȱcurrencyȱsymbolȱandȱvalue.ȱ
2ȱȱȱȱȱȱTheȱsignȱfollowsȱtheȱcurrencyȱsymbolȱandȱvalue.ȱ
3ȱȱȱȱȱȱTheȱsignȱImmediatelyȱprecedesȱtheȱcurrencyȱsymbol.ȱ
4ȱȱȱȱȱȱTheȱsignȱimmediatelyȱfollowsȱtheȱcurrencyȱsymbol.ȱ
char n_sign_posn
Indicatesȱwhereȱtheȱnegative_signȱappearsȱinȱaȱnegativeȱvalue.ȱTheȱ
valuesȱusedȱforȱp_sign_posnȱareȱalsoȱusedȱhere.ȱ
ȱ
Tableȱ16.7ȱȱParametersȱforȱformattingȱlocalȱmonetaryȱvaluesȱ
Download at http://www.pin5i.com/
Chapter 16 Standard Libraryȱ
484ȱ
formedȱ inȱ accordanceȱ withȱ theȱ ISOȱ 4217:1987ȱ standard.ȱ Theȱ firstȱ threeȱ charactersȱ ofȱ
thisȱstringȱareȱtheȱalphabeticȱinternationalȱcurrencyȱsymbol,ȱandȱtheȱfourthȱcharacterȱisȱ
usedȱtoȱseparateȱtheȱsymbolȱfromȱtheȱvalue.ȱ
Theȱ followingȱ valuesȱ willȱ formatȱ monetaryȱ valuesȱ inȱ aȱ styleȱ acceptableȱ inȱ theȱ
UnitedȱStates.ȱ
ȱ
currency_symbol="$"
mon_decimal_point="."
mon_thousands_sep=","
mon_grouping="\3"
positive_sign=""
negative_sign="CR"
frac_digits='\2'
p_cs_precedes='\1'
n_cs_precedes='\1'
p_sep_by_space='\0'
n_sep_by_space='\0'
p_sign_posn='\1'
n_sign_posn='\2'
ȱ
Usingȱ theseȱ parameters,ȱ theȱ valuesȱ 1234567890ȱ andȱ Ȭ1234567890ȱ wouldȱ appearȱ asȱ
$1,234,567,890.00ȱandȱ$1,234,567,890,00CRȱrespectively.ȱ
Settingȱ n_sign_posn='\0'ȱ causesȱ theȱ negativeȱ valueȱ aboveȱ toȱ appearȱ asȱ
($1,234,567,890.00).ȱ
ȱ
ȱ
ȱ
16.9.2
Strings and Locales <string.h>
ȱ
Theȱ collatingȱsequenceȱofȱaȱmachineȇsȱ characterȱsetȱ isȱ fixed,ȱyetȱtheȱlocaleȱprovidesȱaȱ
wayȱtoȱspecifyȱalternateȱsequences.ȱWhenȱaȱcollatingȱsequenceȱotherȱthanȱtheȱdefaultȱ
mustȱbeȱused,ȱtheȱfollowingȱtwoȱfunctionsȱareȱprovided.ȱ
ȱ
int strcoll( char const *s1, char const *s2 );
size_t strxfrm( char *s1, char const *s2, size_t size );
ȱ
Theȱ strcollȱ functionȱ comparesȱ theȱ twoȱ stringsȱ asȱ specifiedȱ byȱ theȱ LC_COLLATEȱ
categoryȱofȱtheȱcurrentȱlocale.ȱItȱreturnsȱaȱvalueȱlessȱthan,ȱequalȱto,ȱorȱgreaterȱthanȱzeroȱ
accordingȱtoȱwhetherȱtheȱfirstȱstringȱisȱlessȱthan,ȱequalȱto,ȱorȱgreaterȱthanȱtheȱsecondȱ
string.ȱ
Noteȱ thatȱ thisȱ comparisonȱ mayȱ requireȱ considerablyȱ moreȱ computationȱ thanȱ
strcmpȱ becauseȱ ofȱ theȱ needȱ toȱ obeyȱ aȱ collatingȱ sequenceȱ thatȱ isȱ notȱ nativeȱ toȱ theȱ
machine.ȱ strxfrmȱisȱprovidedȱtoȱreduceȱtheȱcomputationȱrequiredȱwhenȱstringsȱmustȱ
beȱcomparedȱrepeatedlyȱinȱthisȱmanner.ȱItȱconvertsȱitsȱsecondȱargument,ȱinterpretedȱinȱ
theȱcurrentȱlocale,ȱintoȱanotherȱstringȱthatȱisȱnotȱdependentȱonȱtheȱlocale.ȱAlthoughȱtheȱ
contentsȱ ofȱ theȱ convertedȱ stringȱ areȱ indeterminate,ȱ strcmpȱ givesȱ theȱ sameȱ resultȱ
comparingȱ twoȱ stringsȱ convertedȱ inȱ thisȱ mannerȱ asȱ strcollȱproducesȱcomparingȱtheȱ
originalȱstrings.ȱ
Download at http://www.pin5i.com/
16.10 Summary
16.9.3
485
Effects of Changing the Locale
ȱ
Changingȱtheȱlocaleȱhasȱsomeȱeffectsȱinȱadditionȱtoȱthoseȱpreviouslyȱdescribed.ȱ
1. Aȱ locateȱ mayȱ addȱ charactersȱ toȱ (butȱ mayȱ notȱ changeȱ theȱ meaningsȱ ofȱ existingȱ
charactersȱof)ȱtheȱcharacterȱsetȱusedȱwhenȱtheȱprogramȱisȱexecuting.ȱForȱexample,ȱ
manyȱ Europeanȱ languagesȱ makeȱ useȱ ofȱ extendedȱ characterȱ setsȱ thatȱ includeȱ
accents,ȱcurrencyȱsymbols,ȱandȱotherȱspecialȱcharacters.ȱ
2. Theȱ directionȱ ofȱ printingȱ mayȱ change.ȱ Specifically,ȱ theȱ localeȱ determinesȱ whereȱ aȱ
characterȱshouldȱbeȱprintedȱinȱrelationȱtoȱtheȱpreviousȱcharacterȱthatȱwasȱprinted.ȱ
3. Theȱprintfȱandȱscanfȱfamiliesȱofȱfunctionsȱuseȱtheȱdecimalȱpointȱcharacterȱdefinedȱbyȱ
theȱcurrentȱlocale.ȱ
4. Theȱisalpha,ȱislower,ȱisspace,ȱandȱisupperȱfunctionsȱmayȱincludeȱmoreȱcharactersȱ
thanȱpreviouslyȱdescribedȱifȱtheȱlocaleȱextendsȱtheȱexecutionȱcharacterȱset.ȱ
5. Theȱ collatingȱ sequenceȱ ofȱ theȱ executionȱ characterȱ setȱ mayȱ change.ȱ Thisȱ isȱ theȱ
sequenceȱusedȱbyȱstrcollȱtoȱcompareȱstringsȱtoȱeachȱother.ȱ
6. Manyȱaspectsȱofȱtheȱdateȱandȱtimeȱformatȱproducedȱbyȱstrftimeȱareȱspecificȱtoȱtheȱ
locale,ȱasȱpreviouslyȱdescribed.ȱ
ȱ
ȱ
ȱ
16.10 Summary
ȱ
Theȱ standardȱ libraryȱ includesȱ manyȱ usefulȱ functions.ȱ Theȱ firstȱ groupȱ ofȱ functionsȱ
returnȱintegerȱresults.ȱ absȱandȱ labsȱreturnȱtheȱabsoluteȱvalueȱofȱtheirȱarguments.ȱTheȱ
divȱ andȱ ldivȱ functionsȱ performȱ integerȱ division.ȱ Unlikeȱ theȱ /ȱ operator,ȱ theȱ valueȱ ofȱ
theȱquotientȱisȱwellȱdefinedȱwhenȱoneȱofȱtheȱargumentsȱisȱnegative.ȱTheȱ randȱfunctionȱ
returnsȱaȱpseudoȬrandomȱnumber.ȱCallingȱsrandȱallowsȱyouȱtoȱstartȱatȱarbitraryȱpointsȱ
inȱ theȱ sequenceȱ ofȱ pseudoȬrandomȱ values.ȱ Theȱ atoiȱ andȱ atolȱ functionsȱ convertȱ aȱ
stringȱ toȱ anȱ integerȱ value.ȱ Theȱ strtolȱ andȱ strtoulȱ functionsȱ performȱ theȱ sameȱ
conversion,ȱbutȱgiveȱyouȱmoreȱcontrol.ȱ
ȱ
Mostȱ ofȱtheȱ nextȱgroupȱofȱfunctionsȱ takeȱ doubleȱargumentsȱandȱreturnȱ doubleȱ
results.ȱ Theȱ usualȱ trigonometryȱ functions,ȱ sin,ȱ cos,ȱ tan,ȱ asin,ȱ acos,ȱ atan,ȱ andȱ atan2,ȱ
areȱ provided.ȱ Theȱ firstȱ threeȱ takeȱ aȱ singleȱ argument,ȱ anȱ angleȱ inȱ radians,ȱ andȱ returnȱ
theȱsine,ȱcosine,ȱandȱtangentȱofȱtheȱangle,ȱrespectively.ȱTheȱsecondȱthreeȱreturnȱtheȱarcȱ
sine,ȱ arcȱ cosine,ȱ andȱ arcȱ tangentȱ ofȱ theirȱ argument,ȱ respectively.ȱ Theȱ lastȱ functionȱ
computesȱarcȱtangentȱfromȱanȱxȱandȱyȱvalue.ȱTheȱhyperbolicȱsine,ȱcosine,ȱandȱtangentȱ
areȱcomputedȱbyȱsinh,ȱcoshȱandȱtanh,ȱrespectively.ȱȱTheȱexpȱfunctionȱreturnsȱtheȱvalueȱ
Download at http://www.pin5i.com/
486ȱ
Chapter 16 Standard Libraryȱ
eȱraisedȱtoȱtheȱpowerȱofȱtheȱargumentȱTheȱ logȱfunctionȱreturnsȱtheȱnaturalȱlogarithmȱ
ofȱitsȱargument,ȱandȱlogl0ȱreturnsȱtheȱbaseȱ10ȱlogarithm.ȱ
TheȱfrexpȱandȱldexpȱfunctionsȱareȱusefulȱforȱconstructingȱmachineȬindependentȱ
representationsȱofȱfloatingȱpointȱnumbers.ȱfrexpȱcomputesȱaȱrepresentationȱforȱaȱgivenȱ
value,ȱ andȱ ldexpȱ interpretsȱ aȱ representationȱ toȱ recoverȱ theȱ originalȱ value.ȱ Theȱ modfȱ
functionȱ breaksȱ aȱ floatingȬpointȱ valueȱ intoȱ integerȱ andȱ fractionalȱ parts.ȱ Theȱ powȱ
functionȱraisesȱitsȱfirstȱargumentȱtoȱtheȱpowerȱspecifiedȱbyȱitsȱsecondȱargument.ȱ sqrtȱ
returnsȱ theȱ squareȱ rootȱ ofȱ itsȱ argument.ȱ floorȱ returnsȱ theȱ largestȱ integerȱ notȱ greaterȱ
thanȱ itsȱ argument,ȱ andȱ ceilȱ returnsȱ theȱ smallestȱ integerȱ notȱ lessȱ thanȱ itsȱ argument.ȱ
fabsȱreturnsȱtheȱabsoluteȱvalueȱofȱitsȱargument.ȱfmodȱtakesȱtwoȱarguments,ȱandȱreturnsȱ
theȱ remainderȱ thatȱ resultsȱ fromȱ anȱ integerȱ divisionȱ ofȱ theȱ secondȱ argumentȱ intoȱ theȱ
first.ȱ ȱFinally,ȱ theȱ atofȱandȱ strtodȱconvertȱ stringsȱtoȱfloatingȬpointȱ values.ȱ Theȱ latterȱ
functionȱprovidesȱmoreȱcontrolȱoverȱtheȱconversion.ȱ
Theȱ nextȱ groupȱ ofȱ functionsȱ dealȱ withȱ datesȱ andȱ times.ȱ clockȱ returnsȱ theȱ
amountȱ ofȱ processorȱ timeȱ usedȱ byȱ aȱ programȱ sinceȱ itȱ beganȱ executing.ȱ Theȱ timeȱ
functionȱreturnsȱtheȱcurrentȱdateȱandȱtimeȱofȱdayȱasȱaȱtime_tȱvalue.ȱTheȱctimeȱfunctionȱ
convertsȱ aȱ time_tȱ valueȱ intoȱ aȱ humanȬreadableȱ representationȱ ofȱ theȱ dateȱ andȱ time.ȱ
difftimeȱcomputesȱtheȱdifferenceȱinȱsecondsȱbetweenȱtwoȱ time_tȱvalues.ȱ gmtimeȱandȱ
localtimeȱconvertȱaȱ time_tȱvalueȱtoȱaȱ struct tmȱcontainingȱallȱofȱtheȱcomponentsȱofȱ
theȱdateȱandȱtime.ȱTheȱformerȱfunctionȱusesȱUniversalȱCoordinatedȱTimeȱandȱtheȱlatterȱ
usesȱlocalȱtime.ȱTheȱ asctimeȱandȱ strftimeȱfunctionsȱconvertȱaȱ struct tmȱtoȱaȱhumanȬ
readableȱrepresentationȱofȱtheȱdateȱandȱtime.ȱTheȱlatterȱfunctionȱprovidesȱgreatȱcontrolȱ
overȱtheȱformatȱofȱtheȱresult.ȱFinally,ȱ mktimeȱnormalizesȱtheȱvaluesȱinȱaȱstruct tmȱandȱ
convertsȱthemȱtoȱaȱtime_tȱvalue.ȱ
Nonlocalȱjumpsȱareȱprovidedȱbyȱ setjmpȱandȱ longjmp.ȱȱ setjmpȱisȱcalledȱtoȱsaveȱ
processorȱstateȱ informationȱ inȱ aȱ jmp_bufȱvariable.ȱ Then,ȱaȱ subsequentȱcallȱtoȱ longjmpȱ
restoresȱ theȱ savedȱ processorȱ state.ȱ longjmpȱ mayȱ notȱ beȱ calledȱ alterȱ theȱ functionȱ thatȱ
calledȱsetjmpȱreturns.ȱ
Signalsȱ representȱ unexpectedȱ eventsȱ thatȱ mayȱ occurȱ duringȱ theȱ executionȱ ofȱ aȱ
program,ȱ suchȱ asȱ aȱ userȱ interruptȱ orȱ anȱ arithmeticȱ error.ȱ Theȱ defaultȱ actionȱ whenȱ aȱ
signalȱoccursȱisȱimplementationȱdefined,ȱthoughȱterminatingȱtheȱprogramȱisȱcommon.ȱȱ
Youȱmayȱchangeȱtheȱdefaultȱactionȱbyȱdefiningȱaȱsignalȱhandlerȱandȱinstallingȱitȱwithȱ
theȱ signalȱ function.ȱ Theȱ typeȱ ofȱ workȱ thatȱ youȱ mayȱ performȱ inȱ aȱ signalȱ handlerȱ isȱ
severelyȱrestrictedȱbecauseȱtheȱprogramȱmayȱbeȱinȱanȱinconsistentȱstateȱafterȱtheȱsignalȱ
occurs.ȱ Volatileȱ dataȱ mayȱ changeȱ itsȱ value,ȱ apparentlyȱ allȱ byȱ itself.ȱ Forȱ example,ȱ aȱ
variableȱ thatȱ isȱ changedȱ inȱ aȱ signalȱ handlerȱ shouldȱ beȱ declaredȱ volatile.ȱ Theȱ raiseȱ
functionȱcausesȱtheȱsignalȱindicatedȱbyȱitsȱargumentȱtoȱoccur.ȱ
ȱ
Download at http://www.pin5i.com/
16.11 Summary of Cautions
487
Theȱ vprintf,ȱ vfprintf,ȱ andȱ vsprintfȱ functionsȱ performȱ theȱ sameȱ workȱ asȱ theȱ
printfȱfamilyȱofȱfunctions,ȱexceptȱthatȱtheȱvaluesȱtoȱbeȱprintedȱareȱpassedȱasȱaȱvariableȱ
argumentȱ list.ȱ Theȱ abortȱ functionȱ abortsȱ theȱ programȱ byȱ raisingȱ theȱ SIGABRTȱ signal.ȱ
Theȱatexitȱfunctionȱregistersȱexitȱfunctions,ȱwhichȱareȱcalledȱbeforeȱtheȱprogramȱexits.ȱȱ
Theȱassertȱmacroȱisȱusedȱtoȱterminateȱtheȱprogramȱwhenȱanȱexpressionȱthatȱshouldȱbeȱ
trueȱ isȱ actuallyȱ false.ȱ Whenȱ debuggingȱ isȱ completed,ȱ definingȱ theȱ NDEBUGȱ symbolȱ
eliminatesȱtheȱassertionsȱwithoutȱdeletingȱthemȱfromȱtheȱsourceȱcode.ȱgetenvȱretrievesȱ
valuesȱfromȱtheȱoperatingȱsystemȱenvironment.ȱ systemȱtakesȱaȱstringȱasȱanȱargument,ȱ
andȱusesȱtheȱlocalȱcommandȱprocessorȱtoȱexecuteȱtheȱstringȱasȱaȱcommand.ȱ
Theȱ qsortȱ functionȱ sortsȱ anȱ arrayȱ ofȱ valuesȱ intoȱ ascendingȱ order,ȱ andȱ theȱ
bsearchȱfunctionȱperformsȱaȱbinaryȱsearchȱtoȱlocateȱaȱvalueȱinȱaȱsortedȱarray.ȱBothȱofȱ
theseȱfunctionsȱareȱtypeless—theyȱworkȱonȱarraysȱofȱanyȱtypeȱofȱdata.ȱ
Aȱ localeȱ isȱ aȱ setȱ ofȱ parametersȱ thatȱ tailorȱ theȱ behaviorȱ ofȱ Cȱ programsȱ toȱ
countriesȱaroundȱtheȱworld.ȱTheȱsetlocaleȱfunctionȱisȱusedȱtoȱchangeȱtheȱentireȱlocaleȱ
orȱ partsȱ ofȱ it.ȱ Theȱ localeȱ includesȱ parametersȱ thatȱ defineȱ howȱ numericȱ formattingȱ
shouldȱ beȱ performed.ȱ Theȱ typesȱ ofȱ valuesȱ describedȱ includeȱ nonmonetary,ȱ localȱ
monetary,ȱ andȱ internationalȱ monetaryȱ values.ȱ Theȱ localeȱ doesȱ notȱ performȱ anyȱ
formatting,ȱ itȱ simplyȱ providesȱ theȱ specificationsȱ forȱ theȱ formatting.ȱ Aȱ localeȱ canȱ
specifyȱaȱcollatingȱsequenceȱthatȱisȱdifferentȱfromȱtheȱmachineȇsȱdefaultȱsequence.ȱȱInȱ
thisȱ case,ȱ strxcollȱ isȱ usedȱ toȱ compareȱ stringsȱ accordingȱ toȱ theȱ currentȱ collatingȱ
sequence.ȱ Theȱ valueȱ thatȱ itȱ returnsȱ isȱ analogousȱ toȱ thatȱ returnedȱ byȱ strcmp.ȱ Theȱ
strxfrmȱfunctionȱconvertsȱaȱstringȱinȱtheȱcurrentȱcollatingȱsequenceȱtoȱaȱstringȱinȱtheȱ
defaultȱ collatingȱ sequence.ȱ Stringsȱ convertedȱ inȱ thisȱ mannerȱ canȱ beȱ comparedȱ withȱ
strcmp;ȱ theȱ resultȱ ofȱ theȱ comparisonȱ willȱ beȱ theȱ sameȱ asȱ theȱ resultȱ ofȱ comparingȱ theȱ
originalȱstringsȱwithȱstrxcoll.ȱ
ȱ
ȱ
ȱ
ȱ
16.11 Summary of Cautions
ȱ
1. Notȱ includingȱ theȱ math.hȱ headerȱ fileȱ canȱ makeȱ theȱ mathȱ functionsȱ produceȱ
incorrectȱresultsȱ(pageȱ457).ȱ
2. Theȱclockȱfunctionȱmayȱonlyȱbeȱanȱapproximationȱofȱprocessorȱtimeȱ(pageȱ461).ȱ
3. Theȱvalueȱreturnedȱbyȱtimeȱisȱnotȱnecessarilyȱsecondsȱ(pageȱ462).ȱ
4. Theȱmonthȱinȱaȱstruct tmȱisȱnotȱaȱnumberȱinȱtheȱrangeȱ1Ȭ12ȱ(pageȱ463).ȱ
Download at http://www.pin5i.com/
488ȱ
Chapter 16 Standard Libraryȱ
5. Theȱyearȱinȱaȱstruct tmȱisȱtheȱnumberȱofȱyearsȱsinceȱ1900ȱ(pageȱ464).ȱ
6. longjmpȱmayȱnotȱbeȱusedȱtoȱreturnȱtoȱaȱfunctionȱthatȱisȱnoȱlongerȱactiveȱ(pageȱ468).ȱ
7. Callingȱ exitȱorȱ abortȱfromȱtheȱhandlerȱofȱanȱasynchronousȱsignalȱisȱnotȱsafeȱ(pageȱ
472).ȱ
8. Youȱmustȱreinstallȱaȱsignalȱhandlerȱeachȱtimeȱtheȱsignalȱoccursȱ(pageȱ474).ȱ
9. Avoidȱmultipleȱcallsȱtoȱexitȱ(pageȱ475).ȱ
ȱ
ȱ
ȱ
16.12 Summary of Programming Tips
ȱ
1. Misusingȱsetjmpȱandȱlongjmpȱleadsȱtoȱspaghettiȱcodeȱ(pageȱ468).ȱ
2. Handlingȱsignalsȱmakesȱprogramsȱlessȱportableȱ(pageȱ474).ȱ
3. Usingȱassertionsȱsimplifiesȱdebuggingȱ(pageȱ476),ȱ
ȱ
ȱ
ȱ
16.13 Questions
ȱ
1. Whatȱdoesȱtheȱfollowingȱfunctionȱcallȱreturn?ȱ
ȱ
strtol( "12345", NULL, -5 );
2. IfȱtheȱȇȇrandomȈȱnumbersȱproducedȱbyȱtheȱ randȱfunctionȱareȱnotȱtrulyȱrandom,ȱareȱ
theyȱreallyȱanyȱgood?ȱ
3. Whatȱisȱtheȱresultȱofȱtheȱfollowingȱprogramȱonȱyourȱsystem?ȱ
ȱ
#include <stdlib.h>
int
main()
{
int
i;
for( i = 0; i < 100; i += 1 )
printf( "%d\n", rand() % 2 );
}
4. Howȱwouldȱyouȱwriteȱaȱprogramȱtoȱdetermineȱwhetherȱtheȱclockȱfunctionȱonȱyourȱ
systemȱmeasuresȱtheȱcpuȱtimeȱusedȱorȱelapsedȱtime?ȱ
5. Theȱfollowingȱcodeȱfragmentȱattemptsȱtoȱprintȱtheȱcurrentȱtimeȱinȱmilitaryȱformat.ȱȱ
Whatȱisȱwrongȱwithȱit?ȱ
Download at http://www.pin5i.com/
16.13 Questions
489
#include <time.h>
struct tm *tm;
time_t now;
...
now = time();
tm = locatime( now );
printf( "%d:%02d:%02d %d/%02d/%02d\n"
tm->tm_hour, tm->tm_min, tm->tm_sec,
tm->tm_mon, tm->tm_mday, tm->tm_year );
6. Whatȱisȱwrongȱwithȱtheȱfollowingȱprogram?ȱWhatȱhappensȱwhenȱitȱisȱexecutedȱonȱ
yourȱsystem?ȱ
ȱ
#include <stdlib.h>
#include <setjmp.h>
jmp_buf jbuf;
void
set_buffer()
{
setjmp( jbuf );
}
int
main( int ac, char **av )
{
int
a = atoi( av[ 1 ] );
int
b = atoi( av[ 2 ] );
set_buffer();
printf( "%d plus %d equals %d\n",
a, b, a + b );
longjmp( jbuf, 1 );
printf( "After longjmp\n" );
return EXIT_SUCCESS;
}
7. Writeȱ aȱ programȱ thatȱ willȱ determineȱ whetherȱ anȱ integerȱ divisionȱ byȱ zeroȱ orȱ aȱ
floatingȬpointȱdivisionȱbyȱzeroȱresultsȱinȱaȱ SIGFPEȱsignal.ȱHowȱdoȱyouȱexplainȱtheȱ
results?ȱ
8. Theȱcomparisonȱfunctionȱusedȱbyȱ qsortȱshouldȱreturnȱaȱnegativeȱvalueȱifȱtheȱfirstȱ
argumentȱ isȱ lessȱ thanȱ theȱ second,ȱ andȱ aȱ positiveȱ valueȱ ifȱ theȱ firstȱ argumentȱ isȱ
greaterȱ thanȱ theȱ second.ȱ Wouldȱ itȱ makeȱ anyȱ differenceȱ inȱ qsortȇsȱ behaviorȱ ifȱ theȱ
comparisonȱfunctionȱreturnedȱtheȱoppositeȱvaluesȱinstead?ȱ
Download at http://www.pin5i.com/
Chapter 16 Standard Libraryȱ
490ȱ
16.14 Programming Exercises
ȱ
1. Aȱpopularȱjokeȱamongȱcomputerȱpeopleȱisȱtoȱsay,ȱȈMyȱageȱisȱ29,ȱbutȱIȇmȱnotȱtellingȱ
youȱ theȱ baseȱ ofȱ thatȱ number!Ȉȱ Ifȱ theȱ baseȱ isȱ 16,ȱ theȱ personȱ isȱ reallyȱ 41ȱ yearsȱ old.ȱ
Writeȱaȱprogramȱthatȱtakesȱanȱageȱasȱaȱcommandȱlineȱargumentȱandȱcomputesȱtheȱ
smallestȱ radixȱ (base)ȱ inȱ theȱ rangeȱ 2ȱ throughȱ 36ȱ forȱ whichȱ theȱ ageȱ appearsȱ toȱ beȱ aȱ
numberȱ lessȱ thanȱ orȱ equalȱ toȱ 29.ȱ Forȱ example,ȱ ifȱ theȱ userȱ entersȱ 41,ȱ theȱ programȱ
shouldȱsayȱtoȱuseȱbaseȱ16ȱbecauseȱdecimalȱ41ȱisȱ29ȱinȱbaseȱ16.ȱ
2. Writeȱ aȱ functionȱ thatȱ simulatesȱ theȱ throwingȱ ofȱ aȱ sixȬsidedȱ dieȱ byȱ returningȱ aȱ
randomȱintegerȱinȱtheȱrangeȱ1ȱthroughȱ6.ȱBeȱsureȱthatȱeachȱofȱtheȱvaluesȱisȱequallyȱ
likelyȱ toȱ appear.ȱ Theȱ firstȱ timeȱ theȱ functionȱ isȱ called,ȱ itȱ shouldȱ seedȱ theȱ randomȱ
numberȱgeneratorȱwithȱtheȱtimeȱofȱday.ȱ
3. WriteȱaȱprogramȱthatȱtellsȱtheȱcurrentȱtimeȱofȱdayȱasȱaȱthreeȬyearȬoldȱchildȱwouldȱ
(forȱexample,ȱtheȱbigȱhandȱisȱonȱtheȱ6ȱandȱtheȱlittleȱhandȱisȱonȱtheȱ12).ȱ
4. Writeȱ aȱ programȱ thatȱ takesȱ threeȱ integersȱ asȱ commandȱ lineȱ argumentsȱ andȱ
interpretsȱ themȱ asȱ aȱ monthȱ (1Ȭ12),ȱ aȱ dayȱ (1Ȭ31),ȱ andȱ a.ȱ yearȱ (0Ȭ?).ȱ Itȱ shouldȱ thenȱ
printȱ theȱ dayȱ ofȱ theȱ weekȱ onȱ whichȱ theȱ specifiedȱ dateȱ fellȱ (orȱ willȱ fall).ȱ Forȱ whatȱ
rangeȱofȱyearsȱisȱitȱaccurate?ȱ
5. Winterȱ weatherȱ reportsȱ oftenȱ giveȱ theȱ Ȉwindȱ chill,Ȉȱ whichȱ measuresȱ howȱ coldȱ aȱ
particularȱ temperatureȱ andȱ windȱ speedȱ feel.ȱ Forȱ example,ȱ ifȱ itȱ isȱ Ȭ5°ȱ Celsiusȱ (23°ȱ
Fahrenheit)ȱ withȱ aȱ windȱ ofȱ 10ȱ metersȱ perȱ secondȱ (22.37ȱ mph),ȱ theȱ windȱ chillȱ
temperatureȱisȱȬ22.3°ȱCelsiusȱ(Ȭ8.2°ȱFahrenheit).ȱ
Writeȱaȱfunctionȱwithȱtheȱfollowingȱprototypeȱtoȱcomputeȱtheȱwindȱchill.ȱ
ȱ
double wind_chill( double temp, double velocity );
ȱ
tempȱisȱtheȱairȱtemperatureȱinȱdegreesȱCelsius,ȱandȱ velocityȱisȱtheȱwindȱspeedȱinȱ
metersȱperȱsecond.ȱTheȱfunctionȱreturnsȱtheȱwindȱchillȱtemperature,ȱwhichȱisȱalsoȱ
inȱdegreesȱCelsius.ȱ
Windȱchillȱisȱcomputedȱusingȱthisȱformula:ȱ
ȱ
A B V CV 't
Windchil
A B X CX ȱ
ȱ
Forȱ aȱ givenȱ airȱ temperatureȱ andȱ windȱ velocity,ȱ itȱ givesȱ theȱ temperatureȱ thatȱ
producesȱtheȱsameȱcoolingȱeffectȱwithȱaȱ4ȱmphȱwindȱ(theȱwindȱchillȱstandard).ȱVȱisȱ
theȱ windȱ velocityȱ inȱ metersȱ perȱ second.ȱ Atȱ isȱ 33ȱ Ȭȱ temp,ȱ theȱ differenceȱ betweenȱ
neutralȱskinȱtemperatureȱofȱ33°ȱCelsiusȱandȱtheȱairȱtemperature.ȱTheȱconstantsȱareȱ
A=10.45,ȱ B=10,ȱ C=-1,ȱ andȱ X=1.78816,ȱ whichȱ isȱ 4ȱ mphȱ convertedȱ toȱ metersȱ perȱ
second.ȱȱ
ȱ
Download at http://www.pin5i.com/
16.14 Programming Exercises
491
6. Theȱformulaȱforȱdeterminingȱtheȱmonthlyȱpaymentȱforȱaȱmortgageȱisȱ
ȱ
AI
P
N
1 1 I
ȱ
ȱ
whereȱAȱisȱtheȱamountȱofȱtheȱloan,ȱIȱisȱtheȱinterestȱrateȱperȱperiodȱ(asȱaȱdecimal,ȱnotȱ
aȱpercentage),ȱandȱNȱisȱtheȱnumberȱofȱperiodsȱoverȱwhichȱtheȱloanȱwillȱbeȱrepaid.ȱ
Forȱ example,ȱ aȱ $100,000ȱ loanȱ repaidȱ overȱ 20ȱ yearsȱ alȱ 8%ȱ interestȱ hasȱ aȱ monthlyȱ
paymentȱofȱ$836.44ȱ(20ȱyearsȱisȱ240ȱpaymentȱperiods,ȱandȱtheȱinterestȱperȱpaymentȱ
periodȱisȱ0.66667).ȱ
Writeȱtheȱfunction,ȱprototypedȱbelow,ȱtoȱcomputeȱtheȱloanȱpayment.ȱ
ȱ
double payment( double amount, double interest, int year );
ȱ
yearsȱ specifiesȱ theȱ durationȱ ofȱ theȱ loan,ȱ amountȱ isȱ theȱ amountȱ ofȱ theȱ loan,ȱ andȱ
interestȱisȱtheȱannualȱinterestȱrateȱexpressedȱasȱaȱpercentageȱ(forȱexample,ȱ12%).ȱ
Theȱ functionȱ shouldȱ computeȱ andȱ returnȱ theȱ monthlyȱ paymentȱ forȱ theȱ loan,ȱ
roundedȱtoȱtheȱnearestȱpenny.ȱ
ȱ
7. WellȬdesignedȱrandomȱnumberȱgeneratorsȱreturnȱvaluesȱthatȱappearȱtoȱbeȱrandom,ȱ
yetȱoverȱtimeȱareȱuniform.ȱNumbersȱderivedȱfromȱtheȱrandomȱvaluesȱshouldȱalsoȱ
haveȱtheseȱ properties.ȱForȱexample,ȱaȱpoorlyȱdesignedȱrandomȱnumberȱgeneratorȱ
mightȱ returnȱ valuesȱ thatȱ appearȱ randomȱ butȱ inȱ factȱ alternateȱ betweenȱ evenȱ andȱ
oddȱnumbers.ȱIfȱtheseȱseeminglyȱrandomȱvaluesȱareȱtakenȱmoduloȱtwoȱ(toȱsimulateȱ
theȱresultsȱofȱflippingȱaȱcoin,ȱforȱinstance),ȱtheȱresultȱisȱanȱalternatingȱsequenceȱofȱ
zerosȱ andȱ ones.ȱ Aȱ differentȱ flawȱ wouldȱ beȱ aȱ generatorȱ thatȱ returnedȱ onlyȱ oddȱ
values.ȱȱTakingȱtheseȱvaluesȱmoduloȱtwoȱwouldȱresultȱinȱaȱcontinuousȱsequenceȱofȱ
ones.ȱȱNeitherȱofȱtheseȱsequencesȱcanȱbeȱusedȱbecauseȱtheyȱareȱnotȱrandomȱenough.ȱ
Writeȱ aȱ programȱ toȱ testȱ theȱ randomȱ numberȱ generatorȱ onȱ yourȱ system.ȱ Youȱ
shouldȱgenerateȱ10,000ȱrandomȱnumbersȱandȱperformȱtwoȱtypesȱofȱtests.ȱTheȱfirstȱ
isȱaȱfrequencyȱtest.ȱTakeȱeachȱrandomȱnumberȱmoduloȱtwo,ȱandȱcountȱhowȱmanyȱ
timesȱtheȱresultȱisȱzeroȱandȱone.ȱȱDoȱtheȱsameȱforȱmoduloȱthreeȱthroughȱten.ȱTheȱ
resultsȱ willȱ notȱ beȱ preciselyȱ uniform,ȱ butȱ thereȱ shouldȱ notȱ beȱ anyȱ largeȱ peaksȱ orȱ
valleysȱinȱtheȱfrequencies.ȱ
Theȱsecondȱtestȱchecksȱforȱcyclicȱfrequency.ȱȱTakeȱeachȱrandomȱnumberȱandȱtheȱ
precedingȱ oneȱ moduloȱ two.ȱ Useȱ theseȱ remaindersȱ asȱ theȱ subscriptsȱ ofȱ aȱ twoȬ
dimensionalȱ arrayȱ andȱ incrementȱ theȱ specifiedȱ location.ȱ Repeatȱ forȱ moduloȱ threeȱ
throughȱ ten.ȱ Onceȱ again,ȱ theȱ resultsȱ willȱ notȱ beȱ exactlyȱ even,ȱ butȱ theyȱ shouldȱ beȱ
approximatelyȱuniform.ȱ
Modifyȱ yourȱ programȱ soȱ thatȱ youȱ canȱ provideȱ differentȱ valuesȱ toȱ seedȱ theȱ
randomȱnumberȱgenerator,ȱandȱrunȱtestsȱwithȱseveralȱdifferentȱseeds.ȱȱHowȱgoodȱisȱ
yourȱrandomȱnumberȱgenerator?ȱ
Download at http://www.pin5i.com/
492ȱ
Chapter 16 Standard Libraryȱ
8. Aȱcertainȱdataȱfileȱcontainsȱtheȱagesȱofȱfamilyȱmembers.ȱTheȱagesȱofȱtheȱmembersȱofȱ
oneȱ familyȱ areȱ allȱ onȱ theȱ sameȱ line,ȱ separatedȱ byȱ whiteȱ space.ȱ Forȱ example,ȱ thisȱ
dataȱ
ȱ
45 42 22
36 35 7 3 1
22 20
ȱ
describesȱthreeȱfamiliesȱhavingȱthree,ȱfive,ȱandȱtwoȱmembers,ȱrespectively.ȱ
Writeȱaȱprogramȱthatȱcomputesȱtheȱaverageȱageȱofȱeachȱfamilyȱrepresentedȱinȱaȱ
fileȱofȱthisȱsort.ȱȱItȱshouldȱprintȱtheȱaverageȱageȱusingȱtheȱ%5.2fȱformat,ȱfollowedȱbyȱ
aȱ colonȱ andȱ theȱ inputȱ data.ȱ Thisȱ problemȱ isȱ identicalȱ toȱ oneȱ fromȱ theȱ previousȱ
chapterȱbutȱwithoutȱtheȱlimitationȱonȱhowȱmanyȱmembersȱaȱfamilyȱcanȱhave!ȱYouȱ
may,ȱhowever,ȱassumeȱthatȱtheȱinputȱlinesȱwillȱnotȱexceedȱ512ȱcharactersȱeach.ȱ
9. Whatȱareȱ theȱ oddsȱ ofȱ2ȱstudentsȱ inȱaȱclassȱofȱ30ȱ sharingȱtheȱ sameȱbirthday?ȱ Howȱ
bigȱ wouldȱ aȱ groupȱ ofȱ peopleȱ haveȱ toȱ beȱ forȱ theȱ oddsȱ ofȱ anyȱ 2ȱ ofȱ themȱ sharingȱ aȱ
birthdayȱtoȱbeȱ50%?ȱ
Writeȱaȱprogramȱtoȱdetermineȱtheseȱanswers.ȱGetȱ30ȱrandomȱnumbersȱandȱtakeȱ
themȱmoduloȱ365ȱtoȱrepresentȱdaysȱofȱtheȱyearȱ(ignoreȱleapȱyears).ȱThenȱcheckȱtoȱ
seeȱifȱanyȱofȱtheȱnumbersȱmatch.ȱRepeatȱthisȱtestȱ10,000ȱtimesȱtoȱgetȱanȱestimateȱforȱ
theȱodds.ȱ
Toȱ answerȱ theȱ secondȱ question,ȱ modifyȱ theȱ programȱ soȱ thatȱ itȱ willȱ acceptȱ theȱ
groupȱsizeȱasȱaȱcommandȱlineȱargument.ȱSeedȱtheȱrandomȱnumberȱgeneratorȱwithȱ
theȱtimeȱofȱday,ȱandȱrunȱtheȱprogramȱseveralȱtimesȱtoȱgetȱanȱideaȱofȱhowȱaccurateȱ
theȱoddsȱestimateȱis.ȱ
10. Anȱ insertionȱ sortȱ isȱ performedȱ byȱ addingȱ valuesȱ toȱ anȱ arrayȱ oneȱ byȱ one.ȱ Theȱ firstȱ
valueȱ isȱ simplyȱ storedȱ atȱ theȱ beginningȱ ofȱ theȱ array.ȱ Eachȱ subsequentȱ valueȱ isȱ
addedȱbyȱfindingȱitsȱproperȱpositionȱinȱtheȱarray,ȱmovingȱexistingȱvaluesȱasȱneededȱ
toȱmakeȱroomȱforȱit,ȱandȱthenȱinsertingȱit.ȱ
Writeȱ aȱ functionȱ calledȱ insertion_sortȱ thatȱ performsȱ thisȱ task.ȱ Itsȱ prototypeȱ
shouldȱ beȱ theȱ sameȱ asȱ qsort.ȱ Hint:ȱ Considerȱ theȱ arrayȱ thatȱ youȱ getȱ asȱ havingȱ aȱ
sortedȱ partȱ onȱ theȱ leftȱ andȱ anȱ unsortedȱ partȱ onȱ theȱ right.ȱ Initiallyȱ theȱ sortedȱ partȱ
willȱ beȱ empty.ȱ Asȱ yourȱ functionȱ insertsȱ eachȱ value,ȱ theȱ boundaryȱ betweenȱ theȱ
sortedȱandȱunsortedȱpartsȱmovesȱtoȱaccommodateȱtheȱinsertion.ȱWhenȱallȱelementsȱ
haveȱbeenȱinserted,ȱtheȱunsortedȱpartȱisȱnowȱemptyȱandȱtheȱarrayȱisȱsorted.ȱ
Download at http://www.pin5i.com/
17
Classic Abstract Data Types
Thereȱ areȱ severalȱ abstractȱ dataȱ typesȱ (ADTs)ȱ whoseȱ propertiesȱ makeȱ themȱ soȱ usefulȱ
thatȱ theyȱ areȱ indispensableȱ componentsȱ ofȱ aȱ Cȱ programmerȇsȱ toolkit:ȱ theȱ list,ȱ stack,ȱ
queue,ȱ andȱ tree.ȱ Linkedȱ listsȱ wereȱ discussedȱ inȱ Chapterȱ 12;ȱ thisȱ chapterȱ coversȱ theȱ
remainingȱADTs.ȱ
Theȱfirstȱpartȱofȱtheȱchapterȱdescribesȱtheȱpropertiesȱandȱbasicȱimplementationsȱ
ofȱ theseȱ structures.ȱ Theȱ chapterȱ endsȱ byȱ discussingȱ howȱ toȱ improveȱ theȱ flexibilityȱ ofȱ
theirȱimplementationsȱandȱtheȱresultingȱsafetyȱcompromises.ȱ
ȱ
ȱ
ȱ
17.1 Memory Allocation
ȱ
ThereȱisȱoneȱdecisionȱthatȱmustȱbeȱmadeȱforȱallȱADTs—howȱtoȱobtainȱtheȱmemoryȱthatȱ
storesȱtheȱvalues.ȱThereȱareȱthreeȱchoices:ȱaȱstaticȱarray,ȱaȱdynamicallyȱallocatedȱarray,ȱ
andȱaȱdynamicallyȱallocatedȱlinkedȱstructure.ȱ
Theȱstaticȱarrayȱimposesȱaȱfixedȱsizeȱonȱtheȱstructure.ȱMoreover,ȱthisȱsizeȱmustȱ
beȱdeterminedȱatȱcompileȱtime.ȱHowever,ȱitȱisȱtheȱsimplestȱtechniqueȱandȱleastȱproneȱ
toȱerror.ȱ
Usingȱaȱdynamicȱarrayȱletsȱyouȱwaitȱuntilȱruntimeȱtoȱdecideȱhowȱbigȱtoȱmakeȱ
theȱ array.ȱ Itȱ alsoȱ letsȱ youȱ dynamicallyȱ resizeȱ theȱ arrayȱ whenȱ neededȱ byȱ allocatingȱ aȱ
new,ȱlargerȱarray,ȱcopyingȱtheȱvaluesȱfromȱtheȱoriginalȱarrayȱtoȱtheȱnewȱone,ȱandȱthenȱ
deletingȱ theȱ originalȱ array.ȱ Inȱ decidingȱ whetherȱ orȱ notȱ toȱ useȱ aȱ dynamicȱ array,ȱ youȱ
mustȱweighȱtheȱincreasedȱcomplexityȱagainstȱtheȱflexibilityȱofȱanȱADTȱwithoutȱaȱfixed,ȱ
predeterminedȱsizeȱlimit.ȱ
Finally,ȱ linkedȱ structuresȱ offerȱ theȱ greatestȱ flexibility.ȱ Eachȱ elementȱ isȱ
individuallyȱallocatedȱwhenȱneeded,ȱsoȱthereȱisnȇtȱanyȱmaximumȱsizeȱrestrictionȱotherȱ
thanȱ theȱ memoryȱ availableȱ onȱ theȱ machine.ȱ However,ȱ aȱ linkedȱ structureȱ consumesȱ
extraȱ memoryȱ forȱ theȱ links,ȱ andȱ traversingȱ aȱ linkedȱ structureȱ toȱ accessȱ aȱ specificȱ
elementȱisȱnotȱasȱefficientȱasȱaccessingȱaȱvalueȱinȱanȱarray.ȱ
Download at http://www.pin5i.com/
Chapter 17 Classic Abstract Data Typesȱ
494ȱ
ȱ
17.2 Stacks
ȱ
Theȱ stackȱ isȱ aȱ dataȱ structureȱ characterizedȱ byȱ itsȱ LastȬInȱ FirstȬOutȱ orȱ LIFOȱ behavior.ȱ
Partygoersȱareȱwellȱacquaintedȱwithȱstacks;ȱtheȱhostȇsȱdrivewayȱisȱaȱstackȱofȱcars.ȱTheȱ
lastȱcarȱparkedȱisȱtheȱfirstȱoneȱthatȱmustȱbeȱremoved,ȱandȱtheȱfirstȱcarȱthatȱwasȱparkedȱ
cannotȱbeȱmovedȱuntilȱallȱtheȱothersȱareȱgone.ȱ
ȱ
ȱ
ȱ
17.2.1
Stack Interface
ȱ
Theȱbasicȱstackȱoperationsȱareȱusuallyȱcalledȱpushȱandȱpop.ȱPushȱaddsȱaȱnewȱvalueȱtoȱ
theȱ topȱ ofȱ theȱ stack,ȱ andȱ popȱ removesȱ theȱ topmostȱ valueȱ andȱ returnsȱ it.ȱ Accessȱ isȱ
providedȱonlyȱtoȱtheȱtopȱvalueȱonȱtheȱstack.ȱ
Inȱ theȱ traditionalȱ stackȱ interface,ȱ theȱ onlyȱ wayȱ toȱ accessȱ theȱ topȱ elementȱ isȱ toȱ
removeȱ it.ȱAnȱ alternativeȱinterfaceȱ forȱ theȱstackȱ hasȱ threeȱbasicȱ operations:ȱpush,ȱ pop,ȱ
andȱtop.ȱȱPushȱoperatesȱasȱdescribedȱabove,ȱbutȱpopȱsimplyȱremovesȱtheȱtopȱelement—
itsȱvalueȱisȱnotȱreturned.ȱTopȱreturnsȱtheȱvalueȱofȱtheȱtopȱelementȱwithoutȱremovingȱitȱ
fromȱtheȱstack.ȱ
TIP
Theȱtraditionalȱ popȱfunctionȱhasȱaȱsideȱeffect:ȱitȱchangesȱtheȱstateȱofȱtheȱstack.ȱItȱisȱalsoȱ
theȱ onlyȱ wayȱ toȱ accessȱ theȱ topȱ elementȱ ofȱ theȱ stack.ȱ Havingȱ aȱ topȱ functionȱ letsȱ youȱ
repeatedlyȱaccessȱtheȱvalueȱonȱtheȱtopȱofȱtheȱstackȱwithoutȱhavingȱtoȱsaveȱitȱinȱaȱlocalȱ
variable.ȱ Thisȱ capabilityȱ isȱ anotherȱ exampleȱ ofȱ theȱ benefitsȱ ofȱ designingȱ functionsȱ
withoutȱsideȱeffects.ȱ
Weȱ needȱ twoȱ additionalȱ functionsȱ toȱ useȱ theȱ stack.ȱ Anȱ emptyȱ stackȱ cannotȱ beȱ
popped,ȱ soȱ weȱ needȱ aȱ functionȱ toȱ tellȱ usȱ ifȱ theȱ stackȱ isȱ empty.ȱ Aȱ stackȱ implementedȱ
withȱaȱmaximumȱsizeȱlimitȱshouldȱhaveȱaȱfunctionȱthatȱtellsȱusȱwhetherȱtheȱstackȱisȱfullȱ
ȱ
ȱ
ȱ
17.2.2
Implementing a Stack
ȱ
TheȱstackȱisȱoneȱofȱtheȱeasiestȱADTsȱtoȱimplement.ȱTheȱbasicȱapproachȱisȱtoȱstoreȱsheȱ
valuesȱintoȱsuccessiveȱlocationsȱinȱanȱarrayȱasȱtheyȱareȱpushed.ȱYouȱmustȱkeepȱtrackȱofȱ
theȱsubscriptȱofȱtheȱvalueȱthatȱwasȱmostȱrecentlyȱpushed.ȱToȱpopȱtheȱstackȱyouȱsimplyȱ
decrementȱ thisȱ value.ȱ Theȱ headerȱ fileȱ inȱ Programȱ 17.1ȱ describesȱ theȱ nontraditionalȱ
interfaceȱforȱaȱstackȱmodule.ȱ
TIP
Noteȱ thatȱ theȱ interfaceȱ containsȱ onlyȱ theȱ informationȱ thatȱ aȱ clientȱ needsȱ toȱ useȱ theȱ
stack;ȱ specifically,ȱ itȱ doesȱ notȱ revealȱ howȱ dieȱ stackȱ isȱ implemented.ȱ Inȱ fact,ȱ withȱ aȱ
minorȱ modificationȱ thatȱ weȱ discussȱ later,ȱ thisȱ sameȱ headerȱ fileȱ canȱ beȱ usedȱ withȱ allȱ
threeȱ implementationȱ techniques.ȱ Definingȱ theȱ interfaceȱ inȱ thisȱ mannerȱ isȱ goodȱ
practiceȱ becauseȱ itȱ preventsȱ theȱ clientȱ fromȱ makingȱ assumptionsȱ thatȱ dependȱ onȱ aȱ
particularȱimplementation.ȱ
Download at http://www.pin5i.com/
17.2 Stacksȱ
495
ȱ
ȱ
ȱ
/*
** Interface for a stack module
*/
#define
STACK_TYPE
int
/* Type of value on the stack */
/*
** push
**
Pushes a new value on the stack.
**
to be pushed.
*/
void push( STACK_TYPE value );
The argument is the value
/*
** pop
**
Pops a value off of the stack, discarding it.
*/
void pop( void );
/*
** top
**
Returns the topmost value on the stack without changing the
**
stack.
*/
STACK_TYPE top( void );
/*
** is_empty
**
Returns TRUE if the stack is empty, else FALSE.
*/
int
is_empty( void );
/*
** is_full
**
Returns TRUE if the stack is full, else FALSE.
*/
int
is_full( void );
ȱ
Programȱ17.1ȱȱStackȱinterfaceȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱȱȱstack.hȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Anȱ interestingȱ featureȱ ofȱ thisȱ interfaceȱ isȱ itsȱ declarationȱ ofȱ theȱ typeȱ ofȱ valueȱ toȱ beȱ
TIP
storedȱonȱtheȱstack.ȱTheȱclientȱwouldȱmodifyȱthisȱdeclarationȱtoȱsuitȱhisȱneedsȱbeforeȱ
compilingȱtheȱstackȱmodule.ȱ
Download at http://www.pin5i.com/
496ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
An Arrayed Stack
TIP
ȱ
Ourȱfirstȱimplementation,ȱinȱProgramȱ17.2,ȱusesȱaȱstaticȱarray.ȱTheȱsizeȱofȱtheȱstackȱisȱ
givenȱ inȱ aȱ #define,ȱ whichȱ mustȱ beȱ setȱ byȱ theȱ clientȱ beforeȱ theȱ moduleȱ isȱ compiled.ȱȱ
Thisȱrestrictionȱisȱrelaxedȱinȱtheȱstackȱimplementationsȱdiscussedȱlater.ȱ
ȱ
Everythingȱthatȱisȱnotȱpartȱofȱtheȱexternalȱinterfaceȱisȱdeclaredȱ staticȱtoȱpreventȱtheȱ
clientȱfromȱaccessingȱtheȱvaluesȱinȱanyȱwayȱotherȱthanȱthroughȱtheȱdefinedȱinterface.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** A stack implemented with a static array. The array size can
** be adjusted only by changing the #define and recompiling
** the module.
*/
#include "stack.h"
#include <assert.h>
#define
STACK_SIZE
100
/* Max # of values on the stack */
/*
**
The array that holds the values on the stack, and a pointer
**
to the topmost value on the stack.
*/
static
STACK_TYPE stack[ STACK_SIZE ];
static
int
top_element = -1;
/*
**
push
*/
void
push( STACK_TYPE value )
{
assert( !is_full() );
top_element += 1;
stack[ top_element ] = value;
}
/*
**
*/
pop
ȱ
Programȱ17.2ȱȱStackȱimplementedȱwithȱaȱstaticȱarrayȱ ȱ
ȱ
ȱ
ȱ
continuedȱ...ȱ
Download at http://www.pin5i.com/
17.2 Stacksȱ
497
ȱ
ȱ
void
pop( void )
{
assert( !is_empty() );
top_element -= 1;
}
/*
**
top
*/
STACK_TYPE top( void )
{
assert( !is_empty() );
return stack[ top_element ];
}
/*
**
is_empty
*/
int
is_empty( void )
{
return top_element == -1;
}
/*
**
is_full
*/
int
is_full( void )
{
return top_element == STACK_SIZE - 1;
}
ȱ
Programȱ17.2ȱȱStackȱimplementedȱwithȱaȱstaticȱarrayȱ ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱa_stack.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Theȱvariableȱtop_elementȱholdsȱtheȱsubscriptȱofȱtheȱvalueȱatȱtheȱtopȱofȱtheȱstack.ȱ
Itȱisȱinitializedȱtoȱ-1ȱtoȱindicateȱthatȱtheȱstackȱisȱempty.ȱByȱincrementingȱthisȱvariableȱ
inȱpushȱbeforeȱstoringȱtheȱnewȱvalue,ȱ top_elementȱalwaysȱcontainsȱtheȱsubscriptȱofȱtheȱ
topmostȱ value.ȱ Ifȱ itȱ wereȱ initializedȱ toȱ 0,ȱ top_elementȱ wouldȱ beȱ keepingȱ trackȱ ofȱ theȱ
nextȱ availableȱ spaceȱ inȱ theȱ array.ȱ Thisȱ approachȱ worksȱ butȱ isȱ slightlyȱ lessȱ efficientȱ
becauseȱaȱsubtractionȱisȱrequiredȱinȱorderȱtoȱaccessȱtheȱtopȱelement.ȱ
Download at http://www.pin5i.com/
498ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
ȱ
Aȱtraditionalȱ popȱfunction,ȱwrittenȱwithȱstraightforwardȱcode,ȱwouldȱlookȱlikeȱ
this:ȱ
ȱ
STACK_TYPE
pop( void )
{
STACK_TYPE temp;
assert( !is_empty() );
temp = stack[ top_element ];
top_element -= 1;
return temp;
}
ȱ
Theȱ orderingȱ ofȱ theseȱ operationsȱ isȱ important.ȱ top_elementȱ isȱ decrementedȱ afterȱ theȱ
valueȱ isȱ copiedȱ fromȱ theȱ array,ȱ inȱ contrastȱ toȱ push,ȱ whereȱ itȱ isȱ incrementedȱ beforeȱ
copyingȱ theȱ valueȱ intoȱ theȱ array.ȱ Weȱ canȱ makeȱ theȱ popȱ functionȱ moreȱ efficientȱ byȱ
eliminatingȱtheȱtemporaryȱvariableȱandȱtheȱcopyingȱthatȱgoesȱwithȱit:ȱ
ȱ
assert( !is_empty() );
return stack[ top_element-- ];
ȱ
popȱneedȱnotȱeraseȱvaluesȱfromȱtheȱstack—simplyȱdecrementingȱtheȱtopȱpointerȱ
TIP
isȱenoughȱbecauseȱtheȱoldȱvalueȱcanȱnoȱlongerȱbeȱaccessedȱbyȱtheȱclient.ȱ
ȱ
Aȱnoteworthyȱfeatureȱofȱthisȱstackȱmoduleȱisȱitsȱuseȱofȱ assertȱtoȱguardȱagainstȱillegalȱ
operations,ȱsuchȱasȱpoppingȱaȱstackȱthatȱisȱalreadyȱemptyȱorȱpushingȱanotherȱvalueȱonȱ
aȱstackȱthatȱisȱfull.ȱTheȱassertionsȱcallȱtheȱ is_fullȱandȱ is_emptyȱfunctionsȱratherȱthanȱ
testingȱ top_elementȱ themselves.ȱ Thisȱ approachȱ makesȱ itȱ easierȱ toȱ changeȱ theȱ
implementationȱshouldȱyouȱdecideȱlaterȱtoȱdetectȱemptyȱandȱfullȱdifferently.ȱ
Assertionsȱareȱappropriateȱforȱerrorsȱthatȱtheȱclientȱcannotȱrecoverȱfrom.ȱButȱifȱ
theȱ clientȱ wantsȱ toȱ beȱ sureȱ thatȱ theȱ programȱ doesnȇtȱ abort,ȱ theȱ programȱ mustȱ checkȱ
whetherȱthereȱisȱspaceȱonȱtheȱstackȱbeforeȱattemptingȱtoȱpushȱaȱnewȱvalue.ȱThereforeȱ
theȱassertionsȱmustȱonlyȱcheckȱthingsȱthatȱtheȱclientȱcanȱalsoȱcheck.ȱ
ȱ
ȱ
ȱ
A Dynamically Arrayed Stack
ȱ
Theȱ nextȱ implementationȱ usesȱ aȱ dynamicȱ array,ȱ butȱ firstȱ weȱ needȱ toȱ addȱ twoȱ newȱ
functionsȱinȱtheȱinterface:ȱ
Download at http://www.pin5i.com/
17.2 Stacksȱ
499
ȱ
ȱ
ȱ
/*
** create_stack
**
Create the stack. The argument specifies
**
how many elements the stack can hold.
**
NOTE; this does not apply to the static
**
array version of the stack.
*/
void create_stack( size_t size );
/*
** destroy_stack
**
Destroy the stack. This frees the memory
**
used by the stack. NOTE: this does not
**
apply to the static array stack either.
*/
void destroy_stack( void );ȱ
ȱ
Theȱfirstȱfunctionȱcreatesȱtheȱstackȱwithȱwhateverȱsizeȱtheȱuserȱpassesȱasȱanȱargument.ȱȱ
Theȱsecondȱdeletesȱtheȱstack,ȱandȱisȱneededȱtoȱavoidȱmemoryȱleaks.ȱ
TIP
Theseȱ declarationsȱ mayȱ beȱ addedȱ toȱ stack.hȱ evenȱ thoughȱ theȱ previousȱ stackȱ
implementationȱdoesȱnotȱdefineȱeitherȱfunction.ȱNoteȱthatȱthereȱisȱnoȱdangerȱofȱaȱclientȱ
mistakenlyȱcallingȱeitherȱofȱtheseȱfunctionsȱforȱaȱstaticallyȱarrayedȱstackȱbecauseȱtheyȱ
doȱnotȱexistȱinȱthatȱmodule.ȱ
ȱ
Aȱ betterȱ approachȱ isȱ toȱ implementȱ theȱ unneededȱ functionsȱ inȱ theȱ arrayȱ moduleȱ asȱ
stubsȱ thatȱ doȱ nothing.ȱ Theȱ interfacesȱ forȱ theȱ twoȱ implementationsȱ willȱ thenȱ beȱ
identical,ȱthusȱmakingȱitȱeasierȱtoȱswitchȱfromȱoneȱimplementationȱtoȱanother.ȱ
Interestingly,ȱ usingȱ aȱ dynamicallyȱ allocatedȱ arrayȱ doesȱ notȱ changeȱ theȱ
implementationȱ muchȱ (seeȱ Programȱ 17.3).ȱ Theȱ arrayȱ hasȱ beenȱ replacedȱ byȱ aȱ pointer,ȱ
andȱ theȱ stack_sizeȱ variableȱ hasȱ beenȱ introducedȱ toȱ rememberȱ theȱ sizeȱ ofȱ theȱ stack.ȱ
Theȱdefaultȱinitializationȱwillȱmakeȱbothȱofȱtheseȱzero.ȱ
Theȱcreate_stackȱfunctionȱfirstȱchecksȱthatȱtheȱstackȱwasȱnotȱalreadyȱcreated.ȱItȱ
thenȱ allocatesȱ theȱ requestedȱ amountȱ ofȱ memoryȱ andȱ verifiesȱ thatȱ theȱ allocationȱ wasȱ
successful.ȱAfterȱdestroy_stackȱfreesȱtheȱmemory,ȱitȱsetsȱtheȱsizeȱandȱpointerȱvariablesȱ
backȱtoȱzeroȱsoȱthatȱanotherȱstackȱcanȱbeȱcreatedȱlater.ȱ
Theȱ onlyȱ changesȱ toȱ theȱ restȱ ofȱ theȱ moduleȱ areȱ theȱ comparisonȱ toȱ theȱ
stack_sizeȱvariableȱ ratherȱ thanȱ theȱ STACK_SIZEȱconstantȱinȱ is_fullȱandȱtheȱadditionȱ
ofȱanȱassertionȱtoȱbothȱ is_fullȱandȱ is_empty.ȱTheȱassertionȱpreventsȱanyȱofȱtheȱstackȱ
functionsȱ fromȱ beingȱ calledȱ beforeȱ theȱ stackȱ hasȱ beenȱ created.ȱ Theȱ otherȱ stackȱ
functionsȱdonȇtȱneedȱtheȱnewȱassertionȱbecauseȱtheyȱallȱcallȱoneȱofȱtheseȱtwoȱfunctions.ȱ
Download at http://www.pin5i.com/
500ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
ȱ
ȱ
/*
** A stack implemented with a dynamically allocated array.
** The array size is given when create is called, which must
** happen before any other stack operations are attempted.
*/
#include "stack.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
/*
**
The array that holds the values on the stack, and a pointer
**
to the topmost value on the stack.
*/
static
STACK_TYPE *stack;
static
size_t
stack_size;
static
int
top_element = -1;
/*
**
create_stack
*/
void
create_stack( size_t size )
{
assert( stack_size == 0 );
stack_size = size;
stack = malloc( stack_size * sizeof( STACK_TYPE ) );
assert( stack != NULL );
}
/*
**
destroy_stack
*/
void
destroy_stack( void )
{
assert( stack_size > 0 );
stack_size = 0;
free( stack );
stack = NULL;
}
/*
**
*/
push
ȱ
ȱ
Programȱ17.3ȱȱStackȱimplementedȱwithȱaȱdynamicȱarrayȱ
ȱ
ȱ
ȱ
continuedȱ...ȱ
Download at http://www.pin5i.com/
17.2 Stacksȱ
501
ȱ
ȱ
void
push( STACK_TYPE value )
{
assert( !is_full() );
top_element += 1;
stack[ top_element ] = value;
}
/*
**
pop
*/
void
pop( void )
{
assert( !is_empty() );
top_element -= 1;
}
/*
**
top
*/
STACK_TYPE top( void )
{
assert( !is_empty() );
return stack[ top_element ];
}
/*
**
is_empty
*/
int
is_empty( void )
{
assert( stack_size > 0 );
return top_element == -1;
}
/*
**
is_full
*/
int
is_full( void )
{
assert( stack_size > 0 );
return top_element == stack_size - 1;
}
ȱ
ȱ
Programȱ17.3ȱȱStackȱimplementedȱwithȱaȱdynamicȱarrayȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱd_stack.cȱ
Download at http://www.pin5i.com/
502ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
ȱ
Usingȱ assertȱ toȱ checkȱ theȱ successȱ ofȱ aȱ memoryȱ allocationȱ canȱ leadȱ toȱ unexpectedȱ
programȱ abortsȱ inȱ environmentsȱ whereȱ memoryȱ isȱ limited.ȱ Anȱ alternativeȱ strategyȱ
wouldȱ beȱ toȱ returnȱ aȱ valueȱ fromȱ create_stackȱ indicatingȱ whetherȱ orȱ notȱ itȱ wasȱ
successful.ȱInȱtheȱeventȱofȱaȱfailure,ȱtheȱclientȱprogramȱcouldȱtryȱagainȱwithȱaȱsmallerȱ
size.ȱ
ȱ
ȱ
ȱ
A Linked Stack
ȱ
Becauseȱonlyȱtheȱtopȱelementȱonȱaȱstackȱisȱaccessible,ȱaȱsinglyȱlinkedȱlistȱworksȱwellȱforȱ
aȱlinkedȱstack.ȱPushingȱaȱvalueȱonȱtheȱstackȱisȱaccomplishedȱbyȱaddingȱtheȱnewȱvalueȱ
atȱtheȱstartȱofȱtheȱlist.ȱPoppingȱtheȱstackȱremovesȱtheȱfirstȱvalueȱfromȱtheȱlist.ȱTheȱvalueȱ
atȱtheȱheadȱofȱtheȱlistȱisȱalwaysȱeasilyȱaccessible.ȱ
Inȱ theȱ implementationȱ shownȱ inȱ Programȱ 17.4,ȱ thereȱ isnȇtȱ anyȱ needȱ forȱ aȱ
create_stackȱ function,ȱ butȱ destroy_stackȱ canȱ beȱ implementedȱ toȱ emptyȱ theȱ stack.ȱ
Becauseȱ theȱ memoryȱ toȱ holdȱ theȱ valuesȱ isȱ dynamicallyȱ allocated,ȱ itȱ mustȱ beȱ freedȱ toȱ
avoidȱmemoryȱleaks.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** A stack implemented with a linked list.
** limit.
*/
#include "stack.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
#define
This stack has no size
FALSE 0
ȱ
ȱ
Programȱ17.4ȱȱStackȱimplementedȱwithȱaȱlinkedȱlistȱ
ȱ
ȱ
ȱ
ȱ
continuedȱ...ȱ
Download at http://www.pin5i.com/
17.2 Stacksȱ
503
ȱ
ȱ
/*
**
Define a structure to hold one value.
**
point to the next value on the stack.
*/
typedef
struct
STACK_NODE {
STACK_TYPE value;
struct STACK_NODE *next;
} StackNode;
The link field will
/*
**
A pointer to the topmost node on the stack.
*/
static
StackNode
*stack;
/*
**
create_stack
*/
void
create_stack( size_t size )
{
}
/*
**
destroy_stack
*/
void
destroy_stack( void )
{
while( !is_empty() )
pop();
}
/*
**
push
*/
void
push( STACK_TYPE value )
{
StackNode
*new_node;
new_node = malloc( sizeof( StackNode ) );
assert( new_node != NULL );
new_node->value = value;
new_node->next = stack;
stack = new_node;
}
ȱ
ȱ
Programȱ17.4ȱȱStackȱimplementedȱwithȱaȱlinkedȱlistȱ
ȱ
ȱ
ȱ
ȱ
continuedȱ...ȱ
Download at http://www.pin5i.com/
504ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
ȱ
/*
**
pop
*/
void
pop( void )
{
StackNode
*first_node;
assert( !is_empty() );
first_node = stack;
stack = first_node->next;
free( first_node );
}
/*
**
top
*/
STACK_TYPE top( void )
{
assert( !is_empty() );
return stack->value;
}
/*
**
is_empty
*/
int
is_empty( void )
{
return stack == NULL;
}
/*
**
is_full
*/
int
is_full( void )
{
return FALSE;
}
ȱ
ȱ
Programȱ17.4ȱȱStackȱimplementedȱwithȱaȱlinkedȱlistȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱl_stack.c
Download at http://www.pin5i.com/
17.3 Queuesȱ
505
ȱ
ȱ
TIP
Theȱstructureȱisȱneededȱtoȱbundleȱaȱvalueȱandȱaȱpointerȱtogether,ȱandȱtheȱstackȱ
variableȱ isȱ nowȱ aȱ pointerȱ toȱ oneȱ ofȱ theseȱ structures.ȱ Theȱ stackȱ isȱ emptyȱ whenȱ thisȱ
pointerȱisȱNULL,ȱasȱitȱisȱinitially.ȱ
ȱ
Theȱ destroy_stackȱ functionȱ popsȱ valuesȱ untilȱ theȱ slackȱ isȱ empty.ȱ Again,ȱ noticeȱ thatȱ
existingȱis_emptyȱandȱpopȱfunctionsȱareȱcalledȱratherȱthanȱrepeatingȱtheȱneededȱcode.ȱ
create_stackȱ isȱ anȱ emptyȱ function,ȱ andȱ becauseȱ thisȱ stackȱ cannotȱ fillȱ up,ȱ
is_fullȱalwaysȱreturnsȱfalse.ȱ
ȱ
ȱ
ȱ
17.3 Queues
ȱ
Aȱ queueȱ hasȱ aȱ differentȱ orderingȱ thanȱ aȱ stack:ȱ queuesȱ areȱ FirstȬIn,ȱ FirstȬOutȱ orȱ FIFOȱ
structures.ȱWaitingȱlinesȱareȱusuallyȱqueues.ȱTheȱpersonȱthatȱarrivedȱfirstȱisȱatȱtheȱheadȱ
ofȱtheȱline,ȱandȱnewȱarrivalsȱjoinȱtheȱlineȱatȱitsȱend.ȱ
ȱ
ȱ
ȱ
17.3.1
Queue Interface
ȱ
Unlikeȱ stacks,ȱ thereȱ arenȇtȱ generallyȱ acceptedȱ namesȱ forȱ theȱ queueȱ functionsȱ thatȱ
performȱinsertionȱandȱremovalȱofȱvalues,ȱsoȱweȱwillȱuseȱinsertȱandȱdelete.ȱAlso,ȱthereȱ
isȱnotȱcompleteȱagreementȱonȱwhetherȱinsertionsȱoccurȱatȱtheȱfrontȱofȱtheȱqueueȱorȱatȱ
theȱrear.ȱInȱprincipleȱitȱdoesnȇtȱmakeȱanyȱdifferenceȱwhatȱyouȱcallȱtheȱendȱofȱtheȱlineȱ
whereȱ insertionsȱ occur,ȱ butȱ insertingȱ atȱ theȱ rearȱ andȱ removingȱ fromȱ theȱ frontȱ ofȱ theȱ
queueȱmayȱbeȱeasierȱtoȱrememberȱbecauseȱthisȱmethodȱmoreȱaccuratelyȱdescribesȱourȱ
humanȱexperiencesȱwithȱwaitingȱlines.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** Interface for a queue module
*/
#include <stdlib.h>
#define
QUEUE_TYPE
int
ȱ
Programȱ17.5ȱȱQueueȱinterfaceȱ
/* Type of value in the queue */
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
Chapter 17 Classic Abstract Data Typesȱ
506ȱ
ȱ
ȱ
/*
** create_queue
**
Creates a queue. The argument indicates the maximum number
**
of values that the queue will hold. NOTE: this applies only
**
to the dynamically allocated array implementation.
*/
void create_queue( size_t size );
/*
** destroy_queue
**
Destroys a queue. NOTE: this applies only to the linked and
**
dynamically allocated array implementations.
*/
void destroy_queue( void );
/*
** insert
**
Adds a new value on the queue.
**
to be inserted.
*/
void insert( QUEUE_TYPE value );
The argument is the value
/*
** delete
**
Removes a value from the queue, discarding it.
*/
void delete( void );
/*
** first
**
Returns the first value on the queue without changing the
**
queue itself.
*/
QUEUE_TYPE first( void );
/*
** is_empty
**
Returns TRUE if the queue is empty, else FALSE
*/
int
is_empty( void );
/*
** is_full
**
Returns TRUE if the queue is full, else FALSE
*/
int
is_full( void );
ȱ
Programȱ17.5ȱȱQueueȱinterfaceȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱqueue.hȱ
Download at http://www.pin5i.com/
17.3 Queuesȱ
507
ȱ
Inȱ theȱ traditionalȱ interface,ȱ deleteȱ removesȱ theȱ valueȱ fromȱ theȱ frontȱ ofȱ theȱ
queueȱandȱreturnsȱit.ȱInȱtheȱalternateȱinterface,ȱdeleteȱtakesȱtheȱvalueȱoutȱofȱtheȱqueueȱ
butȱdoesȱnotȱreturnȱit;ȱtheȱ firstȱfunctionȱreturnsȱtheȱfirstȱvalueȱinȱtheȱqueueȱwithoutȱ
removingȱit.ȱ
Theȱ headerȱ fileȱ inȱ Programȱ 17.5ȱ definesȱ theȱ alternateȱ interface.ȱ Itȱ includesȱ
prototypesȱ forȱ theȱ create_queueȱ andȱ destroy_queueȱ functionsȱ neededȱ byȱ theȱ linkedȱ
andȱdynamicȱimplementations.ȱ
ȱ
ȱ
ȱ
17.3.2
Implementing a Queue
ȱ
Queuesȱareȱmoreȱdifficultȱloȱimplementȱthanȱstacks.ȱTwoȱpointersȱaxeȱneeded—oneȱforȱ
theȱfrontȱofȱtheȱlineȱandȱoneȱforȱtheȱrear.ȱAlso,ȱarraysȱareȱnotȱasȱwellȱsuitedȱtoȱqueuesȱ
asȱtheyȱareȱtoȱstacksȱbecauseȱofȱtheȱwayȱqueuesȱuseȱmemory.ȱ
Aȱ stackȱ isȱ alwaysȱ rootedȱ atȱ oneȱ endȱ ofȱ theȱ array.ȱ Aȱ queue,ȱ however,ȱ usesȱ
differentȱelementsȱofȱtheȱarrayȱasȱvaluesȱareȱinsertedȱandȱremoved.ȱConsiderȱaȱqueueȱ
implementedȱasȱanȱarrayȱofȱfiveȱvalues.ȱHereȱisȱhowȱitȱwillȱlookȱafterȱtheȱvaluesȱ10,ȱ20,ȱ
30,ȱ40,ȱandȱ50ȱhaveȱbeenȱinserted.ȱ
ȱ
subscriptȱ
0ȱ
1ȱ
2ȱ
3ȱ
4ȱ
ȱ
10ȱ
20ȱ
30ȱ
40ȱ
50ȱ
ȱ
ȱ
ȱ
front
0ȱ
rearȱ
4ȱ
ȱ
ȱ
ȱ
Afterȱthreeȱremovals,ȱitȱlooksȱlikeȱthis:ȱ
ȱ
subscriptȱ
0ȱ
1ȱ
2ȱ
3ȱ
4ȱ
ȱ
ȱ
ȱ
ȱ
40ȱ
50ȱ
ȱ
ȱ
ȱ
front
3ȱ
rearȱ
4ȱ
ȱ
ȱ
Theȱarrayȱisȱnotȱfull,ȱbutȱthereȱisnȇtȱanyȱroomȱatȱitsȱendȱtoȱinsertȱnewȱvalues.ȱ
Oneȱ solutionȱ toȱ thisȱ problemȱ isȱ toȱ moveȱ theȱ remainingȱ elementsȱ backȱ towardȱ
theȱbeginningȱofȱtheȱarrayȱwhenȱaȱvalueȱisȱremoved.ȱTheȱcopyingȱoverheadȱmakesȱthisȱ
approachȱimpractical,ȱespeciallyȱforȱlargeȱqueues.ȱ
AȱbetterȱalternativeȱisȱtoȱhaveȱtheȱrearȱofȱtheȱqueueȱȈwrapȱaroundȈȱtoȱtheȱfrontȱ
ofȱ theȱ arrayȱ soȱ thatȱ newȱ valuesȱ canȱ beȱ storedȱ inȱ theȱ spaceȱ madeȱ availableȱ byȱ earlierȱ
removals.ȱThisȱmethodȱisȱoftenȱcalledȱaȱcircularȱarray.ȱTheȱfollowingȱdiagramȱillustratesȱ
thisȱconceptȱ
Download at http://www.pin5i.com/
508ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
subscript
1
0
frontȱ
3
2
rearȱ
4
4
50
40
3
Insertingȱanotherȱvalueȱgivesȱthisȱresult:ȱ
subscript
ȱ
1
0
frontȱ
60
3
2
rearȱ
0
4
50
40
3
ȱ
Theȱcircularȱarrayȱisȱeasyȱtoȱimplement—whenȱtheȱrearȱsubscriptȱmovesȱoffȱtheȱ
endȱofȱtheȱarray,ȱsetȱitȱbackȱtoȱzero,ȱasȱisȱdoneȱinȱtheȱfollowingȱcode.ȱ
ȱ
rear += 1;
if( rear >= QUEUE_SIZE )
rear = 0;
ȱ
Theȱfollowingȱapproachȱhasȱtheȱsameȱresult.ȱ
ȱ
rear = ( rear + 1 ) % QUEUE_SIZE;
ȱ
Theȱsameȱtechniqueȱmustȱbeȱappliedȱwhenȱincrementingȱfront.ȱ
Theȱcircularȱarrayȱintroducesȱaȱproblemȱofȱitsȱown,ȱthough.ȱItȱisȱmoreȱcomplexȱ
toȱdetermineȱwhetherȱaȱcircularȱarrayȱisȱfullȱorȱempty.ȱSupposeȱtheȱqueueȱwereȱfull,ȱasȱ
thisȱoneȱis:ȱ
subscript
70
0
frontȱ
1
60
3ȱ
80 2
rearȱ
2
4
50
40
3
ȱ
Download at http://www.pin5i.com/
17.3 Queuesȱ
509
ȱ
Noteȱ theȱ valuesȱ ofȱ frontȱ andȱ rear;ȱ threeȱ andȱ two,ȱ respectively.ȱ Ifȱ fourȱ valuesȱ
areȱ removedȱ fromȱ theȱ queue,ȱ frontȱ willȱ beȱ incrementedȱ fourȱ times,ȱ givingȱ thisȱ
configuration:ȱ
subscript
1
0
frontȱ
2
80 2
rearȱ
2
4
3
Whenȱtheȱlastȱvalueȱisȱremoved,ȱtheȱqueueȱlooksȱlikeȱthis:ȱ
subscript
ȱ
1
0
frontȱ
3
2
rearȱ
2
4
3
ȱ
Theȱproblemȱisȱthatȱtheȱvaluesȱofȱfrontȱandȱrearȱareȱnowȱtheȱsameȱasȱtheyȱwereȱwhenȱ
theȱqueueȱwasȱfull.ȱAnyȱcomparisonȱofȱthemȱthatȱisȱtrueȱwhenȱtheȱqueueȱisȱemptyȱwillȱ
alsoȱbeȱtrueȱwhenȱitȱisȱfull,ȱsoȱweȱcannotȱtestȱforȱanȱemptyȱqueueȱbyȱcomparingȱ frontȱ
andȱrear.ȱ
Thereȱ areȱ twoȱ waysȱ toȱ solveȱ thisȱ problem.ȱ Theȱ firstȱ isȱ toȱ introduceȱ aȱ newȱ
variableȱ thatȱ countsȱ howȱ manyȱ valuesȱ areȱ inȱ theȱ queue.ȱ Itȱ isȱ incrementedȱ withȱ eachȱ
insertionȱ andȱ decrementedȱ withȱ eachȱ removal.ȱ Testingȱ thisȱ variableȱ toȱ determineȱ
whetherȱtheȱqueueȱisȱemptyȱorȱfullȱisȱeasy.ȱ
Theȱ secondȱ approachȱ isȱ toȱ redefineȱ theȱ meaningȱ ofȱ full.ȱ Ifȱ oneȱ elementȱ inȱ theȱ
arrayȱisȱalwaysȱleftȱunused,ȱthenȱwhenȱtheȱqueueȱisȱȈfullȈȱtheȱfrontȱandȱrearȱvaluesȱwillȱ
beȱ differentȱ thanȱ whenȱ theȱ queueȱ isȱ empty.ȱ Byȱ notȱ allowingȱ theȱ arrayȱ toȱ becomeȱ
completelyȱfull,ȱtheȱproblemȱisȱavoided.ȱ
Oneȱ minorȱ questionȱ remains:ȱ Whatȱ valuesȱ shouldȱ frontȱ andȱ rearȱ haveȱ whenȱ
theȱqueueȱisȱempty?ȱWhenȱtheȱqueueȱhasȱoneȱvalueȱinȱit,ȱweȱwantȱ frontȱandȱ rearȱtoȱ
bothȱpointȱtoȱtheȱvalue.ȱAnȱinsertionȱincrementsȱ rear,ȱsoȱinȱorderȱforȱ rearȱtoȱpointȱtoȱ
theȱvalueȱafterȱtheȱfirstȱinsertion,ȱ rearȱmustȱbeȱoneȱlessȱthanȱ frontȱwhenȱtheȱqueueȱisȱ
empty.ȱ Fortunately,ȱ thisȱ stateȱ isȱ alsoȱ theȱ resultȱ ofȱ removingȱ theȱ lastȱ valueȱ fromȱ theȱ
queue,ȱsoȱremovingȱtheȱlastȱvalueȱisȱnotȱaȱspecialȱcase.ȱ
Download at http://www.pin5i.com/
510ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
Theȱqueueȱisȱemptyȱwhenȱ
ȱ
( rear + 1 ) % QUEUE_SIZE == front
ȱ
Becauseȱ weȱ mustȱ stopȱ insertingȱ valuesȱ justȱ beforeȱ frontȱ andȱ rearȱ reachȱ thisȱ
relationship,ȱtheȱqueueȱmustȱbeȱcalledȱȈfullȈȱwhenȱ
ȱ
( rear + 2 ) % QUEUE_SIZE == front
ȱ
ȱ
ȱ
An Arrayed Queue
ȱ
Programȱ17.6ȱimplementsȱaȱqueueȱwithȱaȱstaticȱarray.ȱItȱusesȱtheȱȈdonȇtȱcompletelyȱfillȱ
theȱarrayȈȱtechniqueȱofȱdistinguishingȱbetweenȱanȱemptyȱandȱaȱfullȱqueue.ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
/*
** A queue implemented with a static array. The array size can
** be adjusted only by changing the #define and recompiling
** the module.
*/
#include "queue.h"
#include <stdio.h>
#include <assert.h>
#define
#define
QUEUE_SIZE
ARRAY_SIZE
100
/* Max # of values on the queue */
( QUEUE_SIZE + 1 )
/* Size of array */
/*
**
The array that holds the values on the queue, and pointers
**
to the front and rear of the queue.
*/
static
QUEUE_TYPE queue[ ARRAY_SIZE ];
static
size_t
front = 1;
static
size_t
rear = 0;
ȱ
Programȱ17.6ȱȱQueueȱimplementedȱwithȱaȱstaticȱarrayȱȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
17.3 Queuesȱ
511
ȱ
ȱ
/*
**
insert
*/
void
insert( QUEUE_TYPE value )
{
assert( !is_full() );
rear = ( rear + 1 ) % ARRAY_SIZE;
queue[ rear ] = value;
}
/*
**
delete
*/
void
delete( void )
{
assert( !is_empty() );
front = ( front + 1 ) % ARRAY_SIZE;
}
/*
**
first
*/
QUEUE_TYPE first( void )
{
assert( !is_empty() );
return queue[ front ];
}
/*
**
is_empty
*/
int
is_empty( void )
{
return ( rear + 1 ) % ARRAY_SIZE == front;
}
/*
**
is_full
*/
int
is_full( void )
{
return ( rear + 2 ) % ARRAY_SIZE == front;
}
ȱ
Programȱ17.6ȱȱQueueȱimplementedȱwithȱaȱstaticȱarrayȱȱ
ȱ
ȱ
ȱ
ȱȱȱa_queue.cȱ
Download at http://www.pin5i.com/
512ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
TheȱQUEUE_SIZEȱconstantȱisȱsetȱtoȱtheȱmaximumȱnumberȱofȱvaluesȱthatȱtheȱclientȱ
wantsȱonȱtheȱqueue.ȱBecauseȱthisȱimplementationȱneverȱfillsȱtheȱqueue,ȱ ARRAY_SIZEȱisȱ
definedȱ asȱ oneȱ moreȱ thanȱ QUEUE_SIZE.ȱ Theȱ functionsȱ areȱ straightforwardȱ
implementationsȱofȱtheȱtechniquesȱweȱdiscussed.ȱ
Weȱcouldȱhaveȱusedȱanyȱ valuesȱtoȱ initializeȱ frontȱandȱ rearȱasȱlongȱ asȱ rearȱ isȱ
oneȱlessȱthanȱfront.ȱTheseȱparticularȱvaluesȱleaveȱtheȱfirstȱelementȱofȱtheȱarrayȱunusedȱ
untilȱtheȱfirstȱtimeȱrearȱwrapsȱaround,ȱbutȱsoȱwhat?ȱ
ȱ
ȱ
ȱ
Dynamically Arrayed and Linked Queues
ȱ
Theȱmodificationsȱneededȱtoȱdynamicallyȱallocateȱtheȱarrayȱforȱaȱqueueȱareȱanalogousȱ
toȱthoseȱneededȱforȱaȱstack.ȱConsequently,ȱitsȱimplementationȱisȱleftȱtoȱtheȱexercises.ȱ
Theȱlinkedȱqueueȱisȱsimplerȱinȱsomeȱrespectsȱthanȱitsȱarrayedȱcousins.ȱItȱdoesnȇtȱ
useȱ anȱ array,ȱ soȱ theȱ problemsȱ ofȱ theȱ circularȱ arrayȱ disappear.ȱ Testingȱ forȱ emptyȱ isȱ
simplyȱaȱmatterȱofȱseeingȱifȱtheȱlistȱisȱempty.ȱTheȱtestȱforȱfullȱalwaysȱreturnsȱfalse.ȱThisȱ
implementationȱisȱalsoȱleftȱasȱanȱexercise.ȱ
ȱ
ȱ
ȱ
17.4 Trees
ȱ
Aȱ completeȱ descriptionȱ ofȱ allȱ theȱ varietiesȱ ofȱ treesȱ isȱ beyondȱ theȱ scopeȱ ofȱ thisȱ book.ȱȱ
However,ȱ theȱ techniquesȱ forȱ implementingȱ treesȱ areȱ illustratedȱ quiteȱ nicelyȱ byȱ
describingȱoneȱveryȱusefulȱvariety;ȱtheȱbinaryȱsearchȱtree.ȱ
Aȱtreeȱisȱaȱstructureȱthatȱisȱeitherȱemptyȱorȱhasȱaȱvalueȱandȱzeroȱorȱmoreȱchildren,ȱ
eachȱofȱwhichȱisȱalsoȱaȱtree.ȱThisȱrecursiveȱdefinitionȱimpliesȱcorrectlyȱthatȱthereȱisnȇtȱ
anȱ inherentȱ limitȱ toȱ theȱ heightȱ ofȱ aȱ tree.ȱ Aȱ binaryȱ treeȱ isȱ aȱ specializedȱ formȱ ofȱ treeȱ inȱ
whichȱeachȱnodeȱhasȱatȱmostȱtwoȱchildren,ȱnamedȱleftȱandȱright.ȱAȱbinaryȱsearchȱtreeȱhasȱ
oneȱadditionalȱproperty:ȱTheȱvalueȱinȱeachȱnodeȱisȱgreaterȱthanȱallȱofȱtheȱvaluesȱinȱitsȱ
leftȱsubtreeȱandȱlessȱthanȱallȱofȱtheȱvaluesȱinȱitsȱrightȱsubtree.ȱNoteȱthatȱthisȱdefinitionȱ
precludesȱ havingȱ duplicateȱ valuesȱ inȱ theȱ tree.ȱ Theseȱ propertiesȱ makeȱ binaryȱ searchȱ
treesȱanȱexcellentȱtoolȱforȱquicklyȱlocatingȱdataȱusingȱaȱkey.ȱFigureȱ17.1ȱisȱanȱexampleȱ
ofȱaȱbinaryȱsearchȱtree.ȱEachȱnodeȱinȱtheȱtreeȱhasȱexactlyȱoneȱparentȱ(theȱnodeȱaboveȱ
it),ȱandȱzero,ȱone,ȱorȱtwoȱchildrenȱ(theȱnodesȱdirectlyȱbeneathȱit).ȱTheȱonlyȱexceptionȱisȱ
theȱtopmostȱnode,ȱcalledȱtheȱrootȱofȱtheȱtree,ȱwhichȱdoesnȇtȱhaveȱaȱparent.ȱTheȱnodesȱ
withoutȱchildrenȱareȱcalledȱleafȱnodesȱorȱleaves.ȱTreesȱareȱdrawnȱwithȱtheȱrootȱatȱtheȱtopȱ
andȱtheȱleavesȱatȱtheȱbottom. 55
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
55
ȱNoteȱthatȱtreesȱinȱnature,ȱwithȱtheirȱrootsȱatȱtheȱbottomȱandȱtheirȱleavesȱonȱtop,ȱareȱactuaryȱupsideȱdown.ȱ
Download at http://www.pin5i.com/
17.4 Treesȱ
513
ȱ
20
12ȱ
ȱ5ȱ
25
16ȱ
ȱ9ȱ
28ȱ
17
26ȱ
29
ȱ
ȱ
Figureȱ17.1ȱȱBinaryȱsearchȱtreeȱ
ȱ
ȱ
ȱ
17.4.1
Insertions into a Binary Search Tree
ȱ
Whenȱaȱnewȱvalueȱisȱtoȱbeȱaddedȱtoȱaȱbinaryȱsearchȱtree,ȱitȱmustȱbeȱputȱinȱtheȱproperȱ
positionȱsoȱthatȱtheȱsearchȱtreeȱpropertyȱisȱmaintained.ȱFortunately,ȱthisȱtaskȱisȱsimple.ȱȱ
Theȱbasicȱalgorithmȱworksȱlikeȱthis:ȱ
ȱ
Ifȱtheȱtreeȱisȱempty;ȱ
Insertȱtheȱnewȱvalueȱasȱtheȱrootȱnodeȱ
Otherwise:ȱ
Ifȱtheȱnewȱvalueȱisȱlessȱthanȱtheȱcurrentȱnodeȇsȱvalue:ȱ
Insertȱtheȱnewȱvalueȱinȱtheȱleftȱsubtreeȱofȱtheȱcurrentȱnodeȱ
Otherwise:ȱ
Insertȱtheȱnewȱvalueȱinȱtheȱrightȱsubtreeȱofȱtheȱcurrentȱnode.ȱ
TIP
ȱ
Theȱ recursiveȱ expressionȱ ofȱ thisȱ algorithmȱ isȱ aȱ directȱ consequenceȱ ofȱ theȱ recursiveȱ
definitionȱofȱtheȱtree.ȱ
Toȱ insertȱ 15ȱ intoȱ theȱ treeȱ inȱ Figureȱ 17.1,ȱ compareȱ 15ȱ withȱ 20.ȱ Itȱ isȱ lessȱ soȱ theȱ
valueȱ isȱ insertedȱ intoȱ theȱ leftȱ subtree.ȱ Thisȱ subtreeȇsȱ rootȱ isȱ 12,ȱ soȱ theȱ processȱ isȱ
repeatedȱwithȱthisȱnode:ȱcompareȱ15ȱwithȱ12.ȱThisȱtimeȱ15ȱisȱgreater,ȱsoȱweȱinsertȱ15ȱ
intoȱ12ȇsȱrightȱsubtree.ȱWeȱnowȱcompareȱ15ȱwithȱ16.ȱItȱisȱless,ȱsoȱweȱinsertȱ15ȱintoȱtheȱ
leftȱsubtreeȱofȱnodeȱ16.ȱButȱthisȱsubtreeȱisȱempty,ȱsoȱtheȱnodeȱcontainingȱ15ȱbecomesȱ
theȱrootȱofȱtheȱnewȱleftȱsubtreeȱofȱnodeȱ16.ȱ
ȱ
Becauseȱ theȱ recursionȱ occursȱ atȱ theȱ endȱ ofȱ theȱ algorithmȱ (tailȱ recursion),ȱ itȱ isȱ moreȱ
efficientȱtoȱimplementȱtheȱalgorithmȱiteratively.ȱ
Download at http://www.pin5i.com/
Chapter 17 Classic Abstract Data Typesȱ
514ȱ
ȱ
17.4.2
Deletions from a Binary Search Tree
ȱ
Removingȱaȱvalueȱfromȱaȱtreeȱisȱmoreȱdifficultȱthanȱremovingȱaȱvalueȱfromȱaȱstackȱorȱaȱ
queue.ȱDeletingȱaȱnodeȱfromȱtheȱmiddleȱofȱaȱtreeȱdisconnectsȱitsȱsubtreesȱfromȱtheȱrestȱ
ofȱtheȱtree—weȱmustȱreconnectȱthemȱorȱtheyȱwillȱbeȱlost.ȱ
Thereȱ areȱ threeȱ casesȱ thatȱ weȱ mustȱ handle:ȱ deletingȱ nodesȱ withȱ noȱ children,ȱ
withȱoneȱchild,ȱandȱwithȱtwoȱchildren.ȱTheȱfirstȱsituationȱisȱeasy.ȱDeletingȱaȱleafȱnodeȱ
doesnȇtȱdisconnectȱanyȱsubtrees,ȱsoȱthereȱisȱnothingȱtoȱreconnect.ȱDeletingȱaȱnodeȱwithȱ
onlyȱoneȱchildȱisȱalmostȱasȱeasy:ȱtheȱparentȱofȱtheȱdeletedȱnodeȱinheritsȱtheȱchild.ȱThisȱ
solutionȱpreventsȱthatȱsubtreeȱfromȱbeingȱdisconnected,ȱyetȱpreservesȱtheȱorderingȱofȱ
theȱbinaryȱsearchȱtree.ȱ
Theȱ lastȱ caseȱ isȱ moreȱ difficult.ȱ Ifȱ aȱ nodeȱ hasȱ twoȱ children,ȱ itsȱ parentȱ cannotȱ
inheritȱbothȱofȱthem.ȱOneȱstrategyȱisȱtoȱnotȱdeleteȱtheȱnodeȱatȱall.ȱInstead,ȱtheȱlargestȱ
valueȱ inȱ theȱ nodeȇsȱ leftȱ subtreeȱ isȱ deletedȱ andȱ thatȱ valueȱ replacesȱ theȱ oneȱ thatȱ wasȱ
originallyȱtoȱhaveȱbeenȱdeleted.ȱTheȱdeletionȱfunctionsȱareȱimplementedȱasȱexercises.ȱ
ȱ
ȱ
ȱ
17.4.3
Searching a Binary Search Tree
ȱ
Becauseȱ ofȱ dieȱ orderingȱ imposedȱ onȱ aȱ binaryȱ searchȱ tree,ȱ searchingȱ theȱ treeȱ forȱ aȱ
particularȱvalueȱisȱeasy.ȱHereȱisȱtheȱalgorithm:ȱ
ȱ
Ifȱtheȱtreeȱisȱempty:ȱ
Theȱvalueȱisȱnotȱinȱtheȱtreeȱ
Otherwise:ȱ
Ifȱtheȱrootȱcontainsȱtheȱvalue:ȱ
Theȱvalueȱisȱfoundȱ
Otherwise:ȱ
Ifȱtheȱvalueȱisȱlessȱthanȱtheȱroot:ȱ
Searchȱtheȱleftȱsubtreeȱ
Otherwise:ȱ
Searchȱtheȱrightȱsubtreeȱ
ȱ
Theȱrecursionȱinȱthisȱalgorithmȱisȱalsoȱtailȱrecursion,ȱsoȱanȱiterativeȱimplementationȱisȱ
preferred.ȱ
Whatȱ doȱ youȱ doȱ whenȱ theȱ valueȱ isȱ found?ȱ Itȱ dependsȱ onȱ theȱ clientȇsȱ needs.ȱȱ
Sometimes,ȱ allȱ thatȱ isȱ requiredȱ isȱ toȱ checkȱ forȱ membership.ȱ Inȱ thisȱ case,ȱ returningȱ aȱ
true/falseȱstatusȱisȱadequate.ȱIfȱtheȱdataȱisȱaȱstructureȱthatȱisȱidentifiedȱbyȱaȱkeyȱfield,ȱ
theȱclientȱwillȱwantȱtoȱaccessȱtheȱnonȬkeyȱmembersȱofȱtheȱstructureȱthatȱwasȱlocated,ȱ
whichȱrequiresȱreturningȱaȱpointerȱtoȱtheȱstructure.ȱ
Download at http://www.pin5i.com/
17.4 Treesȱ
515
ȱ
17.4.4
Tree Traversals
ȱ
Treesȱdoȱnotȱlimitȱyouȱtoȱaccessingȱonlyȱoneȱvalueȱasȱdoȱstacksȱandȱqueues.ȱThusȱtreesȱ
haveȱanotherȱbasicȱoperation—theȱtraversal.ȱWhenȱyouȱexamineȱallȱofȱtheȱnodesȱinȱaȱ
tree,ȱyouȱareȱtraversingȱtheȱtree.ȱThereȱareȱseveralȱdifferentȱordersȱinȱwhichȱtheȱnodesȱ
mayȱ beȱ traversed,ȱ theȱ mostȱ commonȱ beingȱ preȬorder,ȱ inȬorder,ȱ postȬorder,ȱ andȱ breadthȬ
first.ȱ Allȱ traversalsȱ startȱ atȱ theȱ rootȱ ofȱ theȱ treeȱ orȱ atȱ theȱ nodeȱ whichȱ isȱ theȱ rootȱ ofȱ
whateverȱsubtreeȱyouȱwishȱtoȱtraverse.ȱ
Aȱ preȬorderȱ traversalȱ examinesȱ theȱ valueȱ inȱ theȱ nodeȱ andȱ thenȱ recursivelyȱ
traversesȱtheȱleftȱandȱrightȱsubtrees.ȱForȱexample,ȱaȱpreȬorderȱtraversalȱofȱtheȱtreeȱ
ȱ
20
12ȱ
5ȱ
25ȱ
16
ȱ
ȱ
wouldȱbeginȱbyȱprocessingȱtheȱvalueȱ20.ȱWeȱthenȱtraverseȱtheȱleftȱsubtree:ȱ
ȱ
12ȱ
ȱ5ȱ
16
ȱ
ȱ
Afterȱprocessingȱtheȱvalueȱ12,ȱweȱwouldȱtraverseȱitsȱleftȱsubtreeȱ
ȱ
ȱ5ȱ
ȱ
ȱ
andȱ processȱ theȱ valueȱ 5.ȱ Itsȱ leftȱ andȱ rightȱ subtreesȱ areȱ empty,ȱ soȱ weȱ haveȱ nowȱ
completedȱthisȱsubtree.ȱ
Havingȱfinishedȱtheȱleftȱsubtreeȱofȱnodeȱ12,ȱweȱcontinueȱwithȱitsȱrightȱsubtreeȱ
ȱ
16ȱ
ȱ
Download at http://www.pin5i.com/
Chapter 17 Classic Abstract Data Typesȱ
516ȱ
ȱ
andȱ processȱ theȱ valueȱ 16.ȱ Bothȱ ofȱ itsȱ subtreesȱ areȱ alsoȱ empty,ȱ whichȱ meansȱ weȱ haveȱ
completedȱtheȱsubtreeȱwhoseȱrootȱisȱ16ȱandȱtheȱsubtreeȱwhoseȱrootȱisȱ12.ȱ
Havingȱ finishedȱ theȱ leftȱ subtreeȱ ofȱ 20,ȱ theȱ nextȱ stepȱ isȱ toȱ processȱ itsȱ rightȱ
subtree:ȱ
ȱ
25ȱ
ȱ
ȱ
Processingȱtheȱvalueȱ25ȱcompletesȱtheȱtraversal.ȱ
Forȱ aȱ largerȱ example,ȱ considerȱ theȱ binaryȱ searchȱ treeȱ inȱ Figureȱ 17.1ȱ Ifȱ eachȱ
nodeȇsȱ valueȱ isȱ printedȱ whenȱ theȱ nodeȱ wasȱ examined,ȱ theȱ outputȱ ofȱ aȱ preȬorderȱ
traversalȱwouldȱbe:ȱ20,ȱ12,ȱ5,ȱ9,ȱ16,ȱ17,ȱ25,ȱ28,ȱ26,ȱ29.ȱ
AnȱinȬorderȱtraversalȱfirstȱtraversesȱtheȱleftȱsubtree,ȱthenȱexaminesȱtheȱvalueȱinȱ
theȱ node,ȱ andȱ traversesȱ theȱ rightȱ subtreeȱ last.ȱ Anȱ inȬorderȱ traversalȱ ofȱ theȱ treeȱ inȱ
Figureȱ17.1ȱwouldȱexamineȱtheȱnodesȱinȱthisȱorderȱ5,ȱ9,ȱ12,ȱ16,ȱ17,ȱ20,ȱ25,ȱ26,ȱ28,ȱ29.ȱ
Aȱ postȬorderȱ traversalȱ traversesȱ theȱ leftȱ andȱ rightȱ subtreesȱ firstȱ andȱ examinesȱ
theȱnodeȇsȱvalueȱlast.ȱAȱpostȬorderȱtraversalȱofȱtheȱsameȱtreeȱwouldȱexamineȱtheȱnodesȱ
inȱthisȱorder:ȱ9,ȱ5,ȱ17,ȱ16,ȱ12,ȱ26,ȱ29,ȱ28,ȱ25,ȱ20.ȱ
Finally,ȱ aȱ breadthȬfirstȱ traversalȱ examinesȱ theȱ nodesȱ ofȱ theȱ treeȱ levelȱ byȱ level.ȱȱ
Firstȱtheȱrootȱisȱprocessed,ȱthenȱitsȱchildren,ȱthenȱallȱofȱitsȱgrandchildren,ȱandȱsoȱforth.ȱȱ
Traversingȱtheȱsampleȱtreeȱinȱthisȱmannerȱwouldȱexamineȱtheȱnodesȱinȱthisȱorder:ȱ20,ȱ
12,ȱ25,ȱ5,ȱ16,ȱ28,ȱ9,ȱ17,ȱ26,ȱ29.ȱAlthoughȱtheȱfirstȱthreeȱtraversalsȱareȱeasilyȱimplementedȱ
asȱrecursiveȱ functions,ȱtheȱbreadthȬfirstȱ traversalȱ isȱanȱ iterativeȱ algorithmȱ thatȱusesȱaȱ
queue.ȱTheȱexercisesȱdescribeȱitȱinȱmoreȱdetail.ȱ
ȱ
ȱ
ȱ
17.4.5
Binary Search Tree Interface
ȱ
TheȱinterfaceȱinȱProgramȱ17.7ȱprototypesȱtheȱfunctionȱforȱinsertingȱvaluesȱintoȱaȱbinaryȱ
searchȱtree.ȱItȱalsoȱincludesȱaȱ findȱfunctionȱtoȱfindȱaȱspecificȱvalueȱinȱtheȱtree,ȱwhichȱ
returnsȱaȱpointerȱtoȱtheȱvalueȱthatȱwasȱfound.ȱOnlyȱoneȱtraversalȱfunctionȱisȱdefined,ȱ
becauseȱtheȱinterfacesȱforȱtheȱremainingȱonesȱdifferȱinȱnameȱonly.ȱ
ȱ
ȱ
ȱ
17.4.6
Implementing a Binary Search Tree
ȱ
Althoughȱ linkedȱ treeȱ implementationsȱ areȱ byȱ farȱ theȱ mostȱ common,ȱ itȱ isȱ possibleȱ toȱ
storeȱaȱbinaryȱsearchȱtreeȱinȱanȱarray.ȱOfȱcourse,ȱtheȱfixedȱlengthȱofȱtheȱarrayȱlimitsȱtheȱ
numberȱofȱelementsȱthatȱcanȱbeȱaddedȱtoȱtheȱtree,ȱbutȱifȱyouȱuseȱdynamicȱallocationȱ
Download at http://www.pin5i.com/
17.4 Treesȱ
517
ȱ
ȱ
/*
** Interface for a binary search tree module
*/
#define
TREE_TYPE
int
/* Type of value in the tree */
/*
** insert
**
Add a new value to the tree. The argument is the value
**
to be added and must not already exist in the tree.
*/
void insert( TREE_TYPE value );
/*
** find
**
Searches for a specific value, which is passed as the first
**
argument.
*/
TREE_TYPE *find( TREE_TYPE value );
/*
** pre_order_traverse
**
Does a pre-order traversal of the tree. The argument is a
**
pointer to a callback function that will be called for
**
each node in the tree, with the value passed as an argument.
*/
void pre_order_traverse( void (*callback)( TREE_TYPE value ) );
ȱ
Programȱ17.7ȱȱBinaryȱsearchȱtreeȱinterfaceȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱȱȱȱȱtree.hȱ
ȱ
ȱ
ȱ
ȱ
youȱ canȱ createȱ aȱ largerȱ spaceȱ andȱ copyȱ theȱ valuesȱ intoȱ itȱ whenȱ theȱ originalȱ arrayȱ
overflows.ȱ
ȱ
ȱ
ȱ
An Arrayed, Binary Search Tree
ȱ
Theȱ keyȱ toȱ representingȱ aȱ treeȱ inȱ anȱ arrayȱ isȱ coȱ useȱ subscriptsȱ toȱ locateȱ parentsȱ andȱ
childrenȱofȱaȱparticularȱvalue.ȱTheȱrulesȱareȱeasy:ȱ
ȱ
TheȱparentȱofȱnodeȱNȱisȱnodeȱN/2.ȱ
ȱTheȱleftȱchildȱofȱnodeȱNȱisȱnodeȱ2N.ȱ
TheȱrightȱchildȱofȱnodeȱNȱisȱnodeȱ2Nȱ+ȱ1.ȱ
ȱ
Theȱformulaȱforȱtheȱparentȱworksȱbecauseȱtheȱintegerȱdivisionȱoperatorȱtruncatesȱanyȱ
fractionalȱpart.ȱ
Download at http://www.pin5i.com/
Chapter 17 Classic Abstract Data Typesȱ
518ȱ
ȱ
CAUTION!
ȱ
Alas,ȱ thereȱ isȱ aȱ minorȱ problem.ȱ Theseȱ rulesȱ assumeȱ thatȱ theȱ rootȱ ofȱ theȱ treeȱ isȱ nodeȱ
one,ȱbutȱCȱarraysȱbeginȱwithȱsubscriptȱzero.ȱTheȱeasiestȱsolutionȱisȱtoȱsimplyȱignoreȱtheȱ
firstȱelementȱofȱtheȱarray.ȱIfȱtheȱelementsȱareȱsoȱlargeȱthatȱthisȱapproachȱwouldȱwasteȱ
tooȱmuchȱspace,ȱthenȱyouȱcanȱuseȱtheseȱalternateȱrulesȱforȱzeroȬbasedȱarrayȱsubscriptsȱ
instead:ȱ
ȱ
TheȱparentȱofȱnodeȱNȱisȱnodeȱ(Nȱ+ȱ1)/2ȱȬȱ1.ȱ
TheȱleftȱchildȱofȱnodeȱNȱisȱnodeȱ2Nȱ+ȱ1.ȱ
TheȱrightȱchildȱofȱnodeȱNȱisȱnodeȱ2Nȱ+ȱ2.ȱ
ȱ
Programȱ17.8ȱisȱaȱbinaryȱsearchȱtreeȱimplementedȱwithȱaȱstaticȱarray.ȱThereȱareȱ
severalȱ pointsȱ ofȱ interestȱ inȱ thisȱ implementation.ȱ Itȱ usesȱ theȱ simplerȱ rulesȱ forȱ
determiningȱchildrenȱsoȱtheȱarrayȱisȱdeclaredȱoneȱlargerȱthanȱtheȱadvertisedȱsizeȱandȱ
itsȱ firstȱ elementȱ isȱ ignored.ȱ Functionsȱ areȱ definedȱ toȱ computeȱ theȱ leftȱ andȱ rightȱ
childrenȱofȱaȱnode.ȱEvenȱthoughȱtheȱcomputationȱisȱsimple,ȱtheȱfunctionȱnamesȱmakeȱ
theȱ codeȱ thatȱ useȱ themȱ muchȱ clearer.ȱ Theseȱ functionsȱ alsoȱ simplifyȱ theȱ taskȱ ofȱ
modifyingȱtheȱmoduleȱtoȱuseȱtheȱalternateȱsetȱofȱrules.ȱ
Thisȱ implementationȱ usesȱ theȱ valueȱ zeroȱ toȱ indicateȱ aȱ nodeȱ thatȱ isȱ notȱ beingȱ
used.ȱIfȱzeroȱisȱaȱlegitimateȱdataȱvalue,ȱaȱdifferentȱvalueȱmustȱbeȱchosenȱandȱtheȱarrayȱ
elementsȱmustȱbeȱinitializedȱdynamically.ȱAnotherȱtechniqueȱisȱtoȱhaveȱaȱcompanionȱ
arrayȱofȱbooleanȱvaluesȱtoȱindicateȱwhichȱnodesȱareȱinȱuse.ȱ
Aȱproblemȱwithȱanȱarrayedȱtreeȱisȱthatȱtheȱspaceȱinȱtheȱarrayȱisȱoftenȱnotȱusedȱ
effectively.ȱSpaceȱisȱwastedȱbecauseȱnewȱvaluesȱmustȱbeȱinsertedȱatȱspecificȱplacesȱinȱ
theȱtreeȱandȱcannotȱjustȱbeȱputȱwhereverȱthereȱhappensȱtoȱbeȱspace.ȱ
Toȱ illustrate,ȱ supposeȱ anȱ arrayȱ ofȱ 100ȱ elementsȱ isȱ usedȱ toȱ holdȱ aȱ tree.ȱ Ifȱ theȱ
valuesȱ1,ȱ2,ȱ3,ȱ4,ȱ5,ȱ6,ȱandȱ7ȱareȱinsertedȱinȱthatȱorder,ȱtheyȱwillȱbeȱstoredȱinȱlocationsȱ1,ȱ
2,ȱ4,ȱ8,ȱ16,ȱ32,ȱandȱ64,ȱrespectively.ȱButȱnowȱtheȱvalueȱ8ȱcannotȱbeȱinsertedȱbecauseȱtheȱ
rightȱ childȱ ofȱ 7ȱ wouldȱ beȱ storedȱ inȱ locationȱ 128,ȱ andȱ theȱ arrayȱ isȱ notȱ thatȱ large.ȱ
Whetherȱorȱnotȱthisȱproblemȱactuallyȱhappensȱdependsȱentirelyȱonȱtheȱorderȱinȱwhichȱ
theȱ valuesȱareȱinserted.ȱIfȱ theȱ sameȱvaluesȱwereȱ insertedȱinȱthisȱ order,ȱ4,ȱ 2,ȱ1,ȱ 3,ȱ6,ȱ 5,ȱ
andȱ7,ȱtheyȱwouldȱoccupyȱlocationsȱ1ȱthroughȱ7ȱofȱtheȱarray,ȱandȱtheȱvalueȱ8ȱcouldȱbeȱ
insertedȱwithoutȱdifficulty.ȱ
Withȱ aȱ dynamicallyȱ allocatedȱ array,ȱ weȱ canȱ reallocateȱ theȱ arrayȱ whenȱ moreȱ
spaceȱ isȱ needed.ȱ Thisȱ techniqueȱ isȱ notȱ aȱ veryȱ goodȱ solutionȱ toȱ theȱ problemȱ ofȱ anȱ
unbalancedȱ tree,ȱ though,ȱ becauseȱ eachȱ newȱ insertionȱ requiresȱ theȱ arrayȱ sizeȱ toȱ beȱ
doubled,ȱ andȱ theȱ spaceȱ availableȱ forȱ dynamicȱ memoryȱ allocationȱ willȱ soonȱ beȱ
exhausted.ȱAȱbetterȱsolutionȱisȱtoȱuseȱaȱlinkedȱbinaryȱtreeȱratherȱthanȱanȱarray.ȱ
Download at http://www.pin5i.com/
17.4 Treesȱ
519
ȱ
ȱ
/*
** A binary search tree implemented with a static array. The
** array size can be adjusted only by changing the #define and
** recompiling the module.
*/
#include "tree.h"
#include <assert.h>
#include <stdio.h>
#define
#define
TREE_SIZE
ARRAY_SIZE
100
/* Max # of values in the tree */
( TREE_SIZE + 1 )
/*
**
The array that holds the values in the tree.
*/
static
TREE_TYPE
tree[ ARRAY_SIZE ];
/*
** left_child
**
Compute the subscript of the left child of a node.
*/
static int
left_child( int current )
{
return current * 2;
}
/*
** right_child
**
Compute the subscript of the right child of a node.
*/
static int
right_child( int current )
{
return current * 2 + 1;
}
/*
** insert
*/
void
insert( TREE_TYPE value )
{
int
current;
ȱ
Programȱ17.8ȱȱBinaryȱsearchȱtreeȱimplementedȱwithȱaȱstaticȱarrayȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
520ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
ȱ
/*
** Ensure the value is nonzero, because zero indicates an
** unused node.
*/
assert( value != 0 );
/*
** Start with the root node.
*/
current = 1;
/*
** Go to the proper subtree until we reach a leaf.
*/
while( tree[ current ] != 0 ){
/*
** Go to the left or right subtree, as appropriate.
** (And make sure we don't have a duplicate value!)
*/
if( value < tree[ current ] )
current = left_child( current );
else {
assert( value != tree[ current ] );
current = right_child( current );
}
assert( current < ARRAY_SIZE );
}
tree[ current ] = value;
}
/*
** find
*/
TREE_TYPE *
find( TREE_TYPE value )
{
int
current;
/*
** Start with the root node.
** go to the proper subtree.
*/
current = 1;
Until we find the value,
ȱ
Programȱ17.8ȱȱBinaryȱsearchȱtreeȱimplementedȱwithȱaȱstaticȱarrayȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
17.4 Treesȱ
521
ȱ
ȱ
while( current < ARRAY_SIZE && tree[ current ] != value ){
/*
** Go to the left or right subtree, as appropriate.
*/
if( value < tree[ current ] )
current = left_child( current );
else
current = right_child( current );
}
if( current < ARRAY_SIZE )
return tree + current;
else
return 0;
}
/*
** do_pre_order_traverse
**
Do one level of a pre-order traverse. This helper function
**
is needed to save the information of which node we're
**
currently processing; this is not a part of the client's
**
interface.
*/
static void
do_pre_order_traverse( int current,
void (*callback)( TREE_TYPE value ) )
{
if( current < ARRAY_SIZE && tree[ current ] != 0 ){
callback( tree[ current ] );
do_pre_order_traverse( left_child( current ),
callback );
do_pre_order_traverse( right_child( current ),
callback );
}
}
/*
** pre_order_traverse
*/
void
pre_order_traverse( void (*callback)( TREE_TYPE value ) )
{
do_pre_order_traverse( 1, callback );
}
ȱ
Programȱ17.8ȱȱBinaryȱsearchȱtreeȱimplementedȱwithȱaȱstaticȱarrayȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱa_tree.cȱ
Download at http://www.pin5i.com/
522ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
A Linked Binary Search Tree
ȱ
Theȱ linkedȱ implementationȱ eliminatesȱ theȱ problemȱ ofȱ unusedȱ arrayȱ spaceȱ byȱ
dynamicallyȱ allocatingȱ memoryȱ toȱ holdȱ eachȱ newȱ valueȱ andȱ linkingȱ theseȱ structuresȱ
togetherȱintoȱaȱtree.ȱThus,ȱthereȱisnȇtȱanyȱunusedȱmemory.ȱ
Programȱ 17.9ȱ isȱ theȱ linkedȱ implementation.ȱ Compareȱ itȱ withȱ theȱ arrayedȱ treeȱ
implementationȱ inȱ Programȱ 17.8.ȱ Becauseȱeachȱ nodeȱ inȱ theȱ treeȱ mustȱ pointȱ toȱ itsȱ leftȱ
andȱ rightȱ children,ȱ aȱ structureȱ isȱ usedȱ toȱ holdȱ theȱ valueȱ andȱ theȱ twoȱ pointers.ȱ Theȱ
arrayȱ isȱ replacedȱ byȱ aȱ pointerȱ toȱ theȱ rootȱ ofȱ theȱ tree.ȱ Thisȱ pointerȱ isȱ initiallyȱ NULL,ȱ
indicatingȱthatȱtheȱtreeȱisȱempty.ȱ
Theȱ insertȱfunctionȱusesȱtwoȱpointers. 56 ȱTheȱfirstȱisȱusedȱtoȱexamineȱnodesȱinȱ
theȱ treeȱ toȱ findȱ theȱ properȱ placeȱ toȱ insertȱ theȱ newȱ value.ȱ Theȱ secondȱ isȱ aȱ pointerȱ toȱ
whateverȱ linkȱ pointsȱ toȱ theȱ nodeȱ currentlyȱ beingȱ examined.ȱ Whenȱ aȱ leafȱ isȱ reached,ȱ
thisȱ pointerȱ isȱ theȱ oneȱ thatȱ mustȱ beȱ changedȱ toȱ insertȱ theȱ newȱ node.ȱ Theȱ functionȱ
walksȱ downȱ theȱ tree,ȱ goingȱ leftȱ orȱ rightȱ accordingȱ toȱ howȱ theȱ newȱ valueȱ comparesȱ
withȱtheȱcurrentȱnodeȇsȱvalue,ȱuntilȱaȱleafȱisȱreached.ȱThenȱaȱnewȱnodeȱisȱcreatedȱandȱ
linkedȱintoȱtheȱtree.ȱThisȱiterativeȱalgorithmȱinsertsȱtheȱfirstȱnodeȱinȱtheȱtreeȱproperlyȱ
withoutȱaȱspecialȱcase.ȱ
ȱ
ȱ
ȱ
Variations on the Tree Interface
ȱ
Asȱ itȱ isȱ shown,ȱ theȱ findȱ functionȱ reallyȱ onlyȱ checksȱ forȱ membership.ȱ Returningȱ aȱ
pointerȱtoȱtheȱvalueȱthatȱwasȱfoundȱisnȇtȱtooȱusefulȱbecauseȱtheȱcallerȱalreadyȱknowsȱ
theȱvalue:ȱitȱwasȱpassedȱasȱanȱargument!ȱ
Supposeȱtheȱvaluesȱcontainedȱinȱtheȱtreeȱareȱinȱfactȱstructuresȱthatȱcontainȱaȱkeyȱ
valueȱandȱsomeȱdata.ȱNowȱweȱcanȱmodifyȇȱtheȱ findȱfunctionȱtoȱbeȱmuchȱmoreȱuseful.ȱ
Locatingȱ aȱ particularȱ nodeȱ byȱ itsȱ keyȱ andȱ thenȱ returningȱ aȱ pointerȱ toȱ theȱ structureȱ
givesȱtheȱclientȱsomethingȱheȱdidnȇtȱpreviouslyȱhave—ȱtheȱdataȱthatȱisȱassociatedȱwithȱ
theȱ key.ȱ However,ȱ toȱ achieveȱ thisȱ resultȱ findȱ mustȱ somehowȱ compareȱ onlyȱ theȱ keyȱ
portionȱofȱtheȱvalueȱinȱeachȱnode.ȱTheȱsolutionȱisȱtoȱwriteȱaȱfunctionȱthatȱmakesȱthisȱ
comparisonȱandȱpassȱfindȱaȱpointerȱtoȱtheȱfunctionȱlikeȱweȱdidȱwithȱqsort.ȱ
Sometimesȱ theȱ clientȱ mayȱ wantȱ toȱ traverseȱ theȱ treeȱ himself,ȱ forȱ example,ȱ toȱ
countȱtheȱnumberȱofȱchildrenȱbelongingȱtoȱeachȱnode.ȱBothȱtheȱTreeNodeȱstructureȱandȱ
theȱpointerȱtoȱtheȱrootȱnodeȱofȱtheȱtreeȱmustȱbeȱmadeȱpublicȱforȱtheȱclientȱtoȱtraverseȱ
theȱ tree.ȱ Theȱ safestȱ wayȱ ofȱ providingȱ theȱ rootȱ pointerȱ isȱ throughȱ aȱ function,ȱ thusȱ
preventingȱtheȱclientȱfromȱchangingȱtheȱrootȱpointerȱhimselfȱandȱlosingȱtheȱtree.ȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
ȱWeȱusedȱtheȱsameȱtechniqueȱinȱChapterȱ12ȱinȱtheȱfunctionȱthatȱinsertedȱvaluesȱintoȱanȱordered,ȱsinglyȱlinkedȱlist.ȱ!fȱyouȱ
lookȱ atȱ theȱ pathȱ thatȱ isȱ followedȱ fromȱ theȱ rootȱ ofȱ theȱ treeȱ toȱ theȱ leafȱ whereȱ theȱ insertionȱ willȱ occur,ȱ youȱ willȱ seeȱ thatȱ itȱ isȱ
essentiallyȱaȱsinglyȱlinkedȱlist.ȱ
56
Download at http://www.pin5i.com/
17.4 Treesȱ
523
ȱ
ȱ
/*
** A binary search tree implemented by linking dynamically allocated
** structures.
*/
#include "tree.h"
#include <assert.h>
#include <stdio.h>
#include <malloc.h>
/*
**
The TreeNode structure holds the value and pointers for one
**
tree node.
*/
typedef struct TREE_NODE {
TREE_TYPE
value;
struct TREE_NODE *left;
struct TREE_NODE *right;
} TreeNode;
/*
**
The pointer to the root node in the tree.
*/
static
TreeNode
*tree;
/*
**
insert
*/
void
insert( TREE_TYPE value )
{
TreeNode
*current;
TreeNode
**link;
/*
** Start with the root node.
*/
link = &tree;
/*
** As long as we keep finding values, go to the proper
** subtree.
*/
while( (current = *link) != NULL ){
/*
** Go to the left or right subtree, as appropriate.
ȱ
Programȱ17.9ȱȱLinkedȱbinaryȱsearchȱtreeȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
524ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
ȱ
** (And make sure we don't have a duplicate value!)
*/
if( value < current->value )
link = &current->left;
else {
assert( value != current->value );
link = &current->right;
}
}
/*
** Allocate a new node; make the proper link field point
** to it.
*/
current = malloc( sizeof( TreeNode ) );
assert( current != NULL );
current->value = value;
current->left = NULL;
current->right = NULL;
*link = current;
}
/*
**
find
*/
TREE_TYPE *
find( TREE_TYPE value )
{
TreeNode
*current;
/*
** Start with the root node.
** go to the proper subtree.
*/
current = tree;
Until we find the value,
while( current != NULL && current->value != value ){
/*
** Go to the left or right subtree, as appropriate.
*/
if( value < current->value )
current = current->left;
else
current = current->right;
}
ȱ
Programȱ17.9ȱȱLinkedȱbinaryȱsearchȱtreeȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
17.4 Treesȱ
525
ȱ
ȱ
if( current != NULL )
return &current->value;
else
return NULL;
}
/*
** do_pre_order_traverse
**
Do one level of a pre-order traverse. This helper function
**
is needed to save the information of which node we're
**
currently processing; this is not a part of the
**
client's interface.
*/
static void
do_pre_order_traverse( TreeNode *current,
void (*callback)( TREE_TYPE value ) )
{
if( current != NULL ){
callback( current->value );
do_pre_order_traverse( current->left, callback );
do_pre_order_traverse( current->right, callback );
}
}
/*
**
pre_order_traverse
*/
void
pre_order_traverse( void (*callback)( TREE_TYPE value ) )
{
do_pre_order_traverse( tree, callback );
}
ȱ
Programȱ17.9ȱȱLinkedȱbinaryȱsearchȱtreeȱȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱȱȱȱȱl_tree.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Itȱ isȱ oftenȱ helpfulȱ forȱ eachȱ treeȱ nodeȱ toȱ haveȱ aȱ pointerȱ toȱ itsȱ parentȱ node.ȱ Theȱ
clientȱ canȱ useȱ theȱ parentȱ pointerȱ toȱ moveȱ bothȱ upȱ andȱ downȱ inȱ theȱ tree.ȱ Theȱ findȱ
functionȱ inȱ thisȱ moreȱ publicȱ treeȱ couldȱ thenȱ returnȱ aȱ pointerȱ toȱ theȱ treeȱ nodeȱ ratherȱ
thanȱ theȱ value,ȱ whichȱ wouldȱ allowȱ theȱ clientȱ toȱ useȱ thatȱ pointerȱ asȱ theȱ beginningȱ ofȱ
otherȱtraversals.ȱ
Oneȱ finalȱ improvementȱ isȱ aȱ destroy_treeȱ functionȱ toȱ freeȱ allȱ ofȱ theȱ memoryȱ
thatȱ wasȱ allocatedȱ forȱ theȱ tree.ȱ Theȱ implementationȱ ofȱ thisȱ functionȱ isȱ leftȱ asȱ anȱ
exercise.ȱ
Download at http://www.pin5i.com/
Chapter 17 Classic Abstract Data Typesȱ
526ȱ
ȱ
17.5 Improvements in Implementation
ȱ
TheȱimplementationsȱinȱthisȱchapterȱillustrateȱhowȱtheȱdifferentȱADTsȱwork,ȱbutȱtheyȱ
areȱinadequateȱinȱseveralȱrespectsȱforȱuseȱinȱrealȱprograms.ȱThisȱsectionȱidentifiesȱtheseȱ
problemsȱ andȱ suggestsȱ howȱ toȱ solveȱ them.ȱ Weȱ useȱ theȱ arrayedȱ stackȱ asȱ anȱ example,ȱ
butȱtheȱtechniquesȱdescribedȱapplyȱtoȱtheȱotherȱADTsȱasȱwell.ȱ
ȱ
ȱ
ȱ
17.5.1
CAUTION!
Having More Than One Stack
ȱ
Theȱ mainȱ problemȱ withȱ theȱ implementationsȱ soȱ farȱ isȱ that,ȱ theyȱ encapsulateȱ theȱ
memoryȱusedȱtoȱholdȱtheȱstructureȱasȱwellȱasȱtheȱfunctionsȱthatȱmanipulateȱit.ȱThusȱaȱ
programȱcannotȱhaveȱmoreȱthanȱoneȱstack!ȱ
Thisȱ limitationȱ isȱ easilyȱ solvedȱ byȱ removingȱ theȱ declarationsȱ ofȱ theȱ arrayȱ andȱ
top_elementȱ fromȱ theȱ stackȱ implementationȱ moduleȱ andȱ puttingȱ themȱ inȱ theȱ clientȇsȱ
codeȱinstead.ȱTheyȱareȱthenȱaccessedȱbyȱtheȱstackȱfunctionsȱthroughȱarguments,ȱsoȱtheȱ
functionsȱareȱnoȱlongerȱtiedȱtoȱoneȱarray.ȱTheȱclientȱcanȱcreateȱanyȱnumberȱofȱarraysȱ
andȱmanipulateȱthemȱasȱstacksȱbyȱcallingȱtheȱstackȱfunctions.ȱ
ȱ
Theȱdangerȱwithȱthisȱapproachȱisȱtheȱlossȱofȱencapsulation.ȱIfȱtheȱclientȱhasȱtheȱdata,ȱheȱ
canȱaccessȱitȱdirectly.ȱIllegalȱaccesses,ȱforȱexampleȱaddingȱaȱnewȱvalueȱtoȱtheȱarrayȱinȱ
theȱwrongȱplaceȱorȱaddingȱaȱvalueȱwithoutȱadjustingȱtop_element,ȱcanȱresultȱinȱlostȱorȱ
illegalȱdataȱorȱmayȱcauseȱtheȱstackȱfunctionsȱtoȱfail.ȱ
Aȱ relatedȱ problemȱ isȱ ensuringȱ thatȱ theȱ clientȱ passesȱ theȱ correctȱ stackȱ andȱ
top_elementȱ argumentsȱ toȱ eachȱ stackȱ functionȱ thatȱ isȱ called.ȱ Ifȱ theseȱ argumentsȱ areȱ
mixedȱ up,ȱ theȱ resultȱ isȱ garbage.ȱ Weȱ canȱ reduceȱ theȱ likelihoodȱ ofȱ thisȱ happeningȱ byȱ
bundlingȱtheȱstackȱarrayȱandȱitsȱtop_elementȱvalueȱtogetherȱinȱaȱstructure.ȱ
Thereȱ wasnȇtȱ anyȱ dangerȱ ofȱ eitherȱ problemȱ occurringȱ whenȱ theȱ stackȱ moduleȱ
containedȱ theȱ data.ȱ Theȱ exercisesȱ describeȱ aȱ modificationȱ thatȱ letsȱ theȱ stackȱ moduleȱ
manageȱmoreȱthanȱoneȱstack.ȱ
ȱ
ȱ
ȱ
17.5.2
Having More Than One Type
ȱ
Evenȱifȱtheȱpreviousȱproblemȱisȱsolvedȱtheȱtypeȱofȱvaluesȱstoredȱonȱtheȱstackȱisȱfixedȱatȱ
compileȱtimeȱbyȱtheȱtypeȱinȱtheȱstack.hȱheaderȱfile.ȱIfȱyouȱneedȱaȱstackȱofȱintegersȱandȱ
aȱstackȱofȱfloats,ȱyouȇreȱoutȱofȱluck.ȱ
ȱ
Download at http://www.pin5i.com/
17.5 Improvements in Implementationȱ
527
ȱ
CAUTION!
Theȱ simplisticȱ wayȱ ofȱ solvingȱ thisȱ problemȱ isȱ toȱ writeȱ aȱ separateȱ copyȱ ofȱ theȱ
stackȱfunctionsȱtoȱ dealȱwithȱeachȱdifferentȱdataȱtype.ȱ Thisȱ approachȱdoesȱtheȱjobȱbutȱ
involvesȱaȱlotȱofȱduplicatedȱcode,ȱwhichȱmakesȱmaintenanceȱmoreȱdifficult.ȱ
Aȱmoreȱelegantȱapproachȱisȱtoȱimplementȱtheȱentireȱstackȱmoduleȱasȱaȱ #defineȱ
thatȱ takesȱ theȱ desiredȱ typeȱ asȱ aȱ parameter.ȱ Thisȱ definitionȱ isȱ thenȱ usedȱ toȱ createȱ theȱ
routinesȱforȱeachȱtypeȱthatȱisȱrequired.ȱForȱthisȱsolutionȱtoȱwork,ȱthough,ȱweȱmustȱfindȱ
aȱwayȱtoȱmakeȱtheȱnamesȱofȱtheȱfunctionsȱgeneratedȱforȱdifferentȱtypesȱuniqueȱsoȱthatȱ
theyȱdonȇtȱconflictȱwithȱeachȱother.ȱYouȱmustȱalsoȱbeȱcarefulȱtoȱcreateȱonlyȱoneȱsetȱofȱ
routinesȱforȱeachȱtypeȱnoȱmatterȱhowȱmanyȱstacksȱofȱthatȱtypeȱyouȱneed.ȱAnȱexampleȱ
ofȱthisȱapproachȱisȱpresentedȱinȱSectionȱ17.5.4.ȱ
Aȱthirdȱapproachȱisȱtoȱmakeȱtheȱstackȱtypelessȱbyȱhavingȱitȱstoreȱ void *ȱvalues.ȱ
Toȱstoreȱintegersȱandȱotherȱdataȱthatȱtakesȱtheȱsameȱamountȱofȱspaceȱasȱaȱpointer,ȱcastsȱ
areȱusedȱtoȱconvertȱtheȱdesiredȱtypeȱtoȱ void *ȱinȱtheȱargumentȱtoȱ pushȱandȱtoȱconvertȱ
theȱvalueȱreturnedȱbyȱ topȱbackȱtoȱtheȱdesiredȱtype.ȱToȱworkȱwithȱlargerȱdata,ȱsuchȱasȱ
structures,ȱpointersȱtoȱtheȱdataȱareȱstoredȱonȱtheȱstack.ȱ
ȱ
Theȱproblemȱwithȱthisȱapproachȱisȱtheȱlossȱofȱtypeȱchecking.ȱThereȱisȱnoȱwayȱtoȱverifyȱ
thatȱtheȱvalueȱpassedȱtoȱpushȱisȱtheȱcorrectȱtypeȱforȱtheȱstackȱbeingȱused.ȱIfȱanȱintegerȱisȱ
accidentallyȱ pushedȱ onȱ aȱ stackȱ thatȱ containsȱ pointers,ȱ theȱ resultȱ isȱ almostȱ sureȱ toȱ beȱ
disaster.ȱ
Makingȱ theȱ treeȱ moduleȱ typelessȱ isȱ aȱ littleȱ moreȱ difficultȱ becauseȱ theȱ treeȱ
functionsȱmustȱcompareȱvaluesȱinȱtheȱtreeȱnodes.ȱHowever,ȱweȱcanȱpassȱaȱpointerȱtoȱaȱ
comparisonȱfunctionȱwrittenȱbyȱtheȱclientȱasȱanȱargumentȱtoȱeachȱtreeȱfunction.ȱAgain,ȱ
theȱresultȱofȱpassingȱtheȱwrongȱpointerȱisȱdisaster.ȱ
ȱ
ȱ
ȱ
17.5.3
Name Clashes
ȱ
Bothȱtheȱstackȱandȱqueueȱmodulesȱhaveȱ is_fullȱandȱ is_emptyȱfunctions,ȱandȱbothȱtheȱ
queueȱ andȱ treeȱ modulesȱ haveȱ anȱ insertȱ function.ȱ Ifȱ youȱ wantedȱ toȱ addȱ aȱ deleteȱ
functionȱ toȱ theȱ treeȱ module,ȱ itȱ wouldȱ conflictȱ withȱ theȱ oneȱ alreadyȱ inȱ theȱ queueȱ
module.ȱ
Toȱcoexistȱinȱoneȱprogram,ȱtheȱnamesȱofȱallȱofȱtheseȱfunctionsȱmustȱbeȱunique.ȱ
However,ȱ thereȱ isȱ strongȱ motivationȱ toȱ retainȱ theȱ ȈstandardȈȱ namesȱ associatedȱ withȱ
eachȱ dataȱ structureȱ wheneverȱ possible.ȱ Theȱ solutionȱ isȱ toȱ compromise:ȱ chooseȱ aȱ
namingȱ conventionȱ thatȱ isȱ tolerableȱ andȱ stickȱ withȱ it.ȱ Forȱ example,ȱ is_queue_emptyȱ
andȱ is_atack_emptyȱ solveȱ theȱ problem.ȱ Theirȱ disadvantageȱ isȱ thatȱ theȱ longerȱ namesȱ
areȱnotȱasȱconvenientȱtoȱuse,ȱyetȱtheyȱdoȱnotȱconveyȱanyȱadditionalȱinformation.ȱ
Download at http://www.pin5i.com/
Chapter 17 Classic Abstract Data Typesȱ
528ȱ
ȱ
17.5.4
Standard Libraries of ADTs
ȱ
Computerȱscienceȱisȱnotȱanȱoldȱdiscipline,ȱbutȱweȱhaveȱcertainlyȱbeenȱatȱitȱlongȱenoughȱ
toȱ learnȱ everythingȱ thereȱ isȱ toȱ knowȱ aboutȱ theȱ behaviorȱ ofȱ stacksȱ andȱ queues.ȱ Thenȱ
whyȱ doesȱ everyoneȱ writeȱ theirȱ ownȱ stackȱ andȱ queueȱ functions?ȱ Whyȱ arenȇtȱ theseȱ
ADTsȱpanȱofȱtheȱstandardȱlibrary?ȱ
Itȱisȱbecauseȱofȱtheȱthreeȱproblemsȱjustȱdiscussed.ȱTheȱnameȱclashesȱareȱsolvedȱ
easilyȱenough,ȱbutȱtheȱlackȱofȱtypeȱsafetyȱandȱtheȱdangersȱthatȱcomeȱfromȱgivingȱtheȱ
clientȱ directȱ accessȱ toȱ theȱ dataȱ makeȱ itȱ infeasibleȱ toȱ writeȱ aȱ libraryȱ ofȱ functionsȱ thatȱ
implementȱaȱstackȱinȱaȱgeneral,ȱyetȱsafeȱway.ȱ
Solvingȱthisȱproblemȱrequiresȱgenericity,ȱtheȱabilityȱtoȱwriteȱaȱsetȱofȱfunctionsȱinȱ
whichȱ theȱ typesȱ ofȱ theȱ dataȱ haveȱ notȱ yetȱ beenȱ decided.ȱ Thisȱ setȱ ofȱ functionsȱ isȱ thenȱ
instantiated,ȱorȱcreated,ȱwithȱeachȱdifferentȱtypeȱthatȱisȱneeded.ȱCȱdoesȱnotȱprovideȱthisȱ
capability,ȱbutȱweȱcanȱuseȱtheȱ#defineȱmechanismȱtoȱapproximateȱit.ȱ
Programȱ17.10aȱcontainsȱaȱ #defineȱwhoseȱbodyȱisȱtheȱentireȱimplementationȱofȱ
anȱ arrayedȱ stack.ȱ Theȱ argumentsȱ toȱ theȱ #defineȱ areȱ theȱ typeȱ ofȱ valueȱ toȱ beȱ stored,ȱ aȱ
suffix,ȱandȱtheȱarrayȱsizeȱtoȱuse.ȱTheȱsuffixȱisȱappendedȱtoȱeachȱofȱtheȱnamesȱdefinedȱ
byȱtheȱimplementationȱtoȱavoidȱnameȱclashes.ȱ
Programȱ17.10bȱusesȱtheȱdeclarationȱinȱProgramȱ17.10aȱtoȱcreateȱtwoȱstacks,ȱoneȱ
thatȱ holdsȱ upȱ toȱ tenȱ integersȱ andȱ anotherȱ thatȱ holdsȱ upȱ toȱ fiveȱ floats.ȱ Whenȱ eachȱ
#defineȱisȱexpanded,ȱ aȱnewȱsetȱofȱstackȱroutinesȱ isȱ createdȱtoȱ manipulateȱ theȱproperȱ
typeȱ ofȱ data.ȱ However,ȱ ifȱ twoȱ stacksȱ ofȱ integersȱ wereȱ needed,ȱ twoȱ setsȱ ofȱ identicalȱ
functionsȱwouldȱbeȱcreated.ȱ
Weȱ solveȱ thisȱ problemȱ byȱ rewritingȱ Programȱ 17.10aȱ asȱ threeȱ separateȱ macros:ȱ
oneȱtoȱdeclareȱtheȱinterface,ȱoneȱtoȱcreateȱtheȱfunctionsȱthatȱmanipulateȱtheȱdata,ȱandȱ
oneȱtoȱcreateȱtheȱdata.ȱWhenȱtheȱfirstȱstackȱofȱintegersȱisȱneeded,ȱallȱthreeȱmacrosȱareȱ
used.ȱAdditionalȱstacksȱofȱintegersȱareȱcreatedȱbyȱrepeatedlyȱinvokingȱtheȱlastȱmacro.ȱȱ
Theȱinterfaceȱtoȱtheȱstackȱmustȱalsoȱbeȱchanged.ȱTheȱfunctionsȱmustȱtakeȱanȱadditionalȱ
argumentȱthatȱspecifiesȱtheȱstackȱtoȱmanipulate.ȱTheseȱmodificationsȱareȱtheȱsubjectȱofȱ
aȱprogrammingȱexercise.ȱ
Thisȱ techniqueȱ makesȱ itȱ possibleȱ toȱ createȱ aȱ libraryȱ ofȱ genericȱ abstractȱ dataȱ
types.ȱ However,ȱ theȱ addedȱ flexiblityȱ comesȱ withȱ aȱ price.ȱ Theȱ userȱ hasȱ severalȱ newȱ
responsibilities.ȱHeȱorȱsheȱmustȱnow:ȱ
ȱ
1. decideȱ onȱ aȱ namingȱ conventionȱ toȱ avoidȱ nameȱ clashesȱ amongȱ stacksȱ ofȱ differentȱ
types,ȱ
2. beȱsureȱtoȱcreateȱexactlyȱoneȱsetȱofȱstackȱroutinesȱforȱeachȱdifferentȱtype,ȱ
3. beȱ sureȱ toȱ useȱ theȱ properȱ nameȱ (forȱ example,ȱ push_intȱ versusȱ push_float)ȱ whenȱ
accessingȱaȱstack.ȱ
Download at http://www.pin5i.com/
17.5 Improvements in Implementationȱ
529
ȱ
ȱ
/*
** GENERIC implementation of a stack with a static array. The array
** size is given as one of the arguments when the stack is
** instantiated.
*/
#include <assert.h>
#define GENERIC_STACK( STACK_TYPE, SUFFIX, STACK_SIZE )
static
static
STACK_TYPE
int
stack##SUFFIX[ STACK_SIZE ];
top_element##SUFFIX = -1;
int
is_empty##SUFFIX( void )
{
return top_element##SUFFIX == -1;
}
int
is_full##SUFFIX( void )
{
return top_element##SUFFIX == STACK_SIZE - 1;
}
void
push##SUFFIX( STACK_TYPE value )
{
assert( !is_full##SUFFIX() );
top_element##SUFFIX += 1;
stack##SUFFIX[ top_element##SUFFIX ] = value;
}
void
pop##SUFFIX( void )
{
assert( !is_empty##SUFFIX() );
top_element##SUFFIX -= 1;
}
STACK_TYPE top##SUFFIX( void )
{
assert( !is_empty##SUFFIX() );
return stack##SUFFIX[ top_element##SUFFIX ];
}
ȱ
Programȱ17.10aȱȱGenericȱarrayedȱstackȱ ȱ
ȱ
ȱ
ȱ
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
\
ȱ
ȱ
ȱȱȱȱg_stack.hȱ
Download at http://www.pin5i.com/
530ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
ȱ
/*
** A client that uses the generic stack module to create two stacks
** holding different types of data.
*/
#include <stdlib.h>
#include <stdio.h>
#include "g_stack.h"
/*
**
Create two stacks, one of integers and one of floats.
*/
GENERIC_STACK( int, _int, 10 )
GENERIC_STACK( float, _float, 5 )
int
main()
{
/*
** Push several values on each stack.
*/
push_int( 5 );
push_int( 22 );
push_int( 15 );
push_float( 25.3 );
push_float( -40.5 );
/*
** Empty the integer stack and print the values.
*/
while( !is_empty_int() ){
printf( "Popping %d\n", top_int() );
pop_int();
}
/*
** Empty the float stack and print the values.
*/
while( !is_empty_float() ){
printf( "Popping %f\n", top_float() );
pop_float();
}
return EXIT_SUCCESS;
}
ȱ
Programȱ17.10bȱȱUsingȱtheȱgenericȱarrayedȱstackȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱg_client.cȱ
Download at http://www.pin5i.com/
17.6 Summaryȱ
531
ȱ
4. beȱsureȱtoȱpassȱtheȱproperȱstackȱdataȱstructureȱtoȱtheȱfunctions.ȱ
ȱ
ItȱisȱnotȱsurprisingȱthatȱgenericityȱisȱhardȱtoȱimplementȱinȱC,ȱbecauseȱtheȱlanguageȱwasȱ
designedȱ longȱ beforeȱ theȱ notionȱ wasȱ described.ȱ Genericityȱ isȱ oneȱ ofȱ theȱ problemsȱ
addressedȱmoreȱcompletelyȱbyȱObjectȬOrientedȱlanguages.ȱ
ȱ
ȱ
ȱ
17.6 Summary
ȱ
Thereȱ areȱ threeȱ techniquesȱ forȱ obtainingȱ memoryȱ forȱ ADTs;ȱ aȱ staticȱ array,ȱ aȱ
dynamicallyȱ allocatedȱ array,ȱ andȱ aȱ dynamicallyȱ allocatedȱ linkedȱ structure.ȱ Theȱ staticȱ
arrayȱ imposesȱ aȱ predetermined,ȱ fixedȱ sizeȱ onȱ theȱ structure.ȱ Theȱ sizeȱ ofȱ aȱ dynamicȱ
arrayȱ canȱ beȱ computedȱ atȱ runȱ time,ȱ andȱ theȱ arrayȱ canȱ beȱ reallocatedȱ ifȱ needed.ȱ Aȱ
linkedȱstructureȱdoesnȇtȱimposeȱanyȱlimitȱonȱtheȱmaximumȱnumberȱofȱvalues.ȱ
AȱstackȱisȱaȱlastȬin,ȱfirstȬoutȱstructure.ȱItsȱinterfaceȱprovidesȱfunctionsȱtoȱpushȱaȱ
newȱ valueȱ onȱ theȱ stackȱ andȱ popȱ aȱ valueȱ offȱ theȱ stack.ȱ Anȱ alternateȱ interfaceȱ addsȱ aȱ
thirdȱfunctionȱwhichȱreturnsȱtheȱlopȱvalueȱonȱtheȱstackȱwithoutȱpoppingȱit.ȱAȱstackȱisȱ
easilyȱ implementedȱ withȱ anȱ arrayȱ byȱ usingȱ aȱ variable,ȱ initializedȱ toȱ Ȭ1,ȱ toȱ rememberȱ
theȱ subscriptȱ ofȱ theȱ topȱ element.ȱ Toȱ pushȱ aȱ newȱ valueȱ onȱ theȱ stack,ȱ theȱ variableȱ isȱ
incrementedȱ andȱ theȱ valueȱ isȱ thenȱ storedȱ inȱ theȱ array.ȱ Whenȱ poppingȱ aȱ value,ȱ theȱ
variableȱ isȱ decrementedȱ afterȱ accessingȱ theȱ valueȱ inȱ theȱ array.ȱ Twoȱ additionalȱ
functionsȱareȱrequiredȱtoȱuseȱaȱdynamicallyȱallocatedȱstack.ȱOneȱcreatesȱtheȱstackȱtoȱaȱ
specifiedȱ size,ȱ andȱ theȱ otherȱ destroysȱ it.ȱ Aȱ singlyȱ linkedȱ listȱ alsoȱ worksȱ wellȱ forȱ
implementingȱaȱstack.ȱValuesȱareȱpushedȱbyȱinsertingȱthemȱatȱtheȱbeginningȱofȱtheȱlist,ȱ
andȱtheȱstackȱisȱpoppedȱbyȱremovingȱtheȱfirstȱclement.ȱ
AȱqueueȱisȱaȱfirstȬin,ȱfirstȬoutȱstructure.ȱItsȱinterfaceȱprovidesȱfunctionsȱtoȱinsertȱ
aȱnewȱvalueȱandȱtoȱdeleteȱanȱexistingȱvalue.ȱBecauseȱofȱtheȱorderingȱaȱqueueȱimposesȱ
onȱ itsȱ elements,ȱ aȱ circularȱ arrayȱ isȱ aȱ moreȱ appropriateȱ implementationȱ thanȱ anȱ
ordinaryȱarray.ȱȱWhenȱaȱvariableȱusedȱasȱaȱsubscriptȱforȱaȱcircularȱarrayȱisȱincrementedȱ
pastȱtheȱendȱofȱtheȱarray,ȱitsȱvalueȱwrapsȱaroundȱtoȱzero.ȱToȱdetermineȱwhenȱtheȱarrayȱ
isȱfull,ȱyouȱmayȱuseȱaȱvariableȱthatȱcountsȱ theȱnumberȱofȱinsertedȱvalues.ȱToȱuseȱtheȱ
frontȱandȱrearȱpointersȱofȱtheȱqueueȱtoȱdetectȱthisȱcondition,ȱthereȱmustȱalwaysȱbeȱatȱ
leastȱoneȱemptyȱelementȱinȱtheȱarray.ȱ
Aȱbinaryȱsearchȱtreeȱ(BST)ȱisȱaȱstructureȱthatȱisȱeitherȱemptyȱorȱhasȱaȱvalueȱandȱ
upȱtoȱtwoȱchildren,ȱcalledȱleftȱandȱright,ȱwhichȱareȱalsoȱBSTs.ȱTheȱvalueȱinȱaȱnodeȱofȱaȱ
BSTȱ isȱ greaterȱ thanȱ allȱ theȱ valuesȱ containedȱ inȱ itsȱ leftȱ subtree,ȱ andȱ lessȱ thanȱ allȱ theȱ
valuesȱinȱitsȱrightȱsubtree.ȱBecauseȱofȱthisȱordering,ȱitȱisȱveryȱefficientȱtoȱsearchȱforȱaȱ
valueȱ inȱ aȱ BST—ifȱ aȱ nodeȱ doesȱ notȱ containȱ theȱ desiredȱ value,ȱ youȱ canȱ alwaysȱ tellȱ
whichȱofȱitsȱsubtreesȱtoȱexamine.ȱToȱinsertȱaȱvalueȱintoȱaȱBST,ȱyouȱfirstȱsearchȱforȱit.ȱIfȱ
Download at http://www.pin5i.com/
532ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
theȱvalueȱisȱnotȱfound,ȱinsertȱitȱatȱtheȱlocationȱwhereȱtheȱsearchȱfailed.ȱWhenȱremovingȱ
aȱvalueȱfromȱaȱBST,ȱcareȱmustȱbeȱtakenȱnotȱtoȱdisconnectȱitsȱsubtreesȱfromȱtheȱtree.ȱAȱ
treeȱisȱtraversedȱbyȱprocessingȱallȱofȱitsȱnodesȱinȱsomeȱorder.ȱThereȱareȱfourȱcommonȱ
orderings.ȱ Aȱ preȬorderȱ traversalȱ processesȱ theȱ node,ȱ andȱ thenȱ traversesȱ itsȱ leftȱ andȱ
rightȱsubtrees.ȱAnȱinȬorderȱtraversalȱtraversesȱtheȱleftȱsubtree,ȱprocessesȱtheȱnode,ȱandȱ
thenȱ traversesȱ theȱ rightȱ subtree.ȱ Aȱ postȬorderȱ traversalȱ traversesȱ theȱ leftȱ andȱ rightȱ
subtrees,ȱ andȱ thenȱ processesȱ theȱ node.ȱ Aȱ breadthȬfirstȱ traversalȱ processesȱ theȱ nodesȱ
leftȱ toȱ rightȱ onȱeachȱlevelȱfromȱtheȱ rootȱdownȱtoȱ theȱleaves.ȱAnȱarrayȱcanȱbeȱ usedȱ toȱ
implementȱ aȱ BST,ȱ butȱ willȱ wasteȱ aȱ lotȱ ofȱ memoryȱ ifȱ theȱ treeȱ isȱ unbalanced.ȱ Aȱ linkedȱ
BSTȱavoidsȱthisȱwaste.ȱ
Thereȱ areȱ threeȱ problemsȱ associatedȱ withȱ straightforwardȱ implementationsȱ ofȱ
theseȱADTs.ȱFirst,ȱtheyȱonlyȱallowȱyouȱ10ȱhaveȱoneȱstack,ȱqueue,ȱorȱtree.ȱThisȱproblemȱ
isȱ solvedȱ byȱ separatingȱ theȱ allocationȱ ofȱ theȱ structureȱ fromȱ theȱ functionsȱ thatȱ
manipulateȱ it,ȱ howeverȱ theȱ resultingȱ lossȱ ofȱ encapsulationȱ increasesȱ theȱ chancesȱ ofȱ
errors.ȱ Theȱ secondȱ problemȱ isȱ theȱ inabilityȱ toȱ declareȱ stacks,ȱ queues,ȱ orȱ treesȱ ofȱ
differentȱ types.ȱ Creatingȱ aȱ separateȱ copyȱ ofȱ theȱ ADTȱ functionsȱ forȱ eachȱ typeȱ makesȱ
maintainingȱtheȱcodeȱmoreȱdifficult.ȱAȱbetterȱapproachȱisȱtoȱimplementȱtheȱcodeȱwithȱaȱ
#defineȱwhichȱisȱthenȱexpandedȱwithȱeachȱrequiredȱtype,ȱthoughȱyouȱmustȱchooseȱaȱ
namingȱ conventionȱ carefully.ȱ Anotherȱ approachȱ isȱ toȱ makeȱ theȱ ADTȱ typelessȱ byȱ
castingȱ theȱ valuesȱ toȱ beȱ storedȱ toȱ void *.ȱ ȱ Aȱ drawbackȱ ofȱ thisȱ strategyȱ isȱ theȱ lossȱ ofȱ
typeȱchecking.ȱTheȱthirdȱproblemȱisȱavoidingȱnameȱclashesȱamongȱtheȱdifferentȱADTsȱ
andȱamongȱtheȱversionsȱ ofȱ aȱsingleȱADTȱthatȱhandleȱ differentȱ typesȱ ofȱdata.ȱ Genericȱ
implementationsȱ ofȱ theȱ ADTsȱ canȱ beȱ created,ȱ thoughȱ theyȱ requireȱ theȱ userȱ toȱ acceptȱ
moreȱresponsibilityȱforȱtheirȱcorrectȱuse.ȱ
ȱ
ȱ
ȱ
17.7 Summary of Cautions
ȱ
1. Usingȱassertionsȱtoȱcheckȱforȱmemoryȱallocationsȱisȱdangerousȱ(pageȱ502).ȱ
2. Theȱcalculationsȱforȱanȱarrayedȱbinaryȱtreeȱassumeȱthatȱtheȱarrayȱsubscriptsȱbeginȱ
atȱoneȱ(pageȱ518).ȱ
3. Encapsulatingȱ theȱ dataȱ inȱ theȱ moduleȱ thatȱ servicesȱ itȱ preventsȱ theȱ clientȱ fromȱ
accessingȱtheȱdataȱincorrectlyȱ(pageȱ526).ȱ
4. Thereȱisȱnoȱtypeȱcheckingȱwithȱtypelessȱfunctions,ȱsoȱbeȱcarefulȱtoȱpassȱtheȱcorrectȱ
typeȱofȱdataȱ(pageȱ527).ȱ
ȱ
Download at http://www.pin5i.com/
17.9 Questionsȱ
533
ȱ
17.8 Summary of Programming Tips
ȱ
1. Avoidingȱfunctionsȱwithȱsideȱeffectsȱmakesȱtheȱprogramȱeasierȱtoȱunderstandȱ(pageȱ
494).ȱ
2. Theȱinterfaceȱforȱaȱmoduleȱshouldȱnotȱdivulgeȱdetailsȱofȱtheȱimplementationȱ(pageȱ
494).ȱ
3. Parameterizingȱtheȱdataȱtypeȱmakesȱitȱeasierȱtoȱchangeȱ(pageȱ495).ȱ
4. Onlyȱtheȱadvertisedȱinterfaceȱforȱaȱmoduleȱshouldȱbeȱpublicȱ(pageȱ496).ȱ
5. Useȱassertionsȱtoȱguardȱagainstȱillegalȱoperationsȱ(pageȱ498).ȱ
6. Makingȱ differentȱ implementationsȱ adhereȱ toȱ aȱ commonȱ interfaceȱ makesȱ modulesȱ
moreȱinterchangeableȱ(pageȱ499).ȱ
7. Reuseȱexistingȱcodeȱratherȱthanȱrewritingȱitȱ(pageȱ505).ȱ
8. Iterationȱisȱmoreȱefficientȱthanȱtailȱrecursionȱ(pageȱ513).ȱ
ȱ
ȱ
ȱ
17.9 Questions
ȱ
1. Supposeȱyouȱhaveȱaȱprogramȱthatȱreadsȱaȱseriesȱofȱnamesȱbutȱmustȱprintȱthemȱinȱ
theȱoppositeȱorder.ȱWhatȱADTȱisȱmostȱappropriateȱforȱthisȱtask?ȱ
2. WhichȱADTȱwouldȱheȱmostȱappropriateȱforȱorganizingȱtheȱmilkȱonȱaȱsupermarketȱ
shelf?ȱ Considerȱ whatȱ happensȱ bothȱ whenȱ customersȱ buyȱ milkȱ andȱ whenȱ theȱ
supermarketȱgetsȱaȱnewȱshipmentȱofȱmilk.ȱ
3. Inȱ theȱ traditionalȱ interfaceȱ forȱ aȱ stack,ȱ theȱ popȱ functionȱ returnsȱ theȱ valueȱ thatȱ itȱ
removedȱ fromȱ theȱ stack.ȱ Wouldȱ itȱ beȱ possibleȱ toȱ provideȱ bothȱ interfacesȱ inȱ oneȱ
module?ȱ
4. Wouldȱtheȱstackȱmoduleȱbeȱsignificantlyȱmoreȱpowerfulȱifȱitȱhadȱanȱ emptyȱfunctionȱ
thatȱremovedȱallȱvaluesȱfromȱtheȱstack?ȱ
5. Theȱ variableȱ top_elementȱ isȱ incrementedȱ beforeȱ storingȱ theȱ valueȱ inȱ pushȱ butȱ isȱ
decrementedȱafterȱreturningȱtheȱvalueȱinȱpop.ȱWhatȱwouldȱhappenȱifȱtheȱorderȱofȱ
theseȱoperationsȱwasȱreversed?ȱ
6. Whatȱwouldȱhappenȱ ifȱallȱofȱtheȱ assertionsȱ wereȱ removedȱ fromȱ theȱ stackȱ moduleȱ
thatȱusesȱaȱstaticȱarray?ȱ
7. Inȱtheȱlinkedȱimplementationȱofȱaȱstack,ȱwhyȱdoesȱtheȱ destroy_stackȱfunctionȱpopȱ
eachȱofȱtheȱvaluesȱonȱtheȱstackȱoneȱbyȱone?ȱ
8. Theȱpopȱfunctionȱinȱtheȱlinkedȱstackȱimplementationȱdeclaresȱaȱlocalȱvariableȱcalledȱ
first_node.ȱȱCanȱthisȱvariableȱbeȱomitted?ȱ
Download at http://www.pin5i.com/
534ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
9. Whenȱaȱcircularȱarrayȱisȱfull,ȱtheȱ frontȱandȱ rearȱvaluesȱhaveȱtheȱsameȱrelationshipȱ
toȱoneȱanotherȱasȱtheyȱdoȱwhenȱtheȱarrayȱisȱempty.ȱHowever,ȱfullȱandȱemptyȱareȱ
differentȱstates.ȱȱConceptually,ȱhowȱcanȱthisȱsituationȱhappen?ȱ
10. Whichȱsolutionȱisȱbetterȱforȱsolvingȱtheȱproblemȱofȱdetectingȱaȱfullȱcircularȱarray:ȱ
(1)ȱalwaysȱleavingȱoneȱarrayȱelementȱunused,ȱorȱ(2)ȱaȱseparateȱvariableȱtoȱcountȱtheȱ
numberȱofȱvaluesȱinȱtheȱarray?ȱ
11. Writeȱ theȱ statementsȱ thatȱ computeȱ theȱ numberȱ ofȱ valuesȱ onȱ aȱ queueȱ fromȱ theȱ
valuesȱofȱfrontȱandȱrear.ȱ
12. Whichȱ isȱ betterȱ suitedȱ forȱ theȱ storageȱ ofȱ aȱ queue,ȱ aȱ singlyȱ linkedȱ listȱ orȱ aȱ doublyȱ
linkedȱlist?ȱ
13. Drawȱtheȱtreeȱthatȱwouldȱresultȱfromȱinsertingȱtheȱfollowingȱvalues,ȱinȱthisȱorder,ȱ
intoȱaȱbinaryȱsearchȱtree:ȱ20,ȱ15,ȱ18,ȱ32,ȱ5,ȱ91,ȱȬ4,ȱ76,ȱ33,ȱ41,ȱ34,ȱ21,ȱ90.ȱ
14. Insertingȱvaluesȱintoȱaȱbinaryȱsearchȱtreeȱinȱeitherȱascendingȱorȱdescendingȱorderȱ
producesȱaȱtreeȱthatȱisȱunbalanced.ȱWhatȱisȱtheȱefficiencyȱofȱsearchingȱsuchȱaȱtreeȱ
forȱaȱvalue?ȱ
15. InȱwhatȱorderȱwouldȱtheȱnodesȱofȱtheȱfollowingȱtreeȱbeȱprocessedȱusingȱaȱpreȬorderȱ
traversal?ȱAnȱinȬorderȱtraversal?ȱAȱpostȬorderȱtraversal?ȱAȱbreadthȬfirstȱtraversal?ȱ
54
36
72ȱ
22ȱ
16ȱ
41
25ȱ
25
80
61ȱ
51
73
ȱ
16. Rewriteȱtheȱdo_pre_order_traversalȱfunctionȱtoȱperformȱanȱinȬorderȱtreeȱtraversalȱ
17. Rewriteȱtheȱdo_pre_order_traversalȱfunctionȱtoȱperformȱaȱpostȬorderȱtreeȱ
traversal.ȱ
18. Whichȱ traversalȱ ofȱ aȱ binaryȱ searchȱ treeȱ willȱ visitȱ theȱ nodesȱ inȱ ascendingȱ orderȱ ofȱ
theirȱvalues?ȱWhichȱwillȱvisitȱtheȱnodesȱinȱdescendingȱorder?ȱ
19. Theȱdestroy_treeȱfunctionȱdeletesȱaȱtreeȱbyȱfreeingȱallȱofȱtheȱmemoryȱallocatedȱforȱ
ȱ
Download at http://www.pin5i.com/
17.10 Programming Exercisesȱ
535
ȱ
theȱnodesȱinȱtheȱtree,ȱwhichȱmeansȱthatȱallȱofȱtheȱtreeȱnodesȱmustȱbeȱprocessedȱinȱaȱ
particularȱorder.ȱWhatȱtypeȱofȱtraversalȱwouldȱbeȱmostȱappropriateȱforȱthisȱtask?ȱ
ȱ
ȱ
ȱ
17.10 Programming Exercises
ȱ
1. Addȱ aȱ resize_stackȱ functionȱ toȱ theȱ dynamicallyȱ allocatedȱ stackȱ module.ȱ Theȱ
functionȱtakesȱoneȱargument:ȱtheȱnewȱsizeȱforȱtheȱstack.ȱ
2. Convertȱ theȱ queueȱ moduleȱ toȱ useȱ dynamicȱ arrayȱ allocationȱ andȱ addȱ aȱ
resize_queueȱfunctionȱ(similarȱtoȱtheȱoneȱdescribedȱinȱProgrammingȱExerciseȱ1)ȱtoȱ
it.ȱ
3. Convertȱtheȱqueueȱmoduleȱtoȱuseȱlinkedȱlistȱallocation.ȱ
4. Theȱ stack,ȱ queue,ȱ andȱ treeȱ modulesȱ wouldȱ beȱ moreȱ usefulȱ ifȱ theyȱ couldȱ handleȱ
moreȱthanȱoneȱstack,ȱqueue,ȱorȱtree.ȱChangeȱtheȱdynamicallyȱarrayedȱstackȱmoduleȱ
soȱ thatȱ itȱ canȱ manageȱ upȱ toȱ tenȱ separateȱ stacks.ȱ Youȱ willȱ haveȱ toȱ changeȱ theȱ
interfacesȱ toȱ theȱ stackȱ functionsȱ toȱ acceptȱ anotherȱ argument—theȱ indexȱ ofȱ theȱ
desiredȱstack.ȱ
5. Writeȱaȱfunctionȱtoȱcountȱtheȱnumberȱofȱnodesȱinȱaȱbinaryȱsearchȱtree.ȱYouȱmayȱuseȱ
whicheverȱimplementationȱyouȱprefer.ȱ
6. Writeȱ aȱ functionȱ toȱ doȱ aȱ breadthȬfirstȱ traversalȱ ofȱ theȱ arrayedȱ binaryȱ searchȱ tree.ȱ
Useȱtheȱfollowingȱalgorithm:ȱ
ȱ
Addȱtheȱrootȱnodeȱtoȱaȱqueue.ȱ
Whileȱtheȱqueueȱisȱnotȱempty:ȱ
Removeȱtheȱfirstȱnodeȱfromȱtheȱqueueȱandȱprocessȱit.ȱ
Addȱallȱofȱtheȱnodeȇsȱchildrenȱtoȱtheȱqueue.ȱ
7. Writeȱaȱfunctionȱtoȱcheckȱwhetherȱaȱbinaryȱtreeȱisȱinȱfactȱaȱbinaryȱsearchȱtree.ȱYouȱ
mayȱuseȱwhicheverȱimplementationȱyouȱprefer.ȱ
8. Writeȱaȱfunctionȱforȱtheȱarrayedȱtreeȱmoduleȱthatȱdeletesȱaȱvalueȱfromȱtheȱtree.ȱIfȱ
theȱ valueȱ toȱ beȱ deletedȱ isȱ notȱ foundȱ inȱ theȱ tree,ȱ theȱ functionȱ mayȱ abortȱ theȱ
program.ȱ
9. Writeȱaȱ destroy_treeȱfunctionȱforȱtheȱlinkedȱimplementationȱofȱtheȱbinaryȱsearchȱ
tree.ȱTheȱfunctionȱshouldȱfreeȱallȱofȱtheȱmemoryȱusedȱinȱtheȱtree.ȱ
10. Writeȱaȱfunctionȱforȱtheȱlinkedȱtreeȱmoduleȱthatȱdeletesȱaȱvalueȱfromȱtheȱtree.ȱIfȱtheȱ
valueȱtoȱbeȱdeletedȱisȱnotȱfoundȱinȱtheȱtree,ȱtheȱfunctionȱmayȱabortȱtheȱprogram.ȱ
Download at http://www.pin5i.com/
536ȱ
ȱ
Chapter 17 Classic Abstract Data Typesȱ
11. Rewriteȱtheȱ#defineȱinȱProgramȱ17.10aȱasȱthreeȱseparateȱ#defines.ȱ
a. oneȱtoȱdeclareȱtheȱstackȱinterfaceȱ
b. oneȱtoȱcreateȱtheȱimplementationȱ
c. oneȱtoȱcreateȱtheȱdataȱforȱaȱstackȱ
Youȱ mustȱ changeȱ theȱ interfaceȱ forȱ theȱ stackȱ toȱ passȱ theȱ stackȱ dataȱ asȱ anȱ explicitȱ
argument.ȱ(Itȱwillȱbeȱmoreȱconvenientȱtoȱpackageȱtheȱstackȱdataȱintoȱaȱstructure.)ȱ
Theseȱmodificationsȱwillȱletȱaȱsingleȱsetȱofȱstackȱfunctionsȱmanipulateȱanyȱstackȱofȱ
theȱcorrespondingȱtype.ȱ
Download at http://www.pin5i.com/
18
Runtime Environment
Inȱthisȱchapter,ȱweȱwillȱexamineȱtheȱassemblyȱlanguageȱcodeȱproducedȱbyȱoneȱspecificȱ
compilerȱ forȱ oneȱ specificȱ computerȱ inȱ orderȱ toȱ learnȱ severalȱ interestingȱ thingsȱ aboutȱ
theȱ runtimeȱ environmentȱ forȱ thisȱ implementation.ȱ Amongȱ theȱ questionsȱ thatȱ willȱ beȱ
answeredȱare,ȱȈWhatȱareȱtheȱlimitsȱofȱmyȱruntimeȱenvironment?ȈȱandȱȈHowȱdoȱIȱgetȱCȱ
andȱassemblyȱlanguageȱprogramsȱtoȱworkȱtogether?Ȉȱ
ȱ
ȱ
ȱ
18.1 Determining the Runtime Environment
ȱ
Yourȱcompilerȱorȱenvironmentȱisȱsureȱtoȱbeȱdifferentȱthanȱtheȱoneȱweȱlookȱatȱhere,ȱsoȱ
youȱ willȱ needȱ toȱ performȱ experimentsȱ likeȱ theseȱ yourselfȱ inȱ orderȱ toȱ findȱ outȱ howȱ
thingsȱworkȱonȱyourȱmachine.ȱ
Theȱfirstȱstepȱisȱobtainingȱanȱassemblyȱlanguageȱlistingȱfromȱyourȱcompiler.ȱOnȱ
UNIXȱ systems,ȱ theȱ -sȱ compilerȱ optionȱ causesȱ theȱ compilerȱ toȱ writeȱ theȱ assemblyȱ
languageȱ forȱ eachȱ sourceȱ fileȱ inȱ aȱ fileȱ whoseȱ nameȱ hasȱ theȱ .sȱ suffix.ȱ Theȱ Borlandȱ
compilersȱ alsoȱ supportȱ thisȱ option,ȱ thoughȱ theyȱ useȱ theȱ .asmȱ suffix.ȱ Consultȱ theȱ
documentationȱforȱspecificȱdetailsȱofȱotherȱsystems.ȱ
Youȱwillȱalsoȱneedȱtoȱreadȱtheȱassemblyȱlanguageȱcodeȱforȱyourȱmachine.ȱItȱisȱ
notȱ necessaryȱ toȱ beȱ aȱ skillfulȱ assemblyȱ languageȱ programmer,ȱ butȱ youȱ willȱ needȱ aȱ
basicȱunderstandingȱofȱwhatȱeachȱinstructionȱisȱdoingȱandȱhowȱtoȱinterpretȱaddressingȱ
modes.ȱAȱmanualȱdescribingȱyourȱcomputerȇsȱinstructionȱsetȱisȱanȱexcellentȱreferenceȱ
forȱthisȱtask.ȱ
Assemblyȱlanguageȱisȱnotȱtaughtȱinȱthisȱchapterȱbecauseȱthatȱisȱnotȱtheȱpointȱofȱ
thisȱ book.ȱ Yourȱ assemblyȱ languageȱ isȱ likelyȱ toȱ differȱ fromȱ thisȱ oneȱ anyway.ȱ
Nevertheless,ȱ ifȱ youȱ compileȱ theȱ testȱ program,ȱ theȱ explanationsȱ ofȱ myȱ machineȇsȱ
assemblyȱ languageȱ mayȱ helpȱ youȱ decipherȱ yours,ȱ becauseȱ bothȱ assemblyȱ programsȱ
implementȱtheȱsameȱsourceȱcode.ȱ
Download at http://www.pin5i.com/
538ȱ
ȱ
Chapter 18 Runtime Environmentȱ
ȱ
/*
** Program to determine the C runtime environment.
*/
/*
** Static initialization
*/
int
static_variable = 5;
void
f()
{
register int
register char
extern
double
int
double
char
/*
**
*/
i1
i6
c1
c3
c5
c7
c9
i1, i2, i3, i4, i5,
i6, i7, i8, i9, i10;
*c1, *c2, *c3, *c4, *c5,
*c6, *c7, *c8, *c9, *c10;
a_very_long_name_to_see_how_long_they_can_be;
int
dbl;
func_ret_int();
func_ret_double();
*func_ret_char_ptr();
Maximum number of register variables.
=
=
=
=
=
=
=
1; i2
6; i7
(char
(char
(char
(char
(char
= 2; i3 = 3; i4 = 4; i5 = 5;
= 7; i8 = 8; i9 = 9; i10 = 10;
*)110; c2 = (char *)120;
*)130; c4 = (char *)140;
*)150; c6 = (char *)160;
*)170; c8 = (char *)180;
*)190; c10 = (char *)200;
/*
** External names
*/
a_very_long_name_to_see_how_long_they_can_be = 1;
/*
** Function calling/returning protocol, stack frame
*/
i2 = func_ret_int( 10, i1, i10 );
dbl = func_ret_double();
c1 = func_ret_char_ptr( c1 );
}
ȱ
Programȱ18.1ȱȱTestȱprogramȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
18.1 Determining the Runtime Environmentȱ
539
ȱ
ȱ
int
func_ret_int( int a, int b, register int c )
{
int
d;
d = b - 6;
return a + b + c;
}
double
func_ret_double()
{
return 3.14;
}
char *
func_ret_char_ptr( char *cp )
{
return cp + 1;
}
ȱ
Programȱ18.1ȱȱTestȱprogramȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
18.1.1
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱȱȱȱruntime.cȱ
Test Program
ȱ
Soȱ letȇsȱ lookȱ atȱ Programȱ 18.1,ȱ theȱ testȱ program.ȱ Itȱ containsȱ variousȱ piecesȱ ofȱ codeȱ
whoseȱ implementationsȱ areȱ ofȱ interest.ȱ Theȱ programȱ doesnȇtȱ accomplishȱ anythingȱ
useful,ȱbutȱitȱdoesnȇtȱhaveȱto—allȱthatȱweȱwantȱtoȱdoȱisȱtoȱlookȱatȱtheȱassemblyȱcodeȱ
theȱ compilerȱ producesȱ forȱ it.ȱ Ifȱ thereȱ areȱ otherȱ aspectsȱ ofȱ yourȱ runtimeȱ environmentȱ
youȱwishȱtoȱinvestigate,ȱmodifyȱtheȱprogramȱtoȱincludeȱexamplesȱofȱthem.ȱ
Theȱ assemblyȱ codeȱ inȱ Programȱ 18.2ȱ wasȱ producedȱ forȱ aȱ computerȱ usingȱ aȱ
microprocessorȱ fromȱ theȱ Motorolaȱ 68000ȱ family.ȱ Iȱ haveȱ editedȱ thisȱ codeȱ toȱ makeȱ itȱ
moreȱclearȱandȱtoȱremoveȱirrelevantȱdeclarations.ȱ
Thisȱisȱaȱlongȱprogram.ȱLikeȱmostȱcompilerȱoutput,ȱitȱcontainsȱnoȱcommentsȱtoȱ
helpȱtheȱreader.ȱButȱdonȇtȱletȱitȱintimidateȱyou!ȱIȇllȱexplainȱmostȱofȱitȱlineȱbyȱlineȱinȱaȱ
seriesȱ ofȱ examplesȱ thatȱ showȱ aȱ fragmentȱ ofȱ Cȱ codeȱ followedȱ byȱ theȱ assemblyȱ codeȱ
producedȱfromȱit.ȱTheȱcompleteȱlistingȱisȱgivenȱonlyȱasȱaȱreferenceȱsoȱyouȱcanȱseeȱhowȱ
allȱofȱtheȱlittleȱpiecesȱinȱtheȱexamplesȱfitȱtogether.ȱ
Download at http://www.pin5i.com/
540ȱ
ȱ
Chapter 18 Runtime Environmentȱ
ȱ
.data
.even
.globl
_static_variable
_static_variable:
.long
5
.text
_f:
.globl
link
moveml
moveq
moveq
moveq
moveq
moveq
moveq
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
pea
jbsr
lea
movl
jbsr
movl
movl
pea
jbsr
addqw
movl
moveml
unlk
rts
_f
a6,#-88
#0x3cfc,sp@
#1,d7
#2,d6
#3,d5
#4,d4
#5,d3
#6,d2
#7,a6@(-4)
#8,a6@(-8)
#9,a6@(-12)
#10,a6@(-16)
#110,a5
#120,a4
#130,a3
#140,a2
#150,a6@(-20)
#160,a6@(-24)
#170,a6@(-28)
#180,a6@(-32)
#190,a6@(-36)
#200,a6@(-40)
#1,_a_very_long_name_to_see_how_long_they_can_be
a6@(-16),sp@d7,sp@10
_func_ret_int
sp@(12),sp
d0,d6
_func_ret_double
d0,a6@(-48)
d1,a6@(-44)
a5@
_func_ret_char_ptr
#4,sp
d0,a5
a6@(-88),#0x3cfc
a6
ȱ
Programȱ18.2ȱȱAssemblyȱlanguageȱcodeȱforȱtestȱprogramȱ
ȱ
ȱ
ȱ
continued...ȱ
Download at http://www.pin5i.com/
18.1 Determining the Runtime Environmentȱ
541
ȱ
ȱ
.globl
_func_ret_int:
link
moveml
movl
movl
subql
movl
movl
addl
addl
moveml
unlk
rts
_func_ret_int
.globl
_func_ret_double:
link
moveml
movl
movl
unlk
rts
L2000000:
_func_ret_double
a6,#-8
#0x80,sp@
a6@(16),d7
a6@(12),d0
#6,d0
d0,a6@(-4)
a6@(8),d0
a6@(12),d0
d7,d0
a6@(-8),#0x80
a6
a6,#0
#0,sp@
L2000000,d0
L2000000+4,d1
a6
.long 0x40091eb8,0x51eb851f
.globl
_func_ret_char_ptr
_func_ret_char_ptr:
link
a6,#0
moveml
#0,sp@
movl
a6@(8),d0
addql
#1,d0
unlk
a6
rts
ȱ
Programȱ18.2ȱȱAssemblyȱlanguageȱcodeȱforȱtestȱprogramȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
18.1.2
ȱ
ȱ
ȱ
ȱȱȱȱruntime.sȱ
Static Variables and Initialization
ȱ
Theȱ firstȱ thingȱ theȱ testȱ programȱ didȱ wasȱ toȱ declareȱ andȱ initializeȱ aȱ variableȱ inȱ staticȱ
memory.ȱ
Download at http://www.pin5i.com/
Chapter 18 Runtime Environmentȱ
542ȱ
ȱ
ȱ
/*
** Static initialization
*/
int
static_variable = 5;
.data
.even
.globl
_static_variable
_static_variable:
.long
5
ȱ
Theȱassemblyȱcodeȱbeginsȱwithȱdirectivesȱtoȱenterȱtheȱdataȱsectionȱofȱtheȱprogramȱandȱ
makeȱ sureȱ thatȱ theȱ variableȱ beginsȱ atȱ anȱ evenȱ address.ȱ Theȱ boundaryȱ alignmentȱ isȱ aȱ
requirementȱ ofȱ theȱ 68000.ȱ Thenȱ theȱ variableȱ nameȱ isȱ declaredȱ global.ȱ Noticeȱ thatȱ theȱ
nameȱ beginsȱ withȱ anȱ underscore.ȱ Manyȱ (butȱ notȱ all)ȱ Cȱ implementationsȱ addȱ anȱ
underscoreȱtoȱtheȱbeginningȱofȱexternalȱnamesȱdeclaredȱinȱtheȱCȱcodeȱtoȱpreventȱtheseȱ
namesȱfromȱconflictingȱwithȱnamesȱusedȱinȱvariousȱlibraryȱroutines.ȱFinally,ȱspaceȱisȱ
createdȱforȱtheȱvariable,ȱandȱitȱisȱinitializedȱwithȱtheȱproperȱvalue.ȱ
ȱ
ȱ
ȱ
18.1.3
The Stack Frame
ȱ
Theȱfunctionȱ fȱbeginsȱnext.ȱThereȱareȱthreeȱpartsȱtoȱaȱfunction:ȱtheȱprologue,ȱtheȱbody,ȱ
andȱ theȱ epilogue.ȱ Theȱ prologueȱ ofȱ aȱ functionȱ doesȱ theȱ workȱ neededȱ toȱ startȱ upȱ aȱ
function,ȱsuchȱasȱreservingȱmemoryȱonȱtheȱstackȱforȱlocalȱvariables.ȱTheȱepilogueȱtakesȱ
careȱofȱcleaningȱupȱtheȱstackȱjustȱbeforeȱtheȱfunctionȱreturns.ȱTheȱbodyȱofȱtheȱfunction,ȱ
ofȱcourse,ȱisȱwhereȱtheȱusefulȱworkȱisȱperformed.ȱ
ȱ
void
f()
{
register int
register char
extern
double
int
double
char
i1, i2, i3, i4, i5,
i6, i7, i8, i9, i10;
*c1, *c2, *c3, *c4, *c5,
*c6, *c7, *c8, *c9, *c10;
a_very_long_name_to_see_how_long_they_can_be;
int
dbl;
func_ret_int();
func_ret_double();
*func_ret_char_ptr();
.text
_f:
.globl
link
moveml
_f
a6,#-88
#0x3cfc,sp@
Download at http://www.pin5i.com/
18.1 Determining the Runtime Environmentȱ
543
ȱ
Theseȱinstructionsȱbeginȱwithȱaȱdirectiveȱtoȱenterȱtheȱcodeȱ(text)ȱsegmentȱofȱtheȱ
program,ȱfollowedȱbyȱaȱglobalȱdeclarationȱforȱtheȱfunctionȱname.ȱNoteȱonceȱagainȱtheȱ
underscoreȱaddedȱtoȱ theȱ frontȱ ofȱtheȱname.ȱ Theȱfirstȱexecutableȱinstructionȱ beginsȱ toȱ
constructȱtheȱstackȱframeȱforȱthisȱfunction.ȱTheȱstackȱframeȱisȱtheȱareaȱonȱtheȱstackȱthatȱ
theȱ functionȱ willȱ useȱ forȱ storageȱ ofȱ variablesȱ andȱ otherȱ values.ȱ Theȱ linkȱ instructionȱ
willȱbeȱexplainedȱinȱdetailȱlater;ȱallȱthatȱisȱimportantȱnowȱisȱthatȱitȱreservesȱ88ȱbytesȱofȱ
spaceȱonȱtheȱstackȱforȱstorageȱofȱlocalȱvariablesȱandȱotherȱvalues.ȱ
Theȱ lastȱ instructionȱ inȱ thisȱ sequenceȱ writesȱ copiesȱ ofȱ theȱ valuesȱ inȱ selectedȱ
registersȱ toȱ theȱ stack.ȱ Theȱ 68000ȱ hasȱ eightȱ registersȱ forȱ manipulatingȱ data,ȱ calledȱ d0ȱ
throughȱd7,ȱandȱeightȱmoreȱregistersȱforȱmanipulatingȱaddresses,ȱcalledȱa0ȱthroughȱa7.ȱȱ
Theȱ valueȱ 0x3cfcȱ indicatesȱ thatȱ registersȱ d2ȱ throughȱ d7ȱ andȱ a2ȱ throughȱ a5ȱ areȱ toȱ beȱ
stored;ȱtheseȱareȱtheȱȈotherȱvaluesȈȱmentionedȱearlier.ȱȱItȱwillȱbecomeȱclearȱshortlyȱwhyȱ
theseȱparticularȱregistersȱwereȱsaved.ȱ
Theȱ localȱ variableȱ declarationsȱ andȱ functionȱ prototypesȱ donȇtȱ produceȱ anyȱ
assemblyȱcode.ȱHadȱanyȱlocalȱvariablesȱbeenȱinitializedȱinȱitsȱdeclaration,ȱinstructionsȱ
wouldȱappearȱhereȱtoȱperformȱtheȱassignment.ȱ
ȱ
ȱ
ȱ
18.1.4
Register Variables
ȱ
Theȱbodyȱofȱtheȱfunctionȱcomesȱnext.ȱTheȱpurposeȱofȱthisȱpartȱofȱtheȱtestȱprogramȱisȱtoȱ
determineȱ howȱ manyȱ variablesȱ canȱ beȱ storedȱ inȱ registers.ȱ Itȱ declaresȱ aȱ lotȱ ofȱ registerȱ
variablesȱ andȱ initializesȱ eachȱ ofȱ themȱ withȱ aȱ differentȱ value.ȱ Theȱ assemblyȱ codeȱ
answersȱtheȱquestionȱbyȱshowingȱwhereȱeachȱvalueȱwasȱstored.ȱ
ȱ
/*
**
*/
i1
i6
c1
c3
c5
c7
c9
Maximum number of register variables.
=
=
=
=
=
=
=
1; i2
6; i7
(char
(char
(char
(char
(char
moveq
moveq
moveq
moveq
= 2; i3 = 3; i4 = 4; i5 = 5;
= 7; i8 = 8; i9 = 9; i10 = 10;
*)110; c2 = (char *)120;
*)130; c4 = (char *)140;
*)150; c6 = (char *)160;
*)170; c8 = (char *)180;
*)190; c10 = (char *)200;
#1,d7
#2,d6
#3,d5
#4,d4
Download at http://www.pin5i.com/
Chapter 18 Runtime Environmentȱ
544ȱ
ȱ
moveq
moveq
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
movl
#5,d3
#6,d2
#7,a6@(-4)
#8,a6@(-8)
#9,a6@(-12)
#10,a6@(-16)
#110,a5
#120,a4
#130,a3
#140,a2
#150,a6@(-20)
#160,a6@(-24)
#170,a6@(-28)
#180,a6@(-32)
#190,a6@(-36)
#200,a6@(-40)
ȱ
Theȱintegerȱvariablesȱareȱinitializedȱfirst.ȱNoticeȱthatȱtheȱvaluesȱ1ȱthroughȱ6ȱareȱ
putȱinȱdamȱregisters,ȱbutȱ7ȱthroughȱ10ȱareȱputȱsomewhereȱelse.ȱThisȱcodeȱshowsȱthatȱ
upȱtoȱ6ȱintegerȱvaluesȱmayȱbeȱkeptȱinȱtheȱdataȱregisters.ȱWhatȱaboutȱdataȱtypesȱotherȱ
thanȱinteger?ȱSomeȱimplementationsȱwillȱnotȱputȱ charȱvariablesȱinȱregisters.ȱOnȱsomeȱ
machinesȱ doublesȱ areȱ tooȱ longȱ toȱ fitȱ inȱ aȱ register,ȱ andȱ otherȱ machinesȱ haveȱ specialȱ
registersȱthatȱareȱusedȱforȱfloatingȬpointȱvalues.ȱItȱisȱeasyȱtoȱmodifyȱtheȱtestȱprogramȱtoȱ
discoverȱtheseȱdetails.ȱ
Theȱ nextȱ severalȱ instructionsȱ initializeȱ theȱ pointerȱ variables.ȱ Theȱ firstȱ 4ȱ valuesȱ
goȱ toȱ registers,ȱ andȱ theȱ remainingȱ onesȱ areȱ putȱ somewhereȱ else.ȱ Thus,ȱ thisȱ compilerȱ
allowsȱupȱtoȱ4ȱpointerȱvariablesȱtoȱbeȱinȱregisters.ȱWhatȱaboutȱotherȱtypesȱofȱpointers?ȱȱ
Again,ȱ furtherȱ experimentationȱ isȱ needed.ȱ Onȱ manyȱ machines,ȱ though,ȱ theȱ sizeȱ ofȱ aȱ
pointerȱisȱtheȱsameȱnoȱmatterȱwhatȱitȱisȱpointingȱat,ȱsoȱyouȱmayȱfindȱthatȱanyȱtypeȱofȱ
pointerȱcanȱbeȱstoredȱinȱaȱregister.ȱ
Whereȱ areȱ theȱ otherȱ variablesȱ put?ȱ Theȱ addressingȱ modeȱ usedȱ performsȱ
indirectionȱandȱindexing.ȱThisȱcombinationȱworksȱmuchȱlikeȱaȱsubscriptȱonȱanȱarray.ȱȱ
Registerȱ a6ȱ isȱ calledȱ theȱ frameȱ pointerȱ andȱ pointsȱ toȱ aȱ ȈreferenceȈȱ locationȱ withinȱ theȱ
stackȱ frame.ȱ Allȱ valuesȱ inȱ theȱ stackȱ frameȱ areȱ accessedȱ byȱ meansȱ ofȱ offsetsȱ fromȱ thisȱ
referenceȱlocation;ȱa6@(-28)ȱspecifiesȱanȱoffsetȱofȱȬ28.ȱNoticeȱthatȱtheȱoffsetsȱbeginȱwithȱ
Ȭ4ȱandȱgrowȱbyȱfourȱeachȱtime.ȱIntegersȱandȱpointersȱonȱthisȱmachineȱoccupyȱ4ȱbytesȱ
ofȱmemoryȱeach.ȱWithȱtheseȱoffsets,ȱyouȱcanȱmakeȱaȱmapȱshowingȱexactlyȱwhereȱeachȱ
variableȱappearsȱonȱtheȱstackȱrelativeȱtoȱtheȱframeȱpointer,ȱa6.ȱ
Havingȱ seenȱ thatȱ registersȱ d2-d7ȱ andȱ a2-a5ȱ areȱ beingȱ usedȱ toȱ holdȱ registerȱ
variables,ȱ itȱ nowȱ becomesȱ clearȱ whyȱ thoseȱ registersȱ wereȱ savedȱ inȱ theȱ functionȱ
prologue.ȱ ȱ Aȱ functionȱ mustȱ saveȱ theȱ valuesȱ inȱ anyȱ registerȱ thatȱ itȱ intendsȱ toȱ useȱ forȱ
registerȱvariablesȱsoȱthatȱtheȱoriginalȱvaluesȱcanȱbeȱrestoredȱbeforeȱreturningȱtoȱtheȱ
Download at http://www.pin5i.com/
18.1 Determining the Runtime Environmentȱ
545
ȱ
ȱcallingȱfunction,ȱthusȱpreservingȱitsȱregisterȱvariables.ȱ
Oneȱ lastȱ thingȱ aboutȱ registerȱ variables:ȱ Whyȱ wereȱ registersȱ d0-d1,ȱ a0-a1,ȱ andȱ
a6-a7ȱnotȱusedȱforȱregisterȱvariables?ȱOnȱthisȱmachine,ȱ a6ȱisȱusedȱasȱtheȱframeȱpointerȱ
andȱ a7ȱ isȱ theȱ stackȱ pointer.ȱ (Thisȱ assemblyȱ languageȱ givesȱ itȱ theȱ aliasȱ sp.)ȱ Aȱ laterȱ
exampleȱwillȱshowȱthatȱ d0ȱandȱ d1ȱareȱusedȱinȱreturningȱvaluesȱfromȱfunctions,ȱsoȱtheyȱ
canȇtȱbeȱusedȱforȱregisterȱvariables.ȱ
Butȱthereȱisȱnoȱapparentȱuseȱofȱ a0ȱorȱ a1ȱinȱthisȱcode.ȱTheȱobviousȱconclusionȱisȱ
thatȱ theyȱ haveȱ someȱ purpose,ȱ butȱ theȱ testȱ programȱ didȱ notȱ containȱ anyȱ codeȱ ofȱ thatȱ
type.ȱFurtherȱexperimentationȱisȱneededȱtoȱanswerȱthisȱquestion.ȱ
ȱ
ȱ
ȱ
18.1.5
Length of External Identifiers
ȱ
Theȱnextȱtestȱtriesȱtoȱdetermineȱtheȱmaximumȱallowableȱlengthȱofȱexternalȱidentifiers.ȱ
Thisȱ testȱ seemsȱ easyȱ enough:ȱ declareȱ andȱ useȱ aȱ variableȱ withȱ aȱ longȱ nameȱ andȱ seeȱ
whatȱhappens.ȱ
ȱ
/*
** External names
*/
a_very_long_name_to_see_how_long_they_can_be = 1;
movl
CAUTION!
#1,_a_very_long_name_to_see_how_long_they_can_be
ȱ
Itȱappearsȱfromȱthisȱcodeȱthatȱthereȱisnȇtȱaȱlimitȱonȱtheȱlengthȱofȱnames.ȱMoreȱprecisely,ȱ
thisȱ nameȱisȱwithinȱwhateverȱlimitȱ thereȱ is.ȱToȱ findȱ theȱlimit,ȱ keepȱ makingȱ theȱ nameȱ
longerȱandȱlongerȱuntilȱitȱisȱtruncatedȱinȱtheȱassemblyȱprogram.ȱ
ȱ
Inȱfact,ȱthisȱtestȱisȱnotȱadequate.ȱ Theȱfinalȱ limitȱ onȱ externalȱnamesȱ isȱimposedȱbyȱ theȱ
linker,ȱ whichȱ mayȱ happilyȱ readȱ longȱ namesȱ butȱ ignoreȱ allȱ butȱ theȱ firstȱ severalȱ
characters.ȱTheȱStandardȱrequiresȱexternalȱnamesȱtoȱbeȱsignificantȱinȱatȱleastȱtheirȱfirstȱ
sixȱcharactersȱ(thoughȱdifferencesȱinȱtheȱcaseȱofȱlettersȱmightȱbeȱlost).ȱToȱtestȱwhatȱtheȱ
linkerȱdoes,ȱsimplyȱlinkȱtheȱprogramȱandȱexamineȱtheȱresultingȱloadȱmapȱorȱnameȱlist.ȱ
ȱ
ȱ
ȱ
18.1.6
Determining the Stack Frame Layout
ȱ
Theȱruntimeȱstackȱholdsȱdataȱneededȱforȱeachȱfunctionȱtoȱrun,ȱincludingȱitsȱautomaticȱ
variablesȱandȱreturnȱaddresses.ȱTheȱnextȱfewȱtestsȱwillȱdetermineȱtwoȱrelatedȱthings:ȱȱ
Download at http://www.pin5i.com/
546ȱ
ȱ
Chapter 18 Runtime Environmentȱ
theȱ organizationȱ ofȱ theȱ stackȱ frameȱ andȱ theȱ protocolȱ forȱ callingȱ andȱ returningȱ fromȱ
functions.ȱȱTheȱresultsȱshowȱhowȱtoȱinterfaceȱCȱandȱassemblyȱlanguageȱprograms.ȱ
ȱ
ȱ
ȱ
Passing Function Arguments
ȱ
Thisȱexampleȱbeginsȱtheȱcallȱtoȱaȱfunction.ȱ
ȱ
/*
** Function calling/returning protocol, stack frame
*/
i2 = func_ret_int( 10, i1, i10 );
movl
movl
pea
jbsr
a6@(-16),sp@d7,sp@10
_func_ret_int
ȱ
Theȱfirstȱthreeȱinstructionsȱpushȱtheȱargumentsȱtoȱtheȱfunctionȱonȱtheȱstack.ȱTheȱfirstȱ
argumentȱ thatȱ isȱ pushedȱ isȱ theȱ oneȱ storedȱ atȱ a6@(-16):ȱ theȱ offsetsȱ examinedȱ earlierȱ
showȱthatȱthisȱvalueȱisȱtheȱvariableȱ i10.ȱ d7ȱisȱpushedȱnext;ȱitȱcontainsȱtheȱvariableȱ i1.ȱ
Theȱ lastȱ argumentȱ isȱ pushedȱ differentlyȱ thanȱ theȱ others.ȱ Theȱ peaȱ instructionȱ simplyȱ
pushesȱ itsȱ operandȱ onȱ theȱ stack,ȱ whichȱ isȱ anȱ efficientȱ wayȱ toȱ pushȱ aȱ literalȱ constant.ȱȱ
Whyȱ areȱ theȱ argumentsȱ beingȱ pushedȱ onȱ theȱ stackȱ inȱ theȱ oppositeȱ orderȱ fromȱ howȱ
theyȱappearedȱinȱtheȱargumentȱlist?ȱTheȱanswerȱwillȱbecomeȱclearȱshortly.ȱ
Theseȱinstructionsȱbeginȱtoȱcreateȱtheȱstackȱframeȱbelongingȱtoȱtheȱfunctionȱthatȱ
isȱaboutȱtoȱbeȱcalled.ȱByȱtracingȱtheȱinstructionsȱandȱkeepingȱtrackȱofȱtheirȱeffects,ȱweȱ
canȱconstructȱaȱcompleteȱpictureȱofȱtheȱstackȱframe.ȱThisȱpictureȱprovidesȱinformationȱȱ
ȱ
ȱ
ȱ
Lowerȱ
Memoryȱ
Addressesȱ
Argumentȱ#1
CurrentȱSPȱ
Argumentȱ#2
Argumentȱ#3
Higherȱ
Memoryȱ
Addressesȱ
?
OriginalȱSPȱValueȱ
ȱ
Figureȱ18.1ȱȱStackȱframeȱafterȱpushingȱtheȱargumentsȱ
ȱ
Download at http://www.pin5i.com/
18.1 Determining the Runtime Environmentȱ
547
ȱ
thatȱ isȱ helpfulȱ ifȱ youȱ needȱ toȱ traceȱ theȱ executionȱ ofȱ aȱ Cȱ programȱ atȱ theȱ assemblyȱ
languageȱ level.ȱ Figureȱ 18.1ȱ showsȱ whatȱ hasȱ beenȱ builtȱ soȱ far.ȱ Theȱ diagramȱ showsȱ
lowerȱmemoryȱaddressesȱatȱtheȱtopȱandȱhigherȱmemoryȱaddressesȱatȱtheȱbottom.ȱTheȱ
stackȱ growsȱ towardȱ lowerȱ memoryȱ addressesȱ (upward)ȱ asȱ valuesȱ areȱ pushedȱ onȱ it.ȱȱ
Theȱstackȱcontentsȱbelowȱtheȱoriginalȱstackȱpointerȱareȱunknown,ȱsoȱitȱisȱshownȱasȱaȱ
questionȱmark.ȱ
TheȱnextȱinstructionȱisȱaȱȈjumpȱsubroutine:Ȉȱitȱpushesȱtheȱreturnȱaddressȱonȱtheȱ
stackȱandȱbranchesȱtoȱtheȱbeginningȱofȱ _func_ret_int.ȱTheȱreturnȱaddressȱisȱusedȱbyȱ
theȱcalledȱfunctionȱwhenȱitȱisȱfinishedȱtoȱgoȱbackȱtoȱwhereȱitȱwasȱcalled.ȱTheȱstackȱnowȱ
looksȱlikeȱFigureȱ18.2.ȱ
ȱ
ȱ
ȱ
Function Prologue
ȱ
Executionȱcontinuesȱwithȱtheȱprologueȱofȱtheȱcalledȱfunction:ȱ
ȱ
int
func_ret_int( int a, int b, register int c )
{
int
d;
.globl
_func_ret_int:
link
moveml
movl
_func_ret_int
a6,#-8
#0x80,sp@
a6@(16),d7
ȱ
ȱ
ȱ
ȱ
ReturnȱAddrȱ
CurrentȱSP
Argumentȱ#1ȱ
Argumentȱ#2ȱ
Argumentȱ#3ȱ
?ȱ
OriginalȱSPȱValue
ȱ
ȱ
Figureȱ18.2ȱȱStackȱframeȱafterȱtheȱjumpȱsubroutineȱinstructionȱ
Download at http://www.pin5i.com/
548ȱ
ȱ
Chapter 18 Runtime Environmentȱ
Theȱprologueȱisȱsimilarȱtoȱtheȱoneȱexaminedȱearlier;ȱtheȱinstructionsȱmustȱbeȱexaminedȱ
inȱmoreȱdetailȱtoȱcompleteȱtheȱmapȱofȱtheȱstackȱframe.ȱTheȱlinkȱinstructionȱhasȱseveralȱ
steps.ȱFirst,ȱtheȱcontentsȱofȱa6ȱareȱpushedȱonȱtheȱstack.ȱSecond,ȱtheȱcurrentȱvalueȱinȱtheȱ
stackȱpointerȱisȱcopiedȱintoȱa6.ȱFigureȱ18.3ȱillustratesȱthisȱresult.ȱ
Finally,ȱ theȱ linkȱ instructionȱ subtractsȱ 8ȱ fromȱ theȱ stackȱ pointer.ȱ Asȱ before,ȱ thisȱ
createsȱtheȱspaceȱthatȱwillȱholdȱtheȱlocalȱvariablesȱandȱsavedȱregisterȱvalues.ȱTheȱnextȱ
instructionȱ savesȱ aȱ singleȱ registerȱ intoȱ theȱ stackȱ frame;ȱ theȱ operandȱ 0x80ȱ designatesȱ
registerȱ d7.ȱTheȱregisterȱisȱstoredȱatȱ theȱtopȱofȱ theȱstack,ȱ whichȱ indicatesȱthatȱ theȱ topȱ
portionȱofȱtheȱstackȱframeȱisȱwhereȱregisterȱvaluesȱareȱsaved;ȱtheȱremainingȱpartȱofȱtheȱ
stackȱframeȱmustȱbeȱwhereȱlocalȱvariablesȱareȱstored.ȱFigureȱ18.4ȱshowsȱwhatȱweȱknowȱ
soȱfarȱaboutȱtheȱstackȱframe.ȱ
Theȱ lastȱ taskȱ theȱ prologueȱ performsȱ isȱ toȱ copyȱ aȱ valueȱ fromȱ theȱ stackȱ intoȱ d7.ȱ
Theȱ functionȱ declaresȱ theȱ thirdȱ argumentȱ toȱ beȱ aȱ registerȱ variable,ȱ andȱ theȱ thirdȱ
argumentȱ isȱ 16ȱ bytesȱ downȱ fromȱ theȱ frameȱ pointer.ȱ Onȱ thisȱ machine,ȱ registerȱ
argumentsȱareȱpassedȱonȱtheȱstackȱnormallyȱandȱcopiedȱintoȱaȱregisterȱinȱtheȱfunctionȱ
prologue.ȱThisȱadditionalȱinstructionȱisȱoverhead—ifȱthereȱarenȇtȱenoughȱinstructionsȱ
inȱtheȱfunctionȱthatȱuseȱtheȱargument,ȱthereȱwonȇtȱbeȱenoughȱsavingsȱinȱspeedȱorȱspaceȱ
toȱoffsetȱtheȱoverheadȱofȱcopyingȱtheȱargumentȱintoȱaȱregister.ȱ
ȱ
ȱ
ȱ
ȱ
Oldȱa6ȱValueȱ
CurrentȱSPȱandȱa6
ReturnȱAddrȱ
Argumentȱ#1ȱ
Argumentȱ#2ȱ
Argumentȱ#3ȱ
?ȱ
OriginalȱSPȱValue
ȱ
ȱ
Figureȱ18.3ȱȱStackȱframeȱduringȱtheȱlinkȱinstructionȱ
Download at http://www.pin5i.com/
18.1 Determining the Runtime Environmentȱ
549
ȱ
Argument Ordering on the Stack
ȱ
Weȱcanȱnowȱdeduceȱwhyȱtheȱargumentsȱareȱpushedȱonȱtheȱstackȱinȱreverseȱorder.ȱTheȱ
calledȱfunctionȱaccessesȱtheȱargumentsȱusingȱoffsetsȱfromȱtheȱframeȱpointer.ȱWhenȱtheȱ
argumentsȱareȱpushedȱinȱreverseȱorder,ȱtheȱfirstȱargumentȱisȱonȱtopȱofȱtheȱpileȱandȱitsȱ
offsetȱfromȱtheȱframeȱpointerȱisȱaȱconstant.ȱInȱfact,ȱtheȱoffsetȱfromȱtheȱframeȱpointerȱtoȱ
anyȱ argumentȱ willȱ beȱ aȱ constantȱ valueȱ thatȱ isȱ independentȱ ofȱ howȱ manyȱ argumentsȱ
wereȱpushed.ȱ
Whatȱwouldȱhappenȱifȱtheȱargumentsȱwereȱpushedȱinȱtheȱoppositeȱorder?ȱThenȱ
theȱ offsetȱ toȱ theȱ firstȱ argumentȱ wouldȱ dependȱ onȱ howȱ manyȱ wereȱ pushed.ȱ Theȱ
compilerȱ couldȱ computeȱ thisȱ valueȱ exceptȱ forȱ oneȱ problem—theȱ actualȱ numberȱ ofȱ
argumentsȱpassedȱmightȱbeȱdifferentȱfromȱtheȱnumberȱofȱparametersȱthatȱtheȱfunctionȱ
expects.ȱInȱthisȱsituation,ȱtheȱoffsetsȱwouldȱbeȱincorrect,ȱandȱwhenȱtheȱfunctionȱtriedȱtoȱ
accessȱanȱargumentȱitȱwouldȱnotȱgetȱtheȱoneȱitȱwanted.ȱ
HowȱareȱextraȱargumentsȱhandledȱinȱtheȱreverseȬorderȱscheme?ȱTheȱdiagramȱofȱ
theȱstackȱframeȱshowsȱthatȱanyȱextraȱargumentsȱthatȱwereȱpassedȱwouldȱappearȱbelowȱ
theȱ firstȱ ones;ȱ theȱ distanceȱ fromȱ theȱ frameȱ pointerȱ toȱ theȱ firstȱ argumentȱ wouldȱ beȱ
unchanged.ȱ Therefore,ȱ theȱ functionȱ wouldȱ accessȱ theȱ firstȱ threeȱ argumentsȱ properlyȱ
andȱsimplyȱignoreȱtheȱextras.ȱ
ȱ
ȱ
ȱ
ȱ
CurrentȱSP
SavedȱRegisterȱValues
LocalȱVariables
Oldȱa6ȱValue
Currentȱa6
ReturnȱAddr
Argumentȱ#1
Argumentȱ#2
Argument #3
?
OriginalȱSPȱValue
ȱ
ȱ
Figureȱ18.4ȱȱStackȱframeȱafterȱtheȱlinkȱinstructionȱ
Download at http://www.pin5i.com/
Chapter 18 Runtime Environmentȱ
550ȱ
ȱ
TIP
Ifȱ theȱ functionȱ somehowȱ knewȱ thatȱ thereȱ wereȱ extraȱ arguments,ȱ onȱ thisȱ machineȱ itȱ
couldȱaccessȱtheirȱvaluesȱbyȱtakingȱtheȱaddressȱofȱtheȱlastȱargumentȱandȱincrementingȱ
thisȱ pointer.ȱ Butȱ itȱ isȱ betterȱ toȱ useȱ theȱ stdarg.hȱ macros,ȱ whichȱ provideȱ aȱ portableȱ
interfaceȱforȱaccessingȱvariableȱarguments.ȱ
ȱ
ȱ
ȱ
Final Stack Frame Layout
ȱ
Theȱmapȱofȱtheȱstackȱframeȱforȱthisȱcompilerȱisȱnowȱcomplete,ȱandȱisȱshownȱinȱFigureȱ
18.5.ȱ
Letȇsȱcontinueȱlookingȱatȱtheȱfunction:ȱ
ȱ
d = b - 6;
return a + b + c;
}
movl
subql
movl
movl
a6@(12),d0
#6,d0
d0,a6@(-4)
a6@(8),d0
ȱ
ȱ
ȱ
SavedȱRegisterȱ
Valuesȱ
StackȱPointer
Localȱ
Variablesȱ
OldȱFrameȱPtrȱ
FrameȱPointer
Argumentsȱ
Pushedȱinȱ
ReverseȱOrderȱ
TopȱofȱPreviousȱStackȱFrame
ȱ
Figureȱ18.5ȱȱStackȱframeȱlayoutȱ
ȱ
Download at http://www.pin5i.com/
18.1 Determining the Runtime Environmentȱ
551
ȱ
addl
addl
moveml
unlk
rts
a6@(12),d0
d7,d0
a6@(-8),#0x80
a6
ȱ
Theȱstackȱframeȱmapȱmakesȱitȱeasyȱtoȱdetermineȱthatȱtheȱfirstȱ movlȱinstructionȱcopiesȱ
theȱsecondȱargumentȱintoȱ d0.ȱTheȱnextȱinstructionȱsubtractsȱ6ȱfromȱthisȱvalue,ȱandȱtheȱ
thirdȱstoresȱtheȱresultȱinȱtheȱlocalȱvariableȱ d.ȱ d0ȱisȱusedȱasȱaȱȈscratchpadȈȱorȱtemporaryȱ
locationȱforȱcomputations;ȱthisȱisȱoneȱofȱtheȱreasonsȱitȱcannotȱbeȱusedȱtoȱholdȱregisterȱ
variables.ȱ
Theȱ nextȱ threeȱ instructionsȱ evaluateȱ theȱ expressionȱ inȱ theȱ returnȱ statement.ȱ
Thisȱvalueȱisȱtheȱoneȱweȱwantȱtoȱreturnȱtoȱtheȱcallingȱfunction.ȱButȱtheȱresultȱisȱjustȱleftȱ
inȱd0;ȱrememberȱthisȱdetailȱforȱlater.ȱ
ȱ
ȱ
ȱ
Function Epilogue
ȱ
Thisȱ functionȇsȱ epilogueȱ beginsȱ withȱ theȱ movemlȱ instruction,ȱ whichȱ restoresȱ theȱ
previouslyȱsavedȱregisterȱvalue(s).ȱThenȱtheȱ unlkȱ(unlink)ȱinstructionȱcopiesȱtheȱvalueȱ
inȱ a6ȱintoȱtheȱstackȱpointerȱandȱloadsȱ a6ȱwithȱitsȱformerȱvalue,ȱwhichȱisȱpoppedȱoffȱofȱ
theȱ stackȱ inȱ theȱ process.ȱ Theȱ effectȱ ofȱ thisȱ actionȱ isȱ toȱ deleteȱ theȱ portionȱ ofȱ theȱ stackȱ
frameȱaboveȱtheȱreturnȱaddress.ȱFinally,ȱtheȱ rtsȱinstructionȱreturnsȱfromȱtheȱfunctionȱ
byȱpoppingȱtheȱreturnȱaddressȱoffȱtheȱstackȱintoȱtheȱprogramȱcounter.ȱ
Executionȱ nowȱ resumesȱ inȱ theȱ callingȱ program.ȱ Noticeȱ thatȱ theȱ stackȱ isȱ notȱ
entirelyȱcleanedȱupȱyet.ȱ
ȱ
i2 = func_ret_int( 10, i1, i10 );
lea
movl
sp@(12),sp
d0,d6
ȱ
Theȱ firstȱ instructionȱ executedȱ afterȱ weȇveȱ returnedȱ toȱ theȱ callingȱ programȱ addsȱ 12ȱ toȱ
theȱstackȱpointer.ȱ Theȱadditionȱeffectivelyȱ popsȱtheȱargumentȱ valuesȱ offȱ ofȱtheȱ stack,ȱ
whichȱisȱnowȱinȱexactlyȱtheȱsameȱstateȱthatȱitȱwasȱinȱbeforeȱtheȱfunctionȱcallȱbegan.ȱ
Itȱ isȱ interestingȱ thatȱ theȱ calledȱ functionȱ doesȱ notȱ removeȱ itsȱ entireȱ stackȱ frameȱ
fromȱtheȱstack:ȱtheȱargumentsȱareȱleftȱforȱtheȱcallingȱprogramȱtoȱremove.ȱTheȱreason,ȱ
onceȱ again,ȱ hasȱ toȱ doȱ withȱ variableȱ argumentȱ lists.ȱ Theȱ callingȱ functionȱ pushesȱ theȱ
argumentsȱonȱtheȱstack,ȱsoȱitȱisȱtheȱonlyȱoneȱwhoȱknowsȱforȱsureȱhowȱmanyȱargumentsȱ
thereȱare.ȱHence,ȱonlyȱtheȱcallingȱfunctionȱcanȱsafelyȱremoveȱthem.ȱ
Download at http://www.pin5i.com/
Chapter 18 Runtime Environmentȱ
552ȱ
ȱ
Return Values
ȱ
Theȱepilogueȱdidȱnotȱtouch d0,ȱsoȱitȱstillȱcontainsȱtheȱvalueȱreturnedȱbyȱtheȱfunction.ȱ
Theȱ secondȱ instructionȱ executedȱ afterȱ returningȱ fromȱ theȱ functionȱ copiesȱ d0ȱ intoȱ d6,ȱ
whichȱisȱtheȱvariableȱ(i2)ȱtoȱwhichȱtheȱresultȱisȱassigned.ȱ
Withȱ thisȱ compiler,ȱ then,ȱ aȱ functionȱ returnsȱ aȱ valueȱ byȱ leavingȱ itȱ inȱ d0,ȱ theȱ
callingȱfunctionȱgetsȱtheȱvalueȱfromȱd0ȱafterȱtheȱfunctionȱhasȱreturned.ȱThisȱprotocolȱisȱ
theȱotherȱreasonȱthatȱd0ȱisȱnotȱusedȱtoȱholdȱregisterȱvariables.ȱ
Theȱnextȱfunctionȱcalledȱreturnsȱaȱdouble.ȱ
ȱ
dbl = func_ret_double();
c1 = func_ret_char_ptr( c1 );
jbsr
movl
movl
_func_ret_double
d0,a6@(-48)
d1,a6@(-44)
pea
jbsr
addqw
movl
a5@
_func_ret_char_ptr
#4,sp
d0,a5
ȱ
Thisȱfunctionȱdoesnȇtȱhaveȱanyȱarguments,ȱsoȱnothingȱisȱpushedȱonȱtheȱstack.ȱAfterȱitȱ
returns,ȱbothȱ d0ȱandȱ d1ȱareȱstored.ȱOnȱthisȱmachine,ȱdoublesȱareȱ8ȱbytesȱlong,ȱtooȱbigȱ
toȱ fitȱ inȱ oneȱ register.ȱ Therefore,ȱ bothȱ d0ȱ andȱ d1ȱ areȱ neededȱ toȱ returnȱ oneȱ ofȱ theseȱ
values.ȱ
Theȱlastȱfunctionȱcallȱillustratesȱhowȱpointerȱvaluesȱareȱreturnedȱfromȱfunctions:ȱ
theyȱareȱalsoȱpassedȱbackȱthroughȱ d0.ȱAȱdifferentȱcompilerȱmightȱpassȱpointerȱvaluesȱ
backȱthroughȱa0ȱorȱsomeȱotherȱregister.ȱTheȱremainingȱinstructionsȱinȱtheȱprogramȱareȱ
theȱprologueȱforȱthisȱfunction.ȱ
ȱ
ȱ
ȱ
18.1.7
Expression Side Effects
ȱ
InȱChapterȱ4ȱIȱmentionedȱthatȱifȱanȱexpressionȱsuchȱasȱ
ȱ
ȱ
y + 3;
ȱ
appearedȱ inȱ aȱ program,ȱ itȱ wouldȱ beȱ evaluatedȱ butȱ wouldȱ notȱ affectȱ theȱ programȱ
becauseȱitsȱresultȱwasȱnotȱsaved.ȱAȱfootnoteȱthenȱexplainedȱthatȱitȱactuallyȱcouldȱaffectȱ
theȱexecutionȱofȱtheȱprogramȱinȱaȱsubtleȱway.ȱ
Considerȱ Programȱ 18.3,ȱ whichȱ isȱ supposedȱ loȱ returnȱ theȱ valueȱ ofȱ a + b.ȱ Theȱ
functionȱ computesȱ aȱ resultȱ butȱ doesnȇtȱ returnȱ anythingȱ becauseȱ theȱ expressionȱ wasȱ
erroneouslyȱ omittedȱ fromȱ theȱ returnȱ statement.ȱ Butȱ withȱ thisȱ compiler,ȱ theȱ functionȱ
actuallyȱworks!ȱȱd0ȱisȱusedȱtoȱcomputeȱx,ȱandȱbecauseȱthisȱexpressionȱisȱtheȱlastȱoneȱȱ
Download at http://www.pin5i.com/
18.1 Determining the Runtime Environmentȱ
553
ȱ
ȱ
/*
** A function that works on some machines despite a major error.
*/
int
erroneous( int a, int b )
{
int
x;
/*
** Compute the answer, and return it
*/
x = a + b;
return;
}
ȱ
Programȱ18.3ȱȱAȱfunctionȱthatȱaccidentallyȱreturnsȱtheȱproperȱvalueȱȱ
ȱ
ȱȱȱȱȱȱȱȱnoȬret.cȱ
ȱ
ȱ
ȱ
ȱ
ȱ
evaluated,ȱ d0ȱ stillȱ containsȱ theȱ resultȱ whenȱ theȱ functionȱ hasȱ finished.ȱ Quiteȱ
accidentally,ȱtheȱfunctionȱreturnsȱtheȱproperȱvalueȱtoȱtheȱcallingȱprogram.ȱ
Nowȱsupposeȱweȱinsertedȱtheȱexpressionȱ
ȱ
a + 3;
ȱ
beforeȱtheȱreturnȱstatement.ȱThisȱnewȱcomputationȱwouldȱchangeȱd0.ȱEvenȱthoughȱtheȱ
resultȱofȱtheȱexpressionȱisȱnotȱstoredȱinȱanyȱvariable,ȱitȱhasȱaffectedȱtheȱexecutionȱofȱtheȱ
programȱbyȱchangingȱtheȱvalueȱthatȱisȱreturnedȱbyȱthisȱfunction.ȱ
Aȱ similarȱ problemȱ canȱ beȱ causedȱ byȱ debuggingȱ statements.ȱ Ifȱ youȱ addȱ theȱ
statementȱ
ȱ
printf( "Function returns the value %d\n", x );
ȱ
beforeȱtheȱ returnȱstatement,ȱtheȱfunctionȱnoȱlongerȱreturnsȱtheȱcorrectȱvalue.ȱRemoveȱ
theȱdebuggingȱstatementȱandȱitȱstartsȱworkingȱagain.ȱItȱisȱextremelyȱfrustratingȱwhenȱ
yourȱdebuggingȱstatementsȱchangeȱtheȱbehaviorȱofȱtheȱprogram!ȱ
Theseȱ effectsȱ areȱ allȱ madeȱ possibleȱ byȱ theȱ originalȱ error—theȱ omissionȱ ofȱ theȱ
expressionȱ fromȱ theȱ returnȱ statement.ȱ Thisȱ scenarioȱ mayȱ soundȱ unlikely,ȱ butȱ itȱ
occurredȱ surprisinglyȱ oftenȱ withȱ oldȱ Cȱ compilersȱ becauseȱ theyȱ wouldȱ notȱ warnȱ theȱ
programmerȱofȱaȱfunctionȱthatȱwasȱsupposedȱtoȱreturnȱaȱvalueȱbutȱdidȱnot.ȱ
Download at http://www.pin5i.com/
554ȱ
ȱ
Chapter 18 Runtime Environmentȱ
18.2 Interfacing With Assembly Language
ȱ
Thisȱexperimentȱhasȱshownȱeverythingȱneededȱtoȱwriteȱassemblyȱlanguageȱprogramsȱ
thatȱcanȱcallȱorȱbeȱcalledȱbyȱCȱprograms.ȱTheȱrelevantȱresultsȱforȱthisȱenvironmentȱareȱ
summarizedȱbelow—yourȱenvironmentȱsurelyȱdiffersȱinȱoneȱorȱmoreȱways!ȱ
First,ȱ theȱ nameȱ ofȱ theȱ assemblyȱ programȱ mustȱ followȱ theȱ rulesȱ forȱ externalȱ
identifiers.ȱOnȱthisȱsystem,ȱitȱmustȱbeginȱwithȱanȱunderscore.ȱ
Second,ȱ theȱ assemblyȱ programȱ mustȱ followȱ theȱ properȱ protocolȱ forȱ functionȱ
callsȱandȱreturns.ȱThereȱareȱtwoȱcases:ȱcallingȱaȱCȱfunctionȱfromȱanȱassemblyȱlanguageȱ
programȱandȱcallingȱanȱassemblyȱlanguageȱfunctionȱfromȱaȱCȱprogram.ȱToȱcallȱCȱfromȱ
assemblyȱlanguage:ȱ
ȱ
1. Ifȱregistersȱd0,ȱd1,ȱa0,ȱorȱa1ȱcontainȱimportantȱvalues,ȱtheyȱmustȱbeȱsavedȱbeforeȱ
callingȱtheȱCȱfunction,ȱbecauseȱtheȱCȱfunctionȱwillȱnotȱpreserveȱthem.ȱ
2. Anyȱargumentsȱtoȱtheȱfunctionȱmustȱbeȱpushedȱonȱtheȱstackȱinȱreverseȱorder.ȱ
3. Theȱ functionȱ mustȱ beȱ calledȱ withȱ aȱ Ȉjumpȱ subroutineȈȱ typeȱ ofȱ instructionȱ thatȱ
pushesȱtheȱreturnȱaddressȱonȱtheȱstack.ȱ
4. Whenȱ theȱ Cȱ functionȱ returns,ȱ theȱ assemblyȱ programȱ mustȱ removeȱ anyȱ
argumentsȱfromȱtheȱstack.ȱ
5. Ifȱaȱreturnȱvalueȱwasȱexpected,ȱitȱwillȱbeȱinȱd0ȱ(ifȱtheȱvalueȱisȱaȱdouble,ȱtheȱotherȱ
halfȱofȱitȱwillȱbeȱinȱd1).ȱ
6. Anyȱregistersȱthatȱwereȱsavedȱbeforeȱtheȱcallȱmayȱnowȱbeȱrestored.ȱ
ȱ
ToȱwriteȱanȱassemblyȱprogramȱthatȱisȱcalledȱfromȱC:ȱ
ȱ
1. Saveȱanyȱregistersȱ(otherȱthanȱd0,ȱd1,ȱa0,ȱandȱa1)ȱthatȱyouȱwishȱtoȱmodify.ȱ
2. Argumentȱ valuesȱ areȱ obtainedȱ fromȱ theȱ stackȱ whereȱ theȱ callingȱ Cȱ functionȱ
pushedȱthem.ȱ
3. Ifȱtheȱfunctionȱshouldȱreturnȱaȱvalue,ȱitȱisȱleftȱinȱd0ȱ(inȱwhichȱcaseȱd0ȱmustȱnotȱbeȱ
savedȱandȱrestored).ȱ
4. Beforeȱreturning,ȱtheȱfunctionȱmustȱremoveȱanythingȱitȱputȱonȱtheȱstack.ȱ
ȱ
ItȱisȱnotȱnecessaryȱtoȱbuildȱaȱcompleteȱCȬstyleȱstackȱframeȱinȱyourȱassemblyȱprogram.ȱ
AllȱyouȱneedȱtoȱdoȱtoȱcallȱaȱCȱfunctionȱisȱtoȱpushȱtheȱargumentsȱinȱtheȱrightȱmannerȱ
andȱcleanȱthemȱupȱwhenȱtheȱfunctionȱreturns.ȱInȱanȱassemblyȱprogramȱcalledȱbyȱaȱCȱ
function,ȱyouȱmustȱaccessȱtheȱargumentsȱfromȱwhereȱtheȱCȱfunctionȱputȱthem.ȱ
Download at http://www.pin5i.com/
18.3 Runtime Efficiencyȱ
555
ȱ
Beforeȱ youȱ canȱ actuallyȱ writeȱ assemblyȱ functions,ȱ youȱ willȱ needȱ toȱ knowȱ theȱ
assemblyȱlanguageȱforȱyourȱmachine.ȱTheȱcursoryȱknowledgeȱthatȱallowedȱusȱtoȱfigureȱ
outȱwhatȱanȱexistingȱassemblyȱprogramȱdoesȱisȱnotȱenoughȱforȱwritingȱnewȱprograms.ȱ
Programsȱ 18.4ȱ andȱ 18.5ȱ areȱ twoȱ examplesȱ thatȱ callȱ assemblyȱ functionsȱ fromȱ Cȱ
functionsȱandȱviceȱversa.ȱTheyȱareȱusefulȱillustrationsȱevenȱthoughȱtheyȱareȱspecificȱtoȱ
thisȱenvironment.ȱTheȱfirstȱexampleȱisȱanȱassemblyȱlanguageȱprogramȱthatȱreturnsȱtheȱ
sumȱ ofȱ threeȱ integerȱ arguments.ȱ Theȱ functionȱ doesȱ notȱ botherȱ completingȱ theȱ stackȱ
frame;ȱ itȱ justȱ computesȱ theȱ sumȱ andȱ returns.ȱ Weȱ wouldȱ callȱ thisȱ functionȱ fromȱ aȱ Cȱ
functionȱinȱthisȱmanner:ȱ
ȱ
sum = sum_three_values( 25, 14, -6 );
ȱ
Theȱ nextȱ exampleȱ showsȱ aȱ fragmentȱ ofȱ anȱ assemblyȱ languageȱ programȱ whichȱ
hasȱthreeȱvaluesȱtoȱprint.ȱItȱcallsȱprintfȱtoȱdoȱtheȱjob.ȱ
ȱ
ȱ
ȱ
18.3 Runtime Efficiency
ȱ
Whenȱ isȱ aȱ programȱ Ȉtooȱ big?Ȉȱ Onȱ olderȱ computers,ȱ whenȱ theȱ programȱ grewȱ largerȱ
thanȱtheȱamountȱofȱmainȱmemory,ȱitȱsimplyȱwouldȱnotȱrun,ȱthusȱitȱwasȱȈtooȱbig.ȈȱEvenȱ
onȱmodernȱmachines,ȱaȱprogramȱthatȱmustȱbeȱstoredȱinȱROMȱmustȱbeȱsmallȱenoughȱtoȱ
fitȱintoȱtheȱavailableȱmemory. 57
ȱ
ȱ
ȱ
ȱ
|
| Sum three integer arguments and return the
| total.
|
.text
.globl
_sum_three_values
_sum_three_values:
movl sp@(4),d0
|Get 1st arg,
addl sp@(8),d0
|add 2nd arg,
addl sp@(12),d0 |add last arg.
rts
|Return.
ȱ
Programȱ18.4ȱȱAssemblyȱlanguageȱprogramȱthatȱsumsȱthreeȱintegersȱ
ȱ
ȱȱȱȱȱȱȱȱȱȱȱsum.sȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
ȱReadȱOnlyȱMemoryȱ(ROM)ȱisȱmemoryȱthatȱcannotȱbeȱchanged.ȱItȱisȱoftenȱusedȱtoȱholdȱprogramsȱinȱcomputersȱdedicatedȱtoȱ
controllingȱsomeȱdevice.ȱ
57
Download at http://www.pin5i.com/
Chapter 18 Runtime Environmentȱ
556ȱ
ȱ
ȱ
|
| Need to print the three values x, y, and z.
|
movl
z,sp@| Push args on the
movl
y,sp@| stack in reverse
movl
x,sp@| order: format, x,
movl
#format,sp@| y, and z.
jbsr
_printf
| Now call printf
addl
#16,sp
| Clean up stack
\&...
.data
format:
.ascii
"x = %d, y = %d, and z = %d"
.byte
012, 0
| Newline and null
.even
x:
.long
25
y:
.long
45
z:
.long
50
ȱ
Programȱ18.5ȱȱAssemblyȱlanguageȱprogramȱthatȱcallsȱprintfȱȱ
ȱ
ȱ
ȱȱȱȱȱȱȱȱprintf.sȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Butȱ manyȱ modernȱ computerȱ systemsȱ makeȱ thisȱ boundaryȱ lessȱ obviousȱ thanȱ itȱ
onceȱ wasȱ byȱ providingȱ virtualȱ memory.ȱ Virtualȱ memoryȱ isȱ implementedȱ byȱ theȱ
operatingȱ system,ȱ whichȱ bringsȱ theȱ activeȱ partsȱ ofȱ theȱ programȱ intoȱ memoryȱ whenȱ
neededȱ andȱ copiesȱ inactiveȱ partsȱ toȱ disk,ȱ thusȱ allowingȱ theȱ systemȱ toȱ runȱ largerȱ
programs.ȱ Butȱ theȱ largerȱ theȱ programȱ theȱ moreȱ copyingȱ isȱ required.ȱ Soȱ ratherȱ thanȱ
beingȱunableȱtoȱrunȱtheȱprogramȱatȱall,ȱweȱgetȱaȱgradualȱreductionȱinȱperformanceȱasȱ
theȱprogramȱgrowsȱlarger.ȱȱSoȱwhenȱisȱtheȱprogramȱtooȱbig?ȱWhenȱitȱrunsȱtooȱslowly.ȱ
Theȱ issueȱ ofȱ executionȱ speedȱ isȱ obviouslyȱ relatedȱ toȱ itsȱ size.ȱ Theȱ slowerȱ theȱ
programȱexecutes,ȱtheȱmoreȱuncomfortableȱitȱwillȱbeȱtoȱuseȱit.ȱItȱisȱhardȱtoȱidentifyȱtheȱ
pointȱ atȱ whichȱ aȱ programȱ isȱ suddenlyȱ Ȉtooȱ slowȈȱ unlessȱ itȱ mustȱ respondȱ toȱ someȱ
physicalȱeventsȱoverȱwhichȱitȱhasȱnoȱcontrol.ȱForȱexample,ȱaȱprogramȱtoȱoperateȱaȱCDȱ
playerȱisȱclearlyȱtooȱslowȱifȱitȱcannotȱprocessȱtheȱdataȱasȱfastȱasȱitȱcomesȱoffȱofȱtheȱCD.ȱ
ȱ
ȱ
ȱ
18.3.1
Improving Efficiency
ȱ
Modemȱ optimizingȱ compilersȱ doȱ aȱ veryȱ goodȱ jobȱ ofȱ producingȱ efficientȱ objectȱ codeȱ
fromȱaȱCȱprogram.ȱTherefore,ȱspendingȱtimeȱtryingȱtoȱmakeȱyourȱcodeȱmoteȱefficientȱ
byȱmakingȱsmallȱchangesȱtoȱitȱisȱusuallyȱnotȱveryȱproductive.ȱ
Download at http://www.pin5i.com/
18.3 Runtime Efficiencyȱ
557
ȱ
TIP
ȱ
Ifȱ aȱ programȱ isȱ tooȱ largeȱ orȱ tooȱ slow,ȱ selectingȱ aȱ moreȱ efficientȱ algorithmȱ orȱ dataȱ
structureȱisȱaȱmuchȱmoreȱeffectiveȱwayȱtoȱimproveȱtheȱperformanceȱthanȱplayingȱwithȱ
individualȱvariablesȱtoȱseeȱifȱdeclaringȱthemȱ registerȱhelpsȱorȱnot.ȱThisȱfactȱdoesȱnotȱ
giveȱ youȱ licenseȱ toȱ beȱ sloppyȱ inȱ yourȱ coding,ȱ however,ȱ becauseȱ poorȱ codeȱ alwaysȱ
makesȱthingsȱworse.ȱ
Ifȱaȱprogramȱisȱtooȱlarge,ȱitȱisȱeasyȱtoȱimagineȱwhereȱyouȱmightȱlookȱforȱwaysȱtoȱ
makeȱitȱsmaller;ȱtheȱlargestȱfunctionsȱandȱdataȱstructures.ȱButȱifȱaȱprogramȱisȱtooȱslow,ȱ
whereȱ doȱ youȱ evenȱ startȱ toȱ lookȱ toȱ improveȱ itsȱ speed?ȱ Theȱ answerȱ isȱ toȱ profileȱ theȱ
program,ȱwhichȱsimplyȱmeansȱtoȱmeasureȱhowȱmuchȱtimeȱisȱspentȱexecutingȱeachȱofȱ
itsȱparts.ȱTheȱportionsȱofȱtheȱprogramȱthatȱtakeȱtheȱlongestȱareȱobviousȱcandidatesȱforȱ
optimization.ȱMakingȱtheȱmostȱheavilyȱusedȱpartsȱofȱtheȱprogramȱfasterȱisȱanȱeffectiveȱ
useȱofȱyourȱtime.ȱ
MostȱUNIXȱsystemsȱcomeȱwithȱprofilingȱtools,ȱandȱsuchȱtoolsȱareȱavailableȱforȱ
manyȱotherȱsystemsȱasȱwell.ȱFigureȱ18.6ȱisȱaȱportionȱofȱtheȱoutputȱfromȱoneȱsuchȱtool.ȱȱȱ
Itȱshowsȱtheȱnumberȱofȱtimesȱeachȱfunctionȱwasȱcalledȱandȱtheȱnumberȱofȱsecondsȱthatȱ
wereȱ spentȱ inȱ thatȱ functionȱ duringȱ oneȱ executionȱ ofȱ aȱ particularȱ program.ȱ Theȱ totalȱ
executionȱtimeȱwasȱ32.95ȱseconds.ȱThereȱareȱthreeȱinterestingȱpointsȱweȱcanȱlearnȱfromȱ
thisȱlist.ȱ
ȱ
1.
Someȱ ofȱ theȱ mostȱ oftenȱ usedȱ functionsȱ areȱ libraryȱ functions.ȱ Inȱ thisȱ example,ȱ
mallocȱandȱ freeȱheadȱtheȱ list.ȱYouȱcannotȱchangeȱhowȱ theyȱ areȱ implemented,ȱ
butȱ ifȱ theȱ programȱ wasȱ redesignedȱ soȱ thatȱ itȱ didȱ notȱ dynamicallyȱ allocateȱ
memoryȱorȱdidȱsoȱlessȱoften,ȱitsȱspeedȱcouldȱbeȱimprovedȱbyȱupȱtoȱ25%.ȱ
2.
Someȱfunctionsȱusedȱaȱlotȱofȱtimeȱbecauseȱtheyȱwereȱcalledȱaȱlot.ȱEvenȱthoughȱ
eachȱindividualȱcallȱwasȱquick,ȱthereȱwereȱaȱlotȱofȱthem.ȱ_nextch_from_chrlstȱisȱ
anȱ example.ȱ Eachȱ callȱ toȱ thisȱ functionȱ usedȱ onlyȱ aboutȱ 4.3ȱ microseconds.ȱȱ
Becauseȱ itȱ isȱ soȱ short,ȱ itȱ isȱ unlikelyȱ thatȱ youȱ couldȱ improveȱ thisȱ functionȱ veryȱ
much.ȱ Butȱ itȱ isȱ worthȱ lookingȱ atȱ simplyȱ becauseȱ itȱ isȱ calledȱ soȱ often.ȱ Aȱ fewȱ
judiciousȱregisterȱdeclarationsȱmightȱmakeȱaȱsignificantȱdifference.ȱ
3.
Someȱ functionsȱ wereȱ notȱ calledȱ often,ȱ butȱ eachȱ callȱ tookȱ aȱ longȱ time.ȱ Forȱ
example,ȱtheȱfunctionȱ _lookup_macroȱaveragedȱoverȱ265ȱmicrosecondsȱperȱcall.ȱ
Findingȱaȱfasterȱalgorithmȱtoȱperformȱthisȱtaskȱcouldȱmakeȱtheȱprogramȱupȱtoȱ
7¾%ȱȱfaster. 58 ȱ
ȱ
Asȱaȱlastȱresort,ȱyouȱcouldȱrecodeȱindividualȱfunctionsȱinȱassemblyȱlanguage.ȱ
ȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱȱ
ȱActuallyȱthereȱisȱaȱfourthȱpointȱtoȱbeȱlearned,ȱȱmallocȱwasȱcalledȱ20,833ȱtimesȱmoreȱoftenȱthanȱfree,ȱsoȱsomeȱmemoryȱhasȱ
leaked!ȱ
58
Download at http://www.pin5i.com/
Chapter 18 Runtime Environmentȱ
558ȱ
ȱ
ȱ
Seconds
------4.94
3.21
2.85
2.82
2.69
2.57
1.35
1.23
1.10
1.09
0.91
0.90
0.82
0.79
0.77
0.65
0.57
0.51
0.46
0.41
0.37
0.35
0.34
0.32
0.31
0.31
0.31
# Calls
------293426
272593
658973
272593
791303
9664
372915
254501
302714
285031
197235
272419
285031
7620
63946
292822
272594
34374
151006
6473
8843
23774
203535
10984
133032
604
52627
Function Name
----------------------malloc
free
_nextch_from_chrlst
_insert
_check_traverse
_lookup_macro
_append_to_chrlst
_interpolate
_next_input_char
_input_fliter
demote
putfreehdr
_nextchar
_lookup_number_register
_new_character
allocate
_getfreehdr
_next_text_char
_duplicate_char
_expression
_sub_expression
_skip_white_space
_copy_interpolate
_copy_function
_duplicate_ascii_char
_process_filled_text
_next_ascii_char
ȱ
Figureȱ18.5ȱȱSampleȱprofilingȱinformationȱ
ȱ
ȱ
ȱ
ȱ
ȱ
ȱ
Theȱ smallerȱ theȱ function,ȱ theȱ easierȱ itȱ isȱ toȱ recode.ȱ Theȱ benefitȱ mayȱ alsoȱ beȱ greater,ȱ
becauseȱ theȱ fixedȱ overheadȱ ofȱ theȱ Cȱ prologueȱ andȱ epilogueȱ consumeȱ aȱ greaterȱ
percentageȱ ofȱ theȱ executionȱ timeȱ ofȱ smallȱ functions.ȱ Recedingȱ largerȱ functionsȱ inȱ
assemblyȱlanguageȱisȱmoreȱdifficultȱandȱisȱthereforeȱaȱlessȱproductiveȱuseȱofȱyourȱtime.ȱ
ȱ
Oftenȱ theȱ profileȱ willȱ notȱ tellȱ youȱ anythingȱ thatȱ youȱ donȇtȱ alreadyȱ know,ȱ butȱ
sometimesȱtheȱresultsȱcanȱbeȱquiteȱunexpected.ȱTheȱadvantageȱofȱprofilingȱisȱthatȱyouȱ
canȱbeȱsureȱyouȱareȱspendingȱyourȱtimeȱonȱtheȱareasȱinȱtheȱprogramȱthatȱcanȱbenefitȱ
mostȱfromȱimprovement.ȱ
ȱ
Download at http://www.pin5i.com/
18.5 Summary of Cautionsȱ
559
ȱ
18.4 Summary
CAUTION!
TIP
ȱ
Someȱofȱtheȱtasksȱweȇveȱexaminedȱonȱthisȱmachineȱareȱaccomplishedȱinȱtheȱsameȱwayȱ
inȱmanyȱotherȱenvironmentsȱasȱwell.ȱForȱexample,ȱmostȱenvironmentsȱconstructȱsomeȱ
kindȱofȱstackȱframeȱinȱwhichȱfunctionsȱstoreȱtheirȱdata.ȱTheȱdetailsȱofȱtheȱframeȱmightȱ
vary,ȱbutȱtheȱbasicȱideaȱisȱquiteȱcommon.ȱ
ȱ
Otherȱ tasksȱ areȱ likelyȱ toȱ beȱ differentȱ fromȱ oneȱ environmentȱ toȱ theȱ next.ȱ Someȱ
computersȱhaveȱspecificȱhardwareȱtoȱkeepȱtrackȱofȱfunctionȱarguments,ȱsoȱtheyȱmayȱbeȱ
handledȱ differentlyȱ thanȱ weȱ haveȱ seen.ȱ Otherȱ machinesȱ mightȱ passȱ functionȱ valuesȱ
backȱdifferently.ȱ
ȱ
Inȱ fact,ȱ differentȱ compilersȱ canȱ produceȱ veryȱ differentȱ codeȱ forȱ theȱ sameȱ machine.ȱȱ
Anotherȱcompilerȱforȱourȱtestȱmachineȱwasȱableȱtoȱuseȱanywhereȱfromȱ9ȱtoȱ14ȱregisterȱ
variables,ȱdependingȱ onȱ otherȱ circumstances.ȱ Differentȱ compilersȱ mayȱ haveȱ differentȱ
stackȱframeȱconventionsȱorȱuseȱincompatibleȱtechniquesȱforȱcallingȱandȱreturningȱfromȱ
functions.ȱ Thereforeȱ youȱ cannot,ȱ inȱ general,ȱ useȱ differentȱ compilersȱ toȱ compileȱ
differentȱpiecesȱofȱoneȱprogram.ȱ
Theȱ bestȱ wayȱ toȱ improveȱ theȱ efficiencyȱ ofȱ aȱ programȱ isȱ toȱ selectȱ betterȱ
algorithmsȱ forȱ it.ȱ Theȱ nextȱ bestȱ wayȱ toȱ improveȱ theȱ executionȱ speedȱ isȱ toȱ profileȱ theȱ
programȱtoȱseeȱwhereȱitȱisȱspendingȱmostȱofȱitsȱtime.ȱConcentratingȱyourȱoptimizationȱ
effortsȱonȱtheseȱportionsȱofȱtheȱprogramȱwillȱgiveȱyouȱtheȱbestȱresults.ȱ
ȱ
Learningȱaboutȱyourȱmachineȇsȱruntimeȱenvironmentȱisȱbothȱusefulȱandȱdangerous—
usefulȱbecauseȱtheȱknowledgeȱyonȱgainȱletsȱyouȱdoȱthingsȱyouȱwouldȱnotȱotherwiseȱbeȱ
ableȱ toȱ do;ȱ dangerousȱ becauseȱ anythingȱ thatȱ dependsȱ onȱ thisȱ knowledgeȱ isȱ likelyȱ toȱ
impairȱ theȱ portabilityȱ ofȱ yourȱ program.ȱ Theseȱ days,ȱ withȱ computersȱ becomingȱ
obsoleteȱ beforeȱ theyȱ reachȱ theȱ storeȱ shelves,ȱ theȱ possibilityȱ ofȱ movingȱ fromȱ oneȱ
machineȱtoȱanotherȱisȱveryȱreal,ȱwhichȱisȱaȱstrongȱmotivationȱtoȱproduceȱportableȱcode.ȱ
ȱ
ȱ
ȱ
18.5 Summary of Cautions
ȱ
1. Theȱ linker,ȱ notȱ theȱ compiler,ȱ determinesȱ theȱ maximumȱ lengthȱ ofȱ externalȱ
identifiersȱ(pageȱ545).ȱ
2. Youȱcannotȱlinkȱprogramsȱproducedȱbyȱdifferentȱcompilersȱ(pageȱ559).ȱ
Download at http://www.pin5i.com/
560ȱ
ȱ
Chapter 18 Runtime Environmentȱ
18.6 Summary of Programming Tips
ȱ
1. Useȱstdargȱtoȱimplementȱvariableȱargumentȱlistsȱ(pageȱ550).ȱ
2. Improvingȱtheȱalgorithmȱisȱmoreȱeffectiveȱthanȱoptimizingȱtheȱcodeȱ(pageȱ557).ȱ
3. Usingȱ techniquesȱ specificȱ toȱ oneȱ environmentȱ makesȱ theȱ programȱ nonportableȱ
(pageȱ559).ȱ
ȱ
ȱ
ȱ
18.7 Questions
ȱ
1. Whatȱdoesȱtheȱstackȱframeȱlookȱlikeȱforȱyourȱenvironment?ȱ
2. Whatȱisȱtheȱlongestȱexternalȱidentifierȱthatȱisȱsignificantȱonȱyourȱsystem?ȱ
3. Howȱ manyȱ variablesȱ willȱ yourȱ environmentȱ storeȱ inȱ registers?ȱ Doesȱ itȱ makeȱ anyȱ
distinctionȱbetweenȱpointerȱandȱnonpointerȱvalues?ȱ
4. Howȱ areȱ argumentsȱ passedȱ toȱ functionsȱ inȱ yourȱ environment?ȱ Howȱ areȱ valuesȱ
returnedȱfromȱfunctions?ȱ
5. Ifȱaȱfunctionȱdeclaresȱoneȱorȱmoreȱofȱitsȱargumentsȱtoȱbeȱregisterȱvariablesȱonȱtheȱ
machineȱexaminedȱinȱthisȱchapter,ȱtheȱargumentsȱtoȱtheȱfunctionȱareȱpushedȱonȱtheȱ
stackȱasȱusualȱandȱthenȱcopiedȱintoȱtheȱrightȱregistersȱinȱtheȱfunctionȱprologue.ȱItȱ
wouldȱ beȱ moreȱ efficientȱ toȱ passȱ thoseȱ argumentsȱ throughȱ theȱ registersȱ directly.ȱȱ
Couldȱthisȱargumentȱpassingȱtechniqueȱbeȱimplemented,ȱandȱifȱso,ȱhowȱcouldȱitȱbeȱ
done?ȱ
6. Inȱtheȱenvironmentȱdiscussed,ȱtheȱcallingȱfunctionȱisȱresponsibleȱforȱremovingȱtheȱ
argumentsȱ thatȱ itȱ pushedȱ onȱ theȱ stack.ȱ Isȱ itȱ possibleȱ forȱ theȱ calledȱ functionȱ toȱ
performȱthisȱtaskȱinstead?ȱIfȱnot,ȱwhatȱisȱrequiredȱtoȱmakeȱitȱpossible?ȱ
7. IfȱassemblyȱlanguageȱprogramsȱareȱmoreȱefficientȱthanȱCȱprograms,ȱwhyȱnotȱwriteȱ
everythingȱinȱassemblyȱlanguage?ȱ
ȱ
ȱ
ȱ
18.8 Programming Exercises
ȱ
1. Writeȱ anȱ assemblyȱ languageȱ functionȱ forȱ yourȱ systemȱ thatȱ takesȱ threeȱ integerȱ
argumentsȱandȱreturnsȱtheirȱsum.ȱ
2. Writeȱ anȱ assemblyȱ languageȱ programȱ thatȱ createsȱ threeȱ integerȱ valuesȱ andȱ callsȱ
printfȱtoȱprintȱthemȱout.ȱ
3. Supposeȱtheȱstdarg.hȱfileȱw
Download