Question

Lors de la compilation du code suivant:

void DoSomething(int Numbers[])
{
    int SomeArray[] = Numbers;
}

le compilateur VS2005 se plaint avec le C2440 d'erreur: 'initialisation': ne peut pas convertir 'int []' à 'int []

Je comprends que vraiment essaie de jeter un pointeur sur un tableau qui ne va pas travailler. Mais comment expliquez-vous l'erreur à quelqu'un d'apprentissage C ++?

Était-ce utile?

La solution

Il y a trois choses que vous devez expliquer à la personne que vous essayez d'aider:

  1. Les tableaux ne peuvent pas être passés par valeur à une fonction en C ++. Pour faire ce que vous essayez de faire, vous devez passer l'adresse du début du tableau à DoSomething() , ainsi que la taille du tableau dans un int séparé (bien, size_t, mais je ne contrarient pas dire que) argument. Vous pouvez obtenir l'adresse du début de certains myArray de tableau avec l'expression &(myArray[0]). Comme il est une chose commune à vouloir faire, C ++ vous permet d'utiliser simplement le nom du tableau - par exemple myArray - pour obtenir l'adresse de son premier élément. (Ce qui peut être utile ou prêtant à confusion, selon la façon dont vous regardez.) Pour rendre les choses encore plus confuses, C ++ vous permet de spécifier un type de tableau (par exemple int Numbers[]) en tant que paramètre à une fonction, mais en secret il traite ce paramètre comme si elle était déclarée comme un pointeur (int *Numbers dans ce cas) - vous pouvez même faire Numbers += 5 l'intérieur DoSomething() pour le faire pointer vers un tableau à partir de la sixième position

  2. Lorsque vous déclarer une variable de tableau tel que SomeArray en C ++, il faut soit prévoir une taille explicite ou une « liste d'initialiser » , qui est une liste séparée par des virgules des valeurs entre accolades . Il est impossible pour le compilateur de déduire la taille du tableau basé sur un autre tableau que vous essayez de lui avec l'initialisation, parce que ...

  3. Vous ne pouvez pas copier un tableau dans un autre, ou d'initialiser une matrice d'un autre en C ++. Donc, même si le paramètre Numbers était vraiment un tableau (par exemple de la taille 1000) et non un pointeur, et que vous avez spécifié la taille de SomeArray (encore une fois comme dire 1000), la int SomeArray[1000] = Numbers; ligne serait illégale.


Pour faire ce que vous voulez faire dans DoSomething(), demandez-vous:

  1. Dois-je modifier les valeurs Numbers?
  2. Si oui, ce que je veux empêcher l'appelant de voir ces changements?

Si la réponse à ces deux questions est « Non », vous ne pas en fait besoin de faire une copie de Numbers en premier lieu -. Il suffit d'utiliser tel quel, et d'oublier de faire un tableau de SomeArray séparé

Si la réponse aux deux questions est « oui », vous devez faire une copie de Numbers dans SomeArray et travailler sur ce lieu. Dans ce cas, vous devriez vraiment faire une SomeArray C ++ vector<int> au lieu d'un autre tableau, car cela simplifie vraiment les choses. (Expliquer les avantages des vecteurs sur l'allocation dynamique de mémoire manuelle, y compris les faits qu'ils peut procéder à l'initialisation à partir d'autres tableaux ou vecteurs, et ils appelleront les constructeurs d'éléments si nécessaire, contrairement à un memcpy() style C.)

Autres conseils

Dire qu'il ya des types et des types incomplets:

struct A;

est un type d'une struct dite incomplète A. Alors que

struct A { };

est un type complet d'un struct appelé A. La taille de la première n'est pas encore connu, alors que la taille de la seconde est connue.

Il existe plusieurs types de classes incomplètes comme le struct ci-dessus. Mais il y a aussi des types de tableaux incomplets:

typedef int A[];

C'est un type tableau incomplet appelé A. Sa taille est pas encore connue. Vous ne pouvez pas créer un tableau hors de celui-ci, parce que le compilateur ne sait pas la taille du tableau est. Mais vous pouvez utiliser pour créer un tableau, uniquement si vous lsinitialisez immédiatement:

A SomeArray = { 1, 2, 3 };

Maintenant, le compilateur connaît le tableau est un tableau int avec 3 éléments. Si vous essayez d'initialiser le tableau avec un pointeur, le compilateur ne sera pas plus intelligent que jamais, et de refuser, parce que cela ne lui donner la taille du tableau à créer.

En essayant de rendre le message d'erreur plus utile, le compilateur est en fait les choses confuses. Même si le paramètre Numbers est déclaré comme un tableau, C / C ++ ne pas (peut) passer en réalité un tableau -. Le paramètre Numbers est en fait un pointeur

Alors l'erreur devrait vraiment dire "cannot convert from 'int *' to 'int []'"

Mais il y aurait confusion - "hey, il n'y a pas int* impliqué dans l'expression", quelqu'un pourrait dire

.

Pour cette raison, il est vraiment préférable d'éviter les paramètres de tableau - les déclarer en tant que pointeurs, puisque c'est ce que vous êtes vraiment obtenir de toute façon. Et l'explication à quelqu'un d'apprentissage C / C ++ devrait les éduquer sur le fait que les paramètres du tableau sont une fiction -. Ils sont vraiment pointeurs

Quand je suis en train d'expliquer quelque chose, j'essaie toujours de descendre au niveau le plus bas, et de construire à partir de là. Ce qu'ils aiment est je façon d'apprendre des choses, et je trouve que les gens sont plus à l'aise si vous commencez avec les bases qu'ils connaissent, et de construire à partir de là.

Dans ce cas, je serais probablement commencer par quelque chose comme:

  

Le compilateur essaie de faire la   mission, parce que vous avez écrit un   opération d'affectation. En C ++, vous   ne peut pas attribuer directement à un tableau,   parce qu'il n'a pas d'affectation intégrée   opérateur (de toute nature, seulement   initialisation et d'indexation est supporté   pour les tableaux). Parce que les supports C +   opérateurs surchargées pour les types, les   compilateur recherche alors une surcharge   opérateur d'affectation pour la   « Attribué à » type qui prend la   comme argument « attribué par de » type.   Comme il n'y a pas non plus surchargées   opérateur int [] qui prend int []   comme argument, les erreurs du compilateur sur   la ligne, et les erreurs vous dit   pourquoi le compilateur ne peut pas traiter la ligne.

Oui, il est probablement exagéré vs juste dire quelque chose sur la connaissance de la taille, les types incomplets, etc. Je me rends compte qu'il est pas non plus complète (par exemple: aucune discussion de cession initialiseur vs affectation normale, etc.). Cependant, mon objectif est généralement d'amener les gens là où ils peuvent trouver la prochaine réponse se, et que vous voulez généralement exposer le processus de réflexion pour arriver à la réponse.

Peut-être votre réponse pourrait être « Parce que le compilateur ne sait pas la taille du tableau est. »

Votre exemple pourrait fonctionner s'il y avait la taille des tableaux explicites (peut-être avec un typedef pour plus de clarté), et ensuite vous pouvez expliquer pointeurs tout en introduisant des allocations de taille variable.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top