Vai alla Home Page About me Courseware Federica Living Library Federica Federica Podstudio Virtual Campus 3D Le Miniguide all'orientamento Gli eBook di Federica La Corte in Rete
 
 
Il Corso Le lezioni del Corso La Cattedra
 
Materiali di approfondimento Risorse Web Il Podcast di questa lezione

Ernesto Burattini » 13.Uso dei puntatori


Puntatori e function

Così come il nome di un array rappresenta l’indirizzo del suo primo elemento, il nome di una function rappresenta l’indirizzo di partenza del suo codice.

Un puntatore a function contiene l’indirizzo di memoria della function; esso può essere passato o restituito da un’altra function e può essere assegnato ad un altro puntatore a function.

Il puntatore a function è molto utile quando è necessario, nel corso di un programma, scegliere tra più function.


Puntatori e function (segue)

Supponiamo di avere due function, funz1 e funz2 del tipo

int funz1(char) ……. e ……. int funz2(char)

ed un’altra function funz

void funz(int, int)

A seconda delle varie opportunità, ci si vuole servire di funz1 o di funz2: il primo intero int può essere il risultato della prima (funz1), il secondo di funz2 o viceversa.

Come possiamo scrivere il codice in maniera tale che la function funz possa richiamare l’una o l’altra tra funz1 o funz2?


Puntatori e function (segue)

Utilizzando i puntatori a function possiamo scrivere il prototipo di funz in questo modo:

void funz(int (*)(char), int)

il primo parametro int da assegnare alla function deve essere il risultato di una function che ha un parametro char (potrebbe essere funz1 o funz2 o qualsiasi altra function che ha le stesse caratteristiche: stessa tipologia di parametri formali e stesso tipo di valore restituito).

L’implementazione della function funz deve avere un’intestazione del tipo

void funz(int (*puntafunz)(char), int n)

mentre la function funz può essere richiamata con una delle seguenti modalità

funz(funz1, m) ……. funz(funz2, m)

Esempio

Un esempio di utilizzo dei puntatori a function concerne l’ordinamento.

Supponiamo di voler ordinare un array A di interi.
Possiamo decidere di ordinarli sia in modo crescente che decrescente.

A questo scopo supponiamo di avere due function, chiamate crescente e decrescente, che restituiscono un valore booleano.

Come organizzare il programma in modo tale da passare la function che serve allo scopo?

Il puntatore a function risolve il problema.

Esempio (segue)

Di seguito è riportato il codice che permette di scegliere fra il realizzare un ordinamento crescente o decrescente dei dati contenuti in un array di interi.

Le function interessate sono:

void ordinaB (int vet[], int N, bool (*confronta)(int,int))

bool crescente(int x, int y)

bool decrescente(int x, int y)

void scambia (int &x1, int &x2)

Esempio (segue)

Mostra codice

Allegato: funzPuntatori

Allegato: InsertArrayPunt.h

Esempio (segue)

Mostra codice

Esercizio

Con i puntatori a funzione scrivere una function che valuti il valore massimo contenuto in un vettore di interi, il minimo e il valore medio.

Con i puntatori a funzione scrivere una function che verifichi se assegnata una matrice di interi essa è unitaria, oppure simmetrica oppure con elementi tutti non negativi.

Variabili dinamiche

Nel caso delle variabili statiche la memoria viene allocata nel momento in cui la variabile è definita; per esempio le variabili

int x, a[10];

Impegnano la memoria nel momento stesso in cui vengono definite, mentre vengono deallocate nel momento in cui il programma termina, se la variabile è globale; se, invece, la variabile è locale (cioé definita in una function) allora viene deallocata quando termina la function.

In molti casi, però, è più comodo avere un controllo completo sulla allocazione di memoria cioè decidere quando allocare o deallocare la variabile in un qualsiasi punto del programma.

Variabili dinamiche (segue)

Questo è il concetto chiave di gestione dinamica della memoria.

Il C++ mette a disposizione del programmatore due istruzioni:

  • new che serve per allocare memoria per una certa variabile durante l’esecuzione del programma;
  • delete che serve a deallocare memoria (libera la zona di memoria occupata dall’oggetto definito con new).

Variabili dinamiche (segue)

Volendo definire due variabili dinamiche, ad esempio un intero ed un array di 100 interi, si procede in questo modo:

  • si definiscono due puntatori ad interi, int *P1, *P2;
  • si usa l’operatore new per indicare che è una variabile dinamica
    sia per l’intero
    P1=new int
    che per l’array
    P2=new int [100]

Se l’operatore new fallisce, ritorna il puntatore nullo NULL: ciò indica che, per qualche ragione, non è stato possibile allocare altra memoria.

Variabili dinamiche (segue)

Il programma può utilizzare i puntatori P1 e P2 nei suoi calcoli; può, inoltre, deallocarli in un qualsiasi momento con l’istruzione delete:

delete P1; // cancella dalla memoria heap l'intero di cui P1 contiene l'indirizzo

delete [ ] P2; // cancella dalla memoria heap l'array di cui P2 contiene l'indirizzo-base

Vediamo l’utilizzo delle variabili dinamiche per un algoritmo di selection sort.

Esempio

Mostra codice

Dal main si evince che viene creato lo spazio e caricato un array con N interi (Legge Vettore), successivamente vengono ordinati (SortSel) e stampati (StampaVettore) i dati e quindi viene liberato lo spazio di memoria.

Esempio (segue)

Mostra codice

Si noti che gli elementi del vettore vengono individuati tramite i puntatori.

Allegato: SortPuntatori2

NB. Il codice allegato prevede l'uso del file header InsertArraypunt.h introdotto nella diap.6 di questa lezione.

Esercizi

Assegnato un array A scrivere una funzione booleana ricorsiva che, operando con i puntatori, determini se i valori disposti nell’array sono simmetrici rispetto al centro.

Assegnato un array A scrivere una procedura ricorsiva che, operando con i puntatori, ordini l’array con l’algoritmo dell’insertion sort.

Esercizi (segue)

Mostra codice

Allegato: arraySimmetrico

NB. Il codice allegato prevede l'uso del file header InsertArraypunt.h introdotto nella diap.6 di questa lezione.

Esercizi (segue)

bool simm (int *array,int *lng, int pos)
{
*lng=*lng-1;
if(*lng <= pos)
return true;
else
{
if(array[*lng]==array[pos])
return simm (array,lng,pos+1);
else
return false;
}
}

I puntatori e i record

Consideriamo il tipo in figura.

La variabile puntP non ha un nome in quanto il suo nome coincide con l’indirizzo.

Le variabili di questo tipo sono dette anonime; il loro contenuto può essere perso se non ne conosciamo più l’indirizzo.


I puntatori e i record (segue)

Per memorizzare il contenuto cui punta puntP dobbiamo:

  • Usare new per allocare lo spazio nello Heap
    • puntP=new Tpersona
  • Inserire i dati
    • cout<<”Cognome=”;
    • cin>>puntP.cognome;
    • cout<<”Nome=”;
    • cin>>puntP.nome;
    • cout<<”Data Nascita=”;
    • cin>>puntP.nascita.giorno >>puntP.nascita.mese >>puntP.nascita.anno;
    • cout<<”Luogo Nascita=”;
    • cin>>puntP.luogo;
    • cout<<”Reddito=”;
    • cin>>puntP.reddito;

Una volta inseriti i dati questi si trovano nella memoria heap a cui è possibile accedere solo attraverso puntP e l’operatore “.”

I puntatori e i record (segue)

Supponiamo siano assegnate due variabili

Supponiamo siano assegnate due variabili


I puntatori e i record (segue)

Passaggio dei puntatori ad una function

Tenendo presente che il puntatore è una variabile che fornisce l’indirizzo di un’altra variabile, analizziamo alcune situazioni-tipo.

Abbiamo un programma principale contenente due puntatori ad un intero; esso richiama due procedure: nella prima la variabile intera è passata per valore, nella seconda per riferimento.

Il programma principale è lo stesso, mentre faremo variare le due procedure.

I puntatori e i record (segue)

#include <iostream>
#include <cstdlib>
using namespace std;
void CallVal(int*);
void CallRif(int* &);
int main () {
int *p1, *p2;
p1=new int;
p2=new int;
*p1=5; *p2=5;

CallVal(p1);

CallRif(p2);

system("pause");
}

Di seguito si mostra il codice e l’output del che opera chiamate dei puntatori sia per valore che per riferimento.

I puntatori e i record (segue)

Mostra codice

Allegato: funzDinamPuntatori3


I puntatori e i record (segue)

Nell’esempio che segue il programma va in errore perché la procedura CallRif(p2) restituisce un puntatore p2=NULL che quindi non può essere stampato come richiesto.

I puntatori e i record (segue)

Mostra codice

Allegato: funzDinamPunt2


I puntatori e i record (segue)

/*
Scrivere un algoritmo ricorsivo per la funzione booleana che ricerca in una
matrice quadrata di ordine N se nelle sue righe dispari esiste almeno uno 0. Se
ciò accade restituisce TRUE altrimenti FALSE. */

#include
#include

using namespace std;

const int N=5;

bool verifica(int*, int*, int*);

Mostra codice

I puntatori e i record (segue)

Mostra codice

Esercizio

Sia K un intero positivo ed R una matrice mxn di interi. Si scriva una funzione ricorsiva che stabilisca se R contenga al suo interno una serie di almeno K elementi consecutivi allineati in uno qualsiasi dei tre versi orizzontale, verticale oppure diagonale. Utilizzare i puntatori.

Esempio per K=3

Esempio per K=3


  • Contenuti protetti da Creative Commons
  • Feed RSS
  • Condividi su FriendFeed
  • Condividi su Facebook
  • Segnala su Twitter
  • Condividi su LinkedIn
Progetto "Campus Virtuale" dell'Università degli Studi di Napoli Federico II, realizzato con il cofinanziamento dell'Unione europea. Asse V - Società dell'informazione - Obiettivo Operativo 5.1 e-Government ed e-Inclusion