GLG Programs fa uso di cookie per migliorare l'esperienza di navigazione degli utenti, ma non per tracciarne un profilo. Proseguendo nella navigazione, si accetta implicitamente l'utilizzo dei cookie.
[OK]Note legaliNon mi importa
Logo GLGPrograms Logo GLGPrograms

Basi di programmazione C++

[Icona della Guida] Introduzione alla programmazione C/C++

Appunti di programmazione C e C++ su GNU/Linux

Parte prima

Introduzione

Il Calcolatore è una macchina programmabile generica: significa che, partendo da un piccolo insieme finito di istruzioni, il computer può essere istruito per eseguire i più svariati compiti.
Iniziare a programmare un computer richiede, come minimo, due operazioni fondamentali:

Questa guida si occuperà di spiegare i fondamenti della programmazione procedurale in C e a oggetti in C++, integrando le lezioni con degli esempi concreti. In questo modo, sarà sicuramente soddisfatto il secondo punto fondamentale della programmazione, e, attraverso gli esempi, sarà data una discreta conoscenza del primo, fermo restando che l'unico modo per comprenderlo a fondo è l'esperienza.

Liberatoria

Nella vita, svolgere un compito in maniera completa, esauriente e perfetta è difficile, per non dire pressocché impossibile. I lettori vogliano perdonare l'autore di questa guida per eventuali errori, omissioni o imprecisioni; nel caso in cui vengano rilevati, per favore segnalateli tramite la pagina di contatto e, sia io che voi, saremo persone migliori. Si noti che alcuni aspetti sono stati comunque volutamente ignorati: questa guida non è stata scritta da Stroustrup per Stroustrup.

Come pensa il computer

Premesse:

Il cervello elettronico del calcolatore è il processore, il componente pensante che si occupa di eseguire le istruzioni. Un processore è in grado di eseguire solo qualche decina di istruzioni elementari in formato binario. Ecco un esempio di un programma che somma i numeri contenuti nelle celle di memoria 0x60 e 0x61 e salva il risultato in 0x62 (per ragioni di complessità, queste istruzioni sono per un Motorola 6809 e non per un comune processore x86):

10110110
00000000
01100000
10111011
00000000
01100001
10110111
00000000
01100010

Come si vede, scrivere un programma in formato binario è alquanto ostico: i primi programmatori, quindi, hanno ben pensato di non scrivere le istruzioni direttamente in formato binario, ma di utilizzare la base 16 o base esadecimale, in modo da poter rappresentare in maniera più leggibile i valori binari. Il programma precedente diventa così:

0xB6
0x00
0x60
0xBB
0x00
0x61
0xB7
0x00
0x62

Ciò tuttavia non è bastato: per semplificare maggiormente il compito, è stato inventato l'assembly, un primitivo linguaggio in cui, ad un insieme semanticamente correlato di istruzioni in linguaggio macchina, viene associata una sigla mnemonica che ricorda la sua funzione. Il precedente programma diventa:

LDA $0060     # carica il valore contenuto in 0x0060 nel registro A
ADDA $0061    # aggiunge il valore contenuto in 0x0061 al registro A
STA $0062     # salva il valore del registro A nella cella 0x0062

L'assembly, come il linguaggio macchina, è un linguaggio di basso livello, cioè che lavora direttamente a contatto con l'hardware, le parti intime del computer, e ne ricalca fedelmente il comportamento.

Poiché ogni processore possiede il suo set o insieme di istruzioni, diverso da quello di ogni altro processore, per poter funzionare su computer diversi, ogni programma dovrebbe essere scritto più volte. Inoltre, utilizzando un linguaggio di basso livello, molte operazioni apparentemente immediate, devono essere scomposte in molti sottoprogrammi (un esempio banale è il ciclo for, che consente di ripetere un'operazione per un determinato numero di volte, e che in assembly richiede un'attenta pianificazione delle condizioni e dei salti).

Per ovviare a questo problema, furono quindi inventati i linguaggi di alto livello, che permettono di astrarre l'hardware e le strutture logiche, e di creare programmi che, in seguito ad una traduzione in linguaggio macchina, possono essere utilizzati su molte diverse architetture.

È importante notare che un programma in linguaggio di alto livello, per essere eseguito dalla macchina, deve essere comunque tradotto in linguaggio macchina, cioè in quei famosi codici binari con 0 e 1 di cui parlavamo all'inizio: per svolgere questo compito, esistono i compilatori, programmi atti a questo scopo.

