+ All Categories
Home > Documents > Pointers and Lexical Scoping -...

Pointers and Lexical Scoping -...

Date post: 14-Mar-2018
Category:
Upload: buinhan
View: 218 times
Download: 3 times
Share this document with a friend
28
Pointers and Lexical Scoping CS449 Fall 2017
Transcript

PointersandLexicalScoping

CS449Fall2017

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

Fix:UseStaJcLocalStorageClass

29

>>gcc./main.c>>./a.out*p=5*p=5

#include<stdio.h>int*foo(){staIcintx=5;return&x;}voidbar(){inty=10;}intmain(){int*p=foo();prina("*p=%d\n",*p);bar();prina("*p=%d\n",*p);return0;}


Recommended