Esercizi di lettura di codice C

From Sistemi Operativi
Revision as of 15:43, 16 October 2015 by Alessio (talk | contribs)
Jump to navigation Jump to search

Questi programmi non sono necessariamente stilisticamente belli (non sono "esempi da copiare") ma presentano dei passaggi di non semplice lettura.

Il consiglio e' di compilarli, provarli e capirne passo-passo il funzionamento. (o spiegare perche' non funzionino).

Ovviamente potete proporre ulteriori esempi. Renzo (talk) 15:42, 10 October 2015 (CEST)

programma 0

#include <stdio.h>

int main(int argc, char *argv[]) {
        int c;
        while ((c=getchar())!=EOF)
                putchar(c);
        return 0;
}

In questo esempio tutto ciò che viene preso in input viene messo in output, fino a quando non viene digitato il carattere di End of File (EOF). Solitamente nei sistemi DOS il carattere EOF viene definito come la combinazione di tasti CTRL+Z, mentre nei sistemi basati su Unix si utilizzano i tasti CTRL+D. (S.G)

Nel caso l'input provenga da file e non da tastiera (ad esempio eseguendo da terminale la riga di comando "./programma0 < testo"), il carattere speciale EOF viene inserito automaticamente alla fine del file "testo". In questo caso il programma prende in input il contenuto di "testo" e stampa a video (carattere per carattere), il contenuto del file, finchè non riconosce il carattere speciale EOF, che fa terminare il ciclo while.

programma 1

#include <stdio.h>

char s1[]="hello world";
char *s2="hello world";

void foo(char *s) {
        printf("%s\n",s);
        s[4]=',';
        printf("%s\n",s);
}

int main(int argc, char *argv[]) {
        foo(s1);
        foo(s2);
        return 0;
}

In questo esempio viene mostrata la differenza tra stringa variabile (s1) e stringa costante (s2). Nel primo caso a tempo di compilazione la stringa costante "hello world" viene copiata passo nella stringa variabile s1 consentendo le normali operazioni di modifica della stringa stessa. Mentre nel secondo caso a tempo di compilazione viene creata la stringa costante "hello world" e memorizzato il suo indirizzo nella variabile s2 NON consentendo le normali operazioni di modifica delle stringa stessa in quanto appunto un costante. (S.G)

programma 2

#include <stdio.h>

char t[]="test";
struct st {
        char s[5];
        char *t;
} st0={"test",t};

void foo (struct st i) {
        i.s[2]='n';
        i.t[2]='n';
}

void bar (struct st *i) {
        i->s[2]='x';
        i->t[2]='x';
}

int main(int argc, char *argv[]) {
        printf("%s %s\n",st0.s,st0.t);
        foo(st0); /* Vengono copiati i valori della struttura st0 in i, le uniche modifiche saranno sul campo i.t in quanto puntatore. */
        printf("%s %s\n",st0.s,st0.t); 
        bar(&st0); /* Viene copiato l'indirizzo della struttura st0 in i, le modifiche vengono apportate su tutti i campi delle struttura. */
        printf("%s %s\n",st0.s,st0.t);
        return 0;
}

Output del programma:

test test

test tent

text text

(S.G)

programma 3

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
        while (argc > 1) {
                int i,j;
                char *s=argv[1];
                for (i=0, j=strlen(s)-1; i < j; i++, j--)
                        s[i] ^= s[j], s[j] ^= s[i], s[i] ^= s[j];
                printf("%s ",s);
                argc--;
                argv++;
        }
        printf("\n");
        return 0;
}

In questo esempio il programma effettua un reverse di tutte le parole che gli vengo date in input ad esclusione di argv[0] che sarebbe il nome del programma, esempio:

INPUT: ./programma3 ciao sistemi operativi

OUTPUT: oaic imetsis ivitarepo

Il punto importante di questo codice è che lo scambio delle singole lettere viene effettuato con l'operatore logico XOR senza cosi avere bisogno di una "variabile di scambio". Qui viene spiegato nel dettaglio il funzionamento dell'operatore logico

(S.G)

programma 4

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct elem {
        char *s;
        struct elem *next;
};
struct elem *root=NULL;

void insert(char *s, struct elem **elp) { /* Inserimento in ordine alfabetico */
        if (*elp && strcmp((*elp)->s, s) < 0) /* se la lista elp non è vuota e se (*elp)->s è alfabeticamente minore di s, inserisce in coda s */
                insert(s,&((*elp)->next));
        else { /* nel caso in cui la lista è vuota o se (*elp)->s è alfabeticamente maggiore di s, inserisce in testa s */
                struct elem tmp={s,*elp};
                struct elem *new=malloc(sizeof(struct elem));
                *new=tmp;
                *elp=new;
        }
}

struct elem *print(struct elem *root) { /* stampa l'intera lista, alla fine dealloca root e restituisce NULL */
        if (root) {
                printf("%s ",root->s);
                root->next=print(root->next);
                free(root);
                return NULL;
        }
}

int main(int argc, char *argv[]) {
        for (;argc>1;argc--,argv++) /* Scorre tutti gli elementi in input del programma (tranne il nome stesso del programma), aggiungendoli in una lista */
                insert(argv[1],&root);
        root=print(root);
        printf("\n");
        return 0;
}

Il programma ordina alfabeticamente gli elementi presi input, esempio:

INPUT: ./programma4 ciao sistemi operativi e macchine virtuali

OUTPUT: ciao e macchine operativi sistemi virtuali

(S.G)

Programma 5

Propongo un esempio relativo all'uso dello statement static:

#include <stdio.h>

int var;

int foo(){
	static int var=0;
	var++;
	return var;
}

int bar(){
	int var=0;
	var ++;
	return var;
}

int foobar(){
	var++;
	return var;
}

int main(int argc, char *argv[]){
	int sum1, sum2, sum3;
	int i;
	for(i=0;i<100;i++){
		sum1=foo();
	}
	printf("%d\n", sum1);
	for(i=0;i<100;i++){
		sum2=bar();
	}
	printf("%d\n", sum2);
	for(i=0;i<100;i++){
		sum3=foobar();
	}
	printf("%d\n", sum3);

	return 0;
}