• ベストアンサー

2つのvoid関数でmallocを使うと2step目でセグメントエラーが出る

プログラムのmainを見やすくするためにサブルーチンとしてvoid関数を使っているのですが、その中でmallocでメモリを確保して配列を作ろうとするとエラーが出てしまいます。概略を書くと #include <stdio.h> #include <math.h> #include <stdlib.h> //voidの宣言 void a(double* ,double*, double,); void b(double* ,double*, double,); main(){ double *c,*d,e; double *f,*g,h; c=(double *)malloc(sizeof(double)*N) //Nは適当な整数です d,f,gも同様の処理 色々な作業 while(適当回数繰り返します){ a(c,d,e); b(f,g,h); 色々な作業 } } void a (double* c, double* d, double e){ double **i,*j,; int k; i=(double **)malloc(sizeof(double *)*M) //Mは適当な整数です for(k=0;k<=M;k++){ i[k]=(double *)malloc(sizeof(double)*M) //Mは適当な整数です } jも同様にメモリ確保 様々な作業(逆行列の計算など) } void bはaとほとんど同じです。 mallocで二次元配列や配列を作っています。勿論同じ文字は使っていません。 以上のようなプログラムでgccは通ります。でも実行するとwhile内での1step目は上手くいくのですが、2step目のb内での始めの(double *)malloc(sizeof(double)*L)(Lは適当な整数です)で、つまりメモリ確保でセグメントエラーが出ます。両者とも片方を削るとエラーは出ません。1step目は何故上手くいくのか、2ステップ目で何故ダメなのかが分かりません。皆様の御教授をお願いします。

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

  • ベストアンサー
  • php504
  • ベストアンサー率42% (926/2160)
回答No.7

mallocは実行時にならないと大きさがわからないとか大きなメモリを一時的に確保したいときなどに使います。 #define N 6 のように大きさがあらかじめわかっているならmain( )関数内で double **crmat; crmat=(double **)malloc(sizeof(double *)*(N+1)); for(kk=0; kk<N+1; kk++){ crmat[kk]=(double *)malloc(sizeof(double)*(N+1)); } とする必要は無く double crmat[ N + 1 ][ N + 1 ]; にすればかなりすっきりしそうです。 関数の引数には今のまま double **crmatとして渡せます。 hakidashi_H( )で row=(int *)malloc(sizeof(int)*5); としてますが for(ipv=1; ipv<=5; ipv++){ //略 row[ipv]=pivot_row; これはアウトです(row[ 5 ] にはアクセスしたらいけません) ここも5-6個の配列であればmalloc使わずに int row[6]; で問題ないでしょう

bechi0226
質問者

お礼

後半の部分のrow=(int *)malloc(sizeof(int)*5);のところは確かに間違いですね。 ここを直したらちゃんと動きました。 メモリの確保をする際には注意しないといけないことが分かりました。 まさかこんなところに原因があったなんて・・・と思いました。

その他の回答 (8)

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

double crmat[ N + 1 ][ N + 1 ]; を double **crmat に渡しちゃだめです~>#7.

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.8

> printf("charge fraction:%e\n",-frac[1]+frac[3]-frac[4] > +frac[6]+frac[8]+2.0*frac[9]); main関数の最後にある上記の文で、 frac[8]と[9]は動的に確保した領域の範囲外にあります。

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

よくそんな長い関数が書けるなぁ. 尊敬しちゃう. とりあえず, 「malloc を使わなくていいところでわざわざムダに malloc を使う」のは止めてほしい. 例えば about_HH の ene_? なんてのは, malloc を使う必要ないよね. あと, いくつかのところでリークを起こしてるから, そこもチェックし直すこと. こっちの例は H_line の Spon_H など. 同じく H_line の gamma_e は for を使えばもっときれいに計算できる. 確かにこれじゃあ「何を消していいかわからない」よなぁ.

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.5

