Uso di Record e Tabelle in C++

Strutture Dati Complesse Record, Tabelle File e loro uso in C++

Tabelle e Record

Strutture Dati Complesse Record, Tabelle File e loro uso in C++

Tabelle e Record

Nella programmazione quando si devono memorizzare grosse quantità di dati nella memoria centrale del calcolatore è opportuno definire delle strutture dati astratte costituite da una raccolta di tipi semplici aggregati attraverso un nome collettivo e identificati da un indice. Ad esempio la gestione di una rubrica telefonica può essere ottenuta definendo per ciascun soggetto il nome, cognome, l’indirizzo e il numero di telefono. Se i soggetti sono molti ad esempio già in numero superiore a 10, la gestione di queste informazioni diventa gravosa e pertanto si conviene organizzare tali informazioni in una struttura di tipo tabella in cui ogni riga costituisce il recapito telefonico di un soggetto. Una struttura dati di questo tipo in memoria centrale è detta appunto tabella, su memoria di massa (su un unità di memorizzazione tipo disco fisso, unità a dischetti) è detto file. Per poter definire una tabella è importante definire la struttura dati elementare di cui è costituita la tabella: il record. Un record è una variabile strutturata eterogenea composta da elementi di tipo diverso e identificata da un nome collettivo. Ad esempio nell’esempio precedente si può definire un record di nome “recapito”. Le componenti del record sono detti campi. E’ utile quando si definisce in un algoritmo e quindi programma un record definire un modello di tale struttura che dia informazioni anche sulla dimensione del record (dimensione logica). La dimensione logica di un record è la somma delle dimensioni di tutte le dimensioni dei campi che formano il record stesso. Inoltre alcuni campi come quelli alfanumerici sono definiti dall’utente altri come quelli numerici hanno dimensioni prefisssate e la loro dimensione varia a seconda del linguaggio di programmazione in cui si codifica l’algoritmo. Ipotizzando che i numeri interi si rappresentano con interi di 2 o 4 byte a massimo e che i numeri reali da 4 a 16 byte non è difficile calcolare la dimensione logica del record. Infatti ogni carattere alfanumerico in base alla sua codifica ASCII occupa lo spazio di un solo byte. Nell’esempio introduttivo se ne rappresenta il tracciato record che è una rappresentazione formale della struttura dati (modello) che il programmatore definisce.

Nell’esempio proposto il tracciato record è:

Recapito
CognomeNomeIndirizzoTelefono
15 caratteri15 caratteri50 caratteri10 caratteri
Dimensione logica 90 caratteri = 90 byte

Poiché il programmatore nel problema ha necessità di avere più record dello stesso tipo allora si definisce una tabella una variabile strutturata identificata da un nome collettivo in cui ogni singolo record è individuato da un indice intero.

Selezione di un campo specifico in un record e di un campo specifico nella tabella.

L’operazione di selezione di un campo specifico all’interno di un record avviene secondo la nomenclatura nome-record.nome-campo ad esempio se nel record “recapiti” si vuole selezionare il campo “indirizzo” si scriverà recapiti.indirizzi. In una tabella se si vuole selezionare del decimo decimo record il campo “telefono” la nomenclatura adottata ipotizzando che il nome della tabella sia “tb” e l’indice della tabella e/o vettore di record i:

tb(10).telefono

Come esempio poniamo il seguente problema dato una tabella di 10 record del tipo “recapito” caricare la tabella.

ClasseNomeTipo
inputtbtabella di 10 elementi di tipo record
 
internokintero indice della tabella

Non ci sono output perchè l’algoritmo ci chiede solo di caricare la tabella. La variabile r viene definita a partire dal modello. In fase di codifica si definisce prima un tipo dati (il nostro modello) e poi in seguito una variabile strutturata a partire dal tipo definito.

  1. Inizio
  2. Ciclo k= 1 a 10
  3. scrivi “dammi il cognome”
  4. leggi tb(k).cognome
  5. scrivi “dammi il nome”
  6. leggi tb(k).nome
  7. scrivi “dammi l’indirizzo”
  8. leggi tb(k).indirizzo
  9. scrivi “dammi telefono”
  10. leggi tb(k).telefono
  11. fine ciclo
  12. Fine

Utilizzo di strutture dati di tipo Record in C++

