0% found this document useful (0 votes)
70 views20 pages

Lecture 1.4

C++ allows pointers to pointers, with each level of indirection denoted by an asterisk in the pointer's declaration. A char** pointer c could point to a char* pointer b, which in turn points to a char variable a. This creates three levels of indirection where c has a value of 8092, *c has a value of 7230, and **c has a value of 'z'.

Uploaded by

nouraiz
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
0% found this document useful (0 votes)
70 views20 pages

Lecture 1.4

C++ allows pointers to pointers, with each level of indirection denoted by an asterisk in the pointer's declaration. A char** pointer c could point to a char* pointer b, which in turn points to a char variable a. This creates three levels of indirection where c has a value of 8092, *c has a value of 7230, and **c has a value of 'z'.

Uploaded by

nouraiz
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
You are on page 1/ 20

Pointers to pointers

 C++ allows the use of pointers that point to pointers, that


these, in its turn, point to data (or even to other pointers).
The syntax simply requires an asterisk (*) for each level of
indirection in the declaration of the pointer:
 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:
Thursday, March 28, 2019 1
Pointers to pointers
 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'

Thursday, March 28, 2019 2


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.
 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.
void pointers
 One of its possible uses may be to
pass generic parameters to a
function. For example: // increaser
 #include <iostream>
 using namespace std;
 void increase (void* data, int psize) int main ()
 { { char a = 'x';
 if ( psize == sizeof(char) ) int b = 1602;
increase (&a,sizeof(a));
 { char* pchar; increase (&b,sizeof(b));
 pchar=(char*)data; cout << a << ", " << b
 ++(*pchar); } << '\n';
 else if (psize == sizeof(int) ) return 0;
 { int* pint; }
 pint=(int*)data; Output: y, 1603
 ++(*pint); }
 }
Memory leak
 Suppose you have the following declaration:
 int *p; // this statement declares p to be a pointer variable of type int.
 p = new int; // line 1
 *p = 54; // line 2
 p = new int; // line 3
 *p = 73; // line 4
 The statement in line 1 allocates memory space of type int and stores the
address of the allocated memory space into p. suppose that the address
of allocated memory space is 1500. then the value of p after execution of
this statement is 1500.
 Next the statement in line 3 executes, which allocates a memory space of
type int and stores the address of the allocated memory space into p.
suppose the address of this allocated memory space is 1800. the value of
p is now 1800.
 Line 4 stores 73 into the memory space to which p points, which is 1800
Memory leak..
 Now the obvious question is, what happened to the
memory space 1500. to which p was pointing, before the
execution of the statement in line 3? After execution of the
statement in line 3, p points to the new memory space at
location 1800. the previous memory space at location 1500
is now inaccessible. In addition, the memory space 1500
remains marked as allocated. In other words, it cannot be
reallocated. This is called memory leak there is an unused
memory space that cannot be allocated.
 How to avoid memory leak. When dynamic variable is no
longer needed, it can be destroyed, its memory can be
deallocated. The C++ operator delete is used to destroy
dynamic variables. delete p;
Dangling Pointers
 If a pointer points to an address that doesn’t belong to your process but is
known by the OS, then this type of pointer is dangling pointer. You should
not use such type of pointers because it leads to a memory fault.
 An uninitialized pointer is called dangling pointer (also called wild pointer)
because we don’t know where it points. So we should always initialize the
pointer.
 int *p;
*p=10;
 int *p=NULL;
 int *q=NULL;
{
int x=10;
q=&x; cout<<x;
}
*q=20 ;
cout<<*q<<endl;

7
Dangling Pointers
 int * fun( )
{
int x=10;
return &x;
}
int main()
{
int *ptr=fun( ); //ptr points to address of x. Here ptr is
dangling pointer.
} 8
Dangling pointers
 Depending on a particular system, after the delete p;
statement executes, the pointer variable might still contain
the addresses of the deallocated memory space. In this case
we say that these pointers are dangling.
 One way to avoid this pitfall is to set these pointers to
NULL after the delete operation.
 int *p;
 p = new int;
 *p = 34;
 delete p;
 p = NULL;
 p = new int;
 *p = 60;
Dynamic Two-Dimensional Arrays
 int **board;
 This statement declares board to be a pointer to a pointer. In
other words, board and *board are pointers. Now board can
store the address of a pointer or an array of pointers of type
int, and *board can store the address of an int memory space or
an array of int values.
Dynamic Two-Dimensional Arrays
 Suppose that you want board to be an array of 10 rows and
