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

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

ただいまの
回答率

87.59%

c言語 リスト構造について...

解決済

回答 4

投稿 編集

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

score 63

前提・実現したいこと

最近C言語でリスト構造を勉強したので自己流でリスト構造のプログラムを作成したのですが正常に作動しません。どなたか解決法を教えてください。

説明不足だったので補足します。
データの追加を行おうとすると動作が停止するのですがadd_data()の修正を試みたのですが、修正箇所が分かりません。

該当のソースコード

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*データ*/
typedef struct {
    int num;            //学籍番号下三桁
    char name[16];        //氏名
}data_t;

/*ノード*/
typedef struct node {
    data_t data;               //データ
    struct node *nextnode;     //後ろのノードへのポインタ
}node_t;

/*関数プロトタイプ宣言*/
node_t *make_node(data_t, node_t *);
void add_data(node_t *);
void remove_data(node_t *);
void search_data(node_t *);
void show_data(node_t *);
void release(node_t *);

int main(void)
{
    int menu;
    node_t *node=NULL;

    do {
        puts("");
        puts("***メニューの選択***");
        puts(" 1.データの追加");
        puts(" 2.データの削除");
        puts(" 3.データの検索");
        puts(" 4.データの表示");
        puts(" 5.終了");

        printf("メニューの選択:");    
scanf("%d", &menu);
        puts("");

        switch (menu)
        {
            case 1: add_data(node);            break;
            case 2: remove_data(node);         break;
            case 3: search_data(node);         break;
            case 4: show_data(node);           break;
            case 5: puts("プログラムを終了");     break;
            default:puts("番号を再入力");        break;
        }
    } while (menu != 5);

    release(node);
    system("pause");
    return 0;
}

/*新規ノードの作成*/
node_t *make_node(data_t data, node_t *nextnode)
{
    node_t *p;

    p = malloc(sizeof(node_t));
    if (p == NULL) {
        puts("領域確保に失敗");
        return NULL;
    }
    else {
        p->data = data;
        p->nextnode = nextnode;
        return p;
    }
}

/*データの追加*/
void add_data(node_t *node)
{
    data_t  data;
    node_t *p=node;

    puts("***追加するデータの入力***");
    printf("学籍番号の下二桁の番号:");    scanf("%d", &data.num);
    printf("氏名:");                    scanf("%s", data.name);

    while (p->nextnode != NULL) {
        p = p->nextnode;
    }
    p = make_node(data, NULL);
}

/*データの表示*/
void show_data(node_t *node)
{
    node_t *p=node;

    if (p ==NULL) {
        puts("データがありません。データを追加してください。");
        return;
    }
    while (p!=NULL){
        printf("番号%*s氏名\n",6,"");
        printf("%2d %10s\n", (p->data).num, (p->data).name);
        p = p->nextnode;
    }
}

/*データの削除*/
void remove_data(node_t *node)
{
    int num;
    node_t *pre;
    if(node==NULL)
        puts("データは見つかりませんでした。"); return;
    puts("***データの削除***");
    printf("番号の入力:");    scanf("%d", &num);

    while (node->nextnode != NULL) {
        if ((node->data).num == num) {
            pre = node->nextnode;
            free(node);
            return;
        }
        pre = node;
        node = node->nextnode;        
    }
    puts("データは見つかりませんでした。");
}

/*データの検索*/
void search_data(node_t *node)
{
    int num;
    node_t *p=node;

    puts("***データの検索***");
    printf("番号の入力:");    scanf("%d", &num);

    if (node == NULL)    
        puts("データは見つかりませんでした");  return;
    while (p->nextnode != NULL) {
        if ((p->data).num == num) {
            puts("---データを発見---");
            printf("氏名:%s\n", (p->data).name);
            return;
        }
        p = p->nextnode;
    }
    puts("データは見つかりませんでした");
}

/*データの後処理*/
void release(node_t *node)
{
    node_t *p;

    if (node = NULL) return;
    while (node->nextnode != NULL) {
        p = node;
        node = node->nextnode;
        free(p);
    }
}


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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • LouiS0616

    2017/10/15 18:06

    どのように上手くいかないのか書いてください。コンパイル出来ない、実行中落ちる、etc.『上手くいかない』という表現は広すぎます。また、特定の入力に対して上手く動作しない場合、その入力と出力、同時に理想とする出力を書いてください。

    キャンセル

  • LouiS0616

    2017/10/15 18:07

    また、コードのインデントが崩れて非常に読みづらくなっています。Teratailには、コードを見やすく表示する機能があります。編集画面を開き、コードを選択した状態で<code>ボタンを押してください。

    キャンセル

回答 4

+1

”正常に作動しません。”では分かりません。
release()内、if (node = NULL) return;・・・これではreturnしません。
"_CRT_SECURE_NO_WARNINGS"をセットしているのでワーニングが出ないせいだと思います。scanf()のワーニングを消すためだと思いますがワーニングを見ないようにするのは止めた方がいいですよ。

remove_data()内、if (node == NULL)
puts("データは見つかりませんでした."); return; ←このreturnはif文の外にあるためこの後の処理は実行されません。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

checkベストアンサー

0

