如何在C ++中初始化指向动态2D数组的指针

时间:2021-02-13 21:29:56

I was giving a adventurer class containing a bunch of functions and member variables. One of them is:

我正在给一个包含一堆函数和成员变量的冒险家类。其中之一是:

string*** items;

so first I thought it was a 3d array that I have to make but I was told that it suppose to be a pointer to a 2d array.

所以首先我认为这是一个3D数组,我必须做,但我被告知它假设是一个指向二维数组的指针。

What I tried to do was make a temp array

我试图做的是制作临时数组

string** temp;

Init that and fill it, I then point my items to temp

初始化并填充它,然后我将我的项目指向temp

items = &temp;

This works till the function exits. Then we I try and call a index value inside items

这可以工作直到函数退出。然后我们尝试在项目中调用索引值

cout<<*item[0][0];

there is nothing. When temp disappears so does the array.

空无一物。当temp消失时,数组也会消失。

This line also doenst work

这条线也很有效

(*items) = new string*[2];

I couldn't find anything online that helped me.

我在网上找不到任何帮助我的东西。

How can I initialize items or keep the array data that i made using temp.

如何初始化项目或保留使用temp生成的数组数据。

For those asking for the code, this is what they gave me:

对于那些要求代码的人来说,这就是他们给我的:

class Adventurer{
private:
    string*** items;
    string name;
    double maxCarryWeight;
    double currentCarryWeight;
    int currentNumberOfItems;
    int maxNumberOfItems;
    double health;
    static int numberOfAdventurers;


public:
    Adventurer(); //default constructor
    Adventurer(const Adventurer& a);  //copy constructor
    ~Adventurer();
    bool pickUpItem(string it, double weight);
    bool dropItem(string it);
    bool dropItem(int index);
    void setName(string n);
    string getName() const;
    void setMaxCarryWeight(double w);
    double getMaxCarryWeight() const;
    void setCurrentCarryWeight(double w);
    double getCurrentCarryWeight() const;    
    void setMaxNumberOfItems(int n);
    int getMaxNumberOfItems() const;
    void setCurrentNumberOfItems(int n);
    int getCurrentNumberOfItems() const;
    int getNumberOfAdventurers() const;
    void setHealth(double h);
    double getHealth() const;
    string** getItem(int index) const;
    Adventurer& operator = (const Adventurer& a);
};

And said that

并说

string*** items;

is a pointer to a 2d array

是指向2d数组的指针

1 个解决方案

#1


0  

It's not entirely clear what you are trying to achieve from your question but it seems your main issue is likely to do with returning the address of a local variable when attempting to allocate your 2D C-style std::string array. Below is a very basic example of how to avoid such an issue via returning the allocated 2D array and then taking the address of this returned value and storing it in your std::string*** items variable.

目前还不完全清楚你要从你的问题中实现什么,但似乎你的主要问题可能是在尝试分配2D C风格的std :: string数组时返回局部变量的地址。下面是如何通过返回分配的2D数组然后获取此返回值的地址并将其存储在std :: string *** items变量中来避免此类问题的一个非常基本的示例。

// allocate memory for a 2D C-style array of std::string's
std::string** allocate_2d_array(std::size_t rows, std::size_t cols) {
    std::string** items_arr = new std::string*[rows];
    for (std::size_t i = 0; i < rows; ++i)
        items_arr[i] = new std::string[cols];
    return items_arr;
}
// print each element of the 2D C-style array via a pointer to the array
void print_items(std::ostream& os, std::string*** items, std::size_t rows, std::size_t cols) {
    for (std::size_t i = 0; i < rows; ++i) {
        for (std::size_t j = 0; j < cols; ++j)
            os << (*items)[i][j] << ' ';
        os << '\n';
    }
}
// destruct the 2D C-style array
void deallocate_2d_array(std::string** items_arr, std::size_t rows, std::size_t cols) {
    for (std::size_t i = 0; i < rows; ++i)
        delete[] items_arr[i];
    delete[] items_arr;
}
int main(void) {
    std::size_t rows = 3;  // matrix rows
    std::size_t cols = 3;  // matrix columns
    // allocate a 2D array of std::string's
    std::string** items_arr = allocate_2d_array(items, 3, 3);
    // set the pointer to a 2D std::string array to address of items_arr
    std::string*** items = &items_arr;
    int count = 0;
    // fill items_arr with data via items pointer
    for (std::size_t i = 0; i < rows; ++i) {
        for (std::size_t j = 0; j < cols; ++j) 
            (*items)[i][j] = std::to_string(++count);
    }
    print_items(std::cout, items); // print matrix to terminal
    deallocate_2d_array(items_arr, rows, cols);  // deallocate items_arr
}

However, as mentioned in the comments, this is not in keeping with modern c++ and one would much rather use a std::vector<std::vector<std::string>> to store a matrix of std::string instances.

但是,正如评论中所提到的,这与现代c ++不一致,而且更倾向于使用std :: vector >来存储std :: string实例的矩阵。

You mentioned that using std::vector is not an option but I suspect that your teacher probably didn't say anything about making your own barebones dynamic array with similar semantics to a std::vector so that is always one way around these silly restrictions. With that in mind, below is the framework for a very basic (and untested) class which mimics a std::vector (without using allocators) which would make your task much simpler.

你提到使用std :: vector不是一个选项,但我怀疑你的老师可能没有说任何关于制作你自己的准系统动态数组与std :: vector类似的语义,所以这总是绕过这些愚蠢的限制。考虑到这一点,下面是一个非常基本的(和未经测试的)类的框架,它模仿std :: vector(不使用allocator),这将使您的任务更加简单。

template<typename Ty>
class dynamic_array {
public:
    typedef Ty value_type;
    typedef Ty& reference;
    typedef const Ty& const_reference;
    typedef Ty* pointer;
    typedef const Ty* const_pointer;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    // CONSTRUCTION/ASSIGNMENT
    dynamic_array()
        : arr_capacity(0), arr_size(0) {}
    dynamic_array(size_type count)
        : arr_capacity(count), arr_size(count) { allocate(count); }
    ~dynamic_array() { destroy(); }
    dynamic_array& operator=(dynamic_array _other) {
        swap(*this, _other);
        return *this;
    }
    // CAPACITY
    bool empty() const noexcept { return arr_size; }
    size_type size() const noexcept { return arr_size; }
    size_type capacity() const noexcept { return arr_capacity; }
    void reserve(size_type new_cap) { if (new_cap > arr_capacity) reallocate(new_cap); }
    // ELEMENT ACCESS
    reference operator[](size_type n) { return arr[n]; }
    const_reference operator[](size_type n) const { return arr[n]; }
    // MODIFIERS
    void clear() {
        for (size_type i = 0; i < arr_size; ++i)
            (&arr[i])->~value_type();
        arr_size = 0;
    }
    void push_back(const value_type& _val) {
        if (arr_size == arr_capacity) // TODO: expand arr using reallocate
        pointer val = new (arr + arr_size) value_type(_val);
        ++arr_size;
    }
    void pop_back() {
        (&arr[arr_size-1])->~value_type();
        --arr_size;
    }
    void swap(dynamic_array& _other) {
        std::swap(arr, _other.arr);
        std::swap(arr_capacity, _other.arr_capacity);
        std::swap(arr_size, _other.arr_size);
    }
    static void swap(dynamic_array& lhs, dynamic_array& rhs) { lhs.swap(rhs); }
private:
    value_type* arr;
    size_type arr_capacity;
    size_type arr_size;
    void allocate(size_type n) { arr = new value_type[n]; }
    void reallocate(size_type new_cap) {
        value_type* tmp = new value_type[new_cap];
        size_type tmp_rows = (new_cap > arr_capacity) ? arr_capacity : new_cap;
        for (size_type i = 0; i < tmp_rows; ++i)
            tmp[i] = std::move(arr[i]);
        delete[] arr;
        arr = tmp;
        arr_capacity = new_cap;
    }
    void destroy { clear(); delete[] arr; }
};

Then instead of messing around with lots of raw pointers and the headaches they bring, you can just pass around your dynamic_array<dynamic_array<std::string>> class instance without needing to worry about memory management.

然后,您可以只需传递dynamic_array >类实例,而无需担心内存管理,而不是乱搞大量原始指针和它们带来的麻烦。


Note: The above dynamic_array class is untested and probably requires some tweaks, it is also not a great example of implementing a STL-style container (you'd need allocator and iterator support), it is just intended as a barebones std::vector mimicking container to get around the "no vector" task requirement.

注意:上面的dynamic_array类是未经测试的,可能需要一些调整,它也不是实现STL样式容器的一个很好的例子(你需要分配器和迭代器支持),它只是作为准系统std :: vector模仿容器以绕过“无向量”任务要求。

#1


0  

It's not entirely clear what you are trying to achieve from your question but it seems your main issue is likely to do with returning the address of a local variable when attempting to allocate your 2D C-style std::string array. Below is a very basic example of how to avoid such an issue via returning the allocated 2D array and then taking the address of this returned value and storing it in your std::string*** items variable.

目前还不完全清楚你要从你的问题中实现什么,但似乎你的主要问题可能是在尝试分配2D C风格的std :: string数组时返回局部变量的地址。下面是如何通过返回分配的2D数组然后获取此返回值的地址并将其存储在std :: string *** items变量中来避免此类问题的一个非常基本的示例。

// allocate memory for a 2D C-style array of std::string's
std::string** allocate_2d_array(std::size_t rows, std::size_t cols) {
    std::string** items_arr = new std::string*[rows];
    for (std::size_t i = 0; i < rows; ++i)
        items_arr[i] = new std::string[cols];
    return items_arr;
}
// print each element of the 2D C-style array via a pointer to the array
void print_items(std::ostream& os, std::string*** items, std::size_t rows, std::size_t cols) {
    for (std::size_t i = 0; i < rows; ++i) {
        for (std::size_t j = 0; j < cols; ++j)
            os << (*items)[i][j] << ' ';
        os << '\n';
    }
}
// destruct the 2D C-style array
void deallocate_2d_array(std::string** items_arr, std::size_t rows, std::size_t cols) {
    for (std::size_t i = 0; i < rows; ++i)
        delete[] items_arr[i];
    delete[] items_arr;
}
int main(void) {
    std::size_t rows = 3;  // matrix rows
    std::size_t cols = 3;  // matrix columns
    // allocate a 2D array of std::string's
    std::string** items_arr = allocate_2d_array(items, 3, 3);
    // set the pointer to a 2D std::string array to address of items_arr
    std::string*** items = &items_arr;
    int count = 0;
    // fill items_arr with data via items pointer
    for (std::size_t i = 0; i < rows; ++i) {
        for (std::size_t j = 0; j < cols; ++j) 
            (*items)[i][j] = std::to_string(++count);
    }
    print_items(std::cout, items); // print matrix to terminal
    deallocate_2d_array(items_arr, rows, cols);  // deallocate items_arr
}

However, as mentioned in the comments, this is not in keeping with modern c++ and one would much rather use a std::vector<std::vector<std::string>> to store a matrix of std::string instances.

但是,正如评论中所提到的,这与现代c ++不一致,而且更倾向于使用std :: vector >来存储std :: string实例的矩阵。

You mentioned that using std::vector is not an option but I suspect that your teacher probably didn't say anything about making your own barebones dynamic array with similar semantics to a std::vector so that is always one way around these silly restrictions. With that in mind, below is the framework for a very basic (and untested) class which mimics a std::vector (without using allocators) which would make your task much simpler.

你提到使用std :: vector不是一个选项,但我怀疑你的老师可能没有说任何关于制作你自己的准系统动态数组与std :: vector类似的语义,所以这总是绕过这些愚蠢的限制。考虑到这一点,下面是一个非常基本的(和未经测试的)类的框架,它模仿std :: vector(不使用allocator),这将使您的任务更加简单。

template<typename Ty>
class dynamic_array {
public:
    typedef Ty value_type;
    typedef Ty& reference;
    typedef const Ty& const_reference;
    typedef Ty* pointer;
    typedef const Ty* const_pointer;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    // CONSTRUCTION/ASSIGNMENT
    dynamic_array()
        : arr_capacity(0), arr_size(0) {}
    dynamic_array(size_type count)
        : arr_capacity(count), arr_size(count) { allocate(count); }
    ~dynamic_array() { destroy(); }
    dynamic_array& operator=(dynamic_array _other) {
        swap(*this, _other);
        return *this;
    }
    // CAPACITY
    bool empty() const noexcept { return arr_size; }
    size_type size() const noexcept { return arr_size; }
    size_type capacity() const noexcept { return arr_capacity; }
    void reserve(size_type new_cap) { if (new_cap > arr_capacity) reallocate(new_cap); }
    // ELEMENT ACCESS
    reference operator[](size_type n) { return arr[n]; }
    const_reference operator[](size_type n) const { return arr[n]; }
    // MODIFIERS
    void clear() {
        for (size_type i = 0; i < arr_size; ++i)
            (&arr[i])->~value_type();
        arr_size = 0;
    }
    void push_back(const value_type& _val) {
        if (arr_size == arr_capacity) // TODO: expand arr using reallocate
        pointer val = new (arr + arr_size) value_type(_val);
        ++arr_size;
    }
    void pop_back() {
        (&arr[arr_size-1])->~value_type();
        --arr_size;
    }
    void swap(dynamic_array& _other) {
        std::swap(arr, _other.arr);
        std::swap(arr_capacity, _other.arr_capacity);
        std::swap(arr_size, _other.arr_size);
    }
    static void swap(dynamic_array& lhs, dynamic_array& rhs) { lhs.swap(rhs); }
private:
    value_type* arr;
    size_type arr_capacity;
    size_type arr_size;
    void allocate(size_type n) { arr = new value_type[n]; }
    void reallocate(size_type new_cap) {
        value_type* tmp = new value_type[new_cap];
        size_type tmp_rows = (new_cap > arr_capacity) ? arr_capacity : new_cap;
        for (size_type i = 0; i < tmp_rows; ++i)
            tmp[i] = std::move(arr[i]);
        delete[] arr;
        arr = tmp;
        arr_capacity = new_cap;
    }
    void destroy { clear(); delete[] arr; }
};

Then instead of messing around with lots of raw pointers and the headaches they bring, you can just pass around your dynamic_array<dynamic_array<std::string>> class instance without needing to worry about memory management.

然后,您可以只需传递dynamic_array >类实例,而无需担心内存管理,而不是乱搞大量原始指针和它们带来的麻烦。


Note: The above dynamic_array class is untested and probably requires some tweaks, it is also not a great example of implementing a STL-style container (you'd need allocator and iterator support), it is just intended as a barebones std::vector mimicking container to get around the "no vector" task requirement.

注意:上面的dynamic_array类是未经测试的,可能需要一些调整,它也不是实现STL样式容器的一个很好的例子(你需要分配器和迭代器支持),它只是作为准系统std :: vector模仿容器以绕过“无向量”任务要求。