Première séance

Durant cette première séance, nous allons écrire de petits programmes qui écrivent dans le terminal. Le but est d'apprendre :

  • à compiler un seul fichier C (un seul fichier pour l'instant !)
  • écrire un programme C sans pointeur

Header files

Des fichiers comme stdio.h sont dans usr/include. Ils contiennent des signatures de fonctions. Ils font partie de la bibliothèque standard. Mais on peut aussi en créer, ou utiliser ceux d'une bibliothèque non-standard (comme raylib pour dessiner à l'écran !).

Entrées-sorties

stdio.h est le fichier pour de la bibliothèque standard (std) pour les entrées-sorties (io).

Pour utiliser ces fonctions, on écrit :

      #include <stdio.h>

Ecrire sur la sortie stdout

putchar('c') écrit un c dans le terminal.

printf est la fonction pour écrire d'un coup des informations plus compliquées ✎ :

    printf("Bonjour");
    printf("Bonjour\n");

    printf("Voici votre identifiant : %d", id);
    printf("Voici votre nouveau prénom : %s", prenom);
    printf("Voici votre nouveau prénom et votre identifiant : %s %d", prenom, id);

⚠ Ne jamais écrire printf(dataFromTheUser) car l'utilisateur pourrait écrire des %s, %d, voire des %n qui écrivent dans la mémoire. Le comportement peut être inattendu, et c'est faille de sécurité garantie :).

Lire l'entrée stdin

getchar() renvoie le prochain caractère sur l'entrée puis le consomme, c'est-à-dire que la prochaine fois que l'on exécute getchar() on lira le prochain caractère. getchar() renvoie EOF si c'est fini.

scanf est la fonction pour lire des informations plus compliquées que l'utilisateur écrit dans la console ou de manière générale dans stdin ⌨ :

    int n;
    scanf("%d", &n);

Quelques éléments du langage C

Une déclaration de variable est un morceau de code qui renseigne le type d'une variable. Par exemple :

    int x;

