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