質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

1498閲覧

c言語双方向循環リスト番兵ノードについて

pocomi

総合スコア3

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2022/05/11 04:54

編集2022/05/11 07:07

現在双方向循環リストでrotateをする関数を書いてるのですが、-1である番兵ノードがどうしても出力されてしまい、番兵ノードを出力しない出力方法が思いつきません。
どなたかアドバイスを頂きたいです。

C

1#include <stdio.h> 2#include <stdlib.h> 3 4struct t_node { 5 struct t_node *next; 6 struct t_node *prev; 7 int data; 8}; 9struct t_node *first_node(int data) { 10 struct t_node *head; 11 head = malloc(sizeof(struct t_node *)); 12 head->next = head; 13 head->prev = head; 14 head->data = data; 15} 16void add_back(struct t_node *list, int data) { 17 struct t_node *node; 18 struct t_node *p = list; 19 node = malloc(sizeof(struct t_node *)); 20 if (node == NULL) 21 return; 22 while (p->next != list) { 23 p = p->next; 24 } 25 p->next->prev = node; 26 p->next = node; 27 node->prev = p; 28 node->data = data; 29 node->next = list; 30} 31void print(struct t_node *head) { 32 struct t_node *tmp; 33 if (head == NULL) 34 return; 35 tmp = head->next; 36 printf("tmp data is %d\n", tmp->data);//5 37 printf("head data is %d\n", head->data);//1 38 while (tmp != head) { 39 printf("%d ", tmp->data); 40 tmp = tmp->next; 41 } 42 printf("%d", tmp->data); 43 printf("\n"); 44} 45void swap(struct t_node *n1, struct t_node *n2) { 46 int tmp; 47 tmp = n1->data; 48 n1->data = n2->data; 49 n2->data = tmp; 50} 51void rotate(struct t_node *list_head) { 52 struct t_node *change_list_head_next; 53 struct t_node *head; 54 struct t_node *last; 55 first_node(0); 56 change_list_head_next = list_head->next; 57 swap(change_list_head_next, list_head); 58 head = list_head->next; 59 last = head->prev; 60 print(head->next); 61 return; 62} 63int main(void) { 64 struct t_node *list_head; 65 struct t_node *change_list_head_next; 66 list_head = NULL; 67 list_head = first_node(-1); 68 add_back(list_head, 3); 69 add_back(list_head, 1); 70 add_back(list_head, 5); 71 print(list_head); 72 rotate(list_head); 73}

出力結果
-1を消したい。

C

13 1 5 -1 25 3 -1 1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ozwk

2022/05/11 05:16

実行するとコアダンプ(Illegal instruction (core dumped))が発生して出力結果を得るどころではありません。 おそらくコードを貼り間違えていますので修正してください
melian

2022/05/11 05:36

ところで、memory sanitizer 付きでコンパイルして実行すると、 head = malloc(sizeof(struct t_node *)); と node = malloc(sizeof(struct t_node *)); の直後で heap buffer overflow が発生します。理由は、、明白ですよね。
episteme

2022/05/11 05:52

関数:first_node() が t_node* を返していません。
guest

回答3

0

折角の双方向リストなのですから、 head->prev を使ったり、循環をノードの(先頭と最後で)移動で行ったりしては如何でしょうか。
(というより、そうしないと双方向リストを使う意味が無いのでは。)

c

1#include <stdio.h> 2#include <stdlib.h> 3 4typedef struct t_node { 5 struct t_node *next; 6 struct t_node *prev; 7 int data; 8} Node; 9 10void initPointers(Node *node) { 11 node->next = node; 12 node->prev = node; 13} 14 15Node *createNode(int data) { 16 Node *node = malloc(sizeof(Node)); 17 if(node == NULL) return NULL; //error 18 initPointers(node); 19 node->data = data; 20 return node; 21} 22//最後に追加 23void addLast(Node *head, Node *node) { 24 Node *last = head->prev; 25 node->prev = last; 26 node->next = head; 27 last->next = node; 28 head->prev = node; 29} 30//先頭に追加 31void addFirst(Node *head, Node *node) { 32 Node *first = head->next; 33 node->prev = head; 34 node->next = first; 35 head->next = node; 36 first->prev = node; 37} 38//最後を削除 39Node *removeLast(Node *head) { 40 if(head->prev == head) return NULL; 41 Node *last = head->prev; 42 head->prev = last->prev; 43 last->prev->next = head; 44 initPointers(last); 45 return last; 46} 47//最初を削除 48Node *removeFirst(Node *head) { 49 if(head->next == head) return NULL; 50 Node *first = head->next; 51 head->next = first->next; 52 first->next->prev = head; 53 initPointers(first); 54 return first; 55} 56 57void print(Node *head) { 58 for(Node *p = head->next; p != head; p = p->next) { 59 printf("%d ", p->data); 60 } 61 printf("\n"); 62} 63 64void rotateRight(Node *head) { 65 Node *last = removeLast(head); 66 if(last != NULL) addFirst(head, last); 67} 68void rotateLeft(Node *head) { 69 Node *first = removeFirst(head); 70 if(first != NULL) addLast(head, first); 71} 72 73int main(void) { 74 Node *head = createNode(-1); 75 76 addLast(head, createNode(3)); 77 addLast(head, createNode(1)); 78 addLast(head, createNode(5)); 79 print(head); 80 81 //rotateLeft(head); 82 rotateRight(head); 83 print(head); 84}