全ケースのテストは行っていませんが取り合えず動く程度ですので参考まで

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*データ*/
typedef struct {
    int num;            //学籍番号下三桁
    char name[16];      //氏名
}data_t;

/*ノード*/
typedef struct node {
    data_t data;               //データ
    struct node *nextnode;     //後ろのノードへのポインタ
}node_t;

/*関数プロトタイプ宣言*/
node_t *make_node(data_t, node_t *);
node_t *add_data(node_t *);
node_t *remove_data(node_t *);
void search_data(node_t *);
void show_data(node_t *);
void release(node_t *);

int main(void)
{
    int menu;
    node_t *node=NULL;

    do {
        puts("");
        puts("***メニューの選択***");
        puts(" 1.データの追加");
        puts(" 2.データの削除");
        puts(" 3.データの検索");
        puts(" 4.データの表示");
        puts(" 5.終了");

        printf("メニューの選択:");
        scanf("%d", &menu);
        puts("");

        switch (menu)
        {
            case 1: node=add_data(node);       break;
            case 2: node=remove_data(node);    break;
            case 3: search_data(node);         break;
            case 4: show_data(node);           break;
            case 5: puts("プログラムを終了");  break;
            default:puts("番号を再入力");      break;
        }
    } while (menu != 5);

    release(node);
    // system("pause"); コメント
    return 0;
}

/*新規ノードの作成*/
node_t *make_node(data_t data, node_t *nextnode)
{
    node_t *p;

    p = malloc(sizeof(node_t));
    if (p == NULL) {
        puts("領域確保に失敗");
        return NULL;
    }
    else {
        p->data = data;
        p->nextnode = nextnode;
    }
    return p;
}

/*データの追加*/
node_t *add_data(node_t *node)
{
    data_t data;
    node_t *p=node;

    puts("***追加するデータの入力***");
    printf("学籍番号の下二桁の番号:");  scanf("%d", &data.num);
    printf("氏名:");                    scanf("%s", data.name);

    while ( node != NULL && p->nextnode != NULL) {
        p = p->nextnode;
    }
    if (node == NULL) {
        node=make_node(data, NULL);
    }else{
         p->nextnode=make_node(data, NULL);
    }
    return node;
}

/*データの表示*/
void show_data(node_t *node)
{
    node_t *p=node;

    if (p == NULL) {
        puts("データがありません。データを追加してください。");
        return;
    }
    while (p!=NULL){
        printf("番号%*s氏名\n",6,"");
        printf("%2d %10s\n", (p->data).num, (p->data).name);
        p = p->nextnode;
    }
}

/*データの削除*/
node_t *remove_data(node_t *node)
{
    int num;
    node_t *head=node;
    node_t *pre=NULL;
    if(node==NULL){
        puts("データは見つかりませんでした。");
        return NULL;
    }
    puts("***データの削除***");
    printf("番号の入力:");
    scanf("%d", &num);

    while (node->nextnode != NULL) {
        if ((node->data).num == num) {
            if (pre == NULL){
                return node->nextnode;
            }else{
                pre->nextnode = node->nextnode;
                free(node);
                return head;
            }
        }
        pre  = node;
        node = node->nextnode;
    }
    puts("データは見つかりませんでした。");
    return head;
}

/*データの検索*/
void search_data(node_t *node)
{
    int num;
    node_t *p=node;

    puts("***データの検索***");
    printf("番号の入力:");
    scanf("%d", &num);

    if (node == NULL) {
        puts("データは見つかりませんでした");
        return;
    }
    while (p->nextnode != NULL) {
        if ((p->data).num == num) {
            puts("---データを発見---");
            printf("氏名:%s\n", (p->data).name);
            return;
        }
        p = p->nextnode;
    }
    puts("データは見つかりませんでした");
}

/*データの後処理*/
void release(node_t *node)
{
    node_t *p;
    if (node == NULL) return;
    p = node;
    release(p->nextnode);
    free(p);
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/10/23 13:44

    ありがとうございました。とても勉強になりました。

    キャンセル

0

データの追加を行おうとすると動作が停止するのですがadd_data()の修正を試みたのですが、修正箇所が分かりません。

初期値NULLのままであるnodeの実体を参照しようとしているからでしょう。


cateyeさんが既にご指摘されているとおり、プログラムに様々な穴があります。
完成させて初めて動かすのではなく、確実にエラーを潰してから拡張した方がよいです。
特に慣れないうちは、エラーメッセージを減らせる点で有用です。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

メインの node_t *node=NULL;でリストの先頭要素を指すつもりですね。
最初の要素を入れる場合を考えてください。
nodeを引数で渡してもnodeの値は変わりませんから、add_node(node)の呼んだ先で何をしてもmainのnodeはNULLのままです。つまり、add_nodeの中をどう改造しても駄目ってこと。

まずはこれが分からないと、いろいろな人のアドバイスが何を言われているか理解できないかも。

対策はいくつかあって
・要素数がn個の時にリストにはn+1個node_t要素がある(「リスト末尾」を表すnode_tを1個置く)ようにする。
・add_nodeを「現在のリスト先頭(空ならNULL)を受け取って、更新したリストの先頭へのポインタを返す関数」に変えること。
・二重ポインタを使いadd_node(node_t**node)に &nodeを渡す。
・などなど

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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