Année universitaire 2002-2003
espace

Licence d'informatique
Module 4 - partie "C / shell"



Travaux dirigés 4 :

  • 1. Pointeurs.
  • 2. Différents types de pointeurs.
  • 3. Exercice 1 : valeurs d'un tableau.
  • 4. Quelques remarques sur les pointeurs.
  • 5. Passage de paramètres.
  • 6. Exercice 2 : permutation de valeurs.
  • 7. Chaînes de caractères.
  • 8. Exercice 3 : longueur d'une chaîne.

  • 1. Pointeurs.

    La mémoire est découpée en octets. Chaque octet est repéré par son numéro d'ordre, ou adresse. Un pointeur "pointe" vers un octet en indiquant son adresse. En pratique, un pointeur est une variable qui contient une valeur de type "adresse" (qui est un type numérique entier correspondant au spécificateur de format %p). Une variable est un pointeur si et seulement si son nom est précédé, lors de sa déclaration, d'un ou de plusieurs caractères * (lesquels caractères ne font pas partie du nom de la variable).

    La manipulation des pointeurs nécessite une bonne maîtrise des deux opérateurs suivants :

    Exemple :

    int a,b=0; /* À l'exécution, on suppose que le système
         alloue un espace mémoire à la variable b, situé
         par exemple à l'adresse 20000 */
    int *p;    /* La variable p peut contenir l'adresse d'un entier.
         Réservation en mémoire d'une zone pour stocker
         cette adresse. À ce moment-là de l'exécution,
         la variable p n'est pas initialisée. */
    p=&b;      /* La variable p pointe vers la zone où est stockée
         la variable b. À ce moment-là de l'exécution :
         p == 20000 */
    a=*p;      /* La variable a prend la valeur logée à l'adresse
         20000, soit 0 */

    Remarques :

    Attention :

    Les valeurs de type "adresse" sont représentées graphiquement par des flèches qui désignent l'objet pointé, excepté la valeur NULL qui doit apparaître en toutes lettres.

    Exemple :

    image 2

    2. Différents types de pointeurs.

    La taille de la zone mémoire pointée par un pointeur est donnée par le type de l'objet pointé. Par exemple, si on a la déclaration suivante :

    alors ch est un pointeur vers une zone de 8 bits en mémoire. Dès lors, l'adresse de l'octet situé immédiatement après est ch+1. En incrémentant ch, il est ainsi possible de parcourir la mémoire d'octet en octet. Un pointeur p déclaré par short *p; pointe sur une zone pouvant contenir un entier court (codé sur 16 bits). En incrémentant p, on balaye la mémoire de 16 bits en 16 bits :

    Balayage de la mémoire

    3. Exercice 1.

    Soit la séquence :

    À l'aide d'une représentation graphique, indiquer les modifications apportées au tableau tab par la séquence d'instructions suivante, et ce après chaque instruction :

    4. Quelques remarques sur les pointeurs.

    5. Passage de paramètres.

    À la préparation de l'appel d'une fonction, une copie est faite de chaque paramètre. Tous les passages de paramètres sont strictement faits par valeur. Une fonction peut changer la valeur de la copie des paramètres, mais ces changements ne modifient pas la valeur des paramètres de départ. Cependant, il est possible de passer en paramètre un pointeur vers une zone mémoire où la fonction opérera des modifications. Ainsi, lorsqu'on passe un tableau en paramètre, on crée en fait une variable de type "pointeur" permettant d'accéder aux zones de la mémoire où sont rangés les éléments du tableau. Il existe donc deux différences importantes entre la variable de type "tableau" déclarée par int tab1[3] et le paramètre de type "tableau" déclaré par int tab2[] :

    Exemple :

    #include <stdio.h>

    void lecture_int_C_correcte(int *p_a)
    {
    scanf("%d",p_a);
    (*p_a)++;
    }

    int main(void)
    {
    int a=0;
    lecture_int_C_bis(&a);
    printf("%d\n",a);
    return(0);
    }

    6. Exercice 2.

    Écrire une fonction qui permute le contenu de deux variables entières, ainsi qu'un exemple d'appel à cette fonction.

    7. Chaînes de caractères.

    Une chaîne de caractères en C est forcément du type "pointeur de caractère". Le dernier caractère, qui indique la fin de la chaîne, doit toujours être le caractère \0, de code ASCII nul. Il existe deux manières de définir une chaîne de caractères :

    7.1. Définition d'une chaîne de caractères à l'aide d'un tableau de caractères.

    Syntaxe :

    Dans ce cas, nom_chaîne1 est une adresse de caractère et ne peut donc pas apparaître dans le membre gauche d'une affectation (c'est l'adresse d'une zone mémoire de TAILLE_CHAINE octets). On dit dans ce cas que l'espace mémoire nécessaire au stockage des caractères de la chaîne est réservé "statiquement". Pour stocker des caractères (composant une chaîne) dans cette zone mémoire réservée, si ces caractères sont tapés au clavier par l'utilisateur, on peut se servir des fonctions getchar ou scanf, déjà vues à plusieurs reprises :

    7.2. Définition d'une chaîne de caractères à l'aide d'un pointeur de caractère.

    Syntaxe :

    Dans ce cas, la variable nom_chaîne2 est un pointeur de caractère, qui peut apparaître dans le membre gauche d'une affectation, mais qui ne pointe pas vers une zone mémoire réservée. On verra dans la séance 5 de travaux dirigés quelle fonction permet de réserver une zone mémoire d'une certaine taille, et d'affecter l'adresse de cette zone à la variable nom_chaîne2. On dira dans ce cas que l'espace mémoire nécessaire au stockage des caractères de la chaîne est réservé "dynamiquement".

    8. Exercice 3.

    Écrire une fonction qui retourne la longueur d'une chaîne de caractères. Écrire un programme principal initialisant la chaîne de caractères (déclarée sous la forme d'une variable de type "tableau de caractères") et appelant cette fonction.


    Ces pages ont été réalisées par A. Crouzil, J.D. Durou et Ph. Joly.
    Pour tout commentaire, envoyer un mail à crouzil@irit.fr, à durou@irit.fr ou à Philippe.Joly@irit.fr.