prof. Nunzio Brugaletta Programmazione e linguaggio C

EnneBi - Programmazione
Avanti Indietro Inizio


5.2 Le tabelle: vettori di strutture

La struttura vettore consente di trattare insiemi di dati omogenei solo che, i dati rappresentati in un vettore, possono possedere un solo attributo. Per conservare dati individuati da più attributi occorre ricorrere alle tabelle.

Una tabella è un insieme finito di elementi ciascuno costituito da una chiave (informazione che serve per individuare l’elemento) e da un valore (informazioni associate alla chiave). Si può pensare la tabella come ad un quadro con le seguenti caratteristiche:

  1. Un numero di riga (chiave) che è associato alla riga e quindi la individua in maniera univoca

  2. Un numero finito di righe in ognuna della quale è conservato un elemento dell’insieme di dati rappresentato (il valore associato alla chiave)

  3. Un numero finito di colonne in ognuna delle quali è rappresentato un attributo dell’elemento conservato nella riga.

Per esempio potremmo conservare in una tabella i libri utilizzati in un anno scolastico. In ogni riga della tabella sono conservate le informazioni relative ad un libro. Ogni colonna della tabella conterrà un attributo del libro (per es. nella prima colonna ci sarà il titolo, nella seconda l’autore ecc..).

Nel linguaggio C una tabella è rappresentata tramite un vettore di strutture. Si propone la risoluzione, come esempio di applicazione dei vettori di strutture, del seguente problema:

Acquisiti i dati riguardanti i libri acquistati in un anno scolastico, si vogliono conoscere i dati dei libri che hanno avuto un costo superiore ad un input dato.

Dal punto di vista informatico è un problema di selezione: data una tabella si tratta di riempire una nuova tabella con le copie delle righe della prima tabella che soddisfano ad una certa condizione

/*
  Dato un elenco di libri e un prezzo dato in input 
  fornisce dati sui libri che costano di più 
*/

#include <stdio.h>
#define QLIB 5           /* Quantità libri caricati */

/* Implementazione delle strutture dati utilizzate */

typedef struct rec {	/*1*/
  char titolo[50]; 
  char autore[20]; 
  char editore[20]; 
  float prezzo; 
}libro;
libro libreria[QLIB],libcost[QLIB];	/*2*/
int qlc=-1;	/*3*/

/* Funzioni per l’elaborazione delle strutture dati */
    
void carica();
void ricerca(float pz);
void comunica();

main(){
  float prezinp;

  /* Caricamento libri e acquisizione prezzo */

  printf("\n\nComunica titolo libri con"); 
  printf("\ncosto maggiore di un input\n"); 
  carica();  
  for(;;){	/*4*/ 
    printf("\nPrezzo da confrontare (0 per finire)= "); 
    scanf("%f",&prezinp); 
    if(!prezinp)	/*5*/ 
      break;

    /* Ricerca libri con costo maggiore */

    qlc=-1;	/*6*/ 
    ricerca(prezinp);

    /* Output titolo libri con costo maggiore */

    printf("\nLibri con prezzo maggiore di %4.2f\n",prezinp); 
    comunica(); 
  } 
  return 0; 
}


/* Caricamento libri */

void carica(){ 
  int i; 
  printf("\nInserimento di %d libri",QLIB); 
  for(i=0;i<QLIB;i++){ 
    fflush(stdin);	/*7*/ 
    printf("\nLibro n°%d\n",i+1); 
    printf("Titolo : "); 
    gets(libreria[i].titolo);	/*7*/ 
    printf("Autore : "); 
    gets(libreria[i].autore);	/*7*/ 
    printf("Editore : "); 
    gets(libreria[i].editore);	/*7*/ 
    printf("Prezzo : ");
    scanf("%f",&libreria[i].prezzo);	/*7*/ 
    while (!getchar()=='\n');	/*8*/
  } 
}

/* ricerca libri con costo maggiore */

void ricerca(float pz){
  int i;  
  for(i=0;i<QLIB;i++){ 
    if(libreria[i].prezzo>pz) 
      libcost[++qlc]=libreria[i];	/*9*/ 
  } 
}

/* Libri con prezzo maggiore */

void comunica(){ 
  int i; 
  for(i=0;i<=qlc;i++){ 
    puts(libcost[i].titolo);	/*10*/ 
    puts(libcost[i].autore);	/*10*/ 
    puts(libcost[i].editore);	/*10*/
    printf("%4.2f\n",libcost[i].prezzo);	/*10*/
  } 
}

A cominciare dalla 1 sono implementate le strutture elaborate nel programma. Nella riga 1 si dichiara la struttura libro. Tale dichiarazione, come la dichiarazione della costante QLIB, è globale: tutte le funzioni conoscono tale struttura.

Nella 2 sono dichiarati due vettori di tipo libro: libreria e libcost (due tabelle). Anche in questo caso si tratta di dichiarazioni globali: tutte le funzioni di manipolazione delle strutture possono accedere a tali variabili.

La variabile intera qlc dichiarata in 3 viene utilizzata per indicare la posizione dell’ultimo elemento inserito nella tabella di output. Attualmente la tabella non contiene righe e quindi tale variabile è inizializzata al valore specificato. L’assenza di una analoga variabile per la tabella di input dipende dal fatto che si ipotizza che la quantità di libri caricati nella tabella di input sia sempre QLIB: non è quindi necessario utilizzare una ulteriore variabile.

Dalla 4 inizia un ciclo senza fine (non sono previste condizioni per l’uscita dal ciclo: nella for ci sono solo istruzioni vuote). L’uscita dal ciclo è determinata dal verificarsi dall’evento specificato nella 5: l’input nullo nella variabile prezinp.

L’assegnazione della 6 è necessaria per azzerare la tabella di output e prepararla per contenere i risultati di una nuova elaborazione. Il programma infatti permette di specificare più volte il prezzo da cercare e per ogni prezzo fornisce l’elenco dei libri con le caratteristiche richieste.

Nelle 7 vengono effettuati gli input delle componenti della riga i-esima della tabella libreria.

Il ciclo utilizzato nella 8 serve per pulire il buffer di tastiera da eventuali caratteri residui da operazioni precedenti. In definitiva si svuota la zona di memoria associata alla tastiera in modo da prepararla per i nuovi dati in ingresso. Tutto ciò è necessario in presenza di utilizzo di gets che preleva dal buffer fino al carattere di fine linea. Se si trovasse un carattere di fine linea, la gets salterebbe l'input e assocerebbe alla variabile, praticamente, una stringa vuota. L'utilizzo del ciclo garantisce l'eliminazione, fino al carattere di fine linea, di tutto ciò che è rimasto nel buffer.

Nelle 9 in pratica si copia la riga i della tabella libreria nella riga qlc della tabella libcost, copiandone le corrispondenti componenti. L’utilizzo di strutture permette, con un'unica operazione di copia sul nome della struttura, di copiare tutte le componenti.

La funzione comunica restituisce in output la riga i-esima, con le sue componenti, nelle 10.



Avanti Indietro Inizio

http://ennebi.solira.org ennebi@solira.org