file Ciao.cc
# include <iostream> int main() { cout << "Ciao a Tutti!" << endl; return 0; }Per scrivere programmi C++ usate un editore di testi .Copiate il programma e salvatelo in un file di nome Ciao.cc L'istruzione
g++ -o Ciao Ciao.cccompilera' il programma' creando un file: Ciao Finalmente l'istruzione
Ciaofara' eseguire il programma che scrivera' la frase Ciao a Tutti.
Cominciamo con un piccolo vocabolario Java/C++:
Java | C++ |
class | class |
proprieta' | data members |
metodi | member functions |
this | this |
super | non esiste:usare l'operatore :: di inherited
|
. | . o -> |
extends Superclass | : public Superclass |
implements Interface | :public Interface (C++ permette l'ereditarieta' multipla) |
A differenza di Java, non tutte le funzioni devono essere definite in una classe;in C++ abbiamo oltre alle member functions anche le free functions funzioni al di fuori di ogni classe.Anzi,ogni programma C++ deve includere almeno una free function, quella chiamata main che viene richiamata dal sistema operativo quando parte il programma.Questo spiega la particolare struttura del programma "Ciao a tutti" in C++.
Compilare sotto Windows: Le istruzioni riportate in queste lezioni sono valide se lavorate in una finestra terminale sotto Linux. Sotto Windows i programmi sono stati provati col compilatore Borland di C++Builder 5 .Dovete salvare i programmi in files col suffisso .cpp . Da una finestra MsDos posizionatevi nella cartella dove avete salvato i files(ad es. Calcola.cpp e Counter.cpp) e date le istruzioni:bcc32 Calcola.cpp Counter.cpp CalcolaQualche programma richiede qualche piccola modifica come:#include <iostream.h>invece di#include <iostream>
Borland offre il C++ Builder Compiler 5 scaricabile liberamente.
Sotto Windows potete anche usare Bloodshed DEV-C++ un ambiente per lo sviluppo di programmi nei linguaggi c e c++ in ambiente windows. L'ambiente integra editor, compilatore, linker e debugger.
Il programma e` scaricabile gratuitamente all'indirizzo http://www.bloodshed.net/dev/devcpp.htm. Sul sito sono disponibili materiali di documentazione.
file Somma.cc
# include <iostream> int main() { float a,b,c; cout << "Scrivi 2 numeri" << endl; cin >> a >> b; c = a+ b; cout << a <<" + "<< b << " = " << c << endl; return 0; }
Java | C++ |
short | short int |
int | int |
long | long int |
float | float |
double | double |
long double | |
byte | char |
char | wchar_t (introdotto da poco) |
boolean | bool (introdotto da poco)(*) |
bool
le costanti false e true in C++ corrispondono ai valori
interi zero e diverso da zero.Anche char
in C++ e' considerato a tutti gli effetti un intero.
if(x=y)faiqualcosa
e' corretta
in C++ ma non in Java.Se il programmatore intendeva scrivere if(x==y)
ecco un errore che scoprira' difficilmente.
Debugging con DDD:DDD e' un programma (in effetti solo un'interfaccia grafica a gdb) che permette di debuggare i programmi C++. Per usarlo, dovete prima compilare il programma con l'opzione -g. Ad esempio:g++ -o Somma -g Somma.cce poi dare il comando :ddd Somma. Si apre una finestra grafica contenente il codice del programma e vari tasti e menu'. La prima cosa da fare e' di creare uno o piu' breakpoint (istruzioni dove il programma si fermera' in attesa). Questo lo si fa cliccando col tasto destro nello spazio vuoto prima dell'istruzione e poi selezionando "set breakpoint". Ora potete cliccare sul tasto Run. Quando il programma si ferma al primo breakpoint potete usare il mouse per vedere il valore delle variabili vicine al breakpoint (basta passare il mouse sopra attendendo qualche istante). Per procedere di un'istruzione alla volta basta cliccare su "Until".Quando il programma e' in esecuzione, potete in ogni momento cliccare su "Interrupt" , esaminare il valore delle variabili o inserire nuovi breakpoint e poi cliccare su "Cont" per riprendere l'esecuzione.
Da notare che l'esame di programmi compilati con ottimizzazione (opzione -O) puo' dare sorprendenti risultati:ad es:variabili non definite, esecuzione non sequenziale di istruzioni.
Programma 3:Scrivete un programma che legge una
serie di numeri e ne calcola la media
.S
file Media.cc
# include <iostream> int main() { int i; float x[10]; double sum; sum = 0; i = 0; while(cin >> x[i]){ sum += x[i]; i = i + 1; } cout << sum/i << endl; return 0; }Commenti:
file Media.cc
#include <iostream.h> double media() { int i,n; cin >> n; float* x = new float[n]; double sum; sum = 0; for ( i = 0; i < n; i++) { cin >> x[i] ; sum += x[i]; } return sum/n; delete [] x; } int main() { cout << media() << endl; return 0; }Commenti:
media
e' fuori dal main in un file
header
.S
file Media.h
double media();
file Calcola.cc
#include <iostream> #include "Media.h" int main() { cout << media() << endl; return 0; }
file Media.cc
#include <iostream> double media() { int i,n; cin >> n; float* x = new float[n]; double sum; sum = 0; for ( i = 0; i < n; i++) { cin >> x[i] ; sum += x[i]; } return sum/n; delete [] x; }
g++ -o Calcola Media.cc Calcola.ccCommenti:
file Calcola.cc
#include <iostream> #include <math.h> int main() { float x; while (cin >> x) { cout << x << " " << sqrt(x) << endl; } return 0; }Per ogni libreria standard bisogna includere il file delle dichiarazioni(header). Quindi l'istruzione include che potrebbe sembrare superficialmente molto simile all'import di Java ha un significato completamente diverso.Il compilatore C++ non fa che copiare il contenuto delle dichiarazioni all'inizio del programma e compilare il tutto. Invece e' solo all'atto del link che dobbiamo indicargli il file contenente la libreria compilata.Un
#include "header"
indica che il file
va cercato a partire dalla cartella dove ci troviamo , #include <header>
nella cartella contenente tutti gli include files.In quest'ultimo caso
la regola e' di non indicare il ".h" a meno che non ci si riferisca alle vecchie librerie C. Queste vengono talvolta indicate anche con un nome che comincia con c e senza il .h (Ad esempio #include <cstdio>
invece di #include <stdio.h>
. Quindi se volete usare le funzioni C di trattamento di stringhe scrivete:#include <string.h>
oppure #include <cstring>
, se invece volete usare le strighe C++ scrivete :
#include <string>
ls /usr/include (per avere la lista dei file) more nomefile (per avere il contenuto di un singolo header file)Invece i gli header files del C++ si possono trovare in
/usr/local/include/g++
using namespace std: Anche se nei programmi che seguono non viene quasi mai usata, questa istruzione la troverete spessissimo nei programmi C++. Che significa e perche si inserisce sempre all'inizio di un programma dopo gli include?L'istruzione using e' legata al fatto che in C++ avete anche dichiarazioni fuori da ogni classe. Questi nomi si possono anch'essi suddividere e qualificare con namespaces.Il namespace std e' quello di tutte le variabili e funzioni delle librerie standard di C++.Ma voi potreste definire un vostro namespace pippo per evitare possibili confusioni e poi usarlo con using namespace pippo.
Oppure usare i nomi completi che si indicano anteponendo il nome del namespece seguito da ::
Cosi' se avete definito una vostra funzione sqrt, avrestestd::sqrt
epippo::sqrt
. Ovviamente std e' il namespace predefinito ed e' per questo che l'istruzione using manca nei programmi di queste lezioni.
Programma 7:
Scrivete una funzione che faccia lo scambio di 2 valori passati come argomenti
S
file Scambia.cc
#include <iostream.h> void scambio(int &x, int &y ) { int temp; temp = x; x = y; y =temp; } int main() { int a,b; a = 1; b=2; cout << a << b << endl; scambio(a,b); cout << a << b << endl; return 0; }Commenti:
Programma 8:
Il primo programma che usa i puntatori!
S
file Puntatori.cc
#include <iostream.h> int main() { int *p; int j; p = &j; cout << *p << endl; *p = 5; cout << *p << ' ' << j << endl; if(p != 0) cout << "Il puntatore p punta a " << *p << " che quindi si trova all\'indir izzo "<< p << endl; return 0; }In Java abbiamo 2 tipi di variabili. Le variabili che indicano tipi primitivi si riferiscono al valore degli stessi, per cui:
int i = 1; int j = 2; j = i;ha come risultato che j alla fine contiene il valore 1. Invece le variabili che si riferiscono ad oggetti contengono solo il puntatore all'oggetto,per cui:
String a = "Torino"; String b = "Milano"; b = a;ha come effetto di distruggere l'oggetto "Milano" in quanto dopo l'assegnazione b=a b punta a "Torino".
<T>*
dove <T> puo'
essere un qualsiasi tipo di dati primitivi,aggregati o oggetti.
int* p
indica che p e' un puntatore a un dato intero.
Vediamo ora vari modi di assegnare il valore al puntatore:
p = &var | p punta a var. L'operatore & ritorna l'indirizzo di una variabile. |
int *p = new int; | un intero viene allocato e il suo indirizzo ritornato in p; alla fine ricordarsi di inserire delete p
|
int *p = new int[10] | un vettore di interi viene allocato e il suo indirizzo tornato in p; alla fine ricordarsi di inserire delete p[]
|
p = NULL oppure p=0 | puntatore vuoto |
p = 5 | p punta all'indirizzo di memoria 5 |
i = *p | permette di ottenere il valore puntato da p . L'asterisco indica in questo caso un operatore detto in gergo di dereferenziazione o indirezione. |
*p = 5 | permette di assegnare il valore 5 all'intero puntato da p. |
Programma 9:
Riscrivete la funzione che scambia i valori di 2 variabili intere in modo da usare i puntatori
S
file Scambia.cc
#include <iostream.h> void scambio(int *x, int *y ) { int temp; temp = *x; *x = *y; *y =temp; } int main() { int a,b; a = 1; b=2; cout << a << b << endl; scambio(&a,&b); cout << a << b << endl; return 0; }
Programma 10:
Riscrivete il programma che calcola la media in modo da usare i puntatori
S
file Media.cc
#include <iostream.h> double media() { int i,n; cin >> n; float* x = new float[n]; float *y = x;//y punta a x[0] double sum; sum = 0; for ( i = 0; i < n; i++) { cin >> x[i] ; sum += *y++; } return sum/n; delete [] x; } int main() { cout << media() << endl; return 0; }
Programma 11:
Riscrivete il programma precedente in modo da leggere i valori nel main e passare il vettore alla funzione
S
file Media.cc
#include <iostream.h> double media(float *y, int n) { int i; double sum; sum = 0; for ( i = 0; i < n; i++) sum += *y++; return sum/n; } int main() { int i,n; cin >> n; float* x = new float[n]; for ( i = 0; i < n; i++) cin >> x[i] ; cout << media(x,n) << endl; delete [] x; return 0; }
In C/C++ quando passate il nome di un vettore, il passaggio degli argomenti avviene per riferimento. In effetti il nome di un vettore non e' altro che il puntatore al primo elemento del vettore. Cioe' se x e' un vettore:
file Media1.cc
#includedouble media(float y[], int n) { int i; double sum; sum = 0; for ( i = 0; i < n; i++) sum += y[i]; return sum/n; } int main() { int i,n; cin >> n; float* x = new float[n]; for ( i = 0; i < n; i++) cin >> x[i] ; cout << media(x,n) << endl; delete [] x; return 0; }
Programma 12:
Scrivete un programma che riversa una stringa di caratteri.
S
file Riversa.cc
#include < iostream.h> #include < string.h> void riversa(char *s, int n) { char *primo = &s[0]; char *ultimo =&s[n-1] ; while(primo < ultimo){ char temp = *primo; *primo++ = *ultimo; *ultimo-- = temp; } } int main() { int n; char str[] = "ROMA"; cout << str ; n = strlen(str); riversa(str,n); cout << str << endl; return 0; }Commenti:
string.h
contiene alcune utili funzioni per il loro trattamento come strlen
Per concludere una importante osservazione su puntatori ,vettori e stringhe:
C++ non fa nessun controllo sulla dimensione del vettore.
Se ,magari usando i puntatori, avete un valore sbagliato di un indice,
C++ continuera' ad eseguire tranquillamente anche se sta sporcando
aree contigue in memoria.
In definitiva C++ come Java ha 2 tipi di variabili:variabili che si
comportano come contenitori e variabili che si comportano come
puntatori.La differenza e' che in C++ la cosa e' possibile
sia per i tipi primitivi che per le classi. Il primo tipo di variabile
viene allocato da una zona di memoria chiamata stack e la gestione
della memoria e' fatta automaticamente. Per il secondo tipo di variabili
invece (se si usa l'operatore new), l'allocazione viene fatta
dal cosiddetto heap ed allora deve essere lo stesso programmatore
a liberare la memoria (con delete) quando i dati o gli oggetti non
servono piu'. Uno degli errori piu' comuni in C++ e' quello del memory leak cioe' scordarsi di cancellare dati non piu' necessari con conseguente
ingombro sempre maggiore di memoria.
I dati e gli oggetti allocati con new(quelli dell'heap) non sono automaticamente disallocati quando non esiste piu' nessun puntatore ad essi!Sta a voi cancellare questi dati e questi oggetti con delete
! E questo va fatto alla fine della funzione dove il dato e' allocato
o nel distruttore dell'oggetto che contiene questi dati diventati garbage(immondizia).