Manuali, links, fotografie e tanto altro
alla portata di un semplice click!
 
 Benvenuto Ospite
Manuali, immagini, fotografie e tanto altro a portata di un click

Cartoline virtuali

Cartolina n° 819



Sono presenti 1307 cartoline virtuali. Entra ora


Giochi online
Happy Landing


1. ermesiti: 10
1. barone400: 10
2. Mike86: 8

Visualizza tutti i giochi.

News Reader















Introduzione alla programmazione in C, Fiorella Sartori email Autore
.: Data Pubblicazione 02-Nov-2004 :: Letture:: 1429 :: Recensione :: Stampa solo questa pagina :: Stampa pagina con tutte le sottopagine:.
01. Caratteristiche del linguaggio C 
02. Storia del linguaggio C 
03. Primo approccio 
04. Compilazione di un programma C 
05. Struttura di un programma C 
06. Variabili 
	06.01. Stampa ed input di variabili 
07. Operatori 
	07.01. Operatori aritmetici 
	07.02. Operatori di confronto 
	07.03. Operatori logici 
	07.04. Operatori di basso livello 
		07.04.01. Operatori di bitwise 
		07.04.02. Bit Fields 
	07.05. Ordine di precedenza degli operatori 
08. Strutture di controllo 
	08.01. If 
	08.02. Operatore "?" 
	08.03. Switch 
	08.04. For 
	08.05. While 
	08.06. Do-While 
	08.07. Break e Continue 
09. Arrays 
	09.01. Array singoli e multidimensionali 
	09.02. Stringhe 
10. Funzioni 
	10.01. Funzioni "void" 
	10.02. Funzioni ed array 
	10.03. Prototipi di funzioni 
11. Ulteriori tipi di dati 
	11.01. Strutture 
	11.02. Unioni 
	11.03. Type-casting 
	11.04. Enumerated Types 
	11.05. Variabili statiche 
12. Errori comuni in C 
	12.01. Assegnazione (=) al posto di confronto (==) 
	12.02. Passaggio dell'indirizzo di puntatori 
	12.03. Mancanza di () per una funzione 
	12.04. Indici di array 
	12.05. Array di caratteri e puntatori 
	12.06. C e' case-sensitive 
	12.07. ";" chiude ogni istruzione 
13. Puntatori 
	13.01. Cos'e' un puntatore 
	13.02. Puntatori e funzioni 
	13.03. Puntatori e array 
	13.04. Array di puntatori 
	13.05. Array multidimensionali e puntatori 
	13.06. Inizializzazione statica degli array di puntatori 
	13.07. Puntatori e strutture 
	13.08. Le "trappole" piu' comuni dei puntatori 
		13.08.01. Non assegnare un puntatore ad un indirizzo di 
			  memoria prima di utilizzarlo 
		13.08.02. Assegnazione indiretta illegale 
14. Allocazione dinamica della memoria 
	14.01. Malloc 
	14.02. Linked Lists 
15. Input ed output 
	15.01. Streams 
		15.01.01. Streams predefinite 
			15.01.01.01. Redirezione 
	15.02. Funzioni comuni di I/O 
	15.03. Formattazione di I/O 
		15.03.01. Printf 
	15.04. Scanf 
	15.05. Files
		15.05.01. Lettura e scrittura su files 
	15.06. Sprintf ed Sscanf 
	15.07. Input dalla linea di comando 
	15.08. I/O di basso livello 
16. Il preprocessore C 
	16.01. #define 
	16.02. #undef 
	16.03. #include 
	16.04. #if - Inclusione condizionale 
17. Scrittura di grossi programmi 
	17.01. File header 
	17.02. Variabili esterne e funzioni 
		17.02.01. Scopo delle variabili esterne 
	17.03. L'utility Make 
	17.04. Programmazione di Make 
	17.05. Creazione di un makefile 
	17.06. Macro di Make 
	17.07. Esecuzione di Make 
18. UNIX e il C 
	18.01. Vantaggi di usare UNIX con il C 
	18.02. Utilizzo delle chiamate di sistema UNIX e delle funzioni 
	       di libreria 
	18.03. Trattamento di file e directory 
		18.03.01. Funzioni di trattamento delle directory 
		18.03.02. Routine di trattamento dei file 
		18.03.03. errno 
	18.04. Controllo e gestione dei processi 
		18.04.01. Esecuzione di comandi UNIX da C 
			18.04.01.01. execl() 
			18.04.01.02. fork() 
			18.04.01.03. wait()
			18.04.01.04. exit() 
		18.04.02. Utilizzo di pipe in un programma C 
			18.04.02.01. popen() - Piping formattato 
			18.04.02.02. pipe() - Piping di basso livello 
		18.04.03. Interruzioni e segnali 
			18.04.03.01. Invio di segnali - kill() 
			18.04.03.02. Ricezione di segnali - signal() 
	18.05. Times Up!! 
19. Opzioni comuni del compilatore C 
	19.01. Opzioni di compilazione 
20. Funzioni della libreria standard C 
	20.01. Manipolazione dei buffer 
	20.02. Classificazione dei caratteri e conversione 
	20.03. Conversione dei dati 
	20.04. Manipolazione delle directory 
	20.05. Manipolazione dei file 
	20.06. Input e Output 
		20.06.01. Stream I/O 
		20.06.02. I/O di basso livello 
	20.07. Matematica 
	20.08. Allocazione di memoria 
	20.09. Controllo dei processi 
	20.10. Ricerca e ordinamento 
	20.11. Manipolazione di stringhe 
	20.12. Time 

==============================================================================

------------------------------------------------------------------------------
01. Caratteristiche del linguaggio C 
------------------------------------------------------------------------------

  Qui di seguito verranno elencate brevemente alcune delle caratteristiche del
  C che definiscono il linguaggio stesso e che hanno contribuito alla 
  popolarita' che ha raggiunto come linguaggio di programmazione:

  - dimensioni ridotte
  - utilizzo frequente di chiamate a funzioni
  - loose typing (a differenza del Pascal)
  - linguaggio strutturato
  - programmazione a basso livello facilmente disponibile
  - implementazione dei puntatori (ampio uso di puntatori per memoria, 
    vettori, strutture e funzioni)

  Il C e' ora diventato un linguaggio professionale ampiamente utilizzato per
  varie ragioni:

  - ha strutture di alto livello
  - puo' maneggiare attivita' di basso livello
  - produce programmi efficienti
  - puo' essere compilato su un'ampia gamma di computers

  Il suo principale inconveniente e' quello di avere un metodo scadente per
  l'identificazione di errori, che puo' escluderne l'utilizzo ai principianti. 
  Comunque con un minimo di diligenza si puo' risolvere elegantemente questo 
  problema, in quanto si possono violare le regole del C non appena si sono 
  imparate (non molti linguaggi lo permettono). Nel caso in cui venga fatto 
  correttamente e con attenzione, questo porta a sfruttare le potenzialita'
  della programmazione C.
  Lo standard per i programmi C in origine era dato dalle caratteristiche 
  messe a punto da Brian Kernighan. Al fine di rendere il linguaggio piu' 
  accettabile a livello internazionale, venne messo a punto uno standard 
  internazionale chiamato ANSI C (American National Standards Institute).

------------------------------------------------------------------------------
02. Storia del linguaggio C 
------------------------------------------------------------------------------

  Le pietre miliari nel corso dell'evoluzione del C come linguaggio sono 
  elencate di seguito:

  - UNIX developed c. 1969 - DEC PDP-7 Assembly Language
  - BCPL - un OS facilmente accessibile che fornisce potenti strumenti di 
    sviluppo prodotti a partire da BCPL. Si tratta di un assemblatore noioso, 
    lungo ed incline agli errori
  - Un nuovo linguaggio "B" come secondo tentativo c. 1970
  - Un linguaggio "C" totalmente nuovo come successore di "B" c. 1971
  - Dal 1973 UNIX OS, quasi totalmente scritto in C 

------------------------------------------------------------------------------
03. Primo approccio 
------------------------------------------------------------------------------

  Un minimo programma in C e':

	main()
	  {
 
	  }

  che corrisponde a un programma in Pascal:

	program minimum;

	begin

	end

  Ogni programma C deve contenere una e una sola funzione main().
  Per ogni parentesi graffa aperta (che corrisponde al begin in pascal)
  deve essercene una chiusa (che corrisponde all'end in pascal).

  I commenti possono essere posti ovunque utilizzando /* (inizio commento)
  e */ (fine commento), ma non si puo' inserire un commento in un altro. 
  Ad esempio:

	/* Esempio di programma in C */
	main()
	  {
	    /* Un ulteriore commento */               ESATTO 
	    /* Commento /* Ancora un commento */ */   ERRATO 
	  }

  Il seguente esempio e' un programma che produce l'output sullo
  schermo della frase "Hello World":

        main()
          {
	    printf("Hello World n");
	    exit(0);
          }

  L'istruzione "printf" e' una funzione C che visualizza cio' che gli
  viene passato come argomento.

  Per creare un file contenente uno dei precedenti programmi si puo'
  utilizzare un qualsiasi text editor disponibile sulla macchina (vi, emacs,
  xedit, ...).
  Il nome del file deve avere l'estensione ".c", cioe' chiamarsi, ad esempio, 
  prog.c. Il contenuto, ovviamente, deve rispettare la sintassi C; per quanto 
  riguarda gli esempi sopra riportati, potrebbero iniziare con una riga del
  tipo
     /* Esempio ... */          (anche con una linea vuota che la precede)
  e terminare con la linea
     } /* Fine del programma */ (anche con una linea vuota che la segue)

