Wie werden alle Mitglieder eines Arrays auf denselben Wert initialisiert?

Lesezeit: 7 Minuten

Matts Benutzeravatar
Matt

Ich habe ein großes Array drin C (nicht C++ falls 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 benutzen memset() in meinem Fall, aber gibt es dafür keine Möglichkeit, die direkt in die C-Syntax integriert ist?

  • Keine der bisherigen Antworten erwähnt die designierte Initialisierungsnotation, 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 diese Fragmente werden unter C99 oder C11 kompiliert.

    – Jonathan Leffler

    11. Mai 2014 um 14:40 Uhr


  • Tatsächlich verwendet abelenkys Antwort einen bestimmten Initialisierer, ist aber kein vollständig geformter Initialisierungscode

    – Rob11311

    5. Juni 2014 um 14:17 Uhr


  • memset() kann helfen, hängt aber vom Wert ab.

    – Nick

    13. Februar 2015 um 12:23 Uhr

  • memset() spezifische Diskussion: stackoverflow.com/questions/7202411/… Ich denke, es funktioniert nur für 0.

    – Ciro Santilli OurBigBook.com

    10. Mai 2016 um 18:55 Uhr

  • @ user16217248 funktioniert auch für “zyklische” Zahlen wie 0x1212, 0x0303 usw. 😉 aber ja, meistens braucht man Nullen

    – Nick

    28. September um 8:12 Uhr

Benutzeravatar von aib
aib

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

Dadurch werden also alle Elemente auf 0 initialisiert:

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

In C++ initialisiert eine leere Initialisierungsliste auch jedes Element auf 0. Dies ist bei C bis C23 nicht erlaubt:

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

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 dass “0” nicht unbedingt “alle Bits-Null” bedeutet, also ist die Verwendung des oben Genannten besser und portabler als memset(). (Gleitkommawerte werden auf +0 initialisiert, Zeiger auf Nullwerte usw.)

  • Betrachtet man Abschnitt 6.7.8 Initialisierung des C99-Standards, so scheint es nicht, dass eine leere Initialisierungsliste erlaubt ist.

    – Jonathan Leffler

    14. Oktober 2008 um 13:59 Uhr

  • C99 hat viele nette Features für die Struktur- und Array-Initialisierung; Die einzige Funktion, die es nicht hat (aber Fortran IV, 1966 hatte), ist eine Möglichkeit, einen bestimmten Initialisierer für ein Array zu wiederholen.

    – Jonathan Leffler

    14. Oktober 2008 um 14:00 Uhr

  • Ich glaube, das habe ich noch nicht gesehen: int myArray[] = {[3] = 123, [7] = 23}; Gibt Ihnen {0, 0, 0, 123, 0, 0, 0, 23}

    – akofink

    24. April 2013 um 13:49 Uhr

  • @akofink: Schauen Sie sich die Antwort von qrdl gleich unten an. Es ist eine GCC-Erweiterung.

    – Aib

    24. April 2013 um 17:16 Uhr

  • @Fratink Siehe §6.7.8.21: „Wenn es weniger Initialisierer in einer von geschweiften Klammern eingeschlossenen Liste gibt als Elemente oder Mitglieder eines Aggregats, oder weniger Zeichen in einem Zeichenfolgenliteral, das zum Initialisieren eines Arrays bekannter Größe verwendet wird, als Elemente darin sind des Arrays, der Rest des Aggregats wird implizit genauso initialisiert wie Objekte mit statischer Speicherdauer.”

    – Aib

    28. Juli 2020 um 16:43 Uhr


Benutzeravatar von qrdl
qrdl

Wenn Ihr Compiler GCC ist, können Sie die folgende “GNU-Erweiterungssyntax” verwenden:

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

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

  • Und diese Syntax führt zu einer enormen Zunahme der Dateigröße kompilierter Binärdateien. Für N = 65536 (statt 1024) springt meine Binärdatei von 15 KB auf 270 KB Größe!!

    – Cetin Sert

    28. März 2013 um 15:15 Uhr


  • @CetinSert Compiler muss 65536 hinzufügen ints in statische Daten, was 256 K entspricht – genau die Größenzunahme, die Sie beobachtet haben.

    – qrdl

    29. März 2013 um 9:53 Uhr

  • @CetinSert Warum sollte ich? Es handelt sich um ein standardmäßiges Compilerverhalten, das nicht spezifisch für designierte Initialisierer ist. Wenn Sie 65536 statisch initialisieren ints, wie int foo1 = 1, foo2 = 1, ..., foo65536 =1; Sie erhalten die gleiche Größenzunahme.

    – qrdl

    29. März 2013 um 20:48 Uhr

  • besser noch: “int array[] = {[0 … 1023] = 5}”, wird die Größe des Arrays automatisch auf 1024 gesetzt, einfacher und sicherer zu ändern.

    – François

    11. April 2013 um 9:19 Uhr

  • @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 die vollständige Form.

    Benutzer67416

    13. April 2013 um 6:59 Uhr


Benutzeravatar von mouviciel
mouviciel

Um ein großes Array mit demselben Wert ohne mehrfaches Kopieren und Einfügen statisch zu initialisieren, 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 die Ersetzung nur an einer Stelle vornehmen.

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.

  • Ich würde das nur im Extremfall in Betracht ziehen, sicherlich ist ein Memset die elegantere Art, es auszudrücken.

    – u0b34a0f6ae

    14. Oktober 2009 um 10:41 Uhr

  • Wenn die Daten ROM-fähig sein müssen, kann memset nicht verwendet werden.

    – Prof. Falken

    5. Juli 2010 um 9:24 Uhr

  • Der Präprozessor generiert den Code tatsächlich aus #defines. Mit größeren Array-Dimensionen wächst die ausführbare Größe. Aber auf jeden Fall + für die Idee 😉

    – Leonid

    3. Oktober 2010 um 12:31 Uhr

  • @Alcott, auf alten Computern und immer noch auf vielen eingebetteten Systemen wird der Code schließlich in einem platziert EPROM oder Rom. ROM-fähig bedeutet in eingebetteten Systemen auch “Code in Flash stecken”, weil es ungefähr die gleichen Auswirkungen hat, nämlich dass der Speicher nicht zur Laufzeit beschrieben werden kann. Dh memset oder andere Anweisungen zum Aktualisieren oder Ändern des Speichers können nicht verwendet werden. Konstanten können jedoch ausgedrückt und geflasht oder ROM-ed werden, bevor das Programm startet.

    – Prof. Falken

    8. Februar 2012 um 8:49 Uhr

  • @ u0b34a0f6ae: Denken Sie daran, dass Sie diese Methode auch verwenden können, wenn VAL_1X ist keine einzelne ganze Zahl, sondern eine Liste. Wie Amigable-Zustände ist dies auch der richtige Weg für eingebettete Systeme, bei denen Sie die Init-Werte eines EEPROMs oder Flash-Speichers definieren möchten. In beiden Fällen können Sie nicht verwenden memset().

    – Martin Scharrer

    5. Februar 2013 um 9:01 Uhr

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

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

Der Compiler leitet die Dimension aus der Initialisiererliste ab. Leider darf 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.

Benutzeravatar von abelenky
abelenki

Ich habe einen Code gesehen, der diese Syntax verwendet:

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

Besonders nützlich wird 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 zufällig einige der Enum-Werte in der falschen Reihenfolge schreiben.

Mehr zu dieser Technik finden Sie hier hier und hier.

  • Dies ist die C99-Initialisierungssyntax, die bereits von einigen der anderen Antworten abgedeckt wird. Sie könnten die Erklärung sinnvollerweise in char const *array[] = { ... }; oder auch char const * const array[] = { ... };könntest du nicht?

    – Jonathan Leffler

    29. April 2012 um 6:29 Uhr

Benutzeravatar von Tarski
Tarski

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.

  • Dies ist die C99-Initialisierungssyntax, die bereits von einigen der anderen Antworten abgedeckt wird. Sie könnten die Erklärung sinnvollerweise in char const *array[] = { ... }; oder auch char const * const array[] = { ... };könntest du nicht?

    – Jonathan Leffler

    29. April 2012 um 6:29 Uhr

Benutzeravatar von plinth
Sockel

Sie können das ganze statische Initialisierungs-Ding wie oben beschrieben ausführen, aber es kann ein echter Mist sein, wenn sich Ihre Array-Größe ändert (wenn Ihr Array embiggens wird, erhalten Sie Müll, wenn Sie nicht die entsprechenden zusätzlichen Initialisierer hinzufügen).

memset gibt Ihnen einen Laufzeittreffer für die Arbeit, aber kein richtiger Codegrößentreffer ist immun gegen Änderungen der Arraygröße. Ich würde diese Lösung in fast allen Fällen verwenden, wenn das Array größer als beispielsweise ein paar Dutzend Elemente ist.

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 zu einem Teil des Build-Prozesses zu machen.

  • Könnten Sie bitte ein Beispiel für diese Verwendung von hinzufügen memset um das Array zu initialisieren?

    – Sopalajo de Arrierez

    3. Mai 2019 um 20:21 Uhr

1428550cookie-checkWie werden alle Mitglieder eines Arrays auf denselben Wert initialisiert?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy