Vai al contenuto
Fondamenti di Informatica

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 sta printf.
  • main è la funzione da cui parte l’esecuzione. Restituisce un int: 0 dice al sistema operativo che tutto è andato bene.
  • Le graffe delimitano un blocco; ogni istruzione termina con il punto e virgola.
  • \n nella 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.

TipoDimensione tipicaContenuto
char1 bytecarattere o piccolo intero
int4 byte (2 su alcuni microcontrollori)intero con segno
long long8 byteintero con segno grande
float4 bytevirgola mobile, circa 7 cifre
double8 bytevirgola 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 / 2 vale 3, 7 % 2 vale 1. Per avere 3,5 almeno un operando deve essere reale: 7.0 / 2.
  • Di assegnamento: =, e le forme abbreviate +=, -=, *=; i++ aumenta i di 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 usare bool, true e false).
  • Logici: && (e), || (o), ! (non). Sono valutati “in corto circuito”: in b != 0 && a / b > 2 la divisione non viene eseguita se b è 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.

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
0
Would love your thoughts, please comment.x
()
x