Si osservi quindi com'è facile sommare due numeri utilizzando un linguaggio ad alto livello, lasciando al compilatore il compito di scrivere il codice macchina, di trovare le celle di memoria per contenere i dati, eccetera...

c = a + b;

La serie di istruzioni di alto livello, facilmente leggibili da un essere umano, costituisce il codice sorgente del programma, mentre la sua versione binaria, in linguaggio macchina, costituisce l'eseguibile vero e proprio.

Compilazione

Abbiamo visto i numerosi vantaggi della programmazione di alto livello, e sappiamo che il programma, per poter essere eseguito dal computer, deve essere tradotto nel corrispondente linguaggio macchina.

Entrambi i tipi di linguaggi hanno vantaggi e svantaggi: i programmi scritti con linguaggi compilati sono più veloci dei loro cugini interpretati, ma devono essere compilati ogni volta che il codice sorgente viene cambiato. Così, mentre l'esecuzione dei primi è più performante, la modifica dei secondi è più immediata. Inoltre, mentre un programma interpretato può essere eseguito facilmente su qualunque tipo di computer o di sistema operativo, a patto che vi sia un interprete, quello compilato deve essere compilato per ogni piattaforma dove si desidera eseguirlo. Infine, mentre un programma interpretato può essere facilmente letto da chiunque lo desideri, utilizzando un linguaggio compilato non si è obbligati a fornire il codice sorgente del programma, rendendo così possibile la sua esecuzione, ma impedendone di fatto il miglioramento, la ricerca degli errori e il controllo.

La mia prima compilazione

Ogni compilatore e ogni ambiente di sviluppo (insieme di strumenti atti a semplificare la scrittura e la produzione di programmi) possiede una procedura per compilare i programmi nella maniera che, chi l'ha prodotto, ritiene sia più efficiente.

Per coloro che sono alle prime armi, consigliamo di installare l'ambiente di sviluppo Code::Blocks, disponibile su GNU/Linux, Microsoft Windows e Apple Mac OS X, facendo attenzione ad installare anche il compilatore GNU (gcc o MinGW, a seconda del sistema operativo).
Per chi invece fosse un po' più audace, consigliamo di utilizzare il metodo tradizionale a riga di comando, che inizialmente può essere più ostico, ma, dopotutto, non si può aspirare a programmare se ci si rifiuta di aprire una riga di comando.

Chi utilizza Code::Blocks, si preoccuperà di far riferimento alla sua documentazione; chi invece vuole seguire la retta via, potrà trovare le prime indispensabili informazioni qui di seguito.

Programma di esempio, da copiare e incollare nel proprio editor di testo preferito, ad esempio Geany, X Code, Notepad++ o l'editor di Code::Blocks. Salvare questo file in un percorso noto, con estensione .c, ad esempio /home/glgprograms/sorgenti/hello.c oppure "C:\Documents and Settings\GLG Programs\sorgenti\hello.c".

#include <stdio.h>

int main(int argc, char** argv)
{
  printf("Hello World!\n");
  return 0;
}

Questo è il nostro codice sorgente. Apriamo un terminale e rechiamoci nella directory che lo contiene (utilizzando cd). Se non si è pratici di questi passaggi, è praticamente obbligatorio prenderci confidenza leggendo i fondamenti di una qualsiasi guida sul terminale Linux/UNIX (questa non è troppo aggiornata, ma è validissima) o sul terminale di Windows.

Compiliamo:

gcc hello.c

Questo comando invoca il compilatore gcc (GNU Compiler Collection) che:

Avviamo il nostro eseguibile a.out e verifichiamo che funzioni:

./a.out

Se tutto è andato bene, verrà stampato sul terminale

Hello world!

Complimenti: la procedura è andata a buon fine e il vostro primo programma è stato compilato ed eseguito. Questa è la procedura standard che seguiamo per compilare i programmi e gli esempi di questa guida. Chiunque è comunque liberissimo di utilizzare altre procedure, magari con gli strumenti integrati nel proprio ambiente di sviluppo, ma, se qualcosa non funziona, non venite a chiedere informazioni a noi.

Concetto di funzione

Il programma minimale

Poiché il modo migliore per capire la teoria è sperimentare nella pratica, iniziamo con il più piccolo programma che può essere scritto, e analizziamolo riga per riga, in modo da avere già da subito un quadro, seppur vago, di ciò che stiamo per affrontare. Si tenga conto che gli argomenti che, per ragioni di chiarezza, è necessario accennare in questo momento, verranno tuttavia spiegati approfonditamente più avanti; se non si comprende a fondo quanto scritto in questa prima parte, ciò non dovrebbe rappresentare un problema.
Qualcuno potrebbe asserire che imparare a programmare iniziando con il concetto di funzione è fuori luogo; dimostreremo che non è così.