------------------------------------------------------------------------------
04. Compilazione di un programma C 
------------------------------------------------------------------------------

  Per compilare il programma si utilizza il comando cc seguito dal nome del
  programma C sorgente, dove "cc" e' il nome del compilatore C. 
  Ad esempio:
		cc prog.c

  Se il compilatore trova errori (in genere syntax error, come errori di 
  battitura, errori di sintassi delle parole chiave o ";" omessi), questi 
  vengono identificati e visualizzati; in caso contrario, viene creato il 
  file eseguibile a.out. Il compilatore non identifica eventuali errori di
  logica del programma, quindi potrebbero essere eseguite delle operazioni
  errate, ed e' compito dell'utente trovarle (anche con l'ausilio di appositi
  programmi di debugging).
  In fase di compilazione possono essere specificate anche ulteriori opzioni: 
  la piu' utilizzata e' "-o nome-file", che crea l'eseguibile con il nome 
  nome-file invece di a.out, ma ne esistono altre come ad esempio "-c" 
  (opzione senza argomenti, per la soppressione di link).
  Altra opzione possibile e' "-g", con cui e' necessario compilare per poter 
  utilizzare il debugger "dbx".
  Ad esempio:	
		cc prog.c -o prog (oppure cc -o prog.c prog)
		cc -c prog.c -o prog
		cc -g prog.c -o prog

  Per far eseguire il programma e' sufficiente scrivere il nome 
  dell'eseguibile creato (e' ovvio che il file eseguibile deve avere i 
  permessi per l'esecuzione, solitamente assegnati automaticamente in fase di
  compilazione):
  si avranno visualizzati sullo schermo gli eventuali risultati.
  Nel momento dell'esecuzione e' possibile osservare ed identificare eventuali
  errori di run-time, come ad esempio le divisioni per zero; in tal caso 
  l'esecuzione termina irregolarmente e viene generato un file core con lo
  stato del programma in esecuzione al momento del verificarsi dell'errore.
  Se il programma in esecuzione non rilascia errori ma produce output errati, 
  e' evidente che contiene errori logici; questi andranno corretti editando 
  il programma sorgente, questo dovra' essere ricompilato e si potra' lanciare
  nuovamente l'esecuzione.

  La compilazione del programma C avviene attraverso le seguenti fasi:

   - un preprocessore che accetta il codice sorgente come input 
     ed e' resposabile della: 

  	 - rimozione di commenti 
   	 - interpretazione di speciali direttive per il preprocessore 
	   denotate da "#". 
    	   Ad esempio: 
		#include - include il contenuto di un determinato file
                           (solitamente chiamato header, con suffisso ".h").
        		 #include  - standard library maths file. 
         		 #include  - standard library I/O file 
		#define  - definisce un nome simbolico o una costante
			   (sostituzione di una macro).
            		 #define MAX_ARRAY_SIZE 100 

   - il compilatore C che traduce il codice sorgente ricevuto dal 
     preprocessore in codice assembly.

   - l' assembler che crea il codice oggetto (in UNIX i file con il suffisso
     .o sono i file in codice oggetto, che corrispondono ai file .obj in 
     MSDOS).

   - il link editor che combina le funzioni definite in altri file sorgenti 
     o definite in librerie, con la funzione main() per creare il file 
     eseguibile.
     Infatti molte delle funzioni presenti in altri linguaggi non sono incluse
     nel C (ad esempio, funzioni di I/O, di manipolazione di stringhe o 
     matematiche), ma il C fornisce tali funzionalita' attraverso un ricco 
     insieme di librerie di funzioni. Molte applicazioni C includono librerie
     standard di funzioni per coprire le utilita' mancanti. 
     In questa fase vengono anche ricostruiti i riferimenti alle variabili
     esterne utilizzate nei sorgenti C.

------------------------------------------------------------------------------
05. Struttura di un programma C 
------------------------------------------------------------------------------

  Un programma C ha in linea di principio la seguente forma:

	Comandi per il preprocessore
	Definizione di tipi
	Prototipi di funzioni (dichiarazione dei tipi delle funzioni e delle
                               variabili passate alle funzioni)
	Variabili
	Funzioni	
    
  Vediamo l'esempio di un programma:
    
    	main()
         {
           printf("I like Cn");
           exit(0);
         }  
   
  Note:
     - Il C richiede un punto e virgola alla fine di ogni statement.
     - printf() e' una funzione standard richiamata da main.
     - n significa una nuova linea (a capo).
     - exit() e' anch'essa una funzione standard che fa terminare il programma 
       (qui non sarebbe necessaria in quanto e' l'ultima linea di main e il 
       programma terminerebbe comunque).

------------------------------------------------------------------------------
06. Variabili 
------------------------------------------------------------------------------

  Il C ha i seguenti tipi di dati:
       
        Tipo			Size (byte)
	        
        char				1	
        unsigned char			1
        short int			2
        unsigned short int		2
        (long) int 			4
        float				4
        double				8
 
  Sui sistemi UNIX tutte le variabili dichiarate "int" sono considerate
  "long int", mentre "short int" deve essere dichiarato esplicitamente. 
  E' importante notare che in C non esiste un tipo di variabile booleano,
  quindi si possono utilizzare variabili "char", "int" o meglio "unsigned
  char". "unsigned" puo' essere utilizzato con tutti i tipi "char" e "int".

  Per dichiarare una varibile si scrive:
	 var_tipo elenco-variabili-separate-da-virgole ;
 
  Le variabili globali si definiscono al di sopra della funzione main(),
  nel seguente modo:

	short number,sum;
	int bignumber,bigsum;
	char letter;
	main()
	{
	...
	}

  E' possibile preinizializzare una variabile utilizzando = (operatore di 
  assegnazione).	
  Ad esempio:	
	int i,j,k=1;
	float x=2.6,y;
	char a;

  Vediamo due esempi di inizializzazione di variabili che si equivalgono,
  senza pero dimenticare che il metodo utilizzato nel primo esempio 
  risulta piu' efficiente:

  Esempio 1:     float sum=0.0;
		 int bigsum=0;
		 char letter='A';
		 main()
		 {
		 ...
		 }
  Esempio2:      float sum;
		 int bigsum;
		 char letter;
		 main()
		 {
		 sum=0.0;
		 bigsum=0;
		 letter='A';
		 ...
		 }
		 	
  E' possibile effettuare assegnazioni multiple purche' le variabili
  siano dello stesso tipo.	  	
  Ad esempio:
  
 	int somma;
 	char letter="A";			
	main()
	  { 
	    int a,b,c=3;
	    a=b=c;
	  }
  dove l'istruzione a=b=c (con c=3) corrisponde ad a=3, b=3 e c=3, ma
  anche in questo caso risulta piu' efficiente il primo metodo.
 
  Si possono definire nuovi propri tipi di variabili utilizzando "typedef"
  (questo risulta utile quando si creano strutture complesse di dati).
  Come esempio di utilizzo semplice consideriamo come sia possibile creare
  i due nuovi tipi di variabile "real" e "letter", che potranno successiva-
  mente essere utilizzati alla stessa maniera dei tipi predefiniti del C.
  Ad esempio:
 	 typedef float real;
 	 typedef char letter;
      variabili dichiarate:
 	 real sum=0.0;	  
	 letter nextletter;

------------------------------------------------------------------------------
06.01. Stampa ed input di variabili 
------------------------------------------------------------------------------

  Il C sfrutta l'output formattato.

  Per stampare il contenuto di una variabile si utilizza la funzione printf().
  Bisogna pero' specificare il formato della variabile utilizzando il 
  carattere speciale di formattazione "%" seguito dal carattere che definisce 
  un certo formato per una variabile:
  
 	 %c  - char
 	 %d  - int
 	 %f  - float
  	
  Ad esempio:	printf("%c%d%f",letter,somma,z);	

  Nota: l'istruzione di formattazione e' racchiusa tra "", e le variabili 
        vengono esposte di seguito; assicurarsi che l'ordine dei formati ed
        il tipo di dato delle variabili coincidano.

  Sempre a proposito della funzione "printf", vediamo il seguente esempio di
  una istruzione di stampa:

	printf(".n.1n..2n...3n");

  per la quale l'output sara': 

	.
	.1
	..2
	...3
 
  scanf() e' la funzione per l'input di valori a strutture di dati.
  Il suo formato e' simile a quello di printf():
   
      scanf("%c%d%f",&ch,&i,&x);  

  Nota: "&" si riferisce all'indirizzo della variabile, e va sempre messo 
	davanti ai nomi di variabili in acquisizione; il motivo verra' 
	spiegato nel paragrafo dei "puntatori".

------------------------------------------------------------------------------
07. Operatori 
------------------------------------------------------------------------------
 
------------------------------------------------------------------------------
07.01. Operatori aritmetici 
------------------------------------------------------------------------------

  Come gia' accennato, le assegnazioni in C vengono effettuate utilizzando 
  "=".  Oltre agli operatori arimetici standard +,-,*,/  e all'operatore % 
  (modulo) per gli interi, in C si hanno anche gli operatori incremento ++ 
  e decremento --, che possono essere preposti o posposti all'argomento. Se 
  sono preposti il valore e' calcolato prima che l'espessione sia valutata, 
  mentre se sono posposti il valore viene calcolato dopo la valutazione della 
  espressione.
  Ad esempio:
     		  int x,z=2;    
      	 1)	  x=(++z)-1; 
			 A questo punto x=2 e z=3
       
      		  int x,z=2;    
       	 2)	  x=(z++)-1; 
			 A questo punto x=1 e z=3

  Riportiamo un ulteriore esempio:
	int x,y,w;
	main()
	{
	x=((++z)-(w--))%100;
	}
  che equivale alle seguenti istruzioni:
	int x,y,w;
	main()
	{
	z++;
	x=(z-w)%100;
	w--;
	}
		 	
  E' importante sottolineare che un'istruzione del tipo
	x++
  e' piu' veloce della corrispondente
	x=x+1

  L'operatore "%" (modulo) puo' essere utilizzato solamente con le variabili
  di tipo integer; la divisione "/" e' utilizzata sia per gli integer che
  per i float.
  A proposito della divisione riportiamo un altro esempio:
	z=3/2
     dove z avra' valore 1, anche se e' stato dichiarato come float
     (di regola, se entrambi gli argomenti della divisione sono integer,
     allora verra' effettuata una divisione integer);
     per avere un risultato corretto sara' necessario scrivere:
	z=3.0/2     oppure 
	z=3/2.0     o, ancora meglio,
	z=3.0/2.0	

  Inoltre esiste una forma contratta per espressioni del tipo
   
	expr1 = expr1 op expr2
   
  (ad esempio: i=i+2 oppure x=x*(y+3))
  che diventano:

	expr1 op = expr2
   
  Per cui i=i+2 puo' essere scritta nel modo contratto come i+=2 
  od x=x*(y+3) diventare x*=y+3.

  Nota: l'espressione x*=y+3 corrisponde a x=x*(y+3) e non a x=x*y+3.

------------------------------------------------------------------------------
07.02. Operatori di confronto 
------------------------------------------------------------------------------

  Per testare l'ugualianza si usa "==" mentre per la disugualianza "!=".
  Ci sono poi gli operatori "<" (minore), ">" (maggiore), "<=" (minore o 
  uguale), ">=" (maggiore o uguale).
 
  NB. if (i==j) ... esegue il contenuto dell'if se i e' uguale a j, ma
      if (i=j) ... e' ancora sintatticamente esatto ma effettua l'assegnazione
      del valore di j ad i e procede se j e' diverso da zero in quanto
      viene interpretato il valore TRUE (e' come scrivere if i ... con i
      diverso da zero). In questo caso si tratterebbe di una "assegnazione di
      valore", una caratteristica chiave del C.

------------------------------------------------------------------------------
07.03. Operatori logici 
------------------------------------------------------------------------------

  Gli operatori logici, solitamente utilizzati con le istruzioni condizionali
  che vedremo piu' avanti, sono "&&" per AND logico  e "||" per OR logico.
  Nota: "&" e "|" hanno un significato diverso, poiche' sono bitwise AND e OR. 

------------------------------------------------------------------------------
07.04. Operatori di basso livello 
------------------------------------------------------------------------------

  Nel capitolo relativo ai puntatori si vedra' come questi permettano il 
  controllo delle operazioni di memoria di basso livello.

  Molti programmi (in particolare le applicazioni di gestione del sistema) 
  devono realmente operare a basso livello, poiche' lavorano su bytes 
  individuali.

  E' importante notare che la combinazione di puntatori e di operatori
  bit-level rendono il C utilizzabile per molte applicazioni a basso livello
  e possono quasi sempre sostituire il codice assembly (ricordiamo che 
  solamente circa il 10% di UNIX e' un codice assembly, mentre il resto e' C).

------------------------------------------------------------------------------
07.04.01. Operatori di bitwise 
------------------------------------------------------------------------------

  Gli operatori di bitwise (che operano sui singoli bit) sono i seguenti:
   "&" AND
   "|" OR
   "^" XOR
   "~" Complemento a 1 (0=>1, 1=>0)
   "<<" shift a sinistra
   ">>" shift a destra  
     
  Nota:	fare attenzione, come gia' detto in precedenza, a non confondere
        & con && (& e' "bitwise and", mentre && e' "logical and"); la stessa
	cosa vale per | e ||.

  "~" e' un operatore unario, cioe' opera su un solo argomento indicato a
  destra dell'operatore.

  Gli operatori di shift eseguono un appropriato shift dall'operatore indicato 
  a destra a quello indicato a sinistra. L'operatore destro deve essere 
  positivo. I bits liberati vengono riempiti con zero (cioe' non si tratta di
  una rotazione, con recupero sul lato opposto dei bit shiftati).

  Ad esempio: z<<2 shifta i bit in z di due posti verso sinistra
	      cosi',         se z=00000010 (binario) o 2 (decimale)
	      allora,  z>>=2 => z=00000000 (binario) o 0 (decimale)
	      inoltre, z<<=2 => z=00001000 (binario) o 8 (decimale)    

  Quindi, uno shift a sinistra e' equivalente ad una moltiplicazione per 2;
  similmente, uno shift a destra equivale ad una divisione per 2.  

  Nota: l'operazione di shift e' molto piu' veloce della reale moltiplicazione
	(*) o divisione (/); cosi', se occorrono veloci moltiplicazioni o 
        divisioni per 2 si puo' utilizzare lo shift. 

  Per illustrare le molteplici caratteristiche degli operatori di bitwise,
  riportiamo una funzione (bitcount) che somma 2 bit settati ad 1 un un numero 
  ad 8 bit (unsigned char) passato come argomento alla funzione:

      int bitcount(unsigned char x)

	    {int count;
	     for (count=0; x!=0; x>>=1);
	         if (x&01)
		    count++;
	     return count;
	    } 

  Questa funzione mostra molti punti del programma C:
	- il loop "for" non viene usato per semplici operazioni di somma
	- x>>=1 => x=x>>1
	- il loop "for" shifta ripetutamente a destra x, finche' x diventa 0
	- il controllo "if" utilizza la valutazione dell'espressione x &01
	- x &01 controlla il primo bit di x, ed esegue count++ se questo e' 1

------------------------------------------------------------------------------
07.04.02. Bit Fields 
------------------------------------------------------------------------------

  I Bit Fields permettono il raggruppamento dei dati in una struttura. Questa
  tecnica viene usata soprattutto quando la gestione della memoria o la 
  memorizzazione dei dati sono uno meta molto ambita.

  Tipici esempi sono costituiti da:

  - raggruppamento di parecchi oggetti in una parola macchinai (i flag di un 
    bit possono essere compattati); ad esempio, la tabella dei simboli 
    nell'ambito dei compilatori;
  - lettura di formati di file esterni (formati di file non standard possono
    essere importati); ad esempio, gli interi di 9 bit.

  Il C permette di fare questo in una definizione di struttura, mettendo
  ":lunghezza-bit" dopo la variabile stessa, e cioe':

     struct packed-struct {
	unsigned int f1:1;
	unsigned int f2:1;
	unsigned int f3:1;
	unsigned int f4:1;
	unsigned int type:4;
	unsigned int funny_int:9;
	} pack;

  Qui la struttura packed-struct contiene 6 elementi: 4 flag da 1 bit (f1,...
  f4) e funny_int da 9 bit.

  Il C automaticamente raggruppa assieme i campi di bit elencati nell'esempio
  appena riportato.

  Solitamente si accede ai membri della struttura nel seguente modo:

     pack.type = 7;

  Notiamo che:

  - solamente "n" bit di basso livello possono essere assegnati ad un numero
    di "n" bit. Cosi' il campo "type" non puo' assumere valori maggiori di 15 
    (4 bits long);
  - i bit fields vengono sempre convertiti al tipo intero prima di eseguirvi
    delle operazioni;
  - e' permesso "mescolare" tipi normali con bit fields;
  - la definizione di "unsigned" e' importante, per assicurarsi che per i 
    flags non venga usato nessun bit per il segno.

------------------------------------------------------------------------------
07.05. Ordine di precedenza degli operatori 
------------------------------------------------------------------------------

  E' necessario fare attenzione al significato di un'espressione come
	a + b * c
  dove potremmo volere sia l'effetto di 
	(a + b) * c
  sia quello di 
	a + (b * c)
  Tutti gli operatori hanno una propria priorita', e gli operatori ad alta
  priorita' sono valutati prima di quelli a bassa priorita'.
  Gli operatori con la stessa priorita' sono valutati da sinistra a destra;
  Cosi'
	a - b - c
  e' valutato 
	(a - b) - c
  come ci si puo' aspettare.

  L'ordine di priorita', dalla piu' alta alla piu' bassa, degli operatori
  in C e':
 
  ()[]->.
  !~-*& sizeof cast ++ --
    (these are rigth -> left)
  */%
  +-
  < <=  >= >
  == !=
  &
  ^
  |
  &&
  ||
  ?: (right -> left)
  = += -= (right -> left)
  ,(comma)
  
  Quindi:
	"a < 10 &&2 * b < c" 
  e' interpretato come:
	"(a < 10) &&((2 * b) < c)".
  ed anche:
	a=
	    b=
		spokes / spokes_per_wheel
		+ spares;
  e' valutato come:
	a=
	    (b=
		(spokes / spokes_per_wheel)
		+ spares
	    );

------------------------------------------------------------------------------
08. Strutture di controllo 
------------------------------------------------------------------------------

  Quelli che seguono sono i vari metodi con cui il C puo' controllare il 
  flusso logico di un programma. A parte alcune minime differenze sintattiche,
  queste istruzioni sono simili a quelle che si possono trovare negli altri
  linguaggi.
  Come abbiamo visto, in C esistono le seguenti operazioni logiche:
	==,!=,||,&&.
  Un altro operatore e' il not "!" unario (ha un solo argomento).

  Questi operatori sono utilizzati congiuntamente alle istruzioni di seguito
  riportate.

------------------------------------------------------------------------------
08.01. If 
------------------------------------------------------------------------------

  L'istruzione "if" ha le stesse funzioni degli altri linguaggi. Puo' avere
  tre forme di base:

  if (expression)
    statement

  if (expression)
    statement1
  else
    statement2

  if (expression1)
    statement1
  else if (expression2)
    statement2
  else 
    statement3
    
  Ad esempio:
    
  	  int x,y,z;
  	  main()
  	   {
  	      int w;
  	      ...
  	      if (x<0)
  	        {
  	           z=w;
  	           ...
  	        }
              else
                {
		   z=y;
 		   ...
 	        }
 	    }

------------------------------------------------------------------------------
08.02. Operatore "?" 
------------------------------------------------------------------------------

  L' operatore ? (ternary condition) e' la forma piu' efficente per esprimere
  semplici if statements. Ha la seguente forma:
  
      expression1 ? expression2 : exprssion3
  
  che equivale a:
 
      if expression1 then expression2 else expression3
  
  Ad esempio:
    
      z=(a>b) ? a : b
    
      cioe'
    	 if (a>b)
  	   z=a;
      	 else
      	   z=b;
      	  
      assegna a z il massimo tra a e b.

------------------------------------------------------------------------------
08.03. Switch 
------------------------------------------------------------------------------

  Permette scelte multiple tra un insieme di items.
  La sua forma generale e':
   
	switch (expression) {
   	    case item1:
   	    		statement1;
   	    		break;
 	    case item2:
   	    		statement2;
   	    		break;
   	    		.
   	    		.
   	    		.
 	    case itemn:
   	    		statementn;
   	    		break;
 	    	
	    case default:
	     		statement;
	     		break;
	    }
	    
	   
  Il valore degli item deve essere una costante (le variabili non sono 
  permesse).
  Il break serve per terminare lo switch dopo l'esecuzione di una scelta, 
  altrimenti verra' valutato anche il caso successivo (questo, a differenza
  di molti altri linguaggi).
     
  E' possibile anche avere un'istruzione nulla, includendo solamente un ";" 
  oppure lasciando fallire l'istruzione di switch omettendo qualsiasi frase
  (come nell'esempio di seguito).

  Il caso "default" e' facoltativo e raggruppa tutti gli altri casi. 

  Ad esempio:
       switch (letter) {
            case 'A':
            case 'E':
            case 'I':
            case 'O':
            case 'U':
               numerovocali++;
               break;
            case " ":
               numerospazi++;
               break;
            default:
               numerocostanti++;
               break;
         }
             
  In questo caso se letter e' una vocale ('A','E','I','O','U') viene 
  incrementato il valore della varibile numerovocali, se e' uno spazio (" ")
  si incrementa numerospazi e altrimenti (se nessuno dei casi precedenti e' 
  vero) viene eseguita la condizione di default e quindi viene incrementato 
  numerocostanti.

------------------------------------------------------------------------------
08.04. For 
------------------------------------------------------------------------------

  L'istruzione C "for" ha la seguente forma:
      
     for (expression1; expression2; expression3)
        statement;
        {or block of statements}
      
     dove expression1 inizializza, expression2 e' il test di termine e
     expression3 e' il modificatore (che puo' anche essere piu' di un semplice
     incremento).
    
  Nota: fondamentalmente il C tratta le istruzioni "for" come i cicli di
         tipo "while".
 
  Ad esempio:
       
       int x;
       main()
       {
          for (i=0;i<3;i++)
            printf("x=%dn",x);
       }
     	   
  che genera come output sullo schermo:
       x=0
       x=1
       x=2
         
  Gli esempi che seguono sono tre forme valide delle istruzioni "for" in C:

	for (x=0;((x<3)&&(x>9));x++)

       	for (x=0,y=4;((x<3)&&(y>9));x++,y+=2)
     in cui si puo' notare che le espressioni multiple possono essere separate
     da una ",";

	for (x=0,y=4,z=4000;z;z/=10)
     in cui si puo' notare che il loop continua l'iterazione fino a quanto z
     diventa 0.

------------------------------------------------------------------------------
08.05. While 
------------------------------------------------------------------------------

  L'istruzione "while" ha la seguente forma:
   
     while (expression)
       statement;
          
  Ad esempio:

       int x=3;
       main()
       {
         while (x>0)
            {
               printf("x=%dn",x);
               x--;
            }
       }
       
  che genera come output sullo schermo:
       x=3
       x=2
       x=1
           
  While puo' accettare non solo condizioni ma anche espressioni, per cui 
  risultano corrette le seguenti istruzioni:
       while (x-);
       while (x=x+1);
       while (x+=5);

  Utilizzando questo tipo di espressioni, solo quando il risultato di x--,
  x=x+1 oppure x+=5 ha valore 0 la condizione di while fallisce e si esce
  dal loop.

  E' possibile avere anche complete operazioni di esecuzione nelle espressioni
  "while":

       while (i++<10)
  che incrementa i fino a raggiungere il valore 10;
         
       while ((ch=getchar())!'q')
          putchar(ch);
  che usa le funzioni getchar() e putchar() delle librerie standard, che 
  rispettivamente leggono un carattere dalla tastiera e scrivono un 
  determinato carattere sullo schermo. Il loop while continua a leggere dalla 
  tastiera e a visualizzare sullo schermo il carattere digitato, fino a quando
  non venga battuto il carattere "q". 

