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