ページ 11

メモリーを解放する方法

Posted: 2014年3月16日(日) 09:38
by たかお
こんにちは。
現在わたしはC+DXライブラリとVisual Studio Express 2012でRPGを製作しています。
配列の要素数を動的に変更したいと考え、malloc関数を使っているのですが、確保したアドレスを解放するときにエラーがでます。

コード:

GameScene GameTest(){

	int items[2] = {3,4};
	int itemSu   = 2;
	char** itemName = (char**)malloc((sizeof (char)) * (itemSu+1));
	Item_GetItemName(items,itemSu,itemName);
	

	//Chara_DrawInfo(items);

	if(itemSu > 0){
		free(items);
		free(itemName);
	}
	
	return GAME_TEST;
}

コード:

void Item_GetItemName(int id[],int kazu,char* itemName[]){
	//kazu分だけchar型配列を生成

	for(int i=0; i<kazu; i++){
		itemName[i] = item_box[id[i]].name;
	}
	itemName[kazu] = NULL;
}

dbgheap.c
ここで「ブレークポイントが発生した」というエラーがでる。

コード:

extern "C" _CRTIMP int __cdecl _CrtIsValidHeapPointer(
        const void * pUserData
        )
{
        if (!pUserData)
            return FALSE;

        if (!_CrtIsValidPointer(pHdr(pUserData), sizeof(_CrtMemBlockHeader), FALSE))
            return FALSE;

        return HeapValidate( _crtheap, 0, pHdr(pUserData) );
}
何が問題なのでしょうか?教えていただきたいです。

Re: メモリーを解放する方法

Posted: 2014年3月16日(日) 09:47
by softya(ソフト屋)
配列化されたポインタの解放ですので、ちゃんとmallocした数だけforループで回しながら解放しないとダメですね。
あとitemsはmallocしていないのでfreeしないでください。
free( itemName ); ← 先にこちらを解放
free( itemName ); ← こちらは後で。

Re: メモリーを解放する方法

Posted: 2014年3月16日(日) 10:33
by box
たかお さんが書きました:

コード:

	char** itemName = (char**)malloc((sizeof (char)) * (itemSu+1));
私が知っている限りにおいて、
malloc()の戻り値を
char **
にキャストするのであれば、
malloc()の引数の型は
char *
つまり、キャストしたい型よりも「1段だけ」低いレベル
でなければならないと思うのですが、いかがでしょうか。
よって、私が知っている限りにおいて、上のコードは

コード:

    char** itemName = (char**)malloc((sizeof (char*)) * (itemSu+1));
または

コード:

    char* itemName = (char*)malloc((sizeof (char)) * (itemSu+1));
のどちらかになるような気がします。いかがでしょうか。

Re: メモリーを解放する方法

Posted: 2014年3月16日(日) 10:45
by たかお
softyaさん、boxさん回答ありがとうございます!

最終的に itemName[itemSu + 1] = {"アイテム名1","アイテム名2",NULL}; このような形にしたいので、

コード:

char** itemName = (char**)malloc((sizeof (char*)) * (itemSu+1));
こちらの書き方にするべきですね。ありがとうございました。

しかし、mallocした数だけ解放しなければならない。ということは理解したのですが、疑問が生まれました。
私は、http://d.hatena.ne.jp/tondol/20090713/1247426321 のサイトを参考にしているのですが、
このサイトの「各行のデータを保持する配列を連続した領域で確保」では、配列を生成しているにも関わらず
一度だけしかメモリを解放していません。他のやり方と何が違うのでしょうか。

Re: メモリーを解放する方法

Posted: 2014年3月16日(日) 10:50
by みけCAT
softya(ソフト屋) さんが書きました:配列化されたポインタの解放ですので、ちゃんとmallocした数だけforループで回しながら解放しないとダメですね。
あとitemsはmallocしていないのでfreeしないでください。
free( itemName ); ← 先にこちらを解放
free( itemName ); ← こちらは後で。

今回のコードでは、itemNameをfreeする必要はないと思いますが、違いますでしょうか?

item_box.nameをfreeする必要があるのでしたら、そのように書かないと、
二重にfreeしたり、freeする必要があるものをfreeしなかったりする事故の原因になると思います。

Re: メモリーを解放する方法

Posted: 2014年3月16日(日) 11:06
by softya(ソフト屋)
失礼しました。
char**から早とちりしてchar*もmallocしていると思い込んだようです。
やりたいことからすると必要そうではありますが、現在は行われていない様ですね。
ということで必要な文字列の長さを確保してのmallocも必要です。

Re: メモリーを解放する方法

Posted: 2014年3月16日(日) 11:20
by たかお
先ほど指摘された書き方

コード:

char** itemName = (char**)malloc((sizeof (char*)) * (itemSu+1));
にしたところ、期待通りの結果がでました。

みなさん回答ありがとうございました。

Re: メモリーを解放する方法

Posted: 2014年3月16日(日) 13:30
by softya(ソフト屋)
あれ? 文字列のポインタをコピーしているだけでしたか。
それなら、free( itemName ); だけでOKです。
忙しい合間に書き込むとダメですね。すいません。