構造体へのポインタの動的確保について

このQ&Aのポイント
  • ポインタを動的確保しようとするとsegmentation faultが起きます。
  • malloc関数を使用すると正常に動作するが、ポインタを参照する際に上手くいかない。
  • ライブラリとのリンクの問題ではないか疑われる。
回答を見る
  • ベストアンサー

構造体へのポインタの動的確保について

構造体へのポインタを動的確保しようとmalloc関数を使用すると segmentation faultが起きます。 typedef struct cell{ char *word; int count; struct cell *next; }node_t; という構造体で node_t *ptr=(node_t*)malloc(sizeof(node_t)*num); という風に動的確保しようとするとsegmentation faultが起きました。 gdbを使って調べると Starting program: /home/programII/week05/a.out file1 file2 Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7b4ce36 in ?? () from /lib/x86_64-linux-gnu/libc.so.6 というメッセージが返ってきます。 これはライブラリとのリンクが正しく行われていないということでしょうか? しかし、ポインタの動的確保以外でmalloc関数を使用すると 正常に動作するのでライブラリ自体が無いわけではないようです。 ptr[2]といった風にポインタを参照したいのですが上手くいきません。 よろしくお願いします。

noname#204615
noname#204615

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

  • ベストアンサー
  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.6

まぁ、もろもろ指摘が既に入っていますが……。 nodePrepend()にブレークポイント張って、変数の「中身」を確認しながらステップ実行して下さい。 たぶん、forループが1回まわる前に気づくでしょう。

noname#204615
質問者

お礼

*listを初期化してnodePrepend内に条件分岐を加えたら ヒープソートまでできるようになりました。 ありがとうございましたm(_ _)m

その他の回答 (7)

  • bull1472
  • ベストアンサー率66% (2/3)
回答No.8

よく見たら、その前に num をインクリメントしてますね。 その必要があるかどうかわかりませんが、そのために p が NULL になってしまいますね。

  • bull1472
  • ベストアンサー率66% (2/3)
回答No.7

直接のエラーの原因は for (i = 1, p = list; i <= num; i++, p = p->next) { ptr[i] = *p; } ここでしょう。 配列をnum個しか確保していないのに、num番目を使ってはいけません。 C言語での配列は、0~num-1を使用します。 また、 free(p); と解放していることも変ですね。

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.5

>Program received signal SIGSEGV, Segmentation fault. >0x00007ffff7b4ce36 in ?? () from /lib/x86_64-linux-gnu/libc.so.6 >というのは、main関数に入る前に >segmentation faultを起こしているように思えるのですが >どうなのでしょうか。 自分の書いたコードに非はないと思い込みたい気持ちはわからなくないですが、nodePrependの使い方がおかしいです。 nodePrependを呼び出す前にやるべき事を忘れていませんか。

noname#204615
質問者

お礼

*listを初期化していませんでしたね… ありがとうございました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

うん, それはコケると思う. デバッガで調べてもらえばわかるはずだけど, nodePrepend がまともに動かないんじゃないかな. そして問題は nodePrepend にはないという....

noname#204615
質問者

お礼

*listを初期化していなかったからでしょうか。 初期化をしたら問題なくヒープソートまでできました。 ありがとうございましたm(_ _)m

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.3

>このmallocの後にfree(ptr)だけを書いてもsegmentation faultが起きます。 それだけだと起きそうにないと思われるんですけどねぇ。 念のため、 sizeof(node_t) はいくつになります? num に入っている値はいくつです? ポインタ2つにint型1つですから、たいしたサイズにはならないハズですけど。 # 64Bit環境っぽい…けど、特にオプション指定しなかった場合にint型が何ビットになったかなぁ…。 取得したポインタに対して何らかの操作を行った…とか、 32Bitと64Bitが混在した…とかでしょうかねぇ……。 周辺のコードを掲示した方がいいかも知れませんね。 # malloc()直後にfree()でも死ぬ…というのが変ですが…。 # numが異常な値でメモリ確保できなかった場合はNULL返却でしょうし。

noname#204615
質問者

補足

返答ありがとうございます。以下、コードです。 ------------------------------------- #include<stdio.h> #include<stdlib.h> #include<string.h> typedef struct cell{ char *word; int count; struct cell *next; }node_t; int readword(FILE *fp,char *s); node_t *alloc_node_t(node_t *ndPtr,char *s); void nodePrepend(node_t **ndPtrPtr,char *s); void selection_sort(node_t *ndPtr,int n); void listprint(node_t *ndPtr); void heapsort(node_t *ndPtr[],int n); void downheap(node_t *ndPtr[],int leaf,int root); void swap(node_t *ndPtr[],int i,int j); int main(int argc,char *argv[]){ int i,num=0; FILE *fp; char buf[32]; node_t *list,*p; for(i=1;i<argc;i++){ if((fp=fopen(argv[i],"r"))==NULL){ fprintf(stderr,"cannot open %s\n",argv[i]); return 1; } while(readword(fp,buf)!=0){ //文字列の読み取り nodePrepend(&list,buf); //線形リストへの追加 } fclose(fp); } for(p=list;p!=NULL;p=p->next){ num++; //要素数のカウント } selection_sort(list,num);       //単純選択法によるソート listprint(list);            //線形リストを表示 printf("----------------------------------------\n"); num++; node_t *ptr=(node_t*)malloc(sizeof(node_t)*num); //ポインタの配列の動的確保 for(i=1,p=list;i<=num;i++,p=p->next){ ptr[i]=*p; } /* heapsort(ptr,num); for(i=1;i<num+1;i++){ printf("%s %d\n", ptr[i]->word , ptr[i]->count); } */ free(p); return 0; } int readword(FILE *fp,char *s){ int ch,k=0; while((ch=getc(fp))==' '|| ch=='\t' || ch=='\n'){}; if(ch==EOF) return 0; s[k]=ch; k++; while((ch=getc(fp))!=' ' && ch!='\t' && ch!='\n' && ch!=EOF){ s[k]=ch; k++; } s[k]='\0'; return 1; } node_t *alloc_node_t(node_t *ndPtr,char *s){ node_t *p; p=(node_t *)malloc(sizeof(node_t)); p->word=(char *)malloc(strlen(s)+1); strcpy(p->word,s); p->count=1; p->next=ndPtr; return p; } void nodePrepend(node_t **ndPtrPtr,char *s){ node_t *ndPtr; for(ndPtr=*ndPtrPtr;ndPtr!=NULL;ndPtr=ndPtr->next){ if(strcmp(ndPtr->word,s)==0){ ndPtr->count++; return; } } ndPtr=alloc_node_t(*ndPtrPtr,s); *ndPtrPtr=ndPtr; } void selection_sort(node_t *ndPtr,int n){ int i,j,min_count,temp_count; char *min,*temp_word; node_t *p,*q,*k; for(i=0;i<n;i++){ p=ndPtr; if(i!=0){ for(j=0;j<i;j++){p=p->next;}; } min=p->word; min_count=p->count; k=p; for(q=p->next;q!=NULL;q=q->next){ if(strcmp(min,q->word)>0){ min=q->word; min_count=q->count; k=q; } } temp_word=p->word; temp_count=p->count; p->word=min; p->count=min_count; k->word=temp_word; k->count=temp_count; } } void listprint(node_t *ndPtr){ int i; while(ndPtr!=NULL){ for(i=0;i<ndPtr->count;i++){ printf("%s\n",ndPtr->word); } ndPtr=ndPtr->next; } } ---------------------------------------- 与えられた課題が 「ファイルから文字列を読み取り、単純選択法により文字が小さい順にソートする。 その後、ヒープソートにより出現回数の少ない順にソートする」 というものです。 読み取った文字列を線形リストに保存し、単純選択法によるソートまではできたのですが ヒープソートをするためにポインタを配列に動的確保しようとしたところで segmentation faultが起きました。 動的確保ができなかったのでヒープソートをする部分は省略していますが これでもsegmentation faultが起きます。 sizeof(node_t)は12、numは11のようです。 配列を動的確保せずにヒープソートした方がいいのでしょうか… また Starting program: /home/programII/week05/a.out file1 file2 Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7b4ce36 in ?? () from /lib/x86_64-linux-gnu/libc.so.6 というのは、main関数に入る前に segmentation faultを起こしているように思えるのですが どうなのでしょうか。 よろしければ引き続きお願い致します。

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.2

>動的確保以前のプログラムは正しく動作するのですが…… そういう場合は「正しく動作しているように見えてるだけ」という事もあります。 うちの環境はlinuxではなくFreeBSDですけど % cat node.c #include <stdio.h> #include <stdlib.h> typedef struct cell { char *word; int count; struct cell *next; } node_t; int main(int argc, char **argv) { int num = 10; node_t *ptr = malloc(sizeof(node_t) * num); printf("%p\n", ptr); free(ptr); return 0; } % cc -o node node.c % ./node 0x801006100 % 何の問題もなく動きますけど。

  • wormhole
  • ベストアンサー率28% (1619/5653)
