Sei sulla pagina 1di 53

C_oding++

Autore: Samuel Finocchio (Informaticage)

Sito web personale:


Sito web: Informaticage.altervista.org
Youtube: www.youtube.com/c/InformaticageNJP

Inizio scrittura:
26 gennaio 2015
0. Introduzione
C++ è un linguaggio di programmazione compilato adatto per la
programmazione sia procedurale che ad oggetti.
Nato come evoluzione del C, infatti il suo primo nome è stato “C with classes”
ovvero “C con classi”.
Il C++ è in grado di lavorare sia ad alto che a basso livello.
La seguente guida ha lo scopo di essere scorrevole e comprensibile,
non mi dilungherò su nessun argomento o riempirò il documento di futilità.
1. Strumenti
Tutto ciò di cui necessiterete è un computer con un sistema operativo in grado
di fare “girare il nostro compilatore” GCC.
Raccomando tuttavia l'utilizzo di un ambiente di sviluppo,
personalmente la mia scelta ricade su Code::Blocks.
http://www.codeblocks.org/downloads

Se siete su windows, ricordatevi di scaricare la versione con minGW.

In alternativa qualunque IDE svolgerà il suo lavoro.

Ho tuttavia una richiesta, non limitatevi a leggere il libro.


Anche se vi sembrerà di aver capito, DOVETE testare il codice.
Non fate copia e incolla, se fate copia e incolla il programma non funzionerà!
Il testo è formattato in modo da impedirvelo.
2. Iniziamo

Eccoci qui davanti alla schermata iniziale del vostro ambiente di


sviluppo preferito, dobbiamo adesso creare un nuovo progetto di
tipo “console application” per metterci all'opera.

Dopo aver assegnato un nome al vostro progetto, probabilmente noterete che


l'IDE ha già generato del codice:

#include <iostream>

using namespace std;

int main()
{
return 0;
}

Per eseguire il nostro programma dovremmo svolgere diversi passaggi che


porteranno il nostro sorgente a diventare un file eseguibile funzionante.

Parliamo di compilazione e linking essendo C++ un linguaggio compilato.

Per fare ciò in un ambiente di sviluppo ci basterà un semplice click o al


massimo 2.

Build, poi run, oppure direttamente build and run.


3. Struttura generale di un programma

Tutti i software più semplici in C++ hanno la seguente forma:

Direttive del preprocessore (approfondiremo poi)


#direttiva 0
#direttiva 1

Funzione main le quali parentesi graffe racchiudono ciò che gli appartiene.

int main() // << Questa è la funzione main


{
Istruzioni eseguite dal main.
istruzione 0;
istruzione 1;

Istruzione di return, ovvero di restituzione, essendo questa


la funzione main, il valore verrà restituito al sistema operativo.
return 0; // Restituiamo qui 0 al sistema operativo
}
4. Output e primo programma

Adesso che abbiamo un'idea di come è strutturato un sorgente C++ possiamo


scriverne uno noi.
Il nostro primo programma “stamperà” a video del testo.
L'istruzione per l'output è cout ovvero console output.

cout << “Testo da scrivere”;

Avrete notato che l'istruzione cout è accompagnata da un operatore


<< il suo compito è indirizzare il testo da scrivere con la cout, un po come un
cartello stradale con le macchine.
La stringa (il testo) che la segue va racchiusa da 2 doppi apici
“ ” per indicare che si tratta di un stringa.

Essendo questa una istruzione va terminata con il punto e virgola ;

Tentate adesso di scrivere un software che visualizzi a schermo una frase.


Se il codice da voi utilizzato è solo quello che avete imparato qui, allora sarete
incappati in un errore.

cout non sarà riconosciuta come istruzione, ciò potrebbe accadere per diversi
motivi:

per utilizzare cout necessitate della libreria iostream da importare in questo


modo:

#include<iostream>

Non basta.. l'istruzione cout come anche la cin deve essere preceduta dal
namespace ovvero della collezione di nomi a cui appartiene.
In questo caso il namespace è std ovvero standard:

std::cout << “testo”;

Il nostro programma dovrà avere questo aspetto:

#include <iostream>

int main()
{
std::cout << “To C or not to C that's the question!”;
std::cin.ignore();
std::cin.get();
return 0;
}

cin.ignore() e cin.get() servono rispettivamente a pulire il buffer della tastiera


e attendere per un input, tutto ciò serve ad evitare la chiusura istantanea del
nostro programma impedendoci di vedere l'output.

Possiamo anche concatenare più stringhe con <<

cout << “Ciao” << “mondo”;

Oppure andare a capo con endl

cout << “Riga 0” << endl << “riga 1” << endl << “riga 3”;

Non essendo endl una stringa NON va racchiusa tra virgolette.

Possiamo evitare di indicare il namespace ogni singola istruzione specificando


l'utilizzo del namespace in tutto il programma o tutta una funzione:

#include <iostream>

using namespace std; // Namespace globale


int main()
{
cout << “uso cout senza specificare”
<< “ il namespace ogni volta in TUTTO il programma!”;
return 0;
}

#include <iostream>

int main()
{
using namespace std; // Namespace locale alla funzione main
cout << “Qui invece ne faccio a meno SOLO nel main :)”;
return 0;
}

Adesso vi starete chiedendo a cosa serve questo “spazio di nomi”,


