C++を使ったセーブ・ロード

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
kloud

C++を使ったセーブ・ロード

#1

投稿記事 by kloud » 9年前

コード:

//*****************************//
//*                           *//
//*   メイン処理 [main.cpp]   *//
//*                           *//
//*****************************//

//**********************//
//*   ヘッダファイル   *//
//**********************//
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "player.h"

/******************/
/*   マクロ定義   */
/******************/
#define MIN_NUM ( 1 )               // 入力最小人数
#define MAX_NUM ( 3 )               // 入力最大人数

/************************/
/*   プロトタイプ宣言   */
/************************/
void Init ( void );                 // 初期化関数
void Uninit ( void );               // 終了関数
int Input ( void );                 // 入力関数
void Output ( int nNumPlayer );     // 出力関数
int Load ( int nNumPlayer );
int Save ( int nNumPlayer );
void SelectMode ( void );

//********************//
//*   構造体の定義   *//
//********************//
typedef enum
{
	MODE_FINISH = 0 ,     // 終了
	MODE_INPUT ,          // 入力
	MODE_OUTPUT ,         // 出力
	MODE_SAVE ,           // セーブ
	MODE_LOAD ,           // ロード
	MODE_MAX ,            // 最大数
}MODE;

//**********************//
//*   グローバル変数   *//
//**********************//
CPlayer g_aPlayer [ MAX_NUM ];

//******************//
//*   メイン処理   *//
//******************//
void main ( void )
{
	// 初期化処理
	Init ();

	// モード選択
	SelectMode ();

	// 終了処理
	Uninit();

    return;
}

void SelectMode ( void )
{
	int nNumPlayer = 0;
	MODE mode;
	memset ( g_aPlayer , 0 , sizeof ( g_aPlayer ) );

    do
   	{
   		// 番号入力
   		printf ( "\nMENU\n" );

   		printf ( "以下の番号から処理を選んでください\n" );

   		printf ( "1. 入力\n" );
   		printf ( "2. 出力\n" );
   		printf ( "3. セーブ\n" );
   		printf ( "4. ロード\n" );
   		printf ( "0. 終了\n" );
   		printf ( "> " );

   		scanf ( "%d" , &mode );

   		// 各番号の処理
   		switch ( mode )
   		{
   			// 終了処理
   			case MODE_FINISH:
   				   printf ( "プログラムを終了します\n" );

   				   break;

   			// 入力処理
   		    case MODE_INPUT:
   				   nNumPlayer = Input ();

   				   break;

   			// 出力処理
   			case MODE_OUTPUT:
   				   Output ( nNumPlayer );

   				   break;

   			// セーブ処理
   			case MODE_SAVE:
   				   Save ( nNumPlayer );

   				   break;

   			// ロード処理
   			case MODE_LOAD:
   				   Load ( nNumPlayer );

   				   break;

   		}
   	}while ( mode != MODE_FINISH );     // 終了処理が呼ばれるまでループ
}

//******************//
//*   初期化関数   *//
//******************//
void Init ( void )
{
	for ( int i = 0; i < MAX_NUM; i++ )
	{
		// プレイヤーの初期化処理
		g_aPlayer[i].Init();
	}
}

//****************//
//*   終了関数   *//
//****************//
void Uninit ( void )
{
	for ( int i = 0; i < MAX_NUM; i++ )
	{
		// プレイヤーの終了処理
		g_aPlayer[i].Uninit();
	}
}

//****************//
//*   入力関数   *//
//****************//
int Input ( void )
{
	int nCntPlayer = 0;          // 入力人数保存変数

	// 入力人数指定
	do
	{
	    printf ( "何人分のデータを入力しますか?(%d~%d人まで) > " , MIN_NUM , MAX_NUM );
	    scanf ( "%d" , &nCntPlayer );
	}while ( nCntPlayer < MIN_NUM | nCntPlayer > MAX_NUM );

	// 入力人数分ループ
	for ( int i = 0; i < nCntPlayer; i++ )
	{
		printf ( "\n~ %d人目のデータ ~\n" , i + 1 );

		// プレイヤー入力処理
		g_aPlayer[i].Input();
	}

	return nCntPlayer;
}

//****************//
//*   出力関数   *//
//****************//
void Output ( int nNumPlayer )
{
	if ( nNumPlayer != NULL )
	{
	   printf ( "\nデータを出力します\n" );

	   // 入力人数分ループ
	   for ( int i = 0; i < nNumPlayer; i++ )
	   {
	   	  printf ( "\n~ %d人目のデータ ~\n" , i + 1 );
	   
	   	  // プレイヤー出力処理
	   	  g_aPlayer[i].Output ();
	   }
	}
	else
	{
		printf ( "データがありません\n" );
	}
}