回答No.1

>node_t *ptr=(node_t*)malloc(sizeof(node_t)*num); >という風に動的確保しようとするとsegmentation faultが起きました。 本当にそのmallocで起きてるsegmentation faultですか。 その後に書いてる何らかの処理で起きてるんじゃないですか?

noname#204615
質問者

補足

このmallocの後にfree(ptr)だけを書いてもsegmentation faultが起きます。 また、このmallocとfreeをコメントアウトすると 動的確保以前のプログラムは正しく動作するのですが……

関連するQ&A

  • ポインタ配列の動的確保

    ポインタの配列の動的確保について教えてください。 入力した数値をポインタ配列に入れるプログラムです。 下記のように書いてみました。(見づらくてごめんなさい) #include<stdio.h> #include<stdlib.h> #define kensu 3 main() { char abc[kensu+1]={'A','B','C','\0'}; char *ptr[kensu]; int i; printf("3つの整数を入力して下さい。\n"); for(i=0;i<kensu;i++){ ptr[i]=(char*)malloc(sizeof(char)*10); if(ptr[i]==NULL){ printf("メモリの取得に失敗しました"); exit(1); } printf("整数%c:",abc[i]); fgets(ptr[i],10,stdin); if(ptr[i][strlen(ptr[i])-1]=='\n') ptr[i][strlen(ptr[i])-1]='\0'; } for(i=0;i<kensu;i++) free(ptr[i]); } ちゃんと動いているようです。 しかし、ポインタ配列の動的確保をネットで調べてみると、ポインタのポインタ(?)を使って、下記のように2度mallocしています。 #include <stdio.h> #include <stdlib.h> #define N 3 int main(void) { char** arr; int i,j; arr = (char**)malloc(N * sizeof(char*)); /* ポインタ配列を確保 */ /* 配列の要素それぞれにつき、メモリ領域を確保 */ for(i=0;i<N;i++) arr[i] = (char*)malloc(N * sizeof(char));   ・・・ ポインタの配列を宣言して、配列の各要素に動的確保するのと ポインタのポインタを宣言し、ポインタ配列を動的確保して、再度配列の要素に動的確保するのとでは、何か違いがあるのでしょうか? ポインタのポインタを宣言し、ポインタ配列を確保する必要性が良く分かっていないのです。 ネット等で調べて見たのですが、理解力がないのかよく分かりませんでした。 どうか教えてください。

  • List構造

    Listの尻にノードを追加する関数で困っています。 以下に、ソースの一部を掲載させていただきます。 typedef struct __node{ int data; struct __node *next; }Node; ... /*リストの尻にノードを追加する関数 * 引数: head. リストの先頭ノードのポインタ data. リストの尻に追加したいint型の変数*/ void Insert_Tail(Node *head, int data) { Node *ptr = head; if(ptr == NULL){ /*<ノードが存在しない時には追加されない>*/ /*領域の確保*/      head = (Node*)calloc(1,sizeof(Node)); /*データをセット*/ head->data = data; head->next = NULL; return ; }else{ /*<ノードが存在するときには正常に動作>*/ while(ptr->next != NULL){ ptr = ptr->next; } /*領域の確保*/ ptr->next = (Node*)calloc(1,sizeof(Node));      /*データのセット*/ ptr->next->data = data; ptr->next->next = NULL; } } コメントアウトにも書かせていただきましたが、ノードがすでに存在するときには、正常にノードの最後に追加してくれるのですが、ノードが存在しない時にはリストに追加してくれません。 どうかご指導、ご指摘の程お願いします。

  • 構造体について

    構造体について分からない点があり,教えて頂きたく投稿いたします. 現在,以下のような構造体を作成しています. typedef struct{ int data; struct node *NEXT; }node; また,それを管理するためのリストを以下の構造体にて宣言しました. typedef struct{ node *crnt; node *last; }node_list; また,使用する関数内での宣言は以下の通りです. node_list *non_dscvr_node_list; //未探査ノードを格納する node *crt_dscvr_node; //現在探査中のノードを示す node *start; そして, start->data = 10; start->NEXT = NULL; non_dscvr_node_list->crnt = start; non_dscvr_node_list->last = start; : : crt_dscvr_node = non_dscvr_node_list->crnt; non_dscvr_node_list->crnt = crt_dscvr_node->NEXT; //ここでエラーがでる. エラーの詳細は以下の通りです. warning: assignment from incompatible pointer type 私としては,リストに格納されている先頭ノードをポップして,次のノードを先頭にしたつもりだったのですが,ポインタタイプに互換性がないと怒られてしまいました. 少し調べては見ましたが,nodeの構造体を管理するために別に構造体を定義しているページがあまり見あたりません. 従って,そのようなページがあれば教えて頂きたいと思います. このような方法はあまりよくないのでしょうか. 併せて教えていただけますようお願いいたします.

  • 構造体のポインタの動作及びそれ故書けない関数

    こんにちは.c言語でのstructureのポインタについての質問,及びその動作ゆえに自分のやりたい書き方ができないので,アドバイスをお願いしたいと思います. まずは,structureのポインタを使った計算が謎の動きをするので,説明して頂けたらと思います.ubuntu 12.04 64bit, コンパイラはgcc 4.6.3, ただg++でやっても同じ動きでした. #include <stdio.h> int main(int argc, char **argv) { struct state_ { double pos[3]; double att[3]; }state = { { 1.0, 2.0, 3.0 }, { 4.0, 5.0, 6.0 }, }; double *state_ptr; state_ptr = &state.pos[0]; printf("%f\t%f\t%f\t%f\t%f\t%f\n", *state_ptr, *(++state_ptr),*(++state_ptr), *(++state_ptr), *(++state_ptr), *(++state_ptr)); double *pos_ptr, *att_ptr; pos_ptr = &state.pos[0]; att_str = &state.att[0]; printf(“head of pos %f, head att %f\n”, *pos_ptr, *att_ptr); return 0; } こうすると,結果は 6.000000 6.000000 6.000000 6.000000 6.000000 6.000000 head of pos 1.000000, head of att 4.000000 はて,どうなっているのでしょうか?少なくとも1行目の最初の6.0はpos[0]の1.0のはずなのでは? ちなみに-Wallをつけると, struct_double_pointer_test.c:17:54: warning: operation on ‘state_ptr’ may be undefined [-Wsequence-point] が出ます. また,++state_ptrをstate_ptr++に変えると結果は 6.000000 6.000000 5.000000 4.000000 3.000000 2.000000 そして -O2をつけると 6.000000 5.000000 4.000000 3.000000 2.000000 1.000000 基本的にメンバーの順番がひっくり返ってますね.これは一体どういうことなんでしょう?undefinedと言われてるから何が起こっても変じゃないでしょ,と言われればそうなんですが,何かなっとくのいく説明があれば嬉しいです.pos_ptr, att_ptrで単体で出すと正しく出るので,*(pointer++)の動作がundefinedってことなんですよね?僕は 1.0 2.0 3.0 4.0 5.0 6.0 となってくれると思った訳です.(ちなみにMacOS gccではこうなりました)structureの中で順番に上からアドレスが振られると思ったので.そして2番目の質問に移る訳ですが,上記の僕の予想通り動いた場合,2つ構造体のポインタを渡して,順番に中身を積分させていくような計算が以下のようにできると思いました. void integrate(struct state_ *x, struct state_ *dx, num_of_double) { const float timestep = 0.01 int i; for(i=0; i<num_of_double, i++){ *x += *dx*timestep; x++, dx++; } } 両方きれいに順番がひっくり返るなら上の書き方でも積分させた値は同じになるからいい?とは言えど怖くてもちろん使えません.こういう計算をさせる場合は,構造体のポイタを渡さずに配列ごとに計算させるんですかね?&pos[0]と&pos_dx[0]を渡すなど?一般的にどういう書き方をするものなのかが知りたいです.

  • 構造体配列の動的確保/ポインタ配列の利用

    構造体配列(10 領域)を動的に確保した後に,ファイル「02student.txt」から情報を読込み,標準出力するプログラムを作成してください。 【プログラムイメージ】 #include<stdio.h> #include<stdlib.h> typedef struct student{ : } STUDENT; int main(void){ STUDENT * st = /* malloc 関数で動的確保(10 領域) */ /* ファイルオープンの処理 */ for(i=0; i<10; i++){ /* ファイル入力処理(ポインタ変数st を各領域を参照し,格納) */ } for(i=0; i<10; i++){ /* 標準出力処理(ポインタ変数st から各領域を参照し,値を確認) */ } /* ファイルクローズの処理 */ /* メモリの解放処理 */ return 0; } 【実行結果】 14001 Aoki M 50 14002 Ishida F 60 : 14010 Kobayashi F 100

  • 構造体のメンバのメモリ確保について

    構造体の中の一部のメンバだけをmalloc関数で メモリ確保したいのですがどのように宣言すればよいのでしょうか? vc++6.0を使用しています。 初歩的な質問ですみませんがお願いします。

  • ポインタを使って構造体の配列を戻り値にするには

    関数の戻り値を構造体の配列(アドレスを受け渡しを利用して)にしたいのですがうまくゆきません。 以下のプログラムではコンパイルはできるのですが、 a0 = 2 a1 = 4198512 a2 = 4329332 と表示されてしまいa1,a2がうまくゆきません。 ********************************************* #include<stdio.h> struct test{ int a; }; struct test *func(void); void main(void) { struct test *data;//構造体ポインタ int i; data = func(); //ポインタにtest関数の戻り値(アドレス)を代入 for(i=0;i<=2;i++){   printf("a%d = %d\n",i,(data+i)->a); //構造体要素を表示 } } struct test *func(void) { struct test data[3]={1,2,3}; //構造体配列を定義 return (&data[0]); //構造体配列の先頭アドレスを返す } ************************************************* test関数から受ける取ったアドレス(&data[0])をポインタ(data)に代入して1づつずらして表示させれば a0=1,a1=2,a=3 となると思ったのですがどこが間違っているのでしょうか? よろしくお願いします。

  • ポインタと構造体

    C言語初心者です。 下のコードはリスト構造のサンプルコードを元に自分で書き直そうとしているコードです。(なので、現時点では不完全なところ(例えばfreeしてないとか)があるのと、自分で理解出来ていない箇所があります。) 実行すると、8から3までの値が一応表示されるようになったですが、その過程の仕組みが自分でもよく理解出来ていません。 (1)tra *q = NULL; 通常、構造体のポインタを使用するときはq = &___のように他の構造体のアドレスを渡して使用出来るようにすると思いますが、ここではなぜ*qに、NULLを代入する必要があるのでしょうか。 (2)そのNULL状態のポインタqを関数printingdudeに突っ込んで結果的に8、7、6、、と出力されるまでの過程がよくわかりません。簡単に解説して頂けると助かります。(ちょっと雑な質問になってしまい申し訳ありません) typedef struct transcript{ int no; struct transcript *next; } tra; void printingdude(struct transcript *m); tra* noud(int v, tra* c); int main(){ tra *q = NULL; int i; for(i = 8; i>1; i--){ printingdude(q); q = noud(i, q); } return; } void printingdude(struct transcript *m){ if(m ==NULL) return; printf("%d\n", m->no); } tra* noud(int v, tra* c){ tra *a = (tra *) malloc(sizeof(tra)); a->no = v; a->next = c; return a; }

  • ポインタ型配列のポインタを構造体のポインタ変数に格納する方法教えて!_ver2

    int型の配列は構造体のポインタ型のint型変数にはキャストすればうまくコンパイルが通りますが、同じ方法でfloat型の配列は構造体のポインタ型のfloat型変数にはキャストしてポインタの値を入れてもうまくコンパイルできず困っています。ちなみにコンパイルエラーは「互換でない型変換」と表示されます。 返答のほど、よろしくお願いいたします。 #include<stdio.h> #include<malloc.h> float time[] ={2.2, 2.3, 2.4}; int time2[] ={2, 2, 2}; struct timelist{ float *time; int *time2; struct timelist *next; }*head; void main(void) { struct timelist *p; p = (struct timelist *)malloc(sizeof(struct timelist)); p -> time = (float *)time[0]; p -> time2 = (int *)time2[0]; printf("time = %f\n", p -> time); printf("time2 = %d\n", p -> time2); }

  • 構造体の初期化の時にポインタを入れるにはどうしたらいいですか?

    構造体の初期化の時にポインタを入れるにはどうしたらいいですか? 例えば、このような構造体で↓ struct PACKET { uint16_t size; // データの長さ uint16_t *data; // データバイト列 }; 初期化の時にsizeとdataを入れるにはどうしたらいいのでしょうか? dataがuint16_t*じゃなくてchar*なら struct PACKET { uint16_t size; // データの長さ char *data; // データバイト列 }; struct PACKET p = { 5, "12345" }; というようにできるのですが・・・

専門家に質問してみよう