plain

13 1 5 25 3 1

ikedas さんご提案の構造にしてみました。テストも追加。

c

1#include <stdio.h> 2#include <stdlib.h> 3 4typedef struct t_node { 5 struct t_node *next; 6 struct t_node *prev; 7 int data; 8} Node; 9 10Node *createNode(int data) { 11 Node *node = malloc(sizeof(Node)); 12 if(node == NULL) return NULL; //error 13 node->next = NULL; 14 node->prev = NULL; 15 node->data = data; 16 return node; 17} 18//最後に追加 19void addLast(Node **head, Node *node) { 20 if(*head == NULL) { //データ無し 21 *head = node; 22 node->next = node; 23 node->prev = node; 24 } else { 25 node->next = *head; 26 node->prev = (*head)->prev; 27 node->next->prev = node; 28 node->prev->next = node; 29 } 30} 31 32void print(Node *head) { 33 Node *p = head; 34 if(p != NULL) { 35 do { 36 printf("%d ", p->data); 37 } while((p = p->next) != head); 38 } 39 printf("\n"); 40} 41 42void rotateRight(Node **head) { 43 if(*head != NULL) *head = (*head)->next; 44} 45void rotateLeft(Node **head) { 46 if(*head != NULL) *head = (*head)->prev; 47} 48 49int main(void) { 50 Node *head = NULL; 51 52 addLast(&head, createNode(3)); 53 addLast(&head, createNode(1)); 54 addLast(&head, createNode(5)); 55 print(head); 56 57 rotateRight(&head); //右へ1回 58 print(head); 59 60 addLast(&head, createNode(7)); //7を追加して 61 print(head); 62 63 rotateLeft(&head); //左へ2回 64 rotateLeft(&head); 65 print(head); 66}

plain

13 1 5 25 3 1 35 3 1 7 41 7 5 3

投稿2022/05/11 07:13

編集2022/05/11 19:20
jimbe

総合スコア12646

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ikedas

2022/05/11 09:11

というか循環リストなので、リストを変更しなくても``head->prev``や``head->next``が求めるものになっているとも思います。
jimbe

2022/05/11 18:31

head が循環の中に含まない、 3,1,5 のノードだけで循環するようにすれば、 head の位置をずらすだけになりますね。
guest

0

ベストアンサー

番兵ノードを設ける理由は、リスト上のノードを渡り歩く際にリスト終端の判定を簡単にしたりするためだと思います。

しかしご提示のコードでは、各関数のループの条件がadd_back()ではp->next != listprint()ではtmp != headとなっていて、関数の引数として与えられたノードに達するとループが停止するようになっています。このように停止すべきノードが毎回与えられるのならば、番兵のような特別なノードはいらないですよね。

つまり、最初にfirst_node()で作成するノードも番兵ノードではなく普通のノードだと考えられますから、出力しないようにする必要はないです。


ご質問の点にのみ回答しました。現在のコードを上記のように変えただけで意図した通りの動作をするのかどうかについては確認していません。

投稿2022/05/11 06:03

ikedas

総合スコア4333

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Java

1void print(struct t_node *head) { 2 struct t_node *tmp; 3 if (head == NULL) 4 return; 5 tmp = head->next; 6 printf("tmp data is %d\n", tmp->data);//5 7 printf("head data is %d\n", head->data);//1 8 while (tmp != head) { 9 printf("%d ", tmp->data); 10 tmp = tmp->next; 11 } 12 printf("%d", tmp->data); // ここでもprintfするのはなぜ? 13 printf("\n"); 14}

投稿2022/05/11 04:57

episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pocomi

2022/05/11 05:01

printf("%d", tmp->data); // ここでもprintfするのはなぜ? 出力結果にある最後の1が出力されなくなってしまうのでprintfで出力しています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問