int Save ( int nNumPlayer )
{
    FILE* fp;
	int nData;

	if ( nNumPlayer < MIN_NUM | nNumPlayer > MAX_NUM )
	{
		printf ( "データがありません\n" );
		return 0;
	}
	else
	{
	    // ファイルを開く
	    fp = fopen ( "savedata.bin" , "wb" );
	    
	    fwrite ( &nNumPlayer , sizeof ( int ) , 1 , fp );
	    
	    for ( int i = 0; i < nNumPlayer; i++ )
	    {
	       nData = g_aPlayer[i].GetLife ();
	       fwrite ( &nData , 4 , 1 , fp );
	    
	       nData = g_aPlayer[i].GetAttack ();
	       fwrite ( &nData , 4 , 1 , fp );
	    
	       nData = g_aPlayer[i].GetSpeed ();
	       fwrite ( &nData , 4 , 1 , fp );
	    }
	    
	    // ファイルを閉じる
        fclose ( fp );
	    
	    printf ( "セーブしました\n" );
	    
	}

	return nNumPlayer;
}

int Load ( int nNumPlayer )
{
    FILE* fp;
	int nData;

	if ( nNumPlayer == NULL )
	{
		printf ( "データがありません\n" );
		return 0;
	}
	else
	{
	    // ファイルを開く
	    fp = fopen ( "savedata.bin", "rb" );
	    
	    fread ( &nNumPlayer , sizeof (int) , 1 , fp );
	    
	    for ( int i = 0; i < nNumPlayer; i++ )
	    {
	       fread ( &nData , 4 , 1 , fp );
	       g_aPlayer[i].SetLife ( nData );
	    
	       fread ( &nData , 4 , 1 , fp );
	       g_aPlayer[i].SetAttack ( nData );
	    
	       fread ( &nData , 4 , 1 , fp );
	       g_aPlayer[i].SetSpeed ( nData );
	    }
	    
	    // ファイルを閉じる
        fclose ( fp );

		printf ( "ロードしました\n" );
	}
	return nNumPlayer;
}
///////////////   EOF   ///////////////
[hr]
以下、player.hとplayer.cppです。

コード:

/********************/
/*   構造体の定義   */
/********************/
class CPlayer
{
public:
	   CPlayer ();              // コンストラクタ
	   ~CPlayer ();             // デストラクタ
	   void Init ();            // 初期化処理
	   void Uninit ();          // 終了処理
	   void Input ();           // 入力処理
	   void Output ();          // 出力処理
	   void SetLife ( int nLife );
	   int GetLife ( void );
	   void SetAttack ( int nLife );
	   int GetAttack ( void );
	   void SetSpeed ( int nLife );
	   int GetSpeed ( void );
private:
	   int m_nLife;             // プレイヤーのライフ
	   int m_nAttack;           // プレイヤーの攻撃力
	   int m_nSpeed;            // プレイヤーのスピード
};
//**********************//
//*   コンストラクタ   *//
//**********************//
CPlayer::CPlayer ()
{
	m_nLife = 0;
	m_nAttack = 0;
	m_nSpeed = 0;
}

//********************//
//*   デストラクタ   *//
//********************//
CPlayer::~CPlayer ()
{
}

//******************************//
//*   プレイヤーの初期化処理   *//
//******************************//
void CPlayer::Init ( void )
{
	m_nLife = 0;
	m_nAttack = 0;
	m_nSpeed = 0;
}

//****************************//
//*   プレイヤーの終了処理   *//
//****************************//
void CPlayer::Uninit ( void )
{
	m_nLife = 0;
	m_nAttack = 0;
	m_nSpeed = 0;
}

//****************************//
//*   プレイヤーの入力処理   *//
//****************************//
void CPlayer::Input ( void )
{
	printf ( "ライフは? > " );
	scanf ( "%d" , &m_nLife );

	printf ( "攻撃力は? > " );
	scanf ( "%d" , &m_nAttack );

	printf ( "スピードは? > " );
	scanf ( "%d" , &m_nSpeed );
}

//****************************//
//*   プレイヤーの出力処理   *//
//****************************//
void CPlayer::Output ()
{
	printf ( "ライフは%d\n" , m_nLife );
	printf ( "攻撃力は%d\n" , m_nAttack );
	printf ( "スピードは%d\n" , m_nSpeed );
}

void CPlayer::SetLife ( int nLife )
{
	m_nLife = nLife;
}

int CPlayer::GetLife ( void )
{
	return m_nLife;
}

void CPlayer::SetAttack ( int nAttack )
{
	m_nAttack = nAttack;
}

int CPlayer::GetAttack ( void )
{
	return m_nAttack;
}

void CPlayer::SetSpeed ( int nSpeed )
{
	m_nSpeed = nSpeed;
}

int CPlayer::GetSpeed ( void )
{
	return m_nSpeed;
}

///////////////   EOF   ///////////////

C++を勉強するために、以前に作ったセーブ・ロードができるメニューのようなもの(C言語のプログラム)を書き直してみました。
ところが、セーブしてからウィンドウを閉じ、再びプログラムを実行してロードするとデータが出力されませんでした。
SelectMode関数内で、nNumPlayer = 0としているところがダメだと思うのですが、どのように書き直せばよいか分かりません。
教えてください。お願いします。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: C++を使ったセーブ・ロード

#2

投稿記事 by みけCAT » 9年前

Load関数内でnNumPlayer == NULLとしているのがおかしいですね。
この条件分岐とLoad関数の引数はいらないので消して、nNumPlayerは普通のローカル変数にするといいでしょう。
また、fopenの戻り値がNULLでないかをチェックし、NULLならその後のファイル操作を行わないようにするべきでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

kloud

Re: C++を使ったセーブ・ロード

#3

投稿記事 by kloud » 9年前

コード:

//*****************************//
//*                           *//
//*   メイン処理 [main.cpp]   *//
//*                           *//
//*****************************//

//**********************//
//*   ヘッダファイル   *//
//**********************//
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "player.h"

/******************/
/*   マクロ定義   */
/******************/
#define MIN_NUM ( 1 )               // 入力最小人数
#define MAX_NUM ( 3 )               // 入力最大人数

/************************/
/*   プロトタイプ宣言   */
/************************/
void Init ( void );                 // 初期化関数
void Uninit ( void );               // 終了関数
int Input ( void );                 // 入力関数
void Output ( int nNumPlayer );     // 出力関数
int Load ();
int Save ( int nNumPlayer );
void SelectMode ( void );

//********************//
//*   構造体の定義   *//
//********************//
typedef enum
{
	MODE_FINISH = 0 ,     // 終了
	MODE_INPUT ,          // 入力
	MODE_OUTPUT ,         // 出力
	MODE_SAVE ,           // セーブ
	MODE_LOAD ,           // ロード
	MODE_MAX ,            // 最大数
}MODE;

//**********************//
//*   グローバル変数   *//
//**********************//
CPlayer g_aPlayer [ MAX_NUM ];

//******************//
//*   メイン処理   *//
//******************//
void main ( void )
{
	// 初期化処理
	Init ();

	// モード選択
	SelectMode ();

	// 終了処理
	Uninit ();

	// キー入力待ち
    rewind (stdin);
    getchar();

    return;
}

void SelectMode ( void )
{
	int nNumPlayer = 0;
	MODE mode;
	memset ( g_aPlayer , 0 , sizeof ( g_aPlayer ) );

    do
   	{
   		// 番号入力
   		printf ( "\nMENU\n" );

   		printf ( "以下の番号から処理を選んでください\n" );

   		printf ( "1. 入力\n" );
   		printf ( "2. 出力\n" );
   		printf ( "3. セーブ\n" );
   		printf ( "4. ロード\n" );
   		printf ( "0. 終了\n" );
   		printf ( "> " );

   		scanf ( "%d" , &mode );

   		// 各番号の処理
   		switch ( mode )
   		{
   			// 終了処理
   			case MODE_FINISH:
   				   printf ( "プログラムを終了します\n" );

   				   break;

   			// 入力処理
   		    case MODE_INPUT:
   				   nNumPlayer = Input ();

   				   break;

   			// 出力処理
   			case MODE_OUTPUT:
   				   Output ( nNumPlayer );

   				   break;

   			// セーブ処理
   			case MODE_SAVE:
   				   Save ( nNumPlayer );

   				   break;

   			// ロード処理
   			case MODE_LOAD:
   				   Load ();

   				   break;

   		}
   	}while ( mode != MODE_FINISH );     // 終了処理が呼ばれるまでループ
}

//******************//
//*   初期化関数   *//
//******************//
void Init ( void )
{
	for ( int i = 0; i < MAX_NUM; i++ )
	{
		// プレイヤーの初期化処理
		g_aPlayer[i].Init();
	}
}

