¿Cómo se le da sentido al error?no se puede convertir de 'int []' a 'int []'
-
22-08-2019 - |
Pregunta
Al compilar el siguiente código:
void DoSomething(int Numbers[])
{
int SomeArray[] = Numbers;
}
el compilador VS2005 se queja con el error C2440:'inicializando':no se puede convertir de 'int []' a 'int []'
Entiendo que en realidad está intentando lanzar un puntero a una matriz que no va a funcionar.Pero, ¿cómo se le explica el error a alguien que aprende C++?
Solución
Hay tres cosas que hay que explicar a la persona que está tratando de ayudar a:
-
Las matrices no se pueden pasar por el valor de una función en C ++. Para hacer lo que está tratando de hacer, tiene que pasar la dirección del inicio de la matriz a
DoSomething()
, así como el tamaño de la matriz en unint
separada (bueno,size_t
, pero yo no se molestan diciendo que) argumento. Puede obtener la dirección del inicio de alguna variedadmyArray
con el&(myArray[0])
expresión. Puesto que esto es una cosa tan común que quiere hacer, C ++ permite utilizar sólo el nombre de la matriz - por ejemplo,myArray
- Para obtener la dirección de su primer elemento. (Que puede ser útil o confusa, dependiendo de la forma que se mire.) Para hacer las cosas aún más confuso, C ++ permite especificar un tipo de matriz (por ejemploint Numbers[]
) como un parámetro a una función, pero en secreto se trata de que el parámetro como si hubiera sido un declarado como un puntero (int *Numbers
en este caso) - incluso se puede hacer dentro deNumbers += 5
DoSomething()
a hacer que apunte a una matriz a partir de la sexta posición -
Cuando se declara una variable de matriz tales como
SomeArray
en C ++, debe proporcionar un tamaño explícito o una "lista de initialiser" , que es una lista separada por comas de valores entre los apoyos . No es posible que el compilador para inferir el tamaño de la matriz basada en otra matriz que se está tratando de inicializar con, porque ... -
No se puede copiar una matriz a otra, o inicializar una matriz de otro en C ++. Así que incluso si el
Numbers
parámetro era realmente una matriz (por ejemplo del tamaño de 1000) y no se un puntero, y se ha especificado el tamaño deSomeArray
(de nuevo como decir 1000), la línea deint SomeArray[1000] = Numbers;
sería ilegal.
Para hacer lo que quiere hacer en DoSomething()
, primero preguntarse:
- ¿Es necesario cambiar cualquiera de los valores en
Numbers
? - Si es así, es lo que quiero evitar que la persona que llama de ver esos cambios?
Si la respuesta a cualquiera de estas preguntas es "no", no, de hecho, es necesario hacer una copia de Numbers
en el primer lugar -. Sólo tiene que utilizar como es, y olvidarse de hacer una matriz separada SomeArray
Si la respuesta a ambas preguntas es "Sí", tendrá que hacer una copia de Numbers
en SomeArray
y trabajar en ese lugar. En este caso, realmente debería hacer un SomeArray
C ++ vector<int>
en lugar de otra matriz, ya que esto realmente simplifica las cosas. (Explicar los beneficios de vectores sobre la asignación de memoria dinámica manual, incluyendo los hechos que puede inicializar de otras matrices o vectores, y van a llamar a los constructores de elementos cuando sea necesario, a diferencia de un memcpy()
de estilo C).
Otros consejos
decir que hay tipos y tipos incompletas:
struct A;
Es un tipo incompleto de una estructura llamada A. Mientras
struct A { };
es un tipo completo de una estructura llamada A. El tamaño de la primera no se conoce todavía, mientras que el tamaño de la segunda se conoce.
Hay tipos de clases incompletas como la estructura anteriormente. Pero también hay tipos de matrices incompletas:
typedef int A[];
Esto es un tipo de matriz incompleta llamado A. Su tamaño no se conoce todavía. No se puede crear una matriz fuera de él, porque el compilador no sabe qué tan grande es la matriz. Pero se puede utilizar para crear una matriz, solamente Si inicializa enseguida:
A SomeArray = { 1, 2, 3 };
Ahora, el compilador sabe la matriz es una matriz int con 3 elementos. Si intenta inicializar la matriz con un puntero, el compilador no será más inteligente que antes, y se niegan, debido a que no se dará el tamaño de la matriz que se creará.
Al tratar de hacer que el mensaje de error más útil, el compilador es en realidad cosas confusas. A pesar de que el parámetro Numbers
se declara como una matriz, C / C ++ no (no) en realidad pasar una matriz -. Numbers
el parámetro es en realidad un puntero
Así que el error realmente debería decir "cannot convert from 'int *' to 'int []'"
Pero entonces no habría confusión - "Hey, no hay int*
implicada en la expresión", alguien podría decir
Por esta razón, lo que realmente es mejor evitar parámetros de matriz - declararlos como punteros, ya que eso es lo que realmente está obteniendo de todos modos. Y la explicación a alguien que está aprendiendo C / C ++ debe educarlos en el hecho de que los parámetros de matriz no son una ficción -. Son realmente punteros
Cuando estoy tratando de explicar algo, yo siempre trato de bajar al nivel más bajo, y construir desde allí. Eso es que a mí me gusta aprender cosas, y me parece que las personas se sienten más cómodos si se inicia con los fundamentos que se conocen, y construir a partir de ahí.
En este caso, probablemente a empezar con algo como:
El compilador está tratando de hacer la asignación, debido a que escribió una operación de asignación. En C ++, No se puede asignar directamente a una matriz, porque no tiene una función de asignación operador (de cualquier tipo, sólo se inicializador y la indexación se apoya para matrices). Debido a que los soportes C ++ operadores sobrecargados para los tipos, las compilador busca entonces una sobrecarga operador de asignación para la "Asignado a" tipo que toma la "Asignado a" tipo como argumento. Dado que tampoco hay sobrecargado operador para int [] que toma int [] como argumento, los errores de compilación en la línea, y los errores que está diciendo por qué el compilador no puede procesar la línea.
Sí, es algo excesivo vs acaba de decir algo sobre el conocimiento de su tamaño, tipos incompletas, etc. Me di cuenta que tampoco es completa (por ejemplo: no hay discusión de la asignación inicializador vs asignación normal, etc.). Sin embargo, mi objetivo es por lo general para hacer que la gente donde pueden averiguar la siguiente respuesta a sí mismos, y por eso normalmente se quiere diseñar el proceso de pensamiento para llegar a la respuesta.
Tal vez su respuesta podría ser: "Debido a que el compilador no sabe qué tan grande es la matriz."
Su ejemplo podría funcionar si hubo tamaños de matriz explícitos (quizá con un typedef para mayor claridad), y luego se puede explicar punteros mientras que la introducción asignaciones de tamaño variable.