FAQ CConsultez toutes les FAQ

Nombre d'auteurs : 28, nombre de questions : 175, création le 11 janvier 2013 

 
OuvrirSommairePointeurs, tableaux et chaînes de caractèresLes tableaux

'int t[] = {10, 20};' crée un tableau de 2 éléments initialisé avec les valeurs t[0] = 10 et t[1] = 20. Cette écriture est donc strictement équivalente à : 'int t[2] = {10, 20};'.

Créé le 2009-03-23  par Melem

'int t[10] = {10, 20};' crée un tableau de 10 éléments initialisé avec les valeurs t[0] = 10, t[1] = 20 et t[2] à t[9] = 0. Notez bien que la mise à 0 des éléments non initialisés d'une variable locale tableau n'a lieu que lorsqu'un élément au moins a été initialisé.

Créé le 2009-03-23  par Melem

t représente l'objet tableau, &t l'adresse de ce tableau et &(t[0]) l'adresse du premier élément du tableau. Ces trois expressions sont donc très différentes et n'ont à priori aucun point commun. Toutefois, &t et &(t[0]) représentent la même adresse, même si elles n'ont pas le même type (pour rappel, les adresses sont typées en C). t tout court quant à lui, lorsqu'il n'est pas utilisé dans sizeof ou avec l'opérateur & ("adresse de"), est toujours converti par le compilateur en &(t[0]). D'autres conversions de ce genre existent également (avec plus ou moins de conditions pour avoir lieu) et elles sont nombreuses. Ce sont ce qu'on appelle les conversions implicites.

La chose la plus importante à retenir est donc qu'une expression de type tableau (comme notre t ci-dessus, qui est de type int [10]), sauf lorsqu'elle est utilisée en unique argument de sizeof ou de l'opérateur & ("adresse de"), est toujours convertie par le compilateur en un pointeur vers son premier élément. Sinon il est reste un tableau.

Mis à jour le 2008-07-27  par Bob, Melem

Pour comprendre le sens de cette expression, il faut au moins savoir deux choses :

- Les adresses sont typées en C. Ajouter 1 à un pointeur revient à se déplacer en mémoire de la taille de la donnée pointée et non de 1 byte.

- Le nom d'un tableau (t), sauf lorsqu'il apparaît dans un sizeof ou à droite de l'opérateur & ("adresse de"), représente toujours un pointeur vers son premier élément (c'est-à-dire &(t[0])).

Le petit programme suivant devrait rendre les choses plus claires.

 
Sélectionnez
#include <stdio.h>
 
int main(void)
{
    int t[] = {10, 20, 30, 40};
    int * p = t;
 
    /* p pointe sur t[0] donc *p equivaut a t[0].                                   */
 
    printf("t[0] = %d\n", *p);
 
    /* p pointe sur t[0] donc p + 1 pointe sur t[1]. *(p + 1) equivaut donc a t[1]. */
 
    printf("t[1] = %d\n", *(p + 1));
 
    /* p pointe sur t[0] donc p + 2 pointe sur t[2]. *(p + 2) equivaut donc a t[2]. */
 
    printf("t[2] = %d\n", *(p + 2));
 
    /* p pointe sur t[0] donc p + 3 pointe sur t[3]. *(p + 3) equivaut donc a t[3]. */
 
    printf("t[3] = %d\n", *(p + 3));
 
    return 0;
}

Ou, sans l'aide de la variable p :

 
Sélectionnez
#include <stdio.h>
 
int main(void)
{
    int t[] = {10, 20, 30, 40};
 
    printf("t[0] = %d\n", *t);
    printf("t[1] = %d\n", *(t + 1));
    printf("t[2] = %d\n", *(t + 2));
    printf("t[3] = %d\n", *(t + 3));
 
    return 0;
}
Mis à jour le 2008-07-27  par gege2061