15 columns. To accomplish this, first we create an array of
10 pointers of type int and assign the address of that array
to board.
 board = new int*[10];
 Next we create the columns of board. The following for
loop accomplish this:
 for(int row = 0; row < 10; row++)
 Board[row] = new int[15];
 Number of rows and number of columns of board can
be specified during program execution.
Dynamic Arrays Example

Thursday, March 28, 2019 12


Shallow Vs. Deep Copy and Pointers
 Suppose that you have the following declaration:
 int *first;
 int *second;
 Further suppose that first points to an int array.
 Next, consider the following statement:
 second = first; //this statement copies the value of first into
second. After this statement executes, both first and second point to
the same array.
 The statement first[4] = 10; not only changes the value of first [4], it
also changes the value of second[4] because they point to the same
array.
 Let us execute the following statement:
 delete [ ]second;
 After this statement executes, the array to which second points is deleted.
Shallow Vs. Deep Copy and Pointers
 First and second pointed to the same array after the statement
 delete [ ] second; executes, first becomes invalid, that is, first ( as well
as second ) are now dangling pointers.
 Therefore, if the program later tries to access the memory to which
first pointed, either the program will access the wrong memory or it
will terminate in an error. This case is an example of a shallow copy.
 More formally, in a shallow copy, two or more pointers of the
same type point to the same memory; that is, they point to the
same data.
 On the other hand, suppose that instead of earlier statement, we have
the following statements:
 second = new int [10];
 for (int j = 0; j < 10; j++)
 second [ j ] = first [ j ];
Shallow Vs. Deep Copy and Pointers
 First and second pointed to the same array after the statement
 delete [ ] second; executes, first becomes invalid, that is, first ( as well
as second ) are now dangling pointers.
 Therefore, if the program later tries to access the memory to which
first pointed, either the program will access the wrong memory or it
will terminate in an error. This case is an example of a shallow copy.
 More formally, in a shallow copy, two or more pointers of the same
type point to the same memory; that is, they point to the same data.
 On the other hand, suppose that instead of earlier statement, we have
the following statements:
Both first and second now point to their
 second = new int [10];
own data. If second deletes its memory,
 for (int j = 0; j < 10; j++) there is no effect on first. This case is an
 second [ j ] = first [ j ]; example of Deep Copy. More formally, in
a deep copy, two or more pointers
have their own data.
Recursion
 The process of solving a problem by reducing it to smaller versions of
itself is called recursion. Recursion is a very powerful way to solve
certain problems for which the solution would otherwise be very
complicated.
 Let us consider a problem that is familiar to most everyone. You
probably learned how to find the factorial of a nonnegative integer. .
 For example, the factorial of 5, written 5!, is 5 * 4 * 3 * 2 * 1 = 120.

1. Every recursive definition must have one (or more) base cases

2. The general case must eventually be reduced to a base case

3. The base case stops the recursion

Here we talk about recursive algorithms and recursive functions. An


algorithm that finds the solution to a given problem by reducing the
problem to smaller versions of itself is called a recursive algorithm. The
recursive algorithm must have one or more base cases, and the
general solution must eventually be reduced to a base case.
Recursion
 A function that calls itself is called a recursive function. The body of
the recursive function contains a statement that causes the same
function to execute again before completing the current call.
Recursive algorithms are implemented using recursive functions.
 A recursive function that implements the factorial function.

int fact ( int n )


{ if ( n == 0)
return 1;
else
return n * fact (n - 1);
}

cout<< fact (3) << endl;


Recursion
fact (3)
 Execution of factorial function num==3
 Output is 6. Because sum != 0
return 3 * fact (2);
 The purpose of recursion is to divide
the problem into smaller problems till fact (2)
the base condition is reached. num==2
Because sum != 0
return 2 * fact (1);

fact (1)
num==1
Because sum != 0
return 1 * fact (0);

fact (0)
num==0
Because sum is 0
return 1;
Direct and Indirect Recursion
 Direct recursion: When function calls itself, it is called direct
recursion, the example we have seen previously is a direct recursion
example.
 Indirect recursion: When function calls

another function and that function calls the


calling function, then this is called indirect
recursion.
For example: function A calls function B
and Function B calls function A.
The END

Question and Answer

Thursday, March 28, 2019 20

You might also like