Declarar e inicializar arreglos en C

7 minutos de lectura

avatar de usuario
david h

¿Hay alguna manera de declarar primero y luego inicializar una matriz en C?

Hasta ahora he estado inicializando una matriz como esta:

int myArray[SIZE] = {1,2,3,4....};

Pero necesito hacer algo como esto.

int myArray[SIZE];

myArray = {1,2,3,4....};

En C99 puedes hacerlo usando un literal compuesto en combinación con memcpy

memcpy(myarray, (int[]) { 1, 2, 3, 4 }, sizeof myarray);

(asumiendo que el tamaño de la fuente y el tamaño del destino es el mismo).

En C89/90 puede emular eso declarando una matriz de “fuente” adicional

const int SOURCE[SIZE] = { 1, 2, 3, 4 }; /* maybe `static`? */
int myArray[SIZE];
...
memcpy(myarray, SOURCE, sizeof myarray);

  • yo diría definitivamente static.

    – café

    29 de junio de 2010 a las 3:48

  • Creo que la forma más conveniente en mi caso, en lugar de asignar cada elemento, copiar cada matriz deseada en una matriz global. Muchas gracias

    – Dave H.

    29 de junio de 2010 a las 3:59

  • +1 para C99. 😉 memcpy(myarray,(int [sizeof(myarray)/sizeof(myarray[0])]{1,2,3,4},tamañode mimatriz); para iniciar el resto a cero apropiado.

    – Nyan

    29 de junio de 2010 a las 6:31

  • @Nyan: Gran idea. Esto también generará un error si hay demasiados inicializadores.

    – Ant

    29 de junio de 2010 a las 6:52


  • He publicado un apéndice a su respuesta que también desencadenará un error de tiempo de compilación si hay demasiado pocos inicializadores.

    –Joseph Quinsey

    30 de junio de 2010 a las 14:38

avatar de usuario
paxdiablo

No, no puede establecerlos en valores arbitrarios en una declaración (a menos que se haga como parte de la declaración).

Puedes hacerlo con código, algo como:

myArray[0] = 1;
myArray[1] = 2;
myArray[2] = 27;
:
myArray[99] = -7;

o (si hay una fórmula):

for (int i = 0; i < 100; i++) myArray[i] = i + 1;

La otra posibilidad es mantener algunas plantillas que están establezca en el momento de la declaración y utilícelos para inicializar su matriz, algo como:

static const int onceArr[]  = {  0,  1,  2,  3,  4,..., 99};
static const int twiceArr[] = {  0,  2,  4,  6,  8,...,198};
:
int myArray[7];
:
memcpy (myArray, twiceArr, sizeof (myArray));

Esto tiene la ventaja de (probablemente) ser más rápido y le permite crear arreglos más pequeños que las plantillas. He usado este método en situaciones en las que tengo que reinicializar una matriz rápidamente pero en un estado específico (si el estado fuera todo ceros, simplemente usaría memset).


Incluso puede localizarlo en una función de inicialización:

void initMyArray (int *arr, size_t sz) {
    static const int template[] = {2, 3, 5, 7, 11, 13, 17, 19, 21, ..., 9973};
    memcpy (arr, template, sz);
}
:
int myArray[100];
initMyArray (myArray, sizeof(myArray));

La matriz estática se creará (casi con certeza) en el momento de la compilación, por lo que no habrá costo de tiempo de ejecución para eso, y el memcpy debería ser deslumbrantemente rápido, probablemente más rápido que 1,229 declaraciones de asignación pero definitivamente menos tipeo de su parte :-).

¿Hay alguna manera de declarar primero y luego inicializar una matriz en C?

¡Hay! pero no usando el método que describiste.

No puede inicializar con una lista separada por comas, esto solo está permitido en la declaración. Sin embargo, puede inicializar con…

myArray[0] = 1;
myArray[1] = 2;
...

o

for(int i = 1; i <= SIZE; i++)
{
  myArray[i-1] = i;
}

  • Gracias, pero lo que estaba buscando era poder inicializarlo en una lista separada por comas, porque esas matrices serán muy grandes y pensé que sería más conveniente de esa manera.

    – Dave H.

    29 de junio de 2010 a las 3:53

avatar de usuario
jose quinsey

Esta es una adición a la respuesta aceptada por AndreyT, con el comentario de Nyan sobre los tamaños de matriz que no coinciden. No estoy de acuerdo con su configuración automática del quinto elemento a cero. probablemente debería ser 5 –el número después de 1,2,3,4. Así que sugeriría un envoltorio para memcpy() para producir un tiempo de compilación error cuando intentamos copiar matrices de diferentes tamaños:

#define Memcpy(a,b) do {                    /* copy arrays */       \
    ASSERT(sizeof(a) == sizeof(b) &&        /* a static assert */   \
           sizeof(a) != sizeof((a) + 0));   /* no pointers */       \
    memcpy((a), (b), sizeof (b));           /* & unnecesary */      \
    } while (0)                             /* no return value */

Esta macro generará un error de tiempo de compilación si su matriz tiene una longitud de 1. Lo cual es quizás una característica.

Debido a que estamos usando una macro, el literal compuesto C99 parece necesitar un par de paréntesis adicionales:

Memcpy(myarray, ((int[]) { 1, 2, 3, 4 }));

Aquí ASSERT() es una ‘afirmación estática’. Si aún no tiene uno propio, uso lo siguiente en varias plataformas:

#define CONCAT_TOKENS(a, b) a ## b
#define EXPAND_THEN_CONCAT(a,b) CONCAT_TOKENS(a, b)
#define ASSERT(e) enum {EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__) = 1/!!(e)}
#define ASSERTM(e,m) /* version of ASSERT() with message */ \
    enum{EXPAND_THEN_CONCAT(m##_ASSERT_line_,__LINE__)=1/!!(e)}

¿Por qué no puedes inicializar cuando declaras?

¿Qué compilador de C estás usando? ¿Es compatible con C99?

Si es compatible con C99, puede declarar la variable donde la necesite e inicializarla cuando la declare.

La única excusa en la que puedo pensar para no hacerlo sería porque necesita declararlo pero hacer una salida anticipada antes de usarlo, por lo que el inicializador se desperdiciaría. Sin embargo, sospecho que cualquier código de este tipo no está tan claramente organizado como debería y podría escribirse para que no fuera un problema.

  • ¡Gracias por la rápida respuesta! Necesito inicializar después de declarar, porque será diferente dependiendo de una condición, me refiero a algo como esto int myArray[SIZE]; if(condición1) { miMatriz{x1, x2, x3, …} } else if(condición2) { miMatriz{y1, y2, y3, …} } . . y así. estoy usando xcode

    – Dave H.

    29 de junio de 2010 a las 3:47


  • ¿Las matrices son constantes? Si es así, una posibilidad es usar dos matrices constantes inicializadas separadas y luego establecer un puntero (a datos constantes) para apuntar a la matriz relevante. También haría que las matrices fueran estáticas. Si las matrices no son constantes, entonces creo que está atascado calculando cada elemento por turno.

    –Jonathan Leffler

    29 de junio de 2010 a las 5:13

  • Sí, las matrices son constantes, también probaré este método, gracias.

    – Dave H.

    29 de junio de 2010 a las 13:47

El OP omitió información crucial de la pregunta y solo la puso en un comentario a una respuesta.

Necesito inicializar después de declarar, porque será diferente dependiendo de una condición, me refiero a algo como esto int myArray[SIZE]; if(condición1) { miMatriz{x1, x2, x3, …} } else if(condición2) { miMatriz{y1, y2, y3, …} } . . y así…

Con esto en mente, todas las matrices posibles deberán almacenarse en datos en algún lugar de todos modos, por lo que no se necesita (o desea) memcpy, solo se requiere un puntero y una matriz 2d.

//static global since some compilers build arrays from instruction data
//... notably not const though so they can later be modified if needed
#define SIZE 8
static int myArrays[2][SIZE] = {{0,1,2,3,4,5,6,7},{7,6,5,4,3,2,1,0}};

static inline int *init_myArray(_Bool conditional){
  return myArrays[conditional];
}

// now you can use:
//int *myArray = init_myArray(1 == htons(1)); //any boolean expression

La versión no en línea proporciona este ensamblaje resultante en x86_64:

init_myArray(bool):
        movzx   eax, dil
        sal     rax, 5
        add     rax, OFFSET FLAT:myArrays
        ret
myArrays:
        .long   0
        .long   1
        .long   2
        .long   3
        .long   4
        .long   5
        .long   6
        .long   7
        .long   7
        .long   6
        .long   5
        .long   4
        .long   3
        .long   2
        .long   1
        .long   0

Para condicionales/matrices adicionales, simplemente cambie el 2 en myArrays al número deseado y use una lógica similar para obtener un puntero a la matriz correcta.

  • ¡Gracias por la rápida respuesta! Necesito inicializar después de declarar, porque será diferente dependiendo de una condición, me refiero a algo como esto int myArray[SIZE]; if(condición1) { miMatriz{x1, x2, x3, …} } else if(condición2) { miMatriz{y1, y2, y3, …} } . . y así. estoy usando xcode

    – Dave H.

    29 de junio de 2010 a las 3:47


  • ¿Las matrices son constantes? Si es así, una posibilidad es usar dos matrices constantes inicializadas separadas y luego establecer un puntero (a datos constantes) para apuntar a la matriz relevante. También haría que las matrices fueran estáticas. Si las matrices no son constantes, entonces creo que está atascado calculando cada elemento por turno.

    –Jonathan Leffler

    29 de junio de 2010 a las 5:13

  • Sí, las matrices son constantes, también probaré este método, gracias.

    – Dave H.

    29 de junio de 2010 a las 13:47

No es posible asignar valores a una matriz todos a la vez después de la inicialización. La mejor alternativa sería usar un bucle.

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

Puede codificar y asignar valores como —array[0] = 1 y así.

Memcpy también se puede usar si ya tiene los datos almacenados en una matriz.

¿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