====== Esercitazione 2 ====== ===== Esercizio 1: funzioni rientranti ===== Si consideri il seguente programma: #include #include int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "use: %s stringa1 stringa2\n", argv[0]); return -1; } char* token1 = strtok(argv[1], " "); while (token1) { printf("%s\n", token1); char* token2 = strtok(argv[2], " "); while(token2) { printf("%s\n", token2); token2 = strtok(NULL, " "); } token1 = strtok(NULL, " "); } return 0; } 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'', 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**: #define _POSIX_C_SOURCE 200112L ===== Esercizio 2: numeri random ===== Generare ''N'' numeri casuali interi nell'intervallo ''[0,K['' utilizzando la funzione ''rand_r()''. N e K sono definiti con delle opportune ''#define'' (es. N=1000 K=10). Calcolare il numero di occorrenze di ciascun intero ''i'' nell'intervallo ''[0,K[''e stamparle sullo standard output. Un esempio di output e': Occorrenze di: 0 : 10.25% 1 : 9.97% 2 : 9.48% 3 : 9.77% 4 : 10.19% 5 : 10.93% 6 : 9.80% 7 : 9.93% 8 : 10.00% 9 : 9.68% ===== Esercizio 3: 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. 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. Passi: * compilare il file da verificare con opzione ''-g'' per includere le informazioni di debugging (anche se non è strettamente necessario). * eseguire il programma con ''valgrind'' nel modo seguente : bash$ valgrind ./prova in questo modo, a schermo verranno riportare le infrazioni rilevate. Ad esempio, //invalid read// o //invalid write// sono accessi in lettura o scrittura a memoria non allocata o gia' deallocata. Se si specifica l'opzione ''--leak-check=full'' (attenzione al doppio trattino), 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.