入出力プログラム課題



1. 入出力サンプルプログラム(構造体、printf()、scanf())

次のプログラムを打ち込んで実行してみて下さい。

/* サンプル7-2 "sample7-2.c" --- 端末との入出力プログラム */

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

struct info {
    char name[256];
    int age;
};
typedef struct info Info;

int main(void) {
    /* 構造体"Info"を用意 */
    Info information;

    /* 名前データの入力 */
    printf("input name>");
    scanf("%s", information.name);

    /* 年齢データの入力 */
    printf("input age>");
    scanf("%d", &(information.age));

    /* 入力したデータの表示 */
    printf("name: %s\n", information.name);
    printf("age:  %d\n", information.age);

    return 0;
}

このプログラムについて、注意すべき点を幾つか挙げます。

1. 構造体を使用している

構造体とは、複数の変数をまとめて扱えるようにしたものです。この例では、次の部分でinfoという名前の構造体を定義しています。

struct info {
  char name[256];
  int age;
};

構造体の定義は、

struct 構造体の名前 {
    まとめたい
    変数を並べる
};

と書きます。従ってこのサンプルでは、charの配列(文字列変数)nameint型変数ageをまとめた構造体infoが定義されています。

また、サンプルでは、typedefstruct infoという型にInfoという別名をつけています。

typedef  型  別名

2. 定義した構造体の使い方

定義した構造体は、普通の変数のように宣言して使用します。サンプルでは、main()関数の先頭で次のように宣言されています。

Info information;

これで、Info型の構造体変数informationが使えるようになりました。構造体変数informationにまとめられている変数を使うには、

構造体変数名.変数名

と記述します。例えば、informationの中のageに18を代入するには、

information.age = 18;

と書きます。

構造体の練習

構造体infoに住所(char address[256];)と郵便番号(int zip_code;)を追加して下さい。住所と郵便番号も入力&表示できるようにして下さい。


構造体の練習の解答例

/* 構造体の練習 */

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

struct info {
    char name[256];
    int age;
	char address[256];
	int zip_code;
};
typedef struct info Info;

int main(void)
{
    /* 構造体"Info"を用意 */
    Info information;
	
    /* 名前データの入力 */
    printf("input name> ");
    scanf("%[^\n]", information.name);

    /* 年齢データの入力 */
    printf("input age> ");
    scanf("%d", &(information.age));

    /* 住所データの入力 */
    printf("input address> ");
    scanf("%[^\n]", information.address);

    /* 郵便番号データの入力 */
    printf("input zip> ");
    scanf("%d", &(information.zip_code));

    /* 入力したデータの表示 */
    printf("name: %s\n", information.name);
    printf("age : %d\n", information.age);
    printf("addr: %s\n", information.address);
    printf("zip : %d\n", information.zip_code);

    return 0;
}

2. 課題1:配列

サンプルプログラム中で入力データを格納していた構造体変数informationを配列にし、複数人のデータを扱えるようにして下さい。良く分からないという人は、以下のプログラムを参考にして下さい。

/* 課題7-2 "exercise7-2.c" --- 配列の練習 */
#include <stdio.h>
#include <stdlib.h>

struct info {
    char name[256];
    int age;
    char address[256];
    int zip_code;
};
typedef struct info Info;

int main(void) {
    /* 構造体変数の配列を用意(3人分) */
    Info information[3];

    /* forループ用変数 */
    int i;

    /* 各種データの入力(3人分) */
    for (i = 0; i < 3; i++) {
        /* 名前の入力 */
        printf("input name> ");
        scanf("%s", information[i].name);

        /* あとは自分で考えよう */
    }

    /*
     * 入力したデータの表示(3人分)
     * ここもforループで3回表示しよう
     */

    return 0;
}

構造体の配列の解答例

/* 課題7-2 "exercise7-2.c" --- 配列の練習 */

#include <stdio.h>

struct info {
    char name[256];
    int age;
    char address[256];
    int zip_code;
};
typedef struct info Info;

int main(void)
{
    /* 構造体変数の配列を用意(3人分) */
    Info information[3];

    /* forループ用変数 */
    int i;

    /* 各種データの入力(3人分) */
    for ( i=0; i < 3; i++ )
      {
	  /* 名前の入力 */
	  printf("input name>");
	  scanf("%[^\n]", information[i].name);

	  /* 年齢データの入力 */
	  printf("input age>");
	  scanf("%d", &(information[i].age));

	  /* 住所データの入力 */
	  printf("input address>");
	  scanf("%[^\n]", information[i].address);

	  /* 郵便番号データの入力 */
	  printf("input zipcode>");
	  scanf("%d", &(information[i].zip_code));
      }

    /* 各種データの入力(3人分) */
    for ( i=0; i < 3; i++ )
      {
	printf("name[%d]: %s\n",i, information[i].name);
	printf("age[%d]:  %d\n",i, information[i].age);
	printf("address[%d]:  %s\n",i, information[i].address);
	printf("zip[%d]:  %d\n",i, information[i].zip_code);
      }
    return 0;
}

3. 課題2:fopen()、fprintf()、fclose()を使ったファイル出力

「おさらい」のファイル入出力プログラムを参考に、課題1のプログラムで入力したデータを ファイル「info.dat」に保存するように変更して下さい。

ヒント

  1. ファイルポインタ = fopen(ファイル名, モード) が必要ですね。
  2. printf、をfprintfにするとファイルに出力できる。
  3. プログラムの最後に fclose()をお忘れなく。

ファイル「info.dat」の内容は、順に、

人数
名前, 年齢, 住所, 郵便番号
名前, 年齢, 住所, 郵便番号
...

となるようにして下さい。例えば、3人分情報を保存したデータファイルは、

3
SazaeSan, 36, Setagayaku, 158
Taiko, 32, Setagayaku, 158
Hanazawa, 14, Setagayaku, 158

となります。


ファイルへの書き出しの解答例

/* 課題2ファイル出力 */

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

struct info {
    char name[256];
    int age;
    char address[256];
    int zip_code;
};
typedef struct info Info;

int main(void)
{
    /* 構造体変数の配列を用意(3人分) */
    Info information[3];

    /* forループ用変数 */
    int i;
    
    /* ファイルポインタ */
    FILE *fp;

    /* 各種データの入力(3人分) */
    for ( i=0; i < 3; i++ )
      {
      /* 名前の入力 */
      printf("input name>");
      scanf("%s", information[i].name);

      /* 年齢データの入力 */
      printf("input age>");
      scanf("%d", &(information[i].age));

      /* 住所データの入力 */
      printf("input address>");
      scanf("%s", information[i].address);

      /* 郵便番号データの入力 */
      printf("input zipcode>");
      scanf("%d", &(information[i].zip_code));
      }

    /* ファイルオープン */
    if( (fp = fopen("info.dat", "w")) == NULL ){
      printf(" *** file open error *** \n");
      exit(1);
    }

    /* 1行目の書き込み */
    fprintf (fp, "3\n");

    /* データの書き込み */
    for ( i=0; i < 3; i++ )
    {
    fprintf(fp,"%s, ", information[i].name);
    fprintf(fp,"%d, ", information[i].age);
    fprintf(fp,"%s, ", information[i].address);
    fprintf(fp,"%d \n", information[i].zip_code);
    }

    /* ファイルクローズ */
    fclose(fp);

    return 0;
}

4. 課題3:fopen()、fscanf()、fclose()を使ったファイル入力

さて、最後にこのようなデータファイルを読み込むプログラムを作りましょう。 次のプログラムの不足部分を補って下さい。

fscanf()で文字列を読み込む時のコツ

scanfの入力書式部分に 「%[^,]」と書くと、","を入力するまでが1つの文字列 であると扱ってくれます。つまり、文字列の区切り文字を指定することができます。 「文字列, 数値, 文字列, 数値[改行]」という行を1つのfscanfで読み込むには、 "%[^,], %d, %[^,], %d\n"と書けば良いことにになります。 データの区切り","と改行"\n"を忘れずに書くことが重要です。

/* 課題7-3 "exercise7-3.c" --- ファイルからのデータ読み込み */

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

struct info {
    char name[256];
    int age;
    char address[256];
    int zip_code;
};
typedef struct info Info;

int main(void) {
    /* 構造体変数の配列を用意(多めに100人分) */
    Info information[100];
    int num;                /* 読み込み人数 */
    int i;                  /* forループ用変数 */
    FILE *fp;               /* ファイルポインタ */

    /*
     * ここに
     * ファイルポインタfpを使用して
     * "info.dat"ファイルをオープン
     * するプログラムを書いて下さい。
     */

    /* 始めに人数を読み込む */
    fscanf(fp, "%d\n", &num);

    /* 人数が100を越えていたら終る */
    if (num > 100) {
        printf("Data for too many people!\n");
        exit(1);
    }

    /* データの読み込み(人数分) */
    for (i = 0; i < num; i++) {
        fscanf(fp, "%[^,], %d, %[^,], %d\n",
               information[i].name, &(information[i].age),
               information[i].address, &(information[i].zip_code));
    }

    /*
     * 入力したデータの表示(num人分)
     */

    fclose(fp);

    return 0;
}

ファイルからの読み込みの解答例

/* 課題3ファイル入力 */

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

struct info {
    char name[256];
    int age;
    char address[256];
    int zip_code;
};
typedef struct info Info;

int main(void)
{
    /* 構造体"Info"を用意 */
    Info information[3];
    /* forループ用変数 */
    int i, j;
    /* ファイルポインタ */
    FILE *fp;
    
    /* ファイルを開いてデータを読み込む */
    fp = fopen("info.dat", "r");

    fscanf( fp, "%d\n", &j ); /* 人数をjに格納 */
    for ( i=0; i < j; i++ ) /* 人数分、ループして読み込み */
    {
        fscanf(fp, "%[^,], %d, %[^,], %d\n"
               , information[i].name, &(information[i].age)
               , information[i].address, &(information[i].zip_code));
    }

    /* ファイルクローズ */
    fclose(fp);

    /* 各種データの出力(j人分) */
    for ( i=0; i < j; i++ )
    {
        /* 入力したデータの表示 */
        printf("name[%d]: %s\n",i, information[i].name);
        printf("age [%d]: %d\n",i, information[i].age);
        printf("addr[%d]: %s\n",i, information[i].address);
        printf("zip [%d]: %d\n",i, information[i].zip_code);
    }


    return 0;
}

さて、時間が余った人は、このプログラムを基に、住所録プログラムを作って下さい。 携帯電話の電話帳のようなものです。最初にメニューが出てきて、住所一覧、住所登録、 住所削除の3つが選べるとします。この中からどれかを数字で選ぶと、それぞれの操作が できます。勿論、編集した住所はファイルに保存されるとします。


戻る