int main(int argc, char** argv)
{
  return 0;
}

I computer possono eseguire un piccolo insieme limitato di operazioni, che, combinate nella giusta maniera, permettono di realizzare operazioni più complesse. È molto utile poter raccogliere un insieme di istruzioni già pronte sotto un unico nome, in modo da non doverle riscrivere tutte ogni volta che abbiamo bisogno di svolgere un determinato compito. Il paragone con la ricetta di cucina è perfetto: se in una ricetta troviamo scritto che dobbiamo sbattere le uova, sappiamo già che dobbiamo prendere una scodella, aprire le uova, metterle dentro, prendere una forchetta e agitarle finché l'albume e il tuorlo si mescolano e diventano di una consistenza più viscosa. Quindi, con sbattere le uova abbiamo riassunto in poche parole una serie di operazioni.

In programmazione, una funzione è una raccolta di operazioni. Tutti i programmi devono avere almeno una funzione contenente operazioni. Si tratta della funzione principale, o funzione main. Ad ogni funzione corrisponde un blocco di istruzioni, delimitato dalle parentesi graffe { e };
Il return 0; finale indica che la nostra funzione main termina e, in particolare, ritorna zero, ma questo lo vedremo più avanti.

Per riassumere quanto detto finora, introduciamo dei commenti all'interno del nostro programma, in maniera da spiegare esattamente cosa fa. I commenti in C sono delimitati da i caratteri /* e */, e, poiché vengono completamente ignorati dal computer, è possibile scriverci ciò che preferiamo.

int main(int argc, char** argv) /* funzione principale del nostro programma */
{                               /* apro il blocco della funzione principale */
  return 0;                     /* la funzione termina */
}                               /* chiudo il blocco della funzione principale */

Se provassimo a eseguire questo programma in un terminale, non vedremmo niente: infatti, l'unica cosa che fa, è uscire dal programma stesso.

Hello World!

Quasi sempre, alcune funzioni di base vengono fornite direttamente dal sistema operativo o dall'ambiente di sviluppo in cui stiamo lavorando, in raccolte di funzioni, altrimenti dette librerie. Una di queste librerie è stdio.h, nome che sta per standard input/output, che contiene le funzioni minime per interagire con l'utente, cioè per interfacciarsi con lo schermo e con la tastiera. Ampliamo il nostro programma:

#include <stdio.h>
int main(int argc, char** argv)
{
  printf("Hello world!");
  return 0;
}

Con #include <stdio.h>, dichiariamo alla macchina che abbiamo intenzione di utilizzare delle funzioni che si trovano nella libreria stdio.h.

Con printf("Hello world!"); chiamiamo la funzione printf (contenuta in stdio.h), che esegue le istruzioni necessarie a scrivere sullo schermo ciò che noi le passiamo come argomento tra parentesi semplici ( e ), cioè Hello world!

Se eseguiamo questo programma in un terminale, verrà quindi mostrata la scritta Hello world!.

Variabili

Un'altra definizione di computer è una macchina che prende dei dati in ingresso, li elabora, e successivamente restituisce dei risultati. Le informazioni necessarie a calcolare il risultato durante l'esecuzione del programma, sono memorizzate in variabili. Ogni variabile ha un nome o identificatore, che la identifica nel programma, e un tipo, ovvero il tipo di valori che può assumere.

Il nome di una variabile può contenere lettere e underscore, ma non può contenere spazi, né numeri come primo carattere, né lettere accentate.
Esistono alcuni tipi fondamentali di variabili: ad esempio, una variabile che contiene la mia età in anni può assumere valori naturali, come 0, 1, 2, ecc..., mentre una variabile che contiene la mia temperatura corporea può assumere valori reali, come 36.0, 36.5, 37.0 ecc...

Per usare una variabile è necessario definirla, o, in maniera più comune ma meno precisa, dichiararla: questa operazione serve per poter riservare nella memoria uno spazio adeguato a contenere il dato che intendiamo memorizzare.
Vediamo alcuni esempi di definizione di variabili:

