web-dev-qa-db-fra.com

Eléments excédentaires de l’initialiseur scalaire pour le pointeur sur un tableau

Je travaille sur un exercice de K & R (ex. 5–9) et j’essayais de convertir le tableau 2D de programmes

static char daytab[2][13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

en utilisant des pointeurs vers un tableau de 13 pouces comme

static char (*daytab)[13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

Mais le compilateur imprimewarning: excès d'éléments dans l'initialiseur scalaire.

Googler n'a pas aidé et même K & R écrit en passant le tableau à une fonction,

myFunction(int daytab[2][13]) {...}

est le même que

myFunction(int (*daytab)[13]) {...}
25
adelbertc

Les deux ne sont que partiellement équivalents. La différence étant que:

static char daytab[2][13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

déclare un tableau à deux dimensions, ce qui inclut de réserver de l'espace pour le tableau et de s'assurer que daytab fait référence à cette mémoire. Toutefois:

static char (*daytab)[13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

... déclare seulement un pointeur. Vous essayez donc d'initialiser un pointeur avec un initialiseur de tableau, qui ne fonctionne pas comme prévu. Il n'y a pas de tableau; il n'y a pas de mémoire réservée pour un tableau. Au lieu de cela, le premier numéro de votre initialiseur est attribué au pointeur daytab et le compilateur génère un avertissement pour vous informer que vous avez spécifié un grand nombre de valeurs supplémentaires qui sont simplement ignorées. Étant donné que le premier numéro de votre initialiseur est 0, vous définissez simplement daytab sur NULL de manière plutôt détaillée.

Ainsi, si vous souhaitez effectuer ce type d'initialisation, utilisez la première version. Elle se décompose en un type de pointeur identique à celui que vous avez déclaré explicitement dans la deuxième version. Vous pouvez donc l'utiliser de la même manière. La deuxième version, avec le pointeur de tableau, est nécessaire lorsque vous souhaitez allouer dynamiquement le tableau ou obtenir une référence à un autre tableau déjà existant.

Donc, vous pouvez faire ceci:

static char arr[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
static char (*ptr)[3] = NULL;

ptr = arr;

... puis utilisez ptr et arr de façon interchangeable. Ou ca:

static char (*ptr)[3] = NULL;

ptr = malloc(2 * sizeof(*ptr));

... pour obtenir un tableau bidimensionnel alloué dynamiquement (non pas un tableau de pointeurs sur des tableaux 1D, mais un tableau 2D réel). Bien sûr, ce n'est pas initialisé dans ce cas.

L '"équivalence" des deux variations signifie simplement que le tableau 2D, lorsqu'il se transforme en pointeur vers son premier élément, se désintègre au type de pointeur déclaré dans la deuxième variante. Une fois que la version du pointeur est en fait dirigée vers un tableau, les deux sont équivalents. Mais la version de tableau 2D configure la mémoire pour le tableau, où la déclaration du pointeur ne ... et où une nouvelle valeur (pointée sur un tableau différent) peut être attribuée au pointeur, contrairement à la variable de tableau 2D.

En C99, vous pouvez le faire (si ce n’est pas static au moins):

char (*daytab)[13] = (char [][13]){
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
27
Dmitri

@Dmitri l'a bien expliqué, mais je voulais ajouter que 

static char (*daytab)[13] = { ... };

est one un pointeur sur un tableau de 13 éléments char. Le compilateur vous avertit parce que vous avez passé dans les tableaux two. C'est comme essayer d'attribuer deux adresses à un pointeur char *p = {a, b}. Il y a plus d'éléments que nécessaire selon votre déclaration. Voir l'explication de Geekforgeek sur la signification réelle d'un pointeur de tableau.

En ce qui concerne l’exercice K & R, considérez 

Option 1:

static char *daytab[2] = { 
    (char []) {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    (char []) {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    };} 

ou Option 2:

static char (*daytab)[13] = (char [][13]) { 
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    };} 

L'option 1 est un tableau de deux pointeurs char

L'option 2 est un pointeur de tableau. Il pointe vers un tableau de 13 éléments char. Tout comme vous pouvez incrémenter un pointeur char pour obtenir la prochaine lettre d'une chaîne, vous pouvez incrémenter ce pointeur de tableau pour récupérer le tableau suivant de 13 chars.

0
khlau