Wie initialisiere ich alle Mitglieder eines Arrays mit demselben Wert?

968

Ich habe ein großes Array in C (nicht C ++, wenn das einen Unterschied macht). Ich möchte alle Mitglieder mit demselben Wert initialisieren.

Ich könnte schwören, dass ich einmal einen einfachen Weg kannte, dies zu tun. Ich könnte es memset()in meinem Fall verwenden, aber gibt es keine Möglichkeit, dies zu tun, die direkt in die C-Syntax integriert ist?

Matt
quelle
16
In keiner der bisherigen Antworten wird die angegebene Initialisierungsnotation erwähnt, die mit C99 und höher möglich ist. Zum Beispiel: enum { HYDROGEN = 1, HELIUM = 2, CARBON = 6, NEON = 10, … };und struct element { char name[15]; char symbol[3]; } elements[] = { [NEON] = { "Neon", "Ne" }, [HELIUM] = { "Helium", "He" }, [HYDROGEN] = { "Hydrogen", "H" }, [CARBON] = { "Carbon", "C" }, … };. Wenn Sie die Auslassungspunkte entfernen , werden diese Fragmente unter C99 oder C11 kompiliert.
Jonathan Leffler
Tatsächlich verwendet Abelenkys Antwort einen bestimmten Initialisierer, ist jedoch nicht vollständig als Initialisierungscode ausgebildet
Rob11311,
memset () kann helfen, hängt aber vom Wert ab.
Nick
2
memset()Spezifische Diskussion: stackoverflow.com/questions/7202411/… Ich denke, es funktioniert nur für 0.
Ciro Santilli 10 病毒 审查 六四 事件 10

Antworten:

1239

Solange dieser Wert nicht 0 ist (in diesem Fall können Sie einen Teil des Initialisierers weglassen und die entsprechenden Elemente werden auf 0 initialisiert), gibt es keinen einfachen Weg.

Übersehen Sie jedoch nicht die offensichtliche Lösung:

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

Elemente mit fehlenden Werten werden auf 0 initialisiert:

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

Dies initialisiert also alle Elemente auf 0:

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

In C ++ initialisiert eine leere Initialisierungsliste auch jedes Element auf 0. Dies ist mit C nicht zulässig :

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

Denken Sie daran, dass Objekte mit statischer Speicherdauer auf 0 initialisiert werden, wenn kein Initialisierer angegeben ist:

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

Und diese "0" bedeutet nicht unbedingt "All-Bits-Null", daher ist die Verwendung der oben genannten Punkte besser und portabler als memset (). (Gleitkommawerte werden auf +0 initialisiert, Zeiger auf Nullwert usw.)

aib
quelle
27
Wenn Sie den C ++ - Standard lesen, können Sie auch int array [10] = {} ausführen. auf Null initialisieren. Ich habe nicht den C-Standard, um zu überprüfen, ob dies auch ein gültiges C ist.
workmad3
54
In Abschnitt 6.7.8 Initialisierung des C99-Standards scheint keine leere Initialisierungsliste zulässig zu sein.
Jonathan Leffler
7
C99 bietet viele nützliche Funktionen für die Struktur- und Array-Initialisierung. Das einzige Merkmal, das es nicht hat (aber Fortran IV, 1966, hatte), ist eine Möglichkeit, einen bestimmten Initialisierer für ein Array zu wiederholen.
Jonathan Leffler
8
@CetinSert: Was meinst du damit, dass es nicht funktioniert? Es macht genau das, was diese Antwort sagt, dass es tun sollte. Es macht nicht das, was der Kommentar in Ihrem Code sagt, aber dieser Kommentar ist falsch.
Benjamin Lindley
9
@CetinSert: Sie sind der einzige, der in diesem Kommentar behauptet hat, dass alle Elemente auf -1 gesetzt würden. Diese Antwort behauptet zu Recht, dass alle nicht spezifizierten Elemente auf Null gesetzt werden. Die Ergebnisse Ihres Codes stimmen mit dieser Behauptung überein.
Benjamin Lindley
394

Wenn Ihr Compiler GCC ist, können Sie die folgende Syntax verwenden:

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

Lesen Sie die detaillierte Beschreibung: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html

qrdl
quelle
12
Und diese Syntax führt zu einer enormen Zunahme der Dateigröße kompilierter Binärdateien. Für N = 65536 (anstelle von 1024) springt meine Binärdatei von 15 KB auf 270 KB !!
Cetin Sert
50
@CetinSert Compiler muss intstatischen Daten 65536 s hinzufügen , was 256 K entspricht - genau die Größe, die Sie beobachtet haben.
Qrdl
15
@CetinSert Warum sollte ich? Dies ist ein Standardverhalten des Compilers, das nicht für bestimmte Initialisierer spezifisch ist. Wenn Sie 65536 ints statisch initialisieren , erhalten int foo1 = 1, foo2 = 1, ..., foo65536 =1;Sie die gleiche Vergrößerung.
Qrdl
27
Besser noch: "int array [] = {[0 ... 1023] = 5}", die Größe des Arrays wird automatisch auf 1024 gesetzt, was einfacher und sicherer zu ändern ist.
Francois
4
@Francois oder für ein 2d-Array, bool array[][COLS] = { [0...ROWS-1][0...COLS-1] = true}obwohl ich nicht sicher bin, ob das besser lesbar ist als das vollständige Formular.
g33kz0r
178

Zum statischen Initialisieren eines großen Arrays mit demselben Wert ohne mehrfaches Kopieren und Einfügen können Sie Makros verwenden:

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

Wenn Sie den Wert ändern müssen, müssen Sie den Austausch nur an einer Stelle durchführen.

Bearbeiten: mögliche nützliche Erweiterungen

(mit freundlicher Genehmigung von Jonathan Leffler )

Sie können dies leicht verallgemeinern mit:

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

Eine Variante kann erstellt werden mit:

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

das funktioniert mit Strukturen oder zusammengesetzten Arrays.

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

Makronamen sind verhandelbar.

Mouviciel
quelle
12
Ich würde dies nur in extremen Fällen in Betracht ziehen, sicherlich ist ein Memset die elegantere Art, es auszudrücken.
u0b34a0f6ae
47
Wenn die Daten ROM-fähig sein müssen, kann memset nicht verwendet werden.
Prof. Falken Vertrag verletzt
9
Der Präprozessor generiert den Code tatsächlich aus #defines. Bei größeren Array-Dimensionen wächst die Größe der ausführbaren Datei. Aber definitiv + für die Idee;)
Leonid
7
@Alcott, auf alten Computern und immer noch auf vielen eingebetteten Systemen wird der Code schließlich in ein EPROM oder ROM gestellt . ROM-fähig bedeutet in eingebetteten Systemen auch "Code in Flash", da dies ungefähr die gleichen Auswirkungen hat, nämlich dass der Speicher nicht zur Laufzeit geschrieben werden kann. Das Memset oder eine andere Anweisung zum Aktualisieren oder Ändern des Speichers kann nicht verwendet werden. Konstanten können jedoch vor dem Start des Programms ausgedrückt und geflasht oder ROM-bearbeitet werden.
Prof. Falken Vertrag verletzt
4
@ u0b34a0f6ae: Beachten Sie, dass Sie diese Methode auch verwenden können, wenn VAL_1Xes sich nicht um eine einzelne Ganzzahl, sondern um eine Liste handelt. Wie bei Amigable-Status ist dies auch bei eingebetteten Systemen der Fall, bei denen Sie die Init-Werte eines EEPROM- oder Flash-Speichers definieren möchten. In beiden Fällen können Sie nicht verwenden memset().
Martin Scharrer
63

Wenn Sie sicherstellen möchten, dass jedes Mitglied des Arrays explizit initialisiert wird, lassen Sie einfach die Dimension in der Deklaration weg:

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

Der Compiler leitet die Dimension aus der Initialisierungsliste ab. Leider kann bei mehrdimensionalen Arrays nur die äußerste Dimension weggelassen werden:

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

ist OK, aber

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

ist nicht.

Frank Szczerba
quelle
ist das richtig ? int myPoints[10][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} };
Praveen Gowda IV
10
Nein. Sie lassen die innerste Dimension weg, die nicht zulässig ist. Dies führt zu einem Compilerfehler.
Frank Szczerba
4
Sowohl Initialisierer als auch Längeninferenz wurden in C99 eingeführt.
Palec
3
@Palec: Seit den Tagen vor dem Standard C (seit der Veröffentlichung der K & R 1st Edition und wahrscheinlich eine Weile zuvor) wurde in C keine Längeninferenz angegeben. Ausgewiesene Initialisierer waren in C99 neu, es werden jedoch keine festgelegten Initialisierer verwendet.
Jonathan Leffler
53

Ich habe Code gesehen, der diese Syntax verwendet:

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

