2012-02-01 1 views
0

私は奇妙な問題を抱えています。私はC++で簡単なゲームを書こうとしていますが、オブジェクトやデータ型には失敗しました。コードがあります:メソッドパラメータのメモリエラー(アクセス違反)

// C++ 
// Statki 

#include <stdio.h> 
#include <time.h> 
#include <map> 
#include <vector> 
#include <string> 
#include <list> 

#define D true 

using namespace std; 

void _(char* message){printf("%s\n",message);}; 

struct relpoint { int x,y; }; 
struct point { int x,y; }; 
struct size { int w,h; }; 

map<const char*, vector<relpoint> > shipshape; 
list<char*> shipTypes = {"XS", "S", "M", "L", "XL"}; 

string alpha="ABCDEFGHIJKLMNOPRSTUVWXYZ"; 

enum fieldtype { UNKNOWN=-1,EMPTY=0,SHIP=1,HIT=2,MISS=3,}; 

enum rotation { EAST=0, SOUTH=1, WEST=2, NORTH=3 }; 

class Ship 
{ 
    char* type; 

}; 

class Sea 
{ 
    public: 
    void init(size mapsize) { init(mapsize, EMPTY); }; 
    void init(size mapsize, fieldtype fill) 
    { 
     if(D)printf("Generating sea\n"); 
     vector<fieldtype> v; 

     seamap.reserve(mapsize.h); 
     v.reserve(mapsize.w); 

     for (int y=0; y<mapsize.h; y++) 
     { 
      v.clear(); 
      for(int x=0; x<mapsize.w; x++) 
      { 
       v.push_back(fill); 
      } 
      seamap.push_back(v); 
     } 

     view(); 
    }; 

    bool place_ship(Ship ship); 

    void view() 
    { 
     for(vector< vector<fieldtype> >::const_iterator yy = seamap.begin(); yy != seamap.end(); ++yy) 
     { 
      for(vector<fieldtype>::const_iterator xx = (*yy).begin(); xx != (*yy).end(); ++xx) 
      { 
       if(D)printf("%d ", *xx); 
      } 
      if(D)printf("\n"); 
     } 
    }; 

    private: 
    vector< vector<fieldtype> > seamap; 
}; 

class Game 
{ 
    public: 

    void initmap(size mapsize) 
    { 
     if(D) printf("\nInit %d×%d map\n", mapsize.w, mapsize.h); 

     (*enemymap).init(mapsize, UNKNOWN); 
     //(*selfmap).init(mapsize); 
    }; 

    bool placeship(string type, point position, rotation rotate); 
    fieldtype shoot(point target); 
    void viewmap(){(*selfmap).view();}; 

    bool eog(); 

    Sea * enemymap; 
    Sea * selfmap; 
}; 

class Bot 
{ 
    public: 

    void init(size mapsize) 
    { 
     if(D)_("Init Bot"); 
    } 

    private: 

    Game * g; 
}; 

class Player 
{ 

    public: 
    Player() { if(D){_("Player fake init");} }; 

    void init(size mapsize) 
    { 
     (*g).initmap(mapsize); 
    }; 

    void viewmap(){(*g).viewmap();}; 

    private: 
    Game * g; 

}; 

class Router 
{ 

    public: 

    void startgame(); 
    void welcomescreen() 
    { 
     printf("\n\n\n\t\t\tShips minigame\n\t\t\t\tby Kris\n\n"); 

     mainmenu(); 
    }; 
    void mainmenu() 
    { 
     printf("Menu (type letter):\n\tN: New game\n\tS: Settings\n\tQ: Quit game\n\n > "); 

     char opt; 
     opt = toupper(getchar()); 

     size ms; 

     switch(opt) 
     { 
      case 'N': 
       ms = getmapsize(); 
       (*P1).init(ms); 
       (*P2).init(ms); 
      break; 

      case 'S': 

      break; 

      case 'Q': 

      break; 

      default: 
       printf("Invalid option %c", opt); 
       mainmenu(); 
     } 
    }; 

    private: 
    Player * P1; 
    Bot * P2; 

    size getmapsize() 
    { 
     size ms; 
     printf("\nSet map size (X Y)\n > "); 
     scanf("%d %d", &ms.w, &ms.h); 
     return ms; 
    }; 
}; 

int main() { 

    vector<relpoint> shp; 
    shp.reserve(5); 
    list<char*>::const_iterator tp = shipTypes.begin(); 
    shp.push_back({0,0}); 
    shipshape[*(tp++)] = shp; 
    shp.push_back({1,0}); 
    shipshape[*(tp++)] = shp; 
    shp.push_back({2,0}); 
    shipshape[*(tp++)] = shp; 
    shp.push_back({3,0}); 
    shipshape[*(tp++)] = shp; 
    shp.push_back({2,1}); 
    shipshape[*tp] = shp; 

    Router R; 
    R.welcomescreen(); 

    printf("\n\n"); 
    return 0; 
} 

それはコンパイルすることができますが、行の後のInit 5×5のマッププログラムはNaruszenieのochronyのpamięci(ポーランドメモリアクセス違反)エラーで停止します。問題は、Sea::init()の両方の機能で発生するようです。

私はUbuntuでg++ -std=c++0x -Wno-write-strings ships2.cpp(警告を防ぐために)をコンパイルしています。

何が問題なのですか?

+0

「enemymap」はその時点で何と思いますか?あなたは宣言は 'Sea'ポインタのようですが、' Sea'をインスタンス化せず、 –

+0

と指定します。また、より慣習的な '' P1-> init(ms) ''の代わりに '(* P1).init(ms)'と言う理由は何ですか? – cvoinescu

答えて

0

初期化されていないポインタを使用しています。ここでオブジェクトをインスタンス化するか、コンストラクタ内で別の場所にインスタンス化して修正できます。

ここでは、initmap呼び出しでインスタンス化する例を示します。

void initmap(size mapsize) 
{ 
    // Initialize the pointer by instantiating a class 
    enemymap = new Sea; 
    if(D) printf("\nInit %d×%d map\n", mapsize.w, mapsize.h); 

    (*enemymap).init(mapsize, UNKNOWN); 
    //(*selfmap).init(mapsize); 
}; 
+0

ありがとうございます - それは動作します。 C++の前に、私はPHPだけを書いていました - まったく違う哲学です。 – Arrvi

2

すべてのクラスにはポインタが含まれていますが、ポインターを初期化したり、ポインターに割り当てるオブジェクトのスペースを割り当てているようなことはありません。 enemymapはどこも指していない場合、この

(*enemymap).init(mapsize, UNKNOWN); 

を行う

は、アクセス違反を取得するには、ほぼ確実な方法です。

+0

コードを調べると、これはすべてのクラスに当てはまります。 –

+0

はいコードにも同様の問題がいくつかあります。 '* enemymap'は実行が停止した場所ですので、修正することから始めなければなりません。 –

+0

'Router'クラスは、現在クラッシュしている場所に*取得するために' Player'と同じことをしているので、(愚かな、未定義の運ではなく)それがどのようにそこにあったのでしょうか? –

0

+1 Bo。しかし、あなた自身のために:

は、-gでコンパイルし、その後

gdb ./mygame.bin 
type 'run' 

after setting the map size 5 5 : 

Program received signal SIGSEGV, Segmentation fault. 
mainmenu (this=<optimized out>) at memacvio.cpp:158 
158     (*P1).init(ms); 

これは、P1はおそらく有効でpoinerではないことを教えなければなりません。