Testi delle esercitazioni


  1. STRCMP Scrivere una funzione C con prototipo int strcmp(char *s, char *t) che restituisca un valore minore di 0 se s<t; 0 se s=t; un valore maggiore di 0 se s>t.

    CRIVELLO Un intero n > 1 non è primo se esiste un numero primo 1 < k < n per cui k divide n (ovvero il resto della divisione di n per k è 0). Sulla base di questa considerazione, completare il seguente programma C per il calcolo dei primi MAX numeri primi (crivello di Eratostene): crivello.c.

  2. STRCPY Scrivere una funzione C con prototipo void strcpy(char *s, char *t) che copi il contenuto della string t nella stringa s. Si assuma che s punti a un blocco di memoria grande abbastanza da contenere t.

    STRDUP Scrivere una funzione C con prototipo char *strdup(char *s) che copi il contenuto della string s in un area di memoria allocata dinamicamente, di lunghezza pari a quella di s, e restituisca un puntatore alla nuova copia.

    STRCAT Scrivere una funzione C con prototipo void strcat(char *s, char *t) che copi il contenuto della stringa t alla fine della stringa s, in modo che al ritorno dalla funzione s sia la concatenazione delle due stringhe originali. Si assuma che s punti a un blocco di memoria grande abbastanza da contenere la concatenazione di s e t.

    JOIN Scrivere una funzione C con prototipo char *join(int n, char *s[]) che, prendendo in input un array s di n elementi (ciascuno dei quali è una stringa), restituisca una nuova stringa, allocata dinamicamente, e contenente la concatenazione di tutte le stringhe in s.

  3. ALBERO A partire dall'header file albero.h scrivere il programma albero.c, il quale invocato con albero n crea un albero con n nodi (i valori del campo intero del nodo sono generati casualmente tramite la macro RAND definita in albero.h) e quindi stampa gli interi contenuti in ciascun nodo per mezzo di una previsita dell'albero (prima stampo il nodo, quindi il figlio sinistro e poi il figlio destro).

    EXSTUDENTE

    1. Scrivere la definizione in C di una struct exstudente che contenga i seguenti campi: nome, cognome, data di nascita, data di laurea. Le date devono essere a loro volta struct con giorno, mese e anno.
    2. Scrivere quindi una funzione C con prototipo struct exstudente *leggiExStudente() che legga i dati di un ex-studente dallo stdin, e restituisca un puntatore a una struct exstudente. Sia la struct che tutte le stringhe in essa contenuta dovranno essere allocate dinamicamente. Suggerimento: si usino printf() e scanf() per, rispettivamente, stampare dei prompt e leggere le risposte da tastiera.
    3. Infine, si scriva una funzione C con prototipo void stampaExStudente(struct exstudente *p) che stampi i dati di un ex-studente, opportunamente formattati, su una sola riga. Suggerimento: si usino le specifiche di lunghezza dei campi della printf per ottenere una stampa adatta a far parte di una tabella di ex-studenti.

  4. MYCAT Traendo spunto dal programma mycat presentato nella dispensa (9.5.1), se ne scriva una versione che, invocata senza parametri, legga da stdin e copi su stdiout, mentr invocata con 1 o più parametri legga i file specificati dai parametri, in ordine, copiandone il contenuto su stdout. (Si noti che in questo modo risolviamo gli esercizi 3 e 4 della sezione 9.5 della dispensa).

    FMYCAT Si converta il programma mycat sviluppato nell'esercizio precedente in modo da usare le funzioni della libreria standard di I/O (fopen(), fread(), fwrite(), fclose()) invece delle corrispondenti funzioni POSIX (open(), read(), write(), close()).

    MISURE DI PRESTAZIONI Usando il comando time della Shell, si misuri il tempo impiegato da mycat e da fmycat per copiare alcuni grandi file. Quale versione è più veloce? Come cambiano le prestazioni al variare della dimensione del buffer in mycat? Che conclusioni possiamo trarre da queste misure?

  5. CONTAX Si scriva un programma contax che, ricevuto come argomento un nome di file, fornisca in uscita il numero totale di caratteri "x" presenti nel file. Si usi la funzione mmap() (e collegate) per mappare il file in memoria. Parte opzionale: si scrivano versioni dello stesso programma basate su read() e fread() e si misurino le prestazioni nei tre casi.

    LSB Si scriva un programma lsb che, invocato senza argomenti, stampi il nome di tutti i file contenuti nella directory corrente, ciascuno preceduto dalla sua lunghezza (in bytes) e dallo spazio effettivamente occupato su disco (sempre in bytes). Se invece vengono forniti degli argomenti, ciascuno di essi sarà il nome di una directory, e il programma deve stampare gli stessi dati per i file contenuti in ciascuna di esse.

    FIND Si scriva un programma find che, invocato con find ext, cerca nella directory corrente e in tutte le sottodirectory un file con estensione .ext. Ogni volta che si trova una voce corrispondente, il programma deve stampare il nome completo del file e la sua lunghezza.

  6. TIMERES Si scriva un programma timeres che, invocato con timeres cmd args..., esegua cmd args..., e restituisca il codice di ritorno di cmd, seguito dal tempo di CPU impiegato per l'esecuzione. Suggerimento: si veda la funzione time(2) per ottenere l'ora corrente, o ftime(3) per una maggiore precisione.

    MICROSHELL-0 Si implementi una microshell che abbia il seguente comportamento:

    1. Legga sullo standard input un comando, seguito dai suoi argomenti
    2. Esegua il comando, con gli argomenti dati
    3. Stampi il valore di ritorno del comando eseguito, e torni all'inizio.

    MICROSHELL-1 Si aggiunga alla shell sviluppata al punto precedente la capacità di fare redirezione di I/O con la consueta sintassi: < file redirige lo standard input, > file redirige lo standard output.

    MICROSHELL-2 Si aggiunga alla shell sviluppata al punto precedente la capacità di eseguire comandi in background con la consueta sintassi: cmd args... & esegue cmd args... in background.

  7. TIMEOUT Si scriva un comando timeout che, invocato con timeout num cmd opzioni, esegua il cmd con le opzioni indicate, terminandolo con SIGINT se il comando è ancora in esecuzione dopo num secondi. Suggerimento: si dovrà inviare un SIGINT e ricevere SIGALRM e SIGCHILD.

    PERF Si scriva un programma perf cmd opzioni che conti quante volte può essere eseguito cmd opzioni nell'arco di 10 secondi (redirigendo lo standard output e lo standard error di cmd opzioni su /dev/null). Il programma deve stampare il numero di esecuzioni complete entro il tempo dato. Opzionalmente, si confronti la velocità di macchine diverse nell'esecuzione dello stesso comando.

    SIGMEM Si scrivano due programmi, lettore e scrittore che comunichino tramite segnali e memoria condivisa. Entrambi i programmi devono mappare in memoria lo stesso file /tmp/lps04.ls (creandolo se non esiste). Quindi, lettore legge una riga dal suo standard input, la scrive in memoria condivisa, e invia un segnale (si scelga con cura quale!) allo scrittore. Quest'ultimo attenderà il segnale, leggerà la stringa dalla memoria condivisa, e la stamperà sul suo standard output. Suggerimento: si consideri come può fare lettore a conoscere il pid di scrittore...

  8. BFF (Esercizio 5 a pag. 152 della dispensa) Si scriva un programma bff che, invocato con bff comando parametri esegua il comando con i parametri dati, intercetti il suo standard output, rimuova tutte le vocali, e invii il risultato sul proprio standard output.

    TALK Si scriva un programma talk che, invocato con talk nomepipe, legga delle stringhe da tastiera e le scriva sulla pipe con nome nomepipe. Si usi il comando cat nomepipe per svuotare la pipe all'altra estremità. Si noti come, con due istanze di talk sia possibile implementare un servizio di comunicazione bidirezionale.
    Il programma talk deve creare la pipe indicata se questa non esiste già; in questo caso, al momento dell'uscita (per EOF sul suo standard input o a causa di un Ctrl-C) deve rimuovere dal file system la pipe che ha creato.