Pointers
Dec 22, 2015
Pointers
Why pointers? - low-level, but efficient manipulation of memory
- dynamic objects
Objects whose memory is allocated during program execution. (Dynamic objects can survive after the function ends in which they were allocated).
Dynamic objects allow flexible-sized arrays and lists
Pointers A pointer is a variable used for storing the
address of a memory cell. We can use the pointer to reference this
memory cell, so to ‘manipulate’ it!
100100…… …… 10241024 ……Memory address: 1024 10032
……1020
Integer a Pointer p
Object whose value represents the location (memory address) of another object
int a;
int* p;
Getting an address: address operator &
int a=100; “&a” “the address of a”
100100…… …… …… ……Memory address: 1024
int a = 100;
cout << a; 100
Cout << &a; 1024
……1020
a
Define a pointer type variable: T*
Examples of (uninitialized) pointers
int* ip; char* s;
int *ip; // ip is a pointer to an int
char *s; // s is a pointer to a char
TypeName *variablename; int *p;
Each type of object (variable) has a pointer type, therefore a pointer variable of that type.
TypeName* variablename; int* p;
equivalent
Store the address in a pointer variable
The value of pointer p is the address of variable a
1001008888 …… 10241024 ……Memory address: 1024 10032
……1020
a p
int a = 100;
int* p = &a;
cout << a << " " << &a <<endl;
cout << p << " " << &p <<endl;
Result is:
100 1024
1024 10032
p is pointing to a
A pointer is also a variable, so it has its own memory address
Dereferencing Operator * We can access to the value stored in the variable
pointed to by preceding the pointer with the “star” operator (*),
1001008888 …… 10241024 ……Memory address: 1024 10032
……1020
int a = 100;
int* p = &a;
cout << a << endl;
cout << &a << endl;
cout << p << " " << *p << endl;
cout << &p << endl;
a p
*p gives 100
An asterisk (‘*’) has two usages
In a definition, an asterisk indicates that the object is a pointer.
char* s; // s is of type pointer to char
(char *s; is possible)
In expressions, an asterisk before a pointer indicates the object the pointer pointed to, called dereferencing
int i = 1, j;
int* ptr; // ptr is an int pointer
ptr = &i; // ptr points to i
j = *ptr + 1; // j is assigned 2
cout << *ptr << j << endl; // display "12"
Summary on two operators * and &
* has two usages:
- pointer
- dereferencing
& has two usages:
- getting address
- reference (‘call by ref’, see later)
Null Address
0 is a pointer constant that represents the empty or null address Indicates that pointer is not pointing to storage of a
valid object Cannot dereference a pointer whose value is null
int* ptr;
ptr = 0;
cout << *ptr << endl; // invalid, ptr
// does not point to
// a valid int
Example#include <iostream> using namespace std;int main (){
int value1 = 5, value2 = 15; int* p1;int* p2; p1 = &value1; // p1 = address of value1p2 = &value2; // p2 = address of value2 *p1 = 10; // value pointed to by p1=10 *p2 = *p1; // value pointed to by p2= value // pointed to by p1 p1 = p2; // p1 = p2 (pointer value copied) *p1 = 20; // value pointed to by p1 = 20 cout << "value1==" << value1 << "/ value2==" << value2; return 0;
}
Result:
Value1 is 10
Value2 is 20
Another Pointer Exampleint a = 3;char s = ‘z’;double d = 1.03;int* pa = &a;char* ps = &s;double* pd = &d;cout << sizeof(pa) << sizeof(*pa) << sizeof(&pa) << endl;cout << sizeof(ps) << sizeof(*ps) << sizeof(&ps) << endl;cout << sizeof(pd) << sizeof(*pd)
<< sizeof(&pd) << endl;
Writing pointer type properly in C++ …
int *a, *b;
a, b are both integer pointers
int* a, b;
a is integer pointer, b is just integer!
typedef int* IntPt;
IntPt a, b;
typedef int MyInt;
MyInt k;int k;
int* a;
int* b;?
Recommended:
Traditional Pointer Usagevoid swap(char* ptr1, char* ptr2){
char temp = *ptr1;*ptr1 = *ptr2;*ptr2 = temp;
}int main() {
char a = 'y';char b = 'n';swap(&a, &b);cout << a << b << endl;return 0;
}
Use pass-by-value of pointers to ‘change’ variable values
C language does not have ‘call by reference’, only ‘call by value’!
Reference: T&
int& b a; b is an alternative name for a
void f(int& b) {};
int main() {
int a;
f(a);
}
Pass by reference (better than ‘pointers’)
void swap(char& y, char& z) {char temp = y;y = z;z = temp;
}int main() {
char a = 'y';char b = 'n';swap(a, b);cout << a << b << endl;return 0;
}
y, z are ‘references’, only names, not like ptr1, ptr2 that are variables
Pointer to ‘Struct’struct Date {…};
Date d={1,10,2009};
Date* pd = &d;
(*pd).day=2;
(*pd).month=11;
Or
pd->day=2;
pd->month=11;
Pointers and arrays
Arrays are pointers!
The name of an array points only to the first element not the whole array.
1000
1012
1016
1004
1008
#include <iostream>Using namespace std;
void main (){// Demonstrate array name is a pointer constantint a[5];cout << "Address of a[0]: " << &a[0] << endl << "Name as pointer: " << a << endl;
}
/* result:Address of a[0]: 0x0065FDE4Name as pointer: 0x0065FDE4*/
Array name is a pointer constant
Result is:
2
2
2
#include <iostream>
Using namespace std;
void main(){
int a[5] = {2,4,6,8,22};
cout << *a << " "
<< a[0] << " "
<< *(&a[0]);
..."
} //main
2
4
8
6
22a[4]
a[0]
a[2]
a[1]
a[3]
Dereference of an array name
This element is called a[0] or *a
To access an array, any pointer to the first element can be used instead of the name of the array.
We could replace *p by *a
#include <iostream>
Using namespace std;
void main(){
int a[5] = {2,4,6,8,22};
int* p = a;
int i = 0;
cout << a[i] << " "
<< *p;
...
}
2
4
8
6
22a[4]
a[0]
a[2]a[1]
a[3]
a p
a
Array name as pointer
2
2
Multiple Array PointersBoth a and p are pointers to the same array.
2 2
4 4
#include <iostream>
Using namespace std;
void main(){
int a[5] = {2,4,6,8,22};
int* p = &a[1];
cout << a[0] << " "
<< p[-1];
cout << a[1] << " "
<< p[0];
...
}
2
4
8
6
22a[4]
a[0]
a[2]
a[1]
a[3]
p
P[0]
A[0]
Pointer ArithmeticGiven a pointer p, p+n refers to the element that is
offset from p by n positions.
2
4
8
6
22
a
a + 2
a + 4
a + 3
a + 1 p
p + 2
p + 3
p - 1
p + 1
*(a+n) is identical to a[n]
Dereferencing Array Pointers
a[3] or *(a + 3)
24
86
22
a
a + 2
a + 4a + 3
a + 1a[2] or *(a + 2)a[1] or *(a + 1)
a[0] or *(a + 0)
a[4] or *(a + 4)
Summary * two usages:
- pointer type definition: int a;
int* p;
- dereferencing: *p is an integer variable if
p = &a;
& two usages:
- getting address: p = &a;
- reference: int& b a;
b is an alternative name for a
First application in passing parameters (‘swap’ example)
int a=10;
int b=100;
int* p;
int* q;
p=&a;
q=&b;
p = q;
*p = *q;
?
?
a[n]: like a vector, an array
a+n*(a+n): like a ‘sequence’ or a ‘list’
Two ways of manipulating an array
‘a’ points to the first element
Dynamic Objects
Memory Management
Static Memory Allocation Memory is allocated at compiling time
Dynamic Memory Memory is allocated at running time
{ int a[200]; …}
{ int n; cin >> n; a[n]???}
Static vs. Dynamic Objects
Static object Memory is acquired
automatically Memory is returned
automatically when object goes out of scope
Dynamic object Memory is acquired by
program with an allocation request
new operation Dynamic objects can
exist beyond the function in which they were allocated
Object memory is returned by a deallocation request
delete operation
Creating a variable (object): new TSyntax
ptr = new SomeType;
where ptr is a pointer of type SomeType
p
Uninitialized int variable
Example
int* p = new int;
‘new’ does two things:
1. Create a variable of given type
2. Point the pointer p to the variable
Destructing a variable (object): delete p
Syntaxdelete p;
storage pointed to by p is returned to free store and p is now undefined
Exampleint* p = new int;
*p = 10;
delete p;
p 10
‘delete’ does two things:
1. Return the pointed object to the system
2. Point the pointer p to NULL
Dynamic Arrays (a collection of variables)
Syntax for allocation: p = new SomeType[Expression];
Where p is a pointer of type SomeType Expression is the number of objects to be constructed -- we
are making an array
Syntax for de-allocation: delete[] p;
Because of the flexible pointer syntax, p can be considered to be an array
p = new T[size]; delete[] p;
ExampleDynamic Memory Allocation
Request for “unnamed” memory from the Operating System
int* p, n=10;
p = new int;
p = new int[100];
p
p
p = new int[n]; p
Freeing (or deleting) Memory
Allocation ExampleNeed an array of unknown sizemain(){ int n; cout << “How many students? “; cin >> n;
int* grades = new int[n];
for(int i=0; i < n; i++){ int mark; cout << “Input Grade for Student” << (i+1) << “ ? :”; cin >> mark; grades[i] = mark; }
. . . printMean( grades, n ); // call a function with dynamic array . . . }
int grades[n];
Dangling Pointer Problem
int* A = new int[5];
for(int i=0; i<5; i++)
A[i] = i;
int* B = A;
delete[] A;
B[0] = 1; // illegal!
A
B0 1 2 3 4
A
B
Locations do not belong to program
—
?
Memory Leak Problemint* A = new int[5];
for(int i=0; i<5; i++)
A[i] = i;
A = new int[5];
A 0 1 2 3 4
— — — — —
These locations cannot be
accessed by program
A 0 1 2 3 42
Static variables (objects) Dynamic variables (objects)
A (direct) named memory location A static part (pointer) + (indirect) nameless memory location
(dynamic part)int a;
a = 20;int* pa;
pa = new int;
*pa = 20;
20a 20pa
static static dynamic
Summary
int* p = new int;
*p = 10;
delete p;
p 10 p 10
int* p = new int[100];
for (i=1;i<100,i++)
p[i] = 10;
delete[] p;
Simple dynamic variable Dynamic array
‘delete p’ is not sufficient
for an array!!!
‘delete’ two actions:
1. Return the object pointed to
2. Point the pointer p to NULL
10 10
Good practice
Logically, Initialize a pointer with NULL Always check a pointer before usage
if (p != NULL) *p
n=100;
int* p = new int[n];
N=150;
P[130]???
Bad examples
{ int n; cin >> n; a[n]???}
It’s possible, but not standard,
Do:
int* a = new int[n];
No! the array stays with the size 100.
More pointers
Pointers to pointers
Pointer to pointer: T**
int a;
int* p;
int** q;
a = 58;
p = &a;
q = &p;
a p q
58
a, *p, and **q are the same object whose value is 58!
But q = &a is illegal!
Pointer to pointers and 2D arrays
Pointer of pointers & 2D Arrays
table[0] or *( table + 0 )
table[1] or *( table + 1 )
table[2] or *( table + 2 )
int table[3][4];for(int i=0; i<3; i++){
for(int j=0; j<4; j++)cout << *(*(table+i) +j);
cout << endl;}
table[i][j]What is **table ?
table + 2
table
table + 1
table and table[0] are of the same address
int table[2][2] = {{0,1}, {2,3}};
cout << table << endl; cout << *table << endl; //same as above cout << table[0] << endl; // same as above
cout << *table[0] << endl; cout << table[0][0] << endl; // same as above cout << **table << end; // same as above
0xffbff9380xffbff9380xffbff938
000
Array of Pointers & Pointer to Arraya
b
c
An array of Pointers
p
int a = 1, b = 2, c = 3;int* p[5];p[0] = &a;p[1] = &b;p[2] = &c;
int list[5] = {9, 8, 7, 6, 5};int* p;p = list;//points to 1st entryp = &list[0];//points to 1st entryp = &list[1];//points to 2nd entryp = list + 1; //points to 2nd entry
A pointer to an array
A Dynamic Table A dynamic table is
an array of pointers to save space when not all rows of the array are full.
int** table;
table = new int*[6];
table[0] = new int[4];table[1] = new int[7];table[2] = new int[1];table[3] = new int[3];table[4] = new int[2];table[5] = NULL;
table[0]table[1]table[2]table[3]table[4]table[5]
table
table[0][0] = 32; table[0][1] = 18;
…
32 18 2412
42 141912161113
1811
13 1413
22
table[0]table[1]table[2]table[3]table[4]table[5]
table
*(*(table+i)+j)
is
table[i][j]
int m, n;
cin >> m >> n >> endl;
int** mat;
mat = new int*[m];
for (int i=0;i<m;i++)
mat[i] = new int[n];
Create a matrix of any dimensions, m by n:
int main() {
int m, n;
cin >> m >> n >> endl;
int** matrix;
matrix = imatrix(m,n);
…
}
int** imatrix(int m, int n) {
int** mat;
mat = new int*[m];
for (int i=0;i<n;i++)
mat[i] = new int[n];
return mat;
}
Put it into a function:Ideas:
Each row must be deleted individually Be careful to delete each row before deleting the table
pointer.
Dynamic matrix deallocation
void deleteImatrix(int** mat,
int m,
int n) {
for(int i=0; i<m; i++)
delete[] mat[i];
delete[] mat;
}
for(int i=0; i<6; i++)
delete[] mat[i];
delete[] mat;
‘argc’ is the actual number of arguments ‘argv’ is an array of char*, each pointing to a character
int main() int main(int argc, char* argv[])
E.g. a.out 20 30 int main(int argc, char* argv[]) {
if (argc != 3) { troubles!!!}
int rows = atoi(argv[1]);
int col = atoi(argv[2]);
}
Examples: main() arguments
Constantness: object or pointer?
(const) object (*const) pointer
‘const’ only modifies a type const T* p constant T, so constant object, const
*p ‘const’ only modifies a type as it might be one of them:
const T* p const T *p
T *const p constant pointer const T *const p = constant pointer to constant
object (both pointer AND object are constants!) No ‘const*’ operator.
Example:
57
A constant object with ‘const’: const int* p;
A constant pointer with ‘*const’: int *const p;
A constant object AND pointer is: const int *const p;
‘const object’ and ‘constant pointer’
Pointer to const object: the content is const, pointer is free int x=10, y=20; const int* pc = &x; pc = &y // OK *pc = 5; // wrong!
Const pointer: the pointer is const, content is free int x=10, y=20; Int *const cp = &x; *cp = 5; // OK cp = &y; // wrong!
int const *pc
59
void f1(const int** bar){
bar[1][1] = 5; // wrong: change int bar[1] = new int[3]; // ok
}
void f2(int *const *bar){
bar[1][1] = 5; // ok bar[1] = new int[3]; // wrong: change int* bar = new int*[3]; // ok
}
void f3(int **const bar) { bar[1][1] = 5; // ok bar[1]= new int[3]; // ok bar = new int*[3]; // wrong: change int**}
int main(){ int** iptr; int i, j;
iptr = new int*[10]; for( i = 0; i < 10; i++ ) iptr[i] = new int[10]; for( i = 0; i < 10; i++ ) for( j = 0; i < 10; i++ ) iptr[i][j] = i*j;
f1(iptr); f2(iptr); f3(iptr);}
Bad: const int ** bar
Bad: int * const * bar
Because of ambiguous ‘const int** b’ and ‘const int **b’,
so it is ‘const int’!
Writing properly matters!!!
More examples …
60
int main(){
int i = 3, j = 10; int* ip = &i; *ip = 4; const int* ipc = ip; *ip = 5; // *ipc is now 5
ip = &j; int *const *ipp1 = &ip; // ok const int* const *ipp2 = &ip; // ok
const int** ipp3 = &ipc; // ok
ipp3 = &ip; // wrong: changing ipp3 // indirectly/inadvertently changes **ipp const int** ipp4 = &ip; // wrong: same reason as above, because if allowed ipp4 //could be changed later
return 0;}
Pointer to function
Function pointers
A running program and functions get a certain space in the main memory To store the executable comiled codes and variables
A function name is an address pointing to the execution codes of the function When the function is called, the codes and variables are loaded to
the call stack A function pointer is a pointer, which points to the address
of the function A function pointer can be passed as a parameter to a
function
int const *pc
#include <iostream>using namespace std;
// put a and b in ascending ordervoid ascending( double& a, double& b ){ if( a > b ){ double tmp = a; a = b; b = tmp; } return;}
// put a and b in descending ordervoid descending( double & a, double & b ){ if( a < b ){ double tmp = a; a = b; b = tmp; } return;}
// function pointervoid order( void (*criteria)(double &, double &), double & a, double & b) { (*criteria)(a, b); // same as criteria(a,b); return;}
int main(){ double x = 0.7; double y = 0.5; order( ascending, x, y ); cout << x << " " << y << endl;
order( descending, x, y ); cout << x << " " << y << endl;
return 1;}
0.5 0.70.7 0.5
Output: