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

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

ただいまの
回答率

88.34%

コンパイルして実行するとエラーが出て動かない。

解決済

回答 3

投稿 編集

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

sanchu52

score 184

コンパイルして実行するとセグメンテーションエラーが出て動かない。
双方向循環リストです。// 先頭要素を初期化 のところでエラーが出ています。
長いコードですが、どなたか動くように教えてもらえませんか。
おねがいいたします。

コード
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


// コマンド 
enum Cmd_tag {
    CMD_ADD,
    CMD_DELETE,
    CMD_SEARCH,
    CMD_CLEAR,
    CMD_PRINT,
    CMD_EXIT,

    CMD_NUM
};

// コマンド文字列の種類 
enum CmdStr_tag {
    CMD_STR_SHORT,
    CMD_STR_LONG,

    CMD_STR_NUM
};

// コマンドの戻り値 
enum CmdRetValue_tag {
    CMD_RET_VALUE_CONTINUE,
    CMD_RET_VALUE_EXIT,
};

// コマンド文字列 
static const char* const CMD_STR[CMD_NUM][CMD_STR_NUM] = {
    { "a", "add" },
    { "d", "delete" },
    { "s", "search" },
    { "c", "clear" },
    { "p", "print" },
    { "e", "exit" }
};


static void init_head(void);
static void print_explain(void);
static void print_blank_lines(void);
static enum CmdRetValue_tag get_cmd(void);
static enum CmdRetValue_tag cmd_add(void);
static enum CmdRetValue_tag cmd_delete(void);
static enum CmdRetValue_tag cmd_search(void);
static enum CmdRetValue_tag cmd_clear(void);
static enum CmdRetValue_tag cmd_print(void);
static enum CmdRetValue_tag cmd_exit(void);
static void add_elem(int value);
static int delete_elem(int value);
static void clear_list(void);
static void print_list(void);
static struct LinkedList_tag* search_tail(void);
static struct LinkedList_tag* search_elem(int value);
static struct LinkedList_tag* delete_one_node(struct LinkedList_tag* node);
//単方向線形リストにはない

static void get_line(char* buf, size_t size);


// コマンド実行関数 
typedef enum CmdRetValue_tag (*cmd_func)(void);

static const cmd_func CMD_FUNC[CMD_NUM] = {
    cmd_add,
    cmd_delete,
    cmd_search,
    cmd_clear,
    cmd_print,
    cmd_exit
};

// 連結リスト型 
struct LinkedList_tag {
    int                     value;
    struct LinkedList_tag*  next;
    struct LinkedList_tag*    prev;    //単方向線形リストにはない
};

static struct LinkedList_tag* gHead;        // 先頭の要素 

int main(void)
{
    init_head();

    while( 1 ){
        print_explain();

        if( get_cmd() == CMD_RET_VALUE_EXIT ){
            break;
        }

        print_blank_lines();
    }

    return 0;
}

// 先頭要素を初期化 
void init_head(void)
{
    // 先頭要素を初期化 
void init_head(void)
{
    static struct LinkedList_tag dummy;
        static struct LinkedList_tag* gHead = &dummy;
    gHead->value = 0;
    gHead->next    =NULL; 
    gHead->prev    =NULL;    //単方向線形リストにはない
}

        gHead->value = 0;
    gHead->next    =gHead; 
    gHead->prev    =gHead;    //単方向線形リストにはない
}

// 説明文を出力
void print_explain(void)
{
    puts( "コマンドを入力して下さい。" );
    printf( " 連結リストに要素を追加する: %s (%s)\n", CMD_STR[CMD_ADD][CMD_STR_SHORT], CMD_STR[CMD_ADD][CMD_STR_LONG] );
    printf( " 連結リストから要素を削除する: %s (%s)\n", CMD_STR[CMD_DELETE][CMD_STR_SHORT], CMD_STR[CMD_DELETE][CMD_STR_LONG] );
    printf( " 連結リストから要素を探す: %s (%s)\n", CMD_STR[CMD_SEARCH][CMD_STR_SHORT], CMD_STR[CMD_SEARCH][CMD_STR_LONG] );
    printf( " 連結リストを空にする: %s (%s)\n", CMD_STR[CMD_CLEAR][CMD_STR_SHORT], CMD_STR[CMD_CLEAR][CMD_STR_LONG] );
    printf( " 連結リストの中身を出力する: %s (%s)\n", CMD_STR[CMD_PRINT][CMD_STR_SHORT], CMD_STR[CMD_PRINT][CMD_STR_LONG] );
    printf( " 終了する: %s(%s)\n", CMD_STR[CMD_EXIT][CMD_STR_SHORT], CMD_STR[CMD_EXIT][CMD_STR_LONG] );
    puts( "" );
}

