How can I create a dynamically sized array of structs?

后端 未结 10 1133
春和景丽
春和景丽 2020-11-27 11:46

I know how to create an array of structs but with a predefined size. However is there a way to create a dynamic array of structs such that the array could get bigger?

<
相关标签:
10条回答
  • 2020-11-27 12:34

    You've tagged this as C++ as well as C.

    If you're using C++ things are a lot easier. The standard template library has a template called vector which allows you to dynamically build up a list of objects.

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

    If you're using C things are a lot harder, yes malloc, realloc and free are the tools to help you. You might want to consider using a linked list data structure instead. These are generally easier to grow but don't facilitate random access as easily.

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

    Yikes, sorry for the worlds longest answer. So WRT to the "don't want to use a linked list comment":

    #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;
    }
    
    0 讨论(0)
  • 2020-11-27 12:35

    For the test code: if you want to modify a pointer in a function, you should pass a "pointer to pointer" to the function. Corrected code is as follows:

    #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;
    }
    
    0 讨论(0)
  • 2020-11-27 12:41

    Your code in the last update should not compile, much less run. You're passing &x to LoadData. &x has the type of **words, but LoadData expects words* . Of course it crashes when you call realloc on a pointer that's pointing into stack.

    The way to fix it is to change LoadData to accept words** . Thi sway, you can actually modify the pointer in main(). For example, realloc call would look like

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

    It's the same principlae as in "num" being int* rather than int.

    Besides this, you need to really figure out how the strings in words ere stored. Assigning a const string to char * (as in str2 = "marley\0") is permitted, but it's rarely the right solution, even in C.

    Another point: non need to have "marley\0" unless you really need two 0s at the end of string. Compiler adds 0 tho the end of every string literal.

    0 讨论(0)
  • 2020-11-27 12:42

    Another option for you is a linked list. You'll need to analyze how your program will use the data structure, if you don't need random access it could be faster than reallocating.

    0 讨论(0)
提交回复
热议问题