------------------------------------------------------------------------------
08.06. Do-While 
------------------------------------------------------------------------------

  L'istruzione C "do-while" ha la seguente forma:
    
     do
       statement;
       while (expression);
         
  (e' simile al Pascal repeat ... until, eccetto il fatto che l'espressione
   dell'istruzione do-while e' vera)
    
  Ad esempio:
      
       int x=3;
       main()
         {
             do {			/* le graffe sono superflue, visto */
               printf("x=%dn",x-);     /* che racchiudono solamente una   */
		}			/* istruzione                      */
             while (x>0);
         }
         
  Il cui output e':
       x=3
       x=2
       x=1

  Nota: l'operatore finale "x-" indica che viene usato il valore corrente 
        di x mentre stampa, e poi viene decrementato x.

------------------------------------------------------------------------------
08.07. Break e Continue 
------------------------------------------------------------------------------

  Il C fornisce due comandi per controllare i loop:
     
  break    - esce da un loop o da uno switch
  continue - salta una iterazione del loop
     
  Consideriamo il seguente esempio, dove leggiamo un valore integer e lo 
  elaboriamo in accordo con le seguenti condizioni. Se il valore che abbiamo
  letto e' negativo, dovremo stampare un messaggio di errore ed abbandonare
  il loop. Se il valore letto e' maggiore di 100, dovremo ignorarlo e 
  continuare con il successivo valore in input. Se il valore e' 0, dovremo
  terminare il loop.

     /* Viene letto un valore intero ed elaborato purche'
        sia maggiore di 0 e minore di 100 */

     while (scanf("%d".&value) == 1 && value !=0) {
        if (value<0) {
           printf("Valore non ammesson");
           break;  /* Abbandona il loop */
        }
        if (value>100) {
           printf("Valore non ammesson");
           continue; /Torna nuovamente all'inizio del loop */
        }
        /*Elabora il valore letto*/
        /*che e' sicuramente tra 0 e 100 */
        .
        .
        .
     }  

