CODEXSPRAWL

sulle tracce della periferia cibernetica

Lezione 9 – Gli errori di programmazione

top-25-programming-errors-should-software-developers-be-liable-imageFile-a-2204

Sta volta ci ho messo più del solito a scrivere l’articolo per due motivi: il Natale, il lavoro, lo studio e il blog non vanno troppo d’accordo se allineati nello stesso spazio-tempo e questa lezione si è rivelata un tantino più lunga e complessa delle altre per la sua specifica natura.

Più o meno, nelle precedenti lezioni, abbiamo cercato di osservare tutte le basi per poter iniziare a programmare ed abbiamo visto, con un esempio, anche come organizzare il nostro lavoro, suddividerlo e renderlo più semplice per altri da comprendere. Spesso, ci siamo imbattuti in una serie di possibili errori che bene o male spuntano sempre quando lavoriamo su un programma: dobbiamo però sempre trovarli e correggerli di modo che il nostro lavoro funzioni al meglio.

Ci sono varie tipologie di errori come, per esempio, gli errori logici derivanti dai risultati; gli errori cosiddetti di run-time individuati dal pc o da una libreria o dal codice (ad esempio, quando ci dimentichiamo di aggiungere una libreria come math.h); gli errori di link-time individuati dal linker il momento in cui tenta di combinare gli object files in programmi esecutivi;  e gli errori trovati dal compiler che possono essere sia di sintassi (come, per esempio, la dimenticanza di un punto e virgola a fine stringa oppure una parentesi mancata, etc.) che di genere (ovvero errori relativi all’incompatibilità tra i type dichiarati e le loro variabili, funzioni, etc.).

Trovare tutti questi possibili errori richiede tempo e pazienza ma, soprattutto, una metodologia per poterli limitare. Inoltre, esercitarsi con il linguaggio di programmazione aiuterà tantissimo nel tempo a fare meno errori e, soprattutto, ad individuarli prima. Ciò significa, quindi, rispettare i seguenti punti:

  • Organizzare il software come si era visto, qui, durante l’esercizio della scrittura di una lettera semplice (ovviamente in quel caso il programma era limitato ma più lungo diventa più la suddivisione in sezioni ed i commenti ci aiuteranno a controllarlo alla fine).
  • Eliminare la maggior parte degli errori grazie al debugging ed al testing interni al nostro compiler che, inizialmente, ad un principiante potranno anche sembrare incomprensibili ma, col tempo, diverranno sempre più semplici da capire.
  • Assicurarsi che il resto degli errori non sia serio.

Questo perché alla fine tutti i software hanno quelli che chiamiamo spesso bug ovvero quegli errori del computer che probabilmente sono sfuggiti ai programmatori e, di norma, vengono corretti successivamente grazie alle cosiddette patch.

Inoltre, quando lavoriamo su un programma dobbiamo sapere esattamente cosa vogliamo esattamente creare poiché, in mancanza di specificità, rischieremo di perderci nella costruzione del codice. In questo caso anche creare degli schemi mentali o su carta può, inizialmente, aiutare.

Non dimentichiamoci, oltre a questo, che appoggiarsi solamente al compiler sia una buona idea: stiamo pur sempre parlando di un software che, in quanto tale, può sbagliare e non accorgersi della presenza di errori come per esempio l’inserimento di un area che presenta un indice negativo. Più il programma su cui stiamo lavorando è complicato più errori di questo tipo possono presentarsi: ciò significa che se il nostro compiler ha messo insieme il codice (o compiled se vogliamo utilizzare una parola più tecnica) non è detto che il nostro programma funzioni o che sia totalmente privo di errori.

Vediamo, ora, alcuni errori presi da una lista selezionata dal solito libro di Stroustrup, Programming, Principles and Practice using C++.

Cout << " Success!\n" ;

Qui sopra, come si può notare count è stato scritto in maiuscolo anziché in minuscolo: è un errore che si corregge facilmente imparando ad utilizzare il compiler.

In questo caso il compiler ci segnalerà l’errore in questo modo: error C2065: ‘Cout’ : undeclared identifier.

cout << " Success !\n ;

Eccole appena dimenticate le virgolette ” che vanno sempre messe per chiudere la frase dopo la n.

Il compiler allora per questa semplice mancanza ci segnalerà due tipi di errori: error C2001: newline in constanterror C2143: syntax error : missing ‘;’ before ‘}’. Come si nota, allora, il compiler non ci avverte direttamente della mancanza delle virgolette ma crede manchi, invece, il punto e virgola.

cout << " Success" << !\n"

