Вы находитесь на странице: 1из 46

06.

Pointers

Overview
1.

Pointer Basics

2.

Pointer as Function Parameter

3.

Pointer and Array

4.

Dynamic Memory Allocation

6.1 Pointer Basics

Introduction

Pointers in C++ == Memory Addresses

Through pointers, we can directly


access/modify the data stored in the memory.

What do we use pointers for in


C++?

To emulate passing parameters by reference


C language still uses pointers to achieve the effect
of pass-by-reference.

Dynamic memory management


We can decide how much memory space we want
at run-time.

Computer Memory
Store 1 byte or 8 bits of data

100

101

102

103

104

105

106

107

108

109

110

Memory Address

Continuous storage of 1-byte cells

Each cell has a unique address ranging from 0 to


2N-1 in increasing order.
N = # of bits of address/data the processor can process at a time
On most computers we use today, N = 32 or 64

Variables and Memory


Addresses

100

char ch;
int x;

101

102

103

104

105

106

107

108

109

110

// 1 byte
// 32-bit integer (needs 4 bytes)

Each variable is allocated an appropriate


amount of memory space.

Each variable has a unique memory address.

The address of the first cell becomes the address of


the variable.
7

Variables and Memory Addresses

Each variable in the program is allocated an


appropriate number of cells in the memory
for storing data.
ch: 1 byte 1 cell
x: 4 bytes 4 (continuous) cells

The location of each variable is determined


by the compiler and the OS (and thus may
vary from one execution to another.)

The address-of operator


&

100

char ch;
int x;

101

102

103

104

105

106

107

108

109

110

// Assume ch occupies 1 byte at location 100


// Assume x occupies 4 bytes starting at location 104

// Print address of ch and x as hexadecimal numbers.


cout << &ch << " " << &x << endl;
// Print 64 68
// Print address of ch and x as decimal numbers.
cout << (unsigned int)&ch << " "
<< (unsigned int)&x << endl;
// Print 100 104

&, when applied to a variable, yields the address of the


variable.
9

Several uses of '&'

In parameter list

int foo(int &x) { }


Indicates x is a reference parameter

Use with variable in an expression


cout << &x;
Yields the address of variable x

10

Pointer Variables

Pointer variables are variables that store


memory addresses
int foo;
int *ptr; // Declaring a pointer variable
ptr = &foo; // ptr stores the address of foo
ptr is a variable that holds an address of a
variable of type int.

11

Assigning Address of Variables to


Pointers
int y = 5;
int *ptr;

ptr = &y;

ptr stores the address of


variable y
or
ptr points to y

1000

ptr 2000

..
.
?

1000

ptr 2000

..
.
1000

12

The Dereference Operator *


*, when applied to a pointer variable in an
expression, yields the variable pointed by the
pointer.
int y = 5;
int *ptr;

When used as a prefix in variable


declaration, * indicates that the
variable is a pointer.

ptr = &y;
// ptr gets the address of y
cout << *ptr; // Same as cout << y;
*ptr = 10; // Same as y = 10;

13

Using pointers to access variables


int x = 10, y = 5;
int *p1, *p2;
Memory View

Pictorial View

p1
?

x
10

1000

10

1004

2000
2004

..
.
?
?

p1
p2

p2
?

14

Using pointers to access variables


p1 = &x;
p2 = &y;
Memory View

Pictorial View

p1
p2

x
10

1000

10

1004

..
.

y
5

2000
2004

1000
1004

p1
p2

15

Using pointers to access variables


*p1 = 7;
*p2 = 11;
Memory View

Pictorial View

p1

x
7

p2

y
11

1000

1004

11

..
.
2000
2004

1000
1004

p1
p2

16

Using pointers to access variables


p2 = p1;

// Not the same as *p2 = *p1

Memory View

Pictorial View

p1

x
7

p2

y
11

1000

1004

11

..
.
2000
2004

1000
1000

p1
p2

17

Using pointers to access variables


cout << *p1 << " " << *p2 << endl;
// Output: 7 7
Memory View

Pictorial View

p1

x
7

p2

y
11

1000

1004

11

..
.
2000
2004

1000
1000

p1
p2

18

Exercise (Please try it on your own)


int x = 7, y = 11;
int *p1, *p2;
p1 = &x;
p2 = &y;

p1

*p1 = *p2;
y = 10;
cout << *p2 << endl;
*p1 = 20;
cout << x << " " << y << endl;

p2

19

Exercise (Please try it on your own)


int x = 7, y = 11;
int *p1, *p2;

