Il 0% ha trovato utile questo documento (0 voti)
441 visualizzazioni1.598 pagine

Tutto in C

Caricato da

Arnold NGAKAM
Copyright
© © All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd
Il 0% ha trovato utile questo documento (0 voti)
441 visualizzazioni1.598 pagine

Tutto in C

Caricato da

Arnold NGAKAM
Copyright
© © All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd

Programmazione in C

Primo programma in C

Introduzione al linguaggio C
Struttura minima di un file C
Sottoinsieme minimale di istruzioni
Compilare il primo programma
Esercizi proposti
Sommario

2
Riferimenti al materiale

Testi
Kernighan & Ritchie: capitolo 1
Cabodi, Quer, Sonza Reorda: capitoli 1, 3
Dietel & Dietel: capitolo 1
Dispense
Scheda: “Primo programma in C”

3
Primo programma in C
Genesi del linguaggio C

Sviluppato tra il 1969 ed il 1973


presso gli AT&T Bell Laboratories
B. Kernighan e D. Ritchie
Per uso interno
Legato allo sviluppo del sistema
operativo Unix Brian Kernighan Dennis Ritchie

Nel 1978 viene pubblicato “The C


Programming Language”, prima
specifica ufficiale del linguaggio
Detto “K&R”

5
Obiettivi del linguaggio

Insieme minimale di costrutti base


Semplicità del compilatore
Sintassi estremamente sintetica
Talvolta criptica
Pensato da programmatori per programmatori
Elevata efficienza
Per nulla user friendly
Portabile
Indipendente dalla macchina
Disponibilità di una libreria standard di funzioni
6
Evoluzione del linguaggio (1/2)

1978, K&R C
1989, ANSI C (o C89)
Frutto del lavoro di
standardizzazione del comitato
X3J11 dell’American National
Standards Institute
Standard X3.159-1989
“Programming Language C”
Seconda edizione del K&R

7
Evoluzione del linguaggio (2/2)

1990, ISO C (o C90)


Ratifica da parte della International Organization
for Standardization dello standard ANSI C
ISO/IEC 9899:1990
1999, ISO C99
Revisione compiuta negli anni ’90
INCITS-ANSI/ISO/IEC 9899-1999
550 pagine
[Link]
Supportata da molti (non tutti) i compilatori

8
Diffusione attuale

I linguaggi attualmente più diffusi al mondo


sono:
C
C++, un’evoluzione del C
Java, la cui sintassi è tratta da C++
C#, estremamente simile a Java e C++
Il linguaggio C è uno dei linguaggi più diffusi
La sintassi del linguaggio C è ripresa da tutti gli
altri linguaggi principali

9
Principali vantaggi del C

Basato su relativamente pochi costrutti da


apprendere
Enorme disponibilità di documentazione ed
esempi
Buona disponibiltà di ambienti di sviluppo gratuiti
Disponibile su qualsiasi configurazione hardware
Elevata efficienza di elaborazione
Adatto a vari tipi di applicazioni
Programmi di sistema
Elaborazione numerica
Programmi interattivi
10
Principali svantaggi del C

Scarsa leggibilità di alcuni costrutti


Facilità nel commettere errori di programmazione
Molti costrutti “pericolosi” sono permessi dal
linguaggio e quindi non vengono segnalati dal
compilatore
Alcuni errori di digitazione possono causare
comportamenti errati
Difficoltà nella realizzazione di interfacce grafiche
Complessità nell’elaborazione dei testi

11
Un esempio

#include <stdio.h>

int main(void
void)
void
{
printf("hello, world\n");

return 0;
}

12
Primo programma in C
Struttura minima di un file C

Applicazioni C in modo “console”


Struttura del programma
Commenti
Direttive #include
Definizione di variabili
Corpo del main

2
Struttura minima di un file C
Tipi di applicazioni (1/4)

Applicazioni grafiche
Interazione mediante
mouse e finestre
Visualizzazione di testi
e grafica
Elaborazione
concorrente 4
Tipi di applicazioni (2/4)

Applicazioni grafiche Applicazioni “console”


Interazione mediante Interazione
mouse e finestre mediante tastiera
Visualizzazione di testi Visualizzazione di
e grafica soli caratteri
Elaborazione Elaborazione
concorrente sequenziale 5
Tipi di applicazioni (3/4)

Applicazioni batch
Nessuna interazione
utente
Compiti lunghi e
ripetitivi
Elaborazione numerica,
trasferimenti in rete 6
Tipi di applicazioni (4/4)

Applicazioni batch Applicazioni server


Nessuna interazione Nessuna interazione
utente utente
Compiti lunghi e Realizzano funzioni
ripetitivi di sistema
Elaborazione numerica, Server locali o
trasferimenti in rete server Internet 7
Applicazioni “console”

Interazione utente limitata a due casi


Stampa di messaggi, informazioni e dati a video
Immissione di un dato via tastiera
L’insieme tastiera+video viene detto terminale
Nessuna caratteristica grafica
Elaborazione
Sequenziale
Interattiva
Mono-utente

8
Modello di applicazioni “console”

Programma
eseguibile

Visualizzazione
Immissione dati 9
risultati
Modello di applicazioni “console”

Scrittura
programma Programma
sorgente in C

Compilatore C

Programma
eseguibile

Visualizzazione
Immissione dati 10
risultati
Modello di applicazioni “console”

Scrittura somma.c
programma Programma
sorgente in C

Compilatore C

[Link]
Programma
eseguibile

Visualizzazione
Immissione dati 11
risultati
Compilatore C
Compilatore C

Traduce i programmi sorgenti scritti in linguaggio


C in programmi eseguibili
È a sua volta un programma eseguibile, a
disposizione del programmatore
Controlla l’assenza di errori di sintassi del
linguaggio
Non serve all’utente finale del programma
Ne esistono diversi, sia gratuiti che commerciali

12
Scrittura
programma
Scrittura del programma

Un sorgente C è un normale file di testo


Si utilizza un editor di testi
Blocco Note
Editor specializzati per programmatori

13
Editor per programmatori

Colorazione ed evidenziazione della sintassi


Indentazione automatica
Attivazione automatica della compilazione
Identificazione delle parentesi corrispondenti
Molti disponibili, sia gratuiti che commerciali

14
Scrittura
Compilatore C
programma
Ambienti integrati

Applicazioni software integrate che contengono al


loro interno
Un editor di testi per programmatori
Un compilatore C
Un ambiente di verifica dei programmi (debugger)
IDE: Integrated
Development
Environment

15
Struttura minima di un file C
Struttura di un sorgente in C

#include <stdio.h>

int main(void
void)
void
{
int a ;

a = 3 ;

printf("hello, world\n");
printf("the magic number is %d\n", a) ;

return 0;
}

17
Struttura di un sorgente in C

Programma principale
#include <stdio.h> (funzione main)

int main(void
void)
void
{
int a ;

a = 3 ;

printf("hello, world\n");
printf("the magic number is %d\n", a) ;

return 0;
}

18
Struttura di un sorgente in C

#include <stdio.h>

int main(void
void)
void
{
int a ;

a = 3 ;

printf("hello, world\n");
printf("the magic number is %d\n", a) ;

return 0;
}
Parentesi graffe che
delimitano il main
19
Struttura di un sorgente in C

#include <stdio.h>

int main(void
void)
void Variabili utilizzate
dal programma
{
int a ;

a = 3 ;

printf("hello, world\n");
printf("the magic number is %d\n", a) ;

return 0;
}

20
Struttura di un sorgente in C

#include <stdio.h>

int main(void
void)
void
{
int a ; Istruzioni eseguibili

a = 3 ;

printf("hello, world\n");
printf("the magic number is %d\n", a) ;

return 0;
}

21
Struttura di un sorgente in C

Richiamo delle
#include <stdio.h> librerie utilizzate

int main(void
void)
void
{
int a ;

a = 3 ;

printf("hello, world\n");
printf("the magic number is %d\n", a) ;

return 0;
}

22
In generale

#include delle librerie

int main(void
void)
void
{

definizione variabili

istruzioni eseguibili

23
Struttura minima di un file C
Commenti

Il testo presente in un sorgente C deve essere


analizzato dal compilatore C, quindi deve
sottostare a tutte le regole sintattiche del
linguaggio
Per aggiungere annotazioni, commenti,
spiegazioni, note, ... si può usare un commento
all’interno del sorgente

/* io sono un commento */

25
Sintassi

Un commento è una qualsiasi sequenza di


caratteri (anche su più righe) che:
Inizia con la coppia di caratteri /*
Termina con la coppia di caratteri */
Non è permesso annidare commenti
All’interno di un commento non devono comparire i
caratteri /*
Tutto ciò che è compreso tra /* e */ viene
ignorato dal compilatore C

26
Esempio

/* programma: hello.c
autore: fulvio corno
*/

/* accedi alla libreria standard */


#include <stdio.h>

int main(void
void)
void
{
int a ; /* numero magico */

a = 3 ; /* assegno un valore */

/* salutiamo l'utente */
printf("hello, world\n") ;
printf("the magic number is %d\n", a) ;

return 0;
} 27
Spazi bianchi

Oltre ai commenti, il compilatore ignora tutti gli


spazi bianchi
Spazi tra un’istruzione e la successiva
Spazi ad inizio linea
Spazi intorno alla punteggiatura
Righe vuote
La spaziatura viene utilizzata per rendere il
sorgente C più ordinato e più facilmente
comprensibile

28
Esempio

/* programma: hello.c autore: fulvio corno */


/* accedi alla libreria standard */
#include <stdio.h>
int main(void
void)
void
{ int a ; /* numero magico */ a = 3 ;
/* assegno un valore */
/* salutiamo l'utente */ printf("hello, world\n") ;
printf("the magic number is %d\n", a) ; return 0;
}

29
Esempio

/* programma: hello.c autore: fulvio corno */


/* accedi alla libreria standard */
#include <stdio.h>
int main(void
void)
void
{ int a ; /* numero magico */ a = 3 ;
/* assegno un valore */
/* salutiamo l'utente */ printf("hello, world\n") ;
printf("the magic number is %d\n", a) ; return 0;
}

#include <stdio.h>
int main(void
void)
void
{ int a ; a = 3 ; printf("hello, world\n") ;
printf("the magic number is %d\n", a) ; return 0; }

30
Struttura minima di un file C
Librerie di funzioni

Ogni compilatore C dispone di diverse librerie di


funzioni già pronte per l’uso
Il programmatore può utilizzare le funzioni di
libreria
È necessario dichiarare a quali librerie si vuole
avere accesso
Direttive #include ad inizio programma
Aggiunge al programma le dichiarazioni di tutte le
funzioni di tale libreria, permettendo al
programmatore di richiamare tali funzioni

32
Sintassi

#include < NomeLibreria .h>

Librerie principali:
#include <stdio.h>
Funzioni di lettura/scrittura su terminale e su file
#include <stdlib.h>
Funzioni base per interazione con sistema operativo
#include <math.h>
Funzioni matematiche
#include <string.h>
Elaborazione di testi 33
Avvertenze

A differenza della regola generale, nelle direttive


#include la spaziatura è importante
Il carattere # deve essere il primo della riga
Può esserci una sola #include per riga
La direttiva #include non va terminata con il ;
Dimenticare una #include potrà portare ad
errori nel corpo del main, quando si chiameranno
le funzioni relative

34
Suggerimenti

Iniziare sempre il sorgente C con le seguenti


linee:
/* programma: NomeFile.c
autore: NomeAutoreDelProgramma
BreveDescrizioneDelProgramma
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void
void)
void
{

. . . .

} 35
Struttura minima di un file C
Variabili

Il programma memorizza le informazioni sulle


quali lavora all’interno di variabili
Ogni variabile è caratterizzata da:
Tipo di dato
Nome
Valore corrente

a 35 x -17

37
Variabili

Il programma memorizza le informazioni sulle


quali lavora all’interno di variabili
Ogni variabile è caratterizzata da:
Tipo di dato
Nome
Valore corrente

a 35 x -17

pi 3.14 nome “fulvio”


38
Tipo di dato

Definisce l’insieme dei valori ammissibili per la


variabile

35 Numeri interi, positivi o negativi

3.14 Numeri reali

“fulvio” Stringhe di testo

‘f’ Singoli caratteri di testo 39


Tipo di dato

Definisce l’insieme dei valori ammissibili per la


variabile

int 35 Numeri interi, positivi o negativi

float 3.14 Numeri reali

“fulvio” Stringhe di testo

char ‘f’ Singoli caratteri di testo 40


Nome

Il programmatore assegna un nome a ciascuna


variabile
Dovrebbe rappresentare lo scopo dei valori
contenuti nella variabile
Sintetico, rappresentativo, mnemonico, facile da
scrivere

41
Nomi ammissibili

Il primo carattere deve essere una lettera


I successivi possono essere lettere o numeri
Lettere maiuscole e minuscole sono diverse
Il simbolo _ viene considerato come una lettera
Non devono essere nomi riservati dal linguaggio

42
Esempi di nomi

a b a1 a2

43
Esempi di nomi

a b a1 a2

num n N somma max

44
Esempi di nomi

a b a1 a2

num n N somma max

area perimetro perim

45
Esempi di nomi

a b a1 a2

num n N somma max

area perimetro perim

n_elementi Nelementi risultato

46
Esempi di nomi

a b a1 a2

num n N somma max

area perimetro perim

n_elementi Nelementi risultato

trovato nome risposta


47
Definizione di variabili

Ogni variabile deve essere definita prima di


poterla utilizzare
Definizioni all’inizio della funzione main
Sintassi della definizione
TipoVariabile NomeVariabile ;

int main(void
void)
void
{
int a ;
int b ;
float x ;

. . . . .
48
}
Definizione di variabili

Ogni variabile deve essere definita prima di


poterla utilizzare
Definizioni all’inizio della funzione main
Sintassi della definizione
TipoVariabile NomeVariabile ;
TipoVariabile NomeVariabile, NomeVariabile ;
int main(void
void)
void
int main(void
void)
void
{
{
int a ;
int a, b ;
int b ;
float x ;
float x ;
. . . . .
. . . . .
} 49
}
Valore contenuto

Ogni variabile, in ogni istante di tempo, possiede


un certo valore
Le variabili appena definite hanno valore ignoto
Variabili non inizializzate
In momenti diversi il valore può cambiare

a ?
t
definizione
50
Valore contenuto

Ogni variabile, in ogni istante di tempo, possiede


un certo valore
Le variabili appena definite hanno valore ignoto
Variabili non inizializzate
In momenti diversi il valore può cambiare

? a 37
t
definizione inizializzazione
51
Valore contenuto

Ogni variabile, in ogni istante di tempo, possiede


un certo valore
Le variabili appena definite hanno valore ignoto
Variabili non inizializzate
In momenti diversi il valore può cambiare

? 37 a -4
t
definizione inizializzazione altra
assegnazione 52
Valore contenuto

Ogni variabile, in ogni istante di tempo, possiede


un certo valore
Le variabili appena definite hanno valore ignoto
Variabili non inizializzate
In momenti diversi il valore può cambiare

? 37 -4 a -3
t
definizione inizializzazione altra incremento
assegnazione 53
Struttura minima di un file C
Istruzioni eseguibili

La funzione main, dopo le definizioni di variabili,


contiene le vere e proprie istruzioni eseguibili
Ciascuna istruzione è terminata da ;
Tutte le istruzioni sono comprese nelle { ... }
Le istruzioni vengono eseguite in ordine
Dopo aver eseguito l’ultima istruzione, il
programma termina

55
Esempio

/* programma: hello.c
autore: fulvio corno
*/

/* accedi alla libreria standard */


#include <stdio.h>

int main(void
void)
void
{
int a ; /* numero magico */

a = 3 ; /* assegno un valore */

/* salutiamo l'utente */
printf("hello, world\n") ;
printf("the magic number is %d\n", a) ;

return 0;
} 56
Tipologie di istruzioni

Istruzioni operative
Lettura dati
scanf("%d", &a) ;
Stampa risultati
printf("%d", a) ;
Elaborazione numerica
a = b + c ;
b = b + 1 ;
c = 42 ;
c = sqrt(a) ;

57
Tipologie di istruzioni

Istruzioni operative Istruzioni di controllo


Lettura dati Modificano il controllo
scanf("%d", &a) ; di flusso
Stampa risultati Scelte
printf("%d", a) ; Iterazioni
Elaborazione numerica Chiamate a funzioni
a = b + c ; Interruzioni e salti
b = b + 1 ; Predefinite dal
c = 42 ; linguaggio C
c = sqrt(a) ; if else while
for return
switch case
break continue
58
goto
Primo programma in C
Sottoinsieme minimale di istruzioni

I tipi int e float


Istruzione printf – semplificata
Istruzione scanf – semplificata
Istruzione di assegnazione
Semplici espressioni aritmetiche

2
Sottoinsieme minimale di istruzioni
Tipi di dato

Ogni costante, ogni variabile, ogni espressione


appartiene ad un determinato tipo
Il tipo determina
L’insieme dei valori che la costante, variabile o
espressione può assumere
L’insieme delle operazioni lecite su tali valori
I tipi possono essere
Semplici (o scalari): singoli valori
Strutturati: insiemi di più valori semplici

4
Il sistema dei tipi C

Tipo di dato

Tipi Scalari Tipi Strutturati void

Tipi interi Tipi reali Enumerazioni Vettori

char float Strutture

int double Union

short / long long Puntatori

signed/unsigned Funzioni

5
Caratteristiche generali

I valori ammessi per ciascun tipo non sono fissati


dallo standard
Dipendono dal compilatore e dal sistema
operativo
Ampiezza dei tipi di dato “naturale” per ogni
calcolatore
Maggior portabilità
Maggior efficienza
Nessuna garanzia di uniformità tra piattaforme
diverse

6
Il tipo int

Il tipo più importante del linguaggio C 35


Valori interi, positivi o negativi
int
Codificato in complemento a due
Espresso solitamente su 16 bit oppure 32 bit
16 bit: da –32 768 a +32 767
32 bit: da –2 147 483 648 a +2 147 483 647
In generale: da INT_MIN a INT_MAX
#include <limits.h>

7
Esempi

i 0
int i, j ;
int N ;
int x ; j 2
i = 0 ;
j = 2 ; N
N = 100 ; 100
x = -3124 ;
x -3124

8
Il tipo float

Valori reali 3.14


Frazionari
float
Esterni all’intervallo permesso
per i numeri interi
Codificato in virgola mobile, singola precisione
Espresso solitamente su 32 bit
da ±1.17 × 10–38 a ±3.40 × 10+38
circa 6 cifre di precisione
In generale: da FLT_MIN a FLT_MAX
#include <float.h>

9
Esempi

a 3.1
float a, b ;
float pigr ; b
float Nav, Qe ; 2.0

a = 3.1 ;
b = 2.0 ; pigr 3.1415
pigr = 3.1415926 ;
Nav = 6.022e23 ;
Qe = 1.6e-19 ; Nav 6.02×1023

Qe 1.6×10–19 10
Sottoinsieme minimale di istruzioni
Istruzioni di stampa

Stampa di messaggi informativi


Stampa di comando “a capo”
Stampa di valori di variabili
Stampa di valori di espressioni calcolate
Stampa di messaggi contenenti valori

Programma
eseguibile

Visualizzazione
risultati
12
Stampa di messaggi

printf("Benvenuto\n") ;

printf("Immetti un numero: ") ;

printf("\n");

Benvenuto

Immetti un numero: _

13
Stampa di variabili

printf("%d ", j) ;

printf("%d\n", N) ;

printf("%f\n", pigr) ;

printf("%f\n", Nav) ;

2 100

3.141593

602200013124147500000000.000000

14
Stampa di espressioni

printf("%d\n", i-j) ;

printf("%d\n", N*2) ;

printf("%f\n", Nav * Qe) ;

-2

200

96352.000000

15
Stampa di messaggi e valori

printf("Risultato=%d\n", N*2) ;

printf("Angolo = %f radianti\n", pigr/4);

Risultato=200

Angolo = 0.785398 radianti

16
Sintassi istruzione printf

#include <stdio.h>
printf("formato ", valore/i ) ;
Formato:
Testo libero (compresi spazi) → viene stampato
letteralmente
Simboli \n → va a capo
Simboli %d → stampa un int
Simboli %f → stampa un float
Valore/i:
Variabile o espressione
Di tipo int o float, corrispondente al simbolo %
17
Casi particolari (1/2)

Per stampare il simbolo % occorre ripeterlo due


volte
printf("Sondaggio: %f%%\n", pSI ) ;
%f → stampa pSI
%% → stampa un simbolo %
\n → va a capo
Sondaggio: 43.12%

18
Casi particolari (2/2)

È possibile stampare più di un valore nella stessa


istruzione
printf("Voti: %d su %d\n", voti, tot ) ;
primo %d → stampa voti
secondo %d → stampa tot
Voti: 18 su 45

19
Sottoinsieme minimale di istruzioni
Istruzioni di lettura

Lettura di un valore intero


Lettura di un valore reale

Programma
eseguibile

Immissione dati

21
Lettura di un intero

scanf( "%d", &N ) ;

213

22
Lettura di un reale

scanf( "%f", &a ) ;

12.5

23
Sintassi istruzione scanf

#include <stdio.h>
scanf("formato ", &variabile ) ;
Formato:
Simboli %d → legge un int
Simboli %f → legge un float
Variabile:
Di tipo int o float, corrispondente al simbolo %
Sempre preceduta dal simbolo &

24
Suggerimento

Combinare le istruzioni printf e scanf per


guidare l’utente nell’immissione dei dati
Ogni scanf deve essere preceduta da una
printf che indica quale dato il programma si
aspetta

printf("Immetti il numero: ");


scanf("%d", &N) ;
printf("Numero immesso: %d\n", N);

25
Errore frequente

Dimenticare il simbolo & nelle istruzioni scanf

printf("Immetti il numero: ");


scanf("%d", N) ;

forma corretta

printf("Immetti il numero: ");


scanf("%d", &N) ;

26
Errore frequente

Dimenticare le variabili da stampare nelle


istruzioni printf

printf("Numero immesso: %d\n");

forma corretta

printf("Numero immesso: %d\n", N);

27
Sottoinsieme minimale di istruzioni
Assegnazione delle variabili

Il valore di una variabile


Deve essere inizializzato, la prima volta
Può essere aggiornato, quante volte si vuole
Per assegnare un nuovo valore ad una variabile si
usa l’operatore =

a ? 37 -4 -3
t
definizione inizializzazione altra incremento
assegnazione
29
Assegnazione di variabili

Assegnazione del valore di una costante


i = 0 ;
a = 3.0 ;
Assegnazione del valore di un’altra variabile
i = N ;
b = a ;
Assegnazione del valore di un’espressione
j = N – i ;
b = a * 2 – 1 ;

30
Sintassi dell’assegnazione

variabile = espressione ;

valore valore
a precedente a espressione

Passo 1: si valuta il valore corrente


dell’espressione
Per tutte le variabili che compaiono
nell’espressione, si usa il valore corrente
Può comparire anche la stessa variabile oggetto
dell’assegnazione
Passo 2: si memorizza tale valore nella variabile,
cancellando il valore precedente
31
Esempi

N = 3 ;

32
Esempi

N = 3 ;
a = b ;
Non confondere con b = a ;

33
Esempi

N = 3 ;
a = b ;
Non confondere con b = a ;
a = a + 1 ;
Incrementa a di un’unità

34
Esempi

N = 3 ;
a = b ;
Non confondere con b = a ;
a = a + 1 ;
Incrementa a di un’unità
a + 1 = a ;
Errore

35
Quesito

Che operazione svolge il seguente frammento di


programma?

a = b ;
b = a ;

36
Risposta

Che operazione svolge il seguente frammento di


programma?

a = b ;
b = a ;

Il valore corrente di b viene copiato in a


Il valore vecchio di a viene perso
Il (nuovo) valore corrente di a (uguale a b) viene
ricopiato in b (operazione inutile)
37
Quesito

Come fare a scambiare tra di loro i valori di due


variabili?

a 7 b –12

38
Quesito

Come fare a scambiare tra di loro i valori di due


variabili?

a 7 b –12

valore valore
a –12
precedente b 7
precedente

39
Risposta

t = a ;
a = b ;
b = t ;

a 7 b –12

t ?

40
Risposta

t = a ;
a = b ;
b = t ;

a 7 b –12

t 7

41
Risposta

t = a ;
a = b ;
b = t ;

a –12 b –12

t 7

42
Risposta

t = a ;
a = b ;
b = t ;

a –12 b 7

t 7

43
Sottoinsieme minimale di istruzioni
Espressioni aritmetiche

Ovunque sia richiesto il valore di una variabile, è


possibile usare un’espressione aritmetica
Nei valori da stampare con la funzione printf
Nei valori da assegnare ad una variabile
Le espressioni si possono costruire ricorrendo a:
Operatori: + - * /
Parentesi: ( ... )
Funzioni di libreria: sqrt(), sin(), cos(), ...

45
Operatori principali

Somma: a+b
Sottrazione: a-b
Moltiplicazione: a*b
Divisione: a/b
Divisione intera (risultato troncato) se entrambi gli
operandi sono int
Resto della divisione: a%b
Solo tra operandi int
Cambio di segno: -a

46
Alcuni operatori avanzati

Incremento: i++
Decremento: N--
Conversione ad intero: (int)a
Conversione a reale: (float)N

47
Funzioni di libreria

#include <math.h>
Funzioni algebriche
fabs, sqrt, cbrt, pow, hypot, ceil, floor,
round, trunc, fmod
Funzioni esponenziali e logaritmiche
exp, exp2, log, log10, log2
Funzioni trigonometriche e iperboliche
cos, sin, tan, cosh, sinh, tanh
Funzioni trigonometriche e iperboliche inverse
acos, asin, atan, atan2, acosh, asinh,
atanh
48
Parentesi

Si possono costruire espressioni complicate a


piacere utilizzando le parentesi
Per maggiore leggibilità, abbondare con le
parentesi ed usare la spaziatura e
l’incolonnamento in modo ordinato
Si utilizzano sempre le parentesi tonde

x1 = ( -b + sqrt( b*b – 4*a*c ) ) /


( 2*a ) ;

A = sqrt( p * (p-a) * (p-b) * (p-c)) ;


49
Primo programma in C
Compilare il primo programma

Un semplice programma
L’ambiente di sviluppo Dev-C++
Codifica del programma
Compilazione e correzione errori
Esecuzione e verifica

2
Compilare il primo programma
Esercizio “Somma due numeri”

Si realizzi un programma in linguaggio C che


acquisisca da tastiera due numeri interi (detti A e
B) e che stampi a video il valore della somma di
tali numeri

Scrittura
programma Programma
sorgente in C

4
Analisi

Somma due numeri

Immetti il primo numero: _

5
Analisi

Somma due numeri

Immetti il primo numero: 18

Immetti il secondo numero: _

6
Analisi

Somma due numeri

Immetti il primo numero: 18

Immetti il secondo numero: 3

La somma di 18 + 3 vale: 21

7
Diagramma di flusso

Leggi A

Leggi B

Calcola
C = A+B

Stampa C

8
Traduzione in C (1/4)

int a ;
Leggi A
scanf("%d", &a) ;

Leggi B

Calcola
C = A+B

Stampa C

9
Traduzione in C (2/4)

Leggi A

int b ;
Leggi B
scanf("%d", &b) ;

Calcola
C = A+B

Stampa C

10
Traduzione in C (3/4)

Leggi A

Leggi B

int c ;
Calcola
C = A+B c = a + b ;

Stampa C

11
Traduzione in C (4/4)

Leggi A

Leggi B

Calcola
C = A+B
printf("La somma %d + %d ",
a, b) ;
Stampa C
printf("vale: %d\n", c) ;

12
Compilare il primo programma
Compilatori e IDE

Occorre identificare ed installare


Un editor (possibilmente per programmatori)
Un compilatore
Un debugger
Oppure trovare un Integrated Development
Environment che integri tutte le funzionalità
precedenti
Esistono molte soluzioni gratuite

14
IDE per C in ambiente Windows

Dev-C++
[Link]

15
IDE per C in ambiente Windows

V IDE
[Link]

16
IDE per C in ambiente Windows

Code::Blocks
[Link]

17
IDE per C in ambiente Windows

lcc-win32
[Link]

18
Interfaccia di Dev-C++

19
Interfaccia di Dev-C++

Menù e toolbar

Editor
programma
sorgente

Messaggi errore 20
Menu principali

21
Compilare il primo programma
Codifica del programma

A partire dal diagramma di flusso


Utilizziamo un editor per immettere le istruzioni C
Creiamo un file sorgente somma.c

Scrittura somma.c
programma Programma
sorgente in C

23
Codifica “Somma due numeri”

Codifichiamo il programma in Dev-C++


somma.c

24
Soluzione proposta (1/2)

#include <stdio.h>
#include <stdlib.h>
somma.c

int main(void
void)
void
{
int a, b ; /* addendi */
int c ; /* somma */

/* LEGGI GLI ADDENDI A E B */


printf("Somma due numeri\n\n") ;

printf("Immetti il primo numero: ") ;


scanf("%d", &a) ;
printf("Immetti il secondo numero: ") ;
scanf("%d", &b) ;

25
Soluzione proposta (2/2)

somma.c

/* CALCOLA LA SOMMA */
c = a + b ;

/* STAMPA IL RISULTATO C */
printf("La somma di %d + %d vale: %d\n",
a, b, c) ;
}

26
Compilare il primo programma
Compilazione del programma

Attivare il compilatore
sul programma somma.c
sorgente somma.c Programma
sorgente in C
Il compilatore verifica
che non ci siano
errori di sintassi Compilatore C

In assenza di errori,
viene generato il [Link]
Programma
programma eseguibile eseguibile
[Link]

28
Correzione errori di sintassi

Il compilatore genera
una lista di messaggi di somma.c
Programma
errore sorgente in C
Capire il messaggio
Identificare il punto
Compilatore C
errato nel programma
Trovare la soluzione
Correggere il Lista degli errori
programma
Generare una nuova
versione del file
29
sorgente
Compilazione “Somma due numeri”

Compiliamo il programma
somma.c

30
Compilare il primo programma
Verifica del programma

Ci mettiamo nei panni dell’utente finale


Eseguiamo il programma
Verifichiamo che funzioni correttamente
Nei casi “normali”
Nei casi “limite”

[Link]
Programma
eseguibile

Visualizzazione
Immissione dati 32
risultati
Errori in esecuzione

Tipologie di errori possibili:


Crash del programma
Blocco imposto dal sistema operativo
Blocco del programma
Ciclo “infinito”
Risultati errati
(Quasi) sempre
Solo in alcuni casi (con alcuni dati ma non con altri)

33
Correzione errori di esecuzione

Lavoro da “detective”
Risalire dai sintomi alle cause del
malfunzionamento
Formulare delle ipotesi sulla causa dell’errore e
verificarle
Una volta trovato l’errore, cercare una soluzione
A seconda della gravità, occorrerà modificare
Il sorgente C
L’algoritmo risolutivo
L’approccio generale
34
Correzione errori di esecuzione
somma.c
Programma
sorgente in C

Compilatore C

[Link]
Programma
eseguibile

Visualizzazione
Immissione dati
risultati
35
Verifica “Somma due numeri”

Eseguiamo il programma con alcuni dati di prova,


verificandone il comportamento corretto

36
Primo programma in C
Esercizi proposti

Esercizio “Equazione di primo grado”


Esercizio “Calcolo di aree”
Esercizio “Somma minuti”

2
Esercizi proposti
Esercizio “Equazione di primo grado”

Data l’equazione
ax+b=0
con a e b inseriti da tastiera, determinare il
valore di x che risolve l’equazione

4
Analisi

EQUAZIONE DI PRIMO GRADO


a x + b = 0

Inserisci il valore di a: 2.5


Inserisci il valore di b: 3.2

La soluzione dell'equazione e':


x = -1.280000

5
Soluzione

primogrado.c

leggi a calcola
x = –b/a
leggi b
stampa x

6
Esercizi proposti
Esercizio “Calcolo di aree”

Si scriva un programma in linguaggio C che, dato


un numero reale immesso da tastiera, detto D,
calcoli e stampi:
L’area del quadrato di lato D
L’area del cerchio di diametro D
L’area del triangolo equilatero di lato D

8
Analisi

CALCOLO DI AREE

Immetti il valore di D: 2

Le aree calcolate sono:


Quadrato di lato 2.000000 = 4.000000
Cerchio di diametro 2.000000 = 3.140000
Triangolo eq. di lato 2.000000 = 1.732051

9
Aree
D

D
A= D 2

aree.c

D D
H

10
D
Aree
D

D
A= D 2

aree.c

R A = π ⋅ R2
R=D
D 2

D D
H

11
D
Aree
D

D
A= D 2

aree.c

R A = π ⋅ R2
R=D
D 2
D⋅H
A=
D D 2
H H = D ⋅ sin (60°) =
D = D ⋅ sin π( 3)= D ⋅ 3
2
12
Avvertenze

Per le funzioni matematiche (sin, sqrt, ...)


occorre includere math.h
Gli argomenti delle funzioni trigonometriche
(sin, cos, ...) devono essere espressi in radianti
Il calcolo del quadrato si ottiene moltiplicando la
variabile per se stessa: D2 = D × D
Il valore di π deve essere definito dal
programmatore in un’apposita variabile
La costante M_PI, definita in math.h, non è più
supportata dallo standard ANSI C

13
Esercizi proposti
Esercizio “Somma minuti” (1/2)

Un consulente deve calcolare il numero di ore e


minuti per cui ha lavorato per un cliente
Il consulente ha lavorato in due distinte sessioni
di lavoro, per ciascuna delle quali ha annotato il
numero di ore e il numero di minuti impiegati

15
Esercizio “Somma minuti” (2/2)

Si scriva un programma in C che, a partire dalle


ore e minuti della prima sessione di lavoro e dalle
ore e minuti della seconda sessione di lavoro,
calcoli il numero di ore e minuti complessivi

16
Analisi

SOMMA MINUTI

Sessione di lavoro 1:
Numero di ore: 2
Numero di minuti: 45

Sessione di lavoro 2:
Numero di ore: 1
Numero di minuti: 30

Tempo totale: 4 ore e 15 minuti

17
Aritmetica dell’orologio

Diciamo:
ore1, min1 le ore/minuti della prima sessione
ore2, min2 le ore/minuti della seconda sessione
oretot, mintot le ore/minuti totali
Non è possibile semplicemente sommare ore e
minuti separatamente, in quanto min1+min2
potrebbe essere maggiore di 59
Bisogna tener conto del “riporto” nella somma dei
minuti

18
Soluzione

mintot = (min1 + min2) modulo 60


oretot = ore1 + ore2 + riporto minuti.c

riporto = parte intera di (min1 + min2) / 60

19
Soluzione

mintot = (min1 + min2) modulo 60


oretot = ore1 + ore2 + riporto minuti.c

riporto = parte intera di (min1 + min2) / 60

int ore1, ore2, oretot ;


int min1, min2, mintot, riporto ;

...

mintot = (min1 + min2) % 60 ;

riporto = (min1 + min2) / 60 ;

oretot = ore1 + ore2 + riporto ;


20
Primo programma in C
Argomenti trattati

Presentazione del linguaggio C


Struttura base di un file sorgente in C
Istruzioni minime per iniziare a programmare
Tipi fondamentali int e float
Istruzioni fondamentali di input/output
Istruzione di assegnazione
Operazioni necessarie per compilare ed eseguire
il programma

2
Suggerimenti

Analizzare sempre il comportamento previsto del


programma prima di iniziare a scrivere il sorgente
Interazione con l’utente
Risoluzione manuale con carta e penna
Abbondare con i commenti
Leggere con attenzione tutti i messaggi di errore
e di warning del compilatore, e correggerli
Verificare il programma con diversi dati di prova

3
Materiale aggiuntivo

Sul CD-ROM
Testi e soluzioni degli esercizi trattati nei lucidi
Scheda sintetica
Esercizi risolti
Esercizi proposti
Esercizi proposti da altri libri di testo

4
Programmazione in C
Scelte ed alternative

Il controllo di flusso
Istruzione if-else
Condizioni complesse
Istruzioni if-else annidate
Istruzione switch
Esercizi proposti
Sommario

2
Riferimenti al materiale

Testi
Kernighan & Ritchie: capitolo 3
Cabodi, Quer, Sonza Reorda: capitoli 2, 4
Dietel & Dietel: capitoli 2, 3
Dispense
Scheda: “Istruzioni di scelta in C”

3
Scelte ed alternative
Il controllo di flusso

Concetto di flusso e di scelta


Rappresentazione grafica
Condizioni booleane semplici
Esempio

5
Il controllo di flusso
Flusso di esecuzione lineare

Il programma C viene
eseguito, di norma dalla A
prima istruzione
all’ultima
Il flusso di esecuzione è B
quindi normalmente di
tipo lineare
C
istruzione_A ;
istruzione_B ;
istruzione_C ; D
istruzione_D ;
7
Eccezioni

In taluni casi il flusso di esecuzione deve variare:


in funzione del valore di qualche variabile di
ingresso, occorre fare operazioni diverse
una certa operazione deve essere ripetuta più
volte
alcune parti del programma vengono attivate solo
se l’utente lo richiede
...
In tal caso, il flusso di esecuzione non segue più
esattamente l’ordine di scrittura delle istruzioni
nel codice sorgente
8
Scelte

Il tipo più semplice di flusso non lineare è


costituito dalle scelte (o alternative)

Se il voto è minore di 18,


allora prenota il prossimo appello,
altrimenti vai in vacanza.
Se il voto è maggiore di 28,
prenota il ristorante.

9
Anatomia di una scelta

Una condizione di scelta è caratterizzata da tre


informazioni:
la “condizione” che determina la scelta (il voto è
minore di 18)
le “operazioni” da svolgere qualora la condizione
sia “vera” (prenota il prossimo appello)
le “operazioni” da svolgere qualora la condizione
sia “falsa” (vai in vacanza)
Le “operazioni” potrebbero anche essere assenti

10
Il controllo di flusso
Notazione grafica

V F
C

A B

12
Notazione grafica

Ramo “vero” Condizione

V F Ramo “falso”
C

A B
Termine della
alternativa
(ricongiunzione)
13
Flussi di esecuzione

V F V F
C C

A B A B

14
Flussi di esecuzione

Condizione vera

V F Istruzioni V F
C eseguite C

Istruzioni
A B A B
non eseguite

15
Flussi di esecuzione

Condizione falsa

V F Istruzioni V F
C eseguite C

A Istruzioni
B A B
non eseguite

16
Il controllo di flusso
Il concetto di condizione

Che tipo di espressioni si utilizzano per esprimere


la condizione C ?
devono dare una risposta univoca
Vero
Falso
sono basate sui valori delle variabili del
programma
Le espressioni di questo tipo sono dette booleane
in quando generano dei valori che rispettano le
leggi della logica di Boole (Vero o Falso)

18
Condizioni di confronto semplici

Spesso le condizioni sono espresse sotto forma di


confronti
Confronto di uguaglianza
Uguale
Diverso
Confronto di ordine
Maggiore
Minore
Maggiore o uguale
Minore o uguale

19
Il controllo di flusso
Equazioni di primo grado

Analizziamo il flusso di esecuzione di un


programma in grado di risolvere le equazioni di
primo grado:
Data l’equazione
ax+b=0
con a e b inseriti da tastiera, determinare il
valore di x che risolve l’equazione

21
Equazione risolutiva

Dai corsi di matematica sappiamo che la


soluzione dell’equazione:
ax+b=0
si può esprimere mediante la formula:
x=–b/a
Tale formula è valida solo se a≠0
Il programma dovrà comportarsi in modo diverso
a seconda che a sia nullo o no

22
Soluzione

leggi a V F
a≠0?

leggi b
calcola
x = –b/a stampa
“errore”
stampa x

23
Scelte ed alternative
Istruzione if-
if-else

Sintassi dell’istruzione
Operatori di confronto
Esercizio proposto di esempio
Risoluzione esercizio (parte I)
Esecuzione del programma
Completamento esercizio
Risoluzione esercizio (parte II)

2
Istruzione if-
if-else
Istruzioni di scelta in C

L’operazione di scelta avviene mediante


l’istruzione if-else
Le condizioni di scelta possono essere semplici od
elaborate
Le scelte possono essere liberamente combinate
tra loro, annidate
In alcuni casi si può usare l’istruzione switch
(trattata nella lezione “Istruzione switch”)

4
Istruzione if-
if-else

if ( C )
{
V F
A ; C
}
else
{ A B
B ;
}

5
Istruzione if-
if-else

Condizione
if ( C )
{ Ramo “vero”
V F
A ; C
}
else Ramo “falso”
{ A B
B ;
}

6
Condizione vera

Condizione vera
if ( C )
{ Istruzioni
eseguite V F
A ; C
}
else
{ Istruzioni
non eseguite A B
B ;
}

7
Condizione falsa

Condizione falsa
if ( C )
{ Istruzioni
non eseguite V F
A ; C
}
else
{ Istruzioni
eseguite A B
B ;
}

8
Esempio

int a, b ;
es-posneg.c
printf("Immetti
printf un numero: ");
scanf("%d",
scanf &a) ;
if ( a > 0 )
{
printf("positivo\n")
printf ;
b = a ;
}
else
{
printf("negativo\n")
printf ;
b = -a ;
}
printf("Il
printf valore assoluto di %d e' %d", a, b) ;

9
Suggerimento

Ad ogni nuova parentesi graffa aperta {, inserire


degli spazi aggiuntivi ad inizio riga
Tale tecnica, detta indentazione, permette una
migliore leggibilità del codice
È visivamente immediato riconoscere l’inizio e la
fine dei blocchi di istruzioni
Molti ambienti di sviluppo hanno funzioni di
indentazione automatica o semi-automatica

10
Note

La condizione C può
essere semplice o
if ( C ) complessa
{ Il blocco A può essere
A ; composto da una sola
} istruzione, o da più
else istruzioni
{ Il blocco B può essere
B ; composto da una sola
} istruzione, o da più
istruzioni

11
Caso particolare: istruzione if

V F
if ( C ) C
{
A ;
} A
Manca la
condizione
else
12
Esempio

es-valabs.c
int a ;

printf("Immetti
printf un numero: ");
scanf("%d",
scanf &a) ;
if ( a < 0 )
{
/* è negativo, gli cambio segno */
a = -a ;
}
printf("Il
printf valore assoluto e' %d", a) ;

13
Caso particolare: parentesi graffe

if ( C ) Se il blocco A è
A ; composto da una sola
else istruzione, allora le
{ parentesi graffe relative
B ; si possono omettere.
} Lo stesso vale per il
blocco B.
if ( C )
{
A ; if ( C )
} A ;
else else
B ; B ;
14
Esempio

es-valabs2.c

int a ;

printf("Immetti
printf un numero: ");
scanf("%d",
scanf &a) ;

if ( a < 0 ) /* è negativo, gli cambio segno */


a = -a ;

printf("Il
printf valore assoluto e' %d", a) ;

15
Errore frequente

È errato mettere il
simbolo di punto-e- if ( a > 0 ) ;
virgola ; dopo a = -a ;
l’istruzione if

viene interpretato come forma corretta

if ( a > 0 )
if ( a > 0 )
/*nulla*/ ;
a = -a ;
a = -a ;

16
Errore frequente

È errato fidarsi della


if ( a > 0 )
sola indentazione
printf("neg");
printf
a = -a ;

viene interpretato come forma corretta

if ( a > 0 )
if ( a > 0 )
{
printf("neg");
printf
printf("neg");
printf
a = -a ;
a = -a ;
}
17
Suggerimento

Anche se vi è una sola istruzione nel blocco


“vero” o nel blocco “falso”, utilizzare sempre le
parentesi graffe
In tal modo il programma sarà più leggibile, e
sarà più facile aggiungere eventuali nuove
istruzioni senza incappare in errori

18
Istruzione if-
if-else
Le condizioni

La condizione C è solitamente basata su


un’operazione di confronto
determinare se una variabile è uguale o meno a
zero, o a un altro valore costante
determinare se una variabile è uguale ad un’altra
variabile, o è diversa, o è maggiore, o minore, ...
determinare se una espressione, calcolata a partire
da una o più variabili, è uguale, diversa, maggiore,
minore, ... di una costante, o una variabile, o
un’altra espressione

20
Operatori di confronto in C

Uguaglianza
Uguale: a == b
Diverso: a != b
Ordine
Maggiore: a > b
Minore: a < b
Maggiore o uguale: a >= b
Minore o uguale: a <= b

21
Esempi

if( a == 0 ) ...
if( a == b ) ...
if( a < 0 ) ...
if( a+b > 3 ) ...
if( x*y != y*x ) ...
if( a/2 == (a+1)/2 ) ...

22
Esempi

if( a == 0 ) ...
if( a == b ) ...
if( a < 0 ) ...
if( a+b > 3 ) ...
if( x*y != y*x ) ...
if( a/2 == (a+1)/2 ) ...

23
Esempi

if( a == 0 ) ...
if( a == b ) ...
if( a < 0 ) ...
if( a+b > 3 ) ...
if( x*y != y*x ) ...
if( a/2 == (a+1)/2 ) ...

24
Esempi

if( a == 0 ) ...
if( a == b ) ...
if( a < 0 ) ...
if( a+b > 3 ) ...
if( x*y != y*x ) ...
if( a/2 == (a+1)/2 ) ...

25
Esempi

if( a == 0 ) ...
if( a == b ) ...
if( a < 0 ) ...
if( a+b > 3 ) ...
if( x*y != y*x ) ...
if( a/2 == (a+1)/2 ) ...

26
Esempi

if( a == 0 ) ...
if( a == b ) ...
if( a < 0 ) ...
if( a+b > 3 ) ...
if( x*y != y*x ) ...
if( a/2 == (a+1)/2 ) ...

27
Errore frequente

Confondere l’operatore /* assegnazione */


di assegnazione = con a = b + c ;
l’operatore di
confronto == /* confronto */
Regola pratica: le if ( a == b+c )...
parentesi tonde
richiedono ==
Regola pratica: il punto- /* assegnazione */
e-virgola richiede = a == b + c ;

/* confronto */
if ( a = b+c )...
28
Istruzione if-
if-else
Esercizio “Controlla A e B”

Si scriva un programma in linguaggio C che legga


due numeri da tastiera, detti A e B, e determini le
seguenti informazioni, stampandole a video:
determini se B è un numero positivo o negativo
determini se A è un numero pari o dispari
calcoli il valore di A+B
determini quale scelta dei segni nell’espressione
(±A) + (±B) porta al risultato massimo, e quale è
questo valore massimo.

30
Struttura generale

Leggi A e B
Controlla il segno di B
Stampa il messaggio opportuno
Controlla la parità di A
Stampa il messaggio opportuno
Calcola A+B
Stampa il risultato
...l’ultimo punto è più difficile
...ci pensiamo dopo!

31
Lettura dei dati

Leggi A e B

int a, b ;

printf("Immetti
printf A");
scanf("%d",
scanf &a) ;

printf("Immetti
printf B");
scanf("%d",
scanf &b) ;

32
Controllo del segno

Controlla il segno di B
Stampa il messaggio opportuno

if(
if b > 0 )
{
printf("B
printf e' positivo\n");
}
else
{
printf("B
printf e' negativo o nullo\n");
}
33
Controllo della parità

Controlla la parità di A
Stampa il messaggio opportuno

if(
if “a è pari” )
{
printf("A
printf e' pari\n");
}
else
{
printf("A
printf e' dispari\n");
}
34
Numero pari

Come determinare se un numero è pari?


Calcoliamo la divisione per 2, e controlliamo il
resto
Se il resto della divisione per 2 vale 0, allora il
numero è pari
Se il resto della divisione per 2 vale 1, allora il
numero è dispari
Il calcolo del resto si ottiene con l’operatore %

if(
if “a è pari” ) if(
if (a % 2) == 0 )

35
Istruzione if-
if-else
Risoluzione esercizio “Controlla A e B”

Risolviamo interattivamente l’esercizio


controlla-ab-v1.c

37
Istruzione if-
if-else
Verifica esercizio “Controlla A e B”

Compiliamo il programma
Eseguiamolo con alcuni dati di prova,
verificandone il comportamento corretto

39
Istruzione if-
if-else
Completamento esercizio “Controlla A e B”

Abbiamo verificato il corretto funzionamento


Rimane da implementare il punto:
determini quale scelta dei segni nell’espressione
(±A) + (±B) porta al risultato massimo, e quale è
questo valore massimo.
Appaiono possibili diverse strategie:
Calcolare le 4 combinazioni e scegliere il massimo
Riscrivere algebricamente l’espressione

41
Strategia 1

La prima strategia prevede di calcolare:


R1 = (+A) + (+B)
R2 = (+A) + (–B)
R3 = (–A) + (+B)
R4 = (–A) + (–B)
Dopo avere calcolato queste 4 variabili, occorre
confrontarle per determinare quale è maggiore di
tutte le altre.
In questo caso è inutilmente macchinoso.

42
Strategia 2

Ragionando algebricamente, la massima somma


che si può ottenere dall’espressione (±A) + (±B)
sarà quando
±A è positivo
±B è positivo
In altre parole, è sufficiente calcolare la somma
dei valori assoluti
|A| + |B|

43
Valore assoluto

Il valore assoluto di una variabile è pari a


il valore dell’opposto della variabile
se la variabile è negativa
il valore della variabile stessa
se la variabile è positiva

44
Valore assoluto

Il valore assoluto di una variabile è pari a


il valore dell’opposto della variabile
se la variabile è negativa
il valore della variabile stessa
se la variabile è positiva
if(
if a<0 )
{
va = -a ;
}
else
{
va = a ;
} 45
Valore assoluto

Il valore assoluto di una variabile è pari a


il valore dell’opposto della variabile
se la variabile è negativa
il valore della variabile stessa
se la variabile è positiva
if(
if a<0 )
{
va = -a ; if(
if a<0 )
} {
else a = -a ;
{ }
va = a ;
} 46
Istruzione if-
if-else
Risoluzione esercizio “Controlla A e B”

Completiamo l’esercizio, codificandolo e


verificandolo controlla-ab-v2.c

48
Scelte ed alternative
Condizioni complesse

Operatori booleani
Operatori booleani in C
Esercizio proposto
Verifica della soluzione

2
Condizioni complesse
Logica Booleana

Le condizioni “semplici” (es. confronti) forniscono


un valore booleano (vero/falso)
Spesso occorre prendere delle scelte in funzione
del valore di più condizioni semplici
Es: x è compreso tra a e b?
x ≥ a, e contemporaneamente x ≤ b
Es: ci sono promossi?
voto1 ≥ 18, oppure voto2 ≥ 18
A questo scopo si possono usare gli operatori
booleani

4
Operatori booleani

Date due qualsiasi condizioni booleane X ed Y


(condizioni semplici, o a loro volta complesse):
X AND Y
è vero se sia X che Y sono veri
X OR Y
è vero se è vero X (indipendentemente da Y)
oppure se è vero Y (indipendentemente da X) o se
sono veri entrambi
NOT X
è vero se X è falso, è falso se X è vero

5
Esempi

x è compreso tra a e b?
(x ≥ a) AND (x ≤ b)
se so già che b ≥ a
( (b ≥ a) AND (x ≥ a) AND (x ≤ b) ) OR
( (b < a) AND (x ≤ a) AND (x ≥ b) )
nel caso generale
ci sono promossi?
(voto1 ≥ 18) OR (voto2 ≥ 18)

6
Condizioni complesse
Operatori booleani in C

Operatore Sintassi
Esempio
booleano in C

AND && (x>=a)&&(x<=b)

OR || (v1>=18)||(v2>=18)

NOT ! !(a>b)

8
Contesto di utilizzo

Solitamente gli operatori booleani && || ! si


utilizzano all’interno della condizione
dell’istruzione if, per costruire condizioni
complesse
Più avanti vedremo come si usano anche nella
condizione del costrutto while
Tali operatori lavorano su operandi che
solitamente sono:
Condizioni semplici (es. (a>b)||(a!=1))
Risultati di altri operatori booleani
(es. ((a>b)&&(b>c))||(c==0))
9
Precedenza degli operatori

Quando più operatori booleani e di confronto


sono presenti nella stessa espressione, vengono
valutati come segue:
Prima gli operatori di confronto
== != > < >= <=
Poi la negazione NOT
!
In seguito la congiunzione AND
&&
Infine la disgiunzione OR
||
10
Esempi

if ( a>0 && b>0 )

11
Esempi

if ( a>0 && b>0 ) if ( a<=0 || b<=0 )

12
Esempi

if ( a>0 && b>0 ) if ( a<=0 || b<=0 )

if ( !(a>0 && b>0) )

13
Esempi

if ( a>0 && b>0 ) if ( a<=0 || b<=0 )

if ( a==0 || (a!=0 && b==0) )

14
Esempi

if ( a>0 && b>0 ) if ( a<=0 || b<=0 )

if ( a==0 || (a!=0 && b==0) )

if ( b>=a && x>=a && x<=b ||


b<a && x<=a && x>=b )

15
Esempi

if ( a>0 && b>0 ) if ( a<=0 || b<=0 )

if ( a==0 || (a!=0 && b==0) )

if ( b>=a && x>=a && x<=b ||


b<a && x<=a && x>=b )

16
Esempi

if ( a>0 && b>0 ) if ( a<=0 || b<=0 )

if ( a==0 || (a!=0 && b==0) )

if ( b>=a && x>=a && x<=b ||


b<a && x<=a && x>=b )

17
Esempi

if ( a>0 && b>0 ) if ( a<=0 || b<=0 )

if ( a==0 || (a!=0 && b==0) )

if ( b>=a && x>=a && x<=b ||


b<a && x<=a && x>=b )

18
Esempi

if ( a>0 && b>0 ) if ( a<=0 || b<=0 )

if ( a==0 || (a!=0 && b==0) )

if ( b>=a && x>=a && x<=b ||


b<a && x<=a && x>=b )

if ( ((b>=a) && (x>=a) && (x<=b)) ||


((b<a) && (x<=a) && (x>=b))
)
19
Suggerimento

In presenza di espressioni complesse, è sempre


conveniente abbondare con le parentesi
leggibilità
indipendenza dalle precedenze degli operatori

if ( b>=a && x>=a && x<=b ||


b<a && x<=a && x>=b )

if ( ((b>=a) && (x>=a) && (x<=b)) ||


((b<a) && (x<=a) && (x>=b))
)
20
Errore frequente

È errato usare in successione più operatori di


confronto senza collegarli mediante operatori
booleani

if ( (a > b) &&
forma
if ( a > b > 0 ) (b > 0)
corretta
)

if ( (a == b) &&
forma
if ( a==b==c ) (b == c)
corretta
)
21
Errore frequente

È errato “sottintendere” parte di un confronto


Esempio: “se a o b sono diversi da uno”

forma
if ( a || b != 1 )
corretta
if ( (a!=1) ||
(b!=1) )
forma
if ( (a||b) != 1 )
corretta

22
Condizioni complesse
Esercizio “Classificazione triangolo 1”

Si scriva un programma in linguaggio C che legga


da tastiera i valori delle lunghezze dei tre lati di
un triangolo (detti A, B e C), e determini:
se il triangolo è equilatero
se il triangolo è isoscele
se il triangolo è scaleno
se il triangolo è rettangolo

Nota: si assuma, per il momento, che i valori A,


B, C descrivano correttamente un triangolo

24
Analisi del problema

Ricordiamo le condizioni matematiche relative alla


classificazione dei triangoli:
Equilatero: le lunghezze dei tre lati A, B, C sono
uguali tra loro
Isoscele: le lunghezze di [almeno] due dei tre lati
A, B, C sono uguali tra loro
ogni triangolo equilatero è anche isoscele
Scaleno: le lunghezze dei tre lati A, B, C sono tutte
diverse tra loro
Rettangolo: possiede un angolo retto
vale il teorema di Pitagora

25
Espressioni matematiche (I)

Equilatero
A=B=C
(A = B) AND (B = C) AND (A = C)
(A = B) AND (B = C)
Isoscele
(A = B) OR (B = C) OR (A = C)
Scaleno
(A ≠ B) AND (A ≠ C) AND (B ≠ C)

26
Espressioni matematiche (II)

Rettangolo
Teorema di Pitagora
Ipotenusa2 = Cateto2 + Cateto2
L’ipotenusa può essere uno qualunque dei lati A, B
oppure C
(A2 = B2+C2) OR (B2 = A2+C2) OR (C2 = A2+B2)

27
Condizioni in C

Equilatero
a==b && b==c
Isoscele
a==b || b==c || a==c
Scaleno
a!=b && b!=c && a!=c
Rettangolo
(a*a == b*b + c*c) ||
(b*b == a*a + c*c) ||
(c*c == a*a + b*b)

28
Condizioni complesse
Verifica “Classificazione triangolo 1”

Analizziamo il codice dell’esercizio e


verifichiamone il corretto funzionamento triangolo.c

30
Scelte ed alternative
Istruzioni if-
if-else annidate

Annidamento di istruzioni if-else


Opzionalità del ramo else
Catene if-else if-...-else
Esercizio proposto
Verifica della soluzione

2
Istruzioni if-
if-else annidate
Scelte annidate

Nelle istruzioni del V F


blocco “vero” o del C1
blocco “else”, è
A1
possibile inserire altri
blocchi di scelta V F B
C2
In tal caso la seconda
scelta risulta annidata A2 A3
all’interno della prima

A4

4
Caso 1

C1 vero, C2 vero V F
Istruzioni eseguite: C1
A1, A2, A4
A1
V F B
C2

A2 A3

A4

5
Caso 2

C1 vero, C2 vero V F
Istruzioni eseguite: C1
A1, A2, A4
A1
C1 vero, C2 falso
V F B
Istruzioni eseguite: C2
A1, A3, A4
A2 A3

A4

6
Caso 3

C1 vero, C2 vero V F
Istruzioni eseguite: C1
A1, A2, A4
A1
C1 vero, C2 falso
V F B
Istruzioni eseguite: C2
A1, A3, A4
C1 falso, C2 A2 A3
indifferente
Istruzioni eseguite:
B A4

7
Corretto annidamento

L’intero blocco di V F
scelta più interno C1
(dalla condizione fino
A1
al ricongiungimento)
deve essere V F B
C2
completamente
contenuto all’interno A2 A3
di uno dei rami del
blocco più esterno
A4

8
Sintassi C
if ( C1 )
{
A1 ; V F
C1
if ( C2 )
{ A1
A2 ;
} V F B
else
C2
{
A3 ; A2 A3
}
A4 ;
} A4
else
{
B ; 9
}
Sintassi C
if ( C1 )
{
A ; V F
C1
}
else B1
{
B1 ; A V F
C2
if ( C2 )
{
B2 ; B2 B3
}
else
{ B4
B3 ;
}
B4 ; 10
}
Caso generale

V F
C1
A1 B1
V F V F
C2 C3

A2 A3 B2 B3

A4 B4

11
Sintassi C

if ( C1 ) else
{ { V F
C1
A1 ; B1 ;
if ( C2 ) if ( C3 ) A1 B1
{ {
V F V F
A2 ; B2 ; C2 C3
} }
else else A2 A3 B2 B3
{ {
A3 ; B3 ;
} } A4 B4
A4 ; B4 ;
} }

12
Sintassi C

Un’istruzione if può comparire ovunque


anche all’interno del blocco “vero” o “falso” di
un’altra istruzione if
Occorre garantire il corretto annidamento delle
istruzioni
le istruzioni annidate vanno completamente
contenute tra le parentesi graffe {...}

13
Esempio

Ricordiamo l’esercizio sull’algoritmo risolutivo


delle equazioni di primo grado
ax+b=0
La soluzione è:
x=–b/a
solo se a≠0

14
Soluzione (parziale)

leggi a V F
a≠0?

leggi b
calcola
x = –b/a stampa
“errore”
stampa x

15
Esempio

Ricordiamo l’esercizio sull’algoritmo risolutivo


delle equazioni di primo grado
ax+b=0
La soluzione è:
x=–b/a
solo se a≠0
x = indeterminato (infinite soluzioni)
se a=0 e b=0
x = impossibile (nessuna soluzione)
se a=0 e b≠0

16
Soluzione (completa)

leggi a V F
a≠0?

leggi b b=0?
V F
calcola
x = –b/a stampa stampa
“indeterminata” “impossibile”
stampa x

17
Soluzione in C (1/2)
#include <stdio.h>
#include <stdlib.h>
primogrado.c
int main(void
void)
void
{
float a, b ;
float x ;

printf("Risoluzione eq. di primo grado\n");


printf("Equazione: a x + b = 0\n") ;

/* Leggi A e B */
printf("Immetti coefficiente a: ");
scanf("%f", &a) ;

printf("Immetti coefficiente b: ");


scanf("%f", &b) ; 18
Soluzione in C (2/2)
if(
if a != 0 )
{
x = - b / a ;
printf("La soluzione e' x = %f\n", x) ;
}
else
{
if(
if b==0 )
{
printf("Equazione indeterminata\n");
}
else
{
printf("Equazione impossibile\n");
}
}
} 19
Istruzioni if-
if-else annidate
Forme abbreviate

Ricordiamo che:
Se il ramo “vero” oppure il ramo “falso” è
composto da una sola istruzione, allora le
parentesi graffe {...} sono opzionali
Se il ramo “falso” non contiene istruzioni, allora la
clausola else si può omettere
Nel contesto di if annidati, queste regole
possono creare una potenziale ambiguità

21
Esempio

if(
if a>0 )
{
c = a ;
}
else if(
if a>0 )
{ c = a ;
if(
if b>0 )
{ = else
if(
if b>0 )
c = b ; c = b ;
} else
else c = 0 ;
{
c = 0 ;
}
}

22
Esempio problematico

if(
if a>0 )
if(
if b>0 )
c = a + b ;
else
c = 0 ;
if(
if a>0 )
if(
if b>0 )
c = a + b ;
else
?
c = 0 ;
if(
if a>0 )
if(
if b>0 )
c = a + b ;
else
c = 0 ;

23
Regola

Ogni clausola else, in assenza di parentesi


graffe che ne esplicitino l’attribuzione, è da
intendersi riferita all’istruzione if più vicina (per
la quale non sia ancora stata attribuita una
clausola else)

if(
if a>0 )
if(
if a>0 ) {
if(
if b>0 ) if(
if b>0 )
c = a + b ; c = a + b ;
else else
c = 0 ; c = 0 ;
}
24
Suggerimento

In presenza di if annidate, è conveniente


abbondare con le parentesi graffe

if(
if a>0 )
if(
if b>0 )
c = a + b ;
else
c = 0 ;
if(
if a>0 ) if(
if a>0 )
{ {
if(
if b>0 ) if(
if b>0 )
c = a + b ; c = a + b ;
} else
else c = 0 ;
c = 0 ; } 25
Istruzioni if-
if-else annidate
Catene di istruzioni condizionali

Talvolta occorre verificare, in sequenza, una serie


di condizioni particolari, trovando la prima
condizione vera tra quelle possibili
Esempio:
Dato un numero intero tra 1 e 12, che rappresenta
il mese corrente, stampare il nome del mese per
esteso (“Gennaio” ... “Dicembre”)

27
Soluzione
if(
if mese == 1 )
printf("Gennaio\n") ;
else
{ mesi.c
if(
if mese == 2 )
printf("Febbraio\n") ;
else
{
if(
if mese == 3 )
printf("Marzo\n") ;
else
{
if(
if mese == 4 )
printf("Aprile\n") ;
else
{
....... /* continua fino a 12 */
}
}
} 28
}
Analisi della soluzione
if(
if( mese == 1 )
printf("
printf("Gennaio
("Gennaio\
Gennaio\n") ;
else
{
if(
if( mese == 2 )

else
printf("
printf("Febbraio
("Febbraio\
Febbraio\n") ;
Annidamento
{
if(
if( mese == 3 )

else
{
printf("
printf("Marzo
("Marzo\
Marzo\n") ; eccessivo
if(
if( mese == 4 )

Scarsa leggibilità
printf("
printf("Aprile
("Aprile\
Aprile\n") ;
else
{
if(
if( mese == 5 )
printf("
printf("Maggio
("Maggio\
Maggio\n") ;
else

Difficile identificazione
{
if(
if( mese == 6 )
printf("
printf("Giugno
("Giugno\
Giugno\n") ;
else
{

delle {...}
if(
if( mese == 7 )
printf("
printf("Luglio
("Luglio\
Luglio\n") ;
else
{
if(
if( mese == 8 )

else
{
printf("
printf("Agosto

if(
("Agosto\
Agosto\n") ;

if( mese == 9 )
printf("
printf("Settembre
("Settembre\
Settembre\n") ;
corrispondenti
else
{
if(
if( mese == 10 )
printf("
printf("Ottobre
("Ottobre\
Ottobre\n") ;
else
{
if(
if( mese == 11 )

else
{
printf("
printf("Novembre

if(
("Novembre\
Novembre\n") ;

if( mese == 12 )
Esistono formattazioni
printf("
printf("Dicembre
("Dicembre\
Dicembre\n") ;

}
}
else
printf("MESE
printf("MESE ERRATO!\
ERRATO!\n") ;
migliori?
}
}
}
}
}
}
}
}
}

29
Soluzione più leggibile
if(
if mese == 1 )
printf("Gennaio\n") ;
else if(
if mese == 2 )
printf("Febbraio\n") ; mesi2.c
else if(
if mese == 3 )
printf("Marzo\n") ;
else if(
if mese == 4 )
printf("Aprile\n") ;
else if(
if mese == 5 )
printf("Maggio\n") ;
............................
else if(
if mese == 9 )
printf("Settembre\n") ;
else if(
if mese == 10 )
printf("Ottobre\n") ;
else if(
if mese == 11 )
printf("Novembre\n") ;
else if(
if mese == 12 )
printf("Dicembre\n") ;
else 30
printf("MESE ERRATO!\n") ;
In generale...

In ogni ramo “falso” c’è if ( C1 )


una sola istruzione: {
A1 ;
la if-else annidata }
anche se a sua volta else if ( C2 )
{
contiene altre istruzioni, A2 ;
è comunque considerata }
una sola istruzione else if ( C3 )
{
È possibile omettere le A3 ;
}
parentesi nel ramo else ..........
else
È conveniente rimuovere {
l’indentazione An ;
}
Ricordarsi dell’else finale
31
Istruzioni if-
if-else annidate
Esercizio “Classificazione triangolo 2”

Si scriva un programma in linguaggio C che legga


da tastiera i valori delle lunghezze dei tre lati di
un triangolo (detti A, B e C), e determini:
se il triangolo è equilatero
se il triangolo è isoscele
se il triangolo è scaleno
se il triangolo è rettangolo
Il programma, prima di classificare il triangolo,
controlli se i numeri A, B, C rappresentano
correttamente un triangolo

33
Analisi

Data una terna di numeri A, B, C, non è detto


che si possa costruire un triangolo con tali
lunghezze dei lati
La lunghezza di ciascun lato deve essere un
numero positivo
Ogni lato deve essere minore della somma degli
altri due
Ogni lato deve essere maggiore della differenza
degli altri due

A B C B ? A

C 34
Struttura proposta

if (i lati non sono positivi)


{
printf("errore") ;
}
else if (ogni lato non è minore della somma degli altri)
{
printf("errore") ;
}
else if (ogni lato non è maggiore della differenza degli altri)
{
printf("errore") ;
}
else
{
/* caso normale */
...vedi triangolo.c
}
35
Condizioni booleane

“i lati non sono positivi”


a<=0 || b<=0 || c<=0
“ogni lato non è minore della somma degli altri”
a>=b+c || b>=a+c || c>=a+b
“ogni lato non è maggiore della differenza degli
altri”
attenzione: la differenza va presa in valore
assoluto!
prima di calcolare A-B, occorre verificare che A>B,
altrimenti bisogna calcolare B-A

36
Condizioni booleane (2)

“ogni lato non è maggiore della differenza degli


altri”
( (b>c) && a <= b-c ) ||
( (b<=c) && a <= c-b ) ||
( (a>c) && b <= a-c ) ||
( (a<=c) && b <= c-a ) ||
( (a>b) && c <= b-a ) ||
( (a<=b) && c <= a-b )

37
Istruzioni if-
if-else annidate
Verifica “Classificazione triangolo 2”

Analizziamo il codice dell’esercizio e


verifichiamone il corretto funzionamento triangolo2.c

39
Scelte ed alternative
Istruzione switch

Sintassi dell’istruzione
Particolarità dell’istruzione
Esercizio proposto
Verifica della soluzione

2
Istruzione switch
Scelte multiple

if(
if mese == 1 )
Quando occorre printf("Gennaio\n") ;
compiere una else if(
if mese == 2 )
printf("Febbraio\n") ;
sequenza di scelte, in else if(
if mese == 3 )
printf("Marzo\n") ;
funzione del valore di else if(
if mese == 4 )
printf("Aprile\n") ;
una variabile, occorre else if(
if mese == 5 )
una catena di if- printf("Maggio\n") ;
............................
else else if(
if mese == 9 )
printf("Settembre\n") ;
Lo stesso risultato si else if(
if mese == 10 )
printf("Ottobre\n") ;
può ottenere in forma else if(
if mese == 11 )
printf("Novembre\n") ;
più compatta else if(
if mese == 12 )
mediante l’istruzione else
printf("Dicembre\n") ;

switch printf("MESE ERRATO!\n") ;


4
Sintassi istruzione switch
switch ( e )
{
case v1:
e=...
A1 ;
e=v1 e=v2

altrimenti
break ;
e=v3
A1
case v2:
A2 ; A2
break ; A3
...
case v3:
A3 ; An
break ;
...........
default:
default
An ; 5
}
Precisazioni (1/2)

L’espressione e può essere una variabile oppure


un’espressione aritmetica
Il tipo di dato deve essere int, char o enum
Ciascun caso è identificato da una costante
L’espressione e viene confrontata con il valore
delle costanti v1...vn
Il tipo di dato deve essere compatibile
Ciascun caso è delimitato da case...break
Non vi sono parentesi graffe {...}

6
Precisazioni (2/2)

I casi possono apparire in qualsiasi ordine


Devono essere tutti diversi
Verrà selezionato al più un caso
Il caso default viene valutato se e solo se
nessuno degli altri casi è stato considerato
Opzionale, ma sempre consigliato

7
L’istruzione break

Il significato di break è di portare l’esecuzione


del programma fino al termine del costrutto
switch
“Salta alla chiusa graffa”: }
In assenza di break, l’esecuzione proseguirebbe
attraverso il caso successivo
Né il prossimo case, né eventuali parentesi graffe,
possono fermare l’esecuzione lineare

8
Casi multipli

Potrebbe essere necessario eseguire lo stesso


codice in corrispondenza di diversi valori
dell’espressione
È possibile accomunare più casi, indicandoli
consecutivamente
switch(
switch ora )
{
case 12: switch(
switch ora )
pranzo = 1 ; {
break; case 12:
break
case 13: case 13:
pranzo = 1 ; pranzo = 1 ;
break; break;
break
break
} }
9
Esempio
switch(
switch mese )
{
case 1:
printf("Gennaio\n") ; mesi3.c
break ;
case 2:
printf("Febbraio\n") ;
break ;
case 3:
printf("Marzo\n") ;
break ;
case 4:
printf("Aprile\n") ;
break ;
..............................
case 12:
printf("Dicembre\n") ;
break ;
default:
default
printf("MESE ERRATO!\n") ; 10
}
Istruzione switch
Istruzione atipica

L’istruzione switch è anomala sotto diversi punti


di vista:
Non utilizza le parentesi graffe per l’annidamento
delle istruzioni interne
Prevede solamente il controllo di uguaglianza
e==v
Richiede che i valori da confrontare siano costanti
break e default sono opzionali
Occorre una forte disciplina nell’utilizzarla
correttamente!

12
Errore frequente
switch(
switch ora )
{
È errato dimenticare case 12:
l’istruzione break al pranzo = 1 ;
case 20:
termine di ogni caso cena = 1 ;
break;
break
}
viene interpretato come
forma corretta
switch(
switch ora )
switch(
switch ora )
{
{
case 12:
case 12:
pranzo = 1 ;
pranzo = 1 ;
cena = 1 ;
break;
break
break;
break
case 20:
case 20:
cena = 1 ;
cena = 1 ;
break;
break
break;
break
} 13
}
Errore frequente

È errato utilizzare variabili come valori dei singoli


case
Se non è possibile usare costanti, allora utilizzare
delle catene di if-else

forma corretta
switch(
switch ora )
if(
if ora==orapranzo )
{
{
case orapranzo:
pranzo = 1 ;
pranzo = 1 ;
}
break;
break
else if(
if ora==oracena )
case oracena:
{
cena = 1 ;
cena = 1 ;
break;
break
}
} 14
Errore frequente

È errato pensare di poter fare confronti di ordine,


o confronti multipli
Utilizzare sequenze di if-else
Non usare else if se i casi non sono
mutuamente esclusivi
forma corretta
switch(
switch ora )
if(
if ora<12 )
{
{
case <12:
mattino = 1 ;
mattino = 1 ;
}
break;
break
if(
if ora==12 || 20 )
case 12 || 20:
{
pasti = 1 ;
pasti = 1 ;
break;
break
} 15
}
Suggerimento

Utilizzare sempre l’istruzione default


Anche se non vi è ragione apparente, è
opportuno che il programma intercetti valori
errati della variabile

switch(
switch ora )
{
......

default:
default
printf("Errore: valore inatteso
%d per la variabile ora\n", ora) ;
}

16
Suggerimento

Posizionare l’istruzione default come ultimo


caso dello switch
Potrebbe stare ovunque
Maggiore leggibilità
L’istruzione break finale si può omettere

17
Istruzione switch
Esercizio “Semplice calcolatrice”

Si scriva un programma in linguaggio C che


implementi una semplice calcolatrice in grado di
compiere le 4 operazioni (+ – × ÷) tra numeri
interi
Il programma presenti un semplice menù da cui
l’utente indichi (con un numero tra 1 e 4)
l’operazione da svolgere
In seguito il programma acquisirà da tastiera i
due operandi e stamperà il risultato
dell’operazione

19
Soluzione (1/4)

#include <stdio.h>
#include <stdlib.h>
calcola.c
int main(void)
{
int op ;
int a, b, c ;
int err ;

printf("Semplice calcolatrice\n\n") ;

printf("Inserisci 1 per la somma\n");


printf("Inserisci 2 per la sottrazione\n");
printf("Inserisci 3 per la moltiplicazione\n");
printf("Inserisci 4 per la divisione\n");

printf("La tua scelta:") ;


scanf("%d", &op) ;
20
Soluzione (2/4)

printf("Inserisci il primo operando: ") ;


scanf("%d", &a) ;

printf("Inserisci il secondo operando: ") ;


scanf("%d", &b) ;

21
Soluzione (3/4)

err = 0 ;
switch(
switch op )
{
case 1:
c = a + b ;
break ;
case 2:
c = a - b ;
break ;
case 3:
c = a * b ;
break ;
case 4:
c = a / b ;
break ;
default:
default
printf("Operazione errata\n") ;
err = 1 ;
} 22
Soluzione (3/4)

err = 0 ; case 4:
switch(
switch op ) if(
if b == 0 )
{ {
case 1: printf("Divisione per zero!\n");
c = a + b ;err = 1 ;
break ;}
case 2: else
c = a -{b ;
break ; c = a / b ;
case 3: }
c = a *break
b ; ;
break ;
case 4:
c = a / b ;
break ;
default:
default
printf("Operazione errata\n") ;
err = 1 ;
} 23
Soluzione (4/4)

if(
if err == 0 )
{
printf("Il risultato vale: %d\n", c) ;
}

24
Istruzione switch
Verifica “Semplice calcolatrice”

Analizziamo il codice dell’esercizio e


verifichiamone il corretto funzionamento calcola.c

26
Scelte ed alternative
Esercizi proposti

Esercizi sul calcolo del massimo


Esercizio “Equazione di secondo grado”
Esercizio “Re e Regina”

2
Esercizi proposti
Esercizio “Calcolo del massimo”

Si scriva un programma in linguaggio C che


acquisisca due numeri interi da tastiera e:
determini, stampando un messaggio opportuno
quale dei due numeri (il primo o il secondo) sia
maggiore
stampi il valore di tale numero
Si trascuri il caso in cui i due numeri siano uguali

4
Esempio

CALCOLO DEL MASSIMO TRA DUE NUMERI

Inserisci il primo numero: 10


Inserisci il secondo numero: -3

Il maggiore tra i numeri inseriti e' il primo


Il valore del numero maggiore e' 10

5
Analisi

Chiamiamo A e B i due numeri introdotti


dall’utente
Chiamiamo MAX il valore del maggiore tra i due
Occorre verificare la condizione A>B
Se A>B, allora MAX sarà pari ad A
Altrimenti, MAX sarà pari a B

6
Diagramma di flusso

Leggi A,B V F
max.c
A>B
Stampa Stampa
“primo” “secondo”

MAX=A MAX=B

Stampa
MAX

7
Esercizio “Calcolo del massimo a 3”

Si scriva un programma in linguaggio C che


acquisisca tre numeri interi da tastiera e:
determini, stampando un messaggio opportuno
quale dei tre numeri (il primo, il secondo o il
terzo) sia maggiore
stampi il valore di tale numero
Si trascuri il caso in cui i numeri siano uguali

8
Esempio

CALCOLO DEL MASSIMO TRA TRE NUMERI

Inserisci il primo numero: 10


Inserisci il secondo numero: -3
Inserisci il terzo numero: 15

Il maggiore tra i numeri inseriti e' il terzo


Il valore del numero maggiore e' 15

9
Analisi

Chiamiamo A, B, C i tre numeri inseriti


Si può procedere in due modi
Usando istruzioni if annidate
se A>B, allora controlla se A>C ...

max3-if.c

10
Analisi

Chiamiamo A, B, C i tre numeri inseriti


Si può procedere in due modi
Usando istruzioni if annidate
se A>B, allora controlla se A>C ...

max3-if.c

Usando espressioni condizionali complesse


se A>B e A>C ...

11
max3-and.c
Esercizi proposti
Esercizio “Equazione di secondo grado”

Data l’equazione
a x2 + b x + c = 0
con a, b e c inseriti da tastiera, determinare il
valore (o i valori) di x che risolvono l’equazione

13
Analisi

Ricordiamo la formula
risolutiva per le − b ± b 2 − 4ac
x1, 2 =
equazioni di secondo 2a
grado
La quantità sotto
radice è il ∆ = b 2 − 4ac
discriminante ∆
Vi sono vari casi
possibili
se a≠0 o a=0
se ∆>0, ∆=0 o ∆<0
14
Casi possibili

Caso Situazione Soluzione/i


Equazione di primo x = −c / b
a=0 grado Impossibile se b = 0, c ≠ 0
Indeterminata se b = 0, c = 0
a≠0 Due soluzioni reali − b ± b 2 − 4ac
x1, 2 =
∆>0 distinte 2a
a≠0 Due soluzioni reali −b
x1 = x2 =
∆=0 coincidenti 2a

a≠0 Due soluzioni x1, 2 = R ± iC


complesse coniugate
∆<0 R = − b 2a , C = b 2 − 4ac 2a
15
Soluzione

Acquisire a, b, c
Se a=0, risolvere l’equazione di secondogrado.c

primo grado
Ri-usiare il codice già scritto, facendo
attenzione al nome delle variabili
Calcolare il discriminante ∆
Il nome della variabile sarà delta
In funzione del segno di delta, usare la formula
opportuna

16
Esercizi proposti
Esercizio “Re e Regina”

Su una scacchiera 8x8 sono posizionati due pezzi:


il Re bianco e la Regina nera
Si scriva un programma in linguaggio C che,
acquisite le posizioni del Re e della Regina,
determini se la Regina è in posizione tale da
poter mangiare il Re
Le posizioni dei due pezzi sono identificate
mediante la riga e la colonna su cui si trovano,
espresse come numeri interi tra 1 e 8

18
Analisi
1 2 3 4 5 6 7 8

8 19
Analisi
1 2 3 4 5 6 7 8

1 Re bianco:
riga 3
2 colonna 2

3 Regina nera:
riga 6
4 colonna 6

8 20
Analisi
1 2 3 4 5 6 7 8

1 Re bianco:
riga 3
2 colonna 2

3 Regina nera:
riga 6
4 colonna 6

6
Il Re è salvo
7

8 21
Analisi
1 2 3 4 5 6 7 8

1 Re bianco:
riga 3
2 colonna 2

3 Regina nera:
riga 6
4 colonna 5

6
Il Re è
sotto scacco
7

8 22
Soluzione (1/2)
ck cq
Acquisire le coordinate dei pezzi
Re: rk, ck rk K

Regina: rq, cq rq Q

Controllare se la Regina
è sulla stessa riga del Re
rq==rk
è sulla stessa colonna del Re
cq==ck
è sulla stessa diagonale discendente del Re
è sulla stessa diagonale ascendente del Re

23
Soluzione (1/2) - Diagonali

Diagonale discendente
K
r–c costante
rq-cq == rk-ck Q

Diagonale ascendente K

r+c costante
rq+cq == rk+ck Q

24
Soluzione (2/2)

Conviene utilizzare una variabile


logica scacco scacco.c

inizializzare scacco=0
fare i vari tipi di controlli
se si verifica una condizione di scacco, porre
scacco=1
Al termine dei controlli, in funzione del valore di
scacco, stampare il messaggio opportuno
se scacco==0, il Re è salvo
se scacco==1, il Re è sotto scacco

25
Scelte ed alternative
Argomenti trattati

Ramificazione del flusso di esecuzione


Istruzione if-else
Condizioni Booleane semplici e complesse
Annidamento di istruzioni if-else
Istruzione switch

2
Tecniche di programmazione

Catene di istruzioni if-else if-...-else


Annidamento delle istruzioni o condizioni
Booleane complesse
Uso di variabili logiche per tenere traccia delle
condizioni incontrate
Istruzione switch per sostituire alcuni tipi di
catene if-else if
Uso di else e default per catturare condizioni
anomale

3
Suggerimenti

Analizzare sempre tutti i casi possibili prima di


iniziare a scrivere il programma
Abbondare con le parentesi graffe
Curare l’indentazione
Aggiungere commenti in corrispondenza della
clausola else e della graffa di chiusura

4
Materiale aggiuntivo

Sul CD-ROM
Testi e soluzioni degli esercizi trattati nei lucidi
Scheda sintetica
Esercizi risolti
Esercizi proposti
Esercizi proposti da altri libri di testo

5
Programmazione in C
Cicli ed iterazioni

La ripetizione
Istruzione while
Schemi ricorrenti nei cicli
Istruzione for
Approfondimenti
Esercizi proposti
Sommario

2
Riferimenti al materiale

Testi
Kernighan & Ritchie: capitolo 3
Cabodi, Quer, Sonza Reorda: capitolo 4
Dietel & Dietel: capitolo 4
Dispense
Scheda: “Cicli ed iterazioni in C”

3
Cicli ed iterazioni
La ripetizione

Concetto di ciclo
Struttura di un ciclo
Numero di iterazioni note
Numero di iterazioni ignote

5
La ripetizione
Flusso di esecuzione ciclico

È spesso utile poter A


ripetere alcune parti del
programma più volte
Nel diagramma di flusso, B
corrisponde a “tornare
indietro” ad un blocco C
precedente
Solitamente la V
D?
ripetizione è controllata
da una condizione F
booleana E
7
Flusso di esecuzione ciclico

Prima del A
ciclo

Istruzioni B
che vengono
ripetute C

Condizione V
D?
di ripetizione
F
Dopo il ciclo E
8
Errore frequente

Ogni ciclo porta in sé il rischio di un grave errore


di programmazione: il fatto che il ciclo venga
ripetuto indefinitamente, senza mai uscire
Il programmatore deve garantire che ogni ciclo,
dopo un certo numero di iterazioni, venga
terminato
La condizione booleana di controllo dell’iterazione
deve divenire falsa

9
Istruzioni eseguibili ed eseguite

Istruzioni eseguibili
Le istruzioni che fanno parte del programma
Corrispondono alle istruzioni del sorgente C
Istruzioni eseguite
Le istruzioni effettivamente eseguite durante una
specifica esecuzione del programma
Dipendono dai dati inseriti
Nel caso di scelte, alcune istruzioni eseguibili non
verranno eseguite
Nel caso di cicli, alcune istruzioni eseguibili
verranno eseguite varie volte
10
Notazione grafica (while)

V F
C

D
11
Notazione grafica (while)

A
Ingresso
Condizione

V F
C Corpo

Ritorno Uscita
D
12
Flussi di esecuzione

A Zero iterazioni

A
V F C → Falso
C D

D
13
Flussi di esecuzione

A Una iterazione

A
V F C → Vero
C B
C → Falso
D
B

D
14
Flussi di esecuzione

A Due iterazioni

A
V F C → Vero
C B
C → Vero
B
B C → Falso
D

D
15
Notazione grafica (do-while)

V F
C

D
16
Notazione grafica (do-while)

A
Ingresso
Corpo

B
Condizione
V F
C
Ritorno
Uscita
D
17
Flussi di esecuzione

A Una iterazione

A
B
C → Falso
B
D
V F
C

D
18
Flussi di esecuzione

A Due iterazioni

A
B
C → Vero
B
B
C → Falso
V F D
C

D
19
Flussi di esecuzione

A Tre iterazioni

A
B
C → Vero
B
B
C → Vero
V F B
C C → Falso
D

D
20
La ripetizione
Problemi

Nello strutturare un ciclo occorre garantire:


Che il ciclo possa terminare
Che il numero di iterazioni sia quello desiderato
Il corpo centrale del ciclo può venire eseguito più
volte:
La prima volta lavorerà con variabili che sono state
inizializzate al di fuori del ciclo
Le volte successive lavorerà con variabili che
possono essere state modificare nell’iterazione
precedente
Garantire la correttezza sia della prima, che delle
altre iterazioni 22
Anatomia di un ciclo (1/5)

Conviene concepire il ciclo come 4 fasi


Inizializzazione
Condizione di ripetizione
Corpo
Aggiornamento

23
Anatomia di un ciclo (2/5)

Conviene concepire il ciclo come 4 fasi


Inizializzazione
Assegnazione del valore iniziale a tutte le variabili
che vengono lette durante il ciclo (nel corpo o nella
condizione)
Condizione di ripetizione
Corpo
Aggiornamento

24
Anatomia di un ciclo (3/5)

Conviene concepire il ciclo come 4 fasi


Inizializzazione
Condizione di ripetizione
Condizione, di solito inizialmente vera, che al
termine del ciclo diventerà falsa
Deve dipendere da variabili che saranno modificate
all’interno del ciclo (nel corpo o nell’aggiornamento)
Corpo
Aggiornamento

25
Anatomia di un ciclo (4/5)

Conviene concepire il ciclo come 4 fasi


Inizializzazione
Condizione di ripetizione
Corpo
Le istruzioni che effettivamente occorre ripetere
Sono lo scopo per cui il ciclo viene realizzato
Posso usare le variabili inizializzate
Posso modificare le variabili
Aggiornamento

26
Anatomia di un ciclo (5/5)

Conviene concepire il ciclo come 4 fasi


Inizializzazione
Condizione di ripetizione
Corpo
Aggiornamento
Modifica di una o più variabili in grado di aggiornare
il valore della condizione di ripetizione
Tengono “traccia” del progresso dell’iterazione

27
La ripetizione
Tipologie di cicli

Cicli in cui il numero di iterazioni sia noto a priori,


ossia prima di entrare nel ciclo stesso
Solitamente si usa una variabile “contatore”
L’aggiornamento consiste in un incrememto o
decremento della variabile
Cicli in cui il numero di iterazioni non sia noto a
priori, ma dipenda dai dati elaborati nel ciclo
Solitamente si una una condizione dipendente da
una variabile letta da tastiera oppure calcolata nel
corpo del ciclo
Difficile distinguere il corpo dall’aggiornamento
Problema di inizializzazione 29
Cicli con iterazioni note

c=0
Inizializzazione

V F Condizione
c<N

Corpo
corpo

Aggiornamento
c=c+1

30
Cicli con iterazioni note

c=0 Forma 0...N-1


Prima iterazione:
c=0
V F
c<N Ultima iterazione:
c=N-1
Corpo ripetuto:
corpo
N volte
Al termine del ciclo
c=c+1 c=N
condizione falsa
31
Cicli con iterazioni note

c=1 Forma 1...N


Prima iterazione:
c=1
V F
c≤N Ultima iterazione:
c=N
Corpo ripetuto:
corpo
N volte
Al termine del ciclo
c=c+1 c=N+1
condizione falsa
32
Cicli con iterazioni note

c=N Forma N...1


Prima iterazione:
c=N
V F
c>0 Ultima iterazione:
c=1
Corpo ripetuto:
corpo
N volte
Al termine del ciclo
c=c–1 c=0
condizione falsa
33
Cicli con iterazioni note

c=N–1 Forma N-1...0


Prima iterazione:
c=N-1
V F
c≥0 Ultima iterazione:
c=0
Corpo ripetuto:
corpo
N volte
Al termine del ciclo
c=c–1 c=-1
condizione falsa
34
Esempio

Acquisire da tastiera una sequenza di numeri


interi e stamparne la somma.
Il programma
inizialmente chiede all’utente quanti numeri
intende inserire
in seguito richiede uno ad uno i dati
infine stampa la somma

35
Soluzione

leggi N
V F
c<N

tot = 0
leggi dato
stampa tot
c=0
tot = tot + dato

c=c+1
36
La ripetizione
Cicli con iterazioni ignote

Non esiste uno schema generale


Esempio:
Acquisire da tastiera una sequenza di numeri interi
e stamparne la somma.
Il termine della sequenza viene indicato inserendo
un dato pari a zero.

38
Soluzione parziale

V F
?????

tot = 0
leggi dato
stampa tot
tot = tot + dato

39
Soluzione 1

dato = 7 V F
dato ≠ 0

tot = 0
leggi dato
stampa tot
tot = tot + dato

40
Soluzione 2

leggi dato V F
dato ≠ 0

tot = dato
leggi dato
stampa tot
tot = tot + dato

41
Soluzione 3

leggi dato
tot = 0
tot = tot + dato
stampa tot

dato ≠ 0
V F

42
Errore frequente

Dimenticare l’inizializzazione di una variabile


utilizzata all’interno del ciclo

dato = 7 V F
dato ≠ 0

tot = 0
leggi dato
stampa tot
tot = tot + dato

43
Errore frequente

Dimenticare l’incremento della variabile contatore

leggi N
V F
c<N

tot = 0
leggi dato
stampa tot
c=0
tot = tot + dato

c=c+1 44
Errore frequente

Dimenticare di inizializzare le altre variabili (oltre


al contatore)

leggi N
V F
c<N

tot = 0
leggi dato
stampa tot
c=0
tot = tot + dato

c=c+1 45
Cicli ed iterazioni
Istruzione while

Sintassi dell’istruzione
Esercizio “Media aritmetica”
Esecuzione del programma
Cicli while annidati
Esercizio “Quadrato”

2
Istruzione while
Istruzioni di ripetizione in C

Nel linguaggio C esistono tre distinte istruzioni di


iterazione
while
do-while
for
La forma più generale è l’istruzione di tipo while
L’istruzione do-while si usa in taluni contesti
(es. controllo errori di input)
L’istruzione for è usatissima, soprattutto per
numero di iterazioni noto
4
Istruzione while

while ( C ) V F
C
{
B ;
} B

5
Comportamento del while

1. Valuta la condizione C
2. Se C è falsa, salta
completamente l’iterazione
while ( C ) e vai all’istruzione che
{ segue la }
B ; 3. Se C è vera, esegui una
} volta il blocco di
istruzioni B
4. Al termine del blocco B,
ritorna al punto 1. per
rivalutare la condizione C
6
Numero di iterazioni note

int i, N ;

i = 0 ;
while ( i < N )
{
/* Corpo dell’iterazione */
...

i = i + 1 ;
}

7
Esempio

int i ; num1-10.c

i = 1 ;
while ( i <= 10 )
{
printf("Numero = %d\n", i) ;
i = i + 1 ;
}

8
Esempio

int i, n ;
fatt.c
float f ;
.... /* leggi n */ ....
i = 2 ;
f = 1.0 ;
while ( i <= n )
{
f = f * i ;
i = i + 1 ;
}
printf("Fattoriale di %d = %f\n",
n, f);
9
Particolarità

Nel caso in cui il corpo del while sia composto


di una sola istruzione, si possono omettere le
parentesi graffe
Non succede quasi mai

while ( C )
{ while ( C )
B ; B ;
}
10
Istruzione while
Esercizio “Media aritmetica”

Si realizzi un programma C in grado di


Leggere un numero naturale n
Leggere n numeri reali
Calcolare e visualizzare la media aritmetica di tali
numeri
Osservazione
Attenzione al caso in cui n≤0

12
Analisi

MEDIA ARITMETICA

Introduci n: 3
Ora introduci 3 valori
Valore 1: 6.5
Valore 2: 2.5
Valore 3: 3.0

Risultato: 4.000000

13
Algoritmo

Acquisisci n
Inizializza totale = 0
Ripeti n volte
Acquisisci un dato
Somma il dato al totale dei dati acquisiti
Calcola e stampa la media = totale / n

14
Algoritmo

Acquisisci n
Se n>0
Inizializza totale = 0
Ripeti n volte
Acquisisci un dato
Somma il dato al totale dei dati acquisiti
Calcola e stampa la media = totale / n
Altrimenti stampa messaggio di errore

15
Traduzione in C (1/3)

#include <stdio.h>
#include <stdlib.h> media.c

int main
main(
(void)
void
{
int i, n ;
float dato ;
float somma ;

printf("MEDIA ARITMETICA\n");

/* Leggi n */
printf("Introduci n: ");
scanf("%d", &n) ;

16
Traduzione in C (2/3)

/* Controlla la correttezza del valore n */


media.c
if(
if n>0 )
{
/* n corretto... procedi! */
....vedi lucido seguente....
}
else
{
/* n errato in quanto e' n <= 0 */
printf("Non ci sono dati da inserire\n");
printf("Impossibile calcolare la media\n");
}

} /* main */

17
Traduzione in C (3/3)

/* Leggi i valori e calcola la media */


printf("Ora immetti %d valori\n", n) ;
media.c
somma = 0.0 ;
i = 0 ;
while(
while i < n )
{
printf("Valore %d: ", i+1) ;
scanf("%f", &dato) ;

somma = somma + dato ;

i = i + 1 ;
}

printf("Risultato: %f\n", somma/n) ;


18
Istruzione while
Verifica “Media aritmetica”

media.c

20
Istruzione while
Annidamento di cicli

All’interno del corpo del ciclo while è possibile


racchiudere qualsiasi altra istruzione C
In particolare, è possibile racchiudere
un’istruzione while all’interno di un’altra
istruzione while
In tal caso, per ogni singola iterazione del ciclo
while più esterno, vi saranno tutte le iterazioni
previste per il ciclo più interno

22
Cicli while annidati

V F
C

23
Cicli while annidati

V F V F
C C

V F
C2

B
B2

24
Cicli while annidati

V F
C
while(
while C )
{ V F
while(
while C2 ) C2
{
B2 ;
} B2
}

25
Esempio

i = 0 ;
while(
while i<N )
conta99.c
{
j = 0 ;
while(
while j<N )
{
printf("i=%d - j=%d\n", i, j);

j = j + 1 ;
}

i = i + 1 ;
}
26
Esempio

i = 0 ;
while(
while i<N )
{ conta99.c
j = 0 ;
while(
while j<N )
{
printf("i=%d - j=%d\n", i, j);
j = j + 1 ;
} i=0 - j=0
i = i + 1 ; i=0 - j=1
} i=0 - j=2
i=1 - j=0
i=1 - j=1
i=1 - j=2
i=2 - j=0
i=2 - j=1
i=2 - j=2 27
Istruzione while
Esercizio “Quadrato”

Si realizzi un programma C in grado di


Leggere un numero naturale n
Visualizzare un quadrato di lato n costituito da
asterischi

29
Analisi

QUADRATO
Introduci n: 5
*****
*****
*****
*****
*****

30
Algoritmo

Acquisisci n
Ripeti n volte
Stampa una riga di n asterischi

31
Algoritmo

Acquisisci n
Ripeti n volte
Stampa una riga di n asterischi

Ripeti n volte
Stampa un singolo
asterisco
Vai a capo

32
Traduzione in C

i = 0 ;
while(
while i<n ) quadrato.c
{
j = 0 ;
while(
while j<n )
{
printf("*") ;
j = j + 1 ;
}

printf("\n");

i = i + 1 ;
}

33
Traduzione in C

i = 0 ;
while(
while i<n ) quadrato.c
{
j = 0 ;
while(
while j<n )
{ Ripeti n volte
printf("*") ;
j = j + 1 ;
}
Stampa una riga
di n asterischi
printf("\n");

i = i + 1 ;
}

34
Traduzione in C

i = 0 ;
while(
while i<n ) quadrato.c
{
j = 0 ;
while(
while j<n )
{ Stampa n
printf("*") ;
j = j + 1 ;
asterischi
}
Vai a capo
printf("\n");

i = i + 1 ;
}

35
Traduzione in C

i = 0 ;
while(
while i<n ) quadrato.c
{
j = 0 ;
while(
while j<n )
{ Ripeti n volte
printf("*") ;
j = j + 1 ;
} Stampa un
printf("\n"); asterisco
i = i + 1 ;
}

36
Cicli ed iterazioni
Schemi ricorrenti nei cicli

Contatori
Accumulatori
Flag
Esistenza e universalità

2
Schemi ricorrenti nei cicli
Contatori

Spesso in un ciclo è utile sapere


Quante iterazioni sono state fatte
Quante iterazioni rimangono da fare
Quale numero di iterazione sia quella corrente
Per questi scopi si usano delle “normali” variabili
intere, dette contatori
Inizializzate prima del ciclo
Incrementate/decrementate ad ogni iterazione
Oppure incrementate/decrementate ogni volta che
si riscontra una certa condizione

4
Contatori

int i, N ;
...
i = 0 ;
while ( i < N )
{
printf("Iterazione %d\n", i+1) ;
i = i + 1 ;
}

5
Esempio

Scrivere un programma in C che


legga dall’utente 10 numeri interi
al termine dell’inserimento, stampi
quanti tra i numeri inseriti sono positivi
quanti tra i numeri inseriti sono negativi
quanti tra i numeri inseriti sono nulli

6
Soluzione (1/3)

contaposneg.c

int npos, nneg, nzero ;

....

npos = 0 ;
nneg = 0 ;
nzero = 0 ;

7
Soluzione (2/3)

i = 0 ;
while(
while i<n )
{ contaposneg.c

printf("Inserisci dato %d: ", i+1);


scanf("%d", &dato);

if(
if dato>0 )
npos = npos + 1 ;
else if(
if dato<0 )
nneg = nneg + 1 ;
else
nzero = nzero + 1 ;

i = i + 1 ;
}
8
Soluzione (3/3)

contaposneg.c

printf("Numeri positivi: %d\n", npos);


printf("Numeri negativi: %d\n", nneg);
printf("Numeri nulli: %d\n", nzero);

9
Schemi ricorrenti nei cicli
Accumulatori (1/2)

Spesso in un ciclo occorre calcolare un valore


TOT che dipende dall’insieme dei valori analizzati
nelle singole iterazioni
Esempi:
TOT = sommatoria dei dati analizzati
TOT = produttoria dei dati analizzati
TOT = massimo, minimo dei dati analizzati
1
2.1e7 TOT
184
99
-7 42
3.5
-9 11
Accumulatori (2/2)

In questo caso si usano delle variabili (intere o


reali) dette accumulatori
Inizializzare TOT al valore che dovrebbe avere in
assenza di dati (come se fosse n=0)
Ad ogni iterazione, aggiornare TOT tenendo conto
del dato appena analizzato
Al termine del ciclo, TOT avrà il valore desiderato

12
Esempio: somma primi 10 interi

Si scriva un programma in C che stampi il valore


della somma dei primi 10 numeri interi

13
Analisi

Inizializzazione di TOT
Qual è la somma dei primi 0 numeri interi?
TOT = 0
Aggiornamento di TOT
Sapendo che TOT è la somma dei primi (i-1)
numeri interi, e sapendo che il prossimo numero
intero da sommare vale i, quanto dovrà valere
TOT?
TOT = TOT + i

14
Soluzione: somma primi 10 interi

int tot ;

i = 1 ;
tot = 0 ;
while(
while i<=10 )
{
tot = tot + i ;

i = i + 1 ;
}

printf("La somma dei numeri da 1 a 10 ");


printf("vale %d\n", tot) ;
15
Esempio: fattoriale di K

Si scriva un programma in C che, dato un


numero intero K, calcoli e stampi il fattoriale di K
TOT = K!

i=K
TOT = K != ∏ i
i =1

16
Analisi

Inizializzazione di TOT
Qual è il valore del fattoriale per K=0?
TOT = 1.0
Aggiornamento di TOT
Sapendo che TOT è pari al fattoriale di i-1, e
sapendo che il prossimo numero da considerare è
i, quanto dovrà valere TOT?
TOT = TOT * i

17
Soluzione: fattoriale di K

float tot ;

i = 1 ;
tot = 1.0 ;
while(
while i<=K )
{
tot = tot * i ;

i = i + 1 ;
}

printf("Il fattoriale di %d ", K);


printf("vale %f\n", tot) ;
18
Esempio: massimo

Si scriva un programma in C che


acquisisca da tastiera N numeri reali
stampi il valore massimo tra i numeri acquisiti

19
Analisi

Inizializzazione di TOT
Qual è il valore del massimo in un insieme di 0
numeri?
Non esiste, non è definito!
TOT = numero molto piccolo, che non possa
certamente essere scambiato con il massimo
Aggiornamento di TOT
Sapendo che TOT è pari al massimo dei primi i-1
dati, e sapendo che il prossimo dato da
considerare è d, quanto dovrà valere TOT?
Se d<=TOT, allora TOT rimane il massimo
Se d>TOT, allora il nuovo massimo sarà TOT=d
20
Esempio: massimo

int max ;

i = 0 ;
max = INT_MIN ;
while(
while i<N )
{
scanf("%d", &dato) ;
if(dato>max)
if
max = dato ;

i = i + 1 ;
}

printf("Massimo = %d\n", max);


21
Schemi ricorrenti nei cicli
Flag, indicatori, variabili logiche

Spesso occorre analizzare una serie di dati per


determinare se si verifica una certa condizione
Esempi:
Tra i dati inseriti esiste il numero 100?
Esistono due numeri consecutivi uguali?

1
2.1e7
184
SI
99
-7
3.5
-9
NO

23
Problemi

Nel momento in cui si “scopre” il fatto, non si può


interrompere l’elaborazione ma occorre
comunque terminare il ciclo
Al termine del ciclo, come fare a “ricordarsi” se si
era “scoperto” il fatto o no?

24
Una possibile soluzione

Per sapere
Se una certa condizione si verifica
è possibile contare
Quante volte quella condizione si verifica
ed in seguito verificare
Verificare se il conteggio è diverso da zero
Ci riconduciamo ad un problema risolubile per
mezzo di una variabile contatore

25
Esempio 1

Tra i dati inseriti esiste


il numero 100?

Conta quante volte tra i


dati inseriti compare il
numero 100

Il conteggio è > 0 ?

26
Soluzione (1/3)

int i, n ; trova100v1.c

int dato ;
int conta ;
/* conta il numero di "100" letti */

printf("TROVA 100\n");

n = 10 ;

printf("Inserisci %d numeri\n", n);

27
Soluzione (2/3)

conta = 0 ;
trova100v1.c
i = 0 ;
while(
while i<n )
{
printf("Inserisci dato %d: ", i+1);
scanf("%d", &dato);

if(
if dato == 100 )
conta = conta + 1 ;

i = i + 1 ;
}

28
Soluzione (3/3)

trova100v1.c

if(
if conta != 0 )
printf("Ho trovato il 100\n");
else
printf("NON ho trovato il 100\n");

29
Esempio 2

Esistono due numeri


consecutivi uguali?

Conta quante volte due


numeri consecutivi sono
uguali

Il conteggio è > 0 ?

30
Soluzione (1/3)

int i, n ;
ugualiv1.c
int dato ;
int precedente ;
int conta ;
/* conta il numero di "doppioni" trovati */

printf("TROVA UGUALI\n");

n = 10 ;

printf("Inserisci %d interi\n", n);

31
Soluzione (2/3)

conta = 0 ;

precedente = INT_MAX ; ugualiv1.c

/* ipotesi: l'utente non lo inserira' mai */

i = 0 ;
while(
while i<n )
{
printf("Inserisci dato %d: ", i+1);
scanf("%d", &dato);

if(
if dato == precedente )
conta = conta + 1 ;

precedente = dato ;

i = i + 1 ; 32
}
Soluzione (3/3)

ugualiv1.c

if(
if conta != 0 )
printf("Ho trovato dei numeri
consecutivi uguali\n");
else
printf("NON ho trovato dei numeri
consecutivi uguali\n");

33
Svantaggi

Il contatore determina quante volte si verifica la


condizione ricercata
In realtà non mi serve sapere quante volte, ma
solo se si è verificata almeno una volta
Usiamo un contatore “degenere”, che una volta
arrivato ad 1 non si incrementa più

34
Variabili “flag”

Variabili intere che possono assumere solo due


valori
Variabile = 0 ⇒ la condizione non si è verificata
Variabile = 1 ⇒ la condizione si è verificata
Viene inizializzata a 0 prima del ciclo
Se la condizione si verifica all’interno del ciclo,
viene posta a 1
Al termine del ciclo si verifica il valore
Sinonimi: Flag, Variabile logica, Variabile
booleana, Indicatore
35
Analisi

i=0

V F
i<N

Controlla se esiste
un dato con certe
caratteristiche

i=i+1
36
Analisi

flag = 0 i=0

V F
i<N

V dato? F

flag = 1

i=i+1
37
Analisi

flag = 0 i=0 V F
flag = 1?

V F
i<N

V dato? F Trovato Non trovato

flag = 1

i=i+1
38
Analisi

flag = 0 i=0 V F
flag = 1?

V F
i<N

V dato? F Trovato Non trovato

flag = 1

i=i+1
39
Analisi

flag = 0 i=0 V F
flag = 1?

V F
i<N

V dato? F Trovato Non trovato

flag = 1

i=i+1
40
Soluzione con flag – esempio 1
int trovato ; /* ho visto il numero "100"? */
....
trovato = 0 ;
trova100v2.c

i = 0 ;
while(
while i<n )
{
scanf("%d", &dato);

if(
if dato == 100 )
trovato = 1 ;

i = i + 1 ;
}

if(
if trovato != 0 )
printf("Trovato il numero 100\n");
else 41
printf("NON trovato il numero 100\n");
Soluzione con flag – esempio 2
int doppi ; /* trovati "doppioni" ? */
...
doppi = 0 ;
ugualiv2.c

precedente = INT_MAX ;
i = 0 ;
while(
while i<n )
{
scanf("%d", &dato);

if(
if dato == precedente )
doppi = 1 ;

precedente = dato ;
i = i + 1 ;
}

if(
if doppi != 0 ) 42
printf("Trovati consecutivi uguali\n");
Schemi ricorrenti nei cicli
Ricerca di esistenza o universalità

L’utilizzo dei flag è può essere utile quando si


desiderino verificare delle proprietà su un certo
insieme di dati
È vero che tutti i dati verificano la proprietà?
È vero che almeno un dato verifica la proprietà?
È vero che nessun dato verifica la proprietà?
È vero che almeno un dato non verifica la
proprietà?

44
Esempi

Verificare che tutti i dati inseriti dall’utente siano


positivi
Determinare se una sequenza di dati inseriti
dall’utente è crescente
Due numeri non sono primi tra loro se hanno
almeno un divisore comune
esiste almeno un numero che sia divisore dei due
numeri dati
Un poligono regolare ha tutti i lati di lunghezza
uguale
ogni coppia di lati consecutivi ha uguale lunghezza
45
Formalizzazione

È vero che tutti i dati verificano la proprietà?


∀x : P(x)
È vero che almeno un dato verifica la proprietà?
∃x : P(x)
È vero che nessun dato verifica la proprietà?
∀x : not P(x)
È vero che almeno un dato non verifica la
proprietà?
∃x : not P(x)

46
Realizzazione (1/2)

Esistenza: ∃x : P(x)
Inizializzo flag F = 0

Ciclo su tutte le x
Se P(x) è vera
Pongo F = 1

Se F = 1, l’esistenza
è dimostrata
Se F = 0, l’esistenza
è negata
47
Realizzazione (1/2)

Esistenza: ∃x : P(x) Universalità: ∀x : P(x)


Inizializzo flag F = 0 Inizializzo flag F = 1

Ciclo su tutte le x Ciclo su tutte le x


Se P(x) è vera Se P(x) è falsa
Pongo F = 1 Pongo F = 0

Se F = 1, l’esistenza Se F = 1, l’universalità
è dimostrata è dimostrata
Se F = 0, l’esistenza Se F = 0, l’universalità
è negata è negata
48
Realizzazione (2/2)

Esistenza: ∃x : not P(x) Universalità: ∀x : not P(x)


Inizializzo flag F = 0 Inizializzo flag F = 1

Ciclo su tutte le x Ciclo su tutte le x


Se P(x) è falsa Se P(x) è vera
Pongo F = 1 Pongo F = 0

Se F = 1, l’esistenza è Se F = 1, l’universalità è
dimostrata dimostrata
Se F = 0, l’esistenza è Se F = 0, l’universalità è
negata negata
49
Esempio 1

Verificare che tutti i dati inseriti dall’utente siano


positivi
int positivi ;
...
positivi = 1 ;
i = 0 ;
while(
while i<n )
{
...
if(
if dato <= 0 )
positivi = 0 ;
....
i = i + 1 ;
}
if(
if positivi == 1 )
printf("Tutti positivi\n"); 50
Esempio 2

Determinare se una sequenza di dati inseriti


dall’utente è crescente
int crescente ;
...
crescente = 1 ;
precedente = INT_MIN ;
i = 0 ;
while(
while i<n )
{
...
if(
if dato < precedente )
crescente = 0 ;
precedente = dato ;
....
i = i + 1 ;
} 51
Esempio 3

Due numeri non sono primi tra loro se hanno


almeno un divisore comune
int A, B ;
int noprimi ;
...
noprimi = 0 ;
i = 2 ;
while(
while i<=A )
{
...
if(
if (A%i==0) && (B%i==0) )
noprimi = 1 ;
....
i = i + 1 ;
} 52
Esempio 4

Un poligono regolare ha tutti i lati di lunghezza


uguale
int rego ;
...
rego = 1 ;
precedente = INT_MIN ;
i = 0 ;
while(
while i<n )
{
...
if(
if lato != precedente )
rego = 0 ;
precedente = lato ;
....
i = i + 1 ;
} 53
Errore frequente

Resettare il flag al valore di inizializzazione,


dimenticando di fatto eventuali condizioni
incontrate in precedenza

trovato = 0 ; trovato = 0 ;
i = 0 ; i = 0 ;
while(
while i<n ) while(
while i<n )
{ {
... ...
if(
if dato == 100 ) if(
if dato == 100 )
trovato = 1 ; trovato = 1 ;
else
trovato = 0 ;
... ...
i = i + 1 ; i = i + 1 ;
} } 54
Errore frequente

Passare ai fatti non appena trovato il primo


elemento che soddisfa la proprietà

trovato = 0 ;
trovato = 0 ;
i = 0 ;
i = 0 ;
while(
while i<n )
while(
while i<n )
{
{
...
...
if(
if dato == 100 )
if(
if dato == 100 )
{
trovato = 1 ;
trovato = 1 ;
....
printf("W!\n");
i = i + 1 ;
}
}
...
if(trovato==1)
i = i + 1 ; 55
printf("W!\n");
}
Errore frequente

Pensare che al primo fallimento si possa


determinare che la proprietà è falsa

trovato = 0 ; trovato = 0 ;
i = 0 ; i = 0 ;
while(
while i<n ) while(
while i<n )
{ {
... ...
if(
if dato == 100 ) if(
if dato == 100 )
trovato = 1 ; trovato = 1 ;
else ....
printf("NO!\n"); i = i + 1 ;
... }
i = i + 1 ; if(trovato==0)
} printf("NO!\n"); 56
Cicli ed iterazioni
Istruzione for

Sintassi dell’istruzione
Operatori di autoincremento
Cicli for annidati

2
Istruzione for
Istruzione for

L’istruzione fondamentale è while


La condizione solitamente valuta una variabile di
controllo
Occorre ricordarsi l’inizializzazione della variabile di
controllo
Occorre ricordarsi di aggiornare (incrementare, ...)
la variabile di controllo
L’istruzione for rende più semplice ricordare
queste cose

4
Istruzione for

V F
for ( I; C; A ) C
{
B ;
} B

5
Istruzione for
Istruzione di
inizializzazione I

V F
for ( I; C; A ) C
{
B ; Istruzione di
} aggiornamento B

Corpo Condizione
6
Esempio

num1-10v2.c

int i ;

for ( i=1; i<=10; i=i+1 )


{
printf("Numero = %d\n", i) ;
}

7
Equivalenza for
while
forwhile

I ;
for ( I; C; A ) while ( C )
{ {
B ; B ;
} A ;
}

8
Esempio

int i ;
int i ;
i = 1 ;
for ( i=1; i<=10; i=i+1 ) while ( i <= 10 )
{ {
printf("%d\n", i) ; printf("%d\n", i) ;
} i = i + 1 ;
}

9
Utilizzo prevalente (1/2)

Le istruzioni di inizializzazione I e di
aggiornamento A possono essere qualsiasi
Solitamente I viene utilizzata per inizializzare il
contatore di controllo del ciclo, e quindi è del tipo
i = 0
Solitamente A viene utilizzata per incrementare
(o decrementare) il contatore, e quindi è del tipo
i = i + 1
for ( I; C; A )
{
B ;
} 10
Utilizzo prevalente (2/2)

L’istruzione for può sostituire un qualsiasi ciclo


while
Solitamente viene utilizzata, per maggior
chiarezza, nei cicli con numero di iterazioni noto a
priori

11
Cicli for con iterazioni note

int i ; int i ;

for ( i=0; i<N; i=i+1 ) for ( i=1; i<=N; i=i+1 )


{ {
....... .......
} }

int i ; int i ;

for ( i=N; i>0; i=i-1 ) for ( i=N-1; i>=0; i=i-1)


{ {
....... .......
} }
12
Casi particolari (1/6)

Se non è necessario inizializzare nulla, si può


omettere l’istruzione I
for(
for ; i != 0 ; i = i – 1 )
La condizione C viene comunque valutata prima
della prima iterazione, pertanto le variabili
coinvolte dovranno essere inizializzate prima
dell’inizio del ciclo
Il simbolo ; è sempre necessario

for ( I; C; A )
{
B ;
} 13
Casi particolari (2/6)

Se l’aggiornamento viene fatto nel ciclo, si può


omettere l’istruzione A
for(
for dato = INT_MIN; dato != 0 ; )
La responsabilità di aggiornare la variabile di
controllo (dato) è quindi del corpo B del ciclo
Il simbolo ; è sempre necessario

for ( I; C; A )
{
B ;
} 14
Casi particolari (3/6)

Se occorre inizializzare più di una variabile, è


possibile farlo separando le varie inizializzazioni
con un simbolo ,
for(
for i=0, j=0; i<N; i=i+1 )
Solitamente uno solo è il contatore del ciclo, gli
altri saranno altri contatori, accumulatori o flag

for ( I; C; A )
{
B ;
} 15
Casi particolari (4/6)

Se occorre aggiornare più di una variabile, è


possibile farlo separando i vari aggiornamenti con
un simbolo ,
for(
for i=0; i<N; i=i+1, k=k-1 )

for ( I; C; A )
{
B ;
} 16
Casi particolari (5/6)

Nel caso in cui si ometta sia I che A, il ciclo for


degenera nel ciclo while equivalente
for(
for ; i<N; )
while(
while i<N )

for ( I; C; A )
{
B ;
} 17
Casi particolari (6/6)

È possibile omettere la condizione C, in tal caso


viene considerata come sempre vera
for(
for i=0; ; i=i+1)
Questo costrutto genera un ciclo infinito. È
necessario che il ciclo venga interrotto con un altro
meccanismo (break, return, exit)
Talvolta si incontra anche un ciclo infinito “puro”
for(
for ; ; )

for ( I; C; A )
{
B ;
} 18
Istruzione for
Istruzione di aggiornamento

Nella maggioranza dei casi, l’istruzione di


aggiornamento A consiste in un incremento
i = i + 1
oppure in un decremento
i = i – 1
Il linguaggio C dispone di operatori specifici per
semplificare la sintassi di queste operazioni
frequenti
for ( I; C; A )
{
B ;
} 20
Operatore di auto-incremento

a++ ;
a = a + 1 ;
++a ;

a-- ;
a = a - 1 ;
--a ;

21
Cicli for con iterazioni note

int i ; int i ;

for ( i=0; i<N; i++ ) for ( i=1; i<=N; i++ )


{ {
....... .......
} }

int i ; int i ;

for ( i=N; i>0; i-- ) for ( i=N-1; i>=0; i-- )


{ {
....... .......
} }
22
Istruzione for
Annidamento di cicli

Come sempre, all’interno del corpo B di un ciclo


(for o while) è possibile annidare altri cicli
(for o while)
Non vi è limite al livello di annidamento
I cicli più interni sono sempre eseguiti “più
velocemente” dei cicli più esterni

24
Esempio

conta99v2.c

for(
for i=0; i<N; i++ )
{
for(
for j=0; j<N; j++ )
{
printf("i=%d - j=%d\n", i, j);
}
}

25
Esercizio

Si scriva un programma in linguaggio C che


acquisisca da tastiera 10 numeri
per ciascuno di tali numeri determini se è un
numero primo, stampando immediatamente un
messaggio opportuno
al termine, se nessuno tra i numeri inseriti era un
numero primo, stampi un messaggio opportuno

26
Analisi (1/2)

TROVA PRIMI
Inserisci 4 numeri interi

Inserisci dato 1: 6
Inserisci dato 2: 3
E' un numero primo
Inserisci dato 3: 4
Inserisci dato 4: 5
E' un numero primo

27
Analisi (2/2)

TROVA PRIMI
Inserisci 4 numeri interi

Inserisci dato 1: 4
Inserisci dato 2: 6
Inserisci dato 3: 8
Inserisci dato 4: 9

Non c'erano numeri primi

28
Numero primo

10primi.c

primo = 1 ;
for(
for j=2; j<dato; j++)
{
if(
if dato%j == 0 )
primo = 0 ;
}

29
Stampa se non ci sono primi

for( i=0; i<n; i++ )


10primi.c
{
scanf("%d", &dato);

....determina se è un numero primo....

if( primo == 1 )
{
printf("E' un numero primo\n");
}
}

30
Stampa se è un primo

trovato = 0 ;
10primi.c
for(
for i=0; i<n; i++ )
{
....acquisisci dato e determina se è un numero primo....

if(
if primo == 1 )
{
printf("E' un numero primo\n");
trovato = 1 ;
}
}
if(
if trovato == 0 )
printf("Non ci sono primi\n") ;
31
Vista d’insieme

trovato = 0 ;
for(
for i=0; i<n; i++ )
{
10primi.c
scanf("%d", &dato);

primo = 1 ;
for(
for j=2; j<dato; j++ )
{
if(
if dato%j == 0 )
primo = 0 ;
}

if(
if primo == 1 )
{
printf("E' un numero primo\n");
trovato = 1 ;
}
}

if(
if trovato == 0 )
printf("Non c'erano numeri primi\n");
32
Vista d’insieme

trovato = 0 ;
for(
for i=0; i<n; i++ )
{
scanf("%d", &dato);
Ciclo esterno
primo = 1 ;
for(
for j=2; j<dato; j++ )
{
if(
if dato%j == 0 )
primo = 0 ;
} Ciclo interno
if(
if primo == 1 )
{
printf("E' un numero primo\n");
trovato = 1 ;
}
}

if(
if trovato == 0 )
printf("Non c'erano numeri primi\n");
33
Vista d’insieme

trovato = 0 ; Flag interno:


for(
for i=0; i<n; i++ )
{ numero primo
scanf("%d", &dato);

primo = 1 ;
for(
for j=2; j<dato; j++ )
{
if(
if dato%j == 0 ) Inizializzazione
primo = 0 ;
}

if(
if primo == 1 ) Aggiornamento
{
printf("E' un numero primo\n");
trovato = 1 ;
} Verifica
}

if(
if trovato == 0 )
printf("Non c'erano numeri primi\n");
34
Vista d’insieme

trovato = 0 ; Flag esterno:


for(
for i=0; i<n; i++ )
{ nessun primo
scanf("%d", &dato);

primo = 1 ;
for(
for j=2; j<dato; j++ )
{
if(
if dato%j == 0 ) Inizializzazione
primo = 0 ;
}

if(
if primo == 1 ) Aggiornamento
{
printf("E' un numero primo\n");
trovato = 1 ;
} Verifica
}

if(
if trovato == 0 )
printf("Non c'erano numeri primi\n");
35
Cicli ed iterazioni
Approfondimenti

Istruzione do-while
Istruzione break
Istruzione continue

2
Approfondimenti
Istruzione do-while
do while

do { B
B ;
} while ( C ) ;
V F
C

4
Confronto

Istruzione while Istruzione do-while


Condizione valutata Condizione valutata
prima di ogni al termine di ogni
iterazione iterazione
Numero minimo di Numero minimo di
iterazioni: 0 iterazioni: 1
Per uscire: Per uscire:
condizione falsa condizione falsa

5
Esempio

Acquisire un numero compreso tra 1 e 10 da


tastiera
Nel caso in cui l’utente non inserisca il numero
correttamente, chiederlo nuovamente

6
Soluzione

printf("Numero tra 1 e 10\n");


do {

scanf("%d", &n) ;

} while ( n<1 || n>10 ) ;

7
Soluzione migliore

printf("Numero tra 1 e 10\n");


do {

scanf("%d", &n) ;

if(
if n<1 || n>10 )
printf("Errore: ripeti\n");

} while ( n<1 || n>10 ) ;

8
Esempio

Si scriva un programma in C che calcoli la somma


di una sequenza di numeri interi
La sequenza termina quando l’utente inserisce il
dato 9999

9
Soluzione

somma = 0 ;
do {

scanf("%d", &dato) ;

if(
if n != 9999 )
somma = somma + dato ;

} while ( dato != 9999 ) ;

10
Approfondimenti
Interruzione dei cicli

Di norma, un ciclo termina quando la condizione


di controllo diventa falsa
Necessario arrivare al termine del corpo per poter
valutare la condizione
Talvolta potrebbe essere comodo interrompere
prematuramente l’esecuzione di un ciclo
A seguito di condizioni di errore
Quando è stato trovato ciò che si cercava

12
Istruzione break

V F
C
while ( C )
{
B1
B1 ;
if ( U ) F V
break ; U
B2 ;
}
B2

13
Funzionamento

Quando viene eseguita l’istruzione break


Viene interrotta l’esecuzione del corpo del ciclo
Il flusso di esecuzione passa all’esterno del ciclo
che contiene il break
Si esce dal ciclo anche se la condizione di controllo
è ancora vera
In caso di cicli annidati, si esce solo dal ciclo più
interno
Funziona con cicli while, for, do-while

14
Esempio

Si scriva un programma in C che calcoli la somma


di una sequenza di numeri interi
La sequenza termina quando l’utente inserisce il
dato 9999

15
Soluzione

somma = 0 ;
do {

scanf("%d", &dato) ;

if(
if dato == 9999 )
break;
break

somma = somma + dato ;

} while ( 1 ) ;
16
Esempio

Si scriva un programma in C che determini se un


numero inserito da tastiera è primo

17
Soluzione

scanf("%d", &dato) ;
primo = 1 ;
for ( i=2; i<dato; i++ )
{
if(
if dato%i == 0 )
{
primo = 0 ;
break ; /* inutile continuare */
}
}

18
Note

L’istruzione break crea programmi non


strutturati: usare con cautela
Non è possibile uscire da più cicli annidati
contemporaneamente

19
Approfondimenti
Istruzione continue

V F
C
while ( C )
{
B1
B1 ;
if ( U ) F V
continue ; U
B2 ;
}
B2

21
Funzionamento

Quando viene eseguita l’istruzione continue


Viene interrotta l’esecuzione del corpo del ciclo
Il flusso di esecuzione passa al termine del corpo
Nel caso di cicli for, viene eseguita l’istruzione di
aggiornamento
Viene nuovamente valutata la condizione
Il ciclo continua normalmente
In caso di cicli annidati, si esce solo dal ciclo più
interno
Funziona con cicli while, for, do-while

22
Esempio

somma = 0 ;
do {

scanf("%d", &dato) ;

if(
if dato == 9999 )
continue ; /* non considerarlo */

somma = somma + dato ;

} while ( dato != 9999 ) ;


23
Avvertenze

L’istruzione continue è oggettivamente poco


utilizzata
Crea un “salto” poco visibile: accompagnarla
sempre con commenti evidenti

24
Cicli ed iterazioni
Esercizi proposti

Esercizio “Decimale-binario”
Esercizio “Massimo Comun Divisore”
Esercizio “Triangolo di Floyd”

2
Esercizi proposti
Esercizio “Decimale-binario”

Si realizzi un programma in C in grado di


Leggere un numero naturale n
Convertire tale numero dalla base 10 alla base 2
Visualizzare il risultato, a partire dalla cifra meno
significativa

4
Analisi

DECIMALE – BINARIO

Inserisci un numero intero positivo: 12

Numero binario: 0 0 1 1

5
Divisioni successive

n = 12 N N%2
n%2 = 0  cifra 0
12 0
n=n/2=6
n%2 = 0  cifra 0 6 0
n=n/2=3 3 1
n%2 = 1  cifra 1
1 1
n=n/2=1
n%2 = 1  cifra 1 0
n = n / 2 = 0  STOP

6
Soluzione

while(
while n!=0 ) bin-dec.c

{
if(
if n%2 == 1 )
printf("1 ") ;
else
printf("0 ") ;

n = n / 2 ;
}

7
Esercizi proposti
Esercizio “Massimo Comun Divisore”

Si scriva un programma in C in grado di calcolare


il massimo comun divisore (MCD) di due numeri
interi.
Il MCD è definito come il massimo tra i divisori
comuni ai due numeri.

9
Analisi

Diciamo N1 e N2 i numeri inseriti dall’utente


Il MCD di N1 e N2 è il massimo tra i numeri che
sono divisori sia di N2, sia di N1.
Troviamo i divisori di N1 ...
... tra quelli che sono anche divisori di N2 ...
... calcoliamo il massimo

10
Algoritmo

k_max = 0
for k = da 1 a N1 bin-dec.c

se k è un divisore di N1
se k è un divisore di N2
aggiorna k_max = k
MCD = k_max

11
Esercizi proposti
Esercizio “Triangolo di Floyd”

Scrivere un programma C per la rappresentazione


del triangolo di Floyd.
Il programma riceve da tastiera un numero
interno N.
Il programma visualizza le prima N righe del
triangolo di Floyd.

1
2 3
4 5 6 N=5
7 8 9 10
11 12 13 14 15 13
Analisi

Occorre stampare i primi numeri interi in forma di


triangolo
La riga k-esima ha k elementi

1
2 3
4 5 6 N=5
7 8 9 10
11 12 13 14 15 14
Algoritmo

cont = 1
for riga = da 1 a N floyd.c

for colonna = da 1 a riga


stampa cont
cont++
vai a capo

1
2 3
4 5 6 N=5
7 8 9 10
11 12 13 14 15 15
Cicli ed iterazioni
Argomenti trattati

Ripetizione del del flusso di esecuzione


Inizializzazione, Condizione, Aggiornamento,
Corpo
Istruzione while
Istruzione for
Cicli annidati

2
Tecniche di programmazione

Cicli con numero di iterazioni note o ignote


Contatori
Accumulatori
Flag

3
Schemi ricorrenti

Calcolo di somme, medie, ...


Calcolo di max, min
Ricerca di esistenza
Ricerca di universalità
Controllo dei dati in input

4
Suggerimenti

Ricordare di verificare sempre le 4 parti del ciclo


Inizializzazione, Condizione, Corpo, Aggiornamento
Le complicazioni nascono da
Cicli annidati
Condizioni if annidate in cicli
Annidamento di flag o ricerche
Procedere sempre per gradi
Pseudo-codice o flow chart
Identificare chiaramente il ruolo dei diversi cicli

5
Materiale aggiuntivo

Sul CD-ROM
Testi e soluzioni degli esercizi trattati nei lucidi
Scheda sintetica
Esercizi risolti
Esercizi proposti
Esercizi proposti da altri libri di testo

6
Programmazione in C
Vettori

Strutture dati complesse


I vettori in C
Operazioni elementari sui vettori
Esercizi guidati sui vettori
Sommario

2
Riferimenti al materiale

Testi
Kernighan & Ritchie: capitoli 1 e 5
Cabodi, Quer, Sonza Reorda: capitolo 5
Dietel & Dietel: capitolo 6
Dispense
Scheda: “Vettori in C”

3
Vettori
Strutture dati complesse

Tipi di dato strutturati


Introduzione ai vettori
Caratteristiche dei vettori

2
Strutture dati complesse
Tipi di dato strutturati

Finora abbiamo utilizzato dei tipi di dato semplici


int, float
Ogni variabile può contenere un solo valore
Il linguaggio C permette di definire tipi di dato
complessi, aggregando più variabili semplici

a 35 x -17

pi 3.14 nome “fulvio”


4
Esigenze

Leggere da tastiera 10
numeri, e stamparli in
ordine inverso
Calcolare e stampare la
tavola pitagorica
Calcolare l’area del
triangolo date le
coordinate dei vertici
Per ogni auto calcolare il
tempo medio e minimo
sul giro
5
Esigenze

Leggere da tastiera 10 35
numeri, e stamparli in 7 dato
ordine inverso 14
Calcolare e stampare la 32
tavola pitagorica -9
Calcolare l’area del 2
triangolo date le 631
coordinate dei vertici -18
Per ogni auto calcolare il 4
tempo medio e minimo 7
sul giro
6
Esigenze

Leggere da tastiera 10 pitagora


numeri, e stamparli in
ordine inverso
1 2 3 4 5
Calcolare e stampare la
tavola pitagorica 2 4 6 8 10
3 6 9 12 15
Calcolare l’area del
triangolo date le
4 8 12 16 20
coordinate dei vertici 5 10 15 20 25
6 12 18 24 30
Per ogni auto calcolare il
tempo medio e minimo
sul giro
7
Esigenze

Leggere da tastiera 10
3.1 x
numeri, e stamparli in A
ordine inverso 0.2 y
Calcolare e stampare la
tavola pitagorica 4.0 x
B
Calcolare l’area del -2.1 y
triangolo date le
coordinate dei vertici 7.5 x
Per ogni auto calcolare il C
3.3 y
tempo medio e minimo
sul giro
8
Esigenze

Leggere da tastiera 10
numeri, e stamparli in 12 n
ordine inverso a1 3.1 min
Calcolare e stampare la 4.2 med
tavola pitagorica
Calcolare l’area del
triangolo date le
9 n
coordinate dei vertici
a2 3.0 min
Per ogni auto calcolare il
tempo medio e minimo 3.9 med
sul giro
9
Dati strutturati (1/2)

Raggruppare più variabili semplici in un’unica


struttura complessa
Diversi meccanismi di aggregazione
Vettore
Matrice
Struttura

10
Dati strutturati (2/2)

Una sola variabile, di tipo complesso, memorizza


tutti i dati della struttura complessa
Vettore_di_int dato
Matrice_di_int pitagora
Struttura_xy A, B, C
Struttura_auto a1, a2

11
Strutture dati complesse
Variabili e vettori
dato1
35
35 dato2
7 dato
dato3 7
14
14 dato4 32
dato5 32 -9
-9 dato6 2
dato7 2 dato8 631
dato9 -18
631 -18
4 dato10
4
7
7
13
Da evitare...

int main(void
void)
void
{
int dato1, dato2, dato3, dato4, dato5 ;
int dato6, dato7, dato8, dato9, dato10 ;
. . . . .
scanf("%d", &dato1) ;
scanf("%d", &dato2) ;
scanf("%d", &dato3) ;
. . .
scanf("%d", &dato10) ;

printf("%d\n", dato10) ;
printf("%d\n", dato9) ;
printf("%d\n", dato8) ;
. . .
printf("%d\n", dato1) ;
} 14
Vettori

Meccanismo di strutturazione più semplice


Utilizzato per aggregare serie di dati
Permette di memorizzare tutti i dati acquisiti o
calcolati, e potervi accedere
In qualsiasi momento
In qualsiasi ordine
I singoli dati sono distinti dal loro numero
d’ordine
Primo, secondo, ..., ultimo dato
Ciascun dato può avere un valore diverso

15
Vettori

Sequenza lineare di 0 35
dati elementari 1 7 dato
Elementi tutti dello 2 14
stesso tipo 3 32
Numero di elementi 4 -9
fisso (N) 5 2
Elementi identificati 6 631
dal proprio indice 7 -18
da 0 a N-1 8 4
9 7
N=10 16
...così è meglio!

int main(void
void)
void
{
int dato[10] ;
. . . . .
for(
for i=0; i<10; i++)
scanf("%d", &dato[i]) ;

for(
for i=9; i>=0; i--)
printf("%d\n", dato[i]) ;
}

17
Insieme o separati?

I singoli dati vengono tenuti insieme in un’unica


variabile di tipo vettore
int dato[10]
Le operazioni (lettura, scrittura, elaborazione)
avvengono però sempre un dato alla volta
scanf("%d", &dato[i])
printf("%d\n", dato[i])
Ogni singolo dato è identificato da
Nome del vettore
Posizione all’interno del vettore

18
Strutture dati complesse
Caratteristiche dei vettori

Caratteristiche statiche 0 35
Nome 1 7 dato
dato 2 14
Tipo di dato base 3 32
int 4 -9
Dimensione totale 5 2
10 6 631
Caratteristiche dinamiche 7 -18
Valori assunti dalle 8 4
singole celle 9 7
35, 7, 14, 32, ...
N=10 20
Esempio

Leggere da tastiera 10 numeri e stamparli in


ordine inverso
Tipo base: int
Dimensione: 10
Lettura delle celle da 0 a 9
Stampa delle celle da 9 a 0

21
Vincoli

Tutte le celle di un vettore avranno lo stesso


nome
Tutte le celle di un vettore devono avere lo
stesso tipo base
La dimensione del vettore è fissa e deve essere
determinata al momento della sua definizione
La dimensione è sempre un numero intero
Ogni cella ha sempre un valore
Impossibile avere celle “vuote”
Le celle non inizializzate contengono valori ignoti

22
Accesso alle celle

Ciascuna cella è identificata dal proprio indice


Gli indici sono sempre numeri interi
In C, gli indici partono da 0
Ogni cella è a tutti gli effetti una variabile il cui
tipo è pari al tipo base del vettore
Ogni cella, indipendentemente dalle altre
deve essere inizializzata
può essere letta/stampata
può essere aggiornata da istruzioni di
assegnazione
può essere usata in espressioni aritmetiche

23
Errore frequente

Non confondere mai 0 35


l’indice con il 1 7 dato
contenuto 2 14
dato[5] = 2 3 32
dato[9] == 4 -9
dato[1] 5 2
dato[i]>dato[j] 6 631
i>j 7 -18
8 4
9 7
N=10 24
Errore frequente

Non si può 0 35
effettuare alcuna 1 7 dato
operazione sul 2 14
vettore 3 32
dato = 0 4 -9
printf(“%d”, 5 2
dato) 6 631
Occorre operare sui 7 -18
singoli elementi 8 4
Solitamente 9 7
all’interno di un ciclo
for N=10 25
Vettori
I vettori in C

Sintassi della definizione


Definizione di costanti
Operazioni di accesso

2
I vettori in C
Definizione di vettori in C

int dato[10] ;

Tipo di dato Nome del Numero di


base vettore elementi

4
Definizione di vettori in C

int dato[10] ;

Tipo di dato Nome del Numero di


base vettore elementi

•• Stesse
Stesse regole
regole che
che valgono
valgono per
per ii
nomi
nomi delle
delle variabili.
variabili.
•• II nomi
nomi dei
dei vettori
vettori devono
devono essere
essere
diversi
diversi dai
dai nomi
nomi delle
delle variabili.
variabili.
5
Definizione di vettori in C

int dato[10] ;

Tipo di dato Nome del Numero di


base vettore elementi

•• int
int
•• float
float
•• In
In futuro vedremo: char,
futuro vedremo: char, struct
struct
6
Definizione di vettori in C

int dato[10] ;

Tipo di dato Nome del Numero di


base vettore elementi

•• Intero
Intero positivo
positivo
•• Costante
Costante nota
nota aa tempo
tempo di
di
compilazione
compilazione
•• Impossibile
Impossibile cambiarla
cambiarla in
in seguito
seguito
7
Esempi

int dato[10] ;
float lati[8] ;
int numeriprimi[100] ;
int is_primo[1000] ;

8
Esempi

0 1
int dato[10] ; 1 2
float lati[8] ; 2 3
int numeriprimi[100] ; 3 5
4 7
int is_primo[1000] ; 5 11
6 13
7 17
8 19
9 23
10 29
11 31
12 37
... ...
9
Esempi

0 0
int dato[10] ; 1 1
float lati[8] ; 2 1
int numeriprimi[100] ; 3 1
4 0
int is_primo[1000] ; 5 0
6 0
7 1
8 0
9 0
10 0
11 1
12 0
... ...
10
Errore frequente

Dichiarare un vettore usando una variabile


anziché una costante

int N = 10 ;
int dato[10] ;
int dato[N] ;

11
Errore frequente

Dichiarare un vettore usando una variabile non


ancora inizializzata

int N ;
int dato[N] ;
int dato[10] ;
. . .

scanf("%d",&N) ;
12
Errore frequente

Dichiarare un vettore usando il nome dell’indice

int i ;
int dato[i] ;
int dato[10] ;
. . .
for(i=0; i<10; i++)
scanf("%d",&dato[i]) ;

13
I vettori in C
Costanti

La dimensione di un vettore deve essere


specificata utilizzando una costante intera
positiva
Costante = valore numerico già noto al momento
della compilazione del programma

int dato[10] ;

15
Problemi

int i ;
int dato[10] ;
Devono essere
tutte uguali.
. . . Chi lo
for(i=0; i<10; i++)
garantisce?
scanf("%d", &dato[i]) ;

for(i=0; i<10; i++)


printf("%d\n", dato[i]) ;

16
Problemi

int i ; Se volessi
int dato[10] ;
Devono essere
lavorare con
tutte uguali.
. . . 20 dati dovrei
Chi lo
modificare in
for(i=0; i<10; i++)
garantisce?
tutti questi
scanf("%d", &dato[i]) ;
punti.
for(i=0; i<10; i++)
printf("%d\n", dato[i]) ;

17
Soluzione

Per risolvere i problemi visti si può ricorrere alle


costanti simboliche
Associamo un nome simbolico ad una costante
Nel programma usiamo sempre il nome simbolico
Il compilatore si occuperà di sostituire, ad ogni
occorrenza del nome, il valore numerico della
costante

18
Costanti simboliche

Costrutto #define
Metodo originario, in tutte le versioni del C
Usa una sintassi particolare, diversa da quella del
C
Definisce costanti valide su tutto il file
Non specifica il tipo della costante
Modificatore const
Metodo più moderno, nelle versioni recenti del C
Usa la stessa sintassi di definizione delle variabili
Specifica il tipo della costante

19
Costrutto #define

Definizione
#define N 10 della
costante
int main(void
void)
void
{ Uso della
int dato[N] ; costante
. . .
}

20
Particolarità (1/2)

La definizione non è terminata dal segno ;


Tra il nome della costante ed il suo valore vi è
solo uno spazio (non il segno =)
Le istruzioni #define devono essere una per
riga
Solitamente le #define vengono poste subito
dopo le #include

#define N 10

21
Particolarità (2/2)

Non è possibile avere una #define ed una


variabile con lo stesso nome
Per convenzione, le costanti sono indicate da
nomi TUTTI_MAIUSCOLI

#define N 10

22
Esempio

#define MAX 10

int main(void
void)
void
{
int i ;
int dato[MAX] ;

. . .

for(i=0; i<MAX; i++)


scanf("%d", &dato[i]) ;

for(i=0; i<MAX; i++)


printf("%d\n", dato[i]) ;
} 23
Modificatore const

int main(void
void)
void Definizione
{ della
const int N = 10 ; costante

int dato[N] ; Uso della


costante
. . .
}

24
Sintassi

Stessa sintassi per dichiarare una variabile


Parola chiave const
Valore della costante specificato dal segno =
Definizione terminata da segno ;
Necessario specificare il tipo (es. int)
Il valore di N non si può più cambiare

const int N = 10 ;

25
Esempio

int main(void
void)
void
{
const int MAX = 10 ;
int i ;
int dato[MAX] ;

. . .

for(i=0; i<MAX; i++)


scanf("%d", &dato[i]) ;

for(i=0; i<MAX; i++)


printf("%d\n", dato[i]) ;
}
26
Suggerimenti

Utilizzare sempre il modificatore const


Permette maggiori controlli da parte del
compilatore
Gli eventuali messaggi d’errore sono più chiari
Aggiungere sempre un commento per indicare lo
scopo della variabile
Utilizzare la convenzione di assegnare nomi
TUTTI_MAIUSCOLI alle costanti

27
I vettori in C
Accesso ai valori di un vettore

Ciascun elemento di dato[0] 35


un vettore è dato[1] 7
equivalente ad una dato[2] 14
singola variabile dato[3] 32
avente lo stesso tipo dato[4] -9
base del vettore dato[5] 2
È possibile accedere dato[6] 631
al contenuto di tale dato[7] -18
variabile utilizzando dato[8]
l’operatore di
4
dato[9] 7
indicizzazione: [ ]
int dato[10] ; 29
Sintassi

nomevettore[
[ valoreindice ]

Come nella Valore intero compreso


dichiarazione tra 0 e ( dimensione
del vettore – 1 )
Costante, variabile o
espressione aritmetica
con valore intero

30
Vincoli

Il valore dell’indice deve essere compreso tra 0 e


N-1. La responsabilità è del programmatore
Se l’indice non è un numero intero, viene
automaticamente troncato
Il nome di un vettore può essere utilizzato
solamente con l’operatore di indicizzazione

31
Uso di una cella di un vettore

L’elemento di un vettore è utilizzabile come una


qualsiasi variabile:
utilizzabile all’interno di un’espressione
tot = tot + dato[i] ;
utilizzabile in istruzioni di assegnazione
dato[0] = 0 ;
utilizzabile per stampare il valore
printf("%d\n", dato[k]) ;
utilizzabile per leggere un valore
scanf("%d\n", &dato[k]) ;

32
Esempi

if (dato[i]==0)
se l’elemento contiene zero
if (dato[i]==dato[i+1])
due elementi consecutivi uguali
dato[i] = dato[i] + 1 ;
incrementa l’elemento i-esimo
dato[i] = dato[i+1] ;
copia un dato dalla cella successiva

33
Vettori
Operazioni elementari sui vettori

Definizioni
Stampa di un vettore
Lettura di un vettore
Copia di un vettore
Ricerca di un elemento
Ricerca del massimo o minimo
Vettori ad occupazione variabile

2
Operazioni elementari sui vettori
Definizioni (1/2)

vettori.c
const int N = 10 ;
/* dimensioni dei vettori */

int v[N] ; /* vettore di N interi */

float r[N] ;
/* vettore di N reali */

int i, j ;
/* indici dei cicli */

4
Definizioni (2/2)

vettori.c

const int M = 100 ;


/* dimensioni dei vettori */

int w[N] ; /* vettore di N interi */


int h[M] ; /* vettore di M interi */

int dato ;
/* elemento da ricercare */

5
Operazioni elementari sui vettori
Stampa di un vettore

Occorre stampare un elemento per volta,


all’interno di un ciclo for
Ricordare che
gli indici del vettore variano tra 0 e N-1
gli utenti solitamente contano tra 1 e N
v[i] è l’elemento (i+1)-esimo

7
Stampa vettore di interi

vettori.c

printf("Vettore di %d interi\n", N) ;

for(
for i=0; i<N; i++ )
{
printf("Elemento %d: ", i+1) ;
printf("%d\n", v[i]) ;
}

8
Stampa vettore di interi

printf("Vettore di %d interi\n", N) ;

for(
for i=0; i<N; i++ )
{
printf("Elemento %d: ", i+1) ;
printf("%d\n", v[i]) ;
}

Stampa di un vettore di 10 interi


Elemento 1: 3
Elemento 2: 4
Elemento 3: 7
Elemento 4: 5
Elemento 5: 3
Elemento 6: -1
Elemento 7: -3
Elemento 8: 2
Elemento 9: 7
Elemento 10: 3
9
Stampa in linea

vettori.c

printf("Vettore di %d interi\n", N) ;

for(
for i=0; i<N; i++ )
{
printf("%d ", v[i]) ;
}
printf("\n") ;

10
Stampa in linea

printf("Vettore di %d interi\n", N) ;

for(
for i=0; i<N; i++ )
{
printf("%d ", v[i]) ;
}
printf("\n") ;

Stampa di un vettore di 10 interi


3 4 7 5 3 -1 -3 2 7 3

11
Stampa vettore di reali

vettori.c

printf("Vettore di %d reali\n", N) ;

for(
for i=0; i<N; i++ )
{
printf("Elemento %d: ", i+1) ;
printf("%f\n", r[i]) ;
}

12
Avvertenze

Anche se il vettore è di reali, l’indice è sempre


intero
Separare sempre i vari elementi almeno con uno
spazio (o un a capo)

13
Operazioni elementari sui vettori
Lettura di un vettore

Occorre leggere un elemento per volta, all’interno


di un ciclo for
Ricordare l’operatore & nella scanf

15
Lettura vettore di interi

vettori.c

printf("Lettura di %d interi\n", N) ;

for(
for i=0; i<N; i++ )
{
printf("Elemento %d: ", i+1) ;
scanf("%d", &v[i]) ;
}

16
Lettura vettore di interi

printf("Lettura di %d interi\n", N) ;

for(
for i=0; i<N; i++ )
{
printf("Elemento %d: ", i+1) ;
scanf("%d", &v[i]) ;
}
Lettura di un vettore di 10 interi
Elemento 1: 3
Elemento 2: 4
Elemento 3: 7
Elemento 4: 5
Elemento 5: 3
Elemento 6: -1
Elemento 7: -3
Elemento 8: 2
Elemento 9: 7
Elemento 10: 3
17
Lettura vettore di reali

vettori.c

printf("Lettura di %d reali\n", N) ;

for(
for i=0; i<N; i++ )
{
printf("Elemento %d: ", i+1) ;
scanf("%f", &r[i]) ;
}

18
Avvertenze

Anche se il vettore è di reali, l’indice è sempre


intero
Fare precedere sempre ogni lettura da una
printf esplicativa

19
Operazioni elementari sui vettori
Copia di un vettore

Più correttamente, si tratta si copiare il


contenuto di un vettore in un altro vettore
Occorre copiare un elemento per volta dal
vettore “sorgente” al vettore “destinazione”,
all’interno di un ciclo for
I due vettori devono avere lo stesso numero di
elementi, ed essere dello stesso tipo base

21
Copia di un vettore

35 12 35 35
7 2 7 7
14 73 14 14
32 -12 32 32
-9 0 -9 -9
2 0 Copia v in w 2 2
631 -17 631 631
-18 44 -18 -18
4 1 4 4
7 17 7 7
v w v w 22
Copia di un vettore

vettori.c

/* copia il contenuto di v[] in w[] */

for(
for i=0; i<N; i++ )
{
w[i] = v[i] ;
}

23
Avvertenze

Nonostante siano coinvolti due vettori, occore


un solo ciclo for, e un solo indice per
accedere agli elementi di entrambi i vettori
Assolutamente non tentare di fare la copia in una
sola istruzione!
w = v ;
w[] = v[] ;
w[N] = v[N] ;
w[1,N] = v[1,N] ;

24
Operazioni elementari sui vettori
Ricerca di un elemento

Dato un valore numerico, verificare


se almeno uno degli elementi del vettore è
uguale al valore numerico
in caso affermativo, dire dove si trova
in caso negativo, dire che non esiste
Si tratta di una classica istanza del problema di
“ricerca di esistenza”

26
Ricerca di un elemento (1/3)

vettori.c

int dato ; /* dato da ricercare */


int trovato ; /* flag per ricerca */
int pos ; /* posizione elemento */

...

printf("Elemento da ricercare? ");


scanf("%d", &dato) ;

27
Ricerca di un elemento (2/3)

trovato = 0 ; vettori.c

pos = -1 ;

for(
for i=0 ; i<N ; i++ )
{
if(
if v[i] == dato )
{
trovato = 1 ;
pos = i ;
}
}

28
Ricerca di un elemento (3/3)

vettori.c

if(
if trovato==1 )
{
printf("Elemento trovato "
"alla posizione %d\n", pos+1) ;
}
else
{
printf("Elemento non trovato\n");
}

29
Varianti

Altri tipi di ricerche


Contare quante volte è presente l’elemento cercato
Cercare se esiste almeno un elemento maggiore (o
minore) del valore specificato
Cercare se esiste un elemento
approssimativamente uguale a quello specificato
...

30
Operazioni elementari sui vettori
Ricerca del massimo

Dato un vettore (di interi o reali), determinare


quale sia l’elemento di valore massimo
quale sia la posizione in cui si trova tale elemento
Conviene applicare la stessa tecnica per
l’identificazione del massimo già vista in
precedenza
Conviene inizializzare il max al valore del primo
elemento

32
Ricerca del massimo (1/2)

float max ; /* valore del massimo */


int posmax ; /* posizione del max */
vettori.c

...
max = r[0] ;
posmax = 0 ;

for(
for i=1 ; i<N ; i++ )
{
if(
if r[i]>max )
{
max = r[i] ;
posmax = i ;
}
}
33
Ricerca del massimo (2/2)

vettori.c

printf("Il max vale %f e si ", max) ;


printf("trova in posiz. %d\n", posmax) ;

34
Operazioni elementari sui vettori
Occupazione variabile

La principale limitazione dei vettori è la loro


dimensione fissa, definita come costante al
tempo di compilazione del programma
Molto spesso non si conosce l’effettivo numero di
elementi necessari fino a quando il programma
non andrà in esecuzione
Occorre identificare delle tecniche che ci
permettano di lavorare con vettori di dimensione
fissa, ma occupazione variabile

36
Tecnica adottata

Dichiarare un vettore di dimensione


sufficientemente ampia da contenere il massimo
numero di elementi nel caso peggiore
Esempio: MAXN
La parte iniziale del vettore sarà occupata dagli
elementi, la parte finale rimarrà inutilizzata
Dichiarare una variabile che tenga traccia
dell’effettiva occupazione del vettore
Esempio: N

37
Tecnica adottata

0 N-1 N MAXN-1 MAXN

3 1 7 12 -3 1 21 43 -8 0 12 3 2 11 3 4 8 76 56 23 4 5 90 15 72 -4 -2 22 73

Elementi Elementi
effettivamente inutilizzati
utilizzati

38
Esempio

/* dimensione massima */
const int MAXN = 100 ;

int v[MAXN] ; /* vettore di dim. max. */

int N ; /* occupazione effettiva


del vettore */

...

N = 0 ; /* inizialmente “vuoto” */

39
Regole di utilizzo

All’inizio del programma si inizializza N al numero


effettivo di elementi
Esempio: scanf("%d", &N);
Verificare sempre che N<=MAXN
Durante l’esecuzione, utilizzare sempre N, e mai
MAXN
Esempio: for(i=0; i<N; i++)
Gli elementi da v[N] a v[MAXN-1] vengono
ignorati (costituiscono memoria “sprecata”)

40
Crescita del vettore

Un vettore ad occupazione variabile può


facilmente crescere, aggiungendo elementi “in
coda”

v[N] = nuovo_elemento ;
N++ ;

41
Esempio

Acquisire da tastiera una serie di numeri reali, e


memorizzarli in un vettore.
La serie di numeri è terminata da un valore
uguale a 0

Il valore di N non è noto all’inizio del programma,


ma viene aggiornato via via che si leggono gli
elementi

42
Soluzione (1/3)

const int MAXN = 100 ; leggi0.c

float v[MAXN] ;
float dato ;

int N ;
int i ;

printf("Inserisci gli elementi\n") ;


printf("(per terminare 0)\n") ;

43
Soluzione (2/3)

N = 0 ; /* vettore inizialm. vuoto */


leggi0.c
/* leggi il primo dato */
i = 0 ;
printf("Elemento %d: ", i+1) ;
scanf("%f", &dato) ;
i++ ;

/* aggiungi al vettore */
if(
if dato != 0.0 )
{
v[N] = dato ;
N++ ;
}
44
Soluzione (3/3)

while(dato!=
while 0.0)
{
leggi0.c
/* leggi il dato successivo */
printf("Elemento %d: ", i+1) ;
scanf("%f", &dato) ;
i++ ;

/* aggiungi al vettore */
if(
if dato != 0.0 )
{
v[N] = dato ;
N++ ;
}
}
45
Esercizio “Positivi e Negativi”

Si realizzi un programma che legga da tastiera


una sequenza di numeri interi (terminata da 0), e
che successivamente stampi
tutti i numeri positivi presenti nella sequenza, nello
stesso ordine
tutti i numeri negativi presenti nella sequenza,
nello stesso ordine

46
Analisi

INSERISCI UNA SEQUENZA (0 per terminare)


Elemento: 3
Elemento: -4
Elemento: 1
Elemento: 2
Elemento: -3
Elemento: 0

Numeri positivi:
3 1 2
Numeri negativi:
-4 -3

47
Approccio risolutivo

Definiamo 3 vettori ad occupazione variabile:


seq, di occupazione N, che memorizza la sequenza
iniziale
pos, di occupazione Np, che memorizza i soli
elementi positivi
neg, di occupazione Nn, che memorizza i soli
elementi negativi
Il programma inizialmente acquisirà da tastiera il
vettore seq, in seguito trascriverà ciascun
elemento nel vettore più opportuno

48
Soluzione (1/4)

const int MAXN = 100 ;

int seq[MAXN] ; posneg.c

int pos[MAXN] ;
int neg[MAXN] ;

int N, Np, Nn ;

int i ;
int dato ;

/* vettori inizialmente vuoti */


N = 0 ;
Np = 0 ;
Nn = 0 ;
49
Soluzione (2/4)

posneg.c

/* LETTURA SEQUENZA INIZIALE */

/* vedi esempio precedente ... */

50
Soluzione (3/4)

for(
for i=0 ; i<N ; i++ )
{
if(seq[i]
if > 0) posneg.c

{
/* positivo => in pos[] */
pos[Np] = seq[i] ;
Np++ ;
}
else
{
/* negativo => in neg[] */
neg[Nn] = seq[i] ;
Nn++ ;
}
}
51
Soluzione (4/4)

posneg.c

printf("Numeri positivi:\n") ;
for(i=0;
for i<Np; i++)
printf("%d ", pos[i]) ;
printf("\n");

printf("Numeri negativi:\n") ;
for(i=0;
for i<Nn; i++)
printf("%d ", neg[i]) ;
printf("\n");

52
Vettori
Esercizi guidati sui vettori

Esercizio “Elementi comuni”


Esercizio “Ricerca duplicati”
Esercizio “Sottosequenza”
Esercizio “Poligono”

2
Esercizi guidati sui vettori
Esercizio “Elementi comuni” (1/2)

Due colleghi intendono fissare una riunione,


pertanto devono identificare dei giorni nei quali
sono entrambi liberi da impegni. A tale scopo,
essi realizzano un programma C che permetta a
ciascuno di immettere le proprie disponibilità, e
che identifichi i giorni nei quali entrambi sono
liberi

4
Esercizio “Elementi comuni” (2/2)

In particolare, in una prima fase il programma


acquisisce le disponibilità dei due colleghi
Per ciascun collega il programma acquisisce un
elenco di numeri interi (supponiamo compresi tra 1
e 31), che indicano i giorni del mese in cui essi
sono disponibili. L’immissione dei dati termina
inserendo 0.
Nella seconda fase, il programma identificherà i
giorni in cui entrambi i colleghi sono disponibili, e
li stamperà a video

5
Analisi (1/3)

COLLEGA NUMERO 1
Inserisci giorno (1-31, 0 per terminare): 2
Inserisci giorno (1-31, 0 per terminare): 4
Inserisci giorno (1-31, 0 per terminare): 6
Inserisci giorno (1-31, 0 per terminare): 10
Inserisci giorno (1-31, 0 per terminare): 0

COLLEGA NUMERO 2
Inserisci giorno (1-31, 0 per terminare): 3
Inserisci giorno (1-31, 0 per terminare): 4
Inserisci giorno (1-31, 0 per terminare): 5
Inserisci giorno (1-31, 0 per terminare): 0

Giorno disponibile: 4

6
Analisi (2/3)

COLLEGA NUMERO 1
Inserisci giorno (1-31, 0 per terminare): 2
Inserisci giorno (1-31, 0 per terminare): 4
Inserisci giorno (1-31, 0 per terminare): 6
Inserisci giorno (1-31, 0 per terminare): 10
Inserisci giorno (1-31, 0 per terminare): 0

COLLEGA NUMERO 2
Inserisci giorno (1-31, 0 per terminare): 3
Inserisci giorno (1-31, 0 per terminare): 5
Inserisci giorno (1-31, 0 per terminare): 7
Inserisci giorno (1-31, 0 per terminare): 0

Purtroppo non vi e' NESSUN giorno disponibile

7
Analisi (3/3)

COLLEGA NUMERO 1
Inserisci giorno (1-31, 0 per terminare): 2
Inserisci giorno (1-31, 0 per terminare): 4
Inserisci giorno (1-31, 0 per terminare): 6
Inserisci giorno (1-31, 0 per terminare): 0

COLLEGA NUMERO 2
Inserisci giorno (1-31, 0 per terminare): 2
Inserisci giorno (1-31, 0 per terminare): 3
Inserisci giorno (1-31, 0 per terminare): 4
Inserisci giorno (1-31, 0 per terminare): 0

Giorno disponibile: 2
Giorno disponibile: 4

8
Algoritmo

Acquisisci le disponibilità del collega 1


Vettore giorni1[] di N1 elementi
Acquisisci le disponibilità del collega 2
Vettore giorni2[] di N2 elementi
Verifica se vi sono elementi di giorni1[] che
siano anche elementi di giorni2[]
Se sì, stampa tali elementi
Se no, stampa un messaggio

9
Ricerca elementi comuni

giorni1
2 8 4 12 7 21 18 22 9 10 25 30 3 17 29

N1

giorni2
6 11 23 21 26 15 16 17 13 26

N2

10
Ricerca elementi comuni

giorni1
2 8 4 12 7 17 18 22 9 10 25 30 3 21 29

N1

giorni2
6 11 23 21 26 15 16 17 13 26

N2

11
Ricerca elementi comuni

giorni1 i

2 8 4 12 7 17 18 22 9 10 25 30 3 21 29

N1

giorni1[i] == giorni2[j]
giorni2

6 11 23 21 26 15 16 17 13 26

j N2

12
Soluzione (1/5)

const int MAXN = 100 ; riunione.c

int N1, N2 ;
int giorni1[MAXN] ; /* giorni collega 1 */
int giorni2[MAXN] ; /* giorni collega 2 */

int giorno ;
int i, j ;
int trovato ;
/* flag: giorni1[i] in giorni2[]? */
int fallito ;
/* flag: trovato almeno un giorno? */

13
Soluzione (2/5)

/* DISPONIBILITA' COLLEGA 1 */
printf("COLLEGA NUMERO 1\n");
N1 = 0 ; riunione.c
printf("Inserisci giorno (1-31): ");
scanf("%d", &giorno) ;

while(
while giorno != 0 )
{
giorni1[N1] = giorno ;
N1++ ;

printf("Inserisci giorno (1-31): ");


scanf("%d", &giorno) ;
}
printf("Collega 1 ha inserito %d giorni\n",
N1);
14
Soluzione (3/5)

/* DISPONIBILITA' COLLEGA 2 */
printf("COLLEGA NUMERO 2\n");
N2 = 0 ; riunione.c
printf("Inserisci giorno (1-31): ");
scanf("%d", &giorno) ;

while(
while giorno != 0 )
{
giorni2[N2] = giorno ;
N2++ ;

printf("Inserisci giorno (1-31): ");


scanf("%d", &giorno) ;
}
printf("Collega 2 ha inserito %d giorni\n",
N2);
15
Soluzione (4/5)

/* RICERCA DEGLI ELEMENTI COMUNI */


fallito = 1 ;
/* Per ogni giorno del collega 1... */ riunione.c
for(
for i=0 ; i<N1; i++ )
{
/* ...verifica se è disponibile
il collega 2... */

/* ...in caso affermativo stampalo */


if(
if trovato == 1 )
{
printf("Giorno disponibile: %d\n",
giorni1[i]) ;
fallito = 0 ;
}
}
16
Soluzione (4/5)

/* RICERCA DEGLI ELEMENTI COMUNI */


fallito = 1 ;
/* Per ogni giorno del collega 1... */ riunione.c
for(
for i=0 ; i<N1; i++ )
{
/* ...verifica se è disponibile
il collega 2... */

/* ...in caso affermativo stampalo */


if(
if trovato == 1 )
{ trovato = 0 ;
for j=0; disponibile:
printf("Giorno
for( j<N2; j++ ) %d\n",
giorni1[i])
{ ;
fallito if(
= 0 giorni2[j]
if ; == giorni1[i] )
} trovato = 1 ;
} }
17
Soluzione (5/5)

riunione.c

/* Se non ne ho trovato nessuno,


stampo un messaggio */
if(fallito==1)
if
printf("NESSUN giorno disponibile\n");

18
Esercizi guidati sui vettori
Esercizio “Ricerca duplicati” (1/2)

La società organizzatrice di un concerto vuole


verificare che non ci siano biglietti falsi. A tale
scopo, realizza un programma in linguaggio C che
acquisisce i numeri di serie dei biglietti e verifica
che non vi siano numeri duplicati

20
Esercizio “Ricerca duplicati” (2/2)

In particolare, il programma acquisisce


innanzitutto il numero di biglietti venduti, N, ed in
seguito acquisisce i numeri di serie degli N
biglietti
Al termine dell’acquisizione, il programma
stamperà “Tutto regolare” se non si sono
riscontrati duplicati, altrimenti stamperà il
numero di serie dei biglietti duplicati

21
Analisi (1/2)

RICERCA BIGLIETTI DUPLICATI

Numero totale di biglietti: 5


Numero di serie del biglietto 1: 1234
Numero di serie del biglietto 2: 4321
Numero di serie del biglietto 3: 1423
Numero di serie del biglietto 4: 1242
Numero di serie del biglietto 5: 3321
Tutto regolare

22
Analisi (2/2)

RICERCA BIGLIETTI DUPLICATI

Numero totale di biglietti: 5


Numero di serie del biglietto 1: 1234
Numero di serie del biglietto 2: 4321
Numero di serie del biglietto 3: 1234
Numero di serie del biglietto 4: 1242
Numero di serie del biglietto 5: 3321
ATTENZIONE: biglietto 1234 duplicato!

23
Algoritmo

Acquisizione del valore di N


Lettura dei numeri di serie
Utilizziamo un vettore: int serie[MAXN]
Ricerca dei duplicati
Stampa dei messaggi finali

24
Ricerca dei duplicati

Prendi un elemento per volta


elem = serie[i] ;
Cerca se altri elementi del vettore sono uguali a
tale elemento
uguali ⇒ (elem == serie[j])
altri ⇒ (i != j)
Si tratta di una ricerca di esistenza per ogni
elemento considerato

25
Soluzione (1/5)

const int MAXN = 100 ;


biglietti.c

int N ; /* num tot biglietti */


int serie[MAXN] ; /* numeri serie */

int elem ;
int i, j ;

/* flag: trovato almeno un duplic.? */


int dupl ;

/* flag per ricerca di esistenza */


int trovato ;
26
Soluzione (2/5)

printf("RICERCA DUPLICATI\n") ;
biglietti.c
printf("\n");

/* ACQUISIZIONE VALORE DI N */
do{
do

printf("Num tot di biglietti: ") ;


scanf("%d", &N) ;
if (N<2 || N>MAXN)
printf("N=%d non valido\n", N) ;

} while(N<2
while || N>MAXN) ;

27
Soluzione (3/5)

biglietti.c

/* LETTURA DEI NUMERI DI SERIE */


for(
for i=0 ; i<N ; i++ )
{
printf("Numero serie biglietto %d: ",
i+1) ;
scanf("%d", &serie[i]) ;
}

28
Soluzione (4/5)
/* RICERCA DEI DUPLICATI */
dupl = 0 ;
for(
for i=0 ; i<N ; i++ )
biglietti.c
{
/* verifica se serie[i] e' duplicato */
elem = serie[i] ;

/* => ricerca esistenza di elem


all'interno di serie[] */

if(trovato
if == 1)
{
printf("ATTENZIONE: %d duplicato\n",
elem) ;
dupl = 1 ;
}
}
29
Soluzione (4/5)
/* RICERCA DEI DUPLICATI */
dupl = 0 ;
for(
for i=0 ; i<N ; i++ )
biglietti.c
{
/* verifica se serie[i] e' duplicato */
elem = serie[i] ;

/* => ricerca esistenza di elem


all'interno di serie[] */

if(trovato
if == 1)
trovato = 0 ;
{ for(
for j=0 ; j<N ; j++ )
printf("ATTENZIONE:
{ %d duplicato\n",
elem)if(
; (i!=j) &&
if
dupl = 1 ; (elem == serie[j]) )
} trovato = 1 ;
} } 30
Soluzione (5/5)

biglietti.c

/* STAMPA DEI MESSAGGI FINALI */


if(dupl==0)
if
printf("Tutto regolare\n");

31
Esercizi guidati sui vettori
Esercizio “Sottosequenza” (1/2)

In un esercizio di telepatia, un sensitivo


scommette di essere in grado di indovinare
almeno 3 numeri consecutivi, in una sequenza di
100 numeri pensati da uno spettatore
Per garantire l’oggettività dell’esperimento, viene
realizzato un programma in C per la verifica
dell’avvenuta telepatia
Per maggior generalità, il programma viene
realizzato in modo da controllare sequenze di
almeno K numeri consecutivi, all’interno di
sequenze di N numeri.
33
Esercizio “Sottosequenza” (2/2)

In particolare, il programma acquisisce


innanzitutto la sequenza di N numeri pensati
dallo spettatore. Si ipotizza che tali numeri siano
interi positivi, compresi tra 1 e 10000
In seguito, il programma acquisisce dal sensitivo
una sequenza di K numeri
Il programma verifica se esiste, nella sequenza di
N numeri, una sottosequenza di K numeri
esattamente uguale a quella inserita dal sensitivo
I valori di N e K sono introdotti dall’utente
all’inizio del programma

34
Analisi

Lunghezza della sequenza complessiva: 6


Lunghezza della sequenza da indovinare: 3
Inserire la sequenza complessiva
Elemento 1: 3
Elemento 2: 4
Elemento 3: 5
Elemento 4: 6
Elemento 5: 7
Elemento 6: 8
Inserire la sequenza da indovinare telepaticamente
Elemento 1: 5
Elemento 2: 6
Elemento 3: 7
Complimenti! Hai ottime capacita' telepatiche

35
Algoritmo (1/2)

Chiamiamo
seq[] la sequenza di N elementi
tele[] la sottosequenza di K elementi (K<N)

36
Algoritmo (2/2)

Verifichiamo se
i primi K elementi di seq[] sono uguali ai K
elementi di tele[]
i K elementi di seq[] con indice da 1 a K sono
uguali ai K elementi di tele[]
i K elementi di seq[] con indice da 2 a K+1 sono
uguali ai K elementi di tele[]
i K elementi di seq[] con indice da 3 a K+2 sono
uguali ai K elementi di tele[]
...

37
Sottosequenze

seq
2 8 4 12 7 21 18 22 9 10 25 30 3 17 29

tele
7 21 18

38
Sottosequenze
i i+K-1
seq
2 8 4 12 7 21 18 22 9 10 25 30 3 17 29

N
7 21 18

0 K-1
tele
7 21 18

39
Sottosequenze
i i+K-1
seq
2 8 4 12 7 21 18 22 9 10 25 30 3 17 29

N
7 21 18

0 K-1
tele
7 21 18 j == 0...K-1
seq[i+j] = tele[j]
K

40
Soluzione (1/4)

const int MAXN = 100 ;


const int MAXK = 10 ;
sensitivo.c

int N ; /* lunghezza seq. completa */


int K ; /* lunghezza sottosequenza */
int seq[MAXN] ; /* seq. completa */
int tele[MAXK] ; /* seq. telepatica */

int i, j ;
int trovato ; /* flag: ricorda se ha
trovato una sottosequenza uguale */
int errore ; /* flag: verifica che
TUTTI gli elementi della
sottosequenza siano uguali */
41
Soluzione (2/4)

sensitivo.c

printf("ESPERIMENTO DI TELEPATIA\n") ;
printf("\n");

/* ACQUISIZIONE LUNGHEZZA SEQUENZE */


...leggi da tastiera i valori di N e K...

/* ACQUISIZIONE SEQUENZA COMPLESSIVA */


...leggi da tastiera il vettore seq[] di N elementi...

/* ACQUISIZIONE SEQ. DA INDOVINARE */


...leggi da tastiera il vettore tele[] di K elementi...
42
Soluzione (3/4)

trovato = 0 ;
/* considera tutti i possibili
punti di partenza (i) */ sensitivo.c

for(
for i=0; i<N-K; i++ )
{
/* verifica se seq[] nelle
posizioni da (i) a (i+K-1) e'
uguale a tele[] nelle posizioni
da (0) a (K-1) */

/* la sottosequenza era corretta? */


if(errore==0)
if
trovato=1 ;
}
43
Soluzione (3/4)

trovato = 0 ;
/* considera tutti i possibili
punti di partenza (i) */ sensitivo.c

for(
for i=0; i<N-K; i++ )
{
/* verifica se seq[] nelle
posizioni da (i) a (i+K-1) e'
uguale a tele[] nelle posizioni
da (0) a (K-1) */

/* la sottosequenza era corretta? */


errore = 0 ;
if(errore==0)
if for(
for j=0; j<K; j++ )
trovato=1
{ ;
} if(
if seq[i+j] != tele[j] )
errore = 1 ; 44
}
Soluzione (4/4)

sensitivo.c

/* STAMPA RISULTATO DELLA VERIFICA */


if(
if trovato==1 )
printf("Complimenti!\n");
else
printf("Esperimento non riuscito\n");

45
Esercizi guidati sui vettori
Esercizio “Poligono” (1/2)

Uno studente di
geometria deve
misurare il perimetro
di una serie di
poligoni irregolari, di
cui conosce le
coordinate cartesiane
(x,y) dei vertici. Per
far ciò realizza un
programma in C

47
Esercizio “Poligono” (2/2)

In particolare, il programma innanzitutto


acquisisce il numero di vertici di cui è composto il
poligono. Chiamiamo N tale numero
In seguito, il programma acquisisce le N coppie
(x,y) corrispondenti agli N vertici
Il programma infine stampa la lunghezza
complessiva del perimetro del poligono
irregolare:
sommando delle lunghezze di ciascun lato
lato determinato dalle coordinate dei vertici

48
Analisi (1/2)

AB = √(2-(-3))²+(5-0)²
BC = √(-3-0)²+(0-(-2))²
A(2,5)
CD = √(0-4)²+(-2-(-2))²
DA = √(4-2)²+(-2-5)²
B(-3,0)
Perimetro =
C(0,-2) D(4,-2) = AB + BC + CD + DA

49
Analisi (2/2)

CALCOLO DEL PERIMETRO

Numero di vertici: 4
Inserire le coordinate dei vertici
Vertice 1: x = 2
y = 5
Vertice 2: x = -3
y = 0
Vertice 3: x = 0
y = -2
Vertice 4: x = 4
y = -2

Lunghezza del perimetro: 21.956729

50
Struttura dati

In questo problema i dati da memorizzare non


sono semplici numeri, ma coppie di numeri
Possiamo utilizzare due vettori
Vettore x[], contenente le ascisse dei punti
Vettore y[], contenente le ordinate dei punti
Esempio:
Punto A(2,5) ⇒ x[0]=2 ; y[0]=5 ;
In tutte le elaborazioni, i due vettori verranno
usati con uguale valore dell’indice
Vettori “paralleli”

51
Soluzione (1/3)

const int MAXN = 10 ;


poligoni.c

int N ; /* numero di vertici */

/* vettori "paralleli" */
float x[MAXN] ;
float y[MAXN] ;

int i ;

float lato ;
float perimetro ;

52
Soluzione (2/3)

/* ACQUISIZIONE NUMERO VERTICI */


poligoni.c
...leggi da tastiera il valore di N...

/* ACQUISIZIONE COORDINATE VERTICI */


printf("Inserire coordinate\n");
for(
for i=0; i<N; i++ )
{
printf("Vertice %d: x = ", i+1) ;
scanf("%f", &x[i]) ;
printf(" y = ") ;
scanf("%f", &y[i]) ;
}

53
Soluzione (3/3)

perimetro = 0 ;

for(
for i=0; i<N-1; i++ ) poligoni.c

{
/* (x[i],y[i])-(x[i+1],y[i+1]) */
lato = sqrt( (x[i]-x[i+1])*(x[i]-x[i+1])
+ (y[i]-y[i+1])*(y[i]-y[i+1]) ) ;
perimetro = perimetro + lato ;
}

/* ultimo lato:
(x[N-1],y[N-1])-(x[0],y[0]) */
lato = sqrt( (x[N-1]-x[0])*(x[N-1]-x[0])
+ (y[N-1]-y[0])*(y[N-1]-y[0]) ) ;
perimetro = perimetro + lato ;

54
Vettori
Argomenti trattati

La struttura dati vettoriale


Dichiarazione di vettori in C
Accesso agli elementi del vettore
Vettori con occupazione variabile

2
Tecniche di programmazione

Lettura e scrittura di vettori


Ricerca di elementi
Ricerche di duplicati, di sottosequenze, di
elementi comuni, ...
Vettori paralleli

3
Vettori e cicli

Per elaborare il contenuto di un vettore sono


spesso necessari dei cicli
Operazioni semplici: scansione del vettore per
stampa, lettura, ricerca, ...
Operazioni complesse: possono richiedere più cicli
annidati

4
Errore frequente

Non è detto che ad ogni vettore corrisponda un


ciclo
Controesempio: nella ricerca di elementi
duplicati, vi è un solo vettore, ma due cicli
annidati
Controesempio: nel calcolo del perimetro, vi sono
due vettori, ma un solo ciclo

5
Errore frequente

Al vettore non è associato alcun indice


particolare, per scandirne gli elementi
Lo stesso vettore può essere usato con indici
diversi
Lo stesso indice può essere applicato a vettori
diversi

6
Suggerimenti

Tenere separate le operazioni di lettura/scrittura


dalle elaborazioni vere e proprie
Procedere per gradi, in modalità top-down,
cercando di riconoscere ove possibile le strutture
note
ricerca di un elemento
verifica di esistenza
verifica di universalità
Non confondere i vari “flag” utilizzati in caso di
cicli annidati

7
Avvertenze

La combinazione di vettori e cicli crea un


fortissimo incremento nella complessità dei
programmi realizzabili
Questo è il punto più ripido nella curva di
apprendimento
Prima di procedere oltre, allenarsi con molti
esercizi di programmazione

8
Materiale aggiuntivo

Sul CD-ROM
Testi e soluzioni degli esercizi trattati nei lucidi
Scheda sintetica
Esercizi risolti
Esercizi proposti
Esercizi proposti da altri libri di testo

9
Programmazione in C
Caratteri e stringhe

Dati testuali
Il tipo char
Vettori di caratteri
Operazioni elementari sulle stringhe
Funzioni di libreria
Esercizi proposti
Sommario

2
Riferimenti al materiale

Testi
Kernighan & Ritchie: capitoli 1 e 5
Cabodi, Quer, Sonza Reorda: capitolo 5
Dietel & Dietel: capitolo 8
Dispense
Scheda: “Caratteri e stringhe in C”

3
Caratteri e stringhe
Dati testuali

Tipi di dato testuali


Caratteri
Stringhe

5
Dati testuali
Tipi di dato testuali

I programmi visti finora erano in grado di


elaborare esclusivamente informazioni numeriche
Numeri interi (int), numeri reali (float)
Variabili singole o vettori
In molti casi è necessario elaborare informazioni
di tipo testuale
Vuoi continuare (s/n)?
Conta le parole di un testo scritto
Gestisci una rubrica di nomi e numeri di telefono
...

7
Il sistema dei tipi C

Tipo di dato

Tipi Scalari Tipi Strutturati void

Tipi interi Tipi reali Enumerazioni Vettori

char float Strutture

int double Union

short/long long Puntatori

signed/unsigned Funzioni

8
Rappresentazione dei testi

Il calcolatore è in grado di rappresentare i


caratteri alfabetici, numerici ed i simboli speciali
di punteggiatura
Ad ogni diverso carattere viene assegnato,
convenzionalmente, un codice numerico
corrispondente
Il programma in C lavora sempre con i codici
numerici
Le funzioni di input/output sono in grado di
accettare e mostrare i caratteri corrispondenti

9
Codice ASCII

10
Source: [Link]
Caratteri e stringhe

Il codice ASCII permette di rappresentare un


singolo carattere

y 7 W ! %

Nelle applicazioni pratiche spesso serve


rappresentare sequenze di caratteri: stringhe

F u l v i o 0 6 A Z N

0 1 1 - 5 6 4 6 3 3 2
11
Dualità caratteri - numeri

Ogni carattere è rappresentato dal suo codice


ASCII

y 7 W ! %
121 55 87 33 37

Ogni stringa è rappresentata dai codici ASCII dei


caratteri di cui è composta

F u l v i o 0 6 A Z N
70 117 108 118 105 111 48 54 65 90 78

0 1 1 - 5 6 4 6 3 3 2
12
48 49 49 45 53 54 52 54 51 51 50
Dati testuali
Caratteri in C

Ogni carattere viene rappresentato dal proprio


codice ASCII
Sono sufficienti 7 bit per rappresentare ciascun
carattere
Il C usa variabili di 8 bit (1 byte)
Non sono previste le lettere accentate né altri
simboli diacritici
Richiedono estensioni speciali e librerie specifiche

14
Codice ASCII

15
Source: [Link]
Codice ASCII

Simbolo
corrispondente

Valore decimale
(tra 0 e 127)

16
Source: [Link]
Codice ASCII

Lettere
minuscole

Lettere
maiuscole

17
Source: [Link] Source: [Link]
Codice ASCII

Cifre
numeriche
Simboli di
punteggiatura

Source: [Link] 18
Source: [Link]
Codice ASCII

Spazio
bianco

Caratteri di
controllo

19
Source: [Link]
Caratteristiche del codice ASCII

Le lettere maiuscole sono tutte consecutive, ed in


ordine alfabetico
Le lettere minuscole sono tutte consecutive, ed in
ordine alfabetico
Le lettere maiuscole vengono “prima” delle
minuscole
Le cifre numeriche sono tutte consecutive, in
ordine dallo 0 al 9
I simboli di punteggiatura sono sparsi

20
Caratteri di controllo

Caratteri speciali, non visualizzabili


Rappresentano comandi di stampa, e non simboli
da stampare
Esempi:
7 – BEL: emetti un “bip”
8 – BS: cancella l’ultimo carattere
10 – LF: avanza di una riga
13 – CR: torna alla prima colonna
27 – ESC: tasto “Esc”
Per alcuni esiste una sequenza di escape in C: \n
21
Errore frequente

Non confondere il carattere ASCII che


rappresenta una cifra numerica con il valore
decimale associato a tale cifra
int char
7 7
55

Per chiarezza useremo gli apici per indicare i


caratteri
char
'7'
55
22
Errore frequente

Pensare che un singolo carattere possa


memorizzare più simboli

char char char char


Fulvio 7
F 7
u 7
l
55 117 108

23
Dati testuali
Stringhe

Una stringa è una struttura dati capace di


memorizzare sequenze di caratteri
In C non esiste un tipo di dato specifico
Si usano vettori di caratteri
La lunghezza di una stringa è tipicamente
variabile durante l’esecuzione del programma
Occorrerà gestire l’occupazione variabile dei
vettori di caratteri

25
Caratteristiche delle stringhe

Memorizzate come singoli caratteri, ma il loro


significato è dato dall’intera sequenza di caratteri
Lunghezza variabile
Mix di lettere/cifre/punteggiatura/spazi
Solitamente non contengono caratteri di controllo

F u l v i o 0 6 A Z N
70 117 108 118 105 111 48 54 65 90 78

0 1 1 - 5 6 4 6 3 3 2
48 49 49 45 53 54 52 54 51 51 50

26
Manipolazione delle stringhe

Occorre trattare l’insieme di caratteri


memorizzato nel vettore come un’unica
“variabile”
Ogni operazione elementare sulle stringhe
coinvolgerà tipicamente dei cicli che scandiscono
il vettore
Molte funzioni di libreria sono già disponibili per
compiere le operazioni più frequenti ed utili

27
Errore frequente

Non confondere una stringa composta da cifre


numeriche con il valore decimale associato a tale
sequenza

int char
137 1 3
7 7
49 51 55

28
Caratteri e stringhe
Il tipo char

Variabili char
Input/output di char
Operazioni sui char
Esercizio “Quadrati di lettere”

2
Il tipo char
Variabili char

I caratteri in C si memorizzano in variabili di tipo


char

char lettera ;

Le costanti di tipo char si indicano ponendo il


simbolo corrispondente tra singoli apici

lettera = 'Q' ;

4
Apici

Non confondere i 3 tipi di apici presenti sulla


tastiera:

Apice singolo ' In C, delimita singoli caratteri


(apostrofo)
Apice doppio " In C, delimita stringhe di
(virgolette) caratteri
Apice rovesciato ` Non utilizzato in C
(accento grave)

5
Dualità dei char

Sintatticamente, i char non sono altro che degli


int di piccola dimensione
Ogni operazione possibile su un int, è anche
possibile su un char
Ovviamente solo alcune di tali operazioni avranno
senso sull’interpretazione testuale (ASCII) del
valore numerico

6
Esempi

int i ;
char c ;

c = 'A' ;

7
Esempi

int i ;
char c ;

c = 'A' ;
c = 65 ; /* equivalente! */

8
Esempi

int i ;
char c ;

c = 'A' ;
c = 65 ; /* equivalente! */
i = c ; /* i sarà 65 */

9
Esempi

int i ;
char c ;

c = 'A' ;
c = 65 ; /* equivalente! */
i = c ; /* i sarà 65 */
c = c + 1 ; /* c sarà 66 = 'B' */

10
Esempi

int i ;
char c ;

c = 'A' ;
c = 65 ; /* equivalente! */
i = c ; /* i sarà 65 */
c = c + 1 ; /* c sarà 66 = 'B' */
c = c * 2 ; /* non ha senso... */

11
Esempi

int i ;
char c ;

c = 'A' ;
c = 65 ; /* equivalente! */
i = c ; /* i sarà 65 */
c = c + 1 ; /* c sarà 66 = 'B' */
c = c * 2 ; /* non ha senso... */
if (c == 'Z') ...

12
Esempi

int i ;
char c ;

c = 'A' ;
c = 65 ; /* equivalente! */
i = c ; /* i sarà 65 */
c = c + 1 ; /* c sarà 66 = 'B' */
c = c * 2 ; /* non ha senso... */
if (c == 'Z') ...
for(
for c='A'; c<='Z'; c++) ...
13
Caratteri speciali

Per alcuni caratteri di controllo il linguaggio C


definisce una particolare sequenza di escape
per poterli rappresentare

C ASCII Significato
'\n' LF – 10 A capo
'\t' TAB – 9 Tabulazione
'\b' BS – 8 Backspace – cancella ultimo car.
'\a' BEL – 7 Emette un “bip”
'\r' CR – 13 Torna alla prima colonna

14
Punteggiatura speciale in C

Alcuni caratteri hanno un significato particolare


dentro gli apici. Per poterli inserire come
carattere esistono apposite sequenze di escape

C ASCII Significato
'\\' \ Immette un backslash
'\'' ' Immette un apice singolo
'\"' " Immette un apice doppio
'\ooo' ooo Immette in carattere ASCII con
codice (ottale) ooo
'\xhh' hh Immette in carattere ASCII con
codice (esadecimale) hh 15
Il tipo char
Input/output di char

Esistono due insiemi di funzioni che permettono


di leggere e stampare variabili di tipo char:
Le funzioni printf/scanf, usando lo
specificatore di formato "%c"
Le funzioni putchar e getchar
In entrambi i casi è sufficiente includere la
libreria <stdio.h>
È possibile mescolare liberamente le due famiglie
di funzioni

17
Stampa di caratteri

char ch ;

printf("%c", ch) ;

char ch ;

putchar(ch) ;
18
Lettura di caratteri

char ch ;

scanf("%c", &ch) ;

char ch ;

ch = getchar() ;
19
Suggerimenti (1/2)

La funzione printf è più comoda quando


occorre stampare altri caratteri insieme a quello
desiderato
printf("La risposta e': %c\n", ch) ;
printf("Codice: %c%d\n", ch, num ) ;
La funzione putchar è più comoda quando
occorre stampare semplicemente il carattere
for(ch='a'; ch<='z'; ch++)
putchar(ch) ;

20
Suggerimenti (2/2)

La funzione getchar è generalmente più


comoda in tutti i casi
printf("Vuoi continuare (s/n)? ");
ch = getchar() ;

21
Bufferizzazione dell’input-output

Tutte le funzioni della libreria <stdio.h>


gestiscono l’input-output in modo bufferizzato
Per maggior efficienza, i caratteri non vengono
trasferiti immediatamente dal programma al
terminale (o viceversa), ma solo a gruppi
È quindi possibile che dopo una putchar, il
carattere non compaia immediatamente sullo
schermo
Analogamente, la getchar non restituisce il
carattere finché l’utente non preme invio

22
Conseguenza pratica

char ch,ch2 ;

printf("Dato: "); Dato: _

ch = getchar() ;

ch2 = getchar() ;

Il programma stampa l’invito ad inserire un dato 23


Conseguenza pratica

char ch,ch2 ;

printf("Dato: "); Dato: _

ch = getchar() ;

ch2 = getchar() ;

getchar blocca il programma in attesa del dato 24


Conseguenza pratica

char ch,ch2 ;

printf("Dato: "); Dato: a_

ch = getchar() ;

ch2 = getchar() ;

L’utente immette 'a', il programma non lo riceve 25


Conseguenza pratica

char ch,ch2 ;

printf("Dato: "); Dato: a


_
ch = getchar() ;

ch2 = getchar() ;

L’utente immette Invio, il programma prosegue 26


Conseguenza pratica

char ch,ch2 ;

printf("Dato: "); Dato: a


_
ch = getchar() ;

ch2 = getchar() ;

Ora ch='a', il programma fa un’altra getchar() 27


Conseguenza pratica

char ch,ch2 ;

printf("Dato: "); Dato: a


_
ch = getchar() ;

ch2 = getchar() ;

Il programma non si blocca in attesa dell’utente 28


Conseguenza pratica

char ch,ch2 ;

printf("Dato: "); Dato: a


_
ch = getchar() ;

ch2 = getchar() ;

C’era già un carattere pronto: Invio! ch2='\n' 29


Consigli pratici

Ricordare che l’utente deve sempre premere


Invio, anche se il programma richiede un singolo
carattere
Ricordare che, se l’utente inserisce più di un
carattere, questi verranno restituiti uno ad uno
nelle getchar successive
Ricordare che l’Invio viene letto come tutti gli
altri caratteri

30
Soluzione proposta

char ch, temp ;

printf("Dato: ");

ch = getchar() ; /* leggi il dato */

/* elimina eventuali caratteri successivi


ed il \n che sicuramente ci sarà */
do {
temp = getchar() ;
} while (temp != '\n') ;

31
Soluzione proposta

char ch, temp ;

printf("Dato: ");

ch = getchar() ; /* leggi il dato */


/* forma più compatta */
while
/* elimina eventuali ( getchar()!='\n'
caratteri successivi )
/*niente*/
ed il \n che sicuramente ci sarà; */
do {
temp = getchar() ;
} while (temp != '\n') ;

32
Il tipo char
Operazioni sui char

Le operazioni lecite sui char derivano


direttamente dalla combinazione tra
Le operazioni permesse sugli int
La disposizione dei caratteri nella tabella ASCII
Le convenzioni lessicali della nostra lingua scritta

34
Conversione ASCII-Carattere

Una variabile di tipo char è allo stesso tempo


Il valore numerico del codice ASCII del carattere
printf("%d", ch) ;
i = ch ;
ch = j ;
ch = 48 ;
Il simbolo corrispondente al carattere ASCII
printf("%c", ch) ;
putchar(ch) ;
ch = 'Z' ;
ch = '4' ;

35
Esempio (1/3)

int i ;
char ch ; char-int.c

printf("Immetti codice ASCII (32-126): ");

scanf("%d", &i) ;

ch = i ;

printf("Il carattere %c ha codice %d\n",


ch, i) ;

36
Esempio (2/3)

printf("Immetti un carattere: ") ; char-int.c


ch = getchar() ;

while(
while getchar() != '\n' )
/**/ ;

i = ch ;

printf("Il carattere %c ha codice %d\n",


ch, i) ;

37
Esempio (3/3)

char-int.c

Immetti un codice ASCII (32-126): 44


Il carattere , ha codice ASCII 44

Immetti un carattere: $
Il carattere $ ha codice ASCII 36

38
Scansione dell’alfabeto

È possibile generare tutte le lettere dell’alfabeto,


in ordine, grazie al fatto che nella tabella ASCII
esse compaiono consecutive e ordinate

char ch ;

for(
for ch = 'A' ; ch <= 'Z' ; ch++ )
putchar(ch) ;

putchar('\n') ;

39
Verifica se è una lettera

Per sapere se un carattere è alfabetico, è


sufficiente verificare se cade nell’intervallo delle
lettere (maiuscole o minuscole)

if(
if ch>='A' && ch<='Z' )
printf("%c lettera maiuscola\n", ch) ;

if(
if ch>='a' && ch<='z' )
printf("%c lettera minuscola\n", ch) ;

if(
if (ch>='A' && ch<='Z') ||
(ch>='a' && ch<='z') )
printf("%c lettera\n", ch) ; 40
Verifica se è una cifra

Per sapere se un carattere è numerico


('0'-'9'), è sufficiente verificare se cade
nell’intervallo delle cifre

if(
if ch>='0' && ch<='9' )
printf("%c cifra numerica\n", ch) ;

41
Valore di una cifra

Conoscere il valore decimale di un carattere


numerico ('0'-'9'), è sufficiente calcolare la
“distanza” dalla cifra '0'

if(
if ch>='0' && ch<='9' )
{
printf("%c cifra numerica\n", ch) ;
val = ch - '0' ;
printf("Il suo valore e': %d", val ) ;
}

42
Da minuscolo a maiuscolo (1/2)

I codici ASCII delle lettere maiuscole e delle


minuscole differiscono solamente per una
costante:
'A' = 65 ... 'Z' = 90
'a' = 97 ... 'z' = 122
Se ch è una lettera minuscola
ch - 'a' è la sua posizione nell’alfabeto
( ch - 'a' ) + 'A' è la corrispondente
lettera maiuscola

43
Da minuscolo a maiuscolo (2/2)

Possiamo interpretare la conversione come una


traslazione della quantità ( 'A'-'a' )

if(
if ch>='a' && ch<='z' )
{
printf("%c lettera minuscola\n", ch) ;
ch2 = ch + ('A'-'a') ;
printf(La maiuscola e': %c\n", ch2) ;
}

44
Confronto alfabetico

Se due caratteri sono entrambi maiuscoli (o


entrambi minuscoli) è sufficiente confrontare i
rispettivi codici ASCII

if(
if ch < ch2 )
printf("%c viene prima di %c", ch, ch2) ;
else
printf("%c viene prima di %c", ch2, ch) ;

45
Il tipo char
Esercizio “Quadrati di lettere”

Si scriva un programma in linguaggio C che


stampi su video una serie di quadrati, composti
dalle successive lettere dell’alfabeto, di
dimensioni sempre crescenti:
Un quadrato 1x1 di lettere A
Un quadrato 2x2 di lettere B
Un quadrato 3x3 di lettere C
...eccetera

47
Analisi

Quanti quadrati vuoi stampare? 4


A

BB
BB

CCC
CCC
CCC

DDDD
DDDD
DDDD
DDDD

48
Soluzione (1/2)

int i, N ;
int riga, col ; quadrati.c

char ch ;

printf("Quanti quadrati? ") ;


scanf("%d", &N) ;

while(N<1
while || N>26)
{
printf("Deve essere tra 1 e 26\n");
printf("Quanti quadrati? ") ;
scanf("%d", &N) ;
}
49
Soluzione (2/2)

for(
for i=0; i<N; i++ )
{
/* stampa un quadrato quadrati.c

di dimensione (i+1) */

ch = i + 'A' ;

for(riga=0;
for riga<i+1; riga++)
{
for(col=0;
for col<i+1; col++)
putchar(ch);
putchar('\n') ;
}
putchar('\n') ;
}
50
Caratteri e stringhe
Vettori di caratteri

Il tipo stringa
Terminatore nullo
Input/output di stringhe

2
Vettori di caratteri
Stringhe in C

Nel linguaggio C non è supportato esplicitamente


alcun tipo di dato “stringa”
Le informazioni di tipo stringa vengono
memorizzate ed elaborate ricorrendo a semplici
vettori di caratteri

char saluto[10] ;

B u o n g i o r n o
4
Esempio

Si realizzi un programma in linguaggio C che


acquisisca da tastiera il nome dell’utente (una
stringa di max 20 caratteri), e stampi a video un
saluto per l’utente stesso

Come ti chiami? Fulvio

Buongiorno, Fulvio!

5
Soluzione (1/3)

saluti.c

const int MAX = 20 ;


char nome[MAX] ;
int N ;
char ch ;
int i ;

printf("Come ti chiami? ") ;

N = 0 ;

6
Soluzione (2/3)

saluti.c

ch = getchar() ;

while(
while ch != '\n' && N<MAX )
{
nome[N] = ch ;
N++ ;
ch = getchar() ;
}

7
Soluzione (3/3)

saluti.c

printf("Buongiorno, ") ;

for(i=0;
for i<N; i++)
putchar( nome[i] ) ;

printf("!\n") ;

8
Commenti (1/2)

Qualsiasi operazione sulle stringhe si può


realizzare agendo opportunamente su vettori di
caratteri, gestiti con occupazione variabile
Così facendo, però vi sono alcuni svantaggi
Per ogni vettore di caratteri, occorre definire
un’opportuna variabile che ne indichi la lunghezza
Ogni operazione, anche elementare, richiede l’uso
di cicli for/while

9
Commenti (2/2)

Alcune convenzioni ci possono aiutare


Gestire in modo standard i vettori di caratteri usati
per memorizzare stringhe
Apprendere le tecniche solitamente utilizzate per
compiere le operazioni più frequenti
Molte funzioni di libreria seguono queste
convenzioni
Conoscere le funzioni di libreria ed utilizzarle per
accelerare la scrittura del programma

10
Vettori di caratteri
Lunghezza di una stringa

Vi sono due tecniche per determinare la


lunghezza di una stringa
1. utilizzare una variabile intera che memorizzi il
numero di caratteri validi

char nome[10] ; F u l v i o Z ! $ .
int lungh_nome ;
6

12
Lunghezza di una stringa

Vi sono due tecniche per determinare la


lunghezza di una stringa
1. utilizzare una variabile intera che memorizzi il
numero di caratteri validi

char nome[10] ; F u l v i o Z ! $ .
int lungh_nome ;
6
2. utilizzare un carattere “speciale”, con funzione di
terminatore, dopo l’ultimo carattere valido

char nome[10] ; F u l v i o Ø ! $ .
13
Carattere terminatore

Il carattere “terminatore” deve avere le seguenti


caratteristiche
Fare parte della tabella dei codici ASCII
Deve essere rappresentabile in un char
Non comparire mai nelle stringhe utilizzate dal
programma
Non deve confondersi con i caratteri “normali”
Inoltre il vettore di caratteri deve avere una
posizione libera in più, per memorizzare il
terminatore stesso

14
Terminatore standard in C

Per convenzione, in C si sceglie che tutte le


stringhe siano rappresentate mediante un
carattere terminatore
Il terminatore corrisponde al carattere di codice
ASCII pari a zero
nome[6] = 0 ;
nome[6] = '\0' ;

F u l v i o Ø ! $ .
15
Vantaggi

Non è necessaria un’ulteriore variabile intera per


ciascuna stringa
L’informazione sulla lunghezza della stringa è
interna al vettore stesso
Tutte le funzioni della libreria standard C
rispettano questa convenzione
Si aspettano che la stringa sia terminata
Restituiscono sempre stringhe terminate

16
Svantaggi

Necessario 1 byte in più


Per una stringa di N caratteri, serve un vettore di
N+1 elementi
Necessario ricordare di aggiungere sempre il
terminatore
Impossibile rappresentare stringhe contenenti il
carattere ASCII 0

17
Esempio

Si realizzi un programma in linguaggio C che


acquisisca da tastiera il nome dell’utente (una
stringa di max 20 caratteri), e stampi a video un
saluto per l’utente stesso

Come ti chiami? Fulvio

Buongiorno, Fulvio!

18
Soluzione (1/3)

saluti0.c

const int MAX = 20 ;


char nome[MAX+1] ;
char ch ;
int i ;

printf("Come ti chiami? ") ;

i = 0 ;

19
Soluzione (2/3)

i = 0 ;
saluti0.c

ch = getchar() ;

while(
while ch != '\n' && i<MAX )
{
nome[i] = ch ;
i++ ;
ch = getchar() ;
}
/* aggiunge terminatore nullo */
nome[i] = '\0' ;

20
Soluzione (3/3)

saluti0.c

printf("Buongiorno, ") ;

for(i=0;
for nome[i]!='\0'; i++)
putchar( nome[i] ) ;

printf("!\n") ;

21
Vettori di caratteri
I/O di stringhe

Diamo per scontato di utilizzare la convenzione


del terminatore nullo
Si possono utilizzare
Funzioni di lettura e scrittura carattere per
carattere
Come nell’esercizio precedente
Funzioni di lettura e scrittura di stringhe intere
scanf e printf
gets e puts

23
Lettura di stringhe con scanf

Utilizzare la funzione scanf con lo specificatore


di formato "%s"
La variabile da leggere deve essere il nome di un
vettore di caratteri
Non utilizzare le parentesi quadre
Non utilizzare la &
Legge ciò che viene immesso da tastiera, fino al
primo spazio o fine linea (esclusi)
Non adatta a leggere nomi composti
(es. "Pier Paolo")

24
Esempio

const int MAX = 20 ;


char nome[MAX+1] ;

printf("Come ti chiami? ") ;

scanf("%s", nome) ;

25
Lettura di stringhe con gets

La funzione gets è pensata appositamente per


acquisire una stringa
Accetta un parametro, che corrisponde al nome
di un vettore di caratteri
Non utilizzare le parentesi quadre
Legge ciò che viene immesso da tastiera, fino al
fine linea (escluso), e compresi eventuali spazi
Possibile leggere nomi composti
(es. "Pier Paolo")

26
Esempio

const int MAX = 20 ;


char nome[MAX+1] ;

printf("Come ti chiami? ") ;

gets(nome) ;

27
Scrittura di stringhe con printf

Utilizzare la funzione printf con lo specificatore


di formato "%s"
La variabile da stampare deve essere il nome di
un vettore di caratteri
Non utilizzare le parentesi quadre
È possibile combinare la stringa con altre variabili
nella stessa istruzione

28
Esempio

printf("Buongiorno, ") ;
printf("%s", nome) ;
printf("!\n") ;

printf("Buongiorno, %s!\n", nome) ;

29
Scrittura di stringhe con puts

La funzione puts è pensata appositamente per


stampare una stringa
La variabile da stampare deve essere il nome di
un vettore di caratteri
Non utilizzare le parentesi quadre
Va a capo automaticamente
Non è possibile stampare altre informazioni sulla
stessa riga

30
Esempio

printf("Buongiorno, ") ;
puts(nome) ;

/* No!! printf("!\n") ; */

31
Conclusione

Utilizzare sempre la convenzione del terminatore


nullo
Ricordare di allocare un elemento in più nei
vettori di caratteri
Utilizzare quando possibile le funzioni di libreria
predefinite
In lettura, prediligere gets
In scrittura
printf è indicata per messaggi composti
puts è più semplice se si ha un dato per riga

32
Caratteri e stringhe
Operazioni elementari sulle stringhe

Lunghezza
Copia di stringhe
Concatenazione di stringhe
Confronto di stringhe
Ricerca di sotto-stringhe
Ricerca di parole

2
Operazioni elementari sulle stringhe
Lunghezza di una stringa

La lunghezza di una stringa si può determinare


ricercando la posizione del terminatore nullo

char s[MAX+1] ;
int lun ;

s S a l v e Ø 3 r W t
0 1 2 3 4 5

4
Calcolo della lunghezza

const int MAX = 20 ;


char s[MAX+1] ;
int lun ;
int i ;

... /* lettura stringa */

for(
for i=0 ; s[i] != 0 ; i++ )
/* Niente */ ;

lun = i ;

5
La funzione strlen

Nella libreria standard C è disponibile la funzione


strlen, che calcola la lunghezza della stringa
passata come parametro
Necessario includere <string.h>

const int MAX = 20 ;


char s[MAX+1] ;
int lun ;

... /* lettura stringa */

lun = strlen(s) ;
6
Operazioni elementari sulle stringhe
Copia di stringhe

L’operazione di copia prevede di ricopiare il


contenuto di una prima stringa “sorgente”, in una
seconda stringa “destinazione”

char src[MAXS+1] ;
char dst[MAXD+1] ;

src S a l v e Ø 3 r W t

dst Ø 2 % q " t o $ n o
8
Risultato della copia

src S a l v e Ø 3 r W t

dst Ø 2 % q " t o $ n o
Copia src in dst

dst S a l v e Ø o $ n o

9
Copia

const int MAXS = 20, MAXD = 30 ;


char src[MAXS+1] ;
char dst[MAXD+1] ;
int i ;

... /* lettura stringa src */

for(
for i=0 ; src[i] != 0 ; i++ )
dst[i] = src[i] ; /* copia */

dst[i] = 0 ; /* aggiunge terminatore */

10
La funzione strcpy

Nella libreria standard C, includendo


<string.h>, è disponibile la funzione strcpy,
che effettua la copia di stringhe
Primo parametro: stringa destinazione
Secondo parametro: stringa sorgente

const int MAXS = 20, MAXD = 30 ;


char src[MAXS+1] ;
char dst[MAXD+1] ;

... /* lettura stringa src */

strcpy(dst, src) ; 11
Avvertenze

Nella stringa destinazione vi deve essere un


numero sufficiente di locazioni libere
MAXD+1 >= strlen(src)+1
Il contenuto precedente della stringa
destinazione viene perso
La stringa sorgente non viene modificata
Il terminatore nullo
Deve essere aggiunto in coda a dst
La strcpy pensa già autonomamente a farlo

12
Errore frequente

Per effettuare una copia di stringhe non si può


assolutamente utilizzare l’operatore =
Necessario usare strcpy

dst = src ; strcpy(dst, src);

dst[] = src[] ;

dst[MAXD] = src[MAXC] ;
13
Operazioni elementari sulle stringhe
Concatenazione di stringhe

L’operazione di concatenazione corrisponde a


creare una nuova stringa composta dai caratteri
di una prima stringa, seguiti dai caratteri di una
seconda stringa

sa S a l v e Ø 3 r W t

sb m o n d o Ø o $ n o

Concatenazione di sa con sb

S a l v e m o n d o Ø w 1 Q r
15
Semplificazione

Per maggior semplicità, in C l’operazione di


concatenazione scrive il risultato nello stesso
vettore della prima stringa
Il valore precedente della prima stringa viene così
perso
Per memorizzare altrove il risultato, o per non
perdere la prima stringa, è possibile ricorrere a
stringhe temporanee ed alla funzione strcpy

16
Esempio

sa S a l v e Ø w z 3 w 7 w 1 Q r

sb m o n d o Ø h ! L . 2 x y E P

Concatenazione di sa con sb

sa S a l v e m o n d o Ø w 1 Q r

sb m o n d o Ø h ! L . 2 x y E P
17
Algoritmo di concatenazione

Trova la fine della prima stringa

sa S a l v e Ø w z 3 w 7 w 1 Q r

18
Algoritmo di concatenazione

Trova la fine della prima stringa


Copia la seconda stringa nel vettore della prima,
a partire della posizione del terminatore nullo
(sovrascrivendolo)

sa S a l v e Ø w z 3 w 7 w 1 Q r

sb m o n d o Ø h ! L . 2 x y E P

19
Algoritmo di concatenazione

Trova la fine della prima stringa


Copia la seconda stringa nel vettore della prima,
a partire della posizione del terminatore nullo
(sovrascrivendolo)
Termina la copia non appena trovato il
terminatore della seconda stringa

sa S a l v e m o n d o Ø w 1 Q r

sb m o n d o Ø h ! L . 2 x y E P

20
Concatenazione

const int MAX = 20 ;


char sa[MAX] ;
char sb[MAX] ;
int la ;
int i ;

... /* lettura stringhe */

la = strlen(sa) ;

for(
for i=0 ; sb[i] != 0 ; i++ )
sa[la+i] = sb[i] ; /* copia */

sa[la+i] = 0 ; /* terminatore */
21
La funzione strcat

Nella libreria standard C, includendo


<string.h>, è disponibile la funzione strcat,
che effettua la concatenazione di stringhe
Primo parametro: prima stringa (destinazione)
Secondo parametro: seconda stringa

const int MAX = 20 ;


char sa[MAX] ;
char sb[MAX] ;

... /* lettura stringhe */

strcat(sa, sb) ; 22
Avvertenze (1/2)

Nella prima stringa vi deve essere un numero


sufficiente di locazioni libere
MAX+1 >= strlen(sa)+strlen(sb)+1
Il contenuto precedente della prima stringa
viene perso
La seconda stringa non viene modificata
Il terminatore nullo
Deve essere aggiunto in coda alla prima stringa
La strcat pensa già autonomamente a farlo

23
Avvertenze (2/2)

Per concatenare 3 o più stringhe, occorre farlo


due a due:
strcat(sa, sb);
strcat(sa, sc);
È possibile concatenare anche stringhe costanti
strcat(sa, "!");

24
Operazioni elementari sulle stringhe
Confronto di stringhe

Il confronto di due stringhe (es.: sa e sb), mira


a determinare se:
Le due stringhe sono uguali
hanno uguale lunghezza e sono composte dagli
stessi caratteri nello stesso ordine
Le due stringhe sono diverse
La stringa sa precede la stringa sb
secondo l’ordine lessicografico imposto dal codice
ASCII
parzialmente compatibile con l’ordine alfabetico
La stringa sa segue la stringa sb

26
Confronto di uguaglianza

Ogni carattere di sa deve essere uguale al


carattere corrispondente di sb
Il terminatore nullo deve essere nella stessa
posizione
I caratteri successivi al terminatore vanno
ignorati

sa S a l v e Ø o 4 d 1 Ø w 1 Q r

sb S a l v e Ø h ! L . 2 x y E P
27
Confronto di uguaglianza

const int MAX = 20 ;


char sa[MAX] ;
char sb[MAX] ;
int uguali ;
int i ;
...

uguali = 1 ;
for(
for i=0 ; sa[i]!=0 && sb[i]!=0 ; i++ )
{
if(sa[i]!=sb[i])
if
uguali = 0 ;
}
if(sa[i]!=0
if || sb[i]!=0)
uguali = 0 ;
28
Confronto di uguaglianza

const int MAX = 20 ;


char sa[MAX] ;
char sb[MAX]Flag:
; ricerca di universalità
int uguali ; della condizione
int i ; sa[i]==sb[i]
...

uguali = 1 ;
for(
for i=0 ; sa[i]!=0 && sb[i]!=0 ; i++ )
{
if(sa[i]!=sb[i])
if
uguali = 0 ;
}
if(sa[i]!=0
if || sb[i]!=0)
uguali = 0 ;
29
Confronto di uguaglianza

const int MAX = 20 ;


char sa[MAX] ;
char sb[MAX] ; Cicla fino al terminatore di
int uguali ; sa o di sb
int i ; (il primo che si incontra)
...

uguali = 1 ;
for(
for i=0 ; sa[i]!=0 && sb[i]!=0 ; i++ )
{
if(sa[i]!=sb[i])
if
uguali = 0 ;
}
if(sa[i]!=0
if || sb[i]!=0)
uguali = 0 ;
30
Confronto di uguaglianza

const int MAX = 20 ;


char sa[MAX] ;
char sb[MAX] ;
int uguali ;
int i ;
...
Verifica che tutti i caratteri
uguali = 1 ; incontrati siano uguali.
for(
for i=0 ; sa[i]!=0 &&
Se sb[i]!=0
no, poni a 0 il;flag
i++ )
uguali.
{
if(sa[i]!=sb[i])
if
uguali = 0 ;
}
if(sa[i]!=0
if || sb[i]!=0)
uguali = 0 ;
31
Confronto di uguaglianza

const int MAX = 20 ;


char sa[MAX] ;
char sb[MAX] ;
int uguali ;
int i ;
...
In questo punto sicuramente
uguali = 1 ; una delle due stringhe è
for(
for i=0 ; sa[i]!=0 && sb[i]!=0 ; i++ )
arrivata al terminatore.
{ Se non lo è anche l’altra,
if(sa[i]!=sb[i])
if allora non sono uguali!
uguali = 0 ;
}
if(sa[i]!=0
if || sb[i]!=0)
uguali = 0 ;
32
Confronto di ordine

Verifichiamo se sa “è minore di” sb. Partiamo


con i=0
Se sa[i]<sb[i], allora sa è minore
Se sa[i]>sb[i], allora sa non è minore
Se sa[i]=sb[i], allora bisogna controllare i
caratteri successivi (i++)
Il terminatore nullo conta come “minore” di tutti
sa S a l v e Ø o 4 d 1 Ø w 1 Q r

sb S a l u t e Ø ! L . 2 x y E P
33
Confronto di ordine (1/2)

const int MAX = 20 ;


char sa[MAX] ;
char sb[MAX] ;
int minore ;
int i ;
...
minore = 0 ;
for(
for i=0 ; sa[i]!=0 && sb[i]!=0
&& minore==0; i++ )
{
if(sa[i]<sb[i])
if
minore = 1 ;
if(sa[i]>sb[i])
if
minore = -1 ;
}
34
Confronto di ordine (2/2)

if(minore==0
if && sa[i]==0 && sb[i]!=0)
minore=1 ;

if(minore==1)
if
printf("%s e' minore di %s\n",
sa, sb ) ;

35
Commenti

minore = 0 ;
for(
for i=0 ; sa[i]!=0 && sb[i]!=0
Ricerca
&& minore==0; i++di esistenza
) della
{ condizione sa[i]<sb[i].
if(sa[i]<sb[i])
if
minore = 1 ;
if(sa[i]>sb[i])
if
minore = -1 ;
}

if(minore==0
if && sa[i]==0 && sb[i]!=0)
minore=1 ;

if(minore==1)
if
...
36
Commenti

minore = 0 ;
for(
for i=0 ; sa[i]!=0 && sb[i]!=0
&& minore==0; i++ )
{
if(sa[i]<sb[i])
if
minore = 1 ; fino al primo terminatore
Cicla
if(sa[i]>sb[i])
if nullo, oppure fino a che non si
minore = -1 “scopre”
; chi è minore.
} In altre parole, continua a
ciclare solo finché le stringhe
if(minore==0
if && sa[i]==0 && sb[i]!=0)
“sembrano” uguali.
minore=1 ;

if(minore==1)
if
...
37
Commenti

minore = 0 ;
for(
for i=0 ; sa[i]!=0 && sb[i]!=0
Sicuramente sa è minore di sb
&& minore==0;Flag:i++ )
minore = 1
{
if(sa[i]<sb[i])
if
minore = 1 ;
if(sa[i]>sb[i])
if
minore = -1 ;
}
Sicuramente sa non è minore
Se flag
if(minore==0
if di sb
&& sa[i]==0 && sb[i]!=0)
minore==0
minore=1 ; Flag: minore = -1
continua a ciclare
if(minore==1)
if
...
38
Commenti

minore = 0 ;
for(
for i=0 ; sa[i]!=0 && sb[i]!=0
&& minore==0; i++ )
{
if(sa[i]<sb[i])
if
minore = 1 ; Se finora erano uguali, ma sa è
if(sa[i]>sb[i])
if più corta di sb, allora sa è
minore = -1 ; minore
}

if(minore==0
if && sa[i]==0 && sb[i]!=0)
minore=1 ;

if(minore==1)
if
...
39
La funzione strcmp

Nella libreria standard C, includendo


<string.h>, è disponibile la funzione strcmp,
che effettua il confronto di stringhe
Primo parametro: prima stringa
Secondo parametro: seconda stringa
Valore restituito:
<0 se la prima stringa è minore della seconda
==0 se le stringhe sono uguali
>0 se la prima stringa è maggiore della seconda

40
Confronti vari

const int MAX = 20 ;


char sa[MAX] ;
char sb[MAX] ;
int ris ;

...

ris = strcmp(sa, sb) ;

if(ris<0)
if
printf("%s minore di %s\n", sa, sb);
if(ris==0)
if
printf("%s uguale a %s\n", sa, sb);
if(ris>0)
if
printf("%s maggiore di %s\n", sa, sb);
41
Suggerimento

Per ricordare il significato del valore calcolato da


strcmp, immaginare che la funzione faccia una
“sottrazione” tra le due stringhe
sa – sb
Negativo: sa minore
Positivo: sa maggiore
Nullo: uguali

const int MAX = 20 ;


char sa[MAX] ;
char sb[MAX] ;
int ris ;
...
ris = strcmp(sa, sb) ; 42
Ordinamento delle stringhe

La funzione strcmp lavora confrontando tra loro


i codici ASCII dei caratteri
Il criterio di ordinamento è quindi dato dalla
posizione dei caratteri nella tabella ASCII

Nullo Spazio Cifre numeriche Lettere maiuscole Lettere minuscole

Ø  0 … 9 A … Z a … z

Caratteri di Punteggiatura Punteggiatura Punteggiatura Punteggiatura


controllo

43
Conseguenze

Ogni lettera maiuscola precede ogni lettera


minuscola
Ciao precede ciao
Zulu precede apache
Gli spazi contano, e precedono le lettere
Qui Quo Qua precede QuiQuoQua
I simboli di punteggiatura contano, ma non vi è
una regola intuitiva
L’ordinamento che si ottiene è lievemente diverso
da quello “standard” alfabetico
44
Operazioni elementari sulle stringhe
Ricerca in una stringa

È possibile concepire diversi tipi di ricerche da


compiersi all’interno di una stringa:
Determinare se un determinato carattere compare
all’interno di una stringa data
Determinare se una determinata stringa compare
integralmente all’interno di un’altra stringa data, in
una posizione arbitraria

46
Ricerca di un carattere (1/2)

Detti:
s una stringa arbitraria
ch un carattere qualsiasi
Determinare se la stringa s contiene (una o più
volte) il carattere ch al suo interno, in qualsiasi
posizione

s S a l v e Ø o 4 d 1 a w 1 Q r

ch a
47
Ricerca di un carattere (2/2)

const int MAX = 20 ;


char s[MAX] ;
char ch ;
int trovato ;
int i ;

...

trovato = 0 ;
for(
for i=0 ; s[i]!=0 && trovato==0; i++ )
{
if(
if s[i]==ch )
trovato = 1 ;
}
48
La funzione strchr (1/2)

Nella libreria standard C, includendo


<string.h>, è disponibile la funzione strchr,
che effettua la ricerca di un carattere
Primo parametro: stringa in cui cercare
Secondo parametro: carattere da cercare
Valore restituito:
!=NULL se il carattere c’è
==NULL se il carattere non c’è

49
La funzione strchr (2/2)

const int MAX = 20 ;


char s[MAX] ;
char ch ;

...

if(strchr(s,
if ch)!=NULL)
printf("%s contiene %c\n", s, ch) ;

50
Ricerca di una sotto-stringa

Detti:
s una stringa arbitraria
r una stringa da ricercare
Determinare se la stringa s contiene (una o più
volte) la stringa r al suo interno, in qualsiasi
posizione

s S a l v e a t u t t i Ø r

r t u t Ø z 3
51
Esempio

s S a l v e a t u t t i Ø r

t u t

r t u t Ø z 3 52
Esempio

s S a l v e a t u t t i Ø r

t u t

t u t

r t u t Ø z 3 53
Esempio

s S a l v e a t u t t i Ø r

t u t t u t t u t

t u t t u t

t u t t u t

t u t t u t

r t u t Ø z 3 54
Esempio

s S a l v e a t u t t i Ø r

t u t t u t t u t

t u t t u t t u t

t u t t u t t u t

t u t t u t

r t u t Ø z 3 55
Algoritmo di ricerca

lr = strlen(r) ; ls = strlen(s)
trovato = 0
Per ogni posizione possibile di r all’interno di s:
pos = 0...ls-lr (compresi)

s S a l v e a t u t t i Ø r

pos r t u t Ø lr ls 56
Algoritmo di ricerca

lr = strlen(r) ; ls = strlen(s)
trovato = 0
Per ogni posizione possibile di r all’interno di s:
pos = 0...ls-lr (compresi)
Controlla se i caratteri di r, tra 0 e lr-1,
coincidono con i caratteri di s, tra pos e
pos+lr-1
Se sì, trovato = 1

s S a l v e a t u t t i Ø r

pos r t u t Ø lr ls 57
Algoritmo di ricerca

lr = strlen(r) ; ls diversi = 0 ;
= strlen(s)
for(i=0;
for i<lr; i++)
trovato = 0 if(r[i]!=s[pos+i])
if
diversi = 1 ;
Per ogni posizione possibile di r all’interno di s:
pos = 0...ls-lr (compresi)
Controlla se i caratteri di r, tra 0 e lr-1,
coincidono con i caratteri di s,tra pos e
pos+lr-1
Se sì, trovato = 1

s S a l v e a t u t t i Ø r

pos r t u t Ø lr ls 58
Algoritmo di ricerca

lr = strlen(r) ; ls = strlen(s)
trovato = 0
Per ogni posizione possibile di r all’interno di s:
pos = 0...ls-lr if(diversi==0)
if
Controlla se i caratteri di trovato=1 ;
r, tra 0 e lr-1,
coincidono con i caratteri di s,tra pos e
pos+lr-1
Se sì, trovato = 1

s S a l v e a t u t t i Ø r

pos r t u t Ø lr ls 59
Ricerca di una sotto-stringa (1/2)

const int MAX = 20 ; substr.c

char s[MAX] ;
char r[MAX] ;
int lr, ls, pos ;
int i ;
int trovato, diversi ;

...

ls = strlen(s);
lr = strlen(r);

60
Ricerca di una sotto-stringa (2/2)

trovato = 0 ;
for(pos=0;
for pos<=ls-lr; pos++)
{ substr.c

/* confronta r[0...lr-1] con s[pos...pos+lr-1] */


diversi = 0 ;
for(i=0;
for i<lr; i++)
if(r[i]!=s[pos+i])
if
diversi = 1 ;

if(diversi==0)
if
trovato=1 ;
}

if(trovato==1)
if
printf("Trovato!\n");
61
La funzione strstr (1/2)

Nella libreria standard C, includendo


<string.h>, è disponibile la funzione strstr,
che effettua la ricerca di una sottostringa
Primo parametro: stringa in cui cercare
Secondo parametro: sotto-stringa da cercare
Valore restituito:
!=NULL se la sotto-stringa c’è
==NULL se la sotto-stringa non c’è

62
La funzione strstr (2/2)

const int MAX = 20 ;


char s[MAX] ;
char r[MAX] ;

...

if(strstr(s,
if r)!=NULL)
printf("Trovato!\n");

63
Operazioni elementari sulle stringhe
Ricerca di parole

Talvolta non interessa trovare una qualsiasi


sotto-stringa, ma solamente verificare se una
parola completa è presente in una stringa

s1 C i a o n o n n o Ø t 2 " r

s2 O g g i n o n c ' e ' Ø 4

r n o n Ø z 3
65
Definizioni (1/2)

Lettera: carattere ASCII facente parte


dell’alfabeto maiuscolo ('A'...'Z') o minuscolo
('a'...'z')
Parola: insieme consecutivo di lettere, separato
da altre parole mediante spazi, numeri o simboli
di punteggiatura

66
Definizioni (2/2)

Inizio di parola: lettera, prima della quale non


vi è un’altra lettera
Non vi è un altro carattere (inizio stringa)
Vi è un altro carattere, ma non è una lettera
Fine di parola: lettera, dopo la quale non vi è
un’altra lettera
Non vi è un altro carattere (fine stringa)
Vi è un altro carattere, ma non è una lettera

67
Algoritmo di ricerca

Per ogni possibile posizione pos di r all’interno di


s
Se il carattere in quella posizione, s[pos], è un
inizio di parola
Controlla se i caratteri di r, tra 0 e lr-1, coincidono
con i caratteri di s,tra pos e pos+lr-1
Controlla se s[pos+lr-1] è una fine di parola
Se entrambi i controlli sono ok, allora trovato=1

68
Algoritmo di ricerca

Per ogni possibile posizione pos di r all’interno di


s
Se il carattere in quella posizione, s[pos], è un
inizio di parola
Controlla se i caratteri di r, tra 0 e lr-1, coincidono
con i caratteri di s,tra pos e pos+lr-1
Controlla se s[pos+lr-1] è una fine di parola
if(
if pos
Se entrambi i controlli == ok,
sono 0 ||
allora trovato=1
s[pos-1] non è una lettera )

69
Algoritmo di ricerca

Per ogni possibile posizione pos di r all’interno di


s
Se il carattere in quella posizione, s[pos], è un
inizio di parola
Controlla se i caratteri di r, tra 0 e lr-1, coincidono
con i caratteri di s,tra pos e pos+lr-1
Controlla se s[pos+lr-1] è una fine di parola
if(
if pos
Se entrambi i controlli == ok,
sono 0 ||
allora trovato=1
s[pos-1] non è una lettera )

if(
if pos == 0 ||
!( (s[pos-1]>='a' && s[pos-1]<='z') ||
(s[pos-1]>='A' && s[pos-1]<='Z') )
)
70
Algoritmo di ricerca

Per ogni possibile posizione pos di r all’interno di


s if(
if pos == ls-lr ||
Se il carattere in quellas[pos+lr] s[pos],
posizione,non è un)
è una lettera
inizio di parola
Controlla se i caratteri di r, tra 0 e lr-1, coincidono
con i caratteri di s,tra pos e pos+lr-1
Controlla se s[pos+lr-1] è una fine di parola
Se entrambi i controlli sono ok, allora trovato=1

71
Algoritmo di ricerca

Per ogni possibile posizione pos di r all’interno di


s if(
if pos == ls-lr ||
Se il carattere in quellas[pos+lr] s[pos],
posizione,non è un)
è una lettera
inizio di parola
if(
if pos == ls-lr se
Controlla || i caratteri di r, tra 0 e lr-1, coincidono
!( (s[pos+lr]>='a' && s[pos+lr]<='z') ||
con i caratteri di s,tra pos e pos+lr-1
(s[pos+lr]>='A' && s[pos+lr]<='Z') )
) Controlla se s[pos+lr-1] è una fine di parola
Se entrambi i controlli sono ok, allora trovato=1

72
Ricerca di una parola (1/2)

trovato = 0 ;
for(pos=0;
for pos<=ls-lr; pos++) parola.c

{
if(
if pos==0 ||
!( (s[pos-1]>='a' &&
s[pos-1]<='z') ||
(s[pos-1]>='A' &&
s[pos-1]<='Z') ) )
{
diversi = 0 ;
for(i=0;
for i<lr; i++)
if(r[i]!=s[pos+i])
if
diversi = 1 ;
73
Ricerca di una parola (2/2)

if(
if diversi==0 &&
parola.c
( pos == ls-lr ||
!( (s[pos+lr]>='a' &&
s[pos+lr]<='z') ||
(s[pos+lr]>='A' &&
s[pos+lr]<='Z') )
) )
{
trovato=1 ;
}
}
}

74
La funzione strparola

Nella libreria standard C non esiste alcuna


funzione che svolga automaticamente la ricerca
di una parola intera!!!
Occorre identificare, ogni volta, se il compito da
svolgere è riconducibile ad una o più funzioni di
libreria
Eventualmente si combinano tra loro più funzioni
di libreria diverse
In alcuni casi occorre però ricorrere all’analisi
carattere per carattere

75
Caratteri e stringhe
Funzioni di libreria

Introduzione
Lunghezza di stringhe
Classificazione di caratteri
Trasformazione di caratteri
Copia e concatenazione
Confronto di stringhe
Ricerca in stringhe
Conversione numero-stringa

2
Funzioni di libreria
Librerie sulle stringhe

La libreria standard C dispone di molte funzioni


predisposte per lavorare su caratteri e stringhe
Tali funzioni si trovano prevalentemente in due
librerie:
<ctype.h> funzioni operanti su caratteri
<string.h> funzioni operanti su stringhe
Tutte le funzioni di libreria accettano e generano
stringhe correttamente terminate

4
Suggerimenti

Quando possibile, utilizzare sempre le funzioni di


libreria
Sono più veloci
Sono maggiormente collaudate
In ogni caso, ricordare che è sempre possibile
effettuare le operazioni direttamente:
Sui caratteri, ricorrendo alla codifica ASCII
Sulle stringhe, ricorrendo alla rappresentazione
come vettori di caratteri

5
Rappresentazione

Nome funzione strlen


Libreria #include <string.h>
Parametri in s : stringa
ingresso
Valore restituito int : la lunghezza della stringa
Descrizione Calcola la lunghezza della stringa s

Esempio lun = strlen(s) ;

6
Convenzioni

Assumiamo che nel seguito di questa lezione


siano valide le seguenti definizioni

const int MAX = 20 ;


char s[MAX] ;
char s1[MAX] ;
char s2[MAX] ;
char r[MAX] ;
int lun ;
int n ;
char ch ;
float x ;
7
Funzioni di libreria
Lunghezza di stringhe

Definite in strlen
<string.h>
Determina la lunghezza
di una stringa data

9
strlen

Nome funzione strlen


Libreria #include <string.h>
Parametri in s : stringa
ingresso
Valore restituito int : la lunghezza della stringa
Descrizione Calcola la lunghezza della stringa s

Esempio lun = strlen(s) ;

10
Funzioni di libreria
Classificazione di caratteri

Definite in <ctype.h> isalpha


Analizzano un singolo isupper
carattere, islower
identificandone la isdigit
tipologia isalnum
Lettera isxdigit
Maiuscola ispunct
Minuscola isgraph
Cifra isprint
Punteggiatura isspace
iscntrl

12
isalpha

Nome funzione isalpha


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito Vero/falso
Descrizione Ritorna “vero” se il carattere ch è una
lettera maiuscola o minuscola (A...Z,
a...z), “falso” altrimenti

Esempio if(isalpha(ch))
if
{ ... }
13
isupper

Nome funzione isupper


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito Vero/falso
Descrizione Ritorna “vero” se il carattere ch è una
lettera maiuscola (A...Z), “falso”
altrimenti

Esempio if(isupper(ch))
if
{ ... }
14
islower

Nome funzione islower


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito Vero/falso
Descrizione Ritorna “vero” se il carattere ch è una
lettera minuscola (a...z), “falso”
altrimenti

Esempio if(islower(ch))
if
{ ... }
15
isdigit

Nome funzione isdigit


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito Vero/falso
Descrizione Ritorna “vero” se il carattere ch è una
cifra numerica (0...9), “falso”
altrimenti

Esempio if(isdigit(ch))
if
{ ... }
16
isalnum

Nome funzione isalnum


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito Vero/falso
Descrizione Ritorna “vero” se il carattere ch è una
lettera oppure una cifra numerica,
“falso” altrimenti.
Equivalente a
isalpha(ch)||isdigit(ch)
Esempio if(isalnum(ch))
if
{ ... } 17
isxdigit

Nome funzione isxdigit


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito Vero/falso
Descrizione Ritorna “vero” se il carattere ch è una
una cifra numerica oppure una lettera
valida in base 16 (a...f, A...F), “falso”
altrimenti.
Esempio if(isxdigit(ch))
if
{ ... }
18
ispunct

Nome funzione ispunct


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito Vero/falso
Descrizione Ritorna “vero” se il carattere ch è un
simbolo di punteggiatura
(!"#$%&'()*+,-./:;<=>?@
[\]^_`{|}~), “falso” altrimenti.
Esempio if(ispunct(ch))
if
{ ... }
19
isgraph

Nome funzione isgraph


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito Vero/falso
Descrizione Ritorna “vero” se il carattere ch è un
qualsiasi simbolo visibile (lettera,
cifra, punteggiatura), “falso”
altrimenti.
Esempio if(isgraph(ch))
if
{ ... }
20
isprint

Nome funzione isprint


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito Vero/falso
Descrizione Ritorna “vero” se il carattere ch è un
qualsiasi simbolo visibile oppure lo
spazio, “falso” altrimenti.

Esempio if(isprint(ch))
if
{ ... }
21
isspace

Nome funzione isspace


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito Vero/falso
Descrizione Ritorna “vero” se il carattere ch è
invisibile (spazio, tab, a capo), “falso”
altrimenti.

Esempio if(isspace(ch))
if
{ ... }
22
iscntrl

Nome funzione iscntrl


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito Vero/falso
Descrizione Ritorna “vero” se ch è un carattere di
controllo (ASCII 0...31, 127), “falso”
altrimenti.

Esempio if(iscntrl(ch))
if
{ ... }
23
Vista d’insieme

A...F G...Z
isupper !"#$%&'(
)*+,-./:
a...f g...z ;<=>?@[\
islower
]^_`{|}~
isalpha ispunct

0...9
isdigit
isxdigit
isalnum isgraph

Spazio isprint

Caratteri di Tab
controllo Newline isspace
24
iscntrl
Funzioni di libreria
Trasformazione di caratteri

Definite in <ctype.h> toupper


Convertono tra lettere tolower
maiuscole e lettere
minuscole

26
toupper

Nome funzione toupper


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito char : carattere maiuscolo
Descrizione Se ch è una lettera minuscola, ritorna
l’equivalente carattere maiuscolo, se
no ritorna ch stesso

Esempio for(i=0;
for s[i]!=0; i++)
s[i] = toupper(s[i]) ;
27
tolower

Nome funzione tolower


Libreria #include <ctype.h>
Parametri in ch : carattere
ingresso
Valore restituito char : carattere maiuscolo
Descrizione Se ch è una lettera minuscola, ritorna
l’equivalente carattere maiuscolo, se
no ritorna ch stesso

Esempio for(i=0;
for s[i]!=0; i++)
s[i] = tolower(s[i]) ;
28
Funzioni di libreria
Copia e concatenazione

Definite in strcpy
<string.h> strncpy
Trasferiscono il strcat
contenuto di una strncat
stringa in un’altra
Sostituendolo
Accodandolo

30
strcpy

Nome funzione strcpy


Libreria #include <string.h>
Parametri in dst : stringa
ingresso src : stringa
Valore restituito nessuno utile
Descrizione Copia il contenuto della stringa src
all’interno della stringa dst (che deve
avere lunghezza sufficiente).

Esempio strcpy(s1, s2) ;


strcpy(s, "") ;
strcpy(s1, "ciao") ; 31
strncpy

Nome funzione strncpy


Libreria #include <string.h>
Parametri in dst : stringa
ingresso src : stringa
n : numero max caratteri
Valore restituito nessuno utile
Descrizione Copia il contenuto della stringa src
(massimo n caratteri) all’interno della
stringa dst.
Esempio strncpy(s1, s2, 20) ;
strncpy(s1, s2, MAX) ;
32
strcat

Nome funzione strcat


Libreria #include <string.h>
Parametri in dst : stringa
ingresso src : stringa
Valore restituito nessuno utile
Descrizione Accoda il contenuto della stringa src
alla fine della stringa dst (che deve
avere lunghezza sufficiente).

Esempio strcat(s1, s2) ;


strcat(s1, " ") ;
33
strncat

Nome funzione strncat


Libreria #include <string.h>
Parametri in dst : stringa
ingresso src : stringa
n : numero max caratteri
Valore restituito nessuno utile
Descrizione Accoda il contenuto della stringa src
(massimo n caratteri) alla fine della
stringa dst.

Esempio strncat(s1, s2) ;


34
Funzioni di libreria
Confronto di stringhe

Definite in strcmp
<string.h> strncmp
Confrontano due
stringhe sulla base
dell’ordine
lessicografico imposto
dalla tabella dei codici
ASCII

36
strcmp

Nome funzione strcmp


Libreria #include <string.h>
Parametri in s1 : stringa
ingresso s2 : stringa
Valore restituito int : risultato confronto
Descrizione Risultato <0 se s1 precede s2
Risultato ==0 se s1 è uguale a s2
Risultato >0 se s1 segue s2
Esempio if(strcmp(s,
if r)==0) {...}
while(strcmp(r,"fine")!=0)
while
{...} 37
strncmp

Nome funzione strncmp


Libreria #include <string.h>
Parametri in s1 : stringa
ingresso s2 : stringa
n : numero max caratteri
Valore restituito int : risultato confronto
Descrizione Simile a strcmp, ma confronta solo i
primi n caratteri, ignorando i
successivi.

Esempio if(strncmp(r,
if "buon", 4)==0)
(buongiorno, buonasera, buonanotte)38
Funzioni di libreria
Ricerca

Definite in strchr
<string.h> strstr
Ricercano all’interno strspn
di una stringa data strcspn
Se compare un
carattere
Se compare una
sotto-stringa
Se compare una
sequenza qualsiasi
composta di
caratteri dati
40
strchr

Nome funzione strchr


Libreria #include <string.h>
Parametri in s : stringa
ingresso ch : carattere
Valore restituito ==NULL oppure !=NULL
Descrizione Risultato !=NULL se il carattere ch
compare nella stringa.
Risultato ==NULL se non compare.

Esempio if(strchr(s,
if '.')!=NULL)...
if(strchr(s,
if ch)==NULL)...
41
strstr

Nome funzione strstr


Libreria #include <string.h>
Parametri in s : stringa
ingresso r : stringa
Valore restituito ==NULL oppure !=NULL
Descrizione Risultato !=NULL se la sotto-stringa
r compare nella stringa s.
Risultato ==NULL se non compare.

Esempio if(strstr(s,
if "xy")!=NULL)...
if(strstr(s,
if s1)==NULL)...
42
strspn

Nome funzione strspn


Libreria #include <string.h>
Parametri in s : stringa
ingresso r : stringa
Valore restituito int : lunghezza sequenza iniziale
Descrizione Calcola la lunghezza della parte
iniziale di s che è composta
esclusivamente dei caratteri presenti
in r (in qualsiasi ordine).
Esempio lun = strspn(s, " ") ;
lun = strspn(s, " :,;.") ;
43
strcspn

Nome funzione strcspn


Libreria #include <string.h>
Parametri in s : stringa
ingresso r : stringa
Valore restituito int : lunghezza sequenza iniziale
Descrizione Calcola la lunghezza della parte
iniziale di s che è composta
esclusivamente da caratteri non
presenti in r (in qualsiasi ordine).
Esempio lun = strcspn(s, " ") ;
lun = strcspn(s, " :,;.") ;
44
Funzioni di libreria
Conversioni numero-stringa

Definite in atoi
<stdlib.h> atof
Mettono in relazione
un valore numerico
(intero o reale) con la
sua rappresentazione
come caratteri
all’interno di una In futuro:
stringa sscanf
"372" ↔ 372 (int) sprintf
"3.0" ↔ 3.0 (float)
46
atoi

Nome funzione atoi


Libreria #include <stdlib.h>
Parametri in s : stringa
ingresso
Valore restituito int : valore estratto
Descrizione Analizza la stringa s ed estrae il
valore intero in essa contenuto (a
partire dai primi caratteri).

Esempio n = atoi(s) ;
n = atoi("232abc") ;
47
atof

Nome funzione atof


Libreria #include <stdlib.h>
Parametri in s : stringa
ingresso
Valore restituito double/float : valore estratto
double/
Descrizione Analizza la stringa s ed estrae il
valore reale in essa contenuto (a
partire dai primi caratteri).

Esempio x = atof(s) ;
x = atof("2.32abc") ;
48
Caratteri e stringhe
Esercizi proposti

Esercizio “Parola palindroma”


Esercizio “Iniziali maiuscole”
Esercizio “Alfabeto farfallino”

2
Esercizi proposti
Esercizio “Parola palindroma”

Sia data una parola inserita da tastiera.


Si consideri che la parola può contenere sia
caratteri maiuscoli che caratteri minuscoli, e
complessivamente al massimo 30 caratteri
Il programma deve svolgere le seguenti
operazioni:
Visualizzare la parola inserita
Aggiornare la parola in modo che tutti i caratteri
siano minuscoli, e visualizzarla
Verificare se la parola è palindroma

4
Palindromia

Una parola è detta palindroma se può essere


letta indifferentemente da sinistra verso destra e
da destra verso sinistra
Esempi:

o t t o

m a d a m

5
Analisi

Acquisisci parola
Stampa parola
Converti in minuscolo
Stampa minuscolo
Verifica se è palindroma
Stampa se è palindroma

6
Analisi

Acquisisci parola
Stampa parola
Converti in minuscolo
const int MAX = 30 ;
Stampa minuscolo
char parola[MAX+1] ;
Verifica se è printf("Inserisci
palindroma parola: ") ;
Stampa se èscanf("%s",
palindroma parola) ;

7
Analisi

Acquisisci parola
Stampa parola
Converti in minuscolo
Stampa minuscolo
printf("Parola inserita: %s\n",
Verifica se è palindroma
parola) ;
Stampa se è palindroma

8
Analisi

Acquisisci parola
Stampa parola
Converti in minuscolo
Stampa minuscolo
char minusc[MAX+1] ;
Verifica se è palindroma
int i ;
Stampa se è palindroma
strcpy(minusc, parola) ;

for(i=0;
for minusc[i]!=0; i++)
{
minusc[i] = tolower( minusc[i] ) ;
} 9
Analisi

Acquisisci parola
printf("Parola minuscola: %s\n",
Stampa parola minusc) ;
Converti in minuscolo
Stampa minuscolo
Verifica se è palindroma
Stampa se è palindroma

10
Analisi

int i, j, palin, lun ;


Acquisisci parola
Stampa parola i = 0 ;
Converti in minuscolo
j = strlen( minusc ) - 1 ;
Stampa minuscolo
palin = 1 ;
Verifica se è palindroma
Stampa se è while(
palindroma
while i<j && palin==1 )
{
if(minusc[i]
if != minusc[j])
palin = 0 ;
i++ ; j-- ;
}
11
Analisi

Acquisisci parola
Stampa if(palin==1)
if
parola
printf("E' palindroma\n") ;
Converti in minuscolo
else
Stampa minuscolo
printf("Non e' palindroma\n") ;
Verifica se è palindroma
Stampa se è palindroma

12
Soluzione

palindroma.c

13
Esercizi proposti
Esercizio “Iniziali maiuscole” (1/2)

Scrivere un programma che legga una frase


introdotta da tastiera
La frase è terminata dall’introduzione del carattere
di invio
La frase contiene sia caratteri maiuscoli che
caratteri minuscoli, e complessivamente al più 100
caratteri

15
Esercizio “Iniziali maiuscole” (2/2)

Il programma deve svolgere le seguenti


operazioni:
Visualizzare la frase inserita
Costruire una nuova frase in cui il primo carattere
di ciascuna parola nella frase di partenza è stato
reso maiuscolo. Tutti gli altri caratteri devono
essere resi minuscoli
Visualizzare la nuova frase

16
Esempio

cHe bElLA gIOrnaTa

Che Bella Giornata

17
Analisi

La frase inserita può contenere degli spazi:


occorrerà usare gets e non scanf
Ogni lettera inziale di parola va convertita in
maiuscolo
Ogni lettera non iniziale di parola va convertita in
minuscolo
Ogni altro carattere va lasciato immutato

18
Conversione delle lettere

for(i=0;
for frase[i]!=0; i++)
{ iniziali.c

if(
if isalpha(frase[i]) &&
( i==0 || !isalpha(frase[i-1]) ) )
{
frase[i] = toupper( frase[i] ) ;
}
else
{
frase[i] = tolower( frase[i] ) ;
}
}

19
Esercizi proposti
Esercizio “Alfabeto farfallino” (1/2)

Scrivere un programma che legga una frase


introdotta da tastiera
La frase è terminata dall’introduzione del carattere
di invio
La frase contiene sia caratteri maiuscoli che
caratteri minuscoli, e complessivamente al più 100
caratteri

21
Esercizio “Alfabeto farfallino” (2/2)

Il programma deve svolgere le seguenti


operazioni:
Visualizzare la frase inserita
Costruire una nuova frase nel cosiddetto “alfabeto
farfallino”
Visualizzare la nuova frase

22
L’alfabeto farfallino

La traduzione nell’alfabeto farfallino di una parola


segue le seguenti regole:
Tutte le consonanti sono tradotte in modo identico
Ogni vocale è tradotta uguale a se stessa, seguita
da altri due caratteri:
la lettera ‘f’ (se la vocale è minuscola) o la lettera ‘F’
(se la vocale è maiuscola)
una copia della vocale stessa
Esempi:
a afa
con cofon
23
Esempio

Vacanze di NATALE

Vafacafanzefe difi NAFATAFALEFE

24
Approccio risolutivo

Copiamo la stringa frase in una nuova stringa


farfa
lun=0
Per ogni carattere frase[i]
Se non è una vocale, va accodato a farfa[lun]
Se è una vocale, occorre accodare a farfa[lun]
i 3 caratteri: frase[i], poi 'f' o 'F', poi
ancora frase[i]
Incrementare lun (di 1 oppure 3)
Infine aggiungere a farfa[lun] il terminatore
nullo

25
Conversione alfabeto (1/2)

lun = 0 ;
for(i=0;
for frase[i]!=0; i++)
{ if(
if isalpha(frase[i]) ) farfallino.c
{ /* lettera alfabetica */
ch = tolower(frase[i]) ;
if(
if ch=='a' || ch=='e' || ch=='i'
|| ch=='o' || ch=='u' )
{ /* vocale: trasforma */
1 farfa[lun] = frase[i] ;

if(isupper(frase[i]))
if
2 farfa[lun+1] = 'F' ;
else farfa[lun+1] = 'f' ;
3 farfa[lun+2] = frase[i] ;

lun = lun + 3 ;
} 26
Conversione alfabeto (2/2)

else
{
/* consonante: copia */ farfallino.c

farfa[lun] = frase[i] ;
lun++ ;
}
}
else
{
/* altro carattere: copia */
farfa[lun] = frase[i] ;
lun++ ;
}
}
farfa[lun] = 0 ; /* terminatore */
27
Caratteri e stringhe
Argomenti trattati

Caratteri e stringhe
Il tipo char
Vettori di char
Stringhe: parole, frasi
Operazioni fondamentali sulle stringhe
Classificazione
Ricerca
Copia e concatenazione
Conversione

2
Tecniche di programmazione

Terminatore nullo
Librerie <string.h> e <ctype.h>
Manipolazione di stringhe come vettori di
caratteri
Manipolazione di stringhe attraverso le funzioni di
libreria
Identificazione di parole all’interno di frasi

3
Stringhe e vettori

Molte operazioni sulle stringhe sono ricondotte ad


analoghe operazioni sui vettori
Molti problemi “astratti” su vettori numerici
assumono forma più “concreta” nel caso delle
stringhe
I cicli sono solitamente governati dal controllo del
terminatore di fine stringa

4
Errore frequente

L’input/output nelle stringhe è spesso


problematico
Utilizzando la funzione scanf, in presenza di
spazi interni alla stringa rimarranno dei caratteri
“non letti”, che daranno fastidio alle successive
scanf
Quando possibile, ricorrere alla funzione gets
per la lettura di una stringa

5
Errore frequente

Le stringhe hanno lunghezza variabile; i vettori


che le contengono hanno lunghezza fissa
È possibile, con una chiamata a strcpy o
strcat, scrivere oltre la dimensione del vettore
Grave errore di programmazione, che può portare
alla corruzione di dati in altre variabili
Abituarsi a verificare la lunghezza prima di
copiare le stringhe
if(strlen(a)
if + strlen(b) + 1 <= MAX)
strcat(a,b) ;
else
ERRORE!!! 6
Materiale aggiuntivo

Sul CD-ROM
Testi e soluzioni degli esercizi trattati nei lucidi
Scheda sintetica
Esercizi risolti
Esercizi proposti
Esercizi proposti da altri libri di testo

7
Programmazione in C
Matrici – Vettori di stringhe

Matrici
Definizione di matrici in C
Operazioni elementari sulle matrici
Vettori di stringhe
Esercizi proposti
Sommario

2
Riferimenti al materiale

Testi
Kernighan & Ritchie: capitoli 1 e 5
Cabodi, Quer, Sonza Reorda: capitolo 5
Dietel & Dietel: capitolo 6
Dispense
Scheda: “Matrici e Vettori di stringhe in C”

3
Matrici – Vettori di stringhe
Matrici

Matrici bidimensionali
Matrici come vettori di vettori
Matrici pluridimensionali

5
Matrici
Il concetto di matrice

La matrice (array) è un’estensione logica del


concetto di vettore
Vettore = Sequenza uni-dimensionale di valori
Tutti dello stesso tipo
Identificati da un indice intero
Dimensione fissa
Matrice = Schiera bi- (o n-) dimensionale di valori
Tutti dello stesso tipo
Identificati da 2 (o n) indici interi
Dimensioni fisse

7
Matrice bidimensionale

colonne
0 1 2 ... M
0 1 2 3 4 5
1 2 4 6 8 10
2 3 6 9 12 15
righe
4 8 12 16 20
...

5 10 15 20 25
N 6 12 18 24 30

pitagora 8
Caratteristiche

Una matrice bi-dimensionale è caratterizzata da


Nome : pitagora
Numero di righe : N
Numero di colonne : M
Tipo degli elementi : int
Le righe sono numerate da 0 ad N-1
Le colonne sono numerate da 0 ad M-1
In totale ci sono N×M elementi
In generale M≠N; per matrici quadrate, M=N

9
Identificazione degli elementi

Elemento (1,2):
colonne riga 1, colonna 2

0 1 2 ... M
0 1 2 3 4 5
1 2 4 6 8 10
2 3 6 9 12 15
righe
4 8 12 16 20
...

5 10 15 20 25
N 6 12 18 24 30
Elemento (5,0): Elemento (4,4):
riga 5, colonna 0 riga 4, colonna 4
pitagora 10
Lavorare con le matrici

Ogni operazione su una matrice deve essere


svolta lavorando singolarmente su ciascuno degli
elementi
Ciò solitamente significa dover ricorrere a due
cicli annidati

for(i=0;
for i<N; i++) /* righe */
{
for(j=0;
for j<M; j++) /* colonne */
{
somma = somma + matrice[i][j] ;
}
} 11
Matrici
Vettori di vettori

Un altro modo di vedere le matrici è concepirle


come vettori di vettori:
Un vettore di N oggetti (righe)
Ciascun oggetto (riga) è composto da M elementi
(colonne)
Questa prende il nome di rappresentazione
“per righe” di una matrice

13
Esempio

0 1 2 3 4 5
1 2 4 6 8 10
2 3 6 9 12 15
4 8 12 16 20
...

5 10 15 20 25
N-1 6 12 18 24 30

pitagora
0 1 2 ... M-1
4 8 12 16 20 14
Codifica

Nella realtà, poiché la memoria di un calcolatore


è uni-dimensionale, le matrici vengono
effettivamente memorizzate “per righe”
1
1 2 3 4 5 2
2 4 6 8 10 3
4
3 6 9 12 15 5
4 8 12 16 20 2
5 10 15 20 25 4
6 12 18 24 30 6
8
10
3
6
9
12
15
4 15
8
12
Matrici
Matrici con più dimensioni

Il concetto di matrice può essere generalizzato


anche a più di 2 dimensioni
Non vi sono, a priori, limiti sul numero di
dimensioni

11 22 33 44 55 N×M×L elementi:
1122224433664488551010
N 2233446666998812121015
1015 elemento(i, j, k)
righe 3 4 6 8 9 12121615
3 4 6 8 9 121216152020
44558810
10
121215
15
1620
1620
2025
2025 0 ≤ i ≤ N-1
5 6 1012 1518202425
5 6 101215182024253030 0 ≤ j ≤ M-1
66 1212 1818 24
24 30
30
0 ≤ k ≤ L-1
L
M livelli
colonne 17
Caratteristiche

Anche le matrici a più dimensioni condividono i


vincoli di base dell’intera famiglia degli array:
Tipo di elementi uniforme
Dimensioni fissate a priori
Indici interi a partire da 0
In pratica è molto raro utilizzare più di 3
dimensioni

18
Matrici – Vettori di stringhe
Definizione di matrici in C

Sintassi della definizione


Operazioni di accesso

2
Definizione di matrici in C
Definizione di matrici in C

int mat[10][5] ;

Tipo di Nome della Numero Numero


dato base matrice di righe di colonne

4
Definizione di matrici in C

int mat[10][5] ;

Tipo di Nome della Numero Numero


dato base matrice di righe di colonne

•• int
int
•• float
float
•• char
char
•• In
In futuro vedremo: struct
futuro vedremo: struct
5
Definizione di matrici in C

int mat[10][5] ;

Tipo di Nome della Numero Numero


dato base matrice di righe di colonne

•• Stesse
Stesse regole
regole che
che valgono
valgono per
per ii
nomi
nomi di
di variabili
variabili ee vettori
vettori
•• II nomi
nomi delle
delle matrici
matrici devono
devono essere
essere
diversi
diversi dai
dai nomi
nomi di di altre
altre variabili
variabili oo
vettori
vettori 6
Definizione di matrici in C

int mat[10][5] ;

Tipo di Nome della Numero Numero


dato base matrice di righe di colonne

•• Interi
Interi positivi
positivi
•• Costanti
Costanti note
note aa tempo
tempo di
di
compilazione
compilazione
•const oppure #define
•const oppure #define
•• Uguali
Uguali oo diverse
diverse 7
Esempi

int pitagora[10][10] ;

0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9 10
1 2 4 6 8 10 12 14 16 18 20
2 3 6 9 12 15 18 21 24 27 30
3 4 8 12 16 20 24 28 32 36 40
4 5 10 15 20 25 30 35 40 45 50
5 6 12 18 24 30 36 42 48 54 60
6 7 14 21 28 35 42 49 56 63 70
7 8 16 24 32 40 48 56 64 72 80
8 9 18 27 36 45 54 63 72 81 90
9 10 20 30 40 50 60 70 80 90 100
8
Esempi

int pitagora[10][10] ;
char tris[3][3] ;

0 1 2
0 . . .
0 1 2
1 . . .
2 . . . 0 . . .
1 . X . 0 1 2
2 . . . 0 O . .
1 . X . 0 1 2
2 . . . 0 O X .
1 . X .
2 . . .

9
Esempi

int pitagora[10][10] ;
char tris[3][3] ;
float rot[2][2] ; 0 1
0 cos β sin β
0 1 1 -sin β cos β
0 0.707 0.707
1 -0.707 0.707 0 1
0 0.500 0.866
1 -0.866 0.500
0 1
0 0.000 1.000
1 -1.000 0.000

10
Matrici a più dimensioni

int mat[10][5] ;

Più Numero di elementi per


dimensioni ciascuna dimensione

float dati[10][5][6] ;

11
Errore frequente

Dichiarare una matrice usando variabili anziché


costanti per le dimensioni

int mat[10][10] ;

int N = 10 ;
int mat[N][N] ;

const int N = 10 ;
int mat[N][N] ;
12
Errore frequente

Dichiarare una matrice usando il nome degli indici

int i, j ;
int mat[i][j] ;

. . .
for(i=0; i<10; i++)
for(j=0; j<10; j++)
scanf("%d",&mat[i][j]) ;

const int N = 10 ;
int mat[N][N] ; 13
Errore frequente

Dichiarare una matrice usando il simbolo di


“virgola”

const int N = 10 ;
const int M = 20 ;

int mat[N,M] ;

int mat[N][M] ;

14
Definizione di matrici in C
Accesso ai valori di una matrice

Ciascun elemento di una matrice è una variabile


del tipo base
Per accedere a tale elemento si usa l’operatore di
indicizzazione: [ ]
Vi sono tanti indici quante sono le dimensioni
della matrice
Ogni indice è racchiuso da una coppia di parentesi
quadre

16
Sintassi

nomematrice[
[ valoreindice1 ][ valoreindice2 ]

Costante, variabile o
espressione aritmetica
con valore intero

17
Sintassi

nomematrice[
[ valoreindice1 ][ valoreindice2 ]

Valore intero compreso


tra 0 e numero di righe -1

Costante, variabile o
espressione aritmetica Valore intero compreso
con valore intero tra 0 e numero di
colonne -1

18
Esempi
pitagora[1][2]

0 1 2 3 4
0 1 2 3 4 5
1 2 4 6 8 10
2 3 6 9 12 15
3 4 8 12 16 20
4 5 10 15 20 25
5 6 12 18 24 30

pitagora[5][0] pitagora[4][4]

int pitagora[6][5] ; 19
Vincoli (1/2)

In una matrice NxMxKx..., il valore dell’indice


deve essere compreso tra 0 e N-1/M-1/K-1/....
La responsabilità è del programmatore
Se qualche indice non è un numero intero, viene
automaticamente troncato

pitagora[i][j] = (i+1)*(j+1) ;

x = pitagora[1][2] ;

20
Vincoli (2/2)

Una variabile di tipo matrice può essere utilizzata


solamente mediante l’operatore di indicizzazione
Occorre agire individualmente sui singoli elementi
Non è possibile agire sull’intera matrice in una sola
istruzione

pitagora[i][j] = (i+1)*(j+1) ;

x = pitagora[1][2] ;

21
Uso di una cella di un vettore

L’elemento di una matrice è utilizzabile come una


qualsiasi variabile:
Utilizzabile all’interno di un’espressione
tot = tot + mat[i][j] ;
Utilizzabile in istruzioni di assegnazione
mat[0][0] = 0 ;
Utilizzabile per stampare il valore
printf("%d\n", mat[z][k]) ;
Utilizzabile per leggere un valore
scanf("%d\n", &mat[k][z]) ;

22
Matrici – Vettori di stringhe
Operazioni elementari sulle matrici

Definizioni
Stampa di una matrice
Lettura di una matrice
Copia di una matrice
Somme di riga o di colonna
Ricerca di un elemento
Ricerca del massimo o del minimo

2
Operazioni elementari sulle matrici
Definizioni (1/2)

matrici.c
const int N = 10 ;
const int M = 5 ; /* dimensioni massime */

float mat[N][M] ; /* matrice 10x5 di reali */


float mat2[N][M] ; /* uguali dimensioni */

float sr[N] ; /* somma per righe */


float sc[M] ; /* somma per colonne */

int i, j ; /* indici dei cicli */

4
Definizioni (2/2)

matrici.c

int trovato ; /* flag */


int riga, col ; /* risultati ricerca */

float dato ; /* elemento da ricercare */

float somma, sommar, sommac ;


/* per calcolo di somme */

float maxr, maxc ; /* massimi */

5
Operazioni elementari sulle matrici
Stampa di matrici

Occorre stampare un elemento per volta,


all’interno di cicli for
Sono necessari due cicli annidati
Il ciclo esterno per scandire le righe (da 0 a N-1)
Il ciclo interno per scandire ciascuna colonna (da 0
a M-1) della riga data
Si può stampare “per righe” (caso normale) o
“per colonne” (trasposta)

7
Stampa per righe matrice di reali

matrici.c
printf("Matrice: %d x %d\n", N, M);

for(i=0;
for i<N; i++)
{
for(j=0;
for j<M; j++)
{
printf("%f ", i-esima
Stampa la riga mat[i][j]) ;
}
printf("\n");
}

8
Stampa per righe matrice di reali

matrici.c
printf("Matrice: %d x %d\n", N, M);

for(i=0;
for i<N; i++) /* Stampa la riga i-esima */
{
for(j=0;
for j<M; j++)
{
printf("%f ", mat[i][j]) ;
}
printf("\n");
}

9
Esempio

Matrice: 10 righe, 5 colonne


1.000000 0.500000 0.333333 0.250000 0.200000
2.000000 1.000000 0.666667 0.500000 0.400000
3.000000 1.500000 1.000000 0.750000 0.600000
4.000000 2.000000 1.333333 1.000000 0.800000
5.000000 2.500000 1.666667 1.250000 1.000000
6.000000 3.000000 2.000000 1.500000 1.200000
7.000000 3.500000 2.333333 1.750000 1.400000
8.000000 4.000000 2.666667 2.000000 1.600000
9.000000 4.500000 3.000000 2.250000 1.800000
10.000000 5.000000 3.333333 2.500000 2.000000

10
Stampa per colonne matrice di reali

matrici.c
printf("Matrice: %d x %d\n", N, M);

for(j=0;
for j<M; j++)
{
for(i=0;
for i<N; i++)
{
printf("%f ", mat[i][j]) ;
}
printf("\n");
}

11
Esempio

Matrice: 10 righe, 5 colonne


1.00 2.00 3.00 4.00 5.00 6.00 7.00 8.00 9.00 10.00
0.50 1.00 1.50 2.00 2.50 3.00 3.50 4.00 4.50 5.00
0.33 0.67 1.00 1.33 1.67 2.00 2.33 2.67 3.00 3.33
0.25 0.50 0.75 1.00 1.25 1.50 1.75 2.00 2.25 2.50
0.20 0.40 0.60 0.80 1.00 1.20 1.40 1.60 1.80 2.00

12
Operazioni elementari sulle matrici
Lettura di matrici

Occorre leggere un elemento per volta


Si procede per righe (o per colonne)
Si utilizzano solitamente due cicli annidati

14
Lettura per righe matrice di reali

printf("Immetti matrice %d x %d\n",


N, M) ; matrici.c

for(i=0;
for i<N; i++)
{
printf("Riga %d:\n", i+1) ;
for(j=0;
for j<M; j++)
{
printf("Elemento (%d,%d): ",
i+1, j+1) ;
scanf("%f", &mat[i][j]) ;
}
}
15
Esempio

Immetti una matrice 10 x 5


Riga 1:
Elemento (1,1): 3.2
Elemento (1,2): 1
Elemento (1,3): -12.4
Elemento (1,4): 2.112
Elemento (1,5): 23
Riga 2:
Elemento (2,1): 23.1
Elemento (2,2): 2.11
Elemento (2,3): .22
Elemento (2,4): 3.14
Elemento (2,5): 2.71

16
Operazioni elementari sulle matrici
Copia di matrici (1/2)

L’operazione di copia di una matrice “sorgente” in


una “destinazione” richiede che ciascun elemento
venga copiato individualmente
La matrice destinazione deve avere dimensioni
uguali o superiori a quelle della sorgente
L’operazione di copia avviene ovviamente a livello
del singolo elemento

18
Copia di matrici (2/2)

matrici.c

for(i=0;
for i<N; i++)

for(j=0;
for j<M; j++)

mat2[i][j] = mat[i][j] ;

19
Operazioni elementari sulle matrici
Sommatorie in matrici

Il calcolo di totali sui dati contenuti in una


matrice può corrispondere a tre diverse
operazioni:
Somma degli elementi di ciascuna riga (totali di
riga)
Somma degli elementi di ciascuna colonna (totali
di colonna)
Somma di tutti gli elementi della matrice

21
Esempio
float mat[N][M] ;
1.00 0.50 0.33 0.25 0.20
2.00 1.00 0.67 0.50 0.40
3.00 1.50 1.00 0.75 0.60
4.00 2.00 1.33 1.00 0.80
5.00 2.50 1.67 1.25 1.00
6.00 3.00 2.00 1.50 1.20
7.00 3.50 2.33 1.75 1.40
8.00 4.00 2.67 2.00 1.60
9.00 4.50 3.00 2.25 1.80
10.00 5.00 3.33 2.50 2.00

22
Esempio
float mat[N][M] ; float sr[N] ;
1.00 0.50 0.33 0.25 0.20 2.28
2.00 1.00 0.67 0.50 0.40 4.56
3.00 1.50 1.00 0.75 0.60 6.85
4.00 2.00 1.33 1.00 0.80 9.13
5.00 2.50 1.67 1.25 1.00 11.41
6.00 3.00 2.00 1.50 1.20 13.70
7.00 3.50 2.33 1.75 1.40 15.98
8.00 4.00 2.67 2.00 1.60 18.26
9.00 4.50 3.00 2.25 1.80 20.55
10.00 5.00 3.33 2.50 2.00 22.83

55.00 27.50 18.33 13.75 11.00 float sc[M] 23;


Somma per righe

for(i=0
for ; i<N ; i++) matrici.c

{
somma = 0.0 ;
for(j=0;
for j<M; j++)
somma = somma + mat[i][j] ;
sr[i] = somma ;
}

for(i=0;
for i<N; i++)
printf("Somma riga %d = %f\n",
i+1, sr[i]) ;

24
Somma per colonne

for(j=0
for ; j<M ; j++) matrici.c

{
somma = 0.0 ;
for(i=0;
for i<N; i++)
somma = somma + mat[i][j] ;
sc[j] = somma ;
}

for(j=0;
for j<M; j++)
printf("Somma colonna %d = %f\n",
j+1, sc[j]) ;

25
Somma complessiva

matrici.c

somma = 0.0 ;
for(i=0
for ; i<N ; i++)
{
for(j=0;
for j<M; j++)
somma = somma + mat[i][j] ;
}

printf("Somma complessiva = %f\n",


somma) ;

26
Operazioni elementari sulle matrici
Ricerca di elementi

Dato un valore dato, ricercare se esso esiste


(almeno una volta) nella matrice
In caso affermativo, specificare la riga e la
colonna
Si utilizzano i soliti due cicli annidati

28
Ricerca elemento (1/2)

printf("Dato da ricercare: ");


scanf("%f", &dato) ;
matrici.c

trovato = 0 ;
riga = -1 ;
col = -1 ;

for(i=0;
for i<N && trovato==0; i++)
for(j=0;
for j<M && trovato==0; j++)
if(
if mat[i][j]==dato )
{
trovato=1 ;
riga = i ;
col = j ;
}
29
Ricerca elemento (2/2)

matrici.c

if(trovato==1)
if
printf("Dato %f presente: (%d,%d)\n",
dato, riga, col) ;
else
printf("Dato %f non presente\n",
dato) ;

30
Operazioni elementari sulle matrici
Massimi e minimi

Per quanto riguarda il calcolo di massimi e minimi


si possono distinguere i 3 scenari:
Massimo/minimo degli elementi di ciascuna riga
Massimo/minimo degli elementi di ciascuna
colonna
Massimo/minimo tra tutti gli elementi della matrice

32
Massimo per righe

for(i=0;
for i<N; i++)
{
col = 0 ; matrici.c

maxr = mat[i][0] ;
for(j=1;
for j<M; j++)
if(
if mat[i][j] > maxr )
{
maxr = mat[i][j] ;
col = j ;
}

printf("Max di riga %d vale %f


e si trova nella colonna %d\n",
i+1, maxr, col+1) ;
}
33
Massimo per colonne

for(j=0;
for j<M; j++)
{
riga = 0 ; matrici.c

maxc = mat[0][j] ;
for(i=1;
for i<N; i++)
if(
if mat[i][j] > maxc )
{
maxc = mat[i][j] ;
riga = i ;
}

printf("Max di colonna %d vale %f


e si trova nella riga %d\n",
j+1, maxc, riga+1) ;
}
34
Osservazioni

Le operazioni qui citate sono gli elementi


fondamentali dell’elaborazione di matrici
Nei problemi concreti si osserveranno delle
combinazioni di tali operazioni
Occorre analizzare il problema, scomporlo nei
suoi sottoproblemi e combinare opportunamente
le varie tecniche

35
Esercizio “Max Sum Abs”

Data una matrice NxN, determinare la riga in cui


la somma dei valori assoluti degli elementi sia
massima

r = maxi ( ∑ j M ij )

36
Soluzione 1

Inizializza max
Per ogni riga i:
Calcola la somma sommar dei valori assoluti di tale
riga
Confronta sommar con il max corrente, ed
eventualmente aggiorna il max
Stampa max

37
Soluzione 1

max = -1.0 ;

for(i=0;
for i<N; i++) maxsumabs1.c

{
sommar = 0.0 ;
for(j=0;
for j<M; j++)
{
sommar = sommar +
fabs(mat[i][j]) ;
}

if(sommar>max)
max = sommar ;
}
printf("R = %f\n", max) ;
38
Soluzione 2

Calcola un vettore di appoggio, di N elementi,


contenente le sommatorie per ogni riga
Trova il max all’interno di questo vettore di
appoggio

Soluzione più lunga dal punto di vista del codice,


ma più semplice da concepire e realizzare

39
Soluzione 2 (1/2)

maxsumabs2.c
for(i=0;
for i<N; i++)
{
sommar = 0.0 ;
for(j=0;
for j<M; j++)
{
sommar = sommar +
fabs(mat[i][j]) ;
}
sr[i] = sommar ;
}

40
Soluzione 2 (2/2)

maxsumabs2.c

max = -1.0 ;

for(i=0;
for i<N; i++)
if(sr[i]>max)
if
max = sr[i] ;

printf("R = %f\n", max) ;

41
Matrici – Vettori di stringhe
Vettori di stringhe

Matrici di caratteri
Vettori di stringhe
I/O di vettori di stringhe

2
Vettori di stringhe
Matrici di caratteri

Nel definire una matrice, è ovviamente possibile


usare il tipo base char
Permette di memorizzare una tabella NxM di
caratteri ASCII
Ogni posizione [i][j] deve contenere un
carattere
Non può essere vuota
Non può contenere più di un carattere
0 1 2
0 O X .
char tris[3][3] ; 1 . X .
2 . . . 4
Esercizio “Verifica Sudoku”

Si realizzi un programma in C che verifichi la


corretta soluzione della griglia di un “Sudoku”
Il programma acquisisce da tastiera la griglia 9x9,
in cui ciascun elemento è un carattere tra 1 e 9
Il programma deve verificare se il Sudoku è stato
correttamente risolto

5
Esempio

5 3 4 6 7 8 9 1 2
6 7 2 1 9 5 3 4 8
1 9 8 3 4 2 5 6 7
8 5 9 7 6 1 4 2 3
4 2 6 8 5 3 7 9 1
7 1 3 9 2 4 8 5 6
9 6 1 5 3 7 2 8 4
2 8 7 4 1 9 6 3 5
3 4 5 2 8 6 1 7 9
6
Analisi

Tutti i valori devono essere singoli caratteri tra ‘1’


e ‘9’
Su ciascuna delle 9 righe, non devono esserci
valori ripetuti
Su ciascuna delle 9 colonne, non devono esserci
valori ripetuti
In ciascuno dei 9 blocchi 3x3, non devono esserci
valori ripetuti

7
Soluzione (1/10)

const int N = 9 ; sudoku.c

char sudoku[N][N] ;

int i, j, k ; /* indici dei cicli */


int r1, c1, r2, c2 ;
char ch ;
int err, good ; /* flag */

printf("Verifica Sudoku\n") ;

8
Soluzione (2/10)

for(i=0;
for i<N; i++)
sudoku.c
{
printf("Riga %d:\n", i+1) ;
for(j=0;
for j<N; j++)
{
Acquisisci un carattere
ch tra ‘1’ e ‘9’

sudoku[i][j] = ch ;
}
}

9
Soluzione (2/10)

for(i=0;
for i<N; i++)
do {{ sudoku.c

printf(" Colonna%d:\n",
printf("Riga %d: ", i+1)j+1) ;;
ch =for(j=0;
getchar()
for ; j++)
j<N;
if(
if {ch<'1' || ch>'9' )
printf("Errata - ripeti\n") ;
Acquisisci un carattere
/* elimina fino ch tra ‘1’linea
fine e ‘9’ */
while(
while getchar()!='\n')
sudoku[i][j] = ch ;
/*nop*/ ;
}
}
} while(
while ch<'1' || ch>'9') ;
10
Soluzione (3/10)

/* Stampa il tabellone */
for(i=0;
for i<9; i++)
{ sudoku.c

for(j=0;
for j<9; j++)
{
printf("%c ", sudoku[i][j]) ;

if(j==2
if || j==5)
printf(" ") ;
}
printf("\n");

if(i==2
if || i==5)
printf("\n") ;
}
11
Soluzione (4/10)

good = 1 ; /* flag generale */


sudoku.c
/* Verifica le righe */
for(i=0;
for i<N; i++)
{
printf("Riga %d: ", i+1) ;
err = 0 ;

/* ricerca duplicati su col. j,k */


for(j=0;
for j<N; j++)
for(k=j+1;
for k<N; k++)
if(sudoku[i][j]==
if
sudoku[i][k])
err = 1 ;
12
Soluzione (5/10)

sudoku.c

if(err==0)
if
printf("OK\n");
else
{
printf("Errore!\n");
good = 0 ;
}
}

13
Soluzione (6/10)

for(i=0;
for i<N; i++) /* Colonne */
{ printf("Colonna %d: ", i+1) ;
err = 0 ; sudoku.c

/* ricerca dupl. su righe j,k */


for(j=0;
for j<N; j++)
for(k=j+1;
for k<N; k++)
if(sudoku[j][i]==sudoku[k][i])
if
err = 1 ;

if(err==0)
if printf("OK\n");
else
{ printf("Errore!\n");
good = 0 ;
}
}
14
Ricerca per blocchi

5 3 4 6 7 8 9 1 2
6 7 2 1 9 5 3 4 8
1 9 8 3 4 2 5 6 7
8 5 9 7 6 1 4 2 3
4 2 6 8 5 3 7 9 1
7 1 3 9 2 4 8 5 6
9 6 1 5 3 7 2 8 4
2 8 7 4 1 9 6 3 5
3 4 5 2 8 6 1 7 9
15
Ricerca per blocchi
j j+2

5 3 4 6 7 8 9 1 2
6 7 2 1 9 5 3 4 8
1 9 8 3 4 2 5 6 7
i 8 5 9 7 6 1 4 2 3
4 2 6 8 5 3 7 9 1
i+2 7 1 3 9 2 4 8 5 6
9 6 1 5 3 7 2 8 4
2 8 7 4 1 9 6 3 5
3 4 5 2 8 6 1 7 9
16
Ricerca per blocchi
j j+2

5 3 4 6 7 8 9 1 2
6 7 2 1 9 5 3 4 8
r1,c1
1 9 8 3 4 2 5 6 7
i 8 5 9 7 6 1 4 2 3
4 2 6 8 5 3 7 9 1
i+2 7 1 3 9 2 4 8 5 6
9 6 1 5 3 7 2 8 4
2 8 7 4 1 9 6 3 5 r2,c2
3 4 5 2 8 6 1 7 9
17
Soluzione (7/10)

for(i=0;
for i<N; i=i+3)
sudoku.c
{
for(j=0;
for j<N; j=j+3)
{
printf("Blocco (%d,%d)-(%d,%d): ",
i+1, j+1, i+3, j+3) ;

/* ricerca duplicati nel blocco */


/* Confronta [r1][c1]
con [r2][c2] */

err = 0 ;

18
Soluzione (8/10)

for(r1=i;
for r1<i+3; r1++)
for(c1=j;
for c1<j+3; c1++)
{ /* elemento [r1][c1]... */ sudoku.c

for(r2=i;
for r2<i+3; r2++)
for(c2=j;
for c2<j+3; c2++)
{
/* ..rispetto a [r2][c2] */
if(
if ((r1!=r2)||(c1!=c2)) &&
sudoku[r1][c1]==
sudoku[r2][c2] )
{
err = 1 ;
}
} /*r2,c2*/
} /*r1,c1*/
19
Soluzione (9/10)

sudoku.c

if(err==0)
if
printf("OK\n");
else
{
printf("Errore!\n");
good = 0 ;
}
} /*j*/
} /*i*/

20
Soluzione (10/10)

sudoku.c

if(good==1)
if
printf("Sudoku valido!\n");
else
printf("Sudoku errato...\n");

21
Vettori di stringhe
Vettori di stringhe

Una matrice di caratteri può anche essere vista


come:
Un vettore di vettori di caratteri, cioè
Un vettore di stringhe
Si tratta di un metodo diverso di interpretare la
stessa struttura dati

23
Esempio
0 1 2
0 O X .
char tris[3][3] ; 1 . X .
2 . . .

char nomi[5][10] ;
0 1 2 3 4 5 6 7 8 9
0 F u l v i o \0 x ! w
1 A n t o n i o \0 . Z
2 C r i s t i n a \0 u
3 E l e n a \0 5 g r d
4 D a v i d e \0 $ 2 e 24
Caratteristiche

5 stringhe di Lunghezza
lunghezza max 9
variabile caratteri Terminatore
nullo in ogni
stringa (riga)
char nomi[5][10] ;
0 1 2 3 4 5 6 7 8 9
0 F u l v i o \0 x ! w
1 A n t o n i o \0 . Z
2 C r i s t i n a \0 u
3 E l e n a \0 5 g r d
4 D a v i d e \0 $ 2 e 25
Sintassi

Definizione

char vett[MAX][LUN] ;

Nome del vettore Numero di


di stringhe stringhe

Lunghezzza massima di ciascuna


stringa (compreso terminatore nullo)
26
Sintassi

Definizione

char vett[MAX][LUN] ;
Accesso al singolo carattere
vett[i][j]

Carattere (j+1)-esimo della stringa


(i+1)-esima, da usarsi per
l’elaborazione carattere-per-carattere
27
Sintassi

Definizione

char vett[MAX][LUN] ;
Accesso alStringa
singolo carattere
(i+1)-esima, da usarsi con le
funzioni di libreria
vett[i][j]

Accesso all’intera stringa

vett[i]

28
Esempio 1

Dato un vettore di stringhe, determinare quante


volte è presente la lettera ‘A’ (maiuscola o
minuscola)

cont = 0 ;
for(i=0;
for i<MAX; i++)
{
for(j=0;
for vett[i][j]!=0; j++)
{
if(toupper(vett[i][j])=='A')
if
cont++ ;
}
}
29
Esempio 2

Dato un vettore di stringhe, determinare se


esistono due stringhe identiche

uguali = 0 ;
for(i=0;
for i<MAX; i++)
{
for(k=i+1;
for k<MAX; k++)
{
if(strcmp(vett[i],
if vett[k])==0)
uguali=1 ;
}
}
30
Occupazione variabile

In un vettore di stringhe, ogni riga (ogni stringa)


è intrinsecamente un vettore di caratteri ad
occupazione variabile
Terminatore nullo per indicare la lunghezza
effettiva
Il numero di stringhe effettivamente memorizzato
potrebbe non riempire l’intero vettore
Variabile intera che indica l’effettiva occupazione
del vettore

31
Esempio

const int MAX = 5 ;


const int LUN = 9 ;

char nomi[MAX][LUN+1] ;
int N ;

0 1 2 3 4 5 6 7 8 9
0 F u l v i o \0 x ! w
1 A n t o n i o \0 . Z
2 C r i s t i n a \0 u
N=3 3 e 4 1 ) a \0 5 g r d
4 1 % < d d e g $ 2 e
32
Errore frequente

Confondere una stringa (vettore di caratteri) con


un vettore di stringhe (matrice di caratteri)

char s[LUN+1] ; char v[MAX][LUN+1] ;

• v[i][j] è il singolo
• s[i] è un singolo
carattere
carattere
• v[i] è un’intera stringa
• s è l’intera stringa
• v è l’intera matrice
33
Vettori di stringhe
Stampa (1/2)

La stampa del contenuto di un vettore di stringhe


si ottiene semplicemente stampando ciascuno
degli elementi
Si può utilizzare puts oppure printf

35
Stampa (2/2)

vettstr.c

for(i=0;
for i<N; i++)
{
puts(vett[i]) ;
}

36
Lettura

Acquisire da tastiera un vettore di stringhe


Un ciclo per ciascuna delle stringhe da leggere
Lunghezza nota a priori
Lunghezza determinata dalla lettura di un certo
dato (es.: “FINE”)
Acquisizione, nel ciclo, di ciascuna delle stringhe
Utilizzo della funzione gets
Eventualmente, lettura in una stringa d’appoggio
per la verifica di correttezza, prima di ricopiare nel
vettore destinazione

37
Dimensione nota a priori (1/2)

char vett[MAX][LUN+1] ;
vettstr.c
char s[250] ;
. . .

do {
printf("Quante stringhe? ") ;
gets(s) ;
N = atoi(s) ;
if(N<1
if || N>MAX)
printf("Valore errato: deve
essere tra 1 e %d\n", MAX) ;
} while(N<1
while || N>MAX) ;

38
Dimensione nota a priori (2/2)

for(i=0;
for i<N; i++)
{ printf("Stringa %d: ", i+1) ;
gets(s) ; vettstr.c

if (strlen(s)==0)
{ printf("Vuota - ripeti\n");
i-- ;
}
else if(strlen(s)>LUN)
if
{ printf("Troppo lunga –
max %d chr\n", LUN) ;
i-- ;
}
else
strcpy(vett[i], s) ;
}
39
Lettura terminata da “FINE”
N = 0 ;
end = 0 ;
do { vettstr.c
printf("Stringa %d: ", N+1) ;
gets(s) ;
if (strlen(s)==0)
printf("Vuota - ripeti\n");
else if(strlen(s)>LUN)
if
printf("Troppo lunga\n") ;
else if(strcmp(s,
if "FINE")==0)
end = 1 ;
else
{ strcpy(vett[N], s) ;
N++ ;
}
} while(end==0)
while ; 40
Matrici – Vettori di stringhe
Esercizi proposti

Esercizio “Statistiche testo”


Esercizio “Magazzino”

2
Esercizi proposti
Esercizio “Statistiche testo”

Un utente inserisce una serie di frasi da tastiera,


su più righe
L’inserimento termina quando l’utente inserisce la
parola FINE su una riga da sola
Il programma deve determinare:
1) Quante righe sono state inserite dall’utente
2) Quanti caratteri sono stati inseriti
3) Quanti caratteri alfanumerici sono stati inseriti
4) Quante parole sono state inserite

4
Analisi

Testo: Nel mezzo del cammin di nostra vita


Testo: mi ritrovai per una selva oscura
Testo: che la diritta via era smarrita.
Testo: FINE
L'utente ha inserito 3 righe
L'utente ha inserito 99 caratteri
L'utente ha inserito 82 caratteri alfanumerici
L'utente ha inserito 19 parole

5
Soluzione (1/5)

statistichetesto.c

const int MAXRIGHE = 2000 ;


const int LUN = 80 ;

char testo[MAXRIGHE][LUN] ;
int Nrighe ; /* righe inserite */
char riga[LUN*10] ;
int i, j ;
int caratteri, caralfa, parole ;

6
Soluzione (2/5)

Nrighe = 0 ;
do { statistichetesto.c

printf("Testo: ");
gets(riga) ;

if(
if strcmp(riga, "FINE")!=0 )
{
/*copia riga in testo[Nrighe] ;*/
strcpy( testo[Nrighe] , riga ) ;

Nrighe++ ;
}
} while(
while strcmp(riga, "FINE")!=0 ) ;
7
Soluzione (3/5)

statistichetesto.c
printf("L'utente ha inserito"
" %d righe\n", Nrighe);

caratteri = 0 ;
for(i=0;
for i<Nrighe; i++)
caratteri = caratteri +
strlen(testo[i]) ;

printf("L'utente ha inserito"
" %d caratteri\n", caratteri) ;

8
Soluzione (4/5)

caralfa = 0 ;
for(i=0;
for i<Nrighe; i++) statistichetesto.c

{
for(j=0;
for testo[i][j]!=0; j++)
{
if(
if isalnum(testo[i][j] ) )
caralfa++ ;
}
}

printf("L'utente ha inserito "


"%d caratteri alfanumerici\n",
caralfa) ;
9
Soluzione (5/5)

parole = 0 ;
for(j=0;
for j<Nrighe; j++)
{ statistichetesto.c

for(i=0;
for testo[j][i]!=0; i++)
{
if(
if isalpha(testo[j][i]) &&
(i==0 || !isalpha(testo[j][i-1])))
{
parole ++ ;
}
}
}

printf("L'utente ha inserito "


"%d parole\n", parole) ;
10
Esercizi proposti
Esercizio “Magazzino” (1/2)

Un’azienda deve tenere traccia dei beni presenti


in un magazzino
L’utente inserisce da tastiera dei “comandi” nel
seguente formato:
bene EU quantità
dove:
bene è il nome di un bene
EU è la lettera 'E' per entrata, 'U' per uscita
quantità è la quantità di bene entrata o uscita

12
Esercizio “Magazzino” (2/2)

L’utente termina il caricamento inserendo un


comando pari a "FINE". In tal caso il
programma deve stampare le quantità di beni
presenti a magazzino

13
Analisi

Comando: viti E 10
Comando: dadi E 50
Comando: viti U 5
Comando: viti E 3
Comando: FINE
viti 8
dadi 50

14
Problemi

Estrazione dei 3 parametri dal comando immesso


dall’utente
Nome prodotto: stringa viti E 10
Direzione: carattere
Quantità: intero
Memorizzazione di nomi di prodotti e quantità
relative
Vettori paralleli
Aggiornamento delle giacenze

15
Stringa di comando

comando viti E 10

prod viti dir E qta 10

Da inizio stringa Ultimi caratteri


Singolo
fino al primo della stringa, da
carattere
spazio convertire in int

Spazio Spazio

16
Analisi del comando (1/2)

i = 0 ;
magazzino.c
while(comando[i]!='
while ')
{
prod[i] = comando[i] ;
i++ ;
}
prod[i] = 0 ;

/* salta lo spazio */
i++ ;

dir = comando[i] ; /* 'E' o 'U' */

17
Analisi del comando (2/2)

/* salta lo spazio */
i++ ; magazzino.c

/* da qui a fine: la quantità */


j = 0 ;
while(comando[i]!=0)
while
{
temp[j] = comando[i] ;
i++ ;
j++ ;
}
temp[j] = 0 ;
qta = atoi(temp) ;
18
Osservazione

L’analisi di una stringa di comando composta da


più campi è sempre un’operazione complessa
Nel caso in cui si dovessero gestire delle
condizioni anomale (es. più spazi consecutivi) o
di errore (es. manca la quantità), il codice
diverrebbe estremamente articolato
Vedremo più avanti la funzione sscanf che può
aiutare in questi casi

19
Rappresentazione del magazzino

Occorre memorizzare, per ciascun prodotto


Il nome
La quantità corrente
Si possono usare due vettori “paralleli”

char prodotti[MAX][LUN+1] ;
int quantita[MAX] ;

int N ; /* occupazione effettiva


vettori prodotti e quantita */

20
Inserimento di un prodotto

Determinare se il prodotto è già in magazzino


Ricerca del nome del prodotto nel vettore
prodotto
Se c’è già, incrementa la quantità
Se non c’è ancora, aggiungi una riga ai vettori

21
Inserimento di un prodotto

/* trova la posizione del prodotto */


trovato = -1 ;
for(i=0;
for i<N; i++) magazzino.c

if(strcmp(prodotti[i],
if prod)==0)
trovato = i ;

if(
if trovato != -1 ) /* esiste già */
quantita[trovato] =
quantita[trovato] + qta ;

else /* prodotto nuovo */


{ strcpy(prodotti[N], prod) ;
quantita[N] = qta ;
N++ ;
}
22
Eliminazione di un prodotto

Determinare se il prodotto è già in magazzino


Ricerca del nome del prodotto nel vettore
prodotto
Se c’è già, decrementa la quantità
Se non c’è ancora, errore

23
Eliminazione di un prodotto

/* trova la posizione del prodotto */


magazzino.c
trovato = -1 ;
for(i=0;
for i<N; i++)
if(strcmp(prodotti[i],
if prod)==0)
trovato = i ;

if(
if trovato == -1 )
printf("Prodotto %s non "
"trovato in magazzino\n", prod);
else
quantita[trovato] =
quantita[trovato] - qta ;

24
Matrici – Vettori di stringhe
Argomenti trattati

Matrici bi-dimensionali e pluri-dimensionali


Matrici di numeri interi e reali
Definizione
Operazioni frequenti
Matrici di caratteri
Vettori di stringhe
Caso particolare di matrici di caratteri
Operazioni frequenti

2
Tecniche di programmazione

Usare matrici per memorizzare schiere di dati


numerici
Usare vettori di stringhe per memorizzare
stringhe di testo di lunghezza variabile
Compiere operazioni di ricerca nei vettori di
stringhe

3
Materiale aggiuntivo

Sul CD-ROM
Testi e soluzioni degli esercizi trattati nei lucidi
Scheda sintetica
Esercizi risolti
Esercizi proposti
Esercizi proposti da altri libri di testo

4
Programmazione in C
Funzioni

Tipi di dato
Funzioni in C
Modifica dei parametri
Parametri “by reference”
La funzione main()
Esercizi proposti
Sommario

2
Riferimenti al materiale

Testi
Kernighan & Ritchie: capitoli 2 e 4
Cabodi, Quer, Sonza Reorda: capitoli 3 e 7
Dietel & Dietel: capitolo 5
Dispense
Scheda: “Tipi di dato in C”
Scheda: “Funzioni in C”

3
Funzioni
Tipi di dato

I tipi scalari in C
Input/output dei tipi scalari
Conversioni di tipo

5
Tipi di dato
Il sistema dei tipi C

Tipo di dato

Tipi Scalari Tipi Strutturati void

Tipi interi Tipi reali Enumerazioni Vettori

char float Strutture

int double Union

short / long long Puntatori

signed/unsigned Funzioni

7
I tipi interi in C

Tipo Descrizione Esempi


char Caratteri ASCII 'a' '7' '!'
int Interi… +2 -18 0
+24221
short int … con meno bit
long int … con più bit
unsigned int Interi senza 0 1 423
segno… 23234
unsigned short int … con meno bit
unsigned long int … con più bit
8
Quanti bit?

Lo standard C non specifica l’ampiezza, in bit, dei


tipi di dato fondamentali
L’operatore sizeof può essere usato per
ricavare una costante pari al numero di byte
occupato da ciascun tipo

sizeof(char
char)
char sizeof(int
int)
int

9
Specifiche del C

=
sizeof(char
char)
char 1

≤ < ≤

sizeof(short
short int)
int sizeof(int
int)
int sizeof(long
long int)
int

= = =

sizeof(unsigned
unsigned sizeof( sizeof(unsigned
unsigned
short int)
int unsigned int)
int long int)
int

≤ ≤
10
Intervallo di rappresentazione

Tipo Min Max


char CHAR_MIN CHAR_MAX
int INT_MIN INT_MAX
short int SHRT_MIN SHRT_MAX
long int LONG_MIN LONG_MAX
unsigned int 0 UINT_MAX
unsigned short int 0 USHRT_MAX
unsigned long int 0 ULONG_MAX

#include <limits.h>
11
Compilatori a 32 bit

Tipo N. Bit Min Max


char 8 -128 127
int 32 -2147483648 2147483647
short int 16 -32768 32767
long int 32 -2147483648 2147483647
unsigned 32 0 4294967295
int
unsigned 16 0 65536
short int
unsigned 32 0 4294967295
long int 12
I tipi reali in C

Tipo Descrizione
float Numeri reali in singola precisione
double Numeri reali in doppia precisione
long double Numeri reali in massima
precisione

segno
} 6
esponente
474 8
± eeeeee
A = ± 114243 × 2
.mmmmm
mantissa

13
Numero di bit

Tipo Dimensione Mantissa Esponente


float 32 bit 23 bit 8 bit
double 64 bit 53 bit 10 bit
long double ≥ double

segno
} 6
esponente
474 8
± eeeeee
A = ± 114243 × 2
.mmmmm
mantissa

14
Intervallo di rappresentazione

float
0

±1.17549435E-38

±3.40282347E+38

double
0

±2.2250738585072014E-308

±1.7976931348623157E+308
15
Tipi di dato
Input/output

I diversi tipi scalari visti sono utilizzabili con le


normali funzioni scanf/printf, adottando degli
specifici indicatori di formato
Utilizzando la funzione gets per l’input, si
possono usare le funzioni di conversione ato...

17
Specificatori di formato

Tipo scanf printf


char %c %[...] %c %d
int %d %d
short int %hd %hd %d
long int %ld %ld
unsigned int %u %o %x %u %o %x
unsigned short int %hu %hu
unsigned long int %lu %lu
float %f %f %g
double %lf %f %g
18
Funzioni di conversione

char line[80] ; char line[80] ;


int x ; float x ;

gets(line) ; gets(line) ;
x = atoi(line) ; x = atof(line) ;

char line[80] ; char line[80] ;


long int x ; double x ;

gets(line) ; gets(line) ;
x = atol(line) ; x = atof(line) ;

19
Tipi di dato
Conversioni di tipo (1/2)

Nel linguaggio C è possibile combinare, nella


stessa espressione, variabili di tipo diverso
I due operandi di un operatore aritmetico possono
avere tipi diversi

int a ; double prod ;


long int b, c ; float v[N] ;
c = b + a ; prod = prod * v[i] ;

21
Conversioni di tipo (2/2)

La variabile di destinazione di un’assegnazione può


avere tipo diverso dal tipo dell’espressione

int a ; double prod ;


long int b ; float v[N] ;
b = a ; prod = v[0] ;

22
Tipologie di conversioni

Per calcolare tali tipi di espressioni, il linguaggio C


applica tre tipi di conversioni:
Conversioni “automatiche” verso il tipo più
capiente, basate sul principio di promozione del
tipo
Arrotondamenti e troncamenti, in caso di
assegnazioni “forzate” a tipi meno capienti
Conversioni “esplicite”, basate sull’operatore di
typecasting

23
Promozione del tipo

Se i due operandi di un operatore aritmetico


hanno tipo diverso, l’operando del tipo più
limitato viene convertito al tipo dell’operando più
esteso

char short int int long int

float double

24
Promozione del tipo

Se i due operandi di un operatore aritmetico


hanno Non
tiposidiverso,
perde mail’operando
precisione. del tipo più
Il C converte automaticamente
limitato viene convertito al tipo dell’operando più
verso i tipi più capienti
esteso

char short int int long int

float double

25
Troncamento del risultato

Nell’operatore di assegnazione var = expr ;


ci possono essere 3 casi:
La variabile destinazione ha lo stesso tipo
dell’espressione calcolata
La variabile destinazione ha un tipo più ampio del
tipo dell’espressione calcolata
Si promuove il tipo dell’espressione al tipo della
variabile destinazione
La variabile destinazione ha un tipo più ristretto
del tipo dell’espressione calcolata
Si approssima il tipo dell’espressione al tipo della
variabile destinazione, perdendo precisione

26
Conversioni esplicite

Qualora si vogliano modificare le regole


predefinite di promozione e troncamendo dei tipi,
il C mette a disposizione un operatore di
conversione esplicita di tipo
Typecasting

(nuovotipo)expr

Converte l’espressione expr dal suo tipo nativo, al


tipo desiderato nuovotipo
Più capiente
Meno capiente: troncamento o approssimazione 27
Esempio 1

double media ;
int somma, N ;

media = somma / N ; /* no */

media = (double
double)somma
double / N ;

28
Esempio 2

int voto ;
float parte1, parte2, parte3 ;

voto = (int
int)
int ((parte1 +
parte2 + parte3)/3) ;

29
Esempio 3

int voto ;
float parte1, parte2, parte3 ;
float media ;

/* arrotondamento all’intero
più vicino */

media = (parte1 +
parte2 + parte3)/3 ;

voto = (int
int)
int (media + 0.5) ;
30
Funzioni
Funzioni in C

Il concetto di funzione
Parametri formali e attuali
Il valore di ritorno
Definizione e chiamata di funzioni
Passaggio dei parametri
Corpo della funzione

2
Funzioni in C
Strategie di programmazione

Riuso di codice esistente


Funzionalità simili in programmi diversi
Funzionalità ripetute all’interno dello stesso
programma
Minore tempo di sviluppo
Frammenti di codice già verificati
Utilizzo di parti di codice scritte da altri
Funzioni di libreria
Sviluppo collaborativo

4
Come riusare il codice? (1/3)

Copia-e-incolla
Semplice, ma poco efficace
Occorre adattare il codice incollato, ritoccando i
nomi delle variabili e costanti utilizzati
Se si scopre un errore, occorre correggerlo in tutti
i punti in cui è stato incollato
Nel listato finale non è evidente che si sta
riutilizzando la stessa funzionalità
Occorre disporre del codice originario
Occorre capire il codice originario

5
Come riusare il codice? (2/3)

Definizione di funzioni
Dichiarazione esplicita che una certa funzionalità
viene utilizzata in più punti
Si separa la definizione della funzionalità rispetto al
punto in cui questa viene utilizzata
La stessa funzione può essere usata più volte con
parametri diversi

6
Come riusare il codice? (3/3)

Ogni miglioramento o correzione è


automaticamente disponibile in tutti i punti in cui
la funzione viene usata
Nel listato finale è evidente che si sta riutilizzando
la stessa funzionalità
Non occorre disporre del codice originario
Non occorre capire il codice originario

7
Principio di funzionamento (1/3)

int main(void
void)
void
{
int x, y ;

/* leggi un numero
tra 50 e 100 e
memorizzalo
in x */
/* leggi un numero
tra 1 e 10 e
memorizzalo
in y */

printf("%d %d\n",
x, y ) ;
}
8
Principio di funzionamento (2/3)

int main(void
void)
void
{
int x, y ;

x = leggi(50, 100) ;
y = leggi(1, 10) ;

printf("%d %d\n",
x, y ) ;
}

9
Principio di funzionamento (3/3)

int leggi(int
int min,
int main(void
void)
void int max)
{ {
int x, y ; int v ;

x = leggi(50, 100) ; do {
y = leggi(1, 10) ; scanf("%d", &v) ;
} while(
while v<min ||
printf("%d %d\n", v>max) ;
x, y ) ;
} return v ;
}

10
Principio di funzionamento (3/3)

min=50 max=100

int leggi(int
int min,
int main(void
void)
void int max)
{ {
int x, y ; int v ;

x = leggi(50, 100) ; do {
y = leggi(1, 10) ; scanf("%d", &v) ;
} while(
while v<min ||
printf("%d %d\n", v>max) ;
x, y ) ;
} return v ;
}

11
Principio di funzionamento (3/3)

min=50 max=100

int leggi(int
int min,
int main(void
void)
void int max)
{ {
int x, y ; int v ;

x = leggi(50, 100) ; do {
y = leggi(1, 10) ; scanf("%d", &v) ;
} while(
while v<min ||
printf("%d %d\n", v>max) ;
x, y ) ;
} return v ;
}

Chiamante Chiamato
12
Principio di funzionamento (3/3)

min=1 max=10

int leggi(int
int min,
int main(void
void)
void int max)
{ {
int x, y ; int v ;

x = leggi(50, 100) ; do {
y = leggi(1, 10) ; scanf("%d", &v) ;
} while(
while v<min ||
printf("%d %d\n", v>max) ;
x, y ) ;
} return v ;
}

13
Sommario

La definizione di una funzione delimita un


frammento di codice riutilizzabile più volte
La funzione può essere chiamata più volte
Può ricevere dei parametri diversi in ogni
chiamata
Può restituire un valore di ritorno al
chiamante
Istruzione return

14
Miglioramento della funzione

int leggi(int
int min, int max)
{
char riga[80] ;
int v ;

do {
gets(riga) ;
v = atoi(riga) ;
if(v<min)
if printf("Piccolo: min %d\n", min) ;
if(v>max)
if printf("Grande: max %d\n", max) ;
} while(
while v<min || v>max) ;

return v ;
}
15
Funzioni in C
Parametri di una funzione

Le funzioni possono
int leggi(int
int min,
ricevere dei parametri int max)
dal proprio chiamante {
...
Nella funzione: }
Parametri formali
Nomi “interni” dei
parametri

17
Parametri di una funzione

Le funzioni possono
int leggi(int
int min,
ricevere dei parametri int max)
dal proprio chiamante {
...
Nella funzione: }
Parametri formali
Nomi “interni” dei
parametri int main(void
void)
void
{
Nel chiamante: ...
Parametri attuali y = leggi(1, 10) ;
...
Valori effettivi }
(costanti, variabili,
espressioni) 18
Parametri formali (1/2)

Uno o più parametri


int leggi(int
int min,
Tipo del parametro int max)
Tipo scalare {
...
Vettore o matrice }
Nome del parametro

Nel caso in cui la


int stampa_menu(void
void)
void
funzione non abbia {
bisogno di parametri, ...
si usa la parola chiave }
void
19
Parametri formali (2/2)

Per parametri vettoriali


esistono 3 sintassi int leggi(int
int v[])
alternative {
...
int v[] }
int v[MAX]
int *v
Per parametri matriciali
int m[RIGHE][COL] int sudoku(int
int m[9][9])
{
int m[][COL] ...
}

20
Avvertenza (1/2)

Il valore della dimensione del vettore (es. MAX)


Viene totalmente ignorato dal meccanismo di
chiamata
Non sarebbe comunque disponibile alla funzione
chiamata
Meglio per chiarezza ometterlo
Si suggerisce di passare un ulteriore parametro
contenente l’occupazione del vettore

21
Avvertenza (2/2)

Nel caso di matrici


Il secondo parametro (es. COL) è obbligatorio e
deve essere una costante
Il primo parametro viene ignorato e può essere
omesso
Per matrici pluri-dimensionali, occorre specificare
tutti i parametri tranne il primo

22
Parametri attuali (1/2)

Uno o più valori, in int main(void


void)
void
esatta corrispondenza {
con i parametri formali y = leggi(1, 10) ;
}
Tipi di dato compatibili
con i parametri formali int main(void
void)
void
È possibile usare {
y = leggi(a, b) ;
Costanti }
Variabili
int main(void
void)
void
Espressioni {
y = leggi(a+b+1,
c*2) ;
} 23
Parametri attuali (2/2)

I nomi delle variabili int main(void


void)
void
usate non hanno {
...
alcuna relazione con i y = leggi(a, b) ;
nomi dei parametri ...
} min=a max=b
formali

int main(void
void)
void
{
Le parentesi sono ...
sempre necessarie, y = stampa_menu() ;
...
anche se non vi sono }
parametri
24
Funzioni in C
Valore di ritorno

Ogni funzione può int leggi(int


int min,
ritornare un valore al int max)
proprio chiamante {
int v ;
Il tipo del valore di
ritorno deve essere scanf("%d", &v) ;
scalare return v ;
L’istruzione return }
Termina l’esecuzione
int main(void
void)
void
della funzione {
Rende disponibile il ...
valore al chiamante y = leggi(a, b) ;
...
} 26
Tipo del valore di ritorno

Valore scalare
char, int (o varianti), float, double
Tipi avanzati
Puntatori, struct
Nessun valore ritornato
void double sqrt(double
double a)
{
...
}

void stampa_err(int
int x)
{
...
27
}
L’istruzione return (1/2)

Restituisce il valore
Costante
Variabile
Espressione
Il tipo deve essere compatibile con il tipo
dichiarato per il valore di ritorno
Sintassi
return x ;
return(x) ;
L’esecuzione della funzione viene interrotta
28
L’istruzione return (2/2)

Per funzioni che non ritornano valori (void):


return ;
Il raggiungimento della fine del corpo della
funzione } equivale ad un’istruzione return
senza parametri
Permesso solo per funzioni void
Per funzioni non-void, è obbligatorio che la
funzione ritorni sempre un valore

29
Nel chiamante...

Il chiamante può:
Ignorare il valore ritornato
scanf("%d", &x) ;
Memorizzarlo in una variabile
y = sin(x) ;
Utilizzarlo in un’espressione
if ( sqrt(x*x+y*y)>z ) ...

30
Convenzioni utili

Le funzioni di tipo matematico ritornano sempre


un valore double
Le funzioni che non devono calcolare un valore
(ma effettuare delle operazioni, per esempio)
ritornano solitamente un valore int
Valore di ritorno == 0 ⇒ tutto ok
Valore di ritorno != 0 ⇒ si è verificato un errore
Molte eccezioni importanti: strcmp, scanf, ...

31
Funzioni in C
Sintassi C per le funzioni

Il linguaggio C prevede 3 distinti momenti :


La dichiarazione (prototipo o function prototype)
L’interfaccia della funzione
Solitamente: prima del main()
La definizione
L’implementazione della funzione
Solitamente: al fondo del file, dopo il main()
La chiamata
L’utilizzo della funzione
Solitamente: dentro il corpo del main() o di altre
funzioni

33
Dichiarazione o prototipo

int leggi(int
int min, int max) ;

Tipo del Nome della Tipi e nomi Punto-e-


valore di funzione dei parametri virgola
ritorno formali

34
Scopo del prototipo

Dichiarare che esiste una funzione con il nome


dato, e dichiarare i tipi dei parametri formali e del
valore di ritorno
Dal prototipo in avanti, si può chiamare tale
funzione dal corpo di qualsiasi funzione
(compreso il main)
Non è errore se la funzione non viene chiamata
I file .h contengono centinaia di prototipi delle
funzioni di libreria
I prototipi sono posti solitamente ad inizio file

35
Definizione o implementazione

Tipo del Nome della Tipi e nomi


valore di funzione dei parametri
ritorno formali

int leggi(int int min, int max)


{
. . . codice della funzione . . .
}

Corpo della funzione Nessun


{ ... } punto-e-virgola 36
Scopo della definizione

Contiene il codice vero e proprio della funzione


Può essere posizionata ovunque nel file (al di
fuori del corpo di altre funzioni)
Il nome della funzione ed i tipi dei parametri e
del valore di ritorno devono coincidere con
quanto dichiarato nel prototipo
Il corpo della funzione può essere arbitrariamente
complesso, e si possono chiamare altre funzioni

37
Chiamata o invocazione

Funzione Valori dei parametri


chiamante attuali
int main(void
void)
void
{
int x, a, b ;
...
x = leggi(a, b) ;
...
}

Uso del valore di Chiamata della


ritorno funzione 38
Meccanismo di chiamata

Le espressioni corrispondenti ai parametri attuali


vengono valutate (e ne viene calcolato il valore
numerico)
Compaiono le variabili del chiamante
I valori dei parametri attuali vengono copiati nei
parametri formali
La funzione viene eseguita
All’istruzione return, il flusso di esecuzione
torna al chiamante
Il valore di ritorno viene usato o memorizzato
39
Riassumendo...

int leggi(int
int min, int max) ;

int main(void
void)
void
{
int x, a, b ;
...
x = leggi(a, b) ;
...
}
int leggi(int int min, int max)
{
. . . codice della funzione . . .
} 40
Funzioni in C
Passaggio dei parametri

Ogni volta che viene chiamata una funzione,


avviene il trasferimento del valore corrente dei
parametri attuali ai parametri formali

Parametro attuale Parametro formale


(chiamante) (chiamato)

Valuta
Valore iniziale
espressione/i
Copia
valore
Uso nella
funzione
42
Conseguenza

La funzione chiamata non ha assolutamente


modo di
Conoscere il nome delle variabili utilizzate come
parametri attuali
Ne conosce solo il valore corrente
Modificare il valore delle variabili utilizzate come
parametri attuali
Riceve solamente una copia del valore
Questo meccanismo è detto passaggio “by value”
dei parametri
È l’unico possibile in C
43
Errore frequente

Immaginare che una funzione possa modificare i


valori delle variabili

void azzera(int
int x)
{
x = 0 ;
}

44
Parametri di tipo vettoriale

Il meccanismo di passaggio “by value” è chiaro


nel caso di parametri di tipo scalare
Nel caso di parametri di tipo array (vettore o
matrice), il linguaggio C prevede che:
Un parametro di tipo array viene passato
trasferendo una copia dell’indirizzo di memoria in
cui si trova l’array specificato dal chiamante
Passaggio “by reference”

45
Conseguenza

Nel passaggio di un vettore ad una funzione, il


chiamato utilizzerà l’indirizzo a cui è memorizzato
il vettore di partenza
La funzione potrà quindi modificare il contenuto
del vettore del chiamante
Maggiori dettagli nella prossima lezione

46
Funzioni in C
Variabili locali

All’interno del corpo int leggi(int


int min,
di una funzione è int max)
possibile definire delle {
int v ;
variabili locali
scanf("%d", &v) ;

return v ;
}

48
Caratteristiche

Le variabili locali sono accessibili solo dall’interno


della funzione
Le variabili locali sono indipendenti da eventuali
variabili di ugual nome definite nel main
In ogni caso, dal corpo della funzione è impossibile
accedere alle variabili definite nel main
Le variabili locali devono avere nomi diversi dai
parametri formali

49
Istruzioni eseguibili

Il corpo di una funzione int leggi(int


int min,
può contenere qualsiasi int max)
combinazione di {
int v ;
istruzioni eseguibili
Ricordare l’istruzione scanf("%d", &v) ;
return return v ;
}

50
Funzioni
Parametri “by reference”

Introduzione
Operatori & e *
Passaggio “by reference”
Passaggio di vettori
Esercizio “strcpy”

2
Parametri “by reference”
Passaggio dei parametri

Il linguaggio C prevede il passaggio di parametri


“by value”
Il chiamato non può modificare le variabili del
chiamante
Il parametro formale viene inizializzato con una
copia del valore del parametro attuale

4
Problemi

Il passaggio “by value” risulta inefficiente qualora


le quantità di dati da passare fossero notevoli
Nel caso del passaggio di vettori o matrici, il
linguaggio C non permette il passaggio “by value”,
ma copia solamente l’indirizzo di partenza
Esempio: strcmp
Talvolta è necessario o utile poter modificare il
valore di una variabile nel chiamante
Occorre adottare un meccanismo per permettere
tale modifica
Esempio: scanf
5
Soluzione

La soluzione ad entrambi i problemi è la stessa:


Nel passaggio di vettori, ciò che viene passato è
solamente l’indirizzo
Per permettere di modificare una variabile, se ne
passa l’indirizzo, in modo che il chiamato possa
modificare direttamente il suo contenuto in
memoria
Viene detto passaggio “by reference” dei
parametri
Definizione impropria, in quanto gli indirizzi sono, a
loro volta, passati “by value”
6
Parametri “by reference”
Operatori sugli indirizzi

Per gestire il passaggio “by reference” dei


parametri occorre
Conoscere l’indirizzo di memoria di una variabile
Operatore &
Accedere al contenuto di una variabile di cui si
conosce l’indirizzo ma non il nome
Operatore *
Prime nozioni della aritmetica degli indirizzi, che
verrà approfondita in Unità successive

8
Operatore &

L’operatore indirizzo-di 1000


1004
restituisce l’indirizzo di 1008
memoria della variabile int a 1012 37
a cui viene applicato 1016
&a è l’indirizzo 1012 int b 1020 -4
1024
&b è l’indirizzo 1020 1028

9
Osservazioni

L’indirizzo di una variabile viene deciso dal


compilatore
L’operatore & si può applicare solo a variabili
singole, non ad espressioni
Non ha senso &(a+b)
Non ha senso &(3)
Conoscere l’indirizzo di una variabile permette di
leggerne o modificarne il valore senza
conoscerne il nome

10
Variabili “puntatore”

Per memorizzare gli indirizzi di memoria, occorre


definire opportune variabili di tipo “indirizzo di...”
Nel linguaggio C si chiamano puntatori
Un puntatore si definisce con il simbolo *
int *p ; /* puntatore ad un valore intero */
float *q ; /* puntatore ad un valore reale */

11
Esempio

int main(void
void)
void 1000
{ 1004
int a, b ; 1008
int *p, *q ; int a 1012 37
1016
a = 37 ; int b 1020 -4
b = -4 ;
1024
p = &a ; 1028
/* p "punta a" a */ 1032
1036
q = &b ; int *p 1040 1012
/* q "punta a" b */ 1044
int *q 1048 1020
} 1052
12
Operatore *

L’operatore di accesso 1000


1004
indiretto permette di 1008
accedere, in lettura o int a 1012 37
scrittura, al valore di una 1016
variabile di cui si int b 1020 -4
1024
conosce l’indirizzo
1028
*p equivale ad a 1032
*q equivale a b 1036
int *p 1040 1012
*p = 0 ;
1044
if( *q > 0 ) ... int *q 1048 1020
1052
13
Costrutti frequenti

Costrutto Significato

int x ; x è una variabile intera

int *p ; p è un puntatore a variabili intere

p = &x ; p punta ad x

*p = 0 ; Azzera la variabile puntata da p (cioè x)

Leggi il contenuto della variabile puntata


b = *p ;
da p e copialo in b 14
Parametri “by reference”
Passaggio “by reference”

Obiettivo: passare ad una funzione una variabile,


in modo tale che la funzione la possa modificare
Soluzione:
Definire un parametro attuale di tipo puntatore
Al momento della chiamata, passare l’indirizzo
della variabile (anziché il suo valore)
All’interno del corpo della funzione, fare sempre
accesso indiretto alla variabile di cui è noto
l’indirizzo

16
Esempio: “Azzera”

Scrivere una funzione azzera, che riceve un


parametro di tipo intero (by reference) e che
azzera il valore di tale parametro

17
Soluzione

void azzera( int *v ) ;

int main( void )


{
int x ;
...
azzera(&x) ;
...
}

void azzera( int *v )


{
*v = 0 ;
}
18
Esempio: “Scambia”

Scrivere una funzione scambia, che riceve due


parametri di tipo intero (by reference) e che
scambia tra di loro i valori in essi contenuti

19
Soluzione

void scambia( int *p, int *q ) ;

int main( void )


{
int a,b ;
...
scambia(&a, &b) ;
...
}

void scambia( int *p, int *q )


{
int t ;
t = *p ;
*p = *q ;
*q = t ;
20
}
Osservazione

Il meccanismo di passaggio by reference spiega


(finalmente!) il motivo per cui nella funzione
scanf è necessario specificare il carattere &
nelle variabili lette
Le variabili vengono passate by reference alla
funzione scanf, in modo che questa possa
scrivervi dentro il valore immesso dall’utente

21
Parametri “by reference”
Passaggio di vettori e matrici

Nel linguaggio C, il nome di un array (vettore o


matrice) è automaticamente sinonimo del
puntatore al suo primo elemento

int main(void
void)
void
{
int v[10] ; p e v sono
int *p ;
del tutto
p = & v[0] ; equivalenti

23
Conseguenze

Quando il parametro di una funzione è di tipo


array (vettore o matrice)
L’array viene passato direttamente “by reference”
Non è necessario l’operatore & per determinare
l’indirizzo
È sufficiente il nome del vettore
Non è necessario l’operatore * per accedere al
contenuto
È sufficiente l’operatore di indicizzazione []
Non è possibile, neppure volendolo, passare un
array “by value”
24
Esercizio “Duplicati”

Scrivere una funzione che, ricevendo due


parametri
Un vettore di double
Un intero che indica l’occupazione effettiva di tale
vettore
possa determinare se vi siano valori duplicati in
tale vettore
La funzione ritornerà un intero pari a 1 nel caso
in cui vi siano duplicati, pari a 0 nel caso in cui
non ve ne siano

25
Soluzione (1/3)

int duplicati(double
double v[], int N) ;
/*
Riceve in ingresso il vettore v[] di double
che contiente N elementi (da v[0] a v[N-1])

Restituisce 0 se in v[] non vi sono duplicati


Restituisce 1 se in v[] vi sono duplicati

Il vettore v[] non viene modificato


*/

26
Soluzione (2/3)

int duplicati(double
double v[], int N)
{
int i, j ;

for(i=0;
for i<N; i++)
{
for(j=i+1;
for j<N; j++)
{
if(v[i]==v[j])
if
return 1 ;
}
}
return 0 ;
}
27
Soluzione (3/3)

int main(void
void)
void
{
const int MAX = 100 ;
double dati[MAX] ;
int Ndati ;
int dupl ;

...
dupl = duplicati(dati, Ndati) ;
...
}

28
Errore frequente

Nel passaggio di un vettore occorre indicarne


solo il nome

dupl = duplicati(dati, Ndati) ;

dupl = duplicati(dati[], Ndati) ;

dupl = duplicati(dati[MAX], Ndati) ;

dupl = duplicati(dati[Ndati], Ndati) ;

dupl = duplicati(&dati, Ndati) ;


29
Osservazione

Nel caso dei vettori, il linguaggio C permette


solamente il passaggio by reference
Ciò significa che il chiamato ha la possibilità di
modificare il contenuto del vettore
Non è detto che il chiamato effettivamente ne
modifichi il contenuto
La funzione duplicati analizza il vettore senza
modificarlo
Esplicitarlo sempre nei commenti di
documentazione

30
Parametri “by reference”
strcpy”
strcpy
Esercizio “strcpy

Si implementi, sotto forma di funzione, la ben


nota funzione di libreria strcpy per la copia di
due stringhe

32
Soluzione (1/2)

void strcpy(char
char *dst, char *src) ;
/*
Copia il contenuto della stringa src
nella stringa dst

Assume che src sia 0-terminata, e restituisce


dst in forma 0-terminata.

Assume che nella stringa dst vi sia spazio


sufficiente per la copia.

La stringa src non viene modificata.


*/

33
Soluzione (2/2)

void strcpy(char
char *dst, char *src)
{
int i ;

for(i=0;
for src[i]!=0; i++)
{
dst[i] = src[i] ;
}
dst[i] = 0 ;
}

34
Osservazione

La funzione può essere dichiarata in due modi:


void strcpy(char *dst, char *src)
void strcpy(char dst[], char src[])
Sono forme assolutamente equivalenti

Tutte le funzioni di libreria che lavorano sulle


stringhe accettano dei parametri di tipo char *

35
Funzioni
La funzione main()
main()

Interfaccia con il sistema operativo


Argomenti sulla linea di comando
Parametri argc e argv
Valore di ritorno del programma
La funzione exit
Esercizio “Calcolatrice”

2
La funzione main()
main()
La funzione main()
main()

La funzione main(), presente in tutti i


programmi C, è una funzione come tutte le altre
Unica particolarità: viene chiamata
automaticamente dal Sistema Operativo, appena
il programma viene avviato
Non esiste mai una chiamata esplicita a main()
L’interfaccia della funzione viene definita dalle
caratteristiche del sistema operativo

4
Interfaccia in modalità “console”

Ricordiamo che il linguaggio C si è evoluto con


interfacce “a caratteri”
L’attivazione di un programma avviene
digitandone il nome in una finestra di comando

5
Il modello “console”

Sistema Operativo

Finestra di comando

Argomenti Codice di uscita

Programma utente

int main()

6
Interfaccia del programma

La finestra di comando permette di passare al


programma una serie di argomenti
Zero, una o più stringhe di testo
Utilizzate dal programma come dati in ingresso
Al termine dell’esecuzione, il programma
restituisce un codice di uscita
Numero intero
Indica eventuali condizioni di errore
Durante l’esecuzione, il programma può accedere
all’input (tastiera) e all’output (schermo)

7
La funzione main()
main()
La linea di comando (1/2)

L’attivazione di un programma avviene digitando


il suo nome in una finestra di comando

Microsoft Windows XP [Versione 5.1.2600]


(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\corno>cd \progr


C:\progr>quadrato
***
***
***
C:\progr>_
9
La linea di comando (2/2)

È possibile passare dei parametri all’attivazione


del programma

C:\progr>quadrato 5 C:\progr>quadrato 5 K
***** KKKKK
***** KKKKK
***** KKKKK
***** KKKKK
***** KKKKK
C:\progr>_ C:\progr>_

10
Nomenclatura

Parametri sulla linea di comando


Command line parameters
Argomenti del programma
Program arguments
Parametri di attivazione
Parametri del main
Argomenti del main
Opzioni [sulla linea di comando]

11
Caratteristiche

Numero variabile di parametri


Anche nessuno
Tipo variabile
Numeri
Caratteri o Stringhe
Il chiamante (sistema operativo) non ha modo di
sapere quanti parametri servono al programma
né di che tipo
Verranno trattati in modo standardizzato

12
Standardizzazione dei parametri

Gli argomenti sulla linea di comando vengono


trattati come un vettore di stringhe
Il programma riceve
Una copia del vettore di stringhe
Un valore numerico che indica quante stringhe
sono presenti

13
Esempi

C:\progr>quadrato Numero argomenti = 0

Numero argomenti = 1
C:\progr>quadrato 5
Argomento 1 = “5”

Numero argomenti = 2
C:\progr>quadrato 5 K Argomento 1 = “5”
Argomento 2 = “K”
14
La funzione main()
main()
Parametri formali del main

I parametri sulla linea di comando sono


disponibili al main attraverso i suoi parametri
formali
La definizione completa della funzione main è:

int main(int
int argc, char *argv[]) ;

Argument count Argument values

16
Il parametro argc

int argc
Numero di parametri sulla linea di comando
Incrementato di uno, in quanto il nome del
programma viene considerato come un parametro
Se non vi sono argomenti effettivi, vale 1
Se vi sono k argomenti effettivi, vale k+1

17
Il parametro argv

char *argv[]
È un vettore di stringhe
Ogni stringa è un parametro del programma
Vi sono argc diverse stringhe
La prima stringa, argv[0], è il nome del
programma
La seconda stringa, argv[1], è il primo
argomento (se esiste)

L’ultimo argomento è in argv[argc-1]

18
Esempi

argc==1
C:\progr>quadrato
argv[0]=="quadrato"

argc==2
C:\progr>quadrato 5 argv[0]=="quadrato"
argv[1]=="5"

argc==3
argv[0]=="quadrato"
C:\progr>quadrato 5 K
argv[1]=="5"
argv[2]=="K" 19
Per capire meglio...

#include <stdio.h>
arg.c
int main(int
int argc, char *argv[])
{
int i ;

printf("argc = %d\n", argc) ;


for(i=0;
for i<argc; i++)
{
printf("argv[%d] = \"%s\"\n",
i, argv[i]) ;
}
}

20
Osservazione

Il vettore argv contiene i dati sotto forma


esclusivamente di stringa
Qualora uno dei dati richiesti sia di tipo numerico
(int o double), occorre effettuare la
conversione da stringa a numero
i = atoi(argv[1]) ;
r = atof(argv[1]) ;
Se il parametro è invece una stringa, conviene
copiarlo in una variabile mediante strcpy

21
La funzione main()
main()
Valore di ritorno

Al termine dell’elaborazione il programma


restituisce un numero intero al sistema operativo
Tale valore viene spesso ignorato, ma in caso di
esecuzione “batch” è possibile interrogarlo a
livello di sistema operativo
in MS-DOS, tramite la variabile ERRORLEVEL
echo %errorlevel%
in sistemi Unix, mediante la macro $?
echo $?

23
Convenzioni

Il valore di ritorno è un int, ma per compatibilità


si preferisce ritornare degli “interi positivi piccoli”
Convenzionalmente
Il valore di ritorno pari a 0 indica “programma
terminato correttamente”
Il valore di ritorno diverso da 0 indica “programma
terminato anormalmente a causa di un errore”
Il valore specifico ritornato (1, 2, 3, ...) può indicare
la causa dell’errore

24
Esempio

25
La funzione main()
main()
Restituzione del valore di ritorno

Quando il programma termina, deve restituire il


valore di ritorno
==0, se tutto OK
!=0, se errore
Il modo più semplice per restituire tale valore è di
utilizzare l’istruzione return all’interno della
funzione main
L’elaborazione viene immediatamente interrotta
Il valore ritornato viene passato al sistema
operativo

27
Esempio

#include <stdio.h>

int main(int
int argc, char *argv[])
{
. . .
. . .
. . .
return 0 ;
}

28
La funzione exit

Esiste inoltre la funzione di libreria exit,


dichiarata in <stdlib.h>, che assolve alla
stessa funzione
Interrompe l’esecuzione del programma
Ritorna il valore specificato
Il vantaggio rispetto all’istruzione return è che
può essere usata all’interno di qualsiasi funzione,
non solo del main

void exit(int
int value) ;

29
Esempio

#include <stdio.h>
#include <stdlib.h>

int main(int
int argc, char *argv[])
{
. . .
. . .
. . .
exit(0) ;
}

30
Suggerimento

Ricordare sempre di ritornare un valore


Mettere come ultima istruzione del main:
exit(0);
Per eventuali condizioni di errore (parametri
assenti, valori illegali, ...) che non possano essere
corrette dal programma, restituire un valore
positivo: exit(1) ;
Tali errori possono essere controllati dall’interno di
qualsiasi funzione: la exit interrompe comunque
l’intero programma

31
La funzione main()
main()
Esercizio “Calcolatrice”

Si scriva un programma da utilizzarsi come


semplice calcolatrice sulla linea di comando
Il programma, denominato calcola, accetta 3
parametri sulla linea di comando
Il primo ed il terzo parametro sono degli operandi,
espressi come numeri reali
Il secondo parametro è un operatore, scelto tra +,
-, * e /
Il programma stampa il risultato corrispondente
all’operazione

33
Analisi

c:\progr>calcola 3 + 2
Risultato: 5.0000
c:\progr>calcola 3 * 2
Risultato: 6.0000
c:\progr>calcola 3 $ 2
Errore: operatore non riconosciuto
c:\progr>calcola 3 +
Errore: operando mancante

34
Soluzione (1/5)

calcola.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int
int argc, char *argv[])
{
double v1, v2 ;
char op[20] ;

35
Soluzione (2/5)

if(argc!=4)
if calcola.c

{
printf("Errore: numero parametri
insufficiente\n");
exit(1) ;
}

v1 = atof(argv[1]) ;
strcpy(op, argv[2]) ;
v2 = atof(argv[3]) ;

36
Soluzione (3/5)

calcola.c

if(strcmp(op,
if "+")==0)
printf("Risultato: %f\n", v1 + v2 ) ;
else if(strcmp(op,
if "-")==0)
printf("Risultato: %f\n", v1 - v2 ) ;
else if(strcmp(op,
if "*")==0)
printf("Risultato: %f\n", v1 * v2 ) ;

37
Soluzione (4/5)

calcola.c
else if(strcmp(op,
if "/")==0)
{
if(v2==0)
if
{
printf("Errore: divisione per zero\n");
exit(2) ;
}
else
printf("Risultato: %f\n", v1 / v2 ) ;
}

38
Soluzione (5/5)

calcola.c

else
{
printf("Errore: operatore
non riconosciuto\n") ;
exit(3) ;
}
exit(0) ;
}

39
Funzioni
Esercizi proposti

Esercizio “Confronto tra date”


Esercizio “Quadrato”
Esercizio “Indovina numero”

2
Esercizi proposti
Esercizio “Confronto tra date”

Si scriva un programma che chieda all’utente di


inserire due date (giorno, mese, anno) e
determini:
Se le date solo uguali
Se la prima data precede la seconda
Se la prima data segue la seconda
Il programma dovrà porre particolare attenzione
a non accettare date non valide
Esempio: 30/02/1984
Esempio: 10/14/2001

4
Analisi

Confronto tra date

Inserisci la PRIMA data


Giorno: 15
Mese: 3
Anno: 2007
Inserisci la SECONDA data
Giorno: 26
Mese: 4
Anno: 1967

La prima data 15/3/2007 SEGUE


la seconda data 26/4/1967

5
Controlli

1 ≤ giorno ≤ 31
1 ≤ mese ≤ 12
1900 < anno < 2100
Se mese = 4, 6, 9, 11, allora giorno ≤ 30
Se mese = 2, allora giorno ≤ 29
Se mese = 2 e l’anno non è bisestile, allora
giorno ≤ 28
L’anno è bisestile se è multiplo di 4

6
Soluzione

Scrivere una funzione per la lettura della data,


che comprenda al suo interno tutti i controlli:

void leggidata( int *giorno,


int *mese, int *anno ) ;

La funzione restituisce, nelle 3 variabili passate


by reference, le componenti (giorno, mese, anno)
della data
La funzione garantisce che la data restituita è
corretta
7
Programma principale
int main(void
void)
void
{
int g1, m1, a1 ; date.c
int g2, m2, a2 ;

printf("Confronto tra date\n\n") ;

printf("Inserisci la PRIMA data\n") ;


leggidata( &g1, &m1, &a1 ) ;

printf("Inserisci la SECONDA data\n") ;


leggidata( &g2, &m2, &a2 ) ;

/*
/* Confronto
Confronto delle
delle date
date */
*/

} /* main */ 8
Confronto delle date
if(
if g1 == g2 && m1 == m2 && a1 == a2 )
printf("Le date sono uguali\n") ;
else if(
if a1<a2 || date.c
(a1==a2 && m1<m2) ||
(a1==a2 && m1==m2 && g1<g2) )
{
printf("La prima data %d/%d/%d "
"PRECEDE la seconda %d/%d/%d\n",
g1, m1, a1, g2, m2, a2) ;
}
else
{
printf("La prima data %d/%d/%d "
"SEGUE la seconda %d/%d/%d\n",
g1, m1, a1, g2, m2, a2) ;
} 9
Funzione leggidata (1/5)

void leggidata( int *giorno, int *mese,


int *anno ) date.c
{
int g, m, a ;
int ok ;

do {
do {
printf("Giorno: ") ;
scanf("%d", &g) ;

if(g<1
if || g>31)
printf("Giorno non valido\n");
} while(
while g<1 || g>31 ) ;
10
Funzione leggidata (2/5)

do {
printf("Mese: ") ;
scanf("%d", &m) ; date.c

if(m<1
if || m>12)
printf("Mese non valido\n");
} while(
while m<1 || m>12 ) ;

do {
printf("Anno: ") ;
scanf("%d", &a) ;

if ( a<=1900 || a>=2100 )
printf("Anno non valido\n") ;
} while(
while a<=1900 || a>=2100 ) ; 11
Funzione leggidata (3/5)

ok = 1 ;
if(
if g>30 && (m==4 || m==6 || date.c
m==9 || m==11) )
{
ok = 0 ;
printf("Il mese %d non "
"ha %d giorni\n", m, g);
}
else if ( g>29 && m==2 )
{
ok = 0 ;
printf("Il mese %d non "
"ha %d giorni\n", m, g);
}
12
Funzione leggidata (4/5)

date.c

else if ( g==29 && m==2 && a%4!=0 )


{
ok = 0 ;
printf("Il mese %d non "
"ha %d giorni perche' "
"l'anno %d non e' bisestile\n",
m, g, a);
}

13
Funzione leggidata (5/5)

date.c

} while(
while ok==0 ) ;

*giorno = g ;
*mese = m ;
*anno = a ;

return ;

} /* leggidata */

14
Esercizi proposti
Esercizio “Quadrato” (1/2)

Si scriva un programma, denominato quadrato,


che stampi a video un quadrato composto di
caratteri tutti uguali.
Il programma riceve due argomenti sulla linea di
comando:
Il primo argomento indica la dimensione del
quadrato (ossia il numero di righe e colonne di cui
è composto)
Il secondo argomento indica il carattere di cui è
composto il quadrato

16
Esercizio “Quadrato” (2/2)

Gli argomenti sono opzionali: se il carattere viene


omesso, occorre stampare “*”. Se anche la
dimensione viene omessa, si assuma pari a 3

17
Analisi

C:\progr>quadrato Quadrato 3x3 di “*”

C:\progr>quadrato 5 Quadrato 5x5 di “*”

C:\progr>quadrato 5 K Quadrato 5x5 di “K”


18
Dal punto di vista del main

argc==1
C:\progr>quadrato
argv[0]=="quadrato"

argc==2
C:\progr>quadrato 5 argv[0]=="quadrato"
argv[1]=="5"

argc==3
argv[0]=="quadrato"
C:\progr>quadrato 5 K
argv[1]=="5"
19
argv[2]=="K"
Soluzione (1/4)

int main(int
int argc, char *argv[]) quadrato.c
{
int dim ;
char ch ;
int i, j ;

if (argc==1)
{
dim = 3 ;
ch = '*' ;
}

20
Soluzione (2/4)

quadrato.c
else if (argc==2)
{
dim = atoi(argv[1]) ;
if(
if dim<1 || dim>20 )
{
printf("Dimens. non valida\n") ;
exit(1) ;
}
ch = '*' ;
}

21
Soluzione (3/4)

else if (argc==3)
{
dim = atoi(argv[1]) ; quadrato.c

if(
if dim<1 || dim>20 )
{
printf("Dimens. non valida\n");
exit(1) ;
}
ch = argv[2][0] ;
if(strlen(argv[2])!=1)
if
{
printf("Carattere non valido\n");
exit(1) ;
}
} 22
Soluzione (4/4)
else
{
printf("Numero argomenti " quadrato.c
"non valido\n") ;
exit(1) ;
}

for(i=0;
for i<dim; i++)
{
for(j=0;
for j<dim; j++)
putchar(ch) ;
putchar('\n') ;
}

exit(0) ;
} 23
Esercizi proposti
Esercizio “Indovina numero”

Si realizzi un programma in C per permettere a


due giocatori umani di giocare ad “indovina il
numero”
Il primo giocatore attiva il programma,
denominato segreto, passandogli sulla linea di
comando un numero intero tra 1 e 100
Il secondo giocatore farà una serie di tentativi,
immettendoli via tastiera
Ad ogni tentativo il programma dirà se il numero
tentato è più alto o più basso del numero da
indovinare
25
Soluzione (1/3)

int main(int
int argc, char *argv[])
{ segreto.c
int segreto ;
int cont, tent ;

/* Acquisisci dalla linea


di comando il numero "segreto" */
if(
if argc != 2 )
{
printf("Numero di parametri "
"errato\n") ;
exit(1) ;
}
26
Soluzione (2/3)

segreto = atoi( argv[1] ) ; segreto.c

if(
if segreto<1 || segreto>100 )
{
printf("Numero segreto "
"errato\n") ;
exit(1) ;
}

printf("INDOVINA IL NUMERO\n\n");

27
Soluzione (3/3)
cont = 1 ;
do {
printf("Tentativo %d: ", cont );
scanf("%d", &tent) ; segreto.c

if(
if tent < segreto )
printf("Basso...\n") ;
else if (tent > segreto )
printf("Alto...\n") ;

cont++ ;
} while (tent != segreto) ;
cont-- ;

printf("Indovinato: %d tentativi\n",
cont) ; 28
Funzioni
Argomenti trattati

Definizione di funzioni in C
Prototipo
Implementazione
Passaggio di parametri alle funzioni
By value
By reference
Vettori
Interfaccia del main
Parametri sulla linea di comando
Valore di ritorno
2
Tecniche di programmazione

Decomporre il programma in più funzioni,


implementando ciascuna individualmente
Identificare le parti ripetitive e racchiuderle in
apposite funzioni
Permette il passaggio di parametri al programma
Analizzare i parametri passati dall’utente

3
Materiale aggiuntivo

Sul CD-ROM
Testi e soluzioni degli esercizi trattati nei lucidi
Scheda sintetica
Esercizi risolti
Esercizi proposti
Esercizi proposti da altri libri di testo

4
Programmazione in C
I/O Avanzato e File

Definizione di file
File di testo in C
Input robusto
Formattazione avanzata
Esercizi proposti
Sommario

2
Riferimenti al materiale

Testi
Kernighan & Ritchie: capitolo 7, appendice B
Cabodi, Quer, Sonza Reorda: capitoli 3, 8
Dietel & Dietel: capitoli 9, 11
Dispense
Scheda: “I/O Avanzato in C”
Scheda: “Gestione dei file in C”

3
I/O Avanzato e File
Definizione di file

Directory e file
File binari e file di testo

5
Definizione di file
Directory e file

Tutti i sistemi operativi permettono di organizzare


le informazioni su hard disk secondo la metafora
di cartelle (directory) e file

Cartelle File

7
Definizioni

File:
Una sequenza di byte
Memorizzata su un disco
Caratterizzata da uno specifico nome
Contenuta all’interno di una specifica directory
Directory:
Un contenitore di file e di altre directory
Caratterizzata da uno specifico nome
Contenuta all’interno di un’altra directory

8
Identificazione di un file

Per identificare un file occorre dunque conoscere:


Il nome assegnato al file
Il nome della directory in cui esso è memorizzato
Una volta identificato un file, è possibile accedere
al suo contenuto
Leggere la sequenza di byte di cui è composto
Modificare la sequenza di byte di cui è composto

01001001010010010101
10100100010100010101
10100101001100101010
00101101001010001010

[Link]
C:\prog 9
Operazioni permesse sui file

Operazioni generiche
Cancellazione di un file esistente
Rinominazione di un file esistente
Copia di un file, creando un nuovo file con lo
stesso nome in una diversa directory
Spostamento di un file, equivalente alla copia con
cancellazione dell’originale
Operazioni specifiche
Creazione di un nuovo file
Modifica del contenuto del file

10
Operazioni generiche o specifiche

Le operazioni generiche sono solitamente svolte


interagendo con il sistema operativo, e si
possono applicare a qualsiasi file
Le operazioni specifiche invece coinvolgono il
contenuto del file, pertanto richiedono programmi
specifici per ogni tipologia di file

11
File = Sequenza di byte

12
Tipi di file

Il significato dei byte memorizzati all’interno dei


file è noto, solitamente, solamente al programma
che lo ha creato
Si parla di tipi di file, che sono solitamente
indicati dall’estensione (ultime lettere del nome
del file)
File prodotto da Microsoft Powerpoint → .ppt
File prodotto da Microsoft Word → .doc
File prodotto da [Link] Writer → .odt
...

13
Conseguenza

Non è possibile lavorare con file gestiti da altri


programmi, a meno di non conoscere il formato
del file
Eccezione: se il formato del file è pubblicamente
documentato, allora sarà possibile leggerlo e
scriverlo interpretando correttamente i byte
Esempio: file di testo (ASCII)
La codifica ASCII è utilizzata in molti campi: testi
(.txt), programmi in C (.c), pagine HTML (.html), ...
Esempio: file Acrobat (.pdf)
Struttura molto complessa, ma documentata
14
Definizione di file
Vista d’insieme dei formati di file

File

File binario File ASCII

Formato Formato Testo Testo Linguaggio


“proprietario” “standard” puro formattato formale

.doc .pdf .txt .html .c

.psd .zip .csv .xml

.xls .jpeg .rtf .java

16
Differenze operative

A livello di programmazione, esistono


Funzioni generali per accedere ai file
Funzioni specifiche per la lettura e la scrittura del
contenuto di file binari
Funzioni specifiche per la lettura e la scrittura del
contenuto di file ASCII
Il corretto funzionamento di un programma
dipende dalla perfetta conoscenza del formato
del file stesso

17
Scelta operativa

In questo corso si tratteranno esclusivamente i


file ASCII
Più semplici da comprendere
Facili da visualizzare e da creare con qualsiasi
editor di testi
Notepad o molte sue alternative
L’ambiente di sviluppo in C
Si userà indifferentemente la denominazione “file
ASCII” o “file di testo”

18
File di “testo puro”

19
File di “testo puro”

• Serie di più righe


• Ciascuna riga ha un
numero variabile di
caratteri
• Solitamente contengono del
testo “libero” (ad es., in
italiano)
• Concetti di: carattere,
parola, frase, riga
20
File di “testo formattato” (es: XML)

21
File di “testo formattato” (es: XML)

• Linguaggio di
programmazione basato su
“tag”
• Possibile “annidamento” dei
tag
• Complesso da analizzare,
richiede strutture dati
avanzate

22
File di “testo formattato” (es: CSV)

23
File di “testo formattato” (es: CSV)

• Ogni riga è un dato


• Ogni dato è rappresentato
da più campi
• I campi sono separati da un
carattere specifico (, o ;)
• I campi possono essere
numerici o testuali
• Ragionevolmente semplice
da analizzare, modificare e
creare
24
File di “testo formattato” (custom)

25
File di “testo formattato” (custom)

• Formato “inventato” ad hoc


per ciascun programma
specifico
• Versione semplificata del
CSV, dove il separatore è lo
spazio e non vi sono
virgolette delimitatrici
• È il più semplice da gestire

26
I/O Avanzato e File
File di testo in C

Accesso ai file
Funzioni fopen/fclose
Funzioni fget*/fput*
Funzioni fprintf/fscanf
Condizione feof

2
File di testo in C
Accesso ai file (1/4)

Un programma C può accedere ad alcuni file


presenti sui dischi del calcolatore
File aperto: file al quale attualmente il programma
ha accesso
File chiuso: file residente su disco al quale
attualmente il programma non ha accesso

4
Accesso ai file (2/4)

All’atto dell’apertura di un file, il programma deve


dichiarare la modalità di accesso
Modalità di lettura: il programma può leggere il
contenuto del file, ma non modificarlo
Modalità di scrittura: il programma può riscrivere
da zero il contenuto del file
Modalità di aggiunta: il programma può
aggiungere nuove informazioni al file
Modalità di lettura/scrittura: tutte le precedenti
I successivi accessi al file devono essere
compatibili con la modalità di accesso dichiarata
5
Accesso ai file (3/4)

L’accesso ai file di testo è rigorosamente


sequenziale
La lettura avviene dalla prima riga all’ultima, dal
primo carattere all’ultimo
In scrittura, ogni riga o carattere scritto vengono
posizionati dopo le righe o caratteri scritti in
precedenza
A partire dal primo carattere, in modalità di scrittura
A partire dall’ultimo carattere esistente, in modalità
di aggiunta

6
Accesso ai file (4/4)

All’atto dell’apertura di un file, il programma deve


dichiarare se il file è di tipo binario oppure di
testo
La differenza consiste solamente nel trattamento
“speciale” del carattere '\n' nel caso dei file di
testo
In questo corso useremo sempre la modalità
testuale

7
Stream associato ad un file

In un programma C, esiste un tipo di dato


specifico per rappresentare le informazioni
relative ad un file aperto
Denominato: file stream (flusso associato ad un
file)
Tipo di dato: FILE * (definito in <stdio.h>)
“Aprire” un file significa quindi creare un nuovo
stream ed associarlo ad uno specifico file sul
disco

8
Significato di stream

Una volta che il file è aperto, il suo stream


rappresenta
Un “collegamento” mediante il quale poter
compiere delle operazioni sul contenuto del file
Le modalità di accesso scelte (testo/binario,
lettura/scrittura/...)
La posizione attuale a cui si è arrivati nello scrivere
o nel leggere il file
Ogni operazione sul file avviene chiamando una
funzione che riceve lo stream come parametro

9
Stati di un file
Directory
Nome file

File chiuso

Risiede su disco,
il programma
non ha accesso
al suo contenuto

10
Stati di un file
Directory Apertura del file Stream
Nome file Posizione attuale
Lettura / Scrittura
Testo / Binario
File aperto
File chiuso
Risiede su disco,
Risiede su disco, il programma ha
il programma accesso al suo
non ha accesso contenuto
al suo contenuto attraverso lo
stream associato

11
Stati di un file
Directory Apertura del file Stream
Nome file Posizione attuale
Lettura / Scrittura
Testo / Binario
File aperto
File chiuso
Risiede su disco,
Risiede su disco, il programma ha
il programma accesso al suo
non ha accesso contenuto
al suo contenuto attraverso lo
stream associato
Chiusura del file

12
Lettura di un file
Apertura del file

File aperto in
lettura

Posizione iniziale
(primo carattere)

13
Lettura di un file
Apertura del file Leggi riga /
Leggi carattere

File aperto in File aperto in


lettura lettura

Posizione iniziale Posizione intermedia


(primo carattere) (n-esimo carattere)

14
Lettura di un file
Apertura del file Leggi riga /
Leggi carattere

File aperto in File aperto in


lettura lettura

Posizione iniziale Posizione intermedia


(primo carattere) (n-esimo carattere)

15
Lettura di un file
Apertura del file Leggi riga /
Leggi carattere

File aperto in File aperto in


lettura lettura

Posizione iniziale Posizione intermedia


(primo carattere) (n-esimo carattere)

Condizione
File aperto in
end-of-file lettura
Leggi riga /
Posizione finale Leggi carattere
Chiusura del file (ultimo carattere) 16
Scrittura di un file
Apertura del file

File aperto in
scrittura

Posizione iniziale
(primo carattere)

17
Scrittura di un file
Apertura del file Scrivi riga /
Scrivi carattere

File aperto in
scrittura

Posizione iniziale
(primo carattere) File aperto in
scrittura

Posizione intermedia
(n-esimo carattere)

18
Scrittura di un file
Apertura del file Scrivi riga /
Scrivi carattere

File aperto in Scrivi riga /


Scrivi carattere
scrittura

Posizione iniziale
(primo carattere) File aperto in
scrittura

Posizione intermedia
(n-esimo carattere)

19
Scrittura di un file
Apertura del file Scrivi riga /
Scrivi carattere

File aperto in Scrivi riga /


Scrivi carattere
scrittura

Posizione iniziale
(primo carattere) File aperto in
scrittura

La posizione intermedia Posizione intermedia


diviene posizione finale (n-esimo carattere)

Chiusura del file 20


Aggiunta ad un file
Apertura del file Scrivi riga /
Scrivi carattere

File aperto in Scrivi riga /


Scrivi carattere
aggiunta

Posizione finale
File aperto in
(ultimo carattere)
aggiunta

Posizione intermedia
La posizione intermedia (n-esimo carattere
diviene posizione finale dopo l’ultimo)

Chiusura del file 21


Funzioni C

Tutte le funzioni per l’accesso ai file sono


contenute in <stdio.h>
Funzioni per apertura e chiusura: fopen,
fclose
Funzioni per la lettura: fgetc, fgets, fscanf
Funzioni per la scrittura: fputc, fputs,
fprintf
Funzioni per lo stato del file: feof

22
File di testo in C
Funzioni fopen e fclose

Apertura del file (fopen):


La funzione fopen apre un file e restituisce una
variabile stream
Richiede il nome del file e le modalità di apertura
Restituisce una nuova variabile di tipo FILE *
Chiusura del file (fclose)
Quando il file non è più richiesto, si chiama la
funzione fclose che chiude il file
Richiede come parametro lo stream,
precedentemente restituito da fopen

24
fopen:
fopen sintassi

Variabile stream
di tipo FILE *
FILE * f ;

...

f = fopen( "nomefile", "modo" ) ;

Stringa Modalità di
contenente il apertura
nome del file (stringa) 25
Nome del file

f = fopen( "nomefile", "modo" ) ;

f = fopen( "[Link]", "modo" ) ;

26
Nome del file

f = fopen( "nomefile", "modo" ) ;

f = fopen( "[Link]", "modo" ) ;

f = fopen( "c:\\prog\\[Link]",
"modo" ) ;

27
Nome del file

f = fopen( "nomefile", "modo" ) ;

f = fopen( "[Link]", "modo" ) ;

f = fopen( "c:\\prog\\[Link]",
"modo" ) ;
char nome[20] ;
gets(nome) ;
f = fopen( nome, "modo" ) ;

28
Nome del file

f = fopen( "nomefile", "modo" ) ;

f = fopen( "[Link]", "modo" ) ;

f = fopen( "c:\\prog\\[Link]",
"modo" ) ;
char nome[20] ;
gets(nome) ;
f = fopen( nome, "modo" ) ;

f = fopen( argv[1], "modo" ) ; 29


Modo di apertura

f = fopen( "nomefile", "modo" ) ;

Modalità lettura, file di testo "rt" "r"

Modalità scrittura, file di testo "wt" "w"

Modalità aggiunta, file di testo "at" "a"

30
Effetto della fopen (1/3)

Modalità "r"
Se il file esiste, viene aperto ed f punta allo
stream relativo, posizionato in lettura al primo
carattere
Se il file non esiste, non viene creato nessuno
stream e f==NULL

31
Effetto della fopen (2/3)

Modalità "w"
Se il file non esiste, viene creato da zero ed f
punta allo stream relativo, posizionato in scrittura
al primo carattere
Se il file esiste già, viene innanzitutto cancellato e
poi ricreato da zero, f punta allo stream relativo,
posizionato in scrittura al primo carattere
Se non è possibile creare il file (perché la directory
non esiste, o il disco è protetto in scrittura, ...),
non viene creato nessuno stream e f==NULL

32
Effetto della fopen (3/3)

Modalità "a"
Se il file non esiste, viene creato da zero ed f
punta allo stream relativo, posizionato in scrittura
al primo carattere
Se il file esiste già, non viene modificato, f punta
allo stream relativo, posizionato in scrittura dopo
l’ultimo carattere
Se non è possibile creare o modificare il file
(perché la directory non esiste, o il disco è protetto
in scrittura, ...), non viene creato nessuno stream
e f==NULL

33
Controllo dell’errore

FILE * f ;

...

f = fopen( "nomefile", "r" ) ;


if(
if f == NULL )
{
printf("Impossibile aprire file\n");
exit(1) ;
}

34
Suggerimento

Ogniqualvolta viene chiamata la funzione fopen,


è indispensabile subito dopo controllare se il
valore ritornato non è NULL
È da considerarsi errore una chiamata ad fopen
di cui non venga controllato il risultato
In caso di errore, solitamente conviene
interrompere il programma segnalando un codice
di errore
Esempio: exit(1) ;

35
fclose:
fclose sintassi

FILE * f ;
...
f = fopen( "nomefile", "modo" ) ;

.../* accesso al file */

fclose(f) ;

Variabile
stream
36
Avvertenze

La funzione fclose può essere chiamata


solamente su stream correttamente aperti
Mai chiamare fclose se f==NULL
Dopo la chiusura del file, non è più possibile
accedere allo stream
Eventualmente, ri-aprirlo nuovamente

37
Controllo dell’errore

La funzione fclose ritorna un valore di tipo intero:


int ris ;
0, se la chiusura è avvenuta con successo
...
EOF, se la chiusura non è stata possibile (ad
ris esempio, disco pieno
= fclose(f) ; o rimosso)
if(ris!=0)
if
{
printf("Impossibile chiudere\n") ;
exit(1) ;
}

38
Suggerimento

Conviene definire due funzioni aggiuntive, che


chiamino le funzioni di libreria fopen e fclose
e addizionalmente compiano i controlli d’errore
Chiameremo myfopen e myfclose tali funzioni
Nei programmi chiameremo sempre myfopen e
myfclose, e mai direttamente le funzioni di
libreria

39
Funzione myfopen

FILE * myfopen(char
char *name, char *mode)
{
FILE * f ;

f = fopen( name, mode ) ; my.c

if (f==NULL)
{ printf("Impossibile aprire %s\n",
name) ;
exit(1) ;
}
return f ;
}
40
Funzione myfclose

int myfclose(FILE *f)


{ int ris ;
my.c

if (f==NULL)
{ printf("ERRORE INTERNO\n") ;
exit(1) ;
}
ris = fclose(f) ;
if(
if ris!=0 )
{ printf("Impossibile chiudere\n") ;
exit(1) ;
}
return ris ;
} 41
File di testo in C
Lettura e scrittura su file

Lettura Scrittura
Carattere singolo fgetc fputc
Riga intera fgets fputs

43
Lettura e scrittura su file

Lettura Scrittura
Carattere singolo fgetc fputc
Riga intera fgets fputs

Legge prossimo
elemento, fino
alla fine del file
Scrive o
aggiunge 44
Lettura e scrittura su file

Lettura Scrittura
Carattere singolo fgetc fputc
Riga intera fgets fputs

Parametro:
char
Parametro: Legge prossimo
stringa elemento, fino
alla fine del file
Scrive o
aggiunge 45
fgetc:
fgetc sintassi

int ch ;

ch = fgetc(f) ;

Stream aperto
in lettura

Prossimo carattere del file;


EOF se il file è finito
46
fputc:
fputc sintassi

int ch ;

fputc(ch, f) ;

Stream aperto in
scrittura o in aggiunta

Carattere da
aggiungere al file
47
fgets:
fgets sintassi

char str[80] ;

fgets(str, 79, f) ;

Max numero di
caratteri letti

Stringa nella quale viene Stream aperto


letta la prossima riga del file in lettura
(fino al \n compreso) 48
Fine del file

La funzione fgets restituisce un valore NULL se


ha tentato di leggere oltre la fine del file

char str[80] ;

While(
While fgets(str, 79, f) != NULL )
{
/* elabora str */
}

49
fputs:
fputs sintassi

char str[80] ;

fputs(str, f) ;

Stream aperto in
scrittura o in aggiunta

Stringa da aggiungere al file


(solitamente termina con \n)
50
Esercizio: “Frequenza lettere”

Sia dato un file di testo, contenente dei brani


scritti da un utente
Si scriva un programma in C che acquisisca sulla
linea di comando il nome di tale file, e che stampi
le frequenze con cui compaiono le varie lettere
dell’alfabeto
Si considerino equivalenti le maiuscole e le
minuscole, e si ignorino i caratteri di spaziatura e
punteggiatura

51
Analisi (1/2)

[Link]

Quel ramo del lago di Como,


che volge a mezzogiorno,
tra due catene non interrotte di monti,
tutto a seni e a golfi,
a seconda dello sporgere e del
rientrare di quelli, vien, quasi
a un tratto, a ristringersi, e a
prender corso e figura di fiume,
tra un promontorio a destra,
e un'ampia costiera dall'altra parte

52
Analisi (2/2)
[Link]
Quel ramo del lago di Como,
che volge a mezzogiorno,
tra due catene non interrotte di monti,
tutto a seni e a golfi,
a seconda dello sporgere e del
C:\prog>frequenza [Link] rientrare di quelli, vien, quasi
a un tratto, a ristringersi, e a
A : 26 prender corso e figura di fiume,
tra un promontorio a destra,

B : 0 e un'ampia costiera dall'altra parte

C : 6
D : 12
E : 32
F : 3
G : 7
H : 1
I : 21
J : 0
K : 0
L : 13 53
Soluzioni possibili

Occorre calcolare un vettore di frequenze, in cui


ciascuna posizione rappresenti la frequenza di
ciascuna delle lettere alfabetiche
Ci sono due approcci possibili alla lettura del file:
Soluzione per caratteri: il file viene letto un
carattere alla volta, usando la funzione fgetc
Soluzione per righe: il file viene letto una riga alla
volta, usando la funzione fgets, e tale riga viene
poi esaminata con un ciclo interno al programma

54
Soluzione 1: per caratteri (1/3)

const int LETT = 26 ;


int freq[LETT] ; /* frequenze lettere */

FILE * f ;
int ch, i ;

if (argc!=2)
{
printf("Numero argomenti errato\n") ;
exit(1) ;
}

for(i=0;
for i<LETT; i++)
freq[i] = 0 ; 55
frequenza.c
Soluzione 1: per caratteri (2/3)

f = myfopen( argv[1], "r" ) ;

ch = fgetc( f ) ;
while(
while ch!=EOF )
{
if(isalpha(ch))
if
{
i = toupper(ch)-'A' ;
/* posizione 0..25 della lettera */
freq[i]++ ;
}
ch = fgetc( f ) ;
}
myfclose( f ) ; 56
frequenza.c
Soluzione 1: per caratteri (3/3)

for(i=0;
for i<LETT; i++)
{
printf("%c : %d\n", i+'A', freq[i]) ;
}

exit(0) ;

57
frequenza.c
Soluzione 2: per righe

const int LUN = 200 ;


char riga[LUN+1];
...

while(
while fgets( riga, LUN, f ) != NULL )
{
for(i=0;
for riga[i]!=0; i++)
{
if(isalpha(riga[i]))
if
{
freq[toupper(riga[i])-'A']++ ;
}
}
} 58
frequenza.c
Esercizio: “Triangolo alfabetico”

Si realizzi un programma in C che crei un file di


testo contenente tutte le lettere dell’alfabeto, con
una disposizione “a triangolo”
La prima riga contiene una volta la lettera A
La seconda riga contiene 2 volte la lettera B
La terza riga contiene 3 volte la lettera C
...
Il nome del file viene passato come primo
argomento sulla linea di comando

59
Analisi

c:\prog>triangolo [Link]

60
Soluzione (1/2)

FILE * f ;
triangolo.c
int i, j ;
char ch ;

if (argc!=2)
{
printf("Numero argomenti errato\n") ;
exit(1) ;
}

f = myfopen( argv[1], "w" ) ;

61
Soluzione (2/2)

for(i=0;
for i<26; i++)
{
triangolo.c
ch = i+'A' ;

for(j=0;
for j<=i; j++)
fputc( ch, f ) ;

fputc( '\n', f ) ;
}

myfclose( f ) ;

exit(0) ;
62
File di testo in C
Output formattato

Qualora sia necessario creare file con più campi


nella stessa riga, è scomodo ricorrere alle
funzioni fputc/fputs
È possibile utilizzare una variante della funzione
printf, operante su uno stream aperto in
scrittura
fprintf(f, "formato", x, y, z) ;

64
fprintf:
fprintf sintassi

FILE * f ;

fprintf(f, "formato", variabili ) ;

Stream aperto in
scrittura o in aggiunta Elenco delle
variabili da scrivere

Formato dei dati da stampare,


usando gli stessi specificatori
validi per printf 65
Input formattato

Qualora sia necessario leggere file con più campi


nella stessa riga
È scomodo ricorrere alla funzione fgetc
Il risultato della funzione fgets deve
successivamente essere analizzato
È possibile utilizzare una variante della funzione
scanf, operante su uno stream aperto in lettura
fscanf(f, "formato", &x, &y, &z) ;

66
fscanf:
fscanf sintassi

FILE * f ;

fscanf(f, "formato", &variabili ) ;

Stream aperto
in lettura Puntatori alle
variabili da leggere

Formato dei dati da leggere,


usando gli stessi specificatori
validi per scanf 67
fscanf:
fscanf una funzione pericolosa

Nonostante la funzione fscanf sia prevista dalla


libreria standard C, è considerata una funzione
pericolosa nella lettura di file in generale
In particolare, qualora il file non sia nel formato
corretto (file contenente errori), allora il
meccanismo di funzionamento di fscanf rende
impossibile acquisire i dati in modo affidabile
Suggerimento: non usare mai fscanf
Nella prossima lezione vedremo una soluzione
robusta al problema

68
File di testo in C
End-of-File

Un file aperto in lettura è inizialmente posizionato


al primo carattere
Ad ogni successiva lettura, avanza la posizione
corrente all’interno del file
Quando è stato letto l’ultimo carattere (o l’ultima
riga) del file, non sono possibili ulteriori letture
In questo caso si dice che si è verificata una
condizione di End-of-File (EOF)
Ulteriori tentativi di lettura genererebbero una
condizione di errore

70
Tentativi di lettura

Se si tenta di leggere oltre l’End-of-File


fgets restituisce NULL
fgetc restituisce EOF
fscanf restituisce EOF
È possibile controllare tali valori di ritorno per
controllare la fine del file
In tali casi, l’errore è già avvenuto, e l’operazione
di lettura non è andata a buon fine

71
Funzione feof

La funzione feof è specificatamente utile per


verificare se uno stream f è già nella condizione
di End-of-File prima di tentare operazioni di
lettura
if ( !feof( f ) ) { ... }
La funzione, partendo dallo stream f, restituisce:
Vero, se lo stream è già in End-of-File, e quindi le
successive letture falliranno
Falso, se lo stream non è ancora in End-of-File, e
quindi sono possibili ulteriori letture

72
Esempio

ch = fgetc( f ) ;
while(
while !feof(f) )
while(
while ch!=EOF ) {
{ ch = fgetc( f ) ;
.../* elabora ch */
.../* elabora ch */
ch = fgetc( f ) ; }
}

73
I/O Avanzato e File
Input robusto

Problemi nella lettura da file


Soluzione basata su fgetc
Funzione sscanf
Soluzione basata su fgets

2
Input robusto
Lettura da file

I file di testo contengono dati secondo un certo


formato
È semplice scrivere un programma in grado di
leggere un file formattato correttamente
Diviene molto complesso gestire eventuali errori
di formato del file

4
Errori di formato

Righe contenenti un numero errato di elementi


Elementi in eccesso
In fondo
All’inizio o in mezzo
Elementi in difetto
Tipi di dato errati
Caratteri, stringhe, interi, reali
Errori di coerenza interna

5
Esempio

Un file di testo contiene i PIN dei bancomat dei


membri di una famiglia
Il file di testo contiene sulla prima riga il numero
di bancomat descritti nel file
Le righe successive contengono le informazioni
su ciascun bancomat, uno per riga
Ciascuna riga contiene 3 campi separati da spazi:
Il nome del proprietario del bancomat
Il numero del bancomat
Il PIN segreto (5 cifre)

6
Esempio di file corretto

[Link]

3
Aldo 123456789 12762
Giovanni 334422445 97864
Giacomo 887868083 32552

7
Definizioni

const char nomefile[] = "[Link]" ;


const int MAX = 20 ;
/* numero max di bancomat */
const int LUN = 15 ;
/* lunghezza del nome */

int N ;
char nome[MAX][LUN+1] ;
int numero[MAX] ;
int pin[MAX] ;

FILE * f ;
int i ;
banco-bad.c
8
Lettura del file (solo se corretto)

f = myfopen(nomefile, "r") ;

fscanf(f, "%d", &N) ;

for(i=0;
for i<N; i++)
{
fscanf(f, "%s %d %d",
nome[i], &numero[i], &pin[i]) ;
}

myfclose(f) ;
banco-bad.c
9
Possibili errori nel file (1/3)

3 Campo mancante
Aldo 123456789 12762
334422445 97864
Giacomo 887868083 32552

10
Possibili errori nel file (1/3)

3 Campo mancante
Aldo 123456789 12762
334422445 97864
Giacomo 887868083 32552

3 Campo extra nella


Aldo 3212 123456789 12762
riga
Giovanni 334422445 97864
Giacomo 887868083 32552

11
Possibili errori nel file (2/3)

3 Campo extra a
Aldo 123456789 12762 3212 fine riga
Giovanni 334422445 97864
Giacomo 887868083 32552

12
Possibili errori nel file (2/3)

3 Campo extra a
Aldo 123456789 12762 3212 fine riga
Giovanni 334422445 97864
Giacomo 887868083 32552

3 Tipi di dato errati


Aldo 123456789 12762
Giovanni 334422445 97864
Giacomo A32Z4324 32552

13
Possibili errori nel file (3/3)

3 Spazi
Pier Aldo 123456789 12762
Giovanni 334422445 97864
Giacomo 887868083 32552

14
Possibili errori nel file (3/3)

3 Spazi
Pier Aldo 123456789 12762
Giovanni 334422445 97864
Giacomo 887868083 32552

3 Incoerenza
Aldo 123456789 12762 interna
Giacomo 887868083 32552

15
Osservazioni

Di fronte a qualsiasi errore di formato, la


funzione fscanf
Perde il “sincronismo” con le righe del file
“Blocca” la lettura in caso di stringhe incontrate
quando si aspettava un numero
Non si “accorge” dell’End-of-File
La funzione fscanf non è sufficientemente
robusta per gestire la lettura da file di testo

16
Input robusto
Lettura basata su fgetc

Dovendo evitare l’utilizzo della funzione fscanf,


si potrebbe optare per la funzione fgetc
L’adozione di fgetc risolve i problemi di
sincronizzazione e di lettura dei dati errati, ma
introduce spesso una complessità eccessiva nel
programma

18
Soluzioni basate su fgetc (1/4)

Acquisizione di una stringa

char s[MAX] ;

i = 0 ;
ch = fgetc(f) ;
while(
while ch != EOF && ch != '\n'
&& ch != ' ' && i < MAX-1 )
{
s[i] = ch ;
i++ ;
ch = fgetc(f) ;
}

s[i] = 0 ; /* terminatore nullo */ 19


Soluzioni basate su fgetc (2/4)

Saltare tutti gli spazi (ma non gli a-capo)

ch = fgetc(f) ;
while(
while ch != EOF && ch != '\n' &&
ch == ' ' )
{
ch = fgetc(f) ;
}

20
Soluzioni basate su fgetc (3/4)

Acquisizione di un intero positivo


char s[MAX] ;

i = 0 ;
ch = fgetc(f) ;
while(
while ch != EOF && isdigit(ch)
&& i < MAX-1 )
{
s[i] = ch ;
i++ ;
ch = fgetc(f) ;
}
s[i] = 0 ; /* terminatore nullo */
21
x = atoi(s) ; /* converti in int */
Soluzioni basate su fgetc (4/4)

Sono possibili tutti i controlli personalizzati, su


Lunghezza minima e massima dei campi
Tipo di caratteri permessi
Alcuni tipi di dati sono complessi da acquisire
Intero relativo: -124
Numero reale: -3.14e+21
Soluzione in generale completa, ma molto lavoro
manuale
Rischio: dimenticare alcuni casi particolari

22
Suggerimento

Utilizzare la funzione fgetc quando occorre


leggere dei testi in “formato libero”
Esempio: statistiche sul testo
Esempio: file di una sola riga
Per file in formato custom, contenenti campi
prefissati e/o di tipo numerico, occorre una
soluzione più comoda

23
Input robusto
Funzione sscanf

La risposta a molti dei problemi sollevati viene da


una nuova funzione di libreria: sscanf
Tale funzione si può usare per analizzare il
contenuto di una stringa, estraendone vari campi
e memorizzandoli in variabili distinte
Ha tutta la funzionalità di scanf e fscanf, ma
lavora soltanto all’interno dei caratteri contenuti
in una stringa
Potente e sicura

25
sscanf:
sscanf sintassi

char str[80] ;

sscanf(str, "formato", &variabili ) ;

Stringa di
caratteri Puntatori alle
variabili da leggere

Formato dei dati da leggere,


usando gli stessi specificatori
validi per scanf 26
Esempio

char str[80] ;
char nome[80] ;
int numero, pin ;

strcpy(str, "Aldo 91243213 1234\n");

sscanf(str, "%s %d %d",


nome, &numero, &pin ) ;

27
Gestione degli errori

La funzione sscanf non potrà mai leggere le


righe successive di un file, in quanto la sua
visibilità è confinata alla stringa passata
Gli eventuali campi in eccesso a fine riga
vengono quindi ignorati automaticamente
Gli eventuali campi mancanti o di formato errato
causano il mancato riconoscimento di quelli
successivi
Condizione di errore facile da verificare
analizzando il valore di ritorno di sscanf

28
Valore di ritorno

La funzione sscanf restituisce al chiamante un


valore intero:
Il valore è pari al numero di argomenti
(specificatori %) correttamente riconosciuti e
memorizzati nelle rispettive variabili

r = sscanf(str, "%s %d %d",


nome, &numero, &pin ) ;

29
Esempio

char str[80] ;
char nome[80] ;
int numero, pin ;
int r ;

strcpy(str, "Aldo 91243213 1234\n");

r = sscanf(str, "%s %d %d",


nome, &numero, &pin ) ;

if(
if r != 3 )
{ ... errore ... }
30
Suggerimenti

Utilizzare sempre sscanf per analizzare una


stringa
Controllare sempre il valore di ritorno
Non utilizzare più la funzione atoi, sostituirla
con sscanf(..."%d"...)
Per acquisire dati da tastiera, combinare con
gets
Per acquisire dati da file, combinare con fgets
Nella prossima lezione vedremo come “istruire”
sscanf a riconoscere formati più complessi
31
Input robusto
Input robusto da file di testo

Affidiamo diversi ruoli alle varie funzioni


fgets
Lettura del file riga per riga
Limite alla lunghezza max delle righe
Riconoscimento End-of-File
sscanf
Analisi dei campi presenti in una riga
Controllo della correttezza del formato
Trasferimento nelle variabili/vettori del programma

33
Schema consigliato

const int LUNRIGA = 200 ;


int r, nr ;
char riga[LUNRIGA+1] ;

f = myfopen(nomefile, "r") ;

/* Ciclo di lettura */

myfclose(f) ;

34
Ciclo di lettura

nr = 0 ;
while(
while fgets(riga, LUNRIGA, f)!=NULL )
{
r = sscanf(riga, "%s %d %d",
nome, &numero, &pin) ;
if( r == 3 )
{
...elabora la la
/* ...elabora riga...
riga... */
}
else
printf("Riga %d ignorata\n", nr+1);
nr++ ;
}
35
Soluzione corretta (1/6)

const char nomefile[]="[Link]";


const int MAX = 20 ;
const int LUN = 15 ;
const int LUNRIGA = 200 ;

int N ;
char nome[MAX][LUN+1] ;
int numero[MAX] ;
int pin[MAX] ;

FILE * f ;
int i, r, nr ;
char riga[LUNRIGA+1] ; banco-ok.c
36
Soluzione corretta (2/6)

f = myfopen(nomefile, "r") ;
if(fgets(riga,
if LUNRIGA, f)==NULL)
{
printf("Errore: file vuoto\n") ;
exit(1) ;
}
r = sscanf(riga, "%d", &N) ;
if(r!=1)
if
{
printf("Errore: La prima riga "
"non contiene il numero\n");
exit(1) ;
} banco-ok.c
37
Soluzione corretta (3/6)

if(
if N<1 || N>MAX )
{
printf("Errore: Num. bancomat "
"%d non valido\n", N) ;
printf("Valori ammessi: "
"da 1 a %d\n", MAX) ;
exit(1) ;
}

banco-ok.c
38
Soluzione corretta (4/6)

i = 0 ;
nr = 0 ;
while(
while fgets( riga, LUNRIGA, f )
!= NULL )
{
if(i==N)
if
{
printf("Errore: troppe "
"righe nel file\n" ) ;
exit(1) ;
}
banco-ok.c
39
Soluzione corretta (5/6)

r = sscanf(riga, "%s %d %d",


nome[i], &numero[i], &pin[i]);

if(
if r == 3 )
i++ ;
else
{
printf("Riga %d ignorata\n",
nr) ;
}
nr++ ;
}
banco-ok.c
40
Soluzione corretta (6/6)

if(
if i != N )
{
printf("Errore: poche righe "
" nel file\n" ) ;
exit(1) ;
}

myfclose(f) ;

banco-ok.c
41
Conclusioni

Prevedere tutti i possibili errori è difficile e


pesante
La maggior parte delle linee di codice è dedicata
alla gestione degli errori o delle anomalie
Gli strumenti offerti dalla “coppia” fgets +
sscanf sono validi ed efficaci

42
I/O Avanzato e File
Formattazione avanzata

Modificatori di formato in output


Modificatori di formato in input
Stream predefiniti

2
Formattazione avanzata
Formattazione dell’output

L’output (su schermo o su file) viene formattato


solitamente mediante la funzione printf (o
fprintf)
Ogni dato viene stampato attraverso un
opportuno specificatore di formato (codici %)
Ciascuno di questi codici dispone di ulteriori
opzioni per meglio controllare la formattazione
Stampa incolonnata
Numero di cifre decimali
Spazi di riempimento
...
4
Specificatori di formato

Tipo printf
char %c %d
int %d
short int %hd %d
long int %ld
unsigned int %u %o %x
unsigned short int %hu
unsigned long int %lu
float %f %e %g
double %f %e %g
char [] %s 5
Forma completa degli specificatori

-
precision
+
.
width *

% format

# *

6
Forma completa degli specificatori

-
precision
+
.
width *

% format

# *

Specificatore di
% obbligatorio formato
Modificatori obbligatorio
opzionali 7
Forma completa degli specificatori

-
precision
+
.
width *

% format

# *

Specificatori
già noti

8
Forma completa degli specificatori

-
precision
+
.
width *

% format

# *

0 Lunghezza totale:
numero minimo di
caratteri stampati

9
Esempi

Istruzione Risultato
printf("%d", 13) ; 13
printf("%1d", 13) ; 13
printf("%3d", 13) ; ּ13
printf("%f", 13.14) ; 13.140000
printf("%6f", 13.14) ; 13.140000
printf("%12f", 13.14) ; ּּּ13.140000
printf("%6s", "ciao") ; ּּciao

10
Forma completa degli specificatori

-
precision
+
.
width *

% format

# * Minimo numero di caratteri


%d totali (eventualmente
0 aggiunge 0 a sinistra)
Numero massimo di cifre
Precisione %f
dopo la virgola
(dipende...)
Massimo numero di
%s caratteri (stringhe più
11
lunghe vengono troncate)
Esempi (1/2)

Istruzione Risultato
printf("%.1d", 13) ; 13
printf("%.4d", 13) ; 0013
printf("%6.4d", 13) ; ּּ0013
printf("%4.6d", 13) ; 000013

printf("%.2s", "ciao") ; ci
printf("%.6s", "ciao") ; ciao
printf("%6.3s", "ciao") ; ּּּcia

12
Esempi (2/2)

Istruzione Risultato
printf("%.2f", 13.14) ; 13.14
printf("%.4f", 13.14) ; 13.1400
printf("%6.4f", 13.14) ; 13.1400
printf("%9.4f", 13.14) ; ּּ13.1400

13
Forma completa degli specificatori

-
precision
+
.
width *

% format

# * - Allinea a sinistra anziché a destra


Aggiungi il segno anche davanti ai
0 + numeri positivi
Aggiungi spazio davanti ai numeri
_ positivi
Riempimento e 0 Aggiungi 0 iniziali fino a width
allineamento
# Formato alternativo (dipende...) 14
Esempi (1/2)

Istruzione Risultato
printf("%6d", 13) ; ּּּּ13
printf("%-6d", 13) ; 13ּּּּ
printf("%06d", 13) ; 000013

printf("%6s", "ciao") ; ּּciao


printf("%-6s", "ciao") ; ciaoּּ

15
Esempi (2/2)

Istruzione Risultato
printf("%d", 13) ; 13
printf("%d", -13) ; -13
printf("%+d", 13) ; +13
printf("%+d", -13) ; -13
printf("% d", 13) ; ּ13
printf("% d", -13) ; -13

16
Formattazione avanzata
Approfondimenti su scanf

Tipologie di caratteri nella stringa di formato


Modificatori degli specificatori di formato
Valore di ritorno
Specificatore %[]

18
Stringa di formato (1/2)

Caratteri stampabili:
scanf si aspetta che tali caratteri compaiano
esattamente nell’input
Se no, interrompe la lettura
Spaziatura (“whitespace”):
Spazio, tab, a capo
scanf “salta” ogni (eventuale) sequenza di
caratteri di spaziatura
Si ferma al primo carattere non di spaziatura (o
End-of-File)

19
Stringa di formato (2/2)

Specificatori di formato (%-codice):


Se il codice non è %c, innanzitutto scanf “salta”
ogni eventuale sequenza di caratteri di spaziatura
scanf legge i caratteri successivi e cerca di
convertirli secondo il formato specificato
La lettura si interrompe al primo carattere che non
può essere interpretato come parte del campo

20
Specificatori di formato
Tipo scanf
char %c %[...]
int %d
short int %hd
long int %ld
unsigned int %u %o %x
unsigned short int %hu
unsigned long int %lu
float %f
double %lf
char [] %s %[...] 21
Forma completa degli specificatori

* width

% format

Specificatore di
Modificatori formato
% obbligatorio
opzionali obbligatorio

22
Forma completa degli specificatori

* width

% format

Specificatori
già noti
% obbligatorio

23
Forma completa degli specificatori

* width

% format

Numero massimo di
caratteri letti per questa
conversione

24
Esempi

Istruzione Input Risultato


scanf("%d", &x) ; 134xyz x = 134
scanf("%2d", &x) ; 134xyz x = 13
scanf("%s", v) ; 134xyz v = "134xyz"
scanf("%2s", v) ; 134xyz v = "13"

25
Forma completa degli specificatori

* width

% format

Leggi questo campo,


ma non memorizzarlo
in alcuna variabile

26
Esempi

Istruzione Input Risultato


scanf("%d %s", &x, v) ; 10 Pippo x = 10
v = "Pippo"
scanf("%s", v) ; 10 Pippo x immutato
v = "10"
scanf("%*d %s", v) ; 10 Pippo x immutato
v = "Pippo"

27
Valore di ritorno

La funzione scanf ritorna un valore intero:


Numero di elementi (%) effettivamente letti
Non conta quelli “saltati” con %*
Non conta quelli non letti perché l’input non
conteneva i caratteri desiderati
Non conta quelli non letti perché l’input è finito
troppo presto
End-of-File per fscanf
Fine stringa per sscanf
EOF se l’input era già in condizione End-of-File
all’inizio della lettura

28
Lettura di stringhe

La lettura di stringhe avviene solitamente con lo


specificatore di formato %s
Salta tutti i caratteri di spaziatura
Acquisisci tutti i caratteri seguenti, fermandosi al
primo carattere di spaziatura (senza leggerlo)
Qualora l’input dei separatori diversi da spazio, è
possibile istruire scanf su quali siano i caratteri
leciti, mediante lo specificatore %[pattern]

29
Struttura di un pattern

^ - carattere

% [ carattere ]

30
Struttura di un pattern

^ - carattere

% [ carattere ]

Definizione di pattern
nella stringa di formato
31
Struttura di un pattern

^ - carattere

% [ carattere ]

Carattere di cui può


essere composta la
stringa da leggere
32
Esempi

Pattern Effetto
%[r] Legge solo sequenze di 'r'

33
Struttura di un pattern

^ - carattere

% [ carattere ]

Caratteri o intervalli
possono essere
ripetuti più volte
34
Esempi

Pattern Effetto
%[r] Legge solo sequenze di 'r'
%[abcABC] Legge sequenze composte da a, b, c, A, B,
C, in qualsiasi ordine e di qualsiasi
lunghezza

35
Struttura di un pattern

^ - carattere

% [ carattere ]

Intervallo di caratteri di
cui può essere composta
la stringa da leggere 36
Esempi

Pattern Effetto
%[r] Legge solo sequenze di 'r'
%[abcABC] Legge sequenze composte da a, b, c, A, B,
C, in qualsiasi ordine e di qualsiasi
lunghezza
%[a-cA-C] Idem come sopra
%[a-zA-Z] Sequenze di lettere alfabetiche
%[0-9] Sequenze di cifre numeriche
%[a-zA-Z0-9] Sequenze alfanumeriche

37
Struttura di un pattern

^ - carattere

% [ carattere ]

Pattern “invertito”: i caratteri


specificati non devono
comparire nella stringa

38
Esempi
Pattern Effetto
%[r] Legge solo sequenze di 'r'
%[abcABC] Legge sequenze composte da a, b, c, A, B,
C, in qualsiasi ordine e di qualsiasi lunghezza
%[a-cA-C] Idem come sopra
%[a-zA-Z] Sequenze di lettere alfabetiche
%[0-9] Sequenze di cifre numeriche
%[a-zA-Z0-9] Sequenze alfanumeriche
%[^x] Qualunque sequenza che non contiene 'x'
%[^\n] Legge fino a file riga
%[^,;.!? ] Si ferma alla punteggiatura o spazio
39
Osservazioni

Ricordare che i pattern devono sempre essere


associati a dati di tipo stringa (vettori di caratteri)
Il comune specificatore "%s" equivale al pattern
"%[^ \t\n]"

40
Esempio

Il file /etc/passwd, presente in tutti i sistemi


operativi derivati da Unix, contiene i dati degli
utenti nel seguente formato:
corno:
:w3tce34:
:501:
:401:
:Fulvio Corno:
:/home/corno:
:/bin/bash

Campi separati da ':'


Nome utente, password: stringhe prive di spazi
User ID, Group ID: interi
Nome reale: stringa generica (con spazi)
Home directory e shell: stringhe generiche

41
Soluzione

f = myfopen("/etc/passwd", "r") ;

while(fgets(riga,
while MAX, f)!=NULL)
{
sscanf(riga,
"%[^:]:[%^:]:%d:%d:"
"%[^:]:%[^:]:%[^:]",
login, pass, &uid, &gid,
realname, home, shell ) ;
/* elabora i dati ... */
}
myfclose(f) ;
42
Formattazione avanzata
Stream predefiniti

L’istruzione fopen permette di aprire nuovi


stream, associati a file esistenti sui dischi
dell’elaboratore
All’avvio di un programma in C, sono già stati
aperti in modo automatico 3 stream predefiniti
stdin
stdout
stderr

44
stdin

stdin è detto lo “standard input” di un


programma
Normalmente è associato al canale di input del
terminale (o della console) nel quale il
programma è avviato
In pratica, la tastiera del P.C.
L’input può essere rediretto, prendendolo da un
file anziché dalla tastiera, avviando il programma
da linea di comando con l’operatore <
prog < [Link]

45
stdout

stdout è detto lo “standard output” di un


programma
Normalmente è associato al canale di output del
terminale (o della console) nel quale il
programma è avviato
In pratica, il video del P.C.
L’output può essere rediretto, salvandolo su un
file anziché su video, avviando il programma da
linea di comando con l’operatore >
prog > [Link]

46
stderr

stderr è detto lo “standard error” di un


programma
Normalmente è associato al canale di output del
terminale (o della console) nel quale il
programma è avviato
In pratica, il video del P.C.
È uno stream distinto ed indipendente da
stdout
Solitamente l’output di stderr non viene
rediretto, per permettere ai messaggi di errore di
essere sempre visti dall’utilizzatore
47
Uso comune

stdin viene usato per acquisire i dati


Può essere rediretto da un file
stdout viene usato per presentare i risultati
Può essere rediretto su un file
stderr viene usato esclusivamente per i
messaggi di errore
Rimane visibile sulla console

48
Equivalenze

La funzione… è equivalente a…

scanf("formato", …); fscanf(stdin,


"formato", …);
printf("formato", …); fprintf(stdout,
"formato", …);
ch=getchar(); ch=fgetc(stdin);

putchar(ch); fputc(ch, stdout);

49
Stampa dei messaggi di errore

if(...condizione
if errore fatale...)
{
fprintf(stderr,
"Messaggio di errore\n") ;
exit(1) ;
}

50
Suggerimento

Tutti i messaggi di errore devono essere stampati


sullo stream stderr
Conviene definire una funzione myerror
Stampa un messaggio di errore
Interrompe il programma

void myerror(char
char *message) ;

51
Funzione myerror

my.c

int myerror(char
char *message)
{
fputs( message, stderr ) ;
exit(1) ;
}

52
I/O Avanzato e File
Esercizi proposti

Esercizio “Somma numeri”


Esercizio “Bersagli”
Esercizio “Consumi toner”

2
Esercizi proposti
Esercizio “Somma numeri”

Un file di testo contiene una serie di numeri interi


(positivi o negativi), uno per riga
Si scriva un programma C che:
Acquisisca da linea di comando il nome del file
Calcoli la somma di tutti i numeri presenti nel file
Stampi in output il valore di tale somma

4
Analisi

[Link]

30
22 [Link]
-3
18
-12
C:\prog>somma [Link]
La somma vale: 55

5
Soluzione (1/4)

sommafile.c
int main(int
int argc, char *argv[])
{
const int MAX = 80 ;

FILE * f ;
char nomefile[MAX] ;
char riga[MAX] ;
int r, num ;

int somma ;

6
Soluzione (2/4)

sommafile.c

if(argc
if != 2)
myerror("Num. argomenti errato\n") ;

strcpy(nomefile, argv[1]) ;

f = myfopen( nomefile, "rt" ) ;

somma = 0 ;

7
Soluzione (3/4)

sommafile.c

while(
while fgets( riga, MAX, f ) != NULL)
{
r = sscanf( riga, "%d", &num ) ;

if(r==1)
if
somma = somma + num ;
else
printf("Riga ignorata\n") ;
}

8
Soluzione (4/4)

sommafile.c

myfclose(f) ;

printf( "La somma vale: %d\n", somma ) ;

exit(0) ;
}

9
Esercizi proposti
Esercizio “Bersagli” (1/2)

Si desidera creare un programma in grado di


calcolare il numero di colpi andati a segno in
un’esercitazione di tiro
I bersagli sono descritti tramite le coordinate
cartesiane del punto in cui sono posizionati
all’interno di una griglia 100 × 100. Le coordinate
sono rappresentate solo da numeri interi,
compresi tra 0 e 99. La posizione dei bersagli è
contenuta nel file di testo [Link]: ogni
riga di tale file contiene le coordinate X e Y di un
singolo bersaglio
11
Esercizio “Bersagli” (2/2)

I colpi sparati sono descritti anch’essi tramite le


loro coordinate X e Y e sono memorizzati in un
file di caratteri il cui nome è passato come primo
parametro sulla linea di comando. Ogni riga di
tale file contiene le coordinate X e Y del punto in
cui è stato sparato un colpo
Si scriva un programma che legga dai file
succitati la posizione dei bersagli ed i colpi sparati
e quindi calcoli il numero di colpi andati a segno,
sia come valore assoluto sia come percentuale
dei colpi sparati
12
Analisi
[Link] [Link]

0 0
49 49
0 99
50 50
50 50 [Link] 51 51
99 0
52 52
99 99

C:\prog>giudice [Link]
Colpi sparati: 4
Colpi andati a segno: 1 (25.0 %)

13
Algoritmo

Acquisire dal file [Link] tutte le


coordinate, memorizzandole in due vettori
paralleli Bx[] e By[]. Lunghezza dei vettori: Nb
Acquisire dal file argv[1] le coordinate dei vari
colpi Cx, Cy. Numero colpi: Nc
Per ciascun colpo, verificare se le coordinate
coincidono con quelle di almeno un bersaglio
Se sì, incrementare Ncc
Stampare Ncc e Ncc/Nc*100

14
Soluzione (1/4)

int main(int
int argc, char *argv[])
{ bersagli.c
const int MAXB = 100 ;
/* massimo numero di bersagli */
const int MAX = 80 ;
/* lunghezza riga del file */
const char FILEB[] = "[Link]";

int Nb ; /* numero di bersagli */


int Bx[MAXB], By[MAXB] ;
/* coordinate dei bersagli */

int Nc ; /* numero colpi sparati */


int Ncc ; /* numero di colpi centrati */
15
Soluzione (2/4)
FILE *f ;
char riga[MAX] ;
int Cx, Cy ; bersagli.c
int i, r, trovato ;

/* 1: acquisizione coordinate bersagli */


f = myfopen( FILEB, "rt") ;
Nb = 0 ;
while(
while fgets(riga, MAX, f) != NULL )
{
r=sscanf(riga,"%d %d",&Bx[Nb],&By[Nb]);
if(
if r!=2 )
myerror("Formato errato\n") ;
Nb ++ ;
}
myfclose(f); 16
Soluzione (3/4)
/* 2: analisi coordinate dei colpi */
if(
if argc != 2 )
myerror("ERR: manca nome file\n"); bersagli.c
f = myfopen( argv[1], "rt") ;

Nc = 0 ;
Ncc = 0 ;
while(
while fgets(riga, MAX, f) != NULL )
{
r = sscanf( riga, "%d %d", &Cx, &Cy );
if(r!=2)
if myerror("Formato errato\n") ;
Nc ++ ;
/* Ricerca del bersaglio */
}
myfclose(f); 17
Soluzione (3/4)
/* 2: analisi coordinate dei colpi */
if(
if argc != 2 )
myerror("ERRORE:
trovato = 0 ; manca nome file\n");
bersagli.c
f = for(i=0;
myfopen( i<Nb
for argv[1], "rt") ;
&& trovato==0; i++)
if(
if Cx==Bx[i] && Cy==By[i] )
Nc = 0 ;trovato = 1 ;
Ncc = 0 ;
while(
if fgets(riga, MAX, f) != NULL )
while
if(trovato==1)
{ Ncc ++ ;
r = sscanf( riga, "%d %d", &Cx, &Cy );
if(r!=2)
if myerror("Formato errato\n") ;
Nc ++ ;
/* Ricerca del bersaglio */
}
myfclose(f); 18
Soluzione (4/4)

bersagli.c

/* 3: stampa risultati */
printf("Colpi sparati: %d\n", Nc) ;
printf("Colpi andati a segno: %d ", Ncc);
if(Nc!=0)
if
printf("(%.2f%%)", Ncc*100.0/Nc) ;
printf("\n");

exit(0) ;
}

19
Esercizi proposti
Esercizio “Consumi toner” (1/3)

Si desidera analizzare la statistica dei consumi di


toner di un’azienda per ottimizzare gli acquisti
futuri
La quantità di cartucce di toner prelevate dal
magazzino ogni giorno è riportata all’interno di un
file di testo il cui nome è passato come primo
parametro sulla riga di comando

21
Esercizio “Consumi toner” (2/3)

Il file contiene una riga per ogni giorno. Ogni riga


contiene in sequenza:
Il nome del dipartimento che ha prelevato il toner
(una stringa lunga al massimo 5 caratteri)
Un numero intero (valore minimo 1 e massimo 99)
che indica la quantità di cartucce di toner
prelevate in quel giorno da quel dipartimento
Non è noto il numero di righe presenti nel file

22
Esercizio “Consumi toner” (3/3)

Il programma riceve inoltre come secondo


argomento sulla linea di comando il nome di un
dipartimento per il quale calcolare l’indicatore
statistico dato come terzo argomento sulla linea
di comando secondo la seguente codifica:
-min indica che si desidera il valore minimo
-max indica che si desidera il valore massimo
-med indica che si desidera il valore medio (da
stamparsi in output con un cifra dopo la virgola)

23
Analisi

[Link]

CONT 10
MAGAZ 20 [Link]
CONT 15

C:\prog>toner [Link] CONT –med


12.5

24
Argomenti del programma

C:\prog>toner [Link] CONT –med

argv[1]
Nome del file argv[3]
contenente i argv[2] Operazione
consumi Dipartimento statistica:
da analizzare -min
-med
-max
25
Soluzione (1/4)

int main(int
int argc, char *argv[])
{ toner.c

const int LUNDIP = 5 ;


const int MAX = 80 ;

char dip[LUNDIP+1], dipf[LUNDIP+1] ;


int stat ;
/* tipo di statistica:
1=min, 2=max, 3=med */
FILE * f ;
int qtaf, r ;
int min, max, tot, cont ;
char riga[MAX+1] ;
26
Soluzione (2/4)

if(argc!=4)
if
myerror("Numero parametri errato\n"); toner.c
/* Acquisisci il nome del dipartimento */
strcpy(dip, argv[2]) ;
/* Acquisisci tipo statistica */
if(
if strcmp( argv[3], "-min") == 0 )
stat = 1 ;
else if ( strcmp( argv[3], "-max") == 0 )
stat = 2 ;
else if ( strcmp( argv[3], "-med") == 0 )
stat = 3 ;
else
myerror("Statistica sconosciuta\n");
27
Soluzione (3/4)
f = myfopen(argv[1], "rt") ;
tot = 0 ;
cont = 0 ; toner.c
min = 100 ;
max = 0 ;
while(
while fgets(riga, MAX, f) != NULL )
{
r = sscanf(riga, "%s %d", dipf, &qtaf);
if(r!=2)
if
printf("Riga ignorata\n");
else
{
/* Aggiorna statistiche */
}
}
myfclose(f) ; 28
Soluzione (3/4)
f = myfopen(argv[1], "rt") ;
tot =if(strcmp(dip,
if0 ; dipf)==0)
cont {= 0 ;
if(
if
min = 100 ; qtaf < min ) toner.c

max = 0 ;min = qtaf ;


while if(
while( if qtaf > max
fgets(riga, ) f) != NULL )
MAX,
{ max = qtaf ;
tot = tot + qtaf
r = sscanf(riga, ;
"%s %d", dipf, &qtaf);
if(r cont++ ;
if(r!=2)
}
printf("Riga ignorata\n");
else
{
/* Aggiorna statistiche */
}
}
myfclose(f) ; 29
Soluzione (4/4)

/* Stampa il valore della statistica */ toner.c


if(cont==0)
if
printf("Nessun elemento\n");
else if(
if stat==1 )
printf("%d\n", min) ;
else if(
if stat ==2 )
printf("%d\n", max) ;
else if(
if stat==3 )
printf("%.1f\n", (float)tot/cont) ;

exit(0) ;
}
30
I/O Avanzato e File
Argomenti trattati (1/2)

File
File binari
File di testo
Gestione dei file in C
Apertura/chiusura
Lettura/scrittura
Gestione degli errori
Il problema degli errori di formattazione

2
Argomenti trattati (2/2)

Formattazione avanzata
Funzione sscanf
Opzioni degli specificatori di formato
In output
In input
Pattern di input
Stream predefiniti
Input robusto
Utilizzo combinato di fgets e sscanf

3
Tecniche di programmazione

Gestire i file, in lettura e scrittura


Verificare gli errori che possono incorrere nelle
operazioni di I/O
Utilizzare le funzioni myfopen, myfclose,
myerror
Utilizzare sscanf per analizzare righe anche dal
formato complesso
Utilizzare printf/fprintf per controllare
l’ampiezza dei campi di output

4
Materiale aggiuntivo

Sul CD-ROM
Testi e soluzioni degli esercizi trattati nei lucidi
Scheda sintetica
Esercizi risolti
Esercizi proposti
Esercizi proposti da altri libri di testo

Potrebbero piacerti anche