arrays initialize - ¿Cómo inicializar todos los miembros de una matriz al mismo valor?




c++ new (17)

Tengo una gran variedad en C (no C ++ si eso hace una diferencia). Quiero inicializar todos los miembros al 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 hacerlo que esté incorporada en la sintaxis de C?


Answers

Para inicializar los tipos de datos "normales" (como int arrays), puede usar la notación de corchetes, pero después de los últimos, los valores serán cero si aún hay espacio en la matriz:

// put values 1-8, then two zeroes
int list[10] = {1,2,3,4,5,6,7,8};

Para inicializar estáticamente una matriz grande con el mismo valor, sin copiar y pegar múltiples, 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.

Edición: 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 funciona con estructuras o matrices compuestas.

#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 macro son negociables


Vi un código que usaba esta sintaxis:

char* array[] = 
{
    [0] = "Hello",
    [1] = "World"
};   

Donde se vuelve particularmente útil es si está creando una matriz que usa enumeraciones como índice:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

#define _ITEM(x) [x] = #x

char* array[] = 
{
    _ITEM(ERR_OK),
    _ITEM(ERR_FAIL),
    _ITEM(ERR_MEMORY)
};   

Esto mantiene las cosas en orden, incluso si escribe algunos de los valores de enumeración fuera de orden.

Puede encontrar más información sobre esta técnica here y here .


Puede hacer todo lo relacionado con el inicializador estático como se detalla arriba, pero puede ser un verdadero fastidio cuando el tamaño de su matriz cambie (cuando su matriz se incremente, si no agrega los inicializadores adicionales apropiados, obtendrá basura).

memset le da un golpe de tiempo de ejecución para hacer el trabajo, pero ningún golpe de tamaño de código hecho correctamente es inmune a los cambios de tamaño de matriz. Usaría esta solución en casi todos los casos cuando la matriz era más grande que, por ejemplo, unas pocas docenas de elementos.

Si fuera realmente importante que la matriz fuera declarada estáticamente, escribiría un programa para escribir el programa por mí y hacerlo parte del proceso de construcción.


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

array = initial_value

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



Si desea asegurarse de que todos los miembros de la matriz estén inicializados explícitamente, simplemente omita la dimensión de la declaración:

int myArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

El compilador deducirá la dimensión de la lista de inicializadores. Desafortunadamente, para matrices multidimensionales solo se puede omitir la dimensión más externa:

int myPoints[][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };

esta bien, pero

int myPoints[][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };

no es.


int i;
for (i = 0; i < ARRAY_SIZE; ++i)
{
  myArray[i] = VALUE;
}

Creo que esto es mejor que

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5...

en caso de que el tamaño de la matriz cambie.


Para la inicialización diferida (es decir, la inicialización del constructor de miembro de clase) considere:

int a[4];

unsigned int size = sizeof(a) / sizeof(a[0]);
for (unsigned int i = 0; i < size; i++)
  a[i] = 0;

Hay una forma rápida de inicializar una matriz de cualquier tipo con un valor dado. Funciona muy bien con matrices grandes. El algoritmo es el siguiente:

  • Inicializar primer elemento de la matriz (forma habitual)
  • copie la parte que se ha establecido en la parte que no se ha configurado, duplicando el tamaño con cada operación de copia siguiente

Para 1 000 000 elementos int array, es 4 veces más rápido que la inicialización de bucle regular (i5, 2 núcleos, 2,3 GHz, memoria de 4GiB, 64 bits):

loop runtime 0.004248 [seconds]

memfill() runtime 0.001085 [seconds]

#include <stdio.h>
#include <time.h>
#include <string.h>
#define ARR_SIZE 1000000

void memfill(void *dest, size_t destsize, size_t elemsize) {
   char   *nextdest = (char *) dest + elemsize;
   size_t movesize, donesize = elemsize;

   destsize -= elemsize;
   while (destsize) {
      movesize = (donesize < destsize) ? donesize : destsize;
      memcpy(nextdest, dest, movesize);
      nextdest += movesize; destsize -= movesize; donesize += movesize;
   }
}    
int main() {
    clock_t timeStart;
    double  runTime;
    int     i, a[ARR_SIZE];

    timeStart = clock();
    for (i = 0; i < ARR_SIZE; i++)
        a[i] = 9;    
    runTime = (double)(clock() - timeStart) / (double)CLOCKS_PER_SEC;
    printf("loop runtime %f [seconds]\n",runTime);

    timeStart = clock();
    a[0] = 10;
    memfill(a, sizeof(a), sizeof(a[0]));
    runTime = (double)(clock() - timeStart) / (double)CLOCKS_PER_SEC;
    printf("memfill() runtime %f [seconds]\n",runTime);
    return 0;
}

