28 votes

Littéraux composés C, pointeur sur les tableaux

Je suis en train d'affecter un composé littérale à une variable, mais il semble ne pas fonctionner, voir:

  int *p[] = (int *[]) {{1,2,3},{4,5,6}};

J'ai eu une erreur de gcc.

mais si j'écris seulement ce:

  int p[] = (int []) {1,2,3,4,5,6};

Alors c'est d'accord.

Mais ce n'est pas ce que je veux.

Je ne comprends pas pourquoi l'erreur atteint son apogée, parce que si je l'initialiser comme un tableau, ou de l'utiliser avec un pointeur de tableaux de caractères, son correct, voir:

  int *p[] = (int *[]) {{1,2,3},{4,5,6}}; //I got a error
  int p[][3] = {{1,2,3},{4,5,6}}; //it's okay
  char *p[] = (char *[]) {"one", "two"...}; // it's okay!

Remarque, je ne comprends pas pourquoi j'ai une erreur dans le premier, et s'il vous plaît je ne peux pas ou je ne veux pas écrire comme la deuxième forme parce que ça doit être un composé littéraux, et je ne veux pas dire quelle est la taille du tableau pour le compilateur. Je veux quelque chose comme la seconde, mais pour les valeurs int.

Merci à l'avance.

27voto

Judge Maygarden Points 14964

Tout d'abord, les moulages sont redondants dans l'ensemble de vos exemples et peuvent être supprimés. Ensuite, vous utilisez la syntaxe à utiliser pour l'initialisation d'un tableau multidimensionnel, et qui nécessite de la deuxième dimension de l'être définies afin d'allouer un bloc séquentiel de la mémoire. Au lieu de cela, essayez l'une des deux approches ci-dessous:

  • Tableau multidimensionnel:

    int p[][3] = {{1,2,3},{4,5,6}};
    
  • Tableau de pointeurs vers une dimensions des tableaux:

    int p1[] = {1,2,3};
    int p2[] = {4,5,6};
    int *p[] = {p1,p2};
    

Cette dernière méthode a l'avantage de permettre les sous-ensembles de longueur variable. Attendu que l'ancienne méthode garantit que la mémoire est aménagé de manière contiguë.

Une autre approche que je recommande fortement que vous n'utilisez PAS de est de coder les entiers littéraux de chaîne. C'est un non-portable hack. Aussi, les données dans les littéraux de chaîne est supposé être constant. Vos tableaux ont besoin d'être muable?

int *p[] = (int *[]) {
    "\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00",
    "\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00"
};

Cet exemple pourrait travailler sur une version 32 bits de poids faible de la machine, mais je suis en train de taper ceci à partir d'un iPad et ne peut pas vérifier pour le moment. Encore une fois, s'il vous plaît ne pas l'utiliser; je me sens sale, même pour l'apporter.

La coulée de la méthode que vous avez découvert aussi semble fonctionner avec un pointeur vers un pointeur. Qui peut être indexé comme un tableau multidimensionnel ainsi.

int **p = (int *[]) { (int[]) {1,2,3}, (int[]) {4,5,6} };

11voto

Mahesh Points 20994

D'abord comprendre que "les Tableaux ne sont pas des pointeurs".

int p[] = (int []) {1,2,3,4,5,6};

Dans le cas ci-dessus, p est un tableau d'entiers. Copie les éléments {1,2,3,4,5,6} de p. Typecasting n'est pas nécessaire ici, et à la fois l' rvalue et lvalue types de correspondance, ce qui est un tableau d'entiers et si aucune erreur.

int *p[] = (int *[]) {{1,2,3},{4,5,6}};

"Remarque, je ne comprends pas pourquoi j'ai eu une erreur dans la première,.."

