ファイル読み書きについて

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

ファイル読み書きについて

#1

投稿記事 by kloud » 9年前

コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct 
{
	char aName[256];     // 名前
	int nAge;            // 年齢
	float fHeight;       // 身長
	float fWeight;       // 体重
}PersonalData;

int Input ( PersonalData* pData );
void Output ( PersonalData* pData , int );
void Save ( PersonalData* pData , int );
void Load ( PersonalData* pData , int );

#define MinCount(1)
#define MaxCount (3)

void main ( void )
{
	PersonalData aData[3];
	int nNumHuman;

#if 1
	// データ入力
	nNumHuman = Input ( &aData[0] );

	// データセーブ
	Save ( &aData[0] , nNumHuman );

#else
	// データロード
	Load ( &aData[0] , nNumHuman );

	// データ出力
	Output ( &aData[0] , nNumHuman );

#endif

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

	return;
}

int Input ( PersonalData* pData )
{	
	int Name_Count;

	for ( int InputNum = 1; InputNum < 4; InputNum++ )
	{
		printf ( "%d人目のデータ \n" , InputNum );

		printf ( "姓(全角5文字以内) > " );                               
		scanf ( "%s" , &pData -> aName[0] );

		Name_Count = strlen ( &pData -> aName[0] );     

		printf ( "名(全角5文字以内) > " );                               
		scanf ( "%s" , &pData -> aName[Name_Count] );

		printf ( "年齢(半角2ケタ) > " );                                
		scanf ( "%d" , &pData -> nAge );

		printf ( "身長(cm) (半角数字・少数第1位まで) > " );              
		scanf ( "%f" , &pData -> fHeight );

		printf ( "体重(kg) (半角数字・少数第1位まで) > " );              
		scanf ( "%f" , &pData -> fWeight );

		pData++;
	}
	return 0;
}

////////////////////
//                //
//   セーブ関数    //
//                //
////////////////////
void Save ( PersonalData* pData , int nNumHuman )
{
	FILE* fp;

	fp = fopen ( "savedata.bin", "wb" );

	if ( fp == NULL )
	{
		printf ( "FILE OPEN ERROR\n" );
	}

	if ( pData != NULL )
	{
		while ( 1 )
		{
			fwrite ( &nNumHuman , sizeof ( int ) , 1 , fp );
	        fwrite ( &pData , sizeof ( pData ) , nNumHuman , fp );
	        fclose ( fp );
       break;
		}
		printf ( "セーブしました\n" );
	}
	
}

////////////////////
//                //
//   ロード関数    //
//                //
////////////////////
void Load ( PersonalData* pData , int nNumHuman )
{
	FILE* fp;

	fp = fopen ( "savedata.bin" , "rb" );

	if ( fp == NULL )
	{
		fputs ( "FILE CLOSE ERROR\n" , stderr );	
	}

	if ( pData != NULL )
	{
		while ( 1 )
		{
			fp = fopen ( "savedata.bin", "rb" );
			fread ( &nNumHuman , sizeof ( int ) , 1 , fp );
  	        fread ( &pData , sizeof ( int ) , nNumHuman , fp );
  	        fclose ( fp );
                break;
		}
		printf ( "セーブしました\n" );
	}
	
	fclose ( fp );
}

void Output ( PersonalData* pData , int nNumHuman )
{
	for ( int nCount_2 = 1; nCount_2 < nNumHuman; nCount_2++ )
	{
		printf ( "%d人目のデータ \n" , nCount_2 );

		printf ( "姓名 : %s\n " , &pData -> aName[0] );     
		
		printf ( "年齢 : %d\n " , pData -> nAge );        

		printf ( "身長: %f cm\n" , pData -> fHeight );     

		printf ( "体重: %f kg\n" , pData -> fWeight );    

	    pData++;
	}
}

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

バイナリデータとして、データをセーブ、ロードするというプログラムを作っています。
自分なりにやってみたのですが、どうしてもうまくいきません。
間違いを教えていただけると幸いです。
よろしくお願いします。


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

Re: ファイル読み書きについて

#2

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

ポインタをファイルに書き込んでもほとんど意味がありません。
実際のデータを書き込むようにしましょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

kloud

Re: ファイル読み書きについて

#3

投稿記事 by kloud » 9年前


早速の返信ありがとうございます。
入力したデータをポインタを使って、セーブ関数でセーブしようとするのも意味がないのでしょうか?

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

Re: ファイル読み書きについて

#4

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

kloud さんが書きました:入力したデータをポインタを使って、セーブ関数でセーブしようとするのも意味がないのでしょうか?
もちろんそんなわけないでしょう。

18行目:1は関数形式マクロの引数名として使えません。
21行目:無駄に非標準のmain関数が使用されています。
23行目:未初期化の自動変数の値は不定であり、それを使用するとundefined behaviorになります。
26行目:全角の1は条件式として不正です。
76行目:読み込んだ件数が返されることが期待されているのに、これでは常に全く読み込んでいないことになってしまいます。
100行目:書き込んでもあまり意味が無いポインタをファイルに書き込んでいる上、書き込む範囲が大きすぎるので「普通」の環境では確保されていない場所にアクセスしてしまうでしょう。
102行目:あってはいけない場所に全角スペースがあります。
Load関数:読み込んだ件数を返した方がいいでしょう。
Save関数、Load関数:NULLをファイルポインタとしてファイル操作関数に渡してはいけません。
131行目:読み込んでもあまり意味が無いポインタをファイルから読み込んでいる上、読み込んだ要素数によっては確保されていない場所にアクセスするかもしれません。
143行目:出力する数が1個少なくなってしまうでしょう。

修正してみました。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct
{
	char aName[256];     // 名前
	int nAge;            // 年齢
	float fHeight;       // 身長
	float fWeight;       // 体重
}PersonalData;

int Input ( PersonalData* pData );
void Output ( PersonalData* pData , int );
void Save ( PersonalData* pData , int );
int Load ( PersonalData* pData );

#define MinCount (1)
#define MaxCount (3)

int main ( void )
{
	PersonalData aData[3];
	int nNumHuman;
	memset(aData, 0, sizeof(aData));

#if 1
	// データ入力
	nNumHuman = Input ( &aData[0] );

	// データセーブ
	Save ( &aData[0] , nNumHuman );

#else
	// データロード
	nNumHuman = Load ( &aData[0] );

	// データ出力
	Output ( &aData[0] , nNumHuman );

#endif

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

	return 0;
}

int Input ( PersonalData* pData )
{
	int Name_Count;

	for ( int InputNum = 1; InputNum < 4; InputNum++ )
	{
		printf ( "%d人目のデータ \n" , InputNum );

		printf ( "姓(全角5文字以内) > " );
		scanf ( "%s" , &pData -> aName[0] );

		Name_Count = strlen ( &pData -> aName[0] );

		printf ( "名(全角5文字以内) > " );
		scanf ( "%s" , &pData -> aName[Name_Count] );

		printf ( "年齢(半角2ケタ) > " );
		scanf ( "%d" , &pData -> nAge );

		printf ( "身長(cm) (半角数字・少数第1位まで) > " );
		scanf ( "%f" , &pData -> fHeight );

		printf ( "体重(kg) (半角数字・少数第1位まで) > " );
		scanf ( "%f" , &pData -> fWeight );

		pData++;
	}
	return 3;
}

////////////////////
//                //
//   セーブ関数    //
//                //
////////////////////
void Save ( PersonalData* pData , int nNumHuman )
{
	FILE* fp;

	fp = fopen ( "savedata.bin", "wb" );

	if ( fp == NULL )
	{
		printf ( "FILE OPEN ERROR\n" );
		return;
	}

	if ( pData != NULL )
	{
		fwrite ( &nNumHuman , sizeof ( int ) , 1 , fp );
		fwrite ( pData , sizeof ( *pData ) , nNumHuman , fp );
		fclose ( fp );
		printf ( "セーブしました\n" );
	}

}

