Frage

Ich versuche, eine Funktion zu erstellen, die ein Array als Argument nimmt, fügt Werte sie (seine Größe bei Bedarf erhöht wird) und gibt die Anzahl der Elemente. Bisher habe ich:

int main(int argc, char** argv) {
    int mSize = 10;
    ent a[mSize];
    int n;
    n = addValues(a,mSize);

    for(i=0;i<n;i++) {
       //Print values from a
    }
}

int addValues(ent *a, int mSize) {
    int size = mSize;

    i = 0;

    while(....) { //Loop to add items to array
        if(i>=size-1) { 
            size = size*2;
            a = realloc(a, (size)*sizeof(ent));
        }
        //Add to array
        i++;
    }
    return i;
}

Dies funktioniert, wenn msize groß genug ist, alle möglichen Elemente des Arrays zu halten, aber wenn es zu skalieren muss, erhalte ich eine Segmentation Fault.

Ich habe auch versucht:

int main(int argc, char** argv) {
    ...
    ent *a;
    ...
}

int addValues(ent *a, int mSize) {
    ...
    a = calloc(1, sizeof(ent);
    //usual loop
    ...
}

ohne Erfolg.

Ich nehme an, das liegt daran, dass, wenn ich realloc nennen, die Kopie von ‚a‘ an anderer Stelle hingewiesen wird - wie es möglich ist, dies zu ändern, so dass ‚a‘ immer auf die gleiche Stelle

Bin ich diesen richtig? Gibt es bessere Möglichkeiten, um mit dynamischen Strukturen in C zu tun? Soll ich eine verknüpfte Liste implementieren mit diesen umgehen?

War es hilfreich?

Lösung

Das Hauptproblem dabei ist, dass Sie versuchen, mit einem Stapel zugeordnete Array verwenden realloc. Sie haben:

ent a[mSize];

Das ist die automatische Zuweisung auf dem Stapel. Wenn Sie diese später verwenden realloc () wollten, würden Sie das Array auf dem Heap mit malloc () erstellen, wie folgt aus:

ent *a = (ent*)malloc(mSize * sizeof(ent));

Damit die malloc Bibliothek (und damit realloc (), etc.) kennt Ihren Array. Von den Blicken von dieser, können Sie verwirrend C99 Arrays variabler Länge mit wahren dynamischem Arrays rel="nofollow , so sicher, dass Sie den Unterschied zu verstehen, bevor Sie versuchen, dies zu beheben.

Wirklich, obwohl, wenn Sie dynamische Arrays in C schreiben, sollten Sie versuchen, OOP-ish Design zu verwenden, um Informationen über Ihre Arrays zu kapseln und sie von dem Benutzer zu verbergen. Sie mögen Informationen (zum Beispiel Zeiger und Größe) über das Array in eine Struktur und Operationen (zum Beispiel Zuordnung, Hinzufügen von Elementen, Entfernen von Elementen, zu befreien, etc.) konsolidieren in spezielle Funktionen, die mit Ihrer Struktur arbeiten. So haben Sie vielleicht:

typedef struct dynarray {
   elt *data;
   int size;
} dynarray;

Und Sie könnten einige Funktionen definieren mit dynarrays arbeiten:

// malloc a dynarray and its data and returns a pointer to the dynarray    
dynarray *dynarray_create();     

// add an element to dynarray and adjust its size if necessary
void dynarray_add_elt(dynarray *arr, elt value);

// return a particular element in the dynarray
elt dynarray_get_elt(dynarray *arr, int index);

// free the dynarray and its data.
void dynarray_free(dynarray *arr);

Auf diese Weise der Benutzer muss nicht mehr genau erinnern, wie die Dinge zu verteilen oder welche Größe das Array ist zur Zeit. Hoffe, das wird Sie begonnen haben.

Andere Tipps

Versuchen Sie es so einen Zeiger auf einen Zeiger auf das Array Nacharbeiten wird eingeleitet, d.h. ent **a. Dann können Sie den Anrufer auf die neue Position des Arrays aktualisieren.

Das ist ein schöner Grund OOP zu verwenden. ja, man kann auf C OOP tun, und es sieht auch schön, wenn es richtig gemacht.

in diesem einfachen Fall, dass Sie nicht brauchen Vererbung noch Polymorphismus, sondern nur die Verkapselung und Methoden Konzepte:

  • definiert eine Struktur mit einer Länge und einem Datenzeiger. vielleicht ein Elementgröße.
  • Schreib Getter / Setter-Funktionen, die auf Zeiger auf diese Struktur arbeiten.
  • die ‚wachsen‘ Funktion ändert die Datenzeiger innerhalb der Struktur, aber jede Struktur Zeiger bleibt gültig.

Wenn Sie die Variablendeklaration im Haupt geändert werden

ent *a = NULL;

der Code würde mehr funktionieren wie Sie in Betracht gezogen, indem kein Stapel zugeordnete Array zu befreien. Festlegen eines auf NULL funktioniert, weil realloc behandelt dies als ob der Benutzer namens malloc (Größe). Beachten Sie, dass mit dieser Änderung der Prototyp zu addValue ändern muss

int addValues(ent **a, int mSize)

und dass der Code muss den Fall von realloc andernfalls behandeln. Zum Beispiel

while(....) { //Loop to add items to array
    tmp = realloc(*a, size*sizeof(ent));
    if (tmp) {
        *a = tmp;
    } else {
        // allocation failed. either free *a or keep *a and
        // return an error
    }
    //Add to array
    i++;
}

Ich würde erwarten, dass die meisten Implementierungen von realloc intern doppelt so viel Speicher zuweisen, wenn der aktuelle Puffer Ändern der Größe muss der ursprüngliche Code der Herstellung

size = size * 2;

nicht erforderlich.

Sie passieren die Array-Zeiger nach Wert. Was dies bedeutet, ist:

int main(int argc, char** argv) {
    ...
    ent *a; // This...
    ...
}

int addValues(ent *a, int mSize) {
    ...
    a = calloc(1, sizeof(ent); // ...is not the same as this
    //usual loop
    ...
}

Ändern so den Wert von a in der addValues Funktion in Haupt nicht den Wert einer Änderung. Um den Wert eines in Haupt ändern müssen Sie einen Verweis auf sie passieren zu addValues. Im Moment wird der Wert von a wird kopiert und an addValues weitergegeben. Um einen Verweis auf eine Verwendung übergeben:

int addValues (int **a, int mSize)

und nennen Sie es mögen:

int main(int argc, char** argv) {
    ...
    ent *a; // This...
    ...
    addValues (&a, mSize);
}

In der addValues greifen die Elemente ein wie folgt aus:

(*a)[element]

und eine Neuverteilung der das Array wie folgt:

(*a) = calloc (...);

Xahtep wird erläutert, wie der Anrufer mit der Tatsache umgehen, dass realloc () könnte das Array an eine neue Position verschieben. Solange Sie dies tun, sollten Sie sich gut.

realloc () kann teuer werden, wenn Sie die Arbeit mit großen Arrays beginnen. Das ist, wenn es Zeit ist, denken an die Verwendung anderer Datenstrukturen zu beginnen -. Eine verknüpfte Liste, einen binären Baum, etc

Wie bereits erwähnt Sie Zeiger passieren sollte auf Zeiger den Zeigerwert zu aktualisieren.
Aber ich würde vorschlagen, Redesign und diese Technik zu vermeiden, in den meisten Fällen kann und sollte vermieden werden. Ohne zu wissen, was genau erreichen Sie versuchen, ist es schwer, alternativen Entwurf vorschlagen, aber ich bin zu 99% sicher, dass es machbar anderer Weg. Und wie Javier traurig - man denke objektorientierte und Sie werden immer besser Code.

Müssen Sie wirklich C benutzen? Dies wäre eine große Anwendung von C ++ 's ‚std :: vector‘ sein, was genau ist ein dynamisch-sized Array (leicht resizeble mit einem einzigen Anruf Sie müssen nicht selbst schreiben und debuggen).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top