Come funziona il processo

Prima di scrivere codice, devi capire il flusso di lavoro fondamentale. Il C non Γ¨ interpretato come Python: devi compilare il tuo codice per ottenere un file eseguibile.

1. Scrivi il codice

Crei un file .c o .cpp con un editor di testo o IDE.

2. Compila

Il compilatore (GCC/G++) trasforma il tuo codice in linguaggio macchina.

3. Esegui

Lanci il file eseguibile generato nel terminale.

4. Debug

Se ci sono errori, li correggi e ricompili.

🐧 Installazione su Linux (Ubuntu/Debian)

Su Linux, GCC Γ¨ quasi sempre giΓ  disponibile o facilmente installabile.

BashTerminale Linux
# Aggiorna i pacchetti
sudo apt update

# Installa GCC, G++ e gli strumenti di sviluppo
sudo apt install build-essential gdb valgrind

# Verifica l'installazione
gcc --version    # dovrebbe mostrare: gcc (Ubuntu ...) X.X.X
g++ --version
gdb --version

# Installa anche make e cmake (build system)
sudo apt install make cmake
build-essential Il pacchetto build-essential installa tutto il necessario: gcc, g++, make, e le header di sistema.

🍎 Installazione su macOS

BashTerminale macOS
# Opzione 1: Xcode Command Line Tools (piΓΉ veloce)
xcode-select --install
# Segui le istruzioni nella finestra che si apre

# Verifica
clang --version   # su macOS, gcc Γ¨ spesso un alias di clang

# Opzione 2: GCC nativo con Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install gcc

# Con Homebrew, gcc si chiama gcc-13 (o versione corrente)
gcc-13 --version

πŸͺŸ Installazione su Windows

Su Windows hai due opzioni principali:

Opzione A: WSL2 (raccomandato)

WSL (Windows Subsystem for Linux) ti dà un ambiente Linux completo dentro Windows. È la scelta migliore per programmare in C/C++.

PowerShellPowerShell come Amministratore
# Installa WSL2 con Ubuntu
wsl --install

# Dopo il riavvio, apri "Ubuntu" dal menu Start
# Poi segui le istruzioni Linux sopra:

Opzione B: MinGW-w64 / MSYS2

BashShell MSYS2
# 1. Scarica MSYS2 da: https://www.msys2.org/
# 2. Installa e apri "MSYS2 UCRT64"
# 3. Aggiorna e installa GCC:
pacman -Syu
pacman -S mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-gdb

# 4. Aggiungi al PATH: C:\msys64\ucrt64\bin

πŸ–₯️ Visual Studio Code β€” Setup

VS Code è l'editor gratuito più usato per C/C++. È leggero, veloce e ha ottime estensioni.

Estensioni essenziali

C/C++ (Microsoft)

IntelliSense, autocompletamento, navigazione del codice, debugging integrato.

C/C++ Extension Pack

Pacchetto completo con cmake, themes e altri strumenti utili.

Code Runner

Esegui file C/C++ con un tasto senza configurare task.json.

Clang-Format

Formattazione automatica del codice secondo standard definiti.

Configurazione tasks.json

JSON.vscode/tasks.json β€” Compila con Ctrl+Shift+B
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Compila C",
      "type": "shell",
      "command": "gcc",
      "args": [
        "-Wall",
        "-Wextra",
        "-std=c17",
        "-g",
        "${file}",
        "-o",
        "${fileDirname}/${fileBasenameNoExtension}",
        "-lm"
      ],
      "group": { "kind": "build", "isDefault": true },
      "problemMatcher": ["$gcc"]
    },
    {
      "label": "Compila C++",
      "type": "shell",
      "command": "g++",
      "args": [
        "-Wall",
        "-Wextra",
        "-std=c++17",
        "-g",
        "${file}",
        "-o",
        "${fileDirname}/${fileBasenameNoExtension}",
        "-lm"
      ],
      "group": "build",
      "problemMatcher": ["$gcc"]
    }
  ]
}

Configurazione launch.json (Debugging)

JSON.vscode/launch.json β€” Debug con F5
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug C/C++",
      "type": "cppdbg",
      "request": "launch",
      "program": "${fileDirname}/${fileBasenameNoExtension}",
      "args": [],
      "stopAtEntry": false,
      "cwd": "${fileDirname}",
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "preLaunchTask": "Compila C"
    }
  ]
}

