Entrambe le parti precedenti la revisioneRevisione precedenteProssima revisione | Revisione precedente |
informatica:sol:laboratorio21:esercitazionib:esercitazione2 [22/02/2021 alle 07:28 (4 anni fa)] – Massimo Torquati | informatica:sol:laboratorio21:esercitazionib:esercitazione2 [25/02/2021 alle 15:25 (4 anni fa)] (versione attuale) – Massimo Torquati |
---|
====== Esercitazione 2 ====== | ====== Esercitazione 2 ====== |
| |
===== Esercizio 1: puntatori a funzioni ===== | ===== Esercizio 1: ''getopt'' ===== |
| |
Scrivere un programma C che prende in ingresso 4 opzioni da linea di comando codificate con '-n', '-m', '-o', '-h' nel modo seguente: | Scrivere un programma C che prende in ingresso 4 opzioni da linea di comando codificate con '-n', '-m', '-o', '-h' nel modo seguente: |
<code c> | <code c> |
nome-programma -n <numero> -m <numero> -o <stringa> -h | nome-programma -n <num. intero> -m <num. intero> -o <stringa> -h |
</code> | </code> |
Il programma dovrà stampare le opzioni riconosciute con il relativo argomento. L'opzione -h non ha argomento e corrisponde al messaggio di uso. | Il programma dovrà stampare sullo standard output le opzioni riconosciute valide con il relativo argomento. L'opzione '-h' non ha argomento e corrisponde al messaggio di uso. |
Effettuare il parsing della command line utilizzando la funzione di libreria 'getopt' (man 3 getopt). Ad ogni opzione è associato un puntatore a funzione contenuto in un vettore (es. V) che esegue la gestione dell'argomento (ad esempio converte la stringa <numero> in un numero e stampa sullo schermo). | Effettuare il parsing della command line utilizzando la funzione di libreria ''getopt'' (man 3 getopt), |
Il frammento di codice main da utilizzare è il seguente: | |
| ===== Esercizio 2: puntatori a funzioni ===== |
| |
| Estendere l'esercizio 1 associando ad ogni opzione del main una funzione che ne faccia la gestione e la stampa sullo standard output. Ad esempio, la gestione dell'opzione '-n' viene fatta dalla funzione 'arg_n(const char*)' la quale convertirà l'argomento associato all'opzione ad intero e farà la stampa sullo standard output, ritornado -1 in caso di errore e 0 in caso di successo. |
| Memorizzare tali funzioni in un vettore con nome 'V'. Utilizzare completando il seguente frammento di codice main. |
| |
<code c> | <code c> |
| |
... // controllo di argc ed inizializzazione del vettore V con i puntatori a funzione | ... // controllo di argc ed inizializzazione del vettore V con i puntatori a funzione |
| |
| int opt; |
while ((opt = getopt(argc,argv, "n:m:o:h")) != -1) { | while ((opt = getopt(argc,argv, "n:m:o:h")) != -1) { |
switch(opt) { | switch(opt) { |
case '?': <gestione parametro non riconosciuto> break; | case '?': { |
| <gestione parametro non riconosciuto> |
| } break; |
default: | default: |
| // invocazione della funzione di gestione passando come parametro l'argomento restituito da getopt |
if (V[opt%4]( (optarg==NULL ? argv[0] : optarg) ) == -1) { | if (V[opt%4]( (optarg==NULL ? argv[0] : optarg) ) == -1) { |
<gestione errore> | <gestione errore> |
} | } |
} | } |
... | |
return 0; | return 0; |
} | } |
</code> | </code> |
| |
===== Esercizio 2: funzioni rientranti ===== | ===== Esercizio 3: funzioni rientranti ===== |
| |
Si consideri il seguente programma: | Si consideri il seguente programma: |
Riscrivere il programma precedente (che produce un output non corretto) utilizzando la chiamata di libreria ''strtok_r'' al posto di ''strtok''. | Riscrivere il programma precedente (che produce un output non corretto) utilizzando la chiamata di libreria ''strtok_r'' al posto di ''strtok''. |
| |
**NOTA**: se si utilizza l'opzione ''-std=c99/11'', per evitare i warnings del tipo "implicit declaration of function X" aggiungere la seguente opzione di compilazione "-D_POSIX_C_SOURCE=200112L", oppure inserire la seguente define **prima del primo include**: | **NOTA**: se si utilizza lo standard ISO 99 o 11 (-std=c99/11), per evitare i warnings del tipo "implicit declaration of function X" aggiungere la seguente opzione di compilazione "-D_POSIX_C_SOURCE=200112L", oppure dichiarare il prototipo della funzione (copiando la segnatura dal man della funzione), oppure inserire la seguente define **prima del primo include**: |
<code> | <code> |
#define _POSIX_C_SOURCE 200112L | #define _POSIX_C_SOURCE 200112L |
</code> | </code> |
| |
===== Esercizio 3: numeri random ===== | ===== Esercizio 4: numeri random ===== |
| |
Generare ''N'' numeri casuali interi nell'intervallo ''[K1,K2['' utilizzando la funzione ''rand_r()''. N, K1 e K2 sono passati come argomenti del main opzionali, e se non forniti dall'utente assumono valori di default sulla base di opportune ''#define'' (es. N=1000 K1=100 K2=120). Il programma deve restituire il numero di occorrenze di ciascun intero ''i'' nell'intervallo ''[K1,K2[''e stamparle sullo standard output. Un esempio di output prodotto considerando K1=0 e K2=10, è il seguente: | Generare ''N'' numeri casuali interi nell'intervallo ''[K1,K2['' utilizzando la funzione ''rand_r()''. N, K1 e K2 sono passati come argomenti del main opzionali, e se non forniti dall'utente assumono valori di default sulla base di opportune ''#define'' (es. N=1000 K1=100 K2=120). Il programma deve restituire il numero di occorrenze di ciascun intero ''i'' nell'intervallo ''[K1,K2[''e stamparle sullo standard output. Un esempio di output prodotto considerando K1=0 e K2=10, è il seguente: |
</code> | </code> |
| |
===== Esercizio 4: valgrind ===== | ===== Esercizio 5: valgrind ===== |
| |
Verificare la correttezza degli accessi in memoria utilizzando ''valgrind'' dei programmi realizzati nell'esercizio 1 e 2. Verificare che non ci siano "memory leaks" all'uscita del programma. | Verificare la correttezza degli accessi in memoria utilizzando ''valgrind'' dei programmi realizzati nell'esercizi precedenti. Verificare che non ci siano "memory leaks" all'uscita del programma. |
| |
Valgrind permette, fra l'altro, di capire se le variabili sono inizializzate prima del loro uso, se accediamo a memoria gia' deallocata o mai allocata o a zone non inizializzate. | Valgrind permette, fra l'altro, di capire se le variabili sono inizializzate prima del loro uso, se accediamo a memoria gia' deallocata o mai allocata o a zone non inizializzate. |
in questo modo, a schermo verranno riportare le infrazioni rilevate nell'accesso alla memoria. Ad esempio, //invalid read// o //invalid write// sono accessi in lettura o scrittura a memoria non allocata o gia' deallocata. | in questo modo, a schermo verranno riportare le infrazioni rilevate nell'accesso alla memoria. Ad esempio, //invalid read// o //invalid write// sono accessi in lettura o scrittura a memoria non allocata o gia' deallocata. |
| |
Con l'opzione ''--leak-check=full'' (attenzione al doppio trattino iniziale), valgrind fornirà dettagli per ogni blocco di memoria che non è più raggiungibile o che, pur essendo raggiungibile, non è stato liberato, dando anche l'informazione di dove il blocco è stato allocato. | Con l'opzione ''--leak-check=full'' (attenzione, davanti a leek c'e' un doppio '-'), valgrind fornirà dettagli per ogni blocco di memoria che non è più raggiungibile o che, pur essendo raggiungibile, non è stato liberato, dando anche l'informazione di dove il blocco è stato allocato. |
| |