Il linguaggio C: primo programma, tipi, variabili, operatori, ingresso e uscita
Struttura di un programma C e compilazione, tipi e variabili, operatori aritmetici, logici e di confronto, conversioni, printf e scanf con un esempio sulle resistenze.
Il C, creato da Dennis Ritchie ai Bell Labs tra il 1969 e il 1973 per scrivere il sistema operativo Unix, è ancora oggi il linguaggio dei sistemi operativi, dei driver, del firmware e di quasi tutti i microcontrollori. È piccolo, veloce e vicino all’hardware, e proprio per questo richiede disciplina: il compilatore controlla poco e lascia al programmatore la responsabilità della memoria. In questa lezione scriviamo i primi programmi: struttura, tipi, variabili, operatori, ingresso e uscita.
Il primo programma
#include <stdio.h>
int main(void)
{
printf("Ciao, mondo!\n");
return 0;
}
#include <stdio.h>chiede al preprocessore di includere le dichiarazioni della libreria standard di ingresso e uscita, dove staprintf.mainè la funzione da cui parte l’esecuzione. Restituisce unint: 0 dice al sistema operativo che tutto è andato bene.- Le graffe delimitano un blocco; ogni istruzione termina con il punto e virgola.
\nnella stringa è il carattere di ritorno a capo.
Si compila e si esegue con gcc ciao.c -o ciao e ./ciao. Conviene sempre attivare gli avvisi, gcc -Wall -Wextra: molti errori del C sono segnalati solo come avvisi.
Tipi e variabili
Ogni variabile ha un tipo, che stabilisce quanti byte occupa e come si interpretano i bit, e va dichiarata prima dell’uso.
| Tipo | Dimensione tipica | Contenuto |
|---|---|---|
char | 1 byte | carattere o piccolo intero |
int | 4 byte (2 su alcuni microcontrollori) | intero con segno |
long long | 8 byte | intero con segno grande |
float | 4 byte | virgola mobile, circa 7 cifre |
double | 8 byte | virgola mobile, circa 16 cifre |
Con unsigned si ottengono le versioni senza segno. sizeof(tipo) dice quanti byte occupa un tipo su quel sistema.
int n = 10; /* dichiarazione con inizializzazione */
double v = 3.3;
char c = 'A'; /* tra apici singoli: un carattere, cioè il numero 65 */
const double PI = 3.14159265358979; /* costante: non si può modificare */
Attenzione: una variabile locale non inizializzata contiene un valore casuale, quello che c’era prima in quella zona di memoria. Usarla prima di assegnarle un valore è un errore che il compilatore non sempre segnala.
Gli operatori
- Aritmetici:
+ - * /e%(resto). Tra interi la divisione tronca:7 / 2vale 3,7 % 2vale 1. Per avere 3,5 almeno un operando deve essere reale:7.0 / 2. - Di assegnamento:
=, e le forme abbreviate+=,-=,*=;i++aumentaidi uno. - Di confronto:
== != < > <= >=. Danno 1 (vero) o 0 (falso): in C non c’è un tipo booleano di base, e ogni valore diverso da zero è vero (con<stdbool.h>si possono usarebool,trueefalse). - Logici:
&&(e),||(o),!(non). Sono valutati “in corto circuito”: inb != 0 && a / b > 2la divisione non viene eseguita sebè zero.
L’errore classico è scrivere if (x = 5) invece di if (x == 5): il primo assegna 5 a x e la condizione è sempre vera. Con -Wall il compilatore avvisa.
Conversioni. In un’espressione con tipi diversi, il tipo “più piccolo” viene convertito in quello “più grande”: in n * 2.5 l’intero n diventa double. Assegnando un reale a un intero la parte decimale si perde: int k = 3.9; vale 3. Si può convertire esplicitamente con un cast: (double)somma / n.
Ingresso e uscita
printf stampa con un formato, in cui gli specificatori % indicano dove e come inserire i valori: %d intero, %u senza segno, %f reale, %c carattere, %s stringa, %x esadecimale. %.2f stampa due decimali, %5d occupa almeno cinque caratteri.
scanf legge dalla tastiera con lo stesso formato, ma vuole l’indirizzo della variabile, ottenuto con & (vedremo il perché nella lezione sui puntatori):
#include <stdio.h>
int main(void)
{
double r1, r2;
printf("Valori delle due resistenze in ohm: ");
if (scanf("%lf %lf", &r1, &r2) != 2) { /* scanf restituisce quanti valori ha letto */
printf("Ingresso non valido\n");
return 1;
}
double serie = r1 + r2;
double parallelo = r1 * r2 / (r1 + r2);
printf("Serie: %.1f ohm, parallelo: %.1f ohm\n", serie, parallelo);
return 0;
}
Con 1000 e 2200 il programma stampa “Serie: 3200.0 ohm, parallelo: 687.5 ohm”. Notare %lf per leggere un double con scanf, mentre con printf basta %f, e il controllo del valore restituito da scanf: un programma robusto non si fida mai dell’ingresso.
Lo stile conta
Un programma si scrive una volta e si legge molte volte, spesso da qualcun altro. Nomi di variabili che dicono cosa contengono (tensione_mV invece di x), indentazione coerente, commenti che spiegano il perché e non il cosa, funzioni brevi. Il compilatore ignora tutto questo; chi deve correggere un bug alle due di notte no.




