Подтвердить что ты не робот

Как создать массив структур с динамическим размером?

Я знаю, как создать массив структур, но с предопределенным размером. Однако существует ли способ создать динамический массив структур, чтобы массив мог стать больше?

Например:

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

Возможно ли это?


Я исследовал это: words* array = (words*)malloc(sizeof(words) * 100);

Я не думаю, что я ясно объяснил, мои извинения.

Я хочу избавиться от 100 и хранить данные по мере их поступления. Таким образом, если в число 76 полей поступает, я хочу сохранить 76, а не 100. Я предполагаю, что я не знаю, сколько данные поступают в мою программу. В описанной выше структуре я мог бы создать первый "индекс" как:

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

Однако я хочу динамически добавлять элементы в массив после. Надеюсь, я достаточно четко описал проблемную область. Основная задача состоит в том, чтобы динамически добавить второе поле, по крайней мере, это проблема на данный момент.


Я сделал небольшой прогресс, однако:

    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 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?

Я проверил некоторые ошибки, и это то, что я нашел. Если после освобождения памяти для x добавьте следующее:

    x=NULL;

то, если я попытаюсь распечатать x, я получаю сообщение об ошибке, которое я хочу. Так что бесплатная функция не работает, по крайней мере, на моем компиляторе? Я использую DevC??


Спасибо, я понимаю теперь из-за:

FirstName - это указатель на массив char, который не выделяется malloc, выделяется только указатель, и после того, как вы звоните бесплатно, он не стирает память, он просто отмечает его как доступный по куча будет написана позже. - MattSmith

P.S. Извините за длинную страницу, я думаю, теперь я привык к этому форуму.

У меня проблема. Я понятия не имею, что делать дальше. Пожалуйста, помогите кому-нибудь. Я пытаюсь модулировать и помещать создание моего массива структур в функцию, но он не работает, и я все пробовал, просто ничего не работает. Я пробую что-то очень простое, и я не знаю, что еще делать. Он по тем же линиям, что и раньше, просто другая функция, loaddata, которая загружает данные и вне метода, который мне нужен, чтобы сделать некоторую печать. Как я могу заставить его работать?. Мой код выглядит следующим образом:

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

Этот простой тестовый код сбой, и я понятия не имею, почему. Где ошибка?

4b9b3361

Ответ 1

Вы отметили это как С++, а также C.

Если вы используете С++, все намного проще. Стандартная библиотека шаблонов имеет шаблон, называемый вектором, который позволяет динамически создавать список объектов.

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

Если вы используете C, все намного сложнее, да malloc, realloc и бесплатные инструменты, которые помогут вам. Вместо этого вы можете рассмотреть возможность использования структуры данных связанных списков. Они, как правило, легче расти, но не облегчают случайный доступ, как легко.

#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, извините за самый длинный ответ в мире. Поэтому WRT для "не хочу использовать комментарий связанного списка":

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

Ответ 2

Если вы хотите динамически распределять массивы, вы можете использовать malloc из stdlib.h.

Если вы хотите выделить массив из 100 элементов, используя структуру words, попробуйте следующее:

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

Размер памяти, которую вы хотите выделить, передается в malloc, а затем возвращается указатель типа void (void*). В большинстве случаев вы, вероятно, захотите отдать его желаемому типу указателя, который в этом случае words*.

Ключевое слово sizeof используется здесь, чтобы узнать размер структуры words, затем этот размер умножается на количество элементов, которые вы хотите выделить.

Как только вы закончите, не забудьте использовать free(), чтобы освободить память кучи, которую вы использовали, чтобы предотвратить утечки памяти:

free(array);

Если вы хотите изменить размер выделенного массива, вы можете попробовать использовать realloc, как упомянули другие, но имейте в виду, что если вы делаете много realloc, вы можете закончить фрагментация памяти. Если вы хотите динамически изменять размер массива, чтобы сохранить низкую площадь памяти для вашей программы, лучше не делать слишком много realloc s.

Ответ 3

Это похоже на академическое упражнение, которое, к сожалению, усложняет работу, поскольку вы не можете использовать С++. В основном вам нужно управлять некоторыми накладными расходами для распределения и отслеживать, сколько памяти было выделено, если вам нужно изменить его размер позже. Именно там сияет стандартная библиотека С++.

В вашем примере следующий код выделяет память и затем изменяет ее размеры:

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

Имейте в виду, что в вашем примере вы просто выделяете указатель на char, и вам все равно нужно выделить строку и, что более важно, освободить ее в конце. Таким образом, этот код выделяет 100 указателей на char, а затем изменяет размер до 76, но не выделяет сами строки.

У меня есть подозрение, что вы действительно хотите выделить количество символов в строке, которая очень похожа на приведенную выше, но смените слово на char.

EDIT: Также имейте в виду, что он делает много смысла для создания функций для выполнения общих задач и обеспечения согласованности, чтобы вы не копировали код повсюду. Например, у вас может быть a) выделить структуру, b) присвоить значения структуре и c) освободить структуру. Таким образом, вы можете:

// 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. Что касается изменения размера структур, он идентичен изменению размера массива char. Однако разница в том, что если вы создадите массив структуры больше, вы должны, вероятно, инициализировать новые элементы массива до NULL. Аналогичным образом, если вы уменьшите массив структуры, вам необходимо очистить до удаления элементов - это свободные элементы, которые были выделены (и только выделенные элементы), прежде чем изменять размер массива struct. Это основная причина, по которой я предложил создать вспомогательные функции для управления этим.

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

Ответ 4

В С++ используйте vector. Это похоже на массив, но вы можете легко добавлять и удалять элементы, и он позаботится о выделении и освобождении памяти для вас.

Я знаю, что заголовок вопроса говорит C, но вы отметили свой вопрос на C и С++...

Ответ 5

Другим вариантом для вас является связанный список. Вам нужно будет проанализировать, как ваша программа будет использовать структуру данных, если вам не нужен произвольный доступ, это может быть быстрее, чем перераспределение.

Ответ 6

Вот как я сделал бы это в С++

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

Используйте тот же самый принцип для любого класса struct или С++.

Ответ 7

Ваш код в последнем обновлении не должен компилироваться, а тем более работать. Вы передаете & x в LoadData. & x имеет тип ** слов, но LoadData ожидает слова *. Конечно, он вылетает, когда вы вызываете realloc на указатель, указывающий на стек.

Чтобы исправить это, нужно изменить LoadData для приема слов **. Thy sway, вы можете на самом деле изменить указатель в main(). Например, вызов realloc будет выглядеть как

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

Это те же самые принципы, что и в "num", которые являются int *, а не int.

Кроме того, вам нужно действительно понять, как хранятся строки в словах. Присвоение строки const char * (как в str2 = "marley\0" ) разрешено, но редко это решение, даже в C.

Еще один момент: не нужно иметь "marley\0", если вам не нужны два нуля в конце строки. Компилятор добавляет 0 к концу каждого строкового литерала.

Ответ 8

Для тестового кода: если вы хотите изменить указатель в функции, вы должны передать "указатель на указатель" на функцию. Исправленный код выглядит следующим образом:

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

Ответ 9

Если вы хотите динамически вырастить массив, вы должны использовать malloc() для динамического выделения некоторого фиксированного объема памяти, а затем использовать realloc(), когда вы закончите. Общей методикой является использование экспоненциальной функции роста, так что вы выделяете некоторую небольшую фиксированную сумму, а затем увеличиваете массив путем дублирования выделенной суммы.

Некоторый пример кода:

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

Ответ 10

Проверьте malloc и realloc.