プログラム作成でSegmentation faultが発生!個所を特定して修正方法を教えてください

このQ&Aのポイント
  • 卒論で作成中のプログラムでSegmentation faultが発生しており困っています。
  • 主な問題箇所は関数Bで、どのように修正すれば良いかわかりません。
  • プログラムはrestartというスタート地点にresenddataをつなげていく形で動作していますが、特定の地点でSegmentation faultが発生しています。
回答を見る
  • ベストアンサー

ご教授ください。Segmentation faultが突然出ました!

卒論でプログラム作成しているのですが、Segmentation faultがでて困っています。 おそらく以下の個所があやしいと思うのですが、どこが危険か教えていただけるでしょうか?大きいプログラムなため以下にあやしい個所を一部抜粋します。 関数Bが特にあやしいと思っていますが、どう直していいのかわかりません;; /* main一部 */ struct buf{ int id; int no; int wnd; struct buf *next; }; struct buf temp; struct buf *restart1=&temp; struct buf *resenddata1; struct buf *rere; /* 関数Aの一部 */ flowdata = (struct buf *)malloc(sizeof(struct buf)); resenddata1->next=flowdata; flowdata->next=NULL; resenddata1=flowdata; temp_num[n]++; resenddata1->no=temp_num[n]; resenddata1->wnd=cwnd[n]; /* 関数Bの一部 */ if(restart1->next != NULL){ rere = restart1->next; restart1->next = rere->next; if(check_no[n] == rere->wnd){ t_dep[n]=t+ceil(rto[n])*2-d12*2; if(rere->no > max_no[n]){ max_no[n] = rere->no; } } free(rere); } 簡単に説明しますと、restartというスタート地点にどんどんresenddataをつなげていっています。(最後にNULL)ある地点にいくとrestart->nextをrereに入れてrereを解放という形です。ちなみにrestart1,restart2と同じようなものがあり、関数Aとrereは同じものを使うようにしています。(resenddata2として.rereは共通) お手数ですが、よろしくお願いします。

noname#1283
noname#1283

質問者が選んだベストアンサー

  • ベストアンサー
  • hitomura
  • ベストアンサー率48% (325/664)
回答No.2

>確かに(1)は必要ないですね^^; いや、必要でした。 resenddata1には今まででに確保したbufのアドレスが入るわけですね。 しかも、No.1のお礼に記述の初期化処理があると。 その場合は確かにこの処理になります。 では更に質問です。 /* 関数Bの一部 */ では、データ列の中間部の開放処理しか書かれていないのですが、先頭部、および、最後尾の処理はどうなっているのでしょうか。 あと、 >struct buf temp; >struct buf *restart1=&temp; の部分ですが、この部分の処理に?となってしまいました。 このデータ構造の場合、tempを使わず、main()の始めのほうでmalloc()した領域をrestart1に設定するのが相場なので。

noname#1283
質問者

お礼

再度ご回答ありがとうございます。 私自身未熟なので四苦八苦しながら作っているので、プログラムに自信がまったくないので、hitomuraさんの回答に「ああ、必要なかったか・・」とすぐに思い込んでしまいました^^; まず、ちょっと最初に説明足らずなところがあったことをお詫びします。かなり大きいプログラムなので全体をのせるわけにもいかず、抜粋したのですが大事なところが抜けていました^^;;以下の部分もそうです。 関数Bのリストの先頭と最後尾ですが関数Aの部分のリストそのものです。つまり すべての関数が参照するexterns.hというヘッダ内で extern struct buf temp; extern struct buf *restart; extern struct buf *resenddata; という処理がしてあり、main.c内で struct buf temp; struct buf *restart=&temp; struct buf *resenddata; としています。つまり先頭はrestartで最後はNULLとなっています。 追加のご質問ですが、そこの部分の処理で最初の構造体の場所を記憶しているのですが、確かにご指摘の方法の方がスマートかと思います。そちらに変更してみようと思っています。 問題のあったプログラムですが、リストの数を表示するようにして問題個所をつめていったところ直りました。 最後になりましたが、hitomuraさん丁寧なご回答ありがとうございました。

