Linguaggio C
Il C è un linguaggio di programmazione di alto livello. Progettato e realizzato da Dennis Ritchie (1941–2011) nel 1972, fu sviluppato presso gli AT&T Bell Laboratories (New Jersey, USA) per ottenere un linguaggio adatto all’implementazione dei sistemi operativi. Utilizzato per la prima volta in modo estensivo per la riscrittura del sistema operativo UNIX dal linguaggio assembly, può essere impiegato con tutti i principali sistemi operativi oggi disponibili.
Stephen C. Johnson, alla fine degli anni Settanta, scrisse il Portable C Compiler (pcc) trasportabile su sistemi diversi dal PDP-11 (Programmed Data Processor-11, la serie di computer su cui furono sviluppate le prime versioni di UNIX): da allora il C cominciò a essere utilizzato come linguaggio in altri sistemi operativi, come MS-DOS (Microsoft Disk Operating System) e CP/M-80 (Control Program for Microcomputers).
Per combinare efficienza e potenza in un linguaggio tendenzialmente compatto, il C non possiede al suo interno alcune funzionalità tipiche di altri linguaggi (per esempio la gestione diretta di monitor e tastiera), demandate a librerie separate da utilizzare all’occorrenza. Questa soluzione consente maggiore flessibilità: il programmatore può decidere se impiegare funzioni esistenti oppure implementarne di proprie, sfruttando gli elementi di base offerti dal linguaggio.
La grande facilità d’uso e la diffusione del C resero necessario evitare la proliferazione di “dialetti”: nel 1983 fu istituito un comitato ANSI per definire uno standard del linguaggio C, da cui nacque lo standard ANSI/ISO C (C89/C90), base delle evoluzioni successive.
- Nato nel 1972 ai Bell Labs per sistemi operativi.
- Efficiente, portabile, con funzioni di I/O delegate a librerie.
- Standardizzato (C89/C90) per evitare dialetti.
- Ancora oggi alla base di molto software di sistema.
Esercizio – C: perché demandare I/O a librerie?
Linguaggio C++
Sebbene il C possieda tutti gli strumenti per implementare qualunque tipo di dato astratto, tale implementazione è demandata interamente al programmatore. Il C++ nacque dall’esigenza di una maggiore astrazione dei dati, che consentisse di definire nuovi tipi in modo semplice, risolvendo numerosi problemi con la stessa efficienza e portabilità del C.
L’ideatore è il danese Bjarne Stroustrup che, insieme ai fondatori di C e UNIX, nei laboratori AT&T iniziò nel 1979 a gettare le basi di un nuovo linguaggio che mantenesse il C come base per garantirne efficienza, portabilità e compatibilità con l’elevato numero di programmi esistenti.
La prima versione prese il nome di “C con classi”; nel 1986 divenne C++. Nel 1990 uscì The Annotated C++ Reference Manual (ARM), base dello standard ISO 1998 (C++98), poi evoluto (C++11/14/17/20/23).
Il C++ mantiene le virtù del C ma aggiunge OOP e astrazione di alto livello, consentendo migrazioni progressive dalla programmazione procedurale.
Perché il C++ ha avuto successo
- Compatibile con il C; ampia base di codice e librerie.
- Standard ISO che migliorano portabilità e interoperabilità.
- Efficienza elevata; adatto a software di sistema e applicazioni desktop.
- Sintassi che ha influenzato C#, Java e molti linguaggi di scripting.
- Estende il C con classi, OOP e astrazione.
- Compatibilità forte con codice C esistente.
- Standard evolutivi (C++98 → C++23).
- Ottimo compromesso tra performance e produttività.
Esercizio – C++: perché l’OOP aiuta nel software grande?
Livelli di funzionalità di un computer
Il livello software più basso corrisponde al linguaggio macchina/assembly. Sopra troviamo il sistema operativo (I/O, RAM, CPU, memoria di massa) e quindi il software di sviluppo (editor, compilatori, interpreti, linker) che traducono linguaggi ad alto livello in codice eseguibile.
Compilatori e interpreti
- Interprete: traduce ed esegue una riga per volta (ottimo per iterazioni rapide).
- Compilatore: traduce l’intero programma in un binario (esecuzione veloce). C/C++ sono compilati.
- Macchina → OS → Tool di sviluppo → Applicazioni.
- Compilatore produce binario; interprete esegue “al volo”.
- C/C++ sono compilati e ad alte prestazioni.
Esercizio – Vantaggio pratico del compilato rispetto all’interprete?
Struttura di un programma in C/C++
Un programma deve contenere main(), punto d’ingresso dell’esecuzione.
Esempio completo (C)
#include <stdio.h>
#include <stdlib.h>
int main() {
int a, b, somma;
printf("Inserire il primo numero: ");
scanf("%d", &a);
printf("Inserire il secondo numero: ");
scanf("%d", &b);
somma = a + b;
printf("La somma di %d e %d e`: %d\n", a, b, somma);
return 0;
}
Direttive, main, dichiarazioni, corpo
- Direttive (
#include) — non terminano con; main()— funzione principale, di normaint main()conreturn 0;- Sezione dichiarativa — dichiarazioni variabili (buona pratica: all’inizio della funzione)
- Corpo — istruzioni tra
{ }, ogni istruzione termina con;
return 0;#includeper librerie; nessun;nelle direttive.int main()è il punto d’ingresso;return 0;indica successo.- Dichiarazioni chiare all’inizio; corpo tra graffe con
;a fine istruzione.
Esercizio – Sposta una dichiarazione vicino all’uso: pro e contro?
I commenti
Commenti in C
somma = a + b; /* commento
su più righe */
Commenti in C++
// commento su una riga
std::cout << "C++"; // commento in coda
| C | C++ | |
|---|---|---|
| Inizio commento | /* |
// |
| Fine commento | */ |
Fine riga |
| Note | Più righe | Una riga (o usa /*...*/) |
//per righe singole;/*...*/per blocchi.- Commenti chiari spiegano il “perché”, non l’ovvio “come”.
- Evita commenti obsoleti: aggiornali o rimuovili.
Esercizio – Trasforma due righe in un commento di blocco
/* Riga 1
Riga 2 */
Il primo programma in C/C++
| C | C++ |
|---|---|
|
|
return 0; alla fine di main() segnala terminazione corretta al sistema.Esercizio – Aggiungi un a-capo all’output
// C
printf("Hello world! in C\n");
// C++
std::cout << "Hello world! in C++\n";
// oppure
std::cout << "Hello world! in C++" << std::endl;
Le direttive #include e namespace
#include inserisce nel sorgente i file header con dichiarazioni e funzioni delle librerie standard.
| C | C++ |
|---|---|
#include <stdio.h>#include "miofile.h" |
#include <iostream>#include "miofile" |
Header con estensione .h |
Header senza .h per standard C++ |
In C++ si usa lo spazio dei nomi std:
using namespace std; // per esempio didattico
// oppure qualificare:
std::cout << "ciao\n";
<...>cerca nei percorsi di sistema;"..."parte dalla cartella del progetto.- In C++ preferisci
<iostream>,<cstdio>,<cmath>, ecc. - Valuta l’uso di
std::invece diusing namespace std;in codice “di produzione”.
Esercizio – Trova l’errore: #include <iostream.h>
.h per gli header standard. Corretto: #include <iostream>.La gestione dell’input/output
Operatori di ridirezione (C++)
<<inserzione → output versocout>>estrazione → input dacin
std::cout << "Ciao a tutti";
std::cout << "x=" << x << " y=" << y << std::endl;
int numero; std::cin >> numero;
Confronto C vs C++
| C | C++ | |
|---|---|---|
| Output | printf(...) |
cout << ... |
| Input | scanf(...) |
cin >> ... |
| A-capo | \n |
\n o endl |
| Esempio | printf("x=%d y=%d\n",x,y); |
cout << "x=" << x << " y=" << y << endl; |
Esercizio – Somma di due interi (C++)
#include <iostream>
int main(){
int a,b; std::cout << "a? "; std::cin >> a;
std::cout << "b? "; std::cin >> b;
std::cout << "somma=" << (a+b) << '\n';
return 0;
}
- C usa
printf/scanfcon specificatori di formato. - C++ usa
cout/cinsenza specificatori. endlforza anche il flush del buffer di output.
Gli operatori in C/C++
Aritmetici
| Simbolo | Operatore | Note |
|---|---|---|
+ |
Addizione | Con stringhe C++ concatena |
- |
Sottrazione | — |
* |
Moltiplicazione | — |
/ |
Divisione | Tra interi tronca |
% |
Modulo | Solo interi |
Esempio (divisione intera)
| C | C++ |
|---|---|
|
|
Unari incremento/decremento
int x=10, y;
y = x++; // postfisso: usa x poi incrementa → y=10, x=11
y = ++x; // prefisso: incrementa poi usa → x=12, y=12
Esercizio – Valuta l’output
int i=15; int a=(i++)*2; // a=30, i=16
i=15; a=(++i)*2; // a=32, i=16
/tra interi tronca;%solo su interi.++xvsx++: prefisso modifica prima, postfisso dopo.- Usa parentesi per controllare la precedenza.
Operatori di confronto, logici e assegnamento
Relazionali
| Forma | Descrizione |
|---|---|
a == b |
uguale |
a != b |
diverso |
a < b |
minore |
a > b |
maggiore |
a <= b |
minore o uguale |
a >= b |
maggiore o uguale |
Logici
| Operatore | Nome | Short-circuit |
|---|---|---|
&& |
AND | Se sinistro è false, destro non valutato |
|| |
OR | Se sinistro è true, destro non valutato |
! |
NOT | Inverte verità |
Assegnamento semplice e composto
| Esteso | Compatto | Significato |
|---|---|---|
x = x + y; |
x += y; |
Somma e assegna |
x = x - y; |
x -= y; |
Sottrai e assegna |
x = x * y; |
x *= y; |
Moltiplica e assegna |
x = x / y; |
x /= y; |
Dividi e assegna |
x = x % y; |
x %= y; |
Modulo e assegna |
Esercizio – Espressione vera solo se a e b sono positivi
(a > 0) && (b > 0)
- Relazionali producono booleani (
true/false). &&/||valutano in short-circuit.- Assegnamenti composti rendono il codice più conciso.
Appendice: Standard C e C++ (cronologia)
| Standard | Anno | Novità principali (non esaustive) |
|---|---|---|
| C89/C90 | 1989/1990 | Primo standard ANSI/ISO |
| C99 | 1999 | Commenti //, inline, nuovi tipi interi, dichiarazioni flessibili |
| C11 | 2011 | _Atomic, _Thread_local, Unicode |
| C++98 | 1998 | Primo standard ISO, OOP, STL |
| C++11 | 2011 | auto, nullptr, lambda, range-for, move semantics |
| C++17 | 2017 | if constexpr, filesystem, structured bindings |
| C++20 | 2020 | Concepts, Modules, Coroutines, Ranges |
| C++23 | 2023 | Migliorie libreria, std::expected, std::print (implementazioni) |
-std=c++20 per g++).Scheda riepilogativa: Operatori in C/C++
Operatori aritmetici
| Simbolo | Nome | Esempio | Effetto |
|---|---|---|---|
+ |
Addizione | a + b |
Somma |
- |
Sottrazione | a - b |
Differenza |
* |
Moltiplicazione | a * b |
Prodotto |
/ |
Divisione | a / b |
Interi: troncamento |
% |
Modulo | a % b |
Resto divisione intera |
Incremento / Decremento
| Forma | Tipo | Esempio | Risultato |
|---|---|---|---|
++x |
Prefisso | y = ++x; |
Incrementa poi usa |
x++ |
Postfisso | y = x++; |
Usa poi incrementa |
--x |
Prefisso | y = --x; |
Decrementa poi usa |
x-- |
Postfisso | y = x--; |
Usa poi decrementa |
Relazionali
| Simbolo | Significato |
|---|---|
== |
Uguale |
!= |
Diverso |
< |
Minore |
> |
Maggiore |
<= |
Minore o uguale |
>= |
Maggiore o uguale |
Logici
| Simbolo | Nome | Short-circuit |
|---|---|---|
&& |
AND | Sì |
|| |
OR | Sì |
! |
NOT | — |
Assegnamento (composti)
| Esteso | Compatto | Significato |
|---|---|---|
x = x + y; |
x += y; |
Somma e assegna |
x = x - y; |
x -= y; |
Sottrai e assegna |
x = x * y; |
x *= y; |
Moltiplica e assegna |
x = x / y; |
x /= y; |
Dividi e assegna |
x = x % y; |
x %= y; |
Modulo e assegna |
- Ricorda short-circuit per
&&e||. /tra interi tronca;%solo per interi.- Parentesi per chiarire la precedenza nelle espressioni complesse.
Ripassiamo insieme
Come si dichiara una variabile?
tipo Identificatore;
tipo Identificatore1, Identificatore2, ...;
tipo Identificatore = valore;
I linguaggi C e C++: le basi (mappa modificabile)
Un programma è un algoritmo tradotto in un linguaggio di programmazione, comprensibile al computer.
Costituenti C/C++: parole chiave, identificatori, commenti, segni di punteggiatura, operatori.
Commenti — C: /* ... */ • C++: // ... (fino a fine riga)
I/O in C — printf(...), scanf(...)
I/O in C++ — cout << ..., cin >> ...
Istruzioni di input/output: esempi rapidi
| Obiettivo | C | C++ |
|---|---|---|
| Output di un messaggio | printf("Messaggio "); |
cout << "Messaggio "; |
Output di x |
printf("%d", x); |
cout << x; |
| Output “Valore = x” | printf("Valore = %d", x); |
cout << "Valore = " << x; |
Input in x |
scanf("%d", &x); |
cin >> x; |
Test – Vero/Falso
- Algoritmo e programma sono sinonimi (I) …… ☐ V ☐ F
- Il linguaggio C non possiede parole chiave (A) …… ☐ V ☐ F
int z;dichiara una variabile intera di nomez(H) …… ☐ V ☐ F- Il simbolo
//indica l’inizio di un commento in C++ (B) …… ☐ V ☐ F cin >> z;visualizza il valore diz(G) …… ☐ V ☐ Fcout >> "Benvenuto";produce un errore (F) …… ☐ V ☐ F
Mostra soluzioni
- F — algoritmo ≠ programma
- F — il C ha keyword
- V
- V
- F —
cinlegge, non stampa - V — si usa
<<, non>>
Test – Risposta multipla
- Sequenza per ottenere un eseguibile:
A) editing → linker → compilatoreB) editing → compilatore → debugC) compilatore → editing → linkerD) editing → compilatore → linker
- Istruzioni di preprocessore: quale è FALSA?
A) si chiamano direttive al preprocessoreB) iniziano con
#+ nome direttivaC) non terminano con;D) terminano con; - Che cosa sono i file header?
A) file opzionaliB) file che contengono le librerie del CC) file da integrare in caso di erroreD) file per intestazione testuale
- Differenza tra
#include <stdio.h>e#include "stdio.h":A) nessunaB) librerie diverseC) percorsi di ricerca diversiD) la seconda viene ignorata se assente constdefinisce costanti tipizzate. Significa:A) ogni costante simbolica ha un tipoB) ogni costante esplicita ha un tipoC) le costanti possono avere tipi diversiD) possono cambiare tipo- Quale è FALSA sugli statement:
A) sono istruzioniB) sono righe di dichiarazioniC) racchiudono l’elaborazioneD) sono errori del compilatore
- Quale è FALSA sugli specificatori di formato:
A) introdotti da
%B) identificano il tipo da stampareC) indicano percentualeD) inprintfformattano il valore - Dopo
a = x++:A) a e x ugualiB) a > xC) a < xD) dipende da x - Espressione corretta per la media:
A)
a+b+c+d/4B)a+(b+c+d)/4C)(a+b+c+d/4D)(a+b+c+d)/4 - Calcola:
int Totale, x = 1; Totale = ++x + 15 * x-- + x++;A) 31B) 32C) 30D) 16 x %= 2assegna a x:A) il 2% di xB) il resto di 2/xC) 0 oppure 1D) un numero > 1
Soluzioni
- D
- D
- B
- C
- A
- D
- C
- C
- D
- — (in C/C++ classico l’espressione ha comportamento indefinito)
- C
Abilità
1) Trova gli errori presenti nel seguente codice.
#include <iostream.h>
int main( )
{
float a, b; /* questo è un commento corretto.
a = 100; // questo commento è valido //
b = 10 */ questo commento è valido /*
return 0;
}
Mostra soluzione
#include <iostream>
int main() {
float a, b; /* commento di blocco chiuso correttamente */
a = 100;
// commento di riga valido
b = 10;
return 0;
}
Note: header standard C++ senza .h; i commenti non si incrociano.
2) In ognuna delle seguenti dichiarazioni di costanti c’è almeno un errore: trovali.
const char C "a";
const int POSTI = 100,00;
const char[2] MESS = "Buongiorno!";
const PGRECO = 3,14;
char const C = 'a';
int POSTI =100;
const char ERRORE "Rilevato errore'
Mostra soluzione
const char C = 'a'; // carattere singolo
const int POSTI = 100; // punto, non virgola
const char MESS[] = "Buongiorno!"; // dimensione dedotta
const double PGRECO = 3.14; // tipo esplicito
const int POSTI2 = 100; // nuovo nome se serve
const char ERRORE[] = "Rilevato errore"; // apici corretti
3) Qual è l’output prodotto dal seguente programma?
#include <stdio.h>
int main()
{
int a=5, b=6, c;
printf("++a = %d\n", ++a);
printf("a = %d\n", a);
printf("a++ = %d\n", a++);
printf("a = %d\n", a);
c = ++b;
printf("b = %d\n", b);
printf("c = %d\n", c);
c = b++;
printf("b = %d\n", b);
printf("c = %d\n", c);
return 0;
}
Mostra soluzione
++a = 6
a = 6
a++ = 6
a = 7
b = 7
c = 7
b = 8
c = 7
Competenze
4) Media di tre numeri
#include <iostream>
int main(){ double a,b,c; std::cin>>a>>b>>c;
std::cout << "media=" << (a+b+c)/3 << '\n'; }
5) Area del cerchio circoscritto a un quadrato (lato L)
Raggio = L/√2. Area = π r² = π (L²/2).
double L; std::cin>>L; double area = 3.1415926535 * (L*L/2.0);
6) Triangolo isoscele con lati AB (lato obliquo) e BC (base): perimetro e area
Perimetro = 2·AB + BC. Altezza = √(AB² − (BC/2)²). Area = (BC·altezza)/2.
7) Radice di ax = b (a ≠ 0)
double a,b; std::cin>>a>>b;
if(a!=0) std::cout<<"x="<<b/a; else std::cout<<"impossibile";
8) Costo del vino a €1,70/L
double litri; std::cin>>litri; std::cout<<litri*1.70;
9) Gradi (G), primi (P), secondi (S) ➜ secondi totali
long G,P,S; std::cin>>G>>P>>S;
long tot = G*3600 + P*60 + S;
10) Giorni/ore/minuti/secondi ➜ secondi totali
long g,o,m,s; std::cin>>g>>o>>m>>s;
long N = g*86400 + o*3600 + m*60 + s;
11) Additivo per vernice
10 g/kg fino a 10 kg, poi 5 g/kg oltre. Esempio:
double kg; std::cin>>kg;
double add = (kg<=10? kg*10.0 : 10*10.0 + (kg-10)*5.0);
12) Scatti telefonici e bolletta
Scatti usati = attuale − precedente. Totale = scatti·costo + canone.
long prev, cur; double costo, canone;
std::cin>>prev>>cur>>costo>>canone;
long scatti = cur - prev;
double totale = scatti*costo + canone;