Lezione 11: Liste a Puntatori e Input/Output Struttura della lezione

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