!DOCTYPE html>
Potreste pensare che la motivazione per seguire delle linee guida per la scrittura del codice sia qualcosa che serve per far contenta/o la/il docente, ma chi beneficia maggiormente di questo siete voi. Impegnarsi per scrivere del codice ordinato, ben strutturato consentirà di collaudarlo più facilmente, di introdurre meno bug o di trovarli più facilmente. Di fatto comunque, scrivere del codice "bene" non richiede più fatica di scriverlo male, per cui: perché no?
Le indicazioni qui riportate presentano alcuni aspetti di interesse cui ci atterremo in questo corso. Come per tutte le cose complicate, non esiste un "ottimo" assoluto, e neanche una lista esaustiva che copra ogni situazione. Ci sono però scelte migliori ed altre peggiori, e lo scopo di questa guida è di farvi propendere per le prime. Nella stragrande maggioranza dei casi sono linee guida adottate comunemente perchè vincenti, in alcuni casi si tratta di preferenze mie.
Può succedere che in base a precedenti esperienze abbiate adottato delle soluzioni diverse, proprio perchè non esiste un ottimo assoluto. Ovunque lavorerete dovrete adottare le linee guida stabilite in quell'ambito: in questo corso, dovreste fare lo sforzo di seguire lo stile di scrittura del codice qua riportato. Questo consentirà una maggior uniformità, anche tra di voi, semplificando la comprensione e il confronto del codice durante le vostre discussioni. Se avete opinioni fortemente diverse supportate da buone motivazioni (tra cui non rientra "ho sempre fatto così"), venite a parlarne.
Nella scrittura del codice (sia su carta, sia con il calcolatore) deve essere facile comprendere cosa si voglia fare. Di fatto, il linguaggio C non pone vincoli sulla spaziatura e sull'andare a capo, per cui si può scrivere un intero programma su una singola riga. Il compilatore non avrebbe problemi e se non ci sono errori di sintassi, crea un eseguibile. Lo stesso eseguibile creato a partire da un programma scritto andando a capo a ogni istruzione e indentando le istruzioni. La prima soluzione sarebbe per noi abbastanza difficile da comprendere, la seconda - si spera - un po' meno.
/* codice poco leggibile */
while(x < y){
if(y %% BASE == 0){
x = modify(y); y++;
} else x++;
}
return x;
/* codice leggibile */
while(x < y){
if(y %% BASE == 0){
x = modify(y);
y++;
} else
x++;
}
return x;
result = longFunctionName(argument, 106 * expression * variable) + variable - longerFunctionName() + otherFunction(variable);
result = longFunctionName(argument, 106 * expression * variable) + variable -
longerFunctionName() + otherFunction(variable);
r = (-b+subp(a))/2*a;
r = (-b + subp(a)) / (2 * a);
Scegliete nomi significativi per variabili e simboli di define: devono in qualche modo suggerire a chi legge il significato dell'informazione/dato rappresentato.
...
...
while(val != 55){
...
}
#define STOP 55
...
...
while(val != STOP){
...
}
int stop; ... stop = 55; ...
#define STOP 55
...
...
while(val != STOP){
...
}
struct strutturaPunti {
int x, y;
float value;
}
...
struct strutturaPunti p;
typedef struct strutturaPunti {
int x, y;
float value;
} point_t;
...
point_t p;
typedef char string_t[DIM+1];
Si adotta lo standard ANSI C 89 per quanto riguarda i tipi base supportati e il non mischiare dichiarazioni e istruzioni, limitandoci a dichiarare variabili solo all'inizio del (sotto)programma.
for(int i = 0; i < N; i++)
for(int i = 0; i < N; i++)
/* ciclo 1 */
...
for(int i = 0; i < N; i++)
/* ciclo 2 */
int sum = 0;
/* perché sum dovrebbe valere 0 a priori? */
...
while(val != STOP){
sum += val;
scanf("%d", &val);
}
int sum;
...
sum = 0;
while(val != STOP){
sum += val;
scanf("%d", &val);
}
list_t * testa = NULL;
int sum;
sum = 0; /* finto approccio a non inizializzare le variabili in fase di dichiarazione */
...
while(val != STOP){
for(i = 0; i < num; i++){
sum += val;
if(sum > max)
max = sum;
sum = 0;
}
int sum;
...
while(val != STOP){
sum = 0;
for(i = 0; i < num; i++){
sum += val;
if(sum > max)
max = sum;
}
list_t * testa = NULL;
#define L 30 ... char voc[L+1];
if(val < min)
min = val;
if(val > max) /* se vera (val < min), valutazione inutile */
max = val;
if(val < min)
min = val;
else if(val > max)
max = val;
if(val > 0)
;
else /* condizione scritta male */
val = -val;
if(val <= 0)
val = -val;
/* l'else è inutile */
if(cond)
return a;
else
return b;
/* il comportamento è identico */
if(cond)
return a;
return b;
/* costrutto inappropriato */
scanf("%d", &val);
while(val < MIN || val > MAX)
scanf("%d", &val);
/* costrutto appropriato */
do
scanf("%d", &val);
while(val < MIN || val > MAX);
/* costrutto appropriato */
scanf("%d", &val);
while(val < MIN || val > MAX){
printf("valore nell'intervallo %d %d\n", MIN, MAX);
scanf("%d", &val);
}
/* costrutto inappropriato */
do {
val = getval();
if(val != STOP){
sottop(val);
n++;
}
}while(val != STOP); /* stessa valutazione già fatta */
/* costrutto appropriato */
val = getval();
while(val != STOP){ /* il corpo del ciclo non è ripetuto */
sottop(val);
val = getval();
}
for(i = 0; i < NUM; scanf("%d", &val[i++]));
isok = 1;
for(i = 0; i < N; i++){
...
if(cond){
isok = 0;
break;
}
}
isok = 1;
for(i = 0; i < NUM && isok; i++){
...
if(cond)
isok = 0;
}
isok = 1;
for(i = 0; i < N; i++){
...
if(cond){
isok = 0;
i = N;
}
}
while(i < NUM){
/* elaborazione */
...
if(cond)
break;
}
stop = 0;
while(i < NUM && !stop){
/* elaborazione */
...
if(cond)
stop = 1;
}
/* tutte le volte si calcola la lunghezza */
for(i = 0; i < strlen(s); i++){
...
}
/* calcolo una volta sola */
dim = strlen(s);
for(i = 0; i < dim; i++){
...
}
/* calcolo e successiva scansione */
dim = strlen(s);
for(i = 0; i < dim; i++){
if(s[i] ... )
}
/* analisi senza un calcolo */
for(i = 0; s[i] != '\0'; i++){
if(s[i] ...)
...
}
if(condizione_errore)
/* gestione eccezioni */
else
/* algoritmo principale */if(! condizione_errore)
/* algoritmo principale */
else
/* gestione eccezioni */
vett = malloc(sizeof(int)*num);
if(vett != NULL){
/* uso della memoria */
...
} else {
printf("Errore allocazione %d interi\n", num);
/* eventuale gestione */
}fp = fopen(filename, "w");
if(fp != NULL){
/* accesso ai dati */
...
} else {
printf("Errore accesso al file %s\n", filename);
/* eventuale gestione */
}void sottop(int vett[], int dim){
int i;
...
for(i = 0; i < dim; i++)
...
}void sottop(int bid[][NC], int nrighe, int ncolonne){
int i, j;
...
for(i = 0; i < nrighe; i++)
for(j = 0; j < ncolonne; j++)
...
}void sottop(int bid[][NC], int NR, int NC){
int i, j;
...
for(i = 0; i < NR; i++)
for(j = 0; j < NC; j++)
...
}void sottop(char * s){
int i;
...
for(i = 0; s[i] != '\0'; i++)
...
}void sottop(char * s){
int i;
...
for(i = 0; *(s+i) != '\0'; i++)
...
}
void sottop(char s[])
int i;
...
for(i = 0; s[i] != '\0'; i++)
...
}
if(x < y){
subp(x);
x++;
} else {
subp(y);
x++;
}
if(x < y)
subp(x);
else
subp(y);
x++;
typedef struct s {
int min, max;
float avg;
} ris_t;
....
ris_t sottop(int v[], int dim){
ris_r risultati;
...
return risultati;
}
void sottop(int v[], int dim, int * min, int * max, float * avg){
...
*min = ...;
*max = ...;
*avg = ...;
}
int max, sum, i, j;
...
for(i = 0; i < num; i++){
sum = 0;
for(j = i+1; j < num; j++)
sum += v[j];
if(i == 0 || sum > max)
max = sum;
}
int max, sum, i, j;
...
max = 0;
for(j = 1; j < num; j++)
max += v[j];
for(i = 1; i < num; i++){
sum = 0;
for(j = i+1; j < num; j++)
sum += v[j];
if(sum > max)
max = sum;
}