【问题标题】:C++ Reallocating pointer to array in dynamic memory in a different functionC ++在不同函数中重新分配指向动态内存中数组的指针
【发布时间】:2019-04-12 13:25:30
【问题描述】:

我刚刚在 C++ 中完成了一个关于指针和动态内存的模块,并且正在尝试完成一项个人作业,以便我可以练习这些概念。该程序管理一个名称字符串数组。我为自己设定的目标是列表存储在堆中(练习使用“new”),并且列表在输入新名称时动态调整大小。

免责声明:我意识到使用向量很容易做到这一点,在为此苦苦挣扎了几个小时后,我重新编写了原始代码以将向量用于列表,没有任何问题。但是我想知道我对指针工作原理的理解在哪里被打破了。

我在程序中遇到的问题是:我将名称数组初始化为具有零个元素,并具有添加名称以处理动态调整大小的函数。首次调用时,它似乎正确地重新调整了数组的大小并向新数组添加了一个新名称。在函数内添加名称,我可以打印新数组的内容。我还可以将旧数组指针重新分配给堆上新数组的地址。但是,当我在将名称添加到列表后从 main 调用打印函数时,列表不包含名称。据我了解,由于我使用的是指针,我应该直接更新值,所以在添加名称函数终止后,值应该保持不变。此外,如果我尝试添加第二个名称,程序会崩溃。我在处理内存方面做错了什么?

我已经搜索了很多,我能找到的最接近的解决方案是这篇文章:

How to make an array with a dynamic size? General usage of dynamic arrays (maybe pointers too)?

我根据我的理解修改了我的代码,但它仍然无法正常工作。

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

不幸的是结果是一样的。

【问题讨论】:

  • name_list_ptr = new string [0]; 分配一个大小为零的数组。对于这样的对象,您无能为力。你可以安全地deletenullptr,这样我就可以省去分配和不得不delete 一个不可用的分配的麻烦,只需让name_list_ptr 指向nullptr
  • 当我遇到这样的问题并且无法使用std::vector 时,我会写一个简单的穷人vector。即使是简单的模拟 vector 工作也很有教育意义,值得投入时间。
  • @user4581301 不幸的是,我还没有开始制作对象类,所以这需要一些时间。这个实现实际上是它的先驱。

标签: c++ pointers memory-management dynamic


【解决方案1】:

在不检查实现逻辑的情况下,您的列表不会更新,因为您分配了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;

希望对你有帮助

【讨论】:

  • 的补充细节,但是如果你修改指针本身,它不会。指向的对象是通过引用传递的(感谢指针)但指针本身是传递的按价值。 list_size 包含调用者提供的地址的副本,更改副本对源没有影响。
  • 没错。我不想提供太多细节以免术语泛滥。
  • 这是一个值得关注的问题,但我认为我们可以在 cmets 中摆脱它。
  • @LuisGP 谢谢!我没有意识到作为对象/容器指针可以通过引用或值传递......尽管现在我大声输入它是有道理的。现在它正在工作,我发现了另一个错误,因为我增加列表大小太晚了,所以我不得不将那行代码移动几行。我以前没见过双星号。我得试试。
  • @AEdwardo 请考虑接受我的回答作为您问题的解决方案。接受正确的答案有助于 stackoverflow 的发展并使社区变得更强大 :)
猜你喜欢
  • 2021-04-15
  • 2015-06-19
  • 1970-01-01
  • 2013-04-18
  • 1970-01-01
  • 1970-01-01
  • 2015-12-10
  • 2013-05-26
  • 2013-10-04
相关资源
最近更新 更多