Inicialización de una matriz normal con un valor predeterminado [duplicar]
Esta pregunta ya tiene una respuesta aquí:
Notas de C++: La inicialización de matrices tiene una buena lista sobre la inicialización de matrices. Tengo un
int array[100] = {-1};
Esperando que esté lleno con -1 pero no es, solo el primer valor es y el resto son 0 mezclados con aleatorio valor.
El código
int array[100] = {0};
Funciona muy bien y establece cada elemento en 0.
Qué me estoy perdiendo aquí.. No se puede inicializar si el valor no es cero ?
2: ¿La inicialización predeterminada (como la anterior ) es más rápida que el bucle habitual a través de toda la matriz y asigna un valor o hace lo mismo?
13 answers
Usando la sintaxis que usaste,
int array[100] = {-1};
Dice: "establecer el primer elemento a -1
y el resto a 0
" ya que todos los elementos omitidos se establecen a 0
.
En C++, para establecer todos a -1
, puede usar algo como std::fill_n
(desde <algorithm>
):
std::fill_n(array, 100, -1);
En portable C, tienes que rodar tu propio bucle. Hay extensiones de compilador o puede depender del comportamiento definido por la implementación como un acceso directo si es aceptable.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-08 23:21:12
Hay una extensión para el compilador gcc que permite la sintaxis:
int array[100] = { [0 ... 99] = -1 };
Esto establecería todos los elementos en -1.
Esto se conoce como "Inicializadores designados" ver aquí para más información.
Tenga en cuenta que esto no está implementado para el compilador de c++ de gcc.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-30 20:22:06
La página a la que enlazaste ya dio la respuesta a la primera parte:
Si un tamaño de matriz explícito es especificado, pero más corto se especifica la lista de inicialización, los elementos no especificados se ponen a cero.
No hay una forma integrada de inicializar toda la matriz a un valor distinto de cero.
En cuanto a cuál es más rápido, se aplica la regla habitual: "El método que da al compilador la mayor libertad es probablemente más rápido".
int array[100] = {0};
Simplemente le dice a la compilador "establecer estos 100 ints a cero", que el compilador puede optimizar libremente.
for (int i = 0; i < 100; ++i){
array[i] = 0;
}
Es mucho más específico. Le dice al compilador que cree una variable de iteración i
, le dice el orden en el que los elementos deben inicializarse, y así sucesivamente. Por supuesto, es probable que el compilador optimice eso, pero el punto es que aquí está sobreespecificando el problema, forzando al compilador a trabajar más duro para llegar al mismo resultado.
Finalmente, si desea establecer la array a un valor distinto de cero, debe (en C++, al menos) usar std::fill
:
std::fill(array, array+100, 42); // sets every value in the array to 42
De nuevo, podría hacer lo mismo con un array, pero esto es más conciso, y le da al compilador más libertad. Solo estás diciendo que quieres que toda la matriz llena con el valor 42. No dices nada sobre en qué orden debe hacerse, o cualquier otra cosa.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-30 20:18:27
C++11 tiene otra opción (imperfecta):
std::array<int, 100> a;
a.fill(-1);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-11 09:20:27
Con {} se asignan los elementos tal como se declaran; el resto se inicializa con 0.
Si no hay = {}
para inicializar, el contenido es indefinido.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-30 20:13:35
La página a la que ha vinculado indica
Si se especifica un tamaño de matriz explícito, pero se especifica una lista de inicialización más corta, los elementos no especificados se ponen a cero.
Problema de velocidad: Cualquier diferencia sería insignificante para matrices tan pequeñas. Si trabaja con matrices grandes y la velocidad es mucho más importante que el tamaño, puede tener una matriz const de los valores predeterminados (inicializados en tiempo de compilación) y luego memcpy
a la matriz modificable.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-30 20:14:46
Otra forma de inicializar la matriz a un valor común, sería generar realmente la lista de elementos en una serie de define:
#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 )
La inicialización de una matriz a un valor común se puede hacer fácilmente:
#define LIST_MAX 6
static unsigned char List[ LIST_MAX ]= { DUP( 123, LIST_MAX ) };
Nota: DUPx introducido para habilitar la sustitución de macro en parámetros a DUP
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-23 08:39:57
Usando std::array
, podemos hacer esto de una manera bastante sencilla en C++14. Es posible hacerlo solo en C++11, pero un poco más complicado.
Nuestra interfaz es un tamaño en tiempo de compilación y un valor predeterminado.
template<typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, 0>, T &&) {
return std::array<std::decay_t<T>, 0>{};
}
template<std::size_t size, typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, size>, T && value) {
return detail::make_array_n_impl<size>(std::forward<T>(value), std::make_index_sequence<size - 1>{});
}
template<std::size_t size, typename T>
constexpr auto make_array_n(T && value) {
return make_array_n(std::integral_constant<std::size_t, size>{}, std::forward<T>(value));
}
La tercera función es principalmente por conveniencia, por lo que el usuario no tiene que construir un std::integral_constant<std::size_t, size>
ellos mismos, ya que es una construcción bastante prolija. El trabajo real es realizado por una de las dos primeras funciones.
La primera sobrecarga es bastante sencilla: Construye un std::array
de tamaño 0. No es necesario copiar, solo lo construimos.
La segunda sobrecarga es un poco más complicada. Reenvía a lo largo del valor que obtuvo como fuente, y también construye una instancia de make_index_sequence
y simplemente llama a alguna otra función de implementación. ¿Cómo se ve esa función?
namespace detail {
template<std::size_t size, typename T, std::size_t... indexes>
constexpr auto make_array_n_impl(T && value, std::index_sequence<indexes...>) {
// 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<std::decay_t<T>, size>{ (static_cast<void>(indexes), value)..., std::forward<T>(value) };
}
} // namespace detail
Esto construye los primeros argumentos de tamaño-1 copiando el valor que pasamos. Aquí, usamos nuestros índices de paquetes de parámetros variádicos como algo para expandir. Hay entradas de tamaño-1 en ese paquete (como especificamos en la construcción de make_index_sequence
), y tienen valores de 0, 1, 2, 3, ... tamaño 2. Sin embargo, no nos importan los valores (por lo que lo lanzamos a void, para silenciar cualquier advertencia del compilador). La expansión del paquete de parámetros expande nuestro código a algo como esto (asumiendo tamaño == 4):
return std::array<std::decay_t<T>, 4>{ (static_cast<void>(0), value), (static_cast<void>(1), value), (static_cast<void>(2), value), std::forward<T>(value) };
Usamos esos paréntesis para asegurarnos de que la expansión de paquetes variádicos ...
expande lo que queremos, y también para asegurarnos de que estamos usando el operador de coma. Sin los paréntesis, parecería que estamos pasando un montón de argumentos a nuestra inicialización de matriz, pero en realidad, estamos evaluando el índice, lanzándolo a void, ignorando ese resultado void, y luego devolviendo el valor, que se copia en la matriz.
El argumento final, el que llamamos std::forward
on, es una optimización menor. Si alguien pasa una cadena std::temporal y dice "hacer una matriz de 5 de estos", nos gustaría tener 4 copias y 1 movimiento, en lugar de 5 copias. El std::forward
asegura que hagamos esto.
El código completo, incluyendo encabezados y algunas pruebas unitarias:
#include <array>
#include <type_traits>
#include <utility>
namespace detail {
template<std::size_t size, typename T, std::size_t... indexes>
constexpr auto make_array_n_impl(T && value, std::index_sequence<indexes...>) {
// 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<std::decay_t<T>, size>{ (static_cast<void>(indexes), value)..., std::forward<T>(value) };
}
} // namespace detail
template<typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, 0>, T &&) {
return std::array<std::decay_t<T>, 0>{};
}
template<std::size_t size, typename T>
constexpr auto make_array_n(std::integral_constant<std::size_t, size>, T && value) {
return detail::make_array_n_impl<size>(std::forward<T>(value), std::make_index_sequence<size - 1>{});
}
template<std::size_t size, typename T>
constexpr auto make_array_n(T && value) {
return make_array_n(std::integral_constant<std::size_t, size>{}, std::forward<T>(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<std::decay_t<decltype(array_n)>::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.");
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-03 04:53:05
1) Cuando se utiliza un inicializador, para una estructura o una matriz como esa, los valores no especificados se construyen esencialmente por defecto. En el caso de un tipo primitivo como ints, eso significa que serán puestos a cero. Tenga en cuenta que esto se aplica recursivamente: podría tener una matriz de estructuras que contengan matrices y si especifica solo el primer campo de la primera estructura, entonces todo el resto se inicializará con ceros y constructores predeterminados.
2) El compilador probablemente generará el inicializador código que es al menos tan bueno como se puede hacer a mano. Tiendo a preferir dejar que el compilador haga la inicialización por mí, cuando sea posible.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-30 20:15:56
Para el caso de una matriz de elementos de un solo byte, puede usar memset para establecer todos los elementos en el mismo valor.
Hay un ejemplo aquí.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-01 07:31:49
En C++, también es posible usar meta programación y plantillas variádicas. El siguiente post muestra cómo hacerlo: Crear programáticamente arrays estáticos en tiempo de compilación en C++.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:33:24
En el lenguaje de programación C++ V4, Stroustrup recomienda usar vectores o valarrays sobre arrays integrados. Con valarrary, cuando los creas, puedes inicializarlos a un valor específico como:
valarray <int>seven7s=(7777777,7);
Para inicializar un array de 7 miembros largos con "7777777".
Esta es una forma de C++ de implementar la respuesta usando una estructura de datos de C++ en lugar de una matriz "C simple".
Cambié a usar el valarray como un intento en mi código para intentar usar C++'isms v.C'isms....
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-14 01:21:50
Debería ser una característica estándar, pero por alguna razón no está incluida en C ni C++estándar...
#include <stdio.h>
__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]);
}
}
En Fortran se puede hacer:
program main
implicit none
byte a(100)
data a /100*2/
integer i
do i = 0, 100
print *, a(i)
end do
end
Pero no tiene números sin signo...
¿Por qué C/C++ no puede simplemente implementarlo? Es realmente tan difícil? Es tan tonto tener que escribir esto manualmente para lograr el mismo resultado...
#include <stdio.h>
#include <stdint.h>
/* 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]);
}
}
¿Y si fuera una matriz de 1.000.00 bytes? Tendría que escribir un script para escribirlo por mí, o recurrir a hacks con assembly / etc. Esto es disparate.
Es perfectamente portátil, no hay razón para que no esté en el idioma.
Simplemente hackearlo como:
#include <stdio.h>
#include <stdint.h>
/* 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;
}
Una forma de hackearlo es a través del preprocesamiento... (El código a continuación no cubre casos extremos, pero está escrito para demostrar rápidamente lo que se podría hacer.)
#!/usr/bin/perl
use warnings;
use strict;
open my $inf, "<main.c";
open my $ouf, ">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);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-03 11:55:15