Deklarieren und Initialisieren von Arrays in C

Lesezeit: 7 Minuten

Benutzeravatar von Dave H
David H

Gibt es eine Möglichkeit, ein Array in C zuerst zu deklarieren und dann zu initialisieren?

Bisher habe ich ein Array wie folgt initialisiert:

int myArray[SIZE] = {1,2,3,4....};

Aber ich muss so etwas tun

int myArray[SIZE];

myArray = {1,2,3,4....};

In C99 können Sie dies mit einem zusammengesetzten Literal in Kombination mit tun memcpy

memcpy(myarray, (int[]) { 1, 2, 3, 4 }, sizeof myarray);

(unter der Annahme, dass die Größe der Quelle und die Größe des Ziels gleich sind).

In C89/90 können Sie dies emulieren, indem Sie ein zusätzliches “source”-Array deklarieren

const int SOURCE[SIZE] = { 1, 2, 3, 4 }; /* maybe `static`? */
int myArray[SIZE];
...
memcpy(myarray, SOURCE, sizeof myarray);

  • ich würde sagen bestimmt static.

    – Café

    29. Juni 2010 um 3:48 Uhr

  • Ich denke, in meinem Fall ist es am bequemsten, anstatt jedes Element zuzuweisen, jedes gewünschte Array in ein globales Array zu kopieren. Vielen Dank

    – David H

    29. Juni 2010 um 3:59 Uhr

  • +1 für C99. 😉 memcpy(myarray,(int [sizeof(myarray)/sizeof(myarray[0])]{1,2,3,4}, Größe meines Arrays); um den Rest auf die entsprechende Null zu initieren.

    – Nyan

    29. Juni 2010 um 6:31 Uhr

  • @Nyan: Tolle Idee. Dies löst auch einen Fehler aus, wenn zu viele Initialisierer vorhanden sind.

    – AnT steht zu Russland

    29. Juni 2010 um 6:52 Uhr


  • Ich habe einen Nachtrag zu Ihrer Antwort gepostet, der auch einen Kompilierzeitfehler auslöst, falls dies auch der Fall ist wenig Initialisierer.

    – Joseph Quinsey

    30. Juni 2010 um 14:38 Uhr

Benutzeravatar von paxdiablo
paxdiablo

Nein, Sie können sie nicht in einer Anweisung auf beliebige Werte setzen (es sei denn, dies ist Teil der Deklaration).

Sie können es entweder mit Code tun, so etwas wie:

myArray[0] = 1;
myArray[1] = 2;
myArray[2] = 27;
:
myArray[99] = -7;

oder (wenn es eine Formel gibt):

for (int i = 0; i < 100; i++) myArray[i] = i + 1;

Die andere Möglichkeit besteht darin, einige Vorlagen beizubehalten sind zum Zeitpunkt der Deklaration gesetzt und verwenden Sie sie, um Ihr Array zu initialisieren, etwa so:

static const int onceArr[]  = {  0,  1,  2,  3,  4,..., 99};
static const int twiceArr[] = {  0,  2,  4,  6,  8,...,198};
:
int myArray[7];
:
memcpy (myArray, twiceArr, sizeof (myArray));

Dies hat den Vorteil, dass es (höchstwahrscheinlich) schneller ist und es Ihnen ermöglicht, kleinere Arrays als die Vorlagen zu erstellen. Ich habe diese Methode in Situationen verwendet, in denen ich ein Array schnell neu initialisieren muss, aber auf einen bestimmten Zustand (wenn der Zustand alle Nullen wäre, würde ich einfach verwenden memset).


Sie können es sogar auf eine Initialisierungsfunktion lokalisieren:

void initMyArray (int *arr, size_t sz) {
    static const int template[] = {2, 3, 5, 7, 11, 13, 17, 19, 21, ..., 9973};
    memcpy (arr, template, sz);
}
:
int myArray[100];
initMyArray (myArray, sizeof(myArray));

Das statische Array wird (mit ziemlicher Sicherheit) zur Kompilierzeit erstellt, sodass dafür keine Laufzeitkosten anfallen, und das memcpy sollte unglaublich schnell sein, wahrscheinlich schneller als 1.229 Zuweisungsanweisungen, aber auf jeden Fall weniger Tipparbeit von Ihrer Seite :-).

Gibt es eine Möglichkeit, ein Array in C zuerst zu deklarieren und dann zu initialisieren?

Es gibt! aber nicht mit der Methode, die Sie beschrieben haben.

Sie können nicht mit einer kommaseparierten Liste initialisieren, dies ist nur in der Deklaration erlaubt. Sie können jedoch initialisieren mit …

myArray[0] = 1;
myArray[1] = 2;
...

oder

for(int i = 1; i <= SIZE; i++)
{
  myArray[i-1] = i;
}

  • Danke, aber was ich gesucht habe, war, es in einer durch Kommas getrennten Liste initialisieren zu können, weil diese Arrays sehr groß sein werden und ich dachte, dass es auf diese Weise bequemer wäre.

    – David H

    29. Juni 2010 um 3:53 Uhr

Benutzeravatar von Joseph Quinsey
Josef Quinsey

Dies ist ein Nachtrag zur akzeptierten Antwort von AndreyT mit Nyans Kommentar zu nicht übereinstimmenden Array-Größen. Ich bin mit ihrer automatischen Einstellung des fünften Elements auf Null nicht einverstanden. Es sollte wahrscheinlich sein 5 –die Zahl nach 1,2,3,4. Also würde ich memcpy() einen Wrapper vorschlagen, um a zu erzeugen Kompilierzeit Fehler, wenn wir versuchen, Arrays unterschiedlicher Größe zu kopieren:

#define Memcpy(a,b) do {                    /* copy arrays */       \
    ASSERT(sizeof(a) == sizeof(b) &&        /* a static assert */   \
           sizeof(a) != sizeof((a) + 0));   /* no pointers */       \
    memcpy((a), (b), sizeof (b));           /* & unnecesary */      \
    } while (0)                             /* no return value */

Dieses Makro generiert einen Kompilierungsfehler, wenn Ihr Array die Länge 1 hat. Das ist vielleicht ein Feature.

Da wir ein Makro verwenden, scheint das zusammengesetzte C99-Literal ein zusätzliches Paar Klammern zu benötigen:

Memcpy(myarray, ((int[]) { 1, 2, 3, 4 }));

Hier ist ASSERT() ein ‘statisches Assertion’. Wenn Sie noch keine eigene haben, verwende ich Folgendes auf einer Reihe von Plattformen:

#define CONCAT_TOKENS(a, b) a ## b
#define EXPAND_THEN_CONCAT(a,b) CONCAT_TOKENS(a, b)
#define ASSERT(e) enum {EXPAND_THEN_CONCAT(ASSERT_line_,__LINE__) = 1/!!(e)}
#define ASSERTM(e,m) /* version of ASSERT() with message */ \
    enum{EXPAND_THEN_CONCAT(m##_ASSERT_line_,__LINE__)=1/!!(e)}

Warum können Sie nicht initialisieren, wenn Sie deklarieren?

Welchen C-Compiler verwendest du? Unterstützt es C99?

Wenn C99 unterstützt wird, können Sie die Variable dort deklarieren, wo Sie sie benötigen, und sie initialisieren, wenn Sie sie deklarieren.

Die einzige Entschuldigung, die mir dafür einfällt, wäre, dass Sie es deklarieren müssen, aber vor der Verwendung einen frühen Exit durchführen müssen, sodass der Initialisierer verschwendet würde. Ich vermute jedoch, dass ein solcher Code nicht so sauber organisiert ist, wie er sein sollte, und so geschrieben werden könnte, dass dies kein Problem darstellt.

  • Danke für die schnelle Antwort! Ich muss nach der Deklaration initialisieren, da dies je nach Bedingung unterschiedlich sein wird, ich meine so etwas wie dieses int myArray[SIZE]; if(condition1) { myArray{x1, x2, x3, …} } else if(condition2) { myArray{y1, y2, y3, …} } . . usw. Ich verwende XCode

    – David H

    29. Juni 2010 um 3:47 Uhr


  • Sind die Arrays konstant? Wenn dies der Fall ist, besteht eine Möglichkeit darin, zwei separat initialisierte konstante Arrays zu verwenden und dann einen Zeiger (auf konstante Daten) so zu setzen, dass er auf das relevante Array zeigt. Sie würden die Arrays auch statisch machen. Wenn die Arrays nicht konstant sind, müssen Sie meines Erachtens nacheinander jedes Element berechnen.

    – Jonathan Leffler

    29. Juni 2010 um 5:13 Uhr

  • Ja, die Arrays sind konstant, ich werde diese Methode auch ausprobieren, danke.

    – David H

    29. Juni 2010 um 13:47 Uhr

Das OP ließ einige wichtige Informationen aus der Frage aus und fügte sie nur in einen Kommentar zu einer Antwort ein.

Ich muss nach der Deklaration initialisieren, da dies je nach Bedingung unterschiedlich sein wird, ich meine so etwas wie dieses int myArray[SIZE]; if(condition1) { myArray{x1, x2, x3, …} } else if(condition2) { myArray{y1, y2, y3, …} } . . usw…

Vor diesem Hintergrund müssen alle möglichen Arrays sowieso irgendwo in Daten gespeichert werden, sodass kein Memcpy erforderlich (oder erwünscht) ist, sondern nur ein Zeiger und ein 2d-Array erforderlich sind.

//static global since some compilers build arrays from instruction data
//... notably not const though so they can later be modified if needed
#define SIZE 8
static int myArrays[2][SIZE] = {{0,1,2,3,4,5,6,7},{7,6,5,4,3,2,1,0}};

static inline int *init_myArray(_Bool conditional){
  return myArrays[conditional];
}

// now you can use:
//int *myArray = init_myArray(1 == htons(1)); //any boolean expression

Die nicht-inline-Version gibt diese resultierende Assembly auf x86_64:

init_myArray(bool):
        movzx   eax, dil
        sal     rax, 5
        add     rax, OFFSET FLAT:myArrays
        ret
myArrays:
        .long   0
        .long   1
        .long   2
        .long   3
        .long   4
        .long   5
        .long   6
        .long   7
        .long   7
        .long   6
        .long   5
        .long   4
        .long   3
        .long   2
        .long   1
        .long   0

Für zusätzliche Bedingungen/Arrays ändern Sie einfach die 2 in myArrays in die gewünschte Zahl und verwenden eine ähnliche Logik, um einen Zeiger auf das richtige Array zu erhalten.

  • Danke für die schnelle Antwort! Ich muss nach der Deklaration initialisieren, da dies je nach Bedingung unterschiedlich sein wird, ich meine so etwas wie dieses int myArray[SIZE]; if(condition1) { myArray{x1, x2, x3, …} } else if(condition2) { myArray{y1, y2, y3, …} } . . usw. Ich verwende XCode

    – David H

    29. Juni 2010 um 3:47 Uhr


  • Sind die Arrays konstant? Wenn dies der Fall ist, besteht eine Möglichkeit darin, zwei separat initialisierte konstante Arrays zu verwenden und dann einen Zeiger (auf konstante Daten) so zu setzen, dass er auf das relevante Array zeigt. Sie würden die Arrays auch statisch machen. Wenn die Arrays nicht konstant sind, müssen Sie meines Erachtens nacheinander jedes Element berechnen.

    – Jonathan Leffler

    29. Juni 2010 um 5:13 Uhr

  • Ja, die Arrays sind konstant, ich werde diese Methode auch ausprobieren, danke.

    – David H

    29. Juni 2010 um 13:47 Uhr

Es ist nicht möglich, einem Array nach der Initialisierung alle Werte auf einmal zuzuweisen. Die beste Alternative wäre die Verwendung einer Schleife.

for(i=0;i<N;i++)
{
     array[i] = i;
}

Sie können Werte fest codieren und zuweisen wie —array[0] = 1 usw.

Memcpy kann auch verwendet werden, wenn Sie die Daten bereits in einem Array gespeichert haben.

1411350cookie-checkDeklarieren und Initialisieren von Arrays in C

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

Privacy policy