PROG 13.3 個数を指定せず、動的に整数データ格納 (p.96 参考)

問題

[実行結果]
19
30
41 (←ここまで入力。control zとENTER)
 19 (先頭から、出力)
 30
 41

[配列ではなくリスト] [append関数] [コメント]
  (セル図)
  • 配列を使用しないで、整数データを格納する構造体を使う。次の構造体へのポインタも格納して、先頭からつないでいく。
  • 1つずつのデータが構造体。次のデータへのポインタ(アドレス)をもつ
/* 整数と、次の要素を示すポインタからなる構造体を定義。次々つないでいく。typedefで、list型を定義 */

typedef struct _list {
   int n;
   struct _list *next;
} list
  • append関数は、これまでのデータの最後に追加する。ptは先頭の構造体を指すポインタ
/* 繰り返して、append */
int main (void) {
   int i;
   list *pt;

   pt = NULL;  /* 空リストの準備完了 */ /* ptは、私たちのセル図ではLにあたる */

   while (scanf("%d", &i) != EOF) {
      pt = append(pt, i); /* ptから辿り、最後にi */
           /* 今回のappendはvoid型ではなく、リスト最初のセルのアドレスを戻り値
        whileループ内のptは最初NULL。1つ要素をappendしたあと、先頭アドレスはずっと同じ */
   }

   printlist(pt); /* 先頭からプリント */

   FreeData(pt);  /* 先頭から、1つずつfree */

   return (0);
}
  • リストを、構造体を使って実装する方法はいくつかある。
  • 今回の方法は、先頭要素の扱いが、「あるごりずむ」の方法とは異なる。
  • どちらにも慣れてほしい。

[プログラム]

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

/* 場合に応じて関数を切り替えるときに、置き換え(define)を使う */
#define MALLOC malloc
/*  
#define MALLOC GC_MALLOC
*/
#define FREE free

/* 整数と、次の要素を示すポインタからなる構造体を定義。次々つないでいく */
typedef struct _list {
    int n;
    struct _list *next;
}  list;

/* list型データを1つ作成する。アドレスが戻り値 */
list *newList (void) {
    list *tmppt;
    tmppt = (list *)MALLOC(sizeof(list));
    tmppt->next = NULL; /* nextはNULLで初期化 nは初期化せず */
    return tmppt;
}

/* 最後に追加 : NULLだったら (最後の要素を見つけたら)
   セルを一つ 作成して 付け替える。append関数は、先頭のアドレスを返す */
list *append (list *pt, int i) {
    list *newcell;

    if (pt == NULL) { /* セルを1つ作っているだけ。ptとはつないでいないことに注意 */
        newcell = newList();
        newcell->n = i;
        return newcell;  /* セルのアドレスをリターン。では、どこでつながるのか */
     } else { /* 再帰条件 */     
        pt -> next = append(pt->next, i); /* ここ、何を言っているのか、読もう */
        return pt; /* 自分をリターン。つまり、リストの先頭 */
     }
}
 
void printlist (list *pt) {
    while (pt != NULL) {
        printf("%3d \n", pt -> n);
        pt = pt -> next;
    }
}

/* p.96より */
void FreeData(list *pt) {
    if (pt != NULL) {
        FreeData(pt->next);
        FREE (pt);
    }
}


/* Control zまで、繰り返して、append */
int main (void) {
    int i;
    list *pt;

    pt = NULL; /* 空リスト準備完了 */

    while (scanf("%d", &i) != EOF) {
        pt = append(pt, i);
    }

    printlist(pt); /* 先頭からプリント */

    FreeData(pt);  /* 先頭から、1つずつfree */

    return (0);
}