Concepts avancés du langage C


précédentsommairesuivant

I. Compléments et rappels

I-A. Les différentes classes de variable

Une variable déclarée à l'intérieur d'un bloc est appelée une variable locale. Elle n'est connue qu'à l'intérieur de ce bloc. On dit que sa visibilité est limitée à ce bloc. Les arguments effectifs d'une fonction sont également des variables locales à cette fonction.

Une variable déclarée à l'extérieur de tout bloc (donc de toute fonction) est dite globale. Elle est donc visible de puis n'importe quelle fonction définie (dans le même fichier source !) après sa déclaration. L'utilisation des variables globales réduit la lisibilité du code. Ne les utilisez que lorsque cela est vraiment nécessaire.

Une variable globale est dite permanente (ou statique). Cela signifie que la mémoire utilisée par cette variable est valide pendant toute la durée d'exécution du programme. Elle ne perd donc jamais sa valeur.

A l'opposé les variables locales sont par défaut automatiques. Leur durée de vie est égale au temps d'exécution du bloc. On peut rendre une variable locale permanente à l'aide du mot-clé static. Par exemple :

 
Sélectionnez
#include <stdio.h>

void f(void);

int main()
{
    f();
    f();
    f();
    
    return 0;
}

void f()
{
    static int i = 100;
    
    printf("i = %d\n", i);
    i++;
}

Dans cet exemple, i est une variable statique (permanente) initialisée à 100. La mémoire utilisée par i est donc allouée avant même que le programme ne s'exécute et non à chaque appel de la fonction. Son contenu est initialisé à 100. Seulement, puisqu'elle a été déclarée dans f, elle ne sera connue que dans f. Mais i est tout sauf une variable « locale » (plus précisément : une variable automatique) à la fonction (f).

Au premier appel de f, on a donc i = 100 (puisqu'elle a été initialisée avec la valeur 100, avant même l'exécution du programme). Au deuxième appel, i = 101 et au troisième appel, i = 102.

I-B. Les expression constantes

Une expression constante est une expression dont la valeur peut être connue sans qu'on ait même à exécuter le programme. Par exemple les constantes littérales, l'adresse d'une variable statique, etc. sont des expressions constantes. Une expression constante peut également être composée, par exemple : 1 + 1.

Attention, une variable déclarée avec le qualificateur const est une variable, pas une expression constante !

I-C. Initialisation des variables

Le langage C permet d'initialiser une variable lors de sa déclaration.

Puisqu'une variable automatique n'est « activée » qu'au moment où l'on entre dans le bloc dans lequel elle a été déclarée, ce qui a lieu pendant l'exécution, on peut initialiser une variable automatique avec n'importe quelle expression et non forcément une expression constante.

De l'autre côté, puisque la mémoire utilisée par une variable statique est allouée avant même l'exécution, elle ne peut être initialisée qu'avec une expression constante.

Lorsqu'une variable statique est déclarée sans aucune initialisation, elle sera initialisée par le compilateur lui-même à 0. A l'opposé, le contenu d'une variable automatique déclarée sans initialisation est à priori indéterminé.

I-D. Les déclarations complexes

Nous avons déjà vu dans le tutoriel précédent comment créer de nouveaux types de données à l'aide du mot-clé typedef. On peut bien sûr exprimer un type sans l'avoir défini avec typedef. Pour obtenir le type d'un objet, il suffit de prendre sa déclaration, sans le point-virgule, et d'effacer l'identificateur. Par exemple, dans les déclarations suivantes :

 
Sélectionnez
int n;
char const * p;
double t[10];

n est de type int, p de type char const *, et t de type double [10] ( « tableau de 10 double »).

Dans le troisième cas, double [10] est bien un type, cependant un tel type ne peut pas être utilisé dans une déclaration ou dans un typedef car les crochets doivent apparaître après l'identificateur. Par contre il pourra figurer en argument de l'opérateur sizeof ou dans le prototype d'une fonction par exemple.

Certains cas sont un peu plus délicats. Par exemple pour déclarer un tableau de 10 char *, on écrira :

 
Sélectionnez
char * t[10];

t est donc de type char * [10].

Or, comme nous le savons déjà, un tableau peut être implicitement converti en un pointeur vers son premier élément. Donc dans l'exemple ci-dessus, t (qui est un tableau de char *) peut être implicitement converti en un pointeur sur char * soit char **.

Dans un cas tel que :

 
Sélectionnez
int t[5][10];
  • t est de type : int [5][10].

  • t[0], t[1], ... t[4] sont de type : int [10].

  • t est donc, pour un pointeur, un pointeur sur int [10].

Si l'on devait déclarer une variable p de ce type, on raisonnerait sans doute comme suit :

  • p est un pointeur sur un int [10]

  • *p est donc un int [10]

d'où :

 
Sélectionnez
int (*p)[10];

p est donc de type int (*)[10] !

Maintenant, en faisant :

 
Sélectionnez
p = t;

p pointe sur t[0] (qui est un tableau de 10 int). De même, p + 1 pointe sur t[1], p + 2 sur t[2] etc.

Evidemment, on peut aussi pointer sur t avec un simple int * (puisqu'un tableau, quelle que soit sa dimension, est un groupement d'objets de même type) mais cela nécessite cette fois-ci un cast et un peu plus d'habileté dans le calcul d'adresses bref, rien qui soit nouveau pour nous. C'est d'ailleurs la seule solution lorsqu'on veut passer un tableau à plusieurs dimensions à une fonction qui se veut d'être générique (en réalité, on utilisera plutôt un pointeur générique ...).


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2008 Melem. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.