Il y a pleins de types primitifs : int, long, unsigned int, char, bool (avec #include <stdbool.h>).

Une instruction est un morceau du programme qui ne renvoie rien. Par exemple, printf("aïe");

Une expression est un morceau du programme qui renvoie une valeur. Par exemple 1+2. Mais aussi x = 42 qui renvoie... 42.

Incrémentation

Considérons l'instruction (qui est aussi une expression)

    x = 42;
  • Both expressions x++ and ++x increment x.
  • The value of the expression x++ is 42.
  • The value of expression ++x is 43.

L'instruction (qui est aussi une expression) suivante

    x += 3;

ajoute 3 à x.

Boucle for

    for(int i = 0; i < n; i++)
        ...


    for(int i = 0; i < n; i++) {
        ...
    }

En fait, la boucle for en C est puissante. Elle a l'expressivité des boucles while :

    for(expr1; expr2; expr3) {
        ...
    }

est équivalent à

    expr1;
    while(expr2) {
        ...
        expr3;
    }

La fonction main

Un programme C contient toujours une fonction main qui est la fonction appelée quand on exécute le programme :

    #include <stdlib.h>

    int main() {
        ...
        return EXIT_SUCCESS;
    }

On verra plus tard une signature plus compliquée pour main car on peut gérer des arguments donnés au programme.

Utilisation du compilateur

gcc -Wall -pedantic -ainsi -std=c99 programme.c -o programme
OptionsMeaning
-Wallenables all compiler's warning messages
-Wextrastill a bit more warnings
-pedanticenables all compiler's warning messages
-ansiturns off gcc features that are not in the ANSI C
-std=c99ANSI C99
-std=c11ANSI C99
-o programmetells that the output is the file programme

Exercices

Triangle d'étoiles

Ecrire un programme qui prend demande à l'utilisateur/rice un nombre entier n puis affiche un triangle d'étoiles sur n lignes. Par exemple si n vaut 5, on affiche :

*
** 
***
****
*****

Pyramide

Même chose avec une pyramide :

   *
  *** 
 *****
*******

Nombre de caractères dans le texte sur stdin

En utilisant getchar(), écrire un programme nombreligne.c qui lit stdin et sur donne le nombre de lignes dans l'entrée.

Par exemple sur

    ./nombreligne < textExemple.txt

il donne le nombre de lignes dans le fichier texte textExemple.txt.

  • Pareil avec le nombre de lignes
  • Pareil avec le nombre de mots

Occurrences de caractères

Dans cet exercice, vous aurez besoin d'un tableau d'entiers de taille 26 déclaré avec int A[26];. On accède au i-ème élément du tableau A avec A[i]. On rappelle que chaque caractère est un nombre entre 0 et 255, codé sur 8 bits. Si c est un char, on peut écrire c - 'a' pour faire la différence entre le code de c et celui de la lettre 'a'.

Ecrire un programme qui lit stdin et qui affiche un histogramme du nombre des occurrences des lettres (on ignore les autres caractères, les chiffres, etc.) comme :

    a ***
    b ******
    c **
    d *
    e ************
    z ***

Variables

La portée (scope) d'une variable est la portion de code dans laquelle la variable peut être utilisée.

La durée de vie (life-time) d'une variable est la durée d'existence d'une variable.

ScopeLife-time
Global variablesAllAlways
Variables in functionsFunctionFunction
Static variables in functionsFunctionAlways

Les variables statiques peuvent servir pour :

  • faire un compteur et cacher le contenu du compteur en dehors
  • faire une fonction pour le drag drop avec la souris (on stocke/cache la position précédente de la souris)

Mémoire

La mémoire allouée pour un programme est divisée en trois parties :

  • Segment de données. On y trouve les variables globales et les variables statiques.
  • Pile d'appels. On y trouve les variables locales à une fonction. Les tableaux locaux sont stockées sur la pile aussi.
  • Le tas mémoire. C'est pour y mettre des données dont on ne connait pas à l'avance la taille, ou dont la taille peut modifiée au cours du programme (structure de données comme des tableaux redimensionnables, des listes chaînées, etc.).

Typage en C

Le type en C sert à dire combien d'octets prend une variable.

La fonction sizeof renvoie combien d'octets sont utilisé pour stocker un certain type / une certaine variable.

sizeof(truc)utilise ... octets
sizeof(char)1
sizeof(int)4
    int x;
    printf("%d\n", sizeof(x));
    
    int A[5];
    printf("%d\n", sizeof(A));

Conversion implicite

    1 + 2.3f

Casting

    int i = 2;
    int j = 3;
    float quotient = 2/3;

Oh non, quotient vaut 0. Mais on peut caster :

    quotient = ((float) 2) / 3

Le C est de bas niveau...

Voici un site où on peut compiler du code C et voir le résultat en assembleur :

https://godbolt.org/

Exercices

Génération de labyrinthes

Proposer un algorithme aléatoire pour générer un labyrinthe comme

XXXXXXXXXXXXXXX
X X     X     X
X XXX X X X XXX
X X   X X X   X
X X XXXXX XXX X
X X   X     X X
X X X X XXXXX X
X X X X X   X X
X XXX X X X X X
X X   X X X   X
X X XXX X XXX X
X X     X X X X
X XXXXXXX X X X
X         X   X
XXXXXXXXXXXXXXX

Il s'agit de produire un tableau A 2D de taille n x m où n et m sont des entiers impairs avec :

  • A[i, j] = 'X' ou ' '
  • A[0, j], A[i, 0], A[n-1, j], A[i, m-1] contiennent 'X' ;
  • A[i, j] = 'X' lorsque i et j sont pairs
  • A[i, j] = ' ' lorsque i et j sont impairs
  • Le graphe G est un arbre, où G est le graphe non orienté (V, E) où V sont les couples (i, j) dans {1, 3, .., n-2} x {1, 3, ..., m-2} et E contient les arêtes {(i, j), (i', j')} avec :
  • i' == i+2 et j'== j et A[i+1, j] == ' '
  • ou i' == i et j' == j+1 et A[i, j+1] == ' '

Prochaine séance

Nous allons utiliser la bibliothèque raylib pour pouvoir afficher des dessins (rectangles, points, lignes, etc.) à l'écran :).

  • Jeu vidéo comme agar.io
  • Afficher une fractale comme celle de mandelbrot
  • Promenade aléatoire
  • Appartenance d'un point à un polygone ?
  • parcours de Graham

Pour aller plus loin