Inicialização de uma matriz normal com um valor padrão

C ++ Notas: Inicialização de matriz tem uma boa lista sobre boot de matrizes. eu tenho um

int array[100] = {-1}; 

esperando que ele esteja cheio com -1, mas não é, apenas o primeiro valor é e o resto é 0 misturado com valores randoms.

O código

 int array[100] = {0}; 

funciona muito bem e define cada elemento como 0.

O que estou perdendo aqui .. Não é possível inicializá-lo se o valor não for zero?

2: A boot padrão (como acima) é mais rápida do que o loop usual em toda a matriz e atribui um valor ou faz a mesma coisa?

Usando a syntax que você usou,

 int array[100] = {-1}; 

diz “defina o primeiro elemento como -1 e o restante como 0 “, pois todos os elementos omitidos são definidos como 0 .

Em C ++, para definir todos como -1 , você pode usar algo como std::fill_n (de ):

 std::fill_n(array, 100, -1); 

No portátil C, você tem que rolar seu próprio loop. Existem extensões de compilador ou você pode depender do comportamento definido pela implementação como um atalho, se isso for aceitável.

Existe uma extensão para o compilador gcc que permite a syntax:

 int array[100] = { [0 ... 99] = -1 }; 

Isso definiria todos os elementos como -1.

Isto é conhecido como “Initializers designados” veja aqui para mais informações.

Observe que isso não está implementado no compilador gcc c ++.

A página que você ligou já deu a resposta para a primeira parte:

Se um tamanho de matriz explícito for especificado, mas uma lista de boot mais curta for especificada, os elementos não especificados serão definidos como zero.

Não há nenhuma maneira interna de inicializar a matriz inteira para algum valor diferente de zero.

Quanto ao que é mais rápido, a regra usual se aplica: “O método que dá mais liberdade ao compilador é provavelmente mais rápido”.

 int array[100] = {0}; 

simplesmente diz ao compilador “configure esses 100 ints para zero”, que o compilador pode otimizar livremente.

 for (int i = 0; i < 100; ++i){ array[i] = 0; } 

é muito mais específico. Ele diz ao compilador para criar uma variável de iteração i , informa a ordem em que os elementos devem ser inicializados e assim por diante. É claro que o compilador provavelmente otimizará isso, mas o ponto é que aqui você está superespecificando o problema, forçando o compilador a trabalhar mais para chegar ao mesmo resultado.

Finalmente, se você quiser definir a matriz para um valor diferente de zero, você deve (em C ++, pelo menos) usar std::fill :

 std::fill(array, array+100, 42); // sets every value in the array to 42 

Novamente, você poderia fazer o mesmo com uma matriz, mas isso é mais conciso e dá ao compilador mais liberdade. Você está apenas dizendo que você quer toda a matriz preenchida com o valor 42. Você não diz nada sobre em que ordem deve ser feito, ou qualquer outra coisa.

C ++ 11 tem outra opção (imperfeita):

 std::array a; a.fill(-1); 

Com {} você atribui os elementos como eles são declarados; o resto é inicializado com 0.

Se não houver = {} para iniciar, o conteúdo é indefinido.

A página que você vinculou

Se um tamanho de matriz explícito for especificado, mas uma lista de boot mais curta for especificada, os elementos não especificados serão definidos como zero.

Problema de velocidade: Quaisquer diferenças seriam insignificantes para matrizes tão pequenas. Se você trabalha com grandes matrizes e a velocidade é muito mais importante que o tamanho, você pode ter uma matriz const dos valores padrão (inicializados em tempo de compilation) e então memcpy los para a matriz modificável.

Outra maneira de inicializar a matriz para um valor comum seria gerar a lista de elementos em uma série de definições:

 #define DUP1( X ) ( X ) #define DUP2( X ) DUP1( X ), ( X ) #define DUP3( X ) DUP2( X ), ( X ) #define DUP4( X ) DUP3( X ), ( X ) #define DUP5( X ) DUP4( X ), ( X ) . . #define DUP100( X ) DUP99( X ), ( X ) #define DUPx( X, N ) DUP##N( X ) #define DUP( X, N ) DUPx( X, N ) 