Cet opérateur permet d'accéder à un élément d'un tableau. Il requiert deux opérandes : une de type pointeur et l'autre de type entier. L'expression X[Y] est équivalente à *((X) + (Y)). Autrement dit, si p possède un type pointeur, alors les expressions p[1], 1[p] et *(p + 1) sont strictement équivalentes, tout comme p[-1], (-1)[p] et *(p - 1), etc.

Créé le 2008-07-27  par gege2061, Melem

Lien : Soit t un tableau. Que signifie *(t + 3) ?

En langage C, on ne classe pas les tableaux selon leurs dimensions, un tableau "à plusieurs dimensions" n'est d'ailleurs en C qu'un tableau dont les éléments sont eux aussi des tableaux. Il n'y a donc pas des règles spéciales pour ces tableaux "à plusieurs dimensions". Voici un exemple de programme manipulant un tableau dont les éléments sont des tableaux.

 
Sélectionnez
#include <stdio.h>
 
int main(void)
{
    int t[10][4]; /* t est un tableau de 10 elements ou */
    /* chaque element est un tableau de 4 entiers       */
 
    size_t j, i;
 
    /* Parcourons les elements du tableau (t[0] a t[9]) */
    for(j = 0; j < sizeof(t) / sizeof(t[0]); j++)
    {
        /* Pour chaque element t[j] du tableau, initialisons */
        /* les elements de t[j] (t[j][0] a t[j][3])          */
 
        for(i = 0; i < sizeof(t[j]) / sizeof(t[j][0]); i++)
        {
            t[j][i] = j;
 
            /* Puis affichons t[j][i] */
 
            printf("%d\t", t[j][i]);
        }
 
        printf("\n");
    }
 
    return 0;
}
Créé le 2009-03-23  par Melem

'int (*p)[4];' crée une variable p tel que (*p) est un tableau de 4 entiers. p est donc un pointeur vers un tableau de 4 entiers. Il est de type int (*)[4]. On ne peut pas utiliser un tel nom de type pour déclarer une variable par exemple mais on peut par contre l'utiliser dans un cast ou un sizeof. Le programme suivant donne un exemple d'utilisation d'un pointeur vers tableau.

 
Sélectionnez
#include <stdio.h>
 
int main(void)
{
    int t[10][4];
    int (*p)[4] = t; /* p pointe sur t[0]. *p <=> t[0]. */;
 
    ( *p )[0] = 0; /* t[0][0] = 0 */
    ( *p )[1] = 0; /* t[0][1] = 1 */
 
    ( *(p + 1) )[0] = 1; /* t[1][0] = 1 */
    ( *(p + 1) )[1] = 1; /* t[1][1] = 1 */
 
    printf("t[0][0] = %d\n", t[0][0]);
    printf("t[0][1] = %d\n", t[0][1]);
    printf("t[1][0] = %d\n", t[1][0]);
    printf("t[1][1] = %d\n", t[1][1]);
 
    return 0;
}
Créé le 2009-03-23  par Melem
 
Sélectionnez
#include <stdio.h>
 
/* Definition d'un type fonction */
 
typedef int F(void);
 
/* Voici deux fonctions de type F */
 
int f1(void);
int f2(void);
 
/* Maintenant la fonction principale */
 
int main(void)
{
    F * t[2];
 
    t[0] = f1;
    t[1] = f2;
 
    printf("t[0]() = %d\n", t[0]());
    printf("t[1]() = %d\n", t[1]());
 
    return 0;
}
 
int f1(void)
{
    return 1;
}
 
int f2(void)
{
    return 2;
}

Etant donné que les fonctions, à l'instar des variables permanentes, existent en mémoire pendant toute l'exécution du programme, l'adresse d'une fonction peut être utilisée pour initialiser une variable permanente (en termes techniques, l'adresse d'une fonction, tout comme l'adresse d'une variable permanente, est donc, en C, une "expression constante").

 
Sélectionnez
#include <stdio.h>
 
typedef int F(void);
 
int f1(void);
int f2(void);
 
F * t[] = {f1, f2};
 
int main(void)
{
    printf("t[0]() = %d\n", t[0]());
    printf("t[1]() = %d\n", t[1]());
 
    return 0;
}
 
int f1(void)
{
    return 1;
}
 
int f2(void)
{
    return 2;
}
Mis à jour le 2009-06-15  par joellel, Melem

Lorsqu'un tableau figure en paramètre d'une fonction, il est automatiquement converti en son adresse (plus précisément en l'adresse de son premier élément). Un tableau n'est donc jamais copié par une fonction. La méthode généralement utilisée pour passer un tableau à une fonction c'est de passer un pointeur vers son premier élément et sa taille (si nécessaire) comme paramètres.

 
Sélectionnez
#include <stdio.h>
 
void initialiser_tab(int * ptr, size_t n_elements)
{
    size_t i;
 
    for(i = 0; i < n_elements; i++)
        ptr[i] = (int)i;
}
 
int main(void)
{
    int t[10];
    size_t i, n_elements = sizeof(t) / sizeof(t[0]);
 
    /* t peut egalement s'ecrire &(t[0]) */
    initialiser_tab(t, n_elements);
 
    for(i = 0; i < n_elements; i++)
        printf("%d\n", t[i]);
 
    return 0;
}

Etant donné qu'un tableau est toujours converti en un pointeur vers son premier élément, les prototypes suivants sont strictement les mêmes :

 
Sélectionnez
void initialiser_tab(int * ptr, size_t n_elements)
void initialiser_tab(int ptr[], size_t n_elements)
void initialiser_tab(int ptr[10], size_t n_elements) /* Le 10 ne sert absolument a rien */

Voici un exemple avec un tableau "à deux dimensions" :

 
Sélectionnez
#include <stdio.h>
 
/* initialiser_tab_2 : initialise un tableau de N elements ou */
/* chaque element est un tableau de M entiers .               */
 
void initialiser_tab_2(int * ptr, size_t N, size_t M)
{    
    /* ptr = &(t[0][0]) d'ou :      */
    /* - ptr[i] <=> t[0][i]         */
    /* - ptr[M * j] <=> t[j][0]     */
    /* - ptr[M * j + i] <=> t[j][i] */
 
    size_t j, i;
 
    for(j = 0; j < N; j++)
    {
        for(i = 0; i < M; i++)
        {
            ptr[M * j + i] = (int)j;
        }
    }
}
 
int main(void)
{
    int t[10][4];
    size_t j, i;
    size_t N = sizeof(t) / sizeof(t[0]), M = sizeof(t[0]) / sizeof(t[0][0]);
 
    /* &(t[0][0]) peut egalement s'ecrire t[0] ou encore (int *)t */
    initialiser_tab_2(&(t[0][0]), N, M);
 
    for(j = 0; j < N; j++)
    {
        for(i = 0; i < M; i++)
            printf("%d\t", t[j][i]);
 
        printf("\n");
    }
 
    return 0;
}
Mis à jour le 2009-03-23  par Bob, gl, Melem

Pour copier un tableau, on a deux solutions. La première consiste à copier chaque case du tableau numéro 1 dans la case correspondante du tableau numéro 2. Mais cette manière est parfois complexe et risque d'être lente.

La deuxième possibilité est d'utiliser la fonction memcpy(). Elle admet trois paramètres, le premier étant le tableau de destination et le deuxième le tableau source. Enfin, le troisième est le nombre d'octets à copier. Par exemple, pour copier le tableau Tab1 dans le tableau Tab2, il suffit de faire :

 
Sélectionnez
#include <string.h>
 
int Tab1[10], Tab2[10];
 
memcpy(Tab2, Tab1, sizeof Tab2);
Mis à jour le 2006-09-11  par Bob, Emmanuel Delahaye
  

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 © 2013 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée.