Essayer de coder ← Retour aux sujets

Un programme C

main()

Un programme C est compilé : gcc transforme le fichier source en un exécutable natif, qui tourne sans interpréteur.

#include <stdio.h>
Déclare printf et scanf (entrées / sorties)
int main(void) { … }
Point d'entrée : l'exécution commence ici
return 0;
Fin normale : 0 veut dire « succès » pour le shell
printf("Bonjour\n");
Affiche du texte ; \n passe à la ligne
/* note */ // note
Commentaire sur plusieurs lignes / jusqu'à la fin de la ligne
bonjour.c
#include <stdio.h>

int main(void) {
    printf("Bonjour NSI !\n");
    return 0;
}
Affichage
Bonjour NSI !

Types et variables

int · double · char

Chaque variable a un type fixé à la déclaration : il décide de la place prise en mémoire et des valeurs possibles.

int age = 17;
Entier relatif (en général 32 bits)
double pi = 3.14159;
Réel en double précision (~15 chiffres)
float t = 36.6f;
Réel en simple précision (~7 chiffres)
char lettre = 'A';
Un caractère, entre apostrophes (stocké comme un petit entier)
const int MAX = 100;
Constante : le compilateur refuse qu'on la modifie
int a, b = 2;
Deux variables ; seule b est initialisée
types.c
#include <stdio.h>

int main(void) {
    int age = 17;
    double taille = 1.78;
    char initiale = 'L';

    printf("%c a %d ans et mesure %.2f m\n", initiale, age, taille);
    return 0;
}
Affichage
L a 17 ans et mesure 1.78 m

printf et scanf

%d %f %s

Les deux fonctions d'entrée / sortie de stdio.h utilisent des spécificateurs de format.

%d
int (entier)
%f %.2f
float / double ; %.2f = 2 décimales
%c
un caractère
%s
une chaîne de caractères
%%
le signe % lui-même
scanf("%d", &n);
Lit un entier au clavier ; &n = adresse de n
Le & de scanf

Devant une variable simple, scanf demande toujours l'adresse (&n). Sans lui, le programme écrit n'importe où en mémoire.

📘 Le cours : premiers pas en C

Le langage C (Dennis Ritchie, 1972) est à la base de nombreux systèmes : Linux, Windows en grande partie, et l'interpréteur Python lui-même sont écrits en C. Il est proche de la machine : tu gères toi-même les types et la mémoire, ce qui le rend très rapide… et exigeant.

De la source à l'exécutable

  1. Écris le code dans un fichier texte main.c.
  2. Compile : gcc -std=c11 -Wall -Wextra -o main main.c (les options -Wall -Wextra activent les avertissements utiles).
  3. Si le compilateur affiche des erreurs, corrige-les : tant qu'il y en a, aucun exécutable n'est produit.
  4. Lance le programme : ./main (Linux, macOS) ou main.exe (Windows).
main.c ──► préprocesseur ──► compilateur ──► éditeur de liens ──► main
           (#include)        (code machine)   (+ bibliothèque C)   (exécutable)
Erreur ou avertissement ?

Une erreur bloque la compilation. Un avertissement (warning) laisse compiler, mais signale presque toujours un vrai bug : traite-le comme une erreur.

Structure minimale d'un programme

  • #include <stdio.h> copie les déclarations de la bibliothèque d'entrées / sorties (indispensable pour printf).
  • int main(void) est la fonction principale ; elle renvoie un int : le code de retour donné au système (0 = tout s'est bien passé).
  • Chaque instruction se termine par un point-virgule ; ; les blocs sont entourés d'accolades { }.
  • L'indentation n'a aucun rôle pour le compilateur, mais elle rend le code lisible : indente toujours.

Les types de base

TypeContenuExempleFormat printf
charun caractère (1 octet)'A', '7'%c
intentier relatif (en général 32 bits)42, -7%d
long longgrand entier (64 bits)10000000000LL%lld
unsigned intentier positif ou nul3000000000u%u
floatréel, simple précision3.14f%f
doubleréel, double précision3.14159%f

Un entier a une taille limitée : un int sur 32 bits va de −2 147 483 648 à 2 147 483 647. Au-delà, c'est un dépassement (overflow) et le résultat est faux. C'est exactement la représentation en complément à deux du chapitre Entiers signés.

Déclarer, initialiser, affecter

Une variable se déclare avec son type. Une variable locale non initialisée contient une valeur quelconque (ce qui traînait en mémoire) : initialise-la toujours.

variables.c
#include <stdio.h>

int main(void) {
    int a = 7;      /* déclaration + initialisation */
    int b;          /* déclaration seule : b contient n'importe quoi */
    b = a * 2;      /* affectation : b vaut 14 */
    a = a + 1;      /* a vaut 8 */
    a += 2;         /* raccourci de a = a + 2 : a vaut 10 */
    a++;            /* incrémentation : a vaut 11 */
    printf("a = %d, b = %d\n", a, b);
    return 0;
}
Affichage
a = 11, b = 14

Opérateurs arithmétiques et division entière

Les opérateurs sont +, -, *, / et % (reste de la division entière). *, / et % passent avant + et - ; les parenthèses changent l'ordre. Entre deux entiers, / fait une division entière : le résultat est tronqué. Pour obtenir un réel, au moins un des deux opérandes doit être réel.

calculs.c
#include <stdio.h>

int main(void) {
    printf("%d\n", 7 / 2);             /* division entière */
    printf("%d\n", 7 % 2);             /* reste */
    printf("%.1f\n", 7 / 2.0);         /* un opérande réel */
    printf("%.1f\n", (double) 7 / 2);  /* conversion (cast) avant la division */
    return 0;
}
Affichage
3
1
3.5
3.5

Afficher avec printf

printf remplace chaque spécificateur (%d, %f…) par la valeur correspondante, dans l'ordre. Le nombre et le type des arguments doivent correspondre aux spécificateurs, sinon le résultat est faux.

SpécificateurType attenduExemple et affichage
%dintprintf("%d", 42) → 42
%5dint, sur 5 caractèresprintf("[%5d]", 42) → [ 42]
%ffloat ou doubleprintf("%f", 1.5) → 1.500000
%.2fréel, 2 décimalesprintf("%.2f", 3.14159) → 3.14
%ccharprintf("%c", 'A') → A
%schaîneprintf("%s", "NSI") → NSI
%%aucunprintf("100%%") → 100%

Lire au clavier avec scanf

scanf lit selon un format et range le résultat à l'adresse qu'on lui donne : d'où le & devant la variable. Pour un double, le format est %lf (et non %f, qui est réservé à printf).

lecture.c
#include <stdio.h>

int main(void) {
    int age;
    double taille;

    printf("Ton age ? ");
    scanf("%d", &age);
    printf("Ta taille en metres ? ");
    scanf("%lf", &taille);

    printf("Tu as %d ans et tu mesures %.2f m.\n", age, taille);
    return 0;
}
Si tu tapes 17 puis 1.78
Ton age ? 17
Ta taille en metres ? 1.78
Tu as 17 ans et tu mesures 1.78 m.

⚠️ Erreurs fréquentes

Oublier le & dans scanf

À éviter
faux.c
scanf("%d", n);   /* n est une valeur, pas une adresse */
Correct
correct.c
scanf("%d", &n);  /* &n : l'adresse de n */

Sans &, scanf écrit à une adresse prise au hasard dans la valeur de n : le programme plante ou se comporte de façon bizarre. Avec -Wall, le compilateur te prévient.

Utiliser une variable non initialisée

À éviter
faux.c
int total;
total += 5;   /* total valait n'importe quoi */
Correct
correct.c
int total = 0;
total += 5;   /* total vaut 5 */

Diviser deux entiers en espérant un réel

À éviter
faux.c
int somme = 7, n = 2;
double moyenne = somme / n;  /* 3.0 : la division est entière */
Correct
correct.c
int somme = 7, n = 2;
double moyenne = (double) somme / n;  /* 3.5 */

Confondre 'A' et "A"

'A' (apostrophes) est un caractère. "A" (guillemets) est une chaîne de deux caractères : 'A' puis le caractère de fin '\0'. Les deux ne sont pas interchangeables : char c = "A"; est une erreur.

Les accents dans printf

Selon l'encodage du terminal, printf("é") peut afficher des symboles étranges. Dans les exercices, on évite les accents dans les chaînes affichées : ça n'a aucune influence sur le calcul.

📋 Aide-mémoire

  • Compiler : gcc -std=c11 -Wall -Wextra -o programme fichier.c ; lancer : ./programme.
  • Squelette : #include <stdio.h>, int main(void) { … return 0; }.
  • / entre deux entiers = division entière ; % = reste ; (double) a / b pour un réel.
  • printf : %d entier, %f réel, %c caractère, %s chaîne. scanf : mêmes formats, %lf pour un double, et toujours & devant la variable.
  • Initialise toujours tes variables ; traite les avertissements du compilateur comme des erreurs.