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 ++?

Foi útil?

Solução

Há três coisas que você precisa explicar para a pessoa que você está tentando ajudar:

  1. 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 uma int separado (bem, size_t, mas eu não iria incomodar dizendo que) argumento. Você pode obter o endereço do início de alguns myArray 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 exemplo int 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é fazer Numbers += 5 dentro DoSomething() para torná-lo apontar para uma matriz começando na sexta posição

  2. Quando declarar uma variável de matriz, tais como SomeArray em C ++, tem de proporcionar um tamanho explícito ou uma "lista initialiser" , 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 ...

  3. 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 da SomeArray (novamente como dizer 1000), o int SomeArray[1000] = Numbers; linha seria ilegal.


Para fazer o que você quer fazer na DoSomething(), primeiro pergunte-se:

  1. Preciso alterar qualquer um dos valores em Numbers?
  2. 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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top