In questo caso ci aiutano anche i colori utilizzati in automatico dal nostro compiler notiamo infatti che abbiamo un ” Success” che verrà ovviamente stampato ma un << che non è seguito da nessun altro possibile ordine come, per esempio, la possibilità di inserire una stringa denominata all’inizio della scrittura del programma come potrebbe essere first_name (error C2143: syntax error : missing ‘;’ before ‘string’); in tal caso dovremo anche ricordare di aggiungere dopo first_name di nuovo <<. Inoltre, mancano il punto e virgola alla fine (error C2143: syntax error : missing ‘;’ before ‘}’) e, anche qui, le virgolette ” da porre prima del punto esclamativo. Otteniamo così una stringa del tipo: cout << ” Success” << first_name << ” !\n”;

Un’altra soluzione più semplice sarebbe eliminare le virgolette ” e << dopo la parola Success ed aggiungere il punto e virgola alla fine.

cout << success << endl;

Beh, qui abbiamo un cout dove non sono presenti le virgolette ” ” e, questo renderà impossibile al nostro programma la stampa della parola success (error C2065: ‘success’ : undeclared identifier). Mentre endl, come avevamo già visto in altre lezioni, funziona come \n.

string res = 7 ; vector<inl> v(10); v[S] = res
cout << "Success!\n ";

Qui, basilarmente, il problema è che non si possono archiviare degli int in una stringa senza convertirli.

Il nostro compiler quindi ci segnalerà una marea di errori che qui elenco:

  • error C2065: ‘inl’ : undeclared identifier
  • error C2923: ‘std::vector’ : ‘inl’ is not a valid template type argument for parameter ‘_Ty’
  • error C2514: ‘std::vector’ : class has no constructors
  • see declaration of ‘std::vector’
  • error C2065: ‘S’ : undeclared identifier
  • error C2146: syntax error : missing ‘;’ before identifier ‘cout’

Allora, i primi errori che saltano all’occhio sono C2065 e C2923, ovvero inl non esiste, semmai dovrebbe essere corretto con int. Lo stesso vale per string che andrebbe sostituito con int proprio perché stiamo lavorando con dei numeri, integers, e non con delle stringhe.

Infine, la S, all’interno delle parentesi quadre segnalata dall’errore C2065, non va vene perché non segnala la grandezza del vettore (per informazioni più specifiche sulle grandezze dei vettori cliccate qui) cosicché dovremo sostituirla con un numero come, per esempio, 5.

Otterremo, quindi, la stringa: int res = 7; vector<int> v (10); v[5] = res; cout << “Success!\n”;.

vector<int> v(10); v(S) = 7; if (v(5)! =7) 
cout << " Success!\n" ;

Qui il compiler ci segnalerà due errori, in spedifico: error C2065: ‘S’ : undeclared identifier e error C2064: term does not evaluate to a function taking 1 arguments. Il primo errore, quindi, lo abbiamo già incontrato ed era relativo, diciamo, ad un miss-type ovvero l’uso di S anziché del 5. Il secondo errore, invece, si trova in due specifici punti ed è relativo alle parentesi tonde che vanno sostituite con le quadre poiché la grandezza del vettore viene segnalata in questo modo. Notiamo anche che è corretto non mettere dopo l’if il punto e virgola.

Il codice che, quindi, riscritto otterremo sarà: vector<int> v (10); v[5] = 7; if (v[5] != 7) cout << “Success!\n”;

i f (cond) cout << "Success!\n "; else cout << "Fail!\n" ;

Anche qui troveremo con il compiler un bel po’ di errori.

  • error C2146: syntax error : missing ‘;’ before identifier ‘f’
  • error C2065: ‘cond’ : undeclared identifier
  • error C2146: syntax error : missing ‘;’ before identifier ‘cout’
  • error C3861: ‘f’: identifier not found
  • error C2181: illegal else without matching if

Prima di tutto, quindi, vediamo di eliminare gli spazi sbagliati tra i, f e ( per gli errori C2146 (letto male dal compiler poiché non manca nessun punto e virgola) e C3861 scrivendo, finalmente, if correttamente ed eliminando anche l’errore C2181.

Infine, C2065 ci fa notare che cond non è stato dichiarato: infatti per poter creare un if-statement dobbiamo prima di tutto porre i valori su cui vogliamo lavorare. Quindi, recuperiamo la stringa precedente relativa a vector <int> v(10); v [5] = 7; per, poi, scrivere al posto di cond le condizioni su cui creare l’if-statement come sopra.

Quindi, unendo per comodità l’esempio sopra a questo su cui stiamo lavorando la correzione risulterà essere: vector<int> v(10); v[5] = 7; if (v[5] != 7) cout << “Success!\n”if (v[5] == 7) cout << “Success!\n “; else cout << “Fail!\n”;

Ovviamente tutti questi esempi con correzioni estrapolati da un programma non hanno molto senso per cui, bene o male, quando li correggiamo dobbiamo solo vedere se hanno o meno un senso logico-sintattico che in qualche modo funzioni.

bool c = false; if (c) cout << "Success !\n"; else cout << "Fail!\n " ;

Qui non ci sono errori per cui possiamo lasciare così le stringe.

string s = "ape " ; boo c = "fool"<s; i f (c) cout << "Success!\n ";

Allora, qui troviamo un’altra serie di errori che però abbiamo già visto prima:

  • error C2065: ‘boo’ : undeclared identifier
  • error C2146: syntax error : missing ‘;’ before identifier ‘c’
  • error C2065: ‘i’ : undeclared identifier
  • error C2146: syntax error : missing ‘;’ before identifier ‘f’
  • error C2146: syntax error : missing ‘;’ before identifier ‘cout’
  • error C3861: ‘f’: identifier not found

Logicamente boo non esiste quindi può essere solo un misstype per bool; come sopra, inoltre, abbiamo un if scritto male a causa degli spazi tra le due lettere che lo compongono (ed ecco perché ci sono l’errore C2065 e C2146). Quindi avremo: string s = “ape “; bool c = “fool”<s; if (c) cout << “Success!\n “;.

string s = "ape "; if (s=="fool") cout < "Success !\n " ;

Semmai o quando decideremo di unire i vari errori connessi qui troveremo un errore, ovvero error C2374: ‘c’ : redefinition; multiple initialization, che ci farà notare che abbiamo scritto due volte nel nostro codice string s = “ape ” quindi vediamo di cancellarne uno. Inoltre abbiamo anche l’error C2678: binary ‘<‘ : no operator found which takes a left-hand operand of type ‘std::ostream’ (or there is no acceptable conversion) per cui vi è una dimenticanza ovvero dopo cout và aggiunto un altro <.

In tal modo avremo: string s = “ape “; if (s==“fool”) cout << “Success !\n “ ;

string s = "ape"; if (s+"fool ") cout < " Success!\n " ;

Abbiamo, qui, due nuovi errori:

  • error C2451: conditional expression of type ‘std::basic_string<char,std::char_traits<char>,std::allocator<char>>’ is illegal
  • error C2678: binary ‘<‘ : no operator found which takes a left-hand operand of type ‘std::ostream’ (or there is no acceptable conversion)

Qui abbiamo un errore nuovo ed uno appena visto (il C2678 in cui manca una < davanti a cout). Mentre, per quanto riguarda il C2451 abbiamo un problema con l’operatore + che si può applicare solo con i numeri e non con le stringhe, quindi, in questo caso dovremo sostituirlo con uno dei seguenti operatori != (non uguale), == (uguale), <= (meno di o uguale), >= (più di o uguale), < (meno di), > (più di).

 Quindi, in definitiva, potremo correggere la stringa in questo modo: string s = “ape”; if (s != “fool “) cout < ” Success!\n “;

vector<char> v(S); for (int i=O; O<v.size(); ++i) ; cout << " Success !\n " ;

Abbiamo qui, di nuovo, la famosa S che proprio non ci sta come grandezza del vettore, segnalata dall’error C2065: ‘S’ : undeclared identifier ed un error C2065: ‘O’ : undeclared identifier che segnala la presenza di una O (che probabilmente avrebbe dovuto essere uno zero) dato che dovrebbe essere un int (ovvero un numero intero).

Così abbiamo: vector<char> v(5); for (int i = 0; 0<v.size(); ++i); cout << ” Success !\n”;

vector<char> v(S); for (int i=O; i<=v.size(); ++i) ; cout << "Success !\n " ;

Ritroviamo i medesimi errori C2065 di cui sopra, quindi la S e la O al posto di quelli che dovrebbero essere un 5 ed un 0, ed un nuovo errore: warning C4018: ‘<=’ : signed/unsigned mismatch che prima non avevamo trovato ma che, in realtà, era presente. Se, infatti, guardiamo meglio tra le parentesi relative al for notiamo i<=v.size(); immaginiamo, quindi, che il programmatore avesse voluto intendere per v.size() la grandezza del vettore oppure una grandezza nulla quindi dovremo sostituire questa dicitura con un numero.

Avremo quindi, per esempio: vector<char> v(5); for (int i = 0; i<=5; ++i); cout << “Success !\n “;

string s = "Success!\n " ; for (int i=O; i<6; ++i) cout << s[i];

La stringa è giusta, il compiler non ci segnalerà nessun errore, ma, se facciamo correre il programma, noteremo che con questo comando non verrà stampata tutta la frase “Success!” ma, solamente, “Succes” a causa dei comandi prestabiliti. Ciò significa che, per poter stampare l’intera parola compresa di punto esclamativo, dovremo sostituire il 6 con un bel 9 (ovvero il numero di caratteri + 1 della frase).

Avremo quindi: string s = “Success!\n “; for (int i = 0; i<9; ++i) cout << s[i];

if (true) then cout << "Success!\n " ; else cout << "Fail!\n " ;

Qui, invece, troviamo tre errori nel compiler:

  • error C2065: ‘then’ : undeclared identifier
  • error C2146: syntax error : missing ‘;’ before identifier ‘cout’
  • error C2181: illegal else without matching if

Quel then dopo l’if proprio non ci sta: per il programma è incomprensibile quindi và tolto. Il punto è virgola che manca (C2146) in realtà non manca perché, come sappiamo, dopo l’if non và messo e, così, anche l’errore C2181 scompare automaticamente.

Così avremo:  if (true) cout << “Success!\n “; else cout << “Fail!\n “;

int x = 2000; char c = x; i f (c==2000) cout << " Success!\n " ;

A parte questo benedetto if sempre con lo spazio in mezzo segnalato dagli errori C2065 e C2146. Probabilmente, qui, il programmatore vorrebbe schiacciare un grosso numero intero in un carattere, x. Sebbene il compiler non ce lo segnali dovremo anche aggiungere un int a da cui derivi il valore di c. Infine, non servirà usare il 2000 nell’uguaglianza ma solamente la x.

string s = "Success !\n "; for (int i=0; i<10; ++i) cout << s[i] ;

Qui nessun errore viene rilevato dal nostro compiler. Vi è comunque un errore di stile relativo alla scritta Success dove sarebbe meglio eliminare lo spazio tra la parola ed il punto esclamativo.

vector v(5); for (int i=0; i<=v.size(); ++i) ; cout << "Success !\n " ;

Qui troviamo nel compiler i seguenti errori:

  • error C2955: ‘std::vector’ : use of class template requires template argument list
  • error C2514: ‘std::vector’ : class has no constructors
  • error C2662: ‘_Vector_alloc<!std::is_empty<_Alloc_types::_Alloc>::value,std::_Vec_base_types<_Ty,_Alloc_types::_Alloc>>::size_type std::vector<_Ty,_Alloc>::size(void) throw() const’ : cannot convert ‘this’ pointer from ‘std::vector’ to ‘const std::vector<_Ty,_Alloc> &’

Tutti questi si limitano semplicemente a dirci che ci siamo dimenticati l’argomento del vettore che potrebbe essere, per esempio, a seconda di quello che stiamo utilizzando, <char>. <string>, <doble>.

Quindi avremo: vector<char> v(5); for (int i = 0; i <= v.size(); ++i); cout << “Success !\n “;

int i = 0 ; int j = 9; while (i<10) ++j; if (j<i) cout << "Success !\n";

Anche qui il nostro compiler non ci segnalerà alcun errore.

int i=0; while (i<10) ++j; if (j<i) cout << " Success !\n ";

Qui troviamo, invece, il solito error C2065: ‘j’ : undeclared identifier che in questo caso ci avverte che il programmatore si è dimenticato di dichiarare, per esempio, int j = 7 per poterlo utilizzare.

Quindi avremo:  int i = 0; int j = 7; while (i<10) ++j; if (j<i) cout << ” Success !\n “;

int x = 4; double d = 5/(x-2); if (d=2*x+0.cout << " Success!\n " ;

Qui c’è un errore abbastanza evidente: un punto al posto della parentesi; una cosa, infatti, che dobbiamo ricordarci quando programmiamo è controllare che tutte le parentesi si aprano e si chiudano.

Il compiler ce lo segnalerà così: error C2146: syntax error : missing ‘)’ before identifier ‘cout’

cin << "Success!\n ";

Qui l’errore è abbastanza evidente poiché il cin và sempre utilizzato con l’operatore >> e non <<, inoltre, non viene trattato come un cout, ovvero non stamperà la frase ma piuttosto legge i caratteri inseriti in un eventuale stringa che lo precedeva, dopodiché un cout stamperà la parola success.

Quindi in definitiva o cambiamo semplicemente cin con cout oppure scriviamo qualcosa del tipo: string_fn; cin >> fn; cout << “Success!\n”;

La cosa migliore e che, per quanto mi riguarda, funziona sempre quando si cercano degli errori è prendersi, dopo un po’, del tempo per rilassarsi, farsi un caffè o prendersi una boccata d’aria: quando si tornerà alla postazione di lavoro sarà più semplice beccare quel malefico errore che ci stava facendo impazzire poco prima! Un’altra cosa che può aiutare è andare a capo nei momenti giusti così da rendere più semplice la lettura del codice ed individuare prima l’errore.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *