動的な配列の確保について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
wasawasa
記事: 94
登録日時: 11年前

動的な配列の確保について

#1

投稿記事 by wasawasa » 11年前

こんにちは、いつもお世話になっています。

特定フォルダ内のpngファイルを検索して検索したファイル名を[ファイル数][ファイル名文字数(256と設定。後からポインタによる確保に変更予定)]という形で動的に確保するchar型のFileName配列に取得する、という構想のプログラムを下記のように記述したところ57行目でFileName[0]に対してアクセス違反が発生してしまいました。FileName配列の確保方法を動的なものにする前はアクセス違反もエラーも無かったので24~25行目か51~56行目が原因だと思うのですが、デバッガを使って変数を覗いてみてもどこがおかしいのか判断できません。(FileName自体に格納されるのは配列へのハンドルだから覗いても意味ない?)

恐らく記憶領域の確保の方法が間違えているのだと思うのですが、一体どうすれば正常に領域を確保できるのでしょうか?
1次元配列にすれば管理が楽だという事は承知ですが、このプログラムは一応ポインタの扱いの練習としての意味合いがそれなりにあるのでFileNameを2次元配列という形で扱うという方針でお願いします。(多分1次元の管理すらできていないのだと思われますが)

コード:

#include "DxLib.h"
#include <windows.h>
#include <tchar.h>
#include <math.h>

#define MAXPATH 256

void hoge()
{
	//フォルダ絶対パス検索用
	int i,j;
	int length;									//プロジェクト実行ファイルパスサイズ
	char *X;									//[\]から[/]へ書き換え用
	char delpath[] = "Debug\\DXlib_test.exe";	//消す文字列(サイズ測定用)
	char picfol[] = "Data\\Pics\\TileA\\";		//目的フォルダ相対パス
	char path[MAXPATH]={0};						//プロジェクトフォルダパス格納用
	char picpath[MAXPATH]={0};					//picフォルダ絶対パス格納用
	//ファイル検索用
	WIN32_FIND_DATA fFind;
	HANDLE hSearch;
	char FindPath[MAXPATH] = {0};
	char FindPng[] = "*.png";//pngファイル検索用
	//画像名格納用
	char **FileName;
	char **FileName2;
	int FileAmount;
	//画像ハンドル格納用
	char LoadPath[MAXPATH]={0};
	int hpicture[100];

	//picフォルダパス検出
	length = GetModuleFileName(NULL, path, MAXPATH);
	for(i=length-strlen(delpath); i<length; i++){
		path[i] = '\0';
	}
	strcat(picpath,path);
	strcat(picpath,picfol);
	//ファイル検索
	
	strcat(FindPath,picpath);
	strcat(FindPath,FindPng);
	hSearch=FindFirstFile(FindPath,&fFind); // 探索開始 
	//1個目が見つからない場合
	if (hSearch==INVALID_HANDLE_VALUE) {// 見つからなければ探索終了 
          FindClose(hSearch);
          return;
	}
	//1個目が見つかった場合
	else{
		i=1;
		FileName2=(char**)malloc(sizeof(char*)*i);
		for(j=0;j<i;j++){
			FileName2[j]=(char*)malloc(sizeof(char*)*MAXPATH);
		}
		FileName=FileName2;
		free(FileName2);
		strcpy(FileName[0],fFind.cFileName);
		//残りを検索
		while (FindNextFile(hSearch,&fFind)) { /* 全ファイルを処理 */
			i++;
			FileName2=(char**)malloc(sizeof(char*)*i);
			for(j=0;j<i;j++){
				FileName2[j]=(char*)malloc(sizeof(char*)*MAXPATH);
			}
			for(j=0;j<i-1;j++){
				strcpy(FileName2[j],FileName[j]);
			}
			FileName=FileName2;
			free(FileName2);
			strcpy(FileName[i],fFind.cFileName);
		}
		FileAmount=i;
	}
	FindClose(hSearch);

	for(i=0;i<FileAmount;i++){
		strcpy(LoadPath,picpath);
		strcat(LoadPath,FileName[i]);
		while(1){
			X = strchr(LoadPath,'\\');
			if(X != NULL){
				*X = '/';
			}
			else{break;}
		}
		hpicture[i]=LoadGraph(LoadPath);
	}

	for(i=0;i<100;i++){
		//DrawStringToHandle( 0, i*10, FileName[i], GetColor( 0, 255, 0 ),CreateFontToHandle( "メイリオ",10,  1, DX_FONTTYPE_ANTIALIASING_EDGE ) ); // 文字を描画する
		DrawGraph( i*20 , i*20 , hpicture[i] , FALSE ) ;
	}
	ScreenFlip();
	WaitKey() ;
}

int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int){
        ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen( DX_SCREEN_BACK ); //ウィンドウモード変更と初期化と裏画面設定


		hoge();
        /*while( ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0 ){
        }*/

        DxLib_End();    // DXライブラリ終了処理
        return 0;
}

旅路のきのこ

Re: 動的な配列の確保について

#2

投稿記事 by 旅路のきのこ » 11年前

こんにちは!
FileName[0]にアクセスできないのは、その直前でfreeしてしまっているからのような気がしました。
あと、FileName2[j]で確保したメモリは解放されないかもしれません。

wasawasa
記事: 94
登録日時: 11年前

Re: 動的な配列の確保について

#3

投稿記事 by wasawasa » 11年前

返信ありがとうございます。

FileName2でメモリを確保してFileName=FileName2と書くと、FileName2に格納されたハンドルがFileNameに渡される上にFileName2で確保した分と同じサイズのメモリをFileNameに確保する、と思っていたのでFileName2のメモリを開放しなければリークしてしまうと思いfree(FileName2)と書いたのですが、FileName=FileName2とやった場合FileNameにはハンドルが渡されるだけなのでしょうか?

かずま

Re: 動的な配列の確保について

#4

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

wasawasa さんが書きました: FileName2でメモリを確保してFileName=FileName2と書くと、FileName2に格納されたハンドルがFileNameに渡される上にFileName2で確保した分と同じサイズのメモリをFileNameに確保する、と思っていたのでFileName2のメモリを開放しなければリークしてしまうと思いfree(FileName2)と書いたのですが、FileName=FileName2とやった場合FileNameにはハンドルが渡されるだけなのでしょうか?
ハンドルというか、ポインタですね。

間違っているのは次のところ。
56行目の free(FileName2); は不要。
68行目の FileName = FileNmae2; の前に free(FileName); を挿入。
69行目の free(FileName2); は不要。
70行目の FileName は FileName[i-1];
53行目と 63行目の sizeof(char*)*MAXPATH は、sizeof(char)*MAXPATH。
45行目の FineClose(hSearch); は不要。
89行目の 100 は、FileAmount。

私なら次のように書くでしょう。

コード:

#include "DxLib.h"
#include <windows.h>
 
#define DELPATH "Debug\\DXlib_test.exe"
#define PICFOL  "Data\\Pics\\TileA\\"
#define FINDPNG "*.png"
 
void hoge()
{
    int i;
    char picpath[MAX_PATH];
    WIN32_FIND_DATA fFind;
    HANDLE hSearch;
    char FindPath[MAX_PATH];
    char **FileName = NULL;
    char **FileName2 = NULL;
    int FileAmount = 0;
    int capa = 0;
    char LoadPath[MAX_PATH];
    int *hpicture;
 
    i = GetModuleFileName(NULL, picpath, MAX_PATH) - strlen(DELPATH);
    picpath[i] = '\0';
    strcpy(picpath + i, PICFOL);
    strcpy(FindPath, picpath);
    strcat(FindPath, FINDPNG);

    hSearch = FindFirstFile(FindPath, &fFind);
    if (hSearch == INVALID_HANDLE_VALUE) return;

    FileAmount = 0;
    do {
        if (FileAmount >= capa) {
            capa = capa ? capa * 2 : 1;
            FileName2 = (char **)malloc(sizeof(char *) * capa);
            for (i = 0; i < FileAmount; i++) FileName2[i] = FileName[i];
            free(FileName);
            FileName = FileName2;
        }
        FileName[FileAmount++] = strdup(fFind.cFileName);
    } while (FindNextFile(hSearch, &fFind));
    FindClose(hSearch);

    for (i = 0; i < FileAmount; i++) {
        strcpy(LoadPath, picpath);
        strcat(LoadPath, FileName[i]);
        hpicture[i] = LoadGraph(LoadPath);
    }
    hpicture = malloc(sizeof(int) * FileAmount);
    for (i = 0; i < FileAmount; i++)
        DrawGraph(i*20, i*20, hpicture[i], FALSE);
    for (i = 0; i < FileAmount; i++)
        DeleteGraph(hpicture[i]) ;
    for (i = 0; i < FileAmount; i++)
        free(FileName[i]);
    free(FileName);
    free(hpicture);

    ScreenFlip();
    WaitKey() ;
}

かずま

Re: 動的な配列の確保について

#5

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

かずま さんが書きました:
wasawasa さんが書きました: 私なら次のように書くでしょう。
訂正です。
49行目の hpicture = malloc(sizeof(int) * FileAmount); は、
44行目の前に移動。

かずま

Re: 動的な配列の確保について

#6

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

かずま さんが書きました:私なら次のように書くでしょう。
35~37行目の 3行は、
FileName2 = realloc(sizeof(char *) * capa); と
1行で書けます。
本当は、FileName2 が NULL かどうかチェックしたほうがよいでしょう。

かずま

Re: 動的な配列の確保について

#7

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

かずま さんが書きました:35~37行目の 3行は、
FileName2 = realloc(sizeof(char *) * capa); と
1行で書けます。
訂正します。
FileName2 = realloc(FileName, sizeof(char *) * capa); と
1行で書けます。

旅路のきのこ

Re: 動的な配列の確保について

#8

投稿記事 by 旅路のきのこ » 11年前

mallocはメモリを確保して、その先頭のアドレスを返すんだと思っています。
ということは、FileName=FileName2としたとき、それはメモリのアドレスを代入することになるので、free(FileName)とfree(FileName2)は同じことを意味しますし、確保したメモリも解放してしまいます。

僕なら不真面目にvector <char *>でも使ってしまいたくなりますが、真面目にやるならかずまさんのように書けばいいと思います。
それでは!

wasawasa
記事: 94
登録日時: 11年前

Re: 動的な配列の確保について

#9

投稿記事 by wasawasa » 11年前

返信ありがとうございます。

なるほど、free()はポインタの先にあるメモリを開放する関数なんですね。そしてポインタだけを廃棄したい場合はNULLを使う、と。
この部分を念頭に置きつつ、かずまさんの提示して頂いたコードを参考にしながら記述してみたら上手くいきました。ありがとうございます。

閉鎖

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