構造体の双方向リンク
前回紹介した一方向のリンクは、このように非常にシンプルで扱いも楽です。しかし、1つ大きな欠点があります。先頭から次々にリンクをたどっていくことはできても、前に戻ることができない──という点です。
前に戻るためのポインタ
「前に戻れない」理由は、構造体のメンバに『次の構造体へのポインタ』しか含んでいないためです。先頭方向にも戻れるようにするためには、メンバに『1つ前の構造体へのポインタ』を追加すればよいわけです。
typedef struct _result{
short int id;
char name[16];
short int score;
struct _result *prev; -------- 1つ前を示すポインタ
struct _result *next; -------- 次を示すポインタ
} result;
先頭の構造体で1つ前を示すメンバ(*prev)と、最後の構造体の次を示すメンバ(*next)にはNULLを代入します。すると、複数の構造体が図1のようにつながります。
このような形を『構造体の双方向リンク』と呼びます。
前後に移動できるプログラム
前回と同じ氏名と成績(点数)を保持する構造体を、双方向リンクでつなぐプログラムを作ってみましょう。今度は、現在参照している構造体の前後を自在に移動できるので、プログラムは以下のような仕様にします。
[N]キーを押すと次のデータを表示
[B]キーを押すと1つ前のデータを表示
[Q]キーを押せばプログラムが終了
先頭データを表示しているときに[B]キーを押しても何もしない
最後のデータを表示しているときに[N]キーを押しても何もしない
リスト2:双方リンクで構造体を前後に移動できるようにしたプログラム(ex3202.c)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
/* 構造体 result を定義 */
typedef struct _result{
short int id;
char name[16];
short int score;
struct _result *prev;
struct _result *next;
} result;
int i; /* ループカウンタ */
result *p, *start; /* 構造体のポインタ */
char ans[4]; /* 入力用 */
result *now; /* 現在注目している構造体を示す */
result *q; /* メモリ解放用 */
/* 元データを配列で準備 */
char _name[5][16] = {"Taro","Hanako","Sayaka","Miki","Hiroshi"};
short int _score[5] = {50, 60, 70, 80, 30};
/* 配列の値を構造体のリンクに */
for (i=0; i<5; i++) {
if (i==0) {
/* 先頭の構造体を生成 */
p = malloc(sizeof(result));
start = p; /* 先頭を保存 */
/* 先頭のみ1つ前にNULLを代入 */
p->prev = NULL;
} else {
/* 次の構造体を生成 */
p->next = malloc(sizeof(result));
/* 次の1つ前=現在の構造体 */
p->next->prev = p;
/* 次の構造体に移動 */
p = p->next;
}
/* IDはカウンタ変数から生成 */
p->id = (short int)i+1;
/* 2項目を代入 */
strcpy(p->name, _name[i]);
p->score = _score[i];
p->next = NULL;
}
/* キー待ちのループ */
now = start;
printf("ID\tName\tScore\n");
printf("%04d\t%s\t%d\n", now->id, now->name, now->score);
printf("? ");
gets(ans);
while ((ans[0] != 'Q') && (ans[0] != 'q')) {
switch (ans[0]) {
case 'N' :
case 'n' :
if (now->next != NULL) {
now = now->next;
}
break;
case 'B' :
case 'b' :
if (now->prev != NULL) {
now = now->prev;
}
defaulet : break;
}
printf("%04d\t%s\t%d\n", now->id, now->name, now->score);
printf("? ");
gets(ans);
}
/* 構造体のリンクをたどってメモリを解放する */
p = start; -------- ポインタを先頭に位置付ける
while (p != NULL) {
q = p->next; /* 次へのポインタを保存 */
free(p);
p = q;
}
return (0);
}
サンプルの実行結果
このプログラムの実行結果は、例えば以下のようにnなります。[N]または[B]キーを入力して、データの表示が前後に移動することを確かめてください。[Q]キーを入力するとプログラムは終了します。
配列の値を書き換えれば、異なるデータを表示することができるのは、前回のサンプルと同じです。
画面1:キーの入力でデータを前後に移動できるプログラム(ex3202.exe)の実行結果
0001 Taro 50
? n
0002 Hanako 60
? n
0003 Sayaka 70
? n
0004 Miki 80
? b
0003 Sayaka 70
? n
0004 Miki 80
? n
0005 Hiroshi 30
? n
0005 Hiroshi 30
? b
0004 Miki 80
? b
0003 Sayaka 70
? b
0002 Hanako 60
? b
0001 Taro 50
? b
0001 Taro 50
? b
0001 Taro 50
? n
0002 Hanako 60
? q
|
|
|