2016-08-03 8 views
1

クラスを使用することで新しく、配列をクラスに分類する際に問題が発生しました。私は50文字に制限されたテキストのchar配列を初期化し、その文字列を関数に置き換えたい。私はそのC++クラス内で配列を宣言し、クラス内で2次元配列を宣言する

casestatematricia[linenumber][columnnumber] 
のように列番号と行番号を入力する場所私はこの後の2次元配列を動的にしたいという

char casestatematricia[][]; 

のように私の2次元配列を初期化することができところで

#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 

戦場を作る。

これは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() 
{ 

} 

ありがとうございます。

+5

文字列を含む 'char'配列を置き換える' std :: string'を見てください。また、生のコンテナを使用する代わりに 'std :: vector'、' std :: list'、 'std :: map'、...(つまり標準コンテナ)を見てください。 – Garf365

+0

@ Garf365私はchar [50]を使用しません。なぜなら、このデータはあとでシリアル化されなければならないため、固定重量を持たなければなりません。 –

+1

私はシリアル化しなければならないデータを持っていて、 'std :: string'でポーランドムはありません。あなたは何人かのセッターを持っているので、サイズの条件を追加するだけです。 – Garf365

答えて

-3

置き換えます

mapname = new char[50]; 

次に置き換えます:

char mapname[50]; 

クラスのコンストラクタで

char *mapname; 

でメモリが割り当て

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

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

EDIT:

if(mapname) 
delete [] mapname; 

彼はクラスに新しいです、この質問を投稿したユーザーとして:メモリを解放するデストラクタで : としては、デストラクタを忘れてしまった私のコメントで指摘C++にも同様に、このようなコンテナやそのようなものは存在しません。

+0

あなたは 'delete'でメモリの割り当てを解除するのを忘れてしまいます。リークメモリの結果になります。スマートポインタの使用について考えてみてください – Garf365

+0

ありがとうございました:3あなたが私に言ったことをもう少し詳しく説明して、理解しながらこれを使うことができますか? –

+0

explique en francais sinon xD –

4

これについて一般的なプラクティスを実行することを検討してください。 ほとんどの(例:数値の)ライブラリは、クラス内で2D配列を使用しません。 これらは、動的に割り当てられた1D配列を使用し、()または[]演算子をオーバーロードして、2D要素のような方法で正しい要素にアクセスします。 外部では、連続したストレージを実際に処理しているとは決して言えませんが、2D配列のように見えます。 このようにして、配列のサイズ変更が容易になり、格納、転置、変形がより効率的になります。あなたの問題のためだけの命題

2

:2次元配列のような1次元配列へのアクセスについては

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]; 
      } 
     } 
    } 
}; 

は、Access a 1D array as a 2D array in C++を見てみましょう。

シリアライゼーションについて考えると、ファイルに保存したいと思うでしょう。ちょうど助言:あなたのソフトを再起動するときに "保存"するだけのファイルに生のメモリを保存しないでください。あなたはポータブルではないソリューションを持っています!そして真剣に、あなたのコンピュータの力で、あなたはファイルからロードする時間を心配する必要はありません!

私は、ファイルの中に地図を保存するために、あなたのクラスの2つの方法を追加することを提案

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; 
     } 
    } 
} 

このソリューションは、単に例のために与えられています。彼らはエラーを管理していませんし、ASCII形式でファイルに保存することを選択しました。バイナリ形式で保存するように変更できますが、RAWメモリの直接書き込みは使用しないでください。 C - serialization techniquesを見ることができます(ちょうどC++に翻訳する必要があります)。でも、memcpyやそれに類するものをシリアル化することはしないでください。

+0

thx私はそういうことをしようとしている、私は既にシリアライゼーションを行っているので、それは必要ないだろう。3 –

-1

私はこの権利を得ることを望みます。あなたには2つの質問があります。 char mapname[50];の値をvoid setmapname(char newmapname[50]);で割り当てる方法を知りたいとします。また、動的なサイズの2D配列を作成する方法を知りたいとします。

どちらの場合でもポインタが必要なので、あなたはポインタに慣れていればいいと思う。

最初の質問については、まずvoid setmapname(char newmapname[50]);の理解を修正したいと思います。 C++関数は配列に取り込まれません。配列へのポインタを受け取ります。それで、void setmapname(char *newmapname);と書くのと同じくらい良いです。理解を深めるには、Passing Arrays to Function in C++

これで、新しいマップ名の長さで読み込むように関数を変更します。 mapnameを割り当てるには、ループを使ってそれぞれのcharをコピーしてください。 2番目の質問については

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]; 
    } 
} 

、あなたが使用する必要がありますが、私はただのポインタを使用することを好むと私は2D戦場を表現するために1次元配列を使用しますGarf365によって提案されたもののように、ベクターを使用することができます。 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; 
} 

ちょうどあなたがそれを使用しなくなったときにclearspace()を呼び出さないようにしてください。

ちょうどあなたの利益のために、これはあなたが希望このヘルプダイナミックなサイズ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; 
} 

を作成する方法です。

PS:文字列をシリアル化する必要がある場合は、可変長の文字列をサポートできるように、パスカル文字列形式を使用できます。例えば"11hello world"、または "3foo"。

+0

いくつかの批判(私は肯定的だと思う):(1) 'setmapname'には、 (std :: copy'、 'std :: memcpy'や' std :: strncpy')=>常にホームメイドの代わりに標準関数を使用する;); (2)所有権やメモリリークのリスクのようないくつかの問題を抱えている生のポインタの使用を避け、スマートポインタを使用する(C++ 11以降、またはブーストで)。 (3)メモリを管理する代わりにコンテナを使用する。=>一般的には、一人だけでコードを書くのではなく、多くの人が開発し、見直した標準を使用することを好む。 – Garf365

+0

例えば 'std :: vector'は手作業で何をするか=>連続したメモリを割り当て、割り当てを解除してアクセスを管理する('ベクトル 'の' at'メソッドを使うと、範囲外の値を与えると例外が発生する(realloc)のようなものがあります...しかし、それは効率的ですが、これを達成するために多くの人々が一丸となって取り組んできました。 – Garf365

+0

@ Garf365、私はあなたに同意します。コードをメンテナンス可能にすることは、私たちのプログラマに行く方法です。しかし、私はOPがまだ学習者であるC++を学んでいるという印象を受けています。だから、私の答えを構造化する方法は、あなたが基本的な理解を正しく理解し、図書館なしでそれを行う方法を知っていることを期待することです。それがどのように行われているか知った後。その後、すべての手段を使って、どんなリソースを使用しても、それは問題ではありません。 – TrBBoI

関連する問題