見出し画像

(答案再提出)C言語教室 第20回 - 双方向リスト

先日提出した下記の答案ですが、kznさんからのご指摘に基づいて修正しました。ご指導有り難うございました。

修正点を元の記事に纏めるとややこしいので、別記事にしました。

※ 冒頭の写真は、「ああ〜!やってしまった」と言っているような雰囲気でチョイスしました。(Johannes Vermeer / Allegory of the Catholic Faith

修正版

(修正点1)Lesson20−3 n番目の要素を返す関数

与えた n が要素の数よりひとつだけ大きかった場合に、おかしな値が返るようです。それからエラーの時に -1 を返すと、要素が -1 だった時に困ってしまいます。ここは値ではなくポインタを返す関数を書いてください。

https://note.com/kazushinakamura/n/nf78b037d62c5?from=notice

ご指摘のとおりで、グーの音も出ません。
修正したコードは以下の通り。

Node * get_Nth_node(Node *head, int seq) {
  Node *current_node = head;

  for (int i = 0; i < seq; i++) {
    if (current_node->next == NULL) return NULL;
    current_node = current_node->next;
  }

  return current_node;
}

見つからなかった場合をチェックするのは、current_nodeではなく、current_node->nextであるべきでしたね。目的のnodeに到達前に現在のnodeの次がなければ(NULLならば)、見つからなかったと判断できます。


(修正点2)序数

序数に負は無いので、答えが負のときは違う表現が良かろうかと。

https://note.com/kazushinakamura/n/nf78b037d62c5?from=notice

おっしゃる通り。
マイナス1番目で見つけたのではなくて、探しているものはないと表示すべきですね。


修正後の実行結果

Lesson20-1: リストの最後に要素を追加する関数
List(head->tail): 10 20 30 40 50 
List(tail->head): 50 40 30 20 10 
the number of nodes in the list : 5

Lesson20-2: リストの先頭の要素を削除する関数
List(head->tail): 20 30 40 50 
List(tail->head): 50 40 30 20 
the number of nodes in the list : 4

Lesson20-3: n番目の要素を返す関数
0th val in the list : 20
1st val in the list : 30
2nd val in the list : 40
3rd val in the list : 50
Specified number(4) is out of range.

Lesson20-4: 要素の中に指定した値が含まれるかを返す関数(見つからなければ−1を返す)
Search value 40 was found in the 2nd node.
Search value 90 was not found in the list.


clangでコンパイル & 実行

、、、Ayumiさん、見て見て、No error, no warning!

jm3nrhMac-mini-:c akio$ gcc lesson20_r1.1.c
jm3nrhMac-mini-:c akio$ ./a.out
Lesson20-1: リストの最後に要素を追加する関数
List(head->tail): 10 20 30 40 50 
List(tail->head): 50 40 30 20 10 
the number of nodes in the list : 5

Lesson20-2: リストの先頭の要素を削除する関数
List(head->tail): 20 30 40 50 
List(tail->head): 50 40 30 20 
the number of nodes in the list : 4

Lesson20-3: n番目の要素を返す関数
0th val in the list : 20
1st val in the list : 30
2nd val in the list : 40
3rd val in the list : 50
Specified number(4) is out of range.

Lesson20-4: 要素の中に指定した値が含まれるかを返す関数(見つからなければ−1を返す)
Search value 40 was found in the 2nd node.
Search value 90 was not found in the list.

Apple clang version 14.0.3 (clang-1403.0.22.14.1)


ソースコードはこちら

/**********************************************************************
	lesson20 doubly linked list
		by Akio van der Meer

[変更履歴]
 (無印)  記事初投稿時のコード
 r1.0   2023/4/4 
        1. get_Nth_node()の戻り値をポインタ型とし、指定した番号が範囲外の場合は
          NULLを返すように変更。
        2. search_val_in_node()で、指定された値が見つからなかった場合の表示を変更。
 r1.1   2023/4/5
        1. 表示のスペルミス修正
        2. lesson20-4の処理結果表示を関数化 

**********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Srch_val_1 40
#define Srch_val_2 90

typedef struct node {
  int val;
  struct node *next;
  struct node *prev;
} Node;

void append_node(Node **head, Node **tail, int val) {
  Node *new_node = (Node *)malloc(sizeof(Node));
  new_node->val = val;
  new_node->next = NULL;

  *tail = new_node;

  if (*head == NULL) {
    *head = new_node;
    new_node->prev = NULL;
      
  } else {
    Node *current_node = *head;
  
    while (current_node->next != NULL) {
        current_node = current_node->next;
    }

    current_node->next = new_node;
    new_node->prev = current_node;
  }
}

void delete_first_node(Node **head, Node **tail) {
  Node *current_node = *head;
   
  if (current_node->next == NULL){
    *head = NULL;
    *tail = NULL;
        
  } else {
    Node *next_node = current_node->next;
    *head = next_node;
    next_node->prev = NULL;
  }
    
  free(current_node);
}

Node * get_Nth_node(Node *head, int seq) {
  Node *current_node = head;

  for (int i = 0; i < seq; i++) {
    if (current_node->next == NULL) return NULL;
    current_node = current_node->next;
  }

  return current_node;
}

int search_val_in_node(Node *head, int srch_val) {
  int cnt = 0;
  int rtn = -1;

  Node *current_node = head;

  while (current_node->next != NULL) {
    if (current_node->val == srch_val) {
      rtn = cnt;
    }
    cnt++;
    current_node = current_node->next;
  }

  return rtn;
}

int count_nodes(Node *head) {
  int cnt = 0;
  Node *current_node = head;

  while (current_node != NULL) {
    cnt++;
    current_node = current_node->next;
  }
  return cnt;
}

void print_all_nodes(Node *head) {
  printf("List(head->tail): ");
  
  Node *current_node = head;
  while (current_node != NULL) {
    printf("%d ", current_node->val);
    current_node = current_node->next;
  }
    printf("\n");
}

void print_reverse_all_nodes(Node *tail) {
  printf("List(tail->head): ");

  Node *current_node = tail;  
   while (current_node != NULL) {
    printf("%d ", current_node->val);
    current_node = current_node->prev;
  }
    printf("\n");
}

void free_nodes(Node **head, Node **tail) {
  Node *current_node = *head;
  while (current_node != NULL) {
    Node *next_node = current_node->next;
    free(current_node);
    current_node = next_node;
  }

  *head = NULL;
  *tail = NULL;
}

char * ordinal_number(int num, char *buf) {
  int len = 0;

  sprintf(buf, "%d", num);
  len = strlen(buf);

  if ((len > 1) && (buf[len - 2] =='1')) {
    strcat(buf, "th"); 
  
  } else {

    switch (buf[len - 1]) {
      case '1': strcat(buf, "st"); break;
      case '2': strcat(buf, "nd"); break;
      case '3': strcat(buf, "rd"); break;
      default : strcat(buf, "th");
    }
  }

  return buf;
}

void print_search_result(Node *head, int srch_val, char *buf) {
  int rst = 0;
  
  rst = search_val_in_node(head, srch_val);
  if (rst != -1) {
    printf("Search value %d was found in the %s node.\n", 
      srch_val, ordinal_number(rst, buf));
  } else {
    printf("Search value %d was not found in the list.\n", srch_val);
  } 
}

int main() {
  Node *head = NULL;
  Node *tail = NULL;

// Lesson20-1 -----------------------------------------------------
  printf("Lesson20-1: リストの最後に要素を追加する関数\n");
  
  append_node(&head, &tail, 10);
  append_node(&head, &tail, 20);
  append_node(&head, &tail, 30);
  append_node(&head, &tail, 40);
  append_node(&head, &tail, 50);

  print_all_nodes(head);
  print_reverse_all_nodes(tail);
  printf("the number of nodes in the list : %d\n", count_nodes(head));

// Lesson20-2 -----------------------------------------------------
  printf("\nLesson20-2: リストの先頭の要素を削除する関数\n");
  delete_first_node(&head, &tail);

  print_all_nodes(head);
  print_reverse_all_nodes(tail);
  printf("the number of nodes in the list : %d\n", count_nodes(head));

// Lesson20-3 -----------------------------------------------------
  printf("\nLesson20-3: n番目の要素を返す関数\n");
  Node * found_node = NULL;
  char buf[11];

  //for (int i = 0; i < count_nodes(head); i++) {
  //敢えて、リスト内のnode数よりも大きな値を関数に与える
  for (int i = 0; i < 5; i++) {     
    found_node = get_Nth_node(head, i);

    if (found_node != NULL) {
        printf("%s val in the list : %d\n", 
          ordinal_number(i, buf), found_node->val);
    } else {
        printf("Specified number(%d) is out of range.\n", i);
    }
  }

// Lesson20-4 -----------------------------------------------------
  printf("\nLesson20-4: 要素の中に指定した値が含まれるかを返す関数(見つからなければ−1を返す)\n");

  print_search_result(head, Srch_val_1, buf);
  print_search_result(head, Srch_val_2, buf);

// 終了処理 ---------------------------------------------------------
  free_nodes(&head, &tail);

  return 0;
}


後記

今回は指摘なしだと思ったんだけどなぁ。
まだまだ修行が足りないようです。

clangでコンパイルする場合、関数が使う別の関数は、それ以前に定義されてないとエラーになるんですね!
Web環境だとエラーとはならなかったのでびっくり。ちゃんと関数を定義しているのに、clangコンパイラから関数が未定義というエラーを返されて、なかなかその意味がわからなかった。


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

いいなと思ったら応援しよう!

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