简体   繁体   English

C ++在类中声明数组并在类中声明2d数组

[英]C++ Declaring arrays in class and declaring 2d arrays in class

I'm new with using classes and I encountered a problem while delcaring an array into a class. 我是使用类的新手,但在将数组分配到类中时遇到了问题。 I want to initialize a char array for text limited to 50 characters and then replace the text with a function. 我想为限制为50个字符的文本初始化一个char数组,然后用一个函数替换文本。

#ifndef MAP_H
#define MAP_H
#include "Sprite.h"
#include <SFML/Graphics.hpp> 
#include <iostream>

class Map : public sprite
{
private:
    char mapname[50];
    int columnnumber;
    int linenumber;
    char casestatematricia[];

public:
    void setmapname(char newmapname[50]);
    void battlespace(int column, int line);
    void setcasevalue(int col, int line, char value);
    void printcasematricia();

};


#endif

By the way I could initialize my 2d array like that 顺便说一句,我可以像这样初始化我的2d数组

char casestatematricia[][];

I want later to make this 2d array dynamic where I enter a column number and a line number like that 我想稍后使此2d数组动态化,在其中输入像这样的列号和行号

casestatematricia[linenumber][columnnumber]

to create a battlefield. 创建战场。

this is the cpp code so that you have an idea of what I want to do. 这是cpp代码,以便您对我要做什么有所了解。

#include "Map.h"
#include <SFML/Graphics.hpp> 
#include <iostream>

using namespace sf;

void Map::setmapname(char newmapname[50])
{
    this->mapname = newmapname;
}
void Map::battlespace(int column, int line)
{

}
void Map::setcasevalue(int col, int line, char value)
{

}
void Map::printcasematricia()
{

}

thank you in advance. 先感谢您。

Consider following common practice on this one. 考虑遵循这一常规做法。 Most (eg numerical) libraries don't use 2D arrays inside classes. 大多数(例如数字)库在类内部不使用2D数组。 They use dynamically allocated 1D arrays and overload the () or [] operator to access the right elements in a 2D-like fashion. 他们使用动态分配的1D数组并重载()或[]运算符,以类似于2D的方式访问正确的元素。 So on the outside you never can tell that you're actually dealing with consecutive storage, it looks like a 2D array. 因此,从外面看,您永远无法说出您实际上在处理连续存储,它看起来像是2D阵列。 In this way arrays are easier to resize, more efficient to store, transpose and reshape. 这样,阵列更易于调整大小,存储,转置和整形更有效。

Just a proposition for your problem: 只是您的问题的命题:

class Map : public sprite
{
private:
    std::string mapname;
    int columnnumber;
    int linenumber;
    std::vector<char> casestatematricia;

    static constexpr std::size_t maxRow = 50;
    static constexpr std::size_t maxCol = 50; 

public:
    Map():
        casestatematricia(maxRow * maxCol, 0)
    {}
    void setmapname(std::string newmapname)
    {
        if (newmapname.size() > 50)
        {
            // Manage error if you really need no more 50 characters..
            // Or just troncate when you serialize!
        }
        mapname = newmapname;
    }

    void battlespace(int col, int row);
    void setcasevalue(int col, int row, char value)
    {
        // check that col and line are between 0 and max{Row|Column} - 1
        casestatematricia[row * maxRow + col] = value;
    }

    void printcasematricia()
    {
        for (std::size_t row = 0; row < maxRow; ++row)
        {
            for (std::size_t col = 0; col < maxCol; ++col)
            {
                char currentCell = casestatematricia[row * maxRow + col];
            }
        }
    }
};

For access to 1D array like a 2D array, take a look at Access a 1D array as a 2D array in C++ . 要访问像2D数组这样的1D数组,请查看C ++中将1D数组作为2D数组访问

When you think about serialization, I guess you want to save it to a file. 当您考虑序列化时,我想您想将其保存到文件中。 Just a advice: don't store raw memory to a file just to "save" time when your relaunch your soft. 只是一个建议:不要将原始内存存储到文件中只是为了在重新启动软件时“节省”时间。 You just have a non portable solution! 您只有一个非便携式解决方案! And seriously, with power of your computer, you don't have to be worry about time to load from file! 认真地说,借助计算机的强大功能,您不必担心从文件加载时间!

I propose you to add 2 methods in your class to save Map into file 我建议您在类中添加2种方法,以将Map保存到文件中

void dump(std::ostream &os)
{
    os << mapname << "\n";
    std::size_t currentRow = 0;
    for(auto c: casestatematricia)
    {
        os << static_cast<int>(c) << " ";
        ++currentRow;

        if (currentRow >= maxRow)
        {
            currentRow = 0;
            os << "\n";
        }
    }
}

void load(std::istream &is)
{
    std::string line;

    std::getline(is, line);
    mapname = line;

    std::size_t current_cell = 0;
    while(std::getline(is, line))
    {
        std::istringstream is(line);
        while(!is.eof())
        {
            char c;

            is >> c;
            casestatematricia[current_cell] = c;

            ++current_cell;
        }
    }
}

This solution is only given for example. 仅以举例的方式给出该解决方案。 They doesn't manage error and I have choose to store it in ASCII in file. 他们不处理错误,我选择将其以ASCII格式存储在文件中。 You can change to store in binary, but, don't use direct write of raw memory. 您可以更改为以二进制形式存储,但是不要使用原始内存的直接写入。 You can take a look at C - serialization techniques (just have to translate to C++). 您可以看一下C-序列化技术 (只需要转换为C ++)即可。 But please, don't use memcpy or similar technique to serialize 但是请不要使用memcpy或类似技术进行序列化

I hope I get this right. 我希望我做对了。 You have two questions. 你有两个问题。 You want know how to assign the value of char mapname[50]; 您想知道如何分配char mapname[50];的值char mapname[50]; via void setmapname(char newmapname[50]); 通过void setmapname(char newmapname[50]); . And you want to know how to create a dynamic size 2D array. 您想知道如何创建动态尺寸的2D数组。

I hope you are comfortable with pointers because in both cases, you need it. 我希望您对指针感到满意,因为在两种情况下都需要它。

For the first question, I would like to first correct your understanding of void setmapname(char newmapname[50]); 对于第一个问题,我想首先纠正您对void setmapname(char newmapname[50]);理解void setmapname(char newmapname[50]); . C++ functions do not take in array. C ++函数不接受数组。 It take in the pointer to the array. 它接受指向数组的指针。 So it is as good as writing void setmapname(char *newmapname); 因此,这与编写void setmapname(char *newmapname);一样好void setmapname(char *newmapname); . For better understanding, go to Passing Arrays to Function in C++ 为了更好地理解,请转到将数组传递给C ++中的函数

With that, I am going to change the function to read in the length of the new map name. 这样,我将更改功能以读取新地图名称的长度。 And to assign mapname , just use a loop to copy each of the char. 并分配mapname ,只需使用循环来复制每个字符。

void setmapname(char *newmapname, int length) {
    // ensure that the string passing in is not 
    // more that what mapname can hold.
    length = length < 50 ? length : 50;

    // loop each value and assign one by one. 
    for(int i = 0; i < length; ++i) {
        mapname[i] = newmapname[i];
    }
}

For the second question, you can use vector like what was proposed by Garf365 need to use but I prefer to just use pointer and I will use 1D array to represent 2d battlefield. 对于第二个问题,您可以使用矢量,如Garf365建议的那样,但我希望仅使用指针,而我将使用1D数组表示2d战场。 (You can read the link Garf365 provide). (您可以阅读Garf365提供的链接)。

// Declare like this
char *casestatematricia; // remember to initialize this to 0.

// Create the battlefield
void Map::battlespace(int column, int line) {

    columnnumber = column;
    linenumber = line;

    // Clear the previous battlefield.
    clearspace();

    // Creating the battlefield
    casestatematricia = new char[column * line];

    // initialise casestatematricia...
}

// Call this after you done using the battlefield
void Map::clearspace() {
    if (!casestatematricia) return;

    delete [] casestatematricia;
    casestatematricia = 0;
}

Just remember to call clearspace() when you are no longer using it. 只要记住在不再使用它时调用clearspace()

Just for your benefit, this is how you create a dynamic size 2D array 仅出于您的利益,这就是您创建动态尺寸2D数组的方式

// Declare like this
char **casestatematricia; // remember to initialize this to 0.

// Create the battlefield
void Map::battlespace(int column, int line) {

    columnnumber = column;
    linenumber = line;

    // Clear the previous battlefield.
    clearspace();

    // Creating the battlefield
    casestatematricia = new char*[column];
    for (int i = 0; i < column; ++i) {
        casestatematricia[i] = new char[line];
    }

    // initialise casestatematricia...
}

// Call this after you done using the battlefield
void Map::clearspace() {
    if (!casestatematricia) return;

    for(int i = 0; i < columnnumber; ++i) {
        delete [] casestatematricia[i];
    }

    delete [][] casestatematricia;
    casestatematricia = 0;
} 

Hope this help. 希望能有所帮助。

PS: If you need to serialize the string, you can to use pascal string format so that you can support string with variable length. PS:如果需要序列化字符串,则可以使用pascal字符串格式,以便支持可变长度的字符串。 eg "11hello world", or "3foo". 例如“ 11hello world”或“ 3foo”。

Replace: 更换:

char mapname[50];

with

char *mapname;

In constructor of your class allocate memory: 在类的构造函数中分配内存:

mapname = new char[50];

Then replace: 然后替换:

void Map::setmapname(char newmapname[50])
{
    this->mapname = newmapname;
}

with: 有:

void Map::setmapname(char *newmapname, size_t size)
{
    memcpy(mapname,newmapname,size);
}

EDIT: As pointed out in comments I forgot destructor: In destructor free the memory: 编辑:正如评论中指出的,我忘记了析构函数:在析构函数中释放内存:

if(mapname)
delete [] mapname;

As the user who posted this question he is new to classes so also to C++, that is why there are no containers and things like that in this answear. 作为发布此问题的用户,他是C ++类的新手,这就是为什么在此answear中没有容器之类的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM