Programmazione in linguaggio C Laboratorio di Algoritmi e Strutture Dati Prof. Luigi Lamberti 2009.
-
Upload
arianna-gattini -
Category
Documents
-
view
223 -
download
1
Transcript of Programmazione in linguaggio C Laboratorio di Algoritmi e Strutture Dati Prof. Luigi Lamberti 2009.
Programmazione in linguaggio C
Laboratorio di Algoritmi e Strutture Dati
Prof. Luigi Lamberti2009
Come NON programmare
#define Z I("123\45678\n");H(x,V){putchar(".XO"[*x]); W((x-V)%10==8){x+=2;I("%d\n",(x-V)/10-1);}}l V[1600],u,r[]={-1,-11,-10,-9,1,11,10,9},h[]={11,18,81,88},ih[]={22,27,72,77},bz,lv=60,*x,*y,m,t;S(d,v,f,_,a,b)l*v;{l c=0,*n=v+100,j=d<u-1?a:-9000,w,z,i,g,q=3-f;W(d>u){R(w=i=0;i<4;i++)w+=(m=v[h[i]])==f?300:m==q?-300:(t=v[ih[i]])==f?-50:t==q?50:0;Y w;}H(z,0){W(E(v,z,f,100)){c++;w= -S(d+1,n,q,0,-b,-j);W(w>j){g=bz=z;j=w;W(w>=b||w>=8003)Y w;}}}W(!c){g=0;W(_){H(x,v)c+= *x==f?1:*x==3-f?-1:0;Y c>0?8000+c:c-8000;}C;j= -S(d+1,n,q,1,-b,-j);}bz=g;Y d>=u-1?j+(c<<3):j;}main(){R(;t<1600;t+=100)R(m=0;m<100;m++)V[t+m]=m<11||m>88||(m+1)%10<2?3:0;I("Level:");V[44]=V[55]=1;V[45]=V[54]=2;s(u);e(lv>0){Zdo{I("You:");s(m);}e(!E(V,m,2,0)&&m!=99);W(m!=99)lv--;W(lv<15&&u<10)u+=2;U("Wait\n");I("Value:%d\n",S(0,V,1,0,-9000,9000));I("move: %d\n",(lv-=E(V,bz,1,0),bz));}}E(v,z,f,o)l*v;{l*j,q=3-f,g=0,i,w,*k=v+z;W(*k==0)R(i=7;i>=0;i--){j=k+(w=r[i]);e(*j==q)j+=w;W(*j==f&&j-w!=k){W(!g){g=1;C;}e(j!=k)*((j-=w)+o)=f;}}Y g;}
#define Y return#define R for#define e while#define I printf#define l int#define W if#define C y=v+111;H(x,v)*y++= *x#define H(a,b) R(a=b+11;a<b+89;a++)#define s(a) t=scanf("%d",&a)#define U Z I
Commenti
La quantità di commenti deve superare abbondantemente il codice C.
Un altro programmatore deve capire come funziona una routine senza chiedervi nulla.
I commenti devono essere scritti PRIMA, in modo da formare l’ossatura su cui verrà scritto il programma, non DOPO!
Inseriremo perciò alcuni righi di spiegazione all’inizio di una funzione o di un segmento di programma, una descrizione accanto ad ogni definizione di variabili, qualche chiarimento accanto ad istruzioni significative.
a = a + 2; // aggiungo 2 alla variabile anon è un commento ma una scemenza: meglio chiarire il motivo di questo incremento.
/* per i commenti di più linee */
// per i commenti fino al termine della riga.
Naming
Il Nome deve richiamare l’uso della variabile e/o della funzione. Per le variabili è preferibile un sostantivo, per le funzioni (metodi) un verbo.
C è case-sensitive; l’iniziale maiuscola per i nostri nomi, li distinguerà a colpo d’occhio dalle parole del C; nomi composti avranno le singole iniziali maiuscole ( CamelCase ):
int NumLati; // descrizione variabile
float AreaCerchio, // descrizione variabile
MaxValore; // descrizione variabile
Definizione di tipi e costanti
Utilizzare il #define per i valori costanti; i nomi vanno scritti in MAIUSCOLO.
#define PIGRECO 3.1415927#define ESC 27
Sempre in MAIUSCOLO andranno i nomi delle strutture
typedef struct scheda { char Campo[16]; int Valore; } SCHEDA;
Nomi di File
Usare nomi corti, senza spazi e senza caratteri speciali o accentati, per garantisce la compatibilità con altri sistemi operativi e protocolli di trasferimento (es. Joliet consente al massimo 31 caratteri per i nomi dei file).
Evitare perciò nomi come:•Media ponderata con il secondo metodo matematico di Eulero.c •lino&mariù.c •prova %4.c•dque.c
ed usare invece:•Media_Aritmetica.c•Primitive_Grafo.c•Gestione_RS232.c•Dynamic_Queue.c
Se il file contiene una sola funzione, usare lo stesso nome per il file.
Spaziatura
Inserire qualche rigo vuoto tra le diverse funzioni e tra le varie sezioni del programma.
Inserire gli spazi tra i nomi e gli operatori
for(i=0,j=N;i<j&&j>=10;i++,j-=3)if(A[i][j])A[i][j]*=i;
diventa
for (i = 0, j = N; i < j && j >= 10; i ++, j -= 3)
if ( A[i][j] ) A[i][j] *= i;
Variabili Globali
L’uso delle variabili globali è fortemente sconsigliato perché:
consente a tutte le procedure di accedere ai dati, con conseguente difficoltà di debug di eventuali errori;
rende difficoltoso il riutilizzo del codice;
quasi sempre, impedisce l’uso della ricorsione:ogni istanza di una funzione ricorsiva deve agiresu un’immagine diversa dei dati.
Allineamento e Indentazione
Allineare le istruzioni, disponendo opportunamente quelle che sono subordinate ad una condizione o ad un ciclo, qualche colonna più a destra.
I simboli di BEGIN e END, ovvero { e } devono essere sempre allineati con l’istruzione cui fa riferimento il blocco (if, else, while, do, switch).
Tutte le istruzioni del blocco devono rientrare: 2-3 colonne dovrebbe essere una misura corretta, purché venga usata sempre la stessa quantità.
Un'indentazione esagerata, lascia poco spazio agli indispensabili commenti.
Operatori aritmetici
addizione + sottrazione -
moltiplicazione * divisione (intera o float) /
incremento ++decremento --
assegnazione =aggiunta +=
detrazione -=assegnazione prodotto *=assegnazione divisione /=
Operatori per i valori Interi
modulo della divisione %Complemento a uno ~
AND bit a bit &OR bit a bit |
EXOR bit a bit ^shift a sinistra <<shift a destra >>
assegnazione modulo %= assegnazione AND &=
assegnazione OR |=assegnazione EXOR ^=
assegnazione shift a sinistra <<=assegnazione shift a destra >>=
Operatori Relazionali
uguale == diverso != minore <
minore o uguale <=maggiore >
maggiore o uguale >=
Operatori Logici
NOT ! AND && OR ||
Operatore Ternario ? :L'unico operatore del C che opera su tre parametri, è una forma sintetica di alcuni casi particolari di if-else:
if (condizione) var = espressione1else var = espressione1
diventa var = condizione ? espressione1 : espressione2;
Se condizione è un valore non nullo, si esegue l'espressione1, viceversa si esegue l'espressione2.
L’operatore ternario ?: può essere inserito in una altra espressione.Ad esempio, per stampare il massimo tra due valori:
printf (“Il massimo è %f \n”, a > b ? a : b );
Precedenze tra gli Operatori
1. ( ) [ ] -> .
2. ! ~ ++ -- + - * & (cast) sizeof()
3. * / %
4. + -
5. << >>
6. < <= >= >
7. == !=
8. & (AND bit a bit)
9. ^
10. |
11. &&
12. ||
13. ? :
14. = += -= *= /= %= &= ^= |= <<= >>=
15. ,
Procedure
Scrivere molte subroutine che svolgono poche funzioni, meglio una sola per volta.
Ogni procedura (livello inferiore) fornisce un servizio al programma chiamante (livello superiore): quest’ultimo non deve sapere come questa funzione viene svolta.
Ad esempio un programma che deve scambiare dati tra due PC, utilizzerà un gruppo di funzioni del tipo Connetti / Scrivi / Leggi / Disconnetti, senza sapere se queste si appoggiano alla Porta Seriale, alla Parallela o alla Ethernet.
In C è usuale inserire le funzioni DOPO il main, utilizzando il prototype per la visibilità.
Uscita da una funzione
Nella programmazione strutturata un blocco di istruzioni deve avere UN punto di inizio e UN punto di uscita.
Questo, ovviamente, vale anche per i sottoprogrammi e il programma principale.
Non usare break per interrompere un ciclo (salvo al termine di un case).
L’unico return di una funzione deve essere l’ultima istruzione.
Main.c#include <stdio.h>#define PIGRECO 3.14159
int Sub1 ( float );
/*=================================================...specifiche del Software, autori, data relase...---------------------------------------------------*/ int main ( void ){ float Area, // ... uso della variabile Raggio; // ... int i, // ... j; // ... istruzione; do { istruzione; if ( condizione ) // motivo della selezione { istruzione; istruzione; for ( i = 0, j = 100; i < j ; i ++, j -= 13) { istruzione; istruzione; } } else // alternativa { istruzione; istruzione; Area = Raggio > 0 ? Raggio * Raggio * PIGRECO : 0; } } while (condizione);}
Sub1.c
#include <stdio.h>
/*=======================================================...specifiche della Subroutine, data ultima modifica... INPUT: parametri di ingresso OUTPUT: valore di uscita ------------------------------------------------------*/ int Sub1( float x // .....){ int k; // ..... istruzione;
switch ( k ) { case 1 : istruzione; istruzione; break; case 23: istruzione; istruzione; break; case 4: istruzione; istruzione; break; default: istruzione; }
return valore;}
/*================================================================= Funzione per la lettura di una stringa in input da tastiera. Il chiamante deve aver allocato spazio non inferiore a LenMax; accettati al massimo LenMax-1 caratteri, con il NULL finale; il LineFeed di chiusura (10) viene eliminato; i caratteri eccedenti verranno persi. -----------------------------------------------------------------*/void LeggiStringa( char *Stringa, // puntatore alla stringa int LenMax // lunghezza massima spazio allocato ){ int i;
fgets ( Stringa, LenMax, stdin );
i = strlen(Stringa); // posizione del NULL i -= 1; // ultimo carattere // elimina il LineFeed di chiusura if (Stringa[i] < 32) Stringa[i] = 0;
fflush ( stdin ); // svuota il buffer}
Controllo dell’Input utente
Costruzione di un progetto
Se il lavoro è complesso, conviene suddividere tutte le funzioni in più files .c, ciascuno con il corrispondente file header .h:
Ogni file C contiene una o più funzioni, legate tra loro da un comune settore del progetto; all’inizio del file occorre citare l’header delle sotto-funzioni chiamate, con #include.
Il corrispondente file H contiene tutti i prototype delle funzioni scritte, le dichiarazioni typedef, struct e define. Non contiene alcuna istruzione eseguibile.
L’ambiente di sviluppo, tramite il file di progetto, provvede a collegare tutti i file tra loro.
NON bisogna usare gli #include per i file .c
Metacomandi
In alcuni casi, richiamare più volte lo stesso file header può creare problemi.
In tal caso, incapsulare il file come segue:
#ifndef NOME#define NOME. . . . . . . . .. . . . . . . . .. . . . . . . . .#endif
Ambiente di lavoro
Per sviluppare un programma in C:
1. Editor
2. Compiler
3. Linker
Le tre funzioni sono solitamente riunite in un unico Ambiente di Sviluppo.
Useremo il wxDev C/C++ scaricabile gratuitamente
Installare wxdevcpp_6.10.2_setup.exe nella cartella C:\Programmi\Dev-Cpp.
Solo sotto Windows, per emulare alcune funzioni per la gestione della finestra di testo, copiare il file libconio.a nella cartella
C:\Programmi\Dev-Cpp\lib
Installazione
Le barre degli strumenti possono essere posizionate in modo diverso a seconda delle esigenze del programmatore
Ad ogni programma da sviluppare deve corrispondere un Progetto : in questo modo è più facile tenere assieme le varie parti di un Job.
Assegnare la modalità Console (ovvero l’utilizzo della finestra di testo)
Scrivere il Nome del progetto
Indicare il linguaggio C
Salvare il progetto in una cartella di lavoro.
Usare una cartella differente per ogni progetto.
Viene proposto un generico file main.c da utilizzare come base di lavoro.
Possiamo anche ignorarlo e aggiungere tutti i files del nostro lavoro già pronti
Per utilizzare le funzioni di gestione della finestra di testo, occorre aggiungere l’opzione relativa alla libreria libconio.a
Nelle opzioni del progetto: selezionare la scheda Opzioni Addizionali e cliccare su Aggiungi libreria
Cercare ed assegnare il fileC:\Programmi\Dev-Cpp\lib\libconio.a
Aggiungere agli header standard i prototype della libreria conio
#include <conio.h>
Questo programma permette di leggere i codici dei tasti ASCII e SPECIALI della tastiera.