Como você fazer o sentido do erro: Não é possível converter de 'int []' para 'int []'
-
22-08-2019 - |
Pergunta
Ao compilar o código a seguir:
void DoSomething(int Numbers[])
{
int SomeArray[] = Numbers;
}
o compilador VS2005 reclama com o C2440 de erro: 'inicializar': não é possível converter de 'int []' para 'int []'
Eu entendo que realmente ele está tentando converter um ponteiro para uma matriz que não vai funcionar. Mas como você explica o erro para alguém aprender C ++?
Solução
Há três coisas que você precisa explicar para a pessoa que você está tentando ajudar:
-
Matrizes não podem ser passados ??por valor para uma função em C ++. Para fazer o que você está tentando fazer, você precisa passar o endereço do início da matriz para
DoSomething()
, bem como o tamanho da matriz em umaint
separado (bem,size_t
, mas eu não iria incomodar dizendo que) argumento. Você pode obter o endereço do início de algunsmyArray
matriz com o&(myArray[0])
expressão. Uma vez que esta é uma coisa tão comum querer fazer, C ++ permite que você use apenas o nome da matriz - por exemplo,myArray
- para obter o endereço do seu primeiro elemento. (Que pode ser útil ou confuso, dependendo da maneira que você olha para ele.) Para tornar as coisas ainda mais confusas, C ++ permite que você especifique um tipo de matriz (por exemploint Numbers[]
) como um parâmetro para uma função, mas secretamente ele trata esse parâmetro como se fosse um declarado como um ponteiro (int *Numbers
neste caso!) - você pode até fazerNumbers += 5
dentroDoSomething()
para torná-lo apontar para uma matriz começando na sexta posição -
Quando declarar uma variável de matriz, tais como , que é uma lista separada por vírgulas de valores entre cintas . Não é possível para o compilador para inferir o tamanho da matriz baseada em outra matriz que você está tentando inicializar com ele, porque ...SomeArray
em C ++, tem de proporcionar um tamanho explícito ou uma "lista initialiser" -
Você não pode copiar uma variedade para outra, ou Inicializar uma matriz de outro em C ++. Assim, mesmo se o
Numbers
parâmetro foi realmente um array (dizer do tamanho 1000) e não um ponteiro, e você especificou o tamanho daSomeArray
(novamente como dizer 1000), oint SomeArray[1000] = Numbers;
linha seria ilegal.
Para fazer o que você quer fazer na DoSomething()
, primeiro pergunte-se:
- Preciso alterar qualquer um dos valores em
Numbers
? - Se assim for, eu quero evitar que o chamador de ver essas alterações?
Se a resposta a qualquer pergunta é "não", você não necessitam fato para fazer uma cópia de Numbers
em primeiro lugar -. Apenas usá-lo como é, e esquecer de fazer uma matriz SomeArray
separado
Se a resposta a ambas as perguntas é "sim", você vai precisar fazer uma cópia do Numbers
em SomeArray
e trabalhar em que, em vez. Neste caso, você deve realmente fazer SomeArray
um C ++ vector<int>
em vez de outro array, como isso realmente simplifica as coisas. (Explique os benefícios de vetores sobre alocação dinâmica de memória manual, incluindo os fatos que eles pode ser iniciado a partir de outras matrizes ou vetores, e eles vão chamar construtores elemento quando necessário, ao contrário de um memcpy()
C-estilo.)
Outras dicas
dizer que existem tipos e tipos incompletos:
struct A;
É um tipo incompleto de um struct chamado A. Enquanto
struct A { };
É um tipo completo de um struct chamado A. O tamanho da primeira ainda não é conhecido, enquanto o tamanho do segundo é conhecido.
Existem tipos de classes incompletos, como a estrutura acima. Mas também existem tipos de matriz incompletos:
typedef int A[];
Isso é um tipo de matriz incompleta chamado A. Seu tamanho ainda não é conhecido. Você não pode criar uma matriz de fora, porque o compilador não sabe quão grande é a matriz é. Mas você pode uso para criar uma matriz, única se você inicializar-lo imediatamente:
A SomeArray = { 1, 2, 3 };
Agora, o compilador sabe a matriz é uma matriz int com 3 elementos. Se você tentar inicializar a matriz com um ponteiro, o compilador não vai ser mais inteligente do que antes, e lixo, porque isso não vai dar-lhe o tamanho da matriz a ser criado.
Na tentativa de tornar a mensagem de erro mais útil, o compilador é na verdade confundindo as coisas. Mesmo que o parâmetro Numbers
é declarado como uma matriz, C / C ++ não (não pode), na verdade, passar um array -. O parâmetro Numbers
é realmente um ponteiro
Assim, o erro realmente deveria dizer "cannot convert from 'int *' to 'int []'"
Mas então não haveria confusão -. "Hey, não há int*
envolvidos na expressão", alguém poderia dizer
Por esta razão, é realmente melhor para parâmetros de matriz evitar - declará-los como ponteiros, já que é o que você está realmente ficando de qualquer maneira. E a explicação para alguém aprender C / C ++ deve educá-los sobre o fato de que os parâmetros de matriz são um fiction -. Eles são realmente ponteiros
Quando eu estou tentando explicar alguma coisa, eu sempre tentar ir para baixo para o nível mais baixo, e construir a partir daí. Isso é que assim que eu gosto de aprender coisas, e acho que as pessoas estão mais confortável se você começar com o básico que eles sabem, e construir a partir daí.
Neste caso, eu provavelmente começar com algo como:
O compilador está tentando fazer o atribuição, porque você escreveu um operação de atribuição. Em C ++, você não pode atribuir directamente para uma matriz, porque não foi construído com atribuição operador (de qualquer tipo, única inicializador e de indexação é suportada para matrizes). Porque suportes C ++ operadores sobrecarregados para tipos, os compilador, em seguida, procura uma sobrecarregado operador de atribuição para o "Atribuído fazer" tipo que leva o "Atribuído pelo de" tipo como seu argumento. Desde Também não há sobrecarregado operador para int [] que toma int [] como um argumento, os erros do compilador sobre a linha, e os erros está dizendo a você por que o compilador não pode processar a linha.
Sim, é provavelmente um exagero vs apenas dizendo algo sobre o conhecimento do tamanho, tipos incompletos, etc. Sei que também não é completo (por exemplo: nenhuma discussão sobre initializer atribuição vs atribuição normal, etc.). No entanto, meu objetivo é, geralmente, para levar as pessoas para onde eles podem descobrir a próxima resposta si e para que você geralmente deseja colocar para fora o processo de pensamento para chegar à resposta.
Talvez a sua resposta poderia ser: "Porque o compilador não sabe quão grande é a matriz é."
Seu exemplo poderia funcionar se não houvesse tamanhos de matriz explícitas (talvez com um typedef para maior clareza), e então você pode explicar ponteiros enquanto a introdução de alocações de tamanho variável.