per farvelo capire farò un esempio:
Immaginate di avere 2 compagni di classe con lo stesso nome che si chiamano
entrambi Mario.
Come fate a chiamare un Mario piuttosto che l'altro? Beh, utilizzate il cognome.
Come fa C++ a non confondersi tra funzioni con lo stesso nome presenti nelle
librerie? (quelle che aggiungiamo con #include)
Con lo spazio di nomi.
Se 'Mario 1' fa di cognome Rossi e 'Mario 2' fa di cognome Agrippa, C++
farebbe così: Rossi::Mario oppure Agrippa::Mario oppure ancora std::cout

Per adesso vi basterà conoscerne lo scopo,e sapere perché avete necessità di


utilizzarlo.
Se non è chiaro non preoccupatevi, se ne parlerà in futuro… Però non vi
scordate di scriverlo!

Se tutto finora è andato per il verso giusto dovreste avere un semplice


programma che scrive una frase e che si chiude quando premete invio.
5. Variabili

E adesso che so scrivere sullo schermo, come faccio a leggere?


Con calma.. Prima di comprare un mobile non prendete le misure in casa?
Bisogna prima pensare ai contenitori, altrimenti i dati poi dove li metti?

Quando in programmazione parliamo di contenitori intendiamo degli spazi in


memoria destinati a contenere dei dati, ed è proprio questa la definizione di
variabile.
La variabile è quindi un contenitore di dati, specializzato per una particolare
categoria di contenuto, il cui contenuto può variare durante l'esecuzione del
programma.

Una variabile necessita di un tipo, il tipo definisce che genere di contenuto


potrà supportare la variabile.
Non potete mettere un computer fisso dentro una borsa per pc portatili come
non potete mettere un numero reale (con la virgola) in un contenitore per
numeri interi (senza virgola)… Giusto?
No! sbagliato, in C++ le variabili sono si delle borse specializzate ma diciamo
che sono delle borse elastiche, potete mettere un numero reale in un
contenitore intero e viceversa però non potete mettere una stringa in un
contenitore di numeri.
Le variabili in C++ sono elastiche perché il linguaggio fa delle conversioni in
modo automatico, queste conversione prendono il nome di conversioni
implicite. Vediamo come funzionano:
3.14 (numero reale) se messo in una variabile intera diventa 3
3 (numero intero) se messo in una variabile reale diventa 3.0

Poi visto che noi a queste scatole teniamo particolarmente gli diamo anche un
nome. Il nome di una variabile si chiama identificatore.
Potete dare qualunque nome alle vostre variabili a patto che non contengano
caratteri speciali, solo l'underscore _ è ammesso.
Inoltre per il problema che ho descritto prima dello spazio di nomi non potete
dargli il nome di parole chiave che il linguaggio utilizza.
Non potete nemmeno farle iniziare con un numero o contenere spazi.
Per rendere tutto più chiaro, facciamo come al solito esempi:
Nomi ammessi:
_var
_var1
Var
Var_
Var_1

Nomi non ammessi:


1var
var%
!var
cout
var numero 1

Adesso che sappiamo cos'è un tipo e cos'è un identificatore vediamo come si


dichiara una variabile.

tipo nome;

Niente di più semplice ed intuitivo, ma aspetta.. quali sono i tipi?

char
Contiene caratteri, uno alla volta: 'a', 'z', '$'
il nome deriva da character ovvero carattere.

string
Contiene una sequenza di caratteri: “ciao mondo”, “sono batman”.
String significa appunto stringa.

int
Contiene numeri interi: 3, 1990, -13
Il nome deriva da integer ovvero intero

float
Contiene numeri reali: 3.14159, 1.618, 1, 41421 , -43.0
I decimali si separano con il punto . e NON con la virgola!
Il nome deriva da floating point ovvero virgola mobile.

double
Contiene numeri reali proprio come float però è più grande, viene definito a
precisione doppia.
Il nome deriva da double ovvero doppio.

bool - Vedi algebra booleana: it.wikipedia.org/wiki/Algebra_di_Boole


Assume valori booleani, true (vero) che corrisponde ad 1 oppure false (falso)
che corrisponde a 0.
Il nome deriva da boolean ovvero booleano.

Dopo tutta questa teoria e giunto il momento di riprendere in mano il nostro


IDE e fare una dichiarazione.
La scelta del tipo va in base allo scopo, se il nostro programma deve chiedere
l'età all'utente servirà un numero e non una stringa, ma attenzione! Un
numero con la virgola sarebbe uno spreco oltre che inadatto.
Quindi:
int age;

Se volete assegnare un valore alla variabile potete fare così:


int age;
age = 10;

oppure tutto in una solo riga:


int age = 10;

come vi ho detto la variabile può assumere più valore durante l'esecuzione:


int age = 45;
age = 1;
age = -345;

Potete utilizzare la cout per mostrare all'utente il contenuto della variabile


int age = 23;
cout << age << endl;

Non si tratta di una stringa, age non va quindi tra virgolette “”!
Ricordate che endl serve per andare a capo.

Per dichiarare più variabili dello stesso tipo sulla stessa riga:

int age, width, height, weight;

Buona pratica è dichiarare le variabili utilizzando identificatori (nomi) in


inglese.
In questo caso:
age = età
width = larghezza
height = altezza
weight = peso (inteso come massa)
6. Che succede in memoria?
Una variabile risiede in memoria centrare (RAM), rispettivamente alla quale ha
2 principali caratteristiche:
• La dimensione, ovvero lo spazio utilizzato.
• L'indirizzo, ovvero dove si trova la nostra variabile.

Possiamo ora immaginare la variabile come una casa, con un indirizzo specifico
e con una dimensione.
La dimensione è designata dall'architettura e dal tipo della variabile mentre
l'indirizzo di memoria, dal sistema operativo.

Se volete sapere quanta memoria occupa la vostra variabile in memoria dovete


utilizzare la funzione sizeof se volete invece sapere dove è situata usate
l'operatore &.

sizeof significa spazio di.


& significa indirizzo di.

cout << sizeof(age);


cout << &age;

Non fidatevi di me! Provate tutto il codice che scrivo e non fate copia e incolla.

Provate ad ottenere il seguente output:

Nella pagina successiva trovate la soluzione, ma provate da soli.


7.

Errori di compilazione

Se riscontrate errori e il vostro programma non compila non abbattetevi,


sarebbe anormale non fare errori.
Controllate la sintassi, capita di scrivere caut invece di cout oppure di invertire
<< e >> ma in particolare controllate i punti e virgola;

Le parentesi tonde e graffe vanno aperte e chiuse altrimenti il compilatore si


arrabbia ;D
Attenti a specificare il namespace, riga per riga o per blocco oppure ancora,
come ho fatto io, per tutto il sorgente.

Il codice deve stare nel blocco del main, che è tra le 2 parentesi graffe:

int main()
{
Qui va il codice
}

ATTENZIONE:
Il linguaggio C++ è case-sensitive, ovvero differenzia maiuscole e minuscole,
scrivere int var, int Var, INT var fa una notevole differenza, quindi controllate
sempre le maiuscole occhio a non divertirvi troppo con lo shift.
8. Leggere l'input
Adesso che sappiamo come funzionano le variabili facciamo scegliere all'utente
il loro contenuto.
Per farlo dobbiamo richiedere un input ovvero un dato acquisito dal nostro
programma, in questo caso da parte dell'utente.
Se cout sta per console output e serve per scrivere potete immaginare che per
leggere basta usare cin ovvero console input.
I dati letti vanno memorizzati nelle variabili la cin ha quindi bisogno di una
variabile per svolgere il proprio compito.

float var;
cin >> var;
cout << “hai inserito “ << var << endl;

Notare che indirizzamento è opposto, non sarà più << come cout, ma sarà >>

cin >> var legge un valore e lo indirizza dentro var.


Proviamo adesso a creare un programma che ci chiede il nome e poi ci saluta.
Attenzione alla scelta del tipo della variabile, può un nome essere memorizzato
in un intero?
L'output deve essere simile a questo:

Scrivete da soli il programma e poi confrontatelo con il sorgente qui sotto.


Soluzione:

cin vi permette di leggere più dati nella stessa chiamata*, basta fare così:

cin >> nome >> cognome;

cognome va dichiarato a sua volte come string!


Nell'utilizzo del programma possiamo poi inserire i valori uno alla volta
separandoli con invio oppure con uno spazio.
l'output sarà il seguente:

*chiamata: richiesta di esecuzione di una funzione.


9. Operatori

Constatata l'esistenza delle variabili per operare con esse necessitiamo degli
operatori, troverete gli operatori sotto forma di parole chiave (sizeof) oppure di
simboli (%,/,+,-,::).

Gli operatori binari (con 2 operandi a e b) matematici sono:


somma: a + b
sottrazione: a – b
moltiplicazione: a * b
divisione: a / b
resto: a % b

le prime 3 sono intuitive, attenzione invece alla divisione che se tra numeri
interi taglia la parte decimale:
3/2 = 1 e non 1.5
Dovrete quindi fare delle conversioni (le vedremo in seguito) per avere il
risultato sperato.

Il resto fa la divisione e restituisce il resto, ma funziona solo con numeri interi:


3%2 = 1 perché 3 - ((3/2) * 2) = 1

Gli operatori unari(un solo operando) matematici sono:


Indica che a è positivo: +a
Indica che a è negativo: -a

Vediamo come usarli:

int a,b;
a = 12;
b = 22;
cout << “La somma è ” << a + b << endl;

int c = a - b;
c = -c;
cout << “La differenza è” << c << endl;

c = -c rende -10 positivo avendo come risultato 10 nella cout, equivale a


c * -1

Creiamo ora un programma che calcoli l'area di un rettangolo.


Troverete la soluzione sotto, ma provate da soli.
Prima di scrivere un programma che richiede la realizzazione di un algoritmo,
non saltate la fase di progettazione.

Sappiamo che l'area di un rettangolo è data dalla base per l'altezza


Abbiamo quindi la necessità di 2 variabili, possiamo salvare il risultato in una
terza variabile chiamata area oppure effettuare l'espressione sulla cout:

area = base * altezza;


cout << area;

oppure

cout << base * altezza;

Quindi:

Altro esercizio (con conversione implicita):


Dato il raggio calcolare l'area del cerchio.
Sapete che l'area del cerchio è data dal raggio al quadrato per il PI greco.
Avete la necessità di chiedere all'utente solamente il raggio.

Noterete che l'output è in virgola mobile anche se la variabile raggio era intera
e la parte decimale non è stata tagliata!

Questo perché il compilatore ha “promosso” l'espressione


raggio * raggio * 3.14159 da intera a virgola mobile prima di calcolarne il
risultato:

6 * 6 * 3.14159 → 36(intero) * 3.14159 → 36.0(reale) * 3.14159 = 113.097

Parliamo in questo caso di conversione implicita (automatica).


10. Selezione

Immaginate di essere onniscienti, di sapere tutto ma non saper ragionare.


La vostra conoscenza sarebbe inutile.
Noi adesso sappiamo leggere, scrivere e operare con le variabili, ma non
sappiamo ragionare con loro.
Adesso starai pensando.. ma cosa dici! il computer è una macchina, non può
ragionare…
E invece!
Non è vero, avete ragione voi: un computer non sa ragionare, in compenso è
bravissimo a risolvere espressioni, sfruttiamo questa sua capacità per fargli
prendere decisioni sulla base di risultati di espressioni.
Ma non espressioni qualunque, eheheh no!
Espressioni booleane.
Se avete prestato attenzione vi ricorderete che sopra, tra i tipi di variabili ho
elencato il tipo bool*.
Un “ragionamento” del computer può quindi avere solo 2 esiti: vero o falso.
Li potete trovare così scritti:
vero - true - 1
falso - false - 0

Se chiedi ad computer se oggi piove ti dirà true o false, non ti dirà “qualche
goccia”, “il cielo è scuro”.
Se il cielo è nero e non cadono gocce false.
Se cade anche una sola goccia true.

se se se.
In italiano introduce un periodo ipotetico, in informatica controlla se un
espressione è vera o falsa.

leggi età
se (età ≥ 18)
scrivi “Sei maggiorenne”

Il se, in c++ if viene detta struttura di controllo, decide se un istruzione o un


blocco di istruzioni verra eseguito.
Un blocco racchiude tante istruzioni che vengono però viste come istruzione
singola relativamente all'if dal compilatore.
Se non avete capito questa frase non preoccupatevi che ora lo vediamo
insieme.

Prima però vediamo la sintassi per poi avvalerci di un esempio:

*bool - Vedi algebra booleana: it.wikipedia.org/wiki/Algebra_di_Boole


Assume valori booleani, true (vero) che corrisponde ad 1 oppure false (falso) che corrisponde a 0.
Il nome deriva da boolean ovvero booleano.
if (true)
cout << “istruzione eseguita”;

if (false)
cout << “Io non verro eseguita :(”;

Così come:

Attenzione ad utilizzare correttamente gli operatori, in caso di errori consultate


sempre il capitolo relativo all'istruzione evidenziata dal vostro ambiente di
sviluppo.

L'istruzione if controlla l'esecuzione di una sola istruzione, quindi non scrivete


codici come questo:

if (age >= 18)


cout << “sei maggiorenne” << endl;
cout << “Puoi prendere la patente” << endl;

L'if avrà il controllo solo sulla prima istruzione, trova un punto e virgola e
termina il suo lavoro, quindi anche se scriverete così:

if (age >= 18) cout << “sei maggiorenne” << endl;


cout << “Puoi prendere la patente” << endl;

Il risultato sarà lo stesso.


Visto che l'if condizione l'esecuzione solo dell'istruzione immediatamente
successiva e potreste avere la necessità di eseguire più istruzioni sotto una
determinata condizione, come fare?

All'inizio del capito ho parlato del blocco:


Un blocco racchiude tante istruzioni che vengono però viste come istruzione singola
relativamente all'if dal compilatore.

Vediamo quindi come creare un blocco:

{
istruzione1;
istruzione2;
istruzione3;

}

Servivano tante storie? Bastava racchiudere le istruzioni tra graffe… già, ma


scusate, mi piace scrivere :D

Il nostro if diventa così:

if (age >= 18)


{
cout << “sei maggiorenne” << endl;
cout << “Puoi prendere la patente” << endl;
}
oppure
if (age >= 18) {
cout << “sei maggiorenne” << endl;
cout << “Puoi prendere la patente” << endl;
}

La prima è più leggibile e preferibile in sorgenti lunghi, ma per non scatenare


guerre tra programmatori meglio limitarmi a dire che è questione di opinioni.

Adesso abbiamo un programma che ci chiede l'età e ci informa del fatto che
siamo maggiorenni se il numero inserito è maggiore o uguale a 18, altrimenti
non fa assolutamente nulla.
E se noi volessimo per esempio informare l'utente di quanti anni di attesa
necessita per arrivare alla maggiore età?
Qui ci viene in soccorso la clausola else (altrimenti) che racchiude le istruzioni
da eseguire in caso l'istruzione if dovesse essere risultata falsa.

Come l' if è limitata ad una sola istruzione o ad un blocco.

Vediamo come si utilizza:


Output:

Per ora abbiamo visto solo gli operatori matematici di base.


Per fare comparazioni servono operatori relazionali:

Gli operatori relazionali (con 2 operandi a e b) sono:


maggiore: a > b
minore: a < b
maggiore o uguale : a >= b
minore o uguale: a <= b
uguale: a == b
Da non confodere con = ovvero l'operatore di assegnazione (var = 13)
diverso: a != b
Adesso voi avete un cane ed una gallina:

cane != gallina → true (sono 2 animali diversi)


zampe_cane != zampe_gallina → true (La gallina ha 2 zampe in meno)
piumaggio_cane == false → true (Il cane non ha le piume)
pelo_gallina == true → false (La gallina non ha il pelo)

Se volessi quindi far distinguere al computer un cane da una gallina lo farei


ragionare così:

Se animale1 ha più zampe di animale2 E SOLO SE animale1 NON ha le piume


allora animale1 è un cane e animale2 è una gallina.

E SOLO SE in informatica è un AND logico ovvero un operatore che implica che


entrambi i suoi operandi siano veri per rendere l'espressione vera:

vero AND vero → vero


vero AND falso → falso
falso AND falso → falso

In C++ assume questa forma: &&

Il NON invece in informatica è una negazione logica, anche chiamata NOT.


Non fa altro che ribaltare il risultato di una espressione logica:

NOT vero → falso


NOT falso → vero

In C++ assume questa forma: ! ed ha la precedenza sugli altri operatori logici.

Voi direte, beh se il cane non proviene da Černobyl' basta solo controllare il
pelo oppure il numero di zampe in questo modo anche se il cane è stato
mutilato in un incidente perdendo delle zampe il programma funziona.
Benissimo:

Se animale1 ha più zampe di animale2 OPPURE animale2 ha le piume allora


animale1 è un cane e animale2 è una gallina.

scrivere “animale2 ha le piume” e “animale1 non ha le piume” in questo caso


ha lo stesso risultato.

OPPURE in informatica prende il nome di OR.


Verifica se almeno uno dei suoi operandi è vero per valutare come vera
l'espressione:

vero OR vero → vero


vero OR falso → vero
falso OR falso → falso

In C++ prende la seguente forma: ||

AND OR e NOT sono operatori logici e possono anche essere usati assieme:
vero AND NOT falso → vero
vero AND vero OR NOT falso → vero
Come al solito facciamoci aiutare da un esercizio esempio.
Dobbiamo scrivere un programma che controlla l'idoneità di un individuo per
salire su una giostra.
Trattandosi di una montagna russa dobbiamo essere alti almeno 1,60 metri, in
alternativa dobbiamo avere 18 anni.

Ecco l'output:

Troverete la soluzione nella pagina successiva.


Ma provate da soli!
Ho

scelto di chiedere l'altezza in metri, per farlo ho necessitato di un numero con


la virgola, se preferite l'altezza in centimetri potete usare un intero.

Se avete fatto attenzione alla parola chiave “in alternativa” che ho usato nel
testo del problema capirete il perché dell' OR.

Ricordate:

and → &&
or → ||
not → !
11. Commenti

Ora che conosciamo tutte queste cose i nostri programmi iniziano a diventare
complessi.
Per capire se avete avuto successo nell'imparare C++ a fine libro tornate su
questa frase… Se vi viene da ridere allora tutto ok.

Cosa sono i commenti?


Un commento è una parte di codice sorgente che il compilatore ignora e che
serve per descrivere porzioni di codice complesse.
Vi capiterà di incontrare codice come questo:

bool isEven(int n) { return !(n % 2) ? true : false; }

Che con un commento sarebbe molto più chiaro:

// Controllo se il numero è pari true o se dispari false


bool isEven(int n) { return !(n % 2) ? true : false; }

Un commento su singola riga inizia con il doppio slash //


per commentare più righe si apre con /* e si chiude con */ in questo modo:

/*
Il seguente codice ordina un vettore di N elementi.
Si scorre N volte per N elementi.
Si tratta di un algorimo di bubble sorting
*/
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(vet[j] < vet [i])
{
swap = vet[i];
vet[i] = vet[j];
vet[j] = swap;
}
}
}

Non spaventatevi del codice, si tratta di argomenti non ancora affrontati, la


vostra incomprensione è normale.

Quando commentate date per scontato che il lettore conosca il linguaggio, no a


commenti del tipo:
if(a > b) // L'istruzione if esegue un blocco di codice se a è maggiore di b
Se non a scopo didattico come in questo libro… ovviamente.

Potete anche usare i commenti in alto per specificare nome, data e autore di
un codice sorgente che verrà distrubuito:

/*
Software: Calcolatrice.cpp
Autore: InformaticageNJP
Data: 01/09/2015
*/

12. Switch

In un programma complesso vi capiterà di necessitare di parecchi if, uno


dentro l'altro (in cascata) o uno sotto l'altro, vediamo:

if (x==0) cout << “zero”;


else if (x==1)
cout << “uno”;
else if (x==2)
cout << “due”;
else
cout << “altro”;

Un codice del genere è scomodo da leggere e rende il programma disordinato.


Non sarebbe più comodo fare un ragionamento come questo?

lavoriamo con x
caso 0: cout << “zero”;

caso 1: cout << “uno”;

caso 2: cout << “due”;

altro caso: cout << “altro”;

Mooolto più leggibile, ma rimane un sogno…. o forse no?


In C++ esiste il costrutto switch che funziona proprio così!
Vediamo come si usa.
Per prima cosa dobbiamo specificare la variabile su cui stiamo lavorando:

switch(var)

Attenzione però! Si tratta di un costrutto che necessita di un blocco, non


dimenticate le parentesi graffe.

switch (var)
{

per controllare il valore della variabile c'è l'istruzione case:

switch(var)
{
case 1:
cout << “ uno “ << endl;
// tutto il codice fino alla fine dello switch verrà eseguito quanto case 1
sarà vero.
cout << “ verrò eseguito anche io! “;
}

nel caso in cui nessun caso (case) restituisce true, c'è l'istruzione di default
(predefinita):

switch(var)
{
case 1:
cout << “ uno “ << endl;
// tutto il codice fino alla fine dello switch verrà eseguito quanto case 1
sarà vero.
cout << “ verrò eseguito anche io! “;

case 56:
cout << “cinquantasei” << endl;
default:
cout << “nessun caso si è rivelato vero!”;
}

proviamo quindi a sostituire il costrutto di 3 if annidati con lo switch:

switch(x)
{
case 0: cout << “zero”;
case 1: cout << “uno”;
case 2: cout << “due”;
default: cout << “altro”;
}

Non copiate e incollate! Riscrivete il codice ed eseguitelo.


Eh già, viene eseguito proprio tutto il codice sotto il caso vero:
Per risolvere è necessario uscire dal costrutto nel caso in cui si trovi una
istruzione true, per farlo utilizziamo l'istruzione break prima di passare al case
successivo:

L'istruzione break ci fa uscire dal blocco switch.


Per fare pratica, come sempre, svolgiamo un esercizio.
Scriviamo un software che chiede in input il numero del mese e ne restituisce il
relativo nome:

Non passate direttamente al codice, ma se trovate difficoltà meglio ragionare


prima su carta.
Nella pagina successiva troverete la soluzione.
Do not try this at home.
Sappiamo che il primo mese è gennaio quindi:
1 → gennaio
e così via, quindi nel caso mese == 1 allora scrivi (“gennaio”);
case 1: cout << “gennaio”;
13. Ciclo while
Probabilmente vi sarà capitato di riempire una bottiglia di acqua, cerchiamo
quindi di capire l'algoritmo utilizzato per riempire la bottiglia:
Inizio
Partiamo con una bottiglia vuota
Aggiungiamo dell'acqua
Controlliamo il livello del liquido dentro la bottiglia
Se non è piena
Aggiungiamo dell'acqua
Controlliamo il livello del liquido dentro la bottiglia
Se non è piena
Aggiungiamo dell'acqua
Controlliamo il livello del liquido dentro la bottiglia
Se non è piena
Aggiungiamo dell'acqua
Controlliamo il livello del liquido dentro la bottiglia
E così via…

Tuttavia ci sono 2 problemi:


L'algoritmo potrebbe essere lunghissimo, più lungo quanto più capiente è la
bottiglia; non possiamo quindi determinare una fine.
Una porzione del codice viene ripetuta.

Per risolvere possiamo riassumere così il codice:

Inizio
Partiamo con una bottiglia vuota.
Mentre la bottiglia non è piena
Aggiungi acqua
Fine.

In C++ il mentre viene rappresentato dal ciclo while che in inglese significa
appunto ciclo mentre.
Il ciclo while esegue un blocco di istruzioni fino a che una determinata
condizione non diventa falsa, qundi esegue il blocco solo se la condizione è
vera.
while (true)
{
// Ciclo infinito
}

while(false)
{
// Questo blocco di codice non verrà mai eseguito
}

Simuliamo il riempimento di una bottiglia d'acqua.


int bottiglia = 0; // ml bottiglia vuota, a 1000 ml la bottiglia sarà piena
while(bottiglia < 1000) // Fino a che ci sono meno di 1000ml d'acqua
{
bottiglia = bottiglia + 10; // Aggiungo 10ml alla volta
} // Termina il blocco e torna in alto per rifare il controllo
cout << “La bottiglia è piena” << endl;

Dopo 100 esecuzioni del ciclo while la bottiglia sarà piena (1000 ml) e si
passerà al resto del codice scrivendo in output “la bottiglia è piena”.

Come esercizio creiamo un programma che stampi la tabellina di un numero


(da uno a 10) scelto dall'utente.
In questo programma non facciamo altro che moltiplicare un numero scelto
dall'utente con un contatore che incrementa di uno ogni ciclo.

Se l'utente sceglie 3:
3*0=0
3*1=3
3*2=6
e così via, dove 3 rappresenta la variabile numero e 0,1,2 rappresentano la
variabile contatore che con l'istruzione contatore = contatore + 1 incrementa.

Quando si parla di ciclo sentirete termini come ripetizione e iterazione che


hanno il medesimo significato.

14. Operatori di incremento, decremento e assegnamento


Nell'utilizzo dei cicli non si può di certo fare a meno degli operatori di
incremento/decremento o degli operatori di assegnamento combinato.
Ma vediamo di cosa si tratta:
Riempendo la bottiglia abbiamo utilizzato l'istruzione
bottiglia = bottiglia + 10; // Aggiungo 10ml
Ma potremmo combinare gli operatori + e = ed ottenere così l'operatore += :
bottiglia += 10; // Aggiungo 10ml
Meglio no? Possiamo eseguire la stessa operazione con gli altri operatori
aritmetici:
num = num + 10 → num += 10
num = num – 10 → num -= 10
num = num * 10 → num *= 10
num = num / 10 → num /= 10
num = num % 10 → num %= 10

E non finisce qui!


Se vogliamo incrementare o decrementare di 1 non serve nemmeno utilizzare
tale operatore:
num += 1;
Ma bensì basta fare così:
num++;

Provate entrambe le soluzioni:

soluzione 1:
int num = 10;
num += 1;
cout << num;

soluzione 2:
int num = 10;
num++;
cout << num;
Possiamo fare la stessa cosa con la sottrazione:
int num = 10;
num--;
cout << num; // 9

Gli operatori var++ e var-- sono operatori di post-incremento/decremento.


Significa che l'incremento della variabile prende effetto dall'istruzione
successiva:

int num = 2;
num++; // num vale ancora 2!
cout << num; // qui vale 3
num--; // num vale 3
cout << num; // qui vale 2

Se volessimo incrementare sulla stessa istruzione la variabile ci sono gli


operatori di pre-incremento/decremento:
++var;
--var;

int num = 2;
++num; // num vale già 3!
cout << num; // qui vale 3
--num // num vale 2
cout << num; // qui vale 2

Capirete tutto meglio nel prossimo capitolo.


15. Side effect

Nel C++ gli operatori hanno un effetto collaterale che prende il nome di
side-effect ovvero un valore restituito al termine dell'utilizzo di un operatore.

Ad esempio:
num = 1;
ha un side effect di 1.
quindi possiamo utilizzarlo per assegnare valori ad altre variabili:

int a = num = 1;
dove a acquisisce il side effect di num = 1 contendo così anch'essa il valore 1:

Tuttavia la cout non permette la loro stampa:

Ma la printf del linguaggio C lo permette:


Possiamo però stampare il side effect dell'incremento e del decremento:

int num = 5;
cout << num++;
cout << num--;

Fate una prova, compilate il codice qui sopra :D


Eh già, prima dell'istruzione successiva non cambia nulla!
Sostituite adesso l'operatore di post-incremento con quello di pre-incremento.

Per rendere tutto più chiaro:


16. Ciclo do-while

No, non ho ripetuto due volte lo stesso capitolo, il ciclo while ed il ciclo
do-while il controllo in posizione diversa… vediamo di che si tratta.

while (condizione)
// Se condizione == true io vengo eseguito!

do
{
// Vengo eseguito almeno una volta
// Se condizione == true io vengo Rieseguito!
}while(condizione); // non dimenticare il ;

Ovvero:
Scrivere
do {
Codice;
} while (condizione);
oppure
codice;
while (condizione) {
codice;
}
Produce lo stesso risultato.
17. Ciclo for

Non in tutti i cicli è necessario contare, tuttavia accade abbastanza spesso.


Il ciclo for diventa molto comodo dove si utilizza una variabile contatore la
quale viene modificata ad ogni esecuzione del ciclo.
È il più complesso tra i cicli poiché non si limita ad effettuare un controllo ma
anche a dichiarare ed operare una variabile contatore.

Eccone la struttura:
for(inizializzazione; controllo; incremento/decremento)
Istruzioni;

per rendere meglio l'idea usiamolo per contare fino a 10:

for (int i = 0; i <= 10; i++)


cout << i << “ “;

Come inizializzazione c'è int i = 0; una variabile intera che parte da 0.


Come condizione i <= 10; fino a che i arriva a 10
Come incremento c'è i++ dove i incrementa di 1.

Il ciclo for si può quindi tradurre così:

per i che va da 0 a 10 incrementando di 1


scrivi (i + “ ”);

Addentriamoci in un esercizio un pochino più complesso.


Stampiamo tutte le tabelline utilizzando 2 cicli for:

Prima provate voi, ma ecco la soluzione:


Notate che il ciclo for contiene il secondo ciclo for!
Per capire il codice eseguitelo con un pezzo di carta accanto e fate tutte le
operazioni che fa l'algoritmo:

I parte da 1
J parte da 1
I non incrementa fino alla fine del ciclo for interno quindi fino a che J non
arriva a 10.
Iniziamo a moltiplicare i * j.
1 * 1; 1 * 2; 1 * 3 ecc.. ovvero:
1 2 3…

Incrementa I
Iniziamo a moltiplicare i * j.
2 * 1; 2 * 2; 2 * 3; 2 * 4 ecc… ovvero:
2 4 6 8…

E così via otteniamo il risultato che avete già osservato.


18. Vettori

E se io vi chiedessi di memorizzare 150 valori inseriti dall'utente, nell'assurdo


caso nel quale non eliminaste semplicemente questo pdf al presentarsi di tale
richiesta, avreste la necessità di dichiarare 150 variabili:
int n1, n2, n3, n4….
Ma torniamo nel concreto, gli esemplari umani di sesso femminile arrivano ad
avere decine di paia di scarpe e quindi di scatole, in quel caso utilizziamo un
armadio porta scarpe, in informatica utilizziamo un vettore.
Quindi cos'è un vettore:
Una struttura che contiene dati omogenei (tutti dello stesso tipo) in modo
ordinato utilizzando un solo identificatore (il nome del vettore) ed un indice (la
posizione dell'elemento del vettore in questione).

Rappresentiamo graficamente un vettore di nome lista_interi di 6 elementi.


124 -34 1 56493 911 -978

Per crearlo basta una riga di codice:


int lista_interi[6];
Per accedere ad un valore.. lettura o scrittura che sia:
lista_interi[0] = 124;
cout << lista_interi[3]; // output → 56493 (guarda il vettore sopra)
Attenzione! si inizia a contare da 0;
Il primo elemento è il numero 0 e l'ultimo il numero 5.
Come regola generale per la dichiarazione:
tipo nome_del_vettore [numero_di_elementi];
Per l'accesso:
nome_vettore[numero_elemento];

Adesso che sappiamo


cos'è un vettore e
come si utilizza,
sporchiamoci subito le mani.
Leggiamo 5 numeri e stampiamoli al contrario:

Prima di addentrarvi nella risoluzione sappiate che i cicli ed in particolare il


ciclo for sono ottimi alleati dei vettori.
Utilizzare una variabile che incrementa come indice del vettore, in questo
modo:
contatore = 0
vettore[contatore] = 2 → equivale a vettore[0] = 2
contatore incrementa di 1… → adesso contatore contiene 1
e ripeto: vettore[contatore] = 5 → equivale a vettore[1] = 5
Per stampare al contrario vi basterà partire da 5 per arrivare a 0:
contatore = 5
contatore decrementa di 1… → ora vale 4

Se vi trovaste in difficoltà ecco una pseudocodifica:


vettore[]: array di 5 interi
contatore: intero
inizio
scrivi “Inserire 5 numeri”
per contatore che va da 0 a 5
leggi vettore[contatore]
scrivi “ribalto...”
per contatore che va da 5 a 0
scrivi vettore[contatore]
fine
La soluzione la trovate nella pagina successiva.
Attenzione a come usate gli indici nel ciclo for “al contrario”!
Notate il maggiore o uguale >= e la partenza da 4.
Ricordate che si conta da 0.
Inoltre sappiate che quando la i contiene 5, la condizione i < 5 è falsa.
Adesso dopo aver caricato un vettore di 10 elementi, calcoliamo la somma
degli elementi, la media, il più grande ed il più piccolo.

L'esercizio è lungo ma piuttosto semplice, trovate come al solito la soluzione


nella pagina successiva.
Per trovare il minimo ho scelto il primo elemento del vettore come pilota
confrontandolo poi con tutti gli altri elementi.
Nel caso in cui viene trovato con l'if un elemento più piccolo, il pilota viene
sostituito con il nuovo elemento.
Al termine del ciclo for il pilota rimanente è l'elemento più piccolo.
Lo stesso ragionamento è valido anche per la ricerca del massimo :D
Approfondimento:
Come una variabile un vettore può essere inizializzato nella dichiarazione:
int a = 10;
int vet[3] = {2,3,4};
int vet[] = {3,4,5,6}; // Possiamo anche omettere il numero di elementi
Per inizializzare tutti gli elementi a 0 basta fare così:
int vet[3] = { };
19. Matrici

Fino ad ora abbiamo visto il tipo più semplice di array, quello


monodimensionale.
Il C++ tuttavia permette di creare array a più dimensioni, ovvero che hanno
sia righe (row) che colonne (column).

Aggiungendo più righe è come se avessimo più vettori “normali” affiancati.


Si dichiarano in modo simile:
int a[3][4]; // 3 righe e 4 colonne
// Per accedere a riga 0 colonna 0
a[0][0] = 10;
// Mentre per accedere a riga 2 colonna 3
a[2][3] = 13;
Come regola generale:
m_array[riga][colonna];
Possiamo inizializzare la matrice (array a 2 dimensioni) nella dichiarazione:
int m_array[][4] = {
{2, 5, -1, 3}, // riga 0
{4, -3, 2, 4}, // riga 1
{0, 23, 7, 1} // Ultima riga senza virgola
};
Il tutto è fattibile ovviamente sulla stessa riga:
int m_array[][4] = { {2, 5, -1}, {4, -3, 2}, {0, 23, 7} };

Dovete specificare ALMENO il numero di colonne


OBBLIGATORIAMENTE anche se la matrice (array bidimensionale)
viene inizializzata nella dichiarazione.

Per accedere agli elementi della matrice bisogna specificare riga e colonna:
Esercizio:
Creiamo sfruttando le matrici un gioco del tris a 2 giocatori.
Per farlo sarà necessario immaginare una matrice 3x3 come il terreno di gioco.
X O O
X X
X O

La matrice sarà però di char e conterrà X oppure O.


Attenzione alla gestione dei turni, i giocatori si dovranno alternare e dovranno
avere assegnata la X o la O.
Inizialmente è possibile inizializzare la matrice ad un carattere da voi scelto
che indica che la coordinata non è stata giocata:

Per leggere l'input la soluzione più semplice è chiedere le coordinate della


matrice.

Ogni turno per far rendere conto al giocatore della situazione sarà necessario
stampare la matrice con i relativi turni.

Dovete inoltre controllare se uno dei 2 ha fatto filetto, ovvero se sono stati
messi in riga 3 simboli uguali.
Prima di aprire code::blocks prendete carta e penna, l'esercizio è piuttosto
complesso e necessita di progettazione.

Non andate avanti nel libro senza essere riusciti DA SOLI a scrivere questo
applicativo.

Come ogni software che scriverete anche questo ha diverse possibili soluzioni.
Nella pagina successiva troverete la mia soluzione, tuttavia ho voluto simulare
un sorgente trovato su internet, per questo troverete delle istruzioni che non
avete ancora imparato ma che non sono chiave alla risoluzione del problema.
Il sorgente è ampiamente commentato per permetterne una facile
comprensione.
Non fatevi ingannare dalla lunghezza, non c'è nulla di complesso.
Come al solito lo troverete nella pagina successiva, ma non sbirciate e non
azzardatevi a copiare e incollare!! ;)

Potete provare a questo indirizzo l'esecuzione del sorgente:


http://cpp.sh/97xp
#include <iostream>
#include <cstring>
#include <cstdlib>

// Se compiliamo su Linux
#ifdef __linux__
#define CLRSRC system("clear") // Pulisce la console su Linux: Bash
// Se compiliamo su windows
#elif _WIN32
#define CLRSRC system("cls") // Pulisce la console su windows: CMD
#endif

using namespace std;

int main()
// A -> X
// B -> O
{
bool filetto = false;
char table[3][3];
char giocatore = 'A';

/* Riempie la matrice con - */


memset(table, '-', 9);
do
{
// Riga e colonna in input
unsigned short int riga, colonna;

for(int riga = 0; riga < 3; riga++)


// Stampa la griglia di gioco
{
for(int colonna = 0; colonna < 3; colonna++)
cout << table[riga][colonna] << " ";
// Va a capo a fine riga
cout << endl;
}

// Indica il giocatore e chiede riga e colonna da giocare


cout << "Turno giocatore " << giocatore << endl;
cout << "Inserire [riga] [colonna] 1..3: ";
cin >> riga >> colonna;

if(!(riga > 0 && riga <= 3 && colonna > 0 && colonna <= 3))
// Se riga e colonna non sono compresi tra 0 e 3
{
CLRSRC;
continue; // Torna a inizio ciclo while ricominciando da capo
}

// L'utente inserire da 1 a 3 ma la matrice esiste da 0 a 2


riga--;
colonna--;

// Gestione e cambio dei turni


if(table[riga][colonna] == '-')
// Se non è stata già giocata
{
if(giocatore == 'A')
// Se è il turno di A
{
table[riga][colonna] = 'X';
giocatore = 'B';
}
else
// Se è il turno di B
{
table[riga][colonna] = 'O';
giocatore = 'A';
}
}

// Contollo della vittoria


// Controllo riga per riga
for (riga = 0; riga < 3; riga++)
/*
Compara gli elementi sulla stessa riga,
vittoria in caso siano 3 uguali sulla stessa riga ex. X X X
*/
if(table[riga][0] == table[riga][1] && table[riga][1] == table[riga][2])
{
// Ignora il carattere di default '-'
if(table[riga][0] != '-')
{
CLRSRC;
// Vittoria del giocatore che ha fatto il turno
cout << "Vittoria del giocatore " << (giocatore == 'A' ? 'B' : 'A') << endl;
filetto = true;
}
}

// Controllo colonna per colonna


for (colonna = 0; colonna < 3; colonna++)
/*
Compara gli elementi sulla stessa colonna, ex. X
X
vittoria in caso siano 3 uguali sulla stessa colonna X
*/
if(table[0][colonna] == table[1][colonna] && table[1][colonna] == table[2][colonna])
{
if(table[0][colonna] != '-')
{
CLRSRC;
// Vittoria del giocatore che ha fatto il turno
cout << "Vittoria del giocatore " << (giocatore == 'A' ? 'B' : 'A') << endl;
filetto = true;
}
}

// Controllo delle diagonali


if(table[0][0] == table[1][1] && table[1][1] == table[2][2] ||
table[2][0] == table[1][1] && table[1][1] == table[0][2])
{
if(table[1][1] != '-')
{
CLRSRC;
// Vittoria del giocatore che ha fatto il turno
cout << "Vittoria del giocatore " << (giocatore == 'A' ? 'B' : 'A') << endl;
filetto = true;
}
}

// Aspetta che l'utente prema un tasto per continuare


cin.ignore();
// Pulisce lo schermo dal vecchio output
if(!filetto)
CLRSRC;
}while(!filetto);

// Ultima stampa del terreno di gioco


cout << endl;
for(int riga = 0; riga < 3; riga++)
// Stampa la griglia di gioco
{
for(int colonna = 0; colonna < 3; colonna++)
cout << table[riga][colonna] << " ";
// Va a capo a fine riga
cout << endl;
}

// Fine dell'esecuzione
return 0;
}