
(答案再提出)C言語教室 第20回 - 双方向リスト
先日提出した下記の答案ですが、kznさんからのご指摘に基づいて修正しました。ご指導有り難うございました。
修正点を元の記事に纏めるとややこしいので、別記事にしました。
※ 冒頭の写真は、「ああ〜!やってしまった」と言っているような雰囲気でチョイスしました。(Johannes Vermeer / Allegory of the Catholic Faith)
修正版
(修正点1)Lesson20−3 n番目の要素を返す関数
与えた n が要素の数よりひとつだけ大きかった場合に、おかしな値が返るようです。それからエラーの時に -1 を返すと、要素が -1 だった時に困ってしまいます。ここは値ではなくポインタを返す関数を書いてください。
ご指摘のとおりで、グーの音も出ません。
修正したコードは以下の通り。
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)序数
序数に負は無いので、答えが負のときは違う表現が良かろうかと。
おっしゃる通り。
マイナス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コンパイラから関数が未定義というエラーを返されて、なかなかその意味がわからなかった。
ここまで読んでいただき、有り難うございました。
いいなと思ったら応援しよう!
