Como criar um array quando o tamanho é uma variável e não uma constante?

Eu tenho um método que recebe uma variável int. Essa variável constitui um tamanho de matriz (por favor, não me ofereça um vetor). Assim, eu preciso iniciar um const int dentro do meu método para inicializar uma matriz de tamanho específico. Pergunta: como faço isso?

void foo(int variable_int){ int a[variable_int] = {0}; //error } 

 int *a = new int[variable_int]; 

Lembre-se de apagar [] o espaço alocado quando você terminar com ele!

C ++ não suporta matrizes de comprimento variável. Em vez disso, você precisará alocar a matriz dinamicamente:

 std::vector a(variable_int); 

ou porque você diz que não quer usar um vetor por algum motivo:

 class not_a_vector { public: explicit not_a_vector(size_t size) : a(new int[size]()) {} ~not_a_vector() {delete [] a;} int & operator[](size_t i) {return a[i];} int operator[](size_t i) const {return a[i];} not_a_vector(not_a_vector const &) = delete; void operator=(not_a_vector const &) = delete; private: int * a; }; not_a_vector a(variable_int); 

ATUALIZAÇÃO: A questão acaba de ser atualizada com a tag “C”, bem como “C ++”. C (desde 1999) suporta arrays de tamanho variável, então seu código deve estar bem nesse idioma.

Você pode facilmente fazer uma variável const a partir de uma variável não-const, escrevendo const int bar = variable_int; – no entanto, isso não vai ajudar você. Em C ++, o tamanho de um array com armazenamento automático deve ser uma constante de tempo de compilation . Você não pode transformar uma variável em uma constante de tempo de compilation, então o que você quer simplesmente não é possível.

Dependendo de suas necessidades, você poderia fazer a ponteiro e alocar memory usando new (e depois delete lo) ou, se o parâmetro foo sempre for conhecido em tempo de compilation, você poderia transformar foo em uma function de modelo como esta:

 template void foo() { int a[n] = {0}; } 

Você pediu uma solução não vetorial, mas vamos analisá-la porque você pode ter rejeitado isso pelas razões erradas. Você não deve se preocupar com o desempenho, porque nas mãos de qualquer compilador competente, ele terá praticamente a mesma sobrecarga que qualquer outra solução compatível com o padrão. Por outro lado, há algumas questões de legibilidade e segurança que explicarei abaixo. Vejamos as maneiras pelas quais você pode fazer isso do mais recomendado ao mínimo.

std :: vector

O recipiente favorito da comunidade e por um bom motivo. Não só pode ser declarado com um tamanho de tempo de execução, mas o tamanho pode ser alterado a qualquer momento. Isso facilita o uso quando o tamanho não pode ser predeterminado, por exemplo, ao pesquisar repetidamente a input do usuário. Exemplos:

 // Known size size_t n; std::cin >> n; std::vector vec(n); // Unknown size std::vector vec; int input; while (std::cin >> input) { // Note: not always the best way to read input vec.push_back(in); } 

Não há muita desvantagem em usar std::vector . O caso de tamanho conhecido requer exatamente uma alocação dinâmica. O tamanho desconhecido requer mais no caso geral, mas você não seria capaz de melhorar de qualquer maneira. Portanto, o desempenho é mais ou menos ideal.

Semanticamente, pode não ser ideal para tamanhos constantes durante a execução. Pode não ser aparente para o leitor que este contêiner não tem a intenção de mudar. Ele não é conhecido pelo compilador, então ele permitirá que você faça algo errado, como push_back em um vector que seja logicamente de tamanho constante.

std :: unique_ptr (ou std :: shared_ptr)

A solução mais segura se for impor o tamanho estático é importante para você.

 size_t n; std::cin >> n; auto arr = std::make_unique(n); 

O tamanho do arr não pode mudar, embora possa ser feito para liberar o array atual e apontar para outro de tamanho diferente. Portanto, se logicamente o tamanho do seu contêiner é constante, isso transmite a intenção de maneira mais clara. Infelizmente, ele também é muito mais fraco que std::vector mesmo no caso de tamanho constante. Não é ciente do tamanho, então você tem que armazenar explicitamente o tamanho. Pelo mesmo motivo, ele não oferece iteradores e não pode ser usado em intervalos for loops. Cabe a você (e ao projeto em questão) se você deseja sacrificar esses resources para impor o tamanho estático.

Inicialmente, eu recomendei boost::scoped_array mas depois de pensar mais, eu não acredito que tenha muito a oferecer sobre esta solução, então vou continuar com a biblioteca padrão.

novo [] – delete []

Tecnicamente, uma solução, mas a menos que você seja forçado a usar um padrão C ++ antigo ou esteja escrevendo uma biblioteca de baixo nível que gerencia a memory internamente, ela é estritamente pior que a solução std::unique_ptr ou std::shared_ptr . Eles não oferecem mais resources, mas são significativamente menos seguros porque você precisa liberar explicitamente a memory quando estiver pronto. Caso contrário, você irá vazá-lo e isso pode causar problemas significativos. Para piorar, usar delete[] corretamente pode não ser trivial para programas com streams complicados de execução e exception handling. Por favor, não use isso quando as soluções acima estiverem disponíveis para você!

 size_t n; std::cin >> n; int* arr = new int[n]; ... // Control flow must reach exactly one corresponding delete[] !!! delete[] arr; 

Bônus: extensão do compilador

Alguns compiladores podem realmente estar ok com o seguinte código

 size_t n; std::cin >> n; int arr[n]; 

Confiar nisso tem graves inconvenientes. Seu código não pode ser compilado em todos os compiladores em conformidade com o C ++. Provavelmente nem compila em todas as versões do compilador fornecido. Além disso, duvido que o executável produzido verifique o valor de n e aloque no heap quando necessário, o que significa que você pode explodir sua pilha. Essa solução só faz sentido quando você sabe que o limite superior de n é pequeno e quando o desempenho é tão importante para você que você está disposto a confiar em um comportamento específico do compilador para obtê-lo. Estes são casos verdadeiramente excepcionais.

Para fazer o que quiser, você precisará usar a alocação dinâmica. Nesse caso, sugiro seriamente usar o vetor – é a coisa “certa” a ser feita em C ++.

Mas se você ainda não quiser usar o vetor [porque você não está além de mim], o código correto é:

  void foo(int variable_int){ int *a = new int[variable_int](); // Parenthesis to initialize to zero. ... do stuff with a ... delete [] a; } 

Como outros sugerem, você também pode usar calloc, que tem o mesmo efeito de inicializar em zero, mas não é realmente a solução “c ++”.

Se você está usando arrays, é uma boa ideia encapsulá-los:

 template class Vector { //... }; 

A biblioteca padrão vem com uma implementação: std :: vector