# ✨ 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: :::