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

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

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

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

連結リスト

連結リストとは、データ構造のひとつであるリストの中で、要素が前後の要素の情報を持つことで、要素が連結(リンク)しているリストの事を呼びます。

Q&A

解決済

2回答

1266閲覧

連結リストに限界などありますか?

dgtack25

総合スコア8

C

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

連結リスト

連結リストとは、データ構造のひとつであるリストの中で、要素が前後の要素の情報を持つことで、要素が連結(リンク)しているリストの事を呼びます。

0グッド

0クリップ

投稿2021/09/25 22:32

前提・実現したいこと

C言語で、入力した回数分のフィボナッチ数列を生成するプログラムを作成しています。
例:入力された数が5なら8、入力された数が8なら34

表示するのは上位100桁で、10,000を入力したときに正常に動くようにしたいです。

発生している問題・エラーメッセージ

基本的にはしっかり動作しているのですが、入力した数が3,618を超えると計算が止まり、プログラムが強制的に終了してしまいます。

該当のソースコード

C言語

1#include <stdio.h> 2#include <stdlib.h> 3 4typedef struct node { 5 struct node* prev; 6 short int l; 7 short int m; 8 struct node* next; 9}node; 10 11void fib(node* head, node* tail, int n); 12 13int main() { 14 int n; 15 node* head, * tail, * ptr, * npt; 16 17 ptr = (node*)malloc(sizeof(node)); 18 19 ptr->prev = NULL; 20 ptr->l = 1; 21 ptr->m = 1; 22 ptr->next = NULL; 23 head = ptr; 24 tail = ptr; 25 26 scanf("%d", &n); 27 28 fib(head, tail, n); 29 30 ptr = head; 31 while (ptr != NULL) { 32 npt = ptr->next; 33 free(ptr); 34 ptr = npt; 35 } 36} 37 38void fib(node* head, node* tail, int n) { 39 node* ptr, * npt; 40 int carry = 0, i = 0, tmp; 41 42 if (n == 0) { 43 ptr = head; 44 while (ptr != NULL) { 45 printf("%d", ptr->l); 46 ptr = ptr->next; 47 } 48 } 49 else if (n == 1) { 50 ptr = head; 51 while ((ptr != NULL) && (i < 100)) { 52 printf("%d", ptr->m); 53 ptr = ptr->next; 54 i++; 55 } 56 }else{ 57 ptr = tail; 58 do { 59 tmp = ptr->m; 60 ptr->m = ptr->l + ptr->m; 61 62 if (10 <= ptr->m) { 63 carry = 1; 64 } 65 66 if (carry == 1) { 67 if (ptr->prev == NULL) { 68 npt = (node*)malloc(sizeof(node)); 69 npt->l = 0; 70 npt->m = 0; 71 ptr->prev = npt; 72 npt->prev = NULL; 73 npt->next = ptr; 74 head = npt; 75 } 76 ptr->m = ptr->m - 10; 77 } 78 ptr->l = tmp; 79 ptr = ptr->prev; 80 81 if (carry == 1) { 82 ptr->l ++; 83 carry = 0; 84 } 85 } while (ptr != NULL); 86 87 n--; 88 fib(head, tail, n); 89 } 90 91}

試したこと

連結リストに原因があるのかと思い、似たようなプログラムを配列を用いる方法で考えてみましたがそもそも配列ではしっかり動作するプログラムを書けませんでした。

連結リストにこだわっているわけではなく、入力した回数分のフィボナッチ数列を生成できればOKです。

どなたかプログラムが停止する理由、また代案などあればご教示願います。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

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

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

guest

回答2

0

ベストアンサー

原因は、fibの再帰呼び出しです。

関数の引数やローカル変数を保存するためのスタック領域は、環境により異なりますが、数MBしかありません。
そのため、再帰呼び出しを大量に繰り返すと、スタック領域を使いつくして落ちます。

再帰をループに書き換えたところ、私の環境では10,000でも動作するようになりました。

投稿2021/09/25 23:04

actorbug

総合スコア2431

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

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

dgtack25

2021/09/25 23:28

連結リストではなく、再帰に限界があったのですね。ありがとうございます。 ちなみにループへはどのように書き換えればよいのでしょうか?
actorbug

2021/09/25 23:58 編集

ざっくり手順を説明すると以下になります。 1. 関数内部全体をfor(;;){...}で囲む 2. if文の分岐で再帰呼び出ししていない箇所については、明示的にreturnで抜けるようにする 3. 再帰呼び出ししている箇所については、再帰呼び出しの実引数を仮引数に代入する処理に置き換える 検索してもあまり情報が見つかりませんでしたが、以下のページなど参考になるかもしれません。 2019年度「プログラミング言語」配布資料 (6) 末尾再帰関数から繰り返し処理へ http://www.fos.kuis.kyoto-u.ac.jp/~igarashi/class/pl/06-rec-iter.html#trans-tail-recursion
dgtack25

2021/09/26 00:54

丁寧な説明ありがとうございました。ループに書き換えたところ上手く動作しました。
guest

0

まず、

npt = (node*)malloc(sizeof(node));

mallocしたときはNULLチェックしましょう。

投稿2021/09/25 22:54

y_waiwai

総合スコア88042

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問