//****************//
//*   終了関数   *//
//****************//
void Uninit ( void )
{
	for ( int i = 0; i < MAX_NUM; i++ )
	{
		// プレイヤーの終了処理
		g_aPlayer[i].Uninit();
	}
}

//****************//
//*   入力関数   *//
//****************//
int Input ( void )
{
	int nCntPlayer = 0;          // 入力人数保存変数

	// 入力人数指定
	do
	{
	    printf ( "何人分のデータを入力しますか?(%d~%d人まで) > " , MIN_NUM , MAX_NUM );
	    scanf ( "%d" , &nCntPlayer );
	}while ( nCntPlayer < MIN_NUM | nCntPlayer > MAX_NUM );

	// 入力人数分ループ
	for ( int i = 0; i < nCntPlayer; i++ )
	{
		printf ( "\n~ %d人目のデータ ~\n" , i + 1 );

		// プレイヤー入力処理
		g_aPlayer[i].Input();
	}

	return nCntPlayer;
}

//****************//
//*   出力関数   *//
//****************//
void Output ( int nNumPlayer )
{
	if ( nNumPlayer != 0 )
	{
	   printf ( "\nデータを出力します\n" );

	   // 入力人数分ループ
	   for ( int i = 0; i < nNumPlayer; i++ )
	   {
	   	  printf ( "\n~ %d人目のデータ ~\n" , i + 1 );
	   
	   	  // プレイヤー出力処理
	   	  g_aPlayer[i].Output ();
	   }
	}
	else
	{
		printf ( "データがありません\n" );
	}
}

int Save ( int nNumPlayer )
{
    FILE* fp;
	int nData;

	if ( nNumPlayer < MIN_NUM | nNumPlayer > MAX_NUM )
	{
		printf ( "データがありません\n" );
		return 0;
	}
	else
	{
	    // ファイルを開く
	    fp = fopen ( "savedata.bin" , "wb" );
	    
		if ( fp == NULL )
		{
			printf ( "FILE OPEN ERROR\n" );
			return 0;
		}
		else
		{
	        fwrite ( &nNumPlayer , sizeof ( int ) , 1 , fp );
	        
	        for ( int i = 0; i < nNumPlayer; i++ )
	        {
	           nData = g_aPlayer[i].GetLife ();
	           fwrite ( &nData , 4 , 1 , fp );
	        
	           nData = g_aPlayer[i].GetAttack ();
	           fwrite ( &nData , 4 , 1 , fp );
	        
	           nData = g_aPlayer[i].GetSpeed ();
	           fwrite ( &nData , 4 , 1 , fp );
	        }
	        
	        // ファイルを閉じる
            fclose ( fp );
	        
	        printf ( "セーブしました\n" );
		}
	}

	return nNumPlayer;
}

int Load ()
{
	int nNumPlayer;
	int nData;
	FILE* fp;
	
	// ファイルを開く
	fp = fopen ( "savedata.bin", "rb" );

	if ( fp == NULL )
	{
		printf ( "FILE OPEN ERROR\n" );
		return 0;
	}
	else
	{
	    fread ( &nNumPlayer , sizeof (int) , 1 , fp );
	       
	    for ( int i = 0; i < nNumPlayer; i++ )
	    {
	       fread ( &nData , 4 , 1 , fp );
	       g_aPlayer[i].SetLife ( nData );
	       
	       fread ( &nData , 4 , 1 , fp );
	       g_aPlayer[i].SetAttack ( nData );
	       
	       fread ( &nData , 4 , 1 , fp );
	       g_aPlayer[i].SetSpeed ( nData );
	    }
	       
	    // ファイルを閉じる
        fclose ( fp );
	    printf ( "ロードしました\n" );
	}
	    return nNumPlayer;
}
///////////////   EOF   ///////////////
ご指摘ありがとうございます。
しかし、まだウィンドウを閉じてからのロードでデータが出力できませんでした。
また、データが入ってない状態で出力すると、1人分のデータがすべて0でが出力されてしまいました。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: C++を使ったセーブ・ロード

#4

投稿記事 by みけCAT » 9年前

Load関数の戻り値を捨てているのがまずいですね。
Inputの時と同様に、SelectMode関数のnNumPlayerを更新するようにしてください。
オフトピック
ところで、C++ではグローバル名前空間でvoid main()を定義することはできないので、main.hはこんな感じですか?

コード:

#ifndef MAIN_H_GUARD_B7DC894F_2990_4793_9985_997AA1C86794
#define MAIN_H_GUARD_B7DC894F_2990_4793_9985_997AA1C86794

void mein();
int main() {
	mein();
	return 0;
}
#define main mein

#endif
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

kloud

Re: C++を使ったセーブ・ロード

#5

投稿記事 by kloud » 9年前

コード:

//*****************************//
//*                           *//
//*   メイン処理 [main.cpp]   *//
//*                           *//
//*****************************//

//**********************//
//*   ヘッダファイル   *//
//**********************//
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "player.h"

/******************/
/*   マクロ定義   */
/******************/
#define MIN_NUM ( 1 )               // 入力最小人数
#define MAX_NUM ( 3 )               // 入力最大人数

/************************/
/*   プロトタイプ宣言   */
/************************/
void Init ( void );                 // 初期化関数
void Uninit ( void );               // 終了関数
int Input ( void );                 // 入力関数
void Output ( int nNumPlayer );     // 出力関数
int Load ();
int Save ( int nNumPlayer );
void SelectMode ( void );

//********************//
//*   構造体の定義   *//
//********************//
typedef enum
{
	MODE_FINISH = 0 ,     // 終了
	MODE_INPUT ,          // 入力
	MODE_OUTPUT ,         // 出力
	MODE_SAVE ,           // セーブ
	MODE_LOAD ,           // ロード
	MODE_MAX ,            // 最大数
}MODE;

//**********************//
//*   グローバル変数   *//
//**********************//
CPlayer g_aPlayer [ MAX_NUM ];

//******************//
//*   メイン処理   *//
//******************//
void main ( void )
{
	// 初期化処理
	Init ();

	// モード選択
	SelectMode ();

	// 終了処理
	Uninit ();

	// キー入力待ち
    rewind (stdin);
    getchar();

    return;
}

void SelectMode ( void )
{
	int nNumPlayer = 0;
	MODE mode;
	memset ( g_aPlayer , 0 , sizeof ( g_aPlayer ) );

    do
   	{
   		// 番号入力
   		printf ( "\nMENU\n" );

   		printf ( "以下の番号から処理を選んでください\n" );

   		printf ( "1. 入力\n" );
   		printf ( "2. 出力\n" );
   		printf ( "3. セーブ\n" );
   		printf ( "4. ロード\n" );
   		printf ( "0. 終了\n" );
   		printf ( "> " );

   		scanf ( "%d" , &mode );

   		// 各番号の処理
   		switch ( mode )
   		{
   			// 終了処理
   			case MODE_FINISH:
   				   printf ( "プログラムを終了します\n" );

   				   break;

   			// 入力処理
   		    case MODE_INPUT:
   				   nNumPlayer = Input ();

   				   break;

   			// 出力処理
   			case MODE_OUTPUT:
   				   Output ( nNumPlayer );

   				   break;

   			// セーブ処理
   			case MODE_SAVE:
   				   Save ( nNumPlayer );

   				   break;

   			// ロード処理
   			case MODE_LOAD:
   				   nNumPlayer = Load ();

   				   break;

   		}
   	}while ( mode != MODE_FINISH );     // 終了処理が呼ばれるまでループ
}

//******************//
//*   初期化関数   *//
//******************//
void Init ( void )
{
	for ( int i = 0; i < MAX_NUM; i++ )
	{
		// プレイヤーの初期化処理
		g_aPlayer[i].Init();
	}
}

//****************//
//*   終了関数   *//
//****************//
void Uninit ( void )
{
	for ( int i = 0; i < MAX_NUM; i++ )
	{
		// プレイヤーの終了処理
		g_aPlayer[i].Uninit();
	}
}

//****************//
//*   入力関数   *//
//****************//
int Input ( void )
{
	int nCntPlayer = 0;          // 入力人数保存変数

	// 入力人数指定
	do
	{
	    printf ( "何人分のデータを入力しますか?(%d~%d人まで) > " , MIN_NUM , MAX_NUM );
	    scanf ( "%d" , &nCntPlayer );
	}while ( nCntPlayer < MIN_NUM | nCntPlayer > MAX_NUM );

	// 入力人数分ループ
	for ( int i = 0; i < nCntPlayer; i++ )
	{
		printf ( "\n~ %d人目のデータ ~\n" , i + 1 );

		// プレイヤー入力処理
		g_aPlayer[i].Input();
	}

	return nCntPlayer;
}

//****************//
//*   出力関数   *//
//****************//
void Output ( int nNumPlayer )
{
	// 人数が0でなかったら
	if ( nNumPlayer != 0 )
	{
	   printf ( "\nデータを出力します\n" );

	   // 入力人数分ループ
	   for ( int i = 0; i < nNumPlayer; i++ )
	   {
	   	  printf ( "\n~ %d人目のデータ ~\n" , i + 1 );
	   
	   	  // プレイヤー出力処理
	   	  g_aPlayer[i].Output ();
	   }
	}
	// 人数が0なら
	else
	{
		printf ( "データがありません\n" );
	}
}

//******************//
//*   セーブ関数   *//
//******************//
int Save ( int nNumPlayer )
{
    FILE* fp;
	int nData;

	// 入力人数が範囲外なら
	if ( nNumPlayer < MIN_NUM | nNumPlayer > MAX_NUM )
	{
		printf ( "データがありません\n" );
		return 0;
	}
	else
	{
	    // ファイルを開く
	    fp = fopen ( "savedata.bin" , "wb" );
	    
		// ファイルが開けなかったら
		if ( fp == NULL )
		{
			printf ( "FILE OPEN ERROR\n" );
			return 0;
		}
		else
		{
			// ファイルへ書き込み
	        fwrite ( &nNumPlayer , sizeof ( int ) , 1 , fp );
	        
	        for ( int i = 0; i < nNumPlayer; i++ )
	        {
				// プレイヤーのライフ保持
	            nData = g_aPlayer[i].GetLife ();
	            fwrite ( &nData , 4 , 1 , fp );
	            
				// プレイヤーの攻撃力保持
	            nData = g_aPlayer[i].GetAttack ();
	            fwrite ( &nData , 4 , 1 , fp );
	            
				// プレイヤーのスピード保持
	            nData = g_aPlayer[i].GetSpeed ();
	            fwrite ( &nData , 4 , 1 , fp );
	        }
	        
	        // ファイルを閉じる
            fclose ( fp );
	        
	        printf ( "セーブしました\n" );
		}
	}

	return nNumPlayer;
}

//******************//
//*   ロード関数   *//
//******************//
int Load ()
{
	int nNumPlayer;
	int nData;
	FILE* fp;
	
	// ファイルを開く
	fp = fopen ( "savedata.bin", "rb" );

	// ファイルを開けなかったら
	if ( fp == NULL )
	{
		printf ( "FILE OPEN ERROR\n" );
		return 0;
	}
	else
	{
		// 人数読み込み
	    fread ( &nNumPlayer , sizeof (int) , 1 , fp );

		// 人数が0でないなら
	    if ( nNumPlayer != NULL )
	    {
	        for ( int i = 0; i < nNumPlayer; i++ )
	        {
				// プレイヤーのライフ取得
	            fread ( &nData , 4 , 1 , fp );
	            g_aPlayer[i].SetLife ( nData );
	            
				// プレイヤーの攻撃力取得
	            fread ( &nData , 4 , 1 , fp );
	            g_aPlayer[i].SetAttack ( nData );
	            
				// プレイヤーのスピード取得
	            fread ( &nData , 4 , 1 , fp );
	            g_aPlayer[i].SetSpeed ( nData );
	        }
	          
	        // ファイルを閉じる
            fclose ( fp );
	        
	        printf ( "ロードしました\n" );
	    }
		// 人数が0だったら
	    else
	    {
		    printf ( "データがありません\n" );
        }
	}

	return nNumPlayer;
}
///////////////   EOF   ///////////////
Loadの戻り値をnNumPlayerに入れて実行したところ、ちゃんとロードができるようになりました。
main.hはみけCATさんが書かれたものとほとんど同じです。

かずま

Re: C++を使ったセーブ・ロード

#6

投稿記事 by かずま » 9年前

コード:

    if ( nNumPlayer < MIN_NUM | nNumPlayer > MAX_NUM )
| ではなく || を使いましょう。

コード:

        if ( nNumPlayer != NULL )
NULL ではなく 0 を使いましょう。

コード:

        if (nNumPlayer >= MIN_NUM && nNumPlayer <= MAX_NUM)
のほうがもっといいでしょう。

fread や fwrite は、連続するメモリ領域の読み書きができるので、
for 文を使って、int のサイズのデータの読み書きをする必要はありません。
fread は、正しく読み込めたかどうかチェックしたほうがいいでしょう。

コード:

int Save(int nNumPlayer)
{
    FILE* fp;
 
    if (nNumPlayer < MIN_NUM || nNumPlayer > MAX_NUM) {
        printf("データがありません\n");
        return 0;
    }
	fp = fopen("savedata.bin", "wb");
	if (fp == NULL) {
		printf("FILE OPEN ERROR\n");
		return 0;
	}
	fwrite(&nNumPlayer, sizeof(int), 1, fp);
	fwrite(g_aPlayer, sizeof(CPlayer), nNumPlayer, fp);
	fclose(fp);
	printf("セーブしました\n");
	return nNumPlayer;
}

int Load()
{
	int nNumPlayer;
	FILE* fp = fopen("savedata.bin", "rb");
	if (fp == NULL) {
		printf("FILE OPEN ERROR\n");
		return 0;
	}
	if (fread(&nNumPlayer, sizeof(int), 1, fp) == 1
	  && nNumPlayer >= MIN_NUM && nNumPlayer <= MAX_NUM
	  && fread(g_aPlayer, sizeof(CPlayer), nNumPlayer, fp) == nNumPlayer) {
		printf("ロードしました\n");
	}
	else {
		printf("データがありません\n");
		nNumPlayer = 0;
	}
	fclose(fp);
	return nNumPlayer;
}

kloud

Re: C++を使ったセーブ・ロード

#7

投稿記事 by kloud » 9年前

コード:

//*****************************//
//*                           *//
//*   メイン処理 [main.cpp]   *//
//*                           *//
//*****************************//

//**********************//
//*   ヘッダファイル   *//
//**********************//
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "player.h"

/******************/
/*   マクロ定義   */
/******************/
#define MIN_NUM ( 1 )               // 入力最小人数
#define MAX_NUM ( 3 )               // 入力最大人数

/************************/
/*   プロトタイプ宣言   */
/************************/
void Init ( void );                 // 初期化関数
void Uninit ( void );               // 終了関数
int Input ( void );                 // 入力関数
void Output ( int nNumPlayer );     // 出力関数
int Load ();
int Save ( int nNumPlayer );
void SelectMode ( void );

//********************//
//*   構造体の定義   *//
//********************//
typedef enum
{
	MODE_FINISH = 0 ,     // 終了
	MODE_INPUT ,          // 入力
	MODE_OUTPUT ,         // 出力
	MODE_SAVE ,           // セーブ
	MODE_LOAD ,           // ロード
	MODE_MAX ,            // 最大数
}MODE;

//**********************//
//*   グローバル変数   *//
//**********************//
CPlayer g_aPlayer [ MAX_NUM ];

//******************//
//*   メイン処理   *//
//******************//
void main ( void )
{
	// 初期化処理
	Init ();

	// モード選択
	SelectMode ();

	// 終了処理
	Uninit ();

	// キー入力待ち
    rewind (stdin);
    getchar();

    return;
}

void SelectMode ( void )
{
	int nNumPlayer = 0;
	MODE mode;
	memset ( g_aPlayer , 0 , sizeof ( g_aPlayer ) );

    do
   	{
   		// 番号入力
   		printf ( "\nMENU\n" );

   		printf ( "以下の番号から処理を選んでください\n" );

   		printf ( "1. 入力\n" );
   		printf ( "2. 出力\n" );
   		printf ( "3. セーブ\n" );
   		printf ( "4. ロード\n" );
   		printf ( "0. 終了\n" );
   		printf ( "> " );

   		scanf ( "%d" , &mode );

   		// 各番号の処理
   		switch ( mode )
   		{
   			// 終了処理
   			case MODE_FINISH:
   				   printf ( "プログラムを終了します\n" );

   				   break;

   			// 入力処理
   		    case MODE_INPUT:
   				   nNumPlayer = Input ();

   				   break;

   			// 出力処理
   			case MODE_OUTPUT:
   				   Output ( nNumPlayer );

   				   break;

   			// セーブ処理
   			case MODE_SAVE:
   				   Save ( nNumPlayer );

   				   break;

   			// ロード処理
   			case MODE_LOAD:
   				   nNumPlayer = Load ();

   				   break;

   		}
   	}while ( mode != MODE_FINISH );     // 終了処理が呼ばれるまでループ
}

//******************//
//*   初期化関数   *//
//******************//
void Init ( void )
{
	for ( int i = 0; i < MAX_NUM; i++ )
	{
		// プレイヤーの初期化処理
		g_aPlayer[i].Init();
	}
}

//****************//
//*   終了関数   *//
//****************//
void Uninit ( void )
{
	for ( int i = 0; i < MAX_NUM; i++ )
	{
		// プレイヤーの終了処理
		g_aPlayer[i].Uninit();
	}
}

