0% found this document useful (0 votes)
93 views80 pages

Unit6 Pointers 1

The document discusses pointers in C++. It explains that pointers are variables that store memory addresses and can be used to indirectly access other variables in memory. It provides examples of declaring pointer variables and assigning the addresses of other variables to pointers using the '&' operator. The document also illustrates how the '*' operator is used to dereference a pointer and access the value at the given memory address.

Uploaded by

farhan khan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
93 views80 pages

Unit6 Pointers 1

The document discusses pointers in C++. It explains that pointers are variables that store memory addresses and can be used to indirectly access other variables in memory. It provides examples of declaring pointer variables and assigning the addresses of other variables to pointers using the '&' operator. The document also illustrates how the '*' operator is used to dereference a pointer and access the value at the given memory address.

Uploaded by

farhan khan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 80

1

CS103 Unit 6 - Pointers

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

Why Use Pointers


• [All of these will be explained as we go…]
• To change a variable (or variables) local to one function in
some other function
– Requires pass-by-reference (i.e. passing a pointer to the other
function)
• When large data structures are being passed (i.e. arrays, class
objects, structs, etc.)
– So the computer doesn’t waste time and memory making a copy
• When we need to ask for more memory as the program is
running (i.e. dynamic memory allocation)
• To provide the ability to access a specific location in the
computer (i.e. hardware devices)
– Useful for embedded systems programming
4

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

– Really pointers are the address of some other 09 08 07 06 05 04 …


variable in memory Memory
– "things" can be data (i.e. int’s, char’s, double’s) or 520 is a “pointer” to the integer 9
other pointers 536 is a “pointer” to the integer 5

• The concept of a pointer is very common and used


in many places in everyday life
– Phone numbers, e-mail or mailing addresses are
references or “pointers” to you or where you live
– Excel workbook has cell names we can use to
reference the data ( =A1 means get data in A1)
– URLs (www.usc.edu is a pointer to a physical HTML
file on some server) and can be used in any other
page to "point to" USC’s website
6

Prerequisites: Data Sizes, Computer Memory

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

C++ Pointer Operators


• Two operators used to manipulate pointers (i.e.
addresses) in C/C++: & and *
– &variable evaluates to the "address-of" variable
• Essentially you get a pointer to something by writing &something
– *pointer evaluates to the data pointed to by pointer (data
at the address given by pointer)
– & and * are essentially inverse operations
• We say ‘&’ returns a reference/address of some value while ‘*’
dereferences the address and returns the value
• &value => address
• *address => value
• *(&value) => value
9

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

– ptr1 = dat; Memory


int a = *ptr1 + 5;
– *ptr1 += 1; // *ptr = *ptr + 1;
– *ptr2 = *ptr1 - *ptr2;
14

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

Cutting through the Syntax


• ‘*’ in a type declaration = declare/allocate a pointer
• ‘*’ in an expression/assignment = dereference
Declaring a pointer De-referencing a
pointer
char *p Yes
*p + 1 Yes
int *ptr Yes
*ptr = 5 Yes
*ptr++ Yes
char *p1[10]; Yes

Helpful tip to understand syntax: We declare an int pointer as:


• int *p because when we dereference it as *p we get an int
• char *x is a declaration of a pointer and thus *x in code yields a char
16

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

Prerequisites: Pointer Basics, Data Sizes

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

Pointer Arithmetic and Array Indexing


• Array indexing and pointer arithmetic are very much related
• Array syntax: data[i]
– Says get the i-th value from the start of the data array
• Pointer syntax: *(data + i) <=> data[i]
– Both of these get the i-th value in an array
• We can use pointers and array names interchangeably:
– int data[10]; // data = 520;
– *(data + 4) = 50; // data[4] = 50;
– int* ptr = data; // ptr now points at 520 too
– ptr[1] = ptr[2] + ptr[3]; // same as data[1] = data[2] + data[3]
ptr 520

520 524 528 532 536 540

int data[10] 09 08 07 06 50 04 …
data = 520 Memory
21

Arrays & Pointers


int main(int argc, char *argv[])
{
• Array names and int data[10] = {9,8,7,6,5,4,3,2,1,0};

pointers have a unique int* ptr, *another; // * needed for each


// ptr var. you declare
relationship
• Array name evaluates ptr = data; // ptr = start address
// of data
to start address of another = data; // another = start addr.
array for(int i=0; i < 10; i++){
data[i] = 99;
– Thus, the name of an ptr[i] = 99; // same as line above
integer array has type: *another = 99; // same as line above
another++;
int*
}
– The name of character
int x = data[5];
array / text string has x = *(ptr+5); // same as line above
type: char* return 0;

• Array indexing is same }

as pointer arithmetic
22

Prerequisites: Pointer Basics

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) }

• The value of y cannot be changed by any other


function (remember it is local)
Code
Code for
for all functions
all functions
Address 0x0000000

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

System stack area


0xffff ffff
24

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

Swap Two Variables


int main()
{
• Classic example of issues with local int x=5,y=7;
swapit(x,y);
variables: cout << "x=" << x << " y=";
cout << y << endl;
– Write a function to swap two variables }
void swapit(int x, int y)
• Pass-by-value doesn’t work { int temp;
temp = x;
– Copy is made of x,y from main and x = y;
y = temp;
passed to x,y of swapit…Swap is }
program output: x=5,y=7
performed on the copies
int main()
• Pass-by-reference (pointers) does { int x=5,y=7;
swapit(&x,&y);
work cout << "x=" << x << "y=";
cout << y << endl;
}
– Addresses of the actual x,y variables in
void swapit(int *x, int *y)
main are passed { int temp;
temp = *x;
– Use those address to change those *x = *y;
*y = temp;
physical memory locations }

program output: x=7,y=5


26

Correct Usage of Pointers


// Computes the product of in1 & in2
• Commonly functions will take some inputs and int mul1(int in1, int in2);
produce some outputs void mul2(int in1, int in2, int* out);

– We'll use a simple 'multiply' function for now even


though we can easily compute this without a function int main()
{
– We could use the return value from the function but int wid = 8, len = 5, a;
let's practice with pointers mul2(wid,len,&a);
cout << "Ans. is " << a << endl;
• Can use a pointer to have a function modify the return 0;
variable of another }
Stack Area of RAM
int mul1(int in1, int in2)
{
0xbe0 8 in1 return in1 * in2;
0xbe4 }
mul 5 in2
0xbe8 0xbf8 out void mul(int in1, int in2, int* out)
Return
{
0xbec 004000ca0 link *out = in1 * in2;
}
0xbf0 8 wid
main 0xbf4 5 len
40
0xbf8 -73249515 a
0xbfc Return
00400120 link
27

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

Passing Arrays as Arguments


• In function declaration / prototype for void add_1_to_array_v1(int [], int);

the formal parameter use void add_1_to_array_v2(int *, int);


int main(int argc, char *argv[])
– type [] or type * to indicate an array is {
being passed int data[10] = {9,8,7,6,5,4,3,2,1,0};
add_1_to_array_v1(data);
• When calling the function, simply 520
cout << “data[0]” << data[0] << endl;
provide the name of the array as the add_1_to_array_v2(data);
cout << “data[0]” <<
520 data[0] << endl;
actual argument return 0;
– In C/C++ using an array name without }
any index evaluates to the starting 520
address of the array void add_1_to_array_v1(int my_array[], int size)
{
• C does NOT implicitly keep track of the int i=0;
size of the array for(i=0; i < 10; i++){
my_array[i]++;
– Thus either need to have the function }
only accept arrays of a certain size } 520

– 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

Argument Passing Example


#include <iostream> Address Address
using namespace std; 0 0
int main() Code Code
{
int len=0; … …
int data[100]; Globals Globals
len = fill_data(data, 100);
… …
for(int i=0; i < len; i++)
cout << data[i] << " "; Heap Heap
cout << endl;
return 0;
} … …