🚩 Flag del Compilatore

Comprendere i flag Γ¨ fondamentale per scrivere codice di qualitΓ .

FlagSignificatoQuando usarlo
-WallAbilita i warning piΓΉ comuniSempre
-WextraWarning aggiuntiviSempre
-WerrorTratta i warning come erroriPer codice pulito
-std=c17Standard C 2017Progetti C
-std=c++17Standard C++ 2017Progetti C++
-gIncludi informazioni di debugDurante lo sviluppo
-O0Nessuna ottimizzazione (default con -g)Debug
-O2Ottimizzazione livello 2Release
-O3Ottimizzazione massimaPerformance critica
-lmCollega la libreria mathQuando usi <math.h>
-fsanitize=addressAddressSanitizer: rileva memory errorsDebug memoria
-fsanitize=undefinedUBSan: rileva undefined behaviorDebug comportamento
BashComandi di compilazione tipici
# Compilazione base
gcc hello.c -o hello

# Compilazione con tutti i warning (raccomandato per imparare)
gcc -Wall -Wextra -std=c17 hello.c -o hello

# Compilazione con debug symbols (per gdb)
gcc -Wall -g -std=c17 hello.c -o hello

# Con sanitizer (trova bug di memoria a runtime)
gcc -Wall -g -fsanitize=address,undefined hello.c -o hello

# Build di release (ottimizzata)
gcc -O2 -std=c17 hello.c -o hello

# PiΓΉ file sorgente
gcc -Wall main.c utils.c lista.c -o programma

# Con libreria matematica
gcc -Wall calcoli.c -o calcoli -lm

πŸ’» Comandi Terminale Essenziali

Devi saper usare il terminale. Ecco i comandi indispensabili:

BashNavigazione e gestione file
# Navigazione
pwd                    # mostra la directory corrente
ls                     # lista i file
ls -la                 # lista dettagliata con file nascosti
cd cartella            # entra in una cartella
cd ..                  # vai su di un livello
cd ~                   # vai alla home
cd /percorso/assoluto  # vai a un percorso assoluto

# File e cartelle
mkdir miei_programmi   # crea una cartella
touch hello.c          # crea un file vuoto
cp sorgente.c copia.c  # copia
mv vecchio.c nuovo.c   # sposta/rinomina
rm file.c              # elimina file (ATTENZIONE: non va nel cestino)
rm -rf cartella        # elimina cartella e contenuto

# Visualizzare file
cat file.c             # mostra il contenuto
less file.c            # mostra a pagine (q per uscire)
head -n 10 file.c      # mostra le prime 10 righe

# Compilazione ed esecuzione
gcc hello.c -o hello   # compila
./hello                # esegui
./hello > output.txt   # reindirizza l'output su file
./hello < input.txt    # leggi input da file

# Varie utili
clear                  # pulisce lo schermo
history                # mostra i comandi precedenti
man gcc                # manuale di gcc (q per uscire)
which gcc              # dove si trova gcc

🌐 Compilatori Online

Se non vuoi installare nulla subito, puoi iniziare con un compilatore online:

Godbolt β€” compiler-explorer.com

Il migliore. Mostra anche l'assembly generato. Supporta C, C++, e decine di compilatori.

onlinegdb.com

Compilatore online con debugger integrato. Ottimo per i principianti.

replit.com

IDE online completo. Puoi creare progetti e condividere il codice.

ideone.com

Semplice e veloce. Supporta C, C++ e molti altri linguaggi.

🎯 Verifica Finale β€” Il Tuo Primo Programma

Segui questi passi per verificare che tutto funzioni:

BashPasso 1 β€” crea la cartella di lavoro
mkdir ~/programmazione-c
cd ~/programmazione-c
CPasso 2 β€” scrivi hello.c (con nano, vim o VS Code)
#include <stdio.h>

int main() {
    printf("======================\n");
    printf(" L'ambiente funziona!\n");
    printf("======================\n");
    printf("GCC e' installato correttamente.\n");
    return 0;
}
BashPasso 3 β€” compila ed esegui
gcc -Wall hello.c -o hello
./hello
Output atteso
======================
 L'ambiente funziona!
