0% found this document useful (0 votes)
15 views54 pages

Chapter 07 Pointers

Chapter Seven of 'Fundamentals of Programming' focuses on pointers, explaining their declaration, usage, and operations in C++. It covers concepts such as the address and dereference operators, pointer arithmetic, and pointers to functions and void pointers. The chapter includes practical examples to illustrate how pointers interact with variables and arrays.

Uploaded by

Ermias Dejene
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)
15 views54 pages

Chapter 07 Pointers

Chapter Seven of 'Fundamentals of Programming' focuses on pointers, explaining their declaration, usage, and operations in C++. It covers concepts such as the address and dereference operators, pointer arithmetic, and pointers to functions and void pointers. The chapter includes practical examples to illustrate how pointers interact with variables and arrays.

Uploaded by

Ermias Dejene
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/ 54

Fundamentals of Programming

[CoEng1112]

Chapter Seven:
Pointers
Introduction
• A pointer is a variable that holds a memory
address, usually the location of another
variable in a memory.
7.1 Declaring variables of type pointer
• Anything (data or instruction) that needs to be
processed must be loaded into internal memory
before its processing takes place. Therefore,
every data and instruction that is being executed
must be allocated some area in the main
(internal) memory.
• Variables are stored in concrete places of the
computer memory.
• The computer memory is only a succession of 1
byte cells (the minimum size for a datum), each
one with a unique address.
Cont’d
Address (dereference) operator (&)
• It is used as a variable prefix to know where
the variable is stored and can be translated as
"address of", thus: &variable1 can be read as
"address of variable1"
• For example:
ted = &andy;
would assign to variable ted the address of
variable andy
Cont’d
• Suppose that andy has been placed in the memory
address 1776 and that we write the following:
andy = 25;
fred = andy;
ted = &andy;
the result is shown in the following diagram:
Cont’d
• A variable storing a memory address is called
a pointer (like ted in the previous example) as
it points to a specific memory location whose
address it is storing under its name.
Cont’d
Reference operator (*)
• To access the value stored in the variable pointed by
pointer just by preceding the pointer identifier with the
reference operator asterisk (*), that can be literally
translated to "value pointed by".
* mypointer can be read as "value pointed by
mypointer".
• Therefore, following with the values of the previous
example, if we write:
beth = *ted;
 read as: "beth equal to value pointed by ted“
 beth would take the value 25, since ted is 1776, and the
value pointed by 1776 is 25.
Cont’d

• Notice the difference of including or not including


the reference asterisk :
 beth = ted; // beth equal to ted ( 1776 )
 beth = *ted; // beth equal to value pointed by
ted ( 25 )
Cont’d
• At this point, and following with the same
example initiated above where:
andy = 25;
ted = &andy;
you should be able to clearly see that all the following
expressions are true:
andy == 25
&andy == 1776
ted == 1776
*ted == 25
Cont’d
Declaring variables of type pointer
• The general form of a pointer declaration is:
type * pointer_name;
where type is the type of data pointed, not
the type of the pointer itself.
• For example:
int * a; //creates integer pointer a
char * b; // creates a character pointer b
float * c; // creates a float pointer c
Cont’d
• Multiple pointers require multiple asterisks
int *myPtr1, *myPtr2;
Cont’d
• Two special operators * and & are used with
pointers. The & returns the memory address
of its operand (usually a variable). The & is
used to in initialize a pointer to point to a
variables address.
• Example:
int i=25 ; // declares an int variable i
int * a ; // declares an int pointer a
a= & i ; // initialises a; stores the memory address of i into a
Cont’d
• The pointer operator, *, does the reverse of &. The unary
operator * returns the value of the variable located at the
address following it. .
Example: Suppose adress of i 1776
int i =25;
int j;
int * a;
a=&i;
j =* a ; // the value (25) stored in the address it points to
* a=7 ; // puts 7 at address (&i) pointed by a
cout << i<<endl;
cout << j<<endl; 7
cout << a <<endl; 25
1776
ex1
Cont’d
// my first pointer value1==10 / value2==20
#include <iostream.h>

int main ()
{
int value1 = 5, value2 = 15;
int * mypointer;

mypointer = &value1;
*mypointer = 10;
mypointer = &value2;
*mypointer = 20;
cout << "value1==" << value1 << "/
value2==" << value2;
return 0;
}

ex2
Cont’d
// my first pointer value1==10 / value2==20
#include <iostream.h>

int main ()
{
int value1 = 5, value2 = 15;
int * mypointer;

mypointer = &value1;
*mypointer = 10;
mypointer = &value2;
*mypointer = 20;
cout << "value1==" << value1 << "/
value2==" << value2;
return 0;
}

