15−5.自己参照構造体

この節で扱う、「自己参照構造体」は、初心者には少し難しいと思っていましたので、説明を控えていましたが、 ご質問を頂きましたので新たにまとめてみました。どうぞ、ご利用ください。(2001.7.6)

(1)自己参照構造体とは

自己参照構造体は、次に示す例のように、メンバに自分自身と同じタグの構造体をポインタで宣言しています。

struct list {
	char name[20];
	struct list *next;	/* 自己参照構造体 */
};

この自己参照構造体は一般にリスト処理で用いられます。

(2)リスト処理

今まで複数のデータをまとめて扱うときには配列を用いて処理をしてきました。

配列は連続するデータを一括して処理しているうちはいいのですが、途中にデータを挿入したり削除をするときに、それ以降のデータを前後にずらす必要があります。 数少ないデータでしたら、前後にデータをずらしても左程時間はかかりません。

しかし、大量のデータや頻繁にデータの追加や削除が行われるシステムでは、それは大変な無駄なのです。 そのような場合に、リスト構造を使ってデータを処理します。

【リスト構造の例】

リスト構造ではデータは物理的に連続に並んでいる必要はありません。 ポインタを使って、次のデータ部を参照することにより、連続した処理を可能にします。

【リストへのデータの挿入】

データを追加するときには、ポインタをつなぎ換え、新しいデータ部を指すようにします。

【リストからのデータの削除】

データを削除する場合には、不要になったデータはそのままにし、次のデータ部にポインタをつなぎ換えるようにします。

(3)自己参照構造体を使ったリスト処理

(例)
#include <stdio.h> 
#include <string.h>
#include <stdlib.h>

struct list {
	int key;			/* キー */
	char name[20];		/* 名前 */
	struct list *next;		/* 次のデータへのポインタ */
};

struct list *add_list(int key, char *name, struct list *head);
void show_list(struct list *p);
void free_list(struct list *p);

int main(void)
{
	struct list *head;		/* 先頭ポインタ */
	char name[20];
	int key = 0;
	
	head = NULL;		/* 先頭ポインタにNULLを設定 */
	
	printf("キーと名前(MAX:19文字)を入力(終了:CTRL+Z)\n");
	while (scanf("%d %s", &key, name) != EOF) {
		/* リストにデータを登録 */
		head = add_list(key, name, head);
	}
	/* リストの表示 */
	show_list(head);
	
	/* リストの開放 */
	free_list(head);

	return 0;
}

/*** リストにデータを登録 ***/
struct list *add_list(int key, char *name, struct list *head)
{
	struct list *p;
	
	/* 記憶領域の確保 */
	if ((p = (struct list *) malloc(sizeof(struct list))) == NULL) {
		printf("malloc error\n");
		exit(EXIT_FAILURE);
	}
	
	/* リストにデータを登録 */
	p->key = key;
	strcpy(p->name, name);
	
	/* ポインタのつなぎ換え */
	p->next = head;		/* 今までの先頭ポインタを次ポインタに */
	head = p;			/* 新たな領域を先頭ポインタに */
	
	return head;
}

/*** リストの表示 ***/
void show_list(struct list *p)
{
	while (p != NULL) {	/* 次ポインタがNULLまで処理 */
		printf("%3d %s\n", p->key, p->name);
		p = p->next;
	}
}

/*** リストの開放 ***/
void free_list(struct list *p)
{
	struct list *p2;

	while (p != NULL) {     /* 次ポインタがNULLまで処理 */
		p2 = p->next;
		free(p);
		p = p2;
	}
}


※Windows9xとMe上で、Windows系のCを用いて「CTRL+Z」の入力を実行した場合、
 「CTRL+Z」の入力後、次の改行までの表示が行なわれません。
※scanf() は、MS-DOS と Windows の環境では「Ctrl+Z」の入力で EOF を返却しますが、
 UNIXの環境では「Ctrl+D」の入力で EOF を返却します。

【関数 add_list の流れ】

  1. まず先頭ポインタ head に NULL を設定

  2. malloc で確保したエリアにデータ1 を格納し、head にデータ1 のアドレスを設定 head に格納されていた NULL は次ポインタへ

  3. malloc で確保したエリアにデータ2 を格納し、head にデータ2 のアドレスを設定

    head に格納されていたデータ1 のアドレスは次ポインタへ

【関数 show_list と free_list の流れ】

  1. まず head のアドレスを main より受け取る

  2. 次ポインタを次々につなぎ換えながらNULL(リスト終了)まで処理を行う。このとき、free_list では、ポインタをfreeする前に次ポインタを退避しておく。

  3. (実行結果例)
    キーと名前(MAX:19文字)を入力(終了:Ctrl+Z)
    1 Ryo
    2 Jiro
    3 Yoko
    4 Ayaka
    ^Z
      4 Ayaka
      3 Yoko
      2 Jiro
      1 Ryo
    
    演習
    ◆◆前ページ  ▲TOP▲  次ページ◆◆

    banner
    「初心者のためのポイント学習C言語」
    Copyright(c) 2000-2004 TOMOJI All Rights Reserved