ページ 11

変数のスコープについて?

Posted: 2014年3月11日(火) 23:54
by たかお
 こんばんは。いつもお世話になっております。

 C+DXライブラリでRPGを製作しています。現在、メニューウィンドウを実装しているところなのですが
不可解な現象が起きましたので質問させていただきました。

 以下のコードの case ITEM: 以降が今回悩んでいる部分です。(このプログラムはsoftyaさんのRPG講座を参考にしています)

コード:

GameSceneMain GameMenu(){

	char* menu[] = {"アイテム","スペル","システム",NULL};
	
	enum MenuScene{MENU,ITEM};
	enum{ITEM_MENU,SPELL_MENU,SYSTEM_MENU};

	static int start = FALSE;
	static int No = 0;
	static MenuScene menuScene;

	if(start == FALSE){
		//基本選択メニュー
		No = Window_OpenWindow(170,20,450,300,MENU_STATUS);

		No = Window_OpenWindow(20,20,140,180,MENU_SELECT);
		Window_SetString(No,menu);
		
		//キャラクターステータス
		
		start = TRUE;
	}

	//所持アイテムの取得
	int pItemId[PLAYER_ITEM_MAX] = {NULL};
	char* pItemName[PLAYER_ITEM_MAX+1] = {NULL};
	char* pItemDesc[PLAYER_ITEM_MAX+1] = {NULL};

	int status[10] = {NULL};
	int equip[PLAYER_EQUIP_MAX] = {NULL};
	char* equipName[PLAYER_EQUIP_MAX+1] = {NULL};
	//キャラステータスの取得
	Chara_GetPlayerStatus(status);
	//キャラの装備品を取得
	Chara_GetPlayerEquip(equip);	//装備品のIDを取得
	Item_GetItem(equip,equipName,PLAYER_EQUIP_MAX,NAME);				//IDからアイテム名を取得
	//キャラステータスの更新
	Window_SetString(No-1,equipName);
	

	switch(menuScene){
	case MENU:
		
		switch(Window_Selecting(Window_GetActWinNo(),key)){
		case ITEM_MENU:
				Window_OpenWindow(270,410,355,50,MENU_LIST);
				Window_OpenWindow(270,140,355,270,MENU_ITEM);
				menuScene = ITEM;
			break;

		case SPELL_MENU:
			break;

		case SYSTEM_MENU:
			break;
		}
		
		//最初のメニューでキャンセルボタンを押すと、メニューを抜ける
		if(key[KEY_INPUT_C] == 1){
			Window_DelAllWindow();
			start = FALSE;
			gameSceneMain = SCENE_MAIN_GAME;
		}
		break;



	case ITEM:

		//キャラクターの所持品を取得
		Chara_GetPlayerItem(pItemId);

		//取得したIDのアイテム名を取得
		Item_GetItem(pItemId,pItemName,2,NAME);

		//アイテム名をウィンドウにセット
		Window_SetString(2,pItemName);
		Window_Test();
		if(key[KEY_INPUT_C] == 1){
		Window_DelWindow(Window_GetActWinNo());
			Window_DelWindow(Window_GetActWinNo());
			menuScene = MENU; 
		}

		DrawFormatString(0,380,white,"%s",pItemName[0]);
		DrawFormatString(0,400,white,"%x",pItemName[1]);
		DrawFormatString(0,420,white,"%d",pItemId[2]);
		break;

	}
	DrawFormatString(0,440,white,"%x",pItemName[1]);
	Window_Test();
	Window_DrawWindow(status);
	Window_DrawInfo();
	Game_DrawInfo("MENU");
	return SCENE_MAIN_MENU;
}

void Game_DrawInfo(char* scene){
	DrawFormatString(540,0,white,scene);
}

Window_SetString関数とWindow_Test関数

コード:

//指定ウィンドウに描画する文字列を設定
void Window_SetString(int No,char** list){
	if(winMng.win[No].flag == TRUE){

		winMng.win[No].komoku = list;
		winMng.win[No].komokuSu = 0;
		for(int i=0; winMng.win[No].komoku[i] != NULL; i++){
			winMng.win[No].komokuSu++;
		}
	}
}

void Window_Test(){
	if(winMng.win[2].flag == TRUE){
		DrawFormatString(0,300,white,"%s",winMng.win[2].komoku[1]);

	}
}
 int配列のpItemIdにプレイヤーIDを代入する→取得したIDのアイテム名をpItemNameに代入する→取得したアイテム名をWindow_SetStringでウィンドウ構造体(別のモジュールにある)のもつ、char** komoku に代入する→char** komoku の文字列を描画する。ということをやろうと考えています。
 しかし、char** komokuを参照しようとすると、エラーが発生するため、DrawFormatStringでpItemNameを描画して、値が代入されているか確認しました。
その結果、switch文の内外で期待通りの値が表示され、文字列が正常に代入されていることがわかりました。
ところが、switch内外でWindow_Testを実行し、char** komokuを参照してみたところ、switch内では参照できるのに、switch外では
参照できませんでした。

 何故このような現象が起きるのでしょうか。教えていただきたいです。

Re: 変数のスコープについて?

Posted: 2014年3月12日(水) 07:41
by たかお
自己解決しました。が、最後にもう一つ質問があります。解決内容は以下の通りです。
ウィンドウの生成は、Window_OpenWindow関数でウィンドウのフレームを設定→WIndow_SetString関数でそのウィンドウに文字列を設定→Window_DrawWIndow関数で画面に描画 という流れなのですが
描画関数はswitchの外にあるため、switchのcase MENU で生成したウィンドウに設定する文字列を case ITEM で設定する前に呼び出されるのが原因でした。
つまり文字列を設定する前に、文字列を呼び出してしまっていたのでエラーになるようです。

質問なんですが、switch文のcase内でローカルな変数を宣言する場合

コード:

switch(test){
case 0:
{
int x = 0;
}
break;
}
このように、{ }で囲む必要がありますが、これは多用しても構わないのでしょうか?
何らかの理由で推奨されないやり方ということはないでしょうか?

Re: 変数のスコープについて?

Posted: 2014年3月12日(水) 09:53
by softya(ソフト屋)
> このように、{ }で囲む必要がありますが、これは多用しても構わないのでしょうか?

どうしても必要ならやりますが、余りやることはないと思います。
理由はコードが長くなる可能性が高いので、更に別関数に分ける可能性が高いです。

Re: 変数のスコープについて?

Posted: 2014年3月12日(水) 10:07
by たかお。
なるほど。やる意味はあまりなさそうですね。回答ありがとうございました!