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

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

ただいまの
回答率

90.84%

  • C

    3333questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C言語 segmentation fault

解決済

回答 4

投稿

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

north_redwings

score 20

C言語の行列の計算です.
N*Nの正方行列とN*1のベクトルの掛け算で動的確保の勉強です.
Nをとりあえずdefineで定義しているのですが,N=2,4,5あたりは問題なく作動するのですが,N=3,8,9あたりは必ずsegmentation faultと出てしまいます.(このエラーについてはよくわかっていません)
以下がコードです.行列の動的確保のコードは授業で配布された物を使用しており,まだしっかりとは解釈できていませんがとりあえず見よう見まねで使いました.

#include <stdio.h>
#include <stdlib.h>
#define N 3

double **dmatrix(int, int);  /* 行列領域の確保 */
double *dvector(int ); /* ベクトル領域の確保 */ 

int main(void) {
  double **mat_A;  /* ポインタへのポインタ */
  double *vec_x, *vec_b;

  printf("N=%d\n",N);

  mat_A = dmatrix(N, N);   /* 領域確保 */
  vec_x = dvector(N);
  vec_b = dvector(N);

  for(int s=0;s<N;s++){
    for(int t=0;t<N;t++){
        mat_A[s][t] = (double)(s+t);
        vec_x[s] = (double)s;
        vec_b[s] = (double)0;
        printf("mat_A[%d][%d]=%lf, vec_x[%d]=%lf, vec_b[%d]=%lf\n",s,t,mat_A[s][t],s,vec_x[s],s,vec_b[s]);
    }
}


  for(int i=0;i<N;i++){
    for(int j=0;j<N;j++){
        vec_b[i] += mat_A[i][j]*vec_x[j];
    }
}
    for(int k=0;k<N;k++){
    printf("\n b[%d]=%lf \n",k,vec_b[k]);
    }
    printf("\n");

  free(mat_A);
  free(vec_x);
  free(vec_b);
  return 0;
}

double **dmatrix(int nr, int nc) {
  double **mat;
  mat = malloc(nr*sizeof(double *));
  if (mat == NULL) 
    puts("Failure!! (from (*dmatrix)[nr])");
  else {
    int i, j;
    double *base = malloc(nr*nc*sizeof(double));
    if (base == NULL)
      puts("Failure!! (from dmatrix[nr][nc])");
    else {
      for (i=0; i < nr; i++)
    mat[i] = base + i*nc;
    }
    free(base);
  }
  return(mat);
}