Cortar a través de toda la charla, la respuesta corta es que si activa la optimización en tiempo de compilación, no lo hará mejor que esto:

int i,value=5,array[1000]; 
for(i=0;i<1000;i++) array[i]=value; 

Bonificación adicional: el código es realmente legible :)


Sé que el usuario Tarski respondió a esta pregunta de manera similar, pero agregué algunos detalles más. Perdone algo de mi C porque estoy un poco oxidado porque estoy más inclinado a querer usar C ++, pero aquí va.

Si conoce el tamaño de la matriz antes de tiempo ...

#include <stdio.h>

typedef const unsigned int cUINT;
typedef unsigned int UINT;

cUINT size = 10;
cUINT initVal = 5;

void arrayInitializer( UINT* myArray, cUINT size, cUINT initVal );
void printArray( UINT* myArray ); 

int main() {        
    UINT myArray[size]; 
    /* Not initialized during declaration but can be
    initialized using a function for the appropriate TYPE*/
    arrayInitializer( myArray, size, initVal );

    printArray( myArray );

    return 0;
}

void arrayInitializer( UINT* myArray, cUINT size, cUINT initVal ) {
    for ( UINT n = 0; n < size; n++ ) {
        myArray[n] = initVal;
    }
}

void printArray( UINT* myArray ) {
    printf( "myArray = { " );
    for ( UINT n = 0; n < size; n++ ) {
        printf( "%u", myArray[n] );

        if ( n < size-1 )
            printf( ", " );
    }
    printf( " }\n" );
}

Hay algunas advertencias arriba; uno es que UINT myArray[size]; no se inicializa directamente en la declaración, sin embargo, el siguiente bloque de código o llamada de función inicializa cada elemento de la matriz al mismo valor que desea. La otra advertencia es que tendría que escribir una initializing function para cada type que soportará y también tendría que modificar la función printArray() para admitir esos tipos.

Puede probar este código con un compilador en línea que se encuentra here .


Si la matriz es int o algo con el tamaño de int o el tamaño de su patrón de mem se ajusta a los tiempos exactos en un int (es decir, todos los ceros o 0xA5A5A5A5), la mejor manera es usar memset() .

De lo contrario, llame a memcpy () en un bucle moviendo el índice.


Nadie ha mencionado el orden del índice para acceder a los elementos de la matriz inicializada. Mi código de ejemplo le dará un ejemplo ilustrativo.

#include <iostream>

void PrintArray(int a[3][3])
{
    std::cout << "a11 = " << a[0][0] << "\t\t" << "a12 = " << a[0][1] << "\t\t" << "a13 = " << a[0][2] << std::endl;
    std::cout << "a21 = " << a[1][0] << "\t\t" << "a22 = " << a[1][1] << "\t\t" << "a23 = " << a[1][2] << std::endl;
    std::cout << "a31 = " << a[2][0] << "\t\t" << "a32 = " << a[2][1] << "\t\t" << "a33 = " << a[2][2] << std::endl;
    std::cout << std::endl;
}

int wmain(int argc, wchar_t * argv[])
{
    int a1[3][3] =  {   11,     12,     13,     // The most
                        21,     22,     23,     // basic
                        31,     32,     33  };  // format.

    int a2[][3] =   {   11,     12,     13,     // The first (outer) dimension
                        21,     22,     23,     // may be omitted. The compiler
                        31,     32,     33  };  // will automatically deduce it.

    int a3[3][3] =  {   {11,    12,     13},    // The elements of each
                        {21,    22,     23},    // second (inner) dimension
                        {31,    32,     33} };  // can be grouped together.

    int a4[][3] =   {   {11,    12,     13},    // Again, the first dimension
                        {21,    22,     23},    // can be omitted when the 
                        {31,    32,     33} };  // inner elements are grouped.

    PrintArray(a1);
    PrintArray(a2);
    PrintArray(a3);
    PrintArray(a4);

    // This part shows in which order the elements are stored in the memory.
    int * b = (int *) a1;   // The output is the same for the all four arrays.
    for (int i=0; i<9; i++)
    {
        std::cout << b[i] << '\t';
    }

    return 0;
}

La salida es:

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

a11 = 11                a12 = 12                a13 = 13
a21 = 21                a22 = 22                a23 = 23
a31 = 31                a32 = 32                a33 = 33

11      12      13      21      22      23      31      32      33

#include<stdio.h>
int main(){
int i,a[50];
for (i=0;i<50;i++){
    a[i]=5;// set value 5 to all the array index
}
for (i=0;i<50;i++)
printf("%d\n",a[i]);
   return 0;
}

Le dará la o / p 5 5 5 5 5 5 ...... hasta el tamaño de la matriz completa


  1. Si su matriz se declara como estática o es global, todos los elementos de la matriz ya tienen un valor predeterminado predeterminado 0.
  2. Algunos compiladores establecen el valor predeterminado de la matriz en 0 en el modo de depuración.
  3. Es fácil establecer el valor predeterminado en 0: int array [10] = {0};
  4. Sin embargo, para otros valores, tiene que usar memset () o loop;

ejemplo: int array [10]; memset (array, -1, 10 * sizeof (int));


Después de leer este tutorial, traté de implementarlo en mi programa.

Tengo 4-5 archivos que contienen direcciones. Cada archivo tiene aproximadamente 30 millones de registros. Estoy usando la misma configuración que está sugiriendo, pero mi número de INSERTOS por segundo es muy bajo (~ 10.000 registros por segundo).

Aquí es donde su sugerencia falla. Utiliza una sola transacción para todos los registros y una sola inserción sin errores / fallos. Supongamos que está dividiendo cada registro en varias inserciones en diferentes tablas. ¿Qué pasa si se rompe el registro?

El comando ON CONFLICT no se aplica, porque si tiene 10 elementos en un registro y necesita que cada elemento se inserte en una tabla diferente, si el elemento 5 recibe un error de CONSTRAINT, entonces todas las 4 inserciones anteriores también deben ir.

Así que aquí es donde viene la reversión. El único problema con la reversión es que pierdes todas tus inserciones y comienzas desde arriba. ¿Cómo puedes resolver esto?

Mi solución fue utilizar múltiples transacciones. Comienzo y finalizo una transacción cada 10,000 registros (No pregunte por qué ese número, fue el más rápido que probé). Creé una matriz con un tamaño de 10.000 e inserto los registros exitosos allí. Cuando se produce el error, hago una reversión, comienzo una transacción, inserto los registros de mi matriz, me comprometo y luego comienzo una nueva transacción después del registro roto.

Esta solución me ayudó a evitar los problemas que tengo al tratar con archivos que contienen registros incorrectos / duplicados (tenía casi un 4% de registros incorrectos).

El algoritmo que creé me ayudó a reducir mi proceso en 2 horas. Proceso de carga final del archivo 1hr 30m que aún es lento pero no comparado con las 4hrs que tomó inicialmente. Logré acelerar las inserciones desde 10.000 / s hasta ~ 14.000 / s.

Si alguien tiene alguna otra idea sobre cómo acelerarlo, estoy abierto a sugerencias.

ACTUALIZACIÓN :

Además de mi respuesta anterior, debes tener en cuenta que las inserciones por segundo dependen del disco duro que estés usando también. Lo probé en 3 PC diferentes con diferentes discos duros y obtuve enormes diferencias en los tiempos. PC1 (1hr 30m), PC2 (6hrs) PC3 (14hrs), así que comencé a preguntarme por qué sería eso.

Después de dos semanas de investigación y comprobación de múltiples recursos: Disco duro, RAM, caché, descubrí que algunas configuraciones en su disco duro pueden afectar la tasa de E / S. Al hacer clic en las propiedades en la unidad de salida deseada, puede ver dos opciones en la pestaña general. Opt1: comprime esta unidad, Opt2: permite que los archivos de esta unidad tengan contenidos indexados.

Al desactivar estas dos opciones, las 3 PC tardan aproximadamente el mismo tiempo en finalizar (1 hora y 20 a 40 minutos). Si encuentra inserciones lentas, verifique si su disco duro está configurado con estas opciones. Te ahorrará mucho tiempo y dolores de cabeza tratando de encontrar la solución





c arrays initialization array-initialize