Inicializar uma matriz para um valor comum pode ser feito facilmente:

 #define LIST_MAX 6 static unsigned char List[ LIST_MAX ]= { DUP( 123, LIST_MAX ) }; 

Nota: DUPx introduzido para ativar a substituição de macros em parâmetros para DUP

Usando std::array , podemos fazer isso de uma maneira bastante direta em C ++ 14. É possível fazer apenas no C ++ 11, mas um pouco mais complicado.

Nossa interface é um tamanho de tempo de compilation e um valor padrão.

 template constexpr auto make_array_n(std::integral_constant, T &&) { return std::array, 0>{}; } template constexpr auto make_array_n(std::integral_constant, T && value) { return detail::make_array_n_impl(std::forward(value), std::make_index_sequence{}); } template constexpr auto make_array_n(T && value) { return make_array_n(std::integral_constant{}, std::forward(value)); } 

A terceira function é principalmente por conveniência, então o usuário não tem que construir um std::integral_constant si mesmo, já que é uma construção bastante prolixa. O trabalho real é feito por uma das duas primeiras funções.

A primeira sobrecarga é bem direta: ela constrói um std::array de tamanho 0. Não há necessidade de cópia, apenas a construímos.

A segunda sobrecarga é um pouco mais complicada. Ele encaminha o valor que obteve como fonte e também constrói uma instância de make_index_sequence e apenas chama alguma outra function de implementação. Como é essa function?

 namespace detail { template constexpr auto make_array_n_impl(T && value, std::index_sequence) { // Use the comma operator to expand the variadic pack // Move the last element in if possible. Order of evaluation is well-defined // for aggregate initialization, so there is no risk of copy-after-move return std::array, size>{ (static_cast(indexes), value)..., std::forward(value) }; } } // namespace detail 

Isso constrói os primeiros argumentos size – 1 copiando o valor que passamos. Aqui, usamos nossos índices de pacotes de parâmetros variadicos como algo para expandir. Existem tamanho – 1 inputs nesse pacote (como especificamos na construção de make_index_sequence ), e elas possuem valores de 0, 1, 2, 3, …, tamanho – 2. No entanto, não nos importamos com os valores (então nós lançamos isso para anular, para silenciar qualquer aviso do compilador). A expansão do pacote de parâmetros expande nosso código para algo como isto (assumindo tamanho == 4):

 return std::array, 4>{ (static_cast(0), value), (static_cast(1), value), (static_cast(2), value), std::forward(value) }; 

Usamos esses parênteses para garantir que a expansão do pacote variádico ... amplie o que queremos e também para garantir que estamos usando o operador de vírgula. Sem os parênteses, pareceria que estamos passando um monte de argumentos para a boot da matriz, mas, na verdade, estamos avaliando o índice, lançando-o para anular, ignorando esse resultado vazio e retornando o valor, que é copiado para a matriz .

O argumento final, aquele a que chamamos std::forward , é uma otimização secundária. Se alguém passar em um std :: string temporário e disser “criar um array de 5”, gostaríamos de ter 4 cópias e 1 movimento, em vez de 5 cópias. O std::forward garante que façamos isso.

O código completo, incluindo headers e alguns testes de unidade:

 #include  #include  #include  namespace detail { template constexpr auto make_array_n_impl(T && value, std::index_sequence) { // Use the comma operator to expand the variadic pack // Move the last element in if possible. Order of evaluation is well-defined // for aggregate initialization, so there is no risk of copy-after-move return std::array, size>{ (static_cast(indexes), value)..., std::forward(value) }; } } // namespace detail template constexpr auto make_array_n(std::integral_constant, T &&) { return std::array, 0>{}; } template constexpr auto make_array_n(std::integral_constant, T && value) { return detail::make_array_n_impl(std::forward(value), std::make_index_sequence{}); } template constexpr auto make_array_n(T && value) { return make_array_n(std::integral_constant{}, std::forward(value)); } struct non_copyable { constexpr non_copyable() = default; constexpr non_copyable(non_copyable const &) = delete; constexpr non_copyable(non_copyable &&) = default; }; int main() { constexpr auto array_n = make_array_n<6>(5); static_assert(std::is_same::value_type, int>::value, "Incorrect type from make_array_n."); static_assert(array_n.size() == 6, "Incorrect size from make_array_n."); static_assert(array_n[3] == 5, "Incorrect values from make_array_n."); constexpr auto array_non_copyable = make_array_n<1>(non_copyable{}); static_assert(array_non_copyable.size() == 1, "Incorrect array size of 1 for move-only types."); constexpr auto array_empty = make_array_n<0>(2); static_assert(array_empty.empty(), "Incorrect array size for empty array."); constexpr auto array_non_copyable_empty = make_array_n<0>(non_copyable{}); static_assert(array_non_copyable_empty.empty(), "Incorrect array size for empty array of move-only."); } 

1) Quando você usa um inicializador, para uma struct ou uma matriz como essa, os valores não especificados são essencialmente construídos por padrão. No caso de um tipo primitivo como ints, isso significa que eles serão zerados. Observe que isso se aplica recursivamente: você pode ter uma matriz de structs contendo arrays e, se especificar apenas o primeiro campo da primeira struct, todo o resto será inicializado com zeros e construtores padrão.

2) O compilador provavelmente irá gerar código inicializador que seja pelo menos tão bom quanto você poderia fazer manualmente. Eu costumo preferir deixar o compilador fazer a boot para mim, quando possível.

