サイトマップ / C言語講座出入り口総目次目次:ヒープ領域>環状のデータ構造

青い直線

環状のデータ構造

青い直線

[双方向リスト]←このソース

/* 双方向リストの特別な例 */

/* 構造体のメンバに、次の構造体へのポインタを持つ構造体を使った、リスト型のデータ構造については既に前々々回前々回に学びました。このようなデータ構造では、次のデータを読み込むことはできても、前のデータに戻ることはできません。前の構造体へのポインタと、次の構造体へのポインタを持つ構造体を使って、双方向リストについても既に学びました

今回は、双方向リストの特別な例について学びます。

最後に malloc( ) によってメモリを割り当てられた構造体の次の構造体を指すポインタを、最初に割り当てられた構造体を指すようにします。最初に割り当てられた構造体の前を指すポインタを最後に割り当てられた構造体を指すようにします。

結果として、データは環状の構造になります。 */

/* ソースプログラムの説明 */

/* 今回も、少しだけ、実用的なプログラムです。環状の構造ということで、山手線の駅名を表示して、n と入力すると、次の駅名が表示され、p と入力すると、前の駅名が表示されます。しかし、それだけでは、無限ループに入ってしまい、リセットをかけないと、プログラムを終了できないので、e と入力すると、メモリを解放して、プログラムが終了するようにします。

    #define NUM_STATION 28
    #define  MAX_STATION_NAME  14	

    typedef struct station station_t;

    struct  station {
        char name[MAX_STATION_NAME];
        station_t  *previous;
        station_t  *next;
    };

構造体の型は、typedef 文で、上記のように宣言します。

山手線の駅名で、英文字で一番長いのは、浜松町です。 浜松町は、英文字で 13 字なので、Cの文字列の最後の '\0' の分を加えて、MAX_STATION_NAME の値を 14 とします。

station_t 型の構造体は、name[ ] という、駅名を読み込む配列と、station_t 型の二つのポインタ、previousと next で構成されています。SetData( ) の中では、station_t 型のポインタ、head, p, q を使います。ポインタの操作については、前回と質的には同じです。しかし、複雑になっているので、ソースプログラム中のコメントを良く読んで下さい。 */

/* ここからソースプログラム */

#include <stdio.h>
#include <stdlib.h>    /* exit(  ) malloc(  ) free(  ) で必要 */
#include <string.h>    /* strcpy(  ) strcmp(  ) で必要 */

#define NUM_STATION 28
#define  MAX_STATION_NAME  14

typedef struct station station_t;

struct  station {
    char name[MAX_STATION_NAME];
    station_t  *previous;
    station_t  *next;
};

station_t *SetData(void);
void FreeData(station_t *head);
void main(void);

const char *stationname[ ] = {
            "Shinagawa", "Tamachi", "Hamamatsuchou", "Shinbashi",
            "Yurakuchou", "Tokyo", "Kanda", "Akihabara",
            "Okachimachi", "Ueno", "Uguisudani", "Nippori",
            "Nishinippori", "Tabata", "Komagome", "Ootsuka",
            "Ikebukuro", "Mejiro", "Takadanobaba", "Shinookubo",
            "Shinjuku", "Yoyogi", "Harajuku", "Shibuya", "Ebisu",
            "Meguro", "Gotanda", "Oosaki"
};

  /* 構造体のメモリを確保して、駅名をセット */
  /* 最初の構造体へのポインタを返す */
station_t *SetData(void)
{
    station_t *head, *p, *q;
    short i;
	
    if ((head = p = (station_t *)malloc(sizeof(station_t))) == NULL)
        exit(2);    /* メモリ割り当てに失敗したら、シェルに戻る */

    strcpy((*head).name, stationname[0]);	

    for (i = 1; i < NUM_STATION; i++) {
        if ((q = (station_t *)malloc(sizeof( station_t))) == NULL)
            exit(2);    /* メモリ割り当てに失敗したら、シェルに戻る */

        strcpy((*q).name, stationname[i]);

        /* 以下の操作を理解するには、図示してみると良い */
			
        q->previous = p;    /* ひとつ前の構造体へのポインタ ( p ) を */
                            /* q->previous に代入 */
		
        p->next = q;        /* 最後に割り当てた構造体へのポインタ ( q ) を */
                            /* p->next に代入 */

        p = q;              /* 次のループに備える */
    }

    p->next = head;         /* この2行で、最初の構造体 ( head )と、 */
    head->previous = p;     /*  最後の構造体 (p) とを、ポインタでつなぐ */
    return (head);
}

  /* メモリの解放 */
void FreeData(station_t *head)
{
    station_t *next;		/* 作業用ポインタ */

/*
注:"Oosaki" は最後に malloc(  )  でメモリを割り当てられた駅です。
ポインタを使って環状の構造にしてあるので、終わりがありません。
そこで、strcmp(  ) を使って、"Oosaki" が現れるまで、メモリを解放しています。
*/
    while (strcmp((*head).name, "Oosaki")) {
        next = head-> next;        /* 次の構造体のアドレスを保存 */
        free(head);                /* メモリを解放 */
        head = next;               /* 次の構造体のアドレスを */	
    }                              /* head に代入 */
    free(head);                    /* "Oosaki" を解放 */
}

void main(void)
{
    station_t *head, *station;
    int c;

    head = SetData(  );
    station = head;        /* head を station にコピー */
                           /* head は最後に使う */

    printf( "  私たちは今%s駅にいます。\n", (*station).name );

    while (1) {
        printf("p: 前の駅  n: 次の駅  e: 終了\n");
        fflush(stdin);        /* 前の入力で stdin に残っている改行コードを捨てる */
        c = getchar(  );
        switch (c) {
            case ('n'):                         /* 入力された文字が n ならば */
                station = station->next;        /* 次の駅名を表示 */
                printf(" %s 駅へ着きました。\n",  (*station).name);
                break;
            case ('p'):                         /* 入力された文字が p ならば */
                station = station->previous;    /* 前の駅名を表示 */
                printf(" %s 駅へ戻りました。\n",  (*station).name);
                break;
            case ('e'):                         /* 入力された文字が e ならば */
                FreeData(head);                 /* malloc(  ) で割り当てたメモリブロックを解放 */
                exit(EXIT_SUCCESS);             /* プログラムを正常終了 */
            default:
                break;
        }
    }
}

/* ここまでソースプログラム */

[双方向リスト]←このソース

青い直線

/* (C) 2000- YFプロ. All Rights Reserved. */    提供:C言語講座−それ自体コンパイルできる教材を使った講座です−

青い直線

サイトマップ / C言語講座出入り口総目次目次:ヒープ領域>環状のデータ構造