ex2
Cont’d
• Here is an example a bit more complicated:
// more pointers value1==10 /
value2==20
#include <iostream.h>

int main ()
{
int value1 = 5, value2 = 15;
int *p1, *p2;

p1 = &value1; // p1 = address of value1


p2 = &value2; // p2 = address of value2
*p1 = 10; // value pointed by p1 = 10
*p2 = *p1; // value pointed by p2 = value pointed by
p1
p1 = p2; // p1 = p2 (value of pointer copied)
*p1 = 20; // value pointed by p1 = 20

cout << "value1==" << value1 << "/ value2==" << value2;
return 0;
}
ex3
7.2 Pointers and Arrays
• C++ interprets the name of an array as a
pointer pointing to the first element of the
array. For example, supposing these two
declarations:
int numbers [20];
int * p;
the following allocation would be valid:
p = numbers;
Cont’d
• The only difference is that we could assign another value to
the pointer p whereas numbers will always point to the first of
the 20 integer numbers of type int with which it was defined.
So, unlike p, that is an ordinary variable pointer, numbers is a
constant pointer (indeed an array name is a constant pointer).
Therefore, although the previous expression was valid, the
following allocation is not:
numbers = p;
because numbers is an array (constant pointer), and no values
can be assigned to constant identifiers.
Cont’d
• Due to the character of variables all the expressions that
include pointers in the following example are perfectly valid:
// more pointers 10, 20, 30, 40, 50,
#include <iostream.h>

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

ex4
Cont’d
• Since name of an array (array name) is a pointer
to its first element, the array name +1 gives the
address of the second element of the array, array
name +2 gives the address of the third element
and so forth. For example, both following
expressions:
a[5] = 0; // a [offset of 5] = 0
*(a+5) = 0; // pointed by (a+5) = 0
are equivalent and valid either if a is a pointer or if
it is an array.
7.3 Pointer initialization
• When declaring pointers we may want to
explicitly specify to which variable we want
them to point,
int number;
int *tommy = &number;
this is equivalent to:
int number;
int *tommy;
tommy = &number;
Cont’d
• You must consider that at the moment of
declaring a pointer, the asterisk (*) indicates only
that it is a pointer, it in no case indicates the
reference operator (*). Remember, they are two
different operators, although they are written
with the same sign. Thus, we must take care not
to confuse the previous with:
int number;
int *tommy;
*tommy = &number;
that anyway would not have much sense in this
case.
Cont’d
• As in the case of arrays, the compiler allows the
special case that we want to initialize the content
at which the pointer points with constants at the
same moment as declaring the variable pointer:
char * terry = "hello";
in this case static storage is reserved for containing
"hello" and a pointer to the first char of this
memory block (that corresponds to 'h') is assigned
to terry.
Cont’d
• If we imagine that "hello" is stored at addresses
1702 and following, the previous declaration
could be outlined thus:

it is important to indicate that terry contains the


value 1702 and not 'h' nor "hello", although 1702
points to these characters.
Cont’d
• The pointer terry points to a string of characters and can be
used exactly as if it was an Array (remember that an array is
just a constant pointer). For example, if our temper changed
and we wanted to replace the 'o' by a '!' sign in the content
pointed by terry, we could do it by any of the following two
ways:
terry[4] = '!';
*(terry+4) = '!';
7.4 Arithmetic of pointers
• Only addition and subtraction operations are
allowed to be conducted.
• When we saw the different data types that exist,
we saw that some occupy more or less space
than others in the memory. For example, in the
case of integer numbers, char occupies 1 byte,
short occupies 2 bytes and long occupies 4.
• Let's suppose that we have 3 pointers:
char *mychar;
short *myshort;
long *mylong;
Cont’d
and that we know that they point to memory locations 1000,
2000 and 3000 respectively.
So if we write:
mychar++;
myshort++;
mylong++;
mychar, as you may expect, would contain the value 1001.
Nevertheless, myshort would contain the value 2002, and
mylong would contain 3004.
• The reason is that when adding 1 to a pointer we are
making it to point to the following element of the same
type with which it has been defined, and therefore the size
in bytes of the type pointed is added to the pointer.
Cont’d

• This is applicable both when adding and subtracting


