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

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

ただいまの
回答率

87.77%

c言語 自己参照型構造体 逆表示

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,024

score 3

前提・実現したいこと

・前提
http://www9.plala.or.jp/sgwr-t/c/sec15-5.html のサイトを拝見させていただき参考にプログラムを作成しました。また主にこのサイトにある説明でリスト構造については学習をしました。
・実現したいこと
構造体をリスト形式にし、入力をリストに格納。それを逆順(リスト的には逆、入力でみると順になるが)で表示するプログラムの出力を正常にしたいです。
リストに格納した順番(3,3 2,2 1,1)の形では出力がうまくいっているため、自らで作成したreverse_list関数内で間違いが起きてると思いますが、ここで長時間止まってしまっているので質問させていただきます。

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

2つの数を入力してください(両方0で終了)
num1 = 1
num2 = 1
-------------------------
num1 = 2
num2 = 2
-------------------------
num1 = 3
num2 = 3
-------------------------
num1 = 0
num2 = 0
-------------------------


最後の破線の下に入力順に値が表示される予定ですが何も表示されません。

該当のソースコード

#include <stdio.h>
#include <stdlib.h>

/* 構造体定義 */
struct list{
    int num1,num2;
    struct list *next;
};

/* 関数定義 */
struct list *add_list(int x,int y,struct list *head);
struct list *reverse_list(struct list *head,struct list *head2);
void show_list(struct list *p);
void free_list(struct list *p);


int main(void){
    struct list *head;      //先頭ポインタ
    struct list *head2;     //順(リストを逆から)表示するためのポインタ

    int num1,num2;

    head = NULL;            //先頭ポインタにNULLを代入
    head2 = NULL;

    /* 入力処理 */
    printf("2つの数を入力してください(両方0で終了)\n");
    while(1){
        printf("num1 = ");
        scanf("%d",&num1);
        printf("num2 = ");
        scanf("%d",&num2);
        printf("-------------------------\n");

        //終了条件
        if(num1 == 0 && num2 == 0)  break;

        head = add_list(num1,num2,head);
    }

    head2 = reverse_list(head,head2);    
    show_list(head2);
    free_list(head);
    free_list(head2);
}

/* リストにデータを格納する関数 */
struct list *add_list(int num1,int num2,struct list *head){
    struct list *p;

    //記憶領域の確保
    if((p = (struct list *)malloc(sizeof(struct list))) == NULL){
        printf("malloc error\n");
        exit(EXIT_FAILURE);
    }

    //リストにデータを登録
    p->num1 = num1;
    p->num2 = num2;

    //ポインタの繋ぎ変え
    p->next = head;     //今までの先頭ポインタを次ポインタに
    head = p;           //新たな領域を先頭ポインタに

    return head;
}

/* データを順に格納する関数 */
struct list *reverse_list(struct list *head,struct list *head2)
{
    struct list *p;

    //記憶領域の確保
    if((p = (struct list *)malloc(sizeof(struct list))) == NULL){
        printf("malloc error\n");
        exit(EXIT_FAILURE);
    }

    while(head != NULL){
        head2->num1 = head->num1;
        head2->num2 = head->num2;

        p->next = head2;
        head2 = p;

        head = head->next;
    }

    return p;
}

/* リストのデータを表示する関数 */
void show_list(struct list *p)
{
    while (p != NULL) {    /* 次ポインタがNULLまで処理 */
        printf("num1=%d,num2=%d\n", p->num1, p->num2);
        p = p->next;
    }
}

/* リスト解放の関数 */
void free_list(struct list *p)
{
    struct list *p2;

    while (p != NULL) {     /* 次ポインタがNULLまで処理 */
        p2 = p->next;
        free(p);
        p = p2;
    }
}

試したこと

ここに問題に対して試したことを記載してください。

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

直しました。

#include <stdio.h>
#include <stdlib.h>

/* 構造体定義 */
struct list{
    int num1,num2;
    struct list *next;
};

/* 関数定義 */
struct list *add_list(int x,int y,struct list *head);
struct list *reverse_list(struct list *head);
void show_list(struct list *p);
void free_list(struct list *p);


int main(void){
    struct list *head;      //先頭ポインタ
    struct list *head2;     //順(リストを逆から)表示するためのポインタ

    int num1,num2;

    head = NULL;            //先頭ポインタにNULLを代入
    head2 = NULL;

    /* 入力処理 */
    printf("2つの数を入力してください(両方0で終了)\n");
    while(1){
        printf("num1 = ");
        scanf("%d",&num1);
        printf("num2 = ");
        scanf("%d",&num2);
        printf("-------------------------\n");

        //終了条件
        if(num1 == 0 && num2 == 0)  break;

        head = add_list(num1,num2,head);
    }

    head2 = reverse_list(head);
    show_list(head2);
    free_list(head);
    free_list(head2);
}

/* リストにデータを格納する関数 */
struct list *add_list(int num1,int num2,struct list *head){
    struct list *p;

    //記憶領域の確保
    if((p = (struct list *)malloc(sizeof(struct list))) == NULL){
        printf("malloc error\n");
        exit(EXIT_FAILURE);
    }

    //リストにデータを登録
    p->num1 = num1;
    p->num2 = num2;

    //ポインタの繋ぎ変え
    p->next = head;     //今までの先頭ポインタを次ポインタに
    head = p;           //新たな領域を先頭ポインタに

    return head;
}

/* データを順に格納する関数 */
struct list *reverse_list(struct list *head)
{
    struct list *head2;

    if (head == NULL)
        return NULL;

    // 記憶領域の確保
    if ((head2 = (struct list *)malloc(sizeof(struct list))) == NULL) {
        printf("malloc error\n");
        exit(EXIT_FAILURE);
    }
    head2->num1 = head->num1;
    head2->num2 = head->num2;
    head2->next = reverse_list(head->next);

    return head2;
}

/* リストのデータを表示する関数 */
void show_list(struct list *p)
{
    while (p != NULL) {    /* 次ポインタがNULLまで処理 */
        printf("num1=%d,num2=%d\n", p->num1, p->num2);
        p = p->next;
    }
}

/* リスト解放の関数 */
void free_list(struct list *p)
{
    struct list *p2;

    while (p != NULL) {     /* 次ポインタがNULLまで処理 */
        p2 = p->next;
        free(p);
        p = p2;
    }
}

ちょっと楽をしましたが動くはずです。
あなたにはいろいろ足りてない部分があります。
まず、struct listはtypedefを使えばstructを省略できます。

typedef struct tag_list {
    int num1, num2;
    struct tag_list *next;
} list;

Cについての熟練度が足りない。これはAOJ(Aizu Online Judge)の基本的な問題を少しやれば身につくでしょう。AOJは他の人の回答を見ることもできるので、自分のコードスタイルをよくすることも簡単にできます。

次に、再帰関数についての造詣を深めたほうがよろしいかと。それはSICP(Structure and Interpretation of Computer Programs)を2章の終わりまでやればいいです。日本語訳も無料で読めます。ただしCではなくSchemeです。Cはシステムプログラミング用の言語なので一回GC付きの言語で世界観をひっくり返しておいたほうがいいでしょう。3章はオブジェクト指向等々、4章はインタプリタ、5章はコンパイラについての解説ですがSICPの3〜5章を読まずとももっとよい良書があるのでSICPを完読することはおすすめしないです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/06 08:48

    何から何までありがとうございます。コードを見たところ無理に継続条件としてheadを進めずに、再帰関数としてheadのnextを与え、NULLなら終わるとすることにとても納得できました。
    AOJやSICPといったサイトも拝見します。本当にありがとうございました。

    キャンセル

0

C言語である程度のコードを書くなら、まずはデバッグできる環境を整えましょう。
Eclipseとか、WindowsならVisualStudioとか。
コードの途中で実行を止めて、変数のナカミを参照したり、1行づつ実行させたりできます。

そうすればアテずっぽでコードを書かなくて済むようになります

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/06 08:51

    Visual Studio Codeでの開発をしております。デバックを繰り返し、あまりに解決しないため質問をさせていただきました。しかし質問をする前にもう少し理解を深めるべきだと把握しました。
    環境の記述を怠っていました。申し訳ありませんでした。

    キャンセル

  • 2020/06/06 09:01

    VSCodeじゃなくて、VisualStudio入れましょうよ。
    ブレークポイントで止めて、ステップ実行させれば何故そういう結果になるかぐらいはわかるでしょうに。

    キャンセル

  • 2020/06/06 09:33

    過去に使用したことがあり、環境も整っていたためVSCodeを使用していました。少し調べてからVisualStudioにするかは検討させていただきます。
    仰る通りで、それでどこが原因かまでは把握できたつもりだったのですがその先が力不足で進まずという感じでした。ご指摘ありがとうございます。こちらの実力不足が原因であるのにそれに答えてくださり、ありがとうございました。

    キャンセル

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

  • ただいまの回答率 87.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る