Comment initialiser tous les membres d'un tableau à la même valeur?


968

J'ai un grand tableau en C (pas C ++ si cela fait une différence). Je veux initialiser tous les membres de la même valeur.

Je pourrais jurer avoir déjà connu un moyen simple de le faire. Je pourrais utiliser memset()dans mon cas, mais n'y a-t-il pas un moyen de le faire intégré à la syntaxe C?


16
Jusqu'à présent, aucune des réponses ne mentionne la notation d'initialisation désignée qui est réalisable avec C99 et au-dessus. Par exemple: enum { HYDROGEN = 1, HELIUM = 2, CARBON = 6, NEON = 10, … };et struct element { char name[15]; char symbol[3]; } elements[] = { [NEON] = { "Neon", "Ne" }, [HELIUM] = { "Helium", "He" }, [HYDROGEN] = { "Hydrogen", "H" }, [CARBON] = { "Carbon", "C" }, … };. Si vous supprimez les points de suspension , ces fragments se compilent sous C99 ou C11.
Jonathan Leffler

En fait, la réponse d'Abelenky utilise un initialiseur désigné, mais le code d'initialisation n'est pas complètement formé
Rob11311

memset () peut aider, mais dépend de la valeur.
Nick

2
memset()discussion spécifique: stackoverflow.com/questions/7202411/… Je pense que cela ne fonctionne que pour 0.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:


1239

À moins que cette valeur ne soit 0 (auquel 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 simple.

Cependant, 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...

Donc, cela initialisera tous les éléments à 0:

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

En C ++, une liste d'initialisation vide initialisera également chaque élément à 0. Ce n'est pas 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 initialiseur n'est spécifié:

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

Et que "0" ne signifie pas nécessairement "tous les bits à zéro", donc l'utilisation de ce qui précède est meilleure et plus portable que memset (). (Les valeurs en virgule flottante seront initialisées à +0, les pointeurs à la valeur nulle, etc.)


27
En parcourant la norme C ++, vous pouvez également faire int array [10] = {}; à zéro initialiser. Je n'ai pas la norme C pour vérifier que c'est aussi un C valide.
workmad3

54
En regardant la section 6.7.8 Initialisation de la norme C99, il ne semble pas qu'une liste d'initialisation vide soit autorisée.
Jonathan Leffler

7
C99 a beaucoup de fonctionnalités intéressantes pour l'initialisation de la structure et du tableau; la seule fonctionnalité qu'il n'a pas (mais Fortran IV, 1966, avait) est un moyen de répéter un initialiseur particulier pour un tableau.
Jonathan Leffler,

8
@CetinSert: Que voulez-vous dire que cela ne fonctionne pas? Il fait exactement ce que cette réponse dit qu'il devrait faire. Il ne fait pas ce que dit le commentaire dans votre code, mais ce commentaire est faux.
Benjamin Lindley

9
@CetinSert: Vous êtes le seul à avoir affirmé, dans ce commentaire, que tous les éléments seraient mis à -1. Cette réponse affirme, à juste titre, que tous les éléments non spécifiés sont mis à zéro. Les résultats de votre code sont en accord avec cette affirmation.
Benjamin Lindley

394

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

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

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


12
Et cette syntaxe entraîne une énorme augmentation de la taille des fichiers binaires compilés. Pour N = 65536 (au lieu de 1024), mon binaire passe de 15 Ko à 270 Ko en taille !!
Cetin Sert

50
@CetinSert Compiler doit ajouter 65536 ints aux données statiques, ce qui correspond à 256 K - exactement l'augmentation de taille que vous avez observée.
qrdl

15
@CetinSert Pourquoi devrais-je? Il s'agit d'un comportement de compilateur standard, non spécifique aux initialiseurs désignés. Si vous initialisez statiquement 65536 ints, comme int foo1 = 1, foo2 = 1, ..., foo65536 =1;vous obtiendrez la même augmentation de taille.
qrdl

27
mieux encore: "int array [] = {[0 ... 1023] = 5}", la taille du tableau sera automatiquement fixée à 1024, plus facile et plus sûre à modifier.
Francois

4
@Francois ou pour un tableau 2D bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true}, bien que je ne suis pas certain que ce soit plus lisible que le formulaire complet.
g33kz0r

178

Pour initialiser statiquement un grand tableau avec la même valeur, sans copier-coller multiple, 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.

Edit: extensions utiles possibles

(avec l'aimable autorisation de Jonathan Leffler )

Vous pouvez facilement généraliser cela avec:

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

Une variante peut être créée en utilisant:

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


12
Je ne considérerais cela que dans des cas extrêmes, un memset est sûrement la manière la plus élégante de l'exprimer.
u0b34a0f6ae

47
Si les données doivent être compatibles avec la ROM, le memset ne peut pas être utilisé.
contrat du professeur Falken a été rompu le

9
Le préprocesseur générera en fait le code à partir de #defines. Avec des dimensions de tableau plus grandes, la taille de l'exécutable augmentera. Mais définitivement + pour l'idée;)
Leonid

7
@Alcott, sur les vieux ordinateurs et toujours sur de nombreux systèmes embarqués, le code est finalement placé dans une EPROM ou une ROM . ROM-capable est également devenu synonyme, dans les systèmes embarqués, de "code mis en flash", car il a à peu près les mêmes implications, à savoir que la mémoire ne peut pas être écrite en runtime. C'est-à-dire que le memset ou toute autre instruction de mise à jour ou de changement de mémoire ne peut pas être utilisé. Cependant, les constantes peuvent être exprimées et flashées ou écrites en ROM avant le démarrage du programme.
contrat du professeur Falken a été rompu le

4
@ u0b34a0f6ae: Gardez à l'esprit que vous pouvez également utiliser cette méthode si ce VAL_1Xn'est pas un entier mais une liste. Comme pour les états Amigable, c'est également la voie à suivre pour les systèmes embarqués où vous souhaitez définir les valeurs init d'une EEPROM ou d'une mémoire Flash. Dans les deux cas, vous ne pouvez pas utiliser memset().
Martin Scharrer

63

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 d'initialisation. 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.


est-ce correct ? int myPoints[10][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
Praveen Gowda IV

10
Non. Vous omettez la dimension la plus intérieure, ce qui n'est pas autorisé. Cela donnera une erreur de compilation.
Frank Szczerba

4
Les initialiseurs et l'inférence de longueur ont été introduits dans C99.
Palec

3
@Palec: Non - l'inférence de longueur est en C depuis l'époque du C pré-standard (depuis la publication de K&R 1st Edition, et probablement un certain temps avant cela). Les initialiseurs désignés étaient nouveaux dans C99, mais cela n'utilise pas les initialiseurs désignés.
Jonathan Leffler

53

J'ai vu du code qui utilise cette syntaxe:

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

Là où cela devient particulièrement utile, c'est si vous créez un tableau qui utilise 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)
};   

Cela maintient les choses en ordre, même s'il vous arrive d'écrire certaines des valeurs d'énumération dans le désordre.

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


8
Il s'agit de la syntaxe d'initialisation C99, déjà couverte par certaines des autres réponses. Vous pourriez utilement faire la déclaration char const *array[] = { ... };ou même char const * const array[] = { ... };, n'est-ce pas?
Jonathan Leffler

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

incase la taille des changements de tableau.


12
Pour mémoire, il s'agit essentiellement d'une version plus lente et plus verbeuse dememset(myArray, VALUE, ARRAY_SIZE);
Benson

18
Comment utiliseriez-vous memset pour initialiser un tableau int à une valeur supérieure à 255? memset ne fonctionne que si la taille du tableau est octet.
Matt

21
@Benson: Vous ne pouvez pas remplacer le code ci-dessus par memset sur les plates-formes où sizeof (int)> sizeof (char). Essayez-le.
ChrisWue

13

Vous pouvez faire tout l'initialisation statique comme détaillé ci-dessus, mais cela peut être un vrai problème lorsque la taille de votre tableau change (lorsque votre tableau s'embigge, si vous n'ajoutez pas les initialiseurs supplémentaires appropriés, vous obtenez des ordures).

memset vous donne un hit d'exécution pour faire le travail, mais aucun hit de taille de code bien fait n'est à l'abri des changements de taille du tableau. J'utiliserais cette solution dans presque tous les cas lorsque le tableau était plus grand que, disons, quelques dizaines d'éléments.

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


Pourriez-vous s'il vous plaît ajouter un exemple sur cette utilisation de memsetpour initialiser le tableau?
Sopalajo de Arrierez

8

Voici une autre façon:

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:

Extensions C

Inits désignés

Posez ensuite la question: 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.


6

Pour initialiser les types de données «normaux» (comme les tableaux int), vous pouvez utiliser la notation entre crochets, mais elle remettra à zéro les valeurs après la dernière 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};

5

Si le tableau se trouve être int ou quoi que ce soit avec la taille de int ou la taille de votre modèle mem correspond aux heures exactes dans un int (c'est-à-dire tous les zéros ou 0xA5A5A5A5), la meilleure façon est d'utiliser memset () .

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


5

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

array = initial_value

dans votre langue préférée compatible avec les tableaux (le mien est Fortran, mais il y en a beaucoup d'autres), et liez-le à votre code C. Vous voudrez probablement en faire une fonction externe.


4

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

  • initialiser le premier élément du tableau (manière habituelle)
  • copier une partie qui a été définie en une partie qui n'a pas été définie, doubler la taille à chaque opération de copie suivante

Pour le tableau d' 1 000 000éléments int, il est 4 fois plus rapide que l'initialisation de boucle normale (i5, 2 cœurs, 2,3 GHz, mémoire 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;
}

2
Désolé, mais ce n'est pas vrai. Vous avez peut-être oublié d'activer l'optimisation de la compilation lors de vos tests (testé avec le mode débogage?). Si je teste cela, la boucle est presque toujours 50% plus rapide que memfill («toujours» en raison de certaines fluctuations de charge sur ma machine). Et en utilisant memset (a, 0, sizeof (a)); est même deux fois plus rapide que le remplissage en boucle.
RS1980

2
Comme pour tout code d'analyse comparative, vous devez être extrêmement prudent. Ajouter une boucle pour exécuter le code temporel 10 fois (et doubler la taille du tableau à 20 Mo) montre - pour moi, fonctionner sur un MacBook Pro avec macOS Sierra 10.12.3 et utiliser GCC 6.3.0 - que la première fois, en utilisant la boucle prend environ 4600 µs, tandis que le memfill()code prend environ 1200 µs. Cependant, lors des itérations suivantes, la boucle prend environ 900-1000 µs tandis que le memfill()code prend 1000-1300 µs. La première itération est probablement impactée par le temps de remplissage du cache. Inversez les tests et memfill()est lent la première fois.
Jonathan Leffler

2

Personne n'a mentionné l'ordre d'index pour accéder aux éléments du tableau initialisé. Mon exemple de code lui 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;
}

La sortie 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

4
<iostream>est pas valable Cque std::cout, std::cinetc. fait partie du std::namespaceet Cne supporte pas namespaces. Essayez plutôt <stdio.h>d' utiliser for printf(...).
Francis Cugler

2

En coupant tout le bavardage, 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 en fait lisible :)


7
La question demandait spécifiquement l'initialisation. Ce n'est explicitement pas l'initialisation, mais l'affectation effectuée après l' initialisation. Cela peut être fait immédiatement, mais ce n'est toujours pas l'initialisation.
Andy

Entièrement inutile pour une grande table de recherche statique à l'intérieur d'une fonction appelée plusieurs fois.
Martin Bonner soutient Monica le

... ne me souviens pas que les tables de recherche statiques à l'intérieur des fonctions faisaient partie de la question d'origine - restez simple. Cela dit, @Community a probablement réussi.
JWDN

1
  1. Si votre tableau est déclaré statique ou global, tous les éléments du tableau ont déjà la valeur par défaut 0 par défaut.
  2. Certains compilateurs définissent le tableau par défaut à 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 (tableau, -1, 10 * sizeof (int));


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

Il donnera le o / p 5 5 5 5 5 5 ...... jusqu'à la taille de l'ensemble


0

Je sais que l'utilisateur a Tarskirépondu à cette question de manière similaire, mais j'ai ajouté quelques détails supplémentaires. Pardonnez une partie de mon C car je suis un peu rouillé car je suis plus enclin à vouloir utiliser C ++, mais c'est parti.


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; l'une est qui UINT myArray[size];n'est pas directement initialisée lors de la déclaration, mais le tout prochain bloc de code ou appel de fonction initialise chaque élément du tableau à la même valeur que vous le souhaitez. L'autre mise en garde est que vous devrez écrire un initializing functionpour chacun que typevous prendrez en charge et vous devrez également modifier la printArray()fonction pour prendre en charge ces types.


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


0

Pour l'initialisation retardée (c'est-à-dire l'initialisation du constructeur du membre de classe), considérez:

int a[4];

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

0

Je sais que la question d'origine mentionne explicitement C et non C ++, mais si vous (comme moi) êtes venu ici à la recherche d'une solution pour les tableaux C ++, voici une astuce intéressante:

Si votre compilateur prend en charge les expressions de repli , vous pouvez utiliser la magie de modèle et std::index_sequencegénérer une liste d'initialisation avec la valeur souhaitée. Et vous pouvez même constexprvous 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 jeter un œil au code au travail (sur Wandbox)


-1

Je ne vois aucune exigence 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+element_sizechangé en(char*)start+element_size


1
Je doute que ce soit ou non une solution. Je ne sais pas si sizeof(void)c'est même valable.
Chris Lutz

3
Ça ne marche pas. Seuls les deux premiers sont initialisés, les autres sont tous non initialisés. J'utilise GCC 4.0 sur Mac OS X 10.4.
dreamlax

Cela appelle un comportement indéfini car les données source de la seconde memcpy()chevauchent l'espace de destination. Avec une implémentation naïve de memcpy(), cela peut fonctionner mais il n'est pas nécessaire que le système le fasse fonctionner.
Jonathan Leffler

-1

À l'époque (et je ne dis pas que c'est une bonne idée), nous avions défini le premier élément, puis:

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

Pas même sûr que cela fonctionnerait plus (cela dépendrait de l'implémentation de memcpy), mais cela fonctionne en copiant à plusieurs reprises l'élément initial sur le suivant - fonctionne même pour les tableaux de structures.


Cela ne fonctionnera pas de manière fiable. À mon humble avis, la norme aurait dû fournir des fonctions similaires memcpymais spécifiées dans l'ordre de copie ascendant ou descendant en cas de chevauchement, mais ce n'est pas le cas.
supercat

Comme je l'ai dit, c'était juste quelque chose que nous avons fait qui ne fonctionnerait pas de manière fiable mais, à l'époque, nous étions plus concentrés sur l'efficacité que sur les fonctionnalités non documentées. Bien qu'il soit plus efficace de copier la mémoire en avant, rien dans la spécification ne dit qu'elle ne peut pas la copier en arrière, dans un ordre aléatoire ou la diviser sur plusieurs threads. memmove () offre la possibilité de copier sans heurts.
Mike

C'est équivalent au code dans une autre réponse - et imparfait. L'utilisation memmove()ne le fait pas fonctionner.
Jonathan Leffler

-2

Si vous voulez dire en parallèle, je pense que l'opérateur virgule lorsqu'il est utilisé en conjonction avec une expression peut le faire:

a[1]=1, a[2]=2, ..., a[indexSize]; 

ou si vous voulez dire dans une seule construction, vous pouvez le faire dans une boucle for:

for(int index = 0, value = 10; index < sizeof(array)/sizeof(array[0]); index++, value--)
  array[index] = index;

// Notez que l'opérateur virgule dans une liste d'arguments n'est pas l'opérateur parallèle décrit ci-dessus;

Vous pouvez initialiser une décomposition de tableau:

array[] = {1, 2, 3, 4, 5};

Vous pouvez appeler Malloc / calloc / sbrk / alloca / etc pour allouer une région de stockage fixe à un objet:

int *array = malloc(sizeof(int)*numberOfListElements/Indexes);

et accéder aux membres par:

*(array + index)

Etc.


L'opérateur de virgule garantit nominalement une évaluation de gauche à droite. S'il n'y a pas d'effets secondaires dans les expressions, alors il peut être possible de paralléliser les opérations, mais il serait inhabituel pour un compilateur de le faire.
Jonathan Leffler
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.