目次
課題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 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 |
/* 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を使って、構造体のデータをファイルへ書き出すプログラムを記入しなさい */ fprintf(fp, "%d, %lf, %lf, %lf, %s, %d", cross[i].id, cross[i].pos.x, cross[i].pos.y, cross[i].wait, cross[i].name, cross[i].points); for(j=0; j<cross[i].points; j++) { fprintf(fp, ", %d", cross[i].next[j]); } fprintf(fp, "\n"); /* 改行 */ } 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; } |
課題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を使って、構造体のデータをファイルから読み込むプログラムを記入しなさい */ fscanf(fp, "%d,%lf,%lf,%lf, %[^,],%d", &(cross[i].id), &(cross[i].pos.x), &(cross[i].pos.y), &(cross[i].wait), cross[i].name, &(cross[i].points)); for(j=0; j<cross[i].points; j++) { fscanf(fp, ",%d", &(cross[i].next[j])); } } 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 の定義を変更すること。加えて、ファイル名もちゃんと変えること。
map1.datが読み込めたひとは、map2.datが読み込めるようにしてみてください。
map2.datは、map.datにローマ字表記の交差点名を付け加えたものです。
構造体を一箇所修正し、対応するfscanfとprintfの箇所を直すだけです。
次回以降はmap2.datを使いますので、必ず動くようにしておいてください。
コンパイル時に、
"warning: ignoring return value of..."
のような警告が出る場合がある。
エラーでなく、警告なので無視しても特に問題はないが、気になるようだったら、
コンパイル時のオプションで "-Wno-unused-result" を付けると出力が抑制できます。