Besonders nützlich ist es, wenn Sie ein Array erstellen, das Aufzählungen als Index verwendet:

enum
{
    ERR_OK,
    ERR_FAIL,
    ERR_MEMORY
};

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

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

Dies hält die Dinge in Ordnung, auch wenn Sie einige der Enum-Werte nicht in der richtigen Reihenfolge schreiben.

Mehr über diese Technik finden Sie hier und hier .

abelenky
quelle
8
Dies ist die C99-Initialisierersyntax, die bereits von einigen anderen Antworten abgedeckt wird. Sie könnten die Erklärung sinnvoll machen char const *array[] = { ... };oder sogar char const * const array[] = { ... };, oder ?
Jonathan Leffler
22
int i;
for (i = 0; i < ARRAY_SIZE; ++i)
{
  myArray[i] = VALUE;
}

Ich denke das ist besser als

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

falls sich die Größe des Arrays ändert.

Tarski
quelle
12
Für die Aufzeichnung ist das im Grunde nur eine langsamere, ausführlichere Version vonmemset(myArray, VALUE, ARRAY_SIZE);
Benson
18
Wie würden Sie memset verwenden, um ein int-Array auf einen Wert größer als 255 zu initialisieren? memset funktioniert nur, wenn das Array bytegroß ist.
Matt
21
@Benson: Sie können den obigen Code auf Plattformen mit sizeof (int)> sizeof (char) nicht durch memset ersetzen. Versuch es.
ChrisWue
13

Sie können den gesamten statischen Initialisierer wie oben beschrieben ausführen, aber es kann eine echte Enttäuschung sein, wenn sich Ihre Arraygröße ändert (wenn sich Ihr Array ändert, wenn Sie nicht die entsprechenden zusätzlichen Initialisierer hinzufügen, erhalten Sie Müll).

memset gibt Ihnen einen Laufzeit-Treffer für die Ausführung der Arbeit, aber kein richtig ausgeführter Code-Größen-Treffer ist immun gegen Änderungen der Array-Größe. Ich würde diese Lösung in fast allen Fällen verwenden, wenn das Array größer als beispielsweise ein paar Dutzend Elemente war.

Wenn es wirklich wichtig wäre, dass das Array statisch deklariert wird, würde ich ein Programm schreiben, um das Programm für mich zu schreiben und es Teil des Erstellungsprozesses zu machen.

Sockel
quelle
Könnten Sie bitte ein Beispiel für diese Verwendung von hinzufügen memset, um das Array zu initialisieren?
Sopalajo de Arrierez
8

Hier ist ein anderer Weg:

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

Sehen:

C-Erweiterungen

Designated inits

Stellen Sie dann die Frage: Wann kann man C-Erweiterungen verwenden?

Das obige Codebeispiel befindet sich in einem eingebetteten System und wird niemals das Licht eines anderen Compilers sehen.

bescheidener_guru
quelle
6

Zum Initialisieren von 'normalen' Datentypen (wie Int-Arrays) können Sie die Klammer-Notation verwenden, die Werte werden jedoch nach dem letzten auf Null gesetzt, wenn noch Platz im Array vorhanden ist:

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

Wenn das Array int oder irgendetwas mit der Größe von int ist oder die Größe Ihres Mem-Musters genau zu einem int passt (dh alle Nullen oder 0xA5A5A5A5), ist es am besten, memset () zu verwenden .

Andernfalls rufen Sie memcpy () in einer Schleife auf, die den Index verschiebt.

ddimitrov
quelle
5

Eine leicht ironische Antwort; Schreiben Sie die Erklärung

array = initial_value

in Ihrer bevorzugten Array-fähigen Sprache (meine ist Fortran, aber es gibt viele andere) und verknüpfen Sie sie mit Ihrem C-Code. Sie möchten es wahrscheinlich als externe Funktion zusammenfassen.

Hochleistungsmarke
quelle
4

Es gibt eine schnelle Möglichkeit, ein Array eines beliebigen Typs mit einem bestimmten Wert zu initialisieren. Es funktioniert sehr gut mit großen Arrays. Der Algorithmus ist wie folgt:

  • initialisiere erstes Element des Arrays (üblicher Weg)
  • Kopieren Sie einen Teil, der in einen Teil gesetzt wurde, der nicht gesetzt wurde, und verdoppeln Sie die Größe bei jedem nächsten Kopiervorgang

