====== Esercitazione 2 ====== Dove si sperimenta qualche tool e si approfondiscono alcune caratteristiche del C sequenziale: errno, perror ... ===== Esercizio 1: mtrace ===== Verificare gli accessi in memoria compiuti dalle funzioni su liste di interi della libreria ''libList.a'' utilizzando la funzione ''mtrace'' e l'utility ''mtrace'', questi strumenti tracciano le azioni di allocazione e deallocazione di memoria compiute dal programma per verificare la presenza di //memory leak// cioe' memoria non deallocata. Per fare questo procedere come segue: * leggere le informazioni in ''man 3 mtrace'' * includere l'header ''mcheck.h'' * inserire la chiamata alla funzione di libreria mtrace() all'inizio della parte del programma C che vogliamo verificare * inserire la chiamata alla funzione di libreria muntrace() alla fine della parte del programma C che vogliamo verificare * compilare il file da verificare con opzione ''-g'' per includere le informazioni di debugging. Ad esempio se il mio file si chiama ''main.c'' posso compilare con bash$ gcc -Wall -pedantic -g -o prova main.c -lList -L. * settare la variabile di ambiente ''MALLOC_TRACE'' al path del file in cui vogliamo che la ''mtrace()'' registri le informazioni sugli accessi di memoria. Ad esempio se voglio registrare le informazioni nel file ''./mtrace.out'' devo usare il comando bash$ export MALLOC_TRACE=./mtrace.out * eseguire, nel nostro esempio con: bash$ ./prova * dopo l'esecuzione nel file ''./mtrace.out'' sono registrati gli accessi in formato testuale non facilmente comprensibile. Interpretarlo con l'utility mtrace. Ad esempio sempre riferendosi al nostro esempio invocare bash$ mtrace ./prova ./mtrace.out questo rispondera' ''No memory leaks'' se tutta la memoria e' stata deallocata o fornira' indicazioni su dove e' stata allocata la mamoria rimasta da deallocare. ===== Esercizio 2: verificare gli accessi in memoria: valgrind ===== Verificare la correttezza degli accessi ai puntatori compiuti dalle funzioni su liste di interi della libreria libList.a utilizzando ''valgrind''. Questo strumento permette fra l'altro di capire se tutte le variabili sono inizializzate prima del loro uso, se accediamo a memoria gia' deallocata o mai allocata e situazioni similari Per fare questo procedere come segue: * compilare il file da verificare con opzione ''-g'' per includere le informazioni di debugging. Ad esempio se il mio file si chiama ''main.c'' posso compilare con bash$ gcc -Wall -pedantic -g -o prova main.c * eseguire 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. ===== Esercizio 3: lettura-scrittura su file con stdio ===== Scrivere un programma C che legge una sequenza di studenti da file ''anagrafe_studenti''. Ogni studente e' memorizzato su file in una singola linea contenente tre stringhe di caratteri separate da ':' e terminata da '\n' secondo il formato cognome:nome:numero_di_matricola quindi ad esempio ... Rossi:Mario:234445 Bixio:Nino:435678 Garibaldi Giuseppe 787899 ... Il programma memorizza i dati relativi a ciascun studente in un array di strutture di tipo studente opportunamente definito e li stampa in ordine alfabetico. Suggerimento: Per la lettura da file usare ''fscanf()'' con una opportuna stringa di formattazione oppure fgets() per leggere fino al primo ''\n'' e ''strchr()'' per localizzare i caratteri separatori '':'' ===== Esercizio 4: lettura-scrittura su file passato come argomento ===== In C e' possibile accedere agli argomenti passati sulla linea di comando tramite la struttura ''argv'' che punta ad una array di stringhe. Per farlo, dichiarare il ''main()'' di tipo int main (int argc, char* argv[]) { ... } in questo modo ''argc'' conterra' il numero di argomenti passati sulla linea di comando, ''argv[0]'' il nome dell'eseguibile e ''argv[1], argv[2], ...'' i vari argomenti passati sulla linea di comando. Ad esempio, se ho compilato il mio programma in un eseguibile ''prova'' bash$ ./prova pippo pluto paperone ''argc'' varra' 3, ''argv[1]'' conterra' //pippo//, ''argv[2]'' //pluto// ed ''argv[3]'' //paperone//. Si chiedere di modificare l'esercizio 3 in modo da realizzare il comando ''leggistud'' bash$ leggistud nome_file che ordina gli studenti contenuti nel file ''nome_file'' passato come primo parametro. Fare in modo di stampare un opportuno messaggio di uso se invocato con un numero di parametri diverso da 1. ===== Esercizio 5: Manipolare ''errno'' e uso di ''perror()'' ===== In C, la maggior parte delle funzioni di libreria che segnalano un errore settano anche la variabile globale ''errno'' con dei codici definiti da diversi standard. I codici sono valori interi, definiti da opportune macro. Per vadere il loro valore eseguire bash$ man errno Dopo l'esecuzione di una funzione di libreria che imposta ''errno'' e' possibile chiamare la funzione di libreria ''perror()'' che ispeziona il valore di ''errno'' e trasforma il valore numerico in un messaggio testuale comprensibile all'utente (vedere ''man perror'' per il suo uso). E' possibile manipolare ''errno'' da programma includendo l'header ''errno.h'' con #include L'esercizio richiede di essegnare a errno i valori ''EINTR EPERM EBUSY'' e stampare i corrispondenti messaggi di errore usando ''perror()''.