//****************//
//*   入力関数   *//
//****************//
int Input ( void )
{
	int nCntPlayer = 0;          // 入力人数保存変数

	// 入力人数指定
	do
	{
	    printf ( "何人分のデータを入力しますか?(%d~%d人まで) > " , MIN_NUM , MAX_NUM );
	    scanf ( "%d" , &nCntPlayer );
	}while ( nCntPlayer < MIN_NUM | nCntPlayer > MAX_NUM );

	// 入力人数分ループ
	for ( int i = 0; i < nCntPlayer; i++ )
	{
		printf ( "\n~ %d人目のデータ ~\n" , i + 1 );

		// プレイヤー入力処理
		g_aPlayer[i].Input();
	}

	return nCntPlayer;
}

//****************//
//*   出力関数   *//
//****************//
void Output ( int nNumPlayer )
{
	// 人数が0でなかったら
	if ( nNumPlayer != 0 )
	{
	   printf ( "\nデータを出力します\n" );

	   // 入力人数分ループ
	   for ( int i = 0; i < nNumPlayer; i++ )
	   {
	   	  printf ( "\n~ %d人目のデータ ~\n" , i + 1 );
	   
	   	  // プレイヤー出力処理
	   	  g_aPlayer[i].Output ();
	   }
	}
	// 人数が0なら
	else
	{
		printf ( "データがありません\n" );
	}
}

//******************//
//*   セーブ関数   *//
//******************//
int Save ( int nNumPlayer )
{
    FILE* fp;
	int nData;

	// 入力人数が範囲外なら
	if ( nNumPlayer < MIN_NUM || nNumPlayer > MAX_NUM )
	{
		printf ( "データがありません\n" );
		return 0;
	}
	else
	{
	    // ファイルを開く
	    fp = fopen ( "savedata.bin" , "wb" );
	    
		// ファイルが開けなかったら
		if ( fp == NULL )
		{
			printf ( "FILE OPEN ERROR\n" );
			return 0;
		}
		else
		{
			// ファイルへ書き込み
	        fwrite ( &nNumPlayer , sizeof ( int ) , 1 , fp );
	        
	        for ( int i = 0; i < nNumPlayer; i++ )
	        {
				// プレイヤーのライフ保持
	            nData = g_aPlayer[i].GetLife ();
	            fwrite ( &nData , 4 , 1 , fp );
	            
				// プレイヤーの攻撃力保持
	            nData = g_aPlayer[i].GetAttack ();
	            fwrite ( &nData , 4 , 1 , fp );
	            
				// プレイヤーのスピード保持
	            nData = g_aPlayer[i].GetSpeed ();
	            fwrite ( &nData , 4 , 1 , fp );
	        }
	        
	        printf ( "セーブしました\n" );
		}
	}

	// ファイルを閉じる
    fclose ( fp );

	return nNumPlayer;
}

//******************//
//*   ロード関数   *//
//******************//
int Load ()
{
	int nNumPlayer;
	int nData;
	FILE* fp;
	
	// ファイルを開く
	fp = fopen ( "savedata.bin", "rb" );

	// ファイルを開けなかったら
	if ( fp == NULL )
	{
		printf ( "FILE OPEN ERROR\n" );
		return 0;
	}
	else
	{
		// 人数読み込み
	    fread ( &nNumPlayer , sizeof (int) , 1 , fp );

		// 人数が0でないなら
	    if ( nNumPlayer >= MIN_NUM && nNumPlayer <= MAX_NUM )
	    {
	        for ( int i = 0; i < nNumPlayer; i++ )
	        {
				// プレイヤーのライフ取得
	            fread ( &nData , 4 , 1 , fp );
	            g_aPlayer[i].SetLife ( nData );
	            
				// プレイヤーの攻撃力取得
	            fread ( &nData , 4 , 1 , fp );
	            g_aPlayer[i].SetAttack ( nData );
	            
				// プレイヤーのスピード取得
	            fread ( &nData , 4 , 1 , fp );
	            g_aPlayer[i].SetSpeed ( nData );
	        }
	        
	        printf ( "ロードしました\n" );
	    }
		// 人数が0だったら
	    else
	    {
		    printf ( "データがありません\n" );
        }
	}

	// ファイルを閉じる
    fclose ( fp );

	return nNumPlayer;
}
///////////////   EOF   ///////////////
かずまさん、ご指摘ありがとうございます。
if文の条件式に関するところは改善しました。
しかし、for文で回さなくてもできるというところは、今回こちらの都合上実装しませんでしたが、大変勉強になりました。
ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る