martedì 14 ottobre 2014

Esercizio 13/10/2014

Esercizio:

Definire un nuovo tipo di dato tramite l'istruzione typedef di nome dipendente, creare poi un array di puntatori di n elementi di tipo dipendente con n scelto dall'utente.

#include <iostream>
using namespace std;

typedef struct persona {
                    char Nome[15];
                    char Cognome[15];
                    float Stipendio;
                       }dipendente;   //creo un nuovo tipo di dato "dipendente"

dipendente *puntatore;   //creo una variabile di tipo puntatore (dipendente)

main()
{
    int ndip;
    cout<<"Compito del 13/10/2014";

//Input da utente per dimensione array di puntatori    
cout<<endl<<endl<<"Quanti dipendenti vuoi inserire?"<<endl;
        cin>>ndip; 
  puntatore=new dipendente[ndip];   //creo un array di puntatori della dimensione "ndip"
*!* con l'istruzione new dipendente si alloca spazio in memoria nella quantità prevista dal tipo di puntatore utilizzato e si genera l'indirizzo da assegnare al primo elemento dell'array puntatore 
//Inserimento dell'array di puntatori
for(int i=0;i<ndip;i++)
{
             cout<<endl<<"Inserisci il Nome: ";
         cin>>puntatore[i].Nome;   //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
         cout<<"Inserisci il Cognome: ";    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
         cin>>puntatore[i].Cognome;
         cout<<"Inserisci lo Stipendio: ";    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
         cin>>puntatore[i].Stipendio;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
}
        cout << endl << endl;
//Visualizzo l'array di puntatori
    for(int i=0;i<ndip;i++)
{
     cout<<"Dati Inseriti nell'elemento "<<i<<": "<<endl;
         cout<<endl<<"Nome: " << puntatore[i].Nome;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
         cout<<endl<<"Cognome: " << puntatore[i].Cognome;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
         cout<<endl<<"Stipendio: " << puntatore[i].Stipendio;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
             cout << endl << endl;
}
return 0;
}





Vediamo alcune prove svolte sull'istruzione DELETE per la deallocazione della memoria allocata in precedenza tramite NEW DIPENDENTE

#include <iostream>
using namespace std;

typedef struct persona {
                    char Nome[15];
                    char Cognome[15];
                    float Stipendio;
                       }dipendente;   //creo un nuovo tipo di dato "dipendente"

dipendente *puntatore;   //creo una variabile di tipo puntatore (dipendente)

main()
{
    int ndip;
    cout<<"Compito del 13/10/2014";

//Input da utente per dimensione array di puntatori
 cout<<endl<<endl<<"Quanti dipendenti vuoi inserire?"<<endl;
        cin>>ndip;
//Visualizzo gli indirizzi puntati dall'array di puntatori SENZA allocazione tramite "new dipendente"
    for(int i=0;i<ndip;i++)
 {
      cout<<"Indirizzi SENZA ALLOCAZIONE 'NEW PUNTATORE' puntato dall'elemento "<<i<< ": "<<endl;
      cout<<endl<<"Nome: " << &puntatore[i].Nome;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout<<endl<<"Cognome: " << &puntatore[i].Cognome;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout<<endl<<"Stipendio: " << &puntatore[i].Stipendio;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout << endl << endl;
 }

  puntatore=new dipendente[ndip];   //creo un array di puntatori della dimensione "ndip"

//Visualizzo gli indirizzi puntati dall'array di puntatori
    for(int i=0;i<ndip;i++)
 {
      cout<<"Indirizzi CON ALLOCAZIONE 'NEW PUNTATORE' puntati dall'elemento "<<i<< ": "<<endl;
      cout<<endl<<"Nome: " << &puntatore[i].Nome;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout<<endl<<"Cognome: " << &puntatore[i].Cognome;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout<<endl<<"Stipendio: " << &puntatore[i].Stipendio;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout << endl << endl;
 }

//Inserimento dell'array di puntatori
 for(int i=0;i<ndip;i++)
 {
    cout<<"Inserimento dell'elemento "<<i<< ": "<<endl;
    cout<<"Inserisci il Nome: ";
    cin>>puntatore[i].Nome;   //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
    cout<<"Inserisci il Cognome: ";    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
    cin>>puntatore[i].Cognome;
    cout<<"Inserisci lo Stipendio: ";    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
    cin>>puntatore[i].Stipendio;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
 }
        cout << endl;
//Visualizzo l'array di puntatori
    for(int i=0;i<ndip;i++)
 {
      cout<<"Dati Inseriti nell'elemento "<<i<<": "<<endl;
      cout<<endl<<"Nome: " << puntatore[i].Nome;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout<<endl<<"Cognome: " << puntatore[i].Cognome;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout<<endl<<"Stipendio: " << puntatore[i].Stipendio;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout << endl;
 }
 cout<<"_____________________________________________________________"<<endl;
 cout<<endl<<"Ripetiamo ora la visualizzazione degli array dopo aver utilizzato"<<endl<<"l'istruzione 'delete' per deallocare lo spazio di memoria"<<endl<<endl;
 delete [] puntatore;

//Visualizzo l'array di puntatori
    for(int i=0;i<ndip;i++)
for(int i=0;i<ndip;i++)
 {
      cout<<"Indirizzi DOPO ISTRUZIONE 'DELETE []' puntati dall'elemento "<<i<< ": "<<endl;
      cout<<endl<<"Nome: " << &puntatore[i].Nome;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout<<endl<<"Cognome: " << &puntatore[i].Cognome;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout<<endl<<"Stipendio: " << &puntatore[i].Stipendio;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout << endl << endl;
 }

//Visualizzo l'array di puntatori
    for(int i=0;i<ndip;i++)
 {
      cout<<"Dati presenti nell'elemento "<<i<<" dopo istruzione 'delete': "<<endl;
      cout<<endl<<"Nome: " << puntatore[i].Nome;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout<<endl<<"Cognome: " << puntatore[i].Cognome;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout<<endl<<"Stipendio: " << puntatore[i].Stipendio;    //notazione puntata con riferimento tramite indice "i" all'elemento dell'array di puntatori a cui si fa riferimento
      cout << endl << endl;
 }

return 0;
}



