# ✨ LA GUIDA DEFINITIVA - C
:::success
:email: Ciao!
La serie delle "GUIDE DEFINITIVE" è un progetto creato in parte per scherzo e in parte per aiutare chi ne ha bisogno. Se riscontri problemi, errori o simili, puoi inviarmi un messaggio su Telegram tramite ([@norineko](https://t.me/norineko)), cercherò di rispondere il prima possibile!
#### Grazie mille! :heart:
:::
Il linguaggio di programmazione C è uno dei più potenti e diffusi. È un **linguaggio compilato**: il codice sorgente viene trasformato in un eseguibile nativo, risultando in programmi molto **veloci** ed **efficienti**. C è usato principalmente per sviluppare software di basso livello, come ad esempio:
- Kernel e sistemi operativi
- Driver e firmware
- Librerie e applicazioni ad alte prestazioni
- Programmi embedded
<br>
## Introduzione
:::warning
:warning: Nota bene
Per eseguire programmi in C è necessario installare un **compilatore C**. Opzioni comuni:
- **GCC** (consigliato; su Windows tramite MinGW-w64 o MSYS2)
- **Clang/LLVM**
- **MSVC** (Microsoft Visual C/C++ – parte di Visual Studio/Build Tools)
:::
### Template
```c
#include <stdio.h>
int main(void) {
// inserisci qui il tuo codice
return 0;
}
```
Possiamo iniziare un nuovo progetto con questo template di partenza che contiene:
- una direttiva `#include` per importare la libreria standard di I/O (`stdio.h`)
- la funzione `main`, punto d’ingresso del programma
- `return 0` per indicare terminazione con successo
<br>
### Commenti
I commenti sono usati per descrivere il codice. Non vengono compilati né eseguiti.
- Commento su singola riga: inizia con `//` e termina a fine linea
- Commento multi‑linea: racchiuso tra `/* ... */`
Esempio in C:
```c
#include <stdio.h>
int main(void) {
printf("Ciao!\n"); // stampa "Ciao!" e va a capo
/* Questo è
* un commento
* multi‑linea */
return 0;
}
```
<br>
## Variabili
Le variabili sono **spazi di memoria** usati per **memorizzare dati**. Ogni variabile ha un **tipo** e un **nome**. Il tipo determina il formato e l’intervallo dei valori memorizzabili.
:::info
:bulb: Le variabili vivono tipicamente in **RAM** durante l’esecuzione del programma.
:::
Tipi di variabili "semplici" più comuni:
- **Interi** (`int`, `short`, `long`, `long long`)
Su molte piattaforme moderne: `int` è a 32 bit (circa da −2.147.483.648 a 2.147.483.647), ma la dimensione è dipendente dall’implementazione. Per ampiezze garantite usa `<stdint.h>` (`int32_t`, `int64_t`, ecc.).
```c
int numeroIntero = 5;
```
- **Floating point** (`float`, `double`)
`float` è in genere a 32 bit (~7 cifre decimali di precisione). `double` è a 64 bit (~15‑16 cifre).
```c
float numeroDecimale = 0.05f; // il suffisso f indica un float
double pi = 3.141592653589793;
```
- **Caratteri** (`char`)
Memorizza un singolo carattere. In C i caratteri si scrivono con **apici singoli**.
```c
char lettera = 'a';
char cifra = '2';
```
- **Stringhe**
In C non esiste un tipo `String` nativo. Una stringa è un **array di char** terminato da `\0`.
```c
char msg[] = "Hello, World!"; // dimensione dedotta (include il terminatore)
char msg2[14] = "Hello, World!"; // spazio esatto: 13 + 1
const char *p = "Hello, World!"; // puntatore a stringa letterale (sola lettura)
```
:::warning
⚠️ Ogni variabile semplice contiene un solo valore alla volta. Per collezioni usa array o strutture dati.
:::
:::info
:bulb: Le variabili vanno **dichiarate** prima dell’uso, specificando tipo, nome e opzionalmente un valore iniziale.
:::
### Booleani
In C “storico” non c’è un tipo booleano nativo. Le condizioni considerano **0 = falso**, **qualsiasi valore diverso da 0 = vero**. Da C99 è disponibile `#include <stdbool.h>` con `bool`, `true`, `false`.
```c
#include <stdio.h>
#include <stdbool.h>
int main(void) {
bool a = true;
bool b = false;
if (a) {
printf("Ciao, mondo!\n");
} else {
printf("Addio, mondo!\n");
}
printf("%d\n", a && b); // stampa 0 (false)
return 0;
}
```
### Array
Un array è una sequenza di elementi dello **stesso tipo**, indicizzati da `0` a `n-1`.
```c
#include <stdio.h>
int main(void) {
int a[10];
for (int i = 0; i < 10; ++i) {
a[i] = i * 2; // assegno ai singoli slot
}
for (int i = 0; i < 10; ++i) {
printf("Elemento %d vale %d\n", i, a[i]);
}
return 0;
}
```
### Puntatori
Un puntatore contiene un **indirizzo di memoria** di un altro oggetto.
```c
#include <stdio.h>
int main(void) {
int x = 5;
int *ptr = &x; // ptr punta a x
printf("x = %d\n", *ptr); // dereferenziazione: leggo il valore puntato
*ptr = 10; // modifico x tramite il puntatore
printf("x = %d\n", x);
return 0;
}
```
:::info
Nota bene:
- Inizializza sempre i puntatori (a un indirizzo valido o a `NULL`).
- Stampa un indirizzo con `%p` e argomento di tipo `void*` (cast se necessario).
- La **aritmetica dei puntatori** avanza di multipli della dimensione del tipo puntato.
:::
### Struct
Le strutture raggruppano variabili di tipi diversi in un unico oggetto.
```c
#include <stdio.h>
#include <string.h>
struct Persona {
char nome[50];
int eta;
float altezza;
};
int main(void) {
struct Persona p1;
// Assegno a un array di char con strcpy (non con =)
strcpy(p1.nome, "Mario");
p1.eta = 25;
p1.altezza = 1.75f;
printf("%s, %d anni, %.2f m\n", p1.nome, p1.eta, p1.altezza);
return 0;
}
```
Lista concatenata minima:
```c
typedef struct Nodo {
int valore;
struct Nodo *next;
} Nodo;
```
<br>
## Funzioni principali (cicli, condizioni, ecc.)
### La funzione `printf`
`printf` stampa testo e valori formattati sulla **console** (stdout).
```c
int numero = 5;
printf("%d\n", numero); // 5
printf("Ciao, mondo!\n");
```
Indicatori di formato comuni:
- `%c` carattere
- `%d` o `%i` intero con segno base 10
- `%u` intero senza segno
- `%f`/`%e`/`%g` double a virgola mobile (in `printf` anche `float` viene promosso a `double`)
- `%s` stringa di caratteri
- `%x`/`%X` esadecimale; `%o` ottale
- `%p` puntatore (indirizzo)
- `%%` stampa un simbolo percentuale
Modificatori utili: `l`/`ll` (es. `%ld`, `%lld`), ampiezza e precisione (es. `%.2f`).
### L’istruzione `if`
Esegue un blocco di codice se la condizione è vera.
```c
if (x == y) {
printf("x è uguale a y\n");
} else {
printf("x non è uguale a y\n");
}
```
:::danger
:warning: `=` assegna; `==` confronta. Non confonderli!
:::
### Ciclo `for`
```c
for (int i = 1; i <= 5; ++i) {
printf("%d\n", i);
}
```
### Ciclo `while`
```c
int x = 1;
while (x <= 10) {
printf("%d\n", x);
++x;
}
```
### Ciclo `do ... while`
Esegue il corpo almeno una volta.
```c
int i = 0;
do {
printf("%d\n", i);
++i;
} while (i <= 10);
```
### `switch`
```c
switch (valore) {
case 1:
// ...
break;
case 2:
// ...
break;
default:
// ...
break;
}
```
## Salti non condizionati
### `break`
Interrompe il ciclo più interno o esce da `switch`.
```c
for (int i = 0; i < 10; ++i) {
if (i == 5) break;
printf("%d ", i);
}
// Output: 0 1 2 3 4
```
### `continue`
Salta alla prossima iterazione del ciclo.
```c
for (int i = 0; i < 10; ++i) {
if (i == 5) continue;
printf("%d ", i);
}
// Output: 0 1 2 3 4 6 7 8 9
```
### `return`
Termina la funzione corrente e può restituire un valore.
```c
int somma(int a, int b) { return a + b; }
int main(void) {
int numero = 0;
if (numero == 0) {
printf("Numero non valido!\n");
return 1; // codice d’errore
}
// ...
return 0; // successo
}
```
:::success
### Esercizio
Mettiamo i concetti in pratica!
1) Dichiara una variabile `int` di nome `numero`
2) Assegna un numero a piacere a `numero`
3) Se `numero > 100` stampa "il numero è maggiore di 100!", altrimenti "il numero è minore o uguale a 100!"
4) (opzionale) mostra anche il valore della variabile
:::spoiler Soluzione
```c
#include <stdio.h>
int main(void) {
int numero = 135;
if (numero > 100) {
printf("Il numero %d è maggiore di 100!\n", numero);
} else {
printf("Il numero %d è minore o uguale a 100!\n", numero);
}
return 0;
}
```
:::
:::
## Operatori
Operatori aritmetici:
- `+`, `-`, `*`, `/` (attenzione: la divisione tra interi tronca)
- `%` modulo (resto) per interi
- `++x`/`x++` incremento; `--x`/`x--` decremento
- `a = b++;` assegna prima `b` ad `a`, poi incrementa `b`
- `a = ++b;` incrementa `b`, poi assegna ad `a`
Operatori di confronto (ritornano 0 o 1):
- `==`, `!=`, `<`, `<=`, `>`, `>=`
Operatori logici:
- `&&` (AND) – vero se entrambi veri
- `||` (OR) – vero se almeno uno vero
- `!` (NOT) – inverte vero/falso
:::info
:bulb: Cortocircuito: in `x || y`, se `x` è vero `y` non viene valutato; in `x && y`, se `x` è falso `y` non viene valutato.
:::
Operatori di assegnazione composti: `+=`, `-=`, `*=`, `/=`, `%=` ecc.
## Funzioni
Una funzione è una porzione di codice riutilizzabile che può accettare parametri e restituire un valore.
```c
#include <stdio.h>
int somma(int a, int b) { // prototipo + definizione
return a + b;
}
int main(void) {
int x = 10, y = 20;
int z = somma(x, y);
printf("La somma di %d e %d è %d\n", x, y, z);
return 0;
}
```
Nota: in C gli argomenti vengono passati **per valore**. Per permettere a una funzione di modificare una variabile del chiamante, passa un **puntatore** (es. `void incrementa(int *p) { (*p)++; }`).
## Espressioni, lvalue e rvalue
- Un **lvalue** designa una locazione di memoria (p.es. una variabile) e può comparire a sinistra di un’assegnazione.
- Un **rvalue** è un valore temporaneo o risultato di un’espressione; non può comparire a sinistra di `=`.
Esempi:
```c
int a = 5; // a è un lvalue, 5 è un rvalue
int *b = &a; // b è un lvalue che contiene l’indirizzo di a
*b = 20; // assegna 20 a a tramite b (lvalue a sinistra di =)
// Attenzione: assegnazione invece di confronto!
if (a = 5) { // assegna 5 ad a; condizione è vera (non zero)
// ...
}
```
Effetti collaterali: un’espressione ha effetti collaterali se modifica stato esterno (p.es. `a++`, I/O, assegnazioni).
## Tipi restituiti dalle espressioni (esempi)
- `'\n'` ha tipo `int` (in C i caratteri letterali hanno tipo int) e rappresenta il newline
- `a + 1` ha tipo del più ampio tra gli operandi (promozioni aritmetiche usuali)
- `"test"` ha tipo `const char[5]` e in molte espressioni decresce a `const char *`
- `abort()` (da `<stdlib.h>`) non restituisce; `sqrt(2.0)` (da `<math.h>`) restituisce `double`
:::info
:bulb: "Valore restituito" = il risultato di un’espressione dopo la sua valutazione.
:::
## I/O di base (input)
- Leggere un intero: `scanf("%d", &x);` (controlla sempre il valore di ritorno)
- Leggere una riga di testo in modo sicuro: `fgets(buffer, sizeof buffer, stdin);`
- Per stampare indirizzi usa `%p`; per `size_t` usa `%zu`.
## Compilare ed eseguire
- Con GCC (C17, warning utili): `gcc -std=c17 -Wall -Wextra -O2 -o programma.exe programma.c`
- Con Clang: `clang -std=c17 -Wall -Wextra -O2 -o programma.exe programma.c`
- Con MSVC (Developer Command Prompt): `cl /std:c17 /W4 programma.c`
Su Windows è comodo installare GCC tramite MinGW‑w64 (MSYS2) oppure usare Visual Studio Build Tools.
## Non hai un PC? Sviluppare C da tablet/solo browser
Se usi un tablet o non hai un computer, puoi programmare in C direttamente dal browser.
- Replit (facile e immediato)
- Vai su https://replit.com e crea un account
- Crea un nuovo Repl scegliendo il template “C”
- Scrivi in `main.c` e premi Run per compilare/eseguire
- Pro: semplice, niente installazioni. Contro: risorse limitate rispetto a un PC locale
- GitHub Codespaces (consigliato, ambiente completo)
- Crea un account GitHub e richiedi il GitHub Student Developer Pack: https://github.com/education/students
- Crea o importa un repository con i tuoi file `.c`
- Dal repo, usa il menu “Code” → “Open with Codespaces” per avviare un ambiente VS Code nel browser
- Avrai editor completo, terminale integrato, git e compilatori; perfetto anche da iPad/Android con tastiera esterna
- Nota: i Codespaces consumano crediti/ore gratuite del tuo piano; lo spazio può andare in sleep quando inattivo
- Altre alternative
- OnlineGDB (debugger C online): https://onlinegdb.com
- Wandbox/Ideone: rapida compilazione online
- Compiler Explorer (Godbolt): https://godbolt.org per confrontare compilatori e vedere l’assembly (non pensato per I/O runtime)
:::info
Suggerimenti d’uso su tablet: attiva la “modalità desktop” del browser, usa una tastiera esterna per scrivere più comodamente `{}`, `[]`, `;`. Salva sempre i progetti su GitHub per non perdere il lavoro.
:::
# Bonus
Concetti base utili.
#### 1) Conversione da decimale a esadecimale
Per convertire un numero decimale (base 10) in esadecimale (base 16):
1) Dividi per 16 e annota il **resto** (0–15; 10=A, 11=B, 12=C, 13=D, 14=E, 15=F)
2) Prendi il **quoziente** e ripeti finché non diventa 0
3) L’esadecimale è la sequenza dei resti **letta al contrario**
Esempio con 1500:
- 1500 / 16 = 93, resto 12 (C)
- 93 / 16 = 5, resto 13 (D)
- 5 / 16 = 0, resto 5
→ Risultato: `5DC`
#### 2) Conversione da esadecimale a decimale
Moltiplica ogni cifra per 16 elevato alla posizione (da destra a sinistra, partendo da 0).
Esempio: `AF` → `(10 × 16^1) + (15 × 16^0) = 160 + 15 = 175`
#### 3) Conversione da binario a decimale
Somma di bit × 2^posizione (posizione da destra, partendo da 0).
Esempi:
- `10011011₂ = 1×2^7 + 0×2^6 + 0×2^5 + 1×2^4 + 1×2^3 + 0×2^2 + 1×2^1 + 1×2^0 = 155`
- `1001101₂ = 1×2^6 + 0×2^5 + 0×2^4 + 1×2^3 + 1×2^2 + 0×2^1 + 1×2^0 = 77`
#### 4) Conversione da decimale a binario (rapida)
Dividi per 2 annotando i resti (0/1); leggi i resti al contrario.
#### 5) Rappresentazione di numeri con segno (two’s complement)
Il bit più significativo rappresenta il **segno**: 0 = positivo, 1 = negativo. Il valore negativo `−x` si ottiene invertendo i bit di `x` e aggiungendo 1. Questo consente somma/sottrazione uniformi a livello binario.
<br>
:::spoiler Da fare
- decimale → esadecimale :heavy_check_mark:
- esadecimale → decimale :heavy_check_mark:
- binario → decimale :heavy_check_mark:
- decimale → binario :heavy_check_mark:
- complemento a due (segno) :heavy_check_mark:
:::