C++
TUTORIAL
Quick guide
C++ Tutorial – By A.C. Neve
1
STRUTTURA DI UN PROGRAMMA IN C++
#include<……………> istruzione di precompilazione per la definizione delle librerie usate
using namespace std
dichiarazione dello spazio dei nomi standard
main()
dichiarazione della funzione principale
{
inizio blocco principale
//
/* ………….
…………….*/
commenti unilinea
-----------
dichiarazione delle variabili (tipo, valore, ecc.) e delle istruzioni
commenti multi linea
{
--------}
}
blocchi secondari
fine blocco principale (e del codice)
Tutte le parole chiave devono essere scritte in minuscolo.
Tutte le istruzioni terminano con il punto e virgola “;”
Attenzione: C++ è case sensitive
VARIABILI
Tutte le variabili devono essere dichiarate e inizializzate prima del loro uso.
Tipo
char
Descrizione
Carattere intero small
Byte
1
int
Intero
4
short int
Intero short
2
long int
Intero long
4
bool
float
double
Boleano
Floating point 32
Floating point 64
1
4
8
Valori
Signed: da -128 a +127
Unsigned: da 0 a 255
Compresi tra due apici ‘A’
Signed: da – 2G a + 2G
Unsigned: da 0 a +4G
Signed: da -32768 a + 32767
Unsigned: da 0 a 65635
Signed: da – 2G a + 2G
Unsigned: da 0 a +4G
True / False
Da ±10-38 a ±10+38
Da ±10-308 a ±10+308
Signed è predefinito per cui può essere omesso
È possibile definire delle costanti. Per es:
cost float pigreco=3.1415
nell’ambito del programma basterà indicare la parola pigreco per usarne il valore.
Per i numeri reali è possibile far uso della notazione esponenziale
A = 7.06548E-6 (equivalente a 7.06548*10-6)
C++ Tutorial – By A.C. Neve
2
AMBITO DI VISIBILITA’
Rappresenta il blocco delle istruzioni nel quale la variabile stessa è dichiarata
Variabile globale
Variabile locale
È valida dal punto in cui è dichiarata fino al termine del codice e deve essere
definita esternamente a qualsiasi blocco. Il suo valore è permanente.
È valida solo all’interno del blocco nel quale è dichiarata e non è accessibile
dall’esterno. Il suo valore è temporaneo.
OPERATORI ALGEBRICI
+ , - , / , * , % quest’ultimo è il modulo
A++ auto incremento (A=A+1)
A—auto decremento (A=A-1)
APPROSSIMAZIONI
int(x)
ceil(x)
floor(x)
round(x)
Prende la parte intera di x
Approssima all’intero inferiore
Approssima all’intero superiore
Approssima all’intero più vicino
CONDIZIONI LOGICHE
==
<
<=
>
>=
!=
Relazionali
Uguale
Minore
Minore uguale
Maggiore
Maggiore uguale
diverso
Logici
&& And
||
Or
!
Not
Logici su Bit
&
And
|
Or
^
Xor
!
Not
Complemento
∼
CASTING
Consiste nella conversione di una variabile da un tipo in un altro:
implicita: non richiede operatori ed è eseguita automaticamente
int A=100;
float B=A;
così A diventa float
esplicita: esistono due tipi di notazione Tradizionale e Funzionale
float A=2.0;
int B,C;
B=(int)A; Tradizionale
C=int(A); Funzionale
C++ Tutorial – By A.C. Neve
3
Esempi:
main()
{
int A=1, B=2;
float C;
C=A/B;
cout<<C;
}
main()
{
int A=1, B=2;
float C;
C=float(A)/float(B);
cout<<C;
}
In risultato è C=0
Il risultato è C=0.5
OPERAZIONI di I/O
L’I/O si effettua con l’uso delle librerie standard di I/O che vengono attivate per
mezzo della direttiva: #include<iostream>
L’istruzione di output è:
cout<<A;
in forma più completa:
cout<<”descrizione della variabile”<<A;
le istruzioni
cout<<”descrizione della variabile”<<A<<’\n’;
cout<<”descrizione della variabile”<<A<<endl;
mandano a capo il cursore.
L’istruzione di input è:
cin>>A;
è consigliabile far precedere questa istruzione da una istruzione di output che
descriva il tipo di richiesta di input e le sue caratteristiche.
C++ Tutorial – By A.C. Neve
4
CONTROLLO di FLUSSO
OP 1
O P2
Esecuzione sequenziale di un gruppo di operazioni
O P3
Selezione a 1 o 2 vie
VERO
CO NDIZIO NE
FALSO
VERO
CO NDIZIO NE
O P 1,2...N
FALSO
O P 1,2...N
O P a,b,c...
if<condizione>
{
<op1>;
<op2>,
- - - - -;
<op3>;
}
if<condizione>
{
<op1,2,3…>,
}
else
{
<opA,B,C…>;
}
Nel caso in cui non ci fossero le {}, la condizione sarebbe applicata solo all’istruzione successiva.
È possibile nidificare più istruzioni if: if …….else if …….else if ……
C++ Tutorial – By A.C. Neve
5
SELEZIONE MULTIPLA
É possibile effettuare selezioni a più vie (scelta multipla) per mezzo dell’istruzione switch così
strutturata:
switch(variabile di controllo)
{
case valore1:
--------break;
case valore2:
--------break;
case valore3:
--------break;
default:
---------
Il codice associato ad ogni
clausola case, viene eseguito
solo se la variabile di controllo
assume il corrispondente valore.
Il codice associato alla clausola
default viene eseguito se il
valore della variabile di
controllo non corrisponde ad
alcun valore della clausola case.
La parola break indica l’uscita
dal blocco.
}
C++ Tutorial – By A.C. Neve
6
RIPETIZIONE
Ciclo indeterminato con controllo in testa:
F AL S O
C O N D IZ IO N E
VE R O
O P 1 ,2 ...N
while(condizione)
{
<op1>;
<op2>;
…..
…..
<opN>;
}
===============================
Ciclo indeterminato con controllo in coda:
O P 1 ,2 ...N
F AL SO
C O N D IZ IO N E
VE R O
do
{
<op1>;
<op2>;
…..
<opN>;
}
while(condizione);
a differenza del precedente while, in questo
caso il ciclo viene eseguito almeno una volta.
===============================
i= 1
Ciclo determinato:
F AL S O
i <= N ?
VE R O
O P 1 ,2 ...N
for(i=1;i<=N;i++)
{
<op1>;
<op2>;
…..
<opN>;
}
i= i+ 1
Viene eseguito N volte.
C++ Tutorial – By A.C. Neve
7
BREAK e CONTINUE
Questi comandi hanno senso solo all’interno di un ciclo, hanno però un comportamento non
facilmente controllabile per cui se ne consiglia un uso limitato.
break – determina l’immediata uscita dal ciclo passando ad eseguire l’istruzione successiva al ciclo.
continue – determina il salto della restante parte del ciclo e l’immediato passaggio al controllo della
condizione per la successiva iterazione.
Nel caso di un ciclo for, viene effettuato anche l’aggiornamento.
exit – termina immediatamente l’esecuzione del programma.
IF ARITMETICO
È un operatore di confronto ternario che ha tre parametri:
¾ la condizione da valutare
¾ l’espressione da restituire se la condizione è vera
¾ l’espressione da restituire se la condizione è falsa
la sua forma generale è del tipo:
(condizione) ? (valore se vera) : (valore se falsa);
l’if aritmetico non è una vera e propria istruzione ma è un operatore che lavora su espressioni.
Esempi:
Z = (X>Y) ? X : Y;
assegna a Z il massimo tra X e Y
MAX = (X>Y) ? ((X>Z) ? X : Z) : ((Y>Z) ? Y : Z);
Assegna a MAX il più grande tra X,Y e Z:
C++ Tutorial – By A.C. Neve
8
LIBRERIA MATEMATICA
La libreria di funzioni matematiche viene resa disponibile dall’istruzione:
#include<cmath>
Le principali sono:
abs
fabs
acos
asin
atan
cos
sin
tan
pow
sqrt
log
log10
exp
ceil
floor
atan2
div
valore assoluto (intero)
valore assoluto (floating point)
arcocoseno (rad)
arcoseno (rad)
arcotangente (rad)
coseno (rad)
seno (rad)
tangente (rad)
potenza
radice quadrata
logaritmo naturale
logaritmo base 10
esponenziale
valore intero superiore
valore intero inferiore
arcotangente di X/Y
restituisce quoziente e resto di X/Y
FUNZIONI
Le funzioni sono una ottima tecnica per evitare la replicazione di blocchi di codice usati più volte
nel programma per svolgere determinate operazioni.
Si presentano come dei piccoli programmi autonomi che all’occasione vengono richiamati.
La prima riga del codice di una funzione ne definisce la così detta firma (signature) mentre le altre
righe rappresentano il corpo della funzione che è delimitato dai simboli { e }.
FIRMA
Tipo di risultato Nome della Funzione(Parametro1, Parametro2, …..ParametroN)
{
Tipo variabile1;
Tipo variabile2;
…….
CORPO …….
Istruzioni
…….
…….
return risultato
L’istruzione return termina l’esecuzione del codice del corpo della funzione e restituisce il valore
calcolato.
C++ Tutorial – By A.C. Neve
9
La chiamata di una funzione, precedentemente definita, avviene specificandone il nome ed i
parametri sui quali eseguire le operazioni.
Una funzione può essere chiamata anche all’interno di una istruzione come per es.
cout<<funzione(N);
oppure
VAR = funzione(N)/funzione(K);
Parametri formali: sono quelli definiti nell’intestazione della funzione.
Parametri attuali: sono quelli specificati al momento della chiamata della funzione (detti anche
argomenti).
Al momento della chiamata, il valore dei parametri attuali viene copiato del valore dei parametri
formali per effettuare i calcoli.
Una funzione può non avere parametri, in questo caso la sua firma conterrà la parola chiave void al
posto dei parametri
Tipo di risultato Nome della funzione(void)
mentre la chiamata avverrà come
Nome della funzione()
¾ Una funzione può restituire un solo valore o nessun valore, in questo ultimo caso il tipo di
risultato sarà indicato con void e cioè: void Nome funzione(parametri).
¾ Una funzione può comprendere più istruzioni return.
¾ Una funzione di tipo void può non contenere alcun return.
¾ Una funzione il cui risultato sia diverso da void, deve contenere almeno una istruzione
return.
Passaggio dei parametri
Per valore: al momento della chiamata della funzione, si effettua una copia del valore dei parametri
attuali nelle variabili dei corrispondenti parametri formali.
Per riferimento: al momento della chiamata della funzione, si associano le variabili che
rappresentano i parametri attuali alle variabili che rappresentano i parametri formali (i
parametri formali si riferiscono perciò alle stesse variabili che rappresentano i parametri
attuali).
In pratica, la funzione chiamata e quella chiamante usano le stesse variabili.
Il passaggio dei parametri per riferimento si effettua anteponendo al nome dei parametri formali il
carattere & nella intestazione della funzione.
Con questa tecnica sia la funzione chiamata che quella chiamante usano le stesse variabili non così
quando si effettua il passaggio per valore. (vedi esempi).
C++ Tutorial – By A.C. Neve
10
Prototipizzazione
Sia chiaro che: al momento della chiamata di una funzione, questa deve essere già stata pre-definita.
Una funzione può chiamare altre funzioni che, a loro volta possono chiamare altre funzioni.
Se la funzione F3 chiama la funzione F2 che poi chiama la F1, le tre funzioni devono essere definite
nell’ordine F1,F2,F3.
Per evitare di non rispettare questa regola, si usa la tecnica della prototipizzazione delle funzioni.
Il prototipo di una funzione è costituito dalla sola firma della funzione seguita dal punto e virgola (;)
con la lista del tipo e nome della funzione e la lista dei tipi e nomi dei parametri formali.
Nella definizione del file fun.cpp, l’uso della parola chiave static ne stabilisce l’invisibilità
all’esterno consentendo così l’uso, nel main, di altri file con lo stesso nome.
Nell’uso di questa tecnica, conviene usare due file:
¾ un file di intestazione (con estensione .h) contenente i soli prototipi
¾ un file di codice (con estensione .cpp) per le funzioni complete del proprio corpo
¾ vi sarà poi il file main.cpp
il file di intestazione deve essere incluso con la direttiva #include<nomefile> sia nel file che
contiene il codice delle funzioni e sia nel file che contiene il codice delle chiamate delle funzioni
stesse (main). Vedi figura seguente.
File: fun.h
int F1(…..);
float F2(…..);
void F3(…..);
File: fun.cpp
#include<fun.h>
static int F1(…..)
{
----------}
static int F2(…..)
{
----------}
static int F3(…..)
{
----------}
C++ Tutorial – By A.C. Neve
File: main.cpp
#include<fun.h>
Void main(void)
{
--------X=F1(…..);
--------Y=F2(…..);
--------Z=F3(…..);
}
11
ARRAY
Un array è un insieme di dati omogenei identificato da un nome dove, ogni singolo elemento è
identificato dal nome dell’array e da un indice che può variare da 0 a N-1 con N numero di elementi
dell’array.
Per es. Vett[3] rappresenta il quarto elemento dell’array Vett (in generale Vett[i] )
Gli array possono avere dimensione 1,2,3 …M per cui il generico elemento sarebbe:
Vett[i] vettore, Vett[i][j] matrice, Vett[i][j][k] array tridimensionale.
Nelle matrici il primo indice è quello di riga e il secondo è quello di colonna.
Negli array multidimensionali tutti gli elementi dell’array sono sequenzialmente allocati in memoria
La dichiarazione di un vettore si effettua nel seguente modo:
float Vett[29];
La dimensione di un array si fissa all’inizio e resta costante.
La dimensione può essere parametrizzata (ma non variabile) nel seguente modo:
…………
int i,DIM
cout<<”Inserire il numero degli elementi dell’array”;
cin>>DIM
float Vett[DIM];
………..
L’inizializzazione dei valori di un array può essere contestuale alla dichiarazione dell’array stesso:
int Vett[5]={3,5,2,7,1};
oppure
int Vett[10]={0};
nel secondo caso, tutti gli elementi dell’array saranno inizializzati a 0.
La modifica di un qualsiasi elemento dell’array si effettua con l’istruzione:
Vett[3]=20;
Iterazioni
Nel trattamento degli array, è molto comodo l’utilizzo dei costrutti iterativi. Per es.:
for (int i=0; i<10; i++)
{
cout<<Vett[i]<<” “;
}
Si ottiene così la stampa dei primi dieci valori del vettore Vett.
Lo spazio tra i due apici consente la separazione tra i dieci valori.
C++ Tutorial – By A.C. Neve
12
Analogamente:
for (int i=0; i<10; i++)
cin>>Vett[i];
consente il caricamento (uno per volta) di dieci valori del vettore Vett.
Il C++ non effettua alcun controllo sui valori dell’indice per cui, l’uso di valori di indici esterni
all’intervallo definito produrrà risultati errati senza alcuna segnalazione dal compilatore.
Gli indici devono essere numeri interi o anche espressioni algebriche che producono però dei
risultati che siano interi.
Array come parametri di funzioni
Gli array possono anche essere usati come parametri di funzioni ma tale passaggio dovrà sempre
avvenire per riferimento, per cui le variazioni dei valori dell’array si riflettono all’esterno della
funzione. È poi necessario passare alla funzione anche la dimensione dell’array stesso.
Nella riga di definizione di una funzione che ha come parametro un array, questo deve essere
indicato con in nome seguito dalle parentesi quadre senza indicazione della dimensione:
float MEDIA(int Vett[], int n)
oppure float MEDIA(int Vett[], int n=10)
la chiamata di una funzione che prevede il passaggio di un array avviene usandone solo il nome:
m=MEDIA(Vett); oppure
m=MEDIA(Vett,10);
Stringhe di caratteri
Si intende per stringa, una sequenza di caratteri. Le stringhe vengono gestite mediante degli array
monodimensionali di caratteri.
Ogni array di caratteri che contiene una stringa, termina con il valore 0 (sequenza di escape \0) per
cui ogni array di dimensione N potrà contenere solo N-1 caratteri perché l’ultimo è il terminatore \0.
Una stringa di nove caratteri sarà dichiarata come:
char stringa[10];
Una stringa può essere inizializzata come un array specificandone i singoli caratteri come:
char stringa[20]={‘c’,’a’,’p’,’i’,’t’,’a’,’l’,’e’,’\0’};
oppure come
char stringa[20]=”capitale”;
in questo caso il carattere terminatore viene aggiunto automaticamente.
Il carattere terminatore può essere anche usato per determinare la lunghezza stessa della stringa
contando i caratteri fino al raggiungimento del terminatore \0 usano un ciclo while o un for
contenente un contatore.
C++ Tutorial – By A.C. Neve
13
La visualizzazione o il caricamento di una stringa di caratteri avviene come per gli array:
Output 1
int i=0;
char Vett[100];
--------while (Vett[i]!=’\0’)
{
cout<<Vett[i];
i++
}
Output 2
int i=0;
char Vett[100];
--------Cout<Vett;
Input
int i=0;
char Vett[100];
--------Cin>Vett;
Questo modo di operare vale solo per le operazioni di IN e OUT.
Per copiare una stringa in un'altra è necessario far uso di un ciclo:
void copiastringa(char Vett1[], char Vett2[])
{
for (int i=0;Vett1[i]!=’\0’;i++)
Vett2[i]=Vett1[i];
}
Attenzione: in fase di input la stringa non deve contenere caratteri quali spazio, tabulatore, ritorno a
capo perché verrebbero interpretati come fine stringa.
L’acquisizione di una stringa che contenga questi caratteri può essere fatta usando il metodo:
cin.getline(stringa,N);
nel quale stringa è un vettore di dimensione N.
Con le stringhe è possibile effettuare l’ordinamento alfabetico in quanto ogni carattere viene
rappresentato con un valore numerico del codice ASCII:
A=65, B=66, C=67, D=68, ………Z=90
a=97, b=98, c=99, c=100, ………..z=122
0=48, 1=49, 2=50, 3=51, …………9=57 ecc.
Le principali funzioni che possono operare sulle stringhe sono:
strcpy – copia stringa
strcat – concatena stringhe
strchr – trova carattere in stringa
strcmp – confronta stringhe
C++ Tutorial – By A.C. Neve
14
STRUTTURE
Quando si ha la necessità di gestire dati non omogenei ma ordinati, si ricorre all’uso dei record.
Un record è un insieme, anche non omogeneo, di dati identificato da un nome e nel quale ogni
singolo componente, detto campo, è identificato da un proprio nome.
La gestione di questi dati avviene per mezzo delle struct che consentono la definizione di strutture
tipo record.
struct recRUBRICA
{
char nome[20];
char indirizzo[30];
char città[20];
char tel[15];
char mail[30];
int anno;
int mese;
int giorno;
};
main()
struct recRUBRICA Mario, Antonio,Giuseppe;
----------Come si nota, dopo la definizione della struttura è possibile dichiarare le variabili del nuovo tipo
recRUBRICA (Mario, Antonio ecc.).
Attenzione: recRUBRICA non è una variabile per cui non può essere oggetto di riferimenti.
L’assegnazione di un campo può essere fatta con le istruzioni seguenti:
Mario.anno=1980;
strcpy (Antonio.città, “Roma”);
oppure con una espressione
età=anno_corrente-Mario.anno;
la dichiarazione delle variabili strutturate può essere fatta anche contestualmente alla definizione
della struttura:
struct recRUBRICA;
{
char nome[20];
char indirizzo[30];
…….
} Mario, Antonio,Giuseppe;
main()
………..
C++ Tutorial – By A.C. Neve
15
Le variabili Mario, Antonio e Giuseppe sono composte da otto sottovariabili (nome, indirizzo ecc.).
Nelle strutture, a differenza degli array, i sottoelementi non sono identificati dalla posizione ma da
un nome.
È anche possibile dichiarare le variabili senza assegnare uno specifico nome alla struttura e quindi
indicando solo struct.
È possibile copiare i valori di ogni singolo campo di una variabile nel corrispondente campo di una
nuova variabile per mezzo della funzione copia stringa:
recRUBRICA Paolo;
----strcpy Paolo.nome,Mario.nome);
strcpy (Paolo.indirizzo,Mario.indirizzo);
----Oppure in una unica soluzione copiando tutti i campi:
Paolo=Mario;
Il caricamento di una variabile può essere fatto anche in una unica soluzione:
recRUBRICA Mario={“Rossi Mario”, “via Po 5”, “Roma”, “065533287”,[email protected],1980,1,3};
Supponendo di voler gestire i dati relativi a 100 persone, sarà necessario definire una tabella che
contenga 100 voci del tipo recRUBRICA.
Si può creare un vettore di elementi di tipo recRUBRICA con la seguente dichiarazione:
recRUBRICA agenda[100];
una array di elementi di tipo struct è detto tabella.
nome
indirizzo
città
tel
mail
anno
mese
giorno
0
1
2
3
4
5
L’accesso ai singoli elementi di una tabella avviene con la tipica tecnica usata per gli array e cioè
usando nome e indice:
cout<<agenda[3].nome;
cin>>agenda[5].città;
C++ Tutorial – By A.C. Neve
16
ORDINAMENTO
L’ordinamento di un array consiste nello spostamento dei suoi elementi fino a disporli in un ordine
crescente o decrescente.
Tutti gli algoritmi di ordinamento si basano su operazioni di confronto e scambio di elementi.
Si evidenzia che, dal punto di vista computazionale, l’operazione di scambio è più onerosa di quella
del confronto in quanto richiede una variabile di appoggio in più e tre assegnazioni.
I classici algoritmi di ordinamento sono l’Exchange-sort e il Bubble-Sort.
Exchange-Sort (ordinamento ingenuo o per scambio diretto)
A partire dal primo e fino all’ultimo, si fissa un elemento dell’array e lo si confronta con tutti i
successivi effettuando, ove necessario, lo scambio tra i due confrontati.
Vett(0)
Vett(1)
Vett(2)
Vett(3)
Vett(4)
Vett(5)
3
2
5
1
6
5
3
5
2
6
5
5
3
6
5
5
6
5
6
5
FIX
1
FIX
1
2
FIX
1
2
3
FIX
1
2
3
5
FIX
1
2
3
5
5
6
Si nota subito che l’algoritmo fa uso di due cicli
determinati:
uno esterno per gli elementi fissi
uno interno per il confronto con tutti i successivi.
Si può anche costatare che, usando due cicli
determinati, questo algoritmo effettua sempre lo stesso
numero di confronti che, per un vettore di N elementi
risulta pari a :
N ⋅ ( N − 1)
N confronti =
2
La complessità risulta proporzionale a N2 sia che il vettore sia già ordinato che ordinato in senso
inverso.
Esempio di funzione:
void ExchangeSort(int Vett[], int N)
{
int i,j;
for(i=0;i<N-1;i++)
for(j=i+1;j<N;j++)
if(Vett[i]>Vett[j]
scambio(Vett[i],Vett[j]);
}
void scambio(int&x, int&y)
{
int z,
z=x;
x=y;
y=z;
}
C++ Tutorial – By A.C. Neve
17
Bubble-Sort
Si confrontano gli elementi a coppie successive eseguendo lo scambio, se necessario, e annotando
l’avvenuto scambio.
Se, al termine dei confronti, si è effettuato almeno uno scambio, si azzera il contatore degli scambi e
si ricomincia con il confronto di tutti gli elementi altrimenti il vettore risulta ordinato.
Vett(0)
Vett(1)
Vett(2)
Vett(3)
Vett(4)
Vett(5)
3
2
5
1
6
5
S=0
S=0
2
3
1
5
5
6
S=1
S=0
2
1
3
5
5
6
S=1
S=0
1
2
3
5
5
6
S=1
S=0
1
2
3
5
5
6
S=0
STOP
Il numero di confronti risulta:
N*(N-1) nel caso peggiore e (N-1) nel caso migliore.
Anche questo algoritmo fa uso di due cicli:
quello interno è determinato e serve per confronti e scambi degli elementi
quello esterno è indeterminato e viene ripetuto fino a quando, in quello interno, vi sono stati degli
scambi.
Esempio di funzione:
void BubbleSort(int Vett[],int N)
{
int I;
bool S;
do
{
S=false;
for(i=0;i<N-1;i++)
if(Vett [i]>Vett [i+1]
{
Scambio(Vett [i],Vett [i+1]);
S=true;
}
}while(S);
void scambio(int&x, int&y)
{
int z,
z=x;
x=y;
y=z;
}
C++ Tutorial – By A.C. Neve
18
Questo algoritmo non è particolarmente efficiente infatti:
l’algoritmo BubbleSort riesce, ad ogni passata, a posizionare l’elemento più grande nell’ultima
posizione del vettore.
È quindi possibile ridurre il numero di confronti.
Si può notare che, dopo la prima scansione e in tutte le successive, è sufficiente riconfrontare solo
gli elementi del vettore di indice minore della posizione nella quale, al passo precedente, è avvenuto
l’ultimo scambio.
Infatti, da quel punto in poi tutti gli elementi del vettore saranno sicuramente già ordinati.
Esempio di funzione:
void BubbleSort(int Vett[],int N)
{
int I,S;
do
{
for(i=0;i<N-1;i++)
if(Vett [i]>Vett [i+1]
{
scambio(Vett [i],Vett [i+1]);
S=i;
}
if(S>0)
N=S;
}while(S!=0);
}
void scambio(int&x, int&y)
{
int z,
z=x;
x=y;
y=z;
}
Si può verificare che, pur restando inalterato il numero di scambi (ovviamente), quello dei confronti
risulta certamente ridotto.
Esistono poi degli algoritmi di ordinamento molto più veloci ma molto più complessi come il
MergeSort o il QuickSort normalmente usati in presenza di elevate quantità di dati
C++ Tutorial – By A.C. Neve
19
RICERCA
La ricerca di un elemento in un insieme di dati è un problema molto diffuso e generalmente
associato a dati presenti in un array.
Se il vettore non è ordinato, l’unico metodo è quello della ricerca completa che consiste nella
scansione sequenziale di tutto il vettore confrontando tutti gli elementi con quello cercato.
Esempio di funzioni:
int RicercaSemplice(int Vett[], int N, int K)
// K = elemento cercato
{
int i=0;
do
{
if(Vett[i]==K)
return i;
i++;
}while(i<N)
return -1;
}
int RicercaSemplice(int Vett[], int N, int K)
// K = elemento cercato
{
int i;
for(i=0;i<N;i++)
if(Vett[i]==K)
return i;
return -1;
}
É evidente che, questa tecnica risulta alquanto onerosa e dispersive.
La situazione potrebbe molto migliorare nel caso in cui il vettore fosse già ordinato.
In questo caso i confronti potrebbero essere estesi fino al punto in cui gli elementi del vettore
avessero un valore maggiore di quello cercato in quanto, una ulteriore ricerca sarebbe inutile.
In un vettore ordinato in modo crescente , la ricerca del 50 sarebbe inutile dopo aver trovato il 51!
Un po’ come la ricerca di un nome nell’elenco telefonico.
Esempio di funzione:
int RicercaCompleta(int Vett[],int N, int K)
// K = elemento cercato
{
int i=0;
while((i<N)&&(Vett[i]<=K))
{
if(Vett[i]==K)
return i;
i++;
}
return -1;
}
C++ Tutorial – By A.C. Neve
20
Ricerca Binaria
Con questa tecnica di ricerca, invece di effettuare la scansione completa del vettore ordinato si
ricerca la metà che lo contiene.
Considerato un vettore ordinato di dimensione N, si calcola il valore dell’indice M dell’elemento
centrale dividendo così il vettore in due parti A e B.
Se il contenuto della cella di indice M contiene il valore cercato, l’algoritmo termina con successo.
Se invece il contenuto della cella M è maggiore dell’elemento cercato, il procedimento descritto si
applica alla parte A altrimenti si applica alla parte B.
Se non è possibile individuare l’elemento centrale, l’algoritmo termina senza aver trovato il valore
cercato.
Considerando un vettore di 1024 elementi, la ricerca richiede al più 10 passi mentre con 1048576
elementi saranno necessari al più 20 passi.
In generale, il numero di dimezzamenti sarà pari a log2(NUM campioni).
È consigliabile far uso di vettore aventi dimensione potenza di 2.
Esempio di funzione:
int RicercaBinaria(int Vett[],int N, int K)
// K = elemento cercato
{
int inizio, fine, centro;
inizio=0;
fine=N-1
while(inizio<=fine)
{
centro=(inizio+fine)/2;
if(Vett[centro]==K)
return centro;
if(Vett[centro]<K)
inizio=centro+1;
else
fine=centro-1;
}
return -1;
}
C++ Tutorial – By A.C. Neve
21
RICORSIVITA’
Una funzione si dice ricorsiva quando al suo interno è presente una chiamata a se stessa.
Tutto ciò potrebbe sembrare l’avvio di una iterazione infinita per cui è opportuno che la struttura
disponga di idonei eventi per il controllo della terminazione.
È quindi necessario definire:
¾ la condizione di terminazione
¾ il passo di ricorsione.
La ricorsione può essere:
diretta: quando il corpo della funzione contiene una chiamata a se stessa
indiretta: quando la funzione F contiene una chiamata alla funzione G che, a sua volta, contiene una
chiamata alla funzione F.
Per es., il calcolo del fattoriale di un intero M si può ottenere per mezzo della funzione:
int Fattoriale(M)
{
if(M==0)
return 1;
else
return(M*Fattoriale(M-1));
}
Un altro esempio può essere quello del calcolo della somma dei primi N numeri interi per mezzo
della seguente funzione ricorsiva:
int SommaNum(N)
{
if(N==1)
return N;
else
return(N+SommaNum(N-1);
}
Per ogni chiamata della funzione viene allocata un’area di memoria distinta con le variabili
caratterizzate da una validità locale e la struttura, per N=4, risulterebbe:
Funzione chiamante
A
H
10
SommaNum
N=4
B
C++ Tutorial – By A.C. Neve
G
6
SommaNum
N=3
C
F
3
SommaNum
N=2
D
E
1
SommaNm
N=1
22
A–
è la chiamata da parte della funzione esterna
B–C–D–
sono le chiamate ricorsive della funzione stessa
E – F – G – H – rappresentano il percorso inverso di de-allocazione degli spazi di memoria usati
nella ricorsione.
Si noti come il risultato venga calcolato durante il processo di ritorno verso la funzione esterna.
È necessario ribadire che, tutte le funzioni ricorsive devono prevedere un opportuno controllo della
condizione di terminazione.
Si fa notare che, negli algoritmi ricorsivi non sono presenti dei cicli che invece esistono negli
algoritmi iterativi. Tutto ciò migliora la leggibilità dei programmi ricorsivi.
Non sempre però la tecnica ricorsiva è più efficiente di quella iterativa come nel calcolo dei numeri
di Fibonacci: F0=0 F1=1 …… Fn=Fn-1 + Fn-2 con n ≥ 2.
Un altro aspetto da non sottovalutare è relativo al fatto che, un algoritmo ricorsivo richiede più
memoria e maggior temo dell’equivalente iterativo a causa dei meccanismi di allocazione e deallocazione della memoria.
C++ Tutorial – By A.C. Neve
23
GESTIONE DEI FILE
Un file è un insieme, non sempre omogeneo, di dati identificato da un nome, memorizzato su disco
e manipolabile da programmi differenti.
La gestione di questi file avviene con l’ausilio del Sistema Operativo (S.O.) che opera per conto dei
programmi che ne fanno richiesta.
Le operazioni utilizzate per la gestione dei file sono:
Apertura
Il programma comunica al S.O. la richiesta di accesso ad uno specifico file.
Il S.O. verifica l’esistenza dal file e la sua disponibilità (già in uso, protetto, ecc.) e
definisce un’area di memoria (buffer) per il transito dei dati da o per il programma.
Chiusura Il programma comunica al S.O. che ha concluso l’accesso al file.
Il file viene perciò salvato, l’area di memoria viene resa libera e viene eliminato il
nome del file dalla lista dei file aperti.
Lettura
Il programma richiede in input dei dati dal file.
Il S.O. trasferisce i dati dal file al buffer rendendoli così disponibili al programma.
Scrittura
Il programma richiede la scrittura di dati sul file.
Il S.O. provvede al trasferimento dei dati dal buffer al disco con relativa conferma.
Un file non può essere letto se prima non sia stato aperto e, una volta terminato l’utilizzo, deve
essere chiuso.
Nel trattamento dei file di testo sequenziali sono distinguibili le seguenti tipologie:
¾ ofstream: file con accesso in sola scrittura
¾ ifstream: file con accesso in sola lettura
¾ fstream: file con accesso sia in lettura che in scrittura.
questa ultima doppia modalità non può essere usata in contemporanea: si apre e poi si chiude una
modalità e poi si apre e si chiude l’altra modalità.
I file sequenziali possono essere letti o scritti per mezzo di istruzioni del tipo out e in che utilizzano
i simboli << e >>.
Esempio:
#include<iostream>
#include<fstream>
using namespace std;
main()
{
ofstream MIOFILE;
MIOFILE.open(“Testo.txt”);
MIOFILE<<(“Buon giorno a tutti”)<<endl;
MIOFILE.close();
}
C++ Tutorial – By A.C. Neve
Questo programma crea un file di nome Testo.txt e
vi inserisce il testo: Buongiorno a tutti.
Nell’istruzione di scrittura <<, la destinazione,
invece del video, risulta il file MIOFILE che viene
associato al file fisico Testo.txt.
Si notino le direttive di apertura e chiusura del
file.
24
In un programma, la gestione dei file richiede l’utilizzo di due nomi distinti:
Nome Fisico: è il nome con il quale il file viene salvato su disco dal S.O.. questo nome deve essere
definito dal pathname completo (C:\Doc\Relazioni\Testo.txt). Se si specifica il solo
nome fisico, il file dovrà risiedere nella stessa cartella del programma che lo usa.
Nome Logico: è il nome che nel programma viene associato al nome fisico quando viene aperto con
il metodo open(…). Nell’esempio precedente MIOFILE è il nome logico e Testo.txt
è il nome fisico.
Si consideri ora il seguente programma:
1) #include<iostream>
2) #include<fstream>
3)
4) using namespace std;
5) //Legge caratteri da un file e li copia in un altro file
6) int main (void)
7) {
8)
fstream f1,f2;
9)
int q;
10)
char k;
11)
cout<<"Inserisci il numero di caratteri da leggere ";
12)
cin>>q;
13)
14)
f1.open("fileletto.txt",ios::in);
15)
if(f1.is_open())
16)
cout<<"File OK"<<endl;
17)
else
18)
cout<<"Errore di apertura"<<endl;
19)
20)
f2.open("filescritto.txt",ios::out);
21)
if (f2.is_open())
22)
cout<<"File OK"<<endl;
23)
else
24)
cout<<"Errore di apertura"<<endl;
25)
f1>>k;
26)
f2<<k;
27)
while((!f1.eof()) && (q>0))
28) {
29)
q--;
30)
cout<<k<<endl;
31)
f1>>k;
32)
f2<<k;
33)
}
34)
35)
cout<<"Copiatura completa"<<endl;
36)
system("pause");
37) f1.close();
38) f2.close();
39) }
C++ Tutorial – By A.C. Neve
25
Questo programma legge un numero q di caratteri dal file “fileletto.txt” e li scrive nel file “file
scritto.txt”. Ne vengono ora esaminate in dettaglio le varie parti:
Riga 8
Sono dichiarati due oggetti di tipo fstream con nomi logici “f1” ed “f2”che saranno
in seguito associati a due file aventi nomi fisici “fileletto.txt” e “file scritto.txt”.
Riga 19
Questa istruzione apre il file “fileletto.txt” che è associato al file di nome logico “f1”.
Il metodo open() della classe fstream prevede due parametri:
il primo specifica il pathname del file fisico
il secondo specifica la modalità di apertura del file stesso.
Le modalità di apertura possono essere:
ƒ ios::in – apre un file, già esistente, in lettura
ƒ ios::out – apre un file in scrittura, lo crea se non esiste o vi sovrascrive se già esiste
ƒ ios::app – apre un file, già esistente, inserendo in coda i nuovi caratteri scritti
ƒ ios::nocreate – apre un file solo se esiste
ƒ ios::noreplace – apre un file solo se non esiste
ƒ ios::trunc – apre un file e cancella quello già esistente
ƒ
Come per la riga 14 ma apre il file in scrittura
Riga 25
Legge un carattere da “f1”
Riga 26
Scrive un carattere in “f2”
Riga 27
Il ciclo while determina la quantità di caratteri da gestire per mezzo delle due
condizioni poste in AND:
(!f1.eof()) – serve per verificare che nel file vi siano ancora dati da leggere. Il
metodo eof() restituisce TRUE se nel file son terminati i caratteri da leggere, FALSE
altrimenti.
(q>0) – serve a controllare la gestione di massimo q caratteri.
Si noti che, la prima lettura da “f1” è stata fatta fuori dal ciclo perché, nel caso in cui
il file “fileletto.txt” non contenga caratteri, il metodo eof() restituirebbe TRUE ed il
ciclo non verrebbe eseguito neanche una volta.
Riga 31
Legge un carattere da “f1”
Riga 32
Scrive un carattere in “f2”
Riga 37,38
Sono le istruzioni che chiudono i due file così che il S.O. provveda al salvataggio sul
disco del dati ancora presenti nel buffer.
Riga 14
Righe
15,16,17,18
20,21,22,23
L’operazione di apertura è molto importante sia che avvenga in lettura che in
scrittura per cui è necessario assicurarsi che il file sia stato correttamente aperto.
Questo controllo può essere fatto per mezzo dei metodi is_open() e fail() che
restituiscono un valore boleano:
is_open() restituisce TRUE se il file è stato correttamente aperto, altrimenti FALSE
fail() restituisce TRUE se il file non è stato correttamente aperto, altrimenti FALSE
C++ Tutorial – By A.C. Neve
26
La lettura di singoli caratteri da tastiera viene effettuata per mezzo dell’istruzione getchar().
È poi possibile leggere una intera riga di testo da un file per mezzo dell’istruzione getline() con
l’aiuto di un vettore nel quale inserire la stringa terminata da un carattere di codice ASCII 0.
Attenzione anche al fatto che le righe del file non contengano il solo carattere CR-LF che
farebbe terminare il programma in modo anomalo.
Esempi di programmi in C++
C++ Tutorial – By A.C. Neve
27
ESEMPIO 1
#include<iostream>
#include<cmath>
using namespace std;
main()
//
Calcolo dell'area e del perimetro del triangolo
{
char cont;
do
{
float x,y,area,ipotenusa,perimetro;
cout<<("Altezza = ");
cin>>x;
cout<<("Base = ");
cin>>y;
area=(x*y)/2;
cout<<"area del triangolo = "<<area<<endl;
ipotenusa=sqrt(x*x+y*y);
perimetro=x+y+ipotenusa;
cout<<"Perimetro del triangolo = "<<perimetro<<endl<<endl;
cout<<"Vuoi continuare? (Y/N)";
cin>>cont;
}
while(cont=='Y');
system("pause");
}
ESEMPIO 2
#include<iostream>
#include<cmath>
using namespace std;
//
Calcolo dei quadrati da 1 a N
main()
{
int i, N;
cout<<"Inserire il valore superiore = ";
cin>>N;
for (i=1; i<=N; i++)
{
cout<<i*i<<endl;
}
cout<<"Lavoro concluso"<<endl<<endl;
system("pause");
}
C++ Tutorial – By A.C. Neve
28
ESEMPIO 3
#include<iostream>
#include<cmath>
using namespace std;
//
Visualizza la sequenza dei numeri pari compresi tra N ed M
main()
{
int N, M;
cout<<("Inserire estremo inferiore: ");
cin>>N;
cout<<("inserire estremo superiore: ");
cin>>M;
if(N%2 !=0) //Se l'estremo inferiore è dispari
N=N+1;
// inizia dal numero pari successivo
while(N<=M) //Finchè N è minore dell'estremo superiore
{
cout<<N<<endl;
N=N+2;
}
cout<<"Lavoro concluso"<<endl<<endl;
system("pause");
}
C++ Tutorial – By A.C. Neve
29
ESEMPIO 4
#include<iostream>
#include<cmath>
using namespace std;
//
Selezione a scelta multipla
main()
{
int N;
cout<<"Inserire il valore = ";
cin>>N;
switch (N)
{
case 1:
cout<<"Area del triangolo"<<endl;
break;
case 2:
cout<<"Area del rettangolo"<<endl;
break;
case 3:
cout<<"Area del rettangolo"<<endl;
break;
default:
cout<<"Valore non accettato"<<endl;
}
system("pause");
}
C++ Tutorial – By A.C. Neve
30
ESEMPIO 5
#include<iostream>
#include<cmath>
using namespace std;
//
//
Calcolo delle combinazioni di k valori presi da un gruppo di n
C(n,k) = n!/(k! * (n-k)!)
long fattoriale(int x)
{
int i;
long f=1;
for (i=1; i<=x; i++)
f=f*i;
return f;
}
main()
{
int n,k,A,B,C;
int fatt;
cout<<("Numero di valori totale del gruppo = ");
cin>>n;
cout<<("Numero di valori presi in gruppo = ");
cin>>k;
A=fattoriale(n);
B=fattoriale(k);
C=fattoriale(n-k);
cout<<A<<endl;
cout<<B<<endl;
cout<<C<<endl;
fatt=fattoriale(n)/(fattoriale(k)*fattoriale(n-k));
cout<<"Il risultato e' "<<fatt<<endl;
system("pause");
}
C++ Tutorial – By A.C. Neve
31
ESEMPIO 6
#include<iostream>
#include<cmath>
using namespace std;
Calcolo del costo di una spedizione
//
main()
{
char classe;
float peso,C,costo;
int distanza;
cout<<"Inserire classe di spedizione (N=normale - U=urgente): ";
cin>>classe;
cout<<"Inserire peso (Kg): ";
cin>>peso;
cout<<"inserire la distanza (Km): ";
cin>>distanza;
if(classe=='U'||classe=='u')
{
if(distanza<100)
C=1.5;
else if(distanza>500)
C=3.0;
else C=2.0;
}
else
{
if(distanza<100)
C=1.0;
else if(distanza>500)
C=2.0;
else C=1.5;
}
costo=C*peso;
cout<<endl<<"Il costo della spedizione e' "<<costo<<" Euro"<<endl<<endl;
cout<<"Lavoro concluso"<<endl;
system("pause");
}
C++ Tutorial – By A.C. Neve
32
ESEMPIO 7
#include<iostream>
#include<cmath>
using namespace std;
Conversione Decimale Binario intero (MAX 65535)
//
main()
{
int k,N;
int bit[16]={0};
cout<<"Inserire numero decimale = ";
cin>>N;
cout<<"Il numero binario vale = ";
k=16;
while(N !=0)
{
bit[k]=N%2;
N=N/2;
k=k-1;
}
for (k=1; k<=16; k++)
{
cout<<bit[k];
}
cout<<(" ")<<endl<<endl;
system("pause");
}
C++ Tutorial – By A.C. Neve
33
ESEMPIO 8
# include<iostream>
using namespace std;
int scambia(int &a, int &b)
{
int t;
t=a;
a=b;
b=t;
cout<<" N interno alla funzione = "<<a<<endl;
cout<<" M interno alla funzione = "<<b<<endl<<endl;
}
//
//
Scambio di due variabili
con passaggio di parametri per riferimento
main(void)
{
int n,m;
cout<<"N = ";
cin>>n;
cout<<"M = ";
cin>>m;
scambia(n,m);
cout<<" N interno al main = "<<n<<endl;
cout<<" M interno al main = "<<m<<endl<<endl;
system ("pause");
}
C++ Tutorial – By A.C. Neve
34
ESEMPIO 9
#include<iostream>
using namespace std;
//
Calcolo della media su vettore
main()
{
float vett[10],TOT=0,media;
int i;
for(i=0;i<10;i++)
{
cout<<"Vett("<<i<<") =";
cin>>vett[i];
}
for(i=0;i<10;i++)
TOT=TOT+vett[i];
media=TOT/10;
if(media==0)
{
cout<<endl<<"ATTENZIONE la media e' uguale a = "<<media<<endl<<endl;
}
else
{
cout<<endl<<"Il valore medio e'"<<media<<endl<<endl;
}
system("pause");
}
C++ Tutorial – By A.C. Neve
35
ESEMPIO 10
#include<iostream>
#include<cmath>
using namespace std;
//
Calcolo della media su vettore usando una funzione
float MEDIA(float Vett[], int n)
{
float TOT,media;
int i;
TOT=0;
cout<<"sono nella funzione"<<endl;
for(i=0;i<n;i++)
{
TOT=TOT+Vett[i];
media=TOT/10;
}
return media;
}
//======================================================
main()
{
float Vett[10],TOT=0,media;
int i;
for(i=0;i<10;i++)
{
cout<<"Vett("<<i<<") =";
cin>>Vett[i];
}
media=MEDIA(Vett,10);
for(i=0;i<10;i++)
{
cout<<Vett[i]<<" ";
}
if(media==0)
{
cout<<endl<<"ATTENZIONE la media e' uguale a = "<<media<<endl<<endl;
}
else
{
cout<<endl<<"Il valore medio e'"<<media<<endl<<endl;
}
system("pause");
}
C++ Tutorial – By A.C. Neve
36
ESEMPIO 11
#include<iostream>
using namespace std;
//
Calcolo della cifra di controllo di un codice a barre
main()
{
int vett[12],TOTpari=0,TOTdisp=0,TOT=0,COD=0,VAL;
int i;
cout<<"**********************************************************"<<endl;
cout<<"*** INSERIRE I PRIMI 12 VALORI DEL CODICE A BARRE ***"<<endl;
cout<<"**********************************************************"<<endl<<endl;
for(i=0;i<12;i++)
{
cout<<"VETT("<<i<<") = ";
cin>>vett[i];
}
for(i=0;i<12;i++)
{
cout<<vett[i]<<" ";
}
cout<<endl<<endl;
for(i=0;i<12;i=i+2)
{
cout<<vett[i]<<" ";
TOTpari=TOTpari+vett[i];
}
cout<<endl<<endl;
cout<<"TOTpari = "<<TOTpari;
cout<<endl<<endl;
// ==========================
for(i=1;i<12;i=i+2)
{
cout<<vett[i]<<" ";
TOTdisp =TOTdisp+vett[i]*3;
}
cout<<endl<<endl;
cout<<"TOTdisp = "<<TOTdisp;
cout<<endl<<endl;
// ==========================
TOT=TOTpari+TOTdisp;
cout<<endl<<"TOT = TOTpari*3+TOTdispari = "<<TOT<<endl;
VAL=(TOT/10)*10+10;
cout<<endl<<"VAL = "<<VAL<<endl;
COD=VAL-TOT;
if(COD==10)
cout<<endl<<"CODICE DI CONTROLLO = 0"<<endl<<endl;
else
cout<<endl<<"CODICE DI CONTROLLO = "<<COD<<endl<<endl;
system("pause");
}
C++ Tutorial – By A.C. Neve
37
ESEMPIO 12
#include <iostream>
#include <cmath>
using namespace std;
//
main()
Equazioni di secondo grado: Ax^2+Bx+C=0
{
float a,b,c,x1,x2,delta;
int vett[3]={0},num;
char ripeti;
do
{
cout<<"Inserire i coefficienti dell'equazione"<<endl;
cout<<"======================================"<<endl<<endl;
cout<<"A = ";
cin>>a;
cout<<"B = ";
cin>>b;
cout<<"C = ";
cin>>c;
if(a==0)
vett[2]=0;
else
vett[2]=1;
if(b==0)
vett[1]=0;
else
vett[1]=1;
if(c==0)
vett[0]=0;
else
vett[0]=1;
num=vett[2]*4+vett[1]*2+vett[0]*1; // Individua il tipo di equazione (0,1,2,……6,7)
switch(num)
{
case 0:
cout<<"Equazione indeterminata poiche' A=B=C=0"<<endl;
break;
case 1:
cout<<"Equazione con infinite soluzioni poiche' A=B=0"<<endl;
break;
case 2:
cout<<"La radice e' uguale a 0 poiche' A=C=0"<<endl;
break;
case 3:
x1=-c/b;
cout<<"Equazione con A=0, radice unica X = "<<x1<<endl;
break;
C++ Tutorial – By A.C. Neve
38
case 4:
cout<<"La radice e' uguale a 0 poiche' B=C=0"<<endl;
break;
case 5:
if(c>0)
{
x1=sqrt(c/a);
cout<<"Radici complesse coniugate: X1=+i "<<x1<<" X2=-i "<<x1<<endl;
}
else
{
x1=sqrt(-c/a);
cout<<"Radici reali uguali e opposte: X1="<<x1<<" X2=-"<<x1<<endl;
}
break;
case 6:
x2=-b/a;
cout<<"Equazione con C=0: "<<"X1 = 0 e X2 = "<<x2<<endl;
break;
case 7:
delta=b*b-4*a*c;
if(delta>0)
{
x1=(-b+sqrt(delta))/(2*a);
x2=(-b-sqrt(delta))/(2*a);
cout<<"Radici reali e distinte: X1="<<x1<<" e x2="<<x2<<endl;
}
else
if(delta==0)
{
x1=-b/(2*a);
cout<<"Radici reali e coincidenti: X1=X2="<<x1<<endl;
}
else
if(delta<0)
{
x1=(-b+sqrt(-delta))/(2*a);
x2=(-b-sqrt(-delta))/(2*a);
cout<<"Radici complesse coniugate: X1=i "<<x1<<" X2=i "<<x2<<endl;
}
break;
}
cout<<endl<<("Vuoi continuare? (y/n)");
cin>>ripeti;
}
while(ripeti=='y'||ripeti=='Y');
system ("pause");
}
C++ Tutorial – By A.C. Neve
39
ESEMPIO 13
#include<iostream>
#include<cmath>
using namespace std;
//
Utilizzo delle strutture
struct anagrafe
{
char cognome[20];
char nome[20];
unsigned int eta;
char indirizzo[30];
char comune[20];
};
//==============================================
main()
{
struct anagrafe Mario, Uccio;
strcpy (Mario.cognome, "Rossi");
strcpy (Mario.nome, "Mario");
strcpy (Mario.indirizzo, "via Roma 15");
strcpy (Mario.comune, "Lecce");
strcpy (Uccio.cognome, "Verdi");
strcpy (Uccio.nome, "Uccio");
strcpy (Uccio.indirizzo, "via Po 10");
strcpy (Uccio.comune, "Bari");
cout<<"Inserisci eta' del sig. Mario ";
cin>>Mario.eta;
cout<<endl<<"Inserisci eta' del sig. Uccio ";
cin>>Uccio.eta;
if(Mario.eta>=Uccio.eta)
{
cout<<endl<<Mario.cognome<<" "<<Mario.nome<<" - "<<Mario.indirizzo
<<" "<<Mario.comune<<endl<<endl;
}
else
{
cout<<endl<<Uccio.cognome<<" "<<Uccio.nome<<" - "<<Uccio.indirizzo
<<" "<<Uccio.comune<<endl<<endl;
}
system("pause");
}
C++ Tutorial – By A.C. Neve
40
ESEMPIO 14
Gestione dei colori sfondo e caratteri
//
main()
{
system ("COLOR 4a");
// L’attributo è costituito da DUE cifre esadecimale:
// la prima per lo sfondo e la seconda per il testo
// secondo la seguente tabella
printf("
printf("
printf("
printf("
printf("
printf("
printf("
printf("
0 = Nero
1 = Blu scuro
2 = Verde
3 = Verde acqua
4 = Bordeaux
5 = Viola
6 = Verde oliva
7 = Grigio chiaro
8 = Grigio\n");
9 = Blu\n");
A = Verde limone\n");
B = Azzurro\n");
C = Rosso\n");
D = Fucsia\n");
E = Giallo\n");
F = Bianco\n\n");
system ("pause");
}
C++ Tutorial – By A.C. Neve
41
ESEMPIO 15
#include<iostream>
#include<cmath>
using namespace std;
//
Calcolo e stampa del grafico della funzione [sinx+sin3x+sin5x+sin7x]
main()
{
int M=0, i=0, j=0, punto=0;
float delta=0.0449, y=0;
char matrix[61][141]={0};
system("COLOR 4b");
system("mode con: cols=150 lines=70");
// Disegno degli assi
for(i=0;i<61;i++)
{
matrix[i][0]='|';
}
for(j=0;j<141;j++)
{
matrix[30][j]='-';
}
// Calcolo, taratura della scala
for(j=0;j<141;j++)
{
y=(sin(M*delta)+sin(3*M*delta)/3+sin(5*M*delta)/5+sin(7*M*delta)/7)*30;
punto=(round(y))+30;
matrix[punto][j]=1;
M=M+1;
}
// Stampa grafico
for(i=0;i<61;i++)
{
for(j=0;j<140;j++)
{
cout<<matrix[i][j];
}
cout<<endl;
}
cout<<endl<<endl;
system("pause");
}
C++ Tutorial – By A.C. Neve
42
ESEMPIO 16
#include <iostream>
#include <cmath>
using namespace std;
//
Verifica e correzione di una stringa in codifica Hamming
main()
{
int i,K1,K2,K3,Err,vett[7];
for(i=6;i>=0;i--)
{
cout<<("Hamming")<<i<<" = ";
cin>>vett[i];
}
cout<<("La stringa Hamming RICEVUTA risulta:");
for(i=6;i>=0;i--)
{
cout<<" "<<vett[i];
}
cout<<endl<<endl;
// Determina il bit errato
K1=(vett[0]+vett[2]+vett[4]+vett[6])%2;
K2=(vett[0]+vett[2]+vett[5]+vett[6])%2;
K3=(vett[3]+vett[4]+vett[5]+vett[6])%2;
Err=K3*4+K2*2+K1*1;
if(Err==0)
{
cout<<("La striga Hamming e' ESATTA !
");
}
else
{
// Corregge il bit errato e stampa la stringa
cout<<("Vi e' un errore sul bit ")<<Err<<endl<<endl;
if(vett[Err-1]==0)
vett[Err-1]=1;
else
if(vett[Err-1]==1)
vett[Err-1]=0;
cout<<("La stringa Hamming CORRETTA diventa:");
}
for(i=6;i>=0;i--)
{
cout<<" "<<vett[i];
}
cout<<endl<<endl;
system("pause");
}
C++ Tutorial – By A.C. Neve
43
ESEMPIO 17
#include <iostream>
#include <cmath>
#include <windows.h>
using namespace std;
//
main()
{
int i;
i=100;
do
{
Beep(i,200);
i=i+100;
}
while(i<=1000);
i=1000;
do
{
Beep(i,200);
i=i-100;
}
while(i>=20);
}
C++ Tutorial – By A.C. Neve
Gestione del BEEP in frequenza e durata
44
ESEMPIO 18
#include<iostream>
#include<cmath>
using namespace std;
//
Tecniche di arrotondamento
main()
{
//=============================================
float x1,x2;
cout<<"Primo valore = ";
cin>>x1;
cout<<"round = "<<round(x1)<<endl;
cout<<"Secondo valore = ";
cin>>x2;
cout<<"round = "<<round(x2)<<endl<<endl;
//=============================================
cout<<"Primo valore = ";
cin>>x1;
cout<<"ceil = "<<ceil(x1)<<endl;
cout<<"Secondo valore = ";
cin>>x2;
cout<<"ceil = "<<ceil(x2)<<endl<<endl;
//=============================================
cout<<"Primo valore = ";
cin>>x1;
cout<<"floor = "<<floor(x1)<<endl;
cout<<"Secondo valore = ";
cin>>x2;
cout<<"floor = "<<floor(x2)<<endl<<endl;
//=============================================
system("pause");
}
C++ Tutorial – By A.C. Neve
45
ESEMPIO 19
#include <iostream>
#include<cmath>
using namespace std;
//
Numeri Pseudocasuali e test della funzione rand()
main()
{
system("COLOR 1e");
int i,R,K=0,cerca,TOT,Max;
float ProbIdeal,ProbReal;
cout<<"Inserisci il numero TOTALE di estrazioni da effettuare ";
cin>>TOT;
cout<<"Inserisci il valore massimo N da generare come (N+1) ";
cin>>Max;
cout<<("Inserisci il numero da cercare (minore o uguale a N) ");
cin>>cerca;
cout<<endl;
srand(time(NULL));
for(i=1;i<=TOT;i++)
{
R=rand()%Max;
if(R==cerca)
K=K+1;
}
cout<<"Il numero cercato e' stato estratto "<<K<<" volte"<<" su "<<TOT
<<" estrazioni"<<endl<<endl;
ProbIdeal=(1/(float(Max)-1))*100;
ProbReal=(float(K)/float(TOT))*100;
cout<<"Probabilita' IDEALE = "<<ProbIdeal<<"%"<<endl;
cout<<"Probabilita' REALE = "<<ProbReal<<"%"<<endl<<endl;
system("pause");
}
C++ Tutorial – By A.C. Neve
46
ESEMPIO 20
#include <iostream>
#include<cmath>
using namespace std;
//
Test della equiprobabilità della funzione RAND
main()
{
system("COLOR 1e");
int i,R,K=0,TOT,Max=10,vett[10]={0};
float Prob;
cout<<"Inserisci il numero TOTALE di estrazioni da effettuare ";
cin>>TOT;
cout<<endl;
srand(time(NULL));
for(i=1;i<=TOT;i++)
{
R=rand()%Max;
vett[R]=vett[R]+1;
}
for(i=0;i<10;i++)
{
Prob=(float(vett[i])/float(TOT))*100;
cout<<"Estratto("<<i<<") = "<<vett[i]<<" volte "<<"Probabilita' = "<<Prob<<"%"<<endl;
}
cout<<endl;
system("pause");
}
C++ Tutorial – By A.C. Neve
47
ESEMPIO 21
#include<iostream>
#include<cmath>
using namespace std;
//
Simulazione di un mazzo di carte
main()
{
system("COLOR 1e");
system("mode con cols=50 lines=50");
int Matrix[4][10],Riga,Col,Maxriga=4,Maxcol=10,i,j,TOT;
srand(time(NULL));
for(i=0;i<4;i++)
{
for(j=0;j<10;j++)
{
Matrix[i][j]=1;
}
}
do
{
do
{
Riga=rand()%Maxriga;
Col=rand()%Maxcol;
}
while(Matrix[Riga][Col]==0);
Matrix[Riga][Col]=0;
switch(Riga)
{
case 0:
cout<<"Carta - Bastoni ";
break;
case 1:
cout<<"Carta - Denari ";
break;
case 2:
cout<<"Carta - Spade ";
break;
case 3:
cout<<"Carta - Coppe ";
break;
}
cout<<(Col+1)<<endl;
TOT=0;
for(i=0;i<4;i++)
{
for(j=0;j<10;j++)
{
TOT=TOT+Matrix[i][j];
}
}
}
while(TOT>0);
cout<<endl;
system("pause");
}
C++ Tutorial – By A.C. Neve
48
ESEMPIO 22
#include<iostream>
#include<cmath>
using namespace std;
//
Ordinamento per scambio
int scambio(int&a, int&b)
{
int z;
z=a;
a=b;
b=z;
}
//====================================================
main(void)
{
system("COLOR 9e");
int i,j,DIM;
cout<<"Inserire il numero dei campioni da ordinare: ";
cin>>DIM;
int vett[DIM];
cout<<"Inserire i "<<DIM<<" campioni"<<endl<<endl;
for(i=0;i<DIM;i++)
{
cout<<"NUM("<<i<<") = ";
cin>>vett[i];
}
//====================================================
for(i=0;i<DIM;i++)
{
for(j=0;j<DIM;j++)
{
if(vett[i]>vett[j])
scambio(vett[i],vett[j]);
}
}
//=====================================================
cout<<endl<<"Il vettore ordinato risulta:"<<endl<<endl;
for(i=0;i<DIM;i++)
{
cout<<vett[i]<<" ";
}
cout<<endl<<endl;
system("pause");
}
C++ Tutorial – By A.C. Neve
49
ESEMPIO 23
#include<iostream>
#include<cmath>
using namespace std;
//
Ordinamento Bubble Sort Ottimizzato
int scambio(int&a, int&b)
{
int z;
z=a;
a=b;
b=z;
}
//====================================================
main(void)
{
system("COLOR 9e");
int i,DIM;
bool s=false;
cout<<"Inserire il numero dei campioni da ordinare: ";
cin>>DIM;
int vett[DIM];
cout<<"Inserire i "<<DIM <<" campioni"<<endl<<endl;
for(i=0;i<DIM;i++)
{
cout<<"NUM("<<i<<") = ";
cin>>vett[i];
}
do
{
s=false;
for(i=0;i<DIM-1;i++)
{
if(vett[i]>vett[i+1])
{
scambio(vett[i],vett[i+1]);
s=true;
cout<<endl<<" s = "<<s<<endl;
cout<<endl;
}
}
cout<<endl<<"========"<<endl<<endl;
}
while(s==true);
//====================================================
cout<<endl<<"Il vettore ordinato risulta:"<<endl<<endl;
for(i=0;i<DIM;i++)
{
cout<<vett[i]<<" ";
}
system("pause");
}
C++ Tutorial – By A.C. Neve
50