int numero2;                  /* numero intero, come 0, 2, -7 o 128923 */
float temperatura = 36.7;     /* numero reale (in realtà approssimato a razionale) */
double piGreca = 3.1415269;   /* numero reale con approssimazione minore */
bool opzione_attiva = true;   /* valore booleano (due stati, cioè vero oppure falso) */
char lettera = 'a';           /* un carattere qualsiasi */

Si noti che, in alcuni casi, è stata anche effettuata un'operazione di assegnamento, cioè è stato assegnato un valore iniziale alle variabili. Prima di leggere un dato da una variabile (vedremo tra poco come fare) è buona norma inizializzarla con un valore noto: infatti, una variabile appena definita contiene il valore precedentemente assegnato alle celle di memoria in cui si trova, valore che è praticamente impossibile prevedere a priori.

Ogni variabile occupa uno spazio ben preciso, e di conseguenza potrà assumere un intervallo di valori prefissato.
Il tipo fondamentale intero può essere modificato attraverso dei qualificatori, in maniera che il programmatore possa controllare qualitativamente quanta memoria occuperà il dato, scegliendo in base allo scopo a cui è destinata la variabile.

short numero1;                /* numero intero piccolo, come -5, 0 o 131 */
unsigned anni;                /* numero naturale positivo, come 0, 2, 41 ma non -7 */
long distanza;                /* numero intero anche molto grande, come -17179869143 o 17179869209 */

Qui di seguito è riportata una tabella di riferimento, con lo spazio occupato in memoria e gli estremi degli intervalli rappresentabili su un comune processore a 32-bit. Si noti che questa tabella è solo indicativa, in quanto i parametri dipendono da molti fattori, come l'architettura del processore o il sistema operativo.
Mentre la memoria abbonda sui comuni computer e permette di trascurare inizialmente questo aspetto, sui microcontrollori bisogna essere parsimoniosi nell'uso di variabili che occupano molta memoria, in quanto questa è estremamente ridotta.

tipomemoria occupata byte (bit)intervallo di rappresentazione
int4 (32)[-2147483648; +2147483647]
short2 (16)[-32768; +32767]
unsigned4 (32)[0; +4294967296]
float4 (32)//calcolare//
double8 (64)//calcolare//
bool1 (8){ true, false }
char1 (8)[-128; +127]

In C esiste un operatore (vedremo gli operatori nel dettaglio successivamente), chiamato sizeof, che consente di conoscere lo spazio che occupa una variabile in memoria in byte. Nel codice, si presenta esteticamente come una comune funzione.

int intero;       /* si osservi che sizeof accetta sia nomi di variabili che tipi */
sizeof(intero);   /* 4 */
sizeof(long);     /* 4 sui processori a 32-bit, 8 sui processori a 64-bit */
sizeof(short);    /* 2 */

La codifica ASCII e il char

Giunti a questo punto, è opportuno chiarire la natura del tipo char. In un computer, tutta l'informazione non è altro che una serie di numeri: perciò, per rappresentare le lettere e i simboli utilizzati comunemente nella lingua scritta, è stato necessario stabilire una convenzione per associare ogni carattere rappresentabile ad un numero.

Questa convezione di codifica è chiamata codifica ASCII, che sta per American Standard Code for Information Interchange. Essa è una codifica a 7 bit, cioè può codificare un massimo di 27 = 128 differenti caratteri. Si noti che questa codifica viene utilizzata solamente per lo scambio di dati con altre periferiche (tastiere, stampanti...) e non è utilizzata per l'elaborazione diretta dell'informazione (ad esempio, per eseguire operazioni matematiche sui numeri).

Lavorare con la tabella tabella ASCII può sembrare estremamente dispendioso, ma tutto diventa più facile dopo aver fatto alcune considerazioni:

Poiché negli elaboratori non è possibile rappresentare agevolmente valori più piccoli di 1 byte (ossia 8 bit), un char ha dimensione 1 byte, e può quindi rappresentare un totale di 256 caratteri. I 128 caratteri aggiuntivi rappresentano un insieme ASCII esteso, con lettere accentate e altri simboli, e che dipende dal locale della singola macchina (esistono code pages estese americane, italiane, nordiche, ecc...). Oggi non si deve più fare riferimento a tale standard, bensì all'UNICODE (o un suo sottoinsieme, come UTF-8), che consente di utilizzare un formato di codifica unico e comune in tutto il mondo, comprendente fino a 65536 differenti caratteri. I primi 128 sono gli stessi della codifica ASCII.

Input e Output

Giunti a questo punto, ci si domanderà come si può stampare sullo schermo il dato contenuto in una variabile, oppure come leggerlo da tastiera per poterlo elaborare. Cerchiamo di dare una risposta esauriente.

