何故か、変数で構造体の配列数を指定すると、内容が表示されません

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

何故か、変数で構造体の配列数を指定すると、内容が表示されません

#1

投稿記事 by kerotan0820 » 14年前

今現在、 名前、誕生日(生年月日)を記憶し、管理出来るプログラムを、構造体、関数などの勉強がてらに作成しております。

コード:

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

    /*************************************************************** 
	          ▲ 名前、生年月日の構造体▲
	***************************************************************/
struct data1 {

	char  name[64];  /*   名前   */
	int   year;      /*    年    */
	int   manth;     /*    月    */
	int   day;       /*    日    */
	int   quantity;  /* データ数 */

}birth[200];


    /***************************************************************
	              ■新規データの入力、データ編集用関数■
    ***************************************************************/
	void inputdata(struct data1 birth[])
	{
		char name1[64];

		printf("名前:"); scanf("%64s",name1); //名前を入力
		strcpy(birth[ birth[0].quantity ].name , name1);
		
		//birth構造体の quantity(データ数)に応じた場所へ入力
		printf("誕生日の登録\n\n");
		printf("西暦:"); scanf("%d",&birth[ birth[0].quantity ].year);
		printf(" 月:"); scanf("%d",&birth[ birth[0].quantity ].manth);
		printf(" 日:"); scanf("%d",&birth[ birth[0].quantity ].day);

		birth[0].quantity+=1;

		return 0;
	}

    /***************************************************************
	                ■保存データ 一覧表示関数■
    ***************************************************************/
	void indicate_data(void)
	{
		if(birth[0].quantity != 0 )
		{
			
			int repetition;
			
			printf("名前    西暦  月  日\n");
			
			for(repetition=0;repetition < birth[0].quantity; repetition++);
			{
				printf("%s"  ,birth[repetition].name);
				printf("%7d"   ,birth[repetition].year);
				printf("    %02d"   ,birth[repetition].manth);
				printf("    %02d\n\n" ,birth[repetition].day);
			}
		}else{
			printf("データがありません\n"
				   "登録してから参照してください");
		}
	}


    /***************************************************************
	              ■バイナリデータへのデータ保存関数■
    ***************************************************************/
	void write_data(void)
	{
        FILE *fp = fopen( "data.dat", "wb" );//バイナリファイルを開く
        if( fp == NULL ){//エラーが起きたらNULLを返す
                return 0;
        }
        fwrite( &birth, sizeof(birth), 1, fp ); // birth構造体の中身を出力
        fclose( fp );//ファイルを閉じる
	}




	/***************************************************************
	                 ■バイナリデータ読み込み関数■
    ***************************************************************/
	void read_data(void)
	{
		FILE *fp = fopen( "data.dat", "rb" );//バイナリファイルを開く
		if( fp == NULL ){//エラーが起きたらNULLを返す
			return 0;
		}
		fread( &birth, sizeof(birth), 1, fp ); // birth 構造体の中身を読み込み
		fclose( fp );//ファイルを閉じる
	}









	    /*************************************************************** 
	                     MAIN  
	    ***************************************************************/

int main(void)
{

	int menu=0;

	while(1){
		
		printf("データ読み込み中...\n");
		system("cls");

		read_data( birth ); //■バイナリデータ読み込み関数■
		
		/*************************************************************** 
	          メインメニュー(分岐)
		***************************************************************/

		printf("新規データの入力        :1\n"
		       "データの編集            :2\n"
		       "アルファベット順名前一覧:3\n\n");

		printf("入力:");
		scanf_s( "%d", &menu ); //どういった動作を行うのか入力
		printf("\n");
		
		switch (menu){

                case 1: // データの新規登録
			   
			  inputdata( birth ); //■構造体への名前,生年月日入力関数■

			  write_data( birth ); //■バイナリデータへのデータ書き込み関数■

			  printf("\n登録が完了しました\n");
			  getch();
			     break;
		   
		        case 2: // データの編集
			   
			   
			     break;
		   
		        case 3: // 登録データ一覧表示

					indicate_data( birth ); //■データ一覧表示関数■

					getch();

			     break;
		   
				default: // 入力エラー
			   
			   printf("1~3以外の値が入力されました\n");
			   
			     break;

			   system("cls");
		} //switch

	} //while
	
	return 0;

}
見にくいプログラムで申し訳ありません。