// fills in integer array w/ int’s fill_data fill_data


// from user until -1 is entered (array=0xbf008, (array=0xbf008,
int fill_data(int *array, int max) max = 100 max = 100
{ val=0, i = 0) val = -1, i = 2)
int val = 0; main: main:
int i = 0; 0xbf004 (len = 0 0xbf004 (len = 2
while(i < max){ 0xbf008 data[0] = ? 0xbf008 data[0] = 4
cin >> val; 0xbf00c data[1] = ? 0xbf00c data[1] = 3
if (val != -1) data[2] = ? data[2] = ?
array[i++] = val; … …
else fffffffc ) fffffffc )
break;
}
Memory (RAM) Memory (RAM)
return i;
}
30

Exercises
• In class exercises
– Roll2
– Product
31

Prerequisites: Pointer Basics

POINTERS TO POINTERS
32

Pointers to Pointers Analogy


• We can actually have multiple levels of
indirection (de-referencing)
• Using C/C++ pointer terminology:
– *9 = gold in box 7 (9 => 7)
– **16 = gold in box 3 (16 => 5 => 3)
– ***0 = gold in box 3 (0 => 8 => 5 => 3)

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

– double **q; // pointer to a double two


hops (two levels of indirection) away 0 8 1 9 2 15 3 12 4 2 5 3
6 11 7 9 8 4 9 7 103 11
1211 131 1418 1510 165 173
34

Pointers to Pointers to…


20bc0 00 k
20bc4 5 x[0]
• Pointers can point to other 20bc8 7 x[1]
20bcc 9 x[2]
pointers 20bd0 myptr
20bd4 ourptr
– Essentially a chain of “links” 20bd8 00
20bdc 00
• Example 20be0

00

– int k, x[3] = {5, 7, 9}; Memory
– int *myptr, **ourptr;
– myptr = x; 20bc0 x=20bc4
– ourptr = &myptr; k 5 7 9
– k = *myptr; // k=? 20bd0
myptr
– k = (**ourptr) + 1; // k=?
20bd4
– k = *(*ourptr + 1); // k+? ourptr
35

Pointers to Pointers to…


• Pointers can point to other 20bc0
20bc4
00
5
k
x[0]
pointers 20bc8
20bcc
7
9
x[1]
x[2]
– Essentially a chain of “links” 20bd0
20bd4
20bc4
20bd0
myptr
ourptr

• 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 *

– int **ourptr = &myptr;


• Indicate the formal type that each expression evaluates to (i.e. int,
int *, int **)
Expression Type
x[0] int
x int*
&k int*
myptr int*
*myptr int
&myptr int**
ourptr int**
*ourptr int*
myptr + 1 int*
38

ARRAYS OF POINTERS AND


C-STRINGS
39

Review: String Function/Library


(#include <cstring>)
• int strlen(char *dest)
• int strcmp(char *str1, char *str2);
– Return 0 if equal, >0 if first non-equal char in str1 is alphanumerically
larger, <0 otherwise
• char *strcpy(char *dest, char *src);
– strncpy(char *dest, char *src, int n);
– Maximum of n characters copied
• char *strcat(char *dest, char *src);
– strncat(char *dest, char *src, int n);
– Maximum of n characters concatenated plus a NULL
• char *strchr(char *str, char c);
– Finds first occurrence of character ‘c’ in str returning a pointer to that
character or NULL if the character is not found
40

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

change this array's contents strcpy(name, "Tommy");


} 240

name = 240 279 300 305


T o m m y \0
41

Arrays of pointers
int main(int argc, char *argv[])
{

• We often want to have int i;


char str1[] = “Bill”;
char str2[] = “Suzy”;
several arrays to store char str3[] = “Pedro”;
char str4[] = “Ann”;
data // I would like to print out each name
cout << str1 << endl;
– Store several text strings cout << str2 << endl;
...
• Those arrays may be related }

(i.e. all names of students in Painful


a class) str1=240 244
B i l l \0

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;

– Store several text strings for(i=0; i < 4; i++){


cout << names[i] << endl;

• Those arrays may be related }


...

(i.e. all names of students in }


Still painful
a class) 240 244

• What type is 'names'? names[0] names = 520


names[1] 524
240
288
B i l l \0

– The address of the 0-th char* names[2] 528 300


288 292
names[3] 532 196 S u z y \0
in the array
300 305
– The address of a char* is P e d r o \0
really just a char**
196 199
A n n \0
43

Arrays of pointers
char *names[4] ={“Bill”,
“Suzy”,

• We can have arrays of “Pedro”,


“Ann”};

pointers just like we int main(int argc, char *argv[])


{
have arrays of other int i;
for(i=0; i < 4; i++){
data types }
cout << names[i] << endl;

• Usually each value of


return 0;
}

the array is a pointer to Painless?!?


240 244
a collection of “related” names[0] names = 520 240 B i l l \0

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

Command Line Arguments


• Now we can understand the arguments Command line:
p r o g 1 4 0.5 10000 0
passed to the main function (int argc, char
*argv[]) Linux shell command line
• At the command prompt we can give
./prog1 Executable
inputs to our program rather than making
querying the user interactively: int main(int argc, char *argv[])
– $ ./prog1 4 0.5 100000 argc = 4 argv = 5a0
– $ cp broke.c broke2.c 5a0
240
• Command line string is broken at argv[0] 240
p r o g 1 \0
argv[1] 288
whitespaces and copied into individual argv[2] 300
288
4 \0
strings and then packaged into an array argv[3] 196
300
(argv)
0 . 5 \0
– Each entry is a pointer to a string (char *)
196
• Argc indicates how long that arrays is 1 0 0 0 0 0 \0
(argv[0] is always the executable name)
45

Command Line Arguments


• Recommended usage: argv[0] p r o g 1 \0

– Upon startup check argc to make sure the argv[1] 4 \0


user has input the desired number of
args (remember the executable counts as argv[2] 0 . 5 \0
one of the args.)
argv[3] 1 0 0 0 0 0 \0
• Problem:
#include <iostream>
– Each argument is a text string…for #include <cstdlib>
using namespace std;
numbers we want its numeric
// char **argv is the same as char *argv[]
representation not its ASCII int main(int argc, char **argv)
{
representation int init, num_sims;
– cstdlib defines: double p;
if(argc < 4){
atoi() [ASCII to Integer] and cout << "usage: prog1 init p sims" << endl;
return 1;
atof() [ASCII to float/double] }
– Each of these functions expects a init = atoi(argv[1]);
pointer to the string to convert p = atof(argv[2]);
num_sims = atoi(argv[3]);
...
46

cin/cout & char*s


396 dat=400

• cin/cout determine everything they do x 5 5 5 5 5 5 5

based on the type of data passed


• cin/cout have a unique relationship with 448 word=440
H e l l o \0
char*s name 300

• When cout is given a variable of any type it


#include <iostream>
will print the value stored in that exact using namespace std;
variable int main()
{
– Exception: When cout is given a char* it int x = 5, dat[10]; // dat is like an int*
char word[10] = "Hello";
will assume it is pointing at a C-string, go to char *name = word;
that address, and loop through each
cout << x << endl; /* 5 */
character, printing them out cout << dat << endl; /* 400 */
• When cin is given a variable it will store cout
cout
<<
<<
word << endl;
name << endl;
/* Hello */
/* Hello */
the input data in that exact variable cout << name[0] << endl; /* H */
cout << (void*) name << endl; /* 440 */
– Exception: When cin is given a char* it will
cin >> x; /* Store into x (@396) */
assume it is pointing at a C-string, go to cin >> name; /* Store string starting
that address, and place the typed at 440 */
return 0;
characters in that memory }
47

Exercises
• Cmdargs_sum
• Cmdargs_smartsum
• Cmdargs_smartsum_str
• toi
48

Recap: Why Use Pointers


• To change a variable (or variables) local to one function in
some other function
– Requires pass-by-reference (i.e. passing a pointer to the other
function)
• When large data structures are being passed (i.e. arrays, class
objects, structs, etc.)
– So the computer doesn’t waste time and memory making a copy
• To provide the ability to access specific location in the
computer (i.e. hardware devices)
– Useful for embedded systems programming
• When we need a variable address (i.e. we don’t or could not
know the address of some desired memory location BEFORE
runtime)
49

Pointer Basics

DYNAMIC MEMORY ALLOCATION


50

Dynamic Memory Allocation


• I want an array for student scores but I don’t know how many
students we have until the user tells me
• What size should I use to declare my array?
– int scores[??]
• Doing the following is not supported by all C/C++ compilers:
int num;
cin >> num;
int scores[num]; // Some compilers require the array size
// to be statically known

• Also, recall local variables die when a function returns


• We can allocate memory dynamically (i.e. at run-time)
– If we want memory to live beyond the end of a functions (i.e. we want
to control when memory is allocated and deallocated)
• This is the primary reason we use dynamic allocation
– If we don't know how much we'll need until run-time
51

Dynamic Memory Analogy


• Dynamic Memory is “ON-Demand Memory”
• Analogy: Public storage rentals
– Need extra space, just ask for some storage and indicate how much
you need (‘new’ statement
with space allocated from the
heap)
– You get back the
“address”/storage room number
(‘new’ returns a pointer to the
allocated storage)
– Use the storage/memory until you
are done with it
– Need to return it when done or else no one
else will ever be able to re-use it
52

Dynamic Memory & the Heap


• Code usually sits at low addresses 0
Code
• Global variables somewhere after code
• System stack (memory for each function instance …
Globals
that is alive)

– Local variables
– Return link (where to return) Heap
– etc.
• Heap: Area of memory that can be allocated and
de-allocated during program execution (i.e. …
dynamically at run-time) based on the needs of
the program
… Stack
• Heap grows downward, stack grows upward… (area for
data local to
– In rare cases of large memory usage, they could a function)
fffffffc
collide and cause your program to fail or generate
an exception/error Memory
53

C Dynamic Memory Allocation


• malloc(int num_bytes) function in stdlib.h
– Allocates the number of bytes requested and returns a pointer to the block of
memory
• free(void * ptr) function
– Given the pointer to the (starting location of the) block of memory, free returns it to the
system for re-use by subsequent malloc calls
54

C++ new & delete operators


• new allocates memory from heap
– replaces “malloc”
– followed with the type of the variable you want or an array type declaration
• double *dptr = new double;
• int *myarray = new int[100];
– can obviously use a variable to indicate array size
– returns a pointer of the appropriate type
• if you ask for a new int, you get an int * in return
• if you ask for an new array (new int[10]), you get an int * in return]
• delete returns memory to heap
– Replaces “free”
– followed by the pointer to the data you want to de-allocate
• delete dptr;
– use delete [] for arrays
• delete [] myarray;
55

Dynamic Memory Analogy


• Dynamic Memory is “ON-Demand Memory”
• Analogy: Public storage rentals
– Need extra space, just ask for some storage and indicate how much
you need (‘new’ statement
with space allocated from the
heap)
– You get back the
“address”/storage room number
(‘new’ returns a pointer to the
allocated storage)
– Use the storage/memory until you
are done with it
– Need to return it when done or else no one
else will ever be able to re-use it
56

Dynamic Memory Allocation


int main(int argc, char *argv[]) 0 Code
{
int num; …

cout << “How many students?” << endl; Globals


cin >> num; …
int *scores = new int[num]; new
Heap allocates:
// can now access scores[0] .. scores[num-1];
return 0; 20bc0 00 scores[0]
}
20bc4 00 scores[1]
20bc8 00 scores[2]
20bcc 00 scores[3]
20bd0 00 scores[4]
int main(int argc, char *argv[])
{
int num;

cout << “How many students?” << endl;
cin >> num; …
int *scores = new int[num];
// can now access scores[0] .. scores[num-1];
delete [] scores fffffffc local vars
return 0;
} Memory
57

Fill in the Blanks


• ________ data = new int;

• ________ data = new char;

• ________ data = new char[100];

• ________ data = new char*[20];

• ________ data = new string;


58

Fill in the Blanks


• ________ data = new int;
– int*
• ________ data = new char;
– char*
• ________ data = new char[100];
– char*
• ________ data = new char*[20];
– char**
• ________ data = new string;
– string*
59

Dynamic Allocation // Computes rectangle area,


• Dynamic Allocation // prints it, & returns it
int* area(int, int);
– Lives on the heap void print(int);
• Doesn't have a name, only pointer/address to it
int main()
– Lives until you 'delete' it {
• Doesn't die at end of function (though pointer to it may) int wid = 8, len = 5, a;
area(wid,len);
• This code fails to save a pointer to the new int once
}
area() finishes
Stack Area of RAM Heap Area of RAM int* area(int w, int l)
{
0xbe0 int* ans = new int;
0x93c ans
*ans = w * l;
area 0xbe4 8 w return ans;
0x93c 40
0xbe8 }
5 l
0xbec Return
004000ca0 link

0xbf0 8 wid
main 0xbf4 5 len
0xbf8 -73249515 a
0xbfc Return
00400120 link

This Photo by Unknown Author is licensed under CC BY-SA


60

Dynamic Allocation // Computes rectangle area,


• Dynamic Allocation // prints it, & returns it
int* area(int, int);
– Lives on the heap void print(int);
• Doesn't have a name, only pointer/address to it
int main()
– Lives until you 'delete' it {
• Doesn't die at end of function (though pointer to it may) int wid = 8, len = 5, a;
area(wid,len);
• This code fails to save a pointer to the new int once
}
area() finishes
Stack Area of RAM Heap Area of RAM int* area(int w, int l)
{
int* ans = new int;
*ans = w * l;
return ans;
0x93c 40 }

MEMORY LEAK
No one saved a pointer
0xbf0 8 wid to this data
main 0xbf4 5 len
0xbf8 -73249515 a
0xbfc Return
00400120 link

This Photo by Unknown Author is licensed under CC BY-SA


61

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

Pointer Mistake // Computes rectangle area,


• Never return a pointer to a local // prints it, & returns it
int* area(int, int);
variable void print(int);
int main()
{
int wid = 8, len = 5, *a;
a = area(wid,len);
cout << *a << endl;
}
Stack Area of RAM Heap Area of RAM
int* area(int w, int l)
0xbe0 {
40 ans
int ans;
area 0xbe4 8 w ans = w * l;
0xbe8 return &ans;
5 l
}
0xbec Return
004000ca0 link

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

SHALLOW VS. DEEP COPY


66

Dealing with Text Strings


#include <iostream>
• What’s the best way to store text using namespace std;
strings for data that we will not int main()
know until run time and that {
// store 10 user names of up to
could be short or long? // 40 chars
char names[10][40];
• Statically:
– Bad! Either wastes space or some
user will enter a string just a little }

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];

different length for(int i=0; i < 10; i++){


/* read in and store each name */
• To achieve this we will need an }
}
array of pointers
– Each pointer will point to an array
of different length

names[0] “Tim”
names[1] “Christopher”
… "Jennifer"
68

More Dealing with Text Strings


#include <iostream>
• Will this code work to store 10 #include <cstring>
names? using namespace std;

– 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

More Dealing with Text Strings


#include <iostream>
• Will this code work to store 10 #include <cstring>
names? using namespace std;

int main()
{
// store 10 user names
// names type is still char **
char* names[10];

// One "scratchpad" array to read in a name


char temp_buf[40];

for(int i=0; i < 10; i++){


0x1c0: cin >> temp_buf;
temp_buf “Timothy” names[i] = temp_buf;
}
// Do stuff with names

for(int i=0; i < 10; i++){


names[0] ??? delete [] names[i];
names[1] ??? }
??? return 0;
… }
???
70

More Dealing with Text Strings


#include <iostream>
• What’s the best way to store text #include <cstring>
strings for data that we will not using namespace std;

know until run time and that could int main()


be short or long? {
// store 10 user names
• Dynamically: // names type is still char **
char* names[10];
– Better memory usage char temp_buf[40];
– Requires a bit more coding for(int i=0; i < 10; i++){
cin >> temp_buf;
// Find length of strings
0x1c0: i=0 int len = strlen(temp_buf);
temp_buf “Timothy” names[i] = new char[len + 1];
strcpy(names[i], temp_buf);
strcpy() }
0x8a4
// Do stuff with names
names[0] 0x8a4 “Timothy”
names[1] ???
??? for(int i=0; i < 10; i++){
… delete [] names[i];
??? }
return 0;
}
71

More Dealing with Text Strings


#include <iostream>
• What’s the best way to store text #include <cstring>
strings for data that we will not using namespace std;

know until run time and that could int main()


be short or long? {
// store 10 user names
• Dynamically: // names type is still char **
char* names[10];
– Better memory usage char temp_buf[40];
– Requires a bit more coding for(int i=0; i < 10; i++){
cin >> temp_buf;
// Find length of strings
0x1c0: i=1 int len = strlen(temp_buf);
temp_buf “Christopher” names[i] = new char[len + 1];
strcpy(names[i], temp_buf);
}
0x8a4
// Do stuff with names
names[0] 0x8a4 “Timothy”
names[1] 0x980 strcpy()
??? 0x980 for(int i=0; i < 10; i++){
delete [] names[i];
??? “Christopher” }
return 0;
… }
72

Shallow Copy vs. Deep Copy


#include <iostream>
• If we want to change the name, #include <cstring>
using namespace std;
what do we have to do?
• Can we just use the assignment int main()
{
operator, ‘=‘? // 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
names[0] 0x8a4 “Timothy” // What if I want to change names[0] & [1]
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;
}
73

Shallow Copy vs. Deep Copy


#include <iostream>
• If we want to change the name, #include <cstring>
using namespace std;
what do we have to do?
• Can we just use the assignment int main()
{
operator, ‘=‘? // 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 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

Shallow Copy vs. Deep Copy


#include <iostream>
• If we want to change the name, #include <cstring>
using namespace std;
what do we have to do?
• Can we just use the assignment int main()
{
operator, ‘=‘? // 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] 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

Shallow Copy vs. Deep Copy


• Pointers are references… assigning #include <iostream>
a pointer doesn’t make a copy of #include <cstring>
using namespace std;
what its pointing at it makes a
copy of the pointer (a.k.a. int main()
{
“shallow copy”) // store 10 user names
// names type is still char **
– Shallow copy = copy of pointers to char* names[10];
data rather than copy of actual data
char temp_buf[40];
for(int i=0; i < 10; i++){
0x1c0: cin >> temp_buf;
temp_buf: “Jennifer” 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] 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

Shallow Copy vs. Deep Copy


• Pointers are references… assigning #include <iostream>
a pointer doesn’t make a copy of #include <cstring>
using namespace std;
what its pointing at
• Deleting the same memory twice int main()
{
will cause the program to crash // 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: “Jennifer” 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] 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

Shallow Copy vs. Deep Copy


#include <iostream>
• Can we use strcpy() instead? #include <cstring>
using namespace std;

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

Shallow Copy vs. Deep Copy


#include <iostream>
• Can we use strcpy() instead? #include <cstring>
using namespace std;
• No! Because what if the new
name is longer than the array int main()
{
allocated for the old name…we'd // store 10 user names
// names type is still char **
write off the end of the array and char* names[10];
corrupt memory char temp_buf[40];
for(int i=0; i < 10; i++){
0x1c0: cin >> temp_buf;
temp_buf: “Tommy T Trojan” names[i] = new char[strlen(temp_buf)+1];
strcpy(names[i], temp_buf);

? 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

You might also like