Pregunta

Tengo una matriz grande 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é integrada en la sintaxis de C?

¿Fue útil?

Solución

A menos que ese valor sea 0 (en cuyo caso puede omitir alguna parte del inicializador y los elementos correspondientes se inicializarán a 0), no hay una manera fácil.

Sin embargo, no pase por alto la solución obvia:

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };

Los elementos con valores faltantes se inicializarán a 0:

int myArray[10] = { 1, 2 }; // initialize to 1,2,0,0,0...

Así que esto inicializará todos los elementos a 0:

int myArray[10] = { 0 }; // all elements 0

En C ++, una lista de inicialización vacía también inicializará cada elemento a 0. Esto es no permitido con C:

int myArray[10] = {}; // all elements 0 in C++

Recuerde que los objetos con duración de almacenamiento estático se inicializarán a 0 si no hay Se especifica el inicializador:

static int myArray[10]; // all elements 0

Y ese " 0 " no significa necesariamente "todos los bits a cero", por lo que usar lo anterior es Mejor y más portátil que memset (). (Los valores de punto flotante serán inicializado a +0, punteros a valor nulo, etc.)

Otros consejos

Si su compilador es GCC, puede usar la siguiente sintaxis:

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

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.

Editar: posibles extensiones útiles

(cortesía de Jonathan Leffler )

Puede 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 utilizando:

#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.

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} };

está bien, pero

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

no lo es.

Vi un código que usaba esta sintaxis:

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

Donde se vuelve particularmente útil es si estás 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 escribes algunos de los valores de enumeración fuera de orden.

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

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 cambie el tamaño de la matriz.

Puedes hacer todo lo relacionado con el inicializador estático como se detalla arriba, pero puede ser un verdadero fastidio cuando cambia el tamaño de la matriz (cuando la matriz se amplía, si no agregas los inicializadores adicionales apropiados, obtendrás 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 compilación.

Aquí hay otra manera:

static void
unhandled_interrupt(struct trap_frame *frame, int irq, void *arg)
{
    //this code intentionally left blank
}

static struct irqtbl_s vector_tbl[XCHAL_NUM_INTERRUPTS] = {
    [0 ... XCHAL_NUM_INTERRUPTS-1] {unhandled_interrupt, NULL},
};

Ver:

C-Extensions

Entidades designadas

Luego haga la pregunta: ¿Cuándo se pueden usar las extensiones C?

El ejemplo de código anterior está en un sistema integrado y nunca verá la luz de otro compilador.

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

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

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 la matriz es int o algo con el tamaño de int o el tamaño de tu 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.

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:

  • inicializa el primer elemento de la matriz (forma habitual)
  • copiar parte que se ha establecido en parte que no se ha establecido, duplicando el tamaño con cada próxima operación de copia

Para 1 000 000 elementos int 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):

tiempo de ejecución de bucle 0.004248 [segundos]

memfill () runtime 0.001085 [segundos]


#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;
}

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

Cortando 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 :)

  1. Si su matriz se declara como estática o es global, todos los elementos en 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:     matriz int [10];     memset (array, -1, 10 * sizeof (int));

#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

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; una es que UINT myArray [tamaño]; 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 un función de inicialización para cada tipo de que soportará y también tendría que modificar el printArray () Función para soportar esos tipos.


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

Para la inicialización diferida (es decir, la inicialización del constructor de miembros 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;

En el pasado (y no estoy diciendo que sea una buena idea), establecemos el primer elemento y luego:

memcpy (& amp; element [1], & amp; element [0], sizeof (element) -sizeof (element [0]);

Ni siquiera estoy seguro de que funcionaría más (eso dependería de la implementación de memcpy) pero funciona copiando repetidamente el elemento inicial al siguiente, incluso funciona para matrices de estructuras.

No veo requisitos en la pregunta, por lo que la solución debe ser genérica: inicialización de una matriz multidimensional posiblemente no especificada construida a partir de elementos de estructura posiblemente no especificados con un valor de miembro inicial:

#include <string.h> 

void array_init( void *start, size_t element_size, size_t elements, void *initval ){
  memcpy(        start,              initval, element_size              );
  memcpy( (char*)start+element_size, start,   element_size*(elements-1) );
}

// testing
#include <stdio.h> 

struct s {
  int a;
  char b;
} array[2][3], init;

int main(){
  init = (struct s){.a = 3, .b = 'x'};
  array_init( array, sizeof(array[0][0]), 2*3, &init );

  for( int i=0; i<2; i++ )
    for( int j=0; j<3; j++ )
      printf("array[%i][%i].a = %i .b = '%c'\n",i,j,array[i][j].a,array[i][j].b);
}

Resultado:

array[0][0].a = 3 .b = 'x'
array[0][1].a = 3 .b = 'x'
array[0][2].a = 3 .b = 'x'
array[1][0].a = 3 .b = 'x'
array[1][1].a = 3 .b = 'x'
array[1][2].a = 3 .b = 'x'

EDITAR: start + element_size cambiado a (char*)start+element_size

Sé que la pregunta original menciona explícitamente a C y no a C ++, pero si usted (como yo) vino aquí en busca de una solución para los arrays de C ++, aquí hay un buen truco:

Si su compilador admite expresiones de plegado , puede usar la plantilla de magia y std :: index_sequence para generar una lista de inicialización con el valor que desee. E incluso puedes constexpr y sentirte 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

Puede consultar el código en el trabajo (en Wandbox)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top