Skip to content
Snippets Groups Projects

% Programmation séquentielle en C % Base II - Inspirés des slides de F. Glück % 25 septembre 2019

Les fonctions (1/N)

  • Chaque partie indépendante d'un programme se met dans une fonction.

  • Syntaxe:

    type identificateur(paramètres) { // variables optionnelles
        instructions;
        return expression; // type donne le type d'expression
    }
  • Exemple:

    int max(int a, int b) {
        if (a > b) {
            return a;
        } else {
            return b;
        }
    }
    
    int main() {
        int c = max(4, 5);
    }

Les fonctions (2/N)

  • Il existe un type void{.C}, "sans type", en C.

  • Il peut être utilisé pour signifier qu'une fonction ne retourne rien, ou qu'elle n'a pas d'arguments.

  • return{.C} utilisé pour sortir de la fonction.

  • Exemple:

    void show_text(void) { // second void optionnel
        printf("Aucun argument et pas de retour.\n");
        return; // optionnel
    }
    
    void show_text_again() { // c'est pareil
        printf("Aucun argument et pas de retour.\n");
    }

Les fonctions (3/N)

Prototypes de fonctions

  • Le prototype donne la signature de la fonction, avant qu'on connaisse son implémentation.

  • L'appel d'une fonction doit être fait après la déclaration du prototype.

    int max(int a, int b); // prototype
    
    int max(int a, int b) { // implémentation
        if (a > b) {
            return a;
        } else {
            return b;
        }
    }

Les fonctions (4/N)

Arguments de fonctions

  • Les arguments d'une fonction sont toujours passés par copie.

  • Les arguments d'une fonction ne peuvent jamais être modifiés.

    void set_to_two(int a) { // a est une nouvelle variable
        // la valeur de a une copie de celle passée en argument
        // lorsque la fonction est appelée, ici -1
    
        a = 2; // la valeur de a est fixée à 2
    } // a est détruite
    
    int main() {
        int x = -1;
        set_to_two(x); // -1 est passé en argument
        // x vaudra toujours -1 ici
    }

Les fonctions (5/N)

Arguments de fonctions: pointeurs

  • Pour modifier un variable, il faut passer son adresse mémoire.

  • L'adresse d'une variable, x{.C}, est accédé par &x{.C}.

  • Un pointeur vers une variable entière a le type, int *x{.C}.

  • La sytaxe *x{.C} sert à déréférencer le pointeur.

    void set_to_two(int *a) { 
        // a contient une copie de l'adresse de la
        // variable passée en argument
    
        *a = 2; // on accède à la valeur pointée par a,
                // et on lui assigne 2
    } // le pointeur est détruit, pas la valeur pointée
    int main() {
        int x = -1;
        set_to_two(&x); // l'adresse de x est passée
        // x vaudra 2 ici
    }

La fonction main() (1/N)

Généralités

  • Point d'entrée du programme.
  • Retourne le code d'erreur du programme:
    • 0: tout s'est bien passé.
    • Pas zéro: problème.
  • La valeur de retour peut être lue par le shell qui a exécuté le programme.
  • EXIT_SUCCESS{.C} et EXIT_FAILURE{.C} (de stdlib.h) sont des valeurs de retour portables de programmes C.

La fonction main() (2/N)

Exemple

int main() {
    // ...
    if (error)
	    return EXIT_FAILURE;
    else
	    return EXIT_SUCCESS;
}
  • Le code d'erreur est lu dans le shell avec $?{.bash}
$ ./prog
$ echo $?
0 # tout s'est bien passé par exemple
$ if [ $? -eq 0 ]; then echo "OK" ; else echo "ERROR"; fi
ERROR # si tout s'est mal passé

Les tableaux (1/N)

Généralités

  • C offre uniquement des tableaux statiques
    • Un tableau est un "bloc" de mémoire contigüe associé à un nom
      • taille fixe déterminée à la déclaration du tableau
      • la taille ne peut pas être changée.
    • Pas d’assignation de tableaux.
    • Un tableau déclaré dans une fonction ou un bloc est détruit à la sortie de celle/celui-ci
      • \Rightarrow Un tableau local à une fonction ne doit jamais être retourné (aussi valable pour toute variable locale)!
  • Les éléments d’un tableau sont accédés avec [i]{.C} où i{.C} est l’index de l’élément.
  • Le premier élément du tableau à l’index 0{.C}!
  • Lorsqu’un tableau est déclaré, la taille de celui-ci doit toujours être spécifiée, sauf s’il est initialisé lors de sa déclaration.

Les tableaux (2/N)

Exemple

float tab1[5]; // tableau de floats à 5 éléments
               // ses valeurs sont indéfinies

int tab2[] = {1, 2, 3}; // tableau de 3 entiers

int val = tab2[1]; // val vaut 2 à présent

int w = tab1[5]; // index hors des limites du tableau
                 // comportement indéfini!
                 // pas d'erreur du compilateur

Les tableaux (3/N)

Les tableaux comme argument

  • Un tableau n'est rien d'autre que le pointeur vers sa première case.

  • Pas moyen de connaître sa taille: sizeof(){.C} inutile.

  • Quand on passe un tableau en argument à une fonction: toujours spécifier sa taille.

    void foo(int tab[]) { // sans taille...
        for (int i = 0; i < ?; ++i) { // on sait pas
            printf("tab[%d] = %d\n", i, tab[i]);
        }
    }
    // avec taille, [n] pas obligatoire
    void bar(int tab[n], int n) {
        for (int i = 0; i < n; ++i) {
            printf("tab[%d] = %d\n", i, tab[i]);
        }
    }