In un computer, i dati possono essere scritti su o letti da un flusso: un flusso è un'astrazione che può rappresentare lo schermo, la tastiera, un file, ma anche una stampante o un modem. I flussi possono essere di sola uscita (output), cioè i dati possono fluire solo dal nostro programma verso il flusso, di sola entrata (input), dove i dati possono solo essere letti per poterli inserire nel nostro programma, e, infine, di entrata e uscita (input/output), dove la comunicazione può avvenire in entrambi i sensi.

La maggior parte dei buoni sistemi operativi fornisce tre flussi distinti:

Si tenga presente che alcuni sistemi inoperativi basati esclusivamente su interfaccia grafica, non consentono di accedere direttamente ai flussi, e anzi, talvolta non viene nemmeno fornito lo standard error.

Output

Per scrivere dati su stdout e stderr, cioè sullo schermo, si utilizza la funzione printf(). È possibile passare a printf più argomenti, indicando quali dati si vogliono stampare e le variabili che li contengono. Ad esempio, per stampare un intero:

int a = 7;
printf("La variabile 'a' vale %d", a);

Analizziamo i due argomenti passati alla funzione:

Pertanto, per chiarire il lungo discorso teorico per il quale un esempio vale più di mille parole, mostriamo l'output del suddetto codice, che sarà:

La variabile 'a' vale 7

Allo stesso modo, è possibile stampare più variabili, anche di diverso tipo, purché queste vengano passate a printf in un ordine corrispondente a quello in cui si presentano i %.

int settimana = 7;
float pi = 3.1415;
char lettera = 'A';
printf("Una settimana ha %d giorni, Pi Greca vale %f e la prima lettera dell'alfabeto è %c.", settimana, pi, lettera);

Il cui output sarà:

Una settimana ha 7 giorni, Pi Greca vale 3.1415 e la prima lettera dell'alfabeto è A.

Qui che segue una tabella riassuntiva dei tipi printf più comuni:

EscapeTipo
%dNumero intero decimale
%fNumero in virgola mobile a precisione semplice (float)
%lfNumero in virgola mobile a doppia precisione (double)
%cCarattere char
%hNumero intero in notazione esadecimale
%oNumero intero in notazione ottale
%uNumero intero senza segno
%sStringa

È molto importante notare che a printf può essere passata una variabile di qualsiasi tipo, purché questa possa essere convertita nel corrispondente tipo printf prima di essere stampata.

double pi = 3.1415;
char lettera = 'A';
printf("%d %h", pi, lettera);    /* stampa 3 40 */

All'interno della stringa per printf, è inoltre possibile inserire altre sequenze di escape, cioè sequenze di caratteri annunciate da un carattere speciale, che non vengono stampate letteralmente ma modificano il comportamento della funzione.
Attraverso il carattere di escape \ (backslash, o barra rovesciata), è possibile stampare alcuni caratteri di controllo; ad esempio, per andare a capo, si usa \n.

printf("Questo testo si trova sulla prima riga\nmentre questo sulla seconda");
Questo testo si trova sulla prima riga
mentre questo sulla seconda

Tra i caratteri di escape più comunemente usati, possiamo trovare i seguenti:

EscapeEffetto
\nva a capo
\tsalta alla tabulazione successiva
\asuona lo speaker (su molti portatili e alcuni fissi non è più in dotazione)
\bcancella l'ultimo carattere

Input

Un programma il cui unico scopo è stampare non serve a molto. I programmi sono fatti per prendere dei dati in ingresso, risolvere un problema attraverso un algoritmo noto, e poi restituirne il risultato. È possibile leggere i dati dalla tastiera e immetterli in delle variabili per poterli elaborare tramite la funzione scanf().

scanf("format", address list...);

La funzione scanf() si comporta in maniera simile a printf():

/* Programma che legge un intero da tastiera e lo restituisce a video */
#include <stdio.h>

int main(int argc, char** argv)
{
  int a;
  printf("Inserisci numero intero: ");
  scanf("%d", &a);                    /* Lettura di un intero decimale nella variabile 'a'*/
  printf("Numero inserito: %d\n", a);
  return 0;
}

Questo semplice programma, alla linea 8 legge un numero intero decimale e lo salva nell'indirizzo di memoria della variabile a. Per specificare l'indirizzo di memoria di una variabile, è necessario preporre l'operatore & all'identificatore della variabile. Prima di proseguire, può essere utile compilare questo programma, verificarne il funzionamento e, una volta capito, estenderlo. Qui di seguito, è esposta una piccola modifica che è possibile fare.