any number to a pointer. It would happen exactly the
same if we write:
mychar = mychar + 1;
myshort = myshort + 1;
mylong = mylong + 1;
Cont’d
• It is important to warn you that both increase
(++) and decrease (--) operators have a greater
priority than the reference operator asterisk (*),
therefore the following expressions may lead to
confussion:
*p++;
*p++ = *q++;
• The first one is equivalent to *(p++) and what it
does is to increase p (the address where it points
to - not the value that contains).
Cont’d
• In the second, because both increase operators
(++) are after the expressions to be evaluated and
not before, first the value of *q is assigned to *p
and then both q and p are increased by one. It is
equivalent to:
*p = *q;
p++;
q++;
• Like always, I recommend you use parenthesis ()
in order to avoid unexpected results.
7.5 Pointers to pointers
• C++ allows the use of pointers that point to
pointers, that these, in its turn, point to data.
In order to do that we only need to add an
asterisk (*) for each level of reference:
char a;
char * b;
char ** c;
a = 'z';
b = &a;
c = &b;
Cont’d
• supposing the randomly chosen memory
locations of 7230, 8092 and 10502:

 c is a variable of type (char **) with a value of


8092
 *c is a variable of type (char*) with a value of
7230
 **c is a variable of type (char) with a value of'z'
Cont’d
void pointers
• The type of pointer void is a special type of pointer. void
pointers can point to any data type, from an integer value
or a float to a string of characters. Its sole limitation is that
the pointed data cannot be referenced directly (we can not
use reference asterisk * operator on them), since its length
is always undetermined, and for that reason we will always
have to resort to type casting or assignations to turn our
void pointer to a pointer of a concrete data type to which
we can refer.
• One of its utilities may be for passing generic parameters to
a function:
Cont’d
// integer increaser 6, 10, 13
#include <iostream.h>

void increase (void* data, int type)


{
switch (type)
{
case sizeof(char) : (*((char*)data))++;
break;
case sizeof(short): (*((short*)data))++;
break;
case sizeof(long) : (*((long*)data))++;
break;
}
}

int main ()
{
char a = 5;
short b = 9;
long c = 12;
increase (&a,sizeof(a));
increase (&b,sizeof(b));
increase (&c,sizeof(c));
cout << (int) a << ", " << b << ", " << c;
return 0;
}
ex5
Cont’d
• sizeof is an operator integrated in the C++
language that returns a constant value with
the size in bytes of its parameter, so, for
example, sizeof(char) is 1, because char type is
1 byte long.
7.6 Pointers to functions
• C++ allows operations with pointers to functions.
The greatest use of this is for passing a function
as a parameter to another function, since these
cannot be passed dereferenced. In order to
declare a pointer to a function we must declare it
like the prototype of the function except the
name of the function is enclosed between
parenthesis () and a pointer asterisk (*) is
inserted before the name. It might not be a very
handsome syntax, but that is how it is done in
C++:
Cont’d
// pointer to functions 8
#include <iostream.h>

int addition (int a, int b)


{ return (a+b); }

int subtraction (int a, int b)


{ return (a-b); }

int (*minus)(int,int) = subtraction;

int operation (int x, int y, int


(*functocall)(int,int))
{
int g;
g = (*functocall)(x,y);
return (g);
}

int main ()
{
int m,n;
m = operation (7, 5, addition);
n = operation (20, m, minus);
cout <<n;
return 0;
ex6 }
Cont’d
• In the example, minus is a global pointer to a
function that has two parameters of type int,
it is immediately assigned to point to the
function subtraction, all in a single line:
• int (* minus)(int,int) = subtraction;
7.7 Dynamic memory
• Until now, in our programs, we have only had as much
memory as we have requested in declarations of
variables, arrays and other objects that we included,
having the size of all of them fixed before the execution
of the program. But, what if we need a variable
amount of memory that can only be determined during
the program execution (runtime), for example, in case
that we need an user input to determine the necessary
amount of space?
• The answer is dynamic memory, for which C++
integrates the operators new and delete.
Cont’d
Operators new and new[ ]
• In order to request dynamic memory, the operator new
exists. new is followed by a data type and optionally
the number of elements required within brackets []. It
returns a pointer to the beginning of the new block of
assigned memory. Its form is:
pointer = new type
or
pointer = new type [elements]
• The first expression is used to assign memory to
contain one single element of type. The second one is
used to assign a block (an array) of elements of type.
Cont’d
• For example:
int * bobby;
bobby = new int [5];
in this case, the operating system has assigned space for 5
elements of type int in a heap and it has returned a pointer to its
beginning that has been assigned to bobby. Therefore, now,
bobby points to a valid block of memory with space for 5 int
elements.
Cont’d
• You could ask what is the difference between
declaring a normal array and assigning memory
to a pointer as we have just done. The most
important one is that the size of an array must be
a constant value, which limits its size to what we
decide at the moment of designing the program
before its execution, whereas the dynamic
memory allocation allows assigning memory
during the execution of the program using any
variable, constant or combination of both as size.
Cont’d
• The dynamic memory is generally managed by the
operating system, and in multitask interfaces it can be
shared between several applications, so there is a
possibility that the memory exhausts. If this happens and
the operating system cannot assign the memory that we
request with the operator new, a null pointer will be
returned. For that reason it is recommended to always
check to see if the returned pointer is null after a call to
new.
int * bobby;
bobby = new int [5];
if (bobby == NULL) {
// error assigning memory. Take measures.
};
Cont’d
Operator delete
• Since the necessity of dynamic memory is usually limited to
concrete moments within a program, once it is no longer
needed it should be freed so that it becomes available for
future requests of dynamic memory. The operator delete
exists for this purpose, whose form is:
delete pointer;
or
delete [] pointer;
 The first expression: to delete memory allocated for a