>2次元配列の初期化する際のインデックスが間違ってるのは写し間違いということなのでしょうか? そうなのかどうかは、質問者さんがお手持ちのコードをコピー&ペーストしてくださればわかることでありましょう。 実行時にセグメントエラーが出るということは、少なくともコンパイルは通っているはずですね。 しかるに、提示されたコードには、 >void a(double* ,double*, double,); >void b(double* ,double*, double,); >c=(double *)malloc(sizeof(double)*N) //Nは適当な整数です >double **i,*j,; >i=(double **)malloc(sizeof(double *)*M) //Mは適当な整数です >i[k]=(double *)malloc(sizeof(double)*M) //Mは適当な整数です という具合に、手で書き写したために生じたのであろう間違いがあります。 よって、私からのアドバイスは「落ちることが再現できる、動くコードを見せてください」という 内容のものになりました。

bechi0226
質問者

補足

分かり易く簡潔に伝えようとして却ってあだになってしまいました。 みなさん、申し訳ありません。 何を消して良いやら分からず、消したところで文字数の上限を超えそうなのでネット上に置いてみました。 http://vega.ess.sci.osaka-u.ac.jp/~bessho/error.c 簡単に説明しておくと、水素の雲の進化を計算するコードです。 問題点は「cool_H_line」と「cool_HH_line」を同時に使うと1回目は上手くいくのに2回目にcool_HH_lineのメモリ確保する行でセグメントエラーが出ることです。 printf("a\n"); gamma_J_H=(double *)malloc(sizeof(double)*63); printf("b\n"); とあるのですが、aが画面に出た後セグメントエラーが出ます。 長いコードになっていますが引き続きよろしくお願いします。

  • chie65535
  • ベストアンサー率43% (8514/19354)
回答No.4

