L`I/O interattivo

Transcript

L`I/O interattivo
I/O INTERATTIVO
scanf: quello che è indispensabile sapere
printf: quello che è utile sapere
Input da tastiera
• Funzioni disponibili (tra le altre):
– scanf
– getchar
• Schema di funzionamento
Tastiera
Sistema Operativo
Driver del periferico
consolle
Buffer di tastiera
Stream stdin
Video
123_
L’utente batte
dei tasti:
123
Sistema Operativo
1 2 3
Il S.O. li trasferisce nel buffer di tastiera e
li invia al video per controllo (eco dei
caratteri)
I caratteri stazionano nel buffer
(possono essere corretti)
Stdin resta vuoto: una funzione di
input è posta in wait
123_
L’utente batte
<Invio>
Sistema Operativo
1 2 3
Il S.O. trasferisce il contenuto del buffer
in stdin
L’utente batte
<Invio>
Sistema Operativo
123
_
Il S.O. trasferisce il contenuto del buffer
in stdin
Il buffer si svuota
1 2 3 \n
Stdin ora non è più vuoto: una
funzione di input in wait diventa
operativa.
• Note:
• i tasti della tastiera vengono identificati dalla
posizione (ad es. coordinate in una matrice di
contatti)
• il driver di tastiera (S.O.) si occupa di convertire
le posizioni in codici che “rappresentano” i
caratteri (codifica ASCII? codifica UNICODE?)
• Per le funzioni di input (scanf, getchar, ecc.)
conta quello che è presente in stdin, non quanto
si vede sullo schermo!!!
Funzionamento della scanf
• La funzione scanf opera a partire dal
format e dagli specificatori di formato
• Sono gli specificatori di formato a
“comandare” la scanf.
• La scanf utilizza come sorgente lo stream
stdin
• Si può immaginare che su stdin ci sia un
cursore che punta al primo carattere
ancora da trattare.
scanf(“%c”,&carat);
• Trasferisce il carattere su cui è posizionato
il cursore in stdin nella cella carat, senza
alcuna manipolazione
• Il cursore avanza di una posizione.
F
3 \n
stdin
• Esempio applicativo:
printf(“Vuoi continuare? Rispondere S/N: “);
scanf(“%c”, &risposta);
• Nota: l’utente inserisce una lettera e poi
<Invio> perché venga accettata.
• La scanf legge la lettera, ma in stdin resta
pendente il carattere ‘\n’
scanf(“%d”, &dato_int);
• Opera in due passi:
• estrazione della sequenza di cifre (token)
• conversione da sequenza di caratteri a
numero in complemento a 2.
• Nota: si definiscono “blank characters” i
caratteri blank (spazio), new-line (‘\n’), tab
(‘\t’).
Tokenizzazione
• I “blank characters” iniziali vengono saltati
• Il primo carattere non-blank deve essere
un carattere compatibile con un numero
intero (segno o cifra): viene
immagazzinato
• Vengono immagazzinate tutte le cifre
successive fino a un carattere non
compatibile con un numero intero
Tokenizzazione (2)
• Lo standard prescrive che questo carattere
finale sia un “blank character”, ma i compilatori
attuali tollerano come terminatore qualsiasi
carattere
• Il carattere terminatore non viene “consumato”.
• In caso di errore la cattura della sequenza si
blocca, la scanf esce con errore, il carattere che
ha dato errore e i successivi non vengono
consumati.
Conversione
• La sequenza di cifre viene convertita in
numero con l’algoritmo del prodotto e
somma.
• Viene controllata la correttezza della
conversione (overflow)
• Viene tenuto conto del segno.
Conversione (2)
• Il risultato della conversione viene scritto nella
variabile di destinazione, senza ulteriori controlli
(attenzione: se la dimensione in byte della
destinazione non è corretta, si potrebbero
sporcare le celle vicine!)
• In caso di errori di conversione la scanf si
blocca ed esce con errore.
\n 1 0 \n
stdin
0000000000001010
cella di memoria
• Esempio applicativo:
printf(“Introduci un numero intero: “);
scanf(“%d”, &dato_int);
• Nota: l’utente inserisce ad esempio -123 e
<Invio> perché venga accettato.
• La scanf legge il numero, ma in stdin resta
pendente il carattere ‘\n’ finale.
•
•
Il token individuato corrisponde alla sequenza -123. Si osservi la
corrispondenza nella tabella ASCII:
carattere
codice
-
45
1
49
2
50
3
51
Per calcolare il “valore” di una cifra, il codice interno effettua
l’operazione
cifra – ‘0’
scanf(“%f”, &dato_float)
• Comportamento analogo al %d, ma in più
viene accettato il ‘.’ e la notazione
scientifica (es. 12.7e-6, che corrisponde a
0.0000127).
• Valgono le stesse considerazioni riguardo
il trasferimento del risultato nella variabile
di destinazione.
scanf(“%s”, stringa)
• I “blank characters” iniziali vengono saltati
• Il primo carattere non-blank viene trasferito nella stringa.
• Vengono trasferiti tutti i caratteri successivi fino al primo
carattere blank.
• Viene aggiunto il carattere terminatore di stringa (‘\0’).
• Il carattere terminatore non viene “consumato”.
• Non viene effettuato nessun controllo sulla lunghezza
della sequenza trasferita: eventualmente vengono
sovrascritte le variabili contigue in memoria alla stringa.
Problemi connessi all’uso della scanf
•
•
•
Tanti, se ne sottolinea uno in particolare.
Se dopo aver letto un numero (specificatori %d o %f) o una stringa
(specificatore %s) si vuole leggere un carattere (specificatore %c), bisogna
essere sicuri che non ci siano caratteri residui in stdin.
Soluzione. Dopo aver letto il numero o la stringa, inserire l’istruzione:
while(getchar() != ‘\n’);
•
che può essere trasformata in una funzione di libreria personale:
void readln(void)
{
while(getchar() != ‘\n’);
return;
}
Lo specificatore scanset
• Ha la forma %[<c1>,<c2>,…,<cn>] oppure
%[<c1>-<cn>], dove <ci> è un carattere
• La scanf con questo specificatore legge e
memorizza i caratteri fintanto che appartengono
al set definito, poi inserisce il carattere null
(come %s, ma accettando solo caratteri definiti
dal set).
• Spesso utilizzato nella forma negativa, come in
%[^\n]: trasferisce finché non è incontrato il
carattere newline.
• Nota: se il format della scanf contiene
caratteri che non siano specificatori di
formato (es. blank tra specificatori),
vengono trattati come scanset:
• Si sconsiglia di utilizzarli: il format della
scanf dovrebbe contenere solo
specificatori di formato.
Output su video
• Funzioni disponibili (tra le altre):
– printf
– putchar
• Funzionamento della printf: opera a partire
dal format, in base alle regole che
seguono
• I caratteri presenti nel format vengono
trasferiti al video senza manipolazione;
• Se è presente un %, è uno specificatore di
formato, considera il carattere successivo
(eccezione: “%%”)
• Se il carattere successivo è c (%c),
preleva il parametro corrispondente e lo
tratta come un codice, inviandolo verso il
video senza manipolazioni
• Se il carattere successivo è d (%d) o f
(%f), preleva il parametro (per un numero
di byte corrispondenti al tipo), interpreta il
pacchetto rispettivamente come intero o
reale, effettua la corrispondente
conversione da dato codificato a sequenza
di caratteri, invia la sequenza di caratteri al
video (il dato è rappresentato sul numero
minimo di caratteri).
• Se il carattere successivo è s (%s), a
partire dall’indirizzo iniziale del parametro,
invia i caratteri verso il video e si ferma
solo quando incontra un carattere null
(‘\0’).
• Nota: il terminale video effettua in
automatico l’andare a capo, quando viene
superato il limite di una riga, e lo “scroll”
delle righe.
Output formattato
• Le direttive di format della printf sono in realtà
più complesse:
%[flag][min dim][.precisione][dimensione]<carattere>
• [flag]: Più usati
+
0
Giustificazione della stampa a sinistra
Premette sempre il segno
Leading zero (invece dei blank)
• [min dim]: Dimensione minima di stampa in caratteri
• [precisione]: Numero di cifre frazionarie (per numeri reali)
• [dimensione]: Uno tra:
h
argomento è short
l
argomento è long
• carattere: Visto in precedenza