構造体を使用したプログラミング2:交差点データのファイル入出力

目次

  1. 課題2:交差点データのファイル書きだし
  2. 課題3:交差点データのファイル読み込み
  3. 課題3−2:交差点データのファイル読み込み


1. 課題2:交差点データのファイル書きだし

 課題1のプログラムを修正し、キーボードから入力した交差点データを次の形式でファイル"map.dat"に
保存するプログラムを作って下さい。交差点情報は1つにつき1行に書かれます。また、隣接交差点は
交差道路数(points)分だけ並びます。


  交差点データ保存形式
  ‾‾‾‾‾‾‾‾‾‾
crossing_point(交差点数)
id, x, y, wait, name, points, next[0], … next[points-1]  ← cross[0]のデータ
id, x, y, wait, name, points, next[0], … next[points-1]  ← cross[1]のデータ
                                ・
                                ・
id, x, y, wait, name, points, next[0], … next[points-1]  ← cross[crossing_point-1]のデータ

 例えば、交差点数が3の場合次のようなファイルになります。
3
1, 12.000000, 23.000000, 11.000000, 長町, 1, 2
2, 34.000000, 56.000000, 90.000000, 西公園, 1, 1
3, 56.000000, 45.000000, 45.000000, 一番町, 2, 1, 2


 ファイルへの保存処理を行なう部分は、関数map_write()として作ります。
 解答例は時間が来たら表示します。

 注) 関数の作り方は前回までのテキストを参照して下さい。

/* writefile.c --- 交差点データのファイル出力 */
#include <stdio.h>
#include <string.h>

#define CrossingNumber  5  /* 交差点数=5 */
#define MaxName        50  /* 最大文字数50文字(半角) */

typedef struct {
	double x, y;           /* 位置 x, y */
} Position;                /* 位置を表す構造体 */

typedef struct {
	int id;                /* 交差点番号 */
	Position pos;          /* 位置を表す構造体 */
	double wait;           /* 平均待ち時間 */
	char name[MaxName];    /* 交差点名 */
	int points;            /* 交差道路数 */
	int next[5];           /* 隣接する交差点番号 */
} Crossing;


Crossing cross[CrossingNumber];


void map_write(char *filename, int crossing_number)
{
	FILE *fp;
	int i, j;

	fp = fopen(filename, "w");
	if (fp == NULL) {
		printf("File %s is not created\n", filename);
		return;
	}

	/* 交差点数の書き込み */
	fprintf(fp, "%d\n", crossing_number);

	for (i = 0; i < crossing_number; i++) {

	/* 関数fprintfを使って、構造体のデータをファイルへ書き出すプログラムを記入しなさい */










} fclose(fp); } int main(void) { int i,j; int crossing_number=0; /* 入力した交差点情報の数 */ char YesNo[16]; /* 入力継続の問い合わせに使用 */ for (i = 0; i < CrossingNumber; i++) { /* データの入力 */ crossing_number++; /* 交差点数を1増やす */ /* 構造体crossへデータを代入するプログラムを記入しなさい */ printf("交差点番号="); scanf("%d", &(cross[i].id)); /* 交差点番号の入力 */ printf("名前="); scanf("%s", cross[i].name); /* 交差点名の入力 */ printf("x座標="); scanf("%lf", &(cross[i].pos.x)); /* x座標の入力 */ printf("y座標="); scanf("%lf", &(cross[i].pos.y)); /* y座標の入力 */ printf("待ち時間="); scanf("%lf", &(cross[i].wait)); /* 待ち時間の入力 */ printf("交差道路数="); scanf("%d", &(cross[i].points)); /* 交差道路数の入力 */ for (j = 0; j < cross[i].points; j++) { /* 交差道路数だけ繰り返し */ printf("隣接交差点番号(No.%d)=", j); scanf("%d", &(cross[i].next[j])); /* 隣接交差点番号の入力 */ } printf("次のデータを入力しますか?(Yes:\"y\")>"); scanf("%s", YesNo); if (strcmp(YesNo, "y") != 0) break; /* 入力文字が"y"ならforループを抜ける(break) */ } for (i = 0; i < crossing_number; i++) { /* データの表示 */ printf("交差点番号:%d, 座標(%lf, %lf), 名前:%s,", cross[i].id, cross[i].pos.x, cross[i].pos.y, cross[i].name); printf(" 待ち時間:%lf, points:%d, adjacent crossing(", cross[i].wait, cross[i].points); for(j=0; j<cross[i].points; j++) { /* 交差道路数だけ繰り返し */ printf("%d ", cross[i].next[j]); } printf(")\n"); } /* ファイルへの書き込み */ map_write("map.dat", crossing_number); return 0; }



2. 課題3:交差点データのファイル読み込み

 課題1、2のプログラムを参考に、課題2で保存したファイル"map.dat"を構造体に読み込み、
交差点情報を画面に表示するプログラムを作って下さい。ファイル読み込み部分は既に下のプログラム中に
関数map_read()として書かれています。fscanf()の部分に注意して下さい。解答例は時間が来たら表示します。

 プログラムが完成したら、課題2で保存したファイル"map.dat"を実際に読み込み、交差点の各種情報が
正確に読み込まれているかどうか確認して下さい。このプログラムは今後のカーナビプログラムの基礎となり
ますので、確実に動くものを必ず作成して下さい。


/* readfile.c --- 交差点データのファイル入力 */
#include <stdio.h>

#define CrossingNumber 100 /* 交差点数=5 */
#define MaxName        50  /* 最大文字数50文字(半角) */

typedef struct {
	double x, y;           /* 位置 x, y */
} Position;                /* 位置を表す構造体 */

typedef struct {
	int id;                /* 交差点番号 */
	Position pos;          /* 位置を表す構造体 */
	double wait;           /* 平均待ち時間 */
	char name[MaxName];    /* 交差点名 */
	int points;            /* 交差道路数 */
	int next[5];           /* 隣接する交差点番号 */
} Crossing;


Crossing cross[CrossingNumber];


int map_read(char *filename)
{
	FILE *fp;
	int i, j;
	int crossing_number;                          /* 交差点数 */

	fp = fopen(filename, "r");
	if (fp == NULL) {
		printf("File %s is not created\n", filename);
		return -1;
	}

	/* はじめに交差点数を読み込む */
	fscanf(fp, "%d", &crossing_number);

	for (i = 0; i < crossing_number; i++) {


	/* 関数fscanfを使って、構造体のデータをファイルから読み込むプログラムを記入しなさい */









} fclose(fp); /* ファイルから読み込んだ交差点数を返す */ return crossing_number; } int main(void) { int i,j; int crossing_number; /* 交差点数 */ /* ファイルの読み込み */ crossing_number = map_read("map.dat"); for (i = 0; i < crossing_number; i++) { /* データの表示 */ printf("交差点番号:%d, 座標(%lf, %lf), 名前:%s,", cross[i].id, cross[i].pos.x, cross[i].pos.y, cross[i].name); printf(" 待ち時間:%lf, points:%d, adjacent crossing(", cross[i].wait, cross[i].points); for(j=0; j<cross[i].points; j++) { /* 交差道路数だけ繰り返し */ printf("%d ", cross[i].next[j]); } printf(")\n"); } return 0; }

さらに仙台市内の交差点データを
  map1.dat
  map2.dat
として用意しました。
これをコピーペーストでテキストファイル化し、保存してください。(または、wgetを使って、上記の地図データのURLを貼り付ければ簡単に取得できます。)
その後、まずmap1.datのデータが完成したプログラムで読み込めるかどうか試してみて下さい。
ただし、このファイルには90個の交差点データが入っていますので、プログラム中の CrossingNumber の定義を変更すること。加えて、ファイル名もちゃんと変えること。


3. 課題3−2:交差点データのファイル読み込み

map1.datが読み込めたひとは、map2.datが読み込めるようにしてみてください。
map2.datは、map.datにローマ字表記の交差点名を付け加えたものです。
構造体を一箇所修正し、対応するfscanfとprintfの箇所を直すだけです。
次回以降はmap2.datを使いますので、必ず動くようにしておいてください。


fscanfの警告について

コンパイル時に、
 "warning: ignoring return value of..."
のような警告が出る場合がある。
エラーでなく、警告なので無視しても特に問題はないが、気になるようだったら、
コンパイル時のオプションで "-Wno-unused-result" を付けると出力が抑制できます。

 
戻る