ESERCIZI RISOLTI IN C LANGUAGE (programmazione avanzata)

Размер: px
Начинать показ со страницы:

Download "ESERCIZI RISOLTI IN C LANGUAGE (programmazione avanzata)"

Транскрипт

1 ESERCIZI RISOLTI IN C LANGUAGE (programmazione avanzata) 1. Gestione file a basso livello 1) Scrivere un programma che carichi in un file binario, gestito a basso livello, una serie di numeri interi contenuti in un array. Il programma necessita di alcuni header file: fcntl.h (per l uso delle costanti simboliche O_RDONLY ed altre); stdlib.h (per l uso della funzione exit()); errno.h (per la gestione degli errori). Il programma di Listato 1.1 mostra una possibile soluzione. Listato 1.1 I-ONumeri.c /* Esempio di gestione file a basso livello */ #define DIMBUF 10 #include <errno.h> /* gestione errori */ int main() int buf[dimbuf]=1,2,3,4,5,6,7,8,9,10, i; fd1; char *filename="i-onumeri.dat"; if ((fd1=open (filename, O_WRONLY O_CREAT))==-1) printf ("Impossibile aprire %s", filename); printf ("%d", errno); /* stampa codice di errore */ exit(1); for(i=0; i<dimbuf; i++) /* ciclo di caricamento in fd1 */ write (fd1, &buf[i], sizeof (int)); close(fd1); if ((fd1=open (filename, O_RDONLY))==-1) printf ("Impossibile aprire il file"); exit (1); for(i=0; i<10; i++) /* ciclo di lettura da fd1 e stampa dei valori */ read (fd1, &buf, sizeof (int)); printf ("%d\n", buf[i]);

2 close (fd1); si osservi, ad esempio nella scrittura, l utilizzo di errno, un numero intero che caratterizza il codice dell errore verificatosi; sempre a titolo di esempio, si noti che la lettura poteva essere realizzata anche con: read (fld1, &buf, sizeof (buf)); for(i=0; i<10; i++) printf ("%d\n", buf[i]); In questo modo, più rapido, si legge direttamente un blocco di dati nel buffer. 2) Scrivere un programma che carichi in un file binario una serie di stringhe. Il file viene gestito con le primitive a basso livello e termina quando si immette la stringa FINE. Il programma che risolve il problema è mostrato in Listato 1.2. Listato 1.2 I-OStringhe.c /* Scrittura stringhe in file a basso livello */ #define DIMBUF 128 void inserisci (char b[], int n); void stampa (char b[], int n); int main() char buf[dimbuf]; int fd1, fd2; char *filename="i-ostringhe.dat"; if ((fd1=open(filename, O_WRONLY O_CREAT))==-1) printf("impossibile aprire il file %s", filename); exit(1); /* errore in apertura fd1 */ inserisci(buf, fd1); /* inserisce dati */ close(fd1); if ((fd2=open(filename, O_RDONLY))==-1) printf("impossibile aprire il file %s", filename); exit(1); /* errore in apertura fd2 */ stampa(buf, fd2); /* legge dati */ close(fd2); void inserisci (char b[], int fdw) int i; printf("immettere il testo (digitare 'FINE' per uscire)\n"); for(i=0;i<dimbuf; i++) b[i]=0; /* pulisce il buffer */

3 do scanf("%s", b); if (write(fdw, b, DIMBUF)!=DIMBUF) printf("errore in scrittura!"); while (strcmp(b, "FINE")); void stampa (char b[], int fdr) while (read(fdr, b, DIMBUF)!=0) printf("%s\n", b); la funzione: void inserisci (char b[], int n); svuota il buffer, lo carica con la stringa successiva, letta da input e scrive il buffer in fd1 fino a quando non si incontra la stringa FINE ; dopo aver chiuso il file, la seconda open() lo apre in lettura e, in caso di successo, ne stampa il contenuto, altrimenti termina l esecuzione; la stampa è ottenuta con la funzione: void stampa (char b[], int n); che legge una ad una le stringhe da fd2 e le invia a stdout, fintantoché trova caratteri. 3) Si progetti, utilizzando le primitive di basso livello che operano sui file, un filtro, che prevede due argomenti passati da linea di comando, che devono essere considerati numeri interi positivi (N1 e N2). Il filtro deve, facendo uso delle funzioni primitive di accesso ai file, riportare sullo standard output (fd=1) una selezione dei caratteri dello standard input (fd=0): in uscita devono essere riportati solo i caratteri il cui codice ASCII è compreso tra N1 ed N2. Il problema si risolve molto semplicemente, convertendo N1 ed N2 ad interi e leggendo da stdin un carattere alla volta e inviandolo a stdout solo se compreso nel range richiesto. In Listato 1.3 è mostrata una possibile soluzione. Listato 1.3 FiltroCaratteri.c /* Filtro di input su caratteri */ int main (int argc, char **argv) int N1, N2, nread; char buf; if (argc<3) printf ("Uso: %s <int> <int> \n", argv[0]); exit(1); N1=atoi (argv[1]); N2=atoi (argv[2]);

4 while((nread=read (0,&buf,1))>0) if(((int)buf>=n1) && ((int)buf<=n2)) write (1, &buf, 1); 4) Scrivere un programma che registri valori interi in un file e che, successivamente, consenta di reperirne uno, in base alla sua posizione, immessa da input. Il file viene gestito con primitive a basso livello. Si usa un buffer (v. Listato 1.4) per caricare il file da programma. Si legge la posizione da recuperare e, tramite accesso diretto, si stampa il contenuto trovato nella posizione richiesta. Listato 1.4 I_ONumeriSeek.c /* Programma di esempio su lseek()*/ #define DIMBUF 10 #include <errno.h> int main() int buf[dimbuf]=1,2,3,4,5,6,7,8,9,10, i, fd1, pos, num; long offset; char *filename="i-onumeri.dat"; if ((fd1=open (filename, O_WRONLY O_CREAT))==-1) printf ("Impossibile aprire il file %s", filename); printf ("%d", errno); exit (1); write(fd1, &buf, sizeof (buf)); /* scrive un blocco di numeri */ close(fd1); printf ("Posizione: "); scanf ("%d", &pos); /* legge la posizione logica */ if ((fd1=open (filename, O_RDONLY))==-1) printf ("Errore in apertura\n"); exit (1); offset=(pos-1)*sizeof (int); /* calcolo offset */ lseek (fd1, offset, SEEK_SET); /* accede alla posizione */ read (fd1, &num, sizeof(int)); /* legge il dato */ printf ("Trovato: %d\n", num); close (fd1);

5 5) Considerare il prototipo della chiamata di sistema lseek(fd, offset, whence) a. spiegare il significato dei parametri della funzione; b. supponendo che il puntatore al file abbia inizialmente il valore 8111, e che la lseek() sia invocata sullo stesso file con offset 243 e con parametro whence che specifica che l offset è relativo al puntatore attuale, calcolare il valore del puntatore al termine della chiamata e specificare in quale blocco logico ricade il puntatore del file nell ipotesi che i blocchi abbiamo dimensione 1 Kb (1024 bytes). a. La lseek() permette di spostare il puntatore su un determinato byte di un file aperto. Il parametro fd è il descrittore di file (un intero restituito dalla open()), il parametro offset indica il numero di byte di cui ci vogliamo spostare e il parametro whence indica la posizione da cui iniziare lo spostamento (inizio file, fine file o posizione attuale); b. dopo la chiamata, il puntatore attuale vale 8354 e si trova nel nono blocco (blocco numero 8). 2. File locking 1) Scrivere un programma che accede ad un file, aprendolo in scrittura. Il file, deve essere acceduto anche da altri processi, per cui si deve garantire l accesso esclusivo di un processo alla volta. Pertanto, il programma deve chiedere il locking del file: se il file è disponibile, il processo occupa la risorsa, altrimenti ne chiede il locking per un dato numero di volte, intervallando le richieste di due secondi. Si preveda un numero massimo di tentativi di accesso, falliti i quali, compare un messaggio del tipo File occupato. Se il file diventa disponibile, prima che i tentativi di accesso siano terminati, il processo applica il lock e occupa la risorsa. Il programma legge il nome del file in filename, passato da linea di comando ed ha una struttura simile a quella del programma precedente file-locking.c. Tuttavia è presente una costante MAX_TRY inizializzata a 3 che indica il massimo numero di tentativi di accesso, ed un contatore di accessi try inizializzato a 1. Si apre il file fd in scrittura, si inizializza la variabile lock di tipo struct flock e si imposta l attributo l_type a F_WRLCK. La SC fcntl() viene posta in un ciclo insieme al controllo (try <= MAX_TRY), all interno del quale una SC sleep(2) temporizza i tentativi di accesso ogni due secondi. Se il ciclo termina per esaurimento dei tentativi, si stampa un messaggio di errore e il processo termina, altrimenti stampa un messaggio che avverte che il file è bloccato. Il termine del processo, e il conseguente sblocco del file, avviene con la pressione di un tasto, analogamente a quanto visto in file-locking.c. Listato 2.3 file-locking-try.c /* Richiesta di lock ciclica */ #include <errno.h> #include <unistd.h> #define MAX_TRY 3 void printout(char *s); int main(int argc, char *argv[]) char *filename=argv[1]; int fd, try=1; struct flock lock; printout("apertura...");

6 fd=open(filename, O_WRONLY); if (fd==-1) /* se il file non può essere aperto */ printf("errore in open()!\n"); exit(1); /* stampa errore ed esce */ memset(&lock, 0, sizeof(lock)); /* altrimenti inizializza flock */ printout("sto bloccando..."); lock.l_type=f_wrlck; /* setta il write lock */ while((fcntl(fd, F_SETLK, &lock)<0) && (try<=max_try)) /* effettua tentativi di accesso */ printf("\ntry %d...", try); try++; sleep(2); /* ogni 2 secondi */ if (try>max_try) /* se i tentativi sono esauriti */ printout("file occupato...riprovare!\n"); exit(1); /* esce, altrimenti */ printout("bloccato..."); /* conserva il blocco fino a che */ getchar(); /* viene premuto un tasto */ lock.l_type=f_unlck; fcntl(fd, F_SETLKW, &lock); /* il file viene sbloccato...*/ close(fd); /* e chiuso */ void printout(char *s) printf("\n%s", s); si noti la presenza del flag F_SETLK, che non blocca il processo se il lock non è disponibile; lanciando lo stesso programma da un altro terminale, si notano le stampe try 1 try 2 che indicano i tentativi di accesso. Se, nel frattempo, prima che try arrivi a 3, si sblocca il file dal primo terminale, il conteggio nel secondo terminale si interrompe ed il processo blocca, a sua volta, il file. Il tutto avviene reciprocamente, scambiando il ruolo dei due terminali. 2) Scrivere una applicazione che acceda in scrittura ad un file di caratteri per modificare un carattere in una data posizione. Il programma deve consentire l accesso esclusivo al file, applicando un blocco sulla sola porzione da modificare. In questo caso, anziché bloccare l intero file, è sufficiente applicare il lock al solo blocco di byte interessato alla modifica. In questo modo, altre applicazioni concorrenti possono accedere alle altre porzioni del file in lettura/scrittura.

7 Listato 2.4 record-locking.c /* Programma di esempio per il record locking */ #include <unistd.h> #include <errno.h> int main(int argc, char *argv[]) int fd; struct flock fl; fd = open("prova.txt", O_RDWR); if (fd == -1) /* In caso di errore...*/ printf("errore di apertura!"); exit(1); /*... esce, altrimenti...*/ fl.l_type = F_WRLCK; /*... imposta lock in scrittura...*/ fl.l_whence = SEEK_SET; fl.l_start = 4; /*... sui byte da 4 a 6 */ fl.l_len = 2; if (fcntl(fd, F_SETLK, &fl) == -1) printf("bloccato...\n"); else getchar(); /* mantiene il blocco...*/ lseek(fd, (long)2*sizeof(char), SEEK_SET); write(fd, "*", 2); /* effettua la modifica e */ fl.l_type = F_UNLCK; /* sblocca la risorsa */ fl.l_whence = SEEK_SET; fl.l_start = 4; fl.l_len = 2; exit(0); il programma richiede il lock dei byte da 4 a 6; in caso di risorsa occupata, il locking è non bloccante e fa terminare la richiesta. L applicazione che detiene l accesso al file, alla pressione di un carattere, applica la modifica e successivamente sblocca la risorsa; la funzione getchar() consente di verificare, lanciando il programma da un altra login, che la risorsa è effettivamente bloccata e che il locking non è bloccante (il programma stampa Bloccato e termina).

Lab. di Sistemi Operativi - Esercitazione n 9- -Thread-

Lab. di Sistemi Operativi - Esercitazione n 9- -Thread- Lab. di Sistemi Operativi - Esercitazione n 9- -Thread- 1 Sommario Esercizi su: Comunicazione tra processi: la funzione pipe() Condivisione dati e codice tra due o più processi: concetto di Thread 2 -

Подробнее

Comunicazione tra processi: pipe Le pipe sono un meccanismo UNIX di Inter Process Communication (IPC)

Comunicazione tra processi: pipe Le pipe sono un meccanismo UNIX di Inter Process Communication (IPC) Comunicazione tra processi: pipe Le pipe sono un meccanismo UNIX di Inter Process Communication (IPC) Le pipe sono canali di comunicazione unidirezionali Limitazione pipe: permettono la comunicazione solo

Подробнее

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca. Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A. 2016-17 Pietro Frasca Lezione 20 Giovedì 22-12-2016 Comunicazione: pipe In Unix, processi possono comunicare

Подробнее

Lab. di Sistemi Operativi - Esercitazione n 7- -Gestione dei processi Unix-

Lab. di Sistemi Operativi - Esercitazione n 7- -Gestione dei processi Unix- Lab. di Sistemi Operativi - Esercitazione n 7- -Gestione dei processi Unix- 1 Sommario Esercizi sulla gestione dei processi Creazione di un nuovo processo: fork Sincronizzazione tra processi: wait 2 -

Подробнее

I files in C. A cura del prof. Ghezzi

I files in C. A cura del prof. Ghezzi I files in C A cura del prof. Ghezzi 1 Perchè i files? Realizzano la persistenza dei dati dati che sopravvivono all esecuzione del programma Sono delle strutture di dati sequenziali 2 Files e S.O. I files

Подробнее

L'Allocazione Dinamica della Memoria nel linguaggio C

L'Allocazione Dinamica della Memoria nel linguaggio C L'Allocazione Dinamica della Memoria nel linguaggio C Prof. Rio Chierego [email protected] http://www.riochierego.it/informatica.htm Sommario Questo documento tratta l'allocazione dinamica della memoria

Подробнее

La Comunicazione tra Processi in Unix

La Comunicazione tra Processi in Unix La Comunicazione tra Processi in Unix La è un canale di comunicazione tra processi: unidirezionale: accessibile ad un estremo in lettura ed all'altro in scrittura molti-a-molti: più processi possono spedire

Подробнее

Aritmetica dei puntatori

Aritmetica dei puntatori Aritmetica dei puntatori Marco Alberti Programmazione e Laboratorio, A.A. 2016-2017 Dipartimento di Matematica e Informatica - Università di Ferrara Ultima modifica: 7 dicembre 2016 sizeof L operatore

Подробнее

Puntatori. Un puntatore contiene un numero che indica la locazione di memoria dove è presente la variabile puntata

Puntatori. Un puntatore contiene un numero che indica la locazione di memoria dove è presente la variabile puntata Puntatori int i = 10; int * pi = &i; pi i = 10 116 int * pi = pi contiene un informazione che mi permette di accedere ( puntare ) ad una variabile intera Un puntatore contiene un numero che indica la locazione

Подробнее

ERRATA CORRIGE. void SvuotaBuffer(void); void SvuotaBuffer(void) { if(getchar()!=10) {svuotabuffer();} }

ERRATA CORRIGE. void SvuotaBuffer(void); void SvuotaBuffer(void) { if(getchar()!=10) {svuotabuffer();} } ERRATA CORRIGE Pulizia del buffer di input: come fare? (1) Dopo aver richiamato getchar() per prelevare un carattere dal buffer di input, inseriamo una seconda chiamata a getchar(), senza assegnare il

Подробнее

Gestione dei file. File di testo e binari

Gestione dei file. File di testo e binari Gestione dei file Un file e definito come un oggetto, presente nel file system, costituito da una sequenza continua di bytes Un file, per poter essere utilizzato, deve essere aperto Successivamente e possibile

Подробнее

File binari e file di testo

File binari e file di testo I file File binari e file di testo distinzione tra file binari file di testo si possono usare funzioni diverse per la gestione di tipi di file diversi Programmazione Gestione dei file 2 File binari e file

Подробнее

Gestione dei file in C

Gestione dei file in C Gestione dei file in C Fondamenti di Informatica Che cos è un file e a cosa serve? Memoria di massa vs memoria centrale q La memoria di massa (disco fisso) è un dispositivo di memorizzazione generalmente

Подробнее

Laboratorio di. Reti Informatiche. Corso di Laurea Triennale in Ingegneria Informatica A.A. 2017/2018. Ing. Carlo Vallati

Laboratorio di. Reti Informatiche. Corso di Laurea Triennale in Ingegneria Informatica A.A. 2017/2018. Ing. Carlo Vallati Laboratorio di Reti Informatiche Corso di Laurea Triennale in Ingegneria Informatica A.A. 2017/2018 Ing. Carlo Vallati [email protected] 1 Esercizi Programmazione con i socket 2 Programma di oggi

Подробнее

CORSO DI SISTEMI OPERATIVI A - ESERCITAZIONE 3

CORSO DI SISTEMI OPERATIVI A - ESERCITAZIONE 3 UNIVERSITÀ DEGLI STUDI DI PARMA Facoltà di Ingegneria Corso di Laurea in Ingegneria Elettronica-Informatica-Telecomunicazioni a.a. 2001-2002 CORSO DI SISTEMI OPERATIVI A - ESERCITAZIONE 3 1 Trasferimento

Подробнее

Corso di Laboratorio di Sistemi Operativi

Corso di Laboratorio di Sistemi Operativi Corso di Laboratorio di Sistemi Operativi Lezione 5 Alessandro Dal Palù email: [email protected] web: www.unipr.it/~dalpalu Processi in Unix Approfondimenti: http://gapil.gnulinux.it/download/

Подробнее

La sincronizzazione è legata alla implementazione delle pipe: int pipe(int fd[2]);

La sincronizzazione è legata alla implementazione delle pipe: int pipe(int fd[2]); int pipe(int fd[2]); Le pipe sono canali di comunicazione unidirezionali che costituiscono un primo strumento di comunicazione (con diverse limitazioni), basato sullo scambio di messaggi, tra processi

Подробнее

C: panoramica. Violetta Lonati

C: panoramica. Violetta Lonati C: panoramica Violetta Lonati Università degli studi di Milano Dipartimento di Scienze dell Informazione Laboratorio di algoritmi e strutture dati Corso di laurea in Informatica AA 2009/2010 Violetta Lonati

Подробнее

A.1 Programma di comunicazione su porta seriale

A.1 Programma di comunicazione su porta seriale Appendice A Programmi di gestione dell apparato A.1 Programma di comunicazione su porta seriale /* INCLUDE */ #include #include #include #include #include

Подробнее

Programmazione di sistema in Linux: gestione dei file. E. Mumolo

Programmazione di sistema in Linux: gestione dei file. E. Mumolo Programmazione di sistema in Linux: gestione dei file E. Mumolo Struttura di Linux System Call per il file system System Call per i processi Hardware: dischi, CPU, monitor, tastiera, schede di rete, porte

Подробнее