p1 = &x;
p2 = &y;
*p1 = y;
*p2 = x;
cout << x << " " << y << endl;
cout << *p1 << " " << *p2
<< endl;

p1

p2

20

Exercise (Please try it on your own)


int x = 7, y = 11, z = 3, *p1, *p2;
p2 = &x;
p2 = &y;
*p2 = 5;
p1 = p2;
p2 = &z;
y = 6;
cout << *p1 << " " << *p2 << endl;
z = *p1;
*p2 = x;
cout << x << " " << y << endl;

p1

p2

21

Pointers to different data


types
int *iptr;
// Pointer to integer
char *cptr;
// Pointer to char
double *dptr;
// Pointer to double
Rectangle *recPtr; // Pointer to a Rectangle object
(see next lecture)

Pointer variables of different types all store memory


addresses.
The pointer type tells the computer how to interpret
the data stored at the location pointed to by the
pointer.
cptr

Treat 1 byte here as


character

iptr

Starting here, treat the next


4 bytes as integer
22

Pointers to different data types


int *iptr;
// Pointer to integer
char *cptr;
// Pointer to char
double *dptr;
// Pointer to double
Rectangle *recPtr;
// Pointer to class Rectangle
(see next lecture)
// Pointers of different types are not compatible
// unless explicitly converted.
iptr = cptr;
cptr = iptr;

// Compile-time error
// Compile-time error

23

Pointer Initialization & Null


Pointer
int y;
int *ptr1 = &y;

Same as
int *ptr1;
ptr1 = &y;

int *ptr2 = 0,
// ptr2 stores the address 0
*ptr3 = NULL; // ptr3 stores the address 0

NULL is a predefined constant representing


address 0 (it has the value 0)

We can use 0 or NULL to indicate that a pointer


variable is not pointing to anything (no data
can be stored at location 0)
24

Pointer Initialization (Pitfalls)


int y;
int *ptr = &y;
ptr = &y;
*ptr = 10;
*ptr = &y;
ptr = 100;

// Correct
// Correct
// Correct
// Compile-time error
// Compile-time error

25

Summary

Concepts of computer memory and how data


are stored in the memory.

Know how to declare pointer variables

Know how to use the address-of operator (&)


and the dereference operator (*)

Understand the difference between copying


pointers and copying the data pointed by the
pointers.
p1 = p2;

vs

*p1 = *p2;

26

6.2 Pointer as
Function Parameter

27

Pointers as Parameters

Pointers are passed by value


The address store in one pointer variable (the actual
parameter) is copied to the another pointer variable
(the formal parameter).

Passing pointers allow us to emulate the


effect of "pass by reference".
When the function receives the memory address,
the function can access the data stored at that
memory address.

28

void foo(int *p) {


*p = 0;
}

// In main()
int x = 3;
int *ptr = &x;
foo(ptr);
cout << x; // Print 0
void foo(int *p) {
*p = 0;
}

// In main()
int x = 3;
int *ptr = &x;
foo(ptr);
cout << x; // Print 0

ptr holds the address of x

ptr

x
3

Value of ptr (address of x) is copied to


p. In effects, p also points to x.

ptr

x
3

29

void foo(int *p) {


*p = 0;
}

// In main()
int x = 3;
int *ptr = &x;
foo(ptr);
cout << x; // Print 0

Copy 0 to the memory location p points


to. (i.e., the memory location of x in
main().)

void foo(int *p) {


*p = 0;
}

// In main()
int x = 3;
int *ptr = &x;
foo(ptr);
cout << x; // Print 0

After the function call, the value of x is


changed to 0.

ptr

x
0

ptr

x
0

30

6.3 Pointer and Array

31

How are 1D arrays stored in


memory?
int foo[10]; // Assume int is 4 byte
Suppose array foo starts at location 800
800

801

802

foo[0]

803

804

805

806

foo[1]

807

808

809

810

811

812

813

foo[2]

Address of an array == Address of its first element


(also known as the base address)
The address of foo[0] 800
The address of foo 800
32

How are 1D arrays stored in memory?

800

801

802

foo[0]

803

804

805

806

foo[1]

807

808

809

810

811

812

813

foo[2]

Address of foo[i] = base address + i * 4


We assume each value of type int is 4 bytes in size
Array size plays no role in determining the address of an
array element.
The address of foo[2]
800 + 2*4 = 808
The address of foo[9]
800 + 9*4 = 836
The address of foo[100] 800 + 100*4 = 1200

33

C++ Representation of 1D Arrays


datatype array[SIZE];

If we know the base address of array and the type of its


element, then we can calculate the address of any of its
elements.

For example, address of array[index] is


base address of array + index * sizeof(datatype)

sizeof(type_name)
yields the number of bytes used to represent the value of type
type_name.
e.g., sizeof(int) yields 4

34

C++ Representation of 1D Arrays

An array in C++ is represented using its base


address.

e.g.
int arrayA[10], arrayB[100];
double arrayC[2];
cout << arrayA << endl; // Print address of arrayA
cout << arrayB << endl; // Print address of arrayB
cout << arrayC << endl; // Print address of arrayC

Note: Array of char is an exception because it is


treated as a string.
35

Pointer Variables and


Arrays

An array is represented by a base address

A pointer variable stores address

A pointer variable can be used as if it is an


array
We can treat the address stored in a pointer variable
as the base address of an array

36

Pointer Variables and


Arrays

int *ptr, foo[5] = {11, 22, 33, 44, 55};


int bar[3] = {10, 9, 8};
ptr = foo;

// ptr gets the base address of array foo

// ptr can now be used as an array


// The value stored in ptr is used as the base address
cout << ptr[0]; // Prints 11
cout << ptr[3]; // Prints 44
ptr = bar; // ptr gets the base address of array bar
cout << ptr[0]; // Prints 10
37

Pointer Variables and


Arrays

int *ptr, foo[5] = {11, 22, 33, 44, 55};


ptr = &foo[1];
11

22

// ptr gets the address of foo[1]


33

44

55

// Virtually, ptr is treated as an array in which its base


// address is the address of foo[1].
// The value stored in ptr is used as the base address
cout << ptr[0]; // Prints 22
cout << ptr[3]; // Prints 55
cout << foo[3]; // Prints 44
38

void printArray(int *ptr, int N) {


for (int i = 0; i < N; i++)
Interpreted the same as
cout << ptr[i] << " ";
int ptr[]
cout << endl;
}
int main() {
int array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
printArray(array, 3);
printArray(&array[0], 3);
printArray(&array[1], 3);
printArray(&array[4], 5);

//
//
//
//

Prints
Prints
Prints
Prints

0
0
1
4

1
1
2
5

2
2
3
6 7 8

return 0;
};

39

6.4 Dynamic Memory


Allocation

40

Dynamic Memory
Management

Determine the size of an array at compile time


int a[5];

Can we use the following code determine the size of an array


at runtime?
int n;
cin >> n
int a[n];

No. Placing n inside a[n] will cause compile-time error

We have to use pointers for dynamic memory management


While your program is running, you can explicitly allocate or reserve
memory space to store data

41

Using new with Arrays


(Dynamic Array Allocation)
int n;
cin >> n;
int *foo; // store the address of the dynamic array
foo = new int[n];
// allocate a continuous memory space for n integers
// assign the base address of the array to foo
// foo can be used as an array
for(int i = 0; i < n; i++)
foo[i] = i;
// free up ALL the space occupied by foo
delete [] foo;

800

801

802

foo[0]

803

804

805

806

foo[1]

807

808

809

810

foo[2]

811

812

813
42

Memory allocation and


deallocation (Operator new
and
delete)
Operator
new

For allocating memory space to store data


It reserves a continuous chunk of memory space
Upon successful allocation, it returns the memory
address of the allocated space
You should always use a pointer variable to save
the memory address returned by new

Operator delete
For freeing up the previously allocated
memory space
43

Allocate Dynamic 2D Array


(Optional)
int **twoDArray; // 2D array
int numOfRow = 4; // # of rows of 2D array
int numOfCol = 5; // # of columns of 2D array
// allocate space for twoDArray
twoDArray = new int*[numOfRow];
// allocate space for each twoDArray[i]
for(int i = 0; i < numOfRow; i++) {
twoDArray[i] = new int[numOfCol];
}
... ...
// free up the space occupied by twoDArray after using it
for(int i = 0; i < numOfRow; i++) {
delete [] twoDArray[i];
}
delete [] twoDArray;

44

Passing Dynamic 2D Array to


Function (Optional)
/* a function to print the 2D array */
void print2DArray(int **ptr, int n, int m) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cout << ptr[i][j] << " ";
}
cout << endl;
}
}
/* in main () */
int **ptr;
int n, m;
// initialize ptr, n, m

// print 2D array
print2DArray(ptr, n, m);
45

Summary

Understand the syntax of passing pointers to


functions that accepts pointers as parameters

Understand how passing pointers to functions


can emulate the effect of "pass-by-reference"

Understand how 1D arrays are represented in


C++ and its relationship with pointers

Know how to use new to dynamically allocate


memory space

46

Вам также может понравиться