Dans le cas ci-dessus, p un tableau d'entiers à pointeurs. Mais l' {{1,2,3},{4,5,6}} est un tableau à deux dimensions ( c'est à dire, [][] ) et ne peut pas être le type coulée de tableau de pointeurs. Vous devez l'initialiser comme -

int p[][3] = { {1,2,3},{4,5,6} };
  // ^^ First index of array is optional because with each column having 3 elements
  // it is obvious that array has two rows which compiler can figure out.

Mais pourquoi cette déclaration de la compilation ?

char *p[] = {"one", "two"...};

Les littéraux de chaîne sont différents de les littéraux entiers. Dans ce cas également, p est un tableau de pointeurs de caractère. Alors qu'en réalité, dit - "one", il peut être copié sur un tableau ou un point à son emplacement en la considérant comme étant en lecture seule.

char cpy[] = "one" ;
cpy[0] = 't' ;  // Not a problem

char *readOnly = "one" ;
readOnly[0] = 't' ;  // Error because of copy of it is not made but pointing
                     // to a read only location.

Avec des littéraux de chaîne, l'un des cas ci-dessus est possible. Donc, c'est la raison pour laquelle la déclaration compilé. Mais -

char *p[] = {"one", "two"...}; // All the string literals are stored in 
                               // read only locations and at each of the array index 
                               // stores the starting index of each string literal.

Je ne veux pas dire quelle est la taille du tableau pour le compilateur.

Allouer dynamiquement de la mémoire à l'aide de malloc est la solution.

Espérons que cela aide !

3voto

tc. Points 23958

Depuis personne ne l'a dit: Si vous voulez avoir un pointeur-à-2D-tableau, vous pouvez (sans doute) faire quelque chose comme

int (*p)[][3] = &(int[][3]) {{1,2,3},{4,5,6}};

EDIT: Ou vous pouvez avoir un pointeur vers son premier élément via

int (*p)[3] = (int[][3]) {{1,2,3},{4,5,6}};

La raison pour laquelle votre exemple ne fonctionne pas est parce qu' {{1,2,3},{4,5,6}} n'est pas valide d'un initialiseur de type int*[] (parce qu' {1,2,3} n'est pas valide d'un initialiseur pour int*). Notez que c'est pas un int[2][3] — c'est tout simplement une défaillance de l'expression.

La raison pour laquelle cela fonctionne pour cordes est parce qu' "one" est valable un initialiseur pour char[] et char[N] (pour N>3). Comme une expression, c'est environ l'équivalent de (const char[]){'o','n','e','\0'} sauf le compilateur ne veut pas trop se plaindre quand il perd constness.

Et oui, il y a une grande différence entre un initialiseur et une expression. Je suis sûr que char s[] = (char[]){3,2,1,0}; est une erreur de compilation dans le C99 (et, éventuellement, C++ pré-0x). Il ya des tas d'autres choses aussi, mais T foo = ...; est l'initialisation d'une variable, pas d'affectation, même si elles se ressemblent. (Ils sont très différents en C++, car l'opérateur d'affectation n'est pas appelé.)

Et la raison de la confusion avec les pointeurs:

  • Type T[] est implicitement converti en type T* (un pointeur vers son premier élément) lorsque cela est nécessaire.
  • T arg1[] en fonction de la liste d'arguments signifie, en réalité, T * arg1. Vous ne pouvez pas passer un tableau à une fonction, pour Diverses Raisons. Il n'est pas possible. Si vous essayez, vous êtes réellement en passant un pointeur vers tableau. (Vous pouvez, cependant, le passage d'une structure contenant un tableau de taille fixe à une fonction.)
  • Ils peuvent tous les deux être déréférencé et indicée à l'identique (je pense) de la sémantique.

EDIT: L'observateur peut-être remarqué que mon premier exemple est à peu près la syntaxe est équivalente à int * p = &1;, ce qui n'est pas valide. Cela fonctionne en C99, car un littéral composé à l'intérieur d'une fonction "automatique durée de stockage associés avec le bloc enfermant" (ISO/IEC 9899:TC3).

1voto

BlackBear Points 10069

Il semble que vous confondez les pointeurs et tableaux. Ils ne sont pas la même chose! Un tableau est la liste elle-même, tandis que un pointeur est une adresse. Puis, avec l'arithmétique des pointeurs vous pouvez prétendre pointeurs sont array, et avec le fait que le nom d'un tableau est un pointeur vers le premier élément tout ce résume en un gâchis. ;)

int *p[] = (int *[]) {{1,2,3},{4,5,6}};      //I got a error

Ici, p est un tableau de pointeurs, si vous essayez d'affecter les éléments dont les adresses sont 1, 2, 3 pour le premier tableau, et 4, 5, 6 pour le second tableau. Le seg fault se passe parce que vous ne pouvez pas accéder à ces emplacements de mémoire.

int p[][3] = {{1,2,3},{4,5,6}};              //it's okay

C'est ok parce que c'est un tableau de tableaux, de sorte cette fois 1, 2, 3, 4, 5 et 6 ne sont pas les adresses mais les éléments eux-mêmes.

char *p[] = (char *[]) {"one", "two"...};    // it's okay!

C'est ok parce que les littéraux de chaîne ("un", "deux", ...), ne sont pas des chaînes de caractères, mais des pointeurs vers ces chaînes, de sorte que vous attribuez à p[1] l'adresse de la chaîne littérale "un".
BTW, c'est la même chose que de faire char abc[]; abc = "abc";. Ce ne compile pas, parce que vous ne pouvez pas affecter un pointeur vers un tableau, alors que char *def; def = "def"; résout le problème.

0voto

Karan Points 6418

Celui que vous utilisez est un tableau de pointeurs int. Vous devez utiliser le pointeur vers le tableau:

 int (*p)[] = (int *) {{1,2,3}, {4,5,6}}
 

Regardez cette réponse pour plus de détails.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X