mallocを使うと、メモリ上は 管理用データ(次の管理データの場所と、ユーザーデータのサイズなど) ユーザーデータ(ここの先頭がmallocから返される) 管理用データ(次の管理データの場所と、ユーザーデータのサイズなど) ユーザーデータ(ここの先頭がmallocから返される) 管理用データ(次の管理データの場所と、ユーザーデータのサイズなど) ユーザーデータ(ここの先頭がmallocから返される) 管理用データ(次の管理データの場所と、ユーザーデータのサイズなど) ユーザーデータ(ここの先頭がmallocから返される) 管理用データ(ここで終り、のマークが付く) と言う状態になります。 ここで、ユーザーが「ユーザーデータの領域を超えて、次の管理用データの上に、ユーザーデータを書き込んでしまう」と言うミスをすると「malloc関数の中で空いている場所を探して、管理用データを辿っていくうちに、管理用データが壊れている場所に行き着き、不正なアドレスにアクセスしてしまう」と言う事が起きます。 つまり 「プログラムで、確保した領域の外にデータを書き込んでいる」 のです。 例えば「10個分しか確保してないのに、11個目以降の場所に書き込んでいる」など。 で、プログラムのforループを見ると >for(k=0;k<=M;k++){ となっていて「kは0からMまでの、M+1回ループ」しています。 「配列iはi[0]~i[M-1]のM個しかない」のに、最後に「i[M]」にポインタを書き込みます。 しかし「i[M]の位置には、mallocの管理用データがある」ので、管理用データが壊われます。 次にmallocを呼ぶ(つまり、b内の最初のmallocを呼ぶ)と「malloc関数の中で空いている場所を探して、管理用データを辿っていくうちに、管理用データが壊れている場所に行き着き、不正なアドレスにアクセスしてしまう」のです。 forループは for(k=0;k<=M;k++){ ではなく for(k=0;k<M;k++){ にしなければなりません。

  • KDASH-XP
  • ベストアンサー率46% (63/136)
回答No.3

すると 2次元配列の初期化する際のインデックスが間違ってるのは写し間違いということなのでしょうか?

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.2

追記です。 ソースコードを載せるときは、エディタなどからコピー&ペーストしてください。 手で書き写そうとすると、 >void a(double* ,double*, double,); こんな風に、コンパイルエラーが出るソースコードを載せてしまうことになります。

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.1

回答しようとする側で何も手を加えなくても現象が再現できる 最小限のソースコードを載せてくださいますか? 質問者さんと、回答しようとする側とで別々のソースコードを見ていると、 行き違いが生じたりして、なかなか解決に至らないように思うのです。

関連するQ&A

  • malloc関数によるメモリの確保

    C初心者です。 malloc関数によるメモリの確保に関して教えてください。 2次元配列のサイズに対してmalloc関数の引数値をたとえば、 (double*)malloc(datasize*sizeof(double)) などとしメモリ領域を確保すると、メモリアドレスはデータのサイズ によらず一定 1234044、1234048となります。 データサイズを大きくし、datasize*sizeof(double)が16Kバイトを超えるとcmd.exeがエラーとなり落ちます。 デバックモードで実行すると 「"System.AccessViolationException"のハンドルされていない例外が不明なモジュールです。で発生しました。 追加情報:保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリがこわれていることが考えられます」 というメッセージがでます。 コンパイラはExpressEdition2008です。 この現象を回避するにはどうすべきか、なぜこのようなことが起こるのかご教授ください。 よろしくお願いいたします。

  • 関数宣言

    3次元で領域を確保するプログラムをmalloc関数を用いて書きました。しかし、プログラムが長いので関数宣言をしなさいといわれたために、以下のプログラムを書きました。しかし、途中でつまづいてしまい、どのように関数を用いたり、関数を定義すれば良いのか混乱しています。初心者ですが、どうかお願いします。 /*ソース*/ #include<stdio.h> #include<stdlib.h> int main(){ double ***C; f3Malloc(C,.,.); //数値を代入(関数の使い方?) f3Free(C,.,.); } /*3次元配列(返し方?)*/ double*** f3Malloc(C,,){ int i,j,x,y,z; x = 2; y = 3; z = 4; C=(double***)malloc(sizeof(double**)*x*y*z); for(i=0;i<y;i++){ C[i]=(double**)malloc(sizeof(double*)*y*z); for(j=0;j<z;j++){ C[i][j]=(double*)malloc(sizeof(double)*z); } } } /*メモリの解放(返し方?)*/ void f3Free(C,.,.){ int i,j,x,y; x = 2; y = 3; for(i=0;i<x;i++){ for(j=0;j<y;j++){ free(C[i][j]); } free(C[i]); } free(C); }

  • malloc関数について。

    typedef struct a{ char *simei; int nenrei; }MEIBO; void main(void) { MEIBO a[5]; int wa; for(i = 0; i <= 4; i++ ) { a[i].simei = malloc(100 * sizeof(char) ); if( a[i].simei == NULL ) /* 領域確保に失敗したか */ { printf( "%dバイトの領域確保に失敗", 100 * sizeof(char) ); return 1; } printf("%d番目を入力してください\n",i+1); scanf("%s",&a[i].simei); printf("%s\n",a[i].simei); } C言語初心者です。これで入力したa[i].simeiが表示されないのですが、間違いを指摘していただけますでしょうか。宜しくお願いします。

  • malloc関数について質問です。

    整数を入力してその分だけ動的にメモリを確保し、その後文字列を入力して確保した領域に格納し、表示するプログラムなんですが、 int main(void) { int n; char *p; puts("整数を入力"); scanf("%d", &n); p = malloc(sizeof(char) *(n+1)); puts("文字を入力");   scanf("%s", p); printf("文字列は%s\n", p); free(p); return 0; } としたら、ちゃんとプログラムは動くんですが、 問題の意図にあっているんでしょうか?

  • malloc関数の使い方について(初心者)

    膨大なデータ数を扱うためにmalloc関数を用いて配列にデータを格納し、それを表示するプログラムを考えました。コンパイルはできるのですが、実行するとエラーが起こります。freeの開放の仕方が間違っているのでしょうか?よろしくお願いします。 /*ソース*/ #include <stdio.h> #include <stdlib.h> #define N 130000 int main(void) { double *p; int i; p = malloc(N); if(!p){ printf("割り当てエラー"); exit(1); } for(i=0;i<N;i++){ p[i]=i; printf("%f\n",p[i]); } free(p); }

  • malloc関数の使い方

    このじゃんけんプログラムに、ゲーム終了時ユーザーとコンピュータが出した全ての手を履歴として表示したいのですがmalloc()関数を使って表示させるとしたらどういったプログラムになりますか。 *aと*b、int stage=0を最初に宣言して void rireki(void) { a = (int *)malloc(sizeof(int) * (draw_no+lose_no+win_no)); a[stage++] = comp; b = (int *)malloc(sizeof(int) * (draw_no+lose_no+win_no)); b[stage++] = user; } 関数を作り、最後にprintf文で書いたのですがうまくいきませんでした。 hd[a[i]]という風に配列に配列を入れたのが駄目だったかもしれません。 for(i=0; i<draw_no+lose_no+win_no; i++){ printf("%d回目 ユーザ:%c コンピュータ:%c\n", i+1, hd[b[i]], hd[a[i]]); } また本の課題なのですが、malloc関数は後に出てくるのでmalloc関数を使わずに履歴表示できるかもしれないのですが その場合配列をあらかじめ宣言して格納する手段になるのでしょうか。 よろしくお願いします。 /* 課題3-6 */ #include <time.h> #include <stdio.h> #include <stdlib.h> int user; /* プレーヤの手 */ int comp; /* コンピュータの手 */ int win_no; /* 勝った回数 */ int lose_no; /* 負けた回数 */ int draw_no; /* 引き分けた回数 */ char *hd[] = {"グー", "チョキ", "パー"}; /* 手 */ /* initialize関数の宣言 */ void initialize(void); /* jyanken関数の宣言 */ void jyanken(void); /* count_no関数の宣言 */ void count_no(int result); /* disp_result関数の宣言 */ void disp_result(int result); /* confirm_retry関数の宣言 */ int confirm_retry(void); /* メイン関数 */ int main(void) { int judge; /* 勝敗 */ int retry; /* もう一度 */ initialize(); /* 初期処理 */ do{ jyanken(); /* じゃんけん実行 */ /* コンピュータとプレーヤの手を表示 */ printf("私は%sで、あなたは%sです。\n", hd[comp], hd[user]); judge = (user - comp + 3) % 3; /* 勝敗を判定 */ count_no(judge); /* 勝/負/引分け回数を更新 */ disp_result(judge); /* 判定結果を表示 */ retry = confirm_retry(); }while(retry == 1); printf("%d勝%d敗%d分けでした。\n", win_no, lose_no, draw_no); return (0); } /*--- 初期処理 ---*/ /* initialize関数の定義 */ void initialize(void) { win_no = 0; /* 勝った回数 */ lose_no = 0; /* 負けた回数 */ draw_no = 0; /* 引き分けた回数 */ srand(time(NULL)); /* 乱数の種を初期化 */ printf("じゃんけんゲーム開始!!\n"); } /*--- じゃんけん実行(手の読み込み/生成) ---*/ /* jyanken関数の定義 */ void jyanken(void) { int i; comp = rand() % 3; /* コンピュータの手 (0~2) を乱数で生成 */ printf("\n\aじゃんけんポン …"); for(i=0; i<3; i++) printf(" (%d)%s", i, hd[i]); printf(":"); scanf("%d", &user); /* プレーヤの手を読み込む */ } /*--- 勝/負/引き分回数を更新 ---*/ /* count_no関数の定義 */ void count_no(int result) { switch(result){ case 0: draw_no++; break; case 1: lose_no++; break; case 2: win_no++; break; } } /*--- 判定結果を表示 ---*/ /* disp_result関数の定義 */ void disp_result(int result) { switch(result){ case 0: puts("引き分けです。"); break; /* 引き分け */ case 1: puts("あなたの負けです。"); break; /* 負け */ case 2: puts("あなたの勝ちです。"); break; /* 勝ち */ } } /*--- 再挑戦するか確認 ---*/ /* confirm_result関数の定義 */ int confirm_retry(void) { int x; printf("もう一度しますか … (0)いいえ (1)はい:"); scanf("%d", &x); return (x); }

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

    ポインタの配列の動的確保について教えてください。 入力した数値をポインタ配列に入れるプログラムです。 下記のように書いてみました。(見づらくてごめんなさい) #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));   ・・・ ポインタの配列を宣言して、配列の各要素に動的確保するのと ポインタのポインタを宣言し、ポインタ配列を動的確保して、再度配列の要素に動的確保するのとでは、何か違いがあるのでしょうか? ポインタのポインタを宣言し、ポインタ配列を確保する必要性が良く分かっていないのです。 ネット等で調べて見たのですが、理解力がないのかよく分かりませんでした。 どうか教えてください。

  • mallocで動的確保後、値が変わる

    最近よく出くわすバグなのですが、mallocでメモリを動的確保して、いくつかの処理をした後に値が変わっていたり、読めなくてセグメンテーションエラーになることがあります。 根本的に何か間違っているのかもしれませんが、なかなかわかりません。 例えばこんな感じです ... int main(int argv,char *argc[]) { double *arrXn; double *arrFn; double *arrX; double *arrY; double *arrV; double *arrD; double **arrCn; ... //N(0~9)を受け取る arrXn=(double *)malloc(sizeof(double)*(N+1)); arrFn=(double *)malloc(sizeof(double)*(N+1)); arrX=(double *)malloc(sizeof(double)*(N+1)); arrY=(double *)malloc(sizeof(double)*(N+1)); arrV=(double *)malloc(sizeof(double)*(N+1)); arrD=(double *)malloc(sizeof(double)*(N+1)); arrCn=(double **)malloc(sizeof(double *)*(N+2)); for(incA=0;incA<=N;incA++){ arrCn[incA]=(double *)malloc(sizeof(double)*4); } for(incA=1;incA<N;incA++){ arrCn[incA][0]=arrFn[incA-1]; arrCn[incA][1]=arrV[incA-1]; arrCn[incA][2]=-3*arrFn[incA-1]+3*arrFn[incA]-2*arrV[incA-1]-arrV[incA]; arrCn[incA][3]=2+arrFn[incA-1]-2*arrFn[incA]+arrV[incA-1]+arrV[incA]; } printf("%lf",arrCn[1][1]);getchar(); //取れる for(incA=0;incA<=numHokan;incA++){ arrX[incA]=Setx(incA); //自作関数 } printf("%lf",arrCn[1][1]);getchar(); //セグメンテーションエラー 特に多次元配列を作成したり、動的確保を大目にすると起こりやすいです。 もし何かお気付きのことがありましたらよろしくお願いします。

  • ヘッダファイル? malloc.hとかは自分で足したり作ったりできるのでしょうか

    CmachineでC言語を勉強していて、メモリの確保までたどり着きました。 でも、プログラムを実行できないんです。調べたところ、malloc.hやmemory.hがCmachineのincludeフォルダに入っていませんでした。 char *b; b = (char *)malloc(sizeof(char)*200); とか書いても実行できませんよね・・・。Cmachineは勉強するのに便利だし、ヘッダファイルを追加できないのでしょうか。includeフォルダにテキストファイルで書いて入れればできそうなのですが。 ちなみに、Visual C++ Express Editionでも同じプログラムを実行したのですが、できませんでした。あれもヘッダファイルが無いとかの問題なのでしょうか。あれは操作が複雑で難しくてよくわかりません。 アドバイスやいい方法をご存知の方、教えてください!!

  • malloc メモリリークについて

    #include<stdio.h> #include<stdlib.h> void alloconly(void) { const int sz=10; static int n=0; void *p; p=(void*)malloc(sz); if(p==NULL){ printf("動的確保不可 %d\n",n+1); printf("確保メモリサイズ %d byte\n",sz*n); exit(-1); } ++n; } int main(void) { for(;;){ alloconly(); } }と言うプログラムがある本に載っており、回答として   動的確保不可 *******(数字)   確保メモリサイズ *********byte(数字)となっていますが私の環境(Reshat Linux)では   強制終了します で終了してしまいます。原因が判らず困っています。ご解答願います。

専門家に質問してみよう