======================
GCC e' installato correttamente.
Se vedi errori di compilazione Gli errori di GCC sono nel formato file.c:riga:colonna: errore: messaggio. Leggi sempre il primo errore: spesso tutti gli altri sono conseguenza di uno solo. Dopo aver corretto, ricompila.

πŸ“ Struttura di un Progetto C

BashStruttura raccomandata per progetti piccoli/medi
mio-progetto/
β”œβ”€β”€ src/            # Codice sorgente (.c)
β”‚   β”œβ”€β”€ main.c
β”‚   β”œβ”€β”€ utils.c
β”‚   └── lista.c
β”œβ”€β”€ include/        # Header file (.h)
β”‚   β”œβ”€β”€ utils.h
β”‚   └── lista.h
β”œβ”€β”€ bin/            # Eseguibile compilato (gitignored)
β”œβ”€β”€ obj/            # File oggetto .o (gitignored)
β”œβ”€β”€ test/           # Test automatici
β”œβ”€β”€ Makefile        # Script di build
└── README.md       # Documentazione
MakefileMakefile base per progetti C
CC      = gcc
CFLAGS  = -Wall -Wextra -std=c17 -g
SRC     = $(wildcard src/*.c)
OBJ     = $(SRC:src/%.c=obj/%.o)
TARGET  = bin/programma

all: dirs $(TARGET)

$(TARGET): $(OBJ)
	$(CC) $(OBJ) -o $@ -lm

obj/%.o: src/%.c
	$(CC) $(CFLAGS) -Iinclude -c $< -o $@

dirs:
	mkdir -p bin obj

clean:
	rm -rf obj bin

run: all
	./$(TARGET)

.PHONY: all clean run dirs
BashUso del Makefile
make         # Compila tutto
make run     # Compila e lancia
make clean   # Pulisce i file generati

πŸ“„ Header File (.h) β€” Separare Dichiarazioni e Implementazioni

Quando il progetto cresce, dividi il codice in piΓΉ file. Gli header file contengono le dichiarazioni (prototipi, struct, costanti), i file .c contengono le implementazioni.

Cinclude/math_utils.h
// Include guard: evita inclusioni multiple
#ifndef MATH_UTILS_H
#define MATH_UTILS_H

// Dichiarazioni delle funzioni
double potenza(double base, int esp);
double radice_quadrata(double n);
int    fattoriale(int n);
int    mcd(int a, int b);
int    mcm(int a, int b);

// Costanti
#define PI     3.14159265358979323846
#define E_NATU 2.71828182845904523536

#endif // MATH_UTILS_H
Csrc/math_utils.c
#include "math_utils.h"   // Include il proprio header
#include <math.h>

double potenza(double base, int esp) {
    if (esp == 0) return 1.0;
    if (esp < 0)  return 1.0 / potenza(base, -esp);
    return base * potenza(base, esp - 1);
}

double radice_quadrata(double n) {
    if (n < 0) return -1.0;  // Errore
    return sqrt(n);
}

int fattoriale(int n) {
    if (n <= 1) return 1;
    return n * fattoriale(n - 1);
}

int mcd(int a, int b) { return b == 0 ? a : mcd(b, a % b); }
int mcm(int a, int b) { return a / mcd(a, b) * b; }  // Evita overflow
Csrc/main.c
#include <stdio.h>
#include "math_utils.h"

int main() {
    printf("2^10 = %.0f\n", potenza(2.0, 10));
    printf("sqrt(144) = %.1f\n", radice_quadrata(144));
    printf("10! = %d\n", fattoriale(10));
    printf("MCD(48,18) = %d\n", mcd(48, 18));
    printf("MCM(4,6) = %d\n", mcm(4, 6));
    return 0;
}
BashCompilare con piΓΉ file
gcc -Wall -Iinclude src/main.c src/math_utils.c -o programma -lm
πŸ‹οΈ Esercizi di Setup
Verifica che il tuo ambiente funzioni correttamente.
1
Verifica l'installazione
FacileSetup

Apri il terminale e verifica che gcc, g++ e make siano installati correttamente. Stampa le loro versioni. Poi crea una cartella ~/esercizi-c e al suo interno crea il file hello.c che stampi la tua versione di GCC nel programma (usa __VERSION__ e __STDC_VERSION__).

C
#include <stdio.h>

int main() {
    printf("GCC version:  %s\n", __VERSION__);
    printf("C Standard:   %ld\n", __STDC_VERSION__);
    printf("Compilato il: %s alle %s\n", __DATE__, __TIME__);
    printf("File:         %s\n", __FILE__);
    return 0;
}
2
Leggi gli errori del compilatore
FacileErrori

Scrivi intenzionalmente questo codice con 5 errori e prova a compilarlo. Poi leggi i messaggi di GCC e correggi uno alla volta. Il codice: dimentica il ; finale di printf, usa = invece di == in un if, dimentica di includere stdio.h, chiama una funzione inesistente, dimentica le parentesi del main.

C
/* File con errori intenzionali β€” da compilare per vedere i messaggi */

// ERRORE 1: manca #include <stdio.h>

int main() {          // OK
    int x = 5;
    printf("x vale %d\n", x)  // ERRORE 2: manca ;

    if (x = 5) {              // ERRORE 3: = invece di ==
        printf("cinque\n");
    }

    funzione_inesistente();   // ERRORE 4: funzione non dichiarata

    return 0;
}

/* Dopo aver visto gli errori, ecco la versione corretta: */
#include <stdio.h>

int main() {
    int x = 5;
    printf("x vale %d\n", x);
    if (x == 5) {
        printf("cinque\n");
    }
    return 0;
}
3
Progetto multi-file
MedioHeader / Makefile

Crea un progetto con la struttura src/, include/, bin/. Definisci un header stringhe.h con 3 funzioni su stringhe (conta vocali, capovolgi, conta parole). Implementale in stringhe.c. Usale in main.c. Scrivi un Makefile per compilare tutto.

C
/* include/stringhe.h */
#ifndef STRINGHE_H
#define STRINGHE_H
int  conta_vocali(const char *s);
void capovolgi(char *s);
int  conta_parole(const char *s);
#endif

/* src/stringhe.c */
#include "stringhe.h"
#include <string.h>
#include <ctype.h>

int conta_vocali(const char *s) {
    int n = 0;
    for (; *s; s++)
        if (strchr("aeiouAEIOU", *s)) n++;
    return n;
}

void capovolgi(char *s) {
    char *inizio = s, *fine = s + strlen(s) - 1;
    while (inizio < fine) { char t=*inizio; *inizio++=*fine; *fine--=t; }
}

int conta_parole(const char *s) {
    int parole = 0, in_parola = 0;
    for (; *s; s++) {
        if (isspace(*s)) in_parola = 0;
        else if (!in_parola) { parole++; in_parola = 1; }
    }
    return parole;
}

/* src/main.c */
#include <stdio.h>
#include "stringhe.h"

int main() {
    char s[] = "Hello World Ciao";
    printf("Vocali: %d\n", conta_vocali(s));
    printf("Parole: %d\n", conta_parole(s));
    capovolgi(s);
    printf("Capovolta: %s\n", s);
    return 0;
}
4
Usa AddressSanitizer
DifficileSanitizer / Debug

Scrivi un programma con questi 3 bug di memoria: 1) accesso fuori da array, 2) uso di variabile non inizializzata, 3) memory leak (malloc senza free). Compilalo con -fsanitize=address,undefined e leggi gli output. Poi correggili.

C
/* buggy.c β€” DA COMPILARE CON: gcc -g -fsanitize=address,undefined buggy.c -o buggy */
#include <stdio.h>
#include <stdlib.h>

int main() {
    // BUG 1: Accesso fuori dall'array
    int arr[5] = {1, 2, 3, 4, 5};
    // printf("%d\n", arr[10]);   // Decommentare per vedere il bug

    // BUG 2: Variabile non inizializzata
    // int x; printf("%d\n", x); // Comportamento indefinito

    // BUG 3: Memory leak
    int *p = malloc(100 * sizeof(int));
    p[0] = 42;
    // free(p);  // Manca questo!

    /* VERSIONE CORRETTA: */
    int arr2[5] = {1, 2, 3, 4, 5};
    printf("%d\n", arr2[4]);   // Ultimo elemento valido

    int y = 0;
    printf("%d\n", y);         // Inizializzato

    int *p2 = malloc(100 * sizeof(int));
    p2[0] = 42;
    free(p2);                  // Liberato!
    p2 = NULL;

    return 0;
}