////////////////////
//                //
//   ロード関数    //
//                //
////////////////////
int Load ( PersonalData* pData )
{
	FILE* fp;
	int nNumHuman = 0;

	fp = fopen ( "savedata.bin" , "rb" );

	if ( fp == NULL )
	{
		fputs ( "FILE CLOSE ERROR\n" , stderr );
		return 0;
	}

	if ( pData != NULL )
	{
		fp = fopen ( "savedata.bin", "rb" );
		fread ( &nNumHuman , sizeof ( int ) , 1 , fp );
		fread ( pData , sizeof ( *pData ) , nNumHuman , fp );
		fclose ( fp );
		printf ( "セーブしました\n" );
	}

	fclose ( fp );

	return nNumHuman;
}

void Output ( PersonalData* pData , int nNumHuman )
{
	for ( int nCount_2 = 0; nCount_2 < nNumHuman; nCount_2++ )
	{
		printf ( "%d人目のデータ \n" , nCount_2 );

		printf ( "姓名 : %s\n " , &pData -> aName[0] );
		
		printf ( "年齢 : %d\n " , pData -> nAge );

		printf ( "身長: %f cm\n" , pData -> fHeight );

		printf ( "体重: %f kg\n" , pData -> fWeight );

		pData++;
	}
}

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

box
記事: 2002
登録日時: 14年前

Re: ファイル読み書きについて

#5

投稿記事 by box » 9年前

ついでに
少数第1位
っていうのは間違ってるので、
小数第1位
と修正する方がよいと思います。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

kloud

Re: ファイル読み書きについて

#6

投稿記事 by kloud » 9年前


返信遅くなり、申し訳ありません。
boxさん、漢字のご指摘ありがとうございます。
ロード関数を void Load ( PersonalData* pData , int* ); として、第二引数を int* nNumHuman とした場合、fread はどのようにすればよいのでしょうか?

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

Re: ファイル読み書きについて

#7

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

普通にすればいいでしょう。

コード:

		fread ( nNumHuman , sizeof ( int ) , 1 , fp );
		fread ( pData , sizeof ( *pData ) , *nNumHuman , fp );
エラー処理を入れると、さらに良くなるでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

kloud

Re: ファイル読み書きについて

#8

投稿記事 by kloud » 9年前

コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//////////////////////
//                  //
//   構造体の定義     //
//                  //
//////////////////////
typedef struct
{
    char aName[256];     // 名前
    int nAge;            // 年齢
    float fHeight;       // 身長
    float fWeight;       // 体重
}PersonalData;

///////////////////////////
//                       //
//   プロトタイプ宣言       //
//                       //
///////////////////////////
int Input ( PersonalData* pData );
void Output ( PersonalData* pData , int );
void Save ( PersonalData* pData , int );
void Load ( PersonalData* pData , int* );

////////////////////
//                //
//   マクロ定義    //
//                //
////////////////////
#define MinCount (1)
#define MaxCount (5)

////////////////////
//                //
//   メイン関数    //
//                //
////////////////////
int main ( void )
{
    PersonalData aData[MaxCount];
    int nNumHuman;
    memset ( aData, 0, sizeof ( aData ) );
 
#if 1
    // データ入力
    nNumHuman = Input ( &aData[0] );
 
    // データセーブ
    Save ( &aData[0] , nNumHuman );
 
#else
    // データロード
    Load ( &aData[0] , &nNumHuman );
 
    // データ出力
    Output ( &aData[0] , nNumHuman );
 
#endif
 
    // キー入力待ち
    rewind (stdin);
    getchar();
 
    return 0;
}

