Review:Pointers• Pointer:Datatypeforanaddress• Referenceoperator:e.g.“int*p=&x;”
– Assignaddressof“x”topointerp• Dereferenceoperator:e.g.“*p=0;”
– AccessthelocaJonpointedtoby“p”• Pointertoarrayvs.arrayofpointers
– “chara[2][3];char(*p)[3]=&a[1];”//pointertoarray– “char*p[2]={"yes","no”};”//arrayofpointers
• Valueofarray:pointertothefirstelementofarray– Given“inta[3];”,“a==&a[0];”– Thuscanbestoredinapointer:“int*p=a;p[0]=0;”
Review:Pointers,Arrays,andStrings#include<stdio.h>#include<string.h>intmain(){charbuf[20];char*str=buf;strcpy(buf,"Hello");prina("str=%s,buf=%s\n",str,buf);prina("strlen(str)=%u,strlen(buf)=%u,strlen(\"Hello\")=%u\n",strlen(str),strlen(buf),strlen("Hello"));prina("sizeof(str)=%u,sizeof(buf)=%u,sizeof(\"Hello\")=%u\n",sizeof(str),sizeof(buf),sizeof("Hello"));return0;}
>>./a.outstr=Hello,buf=Hellostrlen(str)=5,strlen(buf)=5,strlen("Hello")=5sizeof(str)=8,sizeof(buf)=20,sizeof("Hello")=6
PointerArithmeJc• AsubsetofarithmeJcoperatorsthatworkonpointers• Example:meaningof“p+N”#include <stdio.h>int main() { int *p = (int *) 0x1000; printf(“p=%p\np+2=%p\n”, p, p+2); return 0;}• p+N==PointertomemorylocaJonNoffsetsawayfromp
==&p[N] //AddresscalculaJon:p+sizeof(int)*N• Whyuse“p+N”ratherthan“&p[N]”?
– Theymeanexactlythesamething– Justlikethe[]operator,pointerarithmeJcismeanttoworkwithpointersto
elementsinanarray– ButoqenmoreconciseandintuiJvetousepointerarithmeJc
>>./a.outp=0x1000p+2=0x1008
ListofPointerArithmeJcOperaJons
• p+N– Result:PointertolocaJonNoffsetsawayfromp– E.g.“p=p+1;”,“p+=1;”,“++p;”
• p–N(Same,exceptnowoffsetisnegaJve)• p1–p2
– Result:Integeroffsetbetweenp1andp2– E.g.“intoffset=p1–p2;”(offsetbetweenthetwoarrayelements)– p1andp2mustbeofsamepointertype
• p1COMPAREp2(whereCOMPAREisoneof==,!=,<,>,<=,>=)– Result:Numericalcomparisonbetweenp1andp2– E.g.“p1<p2”(whetherp1comesbeforep2inarray)
• WhynotallowotheroperaJons(e.g.“p1+p2”or“p*N”)?– Wouldtheycomputeanymeaningfulvalues?
StrcpyUsingPointerArithmeJcchar* strcpy(char *dest, const char *src) { char *p = dest; while(*p++ = *src++); return dest;}• AteachiteraJonofloop,thebelowhappens(inorder)
1. *p=*src //Copycharat*srctolocaJon*p2. Thecharischeckedagainst0(or‘\0’)todecidewhethertostop
(Remember:returnvalueof=operatoristheassignedvalue)3. p++andsrc++ //Advancepandsrconechar
//Remember:post-incrementhappenslast• Stopswhen*src==‘\0’(whenendofstringisreached)
TypesAllowCorrectPointerArithmeJc#include<stdio.h>intmain(){inta[2][3];int*p=a[0];int(*p2)[3]=a;prina("p=%p,&a[0][0]=%p\n",p,&a[0][0]);prina("p2=%p,&a[0]=%p\n",p2,&a[0]);prina("p+1=%p,&a[0][1]=%p\n",p+1,&a[0][1]);prina("p2+1=%p,&a[1]=%p\n",p2+1,&a[1]);return0;}
>>./a.outp=0xbfdb6374,&a[0][0]=0xbfdb6374p2=0xbfdb6374,&a[0]=0xbfdb6374p+1=0xbfdb6378,&a[0][1]=0xbfdb6378p2+1=0xbfdb6380,&a[1]=0xbfdb6380
• “p”,“p2”pointtothesamelocaJon– p==&a[0][0]– p2==&a[0]
• “p+1”,“p2+1”pointtodifferentlocaJons– p+1==&a[0][1](base+sizeof(int))– p2+1==&a[1](base+sizeof(int[3]))
• Typesallowcompilertotranslatethemeaningof“p+1”correctly
TypesAllowCorrectPointerArithmeJc#include<stdio.h>intmain(){inta[2][3];int*p=a[0];int(*p2)[3]=a;prina("p=%p,&a[0][0]=%p\n",p,&a[0][0]);prina("p2=%p,&a[0]=%p\n",p2,&a[0]);prina("p+1=%p,&a[0][1]=%p\n",p+1,&a[0][1]);prina("p2+1=%p,&a[1]=%p\n",p2+1,&a[1]);return0;}
>>./a.outp=0xbfdb6374,&a[0][0]=0xbfdb6374p2=0xbfdb6374,&a[0]=0xbfdb6374p+1=0xbfdb6378,&a[0][1]=0xbfdb6378p2+1=0xbfdb6380,&a[1]=0xbfdb6380
• Whyarepointerstypeddifferentlydependingonbasetype?– Forcompilertoperformaccurate
pointerarithmeJc(orindexops)– Forcompilertoknowtypeof
dereferencedvalue.E.g.:intn,*p=…;float*q=…;n=*p//Noconversionneededn=*q//Float->intconversion
Thevoid*Type• Mixingdifferentpointertypesresultsincompilerwarning
– E.g.“int*p;char*p2=p;”resultsincompilerwarning– Generally,usingint*topointtocharlocaJonisabadidea
• Exceptwhenassigningtoandfromvoid*type– E.g.“int*p;void*p2=p;”isperfectlyfine– E.g.“void*p;int*p2=p;”isalsoperfectlyfine
• Voidpointer(void*)– Genericpointerthathasnobasetype– Cannotbedereferenced/nopointerarithmeJc
• SizeandtypeoflocaJonpointedtonotknown• AllitcandoispointtoamemorylocaJon
– Thenwhatisitusefulfor?• Topointtoapieceofmemorythatyouhavenotyetdecidetheusefor• Whenyoudecide,youcanassignittoaconcretepointerwithabasetype• WilllaterseeuseswhenwetalkaboutdynamicmemoryallocaJon
TheNULLValue• Equivalenttothenumericalvalue0(Justlike‘\0’isequivalentto0)
• NULLvaluemeanspointerpointstonothing• GoodpracJcetoiniJalizeallpointerstoNULL,insteadofleavingthemdangling.Why?– Easytocheckifapointerisvalid
• Ifpointer!=NULL,thenpointerisvalid• Noeasywaytocheckwhetherapointerisdangling
– IfaccessingNULLpointerbymistake• WillalwaysresultinanImmediatesegmentaJonfault• InsteadofaccessingandcorrupJngsomerandommemory(Resultsinwrongoutputordelayedcrash–hardtodebug)
CommandLineArguments#include<stdio.h>intmain(intargc,char**argv){inti;for(i=0;i<argc;i++){prina("argv[%d]=%s\n",i,argv[i]);}return0;}• argc:totalnumberofcommandlinearguments(includingcommanditself)• argv:stringarraythatcontainsthecommandlinearguments
>>./a.outfoobarargv[0]=./a.outargv[1]=fooargv[2]=bar
ConstTypeQualifier• Typequalifiers:Keywordsthatqualifieshowavariablecanbeused
– E.g.“const”,“volaJle”,etc.• Consttypequalifier:disallowsmodificaJonofvariables
– constfloatpi=3.14;• “pi”isconstant
– char*conststr=“Hello”;• “str”isconstant(cannotpointtoanotherstring)
– constchar*str=“Hello”;• LocaJonpointedtoby“str”isconstant(contentofstringcannotbemodified)
– size_tstrlen(constchar*s);• Contentofstringpointedtoby“s”cannotbemodifiedinside“strlen”
• IfcompilerdetectsmodificaJonècompileerrororwarning– A“contract”programmermakeswithherselfthatcompilerenforces– ServesasaformofdocumentaJonontheuseofvariables– Unlikemerecomments,compilerverifiesdocumentaJoniscorrect!
ExampleUseofConst1#include<string.h>intmain(){char*str="Hello";/*strisaSTRINGCONSTANT*/str[0]=“Y”;return0;}
• “str”pointstoastringconstant(immutablememory)• str[0]=“Y”;modifiesstringpointedtoby“str”• NoamountofallcapscommenJngwillpreventsomeoneelse(oryourself)fromwriJngthiscode
>>gcc./main.c>>./a.outSegmentaJonfault(coredumped)
Ifyourunthisyougetthis:
ExampleUseofConst1#include<string.h>intmain(){constchar*str="Hello";str[0]=“Y”;return0;}
>>gcc./main.c./test.c:6:10:error:read-onlyvariableisnotassignable
Ifyourunthisyougetthis:
• Contract:Stringpointedtoby“str”cannotbemodified• Compileremitserrorsincestr[0]=“Y”;isaviolaJon• A�achingconsttypequalifierguaranteesthattherearenoerrorsin
programwithrespecttomodifying“str”– Iftheprogramcompilescorrectly
ExampleUseofConst2#include<string.h>intmain(){char*str="Hello";/*strisaSTRINGCONSTANT*/strcpy(str,“World”);return0;}
• ThisJmestringconstantpointedtoby“str”ismodifiedbyastrcpy()call
• Sameissueaslastexamplecausescrash
>>gcc./main.c>>./a.outSegmentaJonfault(coredumped)
Ifyourunthisyougetthis:
ExampleUseofConst2#include<string.h>intmain(){constchar*str="Hello";strcpy(str,“World”);return0;}
>>gcc./main.c./test.c:6:10:warning:passing'constchar*'toparameteroftype'char*'discardsqualifiers>>./a.outSegmentaJonfault(coredumped)
Ifyourunthisyougetthis:
• Contractforstrcpy(char*dst,constchar*src):– Stringpointedtoby“dst”canbemodifiedbut“src”cannotbe
• Passing“str”to“dst”canpotenJallyleadtoaviolaJonofcontract– Now“dst”and“str”pointtothesamestring– But“dst”doesnothaveconsttypequalifierandmaymodifystring
• ProgramsJllcompilesbutgivesoffawarning
LexicalScopes• Scope:theporJonofsourcecodeinwhichasymbolislegal
andmeaningful– Symbol:nameofvariable,constant,orfuncJon– AtcompileJme,compilermatcheseachuseofasymboltoitscorrespondingsymboldefiniJonusingscopingrulesèThisprocessiscalledlinkage
• Cdefinesfourtypesofscopes– Blockscope:withincodeblockincurlybraces– FuncJonscope:withinfuncJons– Internallinkagescope:withinasingleCsourcefile– Externallinkagescope:globalacrossenJreprogram
• MeansofencapsulaJonanddata-hiding– InordertomaximizeencapsulaJon,minimizescope
LexicalScopeExampleintglobal;staJcintinternal;intmain(){intfuncJon;{intblock;}}
<main.c>
• “intblock”:BlockScope– Onlyvisiblewithincurlybraces
• “intfuncJon”:FuncJonScope– Onlyvisiblewithin“main()”funcJon
• “staJcintinternal”:InternalLinkageScope– Onlyvisiblewithin“main.c”file– staIc:storageclassspecifierlimiJngthescope
• “intglobal”:ExternalLinkageScope– VisibleacrossenJreprogram(sincenostaJc)
• “externintglobal”:Allowsuseof“global”infoo.c– extern:storageclassspecifierfordeclaringthe
variableisdefinedinanotherCsourcefile• Doesnotdefineanewvariable
– DefiniJon:allocaJngsomethinginmemory– DeclaraJon:tellingcompilersomethingexists
19
externintglobal;voidfoo(){global=10;}
<foo.c>
Shadowing#include<stdio.h>intn=10;voidfoo(){intn=5;prina("Second:n=%d\n",n);}intmain(){prina("First:n=%d\n",n);foo();prina("Third:n=%d\n",n);}
20
>>./a.outFirst:n=10Second:n=5Third:n=10
Shadowing#include<stdio.h>intn=10;voidfoo(){intn=5;prina("Second:n=%d\n",n);}intmain(){prina("First:n=%d\n",n);foo();prina("Third:n=%d\n",n);}
21
• Shadowing:whenavariableinaninnerscope“hides”avariableinanouterscope
• FuncJonscopevariable“intn=5”shadowsexternallinkagescopevariable“intn=10”
• Preventslocalchangesfrominadvertentlyspillingovertoglobalstate– Whoeverwrites“foo()”doesnotneednon-local
knowledgeofglobalvariableswithsamename– Importantformodularprogramming
• Donotoveruseshadowing– Reducesreadability(havetothinkofscopingrules)– Pronetomistakeswhenrenaminglocalvariables
(ifyoumissafew,itwillsJllcompilebutrefertoouterscopevariables)
LifeJme• LifeIme:duraJonofJmewhereavariableislive
– TimebetweentheallocaJonanddeallocaJonofavariableinmemory– IsarunJmeproperty(unlikescopes,alexicalorcompileJmeproperty)
• CdefinesthreetypesoflifeJmes– AutomaIc:variablesthatareautomaJcallycreated/destroyedatscope
begin/end,byallocaJon/deallocaJoncodegeneratedbycompiler– StaIc:variablesthatareliveforenJreduraJonofprogram
(NorelaJonto“staJc”storageclassspecifierforinternallinkagescope)– Manual:memorymanuallycreatedanddestroyedbytheprogrammer
(Willdiscussthislater)• LimitedlifeJmesallowconservaJonofmemory
– AutomaJc/manuallifeJmesallowmemorytobereclaimed• StaJcvariablesareguaranteedtobeiniJalizedto0
– DoneoncebytheStandardCLibraryatrunJmebeforecalling“main()”– AutomaJcvariablesarenotiniJalizedto0
(AutomaJcvariablesmayneedtobecreated/destroyedmulJpleJmesandiniJalizingto0eachJmeistoocostly)
StorageClasses• Storageclass:combinaJonofvariablescopeandlifeJme
• local:Visibleonlywithincurlybraces(blockorfuncJon)andliveonlywhileexecuJngcodeinsidecurlybraces
• staJcglobal:Visiblewithinfileandalwayslive• global:Visibleacrossfilesandalwayslive• automaJcglobal?Impossible,sinceglobalvariablesneedtobealwayslive• staJclocal:Visibleonlywithincurlybracesbutalwayslive
– Isthisstorageclassreallyuseful?
Block/FuncIon InternalLinkage
ExternalLinkage
AutomaJc local N/A N/A
StaJc staJclocal staJcglobal global
StaJcLocalUse1:ReturningLocalArray
char*ascJme(conststructtm*Jmeptr){staIccharresult[26];…sprina(result,…);returnresult;}• Ischararray“result”liveaqerfuncJonreturns?• LocalarraysinafuncJoncannotbereturned
– Valueof“result”isjustacharpointer– LocalarraygetsdeallocatedonfuncJonreturnèdanglingpointer
• StaIcstorageclassspecifieron“result”makesarraystaIclocal– AllowsarraytolivebeyondfuncJonreturn
• Note:StaJchasdifferentmeaningswhenusedonglobalorlocalvariables!– StaJclocal:referstothelifeJmeofthevariable(alwayslive)– StaJcglobal:referstothescopeofthevariable(internallinkage)
StaJcLocalUse2:KeepingTrackofInternalState
voidfoo(){staIcintcount=0;//onlyiniJalizedatprogramstartupprina(“Foocalled%dJme(s).\n”,++count);}• “count”accessedonlyinfoo()->shouldbelocalscope(forencapsulaJon)
• “count”mustbekepttrackofacrosscallstofoo()->shouldhavestaIclifeJme
• “count”willbeiniJalizedto0atbeginningofprogramandthenretainitsvalueacrosscallstofoo()
StaJcLocalUse2:KeepingTrackofInternalState
intmain(){charstr[20],*tok;strcpy(str,"Blue,White,Red");tok=strtok(str,",");while(tok!=NULL){prina("token:%s\n",tok);tok=strtok(NULL,",");}return0;}
• char*strtok(char*str,constchar*delim):CStandardLibraryfuncJonthatparses“str”intoasequenceoftokensusing“delim”asdelimiter– Firstcalltostrtok(withstrargument):returnfirsttokenfor“str”– Subsequentcallstostrtok(withNULLargument):returntokenthatcomesnext– Needinternalstatetokeeptrackofwhereweareinthestring
• Instrtok,currentlocaJoniskeptacrosscallsusingastaJclocalpointer
>>./a.outtoken:Bluetoken:Redtoken:White
Example:LifeJmeofVariables
27
>>gcc./main.c./main.c:InfuncJon‘foo’:./main.c:4:warning:funcJonreturnsaddressoflocalvariable>>./a.out*p=5*p=10
#include<stdio.h>int*foo(){intx=5;return&x;}voidbar(){inty=10;}intmain(){int*p=foo();prina("*p=%d\n",*p);bar();prina("*p=%d\n",*p);return0;}
Example:LifeJmeofVariables#include<stdio.h>int*foo(){intx=5;return&x;}voidbar(){inty=10;}intmain(){int*p=foo();prina("*p=%d\n",*p);bar();prina("*p=%d\n",*p);return0;}
28
• Whathappened?1. Whenfooreturns,itreturnsapointertothe
deallocatedmemorylocaJonfor“x”2. When“*p”isprintedforthefirstJme,itaccesses
thedeallocatedlocaJonbutthelocaJonhasnotbeenreusedyet,soitprintsthecorrectvalue5
3. WhenfuncJonbar()iscalled,variable“inty”isallocatedtothesamelocaJonas“intx”thathasbeendeallocated,overwriJngthevaluewith10
4. When*pisprintedforthesecondJme,itprintstheoverwri�envalue10
• Why“intx”and“inty”endupinthesamelocaJonwillbecomeclearwhenwetalkabouthowmemoryismanagedforlocalvariablesbythecompiler