Laboratorio di Informatica I Lezione 11: Liste a Puntatori e Input/Output Vittorio Scarano Laboratorio di Informatica I Corso di Laurea in Informatica Università degli Studi di Salerno Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Struttura della lezione • Richiamo: – strutture (struct) • Strutture e trattamento di liste a puntatori – necessità: strutture dati dinamiche • Funzioni di libreria standard – printf – scanf • Gestione di file 2 1 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Tipi di dati derivati: le strutture • Tipi di dato costruiti a partire dai tipi di dati fondamentali • Array: – usato per rappresentare dati omogenei • stesso tipo • Struttura: (struct) – usato per rappresentare tipi di dati eterogenei – i componenti della struttura sono detti membri 3 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Strutture dati dinamiche • Tramite i puntatori e calloc/malloc – si riescono a definire array di dimensione scelta a run-time • Considerazioni: – La dimensione dell’array non può variare, una volta scelta – L’array aggrega variabili dello stesso tipo • Sono necessarie strutture dati dinamiche: – che supportino inserimento, cancellazione, etc. – di dati eterogenei 4 2 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Strutture dati autoreferenzianti • Struttura list #include <stdio.h> main () { struct list { int data; struct list *next; } a, b; ... a.data = 19; a.next = &b; b.data = 25; b.next = NULL; .... a data next 19 – campo data (intero) – puntatore ad una variabile di tipo list • Assegnazione di a – campo next: indirizzo di b • Assegnazione di b – campo next: puntatore 0 • NULL definito in stdio.h b data next 25 ∅ 5 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Accesso ai dati della struttura #include <stdio.h> main () { struct list { int data; struct list *next; } a, b; a.data = 19; a.next = &b; b.data = 25; b.next = NULL; printf (“%d”, a.data); printf (“%d”, b.data); printf (“%d”, a.next->data); } a 19 25 ∅ b a data 19 next 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 b data next 25 ∅ 6 3 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Liste lineari a puntatori • Composte da nodi con puntatori • Strutture dati – dinamiche – utilizzate per la rappresentazione di altre strutture dati più complesse Testa Coda data xxx next data next yyy data next zzz ∅ 7 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Operazioni su liste a puntatori • • • • • • Creazione di una lista Scorrere una lista Contare il numero di elementi Ricercare un elemento Inserire un elemento Cancellare un elemento 8 4 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Concetti di base: mantenimento di una lista #include <stdio.h> main () { struct list { int data; struct list *next; }; • Puntatori di base: struct list *head = NULL; struct list *tail = NULL; ............. • Commenti: – head • alla testa della lista – tail • alla coda della lista – tail non necessario – una lista vuota è caratterizzata da head uguale a NULL. 9 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Allocare spazio per un elemento #include <stdio.h> main () { struct list { int data; struct list *next; }; struct list *head = NULL; head = (struct list *) malloc (sizeof(struct list)); head -> data = 10; head -> next = NULL; } head • Puntatore alla testa • Allocazione memoria per un elemento: – dimensione struct list – casting • Uso di head – accesso al campo data – accesso al campo next data next 10 ∅ 10 5 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano L’inserimento in testa alla lista • Quando non è rilevante l’ordine di inserimento: – si può inserire il nuovo elemento in testa alla lista • Il puntatore head si dovrà quindi spostare sull’elemento appena inserito ∅ head 11 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano L’inserimento in testa alla lista • Quando non è rilevante l’ordine di inserimento: – si può inserire il nuovo elemento in testa alla lista • Il puntatore head si dovrà quindi spostare sull’elemento appena inserito head vecchio valore di head data next 10 ∅ 12 6 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano L’inserimento in testa alla lista • Quando non è rilevante l’ordine di inserimento: – si può inserire il nuovo elemento in testa alla lista • Il puntatore head si dovrà quindi spostare sull’elemento appena inserito vecchio valore di head head data next 23 data next 10 ∅ 13 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano L’inserimento in testa alla lista • Quando non è rilevante l’ordine di inserimento: – si può inserire il nuovo elemento in testa alla lista • Il puntatore head si dovrà quindi spostare sull’elemento appena inserito vecchio valore di head data 14 next data 23 head next data next 10 ∅ 14 7 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano L’inserimento in testa alla lista • Quando non è rilevante l’ordine di inserimento: – si può inserire il nuovo elemento in testa alla lista • Il puntatore head si dovrà quindi spostare sull’elemento appena inserito vecchio valore di head data 11 next data head next data 14 next 23 data next 10 ∅ 15 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Creazione lista: inserimento in testa (1) #include <stdio.h> struct list {int data; char nome[30]; struct list *next; }; struct list *aggiungi (struct list *,int, char *); void stampa (struct list *); main () {char nome[30]; struct list *head=NULL; int app; do {printf ("valore: (0 per finire)"); scanf ("%d", &app); if (app !=0){ printf (“Nome:”); scanf (“%s”, nome); head = aggiungi (head, app, nome); } } while (app !=0); stampa (head); } • • • • Struttura list Prototipi di funzioni head inizializzato a NULL Ciclo per input – 0 per sentinella – funzione aggiungi: • • • • puntatore alla testa head l’intero app da inserire la stringa nome del nodo restituisce la nuova head 16 8 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Creazione lista: inserimento in testa (2) struct list *aggiungi (struct list *h, int val, char *nome) {struct list *app; app = (struct list *) malloc (sizeof(struct list)); app->data = val; strcpy (app->nome, nome); app->next = h; return (app); } void stampa (struct list *p) { while (p != NULL) { printf ("Valore: %d\n", p->data); printf (“Nome:%s\n\n”, p->nome); p = p->next; } } Funzione aggiungi: • Parametri – puntatore a testa – intero e nome da inserire – restituisce la nuova testa • Allocazione memoria • Aggiornamento next Funzione stampa: – scorre la lista – avanzamento puntatore 17 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Contare il numero di elementi int conta_nodi (struct list *p) { int num=0; while (p != NULL) { num++; p = p->next; } return (num); } int conta_nodi_ric (struct list *p) { if (p == NULL) return (0); else return (1+ conta_nodi_ric(p->next)); } Funzione conta_nodi: • Parametri – puntatore a testa • Scorre e conta con num Funzione ricorsiva: – se la lista è vuota • la lunghezza è zero – altrimenti • la lunghezza è 1 più la lunghezza della rimanente parte della lista 18 9 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Ricercare un elemento void cerca(struct list *p, int val) { while (p != NULL) { if (p->data == val) printf ("Nome: %s\n", p->nome); p = p->next; } } • Dato il valore (data) stampare il nome (o i nomi) con quel valore • Parametri – puntatore a testa – intero val da cercare • Scorrimento della lista – se è trovato stampa il nome – avanza il puntatore 19 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Struttura dei parametri di printf • La funzione printf: – stringa di controllo • contiene i parametri di formattazione che permettono il trattamento e la formattazione dei parametri (opzionali) che seguono – argomenti • espressioni che vengono valutate e il cui valore è stampato a video printf (“Risultato %d\n”, i); 20 10 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Caratteri di conversione printf Caratteri di formattazione c d u o x,X e,E f g G s p % Comportamento Esempio carattere intero intero decimale senza segno ottale senza segno esadecimale senza segno floating point floating point più breve formato tra e ed f più breve formato tra E ed f stringa puntatore (hex) carattere % A 120 12 56 0xA06 7.12e+00 7.12 Ciao! 0xA06 21 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Controllo della formattazione • Caratteri di controllo della formattazione: – presenti tra il simbolo % ed il carattere di conversione specifico %-7.5f allineamento ampiezza precisione %07d precedi con zeri ampiezza 22 11 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Campi ad ampiezza e precisione variabili • Si può specificare la ampiezza e la precisione di un campo tramite variabili: float f=14.212134321134; int a, p; ..... /*scelgo a e p */ printf ("f = %*.*f \n", a, p, f); 23 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Struttura dei parametri di scanf • La funzione scanf: – stringa di controllo • contiene i parametri di formattazione che permettono il trattamento dei dati inseriti da tastiera e la memorizzazione nelle variabili che seguono – argomenti • variabili passate per riferimento – restituisce il numero di parametri assegnati scanf (“%d”, &i); 24 12 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Caratteri di conversione scanf Caratteri di formattazione c d,i u o x,X e,E,f,g,G s p Comportamento carattere intero intero decimale ottale esadecimale floating point stringa puntatore (hex) Tipo della variabile char intero unsigned unsigned unsigned float stringa void * 25 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Il funzionamento della stringa di controllo • La stringa di controllo determina come deve essere interpretato il flusso di dati in input: – i caratteri non di conversione devono corrispondere a quelli presenti sul flusso di dati int a, b; char c; printf (”Inserire (int,char,int):"); scanf ("%d%c%d", &a, &c, &b); printf ("a=%d, c=%c, b=%d\n", a, c, b); printf (“Inserire (int,F,char,int):"); scanf ("%dF%c%d", &a, &c, &b); printf ("a=%d, c=%c, b=%d\n", a, c, b); 26 13 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Un esempio di applicazione • I caratteri presenti nella stringa di formattazione vengono scartati int a, b; char c; printf (”Inserire (int,char,int):"); scanf ("%d%c%d", &a, &c, &b); printf ("a=%d, c=%c, b=%d\n", a, c, b); printf (“Inserire (int,F,char,int):"); scanf ("%dF%c%d", &a, &c, &b); printf ("a=%d, c=%c, b=%d\n", a, c, b); $ a.out Inserire (int,char,int): 13G43 a=13, c=G, b=43 Inserire (int,F, char,int): 13FG43 a=13, c=G, b=43 $ 27 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Input di range di valori • Stringhe composte da caratteri determinati – si possono specificare i caratteri ammessi ed i caratteri esclusi dalla stringa char s[40], t[40]; scanf (“%[abc]”, s); scanf (“%s”, t); printf (“%s, %s\n”, s, t); 28 14 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Un esempio di applicazione del range • La parte rimanente dell’input viene preso dalla prossima scanf: char s[40], t[40]; printf (“Stringa:”); scanf (“%[abc]”, s); scanf (“%s”, t); printf (“%s, %s\n”, s, t); $ a.out Stringa: aabbbccaabbcffaabbc aabbbccaabbc, ffaabbc $ 29 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Gestione dei file • Nella libreria standard viene definito una struttura FILE che contiene le informazioni per accedere ad i file (descrittore di file) • Necessaria la interfaccia <stdio.h> • Automaticamente sono previsti i descrittori di file stdin, stdout, stderr • Ogni file viene acceduto attraverso un puntatore ad una struttura FILE FILE *f; .... 30 15 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Istruzioni per accedere ai file • Apertura e chiusura di file: – fd = fopen (nomefile, modalità) – fclose (fd) FILE *f; ... f = fopen (“pippo”, “r”); ....... /* operazioni */ fclose (f); • Stringa per la modalità di accesso: – – – – “r” “w” “a” “r+” lettura scrittura append (aggiunta in coda) lettura e scrittura 31 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Istruzioni per leggere e scrivere nei file • fprintf (fd, stringa, parametri...) • fscanf (fd, stringa, parametri...) FILE *f; ... f = fopen (“pippo”, “w”); fprintf (f, “%d”, i); fclose (f); • c = getc(fd) – macro che legge un carattere da fd e restituisce una costante EOF se il file è terminato • putc (c, fd) – macro che scrive c su fd 32 16 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Un esempio: stampa a video di un file #include <stdio.h> main (int argc, char *argv[]) { FILE *fp; int cont=0; char c; if (argc !=2) { printf (”Errore\n"); return; } printf ("Apro %s..", argv[1]); if (! (fp = fopen (argv[1], "r"))){ printf ("Non posso aprire %s\n", argv[1]); return; } printf ("inizio file\n"); while ((c = getc(fp))!=EOF) { putc (c, stdout); cont++; } printf ("\nDimensione file = %d\n", cont); fclose (fp); } • • • • Input da linea di comando Dichiarazione di fp e cont Controllo dell’input Apertura del file con controllo del successo • Ciclo per input – legge un carattere alla volta – stampo su output (= printf) – incremento contatore • Stampa dimensione • Chiusura 33 Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Un altro esempio: copia in maiuscolo (1) #include <stdio.h> main (int argc, char *argv[]) { FILE *fpr, *fpw; int cont=0; char c; if (argc !=3) { printf (”Errore\n"); return; } printf ("Apro %s in lettura..", argv[1]); if (! (fpr = fopen (argv[1], "r"))){ printf ("Non posso aprire %s\n", argv[1]); return; } printf ("Apro %s in scrittura..", argv[2]); if (! (fpw = fopen (argv[2], "w"))){ printf ("Non posso aprire %s\n", argv[2]); return; } printf ("inizio la copia..\n"); ............ /* continua */ • • • • Input da linea di comando Dichiarazione di fpr, fpw Controllo dell’input Apertura del file da leggere con il controllo del successo • Apertura del file da scrivere con il controllo del successo 34 17 Laboratorio di Informatica I Laboratorio di Informatica 2000-2001 Vi.ttorio Scarano Un altro esempio: copia in maiuscolo (2) ........... /* continua */ while ((c = getc(fpr))!=EOF) { putc (toupper(c), fpw); cont++; } printf (".. fatta! Dim. file = %d\n", cont); fclose (fpr); fclose (fpw); } • Ciclo per input – legge un carattere alla volta – stampo su output (= printf) il carattere convertito in maiuscolo (macro toupper) – incremento contatore • Stampa dimensione • Chiusura 35 18