Frage Wie initialisiert man alle Mitglieder eines Arrays auf den gleichen Wert?


Ich habe ein großes Array in C (nicht C ++, wenn das einen Unterschied macht). Ich möchte alle Mitglieder auf den gleichen Wert initialisieren. Ich könnte schwören, dass ich einmal einen einfachen Weg kannte, dies zu tun. ich könnte benutzen memset() in meinem Fall, aber gibt es keinen Weg, dies zu tun, der direkt in die C-Syntax eingebaut ist?


789
2017-10-14 13:13


Ursprung


Antworten:


Es sei denn, dieser Wert ist 0 (in diesem Fall können Sie einen Teil des Initialisierers auslassen und die entsprechenden Elemente werden auf 0 initialisiert, es gibt 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...

Also werden alle Elemente auf 0 initialisiert:

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

In C ++ initialisiert eine leere Initialisierungsliste jedes Element auch auf 0. Das ist nicht erlaubt mit C:

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

Beachten Sie, dass Objekte mit statischer Speicherdauer auf 0 initialisiert werden, wenn dies nicht der Fall ist Initialisierer wird angegeben:

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

Und diese "0" bedeutet nicht unbedingt "alle-Bits-Null", also die Verwendung des obigen ist besser und portabler als memset (). (Gleitkommawerte werden sein initialisiert auf +0, Zeiger auf Nullwert, etc.)


1028
2017-10-14 13:17



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

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

Schau dir die detaillierte Beschreibung an: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Designated-Inits.html


348
2017-10-16 07:38



Wenn Sie ein großes Array mit demselben Wert ohne mehrfaches Kopieren und Einfügen statisch initialisieren möchten, 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 vornehmen.

Edit: 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.


161
2017-10-14 10:27



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

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

Der Compiler wird die Dimension aus der Initialisierungsliste ableiten. Leider kann für mehrdimensionale Arrays nur die äußerste Dimension weggelassen werden:

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

ist in Ordnung, aber

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

ist nicht.


59
2017-10-14 18:30



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 enums 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, selbst wenn Sie einige der Enum-Werte falsch schreiben.

Mehr über diese Technik kann gefunden werden Hier und Hier.


45
2018-03-21 21:02



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.


22
2017-10-14 13:34



Sie können die ganze statische Initialisierer-Sache tun, wie oben beschrieben, aber es kann ein echter Schwachpunkt sein, wenn sich Ihre Array-Größe ändert (wenn Ihr Array embiggens ist, wenn Sie nicht die passenden zusätzlichen Initialisierer hinzufügen, bekommen Sie Müll).

memset gibt Ihnen einen Laufzeit-Hit, um die Arbeit zu erledigen, aber kein Code-Size-Hit, der richtig gemacht wurde, ist immun gegen Änderungen der Array-Größe. Ich würde diese Lösung in fast allen Fällen verwenden, in denen das Array größer als etwa ein paar Dutzend Elemente war.

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


11
2017-10-14 13:29



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

Designierte Eingänge

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.


8
2017-10-14 22:12



Um "normale" Datentypen (wie int-Arrays) zu initialisieren, können Sie die Klammer-Notation verwenden, aber sie werden die Werte nach der letzten Null setzen, wenn noch Platz im Array ist:

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

5
2017-10-14 13:17