C++での動的メモリ確保

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

C++での動的メモリ確保

#1

投稿記事 by kloud » 9年前

以前のセーブ・ロードプログラムに、動的メモリ確保の処理をいれてみたのですが、ロードからの出力ができなくなってしまいました。
何が原因なのでしょうか?
教えてください。お願いします。

コード:

//****************************//
//*   インクルードファイル   *//
//****************************//
#include "player.h"
#include "data.h"
#include <stdio.h>

//**********************//
//*   コンストラクタ   *//
//**********************//
CData::CData ()
{
	m_pPlayer = NULL;
	m_nNumPlayer = 0;
}

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

//********************//
//*   選択処理関数   *//
//********************//
void CData::SelectMode ( void )
{
	MODE mode;

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

   		printf ( "\n" );

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

   				   break;

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

   				   break;

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

   				   break;

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

   				   break;

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

   				   break;

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

//******************//
//*   初期化関数   *//
//******************//
void CData::Init ( void )
{
	// メモリ解放
	if ( m_pPlayer != NULL )
	{
		delete[] m_pPlayer;
		m_pPlayer = NULL;
	}
}

//****************//
//*   終了関数   *//
//****************//
void CData::Uninit ( void )
{
	// メモリ解放
	if ( m_pPlayer != NULL )
	{
		// 人数分終了処理
		for ( int i = 0; i < m_nNumPlayer; i++ )
		{
			m_pPlayer[i].Uninit();
		}
		delete[] m_pPlayer;
		m_pPlayer = NULL;
	}
}

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

	// メモリ解放
	if ( m_pPlayer != NULL )
	{
		delete[] m_pPlayer;
		m_pPlayer = NULL;
	}

	// 動的メモリ確保
	m_pPlayer = new CPlayer [m_nNumPlayer];

	// 人数分初期化
	for ( int i = 0; i < m_nNumPlayer; i++ )
	{
		m_pPlayer[i].Init();
	}

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

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

//****************//
//*   出力関数   *//
//****************//
void CData::Output ( void )
{
	if ( m_nNumPlayer == 0 )
	{
	    printf ( "データがありません\n" );
	}

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

		// プレイヤー出力処理
		m_pPlayer[i].Output ();
	}
}

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

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

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

	// ファイルを開けなかったら
	if ( fp == NULL )
	{
		printf ( "FILE OPEN ERROR\n" );
		return;
	}
	else
	{
		// 人数読み込み
	    fread ( &m_nNumPlayer , sizeof (int) , 1 , fp );
		
		// メモリ解放
		if ( m_pPlayer != NULL )
	    {
		   delete[] m_pPlayer;
		   m_pPlayer = NULL;
	    }
		
		// 動的メモリ確保
	    m_pPlayer = new CPlayer [m_nNumPlayer];
		
		// 人数分初期化
	    for ( int i = 0; i < m_nNumPlayer; i++ )
 	    {
		   m_pPlayer[i].Init();
	    }
		
		// 人数が0でないなら
	    if ( m_nNumPlayer >= MIN_NUM && m_nNumPlayer <= MAX_NUM )
	    {
	        for ( int i = 0; i < m_nNumPlayer; i++ )
	        {
				// プレイヤーのライフ取得
	            fread ( &nData , 4 , 1 , fp );
	            m_pPlayer[i].SetLife ( nData );
	            
				// プレイヤーの攻撃力取得
	            fread ( &nData , 4 , 1 , fp );
	            m_pPlayer[i].SetAttack ( nData );
	            
				// プレイヤーのスピード取得
	            fread ( &nData , 4 , 1 , fp );
	            m_pPlayer[i].SetSpeed ( nData );
	        }
	        
	        printf ( "ロードしました\n" );

			// ファイルを閉じる
            fclose ( fp );
	    }
		// 人数が0だったら
	    else
	    {
		    printf ( "データがありません\n" );
        }
	}
}

///////////////   EOF   ///////////////
[hr]
/*****************************/
/*                           */
/*   データヘッダ [data.h]   */
/*                           */
/*****************************/
#ifndef _DATA_H_
#define _DATA_H_

#define MIN_NUM ( 1 )
#define MAX_NUM ( 3 )

/********************/
/*   構造体の定義   */
/********************/
class CPlayer;

class CData
{
public:
	   typedef enum
       {
       	  MODE_FINISH = 0 ,           // 終了
       	  MODE_INPUT ,                // 入力
       	  MODE_OUTPUT ,               // 出力
       	  MODE_SAVE ,                 // セーブ
       	  MODE_LOAD ,                 // ロード
       	  MODE_MAX ,                  // 最大数
       }MODE;
	   CData ();                      // コンストラクタ
	   ~CData ();                     // デストラクタ
	   void Init ( void );            // 初期化処理
	   void Uninit ( void );          // 終了処理
	   void SelectMode ( void );
private:
	   void Input ( void );            // 入力処理
	   void Output ( void );          // 出力処理
	   void Save ( void );            // セーブ処理
	   void Load ( void );            // ロード処理
	   CPlayer* m_pPlayer;
	   int m_nNumPlayer;              // プレイヤーの数
};

#endif

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


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

Re: C++での動的メモリ確保

#2

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

kloud さんが書きました:以前のセーブ・ロードプログラムに、動的メモリ確保の処理をいれてみたのですが、ロードからの出力ができなくなってしまいました。
適当な条件で実験してみましたが、再現できませんでした。
どのような条件でテストをしたか教えていただけますか?

player.h

コード:

#ifndef PLAYER_H_GUARD_034FBEB4_F212_4A4D_9D66_65B937F8E76B
#define PLAYER_H_GUARD_034FBEB4_F212_4A4D_9D66_65B937F8E76B

#include <cstdio>

struct CPlayer {
	int life, attack, speed;

	void Init(){}
	void Uninit(){}
	void SetLife(int i) { life = i; }
	void SetAttack(int i) { attack = i; }
	void SetSpeed(int i) { speed = i; }
	int GetLife() { return life; }
	int GetAttack() { return attack; }
	int GetSpeed() { return speed; }
	void Output() const {
		printf("%d %d %d\n", life, attack, speed);
	}
	void Input() {
		if (scanf("%d%d%d", &life, &attack, &speed) != 3) {
			puts("入力エラー");
			life = attack = speed = -1;
		}
	}
};

#endif
main.cpp

コード:

#include "data.h"

int main(void) {
	CData d;
	d.SelectMode();
	d.Uninit();
	return 0;
}
実行結果

コード:

YUKI.N>g++ --version
g++ (GCC) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


YUKI.N>g++ -g3 -static -o main main.cpp data.cpp

YUKI.N>main

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 1

何人分のデータを入力しますか?(1~3人まで) > 3

~ 1人目のデータ ~
100 200 300

~ 2人目のデータ ~
10 20 30

~ 3人目のデータ ~
1 2 3

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 2


~ 1人目のデータ ~
100 200 300

~ 2人目のデータ ~
10 20 30

~ 3人目のデータ ~
1 2 3

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 3

セーブしました

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 4

ロードしました

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 2


~ 1人目のデータ ~
100 200 300

~ 2人目のデータ ~
10 20 30

~ 3人目のデータ ~
1 2 3

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 0

プログラムを終了します

YUKI.N>main

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 2

データがありません

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 4

ロードしました

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 2


~ 1人目のデータ ~
100 200 300

~ 2人目のデータ ~
10 20 30

~ 3人目のデータ ~
1 2 3

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 0

プログラムを終了します

YUKI.N>main

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 4

ロードしました

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 2


~ 1人目のデータ ~
100 200 300

~ 2人目のデータ ~
10 20 30

~ 3人目のデータ ~
1 2 3

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 1

何人分のデータを入力しますか?(1~3人まで) > 1

~ 1人目のデータ ~
123 456 789

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 2


~ 1人目のデータ ~
123 456 789

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 3

セーブしました

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 0

プログラムを終了します

YUKI.N>main

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 4

ロードしました

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 2


~ 1人目のデータ ~
123 456 789

MENU
以下の番号から処理を選んでください
1. 入力
2. 出力
3. セーブ
4. ロード
0. 終了
> 0

プログラムを終了します

YUKI.N>
また、出力されたファイルの内容にも異常は見られませんでした。
使用した環境はWindows 7 SP1 x64です。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

kloud

Re: C++での動的メモリ確保

#3

投稿記事 by kloud » 9年前

再度、プログラム全体を見直してみたところ、SetLife,SetAttack,SetSpeed関数の引数と処理がおかしかったみたいです。
その処理を直したら成功しました。
みけCATさん、お手数をかけました。

コード:

//****************************//
//*   インクルードファイル   *//
//****************************//
#include "player.h"
#include "data.h"
#include <stdio.h>

//**********************//
//*   コンストラクタ   *//
//**********************//
CData::CData ()
{
	m_pPlayer = NULL;
	m_nNumPlayer = 0;
}

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

//********************//
//*   選択処理関数   *//
//********************//
void CData::SelectMode ( void )
{
	MODE mode;

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

   		printf ( "\n" );

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

   				   break;

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

   				   break;

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

   				   break;

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

   				   break;

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

   				   break;

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

//******************//
//*   初期化関数   *//
//******************//
void CData::Init ( void )
{
	// メモリ解放
	if ( m_pPlayer != NULL )
	{
		delete[] m_pPlayer;
		m_pPlayer = NULL;
	}
}

//****************//
//*   終了関数   *//
//****************//
void CData::Uninit ( void )
{
	// メモリ解放
	if ( m_pPlayer != NULL )
	{
		// 人数分終了処理
		for ( int i = 0; i < m_nNumPlayer; i++ )
		{
			m_pPlayer[i].Uninit();
		}
		delete[] m_pPlayer;
		m_pPlayer = NULL;
	}
}

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

	// メモリ解放
	if ( m_pPlayer != NULL )
	{
		delete[] m_pPlayer;
		m_pPlayer = NULL;
	}

	// 動的メモリ確保
	m_pPlayer = new CPlayer [m_nNumPlayer];

	// 人数分初期化
	for ( int i = 0; i < m_nNumPlayer; i++ )
	{
		m_pPlayer[i].Init();
	}

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

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

//****************//
//*   出力関数   *//
//****************//
void CData::Output ( void )
{
	if ( m_nNumPlayer == 0 )
	{
	    printf ( "データがありません\n" );
	}

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

		// プレイヤー出力処理
		m_pPlayer[i].Output ();
	}
}

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

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

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

	// ファイルを開けなかったら
	if ( fp == NULL )
	{
		printf ( "FILE OPEN ERROR\n" );
		//return;
	}
	else
	{
		// 人数読み込み
	    fread ( &m_nNumPlayer , sizeof (int) , 1 , fp );
		
		// メモリ解放
		if ( m_pPlayer != NULL )
	    {
		   delete[] m_pPlayer;
		   m_pPlayer = NULL;
	    }
		
		// 動的メモリ確保
	    m_pPlayer = new CPlayer [m_nNumPlayer];
		
		// 人数分初期化
	    for ( int i = 0; i < m_nNumPlayer; i++ )
 	    {
		   m_pPlayer[i].Init();
	    }
		
		// 人数が0でないなら
	    if ( m_nNumPlayer >= MIN_NUM && m_nNumPlayer <= MAX_NUM )
	    {
	        for ( int i = 0; i < m_nNumPlayer; i++ )
	        {
				// プレイヤーのライフ取得
	            fread ( &nData , 4 , 1 , fp );
	            m_pPlayer[i].SetLife ( nData );
	            
				// プレイヤーの攻撃力取得
	            fread ( &nData , 4 , 1 , fp );
	            m_pPlayer[i].SetAttack ( nData );
	            
				// プレイヤーのスピード取得
	            fread ( &nData , 4 , 1 , fp );
	            m_pPlayer[i].SetSpeed ( nData );
	        }
	        
	        printf ( "ロードしました\n" );

			// ファイルを閉じる
            fclose ( fp );
	    }
		// 人数が0だったら
	    else
	    {
		    printf ( "データがありません\n" );
        }
	}
}

///////////////   EOF   ///////////////
[hr]

コード:

//*****************************************//
//*                                       *//
//*   プレイヤーメイン処理 [player.cpp]   *//
//*                                       *//
//*****************************************//

//*****************************//
//*   インクルードファイル   *//
//****************************//
#include <stdio.h>
#include "main.h"
#include "player.h"
#include "data.h"

//**********************//
//*   コンストラクタ   *//
//**********************//
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言語何でも質問掲示板” へ戻る