/* Calcolatrice per somme e differenze */
#include <stdio.h>

int main(int argc, char** argv)
{
  double a, b, c;
  printf("Inserisci due numeri: "); scanf("%lf%lf", &a, &b);
  c = a + b;
  printf("A + B = %lf\n", c);
  return 0;
}

Si noti che alla linea 8 è stata utilizzata un'espressione banale per realizzare la somma di due numeri. Se si ha un poco di dimestichezza con la matematica, è facile capire le espressioni più semplici; tuttavia, analizzeremo dettagliatamente il loro comportamento nella programmazione nel prossimo capitolo.

Espressioni e introduzione agli operatori

Un operatore è una funzione che viene eseguita su uno o più operandi e restituisce un risultato. Una serie di operatori e operandi dà luogo a un'espressione. Un esempio vale più di mille parole:

a + b

Questa è una espressione. Essa contiene un operatore (+) e i suoi due operandi (a b). Quello che fa è evidente: l'operatore + somma i suoi due operandi a e b, e restituisce il risultato. Si noti che tale risultato, per poter essere conosciuto, dovrebbe essere salvato in qualche variabile con un operatore di assegnamento, ad esempio:

c = a + b;

In C (e C++) esistono molti operatori, con delle proprietà specifiche:

Per esempio, gli operatori di moltiplicazione e divisione hanno arietà 2, hanno precedenza su somma e differenza e, se compaiono in fila in un'espressione, vengono valutati da sinistra a destra.

/* Operatori aritmetici -- si utilizzano come i corrispondenti simboli matematici */
+   somma
-   differenza
*   moltiplicazione
/   divisione
%   modulo o resto
/* Operatori di valutazione -- valutano le relazioni tra i loro operandi */
<      minore
<=     minore o uguale
>      maggiore
>=     maggiore o uguale
==     uguale
!=     diverso
/* Operatore di assegnamento */
=
/* Operatori Logici -- corrispondono alle operazioni booleane */
||        OR o somma logica
&&        AND o prodotto logico
!         NOT o negazione
/* Comodi operatori unari */
++        incremento di 1
--        decremento di 1
&         indirizzo in memoria di... (Attenzione: vedremo che può avere anche un altro uso)
sizeof    dimensione di...

Esistono molti altri operatori che, per le loro caratteristiche, meritano dei capitoli a parte. Nel frattempo, quelli esposti, sono più che sufficienti per iniziare davvero a programmare. Seguono alcuni esempi di espressioni e di valutazioni.

23 + 2        /* vale 25 */
a = 4         /* assegna ad a il valore 4 e restituisce l'indirizzo di a */
a == 4        /* valuta se a è uguale a 4, perciò restituisce vero (non zero) */
a < 2         /* restituisce falso (zero) */
++a           /* incrementa a di 1 e ritorna 5 */
5 + 2 * 3     /* vale 11 */
(5 + 2) * 3   /* vale 21 */

Operatori logici

Meritano un paragrafo a sé le condizioni, che sono delle espressioni a tutti gli effetti, con l'unica differenza che possono avere solo due risultati: vero oppure falso. In ambito di programmazione si usano per connettere insieme più valutazioni, costruendo espressioni del tipo "a è maggiore di 3 ma minore di 7?".

Se applichiamo gli operatori logici a espressioni che ritornano valori non booleani viene implicitamente effettuata una conversione, dove per convenzione è attribuito falso a 0, mentre vero a un qualunque altro numero diverso da 0.

#include <stdio.h>

int main()
{
  int a = 5, b = 3;

  printf ("%i\n", (a > 8) && (a < 6));  /* Stampa 0 (falso) */
  printf ("%i\n", (a > 3) && (a < 7));  /* Stampa 1 (vero) */
  printf ("%i\n", (a > 7) || (b < 5));  /* Stampa 1 (vero) */
  printf ("%i\n", (a > 7) || (b < 2));  /* Stampa 0 (falso) */
  printf ("%i\n", a && (!b));          /* Stampa 0 (falso) */
  /* In questo caso a e b sono convertiti entrambi a vero, e
     b viene negato, diventando falso */
}
Pagina scritta da Giovan BattistaGiovan Battista

Hai una domanda? Scrivici!
Questa pagina ti è piaciuta? Condividila!
Share on Facebook Share on Google+ Share on linkedin