//////////////////
//              //
//   入力関数      //
//              //
//////////////////
int Input ( PersonalData* pData )
{
    int Name_Count;
	int Data_Count;

	if ( pData == NULL )
	{
		printf ( "データ入力に失敗しました\n" );
		return 0;
	}

	do
	{
	    printf ( " 何人分のデータを入力しますか?(%d~%d人) > " , MinCount , MaxCount );
	    scanf ( "%d" , &Data_Count );
	}while ( Data_Count < MinCount || Data_Count > MaxCount );

	printf ( "\n %d人分のデータを入力します\n" , Data_Count );

	// 人数分入力
    for ( int InputNum = 1; InputNum < Data_Count + 1; InputNum++ )
    {
		printf ( "\n" );

        printf ( " %d人目のデータ入力 \n" , InputNum );
 
        printf ( " 姓(全角5文字以内) > " );                      // 苗字入力
        scanf ( "%s" , &pData -> aName[0] );
 
        Name_Count = strlen ( &pData -> aName[0] );
 
        printf ( " 名(全角5文字以内) > " );                      // 名前入力
        scanf ( "%s" , &pData -> aName[Name_Count] );
 
        printf ( " 年齢(半角2ケタ) > " );                        // 年齢入力
        scanf ( "%d" , &pData -> nAge );
 
        printf ( " 身長(cm) (半角数字・小数第1位まで) > " );     // 身長入力
        scanf ( "%f" , &pData -> fHeight );
 
        printf ( " 体重(kg) (半角数字・小数第1位まで) > " );     // 体重入力
        scanf ( "%f" , &pData -> fWeight );
 
        pData++;
    }

    return Data_Count;
}
 
////////////////////
//                //
//   セーブ関数     //
//                //
////////////////////
void Save ( PersonalData* pData , int nNumHuman )
{
    FILE* fp;

	// ファイルを開く
    fp = fopen ( "savedata.bin", "wb" );

    if ( fp == NULL )
    {
        printf ( "FILE OPEN ERROR\n" );
        return;
    }
 
    if ( pData != NULL )
    {
		// ファイル書き込み
        fwrite ( &nNumHuman , sizeof ( int ) , 1 , fp );
        fwrite ( pData , sizeof ( *pData ) , nNumHuman , fp );

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

		if ( fclose ( fp ) != EOF )
		{
			fputs ( "FILE CLOSE ERROR" , stderr );
			return;
		}
		else
		{
            printf ( "\nセーブしました\n" );
		}
    }
	else
	{
		printf ( "セーブ失敗\n" );
	}
}
 
////////////////////
//                //
//   ロード関数     //
//                //
////////////////////
void Load ( PersonalData* pData , int* nNumHuman )
{
    FILE* fp;

	// ファイルを開く
    fp = fopen ( "savedata.bin" , "rb" );

    if ( fp == NULL )
    {
        fputs ( "FILE OPEN ERROR\n" , stderr );
        return;
    }
 
    if ( pData != NULL )
    {
        fp = fopen ( "savedata.bin", "rb" );

		// ファイル読み込み
        fread ( nNumHuman , sizeof ( int ) , 1 , fp );
        fread ( pData , sizeof ( *pData ) , *nNumHuman , fp );

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

		if ( fclose ( fp ) != EOF )
		{
			fputs ( "FILE CLOSE ERROR" , stderr );
			return;
		}
		else
		{
            printf ( " ロードしました\n" );
		}
    }
	else
	{
		printf ( "ロード失敗\n" );
	}
}

//////////////////
//              //
//   出力関数     //
//              //
//////////////////
void Output ( PersonalData* pData , int nNumHuman )
{
	if ( pData == NULL )
	{
		printf ( "出力に失敗しました\n" );
		return;
	}

	// 人数分出力
    for ( int nCount_2 = 0; nCount_2 < nNumHuman; nCount_2++ )
    {
		printf ( "\n" );

        printf ( " %d人目のデータ出力 \n" , nCount_2 + 1 );

        printf ( " 姓名 : %s\n" , &pData -> aName[0] );        // 姓名出力
        
        printf ( "年齢 : %d 才\n" , pData -> nAge );           // 年齢出力

        printf ( "身長: %0.1f cm\n" , pData -> fHeight );      // 身長出力

        printf ( " 体重: %0.1f kg\n" , pData -> fWeight );     // 体重出力

		pData++;
	}
}

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

質問にご回答いただきありがとうございました。
また、何かあればよろしくお願いします。


閉鎖

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