Für 1 000 000Elemente intArray ist es 4 mal schneller als normale Schleifeninitialisierung (I5, 2 Kerne, 2,3 GHz, 4GiB Speicher, 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;
}
Maciej
quelle
2
Entschuldigung, aber das stimmt nicht. Vielleicht haben Sie vergessen, die Kompilierungsoptimierung während Ihrer Tests zu aktivieren (getestet im Debug-Modus?). Wenn ich dies teste, ist die Schleife fast immer 50% schneller als memfill ('immer' aufgrund einiger Lastschwankungen auf meinem Computer). Und mit memset (a, 0, sizeof (a)); ist sogar doppelt so schnell wie loopfill.
RS1980
2
Wie bei jedem Benchmarking-Code müssen Sie äußerst vorsichtig sein. Das Hinzufügen einer Schleife zum zehnmaligen Ausführen des Timing-Codes (und das Verdoppeln der Größe des Arrays auf 20 MB) zeigt - für mich auf einem MacBook Pro mit macOS Sierra 10.12.3 und unter Verwendung von GCC 6.3.0 -, dass das erste Mal verwendet wird Die Schleife benötigt ungefähr 4600 µs, während der memfill()Code ungefähr 1200 µs benötigt. Bei nachfolgenden Iterationen dauert die Schleife jedoch ungefähr 900-1000 µs, während der memfill()Code 1000-1300 µs benötigt. Die erste Iteration wird wahrscheinlich durch die Zeit beeinflusst, in der der Cache gefüllt wird. Kehren Sie die Tests um und memfill()ist beim ersten Mal langsam.
Jonathan Leffler
2

Niemand hat die Indexreihenfolge für den Zugriff auf die Elemente des initialisierten Arrays erwähnt. Mein Beispielcode gibt ein anschauliches Beispiel dafür.

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

Die Ausgabe ist:

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
hkBattousai
quelle
4
<iostream>nicht gültig ist , Cwie std::cout, std::cinusw. ist der Teil std::namespaceund Cnicht unterstützt namespaces. Versuchen Sie es mit <stdio.h>für printf(...)statt.
Francis Cugler
2

Die kurze Antwort lautet: Wenn Sie die Optimierung zur Kompilierungszeit aktivieren, werden Sie nichts Besseres tun:

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

Zusätzlicher Bonus: Der Code ist tatsächlich lesbar :)

JWDN
quelle
7
Die Frage wurde speziell zur Initialisierung gestellt. Dies ist explizit keine Initialisierung, sondern eine Zuweisung nach der Initialisierung. Dies kann sofort erfolgen, ist jedoch noch keine Initialisierung.
Andy
Völlig nicht hilfreich für eine große statische Nachschlagetabelle in einer Funktion, die oft aufgerufen wird.
Martin Bonner unterstützt Monica
... erinnern Sie sich nicht an statische Nachschlagetabellen in Funktionen, die Teil der ursprünglichen Frage sind - halten Sie es einfach. Das heißt, @Community hat es wahrscheinlich geschafft.
JWDN
1
  1. Wenn Ihr Array als statisch oder global deklariert ist, haben alle Elemente im Array bereits den Standardwert 0.
  2. Einige Compiler setzen Arrays im Debug-Modus standardmäßig auf 0.
  3. Es ist einfach, den Standardwert auf 0 zu setzen: int array [10] = {0};
  4. Für andere Werte haben Sie jedoch memset () oder loop verwendet.

Beispiel: int array [10]; Memset (Array, -1, 10 * sizeof (int));

Hannah Zhang
quelle
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;
}

Es gibt die o / p 5 5 5 5 5 5 ...... bis zur Größe des gesamten Arrays

Dadhich Sourav
quelle
0

Ich weiß, dass der Benutzer Tarskidiese Frage auf ähnliche Weise beantwortet hat, aber ich habe einige weitere Details hinzugefügt. Verzeihen Sie etwas von meinem C, denn ich bin ein bisschen verrostet, da ich eher dazu neige, C ++ zu verwenden, aber hier ist es.


Wenn Sie die Größe des Arrays im Voraus kennen ...

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

Es gibt ein paar Einschränkungen oben; Eine davon ist, dass sie UINT myArray[size];bei der Deklaration nicht direkt initialisiert wird. Der nächste Codeblock oder Funktionsaufruf initialisiert jedoch jedes Element des Arrays mit demselben gewünschten Wert. Die andere Einschränkung ist, dass Sie initializing functionfür jeden, den typeSie unterstützen , eine schreiben müssen, und Sie müssten auch die printArray()Funktion ändern , um diese Typen zu unterstützen.


Sie können diesen Code mit einem Online-Complier ausprobieren, den Sie hier finden .

Francis Cugler
quelle
0

Beachten Sie für die verzögerte Initialisierung (dh die Initialisierung des Klassenmitgliedskonstruktors) Folgendes:

int a[4];

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

Ich weiß, dass in der ursprünglichen Frage ausdrücklich C und nicht C ++ erwähnt wird, aber wenn Sie (wie ich) hierher gekommen sind, um nach einer Lösung für C ++ - Arrays zu suchen, ist hier ein guter Trick:

Wenn Ihr Compiler Fold-Ausdrücke unterstützt , können Sie Template Magic verwenden und std::index_sequenceeine Initialisierungsliste mit dem gewünschten Wert erstellen. Und Sie können es sogar constexprund fühlen sich wie ein Chef:

#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

Sie können sich den Code bei der Arbeit ansehen (bei Wandbox)

Clemens Sielaff
quelle
-1

Ich sehe keine Anforderungen in der Frage, daher muss die Lösung generisch sein: Initialisierung eines nicht spezifizierten möglicherweise mehrdimensionalen Arrays, das aus nicht spezifizierten möglicherweise Strukturelementen mit einem anfänglichen Elementwert aufgebaut ist:

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

Ergebnis:

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_sizegeändert zu(char*)start+element_size

Sambowry
quelle
1
Ich bin mir nicht sicher, ob dies eine Lösung ist oder nicht. Ich bin mir nicht sicher, ob sizeof(void)es überhaupt gültig ist.
Chris Lutz
3
Es funktioniert nicht. Nur die ersten beiden werden initialisiert, der Rest ist nicht initialisiert. Ich verwende GCC 4.0 unter Mac OS X 10.4.
Dreamlax
Dies ruft ein undefiniertes Verhalten hervor, da sich die Quelldaten im zweiten memcpy()mit dem Zielbereich überschneiden. Mit einer naiven Implementierung von memcpy()kann es funktionieren, aber es ist nicht erforderlich, dass das System es funktioniert.
Jonathan Leffler
-1

Früher (und ich sage nicht, dass es eine gute Idee ist) haben wir das erste Element gesetzt und dann:

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

Ich bin mir nicht einmal sicher, ob es nicht mehr funktionieren würde (das würde von der Implementierung von memcpy abhängen), aber es funktioniert, indem das ursprüngliche Element wiederholt in das nächste kopiert wird - funktioniert sogar für Arrays von Strukturen.

Mike
quelle
Das wird nicht zuverlässig funktionieren. Meiner Meinung nach sollte der Standard Funktionen bereitgestellt haben, die memcpyim Falle einer Überlappung der Bottom-Up- oder Top-Down-Kopierreihenfolge entsprechen, dies jedoch nicht tun.
Supercat
Wie gesagt, es war nur etwas, was wir getan haben, das nicht zuverlässig funktioniert, aber damals haben wir uns mehr auf Effizienz konzentriert als auf das Vermeiden von undokumentierten Funktionen. Während es effizienter ist, Speicher vorwärts zu kopieren, gibt es in der Spezifikation nichts zu sagen, dass er nicht rückwärts in zufälliger Reihenfolge kopiert oder auf mehrere Threads aufgeteilt werden kann. memmove () bietet die Möglichkeit, ohne Konflikte zu kopieren.
Mike
Dies entspricht dem Code in einer anderen Antwort - und ist fehlerhaft. Mit memmove()funktioniert es nicht.
Jonathan Leffler
-2

Wenn Sie parallel meinen, denke ich, dass der Komma-Operator in Verbindung mit einem Ausdruck dies tun kann:

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

oder wenn Sie in einem einzelnen Konstrukt meinen, können Sie dies in einer for-Schleife tun:

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

// Beachten Sie, dass der Kommaoperator in einer Argumentliste nicht der oben beschriebene Paralleloperator ist.

Sie können eine Array-Dekleration initialisieren:

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

Sie können malloc / calloc / sbrk / alloca / etc aufrufen, um einem Objekt einen festen Speicherbereich zuzuweisen:

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

und Zugriff auf die Mitglieder durch:

*(array + index)

Usw.

pchelper4
quelle
Der Kommaoperator garantiert nominell die Auswertung von links nach rechts. Wenn die Ausdrücke keine Nebenwirkungen aufweisen, ist es möglicherweise möglich, die Operationen zu parallelisieren, dies wäre jedoch für einen Compiler ungewöhnlich.
Jonathan Leffler