Question

J'ai un grand tableau en C (pas en C ++ si cela fait une différence). Je veux initialiser tous les membres à la même valeur. Je pourrais jurer que j’ai déjà connu un moyen simple de faire cela. Je pourrais utiliser memset () dans mon cas, mais n'y a-t-il pas un moyen de le faire qui soit intégré à la syntaxe C?

Était-ce utile?

La solution

Sauf si cette valeur est 0 (dans ce cas, vous pouvez omettre une partie de l'initialiseur et les éléments correspondants seront initialisés à 0), il n'y a pas de moyen facile.

Ne négligez pas la solution évidente:

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

Les éléments avec des valeurs manquantes seront initialisés à 0:

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

Cela initialisera donc tous les éléments sur 0:

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

En C ++, une liste d'initialisation vide initialisera également tous les éléments sur 0. non autorisé avec C:

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

N'oubliez pas que les objets avec une durée de stockage statique seront initialisés à 0 si aucun l'initialiseur est spécifié:

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

Et que " 0 " ne signifie pas nécessairement "tout-bits-zéro", donc utiliser ce qui précède est mieux et plus portable que memset (). (Les valeurs en virgule flottante seront initialisé à +0, pointeurs sur une valeur nulle, etc.)

Autres conseils

Si votre compilateur est GCC, vous pouvez utiliser la syntaxe suivante:

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

Voir la description détaillée: http://gcc.gnu.org/onlinedocs/gcc -4.1.2 / gcc / Designated-Inits.html

Pour initialiser de manière statique un grand tableau avec la même valeur, sans plusieurs copier-coller, vous pouvez utiliser des 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 vous devez modifier la valeur, vous devez effectuer le remplacement à un seul endroit.

Modifier: extensions utiles possibles

(courtoisie de Jonathan Leffler )

Vous pouvez facilement généraliser ceci avec:

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

Une variante peut être créée avec:

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

qui fonctionne avec des structures ou des tableaux composés.

#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) };
Les noms de macro

sont négociables.

Si vous voulez vous assurer que chaque membre du tableau est explicitement initialisé, omettez simplement la dimension de la déclaration:

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

Le compilateur déduira la dimension de la liste des initialiseurs. Malheureusement, pour les tableaux multidimensionnels, seule la dimension la plus externe peut être omise:

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

est OK, mais

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

n'est pas.

J'ai vu du code utilisant cette syntaxe:

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

Cela devient particulièrement utile si vous créez un tableau utilisant des énumérations comme index:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

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

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

Ceci garde les choses en ordre, même si vous écrivez certaines des valeurs enum dans le désordre.

Plus d'informations sur cette technique peuvent être trouvées ici et ici .

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

Je pense que c'est mieux que

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

en cas de modification de la taille du tableau.

Vous pouvez effectuer l’ensemble des opérations d’initialisation statique comme indiqué ci-dessus, mais cela peut être une véritable perte de temps lorsque la taille de votre tableau change (lorsque votre tableau s’emballe, si vous n’ajoutez pas d’initialiseurs supplémentaires appropriés, vous obtenez des déchets).

memset vous donne un coup au moteur d'exécution pour effectuer le travail, mais aucun coup de la taille de code effectué correctement n'est à l'abri des changements de taille de tableau. J'utiliserais cette solution dans presque tous les cas où le tableau était plus grand que, par exemple, quelques dizaines d'éléments.

S'il était vraiment important que le tableau soit déclaré de manière statique, j'écrirais un programme pour écrire le programme pour moi et l'intégrer au processus de construction.

Voici un autre moyen:

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

Voir:

C-Extensions

Entrées désignées

Posez ensuite la question suivante: Quand peut-on utiliser des extensions C?

L'exemple de code ci-dessus est dans un système intégré et ne verra jamais la lumière d'un autre compilateur.

Pour initialiser les types de données "normaux" (comme les tableaux int), vous pouvez utiliser la notation entre crochets, mais les valeurs après le dernier seront remises à zéro s'il reste de l'espace dans le tableau:

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

Une réponse légèrement ironique. écrire la déclaration

array = initial_value

dans votre langage favori compatible avec les tableaux (le mien est Fortran, mais il y en a beaucoup d'autres), et le lier à votre code C. Vous voudrez probablement en faire une fonction externe.

S'il s'avère que le tableau est int ou que quelque chose ait la taille int ou que la taille de votre modèle mémoire correspond à des heures exactes dans un int (c'est-à-dire tous les zéros ou 0xA5A5A5A5), le meilleur moyen consiste à utiliser memset () .

Sinon, appelez memcpy () dans une boucle en déplaçant l'index.

Il existe un moyen rapide d’initialiser un tableau de tout type avec une valeur donnée. Cela fonctionne très bien avec les grands tableaux. L'algorithme est le suivant:

  • initialise le premier élément du tableau (manière habituelle)
  • copie une partie qui a été définie dans une partie non définie, en doublant la taille à chaque opération de copie suivante

Pour les éléments 1 000 000 , le tableau int est 4 fois plus rapide qu'une initialisation de boucle normale (i5, 2 cœurs, 2,3 GHz, 4 Go de mémoire, 64 bits):

Durée d'exécution de la boucle: 0,004248 [secondes]

memfill () runtime 0.001085 [secondes]

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

Personne n'a mentionné l'ordre d'index pour accéder aux éléments du tableau initialisé. Mon exemple de code donnera un exemple illustratif.

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

Le résultat est:

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

En coupant toutes les discussions, la réponse courte est que si vous activez l'optimisation au moment de la compilation, vous ne ferez pas mieux que cela:

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

Bonus supplémentaire: le code est réellement lisible:)

  1. Si votre tableau est déclaré statique ou global, tous les éléments dans le tableau ont déjà la valeur par défaut 0.
  2. Certains compilateurs définissent la valeur par défaut de array sur 0 en mode débogage.
  3. Il est facile de définir la valeur par défaut sur 0: int array [10] = {0};
  4. Cependant, pour d’autres valeurs, vous devez utiliser memset () ou loop;

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

Cela donnera le o / p 5 5 5 5 5 5 ...... jusqu'à la taille d'un tableau entier

Je sais que l'utilisateur Tarski a répondu à cette question de la même manière, mais j'ai ajouté quelques détails supplémentaires. Pardonnez un peu de mon C car je suis un peu rouillé parce que je suis plus enclin à vouloir utiliser le C ++, mais le voilà.

Si vous connaissez la taille du tableau à l'avance ...

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

Il y a quelques mises en garde ci-dessus; Le premier est que UINT myArray [size]; n'est pas directement initialisé lors de la déclaration. Toutefois, le bloc de code ou l'appel de fonction suivant initialise chaque élément du tableau avec la même valeur que vous le souhaitez. L'autre inconvénient est que vous devez écrire une fonction d'initialisation pour chaque type que vous allez prendre en charge et que vous devez également modifier le printArray () fonction pour supporter ces types.

Vous pouvez essayer ce code avec un fournisseur en ligne trouvé ici .

Pour l'initialisation différée (c'est-à-dire l'initialisation du constructeur du membre de la classe), tenez compte des éléments suivants:

int a[4];

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

De retour dans la journée (et je ne dis pas que c'est une bonne idée), nous définissons le premier élément, puis:

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

Vous n’êtes même pas sûr que cela fonctionnerait (cela dépendrait de l’implémentation de memcpy), mais cela fonctionne en copiant de façon répétée l’élément initial sur le suivant, même pour les tableaux de structures.

Je ne vois pas d'exigences dans la question, donc la solution doit être générique: initialisation d'un tableau éventuellement multidimensionnel non spécifié construit à partir d'éléments de structure éventuellement non spécifiés avec une valeur de membre initiale:

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

Résultat:

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 + taille_élément remplacé par (char *) start + taille_élément

Je sais que la question initiale mentionne explicitement le C et non le C ++, mais si vous (comme moi) êtes venu chercher une solution pour les tableaux C ++, voici une astuce intéressante:

Si votre compilateur prend en charge les expressions de pliage , vous pouvez utiliser le modèle magique et std :: index_sequence pour générer une liste d'initialiseurs avec la valeur souhaitée. Et vous pouvez même le constexpr et vous sentir comme un patron:

#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

Vous pouvez consulter le code au travail (sur Wandbox)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top