今現在私が困っているのは、二点あります。

一点目。

上から3つ目の大きな注釈、■保存データ 一覧表示関数■ のindicate_data関数で、登録されているデータを一覧表示するもの。

これが、データが正常に表示出来ません。

構造体配列の[ repetition ] を [0] と試しにしてみたところ、正常に [ 0 ]に保存されている名前、生年月日が一覧表示されました。

for文で repetition を 0に初期化しているのに、何故 repetition 変数を配列で使用すると内容が表示されなくなってしまうのでしょうか。





二点目なのですが、今後のプログラムの機能の追加についてなのですが
今現在は一覧表示の関数を作りましたが、これから、アルファベット順、月日順、誕生日まで一ヶ月以内の人、一週間以内の人一覧、などと、いろいろな表示方法を作る予定なのですが、 全てを関数化することしか私は考えられません。
main関数だけは綺麗にしておきたいのですが、皆様ならばどのように構成しますでしょうか。
やはり、プログラムの量が増えてきたからには、ソースファイルの分割を覚えるべきでしょうか。




回答いただけると幸いです。
よろしくお願いします。
けろけろにゃー (」・ω・)」うー!

アバター
a5ua
記事: 199
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#2

投稿記事 by a5ua » 14年前

51行目の

コード:

for(repetition=0;repetition < birth[0].quantity; repetition++);
{
・・・
}
for文の後ろのセミコロンが不要です。このせいで、中身が空のfor文+ただのブロックという意味になってしまっています。

初級者
記事: 200
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#3

投稿記事 by 初級者 » 14年前

今回扱っているデータだと、テキストファイルで管理する方が楽だと思います。

kerotan0820
記事: 91
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#4

投稿記事 by kerotan0820 » 14年前

>>a5ua 様
ご指摘ありがとうございます。
気づきませんでした^^;
無事問題は解決しました。ありがとうございます。


>>初級者様
確かにテキストのほうが、簡単に編集できて便利ですね。
ということで試してみたのですが、

コード:

    /***************************************************************
	              ■バイナリデータへのデータ保存関数■
    ***************************************************************/
	void write_data(void)
	{
        FILE *fp = fopen( "data.txt", "w" );//バイナリファイルを開く
        if( fp == NULL ){//エラーが起きたらNULLを返す
                return 0;
        }
        fwrite( &birth, sizeof(birth), 1, fp ); // birth構造体の中身を出力
        fclose( fp );//ファイルを閉じる
	}
これだと、名前しかテキストにきちんと出力されないのですが、
fprintfなどを使って、ゲムプログラミングの館のセーブデータ作成方法のように、全てのデータを一つ一つ書きこむしか無いのでしょうか。
けろけろにゃー (」・ω・)」うー!

初級者
記事: 200
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#5

投稿記事 by 初級者 » 14年前

ファイルのオープンモードにマッチした関数を使いましょう。

初級者
記事: 200
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#6

投稿記事 by 初級者 » 14年前

戻り値がない、と言っているにもかかわらず、
return 0;
という文があるのはどうしてでしょうか?

本文とコメントが食い違っているところがあります。

kerotan0820
記事: 91
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#7

投稿記事 by kerotan0820 » 14年前

初級者 さんが書きました:戻り値がない、と言っているにもかかわらず、
return 0;
という文があるのはどうしてでしょうか?

本文とコメントが食い違っているところがあります。
main関数のことでしょうか。
初級者 さんが書きました:ファイルのオープンモードにマッチした関数を使いましょう。
プログラミングの館を参考にして実装しただけなので、何がマッチしているとか分かりません・・・;
自力ではもうなん時間も考えているので、参考のURLや具体的な関数を教えていただけると幸いです。
わがまま言って申し訳ありません。
けろけろにゃー (」・ω・)」うー!

non
記事: 1097
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#8

投稿記事 by non » 14年前

kerotan0820 さんが書きました: main関数のことでしょうか。
void write_data(void)
のように、戻り値がvoidの関数のことです。
kerotan0820 さんが書きました:
初級者 さんが書きました:ファイルのオープンモードにマッチした関数を使いましょう。
プログラミングの館を参考にして実装しただけなので、何がマッチしているとか分かりません・・・;
自力ではもうなん時間も考えているので、参考のURLや具体的な関数を教えていただけると幸いです。
わがまま言って申し訳ありません。
fwriteを使うなら、バイナリーモード、fprintfならテキストモードってことでしょうね。
構造体まるごと保存なら、fwriteでバイナリーで行う。初級者さんの勧めでテキストモードで行うなら、fprintfで各メンバーを
一つずつ保存しろってことです。バイナリーでもテキストでもどちらでもよいのですが、ごちゃまぜにしないようにしましょう。

で、このプログラムはkerotan0820さんが、自分の勉強のために作っているのだから、まず、テキストモードで作成し、それが
できてから、バイナリーに変えてみると良いと思います。
kerotan0820 さんが書きました: main関数だけは綺麗にしておきたいのですが、皆様ならばどのように構成しますでしょうか。
やはり、プログラムの量が増えてきたからには、ソースファイルの分割を覚えるべきでしょうか。
「綺麗に」という意味がわかりませんが、mainには全体の流れがわかるように大きなブロックの処理を呼び出す関数だけに
した方がいいです。最初のプログラムのやり方で間違っておりません。
「ソースファイルの分割」は、プログラムがでかくなったら、機能別にわければいいでしょうが、恐らくこの程度のプログラムなら
1000行にもならないでしょうから、とりあえず、1つのファイルに作成してもよいかと思います。完成してから、勉強のために
分割してみるといいでしょう。
ただ、文章の流れからすると、「ソースファイルの分割」でなく、1つの関数を分割するという意味にも読めますが、それなら
以前に、そのようなスレッドがありみなさんのご意見があったと記憶しております。そんなに昔ではありませんでしたので検索して
みてください。
non

アバター
沖 滉均
記事: 237
登録日時: 14年前
住所: K県F市

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#9

投稿記事 by 沖 滉均 » 14年前

少々気になることがあるんですが139行目で使用している getch() って使用できましたっけ?
WindowsでVisual C++だったら conio.h をインクルードする必要があったような気がしますし
Linuxではそもそも使えなかったような気がするのですが

どのような環境で開発されているのかはかかれていないので詳細はわかりませんが

kerotan0820 さんが書きました:
初級者 さんが書きました:戻り値がない、と言っているにもかかわらず、
return 0;
という文があるのはどうしてでしょうか?

本文とコメントが食い違っているところがあります。
main関数のことでしょうか。
あと、こちらの件はmainとindicate_data以外は全て返り値がない(void)のはずなのに
エラー処理でreturn 0;となっているのでこのことでしょう。
There is no royal road to learning.
codeタグで指定できる言語
画像

kerotan0820
記事: 91
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#10

投稿記事 by kerotan0820 » 14年前

>>沖様、non様
回答ありがとうございます。

return 0; について、意味が分かりました。
修正しました。


>>沖様
getch()についてですが、問題なく入力待ちの状態になりましたが…。
Visual C++ 2008を使用しています。
Windows環境です^^;
使える原因はわかりませんが、インクルードしておきます。

>>non様
成程、そういうことなのですね。
理解できました。ありがとうございます。
そこで、自分なりに修正してみたのですが、うまくいかず、調べたりしてみたのですが、なかなか良いサイトが見つかりませんでした。

以下のようなプログラムになりました。

■書き込み■

コード:

    /***************************************************************
	              ■テキストデータへのデータ保存関数■
    ***************************************************************/
	void write_data( void )
	{
		int roop;

        FILE *fp = fopen( "data.txt", "w" );//バイナリファイルを開く
        if( fp == NULL ){//エラーが起きたらNULLを返す
                return 0;
        }
		
		fprintf( fp,"件数[0]=%d\n",birth[0].quantity);

		for(roop=0;roop<birth[0].quantity;roop++){

		fprintf( fp,"名前[%d]=%s\n",roop, birth[roop].name );
		fprintf( fp,"西暦[%d]=%d\n",roop, birth[roop].year );
		fprintf( fp," 月[%d]=%d\n",roop, birth[roop].manth);
		fprintf( fp," 日[%d]=%d\n",roop, birth[roop].day  );

		}

        fclose( fp );//ファイルを閉じる
	}
■読み込み■

コード:

	/***************************************************************
	                 ■テキストファイル読み込み関数■
    ***************************************************************/
	void read_data( void )
	{
		int roop;
		
		FILE *fp = fopen( "data.txt", "r" );//テキストファイルを開く
		if( fp == NULL ){//エラーが起きたらNULLを返す
			return 0;
		}
		for(roop=0;roop<birth[0].quantity;roop++){

		fread( &birth[roop].name , sizeof(birth[roop].name ), 1, fp );
		fread( &birth[roop].year , sizeof(birth[roop].year ), 1, fp );
		fread( &birth[roop].manth, sizeof(birth[roop].manth), 1, fp );
		fread( &birth[roop].day  , sizeof(birth[roop].day  ), 1, fp );

		}
		fclose( fp );//ファイルを閉じる
	}
読み込みは、全く出来ませんでしたが、書き込みは、一つのデータなら綺麗に出力されました。

それが、二人以上の入力をまとめて行ったところ、以下のようにテキストに出ました。

件数[0]=2
名前[0]=件数[0]=1
名前[0]=kerotan0820
西暦[0]=1994
 月[0]=8
 日[0]=20

西暦[0]=1994
 月[0]=8
 日[0]=20
名前[1]=KEROTAN0820
西暦[1]=1994
 月[1]=8
 日[1]=20


一体どういう事なのでしょうか…。


やはり、fprintfを使う上では理解するべきことが多いのでしょうかね…。
この点に関して、何を勉強するべきでしょうか^^;
けろけろにゃー (」・ω・)」うー!

non
記事: 1097
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#11

投稿記事 by non » 14年前

コード:

struct data1 {
 
    char  name[64];  /*   名前   */
    int   year;      /*    年    */
    int   manth;     /*    月    */
    int   day;       /*    日    */
    int   quantity;  /* データ数 */
 
}birth[200];
quantityが各レコードに必要な理由がわかりません。全体で1つあればいいのではないですか?

コード:

        fprintf( fp,"名前[%d]=%s\n",roop, birth[roop].name );
ファイルにはデータだけが保存されればよく、 名前[ ]= なんてのは保存しないのが一般的です。
読むときにじゃまですから。

freadはバイナリのとき使うものでしょう。

2件以上入れたとき、おかしな出力になるとのことですが、あのプログラムで、あのような出力が出るとは思えません。
他におかしいところがあるはず。全体がわからないと、答えようがありません。
non

kerotan0820
記事: 91
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#12

投稿記事 by kerotan0820 » 14年前

>>non様
返信が遅れて大変申し訳ありません。
non さんが書きました:quantityが各レコードに必要な理由がわかりません。全体で1つあればいいのではないですか?
仰るとおりです。
quantityを birth構造体と別に用意して、読み込んだり書き込んだりするのが面倒に思ったので、構造体で扱っていました。
訂正したいと思います。
non さんが書きました:freadはバイナリのとき使うものでしょう
テキストファイルの読み込みは何を使うのでしょうか。
調べると、fgetc、fgetsなどがアリましたが、文字を読み込む関数ですよね?
http://www.geocities.jp/ky_webid/c/035.html
このサイトをみたのですが…。

non さんが書きました:2件以上入れたとき、おかしな出力になるとのことですが、あのプログラムで、あのような出力が出るとは思えません。
他におかしいところがあるはず。全体がわからないと、答えようがありません

全体はこちらです

コード:

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

    /*************************************************************** 
	          ▲ 名前、生年月日の構造体▲
	***************************************************************/
struct data1 {