------------------------------------------------------------------------------
09. Arrays 
------------------------------------------------------------------------------

------------------------------------------------------------------------------
09.01. Array singoli e multidimensionali 
------------------------------------------------------------------------------

  Un esempio di definizione di un array in C e' :
    
	int elenco_numeri[50];
     
  e si accede agli elementi dell'array nel seguente modo:
    
 	terzo_numero= elenco_numeri[2];
    	elenco_numeri[5]=100;
             
  NB. In C gli Array subscripts iniziano da 0 e finiscono alla dimensione 
      dell'array meno uno.  Nell'esempio precedente il range e' 0-49, cioe' 
      elenco_numeri e' un array di 50 elementi e si ha:
      elenco_numeri[0],elenco_numeri[1],....elenco_numeri[49].
      Questa e' una grossa differenza fra il C e gli altri linguaggi e 
      richiede un po' di pratica per raggiungere "la giusta disposizione
      d'animo".
  
  Array multidimensionali sono cosi definiti:
  
	int tabella_numeri[50][50]         => per due dimensioni
    	int big_D[20][30][10][40]          => per piu' di due dimensioni
    
  e si accede agli elementi nel seguente modo:
    
    	numero=tabella_numeri[5][32];
    	tabella_numeri[1][23]=100;

------------------------------------------------------------------------------
09.02. Stringhe 
------------------------------------------------------------------------------

  In C le stringhe sono definite come array di caratteri. Ad esempio, la
  seguente istruzione definisce una stringa di 50 caratteri:
   
      char name[50];
   
  Il C non ha pero' un sistema maneggevole per costruire le stringhe, cosi 
  le seguenti assegnazioni non sono valide:
      char firstname[50], lastname[50], fullname[50];
      firstname = "Mario"                    /* illegale */
      lastname  = "Rossi"                    /* illegale */
      fullname  = "Sig."+firstname+lastname  /* illegale */
 
  Esiste pero' una libreria di routines per il trattamento delle stringhe
  ("< string.h >").

  Per maneggiare le stringhe si possono usare puntatori ad array di char 
  (come vedremo piu' avanti).
  
  Per stampare una stringa si usa printf() con lo speciale carattere di 
  controllo %s:
  
      printf("%s",nome);   

  Nota: e' sufficiente avere il nome della stringa.

  Al fine di permettere l'utilizzo di stringhe con lunghezza variabile,
  il carattere 
.: Ritorna ad argomento Programmazione :: Ritorna a Indice Argomenti :.
Network: Cartoline virtuali - Calendari - Modelle - Playmates - Sfondi - Forum - Old SecurityNews - Warez