L’uso di tabella in C++ come strutture dati statiche avviene utilizzando le dichiarazioni di tipo. Infatti poichè il record per sua definizione è una struttura dati eterogenea definita dall’utente; è opportuno prima dichiarare la struttura come modello e poi utilizzare quel modello come tipo di variabile.

In altri termini si definisce il tipo di record con la seguente dichiarazione:

struct nome {

tipo nome;

tipo nome;

…..

tipo nome: };

Notare il punto e virgola dopo le parentesi graffe.

Dopo aver dichiarato la struttura del record, nella dichiarazione delle varaibili si definisce un array che come tipo di variabile è proprio del tipo record dichiarato in precedenza.

L’algoritmo in C++ utilizzando il procedimento top-down senza parametri è:

#include <iostream>

#include <string>

using namespace std;

struct record_rubrica {

string nome;

string cognome;

string indirizzo;

string telefono;

};

int k;

record_rubrica tb[10];

void carica_tabella (){

for (k=1;k<10;k++) {

cout << “Inserisci il nome” << endl;

cin >> tb[k].nome;

cout << “Inserisci il cognome” << endl;

cin >> tb[k].cognome;

cout << “Inserisci indirizzo ” << endl;

cin >> tb[k].indirizzo;

cout << “Inserisci il telefono” << endl;

cin >> tb[k].telefono;}

}

int main () {carica_tabella;}

Ora all’esercizio svolto realizzare una procedura per la rcierca di un nominativo specifico. Alla tabella dati si deve apportare la seguente variazione:

ClasseNomeTipo
inputcognome1stringa 15 caratteri
inputtbtabella di 10 elementi di tipo r 
internok,trovatointero indice della tabella, variabile che vale 1 se il nominativo è trovato 0 in caso contrario
outputnominativorecord di tipo recapito

L’algoritmo associato alla procedura di ricerca è:

Inizio cerca
k=1
trovato= 0
Scrivi “dammi il cognome della persona da cercare”
Leggi cognome1
Mentre tb(k).cognome <>””
Se cognome1=tb(k).cognome allora
trovato=1
nominativo.cognome= tb(k).cognome
nominativo.nome = tb(k).nome
nominativo.telefono = tb(k).telefono
nominativo.indirizzo = tb(k).indirizzo
scrivi nominativo.nome
scrivi nominativo.cognome
scrivi nominativo.telefono
scrivi nominativo.indirizzo
Fine Se
k=k+1
Fine ciclo
Se trovato = 0 allora
scrivi “nominativo non trovato”
Fine Se
Fine

La relativa codifica in C++ sempre a livello di procedura senza parametri è:

#include <iostream>

#include <string>

using namespace std;

struct record_rubrica {

string nome;

string cognome;

string indirizzo;

string telefono;

};

int k;

record_rubrica tb[10];

record_rubrica nominativo;

bool trovato;

string cognome1;

void carica_tabella (){

for (k=0;k<10;k++) {

cout << “Inserisci il nome” << endl;

getline(cin,tb[k].nome);

cout << “Inserisci il cognome” << endl;

getline(cin,tb[k].cognome);

cout << “Inserisci indirizzo ” << endl;

getline(cin,tb[k].indirizzo);

cout << “Inserisci il telefono” << endl;

getline(cin,tb[k].telefono);}

}

void cerca () {

k=1;

trovato=false;

cout << “Dammi il cognome da cercare ” << endl;

cin >> cognome1;

while (tb[k].cognome != “” ) {

if (tb[k].cognome==cognome1) {

nominativo.cognome=tb[k].cognome;

nominativo.nome=tb[k].nome;

nominativo.indirizzo=tb[k].indirizzo;

nominativo.telefono=tb[k].telefono;

cout << nominativo.cognome << endl;

cout << nominativo.nome << endl;

cout << nominativo.indirizzo << endl;

trovato=true;

}

k=k+1;}

if (trovato=false) {

cout << “Nominativo non trovato” << endl;}

}

int main () {

cerca();

carica_tabella(); }

Sono state realizzate due procedure una per il caricamento della tabella, e uno per la ricerca dei dati della tabella. La variabile trovato serve nella procedura di ricerca per vedere se il nominativo è presente nella tabella. La ricerca svolta in questa procedura è di tipo sequenziale in quanto la tabella, non è ordinata. Un’altra importante modifica è l’utilizzo dell’istruzione geline prevista dalla libreria “iostream” per la gestione di inserimento di stringhe con caratteri speciali.

