Domanda

Ho un grande array in C (non C ++ se questo fa la differenza). Voglio inizializzare tutti i membri allo stesso valore. Potrei giurare che una volta conoscevo un modo semplice per farlo. Potrei usare memset () nel mio caso, ma non c'è un modo per farlo che sia incorporato nella sintassi C?

È stato utile?

Soluzione

A meno che quel valore sia 0 (nel qual caso è possibile omettere una parte dell'inizializzatore e gli elementi corrispondenti verranno inizializzati su 0), non esiste un modo semplice.

Non trascurare l'ovvia soluzione, però:

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

Gli elementi con valori mancanti verranno inizializzati su 0:

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

Quindi questo inizializzerà tutti gli elementi su 0:

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

In C ++, anche un elenco di inizializzazione vuoto inizializzerà ogni elemento su 0. Questo è non consentito con C:

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

Ricorda che gli oggetti con durata di archiviazione statica verranno inizializzati su 0 se no l'inizializzatore è specificato:

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

E questo " 0 " non significa necessariamente "all-bit-zero", quindi usare quanto sopra è migliore e più portatile di memset (). (I valori in virgola mobile saranno inizializzato su +0, puntatori a valore null, ecc.)

Altri suggerimenti

Se il tuo compilatore è GCC puoi utilizzare la seguente sintassi:

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

Controlla la descrizione dettagliata: http://gcc.gnu.org/onlinedocs/gcc -4.1.2 / gcc / Designated-Inits.html

Per inizializzare staticamente un array di grandi dimensioni con lo stesso valore, senza più copia-incolla, è possibile utilizzare le macro:

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

Se è necessario modificare il valore, è necessario effettuare la sostituzione in un solo posto.

Modifica: possibili estensioni utili

(per gentile concessione di Jonathan Leffler )

Puoi facilmente generalizzare questo con:

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

Una variante può essere creata usando:

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

che funziona con strutture o matrici composte.

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

i nomi delle macro sono negoziabili.

Se vuoi assicurarti che ogni membro dell'array sia inizializzato esplicitamente, ometti la dimensione dalla dichiarazione:

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

Il compilatore dedurrà la dimensione dall'elenco di inizializzatori. Sfortunatamente, per le matrici multidimensionali è possibile omettere solo la dimensione più esterna:

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

è OK, ma

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

non lo è.

Ho visto del codice che utilizzava questa sintassi:

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

Dove diventa particolarmente utile è se stai creando un array che usa enum come indice:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

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

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

Ciò mantiene le cose in ordine, anche se ti capita di scrivere alcuni dei valori enum fuori ordine.

Ulteriori informazioni su questa tecnica sono disponibili qui e qui .

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

Penso che sia meglio di

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

incassa le dimensioni delle modifiche dell'array.

Puoi fare tutto l'inizializzatore statico come descritto sopra, ma può essere un vero peccato quando cambiano le dimensioni dell'array (quando l'array si attiva, se non aggiungi gli inizializzatori extra appropriati ottieni spazzatura).

memset ti dà un hit di runtime per fare il lavoro, ma nessun hit di dimensione del codice fatto correttamente è immune alle modifiche della dimensione dell'array. Vorrei usare questa soluzione in quasi tutti i casi in cui l'array era più grande, diciamo, di alcune dozzine di elementi.

Se fosse davvero importante che l'array fosse dichiarato staticamente, scriverei un programma per scrivere il programma per me e renderlo parte del processo di compilazione.

Ecco un altro modo:

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

See:

C-Extensions

Inits designati

Quindi fai la domanda: quando si possono usare le estensioni C?

L'esempio di codice sopra è in un sistema incorporato e non vedrà mai la luce da un altro compilatore.

Per inizializzare tipi di dati 'normali' (come gli array int), puoi usare la notazione parentesi, ma azzererà i valori dopo l'ultimo se c'è ancora spazio nell'array:

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

Una risposta leggermente ironica; scrivi la dichiarazione

array = initial_value

nella tua lingua preferita compatibile con array (il mio è Fortran, ma ce ne sono molti altri) e collegalo al tuo codice C. Probabilmente vorresti concludere che sia una funzione esterna.

Se l'array risulta essere int o qualcosa con la dimensione di int o la dimensione del modello mem si adatta a tempi esatti in un int (cioè tutti gli zero o 0xA5A5A5A5), il modo migliore è usare memset () .

Altrimenti chiama memcpy () in un ciclo che sposta l'indice.

Esiste un modo rapido per inizializzare array di qualsiasi tipo con un determinato valore. Funziona molto bene con array di grandi dimensioni. L'algoritmo è il seguente:

  • inizializza il primo elemento dell'array (modo normale)
  • copia parte che è stata impostata in parte che non è stata impostata, raddoppiando la dimensione ad ogni successiva operazione di copia

Per gli elementi 1 000 000 l'array int è 4 volte più veloce della normale inizializzazione del loop (i5, 2 core, 2,3 GHz, memoria 4GiB, 64 bit):

runtime del ciclo 0.004248 [secondi]

memfill () runtime 0,001085 [secondi]


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

Nessuno ha menzionato l'ordine dell'indice per accedere agli elementi dell'array inizializzato. Il mio codice di esempio fornirà un esempio illustrativo.

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

L'output è:

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

Tagliare tutte le chiacchiere, la risposta breve è che se attivi l'ottimizzazione in fase di compilazione non farai meglio di così:

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

Bonus aggiunto: il codice è in realtà leggibile :)

  1. Se l'array è dichiarato statico o globale, tutti gli elementi nell'array ha già il valore predefinito predefinito 0.
  2. Alcuni compilatori impostano l'array come predefinito su 0 in modalità debug.
  3. È facile impostare il valore predefinito su 0: int array [10] = {0};
  4. Tuttavia, per altri valori, devi usare memset () o loop;

Esempio:     int array [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;
}

Restituirà l'o / p 5 5 5 5 5 5 ...... fino alla dimensione dell'intero array

So che l'utente Tarski ha risposto a questa domanda in modo simile, ma ho aggiunto qualche dettaglio in più. Perdona un po 'della mia C perché sono un po' arrugginito perché sono più propenso a voler usare il C ++, ma eccolo qui.


Se si conosce in anticipo la dimensione dell'array ...

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

Ci sono alcune avvertenze sopra; uno è che UINT myArray [size]; non viene inizializzato direttamente al momento della dichiarazione, tuttavia il blocco di codice o la chiamata di funzione immediatamente successiva inizializza ogni elemento dell'array con lo stesso valore desiderato. L'altro avvertimento è che dovresti scrivere una funzione di inizializzazione per ogni tipo che supporterai e dovresti anche modificare printArray () funzione per supportare quei tipi.


Puoi provare questo codice con un complier online trovato qui .

Per l'inizializzazione ritardata (ovvero l'inizializzazione del costruttore del membro della classe) considerare:

int a[4];

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

Nel passato (e non sto dicendo che sia una buona idea), avremmo impostato il primo elemento e poi:

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

Non sono nemmeno sicuro che funzionerebbe più (ciò dipenderebbe dall'implementazione di memcpy) ma funziona copiando ripetutamente l'elemento iniziale nel successivo - funziona anche per array di strutture.

Non vedo alcun requisito nella domanda, quindi la soluzione deve essere generica: inizializzazione di un array non multidimensionale possibilmente non specificato costruito da elementi di struttura possibilmente non specificati con un valore membro iniziale:

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

Risultato:

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'

EDIT: start + element_size modificato in (char*)start+element_size

So che la domanda originale menziona esplicitamente C e non C ++, ma se tu (come me) sei venuto qui alla ricerca di una soluzione per array C ++, ecco un trucco chiaro:

Se il tuo compilatore supporta espressioni di piega , puoi usare template magic e std :: index_sequence per generare un elenco di inizializzatori con il valore desiderato. E puoi persino constexpr e sentirti come un boss:

#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

Puoi dare un'occhiata al codice al lavoro (su Wandbox)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top