single element, and
 the second one for memory allocated for multiple elements
(arrays).
Cont’d
// Dynamic memory example
#include <iostream.h>
#include <stdlib.h>
int main ()
{
char input [100];
int i,n;
long * l;
cout << "How many numbers do you want to type in? ";
cin.getline (input,100);
i=atoi (input);
l= new long[i];
if (l == NULL)
exit (1);
ex7
Cont’d
for (n=0; n<i; n++)
{ cout << "Enter number: ";
cin.getline (input,100);
l[n]=atol (input);
}
cout << "You have entered: ";
for (n=0; n<i; n++)
cout << l[n] << ", ";
delete[] l;
return 0;
}
ex7
Cont’d-sample output
How many numbers do you want to type in? 5
Enter number : 75
Enter number : 436
Enter number : 1067
Enter number : 8
Enter number : 32
You have entered: 75, 436, 1067, 8, 32,

ex7
Cont’d
• This simple example that memorizes numbers does not have a limited
amount of numbers that can be introduced, thanks to us requesting to the
system to provide as much space as is necessary to store all the numbers
that the user wishes to introduce.
• NULL is a constant value defined in many fold C++ libraries specially
designed to indicate null pointers. In case that this constant is not defined
you can do it yourself by defining it to 0:
#define NULL 0
• It is indifferent to put 0 or NULL when checking pointers, but the use of
NULL with pointers is widely extended and it is recommended for greater
legibility. The reason is that a pointer is rarely compared or set directly to
a numerical literal constant except precisely number 0, and this way this
action is symbolically masked.
Cont’d
Dynamic memory in ANSI-C
• Operators new and delete are exclusive of C++
and they are not available in C language. In C
language, in order to assign dynamic memory
we have to resort to the library stdlib.h. We
are going to see them, since they are also valid
in C++ and they are used in some existing
programs
Cont’d
The function malloc
• It is the generic function to assign dynamic memory to
pointers. Its prototype is:
• void * malloc (size_t nbytes);
• where nbytes is the number of bytes that we want to
be assigned to the pointer. The function returns a
pointer of type void*, which is the reason why we have
to type cast the value to the type of the destination
pointer, for example:
• char * ronny;
• ronny = (char *) malloc (10);
Cont’d
• This assigns to ronny a pointer to an usable block of 10
bytes. When we want to assign a block of data of a different
type other than char (different from 1 byte) we must
multiply the number of elements desired by the size of
each element. Luckyly we have at our disposition the
operator sizeof, that returns the size of the type of a
concrete datum.
int * bobby;
bobby = (int *) malloc (5 * sizeof(int));
• This piece of code assigns to bobby a pointer to a block of 5
integers of type int, this size can be equal to 2, 4 or more
bytes according to the system where the program is
compiled.

ex8
Cont’d
The function calloc
• calloc is very similar to malloc in its operation, its main difference is
in its prototype:
void * calloc (size_t nelements, size_t size);
• since it admits 2 parameters instead of one. These two parameters
are multiplied to obtain the total size of the memory block to be
assigned. Usually the first parameter (nelements) is the number of
elements and the second one (size) serves to specify the size of
each element. For example, we could define bobby with calloc thus:
int * bobby;
bobby = (int *) calloc (5, sizeof(int));
• Another difference between malloc and calloc is that calloc
initializates all its elements to 0.
Cont’d
The function realloc
• It changes the size of a block of memory already assigned to a
pointer.
void * realloc (void * pointer, size_t size);
• pointer parameter receives a pointer to an already assigned
memory block or a null pointer, and size specifies the new size that
the memory block shall have. The function assigns size bytes of
memory to the pointer. The function may need to change the
location of the memory block so that the new size can fit, in that
case the present content of the block is copied to the new one to
guarantee that the existing data is not lost. The new pointer is
returned by the function. If it has not been posible to assign the
memory block with the new size it returns a null pointer but the
pointer specified as parameter and its content remains unchanged.

ex9
Cont’d
The function free
• It releases a block of dynamic memory
previously assigned using malloc, calloc or
realloc.
• void free (void * pointer);
• This function must only be used to release
memory assigned with functions malloc, calloc
and realloc.

You might also like