Wie fügt man ein dynamisches Array IN eine Struktur in C ein?

Lesezeit: 8 Minuten

Toms Benutzeravatar
Tom

Ich habe mich umgesehen, konnte aber keine Lösung für eine wohl gestellte Frage finden. Hier ist der Code, den ich habe:

 #include <stdlib.h>

struct my_struct {
    int n;
    char s[]
};

int main()
{
    struct my_struct ms;
    ms.s = malloc(sizeof(char*)*50);
}

und hier ist der Fehler, den gcc mir gibt: error: invalid use of flexible array member

Ich kann es zum Kompilieren bringen, wenn ich die Deklaration von s innerhalb der Struktur als deklariere

char* s

und dies ist wahrscheinlich eine überlegene Implementierung (Zeigerarithmetik ist schneller als Arrays, ja?), Aber ich dachte, in ca Deklaration von

char s[]

ist das gleiche wie

char* s

  • char s[] ist das gleiche wie char *s nur innerhalb der Parameterliste einer Funktion.

    – Alok Singhal

    13. Januar 2010 um 23:16 Uhr

Benutzeravatar von Jerry Coffin
Jerry Sarg

So wie Sie es jetzt geschrieben haben, wurde es früher als “Struct-Hack” bezeichnet, bis C99 es als “flexibles Array-Mitglied” segnete. Der Grund, warum Sie einen Fehler erhalten (wahrscheinlich sowieso), ist, dass darauf ein Semikolon folgen muss:

#include <stdlib.h>

struct my_struct {
    int n;
    char s[];
};

Wenn Sie dafür Platz zuweisen, möchten Sie die Größe der Struktur zuweisen Plus die Menge an Speicherplatz, die Sie für das Array benötigen:

struct my_struct *s = malloc(sizeof(struct my_struct) + 50);

In diesem Fall ist das flexible Array-Member ein Array aus char und sizeof(char)==1, sodass Sie nicht mit seiner Größe multiplizieren müssen, sondern genau wie bei jedem anderen malloc, das Sie tun müssten, wenn es ein wäre Array eines anderen Typs:

struct dyn_array { 
    int size;
    int data[];
};

struct dyn_array* my_array = malloc(sizeof(struct dyn_array) + 100 * sizeof(int));

Bearbeiten: Dies ergibt ein anderes Ergebnis, wenn Sie das Mitglied in einen Zeiger ändern. In diesem Fall benötigen Sie (normalerweise) zwei separate Zuweisungen, eine für die Struktur selbst und eine für die “zusätzlichen” Daten, auf die der Zeiger zeigen soll. Mit einem flexiblen Array-Member können Sie alle Daten in einem einzigen Block zuweisen.

  • C99 erlaubte das tatsächlich – urghh!

    – Martin Beckett

    13. Januar 2010 um 23:52 Uhr

  • Wow, das habe ich noch nie gesehen … hängt dies davon ab, dass das “flexible Array-Mitglied” das letzte deklarierte Feld in der Struktur ist? Sind Sie darauf beschränkt, nur ein einziges “flexibles Array-Mitglied” pro Struktur zu haben?

    – vicatcu

    14. Januar 2010 um 16:41 Uhr

  • @vicatcu: Ja, zu deinen beiden Fragen. Wenn der Arbeitsspeicher dient und Sie eine Struktur einbetten, die ein flexibles Array-Mitglied enthält, muss es das letzte Mitglied in der äußeren Struktur sein, sodass das flexible Array-Mitglied immer das letzte Element ist, wenn sie alle zusammengefügt werden.

    – Jerry Sarg

    14. Januar 2010 um 17:05 Uhr

AnT steht mit Russlands Benutzer-Avatar
AnT steht zu Russland

Sie müssen zuerst entscheiden, was Sie zu tun versuchen.


Wenn Sie eine Struktur mit einem Zeiger auf eine haben möchten [independent] Array darin, müssen Sie es als deklarieren

struct my_struct { 
  int n; 
  char *s;
}; 

In diesem Fall können Sie das eigentliche Struct-Objekt beliebig erstellen (z. B. eine automatische Variable).

struct my_struct ms;

und weisen Sie dann den Speicher für das Array unabhängig zu

ms.s = malloc(50 * sizeof *ms.s);  

Tatsächlich besteht keine allgemeine Notwendigkeit, den Array-Speicher dynamisch zuzuweisen

struct my_struct ms;
char s[50];

ms.s = s;

Es hängt alles davon ab, welche Art von Lebensdauer Sie von diesen Objekten benötigen. Wenn Ihre Struktur automatisch ist, dann wäre das Array in den meisten Fällen auch automatisch. Wenn das Strukturobjekt besitzt den Array-Speicher, es macht einfach keinen Sinn, etwas anderes zu tun. Wenn die Struktur selbst dynamisch ist, sollte das Array normalerweise auch dynamisch sein.

Beachten Sie, dass Sie in diesem Fall zwei unabhängige Speicherblöcke haben: die Struktur und das Array.


Ein völlig anderer Ansatz wäre die Verwendung des Idioms “struct hack”. In diesem Fall wird das Array zu einem integralen Bestandteil der Struktur. Beide befinden sich in einem einzigen Speicherblock. In C99 würde die Struktur als deklariert werden

struct my_struct { 
  int n; 
  char s[];
}; 

und um ein Objekt zu erstellen, müssten Sie das Ganze dynamisch zuweisen

struct my_struct *ms = malloc(sizeof *ms + 50 * sizeof *ms->s);

Die Größe des Speicherblocks wird in diesem Fall berechnet, um die Strukturmitglieder und das nachfolgende Array der Laufzeitgröße aufzunehmen.

Beachten Sie, dass Sie in diesem Fall keine Möglichkeit haben, solche Strukturobjekte als statische oder automatische Objekte zu erstellen. Strukturen mit flexiblen Array-Membern am Ende können in C nur dynamisch zugewiesen werden.


Ihre Annahme, dass Zeigerarithmetik schneller ist als Arrays, ist absolut falsch. Arrays arbeiten per Definition mit Zeigerarithmetik, also sind sie im Grunde gleich. Außerdem ist ein echtes Array (nicht zu einem Zeiger zerfallen) im Allgemeinen etwas schneller als ein Zeigerobjekt. Der Zeigerwert muss aus dem Speicher gelesen werden, während die Position des Arrays im Speicher aus dem Array-Objekt selbst “bekannt” (oder “berechnet”) ist.

  • UV für sizeof *ms + 50 * sizeof *ms->s: einfacher zu überprüfen und zu pflegen.

    – chux – Wiedereinsetzung von Monica

    19. September 2021 um 3:18 Uhr

Die Verwendung eines Arrays unspezifizierter Größe ist nur am Ende einer Struktur erlaubt und funktioniert nur in einigen Compilern. Es ist eine nicht standardmäßige Compiler-Erweiterung. (Obwohl ich glaube, ich erinnere mich, dass C++0x dies zulassen wird.)

Das Array wird jedoch keine separate Zuordnung für von der Struktur sein. Sie müssen also alle zuweisen my_structnicht nur der Array-Teil.

Was ich tue, ist dem Array einfach eine kleine Größe zu geben, die jedoch nicht Null ist. Normalerweise 4 für Zeichen-Arrays und 2 für wchar_t Arrays, um die 32-Bit-Ausrichtung beizubehalten.

Dann können Sie die deklarierte Größe des Arrays berücksichtigen, wenn Sie die Zuweisung vornehmen. Ich glaube oft nicht an die Theorie, dass der Slop kleiner ist als die Granularität, in der der Heap-Manager ohnehin arbeitet.

Außerdem denke ich, dass Sie sizeof(char*) in Ihrer Zuordnung nicht verwenden sollten.

Das würde ich tun.

struct my_struct {
    int nAllocated;
    char s[4]; // waste 32 bits to guarantee alignment and room for a null-terminator
};

int main()
{
    struct my_struct * pms;
    int cb = sizeof(*pms) + sizeof(pms->s[0])*50;
    pms = (struct my_struct*) malloc(cb);
    pms->nAllocated = (cb - sizoef(*pms) + sizeof(pms->s)) / sizeof(pms->s[0]);
}

Arrays werden in Zeiger aufgelöst, und hier sind Sie muss definieren s wie char *s. Die Struktur ist im Grunde ein Container und muss (IIRC) eine feste Größe haben, daher ist es einfach nicht möglich, ein Array mit dynamischer Größe darin zu haben. Da bist du mallocWenn Sie den Speicher trotzdem verwenden, sollte dies keinen Unterschied machen, wonach Sie suchen.

Im Grunde sagst du, s zeigt einen Speicherplatz an. Beachten Sie, dass Sie später immer noch mit der Notation like darauf zugreifen können s[0].

Zeigerarithmetik ist schneller als Arrays, ja?

Überhaupt nicht – sie sind eigentlich gleich. Arrays werden zur Kompilierzeit in Zeigerarithmetik übersetzt.

char test[100];
test[40] = 12;

// translates to: (test now indicates the starting address of the array)
*(test+40) = 12;

Duncans Benutzeravatar
Duncan

Ich vermute, der Compiler weiß nicht, wie viel Platz er für s zuweisen muss[]falls Sie sich dafür entscheiden, eine automatische Variable damit zu deklarieren.

Ich stimme mit dem überein, was Ben gesagt hat, deklarieren Sie Ihre Struktur

struct my_struct {
    int n;
    char s[1];
};

Auch um seinen Kommentar zur Lagerung zu verdeutlichen, erklärt char *s wird die Struktur nicht auf den Stapel legen (da sie dynamisch zugewiesen wird) und zuweisen s im Haufen, was es tun wird, ist das erste zu interpretieren sizeof(char *) Bytes Ihres Arrays als Zeiger, so dass Sie nicht mit den Daten arbeiten, von denen Sie glauben, dass Sie sie sind, und wahrscheinlich tödlich sein werden.

Es ist wichtig, sich daran zu erinnern, dass die Operationen auf Zeigern und Arrays zwar auf die gleiche Weise implementiert werden können, aber nicht dasselbe sind.

Benutzeravatar von Arpan Saini
Arpan Saini

Arbeitscode zum Speichern von Arrays in einer Struktur in ac und zum Speichern von Werten in den Array-Elementen Bitte hinterlassen Sie einen Kommentar, wenn Sie irgendwelche Zweifel haben, ich werde nach besten Kräften klären

Struktur definieren:

struct process{
    int process_id;
    int tau;
    double alpha;
    int* process_time;
};

Speicherbelegung für Prozessstruktur:

 struct process* process_mem_aloc = (struct process*) malloc(temp_number_of_process * sizeof(struct process));

Mehrere Prozesse durchlaufen und für jeden Prozess das dynamische Array process_time aktualisieren

int process_count = 0;
int tick_count = 0;


while(process_count < number_of_process){


  //Memory allocation for each array of the process, will be containting size equal to number_of_ticks: can hold any value

        (process_mem_aloc + process_count)->process_time = (int*) malloc(number_of_ticks* sizeof(int));

Daten zeilenweise aus einer Datei lesen, in das Array process_time speichern und dann aus dem gespeicherten Wert drucken, die nächste While-Schleife befindet sich innerhalb der Prozess-While-Schleife

        while(tick_count < number_of_ticks){

            fgets(line, LINE_LENGTH, file);
            *((process_mem_aloc + process_count)->process_time + tick_count) = convertToInteger(line);;
            printf("tick_count : %d , number_of_ticks %d\n",tick_count,*((process_mem_aloc + process_count)->process_time + tick_count));
            tick_count++;
        }

        tick_count = 0;

1411190cookie-checkWie fügt man ein dynamisches Array IN eine Struktur in C ein?

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

Privacy policy