C ++ Перераспределение указателя на массив в динамической памяти в другой функции - PullRequest
0 голосов
/ 09 ноября 2018

Я только что выполнил модуль по указателям и динамической памяти в C ++ и пытаюсь выполнить личное задание, чтобы я мог практиковать концепции. Программа управляет массивом строк, которые являются именами. Цель, которую я для себя поставил, состоит в том, чтобы список сохранялся в куче (на практике использовать «новый»), а список динамически изменялся по мере ввода новых имен.

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

Проблема, с которой я столкнулся в программе, заключается в следующем: я инициализирую массив имен так, чтобы он содержал ноль элементов, и у меня есть функция для добавления имен, которая обрабатывает динамический размер. При первом вызове он корректно изменяет размер массива и добавляет новое имя в новый массив. Внутри функции для добавления имени я могу распечатать содержимое нового массива. Я также могу переназначить старый указатель массива на адрес нового массива в куче. Однако, когда я вызываю функцию печати из main после добавления имени в список, список не содержит имени. Насколько я понимаю, поскольку я использую указатели, я должен обновлять значения напрямую, поэтому после завершения функции добавления имени значения должны сохраняться. Также, если я пытаюсь добавить второе имя, программа вылетает. Что я делаю не так с обработкой памяти?

Я немного искал, и самое близкое, что я могу найти для разрешения, был этот пост:

Как сделать массив с динамическим размером? Общее использование динамических массивов (возможно, указателей тоже)?

Я изменил свой код на основе того, что я понимаю из этого, но он все еще не работает должным образом.

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

    using namespace std;

    void add_name_to_list(string * my_list, size_t * list_size);
    string get_name();
    void print_names(const string *const my_list, const size_t *const list_size);

    int main()
    {
        string *name_list_ptr {nullptr};
        name_list_ptr = new string [0];
        size_t name_list_size{0};
        size_t *name_list_size_ptr {&name_list_size};

        print_names(name_list_ptr, name_list_size_ptr);
        add_name_to_list(name_list_ptr, name_list_size_ptr);
        print_names(name_list_ptr, name_list_size_ptr);
        return 0;
    }

    void add_name_to_list (string * my_list, size_t *list_size)
    {
        string new_name{get_name()};
        string *new_string_ptr{nullptr};
            new_string_ptr = new string [*list_size+1];
            // copy existing list into new list
            cout << "List size is " << *list_size << " so *list size == 0 is " << (*list_size == 0) << endl;
            if(*list_size == 0)
            {
                new_string_ptr[0] = new_name;
                *list_size = *list_size +1;
                cout << new_string_ptr[0] << " has been added to position " << *list_size << endl;

            }
            else
            {
                print_names(my_list, list_size);
                for(size_t i{0}; i < *list_size; i++)
                {
                    cout << "At position " << i << " original list is " << my_list[i] << endl;
                    new_string_ptr[i] = my_list[i];
                    cout << "The name " << new_string_ptr[i] << " has been added to position " << i << " of the new list" << endl;
                }
                new_string_ptr[*list_size - 1] = new_name;
                *list_size = *list_size + 1;
            }
            print_names(new_string_ptr, list_size);

            string *temp_ptr{nullptr};
            temp_ptr = new string [*list_size-1];
            cout << "temp ptr is " << temp_ptr << " and my list is " << my_list << endl;
            temp_ptr = my_list;
            cout << "temp ptr is " << temp_ptr << " and my list is " << my_list << endl;
            my_list = new_string_ptr;
            delete [] temp_ptr;
            new_string_ptr = nullptr;
            print_names(my_list, list_size);
    }

    string get_name()
    {
        cin.sync();
        cin.clear();
        string new_name{};
        cout << "\nEnter the full name: ";
        getline(cin, new_name);
        cin.sync();
        cin.clear();
        if(new_name.size() <= 1)
            return "0";
        else
            return new_name;    
    }

    void print_names(const string *const my_list, const size_t *const list_size)
    {
        if(*list_size == 0)
            cout << "The list is empty" << endl;
        else
            for(size_t j{0}; j < *list_size; j++)
                    cout << j << ". " << my_list[j] << endl;
    }

Один вариант, который я попробовал на основе того, что я узнал из поиска:

    cout << "temp ptr is " << temp_ptr << " and my list is " << my_list << endl;
    //my_list = new_string_ptr;
    //delete [] temp_ptr;
    //new_string_ptr = nullptr;

    delete [] my_list;
    my_list = new string[*list_size];
    my_list = new_string_ptr;
    print_names(my_list, list_size);

К сожалению, результаты такие же.

1 Ответ

0 голосов
/ 09 ноября 2018

Без проверки логики реализации ваш список не обновляется, потому что вы присваиваете my_list = new_string_ptr;, но ваша функция получила void add_name_to_list (string * my_list, size_t *list_size).

Поскольку вы новичок в мире C ++, позвольте мне четко объяснить: list_size - указатель на size_t, поэтому, если вы измените указанную память, изменение сохранится, но если вы измените сам указатель, оно не будет.

list_size = new size_t; // This change doesn't persist
list_size++; // This change doesn't persist

*list_size++; // This change persists and the value of pointed memory was increased.

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

Итак, вы должны использовать:

void add_name_to_list (string * &my_list, size_t *list_size)

Или, может быть, вам удобнее с

void add_name_to_list (string ** my_list, size_t *list_size)
[...]
*my_list = new_string_ptr;

Надеюсь, это поможет

...