• No se han encontrado resultados

ȱ

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.ȱ

33ȱMacrosȱareȱimplementedȱbyȱtheȱpreprocessorȱandȱareȱdiscussedȱinȱChapterȱ14.ȱ

34ȱForȱexample, printfȱexaminesȱtheȱcharactersȱinȱtheȱformatȱstringȱtoȱdetermineȱtheȱtypesȱofȱtheȱargumentsȱitȱisȱsupposedȱ

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.ȱ

1. Theȱmacrosȱcannotȱdetermineȱhowȱmanyȱargumentsȱactuallyȱexist.ȱ 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.ȱ

ȱ

CAUTION! 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ȱ

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ȱ

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ȱ

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:ȱ

ȱ

2. Theȱ greatestȱ commonȱ divisorȱ ofȱ twoȱ integersȱ Mȱ andȱ Nȱ (whereȱ M,ȱ Nȱ >ȱ 0)ȱ canȱ beȱ computedȱasȱfollows:ȱ ȱ ȱ ȱ ȱ ȱȱȱȱȱMȱ%ȱNȱ=ȱ0:ȱ ȱ ȱ 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.ȱ

ȱ ȱ

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ȱ

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ȱ

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.ȱ