&
(address-of operator), *
(dereferencing operator)
new
operator
new
— to dynamically allocated storage: this is the only real reason to use pointers in C++
*
and ->
syntactic 'vinegar'
int i = 12;
int *ip = &i;
float *fp = ip; // illegal — fp would appear to be pointing at an 8-byte float, but is really pointing to a 4-byte integer
cout << *fp;; // and print it out produces garbage; perfoming computations with its values is even worse - GIGO
*
int *ip; // pointer to int double *dp; // pointer to double string *sp; // pointer to string
[]
(since the primary manipulation of an array is
subscripting, i.e., the []
operator
()
(e.g., void f(int);
) since the primary use of functions
are to call them (again using ()
's around the arguments).
int
,
pointer to string
, pointer to Donor
, pointer to pointer to int
.
*
) operator
int *ip
, the expression ip
represents the value contained within ip's storage location
int
(i.e., *int
.
*ip
(in which the *
is the operator, and ip
is the operand) represents the
value obtained by retrieving the data in the location pointed at by ip
*ip
is int
*
operator, strips off a pointer from the resulting type
&
) Operator
ip
and the array a
, you would write ip = a
&
operator returns the address of a storage location; the operands is most typically either the name of
a variable (e.g., &total
) or an element of an array (e.g., &a[i]
).
int total
(whose type is , of course int
), the type of the expression
&total
is pointer to int
(i.e., *int
).
&
operators adds a level of pointer to the resulting type.
->
Operator
Employee *ep
— to access a member function — say f
— (or data member)
of the object pointer at by ep
, one would have to write
(*ep).f();the paren's are a consequence of the precedence of the
*
and .
operators.
->
operator
ep->f()that has the identical semantics (meaning)
*
and &
are inverses of each other and cancel each other out: *&x
is the same as x
.
ip
point at (i.e., contain the address of) an integer variable will allow us
to access that variable through ip
. Changing the value of ip
to point at another integer
variable permits us to manipulate THAT variable using the same pointer. This provides great flexibility, as
we will see when we discuss dynamic memory allocation.
int *ip
ip + 1
be?
ip + 1
make sense? ip -1
?
T *p
, p
is incremented by the specified increment multiplied (scaled) by the size of the type (T
)
being pointed to.
char *cp
: cp + 1
-> add 1 byte to cp
int *ip
: ip + 1
-> add 4 bytes to ip
double *dp
:dp + 1
-> add 8 bytes to dp
pointer + integer
— moves pointer upwards by (scaled) value of integer
ip + 1
, ip += 1
, ip++
pointer - integer
— moves pointer downwards by (scaled) value of integer
ip - 1
, ip -= 1
, ip--
ip1 == ip2
ip1 != ip2
pointer - pointer
— determines (scaled) distance between pointers
ip1 - ip2
<
, <=
, etc
ip1 < ip2
— ip1
has a lower address in memory than ip2
int arr[10];
int nums[10]; double averages[14]; string names[100];
int a[5] = {1, 2, 3, 4, 5}; int b[] = {1, 2, 3};
int a[10];
a
(i.e., the name of the array) is viewed as a pointer to the first element of the array
a[i]
refers to the elements i
elements from the beginning of the array.
a[i]
≡ *(a + i)
bool contains(int arr[], int n, int val);
bool contains(int *arr, int n, int val);
bool contains(int arr[], int n, int val);
bool contains(int arr[], int n, int val) { for (int i = 0; i < n; i++) if (arr[i] == val) return true; return false; }
int a[10], *ip;what does
ip = &a[0]
mean?
ip = &a[0]; for (i = 0; i < n; i++) { cout << *ip; ip++; }
ip
at the beginning of the array; the loop then prints the contents of the location pointed at by
ip
, and then moves ip
to the next element. This is done n times (once for each element of the array)
for (i = 0; i < n; i++) cout << *(a+i);
i
elements away from the beginning
of the array is printed
int *ip;
ip
int a[10]
a
a
a points to the first element
a
(no Lvalue).
a
is not a pointer variable but rather a fixed name for the location of the first element
int a[] = {1, 2, 3, 4};you are providing initial values to the elements of the array; you are not assigning an array to
a
int *ip, a[10]all of the following are legal:
a[5]
a[20]
a[-1]
5[a]
ip[5]
ip+1
a+4
a-1
*(a+2)
*(ip+1)
int a[10]i.e.,
a
is an array of 10 elements, what is a+1
?
void print(int a[], int n) { if (n == 0) return; cout << a[0] << ' '; print(a+1, n-1);
sizeof
Operatorcout << sizeof(int);
sizeof
can be a type, variable, or expression.
sizeof
was more hevily used in C, where dynamic allocation of memory was a function whose argument was the number of bytes to allocate
new
takes care of that calculation, using the type that is specified
sizeof
for an array returns the number of bytes allocated to the array
sizeof
produces the number of bytes a pointer takes up on the machine.
new
Operatornew
operator, which accepts a type (and the number of elements
if an array is being allocated), and returns a pointer to the newly allocated storage:
int *ip; ip = new int; // Allocates space for a new integer and returns the address double *dp = new double[100]; // Allocates space for 100 doubles and returns the address of the first
new
).
delete
Operatornew
operator is completely under the programmer's control,; and thus it is up to the
programmer to decide when the memory should be freed.
delete
operator which accepts a pointer to the memory to be freed:
delete ip; delete [] dp;
[]
notation as seen above for dp
,
a corresponding notation should be used when using the delete
operator on that memory.
int *arr;
new
operator:
int n; cin >> n; arr = new int[n];
int x = 12; int *ip = &x; // *ip is now an alias of x
arr
pointer to point to a different area of storage; leaving us with no way to get
to the old area. This was not a problem in itself, because we had copied the information out of it, but it meant that we now had memory
that we could no longer use, nor get to. This situation is called a memory leak and the memory itself (which is
now useless since it can't be reached) is called garbage.
int *ip = new int[10]; ... delete [] ip; ... ip[3] = 1; // uh, oh... ip's storage was freed; we have no business using ip
new
).
nullptr
, NULL
NULL
(obtained via a #include
of cstdlib
) is a value that can be assigned to
any pointer and represents an invalid pointer.
NULL
to determine whether to 'follow' the pointer.
NULL
is actually defined as being 0
; there is a difference of opinion whether to use NULL
or 0
.
nullptr
keyword to be used in place of NULL
&
, and are initialized by supplying the original name for the object.
int i = 12; int &ir = i;
ir++; // Adds 1 to i
new
during runtime, when additional memory is needed.
// checkCapacity accepts an array pointer, and a size and capacity; if necessary, it resizes the array void checkCapacity(int *&arr, int size, int &capacity) { if (size == capacity) { // full, need to grow/reallocate capacity *= 2; int *tmp = new int[capacity]; for (int i = 0; i < size; i++) tmp[i] = arr[i]; delete [] arr; arr = tmp; } }
arr
parm — it's declared as a reference since the pointer may change
(if the array needs to be resized).
vector
).
class vector { public: vector(int capacity=100) : capacity(capacity), size(0), arr(new int[capacity]) {} … private: void checkCapacity() { if (size == capacity) { // full, need to grow/reallocate capacity *= 2; int *tmp = new int[capacity]; for (int i = 0; i < size; i++) tmp[i] = arr[i]; delete [] arr; arr = tmp; } } int *arr; int size, capacity; };