如何为嵌套的指针结构动态分配内存?

时间:2019-09-21 07:29:42

标签: c++ arrays algorithm class dynamic-memory-allocation

我正在尝试为恰好是指针的嵌套结构动态分配内存。我在下面编写了一些虚构的代码来尝试说明我的问题。

这两个结构位于两个单独的头文件中,代码也位于一个名称空间下。

Tiles.h

struct Tiles
{
    int* m_noOfSections;
    int* m_noOfTilesInSecs;
    char* m_TileName;
};
// functions omitted

Flooring.h

struct Flooring
{
    Tiles* m_Tiles;
    int m_noOfTiles;
    char* m_FlooringName;
};
void read(Tiles&);

我正在为 Flooring.h 设计一个函数定义,在该函数中,我必须动态分配Tiles数组,该数组的大小是在此函数中由用户确定的输入。

我尝试使用以下代码,但遇到了问题:

Flooring.cpp

void read(Flooring&Flr) 
{
      Tiles* tiles;
      tiles = new Tiles[Flr.m_noOfTiles];

      for (int i = 0; i < Flr.m_noOfTiles; i++) {
          cout << i + 1 << ": ";
          read(tiles[i]);
      }
}

注意:read(tiles[i]); [声明:void read(Tiles&)]函数将值分配给Tiles的数据成员。我已经测试了Tiles文件中的功能,它们按预期工作。因此,我没有包含这些代码。我认为问题出在我的 Flooring.cpp 实施文件中。

我的期望是,上述读取功能会将值分配给: tiles[i].m_noOfSectionstiles[i].m_noOfTilesinSecstiles[i].m_tileName

问题之一是我没有机会输入tileName,在运行代码时,它跳过了我通常会输入tileName的部分。

输出如下:

Enter the number of sets of tiles: Enter number of sections: [user is able 
    to input value here, but not before when asked to enter the number of the set of tiles]

Tiles.cpp

void read(char* tileName)
{
    cout << "Enter tile name: ";
    read(tileName, 15, "error message") ;
}

带有三个参数的read函数的函数定义可以在下面找到。此功能已在此分配中预定义。我也检查了该功能,但没有发现任何问题,但是无论是否有帮助,我都会将其发布。

void read(char* str, int len, const char* errorMessage)
{
      bool ok;
      do 
      {
         ok = true;
         cin.getline(str, len+1, '\n');
         if (cin.fail()) {
            cin.clear();
            cin.ignore(1000, '\n');
            ok = false;
         }
      }while(!ok && cout << errorMessage);
   }

我希望能提供足够的信息,如果我的格式不正确,或者如果我的术语不适当,我深表歉意,对于各种编程我还是很陌生的。如果忘记了某些信息,请告诉我。

2 个答案:

答案 0 :(得分:2)

我建议使用std::vectorstd::string,通过它们可以自动管理元素的存储,从而可以避免手动分配内存,您可以专注于实现。

这意味着,请从以下几个方面入手:

#include <iostream>
#include <vector>  // std::vector
#include <string>  // std::string

struct Tiles
{
    std::vector<int> m_noOfSections;
    std::vector<int> m_noOfTilesInSecs;
    std::string m_TileName;
};

struct Flooring 
{
    std::vector<Tiles> m_Tiles;
    // int m_noOfTiles; // --> obsolete, as you can get the size by calling `m_Tiles.size()`
    std::string m_FlooringName;
};

作为旁注,在Flooring(也许也在Tiles)中,您确实想将Tiles的名称映射到一组{{1} }。根据需求查看其他数据结构,例如std::pairstd::mapstd::multimapstd::unordered_mapstd::unordered_multimap 标准库为这种情况提供了什么。

答案 1 :(得分:2)

新表达式不分配任何内容,仅在您提供这些值时对其进行值初始化,或者调用构造函数并将参数传递给它。

#include <iostream>
#include <string>
#include <vector>
#include <regex>
#include <sstream>
#include <iterator>
#include <algorithm>

std::istringstream csvFile{R"(animal1,hair,feathers,eggs,milk,airborne,aquatic,predator1,toothed,backbone,breathes,venomous,fins,legs,tail,domestic1,catsize,class_type,aardvark,1,0,0,1,0,0,1,1,1,1,0,0,4,0,0,1,1,antelope,1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,1,1
animal2,hair,feathers,eggs,milk,airborne,aquatic,predator2,toothed,backbone,breathes,venomous,fins,legs,tail,domestic2,catsize,class_type,aardvark,1,0,0,1,0,0,1,1,1,1,0,0,4,0,0,1,1,antelope,1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,1,1
animal3,hair,feathers,eggs,milk,airborne,aquatic,predator3,toothed,backbone,breathes,venomous,fins,legs,tail,domestic3,catsize,class_type,aardvark,1,0,0,1,0,0,1,1,1,1,0,0,4,0,0,1,1,antelope,1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,1,1)"};


class LineAsVector {    // Proxy for the input Iterator
public:
    // Overload extractor. Read a complete line
    friend std::istream& operator>>(std::istream& is, LineAsVector& lv) {

        // Read a line
        std::string line; lv.completeLine.clear();
        std::getline(is, line);

        // The delimiter
        const std::regex re(",");

        // Split values and copy into resulting vector
        std::copy(std::sregex_token_iterator(line.begin(), line.end(), re, -1),
            std::sregex_token_iterator(),
            std::back_inserter(lv.completeLine));
        return is;
    }

    // Cast the type 'CompleteLine' to std::string
    operator std::vector<std::string>() const { return completeLine; }
protected:
    // Temporary to hold the read vector
    std::vector<std::string> completeLine{};
};


int main()
{

    // Read the complete csv file and split it
    // Please note: instead of the istringstream csvFile, you can of course use any other open file stream
    std::vector<std::vector<std::string>> csv{ std::istream_iterator<LineAsVector>(csvFile), std::istream_iterator<LineAsVector>() };

    // Go through all lines of the csv data
    // And print the  0th, 7th, 15th value in each line
    std::for_each(csv.begin(), csv.end(), [](std::vector<std::string> & vs) {
        std::copy_if(vs.begin(), vs.end(), std::ostream_iterator<std::string>(std::cout, " "), [ui = -1](std::string & s) mutable {
            ++ui; return (ui == 0) || (ui == 7) || (ui == 15);
        });
        std::cout << "\n";
    });

    return 0;
}

创建一个tiles = new Tiles[Flr.m_noOfTiles]; Flr.m_noOfTiles的数组,其中包含垃圾非nullptr指针和值。下层内存未初始化。可以通过提供初始化程序列表来完成。

Tiles

您必须为每个指针分配内存。而且,当不需要它时,请按适当的顺序将其从大多数嵌套结构分配到较少嵌套的结构。

根据您需要的操作,这可能不是一件容易的事,并且会导致代码麻烦。这就是C ++具有构造函数和析构函数的原因。所以:

  1. 有没有理由不使用RAII? https://en.cppreference.com/w/cpp/language/raii
  2. 有没有理由不使用标准集合,它们已经实现了RAII。
  3. 您为什么不使用智能指针?