double *dvector(int n) 
{
  double *vec= malloc(n*sizeof(double));
  if (vec == NULL) {
    printf("Failure!! (from dvector) \n");
    exit(1);
  }  
  return(vec);
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

checkベストアンサー

+2

バグの原因はすでに指摘されている箇所のfreeの呼び出しのせいです。

リファクタリングしてみました。少しは見やすいはず。

なお多くの指導教官はろくにC言語の標準規格なんて読んでませんし、安全に配慮したコードなんて書いたことがないので、教えられないのは致し方ありません。
挙句C言語の知識がC89(1989年に標準化、今から28年前!!!)で止まっていたりもっとひどいとその更に前、規格標準化前のK&R Cのころ(だいぶ文法が違う)だったり。

C言語の標準規格は、ANSI C89/ISO C90, (ISO C95), ISO C99, ISO C11となっており、もうすぐISO C17が出そうです。
C17 (not C++17) - Qiita
History of C - cppreference.com

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define N 3

/// 行列の確保
double** new_dmatrix(int nr, int nc)
{
  double** mat = malloc(nr * sizeof(double*));
  if (mat == NULL) {
    puts("Failure!! (from (*new_dmatrix)[nr])");
    exit(1);
  }
  double* base = malloc(nr * nc * sizeof(double));
  if (base == NULL) {
    puts("Failure!! (from new_dmatrix[nr][nc])");
    exit(1);
  }
  for (int i=0; i < nr; i++) {
    mat[i] = base + i*nc;
  }
  //DO NOT FREE THIS MEMORY BLOCK
  //TO AVOID segmentation fault!
  //free(base);
  return mat;
}

///行列の開放
void delete_dmatrix(double** mat)
{
  free(mat[0]);
  free(mat);
}

/// ベクトルの確保
double* new_dvector(int n)
{
  double *vec = malloc(n*sizeof(double));
  if (vec == NULL) {
    printf("Failure!! (from new_dvector) \n");
    exit(1);
  }
  return vec;
}

/// ベクトルの開放
void delete_dvector(double* vec)
{
  free(vec);
}

int main(void)
{
  printf("N=%d\n",N);

  double** mat_A = new_dmatrix(N, N);// 領域確保
  double* vec_x = new_dvector(N);
  double* vec_b = new_dvector(N);

  memset(vec_b, 0, N * sizeof(double));
  for(int s=0;s<N;s++){
    for(int t=0;t<N;t++){
      mat_A[s][t] = (double)(s+t);
      vec_x[s] = (double)s;
      printf("mat_A[%d][%d]=%lf, vec_x[%d]=%lf, vec_b[%d]=%lf\n" , s, t, mat_A[s][t] ,s, vec_x[s], s, vec_b[s]);
    }
  }

  for(int i = 0; i < N; i++){
    for(int j = 0; j < N; j++){
      vec_b[i] += mat_A[i][j] * vec_x[j];
    }
  }
  for(int k = 0; k < N; k++){
    printf("\n b[%d]=%lf \n", k, vec_b[k]);
  }
  putchar('\n');

  delete_dmatrix(mat_A);
  delete_dvector(vec_x);
  delete_dvector(vec_b);
  return 0;
}

https://wandbox.org/permlink/Iq9g2CPMfPGpgKy4

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/09 23:40

    本当に丁寧にありがとうございました.
    助かりました!
    もっと勉強していきます!!!

    キャンセル

+2

サイズnr*ncの領域を取ってサイズncの配列nr個に分けてmatrixにしているので、mat_aの実態は*base内にあります。

なのに baseをfreeしてしまっているので不安定な動作になっています。
あちこちに無駄な処理も含まれています。エラー処理も間違いがありますが、動作テストの範囲内ではメモリ割り当てに失敗することがないので顕在化はしてません。

とりあえず分かりやすさのためには、

 else {
    int i;
   for (i=0; i < nr; i++)
      mat[i] =dvector(nc);
    }
  }


のほうが見通しが良くなるでしょう。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/09 20:50

    ありがとうございます!
    教員から渡されたコードなのであまり考えずに使ってしまいました。要反省ですね…やり直してみます!

    キャンセル

  • 2017/12/09 23:13

    このfreeが原因ですね。その後のmain内のmat_A[s][t]が不正アクセスになる

    キャンセル

  • 2017/12/09 23:21

    今完全に出来上がりました、ありがとうございます!
    教員でも間違えるんですね…確認してから配布してると思ったんですが…笑。

    キャンセル

  • 2017/12/10 08:55

    プログラミングに限らず、教員の担当科目は必ずしも教員自身の理解度を確保して割り当てられてはいないので。

    キャンセル

0

とりいそぎエラーメッセージの意味だけ。
segmentation fault
はLinux等において不正なメモリアクセスがあったときに発生します。たとえば、有効アドレスを示していないポインタを辿って変数書き込みした場合などがこの例です。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/09 20:18

    迅速な回答ありがとうございます。

    僕も調べてみたんですがどうやらメモリ関連のエラーみたいですね…。
    行列の動的確保の部分は解釈出来ていないのと教員から渡されたコードなので(それでもミスがあって自分で直したつもりなのですが)、さらに全ての値のときだけ…値が大きくなると…コンパイル時にランダムで…などではなく上記の通り特定の値のときだけこうなってしまうので尚更困っています…。

    もし後に判明しましたら回答の程よろしくお願いします。

    キャンセル

0

迅速な回答ありがとうございます。

僕も調べてみたんですがどうやらメモリ関連のエラーみたいですね…。
行列の動的確保の部分は解釈出来ていないのと教員から渡されたコードなので(それでもミスがあって自分で直したつもりなのですが)、さらに全ての値のときだけ…値が大きくなると…コンパイル時にランダムで…などではなく上記の通り特定の値のときだけこうなってしまうので尚更困っています…。

もし後に判明しましたら回答の程よろしくお願いします。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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

  • C

    3333questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。