web-dev-qa-db-fra.com

Pourquoi un argument char ** temporaire est-il illégal?

J'ai une fonction, f(char **p), et je voulais l'appeler de la manière la plus simple possible.

J'ai essayé

char ** p = {"a", "b"};
f(p);

et a obtenu:

l'objet scalaire nécessite un élément dans l'initialiseur

donc je l'ai changé en

char * p[2] = {"a", "b"};
f(p);

et ça s'est bien passé [ça aurait été aussi bien avec juste char * p[]].

Pourquoi ne puis-je pas créer un tableau de pointeurs à la volée comme suit?

f({"a", "b"});
25
CIsForCookies

Cela donne un avertissement:

char ** p = {"a", "b"};

parce que p n'est pas un tableau.

Ce n'est pas non plus légal:

f({"a", "b"});

car les accolades en elles-mêmes ne sont pas autorisées dans une expression (mais peuvent être utilisées comme initialiseur).

Il est possible de créer un tableau à la volée comme cela en utilisant un littéral composé :

f((char *[]){"a", "b"});

Vous pouvez également utiliser un littéral composé pour initialiser un temporaire:

char ** p = (char *[]){"a", "b"};

Contrairement à la première instruction, cela est valide car le littéral est un tableau de type char *[2] et se décomposera en char ** qui peut être utilisé pour initialiser une variable de ce type.

Voir la section 6.5.2.5 de la norme C pour plus de détails sur les littéraux composés.

41
dbush

Cette déclaration char ** p = {"a", "b"}; déclenche un avertissement car C ne sait pas interpréter le contenu de {} accolades:

  • Type de déclaration char** suggère qu'il s'agit d'un seul pointeur vers pointeur vers caractère
  • Contenu de {} spécifie deux éléments.

Vous devez dire à C que vous initialisez un pointeur à pointeur avec un pointeur sur l'élément initial d'un tableau anonyme en spécifiant un type devant les accolades:

char ** p = (char*[]){"a", "b"}

Cette construction est appelée "littéral composé". Il pourrait être utilisé dans une déclaration, mais il fonctionne également comme une expression.

Remarque: si vous prévoyez de passer un tableau comme celui-ci à une fonction, vous devez fournir un moyen de déterminer la taille du tableau. Une approche consiste à passer NULL pour "terminer" le tableau, comme ceci:

void f(char **p) {
    int i = 0;
    while (*p) {
        printf("%d:%s\n", i++, *p++);
    }
}
int main(void) {
    f((char*[]){"a", "b", NULL});
    return 0;
}

Démo.

14
dasblinkenlight

C99 et versions ultérieures ajoutées littéraux composés dans le but exact: création de tableaux et de structures à la volée
Exemple:

struct foo {int a; char b[2];} structure;
structure = ((struct foo) {1, 'a', 0});
int *y = (int []) {1, 2, 3};
int *z = (int []) {1}; 

Mis à part std C99 et versions ultérieures, GCC fournit également cette fonctionnalité en tant qu'extension.
Dans votre cas, cela fonctionnera

f((char *[]){"a","b"});

(char *[]){"a","b"} est un littéral composé qui crée un tableau de 2 pointeurs vers char à la volée.

5
haccks