it-swarm.com.de

Wie kann ich ein Array von Strukturen mit dynamischer Größe erstellen?

Ich weiß, wie man ein Array von Strukturen mit einer vordefinierten Größe erstellt. Gibt es eine Möglichkeit, ein dynamisches Array von Strukturen so zu erstellen, dass das Array größer werden könnte?

Zum Beispiel:

    typedef struct
    {
        char *str;
    } words;

    main()
    {
        words x[100]; // I do not want to use this, I want to dynamic increase the size of the array as data comes in.
    }

Ist das möglich?


Ich habe das recherchiert: words* array = (words*)malloc(sizeof(words) * 100);

Ich möchte die 100 loswerden und die Daten speichern, sobald sie hereinkommen. Wenn also 76 Datenfelder eingehen, möchte ich 76 und nicht 100 speichern. Ich gehe davon aus, dass ich nicht weiß, wie viele Daten kommen in mein Programm. In der oben definierten Struktur könnte ich den ersten "Index" erstellen als:

    words* array = (words*)malloc(sizeof(words));

Ich möchte jedoch Elemente dynamisch nach dem Array hinzufügen. Ich hoffe, ich habe den Problembereich klar genug beschrieben. Die größte Herausforderung besteht darin, dynamisch ein zweites Feld hinzuzufügen, zumindest ist dies die Herausforderung für den Moment.


Ich habe jedoch ein bisschen Fortschritte gemacht:

    typedef struct {
        char *str;
    } words;

    // Allocate first string.
    words x = (words) malloc(sizeof(words));
    x[0].str = "john";

    // Allocate second string.
    x=(words*) realloc(x, sizeof(words));
    x[1].FirstName = "bob";

    // printf second string.
    printf("%s", x[1].str); --> This is working, it's printing out bob.

    free(x); // Free up memory.

    printf("%s", x[1].str); --> Not working since its still printing out BOB even though I freed up memory. What is wrong?

Ich habe einige Fehlerprüfungen durchgeführt und das ist, was ich gefunden habe. Wenn ich Speicherplatz für x frei mache, füge ich Folgendes hinzu:

    x=NULL;

wenn ich versuche, x zu drucken, erhalte ich eine Fehlermeldung, die ich will. Ist es also so, dass die freie Funktion zumindest auf meinem Compiler nicht funktioniert? Ich verwende DevC?


Danke, das verstehe ich jetzt:

FirstName ist ein Zeiger auf ein Array von char, das nicht von der Malloc zugewiesen wird. Nur der Zeiger wird zugewiesen. Wenn Sie free aufrufen, wird der Speicher nicht gelöscht, sondern nur als verfügbar auf dem Heap als beendet markiert später geschrieben. - MattSmith

Aktualisieren

Ich versuche zu modularisieren und die Erstellung meines Arrays von Strukturen in eine Funktion zu bringen, aber nichts scheint zu funktionieren. Ich versuche etwas sehr einfaches und weiß nicht, was ich sonst noch tun soll. Es ist in der gleichen Richtung wie zuvor, nur eine weitere Funktion, Ladedaten, die die Daten laden, und außerhalb der Methode, die ich zum Drucken brauche. Wie kann ich es funktionieren lassen? Mein Code lautet wie folgt:

    # include <stdio.h>
    # include <stdlib.h>
    # include <string.h>
    # include <ctype.h>

    typedef struct
    {
        char *str1;
        char *str2;
    } words;

    void LoadData(words *, int *);

    main()
    {
        words *x;
        int num;

        LoadData(&x, &num);

        printf("%s %s", x[0].str1, x[0].str2);
        printf("%s %s", x[1].str1, x[1].str2);

        getch();
    }//

    void LoadData(words *x, int * num)
    {
        x = (words*) malloc(sizeof(words));

        x[0].str1 = "johnnie\0";
        x[0].str2 = "krapson\0";

        x = (words*) realloc(x, sizeof(words)*2);
        x[1].str1 = "bob\0";
        x[1].str2 = "marley\0";

        *num=*num+1;
    }//

Dieser einfache Testcode stürzt ab und ich habe keine Ahnung, warum. Wo ist der Fehler?

49
D. Rattansingh

Sie haben dies sowohl als C++ als auch als C markiert.

Wenn Sie C++ verwenden, ist das viel einfacher. Die Standardvorlagenbibliothek enthält eine Vorlage namens vector, mit der Sie dynamisch eine Liste von Objekten erstellen können.