Para o caso de uma matriz de elementos de byte único, você pode usar memset para definir todos os elementos com o mesmo valor.

Há um exemplo aqui .

Em C ++, também é possível usar meta templates e variadic templates. A postagem a seguir mostra como fazer isso: Criar matrizes estáticas programaticamente no tempo de compilation em C ++ .

Na linguagem de programação C ++ V4, a Stroustrup recomenda o uso de vetores ou valarrays sobre matrizes incorporadas. Com o valarrary’s, quando você as cria, você pode iniciá-las em um valor específico como:

 valarray seven7s=(7777777,7); 

Para inicializar uma matriz com 7 membros com “7777777”.

Esta é uma maneira C ++ de implementar a resposta usando uma estrutura de dados C ++ em vez de uma matriz “plain old C”.

Eu mudei para usar o valarray como uma tentativa no meu código para tentar usar C ++ ‘isms v. C’isms ….

Deve ser um recurso padrão, mas por algum motivo não está incluído no padrão C nem C ++ …

 #include  __asm__ ( " .global _arr; " " .section .data; " "_arr: .fill 100, 1, 2; " ); extern char arr[]; int main() { int i; for(i = 0; i < 100; ++i) { printf("arr[%u] = %u.\n", i, arr[i]); } } 

Em Fortran você poderia fazer:

 program main implicit none byte a(100) data a /100*2/ integer i do i = 0, 100 print *, a(i) end do end 

mas não tem números não assinados ...

Por que o C / C ++ não pode implementá-lo? Isso é realmente tão difícil? É tão bobo ter que escrever isso manualmente para conseguir o mesmo resultado ...

 #include  #include  /* did I count it correctly? I'm not quite sure. */ uint8_t arr = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, }; int main() { int i; for(i = 0; i < 100; ++i) { printf("arr[%u] = %u.\n", i, arr[i]); } } 

E se fosse uma matriz de 1.000,00 bytes? Eu preciso escrever um script para escrever para mim, ou recorrer a hacks com assembly / etc. Isso não faz sentido.

É perfeitamente portátil, não há razão para não estar no idioma.

Basta cortá-lo como:

 #include  #include  /* a byte array of 100 twos declared at compile time. */ uint8_t twos[] = {100:2}; int main() { uint_fast32_t i; for (i = 0; i < 100; ++i) { printf("twos[%u] = %u.\n", i, twos[i]); } return 0; } 

Uma maneira de fazer isso é através do pré-processamento ... (O código abaixo não cobre casos de borda, mas foi escrito para demonstrar rapidamente o que poderia ser feito).

 #!/usr/bin/perl use warnings; use strict; open my $inf, "out.c"; my @lines = <$inf>; foreach my $line (@lines) { if ($line =~ m/({(\d+):(\d+)})/) { printf ("$1, $2, $3"); my $lnew = "{" . "$3, "x($2 - 1) . $3 . "}"; $line =~ s/{(\d+:\d+)}/$lnew/; printf $ouf $line; } else { printf $ouf $line; } } close($ouf); close($inf);