domenica 12 ottobre 2014

I Puntatori 2

I Puntatori - Seconda Lezione

La caratteristica alla base dei puntatori è che con essi si lavora su indirizzi di memoria, questo con il loro utilizzo comporta grandi proprietà a vantaggio del programmatore ma anche alcune possibili problematiche che potrebbero nascere dal loro utilizzo non appropriato: si potrebbe correre il rischio di andare a modificare aree di memoria riservate ad altri processi (ad esempio si potrebbe andare a modificare un area di memoria riservata al sistema operativo il che potrebbe provocare blocchi o problemi di varia natura). Proprio per questo motivo il compilatore esegue dei controlli prima di eseguire la compilazione del codice con puntatori.
Quando lavoriamo con tipi di dati primitivi (int,float,char, ecc…) il compilatore non si pone particolari riserve e cerca di fare quello che gli viene chiesto dalle istruzioni scritte dal programmatore, ma proprio per quanto detto poco fa quando si utilizzano i puntatori invece il compilatore andrà ad eseguire una serie di controlli atti ad evitare un utilizzo inappropriato.



*!* L’area di memoria valida di un puntatore è legata al tipo di puntatore dichiarato (int, float, ecc…)

Vediamo alcuni esempi:








*!* La potenza dei puntatori sta nella possibilità di poter allocare e successivamente liberare (quando non se ne ha più la necessità di utilizzo) lo spaio di memoria allocato al puntatore stesso, cosa che non può invece accadere con le variabili tradizionali (int, float, ecc…) che di conseguenza continuano a mantenere memoria allocata anche qualora non fosse più necessario.

Vediamo alcuni esempi di Codice:


#include <iostream>
using namespace std;
int main()
{
     int a=1;
     int b=10;
     int c;
     cout<<"Inserisci un valore";
     cin >> c;
     if(c>5)
     {
          a++;
          cout<<a;
     }
     else
     {
          b++;
          cout<<b;
     }
return 0;
}

In questo esempio la variabile contatore “a” o “b” viene incrementata a seconda che il valore inserito dall’utente (contenuto nella variabile “c”) sia o meno maggiore del valore 5. Ricollegandoci a quanto detto sopra possiamo vedere come in ogni caso, a prescindere dal valore dato in Input dall’utente, il compilatore allocherà spazio nella memoria per tutte e tre le variabili “a”, “b” e “c”.
Vediamo invece lo stesso esempio di codice scritto questa volta sfruttando le proprietà sopra elencate dei puntatori:

          #include <iostream>
          using namespace std;
          int main()
          {
               int *a;
               int *b;
               int c;
               cout<<"Inserisci un valore";
               cin >> c;
               if(c>5)
               {
                    a=new int;
                    *a=1;
                    *a+=1;
                    cout<<*a;
                    delete a;
               }
               else
               {
                    b=new int;
                    *b=10;
                    *b+=1;
                    cout<<*b;
                    delete b;
               }        
          return 0;
          }

In questo esempio la variabile “a” e la variabile “b” sono di tipo puntatore. Così facendo è possibile tramite l’istruzione “new int” allocare spazio in memoria per la variabile puntatore sono al momento della necessità di utilizzo della variabile senza allocare spazio a prescindere, come succede con le viste nell’esempio precedente, di conseguenza se l’utente inserirà un valore maggiore di 5 nella variabile “c” il programma allocherà memoria per il puntatore “a”, assegnerà il valore 1 all’area di memoria da esso puntata, incrementerà tale valore, visualizzerà “a” in Output e poi tramite l’istruzione delete libererà lo spazio di memoria utilizzato dalla variabile puntatore “a” da li in poi non più necessaria. 
Lo stesso procedimento verrà eseguito per la variabile puntatore “b” se il valore inserito in Input dall’utente sarà minore di 5.

Schema puntatore e indirizzi:


Schema logico di un doppio puntatore:



*!* In questo esempio la variabile puntatore “r” punta ad un indirizzo che punta a sua volta ad un altro indirizzo che contiene un dato di tipo intero.

Fonti:
Prof. Alemanno
Marchesi Giacomo