その他の回答 (1)

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.1

/* 関数Aの一部 */ flowdata = (struct buf *)malloc(sizeof(struct buf)); resenddata1->next=flowdata;  // (1) flowdata->next=NULL; resenddata1=flowdata; // (2) temp_num[n]++; resenddata1->no=temp_num[n]; resenddata1->wnd=cwnd[n]; (1)で設定したデータは(2)で消えてしまいますが、その前にrestartへのコピーは行われているのでしょうか?

noname#1283
質問者

お礼

回答ありがとうございます。 確かに(1)は必要ないですね^^; 補足として初期設定でmain内で resenddata=restart; restart->nest=NULL; を行っています。 未熟なためいろいろおかしいかと思いますが引き続き募集させていただきます。

関連するQ&A

  • C言語 Segmentation fault

    program SPROGRAM 17 4 pas104 SIDENTIFIER 43 4 ( SLPAREN 33 4 上記のようなファイルを読みこんで、1行づつ各トークン(programとか17とか)を構造体に格納する関数reader()を作りましたが、これを以下のparser.cで呼びだすと「Segmentation fault(core dumped)」となってしまいます。gdbのrunコマンドでプログラムを実行すると、関数を呼び出す所で Program received signal SIGSEGV, Segmentation fault. 0x0040140f in reader () と表示されました。が,どうすればよいか全然分かりません・・・ どうすれば正しく動作してくれるのか、どなたか教えてください・・・ 以下ソース /*read.c*/ #include "head.h" void reader(void) { fprintf(stdout,"check"); char buf[BUF_LEN]; if (fgets(buf,sizeof(buf),fp) == NULL)/*ここで1行読みこむ*/ {/*いきなりNULLの場合*/ strcpy(t.str, ""); t.num = SEOF; t.line = 1; } else { 省略 } return; } /*parser.c*/ #include "head.h" struct tokenbox t; FILE *fp; int main(int argc, char *argv[]) { if (argc != 2)/*引数チェック*/ { fprintf(stderr,"Usage: (./parser) (file.ts)\n"); return -1; } int len; len = strlen(argv[1]);/*file.ts の長さ取得*/ if((argv[1][len-1] == 's') && (argv[1][len-2] =='t') && (argv[1][len-3] == '.'))/*tsファイルが指定されているかどうか*/ { fp = fopen(argv[1],"r");/*ファイルオープン*/ if (fp == NULL) { fprintf(stderr,"Such ts file is not exist\n"); return -1; } fprintf(stdout,"authenticate ts file!\n");//←これは出力される reader(); //←ここでSegmentation faultと思われる printf("t.str = %s\n", t.str); printf("t.str[0] = %c\n", t.str[0]); printf("t.num = %d\n", t.num); printf("t.line = %d\n", t.line); fclose(fp); return 0; } else { fprintf(stderr,"the file is not ts\n"); return -1; } } ヘッダファイル一部抜粋 /*head.h*/ #include <stdio.h> #include <string.h> #include <stdbool.h> #define BUF_LEN 128 #define TOKEN_LEN 128 struct tokenbox {/*tsファイルの各情報を格納する構造体*/ char str[TOKEN_LEN]; int num; int line; }; extern struct tokenbox t;/*構造体をtと置く*/ extern FILE *fp; /*ファイルポインタ*/

  • リンクリスト、deleteRecord() の書き方は?

    以下のような関数がありまして、 リストの真ん中と最後を削除することは できるのですが 先頭がうまくいきません。 また、先頭の場合は free() をどのように使うのでしょうか? code を見直してみると読み易くないような気もするんですが、 もっと効率の良い書き方ありますでしょうか? int deleteRecord(struct record **start, char name[]) {   int judge = 0;   struct record *temp, *temp2;   temp = *start;   if(debugmode == 1)     printf("deleteRecord called.\n");   if(temp != NULL) {     if(strcmp(temp->name, name) == 0) {       if(temp->next == NULL) { /* only start point */         temp = NULL;       }       else {         temp = temp->next;       }       judge = 1;     }     else if(temp->next != NULL) {       while(temp->next != NULL) {         if(strcmp(temp->next->name, name) == 0) {           if(temp->next->next != NULL) {             free(temp->next);             temp->next = temp->next->next;           }           else {             free(temp->next);             temp->next = NULL;           }           judge = 1;         }         if(temp->next != NULL)           temp = temp->next;       }     }   }   return judge; }

  • Segmentation fault その2

    ダイクストラ法を用いて最短経路を表示するプログラムなんですが void daijkstra(int a) { //count[] この関数では定義していません(この外です) int g, b, c, d, e, f; //アクセス出来る点を探索. for(b = 0, c = 0;b != ten;b++){ if(adj[a][b] == INT_MAX || a == b) continue; else{ if(no_loop[b] != ten * hen){ count[c] = b;//アクセス出来た点を入力. c++; no_loop[b] = no_loop[b] + 1; } } } count[c] = -1; for(d = 0;count[d] != -1; d++){ c = count[d]; if(place[c] == INT_MAX){ place[c] = adj[a][c] + place[a]; } else{ g = adj[a][c] + place[a]; if(g < place[c]){ place[c] = g; } } } for(e = 0;count[e] != -1;e++){ f = count[e]; daijkstra(f); } return; } こういった感じに完成しました。 ですがSegmentation fault (core dumped)と表示されどうしても出来ない場合が時々あるんです.(main 関数でネットワークをランダムに生成しています。上記の関数だけでは情報が少ない場合はmainを載せます。) スタックオーバーフロウが起きているのは確実なんですがそれを回避する術を知らないのでどうかご協力をお願いします. ten * hen を1に変更すると2回目にアクセスした場合に2回目の方が短い場合更新できなくなるので1以上にして、ten * henは全ての点に全部の辺が付いていると考えた『これ以上はないはず』といういみがあります

  • セグメンテーション違反が出てしまいます・・・.

    #include<stdio.h> typedef struct tag{ int num; char name[10]; struct tag *next; }DATA; void add(void); DATA *head,*wp,*back; int main(void) { FILE *rfp,*wfp; char buf[256]; DATA *p; head=NULL; //ファイルを読み込み--------------------------- rfp=fopen("sample.txt", "r"); while(fgets(buf,256,rfp)!=NULL){ p=(DATA *)malloc(sizeof(DATA)); sscanf(buf,"%d %s", &(p->num),p->name); if(head==NULL){ head=p; head->next=NULL; back=p; } else{ back->next=p; back=p; } p->next=NULL; } fclose(rfp); //読み込み終了--------------------------------- } void add(void){ DATA *newp; newp=(DATA *)malloc(sizeof(DATA)); scanf("%d", &newp->num); scanf("%s", &newp->name); newp->next=NULL; for(wp=head; wp!=NULL; wp=wp->next){ if(head=NULL)head=newp; else if(newp->num < wp->num){ head->next = newp; } } } sample.txtからデータを読み込みそれを構造体のリスト構造にしてその構造体にデータを追加したいのですが、最後のhead->next=newpのところでセグメンテーション違反が出てしまいます。なぜでしょうか? 恐らくプログラムの内容はあまりないと思いますので概要だけ汲み取ってくれたら嬉しいです。因みにadd関数は途中です。

  • 双方向リストのバブルソートについて

    双方向リストをバブルソートを用いてソートしたいです。 下記がプログラム(一部)ですが、ソートした後にリスト表示すると 無限ループに陥ります。 どこがいけないのでしょうか。 #include <stdio.h> #include <stdlib.h> struct cell{ int data; struct cell *next, *prev; }; void insert_head(struct cell **head, int num){ struct cell *p, *p1; p = *head; p1 = make_cell(); *head = p1; p1->data = num; p1->next = p; if(p1->next != (struct cell *)NULL){ p1->next = p; p->prev = p1; } } void print_list(struct cell *head){ struct cell *p; p = head; printf("data = \n"); while(p != (struct cell *)NULL){ printf("%d\n", p->data); p = p->next; } } void sort_list(struct cell **head){ struct cell *p, *p2; int i, n; n = 0; p = *head; while(p->next != (struct cell *)NULL){ p = p->next; n++; } for(i = 0, p = *head; i < n-2; i++){ if(p->data > p->next->data){ if(p == *head){ *head = p->next; }else{ p->prev->next = p->next; } p2 = p->next; p->next = p->next->next; p->next->next = p; p->next->next->prev = p; p->next->prev = p->prev; p->prev = p2; }else p = p->next; } } int main(void){ struct cell *head = (struct cell *)NULL; int n; while(1){ printf("1:Insert head 2:Insert tail 3:Delete 4:List 5:Sort 6:Exit\n"); scanf("%d", &n); switch(n){ case 1: printf("num = "); scanf("%d", &n); insert_head(&head, n); break; case 2: printf("num = "); scanf("%d", &n); insert_tail(&head, n); break; case 3: printf("num = "); scanf("%d", &n); delete_cell(&head, n); break; case 4: print_list(head); break; case 5: sort_list(&head); break; case 6: return 0; break; } } }

  • C言語 二分木探索

    今、int型の二分木にデータを追加する関数(引数は二分木へのポインタと追加する値、追加されたノードへのポインタを返す)をつくろうとしてます。 以前リストにデータを追加する関数をつくったのでそれを変更してつくろうとしているのですが途中までいってつまってしまいました。 つくりかたを教えてください。 よろしくお願いします! struct BinaryTreeNode{ int data; struct BinaryTreeNode *l_next; struct BinaryTreeNode *r_next; }; struct BinaryTree{ int node_num; struct BinaryTreeNode *root; }; BinaryTreeNode *BinaryTreeNodeAlloc(void) { BinaryTreeNode *node; node = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode)); if (node == NULL) { return (NULL); } node->l_next = NULL; node->r_next = NULL; return (node); } BinaryTreeNode *BinaryTreeDataAdd(BinaryTree *list, int x) { BinaryTreeNode *ptr; BinaryTreeNode *prev; BinaryTreeNode *new_node; ptr = list->root; prev = NULL; while (ptr) {       ←?? if (ptr->data < x) { prev = ptr; ptr = ptr->next; } else if (ptr->data == x) { return (NULL); } else { new_node = BinaryTreeNodeAlloc(); if (new_node == NULL) { exit (0);                ←?? } new_node->data = x; new_node->next = ptr; if (prev != NULL) { prev->next = new_node; } else { list->head = new_node; } list->node_num++; return (new_node); } } new_node = BinaryTreeNodeAlloc(); if (new_node == NULL) { exit (0); } new_node->data = x; new_node->r_next = NULL; new_node->l_next = NULL; if (prev != NULL) { prev->next = new_node; } else { list->head = new_node; } list->node_num++; return (new_node); }

  • 単方向リストに適当な値を入れて、逆順に表示するプログラムの仕組みがわかりません。

    以下のプログラムのReverceShowValue関数の仕組みがわかりません。 申し訳ございませんが、ご教授の方、よろしくお願いします。 #if 1 /* リスト構造の実装 * 再帰関数を用いて逆順に表示 */ #include <stdio.h> #include <stdlib.h> typedef struct object{ int value; struct object *next; }OBJ; OBJ* AllocateBlock(int value) { OBJ *block; block = (OBJ*)malloc(sizeof(OBJ)); if(block == NULL){ printf("Allocate Error\n"); exit(1); } block->value = value; block->next = NULL; return block; } void ReverceShowValue(OBJ *p) { if(p != NULL){ ReverceShowValue(p->next); printf("%d\n", p->value); } } void FreeAllocate(OBJ *p_top) { OBJ *temp; while(p_top != NULL){ temp = p_top->next; free(p_top); p_top = temp; } } int main(void) { OBJ *top = NULL; OBJ *temp; int i; for(i = 0;i < 10;i++){ if(top == NULL){ top = AllocateBlock(i); temp = top; } else{ temp->next = AllocateBlock(i); temp = temp->next; } } ReverceShowValue(top); FreeAllocate(top); return 0; } #endif

  • ポインタを使った連結リストへの挿入

    siteiで指定されているポインタの直後に要素xを挿入する関数insertをポインタの連結リストを用いて作成したのですが、実行するとセグメンテーション違反がでて上手く動きません。何処に問題があるのでしょうか?topの初期値が不定になるのが問題と思い、topをNULLで初期化して実行してみたのですが、結果は変わりませんでした。 宜しければ回答または問題点を指摘していただけますでしょうか?宜しくお願いします。 typedef struct{ int data; struct DATA *next; }DATA; DATA top; int insert(int x,DATA *sitei) { DATA *p,*buf; p=&top; while( p!=NULL && p!=sitei) p=p->next; buf=malloc(sizeof(DATA)); buf->next=p->next; p->next=buf; buf2->data=x; return 0; }

  • 【C言語】構造体内の領域解放(free)の仕方

    教えてGoo運営側に内容チェックされているため再度内容を変更し質問させていただきます。 http://okwave.jp/qa/q8080757.html (ダンプを書いたのがまずかったかもしれないので、ここでは削除します。) <プログラムで実行したいこと> ・簡単なリストを作成 ・リストを構成する構造体のメンバはchar*などのメンバがあり、  特に、char*にstrdupにて文字列をコピーする。(正確には文字列のポインタをコピーする。) ・作ったリストをプリントする。 ・領域を確保する。 下記のソースで動くと思ったのですが、領域のfreeでうまくいきません。 どうもない領域をfreeしているようなのです。それがなぜかわかりません。 *** glibc detected *** ./a.out: free(): invalid pointer: 0x00000000020eb030 *** どうしたら、解決するのか、どこが悪いのかご指摘いただけないでしょうか。 以下、私が書いたソースになります。 #include<stdio.h> #include<stdlib.h> #include<string.h> struct word { struct word *next; char *st; int *line_no; int line_cnt; }; struct word *head; void Add_List(char *buf,int no){ struct word* node = malloc(sizeof(struct word*)); struct word* crnt; /*nodeの準備*/ node->next = NULL; //node->st = strdup(buf); node->st = malloc(sizeof(char)*10); strcpy(node->st,buf); node->line_no = malloc(sizeof(int*)); node->line_no[0] = 1; node->line_cnt= 1; if(head == NULL) { head = node; } else { crnt = head; while( crnt->next != NULL) { crnt = crnt->next; } crnt->next = node; } } void printlist(){ struct word *crnt = head; while( crnt != NULL ) { printf("%s\n",crnt->st); crnt = crnt->next; } } int main(){ head = NULL; char buf1[] = {'A','B','C','D','E','\0'}; char buf2[] = {'F','G','H','I','J','\0'}; char buf3[] = {'K','L','M','N','O','\0'}; Add_List(buf1,1); Add_List(buf2,1); Add_List(buf3,1); printlist(); /*この部分がうまくいかない*/ printf("%s\n",head->st); printf("%x \n",head->st); free(head->st); /*********************/ }

  • 構造体について

    typedef struct num{ char rv[1000]; struct number *next; struct number *prev; }Num; このような双方向のリスト構造に void aplist(Num **s,char ns[]){ Num *old, *new; if(*s==NULL){ *s = (Num *)malloc(sizeof(Num)*1); strcpy((*s)->rv,ns); (*s)->next = NULL; (*s)->ago = NULL; return;} old= (*s); while(old->next != NULL){ old = old->next;} new = (Num *)malloc(sizeof(Num)*1); strcpy(new->rv,ns); new->next = NULL; old->next = new; new->prev = old; 関数の中でこのようにnext,oldを指定していったのですが、これでよいでしょうか?また、このリストを逆方向(prevの方向)に表示していきたいのですがどのように書けばよいでしょうか?nsは1行の文字列で、各構造体に1行ずつ入れていっています。