INFORMATICA
Dati sulla linea di comando
Dati sulla linea di comando
• Abbiamo già avuto occasione di osservare come il main sia in realtà
una funzione.
• Come le altre funzioni il main è in grado di ricevere dei parametri che
devono essere indicati tra le parentesi tonde che devono seguire la
parola chiave main.
• Questi parametri vanno scritti di seguito al nome del programma
sulla linea di comando e separati tra loro dallo spazio.
• Si tratta evidentemente di un’utile alternativa all’introduzione dei dati
da tastiera.
• Esempio:
bmi 72.60 175
© Piero Demichelis
2
Dati sulla linea di comando
• I parametri così indicati vengono passati dal sistema
operativo al main tramite la seguente coppia di
parametri:
int argc
char *argv[]
argument counter
argument vector
• argc è una variabile intera che contiene il numero di parametri
contenuti nel vettore di stringhe argv.
• argv è un vettore di stringhe.
• Queste due variabili devono essere dichiarate come
parametri della funzione main:
int main (int argc, char *argv[])
© Piero Demichelis
3
Dati sulla linea di comando
• argc indica il numero di parametri presenti sulla riga di
comando, incluso il nome del programma (pertanto vale
sempre almeno 1).
• il vettore argv[ ] (in realtà è una matrice di caratteri)
contiene i parametri veri e propri sottoforma di stringhe di
caratteri secondo il seguente formato:
- argv[0] è il nome del programma;
- argv[n] è la stringa che rappresenta l’ennesimo parametro dopo
il nome del programma.
• I parametri pertanto sono sempre delle stringhe: per
trasformarli in rappresentazioni numeriche occorre usare
le funzioni approppriate (atoi, atol, atof) o la sscanf.
© Piero Demichelis
4
Dati sulla linea di comando
• Struttura
- Esempio: c:\> programma.exe 3 pippo.dat 3.2
argc = 4
argv[0]
“programma.exe\0”
argv[1]
“3\0”
argv[2]
argv[3]
“pippo.dat\0”
“3.2\0”
© Piero Demichelis
5
Dati sulla linea di comando
• Scrivere un programma che legga sulla linea di comando
due interi N e D, e visualizzi tutti i numeri minori di N che
sono divisibili per D.
• Il programma dovrà pertanto essere eseguito con il
seguente comando:
myprog N D
dove myprog è il nome del programma, N e D sono i due
valori richiesti per il funzionamento del programma.
© Piero Demichelis
6
Dati sulla linea di comando
#include <stdio.h>
int main(int argc, char *argv[])
{
int N, D, i;
Test per verificare che
l’utente abbia introdotto il
numero esatto di dati
if (argc != 3)
{
printf (”\nNumero argomenti errato\nSintassi: myprog N D”);
return 1;
}
N = atoi (argv[1]);
/* oppure: sscanf (argv[1], “%d”, &N);
converte N */
D = atoi (argv[2]);
/* oppure: sscanf (argv[2], “%d”, &D);
converte D */
}
for (i = 1; i < N; i++)
if ((i % D) == 0) printf (”\n%d”, i);
© Piero Demichelis
7
INFORMATICA
typedef
Ridefinizione dei tipi: typedef
• E’ possibile ridefinire un tipo già esistente mediante la parola chiave
typedef, cosicché si può utilizzare un nuovo identificatore (sinonimo)
al posto del precedente.
• Formato:
typedef tipo_esistente nuovo_nome;
• Esempio:
typedef long int interolungo;
interolungo dato_int;
/* ridefinizione di tipo */
/* dato_int e' un intero lungo */
• Mediante typedef si possono definire, ad esempio, tipi astratti,
integer8, integer16 e integer32, dall'ovvio significato, per poi
ridefinirli in funzione del compilatore effettivamente usati.
© Piero Demichelis
9
INFORMATICA
Il tipo enumerazione
Il tipo enumerazione: enum
• Nei problemi reali può succedere di dover trattare colori,
categorie, dimensioni, ecc., per i quali non esiste un tipo
predefinito che si adatti opportunamente alla loro
rappresentazione.
• In questi casi il C permette di definire le entità su cui il
programma deve operare: questa possibilità è data dalla
definizione dei tipi enumerati.
• La forma generale è:
enum [identif_tipo] {identif. [, identif.]} [variabile];
enum identif_tipo variabile;
dove le parti opzionali sono tra parentesi quadra.
© Piero Demichelis
11
Il tipo enumerazione: enum
Esempio:
enum colore {bianco, rosso, blu, giallo, verde, nero};
enum week
{lunedi, martedi, mercoledi, giovedi, venerdi, sabato, domenica};
................................
enum colore col_parete;
enum week giorno;
• La variabile col_parete, di tipo colore, potrà assumere i
valori bianco, rosso, blu, ecc.
• La variabile giorno di tipo week i valori lunedi, martedi,
ecc.
© Piero Demichelis
12
Il tipo enumerazione: enum
• La definizione può apparire in varie forme:
enum {identif. [, identif.]} variabili ;
a)
• variabile può assumere uno dei valori della lista (espressi
in modo simbolico); esempio:
enum colore {bianco, rosso, blu, giallo, verde, nero} col_parete;
b)
enum nome_tipo {identif. [, identif.]};
...............................
enum nome_tipo variabili ;
In questo modo si identifica con nome_tipo la lista dei
valori assunti, successivamente si definisce variabile di
quel tipo enumerativo che potrà assumere soltanto i
valori indicati nella lista precedente.
© Piero Demichelis
13
Il tipo enumerazione: enum
Ad esempio:
enum colore {bianco, rosso, blu, giallo, verde, nero};
................................
enum colore col_parete;
c)
enum nome_tipo {ident. [, ident.]} variabile_1;
.....................................
enum nome_tipo variabile_2, ......, variabile_n ;
è una combinazione delle precedenti; esempio:
enum colore {bianco, rosso, blu, giallo, verde, nero} parete_A;
................................
enum colore parete_B;
© Piero Demichelis
14
Il tipo enumerazione: enum
• In un programma si possono pertanto avere istruzioni del tipo:
col_parete = verde;
giorno = mercoledi;
• Nella definizione di tipo si evidenziano due elementi: l’ identificatore
di tipo, detto tag, e gli identificatori che verranno usati per esprimere
i valori assunti da quel tipo.
• I valori assunti da quel tipo corrispondono a delle costanti intere
definite in modo automatico dal compilatore, che pertanto devono
essere uniche nel programma. Ad esempio,
enum festivo {sabato, domenica};
enum feriale {lunedi, martedi, mercoledi, giovedi, venerdi, sabato};
è errato perché sabato è presente in due tipi; analogamente è
illecito usare, per esempio, l'identificatore domenica come nome di
una variabile.
© Piero Demichelis
15
Il tipo enumerazione: enum
• La lista degli identificatori che denotano i valori assunti da un tipo
enumerato forma un insieme ordinato che il compilatore codifica con
valori interi crescenti a partire da 0.
• Nella definizione del tipo colore, l'identificatore bianco viene
codificato con 0, rosso con 1, blu con 2, ecc. Si possono modificare
questi valori, assegnati automaticamente, imponendo i valori interi
che si vogliono assegnare direttamente nella definizione.
• Si fa seguire al nome dell'identificatore il segno uguale e il valore che
si intende assegnare. Il compilatore assumerà questo numero come
nuovo valore di partenza per le assegnazioni successive.
© Piero Demichelis
16
Il tipo enumerazione: enum
• Esempi:
enum colore {bianco, rosso, giallo, verde, nero};
bianco vale 0, rosso vale 1, blu vale 2, giallo vale 3, ecc.
enum colore {bianco, rosso, blu = 20, giallo, verde, nero};
In questo caso bianco vale 0, rosso vale 1, blu vale 20, giallo vale 21,
ecc.
• E’ possibile attribuire a più identificatori valori identici, o
esplicitamente (ad esempio, blu = 20, giallo = 20), o implicitamente:
se, ad esempio, si pone blu = 0 (lo stesso valore di bianco che a
questo punto è già stato codificato), giallo assumerà lo stesso valore
di rosso, cioé 1).
© Piero Demichelis
17
Il tipo enumerazione: enum
• In generale quindi questi identificatori agiscono come costanti intere e
possono essere usati dovunque è appropriata una costante.
• Un'applicazione interessante è la definizione del tipo logico (assente in
C) ottenuta combinando la definizione di tipo enumerato con la
creazione di un tipo simbolico mediante typedef:
typedef enum {FALSO, VERO} boolean;
/*boolean è definito come sinonimo di un tipo enumerato a due valori*/
boolean finito, trovato;
/* definizione di due variabili logiche */
• Si noti che FALSO e VERO sono definite in un modo implicito e
assumono rispettivamente i valori 0 e 1.
© Piero Demichelis
18
Il tipo enumerazione: enum
• Il linguaggio C definisce gli enumerati come una forma
particolare del tipo intero: ne consegue che i valori
definiti in tipi enumerati differenti sono a tutti gli effetti
dei valori interi.
• Sono pertanto lecite (sintatticamente, non
semanticamente!) assegnazioni di valori di un tipo
enumerato a una variabile di un altro tipo enumerato.
• Un'altra conseguenza è che per le operazioni di I/O dei
dati di tipo enumerato non sono previsti specificatori ad
hoc, in quanto sono a tutti gli effetti degli interi.
© Piero Demichelis
19
Il tipo enumerazione: enum
• Esempio:
enum
enum
enum
enum
materia {italiano, latino, storia, geografia};
giorni {lunedi, martedi};
materia corso;
giorni domani;
main()
{
corso = storia;
corso = 3;
domani = latino;
}
/*
/*
/*
corso assume il valore 2
corso assume il valore 3
domani assume il valore 1
© Piero Demichelis
*/
*/
*/
20
enum: esempio
• Esempio: programma per introdurre da terminale i voti acquisiti in
ogni materia di insegnamento e calcolo della media.
#include <stdio.h>
main()
{
/*
definizioni
*/
enum materia {italiano, latino, storia, geografia};
double sommavoti, voto, numvoti;
enum materia corso;
numvoti = 0;
sommavoti = 0;
printf (“\nCalcola la media dei voti. Introdurre i voti.\n");
© Piero Demichelis
21
enum: esempio
for (corso = italiano; corso <= geografia; corso++)
{
printf (“\nVoto di ");
/* costruisce il messaggio di richiesta voto */
switch (corso)
{
case italiano:
printf ("italiano: ");
break;
case latino:
printf ("latino: ");
break;
case storia:
printf ("storia: ");
break;
case geografia:
printf ("geografia: ");
}
scanf ("%lf ", &voto);
sommavoti += voto; /* accumula in sommavoti (per la media) */
numvoti++;
/* incrementa numvoti (per la media) */
}
printf ("Media dei voti: %5.2f\n", sommavoti/numvoti);
}
© Piero Demichelis
22
INFORMATICA
Il costrutto struct
Il costrutto struct
• Supponiamo di dover realizzare una base dati contenente i
nomi e l’anno di nascita di una popolazione studentesca.
Non si può ricorrere a una matrice bidimensionale con una
dimensione per le variabili di tipo carattere (per i nomi) e
l'altra per la variabile intera (anno di nascita): le matrici
possono essere di dimensioni qualsiasi ma il tipo-base
deve essere unico!
• Occorrerebbe definire una matrice (vettore di vettori) di
caratteri per i nomi e un vettore di interi per l'anno di
nascita: due strutture separate tra loro. Pertanto
l'allineamento dei dati inerenti la stessa persona dovrà
essere garantito dal programmatore.
© Piero Demichelis
24
Il costrutto struct
• La difficoltà è superata da un altro tipo di dato
strutturato, molto più flessibile: il tipo struct.
• Si tratta di una collezione di dati, anche di caratteristiche
molto diverse tra loro, che però sono identificati dallo
stesso nome.
• Una struttura è formata da
membri o campi.
• I campi di un record possono essere di tipo diverso,
scalari, vettori o, a loro volta, altre struct.
© Piero Demichelis
25
Il costrutto struct
• Sono numerose le informazioni che intrinsecamente
possono accordarsi con questo tipo di dato, ad esempio:
- una data è composta da giorno (int), mese (char) e anno (int) e
quindi si può definire una struttura composta da questi tre campi;
- una persona è identificata da nome, cognome, data di nascita,
codice fiscale, stato civile, indirizzo, ecc., quindi si può definire una
struttura composta da tutti questi campi;
- la classifica di una manifestazione sportiva è composta da nome e
cognome degli atleti a cui è associata la prestazione (tempo
impiegato, punti, ecc.).
© Piero Demichelis
26
Il costrutto struct
• Una struct viene definita elencando i nomi che si intendono
attribuire ai singoli campi (identificatori di campo). Per ogni
identificatore di campo poi, occorre specificare il tipo.
struct [nome_struct ]
{
tipo_1 variabile_1;
/* campo 1 */
tipo_2 variabile_2;
/* campo 2 */
..........
tipo_n variabile_n;
/* campo n */
} [variabile] [,variabile]....;
dove le parti opzionali sono tra parentesi quadra.
• nome_struct costituisce il tag, cioè il nome che identifica quel
particolare tipo di struttura in successive dichiarazioni di variabili.
© Piero Demichelis
27
Il costrutto struct: esempi
• definizione di una variabile di tipo record una_persona:
struct
{
char nome[20];
char cognome[20];
int giorno_nascita;
int mese_nascita;
int anno_nascita;
float peso;
int altezza;
} una_persona;
© Piero Demichelis
28
Il costrutto struct : esempi
• definizione di un record denominato data:
struct data
{
int giorno;
enum {gennaio, febbraio, marzo, aprile, maggio, giugno,
luglio, agosto, settembre, ottobre, novembre,
dicembre} mese;
int anno;
};
© Piero Demichelis
29
Il costrutto struct: esempi
• definizione di numero complesso dato come x + iy, dove
x e y sono numeri reali e i  1: vengono definiti la
struct denominata complesso e la variabile val_complex
di quel tipo record.
struct complesso
{
double reale;
double immaginario;
} val_complex;
© Piero Demichelis
30
Il costrutto struct
• Le variabili possono essere dichiarate nell’ambito della stessa
struttura, come succede per la variabile val_complex, oppure
esternamente: ad esempio, dopo le dichiarazioni precedenti,
sarebbero lecite le seguenti:
struct complesso num_complesso;
struct data giorno;
• I campi di una struct sono racchiusi in un blocco e quindi il loro
campo di esistenza è limitato: è per questo che è lecita la definizione
della variabile giorno nell’esempio precedente, pur esistendo un
campo con lo stesso nome.
• Anche una funzione può essere definita di tipo struct e pertanto può
restituire un valore di questo tipo.
© Piero Demichelis
31
Il costrutto struct
• Un campo di una struct può essere un vettore, una matrice o un’altra
struct. Inoltre le struct possono costituire il tipo base per la
definizione di vettori.
• Nel corso del programma si può far riferimento ad uno specifico
campo di una struct indicando l'identificatore della variabile seguito
da un punto e dal nome del campo.
• Il campo di una struct deve essere trattato come una qualsiasi altra
variabile.
• Sul tipo struct nel suo complesso non agisce alcun operatore, ma è
lecita l'assegnazione di un’intera struct a un’altra struct dello stesso
tipo.
• I campi delle struct mantengono invece le proprietà, e quindi gli
operatori, del tipo a cui appartengono.
© Piero Demichelis
32
Il costrutto struct
• Esempio:
/*
uso della struttura complesso
struct complesso
{
double reale;
double immaginario;
};
*/
struct complesso x;
..............
x.reale = 12.5;
x.immaginario = 0.7;
© Piero Demichelis
33
struct: esempio
• Esempio: programma che riceve in input da tastiera delle sequenze
di caratteri (parole) e calcola il numero di volte che è presente
ciascun carattere (frequenza statistica). La fine dell'introduzione
delle parole sia segnalata da EOF (<CTRL>+Z). Il programma
dovrà visualizzare tutti i caratteri diversi introdotti e la loro frequenza
statistica.
• La base dati può essere costituita da un vettore di struct avente due
campi: un campo carattere, di tipo char, e un campo presenze, di tipo
int.
• Per ogni carattere letto da tastiera, si controlla se è già presente: se
presente, si incrementa il campo presenze di quel carattere,
altrimenti lo si memorizza nel campo carattere e si pone il valore 1
nel campo presenze.
© Piero Demichelis
34
struct: esempio
#include <stdio.h>
#define NUM_MAX_CAR 100
main()
{
typedef enum {FALSO, VERO} boolean;
struct memoria
{
char carattere;
int presenze;
};
int indice, num_car_pres;
struct memoria vett_car[NUM_MAX_CAR];
int carat;
char car_letto;
boolean trovato;
© Piero Demichelis
35
struct: esempio
num_car_pres = 0;
printf ("Introduci le sequenze di caratteri.\n ");
printf (" Usa <CR> per andare a capo e <EOF> per finire:\n");
while ((( carat = getchar()) != EOF) && (num_car_pres <
NUM_MAX_CAR))
/*
finché non si arriva a EOF
*/
{
if (carat != '\n')
{
/* carat è diverso da new-line */
car_letto = (char) carat;
/*
trasforma in char
*/
/*
cerca nella struct memoria se il carattere è già presente
*/
trovato = FALSO;
indice = 0;
© Piero Demichelis
36
struct: esempio
while ((!trovato) && (indice < num_car_pres))
{
if (vett_car[indice].carattere == car_letto)
{
/* il carattere introdotto esiste già */
trovato = VERO;
vett_car[indice].presenze++;
/* incr. campo presenze */
}
else
indice++;
/* increm. indice per scansione */
}
/* while not trovato... */
if (!trovato)
{
/* il carattere non c’è ancora nel vettore di struct: lo inserisce */
vett_car[num_car_pres].carattere = car_letto;
vett_car[num_car_pres].presenze = 1;
num_car_pres++; /* incr. numero di caratteri inseriti nella struct*/
}
/* if not trovato */
}
/*
if carat != eoln
*/
}
/*
while not eof...
*/
© Piero Demichelis
37
struct: esempio
/*
stampa i risultati
*/
printf ("Carattere
Presenze\n");
for (indice = 0; indice < num_car_pres; indice++)
{
printf (" %c
", vett_car[indice].carattere);
printf ("%6d\n", vett_car[indice].presenze);
}
}
© Piero Demichelis
38
struct come parametro di funzioni
• Le struct si comportano a tutti gli effetti come variabili di
tipo semplice, con la particolarità che possono essere
viste sia come un insieme aggregato, ad esempio
nell'assegnazione di un record ad un altro, sia come
singoli elementi (campi ).
• In quest'ultimo caso, l'identificatore dell'elemento è
costituito dal nome dell'intera struttura seguito dal punto
e dal nome del campo stesso.
• Anche una funzione può essere definita di tipo struct e
pertanto può restituire un valore di questo tipo.
© Piero Demichelis
39
struct come parametro di funzioni
Esempio: somma di due numeri complessi.
#include <stdio.h>
#include <math.h>
typedef struct
{
double reale;
double immagin;
} complesso;
/* prototipo */
complesso somma_cmplx (complesso dato1, complesso dato2);
© Piero Demichelis
40
struct come parametro di funzioni
main()
{
complesso x, y, total;
printf ("x.reale = ");
scanf ("%lf", &x.reale);
printf ("x.immaginario = ");
scanf ("%lf", &x.immagin);
printf ("y.reale = ");
scanf ("%lf", &y.reale);
printf ("y.immaginario = ");
scanf ("%lf", &y.immagin);
total = somma_cmplx (x, y);
printf ("La somma vale: %lf", total.reale); /* stampa della parte intera */
if (total.immagin < 0.0)
printf (" - i");
/*
stampa l’operatore i
*/
else
printf (" + i");
printf ("%lf\n", fabs (total.immagin)); /* stampa parte immaginaria */
}
© Piero Demichelis
41
struct come parametro di funzioni
complesso somma_cmplx (complesso dato1, complesso dato2)
{
complesso somma;
somma.reale = dato1.reale + dato2.reale;
somma.immagin = dato1.immagin + dato2.immagin;
return (somma);
}
© Piero Demichelis
42
struct come parametro di funzioni
• Osservazioni:
- nel programma principale, i dati di tipo struct vengono usati come
parametri di scanf e printf con le stesse modalità delle variabili di
tipo semplice;
- nella chiamata della funzione di tipo complesso somma_cmplx, i
dati di tipo struct vengono passati by value : pertanto quando il
controllo dell'esecuzione è passato alla funzione, verrà effettuata
una copia delle variabili esterne nelle variabili locali della funzione
dato1 e dato2;
- la funzione è definita di tipo struct e restituisce un valore di tipo
struct, il quale viene assegnato alla variabile total;
- mediante typedef si è ridefinito il nome della struct, semplificando
l'intestazione della funzione.
© Piero Demichelis
43
Scarica

typedef - enum