#include <stdio.h>
#include <vector>

typedef std::vector<char*> words;

int main(int argc, char** argv) {

        words myWords;

        myWords.Push_back("Hello");
        myWords.Push_back("World");

        words::iterator iter;
        for (iter = myWords.begin(); iter != myWords.end(); ++iter) {
                printf("%s ", *iter);
        }

        return 0;
}

Wenn Sie C verwenden, sind die Dinge viel schwieriger. Ja, Malloc, Realloc und Free sind die Werkzeuge, die Ihnen helfen. Möglicherweise möchten Sie stattdessen die Verwendung einer verknüpften Listendatenstruktur in Betracht ziehen. Diese sind im Allgemeinen einfacher zu entwickeln, erleichtern jedoch den wahlfreien Zugriff nicht so einfach.

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

typedef struct s_words {
        char* str;
        struct s_words* next;
} words;

words* create_words(char* Word) {
        words* newWords = malloc(sizeof(words));
        if (NULL != newWords){
                newWords->str = Word;
                newWords->next = NULL;
        }
        return newWords;
}

void delete_words(words* oldWords) {
        if (NULL != oldWords->next) {
                delete_words(oldWords->next);
        }
        free(oldWords);
}

words* add_Word(words* wordList, char* Word) {
        words* newWords = create_words(Word);
        if (NULL != newWords) {
                newWords->next = wordList;
        }
        return newWords;
}

int main(int argc, char** argv) {

        words* myWords = create_words("Hello");
        myWords = add_Word(myWords, "World");

        words* iter;
        for (iter = myWords; NULL != iter; iter = iter->next) {
                printf("%s ", iter->str);
        }
        delete_words(myWords);
        return 0;
}

Ja, entschuldige die längste Antwort der Welt. Also WRT zum "Ich möchte keinen Link-Listen-Kommentar verwenden":

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

typedef struct {
    char** words;
    size_t nWords;
    size_t size;
    size_t block_size;
} Word_list;

Word_list* create_Word_list(size_t block_size) {
    Word_list* pWordList = malloc(sizeof(Word_list));
    if (NULL != pWordList) {
        pWordList->nWords = 0;
        pWordList->size = block_size;
        pWordList->block_size = block_size;
        pWordList->words = malloc(sizeof(char*)*block_size);
        if (NULL == pWordList->words) {
            free(pWordList);
            return NULL;    
        }
    }
    return pWordList;
}

void delete_Word_list(Word_list* pWordList) {
    free(pWordList->words);
    free(pWordList);
}

int add_Word_to_Word_list(Word_list* pWordList, char* Word) {
    size_t nWords = pWordList->nWords;
    if (nWords >= pWordList->size) {
        size_t newSize = pWordList->size + pWordList->block_size;
        void* newWords = realloc(pWordList->words, sizeof(char*)*newSize); 
        if (NULL == newWords) {
            return 0;
        } else {    
            pWordList->size = newSize;
            pWordList->words = (char**)newWords;
        }

    }

    pWordList->words[nWords] = Word;
    ++pWordList->nWords;


    return 1;
}

char** Word_list_start(Word_list* pWordList) {
        return pWordList->words;
}

char** Word_list_end(Word_list* pWordList) {
        return &pWordList->words[pWordList->nWords];
}

int main(int argc, char** argv) {

        Word_list* myWords = create_Word_list(2);
        add_Word_to_Word_list(myWords, "Hello");
        add_Word_to_Word_list(myWords, "World");
        add_Word_to_Word_list(myWords, "Goodbye");

        char** iter;
        for (iter = Word_list_start(myWords); iter != Word_list_end(myWords); ++iter) {
                printf("%s ", *iter);
        }

        delete_Word_list(myWords);

        return 0;
}
35
Tom

Wenn Sie Arrays dynamisch zuordnen möchten, können Sie malloc aus stdlib.h verwenden.

Wenn Sie mit Ihrer words-Struktur ein Array von 100 Elementen zuordnen möchten, versuchen Sie Folgendes:

words* array = (words*)malloc(sizeof(words) * 100);

Die Größe des Speichers, den Sie zuordnen möchten, wird an malloc übergeben und gibt dann einen Zeiger vom Typ void (void*) zurück. In den meisten Fällen möchten Sie es wahrscheinlich in den gewünschten Zeigertyp umwandeln, in diesem Fall words*.

Das Schlüsselwort sizeof wird hier verwendet, um die Größe der words-Struktur herauszufinden. Diese Größe wird dann mit der Anzahl der Elemente multipliziert, die Sie zuordnen möchten.

Wenn Sie fertig sind, stellen Sie sicher, dass Sie free() verwenden, um den verwendeten Heap-Speicher freizugeben, um Speicherlecks zu verhindern.

free(array);

Wenn Sie die Größe des zugewiesenen Arrays ändern möchten, können Sie versuchen, realloc zu verwenden, wie andere bereits erwähnt haben. Wenn Sie jedoch reallocs verwenden, können Sie am Ende Fragmentierung des Speichers beenden. Wenn Sie die Größe des Arrays dynamisch ändern möchten, um einen geringen Speicherbedarf für Ihr Programm zu erhalten, ist es möglicherweise besser, nicht zu viele reallocs zu verwenden.

11
coobird

Dies sieht aus wie eine akademische Übung, die es leider schwieriger macht, da Sie C++ nicht verwenden können. Grundsätzlich müssen Sie einen Teil des Overheads für die Zuordnung verwalten und nachverfolgen, wie viel Speicherplatz zugewiesen wurde, wenn Sie die Größe später ändern müssen. Hier leuchtet die C++ - Standardbibliothek auf.

Für Ihr Beispiel weist der folgende Code den Speicher zu und ändert dessen Größe später:

// initial size
int count = 100;
words *testWords = (words*) malloc(count * sizeof(words));
// resize the array
count = 76;
testWords = (words*) realloc(testWords, count* sizeof(words));

Denken Sie daran, dass Sie in Ihrem Beispiel nur einen Zeiger auf ein Zeichen zuweisen, und Sie müssen immer noch die Zeichenfolge selbst zuweisen und vor allem, um sie am Ende freizugeben. Dieser Code weist dem Zeichen 100 Zeiger zu und ändert die Größe dann auf 76, ordnet die Zeichenfolgen jedoch nicht zu.

Ich habe den Verdacht, dass Sie tatsächlich die Anzahl der Zeichen in einer Zeichenfolge zuweisen möchten, die der oben genannten sehr ähnlich ist, aber Word in Char ändern.

BEARBEITEN: Denken Sie auch daran, dass sehr sinnvoll ist, Funktionen zu erstellen, mit denen Sie allgemeine Aufgaben ausführen und Konsistenz erzwingen können, damit Sie Code nicht überall kopieren. Sie können beispielsweise a) die Struktur zuordnen, b) der Struktur Werte zuweisen und c) die Struktur freigeben. Sie könnten also haben:

// Allocate a words struct
words* CreateWords(int size);
// Assign a value
void AssignWord(Word* dest, char* str);
// Clear a words structs (and possibly internal storage)
void FreeWords(words* w);

BEARBEITEN: Soweit die Größe der Strukturen geändert wird, ist sie identisch mit der Änderung des Char-Arrays. Der Unterschied ist jedoch, wenn Sie das Struktur-Array größer machen, sollten Sie die neuen Array-Elemente wahrscheinlich mit NULL initialisieren. Wenn Sie das Struktur-Array verkleinern, müssen Sie ebenfalls bereinigen, bevor Sie die Elemente entfernen. Dies sind freie Elemente, die zugewiesen wurden (und nur die zugewiesenen Elemente), bevor Sie die Größe des Struktur-Arrays ändern. Dies ist der Hauptgrund, warum ich vorgeschlagen habe, Hilfsfunktionen zu erstellen, um dies zu verwalten.

// Resize words (must know original and new size if shrinking
// if you need to free internal storage first)
void ResizeWords(words* w, size_t oldsize, size_t newsize);
5
Ryan

Verwenden Sie in C++ einen vector . Es ist wie bei einem Array, aber Sie können Elemente problemlos hinzufügen und entfernen, und es wird sich um die Zuweisung und Freigabe von Speicher für Sie kümmern.

Ich weiß, dass der Titel der Frage C lautet, aber Sie haben Ihre Frage mit C und C++ getaggt ...

3
Jeremy Ruten

Eine andere Option für Sie ist eine verknüpfte Liste . Sie müssen analysieren, wie Ihr Programm die Datenstruktur verwendet. Wenn Sie keinen wahlfreien Zugriff benötigen, kann dies schneller sein als eine Neuzuweisung.

3
Neil Williams

So würde ich es in C++ machen

size_t size = 500;
char* dynamicAllocatedString = new char[ size ];

Verwenden Sie für jede Struktur- oder C++ - Klasse denselben Principal.

3
Adrian

Ihr Code im letzten Update sollte nicht kompiliert werden, geschweige denn ausgeführt. Sie übergeben & x an LoadData. & x hat den Typ von ** Wörtern, aber LoadData erwartet Wörter *. Natürlich stürzt es ab, wenn Sie Realloc für einen Zeiger aufrufen, der auf den Stapel zeigt.

Um dies zu beheben, können Sie LoadData so ändern, dass es Wörter akzeptiert **. Sie können den Zeiger tatsächlich in main () ändern. Zum Beispiel würde ein Realloc-Aufruf aussehen

*x = (words*) realloc(*x, sizeof(words)*2);

Es ist das gleiche Prinzip wie in "num", das int * und nicht int ist.

Außerdem müssen Sie wirklich herausfinden, wie die Zeichenfolgen in Wörtern gespeichert wurden. Die Zuweisung eines const-Strings an char * (wie in str2 = "marley\0") ist erlaubt, ist aber selbst in C selten die richtige Lösung.

Ein weiterer Punkt: "Marley\0" muss nicht vorhanden sein, es sei denn, Sie benötigen wirklich zwei 0 am Ende der Zeichenfolge. Der Compiler fügt 0 bis zum Ende jedes String-Literal hinzu.

1
Arkadiy

Für den Testcode: Wenn Sie einen Zeiger in einer Funktion ändern möchten, sollten Sie einen "Zeiger-Zeiger" an die Funktion übergeben. Korrigierter Code lautet wie folgt:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

typedef struct
{
    char *str1;
    char *str2;
} words;

void LoadData(words**, int*);

main()
{
    words **x;
    int num;

    LoadData(x, &num);

    printf("%s %s\n", (*x[0]).str1, (*x[0]).str2);
    printf("%s %s\n", (*x[1]).str1, (*x[1]).str2);
}

void LoadData(words **x, int *num)
{
    *x = (words*) malloc(sizeof(words));

    (*x[0]).str1 = "johnnie\0";
    (*x[0]).str2 = "krapson\0";

    *x = (words*) realloc(*x, sizeof(words) * 2);
    (*x[1]).str1 = "bob\0";
    (*x[1]).str2 = "marley\0";

    *num = *num + 1;
}
1
zhanwu

Wenn Sie das Array dynamisch vergrößern möchten, sollten Sie malloc () verwenden, um eine feste Menge an Speicher dynamisch zuzuweisen, und dann immer, wenn Sie leer sind, realloc (). Eine übliche Technik ist die Verwendung einer exponentiellen Wachstumsfunktion, bei der Sie einen kleinen festen Betrag zuweisen und dann das Array durch Duplizieren des zugewiesenen Betrags vergrößern. 

Ein Beispielcode wäre:

size = 64; i = 0;
x = malloc(sizeof(words)*size); /* enough space for 64 words */
while (read_words()) {
    if (++i > size) {
        size *= 2;
        x = realloc(sizeof(words) * size);
    }
}
/* done with x */
free(x);
0
ob1

Jeder Codierer muss seinen Code vereinfachen, um ihn leicht verständlich zu machen ... auch für Anfänger.

So Array von Strukturen dynamisch verwenden ist einfach, wenn Sie die Konzepte verstehen.

// Dynamically sized array of structures

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

struct book 
{
    char name[20];
    int p;
};              //Declaring book structure

int main () 
{
    int n, i;      

    struct book *b;     // Initializing pointer to a structure
    scanf ("%d\n", &n);

    b = (struct book *) calloc (n, sizeof (struct book));   //Creating memory for array of structures dynamically

    for (i = 0; i < n; i++)
    {
        scanf ("%s %d\n", (b + i)->name, &(b + i)->p);  //Getting values for array of structures (no error check)
    }          

    for (i = 0; i < n; i++)
    {
        printf ("%s %d\t", (b + i)->name, (b + i)->p);  //Printing values in array of structures
    }

    scanf ("%d\n", &n);     //Get array size to re-allocate    
    b = (struct book *) realloc (b, n * sizeof (struct book));  //change the size of an array using realloc function
    printf ("\n");

    for (i = 0; i < n; i++)
    {
        printf ("%s %d\t", (b + i)->name, (b + i)->p);  //Printing values in array of structures
    }

    return 0;
}   
0
Arul Girish