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

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

ただいまの
回答率

89.06%

線形リストでセグメントエラーになってしまいます。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 533

apeirogon0813

score 69

前提・実現したいこと

struct node( int element, struct node *next);
struct node* p;
のようなノードで線形リストで
p

[0]->[1]->[2]
というよなelementの要素が入ったリストを作り
while(p != NULL) {
p = p->next;
}
とし
p->element = 2のとき
p = p->next;
とするとセグメントエラーになってしまいました。
これはNULLを参照してしまったからでしょうか?

いつもはこの様な方法でもおそらくNULLがそのまま代入されてセグメントエラーになってなかったと思うのですが
今回のプログラムではセグメントエラーになってしまいました。

関数dijkstraの局所局所にprint文を入れてどこでエラーなるかチェックしたところ
adjlist[cur] = adjlist[cur]->next;の手前まで出力されていたためこれが原因かと思っていました。。 

#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
#define ROSENZU "rosenzu.txt" /* 路線図データファイル */
#define SETMAX 10600 /* 集合の要素数の最大値 (駅の数) */
char buf[256]; /* 入力された文字列を格納するグローバル変数 */

int dist[SETMAX]; /* 指定された駅から各駅までの最短距離を格納するグローバル変数 */

struct node { int eki, rosen, kyori; struct node *next; };
struct set { int elements[SETMAX]; int size; };

void init_set(struct set *p, int n, int e) {
  int i, j=0;
  p->size = n-1;
  for(i = 0; i < p->size; i++) {
    if(j == e)
      j++;
    p->elements[i] = j++;
  }
}

int delete_min(struct set *p) {
  int i=0, j, min = dist[p->elements[0]];//一回ループを省力するため添字0の値を\
代入しておく                                                                    
  if(p->size == 0) //空集合の場合                                               
    return -1;
  else
    for(j=1; j < p->size; j++) { //一番小さい値の添字の探索                     
      if(dist[p->elements[j]] < min) {
        min = dist[p->elements[j]];
        i = j;
      }
    }
 min = p->elements[i]; //minにはreturnする要素を格納                           
 p->elements[i] = p->elements[p->size -1]; //最小値の場所に格納                
 p->size--;
 return min;
}

//一方向の経路の挿入
struct node* insert_edge(struct node *list, int eki, int rosen, float kyori) {
  struct node *n;
  n = (struct node*)malloc(sizeof(struct node));
  n->eki = eki;
  n->rosen = rosen;
  n->kyori = kyori;
  n->next = list;
  return n;
}

void add_edge(struct node *adjlist[], int eki1, int eki2, int rosen, int kyori) {
  adjlist[eki1] = insert_edge(adjlist[eki1], eki2, rosen, kyori);
  adjlist[eki2] = insert_edge(adjlist[eki2], eki1, rosen, kyori);
}

int dijkstra(struct node *adjlist[], int eki1, int eki2, int ekisu) {
  int i, cur; //cur:直前に最短距離が確定した駅の変数
  struct set unknown;
  for(i=0; i<ekisu; i++) { //到達可能かわからない要素をINT_MAXにする
    if(i == eki1)
      dist[i] = 0;
    else
      dist[i] = INT_MAX;
  }
  cur = eki1;
  init_set(&unknown, ekisu, cur);
//セグメントエラー確認のためここでリストを巡回させるとやはりエラーになった//////////////////////
  while(adjlist[eki1] != NULL) { 
    adjlist[eki1] = adjlist[eki1]->next;
    printf("%d->%d\n",adjlist[eki1],adjlist[eki1]->next);
  }
  ////////////////////////////////////////////////////////////////


    while(unknown.size !=0 || cur != eki2) {
      while(adjlist[cur] != NULL) {
    printf("dist[%d] + adjlist[%d]->kyori < dist[%d] = %d + %d < %d\n",cur,cur,adjlist[cur]->eki,dist[cur],adjlist[cur]->kyori,dist[adjlist[cur]->eki]);
    if(dist[cur] + adjlist[cur]->kyori < dist[adjlist[cur]->eki])
      dist[adjlist[cur]->eki] = dist[cur] + adjlist[cur]->kyori;
    printf("next\n");
printf("eki = %d, next = %d\n", adjlist[cur]->eki, adjlist[cur]->next->eki);
 printf("%d\n",adjlist[cur]->next);
    adjlist[cur] = adjlist[cur]->next; //この前までのprintは出力された
    printf("eki = %d, next = %d\n", adjlist[cur]->eki, adjlist[cur]->next->eki);
      }
      printf("srgsrgs\n");
      cur = delete_min(&unknown); //集合unknownの最短距離の駅をcurに格納
      printf("are\n");
    }
    printf("1\n\n");
  return dist[eki2];
}

int main() {
  int eki1, eki2, rosen, ekisu, i, kyori;
  FILE *fp = fopen(ROSENZU,"r"); /* 路線図ファイルを読む準備 */
 fscanf(fp, "%d ", &ekisu); /* 1行めの駅数を読取り */
 struct node *adjlist[ekisu];
 /* 隣接リスト表現を初期化.すべての頂点に対する隣接リストを空にする */
 for(i=0;i<ekisu;++i) adjlist[i] = NULL;
 while(fgets(buf,sizeof(buf),fp)!=NULL) {
   /* 隣り合う駅の情報を読取り */
   sscanf(buf, "%d:%d:%d:%d␣", &eki1, &eki2, &rosen, &kyori);
   /* そのデータを隣接リスト表現のグラフに追加 */
   add_edge(adjlist, eki1, eki2, rosen, kyori);
 }
 fclose(fp);
 scanf("%d %d ", &eki1, &eki2);
 printf("%d\n", dijkstra(adjlist, eki1, eki2, ekisu));
 /* for(i=0;i<ekisu;++i)
    if(dist[i] < INT_MAX)
    printf("%d: %d\n", i, dist[i]); */
 return 0;
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • apeirogon0813

    2019/01/30 14:45

    関数dijkstraの局所局所にprint文を入れてどこでエラーなるかチェックしたところ
    adjlist[cur] = adjlist[cur]->next;の手前まで出力されていたためこれが原因かと思っていました。。

    キャンセル

  • y_waiwai

    2019/01/30 14:48

    そこらへんの情報ももらさず質問に追記していただければ、解決も早いかと思いますです

    キャンセル

  • apeirogon0813

    2019/01/30 14:49

    ありがとうございます

    キャンセル

回答 1

checkベストアンサー

+3

while(adjlist[eki1] != NULL) { 
    adjlist[eki1] = adjlist[eki1]->next;
    printf("%d->%d\n",adjlist[eki1],adjlist[eki1]->next);
}

↓こうじゃない?

while(adjlist[eki1] != NULL) { 
    printf("%d->",adjlist[eki1]);
    adjlist[eki1] = adjlist[eki1]->next;
    if (adjlist[eki1] != NULL){
        printf("%d",adjlist[eki1]);
    }
    printf("\n");
}


じゃない?

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/01/30 15:25

    そして、元のコードでは、
    少し笑えますが、printf消したら治るな。

    キャンセル

  • 2019/01/30 15:36

    おっしゃるとおりでした。。。

    キャンセル

  • 2019/01/30 15:36

    有難うございました。

    キャンセル

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

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

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