51 votes

Comment créer un tableau de structures de taille dynamique?

Je sais comment créer un tableau de structures, mais avec une taille prédéfinie. Cependant est-il possible de créer un tableau dynamique de structures telles que le tableau pourrait obtenir de plus gros?

Par exemple:

    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.
    }

Est-ce possible?


J'ai fait des recherches: words* array = (words*)malloc(sizeof(words) * 100);

Je ne pense pas que je l'explique moi clairement, mes excuses.

Je veux me débarrasser de l'100 et stocker les données à mesure qu'il arrive. Ainsi, si 76 champs de données, je veux stocker 76 et 100. Je pars du principe que je ne sais pas quelle quantité de données est arrivée dans mon programme. Dans la structure que j'ai défini plus haut, j'ai pu créer le premier "index" comme:

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

Mais je tiens à ajouter dynamiquement des éléments de la matrice après. J'espère que j'ai décrit la zone à problème assez clairement. Le défi majeur est d'ajouter dynamiquement un deuxième champ, au moins, c'est le défi à relever pour le moment.


J'ai fait un peu de progrès cependant:

    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?

J'ai fait un peu de vérification des erreurs et c'est ce que j'ai trouvé. Si après je libérer de la mémoire pour x je ajouter ce qui suit:

    x=NULL;

alors si j'essaie d'imprimer x, j'obtiens une erreur qui est ce que je veux. Donc, est-ce que le libre ne fonctionne pas, au moins sur mon compilateur? J'utilise DevC??


Merci, je comprends maintenant, en raison de:

Le prénom est un pointeur vers un tableau de char qui n'est pas allouée par la fonction malloc, seul le pointeur est alloué et après vous appel gratuitement, il n'efface pas le souvenir, c'est juste la marque comme disponible sur le tas à être écrites plus tard. – MattSmith

P. S. Désolé pour la longue page, je suppose que je suis maintenant habitué à ce forum.

Je suis dans un problème. Je n'ai aucune idée de quoi faire à côté. S'il vous plaît aider quelqu'un. Je suis en train de modulariser et de mettre de la création de mon tableau de structures dans une fonction, mais ça ne fonctionne pas et j'ai tout essayé, rien du tout semble fonctionner. Je suis en train d'essayer quelque chose de très simple et je ne sais pas quoi faire d'autre. C'est dans le même sens qu'avant, juste une autre fonction, loaddata c'est le chargement des données et à l'extérieur de la méthode que j'ai besoin de faire quelque impression. Comment puis-je le faire fonctionner?. Mon code est comme suit:

    # 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;
    }//

Ce simple code de test est de s'écraser et je n'ai aucune idée pourquoi. Où est le bug?

35voto

Tom Points 13036

Vous avez marqués ce que C++ ainsi que C.

Si vous êtes à l'aide de C++ les choses sont beaucoup plus faciles. Le modèle standard de la bibliothèque dispose d'un modèle appelé vecteur qui permet de créer dynamiquement une liste d'objets.

#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;
}

Si vous êtes à l'aide de C, les choses sont beaucoup plus difficile, oui malloc, realloc et gratuit sont les outils pour vous aider. Vous pouvez envisager d'utiliser une liste chaînée structure de données à la place. Ceux-ci sont généralement plus faciles à cultiver, mais ne facilitent pas l'accès aléatoire aussi facilement.

#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;
}

Oups, désolé pour les mondes, la plus longue réponse. Donc WRT pour le "ne veulent pas utiliser une liste chaînée commentaire":

#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;
}

12voto

coobird Points 70356

Si vous souhaitez allouer dynamiquement des tableaux, vous pouvez utiliser malloc de stdlib.h.

Si vous voulez allouer un tableau de 100 éléments à l'aide de votre words struct, essayez les solutions suivantes:

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

La taille de la mémoire que vous souhaitez allouer est passé en malloc , puis il retournera un pointeur de type void (void*). Dans la plupart des cas, vous aurez probablement envie de le jeter aux le type de pointeur, vous avez le désir, qui dans ce cas est - words*.

L' sizeof mot-clé est utilisé ici pour savoir la taille de l' words struct, alors que la taille est multipliée par le nombre d'éléments que vous souhaitez allouer.

Une fois que vous avez terminé, assurez-vous d'utiliser free() , pour libérer de la mémoire dans la mémoire que vous avez utilisé pour prévenir les fuites de mémoire:

free(array);

Si vous souhaitez modifier la taille de l'allocation d'un tableau, vous pouvez essayer d'utiliser l' realloc comme d'autres l'ont mentionné, mais gardez à l'esprit que si vous faites beaucoup de reallocs, vous finirez par fragmentation de la mémoire. Si vous voulez redimensionner dynamiquement le tableau afin de garder une faible empreinte mémoire de votre programme, il peut être préférable de ne pas faire trop d' reallocs.

5voto

Ryan Points 3745

Cela ressemble à un exercice académique qui, malheureusement, il est plus difficile, puisque vous ne pouvez pas utiliser le C++. Fondamentalement, vous avez à gérer le temps de l'affectation et de garder une trace de combien de mémoire a été allouée si vous avez besoin de redimensionner à la taille plus tard. C'est là que le C++ standard library brille.

Pour votre exemple, le code suivant affecte la mémoire et, plus tard, la redimensionne:

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

Gardez à l'esprit, dans votre exemple, vous êtes juste d'allouer un pointeur vers un char et vous avez encore besoin d'allouer de la chaîne elle-même et surtout de le libérer à la fin. Donc ce code alloue 100 pointeurs de char et puis redimensionne à 76, mais n'alloue pas les chaînes elles-mêmes.

Je soupçonne que vous voulez allouer le nombre de caractères dans une chaîne de caractères qui est très similaire à ce qui précède, mais le changement de mot de char.

EDIT: Aussi garder à l'esprit qu'il fait beaucoup de sens pour créer des fonctions pour effectuer des tâches courantes et renforcer la cohérence de sorte que vous n'avez pas de copie de code partout. Par exemple, vous pourriez avoir un) d'allouer la structure, b) affecter des valeurs à la structure, et c) la gratuité de la struct. De sorte que vous pourriez avoir:

// 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);

EDIT: autant Que le redimensionnement de la structs, elle est identique à redimensionner le tableau de char. Cependant la différence est que si vous faites la struct tableau plus grand, vous devriez probablement pour initialiser les nouveaux éléments de tableau de la valeur NULL. De même, si vous faites de la structure de la matrice plus petite, vous avez besoin pour le nettoyage avant de retirer les éléments -- qui est libre des éléments qui ont été attribués (et uniquement les éléments attribués) avant de redimensionner la structure de la matrice. C'est la principale raison pour laquelle je propose de créer des fonctions d'assistance pour les aider à gérer cela.

// 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);

3voto

Neil Williams Points 6446

Une autre option pour vous est une liste chaînée . Vous devrez analyser la manière dont votre programme utilisera la structure de données. Si vous n'avez pas besoin d'un accès aléatoire, cela pourrait être plus rapide que la réaffectation.

2voto

Jeremy Ruten Points 59989

En C ++, utilisez un vecteur . C'est comme un tableau, mais vous pouvez facilement ajouter et supprimer des éléments, ce qui vous permettra d'allouer et de désallouer de la mémoire.

Je connais le titre de la question dit C, mais vous avez marqué votre question avec C et C ++ ...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X