Chapter - Pointers
Chapter - Pointers
POINTERS
Tsigabu T.
Lecturer
Computer Engineering chair
School of Electrical and Computer Engineering
Ethiopian Institute of Technology- Mekelle (EiT-M)
Mekelle
1 University,
Mekelle, Ethiopia
Lecture #1
INTRODUCTION
When you declare a variable, the computer associates the variable
name with a particular location in memory and stores a value there.
When you refer to the variable by name in your code, the
computer must take two steps:
1. Look up the address that the variable name corresponds to
2. Go to that location in memory and retrieve or set the value it contains
C++ allows us to perform either one of these steps independently
on a variable with the & and * operators:
1. &x evaluates to the address of x in memory.
2. *( &x ) takes the address of x and dereferences it – it
retrieves the value at that location in memory. *( &x ) thus
evaluates to the same thing as x.
Pointers are an important feature of C++ (and C), while many other
languages, such as Visual Basic and Java, have no pointers at all.2
5
What Are Pointers?
p = &f; // ERROR
#include <iostream>
using namespace std;
int main()
{ int var1 = 11; //two integer variables
int var2 = 22;
cout << &var1 << endl //print addresses of variables
<< &var2 << endl << endl;
int* ptr; //pointer to integers
ptr = &var1; //pointer points to var1
cout << ptr << endl; //print pointer value
ptr = &var2; //pointer points to var2
cout << ptr << endl; //print pointer value 8
return 0; }
IN THIS PROGRAM
It defines two integer variables, var1 and var2, and
initializes them to the values 11 and 22.
It then prints out their addresses.
9
The Pointer Operators
There are two special operators that are used with pointers: *
and &.
1. The Address-of Operator &
You can find the address occupied by a variable by using the address-
of operator &
It is a unary operator that returns the memory address of its
operand. (Recall that a unary operator requires only one
operand.)
For example, balptr = &balance; puts into balptr the memory
address of the variable balance.
This address is the location of the variable in the computer’s
internal memory. It has nothing to do with the value of balance.
The operation of & can be remembered as returning "the
address of" the variable it precedes. Therefore, the above
assignment statement could be verbalized as "balptr receives
the address of balance.“
10
assume that the variable balance is located at address 100.
Then, after the assignment takes place, balptr has the value
100.
THE ADDRESS-OF OPERATOR &- EXAMPLE
#include <iostream>
using namespace std;
int main()
{
int var1 = 11; //define and initialize
int var2 = 22; //three variables
int var3 = 33;
cout << &var1 << endl //print the addresses
<< &var2 << endl //of these variables
<< &var3 << endl;
return 0;
}
This simple program defines three integer variables and initializes them to the
values 11, 22, and 33. It then prints out the addresses of these variables. 11
2. The "at address or dereference" operator (*) - value
pointed to by
It is the complement of &.
Tsigabu T.
Lecturer
Computer Engineering chair
School of Electrical and Computer Engineering
Ethiopian Institute of Technology- Mekelle (EiT-M)
Mekelle
15 University,
Mekelle, Ethiopia
Lecture #2
ASSIGNING VALUES THROUGH A POINTER
int main ()
{
int numbers[5];
int * p;
p = numbers; *p = 10;
p++; *p = 20;
p = &numbers[2]; *p = 30;
p = numbers + 3; *p = 40;
p = numbers; *(p+4) = 50;
for (int n=0; n<5; n++)
cout << numbers[n] << ", ";
return 0;
}
The following program demonstrates assignment
using a pointer.
#include <iostream>
using namespace std;
int main()
{
int *p, num;
p = #
*p = 100;
cout << num << ' ';
(*p)++;
cout << num << ' ';
(*p)--;
cout << num << '\n';
return 0; 18
}
EXAMPLE
// This program demonstrates the use of the indirection
// operator.
#include <iostream.h>
void main(void)
{
int x = 25;
int *ptr;
}
POINTER ARITHMETIC
Some mathematical operations may be performed on
pointers.
The ++ and -- operators may be used to increment or decrement
a pointer variable.
An integer may be added to or subtracted from a pointer
variable. This may be performed with the +, - +=, or -=
operators.
A pointer may be subtracted from another pointer.
There are only four arithmetic operators that can be used
on pointers: ++, – –, +, and –.
To understand what occurs in pointer arithmetic, let p1 be
an integer pointer with a current value of 2,000 (that is, it
contains the address 2,000). Assuming 32-bit integers,
after the expression p1++; the contents of p1 will be 2,004,
not 2,001! Each time p1 is incremented, it will point to the
next integer.
The same is true of decrements. For example, p1--; will
cause p1 to have the value 1,996, assuming that it 21
previously was 2,000.
You are not limited to only increment and decrement operations. You can also add or
subtract integers to or from pointers.
The expression p1 = p1 + 9; makes p1 point to the ninth element of p1’s base
type, beyond the one to which it is currently pointing.
While you cannot add pointers, you can subtract one pointer from another (provided
they are both of the same base type). The remainder will be the number of elements of the
base type that separate the two pointers.
Other than addition and subtraction of a pointer and an integer, or the subtraction of two
pointers, no other arithmetic operations can be performed on pointers. For example, you
cannot add or subtract float or double values to or from pointers.
When fundamental data types were introduced, we saw that types have different sizes.
For example: char always has a size of 1 byte, bool is one byte, and int two bytes and float
are even larger (four bytes); the exact size of these being dependent on the system.
For example, let's imagine that in a given system, char takes 1 byte, short takes 2 bytes,
and long takes 4.
Suppose now that we define three pointers in this compiler:
char *mychar;
short *myshort;
long *mylong;
and that we know that they point to the memory locations 1000, 2000, and 3000,
respectively.
Therefore, if we write:
++mychar;
++myshort;
++mylong; 22
// This program uses a pointer to display the
contents
// of an integer array.
#include <iostream.h>
void main(void)
{
int set[8] = {5, 10, 15, 20, 25, 30, 35, 40};
int *nums, index;
nums = set;
cout << "The numbers in set are:\n";
for (index = 0; index < 8; index++)
{
cout << *nums << " ";
nums++;
}
cout << "\nThe numbers in set backwards are:\n";
for (index = 0; index < 8; index++)
{
nums--;
cout << *nums << " ";
}
} 24
EXAMPLE
// Demonstrate pointer arithmetic.
#include <iostream>
using namespace std;
int main()
{
int *i, j[10];
double *f, g[10];
int x;
i = j;
f = g;
for(x=0; x<10; x++)
cout << i+x << ' ' << f+x << '\n';
return 0; 25
}
POINTER INITIALIZATION
Pointers can be initialized to point to specific locations
at the very moment they are defined:
int myvar;
int * myptr = &myvar;
Pointers can be initialized either to the address of a
variable (such as in the case above), or to the value of
another pointer (or array):
int myvar;
int *foo = &myvar;
int *bar = foo;
VOID POINTERS
The void type of pointer is a special type of pointer. In C++,
void represents the absence of type.
Therefore, void pointers are pointers that point to a value
that has no type (and thus also an undetermined length
and undetermined dereferencing properties).
This gives void pointers a great flexibility, by being able to
point to any data type, from an integer value or a float to a
string of characters.
In exchange, they have a great limitation: the data pointed
by them cannot be directly dereferenced (which is logical,
since we have no type to dereference to), and for that
reason, any address in a void pointer needs to be
transformed into some other pointer type that points to a
concrete data type before being dereferenced.
// ptrvoid.cpp
// pointers to type void
#include <iostream>
using namespace std;
int main()
{
int intvar; //integer variable
float flovar; //float variable
int* ptrint; //define pointer to int
float* ptrflo; //define pointer to float
void* ptrvoid; //define pointer to void
ptrint = &intvar; //ok, int* to int*
// ptrint = &flovar; //error, float* to int*
// ptrflo = &intvar; //error, int* to float*
ptrflo = &flovar; //ok, float* to float*
ptrvoid = &intvar; //ok, int* to void*
ptrvoid = &flovar; //ok, float* to void*
return 0;
28
}
POINTERS AND ARRAYS
The name of an array is actually a pointer to the first
element in the array. Writing myArray[3] tells the compiler
to return the element that is 3 away from the starting
element of myArray.
To begin, consider this fragment:
char str[80];
char *p1;
p1 = str;
Here, str is an array of 80 characters and p1 is a character pointer.
Thus the assignment p1 = str assigns the address of str[0] to p1.
When an unindexed array name is used in an expression, it yields
a pointer to the first element in the array.
#include <iostream>
Using namespace std;
int main()
{
short numbers[] = {10, 20, 30, 40, 50};
29
cout << "The first element of the array is ";
cout << *numbers << endl;
}
For example, consider these two declarations:
int myarray [20];
int * mypointer;
The following assignment operation would be valid:
mypointer = myarray;
But, the following assignment would not be valid:
myarray = mypointer;
The main difference being that mypointer can be
assigned a different address, whereas myarray can never
be assigned anything, and will always represent the
same block of 20 elements of type int.
For example, if you want to access the fifth element in
str, you could use: str[4] or *(p1+4)
In effect, C++ allows two methods of accessing array
elements: pointer arithmetic and array indexing.
This is important because pointer arithmetic can
sometimes be faster than array indexing 30
POINTER CONSTANTS AND POINTER VARIABLES
I. POINTER CONSTANTS
#include <iostream>
using namespace std;
int main()
{ //array
int intarray[5] = { 31, 54, 77, 52, 93 };
for(int j=0; j<5; j++) //for each element,
cout << *(intarray+j) << endl; //print value
return 0;
}
Could you write *(intarray++)?
Ans: No, because it is pointer Constant. 31
II. POINTER VARIABLE
#include <iostream>
using namespace std;
int main()
{
int intarray[] = { 31, 54, 77, 52, 93 }; //array
int* ptrint; //pointer to int
ptrint = intarray; //points to intarray
for(int j=0; j<5; j++) //for each element,
cout << *(ptrint++) << endl; //print value
return 0;
}
But, because ptrint is a variable and not a constant, it 32
can be incremented.
EXAMPLE
// This program processes the contents of an array.
// Pointer notation is used.
#include <iostream.h>
void main(void)
{
int numbers[5];
char a;
char * b;
char ** c;
a = 'z';
b = &a;
c = &b;
This, assuming the randomly chosen memory locations for each
variable of 7230, 8092, and 10502, could be represented as:
The new thing in this example is variable c,
which is a pointer to a pointer, and can be used in
three different levels of indirection, each one of
them would correspond to a different value:
c is of type char** and a value of 8092
*c is of type char* and a value of 7230
**c is of type char and a value of 'z'
ECEG-: INTRODUCTION TO COMPUTING
POINTERS
Tsigabu T.
Lecturer
Computer Engineering chair
School of Electrical and Computer Engineering
Ethiopian Institute of Technology- Mekelle (EiT-M)
Mekelle
36 University,
Mekelle, Ethiopia
Lecture #3
DYNAMIC MEMORY
In the programs seen in previous chapters, all memory
needs were determined before program execution by
defining the variables needed.
But there may be cases where the memory needs of a
program can only be determined during runtime. For
example, when the memory needed depends on user
input. That is, Variables may be created and destroyed
while a program is running.
On these cases, programs need to dynamically allocate
memory, for which the C++ language integrates the
operators new and delete.
That is,Use the new operator to dynamically allocate
memory, and Use delete to dynamically deallocate
memory.
OPERATORS NEW AND NEW[]
This versatile operator obtains memory from the operating system and
returns a pointer to its starting point. Dynamic memory is allocated
using operator new.
new is followed by a data type specifier and, if a sequence of
more than one element is required, the number of these within
brackets [].
Its syntax is:
pointer = new type
pointer = new type [number_of_elements]
The first expression is used to allocate memory to contain one single
element of type type. The second one is used to allocate a block (an
array) of elements of type type, where number_of_elements is an
integer value representing the amount of these.
For example:
int * foo;
foo = new int [5];
In this case, the system dynamically allocates space for five elements of
type int and returns a pointer to the first element of the sequence,
which is assigned to foo (a pointer). Therefore, foo now points to a valid
block of memory with space for five elements of type int.
#include <iostream>
#include <cstring> //for strlen
using namespace std;
int main()
{
char* str = “Idle hands are the devil’s workshop.”;
int len = strlen(str); //get length of str
char* ptr; //make a pointer to char
ptr = new char[len+1]; //set aside memory: string + ‘\0’
strcpy(ptr, str); //copy str to new memory area ptr
cout << “ptr=” << ptr << endl; //show that ptr is now in
str
delete[] ptr; //release ptr’s memory
return 0;
}
OPERATORS DELETE AND DELETE[]
In most cases, memory allocated dynamically is only needed during
specific periods of time within a program; once it is no longer
needed, it can be freed so that the memory becomes available again
for other requests of dynamic memory.
To ensure safe and efficient use of memory, the new operator is
matched by a corresponding delete operator that returns memory to
the operating system.
This is the purpose of operator delete, whose syntax is:
delete pointer;
delete[] pointer;
the statement delete[] ptr; returns to the system whatever
memory was pointed to by ptr.
The first statement releases the memory of a single element
allocated using new, and the second one releases the memory
allocated for arrays of elements using new and a size in brackets
([]).
The value passed as argument to delete shall be either a pointer to
a memory block previously allocated with new, or a null pointer (in
the case of a null pointer, delete produces no effect).
#include <iostream>
using namespace std;
int main()
{
float *sales, total = 0, average;
int numDays;
cout << "How many days of sales figures do you wish to process?";
cin >> numDays;
sales = new float[numDays]; // Allocate memory
if (sales == NULL) // Test for null pointer
{
cout << "Error allocating memory!\n";
return 1;
} // Get the sales figures from the user
cout << "Enter the sales figures below.\n";
for (int count = 0; count < numDays; count++)
{
cout << "Day " << (count + 1) << ": ";
cin >> sales[count];
} // Calculate the total sales
for (int count = 0; count < numDays; count++)
{
total += sales[count];
}
cout << "\n\nTotal sales: $" << total << endl;
average = total/numDays;
cout << "average sales: $" << average << endl;
delete [] sales; // Free dynamically allocated memory
return 0; 42
}
THE END
43