0% found this document useful (0 votes)
107 views

04 LinkedStructures

This document discusses C++ memory models and linked data structures. It provides examples of creating struct instances by direct instantiation and dynamic instantiation using pointers. It demonstrates copying and passing struct instances, and discusses issues that can arise from aliasing pointers to struct instances. The document also comments on C++ standards, compilers, and open source politics regarding common C++ compilers like g++ and clang++.

Uploaded by

aditya123sridhar
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
107 views

04 LinkedStructures

This document discusses C++ memory models and linked data structures. It provides examples of creating struct instances by direct instantiation and dynamic instantiation using pointers. It demonstrates copying and passing struct instances, and discusses issues that can arise from aliasing pointers to struct instances. The document also comments on C++ standards, compilers, and open source politics regarding common C++ compilers like g++ and clang++.

Uploaded by

aditya123sridhar
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 52

4.

1he C++ memory model,


llnked sLrucLures,
and a few more Au1s
CS138 - WlnLer 2014
rof. Mlke Codfrey

2014-leb-22
"Nice paper, Mike, but could you
please make a few editorial
changes!

On page 1, !.."
2014-leb-22
This is LaTeX, a
document markup
language that we
researchers use to
write our papers
in. It is like HTML
but much more
complicated. Like,
C++ complicated.
2014-leb-22
?ak shavlng
Coal: LdlL paper Lo make a few changes & submlL Lo publlsher
8uL new lapLop runs Maverlcks and old lnsLall of La1ex now broken
Ck, leL's re-lnsLall, oh no, package managemenL sysLem MacorLs no
longer supporLed
8rowse alLernauves, declde Lo lnsLall "homebrew"
8ead homebrew docs, lookup whlch packages l need for La1ex plus
any oLhers l mlghL wanL, check whaL packages l had on old lapLop
(who dld l glve my old lapLop Lo?)
uownload all source les for homebrew lLself, lnsLall ruby, verlfy,
complle, lnsLall homebrew package managemenL sysLem
uownload Lhe source packages for homebrew LhaL l wanL, lncludlng
La1ex, complle, lnsLall, verlfy [1hls Lakes hours!]
Ck, back ln buslness now
2014-leb-22
2014-leb-22
1he orlglnal meme
[From an old Ren and Stimpy cartoon]
2014-leb-22
2014-leb-22
Cperaung
sysLem /
hardware
Memory (RAM)
8un-ume
envlronmenL
user's
program
user's daLa and
worklng sLorage
SLauc daLa
rogram sLack
lreesLore (heap)
1he C/C++ (!ava, yLhon, eLc)
memory model
2014-leb-22
1he memory model
ln C/C++, we Lyplcally complle Lhe source code lnLo Lhe local CS /
hardware-speclc language
Also, Lhe 81L may be wholly or parLly embedded ln Lhe complled code (sLauc
versus dynamlc llnklng)
ln !ava and C#, we complle source code lnLo a unlversal vlrLual machlne
(vM) language (!vM/CL8)
1he vM ls Lhen Lhe run-ume sysLem, and musL be lmplemenLed Lo run on
varlous CSs / hardware plauorms
Some languages, llke Scheme, yLhon, and erl are lotetpteteJ
1he run-ume envlronmenL LranslaLes and Lhen execuLes Lhe source code on
Lhe y
2014-leb-22
Creaung llnked sLrucLures ln C++
We'd llke Lo creaLe llsL-llke sLrucLures ln C++
We saw how Lo do Lhls ln C uslng C-sLrucLs and polnLers ln CS137
C++ sLrucLs are slmllar buL also dlerenL Loo
ln facL, C++ sLrucLs are acLually qulLe a blL more powerful Lhan
C sLrucLs
1hey are equlvalenL (lnLerchangeable modulo defaulL vlslblllLy) Lo C++
classes
We wlll only llghLly brush on Lhe more powerful sLu
noLe LhaL Lhe C++ llbrary denes several useful conLalners
(vecLor, llsL, map, eLc), buL we're golng Lo roll our own"
2014-leb-22
Creaung struct/class lnsLances
lnsLances of classes/sLrucLs are called objects, Lhere are Lwo
ways Lo creaLe Lhem ln C++:

1. ulrecL lnsLanuauon
strctName s;
Space ls allocaLed on Lhe run-ume sLack
8uL lnsLances dlsappear aL Lhe end of Lhelr denlng scope
1hls ls a problem lf we wanL Lo pass around llnked sLrucLures
use a perlod Lo selecL eld (or meLhod)
Coord c;
c.x = 10;
c.y = 20;
2014-leb-22
Creaung struct/class lnsLances
2. uynamlc lnsLanuauon (usually, Lhrough a polnLer)
strctName* sPtr= new strctName;
Space ls allocaLed on Lhe heap (Lho pLr sPtr ls on Lhe sLack) and
perslsLs unul expllclLly deleLed by programmer
MusL remember Lo delete lnsLances when no longer needed
use an "arrow" (mlnus-greaLer1han) Lo selecL eld/meLhod
Coord* p = new Coord;
p->x = 10;
p->y = 20;

delete p;
2014-leb-22
#include<string>
#include<iostream>
using namespace std;

struct Coord {
int x, y;
}; // Need ; at end of struct!

void print (Coord c) {
cout << x = << c.x << y = << c.y << endl;
}
2014-leb-22
int main (int argc,
char* argv[]) {
Coord a;
a.x = 3;
a.y = 5;
Coord b = a; // copy!
print (a);
print (b);
a.x = 17;
print (a);
print (b);

Coord* p1;
p1 = new Coord;
p1->x = 4;
p1->y = 12;
Coord* p2; // alias
p2 = p1; // ptr copy
print (*p1);
p1->x = 42;
print (*p2);

Coord* p3 = &a;
// p3 is an alias
p3->y = 83;
print (a);

delete p1; // good!
delete p2; // error
delete p3; // error
return 0;
}
2014-leb-22
[See dlagram]
LecLure 3
CS138 W14
2014-leb-22
A word abouL C++ sLandards
Cver Lhe years, Lhere have been several omclal sLandard
verslons of Lhe C++ language, each wlLh lLs own formal
denluon:
A8M-90, C++98, C++03, C++11, C++14 (ln dlscusslon phase)
ulerences lnclude changes Lo Lhe core language plus new
elemenLs ln Lhe C++ sLandard llbrary
1he 8oosL llbrary pro[ecL (www.boosL.org) ls used by Lhe C++
communlLy Lo eld LesL new llbrarles, can oen nd hlgh-quallLy,
robusL lmplemenLauons of useful ldeas Lhere
2014-leb-22
A word abouL C++ sLandards
l am uslng (mosLly) C++03 ln Lhese noLes. Why?
Compllers are only now beglnnlng Lo supporL Lhe C++11 dlalecL fully
MosL LexLbooks, web pages, eLc. are sull C++03 for now, Lho Lhls ls
changlng
Most C++ code you see out there or are ||ke|y to work on |n the near
future |s C++03
Companles are generally very slow Lo adopL radlcally new verslons of
exlsung Lechnologles: lL's rlsky and expenslve, and Lhe beneLs Lo
mlgraung are noL usually worLh Lhe boLher.

2014-leb-22
A word abouL C++ compllers
1he orlglnal A1&1 unlx command-llne compller was called
slmply "c++", Lhere are many oLher commerclal compllers
ouL Lhere also, lncludlng MS-vlsual SLudlo
g++ ls an open source C++ compller from Lhe CCC pro[ecL
lL ls "maLure", hlgh quallLy, and supporLs all of C++11
clang++ (whlch slLs on Lop of Lhe LLvM back end) ls anoLher
open source C++ compller LhaL ls overLaklng g++ ln popularlLy
LLVM/clang++ ls much newer and lLs deslgn ls more modern
clang++ ls also hlgh quallLy, and lmplemenLs mosL lf noL all of C++11
clang++ seems Lo be fasLer Lo complle, produce fasLer ob[ecL code,
and glve nlcer error messages Lhan g++ 2014-leb-22
Cpen source pollucs
g++/CCC
ls enurely "free soware", lL ls released under Lhe 3
rd
verslon of Lhe
Cnu ubllc Llcense (CL3)
CL3 requlres LhaL all "derlved works" be released under Lhe CL3 Loo
CCC was deslgned Lo be hard Lo break lnLo chunks LhaL could be used
as a parL of a non-CL pro[ecL
clang++/LLvM
ls also "open source", buL Lhe llcense ls dlerenL and more
"permlsslve" of whaL you can do wlLh Lhe LLvM codebase
8MS would say LhaL lL ls less "free"
LLvM was deslgned Lo be easy Lo Lake aparL + bulld new Lools around
Apple abandoned CCC for LLvM largely because of Lhe llcenslng, Lhey
are blg conLrlbuLors Lo Lhe LLvM pro[ecL
2014-leb-22
Compller archlLecLure 101
lL's common Lo deslgn a compller wlLh an expllclL "fronL-end"
and "back-end"
1he ftoot-eoJ LranslaLes source code lnLo a seL of lnLermedlaLe daLa
sLrucLures LhaL are (usually) largely lndependenL of boLh Lhe source
language (e.g., C++) and Lhe LargeL plauorm (e.g., Llnux, MacCS
uarwln, Wln64)
1he bock-eoJ Lakes Lhe lnLermedlaLe daLa sLrucLures and generaLes
blnary execuLables (and oLher blnarles) LhaL are ued Lo Lhe LargeL CS
e.g., g++ ls Lhe C++ fronL-end for CCC
clang++ ls Lhe C++ fronL-end for LLvM
vlsual-C++ ls Lhe C++ fronL-end (+luL) for Mlcroso vlsual SLudlo

jMote oboot compllets comloq lo c5241!]
2014-leb-22
Compller archlLecLure 101
Cen, Lhe fronL- and back-ends can be Leased aparL lnLo
separaLe componenLs
1hls allows fronL-ends for dlerenL source languages Lo use a common
back-end
8oLh Lhe CCC and LLvM compller sysLems supporL muluple source
languages ln Lhls way:
e.g., C, C++, Cb[ecuve-C, !ava, Ada, lC818An,
2014-leb-22
g++
CCC
backend
C++
source
C
source
gcc
Wln64
exe
Llnux
exe
C++ compllers ln CS138
lor now, we are uslng g++ wlLh MarmoseL, so LhaL's whaL
you have Lo alm Lo geL worklng
robably, lf lL works ln clang++, lL wlll work ln g++ Loo
1he uW sLudenL Llnux envlronmenL has boLh g++ and clang++
?ou can use any compller you llke Lo develop your code,
lncludlng MS-vlsual C++
8u1 lL has Lo work ln MarmoseL uslng g++, and LhaL ls up Lo you Lo
ensure
2014-leb-22
#include <string>
#include <iostream>
using namespace std;

struct Coord {
int x, y;
}; // Need ";" at end of struct!

void print (Coord c) {
cout << "x = " << c.x << " y = " << c.y << endl;
}




2014-leb-22
#include <string>
#include <iostream>
using namespace std;

struct Coord {
int x, y;
}; // Need ";" at end of struct!

void print (Coord c) {
cout << "x = " << c.x << " y = " << c.y << endl;
}

void printPtr (Coord* p) {
cout << "x = " << p->x << " y = " << p->y << endl;
}




2014-leb-22
int main (int argc,
char* argv[]) {
Coord a;
a.x = 3;
a.y = 5;
Coord b = a;
printPtr (a);
printPtr (b);
a.x = 17;
printPtr (a);
printPtr (b);

Coord* p1;
p1 = new Coord;
p1->x = 4;
p1->y = 12;
Coord* p2; // alias
p2 = p1;
printPtr (p1);
p1->x = 42;
printPtr (p2);

// This assgt is evil
Coord* p3 = &a;
p3->y = 83;
printPtr (a);

delete p1;
return 0;
}
2014-leb-22
[See dlagram]
See anything wrong here?
int main (int argc,
char* argv[]) {
Coord a;
a.x = 3;
a.y = 5;
Coord b = a;
printPtr (&a);
printPtr (&b);
a.x = 17;
printPtr (&a);
printPtr (&b);

Coord* p1;
p1 = new Coord;
p1->x = 4;
p1->y = 12;
Coord* p2; // alias
p2 = p1;
printPtr (p1);
p1->x = 42;
printPtr (p2);

// This assgt is evil
Coord* p3 = &a;
p3->y = 83;
printPtr (&a);

delete p1;
return 0;
}
2014-leb-22
[See dlagram]
#include<string>
#include<iostream>
using namespace std;

struct Coord {
int x, y;
}; // Need ";" at end of struct!

void print (Coord c) {
cout << "x = " << c.x << " y = " << c.y << endl;
c.x = 666;
}
void printPtr (Coord* p) {
cout << "x = " << p->x << " y = " << p->y << endl;
p->x = 666;
}


2014-leb-22
int main (int argc,
char* argv[]) {
Coord a;
a.x = 3;
a.y = 5;
print (a);
printPtr (&a);
print (a);

Coord* p1;
p1 = new Coord;
p1->x = 4;
p1->y = 12;
print (*p1);
printPtr (p1);
delete p1;
return 0;
}

2014-leb-22
[See dlagram]
C++ polnLers
A polnLer ls acLually a (sLrange) number
lL's Lhe (numerlc) address of Lhe Lhlng LhaL you are polnung Lo, oen
ln Lhe heap
1here ls such a Lhlng as "pLr arlLhmeuc", as you saw ln CS137
1here ls a speclal C++11 value called nullptr
lf a pLr has Lhe value nullptr Lhls means, "lm oot polouoq to
ooytbloq cotteotly"
lf you [usL declare a pLr, lL wlll conLaln random garbage as lLs lnlual
value
So, aer declarlng a pLr, lL's usually besL Lo seL lL Lo polnL Lo someLhlng or
seL lL Lo nullpLr rlghL away
[revlously, C++03 used Lhe NULL macro]
2014-leb-22
C++ polnLers
. can polnL Lo anyLhlng:
struct/class lnsLances (aka objects)
strings (whlch are ob[ecLs)
ints, doubles, bools, .
even oLher pLrs
We wlll use Lhem mosLly Lo polnL Lo struct / class
lnsLances, Lho
lor mosL of our examples, we'll assume we're managlng a llsL of
sLrlngs
2014-leb-22
nullptr vs. NULL
ln Lhe old days of C, glvlng Lhe (lnLeger) value zero Lo a pLr
was used Lo lndlcaLe LhaL Lhe pLr wasn'L polnung Lo anyLhlng
LaLer, Lhe macro NULL was creaLed as somewhaL safer and
more lnLuluve way Lo express Lhe same ldea
1he (old) C++ sLandards requlres NULL Lo evaluaLe Lo zero, mosLly Lhls
worked Ck buL Lhere were some slLuauons ln whlch lL dldn'L
. because lL could be LreaLed as an lnLeger Loo
C++11 denes Lhe speclal consLanL nullptr
lL's a keywotJ ln Lhe C++11 language (can'L reuse lL as a varlable name)
lL can be LreaLed as any klnd of pLr, buL noL as an lnLeger
lL can also be LreaLed as a bool
2014-leb-22
nullptr vs. NULL
?our compller may noL supporL nullptr as lL's parL of Lhe
new C++11 sLandard
8uL our verslon of g++ seems Lo be ne wlLh lL
NULL and nullptr should work lnLerchangeably for our purposes ln
CS138
. buL use nullptr lf you can !
. and please forglve me lf l forgeL and say NULL !

2014-leb-22
#include <iostream>
#include <string>
using namespace std;

void swap1 (int x, int y){
const int temp = x;
x = y;
y = temp;
cout << x << y <<endl;
}


int main (int argc, char*
argv[]) {
int x = 5;
int y = 37;
swap1 (x, y);
cout << x << y << endl;
return 0;
}

2014-leb-22
[See dlagram]
#include <iostream>
#include <string>
using namespace std;

void swap1 (int x, int y){
const int temp = x;
x = y;
y = temp;
cout << x << y <<endl;
}
void swap2 (int* px, int* py){
const int temp = *px;
*px = *py;
*py = temp;
cout << *px << *py <<endl;
}


int main (int argc, char*
argv[]) {
int x = 5;
int y = 37;
swap1 (x, y);
cout << x << y << endl;
swap2 (x, y);
cout << x << y << endl;
return 0;
}

2014-leb-22
[See dlagram]
See anything wrong here?
#include <iostream>
#include <string>
using namespace std;

void swap1 (int x, int y){
const int temp = x;
x = y;
y = temp;
cout << x << y <<endl;
}
void swap2 (int* px, int* py){
const int temp = *px;
*px = *py;
*py = temp;
cout << *px << *py <<endl;
}


int main (int argc, char*
argv[]) {
int x = 5;
int y = 37;
swap1 (x, y);
cout << x << y << endl;
swap2 (&x, &y);
cout << x << y << endl;
return 0;
}

2014-leb-22
[See dlagram]
#include <iostream>
#include <string>
using namespace std;

void swap1 (int x, int y){
const int temp = x;
x = y;
y = temp;
cout << x << y <<endl;
}
void swap2 (int* px, int* py){
const int temp = *px;
*px = *py;
*py = temp;
cout << *px << *py <<endl;
}


int main (int argc, char*
argv[]) {
int x = 5;
int y = 37;
swap1 (x, y);
cout << x << y << endl;
swap2 (&x, &y);
cout << x << y << endl;
int* px, py;//what's py?
px = &x;
px = new int;
*px = 93;
delete px;
return 0;
}

2014-leb-22
[See dlagram]
8evlew: SLauc and dynamlc
memory allocauon
Memory for your varlables come from elLher:
1. koo-ume stock handles auLomaLed allocauon of sLorage
for params and local varlables as procedures are called
1hls sLorage dlsappears auLomaucally aL Lhe end of Lhe proc call
2. lteestote (aka tbe beop) handles all programmauc
requesLs for sLorage vla malloc (and relauves) and new
(for C++ ob[ecLs/sLrucLs, buL also ints eLc.)
user musL reLurn Lhls sLorage when done vla free / delete
olnLer p ls on Lhe sLack, Lhe ob[ecL lL polnLs Lo ls on Lhe heap
Balloon *p = new Balloon;
2014-leb-22
[See dlagram]
#include <iostream>
#include <string>
using namespace std;

struct Node {
string val;
Node* next;
};

int main (int argc,
char* argv[]) {
Node* p = new Node;
p->val = "first";
p->next = nullptr;
Node* q, r;
// Note: r NOT a ptr


r.val = "flurble";
q = new Node;
q->next = p;
q->val = "second";
Node* s;
s = new Node;
s->val = "third";
s->next = q;
Node* temp = s;
while (temp != nullptr) {
cout << temp->val << endl;
temp = temp->next;
}
// Should delete objects
return 0;
}

2014-leb-22
[See dlagram]
#include <iostream>
#include <string>
using namespace std;

struct Node {
string val;
Node* next;
};

int main (int argc,
char* argv[]) {
Node* p = new Node;
p->val = "first";
p->next = nullptr;
Node* q, r;
// Note: r NOT a ptr


r.val = "flurble";
q = new Node;
q->next = p;
q->val = "second";
Node* s;
s = new Node;
s->val = "third";
s->next = q;
Node* temp = s;
while (nullptr != temp) {
cout << temp->val << endl;
temp = temp->next;
}
// Should delete objects
return 0;
}

2014-leb-22
noLe LhaL we don'L really need loLs of sLandalone polnLers p,
q, s, eLc. Lo creaLe a llsL
lf we wanL Lo creaLe a llsL, all we need ls a pLr Lo Lhe rsL elemenL,
Lhen leL each node's next varlable polnL Lo Lhe nexL elemenL
We'll use Lhe convenuon LhaL Lhe lasL elemenL's next ls Lhe
nullptr (Lhen we can Lell when we're aL Lhe end!)
We wlll now go lnLo Au1s, whlch we wlll (someumes)
lmplemenL uslng llnked sLrucLures
2014-leb-22
LecLure 6
CS138 W14
2014-leb-22
Arrrggghhh: NULL vs. nullptr
NULL works for any dlalecL of C++
nullptr requlres LhaL Lhe compller supporL C++11
1o geL lL Lo work wlLh g++, you may have Lo do Lhls
g++ -std=c++0x file.cc lor g++ v4.6.x
or
g++ -std=c++11 file.cc lor g++ v4.7 or laLer
lor our purposes, you can use elLher NULL or nullptr, lL
doesn'L really mauer
LvenLually, one day, you wlll use nullptr !
2014-leb-22
Au1s
An obsttoct Joto type (Au1) ls a maLhemaucal sLrucLure LhaL
has well-dened and recognlzable behavlour
lL cootolos Joto LhaL may be accessed only ln a prescrlbed manner, by
a seL of named opetouoos
Lach operauon has
A slqootote, whlch descrlbes Lhe params + Lhe Lype of Lhe reLurned value
A pte-cooJluoo (loglc sLmL) LhaL specles whaL ls assumed Lo be Lrue
before Lhe operauon may be applled
A post-cooJluoo (loglc sLmL) LhaL descrlbes Lhe value / eecL of Lhe
operauon
1he formallLy/rlgour of Lhe descrlpuons vary !
2014-leb-22
Some examples of Au1s
A vectot / sepoeoce ls an otJeteJ daLa conLalner LhaL allows
random access Lo lndlvldual elemenLs.
A stock ls an otJeteJ daLa conLalner wlLh a lllO (lasL ln =>
rsL ouL) pollcy on lnserLs/deleLes
8uL no random access Lo arblLrary elemenLs
A poeoe ls an . lllO .
2014-leb-22
Some examples of Au1s
A set ls an oootJeteJ daLa conLalner LhaL can conLaln a glven
elemenL aL mosL once
A molu-set ls . zero, one, or more umes
A Jlcuoooty / mop ls an oootJeteJ daLa conLalner of palrs
lf (a,b) and (a,c) are ln M, Lhen b==c ***
Can do lookup
M[a] reLurns b l (a,b) ln M
A molu-mop ls llke a map, excepL LhaL *** ls noL assumed
1he C++ SLandard Llbrary has lmplemenLauons of Lhese and
many more besldes! (and so does !ava, C#, .)
And Boost.org provldes even more cumng-edge C++ llbrarles
2014-leb-22
Au1s are obsttoct
1here may be muluple ways Lo lmplemenL a glven Au1, buL
Lhe absLracL meooloq ls Lhe same regardless
1haL ls, Lhe absLracL speclcauon of, e.g., a sLack, ls Lhe same
1hls polnL ls lmporLanL!
Cen, a programmlng language wlll supply means Lo creaLe a
hard lotetfoce around Lhe Au1
An lnLerface enforces a llmlLed access of cllenLs Lo Lhe lnLernal deLalls,
whlch Lhe cllenLs should noL be Louchlng dlrecLly
C++/!ava/C# do Lhls very well vla class denluons (C noL so much)
2014-leb-22
WhaL klnd of daLa do Au1s hold?
Many, buL noL all, Au1s are prlmarlly daLa cootoloets
1hey keep a collecuon of daLa of a parucular klnd organlzed ln some
lnLeresung way
e.g., sLack, queue, Lree, vecLor, .
uaLa conLalners can conLaln [usL abouL any klnd of daLa!
lor now, we'll assume LhaL elemenLs are sLrlngs, cos Lhey're more fun
Lo play wlLh
When we geL lnLo CC, we wlll show you how Lo dene qeoetlc
conLalners LhaL can hold any klnd of elemenL klnd
2014-leb-22
SLyle of Au1s
lnlually, we are golng Lo use a foocuoool programmlng sLyle
Lo creaLe our Au1s ln C-lsh C++
1hls ls clean maLhemaucally, buL someumes lnemclenL lf done nalvely
due Lo needless parameLer copylng
1hen, we'll use a more C-llke procedural model uslng tefeteoce
potometets
llnally, we'll lmplemenL Lhem ln an ob[ecL-orlenLed (CC) sLyle
1he general formaL of an Au1 operauon ln Lhls sLyle ls:
oewAu1 opNome (olJAu1, otbetlotoms)
l.e., pass ln Lhe Au1 as a param, geL a new one as a resulL for muLaLor ops
2014-leb-22
Return value
1he sLack Au1
A !"#$% ls an ordered conLalner of daLa LhaL enforces a lllO
pollcy on adds/removes
ermlued operauons: push, pop, peek, isEmpty
. plus a "consLrucLor" (cxr), whlch we'll call initStack for now
nlLs:
Someumes, pop and peek are comblned lnLo one operauon LhaL
performs boLh ops (and ls called pop)
Someumes, peek ls called top
2014-leb-22
1he sLack Au1: More formally
initStack (no args) creaLes + reLurns a (new) empLy sLack Lo Lhe caller
push Lakes sLack s and an elemenL e
oew
and reLurns a new sLack LhaL's
ldenucal Lo s excepL wlLh Lhe new elemenL on "Lop": e
oew
e
1
. e
N

pop Lakes a sLack s and reLurns a new sLack LhaL's ldenucal Lo s excepL
wlLh Lhe Lop elemenL removed: e
2
. e
N

peek Lakes a sLack and reLurns (buL does noL remove) Lhe rsL elL: e
1
isEmpty Lakes a sLack and reLurns Lrue or false, dependlng lf Lhe sLack ls
empLy: l.e., does N=0?
[Assume s ls a sLack whose currenL sequence ls e
1
. e
N
and e
oew
ls Lhe new elemenL

]

2014-leb-22
re- and posL-condluons
1hese are sLaLemenLs of loglc LhaL lnvolve Lhe parameLers,
Lhe reLurn value, and (maybe) Lhe global program sLaLe
re-condluon
ls Lhere anyLhlng we need (assume) Lo be Lrue abouL Lhe parameLers
(+ maybe Lhe global sLaLe) before uslng Lhls operauon?
osL-condluon
WhaL ls Lhe relauonshlp beLween Lhe lnpuL params + (evenLual) reLurn
value (+ maybe Lhe global sLaLe)?
l.e., WhaL does Lhls operauon acLually do?
2014-leb-22
initStack : -> sLack
re: Lrue
osL: reLurned value ls a (new) empLy sLack

isEmpty : sLack -> boolean
re: Lrue
osL: reLurn value ls Lhe same as n==0

push: sLack x elemenL -> sLack
re: Lrue
osL: reLurned sLack ls e
oew
e
1
. e
N

1he sLack Au1: Lven more formally
[Assume s ls a sLack whose currenL sequence ls e
1
. e
N
and e
oew
ls Lhe new elemenL

]

2014-leb-22
pop : sLack -> sLack
re: !isEmpty
osL: reLurned sLack ls e
2
. e
N


peek : sLack -> elemenL
re: !isEmpty
osL: reLurned value ls e
1

nuke : sLack -> sLack
re: true
osL: reLurned value ls an empLy sLack, old nodes deleLed

1he sLack Au1: Lven more formally
[Assume s ls a sLack whose currenL sequence ls e
1
. e
N
and e
oew
ls Lhe new elemenL

]

2014-leb-22
// This is roughly what we want, eventually
// It make take a while to get there
// but how should we define the Stack type itself?

Stack initStack () {}
Stack push (Stack s, string val) {}
bool isEmpty (Stack s) {}
Stack pop (Stack s) {}
string peek (Stack s) {}

int main (int argc, char* argv[]) {
Stack s;
s = initStack ();
s = push (s, "alice");
s = push (s, "bob");
cout << peek (s) << endl;
s = pop (s);

}

2014-leb-22
SLack lnLerface vs. lmplemenLauon
1hls ls Lhe lotetfoce for a sLack LhaL wlll be Lhe same (ldeally)
for any reasonable lmplemenLauon ln a C-llke sLyle
llrsL, we'll look aL an lmplemenLauon LhaL uses a llnked llsL
1hen we wlll use a vector-based approach
8uL Lhe absLracL lnLerface should be Lhe same!
Agaln, for now we assume an elemenL Lype of string
Ceoetlc sLacks (comlng laLer) wlll Lake any klnd of elemenL, llke a
vector does
2014-leb-22
lmplemenung a sLack
as a llnked llsL
llrsL lnLeresung deslgn quesuon:
WhaL daLa Lype (parameLer/reLurn Lype) should we use Lo model a
sLack as a llnked llsL?
8ecall our llnked llsL from Lhe oLher day:
We don'L need a pLr varlable on Lhe sLack for each elemenL, lnsLead
we keep a pLr Lo only Lhe rsL elemenL, and Lhen every Node lnsLance
(on Lhe heap) has a pLr Lo Lhe next elemenL
So we [usL have Lo keep Lrack of a slngle Node*
So Lhe daLa Lype LhaL besL models a sLack wlLh Lhls approach ls Node*
2014-leb-22
lmplemenung a sLack
as a llnked llsL
Conslder:

void push (Node* first, string val) {
Node* newNode = new Node;
newNode->val = val;
newNode->next = first;
// now what?
first = newNode;
}

2014-leb-22
lmplemenung a sLack
as a llnked llsL
Conslder Lhls slgnaLure for push
void push (Node* first, string val)
lf we wanL Lo push a new elemenL on Lo Lhe fronL of Lhe llsL, Lhen Lhe
first pLr wlll need Lo be reseL Lo polnL Lo Lhe new Node we creaLe
And lf we change Lhe first parameLer lnslde Lhe body of push, Lhe
eecL wlll noL percolaLe back Lo Lhe caller "
osslble soluuons:
use tefeteoce potometets (laLer)
uene a class wlLh meLhods push, pop, eLc. (laLer)
8eLurn Lhe new value of first as Lhe value of push
Node* push (Node* first, string val)
2014-leb-22
lmplemenung a sLack
as a llnked llsL
Node* push (Node* first, string val) {
Node* newNode = new Node;
newNode->val = val;
newNode->next = first;
// now what? This!
return newNode;
}

// in the main program
Node* s = nullptr; // new empty stack
// pass a stack in, get a new stack back
s = push (s, "alice");
s = push (s, "bob");


2014-leb-22
lmplemenung a sLack
as a llnked llsL
now leL's lmplemenL pop, peek, and isEmpty,
. and an "exLra" operauon nuke
. LhaL cleans up any mess we made when we're done wlLh Lhe sLack
l.e., deleLe Lhe heap-based Nodes we were uslng
2014-leb-22
LecLure 7
CS138 W14
2014-leb-22
int main (int argc, char* argv[]) {
Node* s = nullptr;
s = push (s, "alice");
s = push (s, "bob");
s = push (s, "carol");
cout << peek(s) << endl;
s = pop(s);
cout << peek(s) << endl;
s = nuke(s);
return 0;
}

2014-leb-22
[See dlagram]
ldlng Lhe lmplemenLauon . a blL
mm, we are tepteseouoq llsLs by uslng a polnLer Lo Lhe rsL
elemenL
lL's klnd of ugly for cllenLs Lo have Lo say Node* when Lhey are
Lhlnklng 5tock
Also lL's ugly for Lhem Lo have Lo know Lhe lnluallzauon deLalls
So leL's do Lhree Lhlngs:
1. Add typedef Node* Stack; aL Lhe beglnnlng of Lhe program
2. 8eplace Node* by Stack ln Lhe param llsLs
3. CreaLe an expllclL new funcuon initStack
2014-leb-22
#include<string>
#include<iostream>
#include<cassert>
using namespace std;

struct Node {
string val;
Node* next;
};

typedef Node* Stack;

Stack initStack () {
return nullptr;
}

bool isEmpty (Stack s) {
return nullptr == s;
}

2014-leb-22
Stack push (Stack s, string val) {
Node* newNode = new Node;
newNode->val = val;
newNode->next = s;
return newNode;
}

string peek (Stack s) {
assert (!isEmpty(s));
return s->val;
}

Stack pop (Stack s) {
assert (!isEmpty(s));
Node* newNode = s-> next;
delete s;
return newNode;
}


2014-leb-22
void nuke (Stack s) {
while (!isEmpty(s)) {
s = pop(s);
}
}

int main (int argc, char* argv[]) {
Stack s = initStack();
s = push (s, "alice");
s = push (s, "bob");
s = push (s, "carol");
cout << peek(s) << endl;
s = pop(s);
cout << peek(s) << endl;
nuke(s);
return 0;
}
2014-leb-22
lL's posslble Lo have muluple dlsuncL sLacks aL Lhe same ume!
int main (int argc, char* argv[]) {
Stack s1 = initStack();
Stack s2 = initStack();
s1 = push (s1, "alice");
s1 = push (s1, "bob");
s1 = push (s1, "carol");
s2 = push (s2, "first");
s2 = push (s2, "second");

}
2014-leb-22
[See dlagram]
. buL you don'L geL "copy semanucs" wlLh Lhls approach
int main (int argc, char* argv[]) {
Stack s1 = initStack();
Stack s2 = initStack();
s1 = push (s1, "alice");
s1 = push (s1, "bob");
s1 = push (s1, "carol");
s2 = push (s2, "first");
s2 = push (s2, "second");
s1 = s2; // Memory leak! Oh no!

}
2014-leb-22
[See dlagram]
Why Joo't we geL copy semanucs?
1he C-llke programmlng model provldes only weak
supporL for programmer-dened absLracuons
ln Lhls deslgn, we're [usL renamlng a polnLer Lype wlLh a
fancy name, C doesn'L glve us Lhe power of real CC
e.g., denlng how new ob[ecLs are made, (re)denlng whaL
asslgnmenL means
We need C++-sLyle structs / classes Lo do Lhe [ob
properly, as we'll see
2014-leb-22
SLack lnLerface vs. lmplemenLauon
1ake a good look aL Lhe lnLerface of Lhe varlous sLack
operauons, and lgnore Lhe code for a mlnuLe
lL's posslble Lo undersLand how Lo use a sLack by slmply sLudylng Lhe
lnLerface (lf Lhere's enough deLall specled by commenLs)
1he acLual deLalls of Lhe lmplemenLauon don'L mauer Lo Lhe cllenL
much as long as Lhey do Lhe [ob correcLly
We wlll see how we mlghL lmplemenL a sLack dlerenLly whlle sull
uslng Lhe same lnLerface
LaLer we wlll use an CC sLyle Lo change Lhe synLax sllghLly buL
preservlng Lhe ldeas
So on Lo Lhe vector-based approach!
And, yes, l wlll Lalk abouL emclency and param copylng aerwards
2014-leb-22
// Exactly the same main program as w. linked list
int main (int argc, char* argv[]) {
// Note that we can have two distinct
// stacks at the same time!
Stack s1; // except that no initStack is required
Stack s2;
s1 = push (s1, "alpaca");
s1 = push (s1, "beaver");
s1 = push (s1, "cat");
s1 = push (s1, "dog");
s2 = push (s2, "one");
s2 = push (s2, "two");
cout << peek(s1) << endl;
cout << peek(s2) << endl;
s1 = pop(s1);
cout << peek(s1) << endl;
nuke(s1); nuke (s2);
return 0;
}
2014-leb-22
[See dlagram]
ComplexlLy of sLack operauons
Llnked llsL lmplemenLauon
push, pop, peek, nuke
vecLor lmplemenLauon
push, pop, peek, nuke
2014-leb-22
SL Leachable momenL: AdapLers
?ou mlghL say Lo yourself:
ney, tbe vector closs Joes tbe job fot me. wby Joot l
jost ose tbot Jltectly lo my molo ptoqtom losteoJ of
botbetloq wltb Jefoloq o speclol lotetfoce ooJ coJe tbot
boslcolly jost teJltects foocuoo colls
1he answer ls LhaL when you deslgn an Au1 for use
by oLhers, Lhe lnLerface ls Lhe mosL lmporLanL parL!

2014-leb-22
// Using a vector directly instead of a
// Stack adapter class
int main (int argc, char* argv[]) {
vector<string> s1;
s1.push_back("alpha");
s1.push_back("beta");
s1.push_back("gamma");
vector<string> s2;
string v = s1.back();
cout << v << endl;
s1.pop_back();
cout << s1.back() << endl;
s2.push_back(v);
cout << s2.back() << endl;
s2.pop_back();
cout << s2.back() << endl; // Assertion failure
return 0;
}
2014-leb-22
An adapLer
1he sLack-lmplemenLed-by-a-vecLor ls an example of whaL's
called an oJoptet
1he sLack Au1 has a small, well undersLood Al: push, pop, eLc.
8uL vector has loLs of oLher funcuonallLy sLacks don'L need
e.g., random access Lo elemenLs, lLeraLors, capacity
ueslgnlng an lnLerface LhaL provldes exoctly whaL cllenLs need
and no more prevenLs Lhe cllenL from dependlng on
feaLures Lhey shouldn'L and also proLecLs Lhem from posslble
fuLure changes ln Lhe underlylng lmplemenLauon
2014-leb-22
An adapLer
lf we dlscover a more emclenL way of lmplemenung Lhe sLack
lnLerface, cllenLs don'L need Lo change Lhelr code as long as
Lhe lnLerface doesn'L change Loo
e.g., suppose we found LhaL Lhe vecLor class ran slowly on cerLaln klnds
of machlnes or LhaL Lhere was a llcenslng problem wlLh Lhe code
1hls sounds llke 8&u deslgn, buL lL's perhaps Lhe slngle mosL
lmporLanL sw englneerlng deslgn prlnclple Lhere ls:
lofotmouoo blJloq: SeparaLe lnu from lmpl. lde lmpl deLalls. ave
cllenLs depend only on well-deslgned, unllkely-Lo-change lnLerfaces.
1he lnu should be much less llkely Lo change Lhan Lhe lmpl deLalls.
2014-leb-22
Should we used a llnked llsL
or a vecLor? Why?
Well LhaL's a good quesuon, ln facL, Lhere already ls a generlc
Stack class ln Lhe S1L!
lL's an adapLor based on a deque (whlch ls somewhaL llke a vector),
and ln a sLyle very slmllar Lo whaL we dld (buL wlLhouL Lhe egreglous
copylng, more laLer), so really we should choose LhaL
lf Lhere were no such llbrary class, Lhen l would probably choose a
vector-based lmplemenLauon over Lhe homebrew llnked llsL, as Lhe
S1L vector class ls ln wlde use and does Lhe [ob and ls llkely Lo be
slmpler Lo lmplemenL (pLrs + llnked sLrucLures => bugs for a whlle)
2014-leb-22
Should we used a llnked llsL
or a vecLor? Why?
1he general polnL, Lho, ls LhaL you don'L and shouldn'L
need Lo undersLand how someLhlng ls lmplemenLed ln order
Lo use lL eecuvely
And lmplemenLers of llbrary classes wlll usually Lry Lo hlde Lhelr non-
essenual lmpl deLalls from you, and you should be graLeful for Lhls
And when you deslgn classes for use wlLhln a sw sysLem, Lhlnk abouL
whaL are Lhe essenual, public parLs, and whlch should be hldden
away from cllenLs as private
2014-leb-22
Cne more emclency lssue
1he nave funcuonal-sLyle vecLor-based approach we have
used does a LC1 of copylng of vecLors!
lL ls noL aL all reallsuc for emclency, Lho lL ls maLhemaucally Ck
A reallsuc lmplemenLauon ln a funcuonal sLyle someumes requlre
Lrlcks Lo make Lhlngs emclenL, buL we won'L go Lhere
lnsLead, we wlll (laLer) show you how Lo do Lhls ln a sLaLe-based CC
sLyle LhaL ls ne, emclency-wlse
1he llnked llsL approach we used does noL have Lhls problem
2014-leb-22
8eference parameLers
C /!ava supporL call-by-value" (only) for parameLers
Copy value of parameLer onLo call stock ftome (aka ocuvouoo tecotJ)
1hls has real overhead cosL lf Lhe param ls a "blg" enuLy, llke an ob[ecL
LhaL conLalns many sub-ob[ecLs
Cnly Lhe reLurn value (lf any) ls copled back
Can change param values lnslde proc, buL changes do noL propagaLe
back Lo Lhe calllng envlronmenL
Can use pLr params Lo cheaL" (common C pracuce, we wlll avold Lhls)
Changes Lo pLr don'L propagaLe back, buL changes Lo values polnLed Lo do!
Can use pLrs Lo pLrs Lo change pLrs!
Wouldn'L lL be nlce Lo allow changes Lo parameLers Lo
propagaLe back Lo Lhe calllng envlronmenL, lf/when we wanL?
2014-leb-22
8eference parameLers
C++ also supporLs Lhe ldea of tefeteoce parameLers
uL an ampersand aer Lhe parameLer Lype ln a proc decl

void swap (int& x, int& y) {}
void push (Stack& first) {}

1he param ls oot copled onLo Lhe call sLack
Any changes you make ln procedure wlll propagaLe back Lo Lhe caller
1hls ls called coll-by-tefeteoce
1he param acLs klnda llke a pLr, buL you use lL normally" as a varlable
of LhaL Lype, noL by dereferenclng wlLh *
8ef params are Lhe norm ln C++, geL used Lo Lhem
Can have a ref or const ref tetoto type . buL walL for CS247
2014-leb-22
AnoLher name for a reference ls an allas.
AnoLher name for "anoLher name for" ls allas.
"AnoLher name for "AnoLher name for"" ls a ulne.
Are ulnes allases? ulscuss for 10 marks.

2014-leb-22
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
void swap1 (int x, int y){
const int temp = x;
x = y;
y = temp;
cout << x << y <<endl;
}
void swap2 (int* px, int* py){
const int temp = *px;
*px = *py;
*py = temp;
cout << *px<< *py <<endl;
}


void swap3 (int& x, int& y){
const int temp = x;
x = y;
y = temp;
}
int main (int argc, char*
argv[]) {
int x = 5;
int y = 37;
swap1 (x, y);
cout << x << y << endl;
swap2 (&x, &y);
cout << x << y << endl;
swap3 (x, y);
cout << x << y << endl;
return 0;
}

2014-leb-22
LecLure 8
CS138 W14
2014-leb-22
CS138 Mld-Lerm
. ls not durlng mld-Lerm week, sorry folks .
lL's on 1hursday, 13 lebruary
l.e., Lwo weeks from Loday

?eah, ylkes, l mean l sull have Lo come up wlLh lL
LasL lecLure of LesLable maLerlal:
1hursday, 6 lebruary
2014-leb-22
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
void swap1 (int x, int y){
const int temp = x;
x = y;
y = temp;
cout << x << y <<endl;
}
void swap2 (int* px, int* py){
const int temp = *px;
*px = *py;
*py = temp;
cout << *px<< *py <<endl;
}


void swap3 (int& x, int& y){
const int temp = x;
x = y;
y = temp;
}
int main (int argc, char*
argv[]) {
int x = 5;
int y = 37;
swap1 (x, y);
cout << x << y << endl;
swap2 (&x, &y);
cout << x << y << endl;
swap3 (x, y);
cout << x << y << endl;
return 0;
}

2014-leb-22
8eference parameLers
C++ supporLs tefeteoce parameLers
uL an ampersand aer Lhe parameLer Lype ln a proc decl

void swap (int& x, int& y) {}
void push (Stack& first) {}

1he param ls oot copled onLo Lhe call sLack
Any changes you make ln procedure wlll propagaLe back Lo Lhe caller
1hls ls called coll-by-tefeteoce
1he param acLs klnda llke a pLr, buL you use lL normally" as a varlable
of LhaL Lype, noL by dereferenclng wlLh *
8ef params are Lhe norm ln C++, geL used Lo Lhem
Can have a ref or const ref tetoto type . buL walL for CS247
2014-leb-22
const& parameLers
A const ref param ls a ref param LhaL you can'L change
1he compller wlll prevenL you from changlng Lhe ob[ecL lnslde Lhe
procedure
Semanucally, lL's olmost Lhe same as a value param
lL ls legal (buL mosLly useless) Lo change a value param
const refs are also more emclenL Lhan value params, as you
don'L copy Lhe whole ob[ecL onLo Lhe run ume sLack, [usL a ref
1hls ls Lhe preferred way ln C++ Lo declare params LhaL you don'L
lnLend Lo change lnslde Lhe procedure
2014-leb-22
"8elax, l've only had Lwo beers"
uslng a (non-const) reference parameLer ls llke glvlng away
Lhe keys Lo your car aL a fraL parLy
!usL how much do you LrusL LhaL procedure, anyway?
Cen, you really do need Lo do lL, buL evaluaLe Lhe rlsk
use a const ref lf Lhe param should noL be changed by Lhe procedure

2014-leb-22
8eference params vs. pLrs
1he C language does noL have references, lL requlres uslng polnLer params
Lo make changes "percolaLe back"
Many C++ sysLems sLarLed ouL llfe as a C sysLem (and/or belng developed by C
programmers), so you wlll oen see Lhls sLyle (pLr params) ln lndusLrlal C++
code
1he beuer, cleaner, easler-Lo-undersLand C++ approach ls Lo use reference
(and consL ref) parameLers
So C++ ob[ecLs should osoolly be passed by reference, noL value or by polnLer
1ho l oen "forgeL" for sLrlngs & slmllar small ob[ecLs and pass Lhem by value
Ck Lo use value params for "small Lhlngs" (baslc Lypes / scalars) llke int,
double, bool, eLc, assumlng you don'L need changes Lo percolaLe back
And lf you do, you can always use a reference param for Lhem Loo
2014-leb-22
typedef Node* Stack;

string peek1 (Stack & first) {
string ans = first-> val;
first = nullptr;
return ans;
}

string peek2 (Stack first) {
string ans = first-> val;
first = nullptr;
return ans;
}

string peek3 (const Stack & first) {
string ans = first-> val;
first = nullptr;
return ans;
}

2014-leb-22
legal and nasLy Lo caller
lllegal, compller wlll complaln
legal buL has no eecL on caller
//
struct Employee {
string name;
int monthlySalary; // other stuff too, probably
};

// red text means common C++ usage
void GiveRaise1 (Employee e, int raise) {}
void GiveRaise2 (const Employee e, const int raise) {}
void GiveRaise3 (Employee &e, int &raise) {}
void GiveRaise4 (const Employee &e, ) {}
void GiveRaise5 (Employee *e, ) {}
void GiveRaise6 (const Employee *e, ) {}
void GiveRaise7 (Employee *const e, ) {}
void GiveRaise8 (const Employee *const e, ) {}

int main () {
Employee * pFrank = new Employee;
pFrank -> name = "Frank Lee";
pFrank -> monthlySalary = 5000;

//
int franksRaise = 700;
GiveRaise1 (*pFrank, franksRaise);
//
}
2014-leb-22
void GiveRaise1 (Employee e, int raise) {}
When Lhls fcn ls called, a copy of Lhe caller's ob[ecL/struct lnsLance e
and lnLeger raise are creaLed on sLack.
1hese coples may be changed wlLhln Lhe fcn, buL Lhe values do noL
percolaLe back Lo caller and are losL aL end of meLhod call.
(CC full LruLh: Lhe meLhod for maklng a copy ls dened by Lhe Employee
copy consLrucLor, we'll see Lhls ln CS247)

void GiveRaise2 (const Employee e, const int raise){}
A copy of ob[ecL e and lnLeger raise are creaLed on sLack, Lhey may noL
be changed wlLhln Lhe fcn/meLhod.
Lecuvely, Lhls ls preuy slmllar Lo GiveRaise1
2014-leb-22
void GiveRaise3 (Employee &e, int &raise) {}
Any menuon of ob[ecL e or lnLeger raise lnslde Lhe meLhod acLually
refers Lo Lhe varlables ln Lhe caller's envlronmenL.
1hus, changes can be made Lo raise or e lnslde GiveRaise3
percolaLe back Lo Lhe calllng envlronmenL lmmedlaLely.
void GiveRaise4 (const Employee &e, ) {}
8ead Lhls as "e ls a ref Lo a Lhlng LhaL's a const Employee"
Any menuon of e refers Lo caller's envlronmenL, buL you can'L change
Lhe ob[ecL e refers Lo ln any way.
Lecuvely, Lhls ls slmllar Lo GiveRaise2 excepL LhaL lL may be more
emclenL lf Employee ls a large" ob[ecL.

2014-leb-22
void GiveRaise5 (Employee *e, ) {}
Call w/o dereferenclng: GiveRaise5(pFrank,) [same for 6, 7, 8]
8ead Lhls as "e ls a polnLer Lo an Employee" [more C-sLyle Lhan C++]
A copy of a polnLer ls made on Lhe sLack, lf you manage Lo change Lhe
member varlables of Lhe ob[ecL e polnLs Lo, Lhese changes wlll perslsL ln
Lhe calllng envlronmenL
?ou can also make e Lo polnL Lo a new or dlerenL ob[ecL, buL LhaL
change wlll be losL aL Lhe end of Lhe meLhod call, and noL percolaLe back
void GiveRaise6 (const Employee *e,) {}
8ead Lhls as "e ls a polnLer Lo a Lhlng LhaL's a const Employee"
1haL ls, e can be changed Lo polnL Lo a dlerenL const Employee,
buL any lnsLance lL polnLs Lo cannoL be changed lnLernally.
lf you do change e Lo polnL Lo anoLher ob[ecL, Lhls ls noL percolaLed
back Lo Lhe caller.
2014-leb-22
void GiveRaise7 (Employee *const e, ) {}
8ead Lhls as "e ls a const polnLer Lo an Employee"
?ou can change Lhe lnLernal values of Lhe ob[ecL e polnLs Lo, buL you
can'L make e polnL Lo a dlerenL ob[ecL
1he const doesn'L add much, as wlLh GiveRaise2
void GiveRaise8 (const Employee *const e, ) {}
8ead Lhls as "e ls a const polnLer Lo a const Employee"
Can'L change Lhe value of Lhe ob[ecL e polnLs Lo, can'L change e Lo
polnL Lo anoLher ob[ecL
A sLrong guaranLee for C, buL Clve8alse4 makes Lhe same guaranLee
and ls easler Lo undersLand
2014-leb-22
usually, use Lhe sLyle of
GiveRaise3 lf you woot changes Lo percolaLe back Lo Lhe calllng
envlronmenL, or
GiveRaise4 lf you Joo't woot changes Lo percolaLe back
. buL uslng value params as ln GiveRaise1 ls also common
8eference parameLers are your frlend!
refer Lhem over C-sLyle polnLers for parameLers LhaL are struct /
class lnsLances
2014-leb-22
8eferences vs. reference parameLers
ln C++, normal ldenuers (varlables) can be references Loo, buL generally
we use Lhem only Lo glve a more convenlenL name Lo someLhlng long .

// Reasonable use
const Employee & e = emplList[Wloo].find(empNum);
cout << e.getName() << " " << e.getAddr() <<endl;

// Probably useless/bad idea
int x = 13;
int& y = x;
y = 36; // Changes value of x!
So C++ reference parameLers are [usL parameLers LhaL happen Lo be
references, lf LhaL makes sense Lo you
lf noL, don'L sweaL lL Loo much
2014-leb-22
8eference params and Au1s
We can now easlly swlLch Lo reference params ln our
Au1 denluons
Cld sLyle: funcuonal and sLaLeless
l.e., pass ln old Au1, geL new one back as reLurn value of proc
nave lmplemenLauon may resulL ln loLs of unneeded copylng of
large ob[ecLs, dependlng on lmpl chosen
new sLyle: sLaLeful.
ass ln "car keys" of Lhe Au1 lnsLance Lo procs, changes may be
made Lo lLs lnLernals before belng passed back (unless passed as a
const reference)
no egreglously unnecessary copylng
2014-leb-22
// vector-based approach of Stack is now quite reasonable
// No more crazy egregious copying of param vectors!
#include <iostream>
#include <string>
#include <vector>
#include <cassert>
using namespace std;

// Simple impl using a vector; as before
typedef vector<string> Stack;

// Note that we're not going to implement
// initStack in this version



2014-leb-22
// New way with ref params
bool isEmpty (const Stack& s){
return s.size()==0;
}

void push (Stack& s, string e){
s.push_back(e);
}


void pop (Stack& s) {
assert (!isEmpty(s));
s.pop_back();
}
2014-leb-22
// Old way with value params
bool isEmpty (Stack s) {
return s.size()==0;
}

Stack push (Stack s, string e){
s.push_back(e);
return s;
}

Stack pop (Stack s) {
assert (!isEmpty(s));
s.pop_back();
return s;
}

// New way with ref params
string peek (const Stack& s){
assert (!isEmpty(s));
return s.back();
}

void nuke (Stack& s) {
while (!isEmpty(s)) {
pop(s);
}
}
// Old way with value params
string peek (Stack s) {
assert (!isEmpty(s));
return s.back();
}

void nuke (Stack s) {
while (!isEmpty(s)) {
s = s.pop();
}
}

2014-leb-22
// Main program as w. linked list w. ref params
int main (int argc, char* argv[]) {
// Note that we can have two distinct
// stacks at the same time!
Stack s1;
Stack s2;
push (s1, "alpaca"); // Old: s1 = push (s1, "alpaca");
push (s1, "beaver"); // etc.
push (s1, "cat");
push (s1, "dog");
push (s2, "one");
push (s2, "two");
cout << peek(s1) << endl; // Same as non-ref param vers
cout << peek(s2) << endl;
pop(s1); // Old: s1 = pop(s1);
cout << peek(s1) << endl;
nuke(s); // Same as non-ref param vers
return 0;
}
2014-leb-22
1he 3 varlable klnds you meeL ln C++
Clobol votlobles are dened ootslJe of any encloslng funcuon/class/sLrucL
1hey come lnLo exlsLence when declared and dle aL Lhe end of Lhe program
We haven'L really used Lhem ln CS138, Lhelr use ls generally frowned upon
locol votlobles (lncl. params) are dened wltblo a funcuon/meLhod body
1hey come lnLo exlsLence (evenLually) when Lhe funcuon ls called, and dle
when lL LermlnaLes (lf noL before)
Membet / lostooce votlobles are a sob-pott of a larger varlable LhaL ls an
lnsLance of a struct or class
1hey are born when Lhe lnsLance ls creaLed, and dle when Lhe lnsLance dles

[We lgnore static class varlables and oLher mlnor excepuons for now]
2014-leb-22
Scopes of ldenuers and A8s
ln C/C++, an lJeoufet (usually, a varlable) ls vlslble from lLs
declarauon unul Lhe end of Lhe currenL scope":
Lnd of currenL block
Lnd of a procedure body
Lnd of loop / if / switch body, eLc.
Clobal varlables are vlslble globally (unul end of le scope)
A scope ls a (usually) conuguous chunk of a program LhaL
dellneaLes boundarles of vlslblllLy for ldenuers
8efore Lhe 1999 sLandard, all declarauons ln C had Lo come aL Lhe
beglnnlng of a scope (noL Lrue for C++)
2014-leb-22
Scopes of ldenuers and A8s
As your program execuLes, scopes are enLered and exlLed
When a new scope ls enLered, an ocuvouoo tecotJ (A8, area
of sLorage also called a stock ftome) ls creaLed for lL
A8s conLaln sLorage for parameLers, Lhe (evenLual) reLurn value, and
local varlables LuS Lhe locauon of where Lhe call was made from
Someumes Lhe same fcn can be called ln muluple places wlLhln a fcn
When a varlable declarauon ls encounLered, space for LhaL varlable ls
creaLed ln Lhe currenL A8
2014-leb-22
Scopes of ldenuers and A8s
"OotslJe of o Joq, o book ls o moo's best ftleoJ.
loslJe of o Joq, lt's too Jotk to teoJ."
Croucho Marx on scopes

When Lhe currenL scope ls exlLed, Lhe A8 for lL ls desLroyed,
along wlLh Lhe sLorage for Lhe varlables
ConLrol reLurns Lo Lhe calllng fcn aL Lhe polnL Lhe call was made
So you need Lo Lake care where Lhlngs are declared
2014-leb-22
#include <iostream>
#include <string>
using namespace std;

// Why won't this compile?
int max (int x, int y) {
if (x > y) {
int bigger = x;
} else {
int bigger = y;
}
return bigger;
}
2014-leb-22
#include <iostream>
#include <string>
using namespace std;

int max (int x, int y) {
// The scope of bigger needs to include
// the return statement!
int bigger;
if (x > y) {
bigger = x;
} else {
bigger = y;
}
return bigger;
}
2014-leb-22
int main (int argc, char* argv[]) {
int x, y;
cin >> x >> y;
if (x == y) {
cout << "they're equal" << endl;
} else {
int ans = max (x, y);
cout << "max is " << ans << endl;
}
// note: ans is not visible from here on
//
}
2014-leb-22
[See dlagram]
1he run-ume call sLack
AL any glven momenL, you mlghL have several scopes open:
e.g., main calls f calls g calls h
lf you pause Lhe execuuon of a program, Lhe sLack wlll conLaln an
acuvauon record for Lhe pendlng call chaln
Lach pend|ng ca|| has |ts own Ak (p|us Aks for any |ntra-fcn scopes)
When Lhe currenL (l.e., deepesL nesLed) call compleLes, lLs A8 ls
deleLed (aer copylng back any reLurn value)
LvenLually, all calls wlll nlsh, and Lhelr A8s wlll be deleLed Loo
2014-leb-22
#include <iostream>
#include <string>
using namespace std;
// All of these assume n >= 0
// Mildly flabby pedagogic version
int fact1 (int n) {
int ans;
if (n <= 1) {
ans = 1;
} else {
ans = n * fact1 (n-1);
}
return ans;
}

// Compact, somewhat cryptic version
int fact2 (int n){
return n <= 1 ? 1 : n * fact2 (n-1);
}


2014-leb-22
// The third way; use this, we will
int fact (int n) {
if (n <= 1) {
return 1;
} else {
return n * fact(n-1);
}
}

int main (int argc, char* argv[]) {
int k;
while ((cin >> k) && k >= 0) {
const int kfact = fact(k); // new const each time!
cout << k << "! = << kfact << endl;
return 0;
}
}

2014-leb-22
[See dlagram]
8ecurslon
?ou may have nouced LhaL Lhe fact funcuon calls
lLself, as you know, Lhls ls called tecotsloo
ln CS137, you saw CCu, mergsesorL, qulcksorL, eLc
8ecurslon ls an eleganL and powerful concepL for
problem solvlng
8uL lL's noLhlng maglcal Lo lmplemenL, you [usL geL
muluple A8s for Lhe same funcuon ln Lhe call sLack aL Lhe
same ume.
2014-leb-22
8ecurslon
8ecurslon ls a general Lechnlque for solvlng a large
problem, Lyplcally by progresslvely breaklng down
Lhe lnpuL unul lL's small enough" Lo solve easlly,
Lhen comblnlng Lhe resulLs back LogeLher
1hree baslc parLs:
1. 1rlvlal base case(s) (LhaL can be solved easlly and dlrecLly)
2. 8educuon operaLor (make Lhe daLa smaller")
3. Composluon operaLor (compose Lhe answer Lo Lhe
smaller" problem Lo geL Lhe full answer)
2014-leb-22



int fact1 (int n) {
if (n <= 1) {
return 1;
} else {
return n * fact1 (n-1);
}
}

8asls case
Composuon
8educuon
2014-leb-22
1owers of anol
We'll come back Lo recurslon ls more deLall when we sLudy more Au1s
(esp. Lrees) . buL before we go, leL's look aL a classlc example: 1he Lowers
of anol
Classlc formulauon:
ln a Lemple ln anol, Lhere are 64 dlerenLly-slzed dlsks sLacked on a pole ln
lncreaslng order of slze
1he monks musL move Lhe dlsks one aL a ume from one pole Lo a second pole,
uslng a Lhlrd pole as a Lemporary
no larger dlsk may ever slL on Lop of a smaller dlsk
1he soluuon ls really shorL and eleganL!
: lf Lhey move one dlsk per second, how long Lo move Lhe whole sLack?
2014-leb-22
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
void hanoi (int N, int src, int dest, int temp) {
if (N>0) {
hanoi (N-1, src, temp, dest);
cout << "Move from " << src << " to " << dest << endl;
hanoi (N-1, temp, dest, src);
}
}
int main (int argc, char* argv[]) {
int N;
cout << "How many rings? ";
cin >> N;
assert (N>0);
hanoi (N, 1, 3, 2);
return 0;
}
2014-leb-22
1he queue Au1
LasL day, we showed how Lhe run-ume sLack sLore A8s of
pendlng calls (lncludlng recurslve calls)
now, we'll expand Lhls menLal model Lo lnclude Lhe run-ume heap
(free sLore) . buL rsL leL's meeL ouL second Au1: Lhe queue
A poeoe ls a conLalner of daLa LhaL enforces a lllO pollcy on
adds/removes
1he permlued operauons are called enter, leave, first,
isEmpty (plus a consLrucLor initQueue)
2014-leb-22
1he queue Au1
More formally:
initQueue creaLes + reLurns a new empLy queue
enter (enqueue) Lakes an elemenL e
new
and a queue q and reLurns a
new queue wlLh Lhe new elemenL aL Lhe end: e
1
. e
n
e
new

leave (dequeue) Lakes a queue q and reLurns a new queue LhaLs
ldenucal Lo q excepL wlLh Lhe rsL elemenL removed: e
2
. e
n

first (fronL) Lakes a queue + reLurns (buL doesn'L remove) rsL
elemenL: e
1
isEmpty 1akes a queue and reLurns Lrue or false, dependlng lf Lhe
queue ls empLy: l.e., does N==0?
[lor each, assume q ls a queue whose currenL sequence ls e
1
. e
n
and e
new
ls Lhe new elemenL

]

2014-leb-22
1he queue Au1: Lven more formally
initQueue: -> queue
re: Lrue
osL: reLurned value ls a new empLy queue

enter: queue x value -> queue
re: Lrue
osL: reLurned queue ls e
1
. e
n
e
new

leave : queue -> queue
re: ! lsLmpLy
osL: reLurned queue ls e
2
. e
n

2014-leb-22
first : queue -> value
re: ! lsLmpLy
osL: reLurned value ls e
1

isEmpty : queue -> boolean
re: Lrue
osL: reLurn value ls Lhe same as n==0

nuke : queue -> queue
re: Lrue
osL: reLurn value empLy queue, old nodes deleLed
1he queue Au1: Lven more formally
2014-leb-22
typedef <mumble> Queue
// If we were using the truly functional style, we'd do this
Queue initQueue() {}
bool isEmpty (Queue q) {}
Queue enter (Queue q, string val) {}
Queue leave (Queue q) {}
string first (Queue q) {}
Queue nuke (Queue q)

int main (int argc, char* argv[]) {
Queue q1;
q1 = enter (q1, "early");
q1 = enter (q1, "timely");
q1 = enter (q1, "late");
cout << first(q1) << endl;
q1 = leave (q1);
cout << first(q1) << endl;
q1 = nuke (q1);
return 0;
}

2014-leb-22
typedef <mumble> Queue
// But we're going to use reference parameters instead
void initQueue (Queue& q) {}
bool isEmpty (const Queue & q) {}
void enter (Queue & q, string val) {}
void leave (Queue & q) {}
string first (const Queue & q) {}
void nuke (Queue & q)

int main (int argc, char* argv[]) {
Queue q1;
enter (q1, "early");
enter (q1, "timely");
enter (q1, "late");
cout << first(q1) << endl;
leave (q1);
cout << first(q1) << endl;
nuke (q1);
return 0;
}

2014-leb-22
LecLure 9
CS138 W14
Clven by Adam 8oeglesL
2014-leb-22
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
void hanoi (int N, int src, int dest, int temp) {
if (N>0) {
hanoi (N-1, src, temp, dest);
cout << "Move from " << src << " to " << dest << endl;
hanoi (N-1, temp, dest, src);
}
}
int main (int argc, char* argv[]) {
int N;
cout << "How many rings? ";
cin >> N;
assert (N>0);
hanoi (N, 1, 3, 2);
return 0;
}
2014-leb-22
lmplemenung a queue wlLh a vecLor
lmplemenung a sLack was easy
uslng a vecLor. ow can we
lmplemenL a queue?
lf we used a vecLor, we'd also have
Lo keep Lrack of where Lhe rsL
elemenL was Loo
nalve vecLor approach: enter
calls push_back
8uL where do we sLore first?
Can'L make lL a sLandalone global
varlable, we we wanL Lo be able Lo
creaLe muluple dlsuncL queues
2014-leb-22
lmplemenung a queue wlLh a vecLor
Suppose we had a queue LhaL was
never more Lhan Lhree elemenLs
long aL any glven momenL, buL mlghL
have a gazllllon elemenLs ln lLs
llfeume
1hls would be really space-lnemclenL
(unless we reslzed lL someumes, or used
a clrcular array, buL LhaL's less slmple)
lnsLead, leL's use a struct wlLh pLrs .
ln a mlnuLe
2014-leb-22
lmplemenung a queue
as a llnked llsL
now leL's (re)conslder Lhe queue
8ecall LhaL nalvely uslng a vecLor (as a value parameLer) Lo
lmplemenL a queue mlghL wasLe a loL of space over ume
. so leL's roll our own dlrecuons uslng a llnked llsL agaln,
buL wlLh a polnLer Lo boLh Lhe rsL and lasL elemenL
We'll dene initQueue, isEmpty, enter,
leave, first
2014-leb-22
typedef <mumble> Queue

void initQueue (Queue& q) {}
bool isEmpty (const Queue & q) {}
void enter (Queue & q, string val) {}
void leave (Queue & q) {}
string first (const Queue & q) {}
void nuke (Queue & q)

int main (int argc, char* argv[]) {
Queue q1;
enter (q1, "early");
enter (q1, "timely");
enter (q1, "late");
cout << first(q1) << endl;
leave (q1);
cout << first(q1) << endl;
nuke (q1);
return 0;
}

2014-leb-22
[See dlagram]
We sull wanL Lo dene a nlce absLracL, clean looklng
Lype for cllenLs Lo use .
. buL we now have Lo keep Lrack of botb a rsL + lasL pLr
. whlch means we can'L use Lhe Lrlck of lemng a Node*
represenL Lhe Au1 as we dld wlLh Stack /
SortedList
lnsLead, we need a sLrucLured represenLauon . l.e., a
struct ln addluon Lo Lhe Node sLrucL Lype
2014-leb-22
LecLure 10
CS138 W14
Clven by Adam 8oeglesL
2014-leb-22
A phllosophlcal polnL
uoes Lhe check ln leave really need Lo be done?
no, as long as we leave Lhe resL of Lhe code as-ls
lf we used q.last==nullptr for isEmpty, Lhen lL
would noL work
owever, lL's a llule dangerous Lo break Lhe
represenLauonal conslsLency of rsL and lasL belng boLh
nuLL or non-nuLL
8euer Lo keep Lhe represenLauon correcL ln case you
declde Lo change your mlnd abouL Lhe lmplemenLauon
laLer
2014-leb-22
ComplexlLy of queue operauons
Llnked llsL lmplemenLauon
enter, leave, first, isEmpty, nuke
vecLor lmplemenLauon
umm, no Lhanks.
2014-leb-22
A noLe on defenslve programmlng
When you sLarL Lo fool around wlLh pLrs, lL's easy Lo make oosty mlsLakes
e.g., forgeL Lo seL a pLr, seL lL Lo Lhe wrong value
?ou may never nouce Lhe error, or see lL manlfesLed only much laLer on
1wo complemenLary approaches Lo undersLandlng whaL wenL wrong:
1. uslng a debugger (long LuLorlal)
2. lnserung prlnL sLmLs and asseruons (easy)
?ou wlll need Lo learn a debugger evenLually, buL you can go a long way
wlLh prlnL sLmLs and asseruons
Also, commenL anyLhlng LhaL's non-obvlous. ?ou wlll Lhank yourself laLer
on (and your colleagues may Lhank you Loo)
8uL don'L over-commenL
2014-leb-22
A noLe on defenslve programmlng
When Lo lnserL a prlnL sLmL ?
AL Lhe beglnnlng of a funcuon call (prlnL params)
AL Lhe end of a fcn call (prlnL resulLs / sLaLe of world)
!usL before deleung someLhlng
AL any ma[or declslon polnL
Any ume you do someLhlng lnLeresung
Cood Lo creaLe speclal purpose prlnL fcns for whole daLa
sLrucLure (for debugglng only)
e.g., prlnL a whole sLack, prlnL all values of a struct lnsLance
rlnung pLr values noL very useful, prlnL Lhe value of Lhe Lhlngs Lhey
polnL Lo lnsLead
2014-leb-22
A noLe on defenslve programmlng
#include <cassert>
Why should we use asseruons, lf Lhey make our program dle?
use lL anywhere you wanL Lo be JeoJ sure of some facL before
proceedlng, proceedlng lf lL's false ls polnLless
1wo usual cases:
1. Check LhaL your loglc/assumpuons are correcL (up Lo you)
lf first ls nullptr you expecL LhaL last wlll be Loo
2. Check LhaL "user" ls belng reasonable (up Lo user, noL you)
e.g., popplng an empLy sLack
2014-leb-22
A noLe on defenslve programmlng
8uL clean up when you're done!
8emove "Lype 1" asseruons, dlagnosuc prlnL sLmLs and speclal prlnL
funcuons ln Lhe verslon you dellver
Ck Lo have Lhem ln durlng developmenL + debugglng, buL when you're
ready Lo shlp, geL rld of Lhem
"1ype 2" asseruons can someumes be le ln, as long as Lhe
check lsn'L very expenslve
e.g., checklng lf a pLr ls nullpLr ls cheap, checklng lf a llsL ls sorLed ls
expenslve
2014-leb-22
#include <iostream>
#include <string>
#include <cassert>
using namespace std;

// many of these per Q
struct Node {
string val;
Node* next;
};

// one of these per Q
struct Queue {
Node* first;
Node* last;
};

void initQueue (Queue& q){
cerr << "initQueue" << endl;
q.first = nullptr;
q.last = nullptr;
}

bool isEmptyQ (const Queue &q) {
cerr << "isEmptyQ" << endl;
return nullptr == q.first;
}


2014-leb-22
void enter (Queue& q, string val) {
cerr << "enter: " << val; // no newline yet
Node* p = new Node;
p->val = val;
p->next = nullptr;
if (nullptr == q.first) {
assert (nullptr == q.last);
cerr << " at front " << endl;
q.first = p;
} else {
assert (nullptr != q.last);
cerr << " after " << q.last->val << endl;
q.last->next = p;
}
q.last = p;
}

2014-leb-22
string first (const Queue & q) {
cerr << "first: ";
assert (!isEmptyQ (q));
cerr << q.first->val << endl;
return q.first->val;
}

void leave (Queue & q) {
cerr << "leave: ";
assert (!isEmptyQ (q));
Node *p = q.first;
cerr << p->val << endl;
q.first = q.first->next;
if (nullptr == q.first) {
q.last = nullptr;
}
delete p;
}
2014-leb-22
void nuke (Queue & q) {
// cerr << "nuke " << endl;
while (!isEmptyQ (q)) {
leave(q);
}
}
2014-leb-22
// A non-standard API element for Queue,
// used only for debugging!
void printQ (const Queue & q) {
// print the values in order
// implementation left to student
}
2014-leb-22
uynamlc arrays
We are golng Lo dlscuss dynamlc arrays" Lo glve you an
undersLandlng of whaL's golng on under Lhe hood"
owever, lf you feel llke you need a dynamlc array ln your
program (lgnorlng Lhe nexL assgL :-), you should almosL
cerLalnly use an S1L vector (or relauve) lnsLead.
vecLors are usually lmplemenLed uslng a dynamlc array, whlch ls why
we are sLudylng Lhem.
ln facLs Lhere's noL much need Lo use any klnd of C-sLyle arrays ln C++
slnce we have vecLors, plus oLher powerful conLalner classes ln Lhe
S1L.
2014-leb-22
uynamlc arrays
1. SLaucally (as ln C)
SLorage ls allocaLed on
Lhe sLack
Array bound musL be a
complle-ume consLanL


int main () {
const int N = 5;
int A[N]; // legal
int m;
cin << m;
int B[m]; // illegal

}
C++ arrays can be declared ln Lwo ways:
2014-leb-22
[See dlagram]
uynamlc arrays
int main () {
int N;
cin >> N;
int* A = new int[N];
string* B = myAlloc(N);
for (int i=0; i<N; i++){
cin >> A[i] >> B[i];
}
// do more fun stuff
delete [] A;
delete [] B;
return 0;
}
2. Dynamically (C++ only)
Storage is allocated on the
heap
Array bound can be a run-
time value (positive int)
Must delete when done
! Need []!
string* myAlloc (int n) {
assert (n>0);
return new string[n];
}

2014-leb-22
[See dlagram]
uynamlc arrays
Can'L reLurn an array from a procedure
8uL arrays are almosL [usL polnLers (wlLh a speclal
synLax for accesslng elemenLs, eLc.)
So can reLurn a pLr lnsLead, lf we allocaLe Lhe
sLorage on Lhe heap
2014-leb-22
uynamlc arrays
ow does "delete []A" work?
1he sysLem needs Lo remember how many elemenLs are ln Lhe heap-
chunk LhaL was allocaLed for Lhe dynamlc array
1he exLenL of Lhe array ls assoclaLed somehow wlLh Lhe block of
sLorage on Lhe heap, oot wlLh Lhe pLr

: Why noL sLore Lhe exLenL aL Lhe beglnnlng of Lhe array?
A: 1haL would break normal array addresslng (pLr arlLhmeuc)
Common approach ls Lo use, eg, 4 byLes befote Lhe array sLorage Lo
hold Lhe exLenL
So Lhls means LhaL Lhe followlng works ne
2014-leb-22
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
string* myAlloc (int n) {
assert (n>0);
return new string[n];
}
int main (int argc, char* argv[]) {
string* A = myAlloc(10);
string* B = myAlloc(20);
string* temp = A;
A = B; // No problem here
B = temp;
delete []A; // If we stored extent w ptr, this
delete []B; // would NOT work, but it does
return 0;
}
2014-leb-22
[See dlagram]
no exLenL for you!
1he exLenL of a dynamlcally allocaLed array has Lo be sLored
somewhere .
. 8u1 lL ls noL accesslble programmaucally or any oLher way
(modulo non-porLable "cheaung")
Cnly Lhe compller/run-ume knows where Lo nd lL
A dynamlcally allocaLed array ls [usL an array, lL ls noL an ob[ecL and
does noL have an Al . so Lhere ls no size() meLhod
[We are noL Lalklng abouL Lhe C++11 class called array, whlch ls
someLhlng dlerenL]
2014-leb-22
LecLure 11
CS138 W14
2014-leb-22
Mld-Lerm
Cn 1hurs, Lhls week, as you know !
1esLable conLenL lncludes everyLhlng up Lo bot oot locloJloq
Loday's lecLure:
Sllde conLenLs, sLu l sald/wroLe/drew LhaL may noL be on slldes
AsslgnmenL conLenLs (buL noL low-level deLalls)
AnyLhlng l sald lsn'L LesLable won'L be LesLed
e.g., oJvooceJ unlx maLerlals ln slldes
2014-leb-22
Mld-Lerm
MlxLure of quesuon klnds:
ShorL answer, Lrue/false
WhaL does Lhls program do?
WrlLe a program LhaL does xxx
WhaL's wrong wlLh Lhls program?
uraw a memory dlagram of Lhls polnL ln execuuon
1he lasL (mulu-parL) quesuon ls worLh 1/3 of Lhe LoLal marks
. so allocaLe your ume wlsely
ln Lhe lmmorLal words of Lhe laLe uouglas Adams .
2014-leb-22
1he llnked llsL
1he generlc "Lhlng" we have been worklng wlLh Lo lmplemenL
our sLacks, queues, eLc. ls called a "llnked llsL". lL has
A speclal pLr Lo Lhe "rsL" elemenL
A bunch of "node" lnsLances, llnked Lo each oLher Lo form a "llne" vla a
"nexL" polnLer
Llnked llsLs can be
unordered, or
ordered by lnseruon ume, or
ordered by key value, or
ordered by some sLrange "oLher" convenuon
2014-leb-22
varlanLs of Lhe llnked llsL
uoubly-llnked llsL:
Llnk Lo rsL and lasL elemenLs of llsL, can Lraverse forwards
or backwards



struct Node {
string val;
Node* next;
Node* prev;
};
2014-leb-22
varlanLs of Lhe llnked llsL
8lnary Lree (more laLer)
Speclal "rooL" node
Lach node has Lwo "chlld"
llnks, a le and a rlghL
Can be sorLed (8S1, heap) or
noL, dependlng on use
non-blnary Lrees also exlsL

struct Node {
string val;
Node* left;
Node* right;
};
2014-leb-22
LlsLs and orderlng
So far, our llsLs (sLack, queue) have been ordered by arrlval
ume ln some way
1hese are called otJeteJ llsts
We can also creaLe llsLs sorLed by Lhe ("key") value of Lhe
elemenL (l.e., sorLed by daLa value)
1hese are called sotteJ llsts
?ou can lmaglne LhaL Lhe daLa sLored ln Lhe node ls much rlcher (l.e.,
more elds) Lhan [usL a slngle sLrlng, buL we'll use only string keys
for slmpllclLy
1he prlorlLy queue (comlng soon) ls a hybrld, parLly based on order of
arrlval and parLly based on daLa (Lhe prlorlLy)
2014-leb-22
SorLed llnked llsL
LeL's use Lhe same Node and creaLe a sotteJ llsL Au1
We need Lo dene:
initList, insert, remove, has, isEmpty,
print
2014-leb-22
Cemng llnked sLrucLures rlghL
Llnked sLrucLures are easy Lo geL wrong!
?ou may noL nouce Lhe lncorrecL llnk unul much laLer, oen lL's hard
Lo gure ouL whaL wenL wrong
e.g., forgemng Lo seL llnk of lasL elemenL Lo NULL ls noL a problem lf you
never go Lo Lhe end agaln
1hlnk defenslvely! Some Lrlcks:
SeL polnLers Lo NULL lf Lhey're noL "acuve"
CreaLe "sLaLe-reporung funcuons" Lo help ln debugglng
use lC and asseruons Lo check your assumpuons
(evenLually) Learn how Lo use a debugger.
2014-leb-22
Cemng llnked sLrucLures rlghL
Suggesuons:
1. uraw plcLures! (Lven l do Lhls 23 years laLer)
2. 8reak down lnLo all posslble "lnLeresung" cases you can Lhlnk of:
LmpLy llsL, one elemenL llsL, "blg" llsL
llrsL elemenL, mlddle elL, lasL elL
1hlng noL Lhere, dupllcaLe Lhlng, all elLs same, .
See lf you can merge cases LogeLher laLer
3. 1esung, Lesung, Lesung!
uon'L rely on MarmoseL Lo Lell you everyLhlng LhaL's wrong, lL's Lhere Lo
help buL lL's noL a cruLch
uon'L be shy abouL creaung large numbers of LesL cases, lL's whaL Lhe pros
do
2014-leb-22
?ou are your own besL LesLer!
A slmple process you can lmplemenL now!
1. ueslgn a seL of LesL cases for your code, glve each a descrlpuve name
1hls mlghL be done wlLh a common drlver (maln) program LhaL can read ln Lhe
LesL case from a daLa le, or you may need a new maln program for each
2. lor each LesL case, creaLe a plaln LexL le wlLh Lhe expecLed ouLpuL
for each LesL run
3. 8un each LesL, sLore Lhe ouLpuL ln a llke-named le (one per LesL run)
4. use diff Lo compare Lhe expecLed Lo Lhe acLual
keqtessloo tesuoq
keep your LesL cases around, tetest evetytbloq when you make a
change, agaln, Lhls ls whaL Lhe pros do!
"A boq ls slmply o test cose yoo fotqot to wtlte."
2014-leb-22
1esL-drlven developmenL
1est-Jtlveo Jevelopmeot ls commonly parL of "aglle
developmenL" processes
uevelop LesL cases LhaL sausfy Lhe reqs befote you wrlLe Lhe code
1hen wrlLe Lhe slmplesL code LhaL sauses Lhe LesLs
keep Lhe LesL cases up Lo daLe! 1he LesLs evolve as your code does.
2014-leb-22
#include <iostream>
#include <string>
#include <cassert>
using namespace std;

struct Node {
string val;
string otherStuff; // we wont really touch it
Node* next;
};

typedef Node* SortedList;

void initList (SortedList& first) {
first = NULL;
}
2014-leb-22
bool isEmpty (const SortedList& first) {
return NULL == first;
}

void print (const SortedList& first) {
cout << "Printing the list:\n";
Node* p = first;
while (NULL != p) {
cout << " \"" << p->val << "\"" << endl;
p = p->next;
}
}
2014-leb-22
// Let's implement these!

// Typically, nodes store key value plus other info.
// Thus lookup would return the "other info" for
// that key. Since this is simpler version, we'll
// just return a boolean to indicate if we found it.
bool lookup (const SortedList & first, string val) {}

// Also ignoring otherStuff from here on in.
void insert (SortedList& first, string val) {}
void remove (SortedList& first, string val) {}


2014-leb-22
lnserL
void insert (SortedList& first, string val) {}

[8ralnsLorm for cases Lo conslder, lL's Ck lf some overlap]
1.
2.
3.
4.
3.
6.
7.
2014-leb-22
// Final version that combines all cases into
// two main scenarios; requires list be sorted already.
void insert (SortedList& first, string val) {
// cerr << "Inserting " << val << endl; // debug
Node* newNode = new Node;
newNode->val = val;
if (NULL == first || val <= first->val) {
// Scenario 1: insert as first element
newNode->next = first;
first = newNode;
} else {
// Scenario 2: insert somewhere after first element
Node* cur = first;
while (NULL!=cur->next && val > cur->next->val){
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
}
}
2014-leb-22
8emove
void remove (SortedList& first, string val) {}
[8ralnsLorm for cases Lo conslder, lL's Ck lf some overlap]
1.
2.
3.
4.
3.
6.
7.
2014-leb-22
// Final version, that combines all cases into
// two main scenarios; requires list be sorted already.
void remove (SortedList& first, string val) {
// cerr << "Deleting \"" << val << "\"\n"; // debug
assert (!isEmpty(first));
Node* temp;

if (first->val == val) {
// Scenario 1: Deleting first element
temp = first;
first = first->next;

// cont'd
2014-leb-22
} else {
// Scenario 2: Deleting non-first element
Node* cur = first;
while (cur->next!=NULL && val>cur->next->val) {
cur = cur->next;
}
// My orig 2009 version: NULL==cur (WRONG!)
if (NULL == cur->next || val != cur->next->val){
// assert (false); // optional
cerr << Couldn't find \"" << val << "\"\n";
return;
}
temp = cur->next;
cur->next = cur->next->next; // aka temp->next
}
// Common to both scenarios
delete temp;
}
2014-leb-22
LecLure 12
CS138 W14
2014-leb-22
First- year and graduating
students:

Check your email February 13
th

for the National Survey of Student
Engagement (NSSE)!
IMPROVE THE WATERLOO EXPERIENCE!
Tell us about your
experience at Waterloo!

Take 15 minutes to earn

$5 on your WatCard and an entry
into a draw for

a $500 undergraduate award
National Survey of Student
Engagement (NSSE)
MldLerm
Any quesuons abouL Lhe mldLerm?
Medlan 77.3
Average 73.7

Check over your mldLerm gradlng
Check Lhe addlng Loo
"Crade grubblng" ls noL really encouraged, buL lf
Lhere's a mlsLake (e.g., your soluuon ls correcL buL
noL whaL we expecLed) Lhen Lalk Lo ChanLelle
2014-leb-24 2014-leb-22
http://opensource.apple.com/source/Security/Security-55471/libsecurity_ssl/lib/sslKeyExchange.c
1eachable momenL:
Why you should use for slngle llnes
Cver Lhe weekend of 22 leb 2014, Apple announced Lhere
was a serlous bug ln Lhelr SSL verlcauon code for lCS
1hls ls a fronL-llne check for maklng secure neLwork connecuons, lL
mauers!
8aslcally, lL was noL checklng SSL cerLs ot oll, due Lo a dumb bug LhaL
would probably have been avolded lf Lhey had used Lhe convenuon of
always uslng for slngle llne lf-sLaLemenL bodles
1he acLual code ls open source .
. and Lhe rooL of Lhe problem ls [usL sloppy programmlng sLyle!
2014-leb-22
WhaL happens here?
Suppose LhaL (as ls usually Lhe case) Lhe signedParam check passes +
err ls seL Lo "all ls well"
1he rsL goto fail ls (rlghLly) sklpped, buL Lhe second ls noL!
1he valldauon of Lhe SSL cerucaLe (err = sslRawVerify()) ls
sklpped
ConLrol Lransfers Lo Lhe fail code, whlch frees some space & reLurns
owever, Lhe error code ls "all ls well" ls reLurned as Lhe value of Lhe
funcuon
1he hashout and sslRawVerify checks are never performed,
ln facL, all code aer Lhe second goto fail up Lo Lhe fail label ls
unreachable (aka "dead") code.
2014-leb-22
lf Lhey had used for slngle llne lf-sLmL bodles, Lhen elLher
1he second goto fail would have been lnslde lL (and never
execuLed, and so harmless), C8
lL would have been ouLslde Lhe and more obvlously vlsually wrong
1o me, Lhe mosL amazlng Lhlng ls noL Lhe dumb bug (Lhey
happen), buL Lhe facL LhaL Apple's Lesung lnfrasLrucLure lsn'L
seL up Lo caLch Lhls, esp. glven Lhls ls fronL-llne securlLy sLu
8eadlng Lhe code glves an obvlous seL of evenLs Lo check for!
Ma[or soware englneerlng fall on Lhelr parL!
1hls ls a publlc embarrassmenL for Lhem, leL's see how Lhey respond
2014-leb-22 2014-leb-24
8ack Lo Lhe sorLed llnked llsL
ere's insert and remove, whlch we
developed lasL ume
2014-leb-22
// Final version that combines all cases into
// two main scenarios; requires list be sorted already.
void insert (SortedList& first, string val) {
// cerr << "Inserting " << val << endl; // debug
Node* newNode = new Node;
newNode->val = val;
if (NULL == first || val <= first->val) {
// Scenario 1: insert as first element
newNode->next = first;
first = newNode;
} else {
// Scenario 2: insert somewhere after first element
Node* cur = first;
while (NULL!=cur->next && val > cur->next->val){
cur = cur->next;
}
newNode->next = cur->next;
cur->next = newNode;
}
}
2014-leb-22
// Final version, that combines all cases into
// two main scenarios; requires list be sorted already.
void remove (SortedList& first, string val) {
// cerr << "Deleting \"" << val << "\"\n"; // debug
assert (!isEmpty(first));
Node* temp;

if (first->val == val) {
// Scenario 1: Deleting first element
temp = first;
first = first->next;

// cont'd
2014-leb-22
} else {
// Scenario 2: Deleting non-first element
Node* cur = first;
while (cur->next!=NULL && val>cur->next->val) {
cur = cur->next;
}
// My orig 2009 version: NULL==cur (WRONG!)
if (NULL == cur->next || val != cur->next->val){
// assert (false); // optional
cerr << Couldn't find \"" << val << "\"\n";
return;
}
temp = cur->next;
cur->next = cur->next->next; // aka temp->next
}
// Common to both scenarios
delete temp;
}
2014-leb-22
ueslgnlng LesL cases
ln WlnLer 2010, l dlscovered a bug ln Lhe remove
code l had wrluen for WlnLer 2009
lL manlfesLed lLself only when you Lrled Lo remove an
enLry LhaL wasn'L acLually Lhere Anu was greaLer Lhan Lhe
lasL elemenL ln Lhe llsL
8uL lf you never Lrled LhaL case, lL looked correcL.
1hls ls noL aL all uncommon!

2014-leb-22
ueslgnlng LesL cases
Lessons learned:
Llnked sLrucLures are teolly hard Lo geL 100 correcL
lL's common for obscure bugs Lo be dlscovered laLer on,
even aer Lhe code has worked preuy well for a long ume
8ugs oen show up only Lhrough systemouc Lesung
unless you are an lCS developer !
1esung ls good for your code: 8e bruLal and creauve
uslng debugged llbrarles ls always beuer Lhan re-lnvenung
Lhe wheel, you wlll probably geL lL wrong Lhe rsL, second,
Lhlrd ume you Lry
2014-leb-22
Some LesL cases for remove
LlemenL presenL
Cne elemenL llsL
8emove rsL elemenL
8emove mlddle elemenL
8emove lasL elemenL
8emove lasL-buL-one
elemenL
LlemenL noL presenL
no elemenLs (asseruon
fallure, we hope)
8efore rsL elemenL
8eLween mlddle
elemenLs
Aer lasL elemenL
LlemenL already deleLed
2014-leb-22
ueslgnlng LesL cases
lundamenLal LruLh of sw Lesung:
?ou cannoL LesL "everyLhlng", comblnaLorlal exploslon of posslble worlds hlLs
you very qulckly
So Lesung becomes an opumlzauon game: Clven xx person-hours, whaL ls Lhe
mosL eecuve way Lo deslgn and lmplemenL a Lesung lnfrasLrucLure?
lL ls much beuer Lo carefully deslgn a seL of cases LhaL LesL expllclL
slLuauons Lhan Lo Lhrow a bunch of quasl-random daLa aL Lhe sysLem
ln addluon Lo Lesung agalnsL Lhe absLracL ldea of whaL Lhe procedure ls
dolng (block-box tesuoq), Lhere are approaches LhaL LesL agalnsL how Lhe
code ls acLually wrluen (wblte-box tesuoq)
1hls ls an advanced Loplc whlch you wlll revlslL laLer
WhlLe-box Lesung mlghL have helped Lo caLch my bug
2014-leb-22
lookup (Lo geL Lo Lhe elemenL's correcL place):
Average case C(N]2) == C(N)
WorsL case C(N)
insert, remove:
Lecuvely, Lhey requlre a lookup Loo
8uL once you arrlve, |t's an C(1) operanon to ad[ust a few po|nters
We menuon Lhls as ln C++ we someumes reLurn lLeraLors LhaL polnL Lo
elemenLs ln Lhe mlddle of Lhe llsL
1he C++ S1L conLalner class list ls lmplemenLed as a plaln
old doubly-llnked llsL
ComplexlLy of sorLed llnked llsL ops
2014-leb-22
. compared Lo arrays
Accesslng an array elemenL ls:
a consLanL ume operauon!
e.g., A[13] == addressCfA + 13 * elemenLSlze
8uL arrays have a xed slze, unllke llnked llsLs, we can'L
(easlly) grow Lhem
vectors have exLra space aL Lhe end, and can grow as needed
lf you were Lo lnserL a new elemenL "ln place":
lL's C(n) Lo nd Lhe rlghL spoL (or C(log n) you use blnary search) .
. Lhen followed by C(n) copy acuons, whlch ls falrly expenslve
2014-leb-22

enter : sortedList X value -> sortedList
re: sortedList ls sorLed
osL: sortedList ls sorLed
&& sortedList conLalns new elemenL
&& sortedList has same elemenLs as before, plus Lhe new one
remove : sortedList X value -> sortedList
re: sortedList ls sorLed && lndlcaLed elemenL presenL
osL: sortedList ls sorLed
&& sortedList has same elemenLs as before,
mlnus Lhe lndlcaLed one
SorLed llnked llsL:
re- and posL-condluons
2014-leb-22
1he prlorlLy queue Au1
A ptlotlty poeoe ls llke a queue, buL each elemenL has a value
ooJ an lnLeger prlorlLy (usually, >=0)
enter ls "same as before"
(?ou can'L really Lell whaL happens unul you call leave)
leave means "remove Lhe oldesL elemenL from among Lhose wlLh
Lhe lowesL (or hlghesL) prlorlLy"
Cen used ln neLwork rouung
Some klnds of daLa are more lmporLanL Lhan oLhers, Lhey geL
preferenual LreaLmenL
e.g., oS, medla sLreamlng, vol
2014-leb-22
1he prlorlLy queue Au1
Always have Lo speclfy:
uoes hlghesL or lowesL prlorlLy mean "mosL lmporLanL"?
noLe LhaL Lhe C++ S1L provldes an lmplemenLauon of
priority_queue, whlch ls whaL you should use ln real llfe
8uL leL's Lry lmplemenung lL ourselves . any ldeas?
Cne ldea: keep a llsL LhaL ls sorLed by prlorlLy, buL wlLhln a glven
prlorlLy, oldesL ls aL Lhe fronL
2014-leb-22
// A working but nave
// implementation

struct Node {
string val;
int prior;
Node* next;
};

typedef Node* PQ;

void initPQ (PQ& pq) {
pq = NULL;
}

bool isMTPQ (const PQ& pq){
return NULL == pq;
}

void leavePQ (PQ& pq) {
assert (!isMTPQ(pq));
Node* p = pq;
pq = pq->next;
delete p;
}

void firstPQ (const PQ& pq,
string & val,int & prior){
assert (!isMTPQ(pq));
val = pq->val;
prior = pq->prior;
}


2014-leb-22
// This is the only hard one; nave implementation
void enterPQ (PQ& pq, string val, int prior) {
Node* p = new Node;
p->val = val;
p->prior = prior;
if (NULL == pq || pq->prior > prior) {
p->next = pq;
pq = p;
} else { // want first node > prior, not >=
Node* temp = pq;
while (NULL != temp->next
&& temp->next->prior <= prior) {
temp = temp->next;
}
p->next = temp->next;
temp->next = p;
}
}

2014-leb-22
// Let's trace this thru
int main (int argc, char* argv[]) {
PQ pq;
initPQ (pq);
enter (pq, apple, 3);
enter (pq, baker, 3);
enter (pq, corps, 6);
enter (pq, deck, 2);
enter (pq, extra, 3);
return 0;
}
2014-leb-22
ComplexlLy of operauons
lor Lhls parucular (nalve) lmplemenLauon only:

firstPQ C(1)

leavePQ C(1)

enterPQ C(N)
2014-leb-23
An even slmpler
lmplemenLauon
enterPQ:
keep a llnked llsL sorLed ln arrlval order (l.e., llke a queue)
ComplexlLy: C(1)
leavePQ, firstPQ:
SLarL aL beglnnlng, look for lowesL prlorlLy elemenL
8uL how do we know whaL Lhe lowesL prlorlLy ls? umm, .
ComplexlLy: C(N)
[1hls ls preuy awful] 2014-leb-23
: A beuer lmplemenLauon
We malnLaln a llsL of llsLs (LCL)!
Speclcally, we malnLaln a sorLed llsL of queues
1he (ouLer) llsL ls sorLed numerlcally by prlorlLy
1hls ls whaL you wlll lmplemenL ln an upcomlng assgL!
Can re-use code from queue and sorLed llnked llsL!
2014-leb-22 2014-leb-22
: LCL lmplemenLauon
string first_PQ (const PQ& pq)
pre: !(isEmptyPQ(pq))
osL: 8eLurn Lhe value of rsL elemenL of rsL queue!

ComplexlLy: C(1)
2014-leb-23
: LCL lmplemenLauon
void leave_PQ (PQ& pq)
pre: !(isEmptyPQ(pq))
osL: erform leaveQ on rsL queue ln LCL
lf Lhls queue ls now empLy, mlghL wanL Lo deleLe Lhe PQnode also
ComplexlLy: C(1)
2014-leb-23
: LCL lmplemenLauon
void enter_PQ (const PQ& pq, string val, int p)
llrsL, nd ouL lf Lhere ls an exlsung queue for prlorlLy p
lf noL, creaLe a new PQnode, and lnserL lL lnLo Lhe ouLer sorLed llsL ln lLs
proper place, creaLe a new (empLy) queue LhaL Lhls node wlll polnL Lo
now, add val Lo Lhe queue for prlorlLy p
ComplexlLy: [Assumlng n elemenLs ln LoLal, and k dlsuncL prlorlues]
SLep 1: llnd approprlaLe queue (lf lL exlsLs, or creaLe one)
1hls ls C(k)
SLep 2: Add new elemenL aL end of LhaL queue
1hls ls C(1)
So Lhe LoLal ume ls C(k). lf kn Lhls ls a blg wln!
So Lhe complexlLy ls lndependenL" of Lhe number of nodes!
2014-leb-23 2014-leb-22
HEAP!
: usually, Lho, lL's a heap
s are usually lmplemenLed uslng a &'#( daLa sLrucLure,
whlch ls a klnd of blooty ttee (nexL lecLure Loplc)
[n8: "lreesLore" / "Lhe heap" ls nC1 a heap ln Lhls sense! Confuslng!]

1he "heap properLy" (Lrue for each node ln Lree, see CS240):
value of parenL node >= value of (boLh) chlldren
1hls means LhaL Lhe largesL elemenL ls always aL Lhe rooL
lnserL/deleLe means sLarL aL rooL and swap posluons wlLh chlldren
1here are many varleues of heap lmplemenLauons wlLh dlerenL
performance characLerlsucs, buL ln Lhe vanllla verslon enter,
leave, and lookup are all C(log n), peek ls C(1) Lho
2014-leb-22
Whlch ls besL?
Assume n elemenLs, k dlsuncL prlorlues, slmllar freq of enterPQ/
leavePQ
lf log
2
n >> k, Lhen LCL ls beuer
lf log
2
n k, Lhen heap ls beuer
lf we have 1,000,000 elemenLs, Lhen log
2
n == 20
So unless Lhere are very few prlorlues, (l.e., k ls very small), Lhe heap ls llkely
Lo be Lhe besL cholce

2014-leb-22
lO lmplemeotouoo enterPQ leavePQ firstPQ
LlsL-of-llsLs (LCL) C(k) C(1) C(1)
eap C(log
2
n) C(log
2
n) C(1)
4. 1he C++ memory model,
llnked sLrucLures,
and a few more Au1s
CS138 - WlnLer 2014
rof. Mlke Codfrey

2014-leb-22

You might also like