// 空白行を出力
void print_blank_lines(void)
{
    puts( "" );
    puts( "" );
}

// コマンドを受け付ける
enum CmdRetValue_tag get_cmd(void)
{
    char buf[20];
    enum Cmd_tag cmd;
    int i;

    get_line( buf, sizeof(buf) );

    cmd = CMD_NUM;
    for( i = 0; i < CMD_NUM; ++i ){
        if( strcmp( buf, CMD_STR[i][CMD_STR_SHORT] ) == 0
         || strcmp( buf, CMD_STR[i][CMD_STR_LONG] ) == 0
        ){
            cmd = i;
            break;
        }
    }

    if( 0 <= cmd && cmd < CMD_NUM ){
        return CMD_FUNC[i]();
    }
    else{
        puts( "そのコマンドは存在しません。" );
    }

    return CMD_RET_VALUE_CONTINUE;
}

// addコマンドの実行
enum CmdRetValue_tag cmd_add(void)
{
    char buf[40];
    int value;

    puts( "追加する数値データを入力して下さい。" );
    fgets( buf, sizeof(buf), stdin );
    sscanf( buf, "%d", &value );

    add_elem( value );

    return CMD_RET_VALUE_CONTINUE;
}

// deleteコマンドの実行
enum CmdRetValue_tag cmd_delete(void)
{
    char buf[40];
    int value;

    puts( "削除する数値データを入力して下さい。" );
    fgets( buf, sizeof(buf), stdin );
    sscanf( buf, "%d", &value );

    if( delete_elem(value) >= 1 ){
        puts( "要素を削除しました。" );
    }
    else{
        puts( "削除する要素は見つかりませんでした。" );
    }

    return CMD_RET_VALUE_CONTINUE;
}

// searchコマンドの実行
enum CmdRetValue_tag cmd_search(void)
{
    char buf[40];
    int value;

    puts( "探索する数値データを入力して下さい。" );
    fgets( buf, sizeof(buf), stdin );
    sscanf( buf, "%d", &value );

    if( search_elem(value) == NULL ){
        printf( "%d は連結リスト中に存在しません。\n", value );
    }
    else{
        printf( "%d は連結リスト中に存在します。\n", value );
    }

    return CMD_RET_VALUE_CONTINUE;
}

// clearコマンドの実行
enum CmdRetValue_tag cmd_clear(void)
{
    clear_list();

    return CMD_RET_VALUE_CONTINUE;
}

// printコマンドの実行
enum CmdRetValue_tag cmd_print(void)
{
    print_list();

    return CMD_RET_VALUE_CONTINUE;
}

// exitコマンドの実行
enum CmdRetValue_tag cmd_exit(void)
{
    puts( "終了します。" );

    return CMD_RET_VALUE_EXIT;
}

// 要素を追加する
// 引数:
//        value:    追加する要素の数値データ。
void add_elem( int value)
{
    struct LinkedList_tag* elem;
    struct LinkedList_tag* tail;

    // リストの末尾を探す 
    tail = search_tail();

    // 追加する要素を作る 
    elem = malloc( sizeof(struct LinkedList_tag) );
    if( elem == NULL ){
        fputs( "メモリ割り当てに失敗しました。", stderr );
        exit( 1 );
    }
    elem->
    value = value;          
    elem->next = gHead;  
    elem->prev = tail;     

    tail->next = elem;

}

int delete_elem(int value)
{
    struct LinkedList_tag* p = gHead->next;
    int count = 0;

    while( p != gHead ){
        if( p->value == value ){
            p = delete_one_node( p );
            // 削除後に有効なポインタを返す。
            // 削除した要素の次にあった要素へのポインタを返す。

            ++count;
        }
        else{
            p = p->next;
        }
    }

    return count;
}

// 要素を空にする
void clear_list(void)
{
    struct LinkedList_tag* p = gHead->next;

    while( p != gHead){
        p = delete_one_node( p );
        // 削除後に有効なポインタを返す。
        // 削除した要素の次にあった要素へのポインタを返す。
    }
}

// 要素を出力する
void print_list(void)
{
    struct LinkedList_tag* p = gHead->next;

    if( p == gHead ){
        puts( "リストは空です。" );
        return;
    }

    while( p != gHead ){
        printf( "%d\n", p->value );
        p = p->next;
    }
}

struct LinkedList_tag* search_tail(void)
{
    struct LinkedList_tag*  p= gHead;

    while( p->next != gHead ){
        p = p->next;
    }

    return p;        // メンバを初期化した後、戻り値として返されます。
}

struct LinkedList_tag* search_elem(int value)
{
    struct LinkedList_tag* p = gHead->next;

    while( p != gHead ){
        if( p->value == value ){
            return p;
        }
        p = p->next;
    }

    return NULL;
}

struct LinkedList_tag* delete_one_node(struct LinkedList_tag* node)
{

     struct LinkedList_tag* const prev = node->prev;

     if( node->next != NULL ){
          node->next->prev = prev;
     }

    prev->next = node->next;

    free( node );

    return prev->next;
}

void get_line(char* buf, size_t size)
{
    fgets(buf, size, stdin);

    // 末尾に改行文字があれば削除する 
    char* p = strchr(buf, '\n');
    if (p != NULL) {
        *p = '\0';
    }
}

/* 実行結果
naka@naka ~/kadai/kadai9-8
$ gcc -o LST_sou_jyun21a LST_sou_jyun21a.c -Wall

naka@naka ~/kadai/kadai9-8
$  LST_sou_jyun21a
コマンドを入力して下さい。
 連結リストに要素を追加する: a (add)
 連結リストから要素を削除する: d (delete)
 連結リストから要素を探す: s (search)
 連結リストを空にする: c (clear)
 連結リストの中身を出力する: p (print)
 終了する: e(exit)

a
追加する数値データを入力して下さい。
6
ここで止まる。(エラー)
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+1

init_head()関数で未初期化のポインタgHeadに値を代入しようとしているのがエラーの原因です。

static struct LinkedList_tag* gHead;        // 先頭の要素 

// 先頭要素を初期化 
void init_head(void)
{
    gHead->value = 0;
    gHead->next    =gHead; 
    gHead->prev    =gHead;    //単方向線形リストにはない
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/02/25 01:11

    gHeadはポインタ型なので、実体のアドレスを入れてやらなければ使えません。

    なので、epistemeさんのようにダミーとして実体を定義してそのアドレスを渡してやるか、
    gHead=(struct LinkedList_tag *)malloc( sizeof(struct LinkedList_tag ) );
    のようにしてアドレスを割り当てないとダメです。

    ポインタが使われたコードを書いた時に、そのポインタがどこを指しているかすぐに説明できないときは多くのケースでそこにバグが含まれます。

    キャンセル

  • 2018/02/25 12:13

    epistemeさんの指摘で、init()に2行追加してコンパイルは実行結果のとおり通りました。
    そのあと実行画面で、実行が止まりました。改めて質問を変えて、質問しなおします。
    ありがとうございます。

    キャンセル

  • 2018/02/25 12:35

    まあ、そうなるわな。

    キャンセル

+1

ポインタgHeadに有効領域を代入する箇所が見当たりません

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

関数を呼ぶ前に構造体(gHead)の初期化をしてください。
該当のinit~関数で何を入れようと思っているのでしょうか。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/02/22 14:23

    // 先頭要素を初期化
    void init_head(void)
    {
    gHeadー>value = 0;
    gHead->next = NULL;
    gHeadー>prev = NULL; //単方向線形リストにはない
    }

    キャンセル

  • 2018/02/22 21:18

    それはgHeadの各要素の初期化です。
    gHead自体が有効領域を指し示さない以上、それは無理です。

    キャンセル

  • 2018/02/25 12:14

    ありがとうございます。

    キャンセル

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

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

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