	char  name[64];  /*   名前   */
	int   year;      /*    年    */
	int   manth;     /*    月    */
	int   day;       /*    日    */
	int   quantity;  /* データ数 */

}birth[200];


    /***************************************************************
	              ■新規データの入力、データ編集用関数■
    ***************************************************************/
	void inputdata( struct data1 birth[] )
	{
		char name1[64];

		printf("名前:"); scanf("%64s",name1); //名前を入力
		strcpy(birth[ birth[0].quantity ].name , name1);
		
		//birth構造体の quantity(データ数)に応じた場所へ入力
		printf("誕生日の登録\n\n");
		printf("西暦:"); scanf("%d",&birth[ birth[0].quantity ].year);
		printf(" 月:"); scanf("%d",&birth[ birth[0].quantity ].manth);
		printf(" 日:"); scanf("%d",&birth[ birth[0].quantity ].day);
		
		birth[0].quantity+=1;
	}

    /***************************************************************
	                ■保存データ 一覧表示関数■
    ***************************************************************/
	void indicate_data(void)
	{
		if(birth[0].quantity != 0 )
		{
			
			int repetition;
			
			printf("名前    西暦  月  日\n");
			
			for(repetition=0;repetition < birth[0].quantity; repetition++)
			{
				printf("%s"  ,birth[repetition].name);
				printf("%7d"   ,birth[repetition].year);
				printf("    %02d"   ,birth[repetition].manth);
				printf("    %02d\n\n" ,birth[repetition].day);
			}
		}else{
			printf("データがありません\n"
				   "登録してから参照してください");
		}
	}


    /***************************************************************
	              ■テキストデータへのデータ保存関数■
    ***************************************************************/
	void write_data( void )
	{
		int roop;

        FILE *fp = fopen( "data.txt", "w" );//バイナリファイルを開く
        if( fp == NULL ){//エラーが起きたらNULLを返す
                return 0;
        }
		
		fprintf( fp,"件数[0]=%d\n",birth[0].quantity);

		for(roop=0;roop<birth[0].quantity;roop++){

		fprintf( fp,"%s\n",roop, birth[roop].name );
		fprintf( fp,"%d\n",roop, birth[roop].year );
		fprintf( fp,"%d\n",roop, birth[roop].manth);
		fprintf( fp,"%d\n",roop, birth[roop].day  );

		}

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




	/***************************************************************
	                 ■テキストファイル読み込み関数■
    ***************************************************************/
	void read_data( void )
	{
		int roop;
		
		FILE *fp = fopen( "data.txt", "r" );//テキストファイルを開く
		if( fp == NULL ){//エラーが起きたらNULLを返す
			return 0;
		}
		for(roop=0;roop<birth[0].quantity;roop++){

		fread( &birth[roop].name , sizeof(birth[roop].name ), 1, fp );
		fread( &birth[roop].year , sizeof(birth[roop].year ), 1, fp );
		fread( &birth[roop].manth, sizeof(birth[roop].manth), 1, fp );
		fread( &birth[roop].day  , sizeof(birth[roop].day  ), 1, fp );

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









	    /*************************************************************** 
	                     MAIN  
	    ***************************************************************/

int main(void)
{

	int menu=0;

	while(1){
		
		printf("データ読み込み中...\n");
		system("cls");

		read_data( birth ); //■バイナリデータ読み込み関数■
		
		/*************************************************************** 
	          メインメニュー(分岐)
		***************************************************************/

		printf("新規データの入力        :1\n"
		       "データの編集            :2\n"
		       "アルファベット順名前一覧:3\n\n");

		printf("入力:");
		scanf_s( "%d", &menu ); //どういった動作を行うのか入力
		printf("\n");
		
		switch (menu){

                case 1: // データの新規登録
			   
			  inputdata( birth ); //■構造体への名前,生年月日入力関数■

			  write_data( birth ); //■バイナリデータへのデータ書き込み関数■

			  printf("\n登録が完了しました\n");
			  getch();
			     break;
		   
		        case 2: // データの編集
			   
			   
			     break;
		   
		        case 3: // 登録データ一覧表示

					indicate_data( birth ); //■データ一覧表示関数■

					getch();

			     break;
		   
				default: // 入力エラー
			   
			   printf("1~3以外の値が入力されました\n");
			   
			     break;

			   system("cls");
		} //switch

	} //while
	
	return 0;

}
けろけろにゃー (」・ω・)」うー!

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

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#13

投稿記事 by box » 14年前

kerotan0820 さんが書きました:

コード:

		birth[0].quantity+=1;
初期化している箇所が見当たりません。大丈夫ですか?
kerotan0820 さんが書きました:

コード:

        FILE *fp = fopen( "data.txt", "w" );//バイナリファイルを開く
コメントと実装とが食い違っています。
テキスト・バイナリーのどちらを扱いたいのでしょうか。
kerotan0820 さんが書きました:

コード:

		FILE *fp = fopen( "data.txt", "r" );//テキストファイルを開く
		fread( &birth[roop].name , sizeof(birth[roop].name ), 1, fp );
テキストファイルをfread()で読んでいるのはどうしてでしょうか。
何をどういう風にしたいのか、設計をやり直す方がいいのではないでしょうか。

ついでに、ループの英語はloopです。roopではなくて。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

kerotan0820
記事: 91
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#14

投稿記事 by kerotan0820 » 14年前

box さんが書きました:初期化している箇所が見当たりません。大丈夫ですか?
一応、動作はしていましたが、修正します。
構造体から quantityは除外したのでまた考え方も変えますが。
box さんが書きました:コメントと実装とが食い違っています。
テキスト・バイナリーのどちらを扱いたいのでしょうか。
回答者様とすでにその答えになる会話をしていますが、説明しますと
元々バイナリデータでやっていたのですが、バイナリだと名前のデータが表示されないので、この手のデータはテキストで扱うのが良い、というアドバイスを回答で頂きました。
なので、テキストでの書き込みに、バイナリから変更しようと頑張っているのですが、ゲームプログラミングの館の、バイナリデータにセーブする単元のような参考ページが無いので、何をどう修正すれば良いのか分からず困っています。
non さんが書きました:このプログラムはkerotan0820さんが、自分の勉強のために作っているのだから、まず、テキストモードで作成し、それが
できてから、バイナリーに変えてみると良いと思います。
などと回答を頂いたので。

box さんが書きました:テキストファイルをfread()で読んでいるのはどうしてでしょうか。
何をどういう風にしたいのか、設計をやり直す方がいいのではないでしょうか。
nonさんにその質問を受けて答えたのが、1つ前の回答なのですが…。
けろけろにゃー (」・ω・)」うー!

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

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#15

投稿記事 by box » 14年前

fgets()の仕様や使い方について、深く研究することをおすすめします。

推測ですけど、
fgetc()の名前の由来:File から Character を GET する
fgets()の名前の由来:File から String を GET する

Character と String とは、たぶん別物でありましょう。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

kerotan0820
記事: 91
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#16

投稿記事 by kerotan0820 » 14年前

>>non様
回答ありがとうございます。
「fgets( ファイルからの1行読み込み)」
ということは、結論からいくとデータの個数に応じて、for文などを使って順に読み込んだりする必要が出てきたりするわけですよね?
となると、このプログラムでなくて、別のプログラムを用意して学習したほうが良いのでしょうか?
けろけろにゃー (」・ω・)」うー!

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

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#17

投稿記事 by box » 14年前

私はnonさんではないので、回答していいかどうか迷うところではありますが…。

仮に、フォーマットが

名前:64バイト
年:4バイト(yyyy形式)
月:2バイト(mm形式)
日:2バイト(dd形式)

あたりのテキストファイルだとすると、1行分読み取るための
64+4+2+2+1(\nの分)+1(終端の\0の分)
という大きさのchar型配列を確保しておいて、
その配列にfgets()で中身を入れればいいだけではないかな、と思っています。
次に、その配列から構造体の各メンバーに値を振り分けるのはsscanf()あたりでとりあえずじゅうぶんかな、と。
そして、1行読むたびに行数をインクリメントして、
fgets()の戻り値がNULLでない間、無限ループする(fgets()の戻り値がNULLになったらbreakしてループから抜ける)、
ということでいいのではないでしょうか。

間違ってたらすみません。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

アバター
沖 滉均
記事: 237
登録日時: 14年前
住所: K県F市

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#18

投稿記事 by 沖 滉均 » 14年前

間が空き過ぎて忘れてしまったのでしょうか?
No.10で
kerotan0820 さんが書きました:return 0; について、意味が分かりました。
修正しました。
と、書いてあったはずなのですがNo.12のコードを見た限り何を理解したのかが私には分かりません。
73行目、102行目でreturn 0;と書いていますがビルド時に警告かエラーが出ませんでしたか?

あと182行目は何のためにあるのでしょうか?
There is no royal road to learning.
codeタグで指定できる言語
画像

non
記事: 1097
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#19

投稿記事 by non » 14年前

kerotan0820 さんが書きました:>>non様
回答ありがとうございます。
「fgets( ファイルからの1行読み込み)」
ということは、結論からいくとデータの個数に応じて、for文などを使って順に読み込んだりする必要が出てきたりするわけですよね?
となると、このプログラムでなくて、別のプログラムを用意して学習したほうが良いのでしょうか?
???????
何か、意味が分かりませんが?????昔のことで・・・

まず、fscanfにしたらいかがですか?一番変更が少なくて済むと思いますよ。
non

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

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#20

投稿記事 by box » 14年前

あと、根本的な問題として、

入力
編集
一覧表示

以外に、メニューから抜けてプログラムを終了する、という命令がないですね。
これはまずいのではないでしょうか。
まさか、Ctrl+C か何かで強制終了させる、というわけではない、と思いたいです。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

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

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#21

投稿記事 by box » 14年前

というわけで、私が先ほど書きました
「設計をやり直す方がいいのではないでしょうか。」
というコメントはそれほど的外れではないような気がします。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

kerotan0820
記事: 91
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#22

投稿記事 by kerotan0820 » 14年前

box さんが書きました:私はnonさんではないので、回答していいかどうか迷うところではありますが…。

仮に、フォーマットが

名前:64バイト
年:4バイト(yyyy形式)
月:2バイト(mm形式)
日:2バイト(dd形式)

あたりのテキストファイルだとすると、1行分読み取るための
64+4+2+2+1(\nの分)+1(終端の\0の分)
という大きさのchar型配列を確保しておいて、
その配列にfgets()で中身を入れればいいだけではないかな、と思っています。
次に、その配列から構造体の各メンバーに値を振り分けるのはsscanf()あたりでとりあえずじゅうぶんかな、と。
そして、1行読むたびに行数をインクリメントして、
fgets()の戻り値がNULLでない間、無限ループする(fgets()の戻り値がNULLになったらbreakしてループから抜ける)、
ということでいいのではないでしょうか。

間違ってたらすみません。
失礼しました。
nonさんではなくて boxさんです。

なるほど… そういう事ですか。
納得しました。
またその方法を実装するとなると、読み込み関数をひと通り書き換えなければなりませんね。
また後日挑戦してみたいと思います。
ありがとうございます。
沖 滉均 さんが書きました:間が空き過ぎて忘れてしまったのでしょうか?
No.10で
kerotan0820 さんが書きました:return 0; について、意味が分かりました。
修正しました。
と、書いてあったはずなのですがNo.12のコードを見た限り何を理解したのかが私には分かりません。
73行目、102行目でreturn 0;と書いていますがビルド時に警告かエラーが出ませんでしたか?

あと182行目は何のためにあるのでしょうか?
おっしゃるとおりでしす。
void で宣言されているのに返り値がある、といったような警告が出ていました。
voidを空( )にしました。

182は、表示をリセットするためにあります。
non さんが書きました:まず、fscanfにしたらいかがですか?一番変更が少なくて済むと思いますよ。
調べて確認してみます。
box さんが書きました:あと、根本的な問題として、

入力
編集
一覧表示

以外に、メニューから抜けてプログラムを終了する、という命令がないですね。
これはまずいのではないでしょうか。
まさか、Ctrl+C か何かで強制終了させる、というわけではない、と思いたいです。
ソフトを終了する、という機能が無いということでしょうか?
特に公開する予定もないので、私自身が Alt+F4 ででも消せればいいやと思っていました。





すみませんが、これ以降の回答は明日以降にさせて頂きます。 ありがとうございました。
けろけろにゃー (」・ω・)」うー!

アバター
沖 滉均
記事: 237
登録日時: 14年前
住所: K県F市

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#23

投稿記事 by 沖 滉均 » 14年前

kerotan0820 さんが書きました:void で宣言されているのに返り値がある、といったような警告が出ていました。
voidを空( )にしました。
voidを空( )にしましたとは?
関数について何か勘違いされているのではないでしょうか
kerotan0820 さんが書きました:182は、表示をリセットするためにあります。
また、182行目についてはそういう意味で言っているのではありません。
インデントが揃っていないため見落としているのかもしれませんが、書いている位置が問題です。
本当にその行は実行されるでしょうか?
There is no royal road to learning.
codeタグで指定できる言語
画像

kerotan0820
記事: 91
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#24

投稿記事 by kerotan0820 » 14年前

void は引数がないのを表すものだと解釈してます。
ゲームプログラミングの館のプログラムをコピーしたので、void は不必要だったのか、としか、考えられませんでした。


182は、きちんと動作しますが?
けろけろにゃー (」・ω・)」うー!

アバター
bitter_fox
記事: 607
登録日時: 14年前
住所: 大阪府

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#25

投稿記事 by bitter_fox » 14年前

kerotan0820 さんが書きました:void は引数がないのを表すものだと解釈してます。
ゲームプログラミングの館のプログラムをコピーしたので、void は不必要だったのか、としか、考えられませんでした。
関数の戻り値の型に当たる部分にvoidを用いた場合は何も値を返さないことを意味するため値を返してはいけません。
また、戻り値の型がvoidの関数から抜ける場合は単に
return;
と書きます。
http://www.mapee.jp/cpp/voidvoid.html


kerotan0820 さんが書きました:182は、きちんと動作しますが?

コード:

    while(1){
        
        printf("データ読み込み中...\n");
        system("cls");
 
        read_data( birth ); //■バイナリデータ読み込み関数■

		switch (menu){
		case 1: // データの新規登録
			inputdata( birth ); //■構造体への名前,生年月日入力関数■
			write_data( birth ); //■バイナリデータへのデータ書き込み関数■
			printf("\n登録が完了しました\n");
			getch();
			break;
		case 2: // データの編集
			break;
		case 3: // 登録データ一覧表示
			indicate_data( birth ); //■データ一覧表示関数■
			getch();
			break;
		default: // 入力エラー
			printf("1~3以外の値が入力されました\n");
			break;
		system("cls");
		} //switch
	} //while
勝手ながらswitch内のインデントを統一させていただきました。
またwhile内の最初のsystem("cls")が実行されているためswitch内のsystem("cls")が実行されているように見えますが実行されていません。

kerotan0820
記事: 91
登録日時: 14年前

Re: 何故か、変数で構造体の配列数を指定すると、内容が表示されません

#26

投稿記事 by kerotan0820 » 13年前

bitter_fox さんが書きました:
kerotan0820 さんが書きました:void は引数がないのを表すものだと解釈してます。
ゲームプログラミングの館のプログラムをコピーしたので、void は不必要だったのか、としか、考えられませんでした。
関数の戻り値の型に当たる部分にvoidを用いた場合は何も値を返さないことを意味するため値を返してはいけません。
また、戻り値の型がvoidの関数から抜ける場合は単に
return;
と書きます。
http://www.mapee.jp/cpp/voidvoid.html


kerotan0820 さんが書きました:182は、きちんと動作しますが?

コード:

    while(1){
        
        printf("データ読み込み中...\n");
        system("cls");
 
        read_data( birth ); //■バイナリデータ読み込み関数■

		switch (menu){
		case 1: // データの新規登録
			inputdata( birth ); //■構造体への名前,生年月日入力関数■
			write_data( birth ); //■バイナリデータへのデータ書き込み関数■
			printf("\n登録が完了しました\n");
			getch();
			break;
		case 2: // データの編集
			break;
		case 3: // 登録データ一覧表示
			indicate_data( birth ); //■データ一覧表示関数■
			getch();
			break;
		default: // 入力エラー
			printf("1~3以外の値が入力されました\n");
			break;
		system("cls");
		} //switch
	} //while
勝手ながらswitch内のインデントを統一させていただきました。
またwhile内の最初のsystem("cls")が実行されているためswitch内のsystem("cls")が実行されているように見えますが実行されていません。
返信、遅れて申し訳ありません。

return について、理解出来ました。
ありがとうございます。

system("cls")が動作ているように見えていた意味が分かりました。
インデント処理までありがとうございます。
今後はインデント処理を徹底してするように、意識していきたいと思います。

それと、このプログラムを作っていて、
文字列を扱う知識、ファイルの入出力の知識があまりにも乏しいことを実感しました。
文字、文字列のあ使い方、ファイルの入出力について学び直した上で、又挑戦しようと思います。
けろけろにゃー (」・ω・)」うー!

閉鎖

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