第8回目 スタック(5/29)

今日のキーワード

■ スタック

■ 数のスタック

数のスタックは次のようになる。
/* list0801.c */
#define SIZE 20

typedef struct{
  int num[SIZE];
  int sp;
} Stack;


Stack *stack_initialize()
{
  Stack *ans;

  ans = (Stack *)malloc(sizeof(Stack));
  ans−>sp = −1;
  return ans;
}

void push(Stack *s, int n)
{
  s−>sp += 1;
  s−>num[s−>sp] = n;
}

int pop(Stack *s)
{
  int ans;

  ans = s−>num[s−>sp];
  s−>sp −= 1;
  return(ans);
}

main()
{
  Stack *s;

  s = stack_initialize();
  push(s,1);
  push(s,2);
  push(s,3);
  printf(”%d\n”,pop(s));
  printf(”%d\n”,pop(s));
  printf(”%d\n”,pop(s));
  free(s)
}

□ 演習1

■ ポインタのスタック

ポインタのスタックは次のように定義する。
typedef struct{
  Student *std[SIZE];
  int sp;
} Stack;
上では省略されているが、Stack 型の宣言をする前に、Student 型の宣言、SIZE の define を済ませておく。
初期化関数 stack_initialize は、list0801.c と同じである。
関数 push は、基本的に以下の処理をする。
int push(Stack *s, Student *s1)
{
  スタックポインタを1つ進める。
  sのstd配列のうち、スタックポインタの位置にある領域に、s1(アドレス値)を書き込む。
}
関数 pop は、基本的に以下の処理をする。
Student *pop(Stack *s)
{
  sのstd配列のうち、スタックポインタの位置にあるアドレス値を得る。
  スタックポインタを1つ戻す。
}
以前に作成した関数 print_student は、student_print に名前を変更する。
メイン関数は、次のとおりとする。
main()
{
  Stack *s;
  Student *st;

  s = stack_initialize();
  st = (Student *)malloc(sizeof(Student));
  set_gakuseki(st,”022002”);
  set_name(st,”天野淳介”);
  push(s,st);
  st = (Student *)malloc(sizeof(Student));
  set_gakuseki(st,”022004”);
  set_name(st,”有川竜則”);
  push(s,st);
  st = (Student *)malloc(sizeof(Student));
  set_gakuseki(st,”022005”);
  set_name(st,”淡路啓太”);
  push(s,st);

  st = pop(s);
  student_print(st);
  free(st);
  st = pop(s);
  student_print(st);
  free(st);
  st = pop(s);
  student_print(st);
  free(st);
}
実行中にメモリの確保されるイメージ
数のスタックの例では、数の実体を配列変数としてスタック内に確保している。一方、構造体 Studentのスタックの例では、Student の実体はスタック(Stack)内に確保せず、その代りに Student へのポインタを配列変数として確保している。スタックは、一時的にデータを格納する場所であり頻繁に書き換えられる。実体でなくポインタを用いることで、Student のデータ(学籍番号や名前)を頻繁にコピーすることを避けている。

□ 演習2

  1. 上記のメイン関数が動作するように、pushとpopを完成させよ。ただし、 エラー処理として、関数 push は、成功すると1を返し、失敗すると0を返すこと。そして、関数 pop は、成功するとStudentへのポインタを返し、失敗するとNULLを返すこと。⇒ prac0802.c
  2. 次のようにメイン関数を作ると、ファイルからデータを入力することができる。動作を確認せよ。⇒ prac0803.c
    • メイン関数の例
      main()
      {
        char buff[BUFSIZ];
        char gakuseki[BUFSIZ];
        char name[BUFSIZ];
        Stack *s;
        Student *st;
      
        s = stack_initialize();
        while(fgets(buff,BUFSIZ,stdin)!=NULL){
          st = (Student *)malloc(sizeof(Student));
          sscanf(buff,”%s %s”,gakuseki,name);
          set_gakuseki(st,gakuseki);
          set_name(st,name);
          push(s,st);
        }
      
        while((st=pop(s))!=NULL){
          student_print(st);
          free(st);
        }
      }
      
    • 入力ファイルの例(datafile という名前で保存)
      022021 河村英明
      022022 岸田純弥
      022023 岸田優樹
      022024 岸本崇史
      022025 木下俊吾
      
    • 実行例
      gcc prac0803.c
      ./a.out < datafile
      022025 木下俊吾
      022024 岸本崇史
      022023 岸田優樹
      022022 岸田純弥
      022021 河村英明
      

■ 宿題


(c) Masato TOKUHISA, 2003, May. 27