Unit6 Pointers 1
Unit6 Pointers 1
Mark Redekopp
2
Why Pointers
• Scenario: You write a paper and include a lot of large
images. You can send the document as an attachment
in the e-mail or upload it as a Google doc and simply e-
mail the URL. What are the pros and cons or sending
the URL?
• Pros
– Less info to send (send link, not all data)
– Reference to original
(i.e. if original changes, you’ll see it)
• Cons
– Can treat the copy as a scratch copy and modify freely
3
Pointer Analogy
• Imagine a set of 18 safe deposit or PO
boxes each with a number
• There are 8 boxes with gold jewelry and
the other 10 do not contain gold but
hold a piece of paper with another box
number (i.e. a pointer to another box)
• Value of box 9 “points-to” box 7
• Value of box 17 “points-to” box 3
08 1 2 15 3 4 53
6 11 7 8 4 9 7 103 11
12 131 14 15 165 173
5
Pointers
• Pointers are references to other things 520 524 528 532 536 540
POINTER BASICS
7
Review Questions
• T/F: The elements of an array are stored
contiguously in memory
– ______________
• When an array is declared (i.e. int dat[10])
and its name is written by itself
(e.g. cout << dat;) in an expression, it
evaluates to what?
– __________________________
8
Pointers
• ‘&’ operator yields address of a variable in C 20bc0 00
20bc4 30 x
(Tip: Read ‘&foo’ as ‘address of foo’) 20bc8 'a' y
– int x = 30; char y='a'; 20bcc 5.375 z
float z = 5.375; 20bd0 107 dat[0]
int dat[2] = {107,43}; 20bd4 43 dat[1]
20bd8 00
– &x => ??, 20bdc 00
– &y => ??, 20be0 00
… … …
– &z => ??,
Memory
– &dat[1] = ??;
– dat => ??
10
Pointers
• ‘&’ operator yields address of a variable in C 20bc0 00
20bc4 30 x
(Tip: Read ‘&foo’ as ‘address of foo’) 20bc8 'a' y
– int x = 30; char y='a'; 20bcc 5.375 z
float z = 5.375; 20bd0 107 dat[0]
int dat[2] = {107,43}; 20bd4 43 dat[1]
20bd8 00
– &x => 0x20bc4, 20bdc 00
– &y => 0x20bc8, 20be0 00
… … …
&z => 0x20bcc,
– &dat[1] = 0x20bd4; Memory
– dat => 0x20bd0
• Number of bits used for an address depends on OS,
etc.
– 32-bit OS => 32-bit addresses
– 64-bit OS => 64-bit addresses
11
Pointers
• Just as we declare variables to store int’s and double’s,
we can declare a pointer variable to store the "address-
of" (or "pointer-to") another variable
– Requires 4-bytes of storage in a 32-bit system or
8-bytes in a 64-bit systems
– Use a * after the type to indicate this a pointer variable to
that type of data
• More on why this syntax was chosen in a few slides…
20bc0 00
• Declare variables: 20bc4 30 x
– int x = 30; char y='a'; 20bc8 'a' y
float z = 5.375;
20bcc 5.375 z
int dat[2] = {107,43};
20bd0 107 dat[0]
– int *ptr1; 20bd4 43 dat[1]
ptr1 = &x; // ptr1 = ______________ ptr1
20bd8
ptr1 = &dat[0]; // Change ptr1 = ______________
20bdc prt2
// i.e. you can change what a pointer points to
20be0 00
– float *ptr2 = &z; // ptr2 = ___________ …
… …
Memory
12
Pointers
• Just as we declare variables to store int’s and double’s,
we can declare a pointer variable to store the "address-
of" (or "pointer-to") another variable
– Requires 4-bytes of storage in a 32-bit system or
8-bytes in a 64-bit systems
– Use a * after the type to indicate this a pointer variable to
that type of data
• More on why this syntax was chosen in a few slides…
20bc0 00
• Declare variables: 20bc4 30 x
– int x = 30; char y='a'; 20bc8 'a' y
float z = 5.375;
20bcc 5.375 z
int dat[2] = {107,43};
20bd0 107 dat[0]
– int *ptr1; 20bd4 43 dat[1]
ptr1 = &x; // ptr1 = 0x20bc4 ptr1
20bd8 20bc420bd0
ptr1 = &dat[0]; // Change ptr1 = 0x20bd0
20bdc 20bcc prt2
//(i.e. you can change what a pointer points to)
20be0 00
– float *ptr2 = &z; // ptr2 = 0x20bcc …
… …
Memory
13
De-referencing / Indirection
• Once a pointer has been written with an address of some
other object, we can use it to access that object (i.e.
dereference the pointer) using the ‘*’ operator 20bc0 00
• Read ‘*foo’ as… 20bc4 30 x
20bc8 'a' y
– ‘value pointed to by foo’ 20bcc 5.375 z
– ‘value at the address given by foo’ 20bd0 107 dat[0]
(not ‘value of foo’ or ‘value of address of foo’) 20bd4 43 dat[1]
20bd8 ptr1
• Using URL analogy, using the * operator on a pointer 20bdc
20bd0
20bcc prt2
is like “clicking on a URL” (follow the link) 20be0 a
• Examples: … … …
De-referencing / Indirection
• Once a pointer has been written with an address of some
other object, we can use it to access that object (i.e.
dereference the pointer) using the ‘*’ operator 20bc0 00
20bc4 30 x
• Read ‘*foo’ as… 20bc8 'a' y
– ‘value pointed to by foo’ 20bcc 5.375 z
– ‘value at the address stored in foo’ 20bd0 107 108 dat[0]
(not ‘value of foo’ or ‘value of address of foo’) 20bd4 43 dat[1]
20bd8 20bd0 ptr1
• By the URL analogy, using the * operator on a 20bdc 20bcc prt2
pointer is like “clicking on a URL” (follow the link) 20be0 112 a
… … …
• Examples:
– ptr1 = dat; Memory
int a = *ptr1 + 5; // a = 112 after exec.
– *ptr1 += 1; // dat[0] = 108
– *ptr2 = *ptr1 - *ptr2; // z=108–5.375=102.625
• '*' in a type declaration = declare/allocate a pointer
• '*' in an expression/assignment = dereference
15
Pointer Questions
• Chapter 13, Question 6
int x, y;
int* p = &x;
int* q = &y;
x = 35; y = 46;
p = q;
*p = 78;
cout << x << " " << y << endl;
cout << *p << " " << *q << endl;
17
POINTER ARITHMETIC
18
Review Questions
• The size of an 'int' is how many bytes?
– ____
• The size of a 'double' is how many bytes?
– ____
• What does the name of an array evaluate to?
– _________________
– Given the declaration int dat[10], dat is an _____
– Given the declaration char str[6], str is a _____
• In an array of integers, if dat[0] lived at address
0x200, dat[1] would live at…?
– ____________
19
Pointer Arithmetic
• Pointers are variables storing addresses and addresses
are just numbers
• We can perform addition or subtraction on those
pointer variables (i.e. addresses) just like any other
variable
• The number added/subtracted is implicitly multiplied
by the size of the object so the pointer will point to a
valid data item
20bc0 00
– int *ptr1 = dat; ptr1 = ptr1 + 1; 20bc4 30 x
// address in ptr was incremented by 4 20bc8 'a' y
20bcc 5.375 z
• Examples: 20bd0 107 dat[0]
– ptr1 = dat; 20bd4 43 dat[1]
20bd8 20bd0 ptr1
– x = x + *ptr1; // x = 137
20bdc 20bcc prt2
– ptr1 = ptr1 + 1; // ptr1 now points at dat[1] 20be0 a
– x = x + *ptr1++; // x = dat[1] = 137+43 then … … …
// inc. ptr1 to 0x20bd8 Memory
– ptr1 = ptr1-2; // ptr1 now points back at dat[0]
20
int data[10] 09 08 07 06 50 04 …
data = 520 Memory
21
as pointer arithmetic
22
PASS BY REFERENCE
23
Pass by Value
void decrement_it(int);
int main()
• Notice that actual arguments are different {
memory locations/variables than the formal int a, y = 3;
decrement_it(y);
arguments cout << "y = " << y << endl;
}
• When arguments are passed a copy of the void decrement_it(int y)
actual argument value (e.g. 3) is placed in the {
y--;
formal parameter (x) }
System
Memory Data for decrement_it
(RAM) (y=3 then 2) and return link
Data
Data forfor
mainmain
(a, (a,
y=3)y=3) and
and return
return
linklink
Pass by Reference
int main()
{
• Pointer value (i.e. the address) is still passed-by- int a, y = 3;
// assume y @ 0x20bd4
value (i.e. a copy is made) // assume ptr
a = y;
• However, the value of the pointer is a reference decrement_it(&y);
cout << "a=" << a;
to y (i.e. y’s address) and it is really the value of cout << "y=" << y << endl;
y that doit() operates on return 0;
}
• Thus we say we are passing-by-reference
// Remember * in a type
• The value of y is CHANGED by doit() and that // declaration means "pointer"
// variable
change is visible when we return. void decrement_it(int* x)
{
Code for all functions *x = *x - 1;
Address 0x0000000
}
System
Memory Data for doit
(RAM) (x=0x20bd4) and return link
Data
Datafor
Data formain
for main(a=3,
main (a=??,
(a=3, y=3)
y=3,
y=2) and
and Resulting Output:
ptr=0x20bd4)
returnandlink
return link
return link
a=3, y=2
System stack area
0xffff ffff
25
Misuse of Pointers/References
• Make sure you don't return a pointer to a // Computes the product of in1 & in2
int* badmul1(int in1, int in2);
dead variable int& badmul2(int in1, int in2);
• You might get lucky and find that old value int main()
{
still there, but likely you won't int wid = 8, len = 5;
int *a = badmul1(wid,len);
cout << "Ans. is " << *a << endl;
return 0;
}
Stack Area of RAM
// Bad! Returns a pointer to a var.
// that will go out of scope
int* badmul1(int in1, int in2)
0xbe0 40 out {
0xbe4 int out = in1 * in2;
badmul1 8 in1
return &out;
0xbe8 5 in2 }
0xbec Return
004000ca0 link
0xbf0 8 wid
main 0xbf4 5 len
0xbe0
0xbf8 -73249515 a
0xbfc Return
00400120 link
28
– Or need to pass the size (length) of the void add_1_to_array_v2(int *my_array, int size)
{
array as another argument int i=0;
for(i=0; i < size; i++){
520 524 528 532 536 540 my_array[i]++;
09 08 07 06 05 04 … }
}
Memory
29
Exercises
• In class exercises
– Roll2
– Product
31
POINTERS TO POINTERS
32
08 1 2 15 3 4 53
6 11 7 8 5 9 7 103 11
12 131 14 15 165 173
33
Pointer Analogy
• What if now rather than holding gold, those
boxes simply held other numbers
• How would you differentiate whether the
number in the box was a "pointer" to
another box or a simple data value?
– You can’t really. Context is needed
• This is why we have to declare something as
a pointer and give a type as well:
– int *p; // pointer to an integer one hop
(one level of indirection) away
• Example 20bd8
20bdc
00
00
– int k, x[3] = {5, 7, 9}; 20be0 00
… …
– int *myptr, **ourptr; Memory
– myptr = x; To figure out the type a pointer expression will
– ourptr = &myptr; yield…Take the type of pointer in the declaration
and let each * in the expression 'cancel' one of
– k = *myptr; //k=5 the *'s in the declaration
– k = (**ourptr) + 1; //k=6
Type Decl. Expr Yields
– k = *(*ourptr + 1); //k=7
myptr = int* *myptr int
ourptr = int** **ourptr int
*ourptr int*
36
Check Yourself
To figure out the type of data a pointer expression will yield…
• Consider these declarations: • Each * in the expression cancels a * from the variable type.
• Each & in the expression adds a * to the variable type.
– int k, x[3] = {5, 7, 9};
– int *myptr = x; Orig. Type Expr Yields
– int **ourptr = &myptr; myptr = int* *myptr int
• Indicate the formal type that ourptr = int** **ourptr int
each expression evaluates to *ourptr int*
(i.e. int, int *, int **) k = int &k int*
&myptr int**
Expression Type
&x[0]
20bc0 x=20bc4
x k 5 7 9
&k 20bd0
myptr myptr
*myptr
20bd4
(*ourptr) + 1 ourptr
myptr + 2
&ourptr
37
Check Yourself
• Consider these declarations:
– int k,x[3] = {5, 7, 9}; • * in an expression yields a type with 1 less *
– int *myptr = x; • & yields a type with 1 more *
C-String Constants
int main(int argc, char *argv[])
{
• C-String constants are the things // These are examples of C-String constants
cout << "Hello" << endl;
we type in "…" and are stored cout << "Bye!" << endl;
...
somewhere in memory (chosen
}
by the compiler)
300 305 240 244
• When you pass a C-string H e l l o \0 B y e ! \0
constant to a function it passes
the start address and it's type is
#include <cstring>
known as a const char * //cstring library includes 300
– char* because you are passing the //void strcpy (char * dest, const char* src);
address int main(int argc, char *argv[])
{
– const because you cannot/should not char name[40]; 300
Arrays of pointers
int main(int argc, char *argv[])
{
str2=288 292
S u z y \0
str3=300 305
P e d r o \0
str4=196 199
A n n \0
42
Arrays of pointers
int main(int argc, char *argv[])
{
int i;
• We often want to have char str1[] = “Bill”;
char str2[] = “Suzy”;
char str3[] = “Pedro”;
several arrays to store char str4[] = “Ann”;
char *names[4];
data names[0] = str1; ...; names[3] = str4;
Arrays of pointers
char *names[4] ={“Bill”,
“Suzy”,
data names[1]
names[2]
524
528
288
300
288 292
S u z y \0
– Could be to another names[3] 532 196
300 305
array P e d r o \0
196 199
A n n \0
44
Exercises
• Cmdargs_sum
• Cmdargs_smartsum
• Cmdargs_smartsum_str
• toi
48
Pointer Basics
0xbf0 8 wid
main 0xbf4 5 len
0xbf8 -73249515 a
0xbfc Return
00400120 link
MEMORY LEAK
No one saved a pointer
0xbf0 8 wid to this data
main 0xbf4 5 len
0xbf8 -73249515 a
0xbfc Return
00400120 link
Dynamic Allocation
• Dynamic Allocation // Computes rectangle area,
// prints it, & returns it
– Lives on the heap int* area(int, int);
• Doesn't have a name, only pointer/address to it void print(int);
– Lives until you 'delete' it int main()
{
• Doesn't die at end of function (though pointer to it may)
int wid = 8, len = 5, *a;
• I must keep at least 1 pointer to dynamic a = area(wid,len);
cout << *a << endl; // 40
memory at all times until I delete it
}
Stack Area of RAM Heap Area of RAM
int* area(int w, int l)
0xbe0 {
0x93c ans
int* ans = new int;
area 0xbe4 8 w *ans = w * l;
0x93c 40
0xbe8 return ans;
5 l
}
0xbec Return
004000ca0 link
0xbf0 8 wid
main 0xbf4 5 len
0xbf8 0x93c a
0xbfc Return
00400120 link
62
0xbf0 8 wid
main 0xbf4 5 len
0xbf8 -73249515 a
0xbfc Return
00400120 link
63
Pointer Mistake
• Never return a pointer to a local variable // Computes rectangle area,
// prints it, & returns it
• Pointer will now point to dead memory and int* area(int, int);
void print(int);
the value it was pointing at will be soon
int main()
corrupted/overwritten {
• We call this a dangling pointer (i.e. a pointer to int wid = 8, len = 5, *a;
a = area(wid,len);
bad or dead memory) cout << *a << endl;
}
Stack Area of RAM Heap Area of RAM
int* area(int w, int l)
{
int ans;
ans = w * l;
return &ans;
}
0xbf0 8 wid
main 0xbf4 5 len
0xbf8 0xbe0 a
0xbfc Return
00400120 link
64
Exercises
• In-class-exercises
– ordered_array
65
too long
names[0] “Tim”
names[1] “Christopher”
…
67
Jagged 2D-Arrays
#include <iostream>
• What we want is just enough using namespace std;
storage for each text string int main()
{
• This is known as a jagged // store 10 user names
2D-array since each array is a char *names[10];
names[0] “Tim”
names[1] “Christopher”
… "Jennifer"
68
– Exercise: deepnames
int main()
• No!! You must allocate storage (i.e. an {
// store 10 user names
actual array) before you have pointers // names type is still ______
pointing to things… char* names[10];
– Just because I make up a URL like: for(int i=0; i < 10; i++){
http://docs.google.com/uR45y781 cin >> names[i];
}
doesn't mean there's a document
there… // Do stuff with names
names[0] ???
names[1] ???
???
… return 0;
??? }
69
int main()
{
// store 10 user names
// names type is still char **
char* names[10];
? 0x8a4
}
// What if I want to change names[0] & [1]
names[0] “Timothy”
names[1] 0x980 cin >> temp_buf; // user enters “Allison”
0x980 names[0] = temp_buf;
cin >> temp_buf; // user enters “Jennifer”
“Christopher” names[1] = temp_buf;
for(int i=0; i < 10; i++){
delete [] names[i];
}
return 0;
}
74
? 0x8a4
}
// What if I want to change names[0] & [1]
names[0] 0x1c0 “Timothy”
names[1] 0x980 cin >> temp_buf; // user enters “Allison”
0x980 names[0] = temp_buf;
cin >> temp_buf; // user enters “Jennifer”
“Christopher” names[1] = temp_buf;
for(int i=0; i < 10; i++){
temp_buf evaluates to address of array. delete [] names[i];
So names[0] = temp_buf simply copies address }
of array into names[0]…It does not make a copy return 0;
of the array }
75
? 0x8a4
}
// What if I want to change names[0] & [1]
names[0] 0x1c0 “Timothy”
names[1] 0x980 cin >> temp_buf; // user enters “Allison”
0x980 names[0] = temp_buf;
cin >> temp_buf; // user enters “Jennifer”
“Christopher” names[1] = temp_buf;
for(int i=0; i < 10; i++){
Same problem with assignment of temp_buf to delete [] names[i];
names[1]. Now we have two things pointing at }
one array and we have lost track of memory return 0;
allocated for Timothy and Christopher…memory leak! }
76
? 0x8a4
}
// What if I want to change names[0] & [1]
names[0] 0x1c0 “Timothy”
names[1] 0x980 cin >> temp_buf; // user enters “Allison”
0x980 names[0] = temp_buf;
cin >> temp_buf; // user enters “Jennifer”
“Christopher” names[1] = temp_buf;
for(int i=0; i < 10; i++){
When we try to “delete” or free the memory pointed delete [] names[i];
to by names[i], it will now try to return memory it }
didn’t even allocate (i.e. temp_buf) and cause return 0;
the program to crash! }
77
int main()
{
// store 10 user names
// names type is still char **
char* names[10];
char temp_buf[40];
for(int i=0; i < 10; i++){
0x1c0: cin >> temp_buf;
temp_buf: “Allison” names[i] = new char[strlen(temp_buf)+1];
strcpy(names[i], temp_buf);
? 0x8a4
}
// What if I want to change names[0] & [1]
names[0] “Timothy”
names[1] 0x980 cin >> temp_buf; // user enters “Allison”
0x980 strcpy(names[0],temp_buf);
cin >> temp_buf; // user enters “Jennifer”
“Christopher” strcpy(names[1], temp_buf);
for(int i=0; i < 10; i++){
delete [] names[i];
}
return 0;
}
78
? strcpy():
0x8a4
}
// What if I want to change names[0] & [1]
names[0] “Timothy”
names[1] 0x980 cin >> temp_buf; // user enters “Allison”
0x980 strcpy(names[0],temp_buf);
cin >> temp_buf; // user enters “Jennifer”
“Christopher” strcpy(names[1], temp_buf);
for(int i=0; i < 10; i++){
delete [] names[i];
}
return 0;
}
79
Deep Copies
#include <iostream>
• If we want to change the name, what #include <cstring>
using namespace std;
do we have to do?
• Must allocate new storage and copy int main()
{
original data into new memory (a.k.a. // store 10 user names
// names type is still char **
deep copy) char *names[10];
– Deep copy = allocate new memory AND then copy
char temp_buf[40];
the original data (1 by 1) to the new memory for(int i=0; i < 10; i++){
cin >> temp_buf;
names[i] = new char[strlen(temp_buf)+1];
0x8a4 strcpy(names[i], temp_buf);
names[0] 0xbf0 “Timothy” }
names[1] 0xd4c 0xbf0 // What if I want to change names[0] & [1]
“Allison” cin >> temp_buf; // user enters “Allison”
0x980 delete [] names[0];
names[0] = new char[strlen(temp_buf)+1];
“Christopher” strcpy(names[0], temp_buf);
0xd4c cin >> temp_buf; // user enters “Jennifer”
delete [] names[1];
“Jennifer”
names[1] = new char[strlen(temp_buf)+1];
strcpy(names[1], temp_buf);
...
80
Exercise
• In-class-exercises
– nxmboard