Nella programmazione quando si devono memorizzare grosse quantità di dati nella memoria centrale del calcolatore è opportuno definire delle strutture dati astratte costituite da una raccolta di tipi semplici aggregati attraverso un nome collettivo e identificati da un indice. Ad esempio la gestione di una rubrica telefonica può essere ottenuta definendo per ciascun soggetto il nome, cognome, l’indirizzo e il numero di telefono. Se i soggetti sono molti ad esempio già in numero superiore a 10, la gestione di queste informazioni diventa gravosa e pertanto si conviene organizzare tali informazioni in una struttura di tipo tabella in cui ogni riga costituisce il recapito telefonico di un soggetto. Una struttura dati di questo tipo in memoria centrale è detta appunto tabella, su memoria di massa (su un unità di memorizzazione tipo disco fisso, unità a dischetti) è detto file. Per poter definire una tabella è importante definire la struttura dati elementare di cui è costituita la tabella: il record. Un record è una variabile strutturata eterogenea composta da elementi di tipo diverso e identificata da un nome collettivo. Ad esempio nell’esempio precedente si può definire un record di nome “recapito”. Le componenti del record sono detti campi. E’ utile quando si definisce in un algoritmo e quindi programma un record definire un modello di tale struttura che dia informazioni anche sulla dimensione del record (dimensione logica). La dimensione logica di un record è la somma delle dimensioni di tutte le dimensioni dei campi che formano il record stesso. Inoltre alcuni campi come quelli alfanumerici sono definiti dall’utente altri come quelli numerici hanno dimensioni prefissate e la loro dimensione varia a seconda del linguaggio di programmazione in cui si codifica l’algoritmo. Ipotizzando che i numeri interi si rappresentano con interi di 2 o 4 byte a massimo e che i numeri reali da 4 a 16 byte non è difficile calcolare la dimensione logica del record. Infatti ogni carattere alfanumerico in base alla sua codifica ASCII occupa lo spazio di un solo byte. Nell’esempio introduttivo se ne rappresenta il tracciato record che è una rappresentazione formale della struttura dati (modello) che il programmatore definisce.

Nell’esempio proposto il tracciato record è:

Recapito
CognomeNomeIndirizzoTelefono
15 caratteri15 caratteri50 caratteri10 caratteri
Dimensione logica 90 caratteri = 90 byte

Poiché il programmatore nel problema ha necessità di avere più record dello stesso tipo allora si definisce una tabella una variabile strutturata identificata da un nome collettivo in cui ogni singolo record è individuato da un indice intero.

Selezione di un campo specifico in un record e di un campo specifico nella tabella.

L’operazione di selezione di un campo specifico all’interno di un record avviene secondo la nomenclatura nome-record.nome-campo ad esempio se nel record “recapiti” si vuole selezionare il campo “indirizzo” si scriverà recapiti.indirizzi. In una tabella se si vuole selezionare del decimo decimo record il campo “telefono” la nomenclatura adottata ipotizzando che il nome della tabella sia “tb” e l’indice della tabella e/o vettore di record i:

tb(10).telefono

Come esempio poniamo il seguente problema dato una tabella di 10 record del tipo “recapito” caricare la tabella.

ClasseNomeTipo
inputtbtabella di 10 elementi di tipo recapito 
internokintero indice della tabella

Non ci sono output perchè l’algoritmo ci chiede solo di caricare la tabella. La variabile r viene definita a partire dal modello. In fase di codifica si definisce prima un tipo dati (il nostro modello) e poi in seguito una variabile strutturata a partire dal tipo definito.

  1. Inizio
  2. Ciclo k= 1 a 10
  3. scrivi “dammi il cognome”
  4. leggi tb(k).cognome
  5. scrivi “dammi il nome”
  6. leggi tb(k).nome
  7. scrivi “dammi l’indirizzo”
  8. leggi tb(k).indirizzo
  9. scrivi “dammi telefono”
  10. leggi tb(k).telefono
  11. fine ciclo
  12. Fine

Utilizzo di strutture dati di tipo Record in C++

L’uso di tabella in C++ come strutture dati statiche avviene utilizzando le dichiarazioni di tipo. Infatti poiché il record per sua definizione è una struttura dati eterogenea definita dall’utente; è opportuno prima dichiarare la struttura come modello e poi utilizzare quel modello come tipo di variabile.

In altri temini si definisce il tipo di record con la seguente dichiarazione:

struct nome {

tipo nome;

tipo nome;

…..

tipo nome: };

Notare il punto e virgola dopo le parentesi graffe.

Dopo aver dichiarato la struttura del record, nella dichiarazione delle varaibili si definisce un array che come tipo di variabile è proprio del tipo record dichiarato in precedenza.

L’algoritmo in C++ utilizzando il procedimento top-down senza parametri è:

#include <iostream>

#include <string>

using namespace std;

struct record_rubrica {

string nome;

string cognome;

string indirizzo;

string telefono;

};

int k;

record_rubrica tb[10];

void carica_tabella (){

for (k=1;k<10;k++) {

cout << “Inserisci il nome” << endl;

cin >> tb[k].nome;

cout << “Inserisci il cognome” << endl;

cin >> tb[k].cognome;

cout << “Inserisci indirizzo ” << endl;

cin >> tb[k].indirizzo;

cout << “Inserisci il telefono” << endl;

cin >> tb[k].telefono;}

}

carica_tabella;}int main () {

Ora all’esercizio svolto realizzare una procedura per la ricerca di un nominativo specifico. Alla tabella dati si deve apportare la seguente variazione:

ClasseNomeTipo
inputcognome1stringa 15 caratteri
inputtbtabella di 10 elementi di tipo r 
internok,trovatointero indice della tabella, variabile che vale 1 se il nominativo è trovato 0 in caso contrario
outputnominativorecord di tipo recapito

L’algoritmo associato alla procedura di ricerca è:

Inizio cerca
k=1
trovato= 0
Scrivi “dammi il cognome della persona da cercare”
Leggi cognome1
Mentre tb(k).cognome <>””
Se cognome1=tb(k).cognome allora
trovato=1
nominativo.cognome= tb(k).cognome
nominativo.nome = tb(k).nome
nominativo.telefono = tb(k).telefono
nominativo.indirizzo = tb(k).indirizzo
scrivi nominativo.nome
scrivi nominativo.cognome
scrivi nominativo.telefono
scrivi nominativo.indirizzo
Fine Se
k=k+1
Fine ciclo
Se trovato = 0 allora
scrivi “nominativo non trovato”
Fine Se
Fine

La relativa codifica in C++ sempre a livello di procedura senza parametri è:

#include <iostream>

#include <string>

using namespace std;

struct record_rubrica {

string nome;

string cognome;

string indirizzo;

string telefono;

};

int k;

record_rubrica tb[10];

record_rubrica nominativo;

bool trovato;

string cognome1;

void carica_tabella (){

for (k=0;k<10;k++) {

cout << “Inserisci il nome” << endl;

getline( cin,tb[k].nome);

cout << “Inserisci il cognome” << endl;

getline(cin,tb[k].cognome);

cout << “Inserisci indirizzo ” << endl;

getline(cin,tb[k].indirizzo);

cout << “Inserisci il telefono” << endl;

getline(cin,tb[k].telefono);}

}

void cerca () {

k=1;

trovato=false;

cout << “Dammi il cognome da cercare ” << endl;

cin >> cognome1;

while (tb[k].cognome != “” ) {

if (tb[k].cognome==cognome1) {

nominativo.cognome=tb[k].cognome;

nominativo.nome=tb[k].nome;

nominativo.indirizzo=tb[k].indirizzo;

nominativo.telefono=tb[k].telefono;

cout << nominativo.cognome << endl;

cout << nominativo.nome << endl;

cout << nominativo.indirizzo << endl;

trovato=true;

}

k=k+1;}

if (trovato=false) {

cout << “Nominativo non trovato” << endl;}

}

int main () {carica_tabella();

cerca();}

Sono state realizzate due procedure una per il caricamento della tabella, e uno per la ricerca dei dati della tabella. La variabile trovato serve nella procedura di ricerca per vedere se il nominativo è presente nella tabella. La ricerca svolta in questa procedura è di tipo sequenziale in quanto la tabella, non è ordinata. Un’altra importante modifica è l’utilizzo dell’istruzione geline prevista dalla libreria “iostream” per la gestione di inserimento di stringhe con caratteri speciali.