¿Cómo inicializar todos los miembros de una matriz con el mismo valor?

7 minutos de lectura

avatar de usuario
Mate

Tengo una gran variedad en C (no C++ si eso hace la diferencia). Quiero inicializar todos los miembros del mismo valor.

Podría jurar que una vez conocí una manera simple de hacer esto. Podría usar memset() en mi caso, pero ¿no hay una manera de hacer esto que esté integrada en la sintaxis de C?

  • Ninguna de las respuestas hasta ahora menciona la notación del inicializador designado que es factible con C99 y superior. Por ejemplo: enum { HYDROGEN = 1, HELIUM = 2, CARBON = 6, NEON = 10, … }; y struct element { char name[15]; char symbol[3]; } elements[] = { [NEON] = { "Neon", "Ne" }, [HELIUM] = { "Helium", "He" }, [HYDROGEN] = { "Hydrogen", "H" }, [CARBON] = { "Carbon", "C" }, … };. Si quitas los puntos suspensivos esos fragmentos se compilan en C99 o C11.

    –Jonathan Leffler

    11 mayo 2014 a las 14:40


  • En realidad, la respuesta de abelenky está usando un inicializador designado, pero no es un código de inicialización completamente formado

    – Rob11311

    5 de junio de 2014 a las 14:17


  • memset() puede ayudar, pero depende del valor.

    – Nick

    13 de febrero de 2015 a las 12:23

  • memset() discusión específica: stackoverflow.com/questions/7202411/… Creo que solo funciona para 0.

    – Ciro Santilli Путлер Капут 六四事

    10 mayo 2016 a las 18:55

avatar de usuario
qrdl

Si su compilador es GCC, puede usar la siguiente sintaxis de “extensión GNU”:

int array[1024] = {[0 ... 1023] = 5};

Echa un vistazo a la descripción detallada:
http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html

  • Y esa sintaxis provoca un gran aumento en el tamaño del archivo de los binarios compilados. ¡Para N = 65536 (en lugar de 1024), mi binario salta de 15 KB a 270 KB de tamaño!

    – Cetina Sert

    28 de marzo de 2013 a las 15:15


  • El compilador @CetinSert tiene que agregar 65536 ints en datos estáticos, que son 256 K, exactamente el aumento de tamaño que ha observado.

    – qrdl

    29 de marzo de 2013 a las 9:53

  • @CetinSert ¿Por qué debería? Es un comportamiento estándar del compilador, no específico para los inicializadores designados. Si inicializa estáticamente 65536 intme gusta int foo1 = 1, foo2 = 1, ..., foo65536 =1; obtendrá el mismo aumento de tamaño.

    – qrdl

    29 de marzo de 2013 a las 20:48

  • mejor aún: “matriz int[] = {[0 … 1023] = 5}”, el tamaño de la matriz se establecerá automáticamente en 1024, más fácil y seguro de modificar.

    – François

    11 de abril de 2013 a las 9:19

  • @Francois o para una matriz 2d, bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true}aunque no estoy seguro de que sea más legible que el formulario completo.

    usuario67416

    13 de abril de 2013 a las 6:59


avatar de usuario
muviciel

Para inicializar estáticamente una matriz grande con el mismo valor, sin copiar y pegar varias veces, puede usar macros:

#define VAL_1X     42
#define VAL_2X     VAL_1X,  VAL_1X
#define VAL_4X     VAL_2X,  VAL_2X
#define VAL_8X     VAL_4X,  VAL_4X
#define VAL_16X    VAL_8X,  VAL_8X
#define VAL_32X    VAL_16X, VAL_16X
#define VAL_64X    VAL_32X, VAL_32X

int myArray[53] = { VAL_32X, VAL_16X, VAL_4X, VAL_1X };

Si necesita cambiar el valor, debe hacer el reemplazo en un solo lugar.

Editar: posibles extensiones útiles

(cortesía de Jonathan Leffler)

Puedes generalizar esto fácilmente con:

#define VAL_1(X) X
#define VAL_2(X) VAL_1(X), VAL_1(X)
/* etc. */

Se puede crear una variante usando:

#define STRUCTVAL_1(...) { __VA_ARGS__ }
#define STRUCTVAL_2(...) STRUCTVAL_1(__VA_ARGS__), STRUCTVAL_1(__VA_ARGS__)
/*etc */ 

que trabaja con estructuras o arreglos compuestos.

#define STRUCTVAL_48(...) STRUCTVAL_32(__VA_ARGS__), STRUCTVAL_16(__VA_ARGS__)

struct Pair { char key[16]; char val[32]; };
struct Pair p_data[] = { STRUCTVAL_48("Key", "Value") };
int a_data[][4] = { STRUCTVAL_48(12, 19, 23, 37) };

los nombres de las macros son negociables.

  • Solo consideraría esto en casos extremos, seguramente un memset es la forma más elegante de expresarlo.

    – u0b34a0f6ae

    14 de octubre de 2009 a las 10:41

  • Si los datos deben ser aptos para ROM, no se puede usar memset.

    – Profesor Falken

    5 de julio de 2010 a las 9:24

  • El preprocesador en realidad generará el código a partir de #defines. Con dimensiones de matriz más grandes, el tamaño del ejecutable crecerá. Pero definitivamente + por la idea 😉

    – Leónidas

    3 de octubre de 2010 a las 12:31

  • @Alcott, en computadoras viejas y aún en muchos sistemas integrados, el código finalmente se coloca en un EPROM o ROM. ROM-able también ha llegado a significar, en sistemas integrados, “código puesto en flash”, porque tiene aproximadamente las mismas implicaciones, a saber, que la memoria no se puede escribir en tiempo de ejecución. Es decir, no se puede usar memset o cualquier otra instrucción para actualizar o cambiar la memoria. Las constantes, sin embargo, se pueden expresar y mostrar o editar en ROM antes de que se inicie el programa.

    – Profesor Falken

    8 de febrero de 2012 a las 8:49

  • @u0b34a0f6ae: Tenga en cuenta que también puede usar este método si VAL_1X no es un solo entero sino una lista. Al igual que los estados de Amigable, este también es el camino a seguir para los sistemas integrados en los que desea definir los valores de inicio de una EEPROM o memoria Flash. En ambos casos no puedes usar memset().

    – Martín Scharrer

    5 de febrero de 2013 a las 9:01

avatar de usuario
Pedro Mortensen

Una respuesta ligeramente irónica; escribir la declaración

array = initial_value

en su lenguaje con capacidad de matriz favorito (el mío es Fortran, pero hay muchos otros), y vincúlelo a su código C. Probablemente querrá envolverlo para que sea una función externa.

  • Solo consideraría esto en casos extremos, seguramente un memset es la forma más elegante de expresarlo.

    – u0b34a0f6ae

    14 de octubre de 2009 a las 10:41

  • Si los datos deben ser aptos para ROM, no se puede usar memset.

    – Profesor Falken

    5 de julio de 2010 a las 9:24

  • El preprocesador en realidad generará el código a partir de #defines. Con dimensiones de matriz más grandes, el tamaño del ejecutable crecerá. Pero definitivamente + por la idea 😉

    – Leónidas

    3 de octubre de 2010 a las 12:31

  • @Alcott, en computadoras viejas y aún en muchos sistemas integrados, el código finalmente se coloca en un EPROM o ROM. ROM-able también ha llegado a significar, en sistemas integrados, “código puesto en flash”, porque tiene aproximadamente las mismas implicaciones, a saber, que la memoria no se puede escribir en tiempo de ejecución. Es decir, no se puede usar memset o cualquier otra instrucción para actualizar o cambiar la memoria. Las constantes, sin embargo, se pueden expresar y mostrar o editar en ROM antes de que se inicie el programa.

    – Profesor Falken

    8 de febrero de 2012 a las 8:49

  • @u0b34a0f6ae: Tenga en cuenta que también puede usar este método si VAL_1X no es un solo entero sino una lista. Al igual que los estados de Amigable, este también es el camino a seguir para los sistemas integrados en los que desea definir los valores de inicio de una EEPROM o memoria Flash. En ambos casos no puedes usar memset().

    – Martín Scharrer

    5 de febrero de 2013 a las 9:01

Sé que la pregunta original menciona explícitamente C y no C++, pero si usted (como yo) vino aquí buscando una solución para las matrices de C++, aquí tiene un buen truco:

Si su compilador es compatible expresiones de plieguepuedes usar plantillas mágicas y std::index_sequence para generar una lista de inicializadores con el valor que desee. E incluso puedes constexpr y siéntete como un jefe:

#include <array>

/// [3]
/// This functions's only purpose is to ignore the index given as the second
/// template argument and to always produce the value passed in.
template<class T, size_t /*ignored*/>
constexpr T identity_func(const T& value) {
    return value;
}

/// [2]
/// At this point, we have a list of indices that we can unfold
/// into an initializer list using the `identity_func` above.
template<class T, size_t... Indices>
constexpr std::array<T, sizeof...(Indices)>
make_array_of_impl(const T& value, std::index_sequence<Indices...>) {
    return {identity_func<T, Indices>(value)...};
}

/// [1]
/// This is the user-facing function.
/// The template arguments are swapped compared to the order used
/// for std::array, this way we can let the compiler infer the type
/// from the given value but still define it explicitly if we want to.
template<size_t Size, class T>
constexpr std::array<T, Size> 
make_array_of(const T& value) {
    using Indices = std::make_index_sequence<Size>;
    return make_array_of_impl(value, Indices{});
}

// std::array<int, 4>{42, 42, 42, 42}
constexpr auto test_array = make_array_of<4/*, int*/>(42);
static_assert(test_array[0] == 42);
static_assert(test_array[1] == 42);
static_assert(test_array[2] == 42);
static_assert(test_array[3] == 42);
// static_assert(test_array[4] == 42); out of bounds

Puedes echar un vistazo a la código en el trabajo (en la caja de varitas mágicas)

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad