C dynamisch wachsendes Array

126

Ich habe ein Programm, das eine "rohe" Liste von Entitäten im Spiel liest, und ich beabsichtige, ein Array zu erstellen, das eine Indexnummer (int) einer unbestimmten Anzahl von Entitäten enthält, um verschiedene Dinge zu verarbeiten. Ich möchte vermeiden, zu viel Speicher oder CPU zu verwenden, um solche Indizes zu führen ...

Eine schnelle und schmutzige Lösung, die ich bisher verwende, besteht darin, in der Hauptverarbeitungsfunktion (lokaler Fokus) das Array mit der Größe der maximalen Spielentitäten und eine weitere Ganzzahl zu deklarieren, um zu verfolgen, wie viele zur Liste hinzugefügt wurden. Dies ist nicht zufriedenstellend, da jede Liste mehr als 3000 Arrays enthält, was nicht so viel ist, sich aber wie Verschwendung anfühlt, da ich die Lösung für 6-7 Listen für verschiedene Funktionen verwenden kann.

Ich habe keine C-spezifischen (nicht C ++ oder C #) spezifischen Lösungen gefunden, um dies zu erreichen. Ich kann Zeiger verwenden, habe aber etwas Angst davor, sie zu verwenden (es sei denn, dies ist der einzig mögliche Weg).

Die Arrays verlassen nicht den lokalen Funktionsumfang (sie müssen an eine Funktion übergeben und dann verworfen werden), falls sich dadurch etwas ändert.

Wenn Zeiger die einzige Lösung sind, wie kann ich sie verfolgen, um Undichtigkeiten zu vermeiden?

Balkanien
quelle
1
Dies ist ein (sehr, sehr kleines) Problem in C, aber wie haben Sie alle C ++ - und C # -Lösungen dafür vermisst?
Ignacio Vazquez-Abrams
11
"Wenn Zeiger die einzige Lösung sind, wie kann ich sie verfolgen, um Lecks zu vermeiden?" Sorgfalt, Aufmerksamkeit und Valgrind. Dies ist genau der Grund, warum Menschen Angst haben, wenn C an erster Stelle steht.
Chris Lutz
27
Sie können C nicht effektiv verwenden, ohne Zeiger zu verwenden. Hab keine Angst.
Qrdl
ohne große Bibliotheken nur eine Funktion für alle auch für Strukturen zB: stackoverflow.com/questions/3456446/…
user411313
6
Die Verwendung von C ohne Zeiger ist wie die Verwendung eines Autos ohne Kraftstoff.
Martinkunev

Antworten:

210

Ich kann Zeiger verwenden, habe aber ein bisschen Angst davor, sie zu verwenden.

Wenn Sie ein dynamisches Array benötigen, können Sie Zeigern nicht entkommen. Warum hast du aber Angst? Sie werden nicht beißen (solange Sie vorsichtig sind). In C gibt es kein eingebautes dynamisches Array. Sie müssen nur eines selbst schreiben. In C ++ können Sie die integrierte std::vectorKlasse verwenden. C # und fast jede andere Hochsprache haben auch eine ähnliche Klasse, die dynamische Arrays für Sie verwaltet.

Wenn Sie vorhaben, Ihre eigenen zu schreiben, sollten Sie zunächst Folgendes tun: Die meisten dynamischen Array-Implementierungen beginnen mit einem Array mit einer (kleinen) Standardgröße. Wenn Sie beim Hinzufügen eines neuen Elements keinen Speicherplatz mehr haben, verdoppeln Sie den Wert Größe des Arrays. Wie Sie im folgenden Beispiel sehen können, ist es überhaupt nicht sehr schwierig: (Ich habe Sicherheitsüberprüfungen der Kürze halber weggelassen)

typedef struct {
  int *array;
  size_t used;
  size_t size;
} Array;

void initArray(Array *a, size_t initialSize) {
  a->array = malloc(initialSize * sizeof(int));
  a->used = 0;
  a->size = initialSize;
}

void insertArray(Array *a, int element) {
  // a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
  // Therefore a->used can go up to a->size 
  if (a->used == a->size) {
    a->size *= 2;
    a->array = realloc(a->array, a->size * sizeof(int));
  }
  a->array[a->used++] = element;
}

void freeArray(Array *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
}

Die Verwendung ist genauso einfach:

Array a;
int i;

initArray(&a, 5);  // initially 5 elements
for (i = 0; i < 100; i++)
  insertArray(&a, i);  // automatically resizes as necessary
printf("%d\n", a.array[9]);  // print 10th element
printf("%d\n", a.used);  // print number of elements
freeArray(&a);
casablanca
quelle
1
Danke für den Beispielcode. Ich habe die spezifische Funktion mit einem großen Array implementiert, werde aber andere ähnliche Dinge damit implementieren und nachdem ich sie kontrolliert habe, die anderen wieder ändern :)
Balkania
2
Vielen Dank für den Code. Eine removeArrayMethode, die das letzte Element entfernt, wäre auch ordentlich. Wenn Sie es zulassen, werde ich es Ihrem Codebeispiel hinzufügen.
Brimborium
5
% d und size_t ... ein bisschen ein Nein-Nein. Wenn Sie C99 oder höher verwenden, können Sie die Zugabe von% z
Randy Howard am
13
Lassen Sie niemals Sicherheitsüberprüfungen mit Speicherzuweisung und Neuzuweisung aus.
Alex Reynolds
3
Es ist ein Leistungskompromiss. Wenn Sie jedes Mal verdoppeln, haben Sie manchmal einen Overhead von 100% und durchschnittlich 50%. 3/2 gibt Ihnen 50% schlechteste und 25% typische. Es liegt auch nahe an der effektiven Basis der Fibionacci-Sequenz im Grenzwert (phi), die oft für ihre "exponentiellen, aber viel weniger gewalttätigen Eigenschaften als die Basis-2" gelobt und verwendet wird, aber einfacher zu berechnen ist. Die +8 bedeutet, dass Arrays, die relativ klein sind, nicht zu viele Kopien erstellen. Es wird ein multiplikativer Begriff hinzugefügt, der es dem Array ermöglicht, schnell zu wachsen, wenn seine Größe irrelevant ist. Bei speziellen Anwendungen sollte dies einstellbar sein.
Dan Sheppard
10

Ich kann mir einige Optionen vorstellen.

  1. Verknüpfte Liste. Sie können eine verknüpfte Liste verwenden, um ein dynamisch wachsendes Array zu erstellen. Aber Sie werden nicht in der Lage sein, array[100]ohne zuerst durchzugehen 1-99. Und es ist möglicherweise auch nicht so praktisch für Sie.
  2. Großes Array. Erstellen Sie einfach ein Array mit mehr als genug Platz für alles
  3. Ändern der Größe des Arrays. Erstellen Sie das Array neu, sobald Sie die Größe kennen, und / oder erstellen Sie jedes Mal ein neues Array, wenn Ihnen der Speicherplatz mit einem gewissen Rand ausgeht, und kopieren Sie alle Daten in das neue Array.
  4. Verknüpfte Liste Array-Kombination. Verwenden Sie einfach ein Array mit einer festen Größe. Wenn Ihnen der Speicherplatz ausgeht, erstellen Sie ein neues Array und verknüpfen Sie es (es ist ratsam, das Array und den Link zum nächsten Array in einer Struktur zu verfolgen).

Es ist schwer zu sagen, welche Option in Ihrer Situation am besten wäre. Das einfache Erstellen eines großen Arrays ist natürlich eine der einfachsten Lösungen und sollte Ihnen nur dann große Probleme bereiten, wenn es wirklich groß ist.

Wolph
quelle
Wie klingen sieben Arrays mit 3264 Ganzzahlen für ein modernes 2D-Spiel? Wenn ich nur paranoid bin, wäre die Lösung ein großes Array.
Balkanien
3
Sowohl Nr. 1 als auch Nr. 4 erfordern hier ohnehin die Verwendung von Zeigern und die dynamische Speicherzuweisung. Ich schlage vor, reallocmit # 3 zu verwenden - weisen Sie dem Array eine normale Größe zu und vergrößern Sie es dann, wenn Sie keine mehr haben. reallocübernimmt bei Bedarf das Kopieren Ihrer Daten. Was die Frage des OP zur Speicherverwaltung betrifft, müssen Sie nur malloceinmal am Anfang, freeeinmal am Ende und reallocjedes Mal , wenn Sie keinen Platz mehr haben. Es ist nicht so schlimm.
Borealid
1
@ Balkania: Sieben Arrays mit 3264 Ganzzahlen sind ein Haar unter 100 KB. Das ist überhaupt nicht viel Erinnerung.
Borealid
1
@ Balkania: 7 * 3264 * 32 bitklingt wie 91.39 kilobytes. Heutzutage nicht so sehr;)
Wolph
1
Diese besondere Auslassung ist eine Schande, denn es ist nicht ganz klar, was bei der reallocRückkehr passieren soll NULL: a->array = (int *)realloc(a->array, a->size * sizeof(int));... Vielleicht wäre es am besten geschrieben worden als: int *temp = realloc(a->array, a->size * sizeof *a->array); a->array = temp;... Auf diese Weise wäre es offensichtlich, dass alles, was passiert, vorher passieren muss Der NULLWert wird zugewiesen a->array(falls überhaupt).
autistisch
10

Wie bei allem, was auf den ersten Blick beängstigender erscheint als später, ist der beste Weg, die anfängliche Angst zu überwinden, in das Unbehagen des Unbekannten einzutauchen ! Es ist manchmal so, wie wir es am meisten lernen.

Leider gibt es Einschränkungen. Während Sie noch lernen, eine Funktion zu verwenden, sollten Sie beispielsweise nicht die Rolle eines Lehrers übernehmen. Ich lese oft Antworten von denen, die anscheinend nicht wissen, wie man sie verwendet realloc(dh die derzeit akzeptierte Antwort! ) Und anderen sagt, wie sie falsch verwendet werden sollen, gelegentlich unter dem Deckmantel, dass sie die Fehlerbehandlung weggelassen haben , obwohl dies eine häufige Gefahr ist was erwähnt werden muss. Hier ist eine Antwort, die erklärt, wie man reallocrichtig verwendet . Beachten Sie, dass die Antwort den Rückgabewert in einer anderen Variablen speichert , um eine Fehlerprüfung durchzuführen.

Jedes Mal, wenn Sie eine Funktion aufrufen und wenn Sie ein Array verwenden, verwenden Sie einen Zeiger. Die Konvertierungen erfolgen implizit, was, wenn überhaupt, noch beängstigender sein sollte, da die Dinge, die wir nicht sehen, häufig die meisten Probleme verursachen. Zum Beispiel Speicherlecks ...

Array-Operatoren sind Zeigeroperatoren. array[x]ist wirklich eine Abkürzung für *(array + x), die unterteilt werden kann in: *und (array + x). Es ist sehr wahrscheinlich, dass Sie *das verwirrt. Wir können weiterhin die Zugabe von dem Problem beseitigen , indem angenommen xwerden 0somit, array[0]wird , *arrayda das Hinzufügen 0nicht den Wert ändern ...

... und so können wir sehen, dass *arraydas gleichbedeutend ist mit array[0]. Sie können eines dort verwenden, wo Sie das andere verwenden möchten, und umgekehrt. Array-Operatoren sind Zeigeroperatoren.

malloc, reallocNicht und Freunde erfinden das Konzept eines Zeigers , die Sie die ganze Zeit verwendet haben; Sie verwenden dies lediglich , um eine andere Funktion zu implementieren, bei der es sich um eine andere Form der Speicherdauer handelt, die am besten geeignet ist, wenn Sie drastische, dynamische Größenänderungen wünschen .

Es ist eine Schande, dass die derzeit akzeptierte Antwort auch gegen einige andere sehr fundierte Ratschläge zu StackOverflow verstößt und gleichzeitig die Gelegenheit verpasst, eine wenig bekannte Funktion einzuführen, die genau für diesen Anwendungsfall glänzt: flexibles Array Mitglieder! Das ist eigentlich eine ziemlich kaputte Antwort ... :(

Wenn Sie Ihre definieren struct, deklarieren Sie Ihr Array am Ende der Struktur ohne Obergrenze. Beispielsweise:

struct int_list {
    size_t size;
    int value[];
};

Auf diese Weise können Sie Ihr Array intin derselben Zuordnung wie Ihre zusammenfassen count, und es kann sehr praktisch sein , sie so zu binden !

sizeof (struct int_list)verhält sich so, als hätte valuees eine Größe von 0, sodass die Größe der Struktur mit einer leeren Liste angezeigt wird . Sie müssen noch die übergebene Größe hinzufügen, reallocum die Größe Ihrer Liste anzugeben.

Ein weiterer praktischer Tipp ist, sich daran zu erinnern, dass dies realloc(NULL, x)gleichbedeutend ist malloc(x), und wir können dies verwenden, um unseren Code zu vereinfachen. Beispielsweise:

int push_back(struct int_list **fubar, int value) {
    size_t x = *fubar ? fubar[0]->size : 0
         , y = x + 1;

    if ((x & y) == 0) {
        void *temp = realloc(*fubar, sizeof **fubar
                                   + (x + y) * sizeof fubar[0]->value[0]);
        if (!temp) { return 1; }
        *fubar = temp; // or, if you like, `fubar[0] = temp;`
    }

    fubar[0]->value[x] = value;
    fubar[0]->size = y;
    return 0;
}

struct int_list *array = NULL;

Der Grund, den ich struct int_list **als erstes Argument gewählt habe, mag nicht sofort offensichtlich erscheinen, aber wenn Sie an das zweite Argument denken, sind Änderungen, die valuevon innen vorgenommen wurden, push_backfür die Funktion, von der wir aufrufen, nicht sichtbar, oder? Das gleiche gilt für das erste Argument, und wir müssen in der Lage sein, unser arraynicht nur hier, sondern möglicherweise auch in allen anderen Funktionen, an die wir es weitergeben, zu ändern ...

arraybeginnt auf nichts zu zeigen; Es ist eine leere Liste. Das Initialisieren entspricht dem Hinzufügen. Beispielsweise:

struct int_list *array = NULL;
if (!push_back(&array, 42)) {
    // success!
}

PS Denkenfree(array); Sie daran, wenn Sie damit fertig sind!

autistisch
quelle
" array[x]ist wirklich eine Abkürzung für *(array + x), [...]" Bist du dir da sicher ???? Sehen Sie sich eine Darstellung ihrer unterschiedlichen Verhaltensweisen an: eli.thegreenplace.net/2009/10/21/… .
C-Star-W-Star
1
Leider, @ C-Star-Puppy, ist die einzige Referenz, die Ihre Ressource anscheinend überhaupt nicht erwähnt, der C-Standard. Dies ist die Spezifikation, nach der sich Ihre Compiler halten müssen, um sich legal als C-Compiler zu bezeichnen. Ihre Ressource scheint meinen Informationen überhaupt nicht zu widersprechen. Dennoch hat der Standard tatsächlich einige Beispiele wie dieses Juwel , wo es aufgedeckt , die array[index]eigentlich ptr[index]in der Verkleidung ... „Die Definition des Index - Operators []ist , dass E1[E2]identisch mit (*((E1)+(E2))) Sie können nicht die std entkräften
autistische
Versuchen Sie diese Demonstration, @ C-Star-Puppy: int main(void) { unsigned char lower[] = "abcdefghijklmnopqrstuvwxyz"; for (size_t x = 0; x < sizeof lower - 1; x++) { putchar(x[lower]); } }... Sie müssen wahrscheinlich #include <stdio.h>und <stddef.h>... Sehen Sie, wie ich geschrieben habe x[lower](mit xdem Integer-Typ) anstatt lower[x]? Dem C-Compiler ist das egal, denn er *(lower + x)hat den gleichen Wert wie *(x + lower)und lower[x]ist der erstere, wo-wie x[lower]der letztere. Alle diese Ausdrücke sind gleichwertig. Probieren Sie sie aus ... überzeugen Sie sich selbst, wenn Sie mein Wort nicht nehmen können ...
autistisch
... und dann gibt es natürlich diesen Teil, auf den ich meine eigene Betonung gelegt habe, aber Sie sollten wirklich das gesamte Zitat ohne Betonung lesen: "Außer wenn es der Operand des Operators sizeof, des Operators _Alignof oder des Operators _Alignof ist unary & operator oder ist ein Zeichenfolgenliteral, das zum Initialisieren eines Arrays verwendet wird. Ein Ausdruck vom Typ '' Array vom Typ '' wird in einen Ausdruck mit dem Typ '' Zeiger auf Typ '' konvertiert, der auf das Anfangselement des Arrays zeigt Objekt und ist kein l-Wert . Wenn das Array-Objekt eine Registerspeicherklasse hat, ist das Verhalten undefiniert. " Gleiches gilt übrigens für Funktionen.
autistisch
Ohh und abschließend, @ C-Star-Puppy, Microsoft C ++ ist kein C-Compiler und seit fast 20 Jahren keiner mehr. Sie können den C89-Modus aktivieren , aber wir haben uns über die späten 1980er Jahre hinaus im Computerbereich weiterentwickelt. Um mehr über dieses Thema zu erfahren , empfehle ich, diesen Artikel zu lesen ... und dann zu einem tatsächlichen C-Compiler wie gccoder clangfür Ihre gesamte C-Kompilierung zu wechseln , da es so viele Pakete gibt, die C99-Funktionen übernommen haben ...
autistisch
3

Aufbauend auf dem Design von Matteo Furlans , als er sagte, "die meisten dynamischen Array-Implementierungen funktionieren, indem sie mit einem Array mit einer (kleinen) Standardgröße beginnen. Wenn Sie beim Hinzufügen eines neuen Elements keinen Platz mehr haben, verdoppeln Sie die Größe des Arrays. " Der Unterschied bei " work in progress " unten besteht darin, dass es nicht doppelt so groß ist, sondern nur das verwendet, was erforderlich ist. Der Einfachheit halber habe ich auch Sicherheitsüberprüfungen weggelassen ... Aufbauend auf der Idee von brimboriums habe ich versucht, dem Code eine Löschfunktion hinzuzufügen ...

Die Datei storage.h sieht folgendermaßen aus ...

#ifndef STORAGE_H
#define STORAGE_H

#ifdef __cplusplus
extern "C" {
#endif

    typedef struct 
    {
        int *array;
        size_t size;
    } Array;

    void Array_Init(Array *array);
    void Array_Add(Array *array, int item);
    void Array_Delete(Array *array, int index);
    void Array_Free(Array *array);

#ifdef __cplusplus
}
#endif

#endif /* STORAGE_H */

Die Datei storage.c sieht folgendermaßen aus ...

#include <stdio.h>
#include <stdlib.h>
#include "storage.h"

/* Initialise an empty array */
void Array_Init(Array *array) 
{
    int *int_pointer;

    int_pointer = (int *)malloc(sizeof(int));

    if (int_pointer == NULL)
    {       
        printf("Unable to allocate memory, exiting.\n");
        free(int_pointer);
        exit(0);
    }
    else
    {
        array->array = int_pointer; 
        array->size = 0;
    }
}

/* Dynamically add to end of an array */
void Array_Add(Array *array, int item) 
{
    int *int_pointer;

    array->size += 1;

    int_pointer = (int *)realloc(array->array, array->size * sizeof(int));

    if (int_pointer == NULL)
    {       
        printf("Unable to reallocate memory, exiting.\n");
        free(int_pointer);
        exit(0);
    }
    else
    {
        array->array = int_pointer;
        array->array[array->size-1] = item;
    }
}

/* Delete from a dynamic array */
void Array_Delete(Array *array, int index) 
{
    int i;
    Array temp;
    int *int_pointer;

    Array_Init(&temp);

    for(i=index; i<array->size; i++)
    {
        array->array[i] = array->array[i + 1];
    }

    array->size -= 1;

    for (i = 0; i < array->size; i++)
    {
        Array_Add(&temp, array->array[i]);
    }

    int_pointer = (int *)realloc(temp.array, temp.size * sizeof(int));

    if (int_pointer == NULL)
    {       
        printf("Unable to reallocate memory, exiting.\n");
        free(int_pointer);
        exit(0);
    }
    else
    {
        array->array = int_pointer; 
    } 
}

/* Free an array */
void Array_Free(Array *array) 
{
  free(array->array);
  array->array = NULL;
  array->size = 0;  
}

Die main.c sieht so aus ...

#include <stdio.h>
#include <stdlib.h>
#include "storage.h"

int main(int argc, char** argv) 
{
    Array pointers;
    int i;

    Array_Init(&pointers);

    for (i = 0; i < 60; i++)
    {
        Array_Add(&pointers, i);        
    }

    Array_Delete(&pointers, 3);

    Array_Delete(&pointers, 6);

    Array_Delete(&pointers, 30);

    for (i = 0; i < pointers.size; i++)
    {        
        printf("Value: %d Size:%d \n", pointers.array[i], pointers.size);
    }

    Array_Free(&pointers);

    return (EXIT_SUCCESS);
}

Freuen Sie sich auf die konstruktive Kritik ...


quelle
1
Wenn Sie konstruktive Kritik suchen, sollten Sie diese besser bei Code Review veröffentlichen . Ein paar Vorschläge: Es ist unbedingt erforderlich, dass der Code den Erfolg von Aufrufen überprüft, malloc()bevor versucht wird, die Zuordnung zu verwenden. Ebenso ist es ein Fehler, das Ergebnis direkt realloc()dem Zeiger auf den ursprünglichen Speicher zuzuweisen, der neu zugewiesen wird. Wenn dies realloc()fehlschlägt, NULLwird zurückgegeben und der Code bleibt mit einem Speicherverlust zurück. Es ist viel effizienter, den Speicher beim Ändern der Größe zu verdoppeln, als jeweils 1 Speicherplatz hinzuzufügen: weniger Aufrufe an realloc().
Ex Nihilo
1
Ich wusste, dass ich auseinander gerissen werden würde, ich scherzte nur, als ich "konstruktive Kritik" sagte ... Danke für den Rat ...
2
Ich versuche nicht, jemanden auseinander zu reißen, sondern biete nur konstruktive Kritik an, die möglicherweise auch ohne Ihren unbeschwerten Näher aufgetaucht ist;)
ex nihilo
1
David, ich habe über Ihren Kommentar nachgedacht. "Es ist viel effizienter, den Speicher beim Ändern der Größe zu verdoppeln, als jeweils 1 Speicherplatz hinzuzufügen: weniger Aufrufe von realloc ()". Würden Sie das bitte für mich näher erläutern, warum ist es besser, die doppelte Speichermenge zuzuweisen und sie möglicherweise nicht zu verwenden, wodurch Speicherplatz verschwendet wird, als nur die für die Aufgabe erforderliche Menge zuzuweisen? Ich verstehe, was Sie über Aufrufe von realloc () sagen, aber warum ist das Aufrufen von realloc () jedes Mal ein Problem? Ist es nicht das, wofür es da ist, um Speicher neu zuzuweisen?
1
Während striktes Verdoppeln möglicherweise nicht optimal ist, ist es sicherlich besser, als den Speicher um jeweils ein Byte (oder eins intusw.) zu erhöhen . Verdoppelung ist eine typische Lösung, aber ich glaube nicht, dass es eine optimale Lösung gibt, die allen Umständen entspricht. Aus diesem Grund ist eine Verdoppelung eine gute Idee (ein anderer Faktor wie 1,5 wäre ebenfalls in Ordnung): Wenn Sie mit einer angemessenen Zuordnung beginnen, müssen Sie möglicherweise überhaupt keine Neuzuweisung vornehmen. Wenn mehr Speicher benötigt wird, wird die angemessene Zuordnung verdoppelt und so weiter. Auf diese Weise benötigen Sie wahrscheinlich nur ein oder zwei Anrufe realloc().
Ex Nihilo
2

Wenn du sagst

Erstellen Sie ein Array, das eine Indexnummer (int) einer unbestimmten Anzahl von Entitäten enthält

Sie sagen im Grunde, dass Sie "Zeiger" verwenden, aber einen, der ein Array-breiter lokaler Zeiger anstelle eines speicherweiten Zeigers ist. Da Sie konzeptionell bereits "Zeiger" verwenden (dh ID-Nummern, die sich auf ein Element in einem Array beziehen), verwenden Sie einfach reguläre Zeiger (dh ID-Nummern, die sich auf ein Element im größten Array beziehen: den gesamten Speicher) ).

Anstatt dass Ihre Objekte Ressourcen-ID-Nummern speichern, können Sie sie stattdessen dazu bringen, einen Zeiger zu speichern. Grundsätzlich das Gleiche, aber viel effizienter, da wir vermeiden, "Array + Index" in einen "Zeiger" zu verwandeln.

Zeiger sind nicht beängstigend, wenn Sie sie als Array-Index für den gesamten Speicher betrachten (was sie tatsächlich sind).

Lie Ryan
quelle
2

So erstellen Sie ein Array mit unbegrenzten Elementen aller Art:

typedef struct STRUCT_SS_VECTOR {
    size_t size;
    void** items;
} ss_vector;


ss_vector* ss_init_vector(size_t item_size) {
    ss_vector* vector;
    vector = malloc(sizeof(ss_vector));
    vector->size = 0;
    vector->items = calloc(0, item_size);

    return vector;
}

void ss_vector_append(ss_vector* vec, void* item) {
    vec->size++;
    vec->items = realloc(vec->items, vec->size * sizeof(item));
    vec->items[vec->size - 1] = item;
};

void ss_vector_free(ss_vector* vec) {
    for (int i = 0; i < vec->size; i++)
        free(vec->items[i]);

    free(vec->items);
    free(vec);
}

und wie man es benutzt:

// defining some sort of struct, can be anything really
typedef struct APPLE_STRUCT {
    int id;
} apple;

apple* init_apple(int id) {
    apple* a;
    a = malloc(sizeof(apple));
    a-> id = id;
    return a;
};


int main(int argc, char* argv[]) {
    ss_vector* vector = ss_init_vector(sizeof(apple));

    // inserting some items
    for (int i = 0; i < 10; i++)
        ss_vector_append(vector, init_apple(i));


    // dont forget to free it
    ss_vector_free(vector);

    return 0;
}

Dieser Vektor / Array kann jede Art von Element enthalten und ist vollständig dynamisch.

Sebastian Karlsson
quelle
0

Nun, ich denke, wenn Sie ein Element entfernen müssen, werden Sie eine Kopie des Arrays erstellen, das das auszuschließende Element verachtet.

// inserting some items
void* element_2_remove = getElement2BRemove();

for (int i = 0; i < vector->size; i++){
       if(vector[i]!=element_2_remove) copy2TempVector(vector[i]);
       }

free(vector->items);
free(vector);
fillFromTempVector(vector);
//

Angenommen getElement2BRemove(), copy2TempVector( void* ...)und fillFromTempVector(...)sind Hilfsmethoden zur Behandlung des Temperaturvektors.

JOSMAR BARBOSA - M4NOV3Y
quelle
Es ist unklar, ob dies tatsächlich eine Antwort auf die gestellte Frage ist oder ob es sich um einen Kommentar handelt.
Es ist eine Meinung für "wie es geht" und ich bitte um Bestätigung (irre ich mich?), WENN jemand eine bessere Idee hat. ;)
JOSMAR BARBOSA - M4NOV3Y
Ich glaube, ich verstehe deinen letzten Satz nicht. Da SO kein Thread-Forum ist, sehen offene Fragen wie diese in Antworten seltsam aus.
1
Ich habe Ihren letzten Satz auf das festgelegt, was Sie meiner Meinung nach sagen möchten.