Il C++ fu ideato dal danese Bjarne Stroustrup presso i laboratori della
AT&T nel 1979.
In quell’epoca era molto sentita l'esigenza di un linguaggio con possibilità
di astrazione dai dati primitivi, che consentisse di definire nuovi
tipi di dati in modo semplice e che fosse anche adatto ad affrontare con
facilità problemi di simulazione.
Stroustrup anziché sviluppare un linguaggio del tutto nuovo
decise di utilizzare il C come linguaggio base, per non perdere i
vantaggi offerti sia in termini di efficienza e portabilità, sia
di compatibilità con i programmi C esistenti, e di estenderne le
funzioni con arricchimenti sintattici.
Caratteristiche:
| Linguaggio ibrido ovvero Orientato agli Oggetti ma anche alla programmazione tradizionale |
| Linguaggio Portabile |
| Consente la gestione di bit, byte, indirizzi di memoria e di interagire con le risorse hardware della macchina |
| Sintassi semplice, utilizza poche parole riservate |
| Linguaggio strutturato |
Secondo un approccio tecnico, seguito dalla maggior parte dei testi sui linguaggi di programmazione potremmo definire la struttura di un programma C++ utilizzando la notazione BNF come segue:
<programma> ::=<dichiarazioni globali>
<funzione> {<funzione>}
Una funzione consiste di 4 parti:
{ <sequenza_istruzioni>}
Andando avanti nelle definizioni, seguendo un approccio più
discorsivo potremmo dire che in C++ esistono solo funzioni, una di
queste deve essere sempre presente e chiamarsi main.
Il main è una funzione indispensabile il cui nome non può
essere cambiato.
Ma vediamo subito un programma che scrive "Ciao Ciao!" sullo schermo:
#include <stdio.h>
/* Include la libreria stdio.h che contiene funzioni necessarie per le
operazioni di I/O */
main()
/* Definiamo la funzione main, che non riceve nessun valore come argomento.
Il programma inizierà l'esecuzione a partire da questa funzione,
che deve essere presente in ogni programma */
{
/* Le istruzioni della funzione sono racchiuse tra le {,} */
printf("Ciao Ciao!\n");
/* Chiamiamo la funzione di libreria
* printf che si occupa di stampare.
* \n indica il NewLine, ossia serve per andare a capo.
* si deve mettere un punto e virgola alla fine di ogni istruzione. */
}
/* chiudiamo la funzione principale main() */
In questo primo programma si notano già delle cose fondamentali:
#include <stdio.h>
main()
{
printf("Ciao
Ciao!\n");
}
dovremmo mettere (void) come parametro del main al posto di (), infatti void significa "vuoto". Inoltre, poiché main è una funzione dovrebbe restituire un valore, pertanto dovrebbe esserci un return , ma se il return è assente, il compilatore restituisce 0 quindi dovrei specificare int prima di main.
#include <stdio.h>
int main(void)
{
printf("Ciao Ciao!\n");
return(0);
}
Caratteri speciali
I seguenti caratteri speciali (detti anche letterali o costanti senza identificatore ) sono utilizzati per le operazioni di stampa:
\b backspace (muove il cursore indietro di
una posizione)
\f form feed (muove il cursore in avanti
di una pagina logica)
\n nuovalinea (va a capo)
\r ritorno carrello (ordina
al cursore di posizionarsi all'inizio della riga)
\t tabulazioni orrizontali
\" virgolette(individuazione del carattere
")
\' apice (individuazione
del carattere ')
Esistono altri tipi di variabile che vedremo dopo, assieme ad altre classificazioni che dividono le variabili in globali, locali ecc.
Per dichiarare una variabile basta scrivere il tipo seguito dal nome che decidiamo di associare alla variabile stessa, ad esempio:
int c1;
In questo caso abbiamo dichiarato
una variabile di tipo intero e di nome c1.
Si noti che abbiamo terminato la
dichiarazione con un ";".
Il nome da dare alla variabile
si chiama identificatore può essere scelto a piacere, rispettando
alcune limitazioni.
Da notare che il C++ è
case-sensitive ovvero distingue tra maiuscole e minuscole, per cui
c1 è diverso da C1.
Le parole chiave come printf()
DEVONO essere scritte in minuscolo, e solitamente anche le variabili sono
scritte con caratteri minuscoli, nonostante si possano usare anche caratteri
maiuscoli.
La regola quindi sarebbe di scrivere
le variabili a lettere minuscole, e se si vuole si può usare il
carattere "_" come ad esempio:
int c1_prova;
Detto questo, vediamo come
assegnare un valore ad una variabile:
c1 = 1000;
Abbiamo introdotto l'operatore
di assegnamento "=", che in questo caso assegna
a c1 il valore 1000.
Si noti che:
c1 = 500+500;
c1 = (250+250)+500;
sono istruzioni equivalenti, infatti
si può assegnare anche un'espressione, (questa sarà calcolata
in fase di precompilazione).
Per stampare il valore di una variabile sul video con la funzione printf() occorre aggiungere %d nel punto che ci interessa, e mettere il nome della variabile dopo la chiusura delle " ", in questo modo:
printf("Il valore di c1 e’ %d.",c1);
Al momento della stampa il %d sarà sostituito
dal valore della variabile c1. Da notare la virgola che separa i doppi
apici "" dalla variabile.
Esempio
#include
<stdio.h>
/* Includiamo la libreria standard */
int
c1;
/* Dichiaro c1, una variabile di tipo intero */
main()
/* Funzione principale, eseguita per prima */
{
/* Inizio della funzione main() */
c1
= 1000;
/* Assegno a c1 il valore 1000 */
printf("Il
valore di C1 e’ %d.\n",c1);
c1
= 1500;
/* Assegno a c1 il valore 1500 */
printf("Il
valore di C1 e’ %d.\n",c1);
}
/* Fine della funzione main() */
Come risultato si ottiene:
Il valore di C1 e' 1000.
Il valore di C1 e' 1500.
Si noti che abbiamo usato %d per indicare che la
variabile in questione è di tipo intero. Per stampare il valore
di una variabile di tipo float, dovremmo mettere %f. Vedremo in seguito
altre opzioni di stampa.
Si noti che il C++ è un linguaggio case-sensitive, pertanto
se scrivessimo Printf il compilatore darebbe un errore in quanto non troverebbe
la funzione nella libreria stdio.h.
Per dichiarare due variabili dello stesso tipo conviene
scrivere:
int c1, c2;
anziché dichiarare singolarmente.
Per stampare più di una variabile numerica occorre mettere un %d o %f nel punto del testo che ci interessa, e mettere poi il nome della variabile dopo la stringa.
Esempio:
printf("C1
= %d , C2 = %d\n", c1, c2);
Ossia si mettono i %d o %f dove interessa, e poi
la lista delle variabili che li sostituiranno nello stesso ordine, separate
da virgole.
| tipi base | char | int | float | double | void |
| modificatori | signed | unsigned | long | short |
il cui effetto serve a ridurre o aumentare la memoria
a disposizione con conseguente diversa possibilità di rappresentazione.
I modificatori hanno effetto solo sui char e int.
| char | 8 | da -128 a 127 |
| unsigned char | 8 | da 0 a 255 |
| signed char | 8 | da -128 a 127 |
| int | 16 | -32.768 a 32.767 |
| unsigned int | 16 | da 0 a 65.535 |
| signed int | 16 | -32.768 a 32.767 |
| short int | 16 | -32.767 a 32.767 |
| unsigned short int | 16 | da 0 a 65.535 |
| signed short int | 16 | -32.768 a 32.767 |
| long int | 32 | -2.147.483.648 a 2.147.483.647 |
| unsigned long int | 32 | da 0 a 4.294.967.295 |
| signed long int | 32 | -2.147.483.648 a 2.147.483.647 |
| float | 32 | 1,2*10-38..3,4*1038 pr.7 cifre |
| double | 64 | 1.3*10-308.. 0.7*10308 pr.15 cifre |
| long double | 80 | 3.4*10-4932 a 1.1*104932 pr.19 cifre |
Come si vede i tipi interi (char, int, short, long) possono essere signed e unsigned, in questo caso sono solo positivi, pertanto contengono il doppio dei valori, in quanto si evita di rappresentare quelli negativi.
I tipi in virgola mobile, ossia float, double e long double, sono comunque signed.
Se si va fuori del range di definizione di una variabile, ad esempio se si aggiunge 100 ad una variabile int che vale già 32700, il risultato è -32736!
Questo a causa dell'aritmetica in complemento a 2, che per semplificare
fa "ricominciare" dal numero più basso quando si supera quello più
alto... dato che non è segnalato alcun errore e il risultato erroneo
può essere usato, ATTENTI A NON FAR ECCEDERE MAI I TIPI, piuttosto
definite dei long, se sospettate che un int non basti.
Poiché l'occupazione in byte del tipo di dati dipende
dal particolare sistema il C++ dispone dell'operatore sizeof.
Restituisce in output la dimensione in byte del tipo di
dato passato come parametro.
Es: sizeof(int) produce in output 2.
Costanti intere
Una costante intera è un numero decimale (base
10), ottale (base 8) o esadecimale (base 16) che rappresenta un valore
intero positivo o negativo.
Es. a
= 0100; (in a è memorizzato il numero
64)
Costanti floating-point
Una costante floating-point è un numero decimale (base 10), che rappresenta un valore reale positivo o negativo. Può essere specificato in 2 modi:
In qualunque notazione, se il numero è scritto
senza suffissi, è assunto di tipo double. Per forzare il tipo float
bisogna apporre il suffisso f (o F)
Es. 10.3 è di tipo double
1.4e-5f è di tipo float.
Costanti carattere
Una costante carattere è rappresentata inserendo fra singoli apici un carattere stampabile oppure una sequenza di escape.
Esempi:
‘A’
carattere A
‘\n’
carattere newline
‘\003’ carattere cuoricino
In memoria un carattere occupa un byte ed è rappresentato da un numero intero di 1 byte (il suo codice ASCII).
Le conversioni fra tipo char e tipo int sono automatiche
(purché il valore intero da convertire sia compreso nel range del
tipo char) e quindi i due tipi possono essere mescolati insieme nelle espressioni
aritmetiche. Per esempio l’operazione:
MiaVar = ‘A’ + 1;
è ammessa, se la variabile MiaVar è stata
dichiarata int oppure char.
Il carattere NULL ha codice ASCII 0 e si rappresenta con
‘\0’ (da non confondere con il carattere 0 decimale che ha codice ASCII
48).
Costanti stringa
Una costante stringa è rappresentata inserendo un insieme di caratteri (fra cui anche sequenze di escape) fra doppi apici (virgolette).
Es. “Ciao \n”
In C++ non esistono le stringhe come tipo intrinseco.
Infatti, come si vedrà, esse sono definite come sequenze (array)
di caratteri, con una differenza rispetto ai normali array: il compilatore,
nel creare una costante stringa, aggiunge automaticamente un NULL dopo
l’ultimo carattere, di conseguenza ‘A’ e
“A” sono due costanti diverse infatti:
‘A’ è un carattere e occupa 1 byte
(con il numero 65)
“A” è una stringa e occupa 2 byte ( con i numeri
65 e 0)
Gli identificatori sono nomi tramite i quali e' possibile fare riferimento a varibili, funzioni, etichette ed altri oggetti definiti dall'utente.
Un identificatore è costituito da uno o più
caratteri:
| asm | double | new | switch |
| auto | else | operator | template |
| break | enum | private | this |
| case | extern | protected | throw |
| catch | float | public | try |
| char | for | register | typdef |
| class | friend | return | union |
| const | goto | short | unsigned |
| continue | if | void | virtual |
| default | inline | sizeof | void |
| delete | int | static | volatile |
| do | long | struct | while |
Esempio: int n (esatto) intn (errato)
char car = 'a';
int i = 7;
float q=4.2;
float x=14e-3F ; Un numero reale può essere rappresentato anche in notazione esponenziale , e indica 10 elevato a esponente, quindi in questo caso equivale a 14*10-3
double r= 123.742;
long double int z = 123.742L
int k=0x80; Il
suffisso 0x indica che il valore in input è in esadecimale
Ricordando che %d si usa per stampare una variabile int, mentre %f si usa per stampare una variabile float, facciamo un esempio pratico:
#include <stdio.h> /* Includiamo la libreria standard */
int c1, c2;
/* Dichiaro 2 variabili di tipo intero */
float a, b;
/* Dichiaro 2 variabili di tipo float */
main()
/* Funzione principale, eseguita per prima */
{
/* Inizio della funzione main() */
c1 = 1000;
/* Assegno a c1 il valore 1000 */
c2 = c1 + 500;
/* Assegno a c2 il valore di c1 + 500 */
a = 21.06;
/* Assegno ad a il valore 21,06 */
b = 3.1415;
/* Assegno a b il valore 3.1415 */
/* Stampo il valore di 2 variabili di tipo int con un solo printf() */
printf("C1 = %d , C2 = %d\n", c1, c2);
/* Stampo il valore di 2 variabili di tipo float con un solo printf() */
printf("A = %f , B = %f\n", a, b);
/* Stampo il valore di tutte le 4 variabili con un solo printf() */
printf("C1=%d,C2=%d,A=%f,B=%f\n",c1,c2,a,b);
}
/* Fine della funzione main() */
Si che in C++ le assegnazioni producono come risultato (oltre alla assegnamento
vero e proprio) il valore che si vuole asegnare, pertanto è
possibile effettuare assegnazioni multiple purche' le variabili siano dello
stesso tipo.
Ad esempio:
int somma;
main()
{
int a,b,c=3; /* equivalente a c=3; b=c; a=c*/
a=b=c;
}
- sottrazione e meno unario
+ addizione
* moltiplicazione
/ divisione
% (modulo) resto della divisione intera (non
puo' essere usato sui tipi float e double )
L'operatore "%" (modulo) può essere utilizzato solamente con le variabili di tipo integer;
L'operatore "/" e' utilizzato sia per la divisione tra interi che per i reali.
A proposito della divisione si osservi che z=3/2 assegnerà
a z il valore 1, anche se e' stato dichiarato come float
in quanto di regola, se entrambi gli argomenti della divisione sono
interi, allora verrà effettuata una divisione intera;
per avere il risultato corretto sarà necessario scrivere:
z = 3.0/2
oppure
z = 3/2.0
o, ancora meglio, z = 3.0/2.0
Esiste una notazione abbreviata per assegnare valori ad una variabile
in espressioni del tipo
quindi ad esempio:
c2 *= c1;
-> c2 = c2 * c1;
c2 /= c1;
-> c2 = c2 / c1;
c2 %= c1; ->
c2 = c2 % c1;
c2 += c1;
-> c2 = c2 + c1;
c2 -= c1;
-> c2 = c2 - c1;
Quando cioè ad una variabile si assegna il valore della stessa variabile +,-,*,/,% qualche altra variabile, o costante,o espressione, anziché riscrivere il suo nome si può abbreviare in questo modo.
Nota: l'espressione x*=y+3 corrisponde a x=x*(y+3) e non a x=x*y+3.
++ incremento
-- decremento
Come già accennato, le assegnazioni in C++ vengono effettuate
utilizzando "=".
Ma oltre agli operatori arimetici standard +,-,*,/ e all'operatore
% (modulo) per gli interi, in C++ si hanno anche gli operatori incremento
++ e decremento -- (il cui effetto produce un incremeto o decremento
di 1 sulla variabile a cui si riferiscono) che possono essere preposti
o posposti alla variabile.
Se sono preposti (es: ++z) l'incremento viene effettuato
prima che sia valutata l'intera espessione , mentre se sono
posposti il prima viene calcolato l'intera espressione e dopo viene effettuato
l'incremento.
Ad esempio:
int x,z=2;
1)
x=(++z)-1;
A questo punto x=2 e z=3
int x,z=2;
2)
x=(z++)-1;
A questo punto x=1 e z=3
E' importante sottolineare che un'istruzione del tipo
x++ e' piu' veloce della corrispondente x=x+1
- (unario)
* / %
+ -
Le parentesi tonde si usano per costituire espressioni, come ad esempio:
c2 = (a-30+c1*(c++)/-(c));
c2 = (a-30+c1*(c2+b))/(c1*5);
ove si intende imporre un diverso ordine di priorità agli operatori.
Le parentesi quadre sono usate per l'indicizzazione degli array
e le parentesi graffe la definizione di inizio e fine di una funzione.
Le espressioni vengono valutate in base alla priorità degli operatori.
A parità di priorità vengono svolte da sinistra verso
destra.
E’ importante che le variabili e costanti che compaiono nell’espressione e la variabile cui viene assegnato il risultato siano tutte dello stesso tipo.
In caso negativo il compilatore provvede ad effettuare una conversione
di tipo automatica.
Per maggior chiarezza si consiglia di esplicitare la conversione di
tipo tramite l’operatore apposito cast.
Es. l’operatore % richiede che entrambi gli operandi siano interi.
I quattro operatori matematici si applicano a qualsiasi variabile di tipo base, ma i tipi dei due operandi devono essere uguali. Tuttavia, nel caso di due tipi diversi, il compilatore esegue una conversione di tipo implicita su uno dei due operandi, adeguando il tipo più semplice a quello più complesso, secondo la seguente gerarchia (in ordine crescente di complessità):
char - short - unsigned short - long - unsigned long - float - double
Es. nell’operazione 3.4/2 il secondo operando è trasformato in 2.0 e il risultato è correttamente 1.7
Nelle assegnazioni, il tipo dell’operando di destra viene sempre trasformato implicitamente nel tipo dell’operando di sinistra (con un messaggio warning se la conversione potrebbe implicare perdita di dati (loss of data ), trasformando un tipo più complesso in un tipo più semplice).
Es. date le variabili char c e double d, l’istruzione c = d è ammessa, ma genera un messaggio warning in fase di compilazione.
Nelle operazioni fra tipi interi, se il valore ottenuto esce dal range
(overflow), l’errore non viene segnalato.
Accade la stessa cosa se l’overflow si verifica a seguito di una conversione
di tipo.
Es. short n = 32767;
n++;
(l’errore non viene segnalato, ma in n si ritrova il numero -32768)
Quando si vuole ottenere una conversione di tipo che non verrebbe eseguita
implicitamente, bisogna usare l’operatore unario di casting (o conversione
esplicita), che consiste nell’indicazione del nuovo tipo fra parentesi
davanti al nome della variabile da trasformare.
Es. se la variabile n é di tipo int, l’espressione (float)n
trasforma il contenuto di n da int in float.
In C++ si può usare anche il formato funzione:
float(n) é equivalente a (float)n
Tutti i tipi base del C++ consentono il casting (con warning di possibile
loss of data se l’operazione trasforma un tipo più complesso in
uno più semplice), fermo restando il fatto che, se la variabile
da trasformare è operando di una certa operazione, il tipo risultante
deve essere fra quelli ammissibili (altrimenti viene generato un
errore in compilazione).
Per esempio: float(n) % 3 é errato in quanto l’operatore
% ammette solo operandi interi.
Vediamo ora un esempio in cui si evidenzia la necessità del casting:
int m=10, n=4;
float r, a=2.7F;
r = m/n+a;
nell’ultima istruzione la divisione è fra due numeri interi
e quindi, essendo i due operandi dello stesso tipo, la conversione implicita
non viene eseguita e il risultato della divisione è il numero intero
2; solo successivamente questo numero viene convertito in modo implicito
in 2.0 per essere sommato ad a.
Se vogliamo che la conversione a float avvenga prima della divisione,
e che questa fornisca il risultato esatto (cioè 2.5), dobbiamo convertire
esplicitamente almeno uno dei due operandi e quindi riscrivere così
la terza istruzione:
r = (float)m/n+a; (non servono altre parentesi perchè
il casting ha la precedenza sulla divisione)
Per leggere i dati dalla tastiera e memorizzarli nelle variabili si può utilizzare la funzione scanf() ,il suo formato è simile al printf():
scanf("stringa di controllo", &variabile);
Se vogliamo leggere un numero nella stringa di controllo si deve mettere un %d se si tratta di intero e %f se si tratta di vuole un numero reale mentre %c se vogliamo leggere un carattere.
Oltre allo specificatore di formato %d,%f ecc., non si deve però mettere altro, attenzione!
Altri caratteri sarebbero interpretati come "caratteri da scartare" in lettura.
Prima di ogni operazione di lettura da input conviene sempre stampare un messaggio:
printf("Immetti
un numero\n");
(stampiamo il messaggio)
scanf("%d",&c1);
(leggiamo il numero, e lo salviamo)
Si noti che, a differenza della printf, il nome della variabile deve
essere preceduto dal carattere "&".
& permette di riferirci all'indirizzo della variabile,
il motivo verrà spiegato nel paragrafo dei "puntatori".
float a,b,c;
/* Definisco 3 variabili di tipo float */
main()
{
printf("\nDammi
il primo numero: ");
scanf("%f",
&a);
printf("\nDammi
il secondo numero: ");
scanf("%f",
&b);
c = a+b;
printf("\%f + %f = %f\n",a,b,c);
}
Si noti che è possibile limitare il numero delle cifre
da stampare modificando un po' %f ad esempio:
%6.4f stampa un numero con 6 cifre totali di cui 4 dopo
il punto.
%.4f lunghezza totale non fissata ma 4 cifre dopo il punto.
%2.0f lunghezza totale di 2 cifre e 0 cifre dopo la virgola.
#include
<stdio.h>
int
a,b,c;
main()
{
printf("\nDammi
2 numeri: ");
scanf("%d%d",&a,&b);
c
= a+b;
printf("\n%d
+ %d = %d\n",a,b,c);
}
USO DELLE DIRETTIVE
Un programma C++ prima della compilazione viene
elaborato da un preprocessore che si occupa di eseguire le
direttive.
Le direttive più importanti sono: #include (per includere file) e #define (per definire costanti o macro)
Abbiamo già visto che #include <stdio.h>
serve per includere nel programma dei file (in questo caso utili
per eseguire le operazioni di I/O).
#include <file>
oppure
#include "file"
La direttiva #define invece serve a definire costanti (o macroistruzioni che vedremo successivamente).
Quando il preprocessore incontra la seguente direttiva:
#define <identificatore> <valore>
dove, <identificatore> é una parola costruita secondo le stesse convenzioni dei nomi delle variabili, e <valore> é un’espressione qualsiasi, delimitata a sinistra e destra da blank (o caratteri di tabulazione o controllo) sostituisce <identificatore> con <valore> in tutto il file (da quel punto in poi).
Es. #define GIORNI 365
da questo punto in poi, ogni volta che il programma deve usare il numero 365, si può utilizzare in sua vece l’identificatore GIORNI
In generale la direttiva #define serve per assegnare un nome o identificatore a una costante predefinita.
In pratica la direttiva #define produce gli stessi risultati dello specificatore di tipo const; al posto della direttiva dell’esempio precedente si sarebbe potuto scrivere la dichiarazione:
const
int GIORNI= 365 ;
Mentre con l’uso di const:
Operazioni di sostituzione di questo tipo sono utili sia
per rendere più leggibili i programmi, (sostituendo i numeri con
parole che si riferiscono al significato di tale numero) sia per renderli
parametrici.
Infatti, se dovessimo modificare un valore costante,
dovremmo ricercarlo e cambiarlo in tutti i punti del programma in cui compare,
mentre se lo definiamo come costante o con #define, basterà
cambiare il suo valore una sola volta nella definizione per cambiarne automaticamente
il valore in tutto il programma.
Si noti che, come suggerisce lo standard, conviene che per gli identificatori delle define siano usati caratteri MAIUSCOLI, (ciò contribuisce a distinguere variabili da costanti).
Vediamo altri esempi:
#define NUM_PAGINE
400
#define NOME_AUTORE
Dante
#define TITOLO
Divina_Commedia
Quando il preprocessore trova nel programma:
NUM_PAGINE
NOME_AUTORE
TITOLO
sostituirà prima di iniziare la compilazione gli
identificatori con le costanti:
400
Dante
Divina_Commedia
Programma che calcola l'area e la circonferenza di un cerchio dato il raggio
Come è noto le operazioni da fare sono:
Area =PG*raggio*raggio
Perimetro = 2*PG*raggio
Dato che PG è un numero reale (3,141592... ecc.) costante possiamo usare il #define per associare 3.14159265 all'identificatore più comodo "PG".
Si ricordi, che PG non è una variabile,
ma un identificatore di costante che sarà sostituito fisicamente,
dopo la precompilazione, con 3.14159265.
#include <stdio.h>
/* Includiamo la libreria standard */
#define PG 3.14159265
/* Scrivendo PI intendiamo 3.14159265 */
float raggio;
/* Definisco una variabile di tipo float */
main()
/* Funzione principale, eseguita per prima */
{
printf("\nRaggio
del cerchio? ");
scanf("%f",
&raggio);
printf("\nArea:
%f", PG*raggio*raggio);
printf("\nPerimetro:
%f\n", 2*PG*raggio);
}
Come si può osservare in questo programma abbiamo definito solo
una variabile: raggio, in quanto per risolvere il problema non era necessario
memorizzare area e perimetro.
In questo esempio abbiamo potuto verificare come tramite la printf
si può stampare anche il risultato di espressioni, e
non solo semplici variabili .
| Iterazione | for | while | do...while | ||
| Selezione | if | if else | if else if | ? | switch |
| Salto | return | break | continue | goto | exit |
iterazione |
for |
while |
while do |
Istruzione iterativa for
Ora vedremo come eseguire un ciclo, ossia come ripetere l'esecuzione
di una istruzione per un numero determinato di volte.
Per prima utilizzaremo l'istruzione for, che ha questa forma:
for (inizializzazione;condizione;incremento)
<istruzione del ciclo>;

Inizialmente diamo a x il valore 1, poi prima di ogni ciclo effettuiamo
il test ovvero controlliamo se x<= 100, in caso positivo eseguiamo il
printf, incrementiamo x di 1 e torniamo al test, altrimenti se non è
soddisfatto non entriamo nel ciclo e passiamo all'istruzione successiva
alla for.

#include "stdio.h"
void main(void)
{int x;
for(x=100; x>=0;
x--)
printf("%d",x);
}
x-- equivale a x=x-1
#include
"stdio.h"
void
main(void)
{int
x;
for(x=1;
x<=10; x+=5)
{
printf("%d",x);
printf("\nIl valore di x e’ %d.\n",x);
}
}
x+=5 equivale a x=x+5
Output:
1
Il valore di x e' 1.
6
Il valore di x e' 6.
#include "stdio.h"
void main(void)
{int x;
int y;
for(x=1, y=1;
x+y<=100; x++, y+=6)
printf("%d\n",x+y);
}
Output:
2
9
16
23
30
37
44
51
58
65
72
79
86
93
100
for (;;) printf("questo loop non finisce mai")

#include <stdio.h>
main()
{
const int MIN_VAL = 2;
const int MAX_VAL = 100;
const int INCR_VAL = 2;
double x;
//uso la variabile i internamente
al blocco della istruzione for
//con la particolare gestione dell’indice
posso calcolare le potenze negative di 2
for (int i = MIN_VAL; i <=
MAX_VAL; i *= INCR_VAL)
{
x = 1/(double)i;
printf("1/
%d = %f \n”, i , x);
}
}
output:
1/ 2 = 0.500000
1/ 4 = 0.250000
1/ 8 = 0.125000
1/ 16 = 0.062500
1/ 32 = 0.031250
1/ 64 = 0.015625
#include <stdio.h>
main()
{
const int MIN_VAL = 2;
const int MAX_VAL = 100;
const int INCR_VAL = 2;
double x;
for (int i = MIN_VAL;
i <= MAX_VAL; i *= INCR_VAL)
{
int y=3;
x = 1/(double)i;
printf("1/ %d =
%f, %d \n”, i , x, y);
}
}
Osservazioni
== uguale
!= diverso
Ora vedremo come eseguire un ciclo, ossia come ripetere l'esecuzione
di una istruzione o più istruzioni per un numero indeterminato
di volte.
Per questo scopo utilizzaremo l'istruzione while (quando), che ha questa
forma:
while (condizione) <istruzione del ciclo>;
{
int c1;
printf("Inserire
il valore di C1>10 \n");
scanf (“%d”,&c1);
while (c1<=10)
{
printf("Valore di C1 non valido\n");
printf("Inserire il valore di C1>10 \n");
scanf (“%d”,&c1);
}
printf("Il valore di C1 e' %d.\n",c1);
}
Analogamente alla for una while
con condizione vuota (sempre vera) corrisponde a un loop.
Istruzione iterativa do ... while
Ora vedremo come eseguire un ciclo, ossia come ripetere l'esecuzione
di una o più istruzioni per un numero indeterminato di volte
eseguendo prima le istruzioni del ciclo e poi il test di uscita.
Per questo scopo utilizzaremo l'istruzione do ... while
(quando), che ha questa forma:
do <istruzione del ciclo>;
while (condizione);

#include <stdio.h>
main()
{
int c1;
do
{
printf("Inserire il valore di C1>10 \n");
scanf (“%d”,&c1);
}
while (c1<=10);
}
Programma che calcola il fattoriale di n>0
#include <stdio.h>
main()
{
int n,i,f;
do
{
printf("Inserire il valore di n>0 \n");
scanf (“%d”,&n);
}
while (n<=0);
i=n;
f=1;
do
{
f*=i; /* f=f*i
*/
i-=1; /* i=i-1
*/
}
while (i>1);
printf("fattoriale
di %d = %d \n",n,f);
}
Avendo definito le variabili di tipi int potrà verificarsi che per valori grandi di n si ottengono valori negativi per il fattoriale, a causa dell'overflow che non viene segnalato!
Analogamente alla for una do ..
while con condizione vuota (sempre vera) corrisponde a un loop.
Selezione |
if |
if else |
if else if |
? | switch |
Selezione if
if ( <condizione>) <istruzione>;
"if" in inglese significa "se", quindi una possibile traduzione
è "se la condizione è vera, esegui l'istruzione (o
il blocco di istruzioni), altrimenti no.".

Si noti che valutare una condizione significa calcolare un valore che può essere vero o falso, in C++ alla condizione falso viene associato il valore 0 mentre a vero viene associato diverso da 0 (=1).
Quindi un if(0) non farebbe mai eseguire l'istruzione, mentre un if(1)
la farebbe eseguire sempre.
Esempio:
#include <stdio.h>
main()
{
int
a;
/* Definiamo una variabile intera a che servirà
per il costrutto if */
printf("\nDammi un intero>10: ");
scanf("%d",&a);
if (a>10) printf("\na è maggiore di 10\n");
}
Il costrutto "if " in questo caso ha un ramo opzionale, chiamato "else"(altrimenti),
la traduzione potrebbe essere: "se la condizione è vera, esegui
istruzione1, altrimenti esegui istruzione2". Quindi l'esecuzione di un'istruzione
esclude l'altra.

printf("\nDammi un intero : ");
scanf("%d",&a);
if (a>10) printf("\n a è maggiore di 10\n");
else printf("\na è minore o uguale di 10\n");
}
Naturalmente è possibile eseguire anziché una istruzione
un blocco di istruzioni.
if ( <condizione1>) <istruzione1>;
else if ( <condizione2>) <istruzione2>; else <istruzione3>;

if (a>10)
{
if (a= =20)
printf("\na
è vale 20\n");
}
else printf ("\na non mi interessa\n");
Osservazione: Attenzione a non scrivere if (a = 20), in
quanto tenendo conto che:
ogni espressione logica vera restituisce il
numero intero 1
ogni espressione logica falsa restituisce
il numero intero 0
in tal caso anche a fronte di un input diverso da 20 (ma >10) verrebbe
assegnato ad a il valore 20, e poiché in C++ ogni assegnazione produce
come output il valore da assegnare alla variabile (in questo caso 20) tale
valore sarebbe utilizzato per valutare l' espressione logica che risulterebbe
vera in quanto produce un valore diverso da 0, pertanto di conseguenza
sarebbe eseguita la printf!
Se l’istruzione controllata da un if consiste a sua volta in un altro
if (sono possibili più istruzioni if “annidate”), ogni
eventuale else si riferisce sempre all’if immediatamente superiore (in
assenza di parentesi graffe).
Per essere sicuri di ottenere quello che si vuole, mettere sempre le
parentesi graffe, anche se sono ridondanti.
Operatore "?"
L' operatore condizionale ? (ternary
condition) e' la forma piu' efficiente per esprimere semplici if,
ha la seguente forma:
<variabile>
= <condizione> ? <risultato1>
: <risultato2>;
che equivale a:
if ( <condizione>)
<variabile>
=<istruzione1>
else <variabile> =<istruzione2>
;
Ad esempio:
z=(a>b) ? a : b
equivale a:
if (a>b)
z=a;
else
z=b;
ovvero assegna a z il massimo tra a
e b.
La selezione switch serve ad effettuare scelte multiple.
La sua forma generale e':
switch (variabile){
case <costante1>: <sequenza di istruzioni1>;
break;
case <costante2>: <sequenza di istruzioni2>;
break;
....
case <costanten>: <sequenza di istruzionin>;
break;
default : <sequenza di istruzioni>;
break;
}

Il caso "default" e' facoltativo e raggruppa tutti i casi diversi da quelli testati con case.
In genere lo switch si usa per creare una menù di selezione e per controllare le varie scelte.
Esempio:
#include <stdio.h>
main()
{
int scelta=1;
/* Definiamo una variabile intera
scelta che servirà per il ciclo while */
while(scelta!=0)
/* Se scelta è diverso (!=) da zero, esegui */
{
printf("\n
Scegli il canto dell'inferno che ti interessa:\n\n");
printf(" 1)
Canto primo. \n");
printf(" 2)
Canto secondo. \n");
printf(" 3)
Canto terzo. \n");
printf(" 4)
Canto quarto. \n");
printf(" 5)
Canto quinto. \n");
printf(" 0)
Esci\n\n");
scanf("%d",&scelta);
/*Leggiamo da input scelta*/
switch(scelta)
/* e usiamo scelta per il confronto */
{
case 1:
printf("\nNel mezzo del cammin di nostra vita\n");
printf("Mi ritrovai per una selva oscura,\n");
printf("Che la diritta via era smarrita.\n");
break;
case 2:
printf("\nLo giorno se n'andava, e l'aer bruno\n");
printf("Toglieva gli animai, che sono in terra.\n");
break;
case 3:
printf("\nPer me si va nella città dolente,\n");
printf("Per me si va nell'eterno dolore,\n");
printf("Per me si va tra la perduta gente.\n");
break;
case 4:
printf("\nRuppemi l'alto sonno nella testa\n");
printf("Un greve tuono, si ch'io mi riscossi,\n");
printf("Come persona che per forza e' desta\n");
break;
case 5:
printf("\nCosi' discesi del cerchio primaio\n");
printf("Giu' nel secondo, che men loco cinghia,\n");
break;
case 0:
printf("\nUscita.\n");
default:
printf("\nSelezione sbagliata!\n");
}
/* Fine del costrutto switch */
}
/* Fine del loop while */
}
/* Fine della funzione main() */
Si noti che che lo switch può verificare
solo l'uguaglianza, a differenza degli if che possono verificare condizioni
qualsiasi.
Salto |
return |
continue |
goto |
break |
exit |
L'istruzione return, come vedremo meglio durante lo studio
delle funzioni, indica con il proprio argomento quale valore deve essere
restituito dalla funzione al termine della sua esecuzione.
L'istruzione goto è detta "di salto incondizionato", perché
quando viene eseguita il controllo passa immediatamente alla istruzione
relativa all'etichetta.
L'etichetta è l'identificatore di una istruzuione, pertanto
precede l'istruzione a cui è riferita e è da questa separata
tramite due punti.
E' però possibile saltare ad una etichetta solo se si trova all'interno della stessa funzione in cui si trova la goto; non sono consentiti salti interfunzione.
L'uso della goto è assolutamente sconsigliato in quanto il programma
facilmente diventa non strutturato!
La giustificazione più usuale all'uso di goto è
relativa alla possibilità di uscire immediatamente da cicli annidati
al verificarsi di una data condizione, ma anche in questi casi è
preferibile utilizzare metodi alternativi.
......
goto <etichetta >;
...
<etichetta>: <istruzione>;
Esempio
#include <stdio.h>
main()
{
int a;
printf("\nDammi un intero : ");
ciclo:
scanf("%d",&a);
if (a>10) goto stampa;
else
{
printf("\na e’ minore o uguale di 10\n");
goto ciclo;
}
stampa:
printf("\n a e’ maggiore di 10\n");
}
Le istruzioni break e continue vengono usate per la terminazione
di un ciclo o di un costrutto switch.
break - permette di uscire da un ciclo o da
uno switch
continue - fa terminare l'esecuzione di una iterazione del ciclo e
saltare nuovamente alla valutazione della condizione del ciclo.
Nel caso di cicli o switch nidificati il comando si riferisce al ciclo o switch più interno in cui sono contenuti i comandi.
esempio:

Si noti che l'effetto di break e continue è simile a quello
dell'istruzione goto pertanto se ne sconsiglia quando è possibile
l'uso.
L'istruzione exit produce la terminazione dell'intero
programma e il ritorno al sistema operativo.