見出し画像

(答案再提出)C言語教室 第23回 - スタックとキュー(キュー編、その4)

前回の記事(「(答案提出)C言語教室 第23回 - スタックとキュー(キュー編、その3)」)で決定版だと思っていたのに、見事にバグってました。

Ayumiさん、ご指摘有り難うございました!
データの境界あたりに注目するあたり、
常識と言われればそれまでですが、
さすが現役ベテラン、目の付け所が違いますね!!

こうなったらともう一踏ん張りいってみましょう。
丁度、GW真っ最中で時間はあるし!

Ayumiさんからのメッセージ

AyumiKatayama
2023年5月1日 09:37

何度もすいません。
ちょっと違っていて・・・。

(1)init_queue
(2)enqueue 10回
(3)dequeue 10回

(1)~(3)を実行したあとにもう一回 dequeue したら、戻り値が true になるんです。キューはもうないですから、戻り値は false が正しいかなと思います。これは、enqueue の10回目に問題があるんですね。

https://note.com/jm3nrh/n/nb9a11a07550d?from=notice

調査結果

queue[]を丁度使い切った直後、queue_top(キューを書き出すポイント)がQueue_MAXの状態になった時、dequeue()関数を実行してqueue_bottom(キューを読み出すポイント)がqueue_topに達するとdequeue()を終了させないといけないのに、queue_bottomが0にリセットされてしまうため、無限にqueue_topに達することがなくなり、dequeue()を無限に実行できるようになってしまいます。

この現象は、一旦queue_top == Que_MAXとなると、後の処理がおかしくなる形で出現します。

テストデータ設計に問題がありましたね。
全ての条件式を網羅するようなデータになってませんでした。反省。

Ayumiさんのご指摘は、enqueue()の10回目に問題があるということでしたが、私的にはenqueue()実行のタイミングでどの配列要素にセットするのかを判断したいので、dequeue()の方のロジックを修正することにしました。

また、こうすることでenqueue()とdequeue()関数のロジックが対照的となってスッキリしました。

修正箇所

bool dequeue(int *queue, int *val) {
  *val = 0;

  if (is_reverse == true) {
    if (queue_bottom < Queue_MAX) {
      *val = queue[queue_bottom];
      queue[queue_bottom++] = 0;
      return true;
    } else {
      queue_bottom = 0;
      is_reverse = false;
    }
  }

  if (is_reverse == false) {
    if (queue_bottom < queue_top) {
        *val = queue[queue_bottom];
        queue[queue_bottom++] = 0;
        return true;
    } else {
      printf("Queue is Empty!\n");
      return false;
    }
  } 
  return true;
}

ソースコード

実行結果

jm3nrhMac-mini-:c akio$ gcc lesson23_r1.3.c
jm3nrhMac-mini-:c akio$ ./a.out
初期状態--------------

print_queue: 
queue dump: 00 00 00 00 00 00 00 00 00 00 

10回追加--------------
enqueued (1)
enqueued (2)
enqueued (3)
enqueued (4)
enqueued (5)
enqueued (6)
enqueued (7)
enqueued (8)
enqueued (9)
enqueued (10)

print_queue: 01 02 03 04 05 06 07 08 09 10 
queue dump: 01 02 03 04 05 06 07 08 09 10 

11回 取り出し--------------
dequeued (1)
dequeued (2)
dequeued (3)
dequeued (4)
dequeued (5)
dequeued (6)
dequeued (7)
dequeued (8)
dequeued (9)
dequeued (10)
Queue is Empty!

print_queue: 
queue dump: 00 00 00 00 00 00 00 00 00 00 

11回追加--------------
enqueued (11)
enqueued (12)
enqueued (13)
enqueued (14)
enqueued (15)
enqueued (16)
enqueued (17)
enqueued (18)
enqueued (19)
enqueued (20)
Queue is FULL! (21 has not been queued.)

print_queue: 11 12 13 14 15 16 17 18 19 20 
queue dump: 11 12 13 14 15 16 17 18 19 20 

10回 取り出し--------------
dequeued (11)
dequeued (12)
dequeued (13)
dequeued (14)
dequeued (15)
dequeued (16)
dequeued (17)
dequeued (18)
dequeued (19)
dequeued (20)

print_queue: 
queue dump: 00 00 00 00 00 00 00 00 00 00 

4回追加--------------
enqueued (22)
enqueued (23)
enqueued (24)
enqueued (25)

print_queue: 22 23 24 25 
queue dump: 22 23 24 25 00 00 00 00 00 00 

2回 取り出し--------------
dequeued (22)
dequeued (23)

print_queue: 24 25 
queue dump: 00 00 24 25 00 00 00 00 00 00 

9回追加--------------
enqueued (26)
enqueued (27)
enqueued (28)
enqueued (29)
enqueued (30)
enqueued (31)
enqueued (32)
enqueued (33)
Queue is FULL! (34 has not been queued.)

print_queue: 24 25 26 27 28 29 30 31 32 33 
queue dump: 32 33 24 25 26 27 28 29 30 31 

11回 取り出し--------------
dequeued (24)
dequeued (25)
dequeued (26)
dequeued (27)
dequeued (28)
dequeued (29)
dequeued (30)
dequeued (31)
dequeued (32)
dequeued (33)
Queue is Empty!

print_queue: 
queue dump: 00 00 00 00 00 00 00 00 00 00 

jm3nrhMac-mini-:c akio$ 


ChatGPT様に褒めてもらうことにした

これまで散々ダメ出しされて、メンタルがしんどくなってきたので、Ayumiさんのアドバイスもあり、ChatGPT様にこのコードの優れた点について指摘してもらうことにした。

次のコードの優れている点について述べよ

このコードの優れている点は、以下の通りです。

1. キューの初期化
init_queue()関数で、動的にint型配列を作成し、その全要素を0で初期化しています。これにより、キューが最初は空であることを明示的に示し、問題を防ぎます。

2. キューへの要素追加
enqueue()関数では、キューの先頭(queue_top)に要素を追加します。また、キューが一杯になった場合、配列の先頭から再度要素を追加するため、is_reverseフラグを立ててキューの方向を反転します。このようにすることで、常にキューに要素を追加することができます。

3. キューからの要素の取り出し
dequeue()関数では、キューの先頭(queue_bottom)から要素を取り出します。また、キューが空になった場合、配列の先頭から再度要素を取り出すため、is_reverseフラグを立ててキューの方向を反転します。このようにすることで、常にキューから要素を取り出すことができます。

4. デバッグのための出力
print_queue()関数では、キューに格納されている要素を表示します。また、dump_queue()関数では、キューに格納されている要素をすべて表示します。これらの関数は、デバッグの際に非常に役立ちます。

5. エラーハンドリング
enqueue()関数では、キューが一杯の場合、エラーメッセージを表示してfalseを返します。また、dequeue()関数では、キューが空の場合、エラーメッセージを表示してfalseを返します。これらの処理により、プログラムの安全性を高めます。

https://chat.openai.com/

うんうん、わかってるね〜。
今夜はぐっすり眠れそうだ、、、(苦笑


ここまで読んでいただき、有り難うございました。

この記事が参加している募集

#AIとやってみた

27,969件

これまでの収益は全て、それを必要としておられる方々へ、支援機関を通して寄付させていただきました。この活動は今後